拦截请求返回值的方法
Posted tangtong1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拦截请求返回值的方法相关的知识,希望对你有一定的参考价值。
在web应用开发时,我们经常会需要拦截请求,在请求前后做一些事,比如打印日志等,这种方式就相当于spring中的面向切面编程,以下总结了下实现这种方式的一些方法。
###1. 使用拦截器+过滤器
这种方法是目前比较通用的方法,不受限于框架限制,不管是用SSH还是springmvc都可以采用,实现方式大致如下:
(1)定义一个拦截器,比如WebRequestInterceptor,在preHandle里面拦截request,从中取出参数等信息,然后打印出来即可。
(2)定义一个过滤器,比如WebResponseFilter,在doFilter里面使用HttpServletResponseWrapper包装传进来的response,然后重写一些方法即可实现。
(注意:这里有个坑,就是直接使用拦截器无法从response里面取出返回值!)
(3)相关代码大致如下:
WebInterceptor.java
package com.zuolin.interceptor;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.zuolin.filter.WrapperResponse;
public class WebInterceptor implements HandlerInterceptor
private static final Logger logger = LoggerFactory.getLogger(WebInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception
if (logger.isDebugEnabled())
StringBuffer sb = new StringBuffer();
sb.append("");
Enumeration<String> headers = request.getHeaderNames();
int i = 0;
while (headers.hasMoreElements())
String header = headers.nextElement();
if (i > 0)
sb.append(", ");
sb.append(header + ": " + request.getHeader(header));
i++;
sb.append("");
logger.debug("Pre handling request: , headers: ", getRequestInfo(request, true), sb.toString());
return true;
private static String getRequestInfo(HttpServletRequest request, boolean requestDetails)
StringBuffer sb = new StringBuffer();
sb.append(request.getMethod()).append(" ");
sb.append(request.getRequestURI());
if (requestDetails)
Enumeration<String> e = request.getParameterNames();
sb.append("");
int i = 0;
while (e.hasMoreElements())
String name = e.nextElement();
String val = request.getParameter(name);
if (val != null && !val.isEmpty())
if (i > 0)
sb.append(", ");
sb.append(name).append(": ").append(val);
i++;
sb.append("");
return sb.toString();
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object,
ModelAndView modelAndView) throws Exception
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object,
Exception exception) throws Exception
String requestInfo = getRequestInfo(request, false);
if (logger.isDebugEnabled())
logger.debug("Complete request: ", requestInfo);
WrapperOutputStream.java
package com.zuolin.filter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
public class WrapperOutputStream extends ServletOutputStream
private ByteArrayOutputStream bos;
public WrapperOutputStream(ByteArrayOutputStream bos)
this.bos = bos;
@Override
public void write(int b) throws IOException
bos.write(b);
WrapperResponse.java
package com.zuolin.filter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class WrapperResponse extends HttpServletResponseWrapper
private ByteArrayOutputStream buffer;
private ServletOutputStream out;
public WrapperResponse(HttpServletResponse response) throws UnsupportedEncodingException
super(response);
buffer = new ByteArrayOutputStream();
out = new WrapperOutputStream(buffer);
@Override
public ServletOutputStream getOutputStream() throws IOException
return out;
@Override
public void flushBuffer() throws IOException
if (out != null)
out.flush();
public byte[] getContent() throws IOException
flushBuffer();
return buffer.toByteArray();
ResponseFilter.java
package com.zuolin.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ResponseFilter implements Filter
private static final Logger logger = LoggerFactory.getLogger(ResponseFilter.class);
@Override
public void destroy()
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException
WrapperResponse wrapperResponse = new WrapperResponse((HttpServletResponse) response);
filterChain.doFilter(request, wrapperResponse);
byte[] content = wrapperResponse.getContent();
if (logger.isDebugEnabled() && content != null && content.length > 0)
logger.debug("Response Content: ", new String(content));
ServletOutputStream out = response.getOutputStream();
out.write(content);
out.flush();
@Override
public void init(FilterConfig paramFilterConfig) throws ServletException
然后记得在web.xml或spring的配置文件中加上以上类的定义就可以直接使用了。
这种方式有个缺陷,就是要写很多代码,而且一般人看不懂这里的流程,因为使用的是流。
###2. 使用spring中的advice
这种就是spring里面的面向切面编程的使用了,这种方式只能依赖于spring的aspect存在,实现方法为:
(1)声明一个类,比如叫WebRequestAroundAdvice;
(2)定义切入点;
(3)定义切入点的处理方法。
(4)相关代码如下:
WebRequestAroundAdvice.java
package com.zuolin.interceptor;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSONObject;
@Aspect
public class WebRequestAroundAdvice
private static final Logger logger = LoggerFactory.getLogger(WebRequestAroundAdvice.class);
@Pointcut( value = "execution(* com.zuolin.controller.*.*(..))" )
public void pointcut()
@Around("pointcut()")
public Object handle(ProceedingJoinPoint joinPoint) throws Throwable
preHandle();
Object retVal = joinPoint.proceed();
postHandle(retVal);
return retVal;
private void preHandle()
if (logger.isDebugEnabled())
HttpServletRequest request = ( (ServletRequestAttributes) RequestContextHolder.getRequestAttributes() ).getRequest();
StringBuffer sb = new StringBuffer();
sb.append("");
Enumeration<String> headers = request.getHeaderNames();
int i = 0;
while (headers.hasMoreElements())
String header = headers.nextElement();
if (i > 0)
sb.append(", ");
sb.append(header + ": " + request.getHeader(header));
i++;
sb.append("");
logger.debug("Pre handling request: , headers: ", getRequestInfo(request, true), sb.toString());
private void postHandle(Object retVal)
if (logger.isDebugEnabled())
HttpServletRequest request = ( (ServletRequestAttributes) RequestContextHolder.getRequestAttributes() ).getRequest();
logger.debug("Post handling request: , response: ", getRequestInfo(request, false), JSONObject.toJSONString(retVal));
private String getRequestInfo(HttpServletRequest request, boolean requestDetails)
StringBuffer sb = new StringBuffer();
sb.append(request.getMethod()).append(" ");
sb.append(request.getRequestURI());
if (requestDetails)
Enumeration<String> e = request.getParameterNames();
sb.append(" ").append("");
int i = 0;
while (e.hasMoreElements())
String name = e.nextElement();
String val = request.getParameter(name);
if (val != null && !val.isEmpty())
if (i > 0)
sb.append(", ");
sb.append(name).append(": ").append(val);
i++;
sb.append("");
return sb.toString();
然后在spring的配置文件中配置这个bean就可以直接使用了。
这种方式的优点就是代码很简洁,只要稍微学过一点AOP都能很容易理解,缺点就是依赖于spring。
这里只使用了spring的around advice,当然,使用其它的几种advice的组合也可以实现相同的效果,或者混合使用拦截器和advice也可以,关键在于你。
欢迎关注我的公众号“彤哥读源码”,查看更多“源码&架构&算法”系列文章, 与彤哥一起畅游源码的海洋。
以上是关于拦截请求返回值的方法的主要内容,如果未能解决你的问题,请参考以下文章
Springday05 SpringMVC访问静态资源操作请求域控制器方法返回值JSON数据交互RESTful风格文件上传异常处理拦截器