欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot實(shí)現(xiàn)數(shù)據(jù)加密脫敏的示例代碼

 更新時間:2023年08月03日 10:22:50   作者:孤居自傲  
這篇文章主要為大家學(xué)習(xí)介紹了SpringBoot如何利用注解+反射+AOP實(shí)現(xiàn)數(shù)據(jù)加密脫敏的功能,文中的示例代碼講解詳細(xì),需要的可以參考一下

SpringBoot 實(shí)現(xiàn)數(shù)據(jù)加密脫敏(注解 + 反射 + AOP)

場景:響應(yīng)政府要求,商業(yè)軟件應(yīng)保證用戶基本信息不被泄露,不能直接展示用戶手機(jī)號,身份證,地址等敏感信息。

根據(jù)上面場景描述,我們可以分析出兩個點(diǎn)。

  • 不被泄露說明用戶信息應(yīng)被加密儲存;
  • 不能直接展示說明用戶信息應(yīng)脫敏展示;

解決方案

傻瓜式編程:將項目中關(guān)于用戶信息實(shí)體類的字段,比如姓名,手機(jī)號,身份證,地址等,在新增進(jìn)數(shù)據(jù)庫之前,對數(shù)據(jù)進(jìn)行加密處理;在列表中展示用戶信息時,對數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行解密脫敏,然后返回給前端;

切入式編程:將項目中關(guān)于用戶信息實(shí)體類的字段用注解給標(biāo)記,新增用戶信息實(shí)體類(這里我們用UserBO來表示,給UserBO里面的name,phone字段添加@EncryptField),返回用戶信息實(shí)體類(這里我們用UserDO來表示,給UserDO里面的name,phone字段添加@DecryptField);然后利用@EncryptField,@DecryptField做為切入點(diǎn),以切面的形式實(shí)現(xiàn)加密,解密脫敏;

傻瓜式編程不是說傻,而是相當(dāng)于切入式編程,傻瓜式編程需要對用戶信息相關(guān)的所有接口進(jìn)行加密,解密脫敏的邏輯處理,這里改動的地方就比較多,風(fēng)險高,重復(fù)操作相同的邏輯,工作量大,后期不好維護(hù);切入式編程只需要對用戶信息字段添加注解,對有注解的字段統(tǒng)一進(jìn)行加密,解密脫敏邏輯處理,操作方便,高聚合,易維護(hù);

方案實(shí)現(xiàn)

傻瓜式編程沒什么難度,這里我給大家有切入式編程來實(shí)現(xiàn);在實(shí)現(xiàn)之前,跟大家預(yù)熱一下注解,反射,AOP的知識;

注解實(shí)戰(zhàn)

創(chuàng)建注解

創(chuàng)建一個只能標(biāo)記在方法上的注解:

package com.weige.javaskillpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)         //METHOD 說明該注解只能用在方法上
@Retention(RetentionPolicy.RUNTIME) //RUNTIME 說明該注解在運(yùn)行時生效
public @interface Encryption {
}

創(chuàng)建一個只能標(biāo)記在字段上的注解:

package com.weige.javaskillpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)           //FIELD 說明該注解只能用在字段上
@Retention(RetentionPolicy.RUNTIME)  //RUNTIME 說明該注解在運(yùn)行時生效
public @interface EncryptField {
}

創(chuàng)建一個標(biāo)記在字段上,且有值的注解:

package com.weige.javaskillpoint.annotation;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptField {
	// 注解是可以有值的,這里可以為數(shù)組,String,枚舉等類型
	// DesensitizationEnum desensitizationEnum = field.getAnnotation(DecryptField.class).value(); 這里的field是指當(dāng)前標(biāo)記的字段
    DesensitizationEnum value(); 
}

注解使用

創(chuàng)建枚舉

package com.weige.javaskillpoint.enums;
public enum DesensitizationEnum {
    name,     // 用戶信息姓名脫敏
    address,  // 用戶信息地址脫敏
    phone;    // 用戶信息手機(jī)號脫敏
}

創(chuàng)建UserDO類

package com.weige.javaskillpoint.entity;
import com.weige.javaskillpoint.annotation.DecryptField;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
import com.weige.javaskillpoint.utils.AesUtil;
import java.lang.reflect.Field;
// 用戶信息返回實(shí)體類
public class UserDO {
    @DecryptField(DesensitizationEnum.name)
    private String name;
    @DecryptField(DesensitizationEnum.address)
    private String address;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public UserDO(String name, String address) {
        this.name = name;
        this.address = address;
    }
    public static void main(String[] args) throws IllegalAccessException {
        // 生成并初始化對象
        UserDO userDO = new UserDO("夢想是什么","湖北省武漢市");
        // 反射獲取當(dāng)前對象的所有字段
        Field[] fields = userDO.getClass().getDeclaredFields();
        // 遍歷字段
        for (Field field : fields) {
            // 判斷字段上是否存在@DecryptField注解
            boolean hasSecureField = field.isAnnotationPresent(DecryptField.class);
            // 存在
            if (hasSecureField) {
                // 暴力破解 不然操作不了權(quán)限為private的字段
                field.setAccessible(true);
                // 如果當(dāng)前字段在userDo中不為空 即name,address字段有值
                if (field.get(userDO) != null) {
                    // 獲取字段上注解的value值
                    DesensitizationEnum desensitizationEnum = field.getAnnotation(DecryptField.class).value();
                    // 控制臺輸出
                    System.out.println(desensitizationEnum);
                    // 根據(jù)不同的value值 我們可以對字段進(jìn)行不同邏輯的脫敏 比如姓名脫敏-魏*,手機(jī)號脫敏-187****2275 
                }
            }
        }
    }
}

反射實(shí)戰(zhàn)

創(chuàng)建UserBO類

package com.weige.javaskillpoint.entity;
import com.weige.javaskillpoint.annotation.EncryptField;
import java.lang.reflect.Field;
// 用戶信息新增實(shí)體類
public class UserBO {
    @EncryptField
    private String name;
    @EncryptField
    private String address;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public UserBO(String name, String address) {
        this.name = name;
        this.address = address;
    }
    @Override
    public String toString() {
        return "UserBO{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
    public static void main(String[] args) throws IllegalAccessException {
        UserBO userBO = new UserBO("周傳雄","湖北省武漢市");
        Field[] fields = userBO.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean annotationPresent = field.isAnnotationPresent(EncryptField.class);
            if(annotationPresent){
                // 當(dāng)前字段內(nèi)容不為空
                if(field.get(userBO) != null){
                    // 這里對字段內(nèi)容進(jìn)行加密
                    Object obj = encrypt(field.get(userBO));
                    // 字段內(nèi)容加密過后 通過反射重新賦給該字段
                    field.set(userBO, obj);
                }
            }
        }
        System.out.println(userBO);
    }
    public static Object encrypt(Object obj){
        return "加密: " + obj;
    }
}

AOP實(shí)戰(zhàn)

切入點(diǎn):

package com.weige.javaskillpoint.controller;
import com.weige.javaskillpoint.annotation.Encryption;
import com.weige.javaskillpoint.entity.UserBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/encrypt")
@Slf4j
public class EncryptController {
    @PostMapping("/v1")
    @Encryption  // 切入點(diǎn)
    public UserBO insert(@RequestBody UserBO user) {
        log.info("加密后對象:{}", user);
        return user;
    }
}

切面:

package com.weige.javaskillpoint.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class EncryptAspect {
    //攔截需加密注解 切入點(diǎn)
    @Pointcut("@annotation(com.weige.javaskillpoint.annotation.Encryption)")
    public void point() {
    }
    @Around("point()") //環(huán)繞通知
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //加密邏輯處理
        encrypt(joinPoint);
        return joinPoint.proceed();
    }
}

為什么這里要使用AOP:無論是注解,反射,都需要一個啟動方法,我上面演示的是通過main函數(shù)來啟動。使用AOP,項目啟動后,只要調(diào)用切入點(diǎn)對應(yīng)的方法,就會根據(jù)切入點(diǎn)來形成一個切面,進(jìn)行統(tǒng)一的邏輯增強(qiáng);如果大家熟悉SpringMVC,SpringMVC提供了 ResponseBodyAdvice 和 RequestBodyAdvice兩個接口,這兩個接口可以對請求和響應(yīng)進(jìn)行預(yù)處理,就可以不需要使用AOP;

加密解密脫敏實(shí)戰(zhàn)

項目目錄:

pom.xml文件:

<dependencies>
        <!--Springboot項目自帶 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Springboot Web項目 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <!-- hutool  -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.20</version>
        </dependency>
		<!-- 切面 aop  -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
    </dependencies>

實(shí)體類

用戶信息新增實(shí)體類 :UserBO

package com.weige.javaskillpoint.entity;
import com.weige.javaskillpoint.annotation.EncryptField;
// 實(shí)體類
public class UserBO {
    @EncryptField
    private String name;
    @EncryptField
    private String address;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public UserBO(String name, String address) {
        this.name = name;
        this.address = address;
    }
    @Override
    public String toString() {
        return "UserBO{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

用戶信息返回實(shí)體類 :UserDO

package com.weige.javaskillpoint.entity;
import com.weige.javaskillpoint.annotation.DecryptField;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
// 實(shí)體類
public class UserDO {
    @DecryptField(DesensitizationEnum.name)
    private String name;
    @DecryptField(DesensitizationEnum.address)
    private String address;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public UserDO(String name, String address) {
        this.name = name;
        this.address = address;
    }
}

脫敏枚舉

package com.weige.javaskillpoint.enums;
public enum DesensitizationEnum {
    name,
    address,
    phone;
}

注解

解密字段注解(字段):

package com.weige.javaskillpoint.annotation;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptField {
    DesensitizationEnum value();
}

解密方法注解(方法 作切入點(diǎn)):

package com.weige.javaskillpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Decryption {
}

加密字段注解(字段):

package com.weige.javaskillpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
}

加密方法注解(方法 作切入點(diǎn)):

package com.weige.javaskillpoint.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encryption {
}

控制層

解密 Controller:

package com.weige.javaskillpoint.controller;
import com.weige.javaskillpoint.annotation.Decryption;
import com.weige.javaskillpoint.entity.UserDO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/decrypt")
public class DecryptController {
    @GetMapping("/v1")
    @Decryption
    public UserDO decrypt() {
        return new UserDO("7c29e296e92893476db5f9477480ba7f", "b5c7ff86ac36c01dda45d9ffb0bf73194b083937349c3901f571d42acdaa7bae");
    }
}

加密 Controller:

package com.weige.javaskillpoint.controller;
import com.weige.javaskillpoint.annotation.Encryption;
import com.weige.javaskillpoint.entity.UserBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/encrypt")
@Slf4j
public class EncryptController {
    @PostMapping("/v1")
    @Encryption
    public UserBO insert(@RequestBody UserBO user) {
        log.info("加密后對象:{}", user);
        return user;
    }
}

切面

解密脫敏切面:

package com.weige.javaskillpoint.aop;
import com.weige.javaskillpoint.annotation.DecryptField;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
import com.weige.javaskillpoint.utils.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
@Slf4j
@Aspect
@Component
public class DecryptAspect {
    //攔截需解密注解
    @Pointcut("@annotation(com.weige.javaskillpoint.annotation.Decryption)")
    public void point() {
    }
    @Around("point()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //解密
        return decrypt(joinPoint);
    }
    public Object decrypt(ProceedingJoinPoint joinPoint) {
        Object result = null;
        try {
            Object obj = joinPoint.proceed();
            if (obj != null) {
                //拋磚引玉 ,可自行擴(kuò)展其他類型字段的判斷
                if (obj instanceof String) {
                    decryptValue();
                } else {
                    result = decryptData(obj);
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return result;
    }
    private Object decryptData(Object obj) throws IllegalAccessException {
        if (Objects.isNull(obj)) {
            return null;
        }
        if (obj instanceof ArrayList) {
            decryptList(obj);
        } else {
            decryptObj(obj);
        }
        return obj;
    }
    private void decryptObj(Object obj) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean hasSecureField = field.isAnnotationPresent(DecryptField.class);
            if (hasSecureField) {
                field.setAccessible(true);
                if (field.get(obj) != null) {
                    String realValue = (String) field.get(obj);
                    DesensitizationEnum desensitizationEnum = field.getAnnotation(DecryptField.class).value();
                    String value = (String) AesUtil.decrypt(realValue,desensitizationEnum);
                    field.set(obj, value);
                }
            }
        }
    }
    private void decryptList(Object obj) throws IllegalAccessException {
        List<Object> result = new ArrayList<>();
        if (obj instanceof ArrayList) {
            result.addAll((Collection<?>) obj);
        }
        for (Object object : result) {
            decryptObj(object);
        }
    }
    private void decryptValue() {
        log.info("根據(jù)對象進(jìn)行解密脫敏,單個字段不做處理!");
    }
}

加密切面:

package com.weige.javaskillpoint.aop;
import com.weige.javaskillpoint.annotation.EncryptField;
import com.weige.javaskillpoint.entity.UserBO;
import com.weige.javaskillpoint.utils.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
@Slf4j
@Aspect
@Component
public class EncryptAspect {
    //攔截需加密注解
    @Pointcut("@annotation(com.weige.javaskillpoint.annotation.Encryption)")
    public void point() {
    }
    @Around("point()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //加密
        encrypt(joinPoint);
        return joinPoint.proceed();
    }
    public void encrypt(ProceedingJoinPoint joinPoint) {
        Object[] objects;
        try {
            objects = joinPoint.getArgs();
            if (objects.length != 0) {
                for (Object object : objects) {
                    if (object instanceof UserBO) {
                        Field[] fields = object.getClass().getDeclaredFields();
                        for (Field field : fields) {
                            if (field.isAnnotationPresent(EncryptField.class)) {
                                field.setAccessible(true);
                                if (field.get(object) != null) {
                                    // 進(jìn)行加密
                                    Object o = field.get(object);
                                    Object encrypt = AesUtil.encrypt(field.get(object));
                                    field.set(object, encrypt);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
}

工具類

加密工具類:AesUtil

package com.weige.javaskillpoint.utils;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
public class AesUtil {
    // 默認(rèn)16位 或 128 256位
    public static String AES_KEY = "Wk#qerdfdshbd910";
    public static AES aes = SecureUtil.aes(AES_KEY.getBytes());
    public static Object encrypt(Object obj) {
        return aes.encryptHex((String) obj);
    }
    public static Object decrypt(Object obj, DesensitizationEnum desensitizationEnum) {
        // 解密
        Object decrypt = decrypt(obj);
        // 脫敏
        return DesensitizationUtil.desensitization(decrypt, desensitizationEnum);
    }
    public static Object decrypt(Object obj) {
        return aes.decryptStr((String) obj, CharsetUtil.CHARSET_UTF_8);
    }
}

脫敏工具類:DesensitizationUtil

package com.weige.javaskillpoint.utils;
import cn.hutool.core.util.StrUtil;
import com.weige.javaskillpoint.enums.DesensitizationEnum;
public class DesensitizationUtil {
    public static Object desensitization(Object obj, DesensitizationEnum desensitizationEnum) {
        Object result;
        switch (desensitizationEnum) {
            case name:
                result = strUtilHide(obj, 1);
                break;
            case address:
                result = strUtilHide(obj, 3);
                break;
            default:
                result = "";
        }
        return result;
    }
    /**
     * start從0開始
     */
    public static Object strUtilHide(String obj, int start, int end) {
        return StrUtil.hide(obj, start, end);
    }
    public static Object strUtilHide(Object obj, int start) {
        return strUtilHide(((String) obj), start, ((String) obj).length());
    }
}

以上代碼不難,大伙復(fù)制到本地跑一遍,基本就能理解;愿每一位程序員少走彎路!

以上就是SpringBoot實(shí)現(xiàn)數(shù)據(jù)加密脫敏的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot數(shù)據(jù)加密脫敏的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot中使用異步調(diào)度程序的高級方法

    SpringBoot中使用異步調(diào)度程序的高級方法

    本文主要介紹了SpringBoot中使用異步調(diào)度程序的高級方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • 給新來的同事講where?1=1是什么意思

    給新來的同事講where?1=1是什么意思

    當(dāng)遇到多個查詢條件,使用where 1=1 可以很方便的解決我們的問題,但這究竟有什么意思呢?所以下面這篇文章主要給大家介紹了關(guān)于where?1=1是什么意思,需要的朋友可以參考下
    2021-12-12
  • 一文詳解Java?etcd的應(yīng)用場景及編碼實(shí)戰(zhàn)

    一文詳解Java?etcd的應(yīng)用場景及編碼實(shí)戰(zhàn)

    etcd?是一個高度一致的分布式鍵值存儲系統(tǒng)。本文旨在幫助大家理解etcd,從宏觀角度俯瞰etcd全局,掌握etcd的基本操作技能,需要的可以參考一下
    2022-08-08
  • MyBatis帶參查詢的方法詳解

    MyBatis帶參查詢的方法詳解

    這篇文章主要介紹了MyBatis帶參查詢的方法詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • groovy腳本定義結(jié)構(gòu)表一鍵生成POJO類

    groovy腳本定義結(jié)構(gòu)表一鍵生成POJO類

    這篇文章主要為大家介紹了groovy腳本定義結(jié)構(gòu)表一鍵生成POJO類示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Springboot傳參詳解

    Springboot傳參詳解

    這篇文章主要介紹了Springboot傳參的相關(guān)知識,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-11-11
  • java短信驗(yàn)證碼獲取次數(shù)限制實(shí)例

    java短信驗(yàn)證碼獲取次數(shù)限制實(shí)例

    這篇文章主要介紹了java短信驗(yàn)證碼獲取次數(shù)限制實(shí)例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • JavaWeb之Filter與Listener使用解析

    JavaWeb之Filter與Listener使用解析

    這篇文章主要介紹了JavaWeb之Filter與Listener使用解析,Filter表示過濾器,是JavaWeb三大組件(Servlet、Filter、Listener)之一,過濾器可以把對資源的請求攔截下來,從而實(shí)現(xiàn)一些特殊的功能,需要的朋友可以參考下
    2024-01-01
  • java面試常問的Runnable和Callable的區(qū)別

    java面試常問的Runnable和Callable的區(qū)別

    大家好,本篇文章主要講的是java面試常問的Runnable和Callable的區(qū)別,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • java反射原理制作對象打印工具

    java反射原理制作對象打印工具

    本文主要給大家介紹了java反射原理制作對象打印工具的方法和代碼,以及一個熱心網(wǎng)友給出的更加簡潔方便的代碼,小伙伴們需要的話可以參考下。
    2015-12-12

最新評論