java 如何在Sping Boot 中设计统一的错误处理和日志

ccgok5k5  于 2023-04-04  发布在  Java
关注(0)|答案(1)|浏览(105)

我开发了一个日志系统和错误处理,想记录请求响应日志、业务层日志和错误日志,但是当我加入上传过程时,出现了一个错误,提示我类型转换失败,另外,像这样设计日志和错误处理是正确的吗,比如把请求响应放在拦截器中统一的返回值和错误处理使用controlleradvice
下面是我实现的代码
这是过滤器

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
            ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
            filterChain.doFilter(requestWrapper,responseWrapper);
            responseWrapper.copyBodyToResponse();

    }

这个loginterceptor

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");
        String dateFormat = format.format(date);
        makeLog(dateFormat, request, (ContentCachingResponseWrapper) response);
        return true;
    }

    private void makeLog(String date,HttpServletRequest request,ContentCachingResponseWrapper response) throws IOException {
        String responseData = new String(response.getContentAsByteArray());
        LogInfo logInfo = new LogInfo();
        logInfo.setUri(request.getRequestURI());
        logInfo.setCreateTime(date);
        logInfo.setRequest(request.getInputStream().readAllBytes());
        logInfo.setResponse(responseData);
        logInfo.setClientIP(request.getRemoteAddr());
        log.info("logData:{}",logInfo);
        loggerService.insert(logInfo);
    }

这是exceptioncontroller

public class ExceptionAdvice {
    @ExceptionHandler(DataAccessException.class)
    public ResultVO sqlHandler(DataAccessException  e){
        Throwable cause = e.getCause();
        ResultVO resultVO = new ResultVO();
        if (cause instanceof SQLException sqlException){
            log.error(sqlException.getMessage());
            resultVO.setCode(sqlException.getSQLState());
            resultVO.setMessage(sqlException.getMessage());
        }else {
            resultVO.setMessage(cause.getMessage());
        }
        return resultVO;
    }
    @ExceptionHandler(BusinessException.class)
    public ResultVO businessHandler(BusinessException e){
        log.error(e.getMessage());
        ResultVO resultVO = new ResultVO();
        resultVO.setCode(e.getErrCode().getCode());
        resultVO.setMessage(e.getErrCode().getMsg());
        return resultVO;
    }
    @ExceptionHandler(Exception.class)
    public ResultVO err(Exception e){
        log.error(e.getMessage());
        e.printStackTrace();
        ResultVO resultVO = new ResultVO();
        resultVO.setCode("500");
        resultVO.setMessage(e.getMessage());
        return resultVO;
    }

这是结果

public class ResultAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        //System.out.println("====================================================supports");
        return !returnType.getParameterType().equals(ResultVO.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        System.out.println("====================================================beforeBodyWrite");
        ResultVO resultVO = new ResultVO(body);
        resultVO.setCode("1");
        resultVO.setMessage("success!!");

        return resultVO;
    }

当我在运行时,他的错误是没有预料到的,比如数据库连接失败,他从mybatis报告了一个错误“org. springframework. jdbc. CannotGetJdbcConnectionException:无法获取JDBC连接r n # #错误可能存在于com/kert/compute/dao/LogMapper. java(最佳猜测)”\r\n###错误可能涉及com.kert.compute.dao.LogMapper.insert\r\n###执行更新时出错\r\n###原因:无法获取数据库连接异常:无法获取JDBC连接”,
上传文件时,报告“class org. apache. Catalina . connector. ResponseFacade cannot be cast to class org. springframework. web. util. ContentCachingResponseWrapper(org. apache. catalina. connector. ResponseFacade and org. springframework. web. util. ContentCachingResponseWrapper are in unnamed module of loader 'app')”消息

omhiaaxx

omhiaaxx1#

关于您遇到的错误的第一个问题,该错误似乎是由尝试将ResponseFacade强制转换为ContentCachingResponseWrapper时的类型转换失败引起的。这可能是因为ResponseFacade类与ContentCachingResponseWrapper类不兼容,或者因为ContentCachingResponseWrapper类在拦截器中使用之前未正确示例化。要解决此问题,您可能需要检查您的实现,并确保使用了适当的类并正确地示例化。
至于你的第二个问题,关于你的日志系统和错误处理的设计,你的方法似乎是合理的。将请求响应放置在拦截器中,并在业务层使用AOP进行处理,是日志和错误处理的常见模式。使用控制器通知进行统一的返回值和错误处理也是一个很好的实践。然而确保你的实现是模块化的并且易于维护是很重要的。你也可以考虑使用一个日志框架,比如Log4j或者Logback来简化你的日志实现,并提供更高级的特性。

相关问题