Follow common wx: CodingTechWork
introduction
During the development process, there will be some requirements to fully convert some method input parameters of the controller layer. The easiest thing to think of may be that when calling the service method of the lower layer, the public method is called to perform input parameter conversion. The only problem brought about at this time The code is unsightly and redundant. So is there any way to solve this problem more elegantly? The answer is yes: facets.
We implement an AOP aspect program to perform special conversion on the parameters that need to be converted in the input parameters, without the need to perform conversion processing in each method of each controller layer.
practice
controller class
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.*;
/**
* @Description controller
* @Author Liao Jy
* @Date 2023/6/28
*/
@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!";
}
}
Noodles
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;
/**
* @Description DefaultArgumentsAspect
* @Author LiaoJy
* @Date 2023/6/28
*/
@Component
@Aspect
@Slf4j
public 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);
}
}
}
verify
No parameter test interface 1
- interface call
- console log
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!
- Result Analysis
No parameters are obtained, and the interface is used normally. Printno fields!
without converting arguments.
Does not contain the specified parameter test interface 2
-
interface call
-
console log
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<java.lang.String>"}},"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!
- Result Analysis
The specified parameters are not obtained, and the interface is used normally. Printno name field!
without converting arguments.
Contains the specified parameter test interface 3
-
interface call
-
console log
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
- Result analysis
The specified parameter is obtained, and the name value is replaced withsystem
, and the aspect conversion parameter is successful.