千家信息网

怎么使用的Java 注解

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,本篇内容主要讲解"怎么使用的Java 注解",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么使用的Java 注解"吧!Java 元注解注解(Annotat
千家信息网最后更新 2026年10月31日怎么使用的Java 注解

本篇内容主要讲解"怎么使用的Java 注解",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么使用的Java 注解"吧!

Java 元注解

注解(Annotation)是一种可以放在 Java 类上,方法上,属性上,参数前面的一种特殊的注释,用来注释注解的注解叫做元注解。元注解我们平常不会编写,只需要添加到我们自己编写的注解上即可,。

Java 自带的常用的元注解有@Target,@Retention,@Documented,@Inherited 分别有如下含义

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. @Target:标记这个注解使用的地方,取值范围在枚举 java.lang.annotation.ElementType:TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE。

  3. @Retention :标识这个注解的生命周期,取值范围在枚举 java.lang.annotation.RetentionPolicy,SOURCE,CLASS,RUNTIME,一般定义的注解都是在运行时使用,所有要用 @Retention(RetentionPolicy.RUNTIME);

  4. @Documented:表示注解是否包含到文档中。

  5. @Inherited :使用@Inherited定义子类是否可继承父类定义的Annotation。@Inherited仅针对@Target(ElementType.TYPE)类型的annotation有效,并且仅针对class的继承,对interface的继承无效。

定义注解

上面介绍了几个元注解,下面我们定义一个日志注解来演示一下,我们通过定义一个名为OperationLog 的注解来记录一些通用的操作日志,比如记录什么时候什么人查询的哪个表的数据或者新增了什么数据。编写注解我们用的是 @interface 关键字,相关代码如下:

package com.api.annotation;  import java.lang.annotation.*;  /**  * 
* Function:
* Author:@author 子悠
* Date:2020-11-17 22:10
* Desc:用于记录操作日志
*/ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface OperationLog { /** * 操作类型 * * @return */ String type() default OperationType.SELECT; /** * 操作说明 * * @return */ String desc() default ""; /** * 请求路径 * * @return */ String path() default ""; /** * 是否记录日志,默认是 * * @return */ boolean write() default true; /** * 是否需要登录信息 * * @return */ boolean auth() default true; /** * 当 type 为 save 时必须 * * @return */ String primaryKey() default ""; /** * 对应 service 的 Class * * @return */ Class defaultServiceClass() default Object.class; }

说明

上面的注解,我们增加了@Target({ElementType.METHOD}) , @Retention(RetentionPolicy.RUNTIME), @Documented 三个元注解,表示我们这个注解是使用在方法上的,并且生命周期是运行时,而且可以记录到文档中。然后我们可以看到定义注解采用的u是@interface 关键字,并且我们给这个注解定义了几个属性,同时设置了默认值。主要注意的是平时我们编写的注解一般必须设置@Target和@Retention,而且 @Retention一般设置为RUNTIME,这是因为我们自定义的注解通常要求在运行期读取,另外一般情况下,不必写@Inherited。

使用

上面的动作只是把注解定义出来了,但是光光定义出来是没有用的,必须有一个地方读取解析,才能提现出注解的价值,我们就采用 Spring 的 AOP 拦截这个注解,将所有携带这个注解的方法所进行的操作都记录下来。

package com.api.config;  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.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping;  import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*;  /**  * 
* Function:
* Author:@author 子悠
* Date:2020-11-17 14:40
* Desc:aspect for operation log
*/ @Aspect @Component @Order(-5) @Slf4j public class LogAspect { /** * Pointcut for methods which need to record operate log */ @Pointcut("within(com.xx.yy.controller..*) && @annotation(com.api.annotation.OperationLog)") public void logAspect() { } /** * record log for Admin and DSP * * @param joinPoint parameter * @return result * @throws Throwable */ @Around("logAspect()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { Object proceed = null; String classType = joinPoint.getTarget().getClass().getName(); Class targetCls = Class.forName(classType); MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes()); OperationLog operation = targetMethod.getAnnotation(OperationLog.class); if (null != operation && operation.write()) { SysMenuOpLogEntity opLogEntity = new SysMenuOpLogEntity(); StringBuilder change = new StringBuilder(); if (StrUtil.isNotBlank(operation.type())) { switch (operation.type()) { case OperationType.ADD: proceed = joinPoint.proceed(); String addString = genAddData(targetCls, operation.defaultServiceClass(), joinPoint.getArgs()); opLogEntity.setAfterJson(addString); change.append(OperationType.ADD); break; case OperationType.DELETE: String deleteString = autoQueryDeletedData(targetCls, operation.primaryKey(), operation.defaultServiceClass(), joinPoint.getArgs()); opLogEntity.setBeforeJson(deleteString); change.append(OperationType.DELETE); proceed = joinPoint.proceed(); break; case OperationType.EDIT: change.append(OperationType.EDIT); setOpLogEntity(opLogEntity, targetCls, operation.primaryKey(), operation.defaultServiceClass(), joinPoint.getArgs()); proceed = joinPoint.proceed(); break; case OperationType.SELECT: opLogEntity.setBeforeJson(getQueryString(targetCls, operation.defaultServiceClass(), joinPoint.getArgs())); change.append(operation.type()); proceed = joinPoint.proceed(); break; case OperationType.SAVE: savedDataOpLog(opLogEntity, targetCls, operation.primaryKey(), operation.defaultServiceClass(), joinPoint.getArgs()); change.append(operation.type()); proceed = joinPoint.proceed(); break; case OperationType.EXPORT: case OperationType.DOWNLOAD: change.append(operation.type()); proceed = joinPoint.proceed(); break; default: } opLogEntity.setExecType(operation.type()); } StringBuilder changing = new StringBuilder(); if (StrUtil.isNotBlank(opLogEntity.getExecType())) { if (operation.auth()) { LoginUserVO loginUser = getLoginUser(); if (null != loginUser) { opLogEntity.setUserId(loginUser.getUserId()); opLogEntity.setUserName(loginUser.getUserName()); changing.append(loginUser.getUserName()).append("-"); } else { log.error("用户未登录"); } } opLogEntity.setCreateTime(DateUtils.getCurDate()); opLogEntity.setRemark(getOperateMenuName(targetMethod, operation.desc())); opLogEntity.setPath(getPath(targetMethod, targetMethod.getName())); opLogEntity.setChanging(changing.append(change).toString()); menuOpLogService.save(opLogEntity); } } return proceed; } /** * query data by userId * * @param targetCls class * @param defaultServiceClass default service class * @return * @throws Exception */ private String queryByCurrentUserId(Class targetCls, Class defaultServiceClass) throws Exception { BaseService baseService = getBaseService(targetCls, defaultServiceClass); LoginUserVO loginUser = dspBaseService.getLoginUser(); if (null != loginUser) { Object o = baseService.queryId(loginUser.getUserId()); return JsonUtils.obj2Json(o); } return null; } /** * return query parameter * * @param targetCls class * @param args parameter * @param defaultServiceClass default service class * @return * @throws Exception */ private String getQueryString(Class targetCls, Class defaultServiceClass, Object[] args) { if (args.length > 0) { Class entityClz = getEntityClz(targetCls, defaultServiceClass); for (Object arg : args) { if (arg.getClass().equals(entityClz) || arg instanceof BaseModel) { return JsonUtils.obj2Json(arg); } } } return null; } /** * save record log while OperatorType is SAVE * * @param opLogEntity entity * @param targetCls class * @param primaryKey primaryKey * @param defaultServiceClass default service class * @param args parameter * @throws Exception */ private void savedDataOpLog(SysMenuOpLogEntity opLogEntity, Class targetCls, String primaryKey, Class defaultServiceClass, Object[] args) throws Exception { Class entityClz = getEntityClz(targetCls, defaultServiceClass); BaseService baseService = getBaseService(targetCls, defaultServiceClass); for (Object arg : args) { if (arg.getClass().equals(entityClz)) { if (StrUtil.isNotBlank(primaryKey)) { Field declaredField = entityClz.getDeclaredField(primaryKey); declaredField.setAccessible(true); Object primaryKeyValue = declaredField.get(arg); //if primary key is not null that means edit, otherwise is add if (null != primaryKeyValue) { //query data by primary key Object o = baseService.queryId(primaryKeyValue); opLogEntity.setBeforeJson(JsonUtils.obj2Json(o)); } } opLogEntity.setAfterJson(JsonUtils.obj2Json(arg)); } } } /** * set parameter which edit data * * @param opLogEntity entity * @param targetCls class * @param primaryKey primaryKey * @param defaultServiceClass default service class * @param args parameter * @throws Exception */ private void setOpLogEntity(SysMenuOpLogEntity opLogEntity, Class targetCls, String primaryKey, Class defaultServiceClass, Object[] args) throws Exception { Map saveMap = autoQueryEditedData(targetCls, primaryKey, defaultServiceClass, args); if (null != saveMap) { if (saveMap.containsKey(ASPECT_LOG_OLD_DATA)) { opLogEntity.setBeforeJson(saveMap.get(ASPECT_LOG_OLD_DATA)); } if (saveMap.containsKey(ASPECT_LOG_NEW_DATA)) { opLogEntity.setBeforeJson(saveMap.get(ASPECT_LOG_NEW_DATA)); } } } /** * query data for edit and after edit operate * * @param targetCls class * @param primaryKey primaryKey * @param defaultServiceClass default service class * @param args parameter * @return map which data * @throws Exception */ private Map autoQueryEditedData(Class targetCls, String primaryKey, Class defaultServiceClass, Object[] args) throws Exception { if (StrUtil.isBlank(primaryKey)) { throw new Exception(); } Map map = new HashMap<>(16); Class entityClz = getEntityClz(targetCls, defaultServiceClass); BaseService baseService = getBaseService(targetCls, defaultServiceClass); for (Object arg : args) { if (arg.getClass().equals(entityClz)) { Field declaredField = entityClz.getDeclaredField(primaryKey); declaredField.setAccessible(true); Object primaryKeyValue = declaredField.get(arg); //query the data before edit if (null != primaryKeyValue) { //query data by primary key Object o = baseService.queryId(primaryKeyValue); map.put(ASPECT_LOG_OLD_DATA, JsonUtils.obj2Json(o)); map.put(ASPECT_LOG_NEW_DATA, JsonUtils.obj2Json(arg)); return map; } } } return null; } /** * return JSON data which add operate * * @param targetCls class * @param args parameter * @param defaultServiceClass default service class * @return add data which will be added * @throws Exception */ private String genAddData(Class targetCls, Class defaultServiceClass, Object[] args) throws Exception { List parameter = new ArrayList<>(); for (Object arg : args) { if (arg instanceof HttpServletRequest) { } else { parameter.add(arg); } } return JsonUtils.obj2Json(parameter); } /** * query delete data before delete operate * * @param targetCls class * @param primaryKey primaryKey * @param defaultServiceClass default service class * @param ids ids * @return delete data which will be deleted * @throws Throwable */ private String autoQueryDeletedData(Class targetCls, String primaryKey, Class defaultServiceClass, Object[] ids) throws Throwable { if (StrUtil.isBlank(primaryKey)) { throw new OriginException(TipEnum.LOG_ASPECT_PRIMARY_KEY_NOT_EXIST); } //get service BaseService baseService = getBaseService(targetCls, defaultServiceClass); //get entity Class entityClz = getEntityClz(targetCls, defaultServiceClass); //query deleted data by primary key Query query = new Query(); WhereOperator whereOperator = new WhereOperator(entityClz); Set set = new HashSet<>(Arrays.asList((Object[]) ids[0])); whereOperator.and(primaryKey).in(set.toArray()); query.addWhereOperator(whereOperator); List list = baseService.queryList(query); return JsonUtils.obj2Json(list); } /** * return service by targetCls * * @param targetCls current controller class * @param defaultServiceClass default service class * @return service instance * @throws Exception */ private BaseService getBaseService(Class targetCls, Class defaultServiceClass) throws Exception { //根据类名拿到对应的 service 名称 String serviceName = getServiceName(targetCls, defaultServiceClass); BaseService baseService; if (null != defaultServiceClass) { baseService = (BaseService) ApplicationContextProvider.getBean(serviceName, defaultServiceClass); } else { Class type = targetCls.getDeclaredField(serviceName).getType(); baseService = (BaseService) ApplicationContextProvider.getBean(serviceName, type); } return baseService; } /** * return service name * * @param targetCls current controller class * @param defaultServiceClass default service class * @return service name */ private String getServiceName(Class targetCls, Class defaultServiceClass) { if (null != defaultServiceClass && Object.class != defaultServiceClass) { return StrUtil.left(defaultServiceClass.getSimpleName(), 1).toLowerCase() + defaultServiceClass.getSimpleName().substring(1); } return StrUtil.left(targetCls.getSimpleName(), 1).toLowerCase() + targetCls.getSimpleName().substring(1).replace("Controller", "Service"); } /** * return entity class * * @param targetCls current controller class * @param defaultServiceClass default service class * @return entity class * @throws Exception */ private Class getEntityClz(Class targetCls, Class defaultServiceClass) { try { Class type; if (null != defaultServiceClass && Object.class != defaultServiceClass) { type = defaultServiceClass; } else { type = targetCls.getDeclaredField(getServiceName(targetCls, null)).getType(); } String entityName = type.getName().replace("service", "entity").replace("Service", "Entity"); Class entityClz = Class.forName(entityName); return entityClz; } catch (Exception e) { log.error("获取 class 失败"); } return null; } /** * require path * * @param targetMethod target method * @param defaultPath default require path * @return require path */ private String getPath(Method targetMethod, String defaultPath) { String path = defaultPath; PostMapping postMapping = targetMethod.getAnnotation(PostMapping.class); GetMapping getMapping = targetMethod.getAnnotation(GetMapping.class); RequestMapping requestMapping = targetMethod.getAnnotation(RequestMapping.class); if (null != postMapping) { path = postMapping.value()[0]; } else if (null != getMapping) { path = getMapping.value()[0]; } else if (null != requestMapping) { path = requestMapping.value()[0]; } return path; } }

上面的代码中我们定义了一个切面指定需要拦截的包名和注解,因为涉及到很多业务相关的代码,所以不能完整的提供出来,但是整个思路就是这样的,在每种操作类型前后将需要记录的数据查询出来进行记录。代码很长主要是用来获取相应的参数值的,大家使用的时候可以根据自己的需要进行取舍。比如在新增操作的时候,我们将新增的数据进行记录下来;编辑的时候将编辑前的数据查询出来和编辑后的数据一起保存起来,删除也是一样的,在删除前将数据查询出来保存到日志表中。

同样导出和下载都会记录相应信息,整个操作类型的代码如下:

package com.api.annotation;  /**  * 
* Function:
* Author:@author 子悠
* Date:2020-11-17 22:11
* Desc:无
*/ public interface OperationType { /** * 新增 **/ String ADD = "add"; /** * 删除 **/ String DELETE = "delete"; /** * 使用实体参数修改 **/ String EDIT = "edit"; /** * 查询 **/ String SELECT = "select"; /** * 新增和修改的保存方法,使用此类型时必须配置主键字段名称 **/ String SAVE = "save"; /** * 导出 **/ String EXPORT = "export"; /** * 下载 **/ String DOWNLOAD = "download"; }

后续在使用的时候只需要在需要的方法上加上注解,填上相应的参数即可@OperationLog(desc = "查询单条记录", path = "/data")

到此,相信大家对"怎么使用的Java 注解"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

注解 数据 查询 方法 代码 日志 时候 类型 参数 数据查询 面的 信息 关键 关键字 内容 名称 周期 地方 属性 文档 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技有限公司 上海喔噻互联网科技有限公司 互联网科技图片 北京路客互联网科技有限公司 关于新基建和互联网科技 互联网科技的发展 互联网金融科技平台 互联网科技公司有哪些 互联网 科技服务平台 华中科技有哪些互联网大佬 互联网和黑科技的看法 智腾互联网科技有限公司 互联网5g黑科技有哪些 996高科技互联网公司 企晟互联网信息科技有限公司 元气玛特互联网科技公司是外包吗 互联网风格科技公司名称 上海同邻互联网科技有限公司规模 保山互联网科技靠谱吗 优雇互联网科技有限公司 互联网高科技 中国互联网科技股 中资互联网科技 世界互联网领先科技成果 上海卓越科技 互联网 中盈科技互联网信息有限公司 南山科技园互联网公司有哪些 35岁以上互联网科技行业 全球科技与互联网公司市值变化 江苏互联网智能科技产品出厂价
0