qq_43751299 2021-05-26 23:41 采纳率: 50%
浏览 451
已采纳

springboot使用aop打印异步请求的日志报空指针

这是我的aop日志配置

package com.wtblog.service.config;

import com.wtblog.utils.ResultEntity;
import lombok.extern.slf4j.Slf4j;
import nl.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

@Aspect
@Component
@Slf4j
public class WebLogAspect {

    /**
     * 进入方法时间戳
     */
    private Long startTime;
    /**
     * 方法结束时间戳(计时)
     */
    private Long endTime;

    public WebLogAspect() {
    }

    /**
     * 定义请求日志切入点,其切入点表达式有多种匹配方式,这里是指定路径
     */
    @Pointcut("execution(* com.wtblog.service..*.*(..))")
    public void webLogPointcut() {
    }


    @Around("webLogPointcut()&&args(..,bindingResult)")
    public Object  doAround(ProceedingJoinPoint joinPoint, BindingResult bindingResult) throws Throwable {
        Object result = null;

        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //获取请求头中的User-Agent
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        //打印请求的内容
        startTime = System.currentTimeMillis();
        log.info("请求开始时间:{}", LocalDateTime.now());
        log.info("请求Url : {}", request.getRequestURL().toString());
        log.info("请求方式 : {}", request.getMethod());
        log.info("请求ip : {}", request.getRemoteAddr());
        log.info("请求参数 : {}", Arrays.toString(joinPoint.getArgs()));
        // 系统信息
        log.info("浏览器:{}", userAgent.getBrowser().toString());
        log.info("浏览器版本:{}", userAgent.getBrowserVersion());
        log.info("操作系统: {}", userAgent.getOperatingSystem().toString());

        List<ObjectError> ls = bindingResult.getAllErrors();
        if (ls != null && ls.size() > 0) {
            // 保存异常日志记录
            log.error("发生异常时间:{}", LocalDateTime.now());
            log.error("抛出异常:{}", ls.get(0).getDefaultMessage());
            return ResultEntity.failure().message(ls.get(0).getDefaultMessage());
        }
        result = joinPoint.proceed();
        return result;
    }


    /**
     * 前置通知:
     * 1. 在执行目标方法之前执行,比如请求接口之前的登录验证;
     * 2. 在前置通知中设置请求日志信息,如开始时间,请求参数,注解内容等
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLogPointcut()")
    public void doBefore(JoinPoint joinPoint) {

        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //获取请求头中的User-Agent
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        //打印请求的内容
        startTime = System.currentTimeMillis();
        log.info("请求开始时间:{}", LocalDateTime.now());
        log.info("请求Url : {}", request.getRequestURL().toString());
        log.info("请求方式 : {}", request.getMethod());
        log.info("请求ip : {}", request.getRemoteAddr());
        log.info("请求参数 : {}", Arrays.toString(joinPoint.getArgs()));
        // 系统信息
        log.info("浏览器:{}", userAgent.getBrowser().toString());
        log.info("浏览器版本:{}", userAgent.getBrowserVersion());
        log.info("操作系统: {}", userAgent.getOperatingSystem().toString());
    }

    /**
     * 返回通知:
     * 1. 在目标方法【正常结束之后】执行
     * 1. 在返回通知中补充请求日志信息,如返回时间,方法耗时,返回值,并且保存日志信息
     *
     * @param ret
     * @throws Throwable
     */
    @AfterReturning(returning = "ret", pointcut = "webLogPointcut()")
    public void doAfterReturning(Object ret) throws Throwable {
        endTime = System.currentTimeMillis();
        log.info("请求结束时间:{}", LocalDateTime.now());
        log.info("请求耗时:{}ms", (endTime - startTime));
        // 处理完请求,返回内容
        log.info("请求返回 : {}", ret);
    }

    /**
     * 异常通知:
     * 1. 在目标方法【非正常结束后】,发生异常或者抛出异常时执行
     * 1. 在异常通知中设置异常信息,并将其保存
     *
     * @param throwable
     */
    @AfterThrowing(value = "webLogPointcut()", throwing = "throwable")
    public void doAfterThrowing(Throwable throwable) {
        // 保存异常日志记录
        log.error("发生异常时间:{}", LocalDateTime.now());
        log.error("抛出异常:{}", throwable.getMessage());
    }
}

这是异步请求调用

@CrossOrigin
@RestController
@RequestMapping("/servicebloguser/blog-user")
@EnableAsync
public class BlogUserController {

    @Autowired
    private BlogUserService blogUserService;


    @ApiOperation(value = "用户使用邮箱注册,进行验证,获取验证码")
    @GetMapping("user/get/verification/code/by/email")
    public ResultEntity userGetVerificationCodeByEmail(@RequestParam(value = "email") String email) {
        try {
            blogUserService.userGetVerificationCodeByEmail(email);
            return ResultEntity.success();
        } catch (WTException e) {
            e.printStackTrace();
            return ResultEntity.failure().code(e.getCode()).message(e.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failure();
        }
    }

}
package com.wtblog.service.servicebloguser.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wtblog.exception.WTException;
import com.wtblog.service.servicebloguser.entity.BlogRegistInfoVO;
import com.wtblog.service.servicebloguser.entity.BlogUser;
import com.wtblog.service.servicebloguser.mapper.BlogUserMapper;
import com.wtblog.service.servicebloguser.service.BlogUserService;
import com.wtblog.service.utils.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.regex.Pattern;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author WT-X
 */
@Service
public class BlogUserServiceImpl extends ServiceImpl<BlogUserMapper, BlogUser> implements BlogUserService {

    @Autowired
    private JavaMailSenderImpl javaMailSender;

    

    // 用户使用邮箱注册,进行验证,获取验证码
    @Async
    @Override
    public void userGetVerificationCodeByEmail(String email) {
        // 校验email数据格式
        String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
        if (email == null || email == "" || !Pattern.compile(regEx1).matcher(email).matches()) {
            throw new WTException(20001, "邮件有误,请确认后填写~");
        }
        // 生成验证码
        String emailServiceCode = UUID.randomUUID().toString().replace("-", "").substring(0, 4);
        // 设置发件者信息
        SimpleMailMessage message = new SimpleMailMessage();
        // 主题
        message.setSubject("注册验证码");
        // 邮件内容
        message.setText("注册验证码是:" + emailServiceCode);
        // 发件者邮箱
        message.setFrom("12100000@qq.com");
        // 收件者邮箱
        message.setTo(email);
        try {
            javaMailSender.send(message);
        }catch (Exception e){
            throw new WTException(20001, "邮件发送失败发送~");
        }

    }




}

已经测试过了,在屏蔽掉日志打印那块,程序正常进行。。。而且日志本身打印其他没出过问题。。。来个大佬指导一下!

  • 写回答

7条回答 默认 最新

  • Ryder_code 2021-05-27 07:09
    关注

    异步线程调用RequestContextHolder.getRequestAttributes()的问题引起的

    解决方法:

    1.去掉异步调用 

    2. 启动类添加以下代码

        @Bean
        public RequestContextListener requestContextListener(){
            return new RequestContextListener();
        }

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(6条)

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效