1.自定义注释
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface Log {LogType type() default LogType.SPACE;}
2.type值的枚举
public enum LogType {SPACE(""),INSERT("增加"),DELETE("删除"),UPDATE("修改"),QUERY("查询");private String description;private LogType( String string) {description=string;}public String GetDescription(){return description;}}
3.注释的使用
public abstract class AbstractService<T, M> implements IService<T, M>{@Override@Log(type = LogType.INSERT)public int add(T t){return getMapper().insert(t);}}
4.自定义切面(注意@Aspect 和@Component注解)
@Aspect@Componentpublic class OperateLogAspect {@Autowiredprivate IOperationLogService operationLogService;/*** 后置增强*/@After("@annotation(.reformer.annotation.Log) && @annotation(log)")private void after(JoinPoint joinPoint, Log log) {//读取中的用户HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();Admin user = (Admin) request.getAttribute(Constants.CURRENT_ADMIN);//未登录或登录操作if (null == user) {return;}//没有参数if (joinPoint.getArgs() == null) {return;}OperationLog operationLog = new OperationLog();operationLog.setUserId(user.getId());operationLog.setIpAddr(getIP(request));operationLog.setOpearteTime(new Date());Object[] os = joinPoint.getArgs();//获取类名String className = joinPoint.getTarget().getClass().getSimpleName();//获取方法名String methodName = joinPoint.getSignature().getName();String param = className + "." + methodName + ":";for (int i = 0; i < os.length; i++) {param += "参数[" + i + "]:" + os[i].toString();}operationLog.setOperation(log.type().GetDescription());operationLog.setOperateContent(param);//写入数据库operationLogService.insertSelective(operationLog);return;}//获取请求IPpublic String getIP(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}}
</pre><p></p><pre>
5.配置Spring-mvc.xml
proxy-target-class="true"为开启CGLIB动态代理
<!--自定义切面所在包--><context:component-scan base-package=".reformer.service"/><!--识别切面,开启CGLIB动态代理--><aop:aspectj-autoproxy proxy-target-class="true"/>
6.此过程中遇到的麻烦
在数据库写操作日志时报read-only的错误,原因事务配置了read-only,如下:
<!-- 事务管理 通知 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!-- 对insert,update,delete 开头的方法进行事务管理,只要有异常就回滚 --><tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/><tx:method name="create*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/><tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/><tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/><tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/><!-- select,count开头的方法,开启只读,提高数据库访问性能 --><tx:method name="select*" read-only="true"/><tx:method name="query*" read-only="true"/><tx:method name="count*" read-only="true"/><tx:method name="find*" read-only="true"/><tx:method name="get*" read-only="true"/><!-- 对其他方法 使用默认的事务管理 --><tx:method name="*"/></tx:attributes></tx:advice>
解决方法:
1.此处设置read-only的地方全部都是查询,可以不记录查询日志,及查询方法前不加自定义注解@Log
2.去掉事务的read-only属性