Spring拦截器关于获取request body参数问题(request body miss)

我是个java小白,在近期的开发中,有这样一个任务,拦截请求,统一对请求进行token的验证,由于特殊原因,工程全部采用post请求。想到的就是拦截器、Filter、aop。

由于要求尽量使用spring组件,所以排除Filter,由于工程的URL没有统一规范,所以aop也排除,最后使用了拦截器,在使用的过程中会出现Required request body is missing错误,经过查找资料发现是request body中获取参数时使用流获取,但是request的流只能使用一次,给出的办法就是在获取流之前对流进行复制。具体实现见下面代码。

1:首先自定义一个类继承HttpServletRequestWrapper,用来备份流

public class BufferedServletRequestWrapper extends HttpServletRequestWrapper {

	private byte[] buffer;

	public BufferedServletRequestWrapper(HttpServletRequest request) throws IOException {
		super(request);
		InputStream is = request.getInputStream();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte buff[] = new byte[1024];
		int read;
		while ((read = is.read(buff)) > 0) {
			baos.write(buff, 0, read);
		}
		this.buffer = baos.toByteArray();
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		return new BufferedServletInputStream(this.buffer);
	}

	// 对外提供读取流的方法
	@Override
	public BufferedReader getReader() throws IOException {
		return new BufferedReader(new InputStreamReader(getInputStream()));
	}
}

2:在spring配置文件中自定义拦截器组件

<mvc:interceptors>
		<!-- token校验 -->
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="类的全路径">
				<property name="excludeMapping">
					<list>
						<value>/doctorWebLoginAccount/doctorLogin/app</value>
						<value>/doctorWebLoginAccount/doctorLogin/web</value>
						<value>/ws</value>
						<value>/fileUpload/uploadPicture</value>
						<value>/fileUpload/uploadSignature</value>
						<value>/doctor/registe</value>
						<value>/hospitalAndDepartment/findHospital</value>
						<value>/hospitalAndDepartment/findDepartment</value>
						<value>/hospDoctorTreatment/usageSelect</value>
						<value>/chiefComplaint/symptom</value>
						<value>/initialDiagnose/list</value>
						<value>/doctor/patientInfo</value>
						<value>/doctor/updateAccountInfo</value>
						<value>/doctor/getMessageCode</value>
						<value>/doctor/storeBaseInfo</value>
						<value>/doctor/storeBaseGoods/list</value>
						<value>/doctor/checkPhoneNum</value>
						<value>/storeBaseGoods/pageList</value>
					</list>
				</property>
			</bean>
		</mvc:interceptor>
	</mvc:interceptors>

3:定义拦截的实现类

public class ValidateTokenInterceptor implements HandlerInterceptor{
    
    //不拦截的请求
    private String[] excludeMapping;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		//不需要过滤的请求
		for(String exclude : excludeMapping){
			if(request.getRequestURI().endsWith(exclude)){
				return true;
			}
		}
		BufferedServletRequestWrapper requestWrapper = new BufferedServletRequestWrapper(request);
    //在这边替换流,使用工具类GetRequestJsonUtils获取json参数
		JSONObject json = GetRequestJsonUtils.getRequestJsonObject(requestWrapper);
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		logger.info("返回视图之前!");
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		logger.info("请求结束之后!");
	}

	public void setExcludeMapping(String[] excludeMapping) {
		this.excludeMapping = excludeMapping;
	}
	
	
}

4:最后自定义一个Filter(spring请求的链式执行顺序为Filter-->拦截器-->controller)用来备份流

public class TranslateRequestWrapper implements Filter{

	/**
	 * 销毁
	 */
	@Override
	public void destroy() {
		
	}

	/**
	 * 过滤
	 */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		ServletRequest requestWrapepr = null;
		if(request instanceof HttpServletRequest){
			requestWrapepr = new BufferedServletRequestWrapper((HttpServletRequest)request);
		}
		if(requestWrapepr == null){
			chain.doFilter(request, response);
		}else{
			chain.doFilter(requestWrapepr, response);
		}
	}

	/**
	 * 初始化
	 */
	@Override
	public void init(FilterConfig arg0) throws ServletException {
		
	}

}

5:附上从流中读取参数的工具类

public class GetRequestJsonUtils {
	public static JSONObject getRequestJsonObject(HttpServletRequest request) throws IOException {
		String json = getRequestJsonString(request);
		return JSONObject.parseObject(json);
	}
	 /***
     * 获取 request 中 json 字符串的内容
     * 
     * @param request
     * @return : <code>byte[]</code>
     * @throws IOException
     */
    public static String getRequestJsonString(HttpServletRequest request)
            throws IOException {
        String submitMehtod = request.getMethod();
        // GET
        if (submitMehtod.equals("GET")) {
        	if(StringUtils.isNotEmpty(request.getQueryString())){
        		return new String(request.getQueryString().getBytes("iso-8859-1"),"utf-8").replaceAll("%22", "\"");
        	}else{
        		return new String("".getBytes("iso-8859-1"), "utf-8").replaceAll("%22", "\"");
        	}
        // POST
        } else {
            return getRequestPostStr(request);
        }
    }
 
    /**      
     * 描述:获取 post 请求的 byte[] 数组
     * <pre>
     * 举例:
     * </pre>
     * @param request
     * @return
     * @throws IOException      
     */
    public static byte[] getRequestPostBytes(HttpServletRequest request)
            throws IOException {
        int contentLength = request.getContentLength();
        if(contentLength<0){
            return null;
        }
        byte buffer[] = new byte[contentLength];
        for (int i = 0; i < contentLength;) {
 
            int readlen = request.getInputStream().read(buffer, i,
                    contentLength - i);
            if (readlen == -1) {
                break;
            }
            i += readlen;
        }
        return buffer;
    }
 
    /**      
     * 描述:获取 post 请求内容
     * <pre>
     * 举例:
     * </pre>
     * @param request
     * @return
     * @throws IOException      
     */
    public static String getRequestPostStr(HttpServletRequest request)
            throws IOException {
        byte buffer[] = getRequestPostBytes(request);
        String charEncoding = request.getCharacterEncoding();
        if (charEncoding == null) {
            charEncoding = "UTF-8";
        }
        return new String(buffer, charEncoding);
    }
}

这样就不会出现request body si missing

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值