拦截请求返回值的方法

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风格文件上传异常处理拦截器

nginx拦截请求修改返回数据

springMVC——拦截器

用程序拦截器拦截请求

另类的打印请求参数返回值的方法

另类的打印请求参数返回值的方法