关注common wx: CodingTechWork
引言
在开发过程中,会有一些需求将controller层的一些方法入参进行全量转换,最容易想到的可能是在调用下层service方法时,调用公共的方法进行入参转换,这时带来的唯一问题就是代码不雅观,比较冗余。那还有什么方法可以更优雅的解决这个问题吗?答案是有的:切面。
我们实现一个AOP切面程序,对入参中的需转换的参数进行专项转换,而无需在各个controller层的各个方法中进行转换处理。
实践
controller类
package com.test.selfcoding.controller;import com.test.selfcoding.bean.PersonBean;import com.test.selfcoding.service.HelloWorldService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;@RestController@RequestMapping("/hello/world")public class HelloWorldController { @Autowired private HelloWorldService helloWorldService; @GetMapping("/test1") public String testGetHelloWorld() { return helloWorldService.getHelloWolrd(); } @PostMapping("/test2") public String testPostHelloWord(@RequestBody PersonBean personBean) { return helloWorldService.postHelloWorld(personBean); } @GetMapping("/test3") public String testPostHelloWord(@RequestParam String personName) { return personName + ", hi world!"; }}
切面类
package com.test.selfcoding.aspect;import com.alibaba.fastjson.JSON;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Field;import java.lang.reflect.Modifier;import java.util.Arrays;@Component@Aspect@Slf4jpublic class DefaultArgumentsAspect { @Before(value = "execution(* com.test.selfcoding.controller..*(..))") public void doBefore(JoinPoint joinPoint) { try { //获取入参列表 Object[] args = joinPoint.getArgs(); log.info("args: {}", JSON.toJSONString(args)); //入参判空 if (null == args || args.length == 0) { log.info("no fields!"); return; } //获取第一个入参(主要针对@RequestBody,一般只会有一个入参,若遇到多个@RequestParam,需循环处理) Object arg = args[0]; //获取字段域 Field[] fields = arg.getClass().getDeclaredFields(); log.info("getDeclaredFields: {}", JSON.toJSONString(fields));//判断入参中是否有"name" if (Arrays.stream(fields).noneMatch(item -> "name".equals(item.getName()))) { log.info("no name field!"); return; } //入参中有"name",获取该字段 Field field = arg.getClass().getDeclaredField("name"); //判断是否可使用 boolean accessible = ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()); //若不可用,则需要进行setAccessible if (accessible) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); // 获取request对象 HttpServletRequest request = attributes.getRequest(); log.info("method name: {}", request.getRequestURI()); field.setAccessible(true); //将name参数替换为system field.set(arg, "system"); } } catch (Exception e) { log.error("切面参数设置异常", e); } }}
验证
无参测试接口1
- 接口调用
- 控制台日志
2023-06-28 18:06:06.060 INFO 6495 --- [nio-8001-exec-1] c.t.s.aspect.DefaultArgumentsAspect : args: []2023-06-28 18:06:06.061 INFO 6495 --- [nio-8001-exec-1] c.t.s.aspect.DefaultArgumentsAspect : no fields!2023-06-28 18:06:06.066 INFO 6495 --- [nio-8001-exec-1] c.t.s.s.impl.HelloWorldServiceImpl : getHelloWolrd() get str success.result: hugh, hello world!
- 结果分析
未获取到参数,正常走接口。打印no fields!
,无需转换参数。
不包含指定参数测试接口2
-
接口调用
-
控制台日志
2023-06-28 18:08:04.040 INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect : args: ["xiaowang"]2023-06-28 18:08:04.055 INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect : getDeclaredFields: [{"accessible":false,"annotatedType":{"annotatedGenericComponentType":{"annotations":[],"declaredAnnotations":[],"type":"char"},"annotations":[],"declaredAnnotations":[],"type":"[C"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"[C","modifiers":18,"name":"value","synthetic":false,"type":"[C"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"int"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"int","modifiers":2,"name":"hash","synthetic":false,"type":"int"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"long"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"long","modifiers":26,"name":"serialVersionUID","synthetic":false,"type":"long"},{"accessible":false,"annotatedType":{"annotatedGenericComponentType":{"annotations":[],"declaredAnnotations":[],"type":"java.io.ObjectStreamField"},"annotations":[],"declaredAnnotations":[],"type":"[Ljava.io.ObjectStreamField;"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"[Ljava.io.ObjectStreamField;","modifiers":26,"name":"serialPersistentFields","synthetic":false,"type":"[Ljava.io.ObjectStreamField;"},{"accessible":false,"annotatedType":{"annotatedActualTypeArguments":[{"annotations":[],"declaredAnnotations":[],"type":"java.lang.String"}],"annotations":[],"declaredAnnotations":[],"type":{"actualTypeArguments":["java.lang.String"],"rawType":"java.util.Comparator","typeName":"java.util.Comparator" }},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":{"$ref":"$[4].annotatedType.type"},"modifiers":25,"name":"CASE_INSENSITIVE_ORDER","synthetic":false,"type":"java.util.Comparator"}]2023-06-28 18:08:04.056 INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect : no name field!
- 结果分析
未获取到指定的参数,正常走接口。打印no name field!
,无需转换参数。
包含指定参数测试接口3
-
接口调用
-
控制台日志
2023-06-28 18:10:15.481 INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect : args: [{"age":1,"name":"xiaohong"}]2023-06-28 18:10:15.482 INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect : getDeclaredFields: [{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"java.lang.String"},"annotations":[],"declaringClass":"com.test.selfcoding.bean.PersonBean","enumConstant":false,"genericType":"java.lang.String","modifiers":2,"name":"name","synthetic":false,"type":"java.lang.String"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"int"},"annotations":[],"declaringClass":"com.test.selfcoding.bean.PersonBean","enumConstant":false,"genericType":"int","modifiers":2,"name":"age","synthetic":false,"type":"int"}]2023-06-28 18:10:15.482 INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect : method name: /hello/world/test2
- 结果分析
获取到指定的参数,进行name值替换为system
,切面转换参数成功。
来源地址:https://blog.csdn.net/Andya_net/article/details/131442326