1.自定义注解
package cn.wwkj.pms.basis.annotation;
import cn.wwkj.pms.basis.entity.vo.EnumLogCode;
import java.lang.annotation.*;
/**
* 日志注解 日志记录注解使用方法@SysLogAnno(value = "添加年份",operateType = EnumLogCode .SYS)
* @author GaoDongYang
* @date 2020/8/12 14:33
*/
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SysLogAnno {
/**
* 操作内容
* @return String
*/
String value() default "";
/**
* 日志code类型
* @return EnumLogCode
*/
EnumLogCode operateType() default EnumLogCode.SYS;
}
- @Target({ElementType.METHOD}) 注解 表明作用在方法上的注解
ElementType 是一个枚举类型的常量提供了一个简单的分类:表示你自定义的注解可能出现在Java程序中的语法位置,常用的有METHOD、PARAMETER
可用位置和类型有:
package java.lang.annotation;
/**
1. The constants of this enumerated type provide a simple classification of the
2. syntactic locations where annotations may appear in a Java program. These
3. constants are used in {@link Target java.lang.annotation.Target}
4. meta-annotations to specify where it is legal to write annotations of a
5. given type.
6. @author Joshua Bloch
7. @since 1.5
8. @jls 9.6.4.1 @Target
9. @jls 4.1 The Kinds of Types and Values
*/
public enum ElementType {
/** 类, 接口 (包括注释类型), 或 枚举 声明 */
TYPE,
/** 字段声明(包括枚举常量) */
FIELD,
/** 方法声明(Method declaration) */
METHOD,
/** 正式的参数声明 */
PARAMETER,
/** 构造函数声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注释类型声明 */
ANNOTATION_TYPE,
/** 包声明 */
PACKAGE,
/**
* 类型参数声明
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 使用的类型
*
* @since 1.8
*/
TYPE_USE
}
- @Retention({RetentionPolicy.Runtime}) 注解
RetentionPolicy这个枚举类型的常量描述保留注释的各种策略,它们与元注释(@Retention)一起指定注释要保留多长时间,一般Runtime
package java.lang.annotation;
/**
1. Annotation retention policy. The constants of this enumerated type
2. describe the various policies for retaining annotations. They are used
3. in conjunction with the {@link Retention} meta-annotation type to specify
4. how long annotations are to be retained.
5. 6. @author Joshua Bloch
7. @since 1.5
*/
public enum RetentionPolicy {
/**
* 注释只在源代码级别保留,编译时被忽略
*/
SOURCE,
/**
* 注释将被编译器在类文件中记录
* 但在运行时不需要JVM保留。这是默认的
* 行为.
*/
CLASS,
/**
*注释将被编译器记录在类文件中
*在运行时保留VM,因此可以反读。
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
-
@Documented注解 就是一个声明
Documented注解表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注释了文档化,它的注释成为公共API的一部分。
2.引入aop依赖
pom文件中
<!--spring切面aop依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
3.自定义切面类
package cn.wwkj.pms.basis.aspect;
import cn.wwkj.pms.basis.annotation.SysLogAnno;
import cn.wwkj.pms.basis.entity.bo.Log;
import cn.wwkj.pms.basis.entity.vo.EnumLogCode;
import cn.wwkj.pms.basis.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 日志切面
* @author gaodongyang
* @date 2020/8/12 14:37
**/
@Aspect
@Component
@Order(0)
@Slf4j
public class LogAspect {
private final SysLogService sysLogService;
private final ObjectMapper objectMapper;
/**
* 构造注入
* @param sysLogService 日志
* @param objectMapper json序列化映射器
*/
public LogAspect(SysLogService sysLogService, ObjectMapper objectMapper) {
this.sysLogService = sysLogService;
this.objectMapper = objectMapper;
}
/**
* 设置切点 对有@SysLogAnno注释的方法生效
* @author gaodongyang
* @date 2020/8/12 14:42
**/
@Pointcut("@annotation(cn.wwkj.pms.basis.annotation.SysLogAnno)")
public void logPointCut() {
}
/**
* 环绕通知
* @author gaodongyang
* @date 2020/8/12 16:47
* @param point 连接点
* @return Object 结果
**/
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
log.info("环绕通知开始。。。。。");
//日志
Log sysLog = new Log();
Object result = null;
try {
// 执行方法
result = point.proceed();
sysLog.setRet(0);
}catch (Exception e){
log.error(e.getMessage(),e);
sysLog.setRet(1)
.setRetStr(e.getMessage());
}finally {
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) point.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
// 获得注解 操作
SysLogAnno monitorLog = method.getAnnotation(SysLogAnno.class);
// 获得code
EnumLogCode operateType = monitorLog.operateType();
// 获得操作内容
String value = monitorLog.value();
System.out.print(result);
sysLog.setCont1(value);
//请求的参数
Object[] args = point.getArgs();
//将参数所在的数组转换成json
StringBuilder params = new StringBuilder();
for(Object o : args){
params.append(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(o));
}
sysLog.setRemark1(params.toString());
//添加日志
sysLogService.add(operateType,sysLog);
log.info("环绕通知结束。。。。。");
}
return result;
}
}
4.日志有关数据库,这里只写插入方法
日志插入service层的add方法,主要就是在本方法上加上**@Transactional(propagation = Propagation.NOT_SUPPORTED)**事务,防止在其他方法上加日志注解时,因其方法内部的错误导致事务回归,日志也回滚,不能在其他方法执行失败时把日志插入数据库中。
/**
* 添加日志
* @param logParam 日志字段实体
* @author GaoDongYang, GongLiHai
* @date 2020/8/11 10:38
**/
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addLog(Log logParam) {
//初始化日志对象,并设置设备信息,用户信息,ip等内容
SysLog sysLog = new SysLog(logParam)
.setDevice(getDevice(request.getHeader("User-Agent")))
.setUserDept(CurrentUserService.currentUserDetails())
.setIp(((WebAuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails()).getRemoteAddress())
.setInParam(getFmtInParam(logParam.getInParam()));
sysLogMapper.insert(sysLog);
}
5.使用时,只需加上注解
/**
* 添加要素详情
* @param elementDetail 要添加的要素详情信息
* @param year 年份
* @return 返回添加结果
* @author WeiJian
**/
@RequestMapping("/addElementDetail")
@SysLogAnno(value = "添加年份",operateType = EnumLogCode .SYS)
public Result<?> addElementDetail(@Valid ElementDetail elementDetail, @CurrentYear int year) {
elementDetail.setYear(year);
return ResultUtil.updateResult(elementDetailService.addElementDetail(elementDetail));
}
6.我定义的注解中operateType = EnumLogCode .SYS时枚举类型
也可不用枚举,传字符串什么的都一样
package cn.wwkj.pms.basis.entity.vo;
/**
* 日志 code name 枚举类
* @author gaodongyang
* @date 2020/8/11 10:00
**/
@SuppressWarnings("unused")
public enum EnumLogCode {
//code数据库映射
SYS("001","系统日志"),
SYS_LOGIN("001001","登录日志");
private String name;
private String code;
EnumLogCode(String code, String name){
this.name = name;
this.code = code;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
}