AOP,自定义注解,反射机制实现前端数据在后端自动解密

刚参加工作不久,很多基础东西都不懂,希望通过博客一步步积累,本文主要是为了整理一下最近自学的spring aop,自定义注解,反射机制。
项目结构如下:
这里写图片描述
demo主要功能: 前端请求controller接口上传用户信息,用户信息里面包括加密的信息,利用aop拦截所有controller方法,通过反射机制读取运行时信息进行解密操作,service层对解密后的用户信息进行显示

Controller层-SpringMVC

DemoController,有一个请求处理方法

@RestController
@RequestMapping("/demo")
@Api(description = "demo接口")
public class DemoController{
    @Autowired
    private DemoService demoService;
    @ApiOperation("提交用户信息")
    @RequestMapping(value="/uploadUserInfo",method = RequestMethod.POST)
    public void submitInfo(@RequestBody UserInfoParam param){
        demoService.submitInfo(param);
    }
}

方法接受参数为UserInfoParam,定义如下:包括加密字段mobile,且设计为所有包括加密字段的参数类需继承BasicAnnotationParam

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("用户信息参数")
public class UserInfoParam extends BasicAnnotationParam{
    /**
     * 手机号
     */
    @EncryptField
    private String mobile;
    /**
     * 年龄
     */
    private Integer age;
}

关于SpringMVC的内容可进一步讨论

AOP

由于在Controller接口方法里面,请求参数可能包含加密字段,因此利用aop对Controller所有方法进行拦截。

@Component
@Aspect
@Slf4j
public class EncryptDecryptAop {
    @Autowired
    private DecryptDomainService decryptDomainService;
    //设置切面, 多个切入点字段加解密aop技术,反射机制
    @Around("execution(* com.example.demo.controller.DemoController.*(..))")
    public Object doProcess(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("方法执行前。。。");
        //捕获方法参数列表
        List<Object> methodArgs = this.getMethodArgs(proceedingJoinPoint);
        //循环所有参数
        for (Object item : methodArgs) {
            //若参数为BasicAnnotationParam的子类
            if (item instanceof BasicAnnotationParam) {
                //捕获参数类中的所有字段
                Field[] fields = item.getClass().getDeclaredFields();
                //遍历所有字段
                for (Field field : fields) {
                    //若该字段被EncryptField注解,则进行加密
                    if (null != AnnotationUtils.findAnnotation(field, EncryptField.class)) {
                        //设置private类型允许访问
                        field.setAccessible(Boolean.TRUE);
                        field.set(item, decryptDomainService.decryptField(field.get(item)) );
                        field.setAccessible(Boolean.FALSE);
                    }
                }
            }
        }
        log.info("方法开始执行。。。。");
        Object result = proceedingJoinPoint.proceed();
        //还可以对返回值result进行解密处理
        log.info("方法执行后。。。");
        return result;
    }
    /**
     * 获取方法请求参数
     */
    private List<Object> getMethodArgs(ProceedingJoinPoint proceedingJoinPoint) {
        List<Object> methodArgs = Lists.newArrayList();
        for (Object arg : proceedingJoinPoint.getArgs()) {
            if (null != arg) {
                methodArgs.add(arg);
            }
        }
        return methodArgs;
    }
}

@Around(“execution(* com.example.demo.controller.DemoController.*(..))”) 注解标明拦截方式为环绕型,对DemoController下的任何方法进行拦截,可在拦截方法的执行前后进行额外处理。
该注解作用于方法public Object doProcess(ProceedingJoinPoint proceedingJoinPoint)。
关于spring aop的内容可进一步讨论。。。

java反射机制

在上述的AOP拦截方法处理中,判断方法参数中是否包含加密字段,需要采用java反射机制。
首选,通过proceedingJoinPoint.getArgs()获取方法的参数对象列表methodArgs,并遍历该参数列表。
对所有未继承BasicAnnotationParam类的参数进行忽略,约定此类参数不包含加密字段。
接着,读取参数实例化对象的运行时信息,即对应类的Class对象,有了Class对象对象就可以知道该类的所有运行时信息啦!
比如获取该参数类对所有属性字段
Field[] fields = item.getClass().getDeclaredFields();
再对所有字段信息进行遍历,检查字段是否被EncryptField注解所作用。
对所有EncryptField作用对字段解密操作,
在进行解密的时候,由于属性字段的访问权限一般为private,因此需对该字段临时允许访问,即field.setAccessible(Boolean.TRUE);
允许访问后即可对字段值进行解密
field.set(item, decryptDomainService.decryptField(field.get(item)) );
在Field为反射机制相关对类,包括get和set方法,只需传入某个实例化对象即可获得值。
在解密后不要忘了把属性字段对访问权限还原。
field.setAccessible(Boolean.FALSE);

上述解密方法的实现: 简单模拟解密过程,对加密手机号进行反转
@Override
public String decryptField(Object param) {
StringBuilder message = new StringBuilder(param.toString());
return message.reverse().toString();
}


关于反射机制的内容可进一步讨论。。。

自定义注解

上述对注解@EncryptField为自定义注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EncryptField {
}

该注解主要作用是标明哪些字段已加密,且通过反射机制可读取到。
关于注解的内容可进一步讨论。。。

Service层

对解密后的用户信息进行输出。

@Service
@Slf4j
public class DemoServiceImpl implements DemoService {
    /**
     * 提交用户信息
     */
    @Override
    public void submitInfo(UserInfoParam param) {
        log.info("正在输出mobile={},age={}", param.getMobile(), param.getAge());
    }
}

结果测试

本地启动项目,端口8080,利用命令curl发起http请求
curl -X POST –header “Content-Type: application/json” –header “Accept: /” -d “{\”age\”: 10,\”mobile\”:\”68623226131\”}” “http://127.0.0.1:8080/demo/uploadUserInfo

允许结果为:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值