我正在创建一个方面来像org.springframework.web.bind.annotation.RestController这样使用@Pointcut注册我的应用程序,当我的类正常响应时,此方法非常有效,但是当由于某种原因发生异常时,即使我的http响应返回500,返回的httpStatus也始终为200当发生错误时,我认为这是因为RestController不会设置http状态,而是将其委托给异常处理程序,我该如何解决这个问题,并且在restcontroller上仍然具有可追溯性?

跟随我的休息控制器

@Slf4j
@RestController
@RequestMapping("/api/conta")
public class ContaResourceHTTP {


    @JetpackMethod("Pagamento de conta")
    @PostMapping("/pagamento")
    public void realizarPagamento(@RequestBody DTOPagamento dtoPagamento) throws InterruptedException
    {

    }

    @JetpackMethod("Transferência entre bancos")
    @PostMapping("/ted")
    public void realizarTED(@RequestBody DTOPagamento dtoPagamento) throws java.lang.Exception
    {
        if(true)
            throw new Exception("XXX");
        //log.info(dtoPagamento.toString());
    }

}


我的AOP实施:

@Aspect
@Component
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Slf4j
public class MetricsAspect {

    //@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    @Pointcut("execution(* javax.servlet.http.HttpServlet.*(..)) *)")
    public void springBeanPointcut() {
    }

    @Autowired
    Tracer tracer;

    @Around("springBeanPointcut()")
    public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();

        long inicioProcesso = System.currentTimeMillis();

        joinPoint.proceed();

        long finalProcesso = System.currentTimeMillis();

        long duracaoProcesso = finalProcesso - inicioProcesso;

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        Metrics metricas = new Metrics();

        metricas.setDuracaoMs(duracaoProcesso);
        metricas.setDataHoraRequisicao(milissegundosToStringDate(inicioProcesso));
        metricas.setDataHoraResposta(milissegundosToStringDate(finalProcesso));
        metricas.setServidorOrigem(request.getRemoteAddr());
        metricas.setPortaOrigem(request.getRemotePort());
        metricas.setDominioAcesso(request.getLocalName());
        metricas.setPortaAcesso(request.getLocalPort());
        metricas.setUrlPath(request.getRequestURI());
        metricas.setMetodoHttp(request.getMethod());
        metricas.setIdTransacao(tracer.currentSpan().context().traceIdString());
        metricas.setIdSpan(tracer.currentSpan().context().spanIdString());
        metricas.setStatusHttp(response.getStatus());

        log.info(JSONConversor.toJSON(metricas));

    }

    public String milissegundosToStringDate(long ms) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

        Date dataInicial = new Date(ms);

        return dateFormat.format(dataInicial);
    }
}


我的异常处理程序:

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ExceptionControllerAdvice {


    @ExceptionHandler({ Throwable.class })
    public ResponseEntity<ApiError> handlerValidationException2(Throwable e) {
        return new ResponseEntity<>(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, e, traceRespostaAPI),
                HttpStatus.INTERNAL_SERVER_ERROR);
    }


}

最佳答案

一段时间后,我能够使用可能不是最适合该问题的解决方案来解决该问题,基本上,我使用了两个切入点,一个在restcontroller中,用于截获@JetpackMethod批注值,并将其添加到http响应标头中,之前关于HttpServlet的另一种建议,实际上是真正使人获得修改后的http状态的建议。

这是下面的代码,解决了我的问题。

此类截取注释并将其值添加到标头。

@Aspect
@Component
public class InterceptRestAnnotationAspect {

    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void restControllerExecution() {}


    @Before("restControllerExecution()")
    public void setMetodoHttpHeader(JoinPoint joinPoint) throws Throwable {

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        String origem = VerificadorOrigem.processarOrigem(joinPoint);

        response.setHeader("nomeMetodo", origem);

    }

}


另一个类记录了我需要的servlet指标,并且可以检索之前在标头中输入的值。

@Aspect
@Component
@Slf4j
public class MetricsAspect {

    @Pointcut("execution(* javax.servlet.http.HttpServlet.*(..)) *)")
    public void servletService() {
    }

    @Autowired
    Tracer tracer;

    @Around("servletService()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();

        long inicioProcesso = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long finalProcesso = System.currentTimeMillis();

        long duracaoProcesso = finalProcesso - inicioProcesso;

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        Metrics metricas = new Metrics();

        String funcionalidade = response.getHeader("nomeMetodo") == null ? "Indeterminada"
                : response.getHeader("nomeMetodo");

        metricas.setNivelLog("INFO");
        metricas.setFuncionalidade(funcionalidade);
        metricas.setDuracaoMs(duracaoProcesso);
        metricas.setDataHoraRequisicao(ManipulaData.milissegundosToStringDate(inicioProcesso));
        metricas.setDataHoraResposta(ManipulaData.milissegundosToStringDate(finalProcesso));
        metricas.setServidorOrigem(request.getRemoteAddr());
        metricas.setPortaOrigem(request.getRemotePort());
        metricas.setDominioAcesso(request.getLocalName());
        metricas.setPortaAcesso(request.getLocalPort());
        metricas.setUrlPath(request.getRequestURI());
        metricas.setMetodoHttp(request.getMethod());
        metricas.setIdTransacao(tracer.currentSpan().context().traceIdString());
        metricas.setIdSpan(tracer.currentSpan().context().spanIdString());
        metricas.setStatusHttp(response.getStatus());

        log.info(JSONConversor.toJSON(metricas));

        return result;

    }
}

10-08 10:51