AOP日志组件 多次获取post参数

  • 需求:新增接口日志组件。通过拦截器对接口URL进行拦截处理,然后将接口post请求的参数与结果,写入日志表。
  • 问题:POST方法的参数是存储在request.getInputStream中,只能读一次,不能多次读取。从中读取post请求参数,只能读取一次。在filter中获取之后,controller无法获取post请求参数。
  • 解决办法:继承HttpServletRequest,先获取到请求参数,再加参数重新set到inputStream。

1.拦截器记录日志

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
String requestPath = httpRequest.getServletPath().split("\\?")[0]; if(request == null){
chain.doFilter(request, response);
return ;
}
for (String noFilter : NO_FILETER_LIST) {
if(requestPath.toLowerCase().contains(noFilter)){
chain.doFilter(request, response);
return ;
}
} Pattern pattern = Pattern.compile(".*[api|interface].*");
Matcher matcher = pattern.matcher(requestPath);
if(matcher.matches()){
LoggerManager loggerManager = SpringLoadListener.getBean("loggerManager",LoggerManager.class);
//扩展request,防止字符注入等
XssSqlHttpServletRequestWrapper xssRequest = new XssSqlHttpServletRequestWrapper((HttpServletRequest)request);
ResponseWrapper wrapResponse = new ResponseWrapper((HttpServletResponse)response);
//继续请求处理类
chain.doFilter(xssRequest, wrapResponse);
//获取URL的参数 get请求
Map<Object, Object> urlParam = xssRequest.getParameterMap();
//获取post参数
String param = xssRequest.getRequestParams();
JSONObject jObject = JSONObject.fromObject(urlParam);
jObject.put("postParam", param.toString());
String params = jObject.toString();
//获取接口处理类返回结果
byte[] data = wrapResponse.getResponseData();
String result = new String(data,"UTF-8");
//保存日志
loggerManager.operateInterfaceLogger("", params, requestPath, result);
ServletOutputStream out = response.getOutputStream();
out.write(data);
out.flush();
}else{
chain.doFilter(request, response);
} }

2.处理request请求,先获取inputStream,将请求参数复制给其他方法,同时再将获取的inputStream赋值回request中。

public class XssSqlHttpServletRequestWrapper extends HttpServletRequestWrapper
{
HttpServletRequest orgRequest = null;
private byte[] bytes;
private WrappedServletInputStream wrappedServletInputStream; public XssSqlHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.orgRequest = request;
//读取输入流的请求参数,保存到bytes中
bytes = IOUtils.toByteArray(request.getInputStream());
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream); //把post参数重新写入请求流
reWriteInputStream();
} /**
* 把参数重新写进请求里
*/
public void reWriteInputStream() {
wrappedServletInputStream.setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0]));
} @Override
public ServletInputStream getInputStream() throws IOException {
return wrappedServletInputStream;
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(wrappedServletInputStream));
} /**
* 获取post参数
*/
public String getRequestParams() throws IOException {
return new String(bytes, this.getCharacterEncoding());
} //清洗参数,防止xss注入
public String[] getParameterValues(String parameter)
{
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = xssEncode(values[i]);
}
return encodedValues;
} public String getParameter(String name)
{
String value = super.getParameter(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
} public String getHeader(String name)
{
String value = super.getHeader(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
} private static String xssEncode(String s)
{
return StringUtil.xssEncode(s);
} public HttpServletRequest getOrgRequest()
{
return this.orgRequest;
} public static HttpServletRequest getOrgRequest(HttpServletRequest req)
{
if ((req instanceof XssSqlHttpServletRequestWrapper)) {
return ((XssSqlHttpServletRequestWrapper)req).getOrgRequest();
} return req;
} private class WrappedServletInputStream extends ServletInputStream {
public void setStream(InputStream stream) {
this.stream = stream;
}
private InputStream stream;
public WrappedServletInputStream(InputStream stream) {
this.stream = stream;
}
public int read() throws IOException {
return stream.read();
} public boolean isFinished() {
return true;
} public boolean isReady() {
return true;
} public void setReadListener(ReadListener readListener) { }
} }

3.Manager保存日志记录。对LoggerAnnotation自定义注解,实现AOP日志保存。

@LoggerAnnotation(type="INTERFACE", name="#name", params="#params", desc="#pageLink")
public String operateInterfaceLogger(String name, String params, String pageLink, String result)
{
return result; } @Component
@Aspect
@Async
public class LoggerOperationAop
{
private static final Logger logger = LoggerFactory.getLogger(LoggerOperationAop.class);
@Autowired
private LoggerManager loggerManager;
@Autowired
private UserManager userManager;
@Autowired
private JdbcTemplateImpl jdbcTemplate; public LoggerOperationAop() {} @Pointcut("@annotation(LoggerAnnotation)")
private void serviceAspect(LoggerAnnotation LoggerAnnotation) {} @Around("serviceAspect(LoggerAnnotation)")
public Object process(ProceedingJoinPoint point, LoggerAnnotation LoggerAnnotation)
throws Throwable
{
String targetName = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
Object[] arguments = point.getArgs(); String operationType = LoggerAnnotation.type();
String message = LoggerAnnotation.desc();
String params = LoggerAnnotation.params();
String name = LoggerAnnotation.name();
String id = LoggerAnnotation.id();
String[] paramNames = ReflectParamNames.getNames(targetName, methodName);
if ((StringUtil.isNotBlank(name)) && (name.startsWith("#"))) {
String value = SpelParser.getKey(name, "", paramNames, arguments);
if (StringUtil.isNotBlank(value)) {
targetName = value;
}
}
String methodParams = "";
if ((StringUtil.isNotBlank(params)) && (params.startsWith("#"))) {
methodParams = SpelParser.getKey(params, "", paramNames, arguments);
}
if ((StringUtil.isNotBlank(message)) && (message.startsWith("#"))) {
String value = SpelParser.getKey(message, "", paramNames, arguments);
if (StringUtil.isNotBlank(value)) {
message = value;
}
} String userId = null;
String userName = "游客";
try {
Subject currentSubject = SecurityUtils.getSubject();
if (currentSubject != null) {
Object tmpObj = currentSubject.getSession().getAttribute("authorizeUser");
if ((tmpObj != null) && ("INTERFACE".equals(operationType))) {
userName = StringUtil.parseAny2String(tmpObj);
} else if (currentSubject.getPrincipal() != null) {
ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser)currentSubject.getPrincipal();
userId = shiroUser.getUserId();
userName = shiroUser.getLoginName();
}
}
} catch (Exception e) {
logger.info("不支持shiro技术框架");
logger.error("异常信息:{}", e.getMessage());
} Object target = point.proceed();
try
{
String extName = DateUtil.getYearMonth(new Date());
String sql = " INSERT INTO T_E4S_DB_LOG_MESSAGE_" + extName +
" (USER_ID,USER_NAME,CLASS_NAME,METHOD_NAME,METHOD_PARAMS,LOG_DATE,LOG_MESSAGE,OPERATION_TYPE,REMARK) " +
" VALUES(?,?,?,?,?,?,?,?,?) ";
Object[] object = { userId, userName, targetName, methodName, methodParams,
new Date(), message, operationType, target };
this.jdbcTemplate.beginTranstaion();
this.jdbcTemplate.update(sql, object);
this.jdbcTemplate.commit();
}
catch (Exception ex) {
logger.error("==异常通知异常==");
logger.error("异常信息:{}", ex.getMessage());
this.jdbcTemplate.rollback();
} return target;
}
}

LoggerFilter里一个实现了XssSqlHttpServletRequestWrapper类,其构造器自动读取了servletRequest里的输入流,并把数据保存了下来,最后又把数据重新写入servletRequest里,在filter中可以读取post请求参数,cotroller也可以再次从request里读取到post请求参数。

AOP日志组件 多次获取post参数的更多相关文章

  1. Performance Counter的使用——获取各类组件性能,获取CPU参数等

    一 PerformanceCounter 基本介绍1 简单介绍表示 Windows NT 性能计数器组件 命名空间:System.Diagnostics程序集:System(在 system.dll ...

  2. 08 SSM整合案例(企业权限管理系统):11.AOP日志

    04.AdminLTE的基本介绍 05.SSM整合案例的基本介绍 06.产品操作 07.订单操作 08.权限控制 09.用户和角色操作 10.权限关联 11.AOP日志 11.AOP日志 1.数据库与 ...

  3. vue-router2.0 组件之间传参及获取动态参数

    <li v-for=" el in hotLins" > <router-link :to="{path:'details',query: {id:el ...

  4. [js开源组件开发]query组件,获取url参数和form表单json格式

    query组件,获取url参数和form表单json格式 距离上次的组件[js开源组件开发]ajax分页组件一转眼过去了近二十天,或许我一周一组件的承诺有了质疑声,但其实我一直在做,只是没人看到……, ...

  5. 我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)

    回到目录 之前的讲过两篇关于日志组件的文章,分别是<第一回  日志记录组件之自主的Vlog>和<第三回  日志记录组件之log4net>,而今天主要说一下我自己开发的另一种日志 ...

  6. java日志组件介绍(common-logging,log4j,slf4j,logback )

    转自:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.html common-logging是apache提供的一个通用的日志 ...

  7. 你的日志组件记录够清晰嘛?--自己开发日志组件 Logger

    现在现成的日志组件实在是太多太多,为什么我还需要自己实现呢????? 需求来源于java的log4j, [07-31 16:40:00:557:WARN : com.game.engine.threa ...

  8. 转:java日志组件介绍(common-logging,log4j,slf4j,logback )

    原网址:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.html common-logging common-logging是 ...

  9. 日志组件logback的介绍及配置使用方法

    一.logback的介绍 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分成三个模块:logback-core,logback- classic和logback-acc ...

随机推荐

  1. hdu 4694 Important Sisters【支配树】

    求出支配树输出到father的和即可 支配树见:https://blog.csdn.net/a710128/article/details/49913553 #include<iostream& ...

  2. IT兄弟连 JavaWeb教程 JSP内置对象经典案例

    案例需求:使用MVC模式编写一个程序当发起一个deptList.do请求时在servlet中准备一个部门列表对象,把这个列表对象放入request作用域中,然后转发到deptlist.jsp,使用js ...

  3. 阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:1. 连接阿里云物联网

    文档目录: 说明 1. 连接阿里云物联网 2. IoT 客户端 3. 订阅Topic与响应Topic 4. 设备上报属性 4.1 上报位置信息 5. 设置设备属性 6. 设备事件上报 7. 服务调用 ...

  4. 推荐 VS2010入门教程—鸡啄米

    http://www.jizhuomi.com/catalog.asp?tags=VS2010 推荐 VS2010入门教程—鸡啄米,真的非常使用和经典!

  5. 两句话跳转QQ聊天界面 通过web方式

    NSString *qq=[NSString stringWithFormat:"]; NSURL *url2 = [NSURL URLWithString:qq]; if ([[UIApp ...

  6. UVa10375:选择与除法(唯一分解定理)

    The binomial coefficient C(m,n) is defined as Given four natural numbers p, q, r, and s, compute the th ...

  7. CATIA 基础详解 第01章 CATIA初认识

    1.1 CATIA V5产品介绍 CATIA V5是基于美国IBM公司与法国达索系统公司(Dassault Systèmes)软件解决方案推出的新一代产品,它致力于满足以设计流程为中心的设计需求.它提 ...

  8. python入门之流程控制

    if else 格式: if 条件 command1 command2elif 条件: command3    command4 else: command3 command4 注意条件后和else后 ...

  9. WebService_Demo

    简述 使用IDEA开发webservice服务,从零开始一步一步指引你. 服务端开发 首先创建一个webservice项目,如下图 创建完项目后idea会帮我们创建一个类,helloword,我们把它 ...

  10. DrawTool画笔之纹理笔

    先上图: 今天我们要实现的是DrawTool画笔集合中的一种纹理笔,很多人可能对纹理笔概念还比较生疏,其实如果你接触过类似一些教育行业交互式白板的话,对纹理笔并不会感到陌生,纹理笔我们可以简单的理解为 ...