自定义注释与操作行为记录

自定义注释与操作行为记录

自定义注释就是一个标记,一个信息收集器,如果配合SPRING的AOP使用,可以记录用户的操作行为。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 新增的用法:@Audit(behaviour="新增了专题", 
 *            value="#{args[0].colSubject}")
 *
 * 修改的用法:@Audit(behaviour="修改了专题", id="#{args[0].colSubject.id}", 
 *            className="com.paul.program.colsubject.valueobject.ColSubject",
 *            value="#{args[0].colSubject}")
 *
 * 删除的用法:@Audit(behaviour="删除了专题", id="#{args[0].colSubject.id}"
 *             className="com.paul.program.colsubject.valueobject.ColSubject")
 *             
 * 
@author  PAUL
 *
 
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @ interface Audit {
    
    String id()  default "";
    String className()  default "";
    String collectionName()  default "";
    String value()  default "";
    String behaviour();

}


值对象
AuditData.java
package com.paul.common.audit;

import java.io.Serializable;
import java.util.Date;

import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

import com.paul.common.util.jackson.CustomJsonDateSerializer;

@Document(collection = "auditdata")
public  class AuditData  implements Serializable{

     private  static  final  long serialVersionUID = -4011585863836336249L;
    
    @Id
     private String id;
    
    @CreatedBy
    @Field("userid")
    @JsonProperty("userid")
     private String userId;
    
    @CreatedDate
    @Field("createdate")
    @JsonProperty("createdate")
    @JsonSerialize(using = CustomJsonDateSerializer. class)
     private Date createDate;
    
     private String behaviour;
    
    @Field("newvalue")
    @JsonProperty("newvalue")
     private String newValue;
    
    @Field("oldvalue")
    @JsonProperty("oldvalue")
     private String oldValue;

     public String getId() {
         return id;
    }

     public  void setId(String id) {
         this.id = id;
    }

     public String getUserId() {
         return userId;
    }

     public  void setUserId(String userId) {
         this.userId = userId;
    }

     public Date getCreateDate() {
         return createDate;
    }

     public  void setCreateDate(Date createDate) {
         this.createDate = createDate;
    }

     public String getBehaviour() {
         return behaviour;
    }

     public  void setBehaviour(String behaviour) {
         this.behaviour = behaviour;
    }


     public String getNewValue() {
         return newValue;
    }

     public  void setNewValue(String newValue) {
         this.newValue = newValue;
    }

     public String getOldValue() {
         return oldValue;
    }

     public  void setOldValue(String oldValue) {
         this.oldValue = oldValue;
    }

     public String toString() {
         return "AuditData [id=" + id + ", userId=" + userId + ", createDate="
                + createDate + ", behaviour=" + behaviour + ", newValue="
                + newValue + ", oldValue=" + oldValue + "]";
    }
    

}


RootObject.java
package com.paul.common.audit;

public  class RootObject {

     private  final Object[] args;

     private  final Object invokedObject;

     private  final Object returned;

     private  final Throwable throwned;

     public RootObject(Object invokedObject, Object[] args, Object returned, Throwable throwned) {
         super();
         this.invokedObject = invokedObject;
         this.args = args;
         this.returned = returned;
         this.throwned = throwned;
    }

     public Object[] getArgs() {
         return args;
    }

     public Object getInvokedObject() {
         return invokedObject;
    }

     public Object getReturned() {
         return returned;
    }

     public Throwable getThrowned() {
         return throwned;
    }

}


TemplateParserContext.java
package com.paul.common.audit;

import org.springframework.expression.ParserContext;

public  class TemplateParserContext  implements ParserContext {

     public String getExpressionPrefix() {
         return "#{";
    }

     public String getExpressionSuffix() {
         return "}";
    }

     public  boolean isTemplate() {
         return  true;
    }
}


获取用户ID
package com.paul.common.audit.aware;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.AuditorAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.paul.common.constant.Constants;
import com.paul.program.account.valueobject.Account;

@Component
public  class MyAppAuditor  implements AuditorAware<String> {
    
     private  static Logger logger = LoggerFactory.getLogger(MyAppAuditor. class);

     //  get your user name here
     public String getCurrentAuditor() {
        
        String result = "N/A";
         try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes()).getRequest();
            Account account = (Account)request.getSession().getAttribute(Constants.USER_INFO);
            result = account.getLoginName();
        }  catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
         return result;
    }
}


切面
package com.paul.common.audit.interceptor;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;

import com.paul.common.audit.AuditData;
import com.paul.common.audit.AuditDataRequest;
import com.paul.common.audit.RootObject;
import com.paul.common.audit.TemplateParserContext;
import com.paul.common.audit.annotation.Audit;
import com.paul.common.audit.service.AuditDataService;
import com.paul.common.util.StringUtils;

@Component
@Aspect
public  class AuditAspect {
    
     private  static Logger logger = LoggerFactory.getLogger(AuditAspect. class);
    
    @Autowired
     private AuditDataService auditDataService;
    
    @Autowired
     private MongoTemplate mongoTemplate;
    
     private SimpleDateFormat dateFormatPrototype =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

     private Map<String, Expression> expressionCache =  new ConcurrentHashMap<String, Expression>();

     private ExpressionParser expressionParser =  new SpelExpressionParser();

     private ParserContext parserContext =  new TemplateParserContext();
    

     protected  static  void appendThrowableCauses(Throwable throwable, String separator, StringBuilder toAppendTo) {
        List<Throwable> alreadyAppendedThrowables =  new ArrayList<Throwable>();

         while (throwable !=  null) {
             //  append
            toAppendTo.append(throwable.toString());
            alreadyAppendedThrowables.add(throwable);

             //  cause
            Throwable cause = throwable.getCause();
             if (cause ==  null || alreadyAppendedThrowables.contains(cause)) {
                 break;
            }  else {
                throwable = cause;
                toAppendTo.append(separator);
            }
        }
    }
    
     private String getValueByEl(String template, Object invokedObject, Object[] args, Object returned, Throwable throwned)
    {
        String result = "N/A";
         if(StringUtils.isBlank(template))
             return result;
         try {
            Expression expression = expressionCache.get(template);
             if (expression ==  null) {
                expression = expressionParser.parseExpression(template, parserContext);
                expressionCache.put(template, expression);
            }

            Object evaluatedMessage = expression.getValue( new RootObject(invokedObject, args, returned, throwned), Object. class);
            result = evaluatedMessage.toString();
        }  catch (ParseException e) {
            logger.error(e.getMessage(), e);
        }  catch (EvaluationException e) {
            logger.error(e.getMessage(), e);
        }
         return result;
    }


     protected AuditData buildAuditData(Audit auditAnnotation, Object invokedObject, Object[] args, Object returned, Throwable throwned,  long durationInNanos) {
        
        AuditData auditData =  new AuditData();
        auditData.setBehaviour(auditAnnotation.behaviour());
        String id =  this.getValueByEl(auditAnnotation.id(), invokedObject, args, returned, throwned);
        auditData.setOldValue( this.getOldValueToString(id, auditAnnotation.className()));
         try {
            String newValue =  this.getValueByEl(auditAnnotation.value(), invokedObject, args, returned, throwned);
            auditData.setNewValue(newValue);

            StringBuilder msg =  new StringBuilder();

            SimpleDateFormat simpleDateFormat = (SimpleDateFormat) dateFormatPrototype.clone();
            msg.append(simpleDateFormat.format( new Date()));
//             auditData.setCreateDate(simpleDateFormat.format(new Date()));

            msg.append(" ").append(newValue);

             if (throwned !=  null) {
                msg.append(" threw '");
                appendThrowableCauses(throwned, ", ", msg);
                msg.append("'");
            }
            msg.append(" by ");
            String user =  this.getUser();
             if (user ==  null) {
                user = "anonymous";
            } 
            msg.append(" in ") .append(TimeUnit.MILLISECONDS.convert(durationInNanos, TimeUnit.NANOSECONDS)).append(" ms");
             return auditData;
        }  catch (Exception e) {
             /* StringBuilder msg = new StringBuilder("Exception evaluating template '" + template + "': ");
            appendThrowableCauses(e, ", ", msg);
*/
             return auditData;
        }
    }
    
     private String getOldValueToString( /* ProceedingJoinPoint proceedingJoinPoint, */ String id, String className) 
    {
        String result = "N/A";
         /* String id = "5385be613d2a47eec07c53d4";
        try {
            MethodSignature methodSig = (MethodSignature) proceedingJoinPoint.getSignature();
            Object target = proceedingJoinPoint.getTarget();
            Object newValue = proceedingJoinPoint.getArgs()[0];
            String findMethodName = "findOne";
            Object oldValue=null;
            Method findMethod = target.getClass().getDeclaredMethod(findMethodName, (Class<?>[])null);
            oldValue = findMethod.invoke(target, (Object[]) null);

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
*/
         if(StringUtils.isBlank(id) || StringUtils.isBlank(className))
             return result;
        
         try {
            Object object = mongoTemplate.findById(id, Class.forName(className));
            result = ToStringBuilder.reflectionToString(object,  ToStringStyle.SHORT_PREFIX_STYLE); 
        }  catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
         return result;
    }
    
//     @Around("execution(* com.paul..**.repository..*(..))")
    @Around("@annotation(auditAnnotation)")
     public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint, Audit auditAnnotation)  throws Throwable {
        
         boolean ok =  false;
        Object o =  null;
        AuditData auditData =  null;
         try 
        {
            auditData = buildAuditData(auditAnnotation, proceedingJoinPoint.getThis(), 
                    proceedingJoinPoint.getArgs(), 
                    o,  null, 10);
            o = proceedingJoinPoint.proceed();
            ok =  true;
             return o;
        } 
         finally 
        {
             if (ok)
            {
//                 String value = (MessageFormat.format(auditAnnotation.value(), proceedingJoinPoint.getArgs()));
                 try 
                {
                    AuditDataRequest auditDataRequest =  new AuditDataRequest();
                    auditDataRequest.setAuditData(auditData);
                    auditDataService.addAuditData(auditDataRequest);
                    logger.info(auditData + "");
                } 
                 catch (Exception e) 
                {
                    logger.error(e.getMessage(), e);
                }
            }    
        }
    }
    
     private String getUser()
    {
         return "Paul";
    }
    

}


保存至数据库
package com.paul.common.audit.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import com.paul.common.audit.AuditData;
import com.paul.common.audit.AuditDataRequest;
import com.paul.common.audit.annotation.Audit;
import com.paul.common.audit.repository.AuditDataRepository;
import com.paul.program.colsubject.valueobject.ColSubjectRequest;

@Service
public  class AuditDataService {
    
    @Autowired
     private AuditDataRepository auditDataRepository;
    
//     @Audited(message = "save(#{args[0].name}, #{args[0].email}): #{returned?.id}")
    @Audit(behaviour="修改了审计", id="#{args[0].colSubject.id}", 
            className="com.paul.program.colsubject.valueobject.ColSubject",
            value="#{args[0].colSubject}")
     public  void saveObject(ColSubjectRequest colSubjectRequest)
    {
        
    }
    
    @Audit(behaviour="删除了专题", id="#{args[0]}",
             className="com.paul.program.subject.valueobject.Subject")
     public  void delete(String id) {
    }
    
    @Audit(behaviour="新增了专题", value="#{args[0].colSubject}")
     public  void add(ColSubjectRequest colSubjectRequest) {
    }
    
     public AuditData addAuditData(AuditDataRequest auditDataRequest)
    {
         return auditDataRepository.save(auditDataRequest.getAuditData());
    }
    
     public Page<AuditData> findAll(AuditDataRequest auditDataRequest)
    {
        Page<AuditData> page = auditDataRepository.findAll(auditDataRequest.getPageable());
         return page;
    }

}


DAO
package com.paul.common.audit.repository;

import org.springframework.data.repository.PagingAndSortingRepository;

import com.paul.common.audit.AuditData;

/**
 * 审计
 * 
 
*/
public  interface AuditDataRepository  extends PagingAndSortingRepository<AuditData, String>{
    
}

你可能感兴趣的:(自定义注释与操作行为记录)