spring拦截器与过滤器简单实现日志功能

spring拦截器与过滤器简单实现日志功能

HandlerInterceptor拦截器+Filter+HttpServletRequestWrapper的包装类

开发思路

日志记录包含的是程序所有接收到的请求与响应.单个设置并不符合需求.应全局对请求进行拦截获取,拿到请求对象响应对象,从请求对象响应对象中取得请求接口 请求参数 请求ip浏览器 请求身份等关键信息,存入到数据库中,新加一个页面筛选查看日志系统捕获的所有请求.

如何拿到请求的数据,可以使用HandlerInterceptor拦截器.

使用HandlerInterceptor拦截器发现存在问题:无法获取到json格式传输的数据.因为json格式传输的数据并不是存储在RequestMap对象中.
通过使用过滤器拿到json格式传递的数据,因为过滤器优先于拦截器执行.在过滤器中拿到json格式传输的数据,将数据通过设置request中参数的方法存储到request对象中.流程到拦截器中时从request中取出参数.
实现这一步发现新的问题,由于在json格式存储数据是io流,在过滤器中已经读取了,导致json格式数据丢失,无法在controller中拿到json参数,
通过自己重写一个包装类处理request请求对象,避免原对象中流的丢失. 在包装类中获取json请求的参数,将数据保存到reques对象中,在SysEventService拦截器中获取request的内容,拿到json请求参数
日志功能最核心的部分完成

代码展示

注册拦截器

//springmvc中配置拦截器
 <mvc:interceptor>
		    //拦截的路径
            <mvc:mapping path="/**"/>
            //不拦截的路径
            <mvc:exclude-mapping path="/resources/**"/>
         
    
            <mvc:exclude-mapping path="/inventory/goods/supplier_importExcel_excel.do"/>
            <bean class="com.mysoft.lesite.modules.exceptionHandling.EventInterceptor" />
            
        </mvc:interceptor> 

注册过滤器

//web.xml中配置过滤器
 <filter>
    <filter-name>requestFilter</filter-name>
    <filter-class>HttpServletFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>requestFilter</filter-name>
    <url-pattern>/*</url-pattern>
    

</filter-mapping> 

HandlerInterceptor拦截器

public class EventInterceptor extends HandlerInterceptorAdapter {
	/**
	 * 
	 * preHandle:在方法被调用前执行。在该方法中可以做类似校验的功能。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行,也就是说我们想调用的方法 不会被执行,但是你可以修改response为你想要的响应。
postHandle:在方法执行后调用。
afterCompletion:在整个请求处理完毕后进行回调,也就是说视图渲染完毕或者调用方已经拿到响应。
**
*/

	@Autowired
    private SysEventService sysEventService;

    private final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal StartTime");

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 开始时间(该数据只有当前请求的线程可见)
        startTimeThreadLocal.set(System.currentTimeMillis());
        return super.preHandle(request, response, handler);
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // 保存日志
        sysEventService.saveEvent(request, response, ex, startTimeThreadLocal.get(), System.currentTimeMillis());
        super.afterCompletion(request, response, handler, ex);
    }

}
@Service
public class SysEventService {

	@Autowired
	SysEventMapper service;

	@Autowired
	LeStoreService leStoreService;

	private ExecutorService executorService = Executors.newCachedThreadPool();

	public void saveEvent(HttpServletRequest request, HttpServletResponse response, Exception ex, long startTime,
			long endTime) throws IOException {

		// 时间处理类
		TimeManager timeManager = new TimeManager();
		// 处理一下返回--@ReponseBody返回无法获取
//	    	ResponseWrapper resonseWrapper = new ResponseWrapper((HttpServletResponse) response);
		// 处理请求
//	    	BodyRequestWrapper  requestWrapper = new BodyRequestWrapper(request);
		Logger logger = LoggerFactory.getLogger(FileUtils.class);
		final SysEventEntity record = new SysEventEntity();
		record.setId(Tools.getUUID());
		record.setMethod(request.getMethod());
		record.setRequestUri(request.getServletPath());
//	        record.setClientHost(WebUtil.getHost(request));
//	        RequestMapper	myRequestWrapper = new RequestMapper((HttpServletRequest) request);
//	        String body = myRequestWrapper.getBody();
		String body = JSON.toJSONString(request.getAttribute("jsonBody"));

		record.setUserAgent(request.getHeader("user-agent"));
		//如果是图片或文件上传就跳过
	
			// 判断是否是json传值
			if (body == null || body.replace("\"", "").length() <= 0) {
				record.setParammeters(JSON.toJSONString(request.getParameterMap()));
//				record.setParammeters(JSON.toJSONString(request.getParameterMap().size()));
			} else {
//				record.setParammeters(JSON.toJSONString(body));
				record.setParammeters(JSON.toJSONString(body));
			}
		
	

		String returneValue = String.valueOf(request.getAttribute("response"));
//	        record.setParammeters(requestWrapper.getJsonData());
		// 获取网页登录信息
		if (request.getSession().getAttribute("sessionMember") != null) {
			SessionMember sessionMember = (SessionMember) request.getSession().getAttribute("sessionMember");
			record.setCreateBy("1");
			record.setAh1(sessionMember.getAh1());
			record.setAa3(sessionMember.getAa3());
			record.setAb4(sessionMember.getAb4());

		} 

		record.setResponseData(returneValue);
//	      record.setCreateBy(sessionMember !=  null?:"非关系系统用户");
//	        record.setStatus(response.getStatus());
		
		//设置时间
//		record.setCreateTime(timeManager.getTimeString(startTime));
		record.setCreateTime(DateUtil.getTime());
		final String msg = (String) request.getAttribute("msg");

		executorService.submit(new Runnable() {
			public void run() {
				try { // 保存操作
					if (StringUtils.isNotBlank(msg)) {
						record.setRemark(msg);
					} else {
//	                        record.setRemark(ExceptionUtil.getStackTraceAsString(ex));
						record.setRemark("ExceptionUtil.getStackTraceAsString(ex)");
					}
					// 插入一条记录
					try {
						service.insert(record);
					} catch (Exception e) {
						// TODO: handle exception
						
						record.setResponseData("记录日志数据过长插入存在问题"+e);
						record.setParammeters(record.getParammeters().substring(0,100));
						service.insert(record);
					}
					
					// 内存信息
					if (logger.isDebugEnabled()) {

						String message = "开始时间: {}; 结束时间: {}; 耗时: {}s; URI: {}; ";
						// 最大内存: {}M; 已分配内存: {}M; 已分配内存中的剩余空间: {}M; 最大可用内存: {}M.
						// long total = Runtime.getRuntime().totalMemory() / 1024 / 1024;
						// long max = Runtime.getRuntime().maxMemory() / 1024 / 1024;
						// long free = Runtime.getRuntime().freeMemory() / 1024 / 1024;
						// , max, total, free, max - total + free
						logger.debug(message, timeManager.getTimeString(startTime), timeManager.getTimeString(endTime),
								(endTime - startTime) / 1000.00, record.getRequestUri());
					}
				} catch (Exception e) {
					logger.error("Save event log cause error :", e);
				}
			}
		});
	}

}

过滤器

public class HttpServletFilter  implements Filter {
	   public void init(FilterConfig filterConfig) throws ServletException {
	    }
	   
	    public void destroy() {

	    }
		public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
				throws IOException, ServletException {
			// TODO Auto-generated method stub
			RequestMapper requestWrapper = null;
			Boolean isStata = true;
		     String hs = JSON.toJSONString(request.getParameterMap());
		     String path = ((HttpServletRequest) request).getRequestURI();
		     ArrayList<String> listData =  new ArrayList<String>();
		     //需要略过的请求
		     listData.add("/inventory/goods/supplier_importExcel_excel.do");
		    
		     listData.add("/resources/");
		     listData.add("/login/");
		     listData.add("/statistics/stockppdStatistics");
		     listData.add("/portal/purchase/purchasecheckMain/le_purchase_attachment/upload.do");
		     listData.add("/inventory/goods/supplier_importExcel_excel.do");
		   
		     for(String item : listData ) {
		    	 //判断是否是不需过滤的地址
		    	 if(path.indexOf(item) != -1) {
		    		 isStata = false; 
				       
		    	 }
		    	 
		     } 
		     if(isStata) {
		    	 	//用自己写的包装类处理request请求对象
		            requestWrapper = new RequestMapper((HttpServletRequest) request);
		            request.setAttribute("jsonBody", requestWrapper.getBody());
		            requestWrapper.setAttribute("jsonBody", requestWrapper.getBody());
		            chain.doFilter(requestWrapper, response);
		        }else {
		        	 chain.doFilter(request, response);
		        }
		     
//		        if(requestWrapper == null) {
//		            chain.doFilter(request, response);
//		        } else {
//		            chain.doFilter(requestWrapper, response);
//		        }
		        
//		        chain.doFilter(request, response);
		}

}

存在问题

这种方式的拦截报错只能获取到请求中的数据,如果是程序本身捕获错误,未返回给请求中,无法拿到报错信息.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值