ChatGPT对话02

Q&A1

Q1:清理2023年,除了20230109目录外,保留近一个月的目录shell脚本

A1:以下是清理除20230109目录外,保留近一个月的目录的shell脚本:

1
2
3
4
复制代码#!/bin/bash

# 删除早于30天的目录
find /path/to/directory/* -type d ! -name "20230109" -ctime +30 -exec rm -rf {} \;

/path/to/directory/替换为要清理的目录的路径。这个脚本使用find命令来查找除了名为20230109的目录以外的所有目录,并删除它们,同时保留近30天内被修改过的目录。

学到了学到了,运维时就可以通过手动或定时任务清理一些不需要的文件了。

Q&A2

Q2:SpringBoot统一接口打印入参出参日志

A2:

在 Spring Boot 中,我们可以通过 AOP 实现统一打印接口的入参和出参日志。具体实现方式如下:

  1. 创建一个切面类 LogAspect,用来定义切点以及需要记录日志的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@Aspect
@Component
public class LogAspect {

private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

/**
* 定义切点,匹配所有controller包下面所有公共方法
*/
@Pointcut("execution(public * com.example.controller..*.*(..))")
public void executionLog() {}

/**
* 通过环绕通知拦截请求参数与返回结果
* @param pjp 切点
*/
@Around("executionLog()")
public Object around(ProceedingJoinPoint pjp) {

// 记录请求开始时间
long startTime = System.currentTimeMillis();

// 获取当前请求对象并记录请求参数
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
logRequestParams(request, pjp.getSignature().getName(), pjp.getArgs());

// 执行请求内容,并处理响应结果
Object result;
try {
result = pjp.proceed();
} catch (Throwable throwable) {
logger.error("error occurred while processing the request: {}", throwable.getMessage());
return Response.fail(ResponseCode.ERROR.getCode(), "系统繁忙,请稍候再试");
}

// 记录响应结果
logResponseResult(result);

// 记录请求结束时间
long endTime = System.currentTimeMillis();

// 输出耗时信息
logger.info("\n{} 请求处理结束,耗时:{}ms", pjp.getSignature(), (endTime - startTime));
return result;
}

/**
* 记录请求参数
*/
private void logRequestParams(HttpServletRequest request, String methodName, Object[] args) {
StringBuilder sb = new StringBuilder();
sb.append("\n╔------------------------------------------");
sb.append("\n║ Method Name : ").append(methodName);
sb.append("\n║ URL : ").append(request.getRequestURI());
sb.append("\n║ HTTP Method : ").append(request.getMethod());

if (args.length > 0) {
for (Object arg : args) {
// 参数为对象或Map类型时,转换为JSON字符串记录日志
if (arg != null && (arg instanceof JSONObject || arg.getClass().isAssignableFrom(Map.class))) {
sb.append("\n║ Request Parameters:");
sb.append(JSONObject.toJSONString(arg));
} else {
sb.append("\n║ Request Parameters:");
sb.append(arg);
}
}
}

sb.append("\n╚==========================================");
logger.info(sb.toString());
}

/**
* 记录响应结果
*/
private void logResponseResult(Object result) {
if (result == null) {
return;
}

// 将响应结果转换为 JSON 字符串,并打印
String resultJsonString = "";
if (result instanceof JSONObject) {
resultJsonString = JSONObject.toJSONString(result);
} else {
resultJsonString = JSONObject.toJSONString(Response.success(result));
}

logger.info("\n╔------------------------------------------" +
"\n║ Response :" + resultJsonString +
"\n╚==========================================");
}
}
  1. 在配置文件中开启 AOP 自动代理。

在 application.yml 或 application.properties 文件中添加以下配置:

1
2
3
spring:
aop:
auto: true
  1. 启动项目查看控制台日志。

现在,只要是位于 com.example.controller 包内的公共方法都会被 LogAspect 拦截,并在控制台输出请求参数和响应结果的日志信息。

这个回答还是挺好的,copy下,修改就能用了,而且这个代码有意思的点是Response.fail(ResponseCode.ERROR.getCode(), "系统繁忙,请稍候再试");,这个还是统一响应结果,有趣的勒。

Q&A3

Q3:springboot自定义拦截器

A3:在Spring Boot中自定义拦截器的步骤如下:

  1. 创建一个实现HandlerInterceptor接口的拦截器类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 在请求处理之前进行调用(Controller方法调用之前)
    // 返回true,则继续执行后续的Interceptor或Controller业务方法;返回false,则不再执行后续的Interceptor或Controller业务方法。
    return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    // 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    // 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
    }
    }

  2. 注册拦截器 方法一:重写WebMvcConfigurerAdapter类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Configuration
    public class WebMvcConfigurer extends WebMvcConfigurerAdapter {

    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(myInterceptor).addPathPatterns("/**")
    }
    }

方法二:实现WebMvcConfigurer接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Bean
MyInterceptor getMyInterceptor(){
return new CorsInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");
}
}

3. 若需要在拦截器中使用Bean 可以通过@Configuration,@Component等方式确保该Bean被Spring管理,然后通过@Autowired或@Resource注解引入

注意:默认情况下,添加的拦截器将会应用到所有的请求路径上。如果有特殊需求,可以通过addPathPatternsexcludePathPatterns方法来进行配置。

除了以下实现HandlerInterceptor接口外,还支持使用@ControllerAdvice+AOP对控制器方法进行拦截处理;也可以使用Servlet Filter对HTTP请求与响应进行拦截处理。