springboot-拦截器-过滤器-Required request body is missing 异常
2017-11-21 16:49
2466 查看
SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
众所周知所有的post请求中的body参数是已流形式存在的,而流数据只能读取一次(为啥看这里),如果在拦截器中需要对post参数进行处理的话,就会报Required request body is missing 异常。既然知道原因,那只要能将流保存起来就可以解决问题。怎样让参数流能多次读取? 我在网上找到的方案是使用HttpServletRequestWrapper包装HttpServletRequest。
首先自定义一个requestWrapper类继承HttpServletRequestWrapperpublic class KoalaHttpRequestWrapper extends HttpServletRequestWrapper{
private final Logger log=Logger.getLogger(KoalaHttpRequestWrapper.class);
private byte[] requestBody=null;//用于将流保存下来
public KoalaHttpRequestWrapper(HttpServletRequest request) {
super(request);
try {
requestBody=StreamUtils.copyToByteArray(request.getInputStream());
} catch (IOException e) {
log.error("Wrap requestBody failed");
}
}
@Override
public ServletInputStream getInputStream() throws IOException{
if(requestBody==null) {
requestBody=new byte[0];
}
final ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public void setReadListener(ReadListener listener) {
// do nothing
}
@Override
public boolean isReady() {
return false;
}
@Override
public boolean isFinished() {
return false;
}
};
}
@Override//对外提供读取流的方法
public BufferedReader getReader() throws IOException{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}
然后在拦截器的的preHandle中用KoalaHttpRequestWrapper替代HttpServletRequest
public class FixParamHandleInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Ex 4000 ception { // do nothing } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse response, Object arg2, ModelAndView arg3) throws Exception { // do nothing } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception { KoalaHttpRequestWrapper requestWrapper=new KoalaHttpRequestWrapper(request); boolean flag = true; PrintUtil.print(">>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)"); String servletPath = requestWrapper.getServletPath(); PrintUtil.printErr("请求路径是: " + servletPath); HandlerMethod hm = (HandlerMethod) arg2;//将其强转过来 Method method = hm.getMethod(); InterceptNote annotation = method.getAnnotation(InterceptNote.class); PrintUtil.printErr("是不是空**************: " + annotation); if(annotation==null){//表示需要被拦截的url flag = judgeUserId(requestWrapper); }else{ flag = true; } if(!flag){ throw new ServiceException("帐号异常",CustomResultCode.ACCOUNT_EXE); } return flag; } /** * 拦截处理 * * @Description:TODO * @param request * @param response * @param handler * @return boolean * @exception: * @author: 徐正顺 * @time:2017年11月03日上午10:36:16 *//* @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { PrintUtil.print(">>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
//在这里替换 KoalaHttpRequestWrapper requestWrapper=new KoalaHttpRequestWrapper(request); boolean flag = true; String servletPath = request.getServletPath(); PrintUtil.printErr("请求路径是: " + servletPath); HandlerMethod hm = (HandlerMethod) handler;//将其强转过来 Method method = hm.getMethod(); InterceptNote annotation = method.getAnnotation(InterceptNote.class); PrintUtil.printErr("是不是空**************: " + annotation); if(servletPath.contains("swagger")||servletPath.contains("v2/api")){ return true;//放行swagger } if(annotation==null){//表示需要被拦截的url flag = judgeUserId(requestWrapper); }else{ flag = true; } if(!flag){ throw new ServiceException("帐号异常",CustomResultCode.ACCOUNT_EXE); } if (IGNORE_URI != null) { if(IGNORE_URI.contains(servletPath)){ PrintUtil.printErr("放行了了: " + servletPath); flag = true; } else{ if(servletPath.contains("swagger")||servletPath.contains("v2/api")){ flag=true;//放行swagger }else{ flag = judgeUserId(request); } PrintUtil.printErr(flag+" 拦截了: " + servletPath); } } // 需要拦截处理的请求 return flag; } *//** * 请求处理之后进行调用,但是在视图被渲染之前 拦截处理 * * @Description:TODO * @param request * @param response * @param handler * @return boolean * @exception: * @author: 徐正顺 * @time:2017年11月03日上午10:36:16 *//* @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //System.out.println(">>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)"); } *//** * 在整个请求结束之后被调用 拦截处理 * * @Description:TODO * @param request * @param response * @param handler * @return boolean * @exception: * @author: 徐正顺 * @time:2017年11月03日上午10:36:16 *//* @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //System.out.println(">>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)"); }*/ /** * 判断请求中的userId是否与jwt中的userId一致 * @Description:TODO * @param request * @return * boolean * @exception: * @author: 徐正顺 * @time:2017年11月7日 上午10:19:07 */ private boolean judgeUserId(KoalaHttpRequestWrapper request){ String jwtUserId = JwtUtil.getJwtUserId(request); String userId = JwtUtil.getUserId(request); PrintUtil.printErr("*****************************************"); PrintUtil.print("jwtUserId=="+jwtUserId+" "+"userId=="+userId); PrintUtil.printErr("*****************************************"); if(jwtUserId==null||userId==null){ return false; } return jwtUserId.equals(userId)?true:false; } }
然后就是流数据的读取了public static String getUserId(KoalaHttpRequestWrapper request) {
String method = request.getMethod();
String servletPath = request.getServletPath();
PrintUtil.printErr("请求路径是: " + servletPath);
String userId = null;
if ("GET".equals(method)) {// get请求获取参数方式
userId = request.getParameter("userId");
} else if ("POST".equals(method)) {// post请求获取参数方式
BufferedReader br;
StringBuilder bodyStr = new StringBuilder();
try {
br = request.getReader();
String str;
while ((str = br.readLine()) != null) {
bodyStr.append(str);
}
} catch (IOException e) {
throw new ServiceException("帐号异常", CustomResultCode.ACCOUNT_EXE);
}
String query1 = request.getQueryString();
String query = bodyStr.toString();
Map<String, Object> map = new HashMap<String, Object>();
try {
map = JSON.parseObject(query, Map.class);
userId = map.get("userId").toString();
} catch (Exception e) {
throw new ServiceException("帐号异常", CustomResultCode.ACCOUNT_EXE);
}
} else {// 其它请求逻辑
userId = null;
}
return userId;
} 然后需要自定义过滤器
* @description 签名拦截器
* @author 27834
* @date 2017-11-13
*/
@Order(1)
@WebFilter(filterName="koalaSignFilter",urlPatterns="/*")
public class KoalaSignFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// do nothing
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ServletRequest requestWrapper=null;
if(request instanceof HttpServletRequest) {
requestWrapper=new KoalaHttpRequestWrapper((HttpServletRequest)request);
}
if(requestWrapper==null) {
chain.doFilter(request, response);
}else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
// do nothing
}
}
可能项目启动时不会自动加载这个filter,最好在启动类中配置一个bean
/**
* 让项目启动时能自动扫描到koalaSignFilter
* @Description:TODO
* @return
* FilterRegistrationBean
* @exception:
* @author: 徐正顺
* @time:2017年11月21日 下午3:03:28
*/
@Bean
public FilterRegistrationBean Filters() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new KoalaSignFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("koalaSignFilter");
return registrationBean;
}
然后就ok了
相关文章推荐
- springmvc Required request body content is missing异常
- org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing
- Required request body is missing 错误解决
- Required request body is missing
- Required request body is missing 错误解决
- javas Required request body is missing
- SpringMVC在使用JSON时出现错误:charset=UTF-8' not supported和Required request body is missing
- 关于springboot过滤器处理request参数问题
- SpringMVC异常:org.springframework.web.multipart.MultipartException: The current request is not a multi
- Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证
- Spring Boot (教程八: 过滤器、监听器、拦截器)
- springboot配置监听器、过滤器和拦截器
- when you start Windows 7: "The Windows Boot Configuration Data file is missing required information"
- Spring Boot实战:拦截器与过滤器
- [置顶] 一步一步学springboot (六)集成拦截器和过滤器及监听器
- Spring Boot中使用Feign调用时Hystrix提示异常:"could not be queued for execution and no fallback available."以及"Rejected command because thread-pool queueSize is at rejection threshold"
- The web.config file for this project is missing the required DirectRequestModule.
- spring boot实现过滤器和拦截器demo
- SpringBoot 中 @RequestBody的正确使用方法
- spring中出现dataSource is required异常