spring boot – getReader() has already been called for this request

最近有这样一个想法,当程序出错时,将请求体上传到 sentry,至于 sentry 的集成,可以参考我以前写的博客: 自建 sentry 并与 spring boot 集成
,sentry 是一个开源的崩溃跟踪平台吧,类似Android开发中常用的 bugly 等。但是,我遇到了: java.lang.IllegalStateException: getReader() has already been called for this request
这样的错误。这个错误的原因是:ServletRequest 里的 getReader 和 getInputStream 两个方法只能被调用一次,且是二选一,不是每个都可调用一次,是两个加起来只能调用一次,对此,网上有太多的解决方案。而我今天要提出的方案,却并不是重写某些方法等,而是使用 aop,没错,就是切面编程啦。请看如下代码

@Aspect
@Component
public class ServiceAspect {
    public static final String POINT = "execution(public * top.kpromise..mapper..*.*(..))";

    @Around(POINT)
    public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            rollBack(joinPoint);
            throw new KpException(getArgs(joinPoint, joinPoint.getArgs()).toString(), e);
        }
        return result;
    }

    private void rollBack(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Annotation[] annotations = signature.getMethod().getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof Transactional) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                break;
            }
        }
    }

    private StringBuilder getArgs(ProceedingJoinPoint joinPoint, Object[] args) {
        if (args.length <= 0) return new StringBuilder();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        StringBuilder stringBuilder = new StringBuilder();
        String[] names = signature.getParameterNames();
        int length = args.length;
        ObjectMapper mapper = new ObjectMapper();
        for (int i = 0; i < length; i++) {
            if (i > 0) {
                stringBuilder.append(",");
            }
            Object arg = args[i];
            if (arg == null) continue;
            try {
                String value = mapper.writeValueAsString(arg);
                stringBuilder.append(names[i]).append("=").append(value);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return stringBuilder;
    }
}

这里,使用了 Around 方法,然后又用到了 try catch,使用 try catch 后会导致 controller 里的 事物不回滚,此处,我进行了手动回滚。最后,getArgs 这个方法演示了我如何获取到入参。

你也可以不用再抛异常,直接调用 sentry 的方法进行上传,当然了,如果你喜欢,你也可以抛出异常,丢给 有 @RestControllerAdvice 注解的崩溃处理类来处理。

原文 

https://www.kpromise.top/get-reader-has-already-been-called-for-this-request/

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » spring boot – getReader() has already been called for this request

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址