注解定义:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
ElementType 配置介绍:
TYPE
描述:类、接口(包括注解类型)、或枚举声明。
示例:@MyAnnotation public class MyClass {}
FIELD
描述:字段声明(包括枚举常量)。
示例:@MyAnnotation private int myField;
METHOD
描述:方法声明。
示例:@MyAnnotation public void myMethod() {}
PARAMETER
描述:形式参数声明。
示例:public void myMethod(@MyAnnotation String param) {}
CONSTRUCTOR
描述:构造器声明。
示例:@MyAnnotation public MyClass(int value) {}
LOCAL_VARIABLE
描述:局部变量声明(但注意,Java 注解在 Java 8 之前不能用于局部变量)。
示例(Java 8 及以上):void myMethod() { @MyAnnotation int localVar; }
ANNOTATION_TYPE
描述:注解类型声明。
示例:@MyAnnotation public @interface MyOtherAnnotation {}
PACKAGE
描述:包声明。从 Java 9 开始,注解可以应用于包声明。
示例(Java 9 及以上):@MyAnnotation package com.example;
TYPE_PARAMETER
描述:类型参数声明(Java 8 引入)。
示例:public class MyClass<@MyAnnotation T> {}
TYPE_USE
描述:类型的使用(Java 8 引入)。这允许注解应用于任何类型的使用,如泛型、强制类型转换等。
示例:public void myMethod(List<@MyAnnotation String> list) {}
// 注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
/**
* Annotation retention policy. The constants of this enumerated type
* describe the various policies for retaining annotations. They are used
* in conjunction with the {@link Retention} meta-annotation type to specify
* how long annotations are to be retained.
*
* @author Joshua Bloch
* @since 1.5
*/
public enum RetentionPolicy {
/**
* 源码阶段存在
*/
SOURCE,
/**
* 编译阶段存在
*/
CLASS,
/**
* 运行阶段存在
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
// 生成java doc文档 时是否增加该注解显示
@Documented
// 别名
@AliasFor 属性可互换, 如 attribute 和 value 写那个配置都一样
可参考:https://www.jb51.net/program/3149973yk.htm
public @interface AliasFor {
@AliasFor("attribute")
String value() default "";
@AliasFor("value")
String attribute() default "";
Class<? extends Annotation> annotation() default Annotation.class;
}
常见注解解介绍:
@RestController = @ResponseBody + @Controller
该注解等同于 @ResponseBody + @Controller, 可以在controller 上使用,等同这两个注解。
@Controller
标注该类为控制器
@PostMapping
@GetMapping
标志请求的类型,请求路径
@RequestMapping
标注在类上,为该类所有方法增加请求路径
标注在方法上,指定方法请求路径,可配置请求类型 如 GET POST
@RequestMapping(value = "/test", method = RequestMethod.GET)
@RequestBody
指定在方法入参上,标识该参数通过 请求体传递,一般是json 串 POST请求传
@ResponseBody
指定返回数据为 web返回实体类型
@ControllerAdvice
统一的报错拦截处理,结合 @ExceptionHandler 可以对异常进行统一处理 如包装异常,日志打印等
@ComponentScan
用在spring boot 启动类上,用于标注spring 扫描路径,如果没有被包含进去的bean,不会被spring 管理与创建,自动注入会报错
@Configuration
用在类上,标注该类为配置类,在spring 启动时,会取读该类的配置,例如自定义webmvc 配置增加拦截器时会用到
@EnableConfigurationProperties
@EnableConfigurationProperties注解的作用是:使 使用 @ConfigurationProperties 注解的类生效。
如果一个配置类只配置@ConfigurationProperties注解,而没有使用@Component或者实现了@Component的其他注解,那么在IOC容器中是获取不到properties 配置文件转化的bean。
说白了 @EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。
@Import
导入一个或多个Bean(可以实现不在 componentScan 标注路径下的bean包进行扫描)
导入@Configuration类
导入ImportSelector的实现类
导入ImportBeanDefinitionRegistrar的实现类
@Primary
当存在多个相同类型的Bean注入时,加上@Primary注解,指定更高的优先级。
@Qualifier
存在多个相同类型的Bean注入时,加上@Qualifier注解,指定注入名称。
@Bean
标注方法上,返回的结果指定为 bean, 被spring 容器管理
@Value
标注在变量从上,从配置文件设置变量值,启动时未设置值,会报错
@Service
标注该类为 service 类,能够会spring 容器管理 在 controller 中可以被自动注入
@Component
标注该类为组件类,可以能够会spring 容器管理 在 service等被自动注入
@RequestParam
写在cotroller 的方法中,变量名默认为通过路径传参的参数名称
@Autowired
对指定的对象进行自动注入,如果ioc 容器中不存在,则会报错
@Deprecated
标注该类/方法被废弃,使用时会有提示,无实际影响
使用spring 自定义注解 + aop 实现接口出入参记录:
注解定义:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 日志记录注解
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 模块名称
*/
String modelName() default "";
}
注解切面逻辑:
import com.alibaba.fastjson.JSON;
import com.datadriver.log.annoations.Log;
import com.datadriver.log.dao.LogMapper;
import com.datadriver.log.entity.SystemLog;
import com.datadriver.spring.boot.security.SecurityUserDetails;
import com.datadriver.util.StringUtil;
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.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
/**
* @ClassName LogAspect
* @Description 日志切面
* @Author lvhui7
* @Date 2024/8/29
*/
@Slf4j
@Aspect
@Component
public class LogAspect {
@Autowired
private LogMapper logMapper;
@Autowired
private HttpServletRequest request;
/**
* 切入点
*/
@Pointcut("@annotation(com.test.log.annoations.Log)")
public void logPointCut() {
// do nothing
}
// 环绕
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
Date date = new Date();
Object result = point.proceed();
long time = System.currentTimeMillis() - beginTime;
this.saveLog(point, time, date);
return result;
}
/**
* 记录日志信息。
* @param joinPoint 切点,用于获取方法签名和目标对象。
* @param time 执行时间。
*/
private void saveLog(ProceedingJoinPoint joinPoint, long time, Date beginTime) {
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SystemLog systemLog = new SystemLog();
systemLog.setId(StringUtil.getUUID());
Log logAnnotation = method.getAnnotation(Log.class);
if (logAnnotation != null) {
systemLog.setModule(logAnnotation.modelName());
}
systemLog.setTime(time);
// 获取类名
String className = joinPoint.getTarget().getClass().getName();
systemLog.setClassName(className);
// 获取方法名
String methodName = signature.getName();
systemLog.setMethodName(methodName);
// 从 SecurityContextHolder 中获取当前登录人的相关信息
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
SecurityUserDetails details = (SecurityUserDetails) authentication.getPrincipal();
String username = details.getUsername();
systemLog.setNotesId(username);
Map<String, String[]> parameterMap = request.getParameterMap();
systemLog.setIp(request.getRemoteAddr());
systemLog.setParams(JSON.toJSONString(parameterMap));
systemLog.setRequestedOn(beginTime);
// 写入数据库
logMapper.insertLog(systemLog);
} catch (Exception e) {
// 出现异常不抛出,避免回滚事务
log.warn("日志记录异常:", e);
}
}
}
启动类增加aspectj 注解@EnableAspectJAutoProxy
pom 文件,增加相关依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
在需要记录接口出入参的方法上加上注解即可:
@Log(modelName = "测试记录日志")
@RequestMapping(value = "test", method = RequestMethod.POST)
public ApiResult testMethod(Model model,
HttpServletRequest request,
@RequestParam("name") String name,
@RequestParam("type") String type) {
// 省略业务逻辑
return ApiResult.success();
}
起始还有个地方可以优化一下,记录的请求,可以改成异步的,避免接口请求时间被加长了,不过项目请求量小,就不做处理了~
标签:lang,java,自定义,记录,public,import,注解,annotation From: https://www.cnblogs.com/charler/p/18440189