拦截请求返回值的方法

转载自点击打开链接

在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)相关代码如下:

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也可以,关键在于你。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值