自定义注解给属性加密

本文介绍了一种在Java中使用自定义注解实现字段级加密的方法。通过创建注解@EncryptionSM4,并在需要加密的字段上应用此注解,实现了对指定字段的SM4加密。同时提供了对List集合中元素的加密处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、创建注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EncryptionSM4 {
//可以给个默认值,然后根据不同的值采用不同加密方式
//String type() default "SM4";
}

2、在属性上加入注解

需要加密的字段

//三个实例类注意
//请求报文
@Data
public class FallbackRequestModel implements Serializable {
    /**
     * 交易流水号
     */
    @NotBlank(message = "tradeNo必填!")
    private String tradeNo;
    /**
     * 服务接口公共入参
     */
    @NotNull(message = "common必填!")
    private CommonModel common;
}

@Data
public class CommonModel implements Serializable {
    @NotEmpty(message = "people不能为空!")
    private List<PeopleModel> people;
}

@Data
public class PeopleModel implements Serializable {
    @NotBlank(message = "idNumber不能为空!")
    @EncryptionSM4
    private String idNumber;
}

请求报文示例:

{
     "tradeNo":"12345",
     "common": { 
        "people": [{
                "idNumber": "852741963852741" 
            },
            {
             
                "idNumber": "1234567987984891"
            }
        ]
    }
}

我们需要给每个人的证件号加密,这些people是一个list集合

3、 编写方法,解析注解

  /**
     * 加密
     * 
     * @param obj
     * @throws Exception
     */
    @SuppressWarnings("rawtypes")
    private void encrypt(Object obj) throws Exception {
        if (null == obj) {
            return;
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            Class<?> fieldType = field.getType();
            // 字符串
            if (fieldType == String.class) {
                if (field.isAnnotationPresent(EncryptionSM4.class)) {
                    field.setAccessible(Boolean.TRUE);
                    handleField(obj, field, config.getRegistrationCheck().getEncryptionKey());
                    field.setAccessible(Boolean.FALSE);
                }
            } else if (List.class.isAssignableFrom(fieldType)) {
                // 判断是否为list
                Type genericType = field.getGenericType();
                if (genericType instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) genericType;
                    Class genericClazz = (Class) pt.getActualTypeArguments()[0];
                    // list<String>
                    if (genericClazz == String.class) {
                        if (field.isAnnotationPresent(EncryptionSM4.class)) {
                            field.setAccessible(Boolean.TRUE);
                            List list = (List) field.get(obj);
                            if (list != null && !list.isEmpty()) {
                                for (int i = 0; i < list.size(); i++) {
                                    if (list.get(i) != null) {
                                        list.set(i, DataSecurityUtil.encryption((String) list.get(i),
                                                config.getRegistrationCheck().getEncryptionKey()));
                                    }
                                }
                            }
                            field.setAccessible(Boolean.FALSE);
                        }
                    } else {
                        field.setAccessible(Boolean.TRUE);
                        List list = (List) field.get(obj);
                        if (list != null && !list.isEmpty()) {
                            for (Object subObj : list) {
                                encrypt(subObj);
                            }
                        }
                        field.setAccessible(Boolean.FALSE);
                    }
                }
            } else if (fieldType.getName().startsWith("com.sleb.transit.cbittransit.model")) {
                // 判断属于自定义的model
                field.setAccessible(Boolean.TRUE);
                encrypt(field.get(obj));
                field.setAccessible(Boolean.FALSE);
            } else if (fieldType == Object.class) {
                field.setAccessible(Boolean.TRUE);
                encrypt(field.get(obj));
                field.setAccessible(Boolean.FALSE);
            }
        }
    }

    private static void handleField(Object obj, Field field, String secretKey) throws Exception {
        if (null == obj) {
            return;
        }
        // 说明:sm4依赖包传入null会出现空指针异常
        Object item = field.get(obj);
        if (null != item) {
            field.set(obj, DataSecurityUtil.encryption((String) field.get(obj), secretKey));
        }
    }

因为我的加密字段都在list集合中,如果有的在普通对象中,可以在加个判断。

   // 若属性有该注解,且属性为字符串类型,则根据对应的加密方式进行加密
  if (field.isAnnotationPresent(Security.class) && field.getType().equals(String.class)) {
       // 获取加密方式
       String type = field.getAnnotation(Security.class).type();
       switch (type) {
           case "SM4":
               // 可自定义加密
               field.set(obj, "ttt" + field.get(obj));
               break;
           default:
               break;
       }

注:根据自己的业务需求进行更改,本文知识提供一些思路

### 创建自定义注解 在 Spring Boot 中,自定义注解是一种用于增强代码可读性、实现逻辑解耦的有效方式。通过结合 AOP 或拦截器技术,可以实现诸如日志记录、权限控制、数据加解密等功能。 #### 定义自定义注解 创建一个自定义注解通常需要使用 `@interface` 关键字,并可以结合元注解(如 `@Retention`、`@Target` 等)来定义其作用范围和生命周期。例如: ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CustomAnnotation { String value() default "default value"; } ``` 上述注解可用于方法上,并在运行时通过反射获取其值[^1]。 --- ### 使用自定义注解与 AOP 结合 为了使自定义注解具备实际功能,通常需要配合 AOP(面向切面编程)进行处理。AOP 允许开发者定义“切面”以集中管理横切关注点,例如日志记录或安全检查。 以下是一个结合 AOP 处理自定义注解的示例: ```java import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class CustomAnnotationAspect { @Around("@annotation(customAnnotation)") public Object handleCustomAnnotation(ProceedingJoinPoint joinPoint, CustomAnnotation customAnnotation) throws Throwable { System.out.println("Before method execution with annotation value: " + customAnnotation.value()); Object result = joinPoint.proceed(); System.out.println("After method execution"); return result; } } ``` 在这个切面中,所有被 `@CustomAnnotation` 注解的方法都会在执行前后输出日志信息。这种设计适用于统一处理特定行为的需求[^5]。 --- ### 自定义注解与配置属性结合 除了 AOP,还可以将自定义注解与配置文件相结合,从而动态控制某些逻辑。例如,可以通过 `application.properties` 定义一些参数,并在自定义注解中引用这些参数。 假设在配置文件中有如下内容: ```properties myapp.feature.enabled=true ``` 可以通过 `@Value` 注入该属性,并在切面中根据其值决定是否执行特定逻辑: ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class FeatureToggleHandler { @Value("${myapp.feature.enabled}") private boolean featureEnabled; public boolean isFeatureEnabled() { return featureEnabled; } } ``` 然后,在切面中使用该配置值判断是否启用某项功能: ```java @Around("@annotation(customAnnotation)") public Object handleWithFeatureCheck(ProceedingJoinPoint joinPoint, CustomAnnotation customAnnotation) throws Throwable { if (featureToggleHandler.isFeatureEnabled()) { System.out.println("Feature is enabled. Proceeding..."); return joinPoint.proceed(); } else { System.out.println("Feature is disabled."); return null; } } ``` 这种方式使得自定义注解的功能更加灵活,可以根据环境变化进行调整[^3]。 --- ### 实际应用场景 - **日志记录**:对带有特定注解的方法进行调用前后的日志记录。 - **权限控制**:限制只有特定角色或权限的用户才能访问标注了特定注解的方法。 - **性能监控**:统计方法执行时间,识别系统瓶颈。 - **数据加解密**:对敏感字段自动进行加密/解密操作,避免手动处理带来的错误风险[^4]。 --- ### 总结 自定义注解结合 AOP 和配置管理,为 Spring Boot 应用提供了强大的扩展能力。开发者可以通过简洁的方式实现复杂的功能,并提升代码的可维护性和可测试性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值