怎么使用的Java注解
本篇内容主要讲解“怎么使用的Java 注解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用的Java 注解”吧!
公司主营业务:成都网站设计、成都做网站、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联建站是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联建站推出吴兴免费做网站回馈大家。
Java 元注解
注解(Annotation)是一种可以放在 Java 类上,方法上,属性上,参数前面的一种特殊的注释,用来注释注解的注解叫做元注解。元注解我们平常不会编写,只需要添加到我们自己编写的注解上即可,。
Java 自带的常用的元注解有@Target,@Retention,@Documented,@Inherited 分别有如下含义
鸿蒙官方战略合作共建——HarmonyOS技术社区
@Target:标记这个注解使用的地方,取值范围在枚举 java.lang.annotation.ElementType:TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE。
@Retention :标识这个注解的生命周期,取值范围在枚举 java.lang.annotation.RetentionPolicy,SOURCE,CLASS,RUNTIME,一般定义的注解都是在运行时使用,所有要用 @Retention(RetentionPolicy.RUNTIME);
@Documented:表示注解是否包含到文档中。
@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 { MapsaveMap = 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
上面的代码中我们定义了一个切面指定需要拦截的包名和注解,因为涉及到很多业务相关的代码,所以不能完整的提供出来,但是整个思路就是这样的,在每种操作类型前后将需要记录的数据查询出来进行记录。代码很长主要是用来获取相应的参数值的,大家使用的时候可以根据自己的需要进行取舍。比如在新增操作的时候,我们将新增的数据进行记录下来;编辑的时候将编辑前的数据查询出来和编辑后的数据一起保存起来,删除也是一样的,在删除前将数据查询出来保存到日志表中。
同样导出和下载都会记录相应信息,整个操作类型的代码如下:
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 注解”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
文章名称:怎么使用的Java注解
链接地址:http://ybzwz.com/article/jpshos.html