Spring aop切面做日志处理操作有两种方式:
一:通过aop拦截器进行。该拦截器只能单个对业务类进行配置。
在spring配置文件中配置:
<bean id="beforeAdvice" class="com.test.tms.aop.BeforeAdvice"></bean>
<bean id="afterAdvice" class="com.test.tms.aop.AfterAdvice"></bean>
<bean id="compareInterceptor" class="com.test.tms.aop.CompareInterceptor"></bean>
<bean id="studenttarget" class="com.test.tms.aop.StudentImpl"></bean>
<bean id="student" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.test.tms.aop.IStudent</value>
</property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>compareInterceptor</value>
</list>
</property>
<property name="target">
<ref bean="studenttarget" />
</property>
</bean>
然后创建业务接口IStudent和业务实现类StudentImpl。并创建相关Advice,如BeforeAdvice、AfterAdvice、CompareInterceptor。
最后编写测试类:
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx =
new FileSystemXmlApplicationContext("/applicationContext.xml");
IStudent person = (IStudent)ctx.getBean("student");
person.addStudent("dragon");
}
}
二、通过aop注解实现spring mvc切面日志处理。注意:我们在处理cottroller类进行aop切面时,在poincut需要写上execution(* org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(..))。因为你controller注解的类,都被这个org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter给代理了。
我们通过aspectj进行aop处理。需要在我们项目中导入2个jar包。aspectjrt.jar和aspectjweaver.jar。
在配置文件applicationContext-mvc.xml中增加对aspectj注解的启动等。如下:
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- aop -->
<bean id="logService" class="com.test.tms.common.aop.LogService"></bean>
接下来建立切面类.
package com.test.tms.common.aop;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import com.test.tms.common.annotation.MethodLog;
/**
* @author LiuKe
* @version 1.0 2013-10-21
* @show 日志切面
*/
@Component
@Aspect
public class LogService{
@Pointcut("@annotation(com.test.tms.common.annotation.MethodLog)")
public void log(){}
@Before("log()")
public void LogRequest(JoinPoint joinPoint)
{
Object obj[] = joinPoint.getArgs();
for(Object o :obj){
System.out.println("----------------"+o+"----------------");
}
// System.out.println("========checkSecurity=="+joinPoint.getSignature().getName());//这个是获得方法名
// System.out.println("记录了一个请求");
}
@After("log()")
public void LogResponse(JoinPoint joinPoint)
{
}
@AfterThrowing("log()")
public void LogThrowing(JoinPoint joinPoint)
{
}
@Around("log()")
public Object around(ProceedingJoinPoint point) throws Throwable {
String loginName;
String name;
String monthRemark = getMthodRemark(point);
String monthName = point.getSignature().getName();
String packages = point.getThis().getClass().getName();
if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 如果是CGLIB动态生成的类
try {
packages = packages.substring(0, packages.indexOf("$$"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
String operatingcontent = "";
Object[] method_param = null;
Object object;
try {
method_param = point.getArgs(); //获取方法参数
// String param=(String) point.proceed(point.getArgs());
object = point.proceed();
} catch (Exception e) {
// 异常处理记录日志..log.error(e);
throw e;
}
//这里有点纠结 就是不好判断第一个object元素的类型 只好通过 方法描述来 做一一 转型感觉 这里 有点麻烦 可能是我对 aop不太了解 希望懂的高手在回复评论里给予我指点
//有没有更好的办法来记录操作参数 因为参数会有 实体类 或者javabean这种参数怎么把它里面的数据都解析出来?
if ((monthRemark).equals("新增域")) {
System.out.println("新增域=============================");
} else {
System.out.println("新增域2222=============================");
}
return object;
}
// 获取方法的中文备注____用于记录用户的操作日志描述
public static String getMthodRemark(ProceedingJoinPoint joinPoint)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
String methode = "";
for (Method m : method) {
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
MethodLog methodCache = m.getAnnotation(MethodLog.class);
if (methodCache != null) {
methode = methodCache.remark();
}
break;
}
}
}
return methode;
}
}
接下来建立元注解。
package com.test.tms.common.annotation;
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;
/**
* 表示对标记有xxx注解的类,做代理 注解@Retention可以用来修饰注解,是注解的注解,称为元注解。
* Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型,
* 这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配
* RententionPolicy使用。RetentionPolicy有3个值:CLASS RUNTIME SOURCE
* 用@Retention(RetentionPolicy
* .CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;
* 用@Retention(RetentionPolicy.SOURCE
* )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;
* 用@Retention(RetentionPolicy.RUNTIME
* )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时,
* 所以他们可以用反射的方式读取。RetentionPolicy.RUNTIME
* 可以让你从JVM中读取Annotation注解的信息,以便在分析程序的时候使用.
*
* 类和方法的annotation缺省情况下是不出现在javadoc中的,为了加入这个性质我们用@Documented
* java用 @interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类。
* @interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字
*
* @author q
*
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
String remark() default "";
String operType() default "0";
// String desc() default "";
}
最后在业务类的方法上增加元注解。
package com.test.tms.domain.controller;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
/**
* 域控制层
*
*
*/
@Controller
@RequestMapping("domain")
@SessionAttributes("userInfo")
public class DomainController extends BaseController {
@Resource(name = "domainServiceImpl")
private IDomainService domainService;
/**
* 新增域
*
* @param domainDO
* @param request
* @return
* @throws ParseException
*/
@RequestMapping("/addDomain")
@MethodLog(remark = "新增域")
public String addDomain(DomainDO domainDO, HttpServletRequest request)
throws ParseException {
String tokenTypeArray = request.getParameter("tokenTypeArray");
String entityTpltArray = request.getParameter("entityTpltArray");
java.text.SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
java.util.Date dateInstance = df.parse("2014/10/27");
domainDO.setTokenType(tokenTypeArray);
domainDO.setEntityTplt(entityTpltArray);
domainDO.setCreateTime(dateInstance);
domainDO.setLastUpdate(11111L);
domainService.save(domainDO);
return "redirect:/domain/getDomainList.jhtml";
}
}
至此就完成了spring mvc 对controller控制层的aop日志操作。