赞
踩
一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的,这种方式可以实现Bean预处理、后处理。
这里是利用springmvc的拦截器开发了log功能,用于跟踪、记录系统用户的操作轨迹,以便日后的认责。
该功能使用很方便,是可配置的、细粒度的日志记录功能。之所以细粒度,因为level分为三层,默认包层(rootLogLevel默认值TRACE),自定义包层(customLogLevel),具体方法层(@Log默认值TRACE)
Spring MVC的拦截器不仅可实现Filter的所有功能,还可以更精确的控制拦截精度。
Spring为我们提供了org.springframework.web.servlet.handler.HandlerInterceptorAdapter这个适配器,继承此类,可以非常方便的实现自己的拦截器。他有三个方法:
- public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)
- throws Exception{
- return true;
- }
- public voidpostHandle(
- HttpServletRequest request, HttpServletResponse response, Objecthandler, ModelAndView modelAndView)
- throwsException {
- }
- public voidafterCompletion(
- HttpServletRequest request, HttpServletResponse response, Objecthandler, Exception ex)
- throwsException {
- }
分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
- <!--系统日志跟踪功能 -->
- <beanid="log4JDBCImpl"class="com.ketayao.ketacustom.log.impl.Log4JDBCImpl" >
- <propertyname="logEntityService" ref="logEntityServiceImpl"/>
- <propertyname="rootLogLevel" value="ERROR"/>
- <!--自定义日志级别 -->
- <propertyname="customLogLevel">
- <map>
- <entrykey="com.ketayao.ketacustom" value="TRACE" />
- <entrykey="com.sample" value="INFO" />
- </map>
- </property>
- </bean>
-
- <mvc:interceptors>
- <mvc:interceptor>
- <mvc:mappingpath="/management/**" />
- <mvc:mappingpath="/login/timeout/success"/>
- <beanclass="com.ketayao.ketacustom.log.spring.LogInterceptor" >
- <propertyname="logAPI" ref="log4JDBCImpl"/>
- </bean>
- </mvc:interceptor>
- </mvc:interceptors>
mvc:interceptors
这个标签用于注册一个自定义拦截器或者是WebRequestInterceptors.
可以通过定义URL来进行路径请求拦截,可以做到较为细粒度的拦截控制。
- /**
- * 自定义LogAPI接口
- * 定义日志记录和日志级别规范
- */
-
- publicinterface LogAPI {
- voidlog(String message, LogLevel logLevel);
-
- voidlog(String message, Object[] objects, LogLevel logLevel);
-
- /**
- *
- * 得到全局日志等级
- * @return
- */
- LogLevelgetRootLogLevel();
-
- /**
- *
- * 得到自定义包的日志等级
- * @return
- */
- Map<String,LogLevel> getCustomLogLevel();
- }
- /**
- * 值越大,等级越高。
- */
-
- publicenum LogLevel {
- TRACE("TRACE"),
-
- DEBUG("DEBUG"),
-
- INFO("INFO"),
-
- WARN("WARN"),
-
- ERROR("ERROR");
-
- privateString value;
-
- LogLevel(Stringvalue) {
- this.value= value;
- }
-
- publicString value() {
- returnthis.value;
- }
- }
由代码发现,枚举值后面有属性值,这是Enums的构造函数的用法
- /**
- * 全局日志等级<包日志等级<类和方法日志等级
- * @author <ahref="mailto:ketayao@gmail.com">ketayao</a>
- * Version 2.1.0
- * @since 2013-5-3 下午4:41:55
- */
- publicclass Log4JDBCImpl implements LogAPI {
-
- privateLogLevel rootLogLevel = LogLevel.ERROR;
-
- privateLogEntityService logEntityService;
-
- privateMap<String, LogLevel> customLogLevel = Maps.newHashMap();
-
- /**
- *
- * @param message
- * @param objects
- * @param logLevel
- * @seecom.ketayao.ketacustom.log.impl.LogAdapter#log(java.lang.String,java.lang.Object[], com.ketayao.ketacustom.log.LogLevel)
- */
- @Override
- publicvoid log(String message, Object[] objects, LogLevel logLevel){
-
- MessageFormatmFormat = new MessageFormat(message);
- Stringresult = mFormat.format(objects);
-
- if(!StringUtils.isNotBlank(result)) {
- return;
- }
-
- Subjectsubject = SecurityUtils.getSubject();
- ShiroDbRealm.ShiroUsershiroUser = (ShiroDbRealm.ShiroUser)subject.getPrincipal();
-
- //result= shiroUser.toString() + ":" + result;
-
- LogEntitylogEntity = new LogEntity();
- logEntity.setCreateTime(newDate());
-
- logEntity.setUsername(shiroUser.getLoginName());
- logEntity.setMessage(result);
- logEntity.setIpAddress(shiroUser.getIpAddress());
- logEntity.setLogLevel(logLevel);
-
- logEntityService.save(logEntity);
- }
-
- publicvoid setRootLogLevel(LogLevel rootLogLevel) {
- this.rootLogLevel= rootLogLevel;
- }
-
- /**
- *
- * @return
- * @seecom.ketayao.ketacustom.log.LogTemplate#getRootLogLevel()
- */
- @Override
- publicLogLevel getRootLogLevel() {
- returnrootLogLevel;
- }
-
- publicvoid setCustomLogLevel(Map<String, LogLevel> customLogLevel) {
- this.customLogLevel= customLogLevel;
- }
-
- @Override
- publicMap<String, LogLevel> getCustomLogLevel() {
- returncustomLogLevel;
- }
-
- publicvoid setLogEntityService(LogEntityService logEntityService) {
- this.logEntityService= logEntityService;
- }
-
- @Override
- publicvoid log(String message, LogLevel logLevel) {
- log(message,null,logLevel);
- }
-
- }
- /**
- *
- */
- @Documented
- @Target({METHOD})
- @Retention(RUNTIME)
- public@interface Log {
- /**
- *
- * 日志信息
- * @return
- */
- Stringmessage();
-
- /**
- *
- * 日志记录等级
- * @return
- */
- LogLevellevel() default LogLevel.TRACE;
-
- /**
- *
- * 是否覆盖包日志等级
- * 1.为false不会参考level属性。
- * 2.为true会参考level属性。
- * @return
- */
- booleanoverride() default false;
- }
- /**
- *将request放入ThreadLocal用于LOG_ARGUMENTS注入。
- */
- publicabstract class LogUitl {
- //用于存储每个线程的request请求
- privatestatic final ThreadLocal<HttpServletRequest> LOCAL_REQUEST = newThreadLocal<HttpServletRequest>();
-
- publicstatic void putRequest(HttpServletRequest request) {
- LOCAL_REQUEST.set(request);
- }
-
- publicstatic HttpServletRequest getRequest() {
- returnLOCAL_REQUEST.get();
- }
-
- publicstatic void removeRequest() {
- LOCAL_REQUEST.remove();
- }
-
- /**
- * 将LogMessageObject放入LOG_ARGUMENTS。
- * 描述
- * @param logMessageObject
- */
- publicstatic void putArgs(LogMessageObject logMessageObject) {
- HttpServletRequestrequest = getRequest();
- request.setAttribute(SecurityConstants.LOG_ARGUMENTS,logMessageObject);
- }
-
- /**
- * 得到LogMessageObject。
- * 描述
- * @param logMessageObject
- */
- publicstatic LogMessageObject getArgs() {
- HttpServletRequestrequest = getRequest();
- return(LogMessageObject)request.getAttribute(SecurityConstants.LOG_ARGUMENTS);
- }
- }
- /**
- *莫紧张,仅仅是一个例子。
- */
- @Controller
- @RequestMapping("/management/sample/task")
- publicclass TaskController {
-
- @Autowired
- privateTaskService taskService;
-
- @Autowired
- privateValidator validator;
-
- privatestatic final String CREATE = "management/sample/task/create";
- privatestatic final String UPDATE = "management/sample/task/update";
- privatestatic final String LIST = "management/sample/task/list";
- privatestatic final String VIEW = "management/sample/task/view";
-
- @RequiresPermissions("Task:save")
- @RequestMapping(value="/create",method=RequestMethod.GET)
- publicString preCreate(Map<String, Object> map) {
- returnCREATE;
- }
-
- /**
- * LogMessageObject的write用法实例。
- */
- @Log(message="添加了{0}任务,LogMessageObject的isWritten为true。",level=LogLevel.INFO)
- @RequiresPermissions("Task:save")
- @RequestMapping(value="/create",method=RequestMethod.POST)
- public@ResponseBody String create(Task task) {
- BeanValidators.validateWithException(validator,task);
- taskService.save(task);
-
- //加入一个LogMessageObject,该对象的isWritten为true,会记录日志。
- LogUitl.putArgs(LogMessageObject.newWrite().setObjects(newObject[]{task.getTitle()}));
- returnAjaxObject.newOk("任务添加成功!").toString();
- }
-
- /**
- * LogMessageObject的ignore用法实例,ignore不会记录日志。
- */
- @Log(message="你永远不会看见该日志,LogMessageObject的isWritten为false。",level=LogLevel.INFO)
- @RequiresPermissions("Task:edit")
- @RequestMapping(value="/update/{id}",method=RequestMethod.GET)
- publicString preUpdate(@PathVariable Long id, Map<String, Object> map) {
- Tasktask = taskService.get(id);
-
- map.put("task",task);
-
- //加入一个LogMessageObject,该对象的isWritten为false,不会记录日志。
- LogUitl.putArgs(LogMessageObject.newIgnore());
- returnUPDATE;
- }
-
- /**
- * Log的level用法实例
- *1.level分为三层,默认包层(rootLogLevel默认值TRACE),自定义包层(customLogLevel),具体方法层(@Log默认值TRACE)
- *2.参考顺序:默认包层->自定义包层->具体方法层->LogMessageObject
- * 3.有自定义包层的level等级会忽略默认包层
- * 4.@Log的level大于等于自定义包层或者默认的level会输出日志;小于则不会。
- */
- @Log(message="Log的level用法实例,LogLevel.TRACE小于自定义包层LogLevel.INFO,不会输出日志。",level=LogLevel.TRACE)
- @RequiresPermissions("Task:edit")
- @RequestMapping(value="/update",method=RequestMethod.POST)
- public@ResponseBody String update(Task task) {
- BeanValidators.validateWithException(validator,task);
- taskService.update(task);
-
- returnAjaxObject.newOk("任务修改成功!").toString();
- }
-
- /**
- * Log的override用法实例
- * 假如override为true,会忽略掉level
- *
- * 批量删除展示
- */
- @Log(message="Log的override用法实例,override为true,会忽略掉level。删除了{0}任务。",level=LogLevel.TRACE, override=true)
- @RequiresPermissions("Task:delete")
- @RequestMapping(value="/delete",method=RequestMethod.POST)
- public@ResponseBody String deleteMany(Long[] ids) {
- String[]titles = new String[ids.length];
- for(int i = 0; i < ids.length; i++) {
- Tasktask = taskService.get(ids[i]);
- taskService.delete(task.getId());
-
- titles[i]= task.getTitle();
- }
-
- LogUitl.putArgs(LogMessageObject.newWrite().setObjects(newObject[]{Arrays.toString(titles)}));
- returnAjaxObject.newOk("任务删除成功!").setCallbackType("").toString();
- }
-
- @RequiresPermissions("Task:view")
- @RequestMapping(value="/list",method={RequestMethod.GET, RequestMethod.POST})
- publicString list(Page page, String keywords, Map<String, Object> map) {
- List<Task>tasks = null;
- if(StringUtils.isNotBlank(keywords)) {
- tasks= taskService.find(page, keywords);
- } else{
- tasks= taskService.findAll(page);
- }
-
- map.put("page",page);
- map.put("tasks",tasks);
- map.put("keywords",keywords);
-
- returnLIST;
- }
-
- /**
- * 自定look权限,实例。
- * 描述
- * @param id
- * @param map
- * @return
- */
- @RequiresPermissions("Task:look")
- @RequestMapping(value="/view/{id}",method={RequestMethod.GET})
- publicString view(@PathVariable Long id, Map<String, Object> map) {
- Tasktask = taskService.get(id);
- map.put("task",task);
- returnVIEW;
- }
- }
LogInterceptor: 继承HandlerInterceptorAdapter,覆盖三个方法实现
- /**
- * 继承HandlerInterceptorAdapter,覆盖三个方法实现
- */
-
- publicclass LogInterceptor extends HandlerInterceptorAdapter {
- privatefinal static Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class);
-
- privateLogAPI logAPI;
-
- /**
- * 将request存入LogUitl中的LOCAL_REQUEST。
- * @param request
- * @param response
- * @param handler
- * @return
- * @throws Exception
- */
- @Override
- publicboolean preHandle(HttpServletRequest request,
- HttpServletResponseresponse, Object handler) throws Exception {
- LogUitl.putRequest(request);
- returntrue;
- }
-
- @Override
- publicvoid postHandle(HttpServletRequest request,
- HttpServletResponseresponse, Object handler,
- ModelAndViewmodelAndView) throws Exception {
-
- if(!(handler instanceof HandlerMethod)) {
- return;
- }
-
- finalHandlerMethod handlerMethod = (HandlerMethod)handler;
- Methodmethod = handlerMethod.getMethod();
-
- finalLog log = method.getAnnotation(Log.class);
- if (log!= null) {
- //得到LogMessageObject
- finalLogMessageObject logMessageObject = LogUitl.getArgs();
- //另起线程异步操作
- newThread(new Runnable() {
-
- @Override
- publicvoid run() {
- try {
- LogLevellastLogLevel = logAPI.getRootLogLevel();
-
- //先对自定义包等级做判断
- Map<String,LogLevel> customLogLevel = logAPI.getCustomLogLevel();
- if(!customLogLevel.isEmpty()) {
- Class<?>clazz = handlerMethod.getBean().getClass();
- StringpackageName = clazz.getPackage().getName();
-
- Set<String>keys = customLogLevel.keySet();
- for(String key : keys) {
- if(packageName.startsWith(key)) {
- lastLogLevel= customLogLevel.get(key);
- break;
- }
- }
- }
-
- LogMessageObjectdefaultLogMessageObject = logMessageObject;
- if(defaultLogMessageObject == null) {
- defaultLogMessageObject= LogMessageObject.newWrite();
- }
-
- if(defaultLogMessageObject.isWritten()) { // 判断是否写入log
- //覆盖,直接写入日志
- if(log.override()) {
- logAPI.log(log.message(),defaultLogMessageObject.getObjects(), log.level());
- }else {
- //不覆盖,参考方法的日志等级是否大于等于最终的日志等级
- if(!log.override() && log.level().compareTo(lastLogLevel) >= 0 ) {
- logAPI.log(log.message(),defaultLogMessageObject.getObjects(), log.level());
- }
- }
- }
- }catch (Exception e) {
- LOGGER.error(Exceptions.getStackTraceAsString(e));
- }
- }
- }).start();
-
- }
-
- }
-
- /**
- * 清除LogUitl中的LOCAL_REQUEST。
- * @param request
- * @param response
- * @param handler
- * @param ex
- * @throws Exception
- * @seeorg.springframework.web.servlet.handler.HandlerInterceptorAdapter#afterCompletion(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
- */
- @Override
- publicvoid afterCompletion(HttpServletRequest request,
- HttpServletResponseresponse, Object handler, Exception ex)
- throwsException {
- LogUitl.removeRequest();
- }
-
- publicvoid setLogAPI(LogAPI logAPI) {
- this.logAPI= logAPI;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。