java打印请求参数日志

之前写过一篇博客,是通过拦截器的方式对所有http请求进行日志打印,但是这有一个严重的问题,那就是body数据只能从流里取出来一次,虽然通过复制的方式解决了这个问题,却又引入新的问题。
项目进行流读取及流复制的操作是一件非常消耗CPU资源的一件事,当并发数不高的时候服务会很正常,但是并发数高起来之后就需要更多的CPU核数来支持服务运行。正因为上述考虑,随后将日志从拦截器中改为了aop,这样就不存在多次读取流的问题,本质上切面拿的是controller层方法入参,跟servlet就无关了。
具体代码如下:

@Component
@Aspect
@Slf4j
public class LogCollectionAop {

    @Resource(name = "headKafkaTemplate")
    private KafkaTemplate<String, String> headKafkaTemplate;
    @Value("${spring.kafka.header-topic}")
    private String headerTopic;

    @Pointcut("execution(* com.sohu.mp.appletbackend.controller.*.*(..))")
    public void log(){}

    @Before("log()")
    //只有@Around注解才能配合使用ProceedingJoinPoint,其他方法用JoinPoint。少了proceed()方法
    public void doBefore(JoinPoint pjp) throws Throwable {
        ServletRequestAttributes servletAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        assert servletAttributes != null;
        HttpServletRequest request = servletAttributes.getRequest();
        getHeaderLog(request,pjp);
    }

    private void getHeaderLog(HttpServletRequest request, JoinPoint pjp){
        //取参数,打印参数
        if (request.getMethod().equals("GET")){
        //get请求如果也用下边的方式取参数,会没有参数名称,所以还是从servlet中取
            getParam = request.getQueryString();;
        }
        if (request.getMethod().equals("POST")){
        //这么取,取出来的是方法的入参,不仅仅是body里的参数,body只是其中一项
            Object[] arguments = pjp.getArgs();
            StringBuilder sb = new StringBuilder();
            Arrays.stream(arguments).forEach(sb::append);
            body = StringUtils.trimAllWhitespace(sb.toString());
        }
    }
}

当然也能取出来参数名,但是取出来的是你命名的变量名,而不是@RequestParam(value="")中的value。不需要通过反射取参数名,通过下边这种方式即可。

			Object[] args = pjp.getArgs();
            MethodSignature methodSignature = (MethodSignature)pjp.getSignature();
            //获取参数名
            Parameter[] ps = methodSignature.getMethod().getParameters();
            String[] parameterNames = new String[ps.length];
            for (int i=0;i<ps.length;i++){
                parameterNames[i] = ps[i].getName();
            }
            // 通过map封装参数和参数值
            HashMap<String, String> paramMap = new HashMap();
            for (int i = 0; i < parameterNames.length; i++) {
                paramMap.put(parameterNames[i], StringUtils.trimAllWhitespace(String.valueOf(args[i])));
            }

拦截器打印参数

你可能感兴趣的:(日常工作问题,java,web开发,aop)