- 浏览: 948460 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (423)
- mysql (37)
- hibernate (3)
- struts (9)
- spring (33)
- dom4j (2)
- junit (0)
- exception (1)
- 随笔杂谈 (12)
- google app engine (1)
- XMPP (1)
- OAuth安全授权 (1)
- 版本控制 (8)
- 心情感悟 (0)
- core java (19)
- log4j (7)
- jquery (12)
- javascript (10)
- 网站性能优化及工具 (11)
- 服务器架设配置等 (38)
- EXT (4)
- 正则表达式 (5)
- 日志统计分析 (2)
- htmlparse (4)
- httpclient (5)
- java随笔 (5)
- dhtmlxtree (1)
- freemarke (5)
- memcached (6)
- javamail (5)
- Linux命令 (10)
- 应用监控cpu web jdbc等 (4)
- jmagick (9)
- 第三方缓存策略 (9)
- ORM (2)
- hadoop (2)
- 大数据量处理 (8)
- 经典 (1)
- 权限设计 (1)
- andriod (1)
- mybatis (12)
- redis (24)
- 数据结构_算法 (5)
- 分布式系统 (1)
- php (1)
- 网络编程 (3)
- 服务器部署 (3)
- ios (2)
- IM (23)
- mina (1)
- 视讯和语音 (1)
- 代码生成 (1)
- 架构 (4)
- 建模工具 (1)
- oracle (4)
- solr (10)
- 构建工具 (7)
- html5 (1)
- nginx (5)
- css (1)
- 大数据-分布式 (2)
- 设计模式 (2)
- mq (2)
- jvm调优 (8)
- 并发编程 (2)
- 搜索引擎 (1)
- UML (2)
最新评论
-
天使建站:
jquery获取网页里多选框checkbox选中项的值的方法及 ...
JS jQuery分别获取选中的复选框值 -
abao1:
发现一个小问题 sortAndSave方法中的for循环 第二 ...
完整java实现外部排序 -
西巴拉古呀那:
Kafka分布式消息系统实战(与JavaScalaHadoop ...
消息系统kafka介绍 -
kafodaote:
Kafka分布式消息系统实战(与JavaScalaHadoop ...
消息系统kafka介绍 -
成大大的:
Kafka分布式消息系统实 ...
消息系统kafka介绍
最近项目组长分配给我一个任务,让我完成一个操作日志的管理功能。需求是这样的:项目很大,有好几个子系统,而且这些子系统已经都在开发过程中了,都进行了大半了。现在要实现的操作日志管理是要将用户在登录系统后所做的重要操作记录下来并查询。记录的内容包括操作人的相关信息(比如:用户ID,用户名,用户IP地址,所属机构等)和所执行的操作的相关信息(比如:所属模块名称、类名、方法名、参数、是否操作成功、描述信息和错误信息)。操作日志查询功能没有什么可说的,难点是在于操作日志的记录,首先要考虑到的是日志的记录不能或要尽量少地让其他人改动自己的代码;其次要考虑到日志记录的灵活性。因此我采用了注解的方式来实现,只要将注解添加到想要记录日志的方法体上就可以实现操作日志的记录。
实现步骤如下:
第一步:启用@AspectJ支持。
在你的工程lib目录下添加aspectjweaver.jar和aspectjrt.jar并在spring 的配置文件中添加如下代码:
Xml代码
<aop:aspectj-autoproxy/>
<aop:aspectj-autoproxy/> 这一步就完成了@AspectJ的支持,从而可以实现通过注解方式将通知编织到非公共方法中。
第二步:编写自定义注解。实现对方法所实现的功能进行描述,以便在通知中获取描述信息,代码非常简单,如下:
Java代码 package com.abchina.rmpf.logmng.ann; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface rmpfLog { String desc() default "无描述信息"; } package com.abchina.rmpf.logmng.ann; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface rmpfLog { String desc() default "无描述信息"; }
第三步:编写操作日志切面通知实现类。
在编写切面通知实现类之前,我们需要搞清楚我们需要哪些通知类型,是前置通知、后置通知、环绕通知或异常通知?根据我的需求,我们知道我们记录的操作日志有两种情况,一种是操作成功,一种是操作失败。操作成功时则方法肯定已经执行完成,顾我们需要实现一个后置通知;操作失败时则说明方法出现异常无法正常执行完成,顾还需要一个异常通知。因此我们就需要实现这两个通知即可。代码如下:
package com.abchina.rmpf.logmng.aop; import java.io.File; import java.lang.reflect.Array; import java.util.Collection; import java.util.Iterator; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.springframework.util.ResourceUtils; import plantix.core.business.exception.BusinessException; import plantix.core.context.ThreadContext; import com.abchina.rmpf.privmng.web.vo.ActorVO; import com.abchina.rmpf.common.Constant; import com.abchina.rmpf.common.DateTool; import com.abchina.rmpf.logmng.ann.rmpfLog; import com.abchina.rmpf.logmng.service.ILogService; import com.abchina.rmpf.logmng.web.vo.LogVO; import com.opensymphony.xwork2.ActionContext; @Aspect //该注解标示该类为切面类 public class LogAspect { /** * LogService * @generated */ private ILogService logService; //标注该方法体为后置通知,当目标方法执行成功后执行该方法体 @AfterReturning("within(com.abchina.irms..*) && @annotation(rl)") public void addLogSuccess(JoinPoint jp, rmpfLog rl){ Object[] parames = jp.getArgs();//获取目标方法体参数 String params = parseParames(parames); //解析目标方法体的参数 String className = jp.getTarget().getClass().toString();//获取目标类名 className = className.substring(className.indexOf("com")); String signature = jp.getSignature().toString();//获取目标方法签名 String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("(")); String modelName = getModelName(className); //根据类名获取所属的模块 String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY); //用户IP ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY)); LogVO logvo = new LogVO(); logvo.setId(java.util.UUID.randomUUID().toString()); logvo.setClassname(className); logvo.setMethodname(methodName); logvo.setArgument(params); logvo.setMemo(rl.desc()); logvo.setModelname(modelName); logvo.setIp(ip); logvo.setOperationtime(DateTool.getDateTime4()); // logvo.setErr(""); logvo.setFlag("1"); if(actor!=null){ logvo.setOrgid(actor.getOrgcode()); logvo.setUserid(actor.getUserid()); logvo.setUsername(actor.getUsername()); } logService.insertLog(logvo); } //标注该方法体为异常通知,当目标方法出现异常时,执行该方法体 @AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex") public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){ Object[] parames = jp.getArgs(); String params = parseParames(parames); String className = jp.getTarget().getClass().toString(); className = className.substring(className.indexOf("com")); String signature = jp.getSignature().toString(); String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("(")); String modelName = getModelName(className); String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY); ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY)); LogVO logvo = new LogVO(); logvo.setId(java.util.UUID.randomUUID().toString()); logvo.setClassname(className); logvo.setMethodname(methodName); logvo.setArgument(params); logvo.setMemo(rl.desc()); logvo.setModelname(modelName); logvo.setIp(ip); logvo.setOperationtime(DateTool.getDateTime4()); logvo.setErr(ex.toString());//记录异常信息 logvo.setFlag("0"); if(actor!=null){ logvo.setOrgid(actor.getOrgcode()); logvo.setUserid(actor.getUserid()); logvo.setUsername(actor.getUsername()); } logService.insertLog(logvo); } /** * 根据包名查询检索其所属的模块 * @param packageName 包名 * @return 模块名称 */ private String getModelName(String packageName){ String modelName = ""; SAXReader reader = new SAXReader(); try { //读取project.xml模块信息描述xml文档 File proj = ResourceUtils.getFile("classpath:project.xml"); Document doc = reader.read(proj); //获取文档根节点 Element root = doc.getRootElement(); //查询模块名称 modelName = searchModelName(root, packageName); } catch (Exception e) { e.printStackTrace(); } return modelName; } /** * 采用递归方式根据包名逐级检索所属模块 * @param element 元素节点 * @param packageName 包名 * @return 模块名称 */ private String searchModelName(Element element, String packageName){ String modelName = searchModelNodes(element, packageName); //若将包名解析到最后的根目录后仍未检索到模块名称,则返回空 if(packageName.lastIndexOf(".")==-1){ return modelName; } //逐级检索模块名称 if(modelName.equals("")){ packageName = packageName.substring(0, packageName.lastIndexOf(".")); modelName = searchModelName(element, packageName); } return modelName; } /** * 根据xml文档逐个节点检索模块名称 * @param element 节点元素 * @param packageName 包名 * @return 模块名称 */ @SuppressWarnings("unchecked") private String searchModelNodes(Element element, String packageName){ String modelName = ""; Element modules = element.element("modules"); Iterator it = modules.elementIterator(); if(!it.hasNext()){ return modelName; } while (it.hasNext()) { Element model = (Element) it.next(); String pack = model.attributeValue("packageName"); String name = model.elementText("moduleCHPath"); if(packageName.equals(pack)){ modelName = name; return modelName; } if(modelName!=null && !modelName.equals("")){ break; } modelName = searchModelNodes(model, packageName); } return modelName; } /** * 解析方法参数 * @param parames 方法参数 * @return 解析后的方法参数 */ private String parseParames(Object[] parames) { StringBuffer sb = new StringBuffer(); for(int i=0; i<parames.length; i++){ if(parames[i] instanceof Object[] || parames[i] instanceof Collection){ JSONArray json = JSONArray.fromObject(parames[i]); if(i==parames.length-1){ sb.append(json.toString()); }else{ sb.append(json.toString() + ","); } }else{ JSONObject json = JSONObject.fromObject(parames[i]); if(i==parames.length-1){ sb.append(json.toString()); }else{ sb.append(json.toString() + ","); } } } String params = sb.toString(); params = params.replaceAll("(\"\\w+\":\"\",)", ""); params = params.replaceAll("(,\"\\w+\":\"\")", ""); return params; } public ILogService getLogService() { return logService; } public void setLogService(ILogService logService) { this.logService = logService; } } package com.abchina.rmpf.logmng.aop; import java.io.File; import java.lang.reflect.Array; import java.util.Collection; import java.util.Iterator; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.springframework.util.ResourceUtils; import plantix.core.business.exception.BusinessException; import plantix.core.context.ThreadContext; import com.abchina.rmpf.privmng.web.vo.ActorVO; import com.abchina.rmpf.common.Constant; import com.abchina.rmpf.common.DateTool; import com.abchina.rmpf.logmng.ann.rmpfLog; import com.abchina.rmpf.logmng.service.ILogService; import com.abchina.rmpf.logmng.web.vo.LogVO; import com.opensymphony.xwork2.ActionContext; @Aspect //该注解标示该类为切面类 public class LogAspect { /** * LogService * @generated */ private ILogService logService; //标注该方法体为后置通知,当目标方法执行成功后执行该方法体 @AfterReturning("within(com.abchina.irms..*) && @annotation(rl)") public void addLogSuccess(JoinPoint jp, rmpfLog rl){ Object[] parames = jp.getArgs();//获取目标方法体参数 String params = parseParames(parames); //解析目标方法体的参数 String className = jp.getTarget().getClass().toString();//获取目标类名 className = className.substring(className.indexOf("com")); String signature = jp.getSignature().toString();//获取目标方法签名 String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("(")); String modelName = getModelName(className); //根据类名获取所属的模块 String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY); //用户IP ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY)); LogVO logvo = new LogVO(); logvo.setId(java.util.UUID.randomUUID().toString()); logvo.setClassname(className); logvo.setMethodname(methodName); logvo.setArgument(params); logvo.setMemo(rl.desc()); logvo.setModelname(modelName); logvo.setIp(ip); logvo.setOperationtime(DateTool.getDateTime4()); // logvo.setErr(""); logvo.setFlag("1"); if(actor!=null){ logvo.setOrgid(actor.getOrgcode()); logvo.setUserid(actor.getUserid()); logvo.setUsername(actor.getUsername()); } logService.insertLog(logvo); } //标注该方法体为异常通知,当目标方法出现异常时,执行该方法体 @AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex") public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){ Object[] parames = jp.getArgs(); String params = parseParames(parames); String className = jp.getTarget().getClass().toString(); className = className.substring(className.indexOf("com")); String signature = jp.getSignature().toString(); String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("(")); String modelName = getModelName(className); String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY); ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY)); LogVO logvo = new LogVO(); logvo.setId(java.util.UUID.randomUUID().toString()); logvo.setClassname(className); logvo.setMethodname(methodName); logvo.setArgument(params); logvo.setMemo(rl.desc()); logvo.setModelname(modelName); logvo.setIp(ip); logvo.setOperationtime(DateTool.getDateTime4()); logvo.setErr(ex.toString());//记录异常信息 logvo.setFlag("0"); if(actor!=null){ logvo.setOrgid(actor.getOrgcode()); logvo.setUserid(actor.getUserid()); logvo.setUsername(actor.getUsername()); } logService.insertLog(logvo); } /** * 根据包名查询检索其所属的模块 * @param packageName 包名 * @return 模块名称 */ private String getModelName(String packageName){ String modelName = ""; SAXReader reader = new SAXReader(); try { //读取project.xml模块信息描述xml文档 File proj = ResourceUtils.getFile("classpath:project.xml"); Document doc = reader.read(proj); //获取文档根节点 Element root = doc.getRootElement(); //查询模块名称 modelName = searchModelName(root, packageName); } catch (Exception e) { e.printStackTrace(); } return modelName; } /** * 采用递归方式根据包名逐级检索所属模块 * @param element 元素节点 * @param packageName 包名 * @return 模块名称 */ private String searchModelName(Element element, String packageName){ String modelName = searchModelNodes(element, packageName); //若将包名解析到最后的根目录后仍未检索到模块名称,则返回空 if(packageName.lastIndexOf(".")==-1){ return modelName; } //逐级检索模块名称 if(modelName.equals("")){ packageName = packageName.substring(0, packageName.lastIndexOf(".")); modelName = searchModelName(element, packageName); } return modelName; } /** * 根据xml文档逐个节点检索模块名称 * @param element 节点元素 * @param packageName 包名 * @return 模块名称 */ @SuppressWarnings("unchecked") private String searchModelNodes(Element element, String packageName){ String modelName = ""; Element modules = element.element("modules"); Iterator it = modules.elementIterator(); if(!it.hasNext()){ return modelName; } while (it.hasNext()) { Element model = (Element) it.next(); String pack = model.attributeValue("packageName"); String name = model.elementText("moduleCHPath"); if(packageName.equals(pack)){ modelName = name; return modelName; } if(modelName!=null && !modelName.equals("")){ break; } modelName = searchModelNodes(model, packageName); } return modelName; } /** * 解析方法参数 * @param parames 方法参数 * @return 解析后的方法参数 */ private String parseParames(Object[] parames) { StringBuffer sb = new StringBuffer(); for(int i=0; i<parames.length; i++){ if(parames[i] instanceof Object[] || parames[i] instanceof Collection){ JSONArray json = JSONArray.fromObject(parames[i]); if(i==parames.length-1){ sb.append(json.toString()); }else{ sb.append(json.toString() + ","); } }else{ JSONObject json = JSONObject.fromObject(parames[i]); if(i==parames.length-1){ sb.append(json.toString()); }else{ sb.append(json.toString() + ","); } } } String params = sb.toString(); params = params.replaceAll("(\"\\w+\":\"\",)", ""); params = params.replaceAll("(,\"\\w+\":\"\")", ""); return params; } public ILogService getLogService() { return logService; } public void setLogService(ILogService logService) { this.logService = logService; } }
大家看上面的代码会发现这两个方法体:
@AfterReturning("within(com.abchina.irms..*) && @annotation(rl)") public void addLogSuccess(JoinPoint jp, rmpfLog rl){…} @AfterReturning("within(com.abchina.irms..*) && @annotation(rl)") public void addLogSuccess(JoinPoint jp, rmpfLog rl){…} Java代码 @AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex") public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){…} @AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex") public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){…}
这两个方法体分别是后置通知和异常通知的实现。它们有两个相同的参数jp和rl,jp是切点对象,通过该对象可以获取切点所切入方法所在的类,方法名、参数等信息,具体方法可以看方法体的实现;rl则是我们的自定义注解的对象,通过该对象我们可以获取注解中参数值,从而获取方法的描述信息。在异常通知中多出了一个ex参数,该参数是方法执行时所抛出的异常,从而可以获取相应的异常信息。此处为我写的自定义异常。注意:如果指定异常参数,则异常对象必须与通知所切入的方法体抛出的异常保持一致,否则该通知不会执行。
addLogSuccess方法签名上的@AfterReturning("within(com.abchina.irms..*) && @annotation(rl)")注解,是指定该方法体为后置通知,其有一个表达式参数,用来检索符合条件的切点。该表达式指定com/abchina/irms目录下及其所有子目录下的所有带有@rmpfLog注解的方法体为切点。
addLog方法签名上的@AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex")注解,是指定方法体为异常通知,其有一个表达式参数和一个抛出异常参数。表达式参数与后置通知的表达式参数含义相同,而抛出异常参数,则表示如果com/abchina/irms目录下及其所有子目录下的所有带有@rmpfLog注解的方法体在执行时抛出BusinessException异常时该通知便会执行。
注意:切面通知实现类是一个普通的pojo对象,如果要想指定其为通知对象,则需在其类名上添加@Aspect注解
第四步:在spring配置文件中创建通知bean对象。
Xml代码 <bean id="logAspect" class="com.abchina.rmpf.logmng.aop.LogAspect"> <property name="logService"> <ref local="com.abchina.rmpf.logmng.service.impl.LogServiceImpl"/> </property> </bean> <bean id="logAspect" class="com.abchina.rmpf.logmng.aop.LogAspect"> <property name="logService"> <ref local="com.abchina.rmpf.logmng.service.impl.LogServiceImpl"/> </property> </bean>
第五步:使用操作日志记录注解。
通过以上四步操作后,操作日志的记录功能就算完成了,那我们该如何使用呢?很简单!在com/abchina/irms目录下及其所有子目录下任意找到一个service层的某个类的方法,在其方法体上添加@rmpfLog(desc=”描述信息”)即可。代码如下:
Java代码 @rmpfLog(desc="创建关联交易合同") @Transactional public void insertRtcont(RtcontVO rtcontVO) throws BusinessException { rtcontAL.insertRtcont(toRtcontDomain(rtcontVO)); }
http://www.85java.com/thread-2664-1-1.html
发表评论
-
各种数据库(oracle、mysql、sqlserver等)在Spring中数据源的配置和JDBC驱动包
2013-07-16 13:09 2826在开发基于数据库的应 ... -
springmvc rest框架搭建中遇到的问题-xml转换错误
2013-01-18 11:26 2002.bean to xml显示的xml不是我往Model ... -
spring3.5 mvc json view bug MappingJacksonJsonView
2013-01-18 11:27 1540在返回单一model的json的时候。 MappingJa ... -
Spring MVC的多视图解析器配置及与Freemarker的集成
2013-01-18 11:27 3682http://my249645546.iteye.com/ ... -
xStream完美转换XML、JSON
2013-01-17 16:02 1256http://www.cnblogs.com/hoojo/a ... -
SpringMVC 中整合JSON、XML视图一
2013-01-17 16:01 1371http://www.cnblogs.com/hoojo/a ... -
Spring MVC 之 视图解析器ResourceBundleViewResolver
2013-01-17 10:45 1276http://blog.csdn.net/q34982 ... -
spring3mvc自定义多视图解析器
2013-01-17 10:41 1662使用视图名后缀来判断选择相应的视图解析器自定义一个视图解析器 ... -
spring3.0.6 使用context:property-placeholder载不进属性
2012-12-15 14:43 1376我用spring3.0.6+mybatis3.0.6+myba ... -
Spring定时任务的多种使用方法总结
2012-10-18 09:48 1729这里使用的是Spring2.5,需要的jar包:spring. ... -
spring mvc例子
2012-03-11 11:35 2073使用拦截器 和Struts2一样,Spring MVC也可以 ... -
在 Spring Bean 內取得 HttpServletRequest
2011-10-11 16:13 1227使用 Java 去開發 Web 應用程式時,大部份時候都會使用 ... -
spring3+freemark自定义标签
2011-10-09 18:27 2749<bean id="viewResolver& ... -
OpenSessionInViewFilter作用及配置
2011-06-15 10:31 1334摘自:http://www.yybean.com/opense ... -
spring httpinvoke 例子
2011-04-21 17:15 1204http://ajava.org/course/open/11 ... -
Spring基于注解的缓存配置--EHCache AND OSCache
2011-04-02 23:38 2341本文将构建一个普通工程来说明spring注解缓存的使用方式,关 ... -
使用 ActiveMQ 示例
2011-03-30 17:38 1365企业中各项目中相互协作的时候可能用得到消息通知机制。比如有 ... -
使用Spring HTTP invoker进行远程调用
2011-03-30 10:34 1694使用Spring HTTP invoker进行远程调用Spri ... -
Java Spring2.5 Remote Invoke HTTP Invoker远程调用
2011-03-30 08:42 1971近日,一个项目涉及到系统间接口调用,考虑到系统间用的都是j ... -
Spring AOP不能拦截同一个对象内方法的嵌套调用
2011-03-30 08:27 2293在开发基于 Spring 的应用的过程中碰到了一个 ...
相关推荐
5. AOP集成:Spring的AOP支持可以用于拦截数据库操作,添加如日志记录、性能监控等功能。通过自定义Advisor或使用Spring提供的DelegatingExceptionResolver,可以实现更细粒度的控制。 四、mybatisForSpring3文件...
Struts2的核心是拦截器,可以自定义拦截器实现如权限控制、日志记录等功能。在本项目中,Struts2可能通过注解来定义Action和Action方法,比如`@Action`和`@Results`,以减少XML配置文件的数量。 **Spring3.0** 是一...
- **拦截器**:允许自定义行为,实现如权限检查、日志记录等功能。 - **OGNL(Object-Graph Navigation Language)**:作为默认表达式语言,用于视图和模型之间的数据绑定。 - **插件架构**:易于扩展,可以集成其他...
Spring 3.0 提供了更强大的 AOP 支持,包括自定义注解和增强。 3. **注解驱动开发**:Spring 3.0 大量引入了注解,如 `@Autowired`、`@Service`、`@Repository` 和 `@Controller`,这些注解简化了配置文件,使得...
总之,Spring 3.0源码的深度分析有助于我们理解Spring框架的设计理念,掌握其核心功能的实现原理,从而更好地利用Spring进行软件开发。通过学习源码,我们可以学到如何优雅地实现IoC、AOP、MVC等设计模式,以及如何...
7. **拦截器**:使用`@Interceptor`可以创建自定义拦截器,对请求进行预处理或后处理,如权限检查、日志记录等。 8. **异常处理**:通过`@ExceptionHandler`注解,可以在控制器中处理特定类型的异常,提供更友好的...
《SpringMVC 4.0 + MyBatis 3.0 整合及Log4j日志记录详解》 在当今的Java Web开发领域,SpringMVC和MyBatis是两个非常重要的框架,它们分别负责控制层和持久层的操作。SpringMVC提供了强大的MVC模式支持,而MyBatis...
Spring 3.0的AOP支持允许开发者定义切面,实现如日志记录、权限控制等功能。使用@Aspect、@Before、@After等注解可以定义切点和通知,实现代码的解耦。例如,创建一个简单的日志切面: ```java @Aspect @...
4. **Bean的生命周期管理**:Spring管理Bean的创建、初始化、使用和销毁,支持自定义生命周期回调方法,以及基于XML或注解的声明式生命周期配置。 5. **数据访问集成**:Spring提供了对各种数据访问技术的集成,...
7. **Bean的生命周期**:Spring管理的Bean有多种生命周期状态,包括初始化、活跃、销毁等,开发者可以自定义生命周期回调方法,如`@PostConstruct`和`@PreDestroy`注解。 8. **Spring表达式语言(SpEL)**:Spring ...
总之,Struts2、Spring3.0和Hibernate3.5的组合为Java Web开发提供了强大的工具集,它们之间的协作能够帮助开发者构建出功能丰富、可扩展的应用程序。通过合理的配置和集成,开发者可以专注于业务逻辑,而不必过于...
Struts 2还引入了拦截器(Interceptors)机制,可以实现如权限验证、日志记录等功能,增强了框架的灵活性和可扩展性。 **Spring 2.0** 是一个全面的后端框架,包括依赖注入(DI)、面向切面编程(AOP)、数据访问/...
4. AOP在实际项目中的应用:例如日志记录、事务管理等常见场景。 四、Spring MVC 1. Spring MVC简介:了解Spring MVC的架构,处理请求的流程,以及各组件的作用。 2. DispatcherServlet和HandlerMapping:解析请求...
2. **AOP(Aspect-Oriented Programming, 面向切面编程)**:Spring提供了对AOP的支持,可以方便地实现日志记录、事务管理等横切关注点。 3. **MVC(Model-View-Controller)**:Spring MVC是Spring框架的一部分,...
7. **拦截器(Interceptor)**:拦截器可以实现全局的功能,如日志记录、权限检查等。通过实现`HandlerInterceptor`接口并添加到拦截器链中,可以在请求处理前后执行自定义逻辑。 8. **转换器与格式化器(Converter...
2. **Interceptor(拦截器)**:允许在Action执行前后添加自定义逻辑,实现如日志记录、权限验证等功能。 3. **Result类型**:定义了Action执行后的结果页面或跳转逻辑。 4. **Struts2配置文件**(struts.xml):...
7. **拦截器链**:Interceptor接口的实现可以定义自定义拦截器,用于统一处理如权限检查、日志记录等功能。 8. **消息源**:Spring MVC提供MessageSource接口,用于处理国际化消息,支持多种格式的消息资源文件。 ...
- **AOP 模块:** 支持面向切面编程,可以方便地实现日志记录、性能统计、安全控制等横切关注点的编程。 - **数据访问/集成:** 提供了JDBC抽象层,简化了JDBC编程;还支持多种ORM框架(如Hibernate、MyBatis)的...
在Spring MVC中,我们可以自定义拦截器来实现预处理和后处理逻辑,如日志记录、权限检查等。定义一个拦截器需要实现`HandlerInterceptor`接口,重写`preHandle`、`postHandle`和`afterCompletion`方法。 在这个项目...
在本项目中,我们主要探讨的是如何在Spring MVC框架下集成MongoDB 3.0数据库,同时利用log4j2进行日志管理,并且运用注解进行程序的简化与优化。下面将对这些核心知识点进行详细阐述。 首先,Spring MVC是Spring...