解决SpringMVC拦截器中Request数据只能读取一次的问题

解决SpringMVC拦截器中Request数据只能读取一次的问题



开发项目中,经常会直接在request中取数据,如Json数据,也经常用到@RequestBody注解,也可以直接通过request.getParameter()从Request中取数据。

但是有时候我们要在请求到具体的业务之前做一些操作比如日志记录、数据校验、统一的处理等等,可以在拦截器中处理。

由于 request中getReader()和getInputStream()只能调用一次,我们在拦截器中获取Request中数据后,后面就没法在继续获取数据了,那么可以重写HttpServletRequestWrapper方法来解决。

1. 重写HttpServletRequestWrapper方法:

package com.centit.server.common.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * <p>request包装类<p>
 * @version 1.0
 * @author li_hao
 * @date 2019年3月3日
 */
public class RequestWrapper extends HttpServletRequestWrapper {
    private final String body;
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        body = stringBuilder.toString();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            public boolean isFinished() {
                return false;
            }
            public boolean isReady() {
                return false;
            }
            public void setReadListener(ReadListener readListener) {}
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return servletInputStream;

    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
    public String getBody() {
        return this.body;
    }

}


2. 拦截器

package com.centit.server.common.interceptor;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.centit.server.common.utils.RequestWrapper;

/**
 * <p>拦截器<p>
 * @version 1.0
 * @author li_hao
 * @date 2019年3月3日
 */
public class HandlerInterceptor extends HandlerInterceptorAdapter{

    public static Set<HttpSession> sessions;

    static{
        if(sessions==null){
            sessions = Collections.synchronizedSet(new HashSet<HttpSession>());
        }
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String uri = request.getRequestURI();  //获取请求方法:格式为:/meetingserv_xa/smDept/queryAllSmDeptTreeList
        String contextpath = request.getContextPath();

        System.out.println(uri);
        System.out.println(contextpath);

        String ipAddr = getIpAddr(request);  //获取客户端ip
        System.out.println(ipAddr);

        RequestWrapper myRequestWrapper = new RequestWrapper((HttpServletRequest) request);
        String body = myRequestWrapper.getBody();
        System.out.println(body);  //请求数据

        return super.preHandle(request, response, handler);
    }

    /**
     * 获取客户端请求的当前网络ip
     * @param request
     * @return
     */
    public String getIpAddr(HttpServletRequest request){
        String ipAddress = request.getHeader("x-forwarded-for");
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                    //根据网卡取本机配置的IP
                    InetAddress inet=null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress= inet.getHostAddress();
                }
            }
            //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照‘,‘分割
            if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
                if(ipAddress.indexOf(",")>0){
                    ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
                }
            }
            return ipAddress;
    }
}


3. 配置拦截器(spring-mvc.xml):

<!-- 拦截器 -->
     <mvc:interceptors>
        <bean class="com.centit.server.common.interceptor.HandlerInterceptor" />
    </mvc:interceptors>


4. 过滤器:

package com.centit.server.common.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import com.centit.server.common.utils.RequestWrapper;

/**
 * <p>过滤器<p>
 * @version 1.0
 * @author li_hao
 * @date 2019年3月3日
 */
public class HttpServletFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(request instanceof HttpServletRequest) {
            requestWrapper = new RequestWrapper((HttpServletRequest) request);
        }
        if(requestWrapper == null) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
    public void destroy() {

    }
}


5. 配置过滤器(web.xml):

  <filter>
    <filter-name>requestFilter</filter-name>
    <filter-class>com.centit.server.common.filter.HttpServletFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>requestFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

原文地址:https://www.cnblogs.com/hooly/p/10465925.html

时间: 2024-08-27 20:30:25

解决SpringMVC拦截器中Request数据只能读取一次的问题的相关文章

SpringMVC拦截器中通过反射得到Controller方法注解时ClassCastException解决方案

错误应用场 在Controller中,我们自定义了一个@Auth注解来实现权限控制功能,如: @Auth(verifyLogin=false,verifyURL=false) @RequestMapping("/login") public ModelAndView login(HttpServletRequest request,HttpServletResponse response) throws Exception{ Map<String,Object> conte

解决SpringMVC拦截器拦截静态资源的问题。

在使用SpringMVC进行开发的时候,遇到了以下代码不能执行的情况.而且我已经正确导入了JQuery框架. <script type="text/javascript"> $(function(){ alert("你好啊"); }) </script> 明明记得之前是可以执行的为什么现在却不能了.在浏览器的开发这工具上只能看到 SyntaxError: expected expression, got '<'[详细了解] 这个报错.

解决springmvc拦截器拦截静态资源的两种方式

1.是采用<mvc:default-servlet-handler />,(一般Web应用服务器默认的Servlet名称是"default",所以这里我们激活Tomcat的defaultServlet来处理静态文件 在web.xml中配置 <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/js/*</url-pattern> &

spring boot拦截器中获取request post请求中的参数

最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题. 首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取到参数,post是不行的,后来想到了使用流的方式,调用request.getInputStream()获取流,然后从流中读取参数,如下代码所示: String body = ""; StringBuilder stringBuilder = new StringBuilder(); Buf

Springboot中SpringMvc拦截器配置与应用(实战)

一.什么是拦截器,及其作用 拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略.它通过动态拦截Action调用的对象,允许开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了一种可以提取action中可重用的部分的方式. 拦截器的使用场景越来越多,尤其是面向切片编程流行之后.那通常拦截器可以做什么呢? 之前我们在Agent介绍中,提到过统计函数的调用耗时.这

在JSP中常见问题,防止SpringMVC拦截器拦截js等静态资源文件的解决方案

方案一.拦截器中增加针对静态资源不进行过滤(涉及spring-mvc.xml) <mvc:resources location="/" mapping="/**/*.js"/> <mvc:resources location="/" mapping="/**/*.css"/> <mvc:resources location="/assets/" mapping="/a

SpringMVC拦截器的使用

SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那样子判断当前时间是否是购票时间. 一.springMVC拦截器的实现方式 springMVC拦截器的实现一般有两种方式:第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口.第二种方式是继承实现了HandlerInterceptor接口的类,比

SpringMVC拦截器_1_拦截器的实现

SpringMVC interceptor:下列参考的blog文章 Spring MVC简介 SpringMVC 拦截器实现原理和登录实现 SpringMVC拦截器详解[附带源码分析] 学习SpringMVC--拦截器 ********************* 1-1 拦截器 拦截器是指通过统一拦截从浏览器发往服务器的请求来完成功能的增强. 使用场景:解决请求的共性问题(如:乱码问题,权限验证等) ===2 拦截器的实现========================== ---2-1 拦截器

springmvc拦截器使用和原理理解

与struts2类似,springmvc的拦截器主要作用也是在服务端真正处理请求前后进行一些相关的操作. 例如初始化资源,权限监控,会话设置,菜单获取,资源清理等. 步骤: 1. 定义拦截器 自定义拦截器一般继承自HandlerInterceptorAdapter 或者实现 HandlerInterceptor 接口. 实现接口需要实现对应的3中方法,继承父类只需要实现需要的方法即可.preHandle,postHandle,afterCompletion public class MyInte