关于注解,很多人都清楚它们的用途,像@Autowired,@Controller,@Service等等
而自定义注解,就是我们自己创建一个注解。
自定义注解的格式:
public @interface 注解名 {定义体}
本文使用自定义注解结合springAop,记录用户的操作日志。
说到Aop切面编程,这种官方词语,看着就慌。
举个例子,现在你要吃?(面包),但你喜欢吃有馅的食物,于是你用水果刀切开一道口,往里头加了点葡萄干,然后又切了道口,往里头挤了点奶油。这样一来,面包就变美味了,切面包 == 切面?
?同理,现在有个修改数据的方法A,因为不知道是谁修改了数据,所以你打算在程序执行方法A后,自动保存操作日志。
于是你开始操刀:
A(){
/** 执行操作 **/
saveLog();
}
saveLog(){
Log log = new Log();
log.setModule("用户管理");
log.setAction("修改数据");
log.setCreateTime(new Date());
log.setCreateId(userName);
dao.saveLog(log);
}
很完美?
这时,其他功能也要跟着使用?。虽说能把saveLog()抽成公共方法,但每个需要保存日志的方法,都需要在尾部加上saveLog()。假如又需要在方法执行前,做其他操作,难道又要改成:
A(){
doSomething();
/** 执行操作 **/
saveLog();
}
B(){
doSomething();
/** 执行操作 **/
saveLog();
}
C(){
doSomething();
/** 执行操作 **/
saveLog();
}
这是不可取的?。
而切面编程,能在方法执行前后,或者抛出异常时,自动执行一系列方法,非常漂亮的解决了这种问题。
回归主题,来为用户添加操作日志。
在spring配置文件里开启aop:
<aop:aspectj-autoproxy proxy-target-class="true" />
创建自定义注解LogAnnotation,默认模块是用户管理,默认操作是登录。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface LogAnnotation {
String module() default "用户管理";
String action() default "登录";
}
创建切面程序:
@Aspect
@Component
public class LogAspect {
private Logger logger = Logger.getLogger(LogAspect.class);
@Autowired
private SysUserLogMapper sysUserLogMapper;
@Pointcut("@annotation(com.plan.LogAnnotation)")
private void logPointCut() {}
@After("logPointCut()")
public void after(JoinPoint joinPoint) {
try {
SysUserLog log = new SysUserLog();
setUserInfo(log);
setLogInfo(joinPoint,log);
sysUserLogMapper.insert(log);
} catch (InvalidSessionException e) {
logger.error(e.getMessage());
}
}
/**
* 设置用户信息
* @param log
*/
public void setUserInfo(SysUserLog log) {
Session session = SecurityUtils.getSubject().getSession();
User user = (User) session.getAttribute("user");
log.setUserId(user.getUserId());
log.setUserName(user.getChineseName());
log.setCreateDate(new Date());
}
/**
* 设置操作信息
* @param joinPoint
* @param log
*/
public void setLogInfo(JoinPoint joinPoint, SysUserLog log){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
log.setModule(annotation.module());
log.setAction(annotation.action());
}
}
切面编程还有@before,这里就不写出来了。而关于@AfterThrowing,必须是方法体抛出异常,才能捕获到。
在需要记录日志的功能方法上添加注解:
@LogAnnotation(module="用户管理",action="登录")
public String userLogin() {
}
@LogAnnotation 对应的,就是 public @interface LogAnnotation
如此一来,在执行userLogin()方法后,程序会自动执行LogAspect类的after方法,得以记录日志。
以上!!!
另需注意
如果没使用springMVC,而是struts,或许会出现@Autowired类为NULL的情况,此时需要在struts.xml 配置文件上,加上这句:
<constant name="struts.objectFactory.spring.autoWire.alwaysRespect" value="true" />
确保Spring的自动装配策略总是被考虑的。