spring 框架下,如何通过拦截器和过滤器读取request里的内容

当我们用spring 拦截器实现权限校验的时候,往往我们需要从request中获取一些数据进行校验,但是当我们在拦截器获取到数据,getinputStream,那么在后续的action即:controller中我们获取不到request,这是为什么呢?因为java.util.Map所包装的HttpServletRequest对象的参数是不可改变的。 这句话的意思就是我们通过request.getInputStream.那么request就没有啦。那么我们后续的操作也就拿不到request啦。这就影响我们后续的操作。那么既然我们知道问题所在,我们只需要把request拿出来,复制一份,保存,当我们拦截器完成工作以后,我们将我们保存的request输入进去,就可以进行后续的操作。如果我们想要塞进去,那么我们就要实现一个过滤器,拦截器,还有HttpServletRequestWrapper包装器。拦截器与过滤器的区别:拦截器是基于java的反射机制的,而过滤器是基于函数回调。拦截器不依赖与servlet容器,过滤器依赖与servlet容器。拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。执行顺序:过滤前 – 拦截前 – Action处理 – 拦截后 – 过滤后。个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程(还没想到要做啥),再向上返回到过滤器的后续操作。

那么我们开始实现吧:

  1. 实现自己的HttpServletRequestWrapper 类,将request保存到wrapper的body字段中。
    
    	private final static Logger log = LoggerFactory.getLogger(RequestToJson.class);
    	private final byte[] body;
    
    	public RequestToJson(HttpServletRequest request) throws IOException {
    		super(request);
    		String sessionStream = getBodyString(request);
    		log.info("RequestToJson body:"+sessionStream);
    		body = sessionStream.getBytes(Charset.forName("UTF-8"));
    	}
    
    	
    	@Override
    	public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
            ServletInputStream servletInputStream = new ServletInputStream() {
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
    
    			@Override
    			public boolean isFinished() {
    				// TODO Auto-generated method stub
    				return false;
    			}
    
    			@Override
    			public boolean isReady() {
    				// TODO Auto-generated method stub
    				return false;
    			}
    
    			@Override
    			public void setReadListener(ReadListener listener) {
    				// TODO Auto-generated method stub
    				
    			}
            };
            return servletInputStream;
        }
    //返回自己的inputStream
    	@Override
    	public BufferedReader getReader() throws IOException {
    		return new BufferedReader(new InputStreamReader(this.getInputStream()));
    	}
    
    	/**
    	 * 复制input输入流
    	 * 
    	 * @param inputStream
    	 * @return
    	 * @throws IOException
    	 */
    	public InputStream cloneInputStream(ServletInputStream inputStream) throws IOException {
    		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    		byte[] buffer = new byte[1024];
    		int len = 0;
    		try {
    			while ((len = inputStream.read(buffer)) > -1) {
    				byteArrayOutputStream.write(buffer, 0, len);
    			}
    			byteArrayOutputStream.flush();
    		} catch (IOException e) {
    			log.info("clone servletInputStream failed", e);
    			throw e;
    		}
    		InputStream byInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    		return byInputStream;
    	}
    //获取request中的getInputStream,返回String字段
    	public String getBodyString(final ServletRequest request) {
    		StringBuilder sb = new StringBuilder();
    		InputStream inputStream = null;
    		BufferedReader reader = null;
    		try {
    			inputStream = cloneInputStream(request.getInputStream());
    			reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
    			String line = "";
    			while ((line = reader.readLine()) != null) {
    				sb.append(line);
    			}
    		} catch (IOException e) {
    			log.info("get request body code error:", e);
    		} finally {
    			if (inputStream != null) {
    				try {
    					inputStream.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			if (reader != null) {
    				try {
    					reader.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    		return sb.toString();
    	}
    

     

  2. 实现Filter接口,拦截器:过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符 
  3. @Component
    @WebFilter(filterName = "NowidUserFilter", urlPatterns = "/user/*")
    public class NowidUserFilter implements Filter {
    	private final static Logger log = LoggerFactory.getLogger(NowidUserFilter.class);
    
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    		// TODO Auto-generated method stub
    
    	}
    
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    			throws IOException, ServletException {
    		log.info("execute NowidUserFilter 。。。。");
    		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            //保存到自我实现的包装器,body是不可改变
    		ServletRequest requestWrapper = new RequestToJson(httpServletRequest);
    		chain.doFilter(requestWrapper, response); 
    
    	}
    
    	@Override
    	public void destroy() {
    		// TODO Auto-generated method stub
    
    	}
    
    }
    

      实现拦截器,然后调用包装类中的方法返回字符串,就可以自我操作啦。我的实现是json,用的是阿里巴巴的fastjson

    @Component
    public class NowIdUserStatusInterceptor implements HandlerInterceptor {
    	private static Logger logger = LoggerFactory.getLogger(NowIdUserStatusInterceptor.class);
    	@Autowired
    	private RedisTemplate<String, String> redisTemplate;
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		logger.info("NowIdUserStatusInterceptor>>>>preHandle");
    		String ip = Tool.getRemoteIp(request);
    		RequestToJson reqJson = new RequestToJson(request);
    		JSONObject jsonObject = JSONObject.parseObject(reqJson.getBodyString(request));
    		String phone = jsonObject.getString("phone");
    		String userId = jsonObject.getString("userid");
    		String redisuserid = redisTemplate.opsForValue().get("user"+ip+userId);
    		String redisphone = redisTemplate.opsForValue().get("user" + ip + phone);
    		logger.info("login user is :"+redisuserid +" |"+redisphone);
    		if (redisuserid == null && redisphone == null) {
    			// 获取项目路径+登录路径
    			response.sendRedirect(request.getContextPath() + "/admin/login");
    			return false;
    		} else {
    //			logger.info("拦截器校验通过" +request);
    			return true;
    		}
    	}
    
    	@Override
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    			ModelAndView modelAndView) throws Exception {
    		// TODO Auto-generated method stub
    		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    	}
    
    	@Override
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    			throws Exception {
    		// TODO Auto-generated method stub
    		HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    	}
    

    这样就可以顺利的执行啦,在一开始的时候我没有实现过滤器,所以还是获取不到,所以这三个都是必须实现的

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值