一、引入对应的maven jar
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、编写自定义注解
package com.al.api.aop.annotation;
import java.lang.annotation.*;
/**
* @Description TODD
* @Author zhuzhibin
* @Date 2021/1/13 14:02
* @Version 1.0
**/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuditAnno {
String value() default "";//执行的方法名称
String moduleName() default ""; //模块名称
String moduleCode() default ""; //模块code
String operationType() default "";//操作类型
}
三、创建切面类
package com.al.api.aop;
import cn.hutool.http.HttpUtil;
import com.al.api.aop.annotation.AuditAnno;
import com.al.api.utils.AdminInfoContext;
import com.al.base.dto.region.AuditLogDTO;
import com.al.base.service.region.AuditLogService;
import com.al.common.utils.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Collection;
/**
* @ClassName AuditAop
* @Description TODO
* @Author Administrator
* @Date 2021/1/13 14:03
* @Version 1.0
*/
@Slf4j
@Aspect
@Component
public class AuditAopConfig {
@Reference(check = false)
private AuditLogService auditLogService;
// 操作类型
ThreadLocal<String> operateType = new ThreadLocal<>();
// 模块名称
ThreadLocal<String> moduleName = new ThreadLocal<>();
// 模块code
ThreadLocal<String> moduleCode = new ThreadLocal<>();
// 功能模块
ThreadLocal<String> methodName = new ThreadLocal<>();
// ip信息
ThreadLocal<String> Ip = new ThreadLocal<>();
// 操作信息实体
ThreadLocal<AuditLogDTO> ald = new ThreadLocal<>();
@Pointcut("execution(public * com.al.api.modules.*.controller.*.create(..)) && " +
"@annotation(com.al.api.aop.annotation.AuditAnno)")
public void add_log(){}
@Pointcut("execution(public * com.al.api.modules.*.controller.*.update(..)) && " +
"@annotation(com.al.api.aop.annotation.AuditAnno)")
public void update_log(){}
@Pointcut("execution(public * com.al.api.modules.*.controller.*.del(..)) && " +
"@annotation(com.al.api.aop.annotation.AuditAnno)")
public void del_log(){}
/**
* @Author zhuzhibin
* @Description //TODO 编辑操作的审计日志记录
* @Date
* @Param
* @return
**/
@Before("update_log()")
public void updateLog(JoinPoint joinPoint){
AuditLogDTO auditLogDTO = new AuditLogDTO();
try{
logPre(joinPoint);//注解中对应的参数
auditLogDTO.setType(operateType.get());
auditLogDTO.setModuleName(moduleName.get());
auditLogDTO.setModuleCode(moduleCode.get());
auditLogDTO.setMethod(methodName.get());
String args = JSON.toJSONString(joinPoint.getArgs()[0]);//前台穿过来的参数
JSONObject jsonObject = JSONObject.parseObject(args);
auditLogDTO.setDataNow(args);
String dataId = jsonObject.get("id").toString();
String moduleCode = auditLogDTO.getModuleCode();
//根据 tableName \ id
String result = auditLogService.selectObjById(dataId, moduleCode);
auditLogDTO.setDataOld(JSON.toJSONString(result));
getIp();
auditLogDTO.setIp(Ip.get());//操作的ip
auditLogDTO.setCreatorId(AdminInfoContext.getAdminIdAndOrgId().split(",")[0]);//操作人的id
ald.set(auditLogDTO);
auditLogService.add(ald.get());
}catch (Exception e){
log.error("编辑审计出现错误。"+e);
}
}
/**
* @Author zhuzhibin
* @Description //TODO 新增操作的审计日志记录
* @Date
* @Param
* @return
**/
@AfterReturning(returning = "obj",pointcut = "add_log()")
public void addLog(JoinPoint joinPoint,Object obj){
JSONObject json = JSONObject.parseObject(JSON.toJSONString(obj));
if("success".equals(json.get("msg"))){
AuditLogDTO auditLogDTO = new AuditLogDTO();
try{
logPre(joinPoint);//注解中对应的参数
auditLogDTO.setType(operateType.get());
auditLogDTO.setModuleName(moduleName.get());
auditLogDTO.setModuleCode(moduleCode.get());
auditLogDTO.setMethod(methodName.get());
String args = JSON.toJSONString(joinPoint.getArgs()[0]);//前台穿过来的参数
auditLogDTO.setDataNow(args);
auditLogDTO.setDataOld(null);//新增设置为null,删除设置为最后,修改的时候 时候需要进行查询
getIp();
auditLogDTO.setIp(Ip.get());//操作的ip
auditLogDTO.setCreatorId(AdminInfoContext.getAdminIdAndOrgId().split(",")[0]);//操作人的id
ald.set(auditLogDTO);
auditLogService.add(ald.get());
}catch (Exception e){
log.error("新增审计出现错误。"+e);
}
}
}
/**
* @Author zhuzhibin
* @Description //TODO 删除操作的审计日志记录
* @Date
* @Param
* @return
**/
@Before("del_log()")
public void delLog(JoinPoint joinPoint) throws Throwable {
try{
AuditLogDTO auditLogDTO = new AuditLogDTO();
logPre(joinPoint);//注解中对应的参数
auditLogDTO.setType(operateType.get());
auditLogDTO.setModuleName(moduleName.get());
auditLogDTO.setModuleCode(moduleCode.get());
auditLogDTO.setMethod(methodName.get());
String args = JSON.toJSONString(joinPoint.getArgs()[0]);//前台穿过来的参数
auditLogDTO.setDataNow(null);
auditLogDTO.setDataOld(args);//新增设置为null,删除设置为最后,修改的时候 时候需要进行查询
getIp();
auditLogDTO.setIp(Ip.get());//操作的ip
auditLogDTO.setCreatorId(AdminInfoContext.getAdminIdAndOrgId().split(",")[0]);//操作人的id
ald.set(auditLogDTO);
auditLogService.add(ald.get());
}catch (Exception e){
log.error("删除审计出现错误。"+e);
}
}
/**
* @Author zhuzhibin
* @Description //TODO 获取请求过来的ip
* @Date
* @Param
* @return
**/
private void getIp(){
//获取请求对象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = HttpUtil.getClientIP(request);
Ip.set(ip);
}
/**
* @Author zhuzhibin
* @Description //TODO 获取自定义注解的参数
* @Date
* @Param
* @return
**/
private void logPre(JoinPoint pjp) throws Exception {
for (Method method : Class.forName(pjp.getTarget().getClass().getName()).getMethods()) {
if (method.getName().equals(pjp.getSignature().getName())) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == pjp.getArgs().length) {
//获取注解信息
operateType.set(method.getAnnotation(AuditAnno.class).operationType());
moduleName.set(method.getAnnotation(AuditAnno.class).moduleName());
moduleCode.set(method.getAnnotation(AuditAnno.class).moduleCode());
methodName.set(method.getAnnotation(AuditAnno.class).value());
break;
}
}
}
}
/**
* @Author zhuzhibin
* @Description //TODO 从dubbo 中 获取对应的bean
* @Date
* @Param
* @return
**/
public static <T> T getDubboBean(Class<T> requiredType){
ReferenceAnnotationBeanPostProcessor dubboContext = SpringUtil.getBean(ReferenceAnnotationBeanPostProcessor.class);
Collection<ReferenceBean<?>> referenceBeans = dubboContext.getReferenceBeans();
for (ReferenceBean<?> referenceBean : referenceBeans) {
Class<?> objectType = referenceBean.getObjectType();
if(objectType == requiredType){
return (T)referenceBean.getObject();
}
}
return null;
}
}
四、通过spring application 获取对应的 service 服务类 为了修改审计日志的时候 进行调用【由于我使用的是dubbo 服务化注解的方式,所以使用了 动态sql 进行实现。】
1、
List<LinkedHashMap<String,Object>> selectObjById(@Param("id") String id, @Param("tableName") String tableName);
2、
<select id="selectObjById" parameterType="java.lang.String" resultType="java.util.LinkedHashMap">
SELECT
*
FROM
${tableName}
WHERE
id = #{id}
</select>