最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中實現(xiàn)數(shù)據(jù)脫敏的六種常用方案

 更新時間:2025年09月14日 10:25:33   作者:劉大華  
在日常的開發(fā)開發(fā)工作中,我相信各位老鐵肯定遇到過這種需求手機號中間四位得用*顯示等,既要展示部分數(shù)據(jù),又要保證敏感信息不泄露,這就是所謂的數(shù)據(jù)脫敏,所以今天給大家分享6種我在項目中常用的脫敏方案,需要的朋友可以參考下

前言

在日常的開發(fā)開發(fā)工作中,我相信各位老鐵肯定遇到過這種需求: “手機號中間四位得用*顯示”、“身份證中間八位要隱藏”、“用戶郵箱前綴脫敏”…… 例如:

  • 手機號:13812345678138****5678
  • 身份證:430101199003078888430101********8888
  • 姓名:張三四張*四
  • 郵箱號:12345678@qq.com1234****@qq.com
  • 銀行卡:62303518888524056230********2405

既要展示部分數(shù)據(jù),又要保證敏感信息不泄露。這就是所謂的數(shù)據(jù)脫敏

今天給大家分享6種我在項目中常用的脫敏方案,SpringBoot項目拿來即用,可以直接復(fù)制粘貼!

方案一:Hutool工具庫(懶人必備?。?/h2>

不想造輪子可以直接用現(xiàn)成的!

// Maven依賴
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.0</version>
</dependency>

// 使用示例
String phone = "13812345678";
String maskedPhone = DesensitizedUtil.mobilePhone(phone); // 138****5678

String idCard = "430101199003078888";
String maskedIdCard = DesensitizedUtil.idCardNum(idCard, 6, 4); // 430101********8888

String name = "張三四";
String maskedName = DesensitizedUtil.chineseName(name); // 張*四

String email = "12345678@qq.com";
String maskedEmail = DesensitizedUtil.email(email); // 1234****@qq.com

String bankCard = "6230351888852405";
String maskedBankCard = DesensitizedUtil.bankCard(bankCard); // 6230********2405

功能全面,開箱即用

方案二:正則工具類

寫個工具類,需要的時候手動處理一下,這是最簡單直接的方式。

/**
 * 脫敏工具類 - 簡單直接
 */
public class SensitiveUtil {
    
    /**
     * 手機號脫敏:13812345678 -> 138****5678
     */
    public static String maskPhone(String phone) {
        if (StringUtils.isEmpty(phone) || phone.length() != 11) {
            return phone;
        }
        return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }
    
    /**
     * 身份證脫敏:430101199003078888 -> 430101********8888
     */
    public static String maskIdCard(String idCard) {
        if (StringUtils.isEmpty(idCard) || idCard.length() < 15) {
            return idCard;
        }
        return idCard.replaceAll("(\\d{6})\\d{8}(\\w{4})", "$1********$2");
    }
    
    /**
     * 姓名脫敏:張三四 -> 張*四
     */
    public static String maskName(String name) {
        if (StringUtils.isEmpty(name)) {
            return name;
        }
        if (name.length() == 1) {
            return "*";
        }
        if (name.length() == 2) {
            return name.charAt(0) + "*";
        }
        return name.substring(0, 1) + "*" + name.substring(name.length() - 1);
    }
    
    /**
     * 郵箱脫敏:12345678@qq.com -> 1234****@qq.com
     */
    public static String maskEmail(String email) {
        if (StringUtils.isEmpty(email) || !email.contains("@")) {
            return email;
        }
        String[] parts = email.split("@");
        if (parts[0].length() <= 4) {
            return parts[0].substring(0, 1) + "****@" + parts[1];
        }
        return parts[0].substring(0, 4) + "****@" + parts[1];
    }
    
    /**
     * 銀行卡脫敏:6230351888852405 -> 6230********2405
     */
    public static String maskBankCard(String bankCard) {
        if (StringUtils.isEmpty(bankCard) || bankCard.length() < 8) {
            return bankCard;
        }
        return bankCard.replaceAll("(\\d{4})\\d{8}(\\d{4})", "$1********$2");
    }
}

怎么用?很簡單:

User user = userService.getById(123);

// 手動脫敏
user.setPhone(SensitiveUtil.maskPhone(user.getPhone()));
user.setIdCard(SensitiveUtil.maskIdCard(user.getIdCard()));
user.setName(SensitiveUtil.maskName(user.getName()));
user.setEmail(SensitiveUtil.maskEmail(user.getEmail()));
user.setBankCard(SensitiveUtil.maskBankCard(user.getBankCard()));

return user;

非常簡單易懂,數(shù)據(jù)脫敏不再是問題。

但有些朋友又說了:“每寫一個接口或者每一個字段都要單獨調(diào)用,有點心累。有沒有更方便的方案?” 請看方案二。

方案三:自定義注解 + Jackson

利用Jackson的序列化機制,在返回JSON時自動對標注了注解的字段進行脫敏。

// 脫敏注解
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerializer.class)
public @interface Sensitive {
    SensitiveType value();
}

// 脫敏類型枚舉
public enum SensitiveType {
    PHONE,      // 手機號
    ID_CARD,    // 身份證
    NAME,       // 姓名
    EMAIL,      // 郵箱
    BANK_CARD   // 銀行卡
}

// 脫敏序列化器
public class SensitiveSerializer extends JsonSerializer<String> {
    private SensitiveType type;
    
    public SensitiveSerializer(SensitiveType type) {
        this.type = type;
    }
    
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        String result;
        switch (type) {
            case PHONE:
                result = SensitiveUtil.maskPhone(value);
                break;
            case ID_CARD:
                result = SensitiveUtil.maskIdCard(value);
                break;
            case NAME:
                result = SensitiveUtil.maskName(value);
                break;
            case EMAIL:
                result = SensitiveUtil.maskEmail(value);
                break;
            case BANK_CARD:
                result = SensitiveUtil.maskBankCard(value);
                break;
            default:
                result = value;
        }
        gen.writeString(result);
    }
}

使用方式

public class User {
    private String name;
    
    @Sensitive(SensitiveType.PHONE)
    private String phone;
    
    @Sensitive(SensitiveType.ID_CARD)
    private String idCard;
    
    @Sensitive(SensitiveType.NAME)
    private String name;
    
    @Sensitive(SensitiveType.EMAIL)
    private String email;
    
    @Sensitive(SensitiveType.BANK_CARD)
    private String bankCard;
}

性能好,只在序列化時生效。配置一次,全局都可以用,不影響業(yè)務(wù)邏輯。缺點是需要配置Jackson

方案四:Lombok + 自定義Getter(輕量級替代方案)

如果你不想引入太多框架,但用了Lombok,這個方案很合適。

思路:讓Lombok不生成默認getter,我們自己寫一個帶脫敏邏輯的getter。

1. 關(guān)閉Lombok的默認getter

去掉@Data,只保留你需要的Lombok注解,手動添加帶脫敏的getter

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Setter
public class UserVO {

    private String name;
    private String phone;
    private String idCard;
    private String email;
    private String bankCard;

    // 自定義脫敏 getter
    public String getName() {
        return SensitiveUtil.maskName(name);
    }

    public String getPhone() {
        return SensitiveUtil.maskPhone(phone);
    }

    public String getIdCard() {
        return SensitiveUtil.maskIdCard(idCard);
    }
    
    public String getEmail() {
        return SensitiveUtil.maskEmail(email);
    }
    
    public String getBankCard() {
        return SensitiveUtil.maskBankCard(bankCard);
    }
}

這樣只要調(diào)用user.getxx(),返回的就是脫敏后的數(shù)據(jù)。

實現(xiàn)簡單,不依賴額外組件,適合小項目。但每個字段都要手動寫getter,有點啰嗦了。

方案五:AOP切面深度脫敏(推薦)

這個是主推的方案,特別適合嵌套對象、List、Map等類型。 為什么?因為前面的方法大多只處理單層DTO
但現(xiàn)實中經(jīng)常是:

public class User {
    @Sensitive(SensitiveType.PHONE)
    private String phone; // 這個能脫敏
    
    private UserDetail detail; // 這里面還有敏感字段
}

public class UserDetail {
    @Sensitive(SensitiveType.ID_CARD)
    private String idCard; // 這個脫敏不了!
}

返回User對象時,phone字段能脫敏,但detail.idCard還是明文顯示!

解決方案:用AOP + 深度遞歸反射。詳細步驟如下:

1. 定義脫敏類型枚舉

/**
 * 脫敏類型枚舉
 */
public enum SensitiveType {
    PHONE,      // 手機號
    ID_CARD,    // 身份證
    NAME,       // 姓名
    EMAIL,      // 郵箱
    BANK_CARD   // 銀行卡
}

2. 定義注解@Sensitive

/**
 * 脫敏注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sensitive {
    SensitiveType value();
}

3. 需要保留方案一的工具類,增加以下的maskByType方法

/**
 * 根據(jù)類型脫敏
*/
public static String maskByType(String value, SensitiveType type) {
	if (StringUtils.isBlank(value)) {
            return value;
        }

        switch (type) {
            case PHONE: return maskPhone(value);
            case ID_CARD: return maskIdCard(value);
            case NAME: return maskName(value);
            case EMAIL: return maskEmail(value);
            case BANK_CARD: return maskBankCard(value);
            default: return value;
        }
    }
}

4. 寫AOP切面(核心邏輯)

/**
 * 深度脫敏AOP處理器
 */
@Aspect
@Component
@Slf4j
public class DeepSensitiveAspect {
    
    // 定義切點:攔截Controller層所有方法
    @Pointcut("execution(* com.example.controller..*.*(..))")
    public void controllerPointcut() {}
    
    // 定義切點:攔截Service層所有方法
    @Pointcut("execution(* com.example.service..*.*(..))")
    public void servicePointcut() {}
    
    /**
     * 環(huán)繞通知:處理Controller層返回結(jié)果
     */
    @Around("controllerPointcut()")
    public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        return processDeepSensitive(result);
    }
    
    /**
     * 環(huán)繞通知:處理Service層返回結(jié)果
     */
    @Around("servicePointcut()")
    public Object aroundService(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        return processDeepSensitive(result);
    }
    
    /**
     * 深度脫敏處理
     */
    private Object processDeepSensitive(Object obj) {
        if (obj == null) {
            return null;
        }
        
        // 處理集合類型
        if (obj instanceof List) {
            return processList((List<?>) obj);
        }
        
        // 處理數(shù)組類型
        if (obj.getClass().isArray()) {
            return processArray((Object[]) obj);
        }
        
        // 處理Map類型
        if (obj instanceof Map) {
            return processMap((Map<?, ?>) obj);
        }
        
        // 處理分頁對象(Spring Data Page)
        if (obj instanceof Page) {
            return processPage((Page<?>) obj);
        }
        
        // 處理普通Java對象
        if (isCustomClass(obj.getClass())) {
            return processObject(obj);
        }
        
        // 基本類型直接返回
        return obj;
    }
    
    /**
     * 處理List集合
     */
    private List<?> processList(List<?> list) {
        if (list == null || list.isEmpty()) {
            return list;
        }
        
        return list.stream()
            .map(this::processDeepSensitive)
            .collect(Collectors.toList());
    }
    
    /**
     * 處理數(shù)組
     */
    private Object[] processArray(Object[] array) {
        if (array == null || array.length == 0) {
            return array;
        }
        
        Object[] result = new Object[array.length];
        for (int i = 0; i < array.length; i++) {
            result[i] = processDeepSensitive(array[i]);
        }
        return result;
    }
    
    /**
     * 處理Map
     */
    private Map<?, ?> processMap(Map<?, ?> map) {
        if (map == null || map.isEmpty()) {
            return map;
        }
        
        Map<Object, Object> result = new HashMap<>();
        for (Map.Entry<?, ?> entry : map.entrySet()) {
            result.put(entry.getKey(), processDeepSensitive(entry.getValue()));
        }
        return result;
    }
    
    /**
     * 處理分頁對象
     */
    private Page<?> processPage(Page<?> page) {
        if (page == null) {
            return null;
        }
        
        List<?> content = processList(page.getContent());
        return new PageImpl<>(content, page.getPageable(), page.getTotalElements());
    }
    
    /**
     * 處理單個對象
     */
    private Object processObject(Object obj) {
        if (obj == null) {
            return null;
        }
        
        Class<?> clazz = obj.getClass();
        try {
            // 獲取所有字段(包括父類)
            List<Field> fields = getAllFields(clazz);
            
            for (Field field : fields) {
                field.setAccessible(true);
                
                // 檢查是否有脫敏注解
                Sensitive sensitive = field.getAnnotation(Sensitive.class);
                if (sensitive != null && field.getType() == String.class) {
                    // 處理敏感字段
                    processSensitiveField(obj, field, sensitive);
                } else {
                    // 遞歸處理嵌套對象
                    processNestedField(obj, field);
                }
            }
        } catch (Exception e) {
            log.warn("脫敏處理失敗: {}", e.getMessage());
        }
        
        return obj;
    }
    
    /**
     * 處理敏感字段
     */
    private void processSensitiveField(Object obj, Field field, Sensitive sensitive) {
        try {
            String value = (String) field.get(obj);
            if (StringUtils.isNotBlank(value)) {
                String maskedValue = SensitiveUtil.maskByType(value, sensitive.value());
                field.set(obj, maskedValue);
            }
        } catch (IllegalAccessException e) {
            log.warn("字段脫敏失敗: {}", field.getName());
        }
    }
    
    /**
     * 處理嵌套字段
     */
    private void processNestedField(Object obj, Field field) {
        try {
            Object fieldValue = field.get(obj);
            if (fieldValue != null && isCustomClass(field.getType())) {
                // 遞歸處理嵌套對象
                processObject(fieldValue);
            }
        } catch (IllegalAccessException e) {
            // 忽略無法訪問的字段
        }
    }
    
    /**
     * 獲取所有字段(包括父類)
     */
    private List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null && clazz != Object.class) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }
    
    /**
     * 判斷是否為自定義類(非JDK類)
     */
    private boolean isCustomClass(Class<?> clazz) {
        return clazz != null && 
               !clazz.isPrimitive() && 
               !clazz.getName().startsWith("java.") &&
               !clazz.getName().startsWith("javax.");
    }
}

5. 實體類使用示例

/**
 * 用戶實體
 */
@Data
public class User {
    private Long id;
    
    @Sensitive(SensitiveType.NAME)
    private String name;
    
    @Sensitive(SensitiveType.PHONE)
    private String phone;
    
    @Sensitive(SensitiveType.ID_CARD)
    private String idCard;
    
    @Sensitive(SensitiveType.EMAIL)
    private String email;
    
    @Sensitive(SensitiveType.BANK_CARD)
    private String bankCard;
    
    // 嵌套對象也會被處理
    private UserDetail detail;
}

/**
 * 用戶詳情實體
 */
@Data
public class UserDetail {
    @Sensitive(SensitiveType.PHONE)
    private String emergencyPhone;
    
    @Sensitive(SensitiveType.ID_CARD)
    private String spouseIdCard;
}

6. Controller使用示例

@RestController
@RequestMapping("/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    /**
     * 返回單個用戶(自動脫敏)
     */
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    /**
     * 返回用戶列表(自動脫敏)
     */
    @GetMapping
    public List<User> getUsers() {
        return userService.getAllUsers();
    }
    
    /**
     * 返回分頁數(shù)據(jù)(自動脫敏)
     */
    @GetMapping("/page")
    public Page<User> getUsersByPage(Pageable pageable) {
        return userService.getUsersByPage(pageable);
    }
}

7. 效果驗證

{
  "id": 1,
  "name": "張*四",
  "phone": "138****5678",
  "idCard": "430101********8888",
  "email": "1234****@qq.com",
  "bankCard": "6230********2405",
  "detail": {
    "emergencyPhone": "139****8765",
    "spouseIdCard": "110105********1234"
  }
}

優(yōu)點

  • 全面支持:手機號、身份證、姓名、郵箱、銀行卡全搞定
  • 深度處理:支持多層嵌套對象脫敏
  • 零侵入:業(yè)務(wù)代碼無需任何修改
  • 高性能:使用反射緩存,性能優(yōu)化
  • 易擴展:新增脫敏類型只需擴展枚舉和工具方法

方案六:Mysql數(shù)據(jù)庫層脫敏

最簡單的MySQL脫敏SQL

SELECT 
    id,
    CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) AS phone,
    CONCAT(LEFT(id_card, 6), '********', RIGHT(id_card, 4)) AS id_card,
    CONCAT(LEFT(name, 1), '*', RIGHT(name, 1)) AS name,
    CONCAT(LEFT(email, 4), '****', SUBSTRING(email, LOCATE('@', email))) AS email,
    CONCAT(LEFT(bank_card, 4), '********', RIGHT(bank_card, 4)) AS bank_card
FROM users;

分字段詳細寫法

1. 手機號脫敏

SELECT CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) AS phone FROM users;
-- 13812345678 → 138****5678

2. 身份證脫敏

SELECT CONCAT(LEFT(id_card, 6), '********', RIGHT(id_card, 4)) AS id_card FROM users;
-- 430101199003078888 → 430101********8888

3. 姓名脫敏

SELECT 
    CASE 
        WHEN LENGTH(name) = 1 THEN '*'
        WHEN LENGTH(name) = 2 THEN CONCAT(LEFT(name, 1), '*')
        ELSE CONCAT(LEFT(name, 1), '*', RIGHT(name, 1))
    END AS name 
FROM users;
-- 張三四 → 張*四

4. 郵箱脫敏

SELECT 
    CONCAT(LEFT(email, 4), '****', SUBSTRING(email, LOCATE('@', email))) AS email 
FROM users;
-- 12345678@qq.com → 1234****@qq.com

5. 銀行卡脫敏

SELECT CONCAT(LEFT(bank_card, 4), '********', RIGHT(bank_card, 4)) AS bank_card FROM users;
-- 6230351888852405 → 6230********2405

6. 完整查詢示例

-- 查詢單個用戶
SELECT 
    id,
    CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) AS phone,
    CONCAT(LEFT(id_card, 6), '********', RIGHT(id_card, 4)) AS id_card,
    CASE 
        WHEN LENGTH(name) = 1 THEN '*'
        WHEN LENGTH(name) = 2 THEN CONCAT(LEFT(name, 1), '*')
        ELSE CONCAT(LEFT(name, 1), '*', RIGHT(name, 1))
    END AS name,
    CONCAT(LEFT(email, 4), '****', SUBSTRING(email, LOCATE('@', email))) AS email,
    CONCAT(LEFT(bank_card, 4), '********', RIGHT(bank_card, 4)) AS bank_card
FROM users 
WHERE id = 1;

-- 查詢用戶列表
SELECT 
    id,
    CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) AS phone,
    CONCAT(LEFT(name, 1), '*', RIGHT(name, 1)) AS name
FROM users 
ORDER BY id DESC 
LIMIT 10;

7. 創(chuàng)建視圖方案

如果經(jīng)常要用,建個視圖更方便:

CREATE VIEW v_user_masked AS
SELECT 
    id,
    CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) AS phone,
    CONCAT(LEFT(id_card, 6), '********', RIGHT(id_card, 4)) AS id_card,
    CASE 
        WHEN LENGTH(name) = 1 THEN '*'
        WHEN LENGTH(name) = 2 THEN CONCAT(LEFT(name, 1), '*')
        ELSE CONCAT(LEFT(name, 1), '*', RIGHT(name, 1))
    END AS name,
    CONCAT(LEFT(email, 4), '****', SUBSTRING(email, LOCATE('@', email))) AS email,
    CONCAT(LEFT(bank_card, 4), '********', RIGHT(bank_card, 4)) AS bank_card
FROM users;

-- 直接用視圖查詢
SELECT * FROM v_user_masked WHERE id = 1;

8. 聯(lián)表查詢脫敏

SELECT 
    u.id,
    CONCAT(LEFT(u.name, 1), '*', RIGHT(u.name, 1)) AS user_name,
    CONCAT(LEFT(u.phone, 3), '****', RIGHT(u.phone, 4)) AS user_phone,
    o.order_no,
    o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

最后總結(jié)

方案優(yōu)點缺點適用場景
Hutool 工具庫開箱即用,代碼簡潔,功能全依賴第三方庫,靈活性有限快速開發(fā)、小項目、原型階段
正則工具類 + 手動調(diào)用簡單直接,無額外依賴需手動調(diào)用,侵入業(yè)務(wù)代碼單字段少量脫敏,輕量級應(yīng)用
自定義注解 + Jackson 序列化自動化序列化脫敏,性能好僅作用于 JSON 輸出,不支持嵌套對象深層脫敏REST API 返回數(shù)據(jù)脫敏
Lombok + 自定義 Getter輕量,無需切面或框架每個字段都要寫 getter,重復(fù)代碼多VO/DTO 層控制輸出,適合簡單結(jié)構(gòu)
AOP 切面深度脫敏(推薦)支持嵌套對象、集合、分頁;零侵入業(yè)務(wù);可全局生效;易擴展實現(xiàn)復(fù)雜,需理解反射和 AOP中大型項目,復(fù)雜數(shù)據(jù)結(jié)構(gòu),統(tǒng)一脫敏治理
MySQL 數(shù)據(jù)庫層脫敏不依賴 Java 層,查詢即脫敏,安全隔離SQL 復(fù)雜,維護成本高,無法動態(tài)控制報表查詢、只讀視圖、DBA 視角脫敏

最佳實踐建議

1.如果你是新手或者小項目起步,方案一(Hutool)方案二(工具類)

2.如果你做的是標準后端服務(wù)API,推薦方案三(Jackson 注解序列化) 結(jié)合 @Sensitive注解,在返回 JSON時自動脫敏。

3.如果你的項目結(jié)構(gòu)復(fù)雜、嵌套深、List/Map/分頁多,強烈推薦 方案五(AOP深度脫敏)!這是真正意義上的“一次配置,處處脫敏”。

4.如果你有DB權(quán)限且需要給前端/報表提供固定脫敏視圖,使用 方案六(MySQL脫敏+視圖),實現(xiàn)數(shù)據(jù)訪問層面的安全隔離。

以上就是SpringBoot中實現(xiàn)數(shù)據(jù)脫敏的六種常用方案的詳細內(nèi)容,更多關(guān)于SpringBoot數(shù)據(jù)脫敏方案的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Mybatis分頁的4種方式實例

    Mybatis分頁的4種方式實例

    這篇文章主要介紹了Mybatis分頁的4種方式實例,包括數(shù)組分頁,sql分頁,攔截器分頁,RowBounds分頁,需要的朋友可以參考下
    2022-04-04
  • MyBatis/mybatis-plus項目打印SQL的方法實現(xiàn)

    MyBatis/mybatis-plus項目打印SQL的方法實現(xiàn)

    SpringBoot項目中,經(jīng)常需要打印SQL語句及其參數(shù),本文就來介紹一下MyBatis/mybatis-plus項目打印SQL的方法實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • Java+OpenCV調(diào)用攝像頭實現(xiàn)拍照功能

    Java+OpenCV調(diào)用攝像頭實現(xiàn)拍照功能

    隨著我們對環(huán)境、Mat基本使用越來越熟練、Java Swing也逐步熟悉了起來。本文將通過OpenCV驅(qū)動攝像頭實現(xiàn)識臉和拍照功能,需要的可以參考一下
    2022-03-03
  • Java自動拆裝箱簡單介紹

    Java自動拆裝箱簡單介紹

    這篇文章主要為大家詳細介紹了Java自動拆裝箱的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 一文掌握Java 數(shù)據(jù)結(jié)構(gòu)超詳細筆記(收藏版)

    一文掌握Java 數(shù)據(jù)結(jié)構(gòu)超詳細筆記(收藏版)

    本文給大家介紹Java數(shù)據(jù)結(jié)構(gòu),包括數(shù)組、鏈表、List、Set、Map及迭代器,對比了其內(nèi)存特性、操作效率和應(yīng)用場景,并介紹了哈希及沖突解決方法,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • Spring?Boot實現(xiàn)WebSocket實時通信

    Spring?Boot實現(xiàn)WebSocket實時通信

    本文主要介紹了Spring?Boot實現(xiàn)WebSocket實時通信,包含實現(xiàn)實時消息傳遞和群發(fā)消息等功能,具有一定的參考價值,感興趣的可以了解一下
    2024-05-05
  • SpringBoot應(yīng)用是否存在MySQL連接泄漏問題的排查方法

    SpringBoot應(yīng)用是否存在MySQL連接泄漏問題的排查方法

    這篇文章主要介紹了排查SpringBoot應(yīng)用MySQL連接泄漏的方法,需檢查連接數(shù)、空閑連接,配置連接池參數(shù),確保資源關(guān)閉,并使用監(jiān)控工具如Actuator和Prometheus分析,需要的朋友可以參考下
    2025-06-06
  • Java連接Sql數(shù)據(jù)庫經(jīng)常用到的操作

    Java連接Sql數(shù)據(jù)庫經(jīng)常用到的操作

    這篇文章主要介紹了Java連接Sql數(shù)據(jù)庫經(jīng)常用到的操作的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • Java對象數(shù)組的添加、刪除和遍歷代碼示例

    Java對象數(shù)組的添加、刪除和遍歷代碼示例

    在Java編程中,我們經(jīng)常需要對數(shù)據(jù)結(jié)構(gòu)進行遍歷操作,并根據(jù)業(yè)務(wù)需求刪除部分元素,這篇文章主要給大家介紹了關(guān)于Java對象數(shù)組的添加、刪除和遍歷的相關(guān)資料,需要的朋友可以參考下
    2024-04-04
  • Java 泛型詳解(超詳細的java泛型方法解析)

    Java 泛型詳解(超詳細的java泛型方法解析)

    這篇文章主要介紹了深入理解java泛型Generic,文中有非常詳細的代碼示例,對正在學(xué)習java的小伙伴們有非常好的幫助,需要的朋友可以參考下,希望對你有幫助
    2021-07-07

最新評論

景洪市| 伊川县| 清新县| 马关县| 岳普湖县| 兰州市| 壤塘县| 福清市| 印江| 民丰县| 江陵县| 南皮县| 沐川县| 青州市| 长治县| 宜阳县| 伊春市| 海丰县| 喀喇| 德格县| 体育| 泰来县| 泌阳县| 易门县| 连南| 北票市| 五华县| 富民县| 康保县| 遂昌县| 五河县| 远安县| 桃江县| 高陵县| 多伦县| 德惠市| 浦城县| 靖江市| 淮北市| 桓台县| 万年县|