Spring Controller 打印入参/出参

本文介绍了如何在Spring Boot项目中实现Controller层的请求参数和返回结果的日志打印。通过自定义注解`@LogPrint`,结合AOP切面处理,详细记录了实现步骤,包括pom.xml依赖配置、切面创建、注解使用等。同时,文章讨论了日志打印过程中遇到的问题,如中文乱码、日志过滤等,并提供了简化版本的解决方案。

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

参考

思路:

自定义注解,针对注解创建切面,对Controller 中的方法使用注解,通过切面中的 @Before, @Around 获取数据并打印

实现步骤

完整代码地址:https://gitee.com/springff/logprint

日志打印 pom.xml 依赖

<!-- spring-aop -->
<spring.version>4.3.12.RELEASE</spring.version>
<!-- jackson-databind, jackson-core, jackson-annotations -->
<jackson.version>2.9.1</jackson.version>
<!-- aspectjrt, aspectjweaver 实现切面 -->
<aspectj.version>1.8.9</aspectj.version>
<!-- logback-core 会自动引入依赖的 sjf4j -->
<logback.version>1.2.2</logback.version>
<!-- lombok sjf4j 中 log 对象实例化-->
<lombok.version>1.16.18</lombok.version>

spring-mvc.xml 添加 aop 自动代理 <aop:aspectj-autoproxy/>

新建注解 LogPrint,将注解作为切点,作用到 Controller 的方法

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogPrint {
    String description() default "";
}

新建切面 LogPrintAspect,在 controller 方法调用前,调用后打印入参,出参

@Aspect
@Component
@Slf4j
public class LogPrintAspect {
    // 1,声明切点
    @Pointcut("@annotation(cn.exrick.common.annotaion.LogPrint)")
    public void logPrint(){}
    // 2,打印入参 joinPoint.getArgs() -- 获取入参
    @Before("logPrint()")
    public void doBefore(JoinPoint joinPoint){
    // 3, 打印出参 proceedingJoinPoint.proceeding() -- 执行切点修饰的方法,拿到结果,打印响应
    @Around("logPrint()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {}
	// 4,切点作用的方法结束
    @After("logPrint()")
    public void doAfter(){}
}

使用注解 @LogPrint 修饰 Controller 类中的方法

@RestController
public class LogController {
    @LogPrint
    @RequestMapping("/logGet")
    public Object getTest(String name, String age){
        String content = name + "今年" + age + "岁";
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("content", content);
        return resultMap;
    }
}

日志打印结果

在这里插入图片描述

过程记录

日志打印存在的问题:打印请求与打印响应并不是相邻输出,查看日志的时候需要添加上过滤条件

jackson 直接返回带中文的字符串,中文显示乱码 ????18?。将字符串放到HashMap 中返回,中文正常显示{"content": "张三今年18岁"}

@LogPrint 注解加上后日志不打印?<aop:aspectj-autoproxy/> 没有添加导致 aop 在 spring 框架中不启用

日志打印简化版本,日志过滤

添加

<!-- aop 配置批量添加切面 -->
<aop:config>
    <aop:advisor advice-ref="txAdvice"
                 pointcut="execution(* cn.exrick.manager.service..*.*(..))" />
</aop:config>

todo

  • 注解的实现
  • jsonUtil 的实现
  • jackson post 请求拿不到数据(使用 postman模拟请求前提下)
  • 根据日志id,过滤日志,在 linux 中怎样进行过滤

其他参考

### 回答1: 您可以通过使用AOP(面向切面编程)来实现对Spring Boot接口的进行打印。 首先,定义一个切面类,在该类中编写打印代码: ``` @Aspect @Component public class LogAspect { private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class); @Pointcut("execution(public * com.example.controller.*.*(..))") public void log() {} @Before("log()") public void doBefore(JoinPoint joinPoint) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); LOGGER.info("请求URL : {}", request.getRequestURL().toString()); LOGGER.info("请求方法 : {}", request.getMethod()); LOGGER.info("请求IP : {}", request.getRemoteAddr()); LOGGER.info("请求 : {}", Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "ret", pointcut = "log()") public void doAfterReturning(Object ret) throws Throwable { LOGGER.info("请求 : {}", ret); } } ``` 其中,使用@Pointcut注解定义切点,在本例中为所有在com.example.controller包下的方法。 使用@Before注解定义在切点之前执行的操作,在本例中为打印请求URL、请求方法、请求IP和请求。 使用@AfterReturning注解定义在切点之后执行的操作,在本例中为打印请求。 对于中包含MultipartFile类型的情况,您可以使用instanceof进行判断,并对MultipartFile进行特殊处理。例如: ``` for (Object arg : joinPoint.getArgs()) { if (arg instanceof MultipartFile) { ### 回答2: 在Spring Boot中,可以通过一些方式来打印接口的。 首先,我们可以在方法的参数中使用`@RequestBody`注解来接收请求的,该注解可以将请求的JSON数据转换成对应的实体类对象。如果实体类中包含了`MultipartFile`类型的属性,可以通过以下代码处理: ```java @PostMapping("/upload") public void uploadFile(@RequestParam("file") MultipartFile file) throws IOException { // 打印 System.out.println(":"); System.out.println("文件名:" + file.getOriginalFilename()); System.out.println("文件类型:" + file.getContentType()); System.out.println("文件大小:" + file.getSize()); // 具体的文件处理逻辑 // ... } ``` 上述代码中,`@RequestParam("file")`用于获取请求参数中名为`file`的`MultipartFile`类型对象,并打印相关的属性信息。 另外,对于是实体类的情况,同样可以通过`@RequestBody`注解来接收请求的JSON数据并转换成对应的实体类对象。如果实体类中包含了`MultipartFile`类型的集合属性,可以通过以下代码处理: ```java @PostMapping("/upload") public void uploadFiles(@RequestBody Entity entity) { // 打印 System.out.println(":"); System.out.println("属性1:" + entity.getProperty1()); System.out.println("属性2:" + entity.getProperty2()); // 打印MultipartFile集合中的属性信息 List<MultipartFile> files = entity.getFiles(); for (MultipartFile file : files) { System.out.println("文件名:" + file.getOriginalFilename()); System.out.println("文件类型:" + file.getContentType()); System.out.println("文件大小:" + file.getSize()); // 具体的文件处理逻辑 // ... } } ``` 上述代码中,`Entity`即为实体类,其中包含了名为`files`的`MultipartFile`集合属性。通过遍历集合中的每个`MultipartFile`对象,可以打印相关的属性信息。 综上所述,通过上述代码可以在Spring Boot中打印接口的,包括处理包含`MultipartFile`和实体类的情况。 ### 回答3: 在Spring Boot中打印接口可以通过切面编程来实现。首先需要创建一个切面类,用于处理日志的打印。 ```java @Aspect @Component public class LogAspect { private Logger logger = LoggerFactory.getLogger(LogAspect.class); @Pointcut("execution(* com.example.controller.*.*(..))") public void controllerPointcut() {} @Before("controllerPointcut()") public void logRequest(JoinPoint joinPoint) { // 打印接口 logger.info("接口: {}", Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "result", pointcut = "controllerPointcut()") public void logResponse(Object result) { // 打印接口 logger.info("接口: {}", result); } } ``` 在切面类中,通过`@Before`注解的方式,在方法执行前打印接口的;通过`@AfterReturning`注解的方式,在方法返回后打印接口的。 如果接口中包含`MultipartFile`,可以在切面类中获取其相关信息并打印来。 实体类中包含`MultipartFile`集合的情况,可以通过增加一段逻辑来判断并处理打印。例如: ```java if (arg instanceof MultipartFile) { MultipartFile file = (MultipartFile) arg; logger.info("文件名: {}", file.getOriginalFilename()); } ``` 以上代码判断是否为`MultipartFile`类型,如果是的话,则打印文件名。 需要注意的是,切面类需要添加`@Aspect`和`@Component`注解,用于声明该类为切面类,并将其纳Spring容器管理。 另外,需要在Spring Boot的配置类中添加`@EnableAspectJAutoProxy`注解,启用切面的自动代理功能。 以上是一个简单示例,可以根据实际需求进行扩展和调整。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值