最近在写日志管理,想着使用拦截器加注解的方式,但是遇到了一个问题,就是如果使用@RequestBody注解接收的参数只能读取一次,造成了我在拦截器中如果接收了参数,在Controller层就接收不到了,为了解决这个问题,在网上查了方法。自定义一个MyRequestWrapper 继承 HttpServletRequestWrapper不多说,看代码:

package cn.huimin100.cms.handler;
 
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
 
/**
* 与HttpServletRequestWrapperFilter配合使用,保证@RequestBody注解的参数可以读取两次
* 因为要在拦截器中获取参数
*/
public class MyRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public MyRequestWrapper(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() {
 
 
@Override
public boolean isFinished() {
return false;
}
 
@Override
public boolean isReady() {
return false;
}
 
@Override
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;
}
}
 
需要结合过滤器使用:
package cn.huimin100.cms.handler;
 
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
 
/**
* 该过滤器与MyRequestWrapper配合使用,可以让@RequestBody注解的参数至少可以读取两次,
* 从而使得在拦截器中可以获取@RequestBody注解的参数。
*/
@WebFilter(filterName="HttpServletRequestWrapperFilter",urlPatterns="/*")
public class HttpServletRequestWrapperFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
 
}
 
@Override
public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper= null;
if(request instanceof HttpServletRequest){
requestWrapper = new MyRequestWrapper((HttpServletRequest) request);
}
if(null == requestWrapper){
filterChain.doFilter(request,servletResponse);
}else{
filterChain.doFilter(requestWrapper,servletResponse);
}
}
 
@Override
public void destroy() {
 
}
}
 
拦截器中这样获取参数
package cn.huimin100.cms.handler;
 
import cn.huimin100.cms.config.LogAnnotation;
import cn.huimin100.cms.mapper.newcms.ActionLogsMapper;
import cn.huimin100.cms.pojo.po.ActionLogs;
import cn.huimin100.cms.util.DateUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
 
/**
* 在读取@RequestBody注解的参数的时候,需要配合MyRequestWrapper使用
* 一遍保证这些参数可以在Controller层再次读取
*/
public class LogManageInterceptor extends HandlerInterceptorAdapter {
private final Logger logger = LoggerFactory.getLogger(LogManageInterceptor.class);
 
@Autowired
private ActionLogsMapper logMapper;
 
public static final String USER_NAME="user__name";
public static final String BRANCH_ID="branch__id";
public static final String USER_ID="user__id";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
if(annotation != null){
try{
ActionLogs log = new ActionLogs();
//操作类型
log.setAction(annotation.action().getCode());
//操作目标方法
log.setCategory(annotation.targetMethod().getCode());
//操作人姓名
log.setActionTime(DateFormatUtils.format(new Date(), DateUtil.DATETIME_DEFAULT_FORMAT));
log.setIsmiddlemode(2);
Map<String, String[]> parameterMap = request.getParameterMap();
if(parameterMap == null || parameterMap.isEmpty()){
MyRequestWrapper myRequestWrapper = new MyRequestWrapper((HttpServletRequest) request);
String body = myRequestWrapper.getBody();
JSONObject jsonObject = JSONObject.parseObject(body);
log.setOperator(jsonObject.getString(USER_NAME));
log.setOperatorId(jsonObject.getInteger(USER_ID));
log.setBranchId(jsonObject.getInteger(BRANCH_ID));
}else{
log.setOperator(request.getParameter(USER_NAME));
log.setOperatorId(Integer.valueOf(request.getParameter(USER_ID)));
log.setBranchId(Integer.valueOf(request.getParameter(BRANCH_ID)));
}
logMapper.insertSelective(log);
}catch (Exception e){
logger.error("记录操作日志错误 e:{}",e);
}
}
}
return true;
}
}

@RequestBody注解的参数仅仅读取一次的问题解决。的更多相关文章

  1. spring中RequestBody注解接收参数时用JSONField转参数名无效问题

    问题: 在springboot项目中使用@RequestBody注解接收post请求中body里的json参数的情况.即: @RequestMapping(value = "/get-use ...

  2. @RequestParam @RequestBody @PathVariable 等参数绑定注解详解

    文章主要讲解request 数据到handler method 参数数据的绑定所用到的注解和什么情形下使用. 简介: handler method 参数绑定常用的注解,我们根据他们处理的Request ...

  3. Spring @RequestParam @RequestBody @PathVariable 等参数绑定注解详解

    背景 昨天一个人瞎倒腾spring boot,然后遇到了一点问题,所以把这个问题总结一下. 主要讲解request 数据到handler method 参数数据的绑定,所用到的注解和什么情形下使用. ...

  4. 11.@RequestParam @RequestBody @PathVariable 等参数绑定注解详解

    对@RequestMapping进行地址映射讲解之后,该篇主要讲解request 数据到handler method 参数数据的绑定所用到的注解和什么情形下使用: 简介: handler method ...

  5. @RequestParam @RequestBody @PathVariable 等参数绑定注解详解(转)

    引言: 接上一篇文章,对@RequestMapping进行地址映射讲解之后,该篇主要讲解request 数据到handler method 参数数据的绑定所用到的注解和什么情形下使用: 简介: han ...

  6. (转)@RequestParam @RequestBody @PathVariable 等参数绑定注解详解

    引言: 接上一篇文章,对@RequestMapping进行地址映射讲解之后,该篇主要讲解request 数据到handler method 参数数据的绑定所用到的注解和什么情形下使用: 简介: han ...

  7. 【转】@RequestParam @RequestBody @PathVariable 等参数绑定注解详解

    @RequestParam @RequestBody @PathVariable 等参数绑定注解详解 2014-06-02 11:24 23683人阅读 评论(2) 收藏 举报 目录(?)[+] 引言 ...

  8. springmvc @RequestParam @RequestBody @PathVariable 等参数绑定注解详解

    简介: handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型) A.处理requet uri 部分(这里指uri templat ...

  9. 转载:@RequestParam @RequestBody @PathVariable 等参数绑定注解详解

    转载自:https://blog.csdn.net/walkerjong/article/details/7946109#commentBox   因为写的很好很全,所以转载过来 引言:接上一篇文章, ...

随机推荐

  1. [Day6]引用数据类型、ArrayList 集合

    1.类的定义与使用 (1)类的定义格式 创建java文件,与类名相同 public class 类名{ 数据类型  属性名称1: 数据类型  属性名称2: … } (2)使用格式 导包:我们将所有的类 ...

  2. Memcache&Redis

    Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.减少数据库读取次数来提高网站速度 先在一台机器安装memcache 然后使用Python 安装pip3 i ...

  3. ios dispatch_async使用

    一般这样使用: dispatch_async(dispatch_get_global_queue(0, 0),^{ //进入另一个线程 dispatch_async(dispatch_get_main ...

  4. 【JVM】-NO.115.JVM.1 -【JDK11 HashMap详解-4-伸展树、B树】

    .Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  5. cookie session 讲解

    cookie: cookie的定义: cookie 是由web服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息,并且在每次请求时会携带保存的数据去访问服务器,所以cookie有 ...

  6. 用mpvue构建微信小程序

    背景 由于机器人协会进行鼓励大家多读书的活动,所以为了可以更好的.更有效果,所以我跟会长提了一个建议,做一个微信小程序,那么为什么是微信小程序呢? 1.现在微信小程序比较好,用户也比较多:利用微信小程 ...

  7. nrm 使用

    全局安装 npm i nrm -g   全局安装nrm nrm ls  查看镜像地址: npm ---- https://registry.npmjs.org/ cnpm --- http://r.c ...

  8. ECMAScript6 入门教程 初学记录let命令 块级作用域

    一.基本语法-let命令 (1)ES6新增了let命令,用来声明变量.所声明的变量,只在let命令所在的代码块内有效. 循环的计数器,就很合适使用let命令.计数器i只在for循环体内有效,在循环体外 ...

  9. timer控件、三级联动、帐号激活权限设置

    一.Timer控件 Timer实际就是一个线程控件. 属性:Enabled    是否被启用 Interval     多长时间执行一次控件中的代码 事件: Tick     事件中放要执行的代码. ...

  10. 20175208 《Java程序设计》第四周学习总结

    第五章主要学习内容 1.子类的继承性: (1)子类与父类在同一包中的继承性:子类自然地继承了其父类中不是private的成员变量作为自己的成员变量. (2)子类与父类不在同一包中的继承性:子类只继承父 ...