Spring Aspect获取request和response

版权声明:本文来自kid_2412的csdn博客,欢迎转载! https://blog.csdn.net/kid_2412/article/details/52180657

最近在项目中把给客户端的protobuf结构转换成给网页端的json,可以直接使用spring的aspect拦截controller层的方法,然后拿到request和response进行转换。spring我使用的是全注解方式。其实这里有2个坑:

  1. 如何在spring aspect中获取HttpServletRequest和HttpServletResponse。
  2. 获取到request和response后pb转json重新输出出现乱码。会抛出java.io.CharConversionException: Not an ISO 8859-1 character异常。

其实在spring的aspect中很好获取HttpServletRequest和HttpServletResponse,通过spring-web模块下的RequestContextHolder就能获取到。spring-web对servlet的上下文进行了封装,可以看到是通过NamedThreadLocal进行封装的。

这里写图片描述

通过静态方法getRequestAttributes取出。

这里写图片描述

可以通过如下代码获取request:

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

而response可以这样:

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

pb转换json也不复杂,使用google提供的工具类JsonFormat.printToString即可。但是在通过response输出时会遇到剩下的那俩个问题。当输出json有中文时,会出现字符集无法转换的异常,网上给出的解决方案是用从response中获取PrintWriter对象,但是如果使用PrintWriter就会出现接下来的writer已经被调用的问题,产生java.lang.IllegalStateException: getOutputStream() has already been called for this response异常,所以还是转回SerlvetOutPutStream。

最后完整的代码如下:

@Aspect
@Component
public class PB2JsonAspect {
    public static final Logger LOGGER = LogManager.getLogger(PB2JsonAspect.class);
    private static final String RESPONSE_CHARSET = "UTF-8";

    @Pointcut("execution(* fm.jiecao.rest.*.controller.*.*(..))")
    public void PB2JsonAfter() {
    }

    @AfterReturning(pointcut = "PB2JsonAfter()", returning = "returnValue")
    public void afterReturning(Object returnValue) {
        LOGGER.info("PB2JsonAspect afterReturning...");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//获取request
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();//获取response

        if (checkHasFlag(request) && checkReturnValueIsPb(returnValue)) {
            String json = JsonFormat.printToString((Message) returnValue);//转换json
            ServletOutputStream out = null;
            try {
                response.setCharacterEncoding(RESPONSE_CHARSET);
                response.setContentType("text/json;charset=" + RESPONSE_CHARSET);
                out = response.getOutputStream();
                out.write(json.getBytes(RESPONSE_CHARSET));
                LOGGER.debug("pb->json:" + json);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null != out) {
                    try {
                        out.flush();
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private boolean checkReturnValueIsPb(Object returnValue) {
        if (returnValue instanceof Message) {//检查是否是pb
            return true;
        } else {
            return false;
        }
    }

    private boolean checkHasFlag(HttpServletRequest request) {
        if (null == request) return false;
        String contentType = request.getContentType();
        String accept = request.getHeader("Accept");
        //检查accept和content-type
        if (StringUtils.isNotBlank(contentType) && contentType.contains("application/json") || StringUtils.isNotBlank(accept) && accept.contains("application/json") ) {
            return true;
        } else {
            return false;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/kid_2412/article/details/52180657