注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解。
主要的作用:
- 生成文档,通过代码里标识的元数据生成javadoc文档。
- 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
- 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
- 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。
内置注解
Java 1.5开始自带的标准注解,包括@Override、@Deprecated和@SuppressWarnings:
- @Override:表示当前的方法定义将覆盖父类中的方法
- @Deprecated:表示代码被弃用,如果使用了被@Deprecated注解的代码则编译器将发出警告
- @SuppressWarnings:表示关闭编译器警告信息
元注解
在JDK 1.5中提供了4个标准的元注解:@Target,@Retention,@Documented,@Inherited。
- @Target
Target注解的作用是:描述注解的使用范围(即:被修饰的注解可以用在什么地方)
Target注解用来说明那些被它所注解的注解类可修饰的对象范围:注解可以用于修饰 packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数),在定义注解类时使用了@Target 能够更加清晰的知道它能够被用来修饰哪些对象,它的取值范围定义在ElementType 枚举中。
- @Retention
Reteniton注解的作用是:描述注解保留的时间范围(即:被描述的注解在它所修饰的类中可以被保留到何时)
Reteniton注解用来限定那些被它所注解的注解类在注解到其他类上以后,可被保留到何时,一共有三种策略,定义在RetentionPolicy枚举中。
1 2 3 4 5 |
public enum RetentionPolicy { SOURCE, // 源文件保留 CLASS, // 编译期保留,默认值 RUNTIME // 运行期保留,可通过反射去获取注解信息 } |
- @Documented
Documented注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。
- @Inherited
Inherited注解的作用:被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
大致了解注解的一些概念,下面自己定义一个注解。
自定义注解
最为常见的就是使用Spring AOP切面实现统一的操作日志管理
- 自定义Log注解
123456789101112131415161718192021222324@Target({ ElementType.PARAMETER, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Log {/*** 模块*/public String title() default "";/*** 功能*/public BusinessType businessType() default BusinessType.OTHER;/*** 操作人类别*/public OperatorType operatorType() default OperatorType.MANAGE;/*** 是否保存请求的参数*/public boolean isSaveRequestData() default true;}
实现日志的切面, 对自定义注解Log作切点进行拦截
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133@Aspect@Componentpublic class LogAspect {private static final Logger log = LoggerFactory.getLogger(LogAspect.class);/*** 配置织入点 - 自定义注解的包路径**/@Pointcut("@annotation(com.xxx.aspectj.lang.annotation.Log)")public void logPointCut() {}/*** 处理完请求后执行** @param joinPoint 切点*/@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {handleLog(joinPoint, null, jsonResult);}/*** 拦截异常操作** @param joinPoint 切点* @param e 异常*/@AfterThrowing(value = "logPointCut()", throwing = "e")public void doAfterThrowing(JoinPoint joinPoint, Exception e) {handleLog(joinPoint, e, null);}protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {try {// 获得注解Log controllerLog = getAnnotationLog(joinPoint);if (controllerLog == null) {return;}// 获取当前的用户User currentUser = ShiroUtils.getSysUser();// *========数据库日志=========*//OperLog operLog = new OperLog();operLog.setStatus(BusinessStatus.SUCCESS.ordinal());// 请求的地址String ip = ShiroUtils.getIp();operLog.setOperIp(ip);// 返回参数operLog.setJsonResult(JSONObject.toJSONString(jsonResult));operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());if (currentUser != null) {operLog.setOperName(currentUser.getLoginName());if (StringUtils.isNotNull(currentUser.getDept())&& StringUtils.isNotEmpty(currentUser.getDept().getDeptName())) {operLog.setDeptName(currentUser.getDept().getDeptName());}}if (e != null) {operLog.setStatus(BusinessStatus.FAIL.ordinal());operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));}// 设置方法名称String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();operLog.setMethod(className + "." + methodName + "()");// 设置请求方式operLog.setRequestMethod(ServletUtils.getRequest().getMethod());// 处理设置注解上的参数getControllerMethodDescription(controllerLog, operLog);// 保存数据库AsyncManager.me().execute(AsyncFactory.recordOper(operLog));} catch (Exception exp) {// 记录本地异常日志log.error("==前置通知异常==");log.error("异常信息:{}", exp.getMessage());exp.printStackTrace();}}/*** 获取注解中对方法的描述信息 用于Controller层注解** @param log 日志* @param operLog 操作日志* @throws Exception*/public void getControllerMethodDescription(Log log, OperLog operLog) throws Exception {// 设置action动作operLog.setBusinessType(log.businessType().ordinal());// 设置标题operLog.setTitle(log.title());// 设置操作人类别operLog.setOperatorType(log.operatorType().ordinal());// 是否需要保存request,参数和值if (log.isSaveRequestData()) {// 获取参数的信息,传入到数据库中。setRequestValue(operLog);}}/*** 获取请求的参数,放到log中** @param operLog* @param request*/private void setRequestValue(OperLog operLog) {Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();String params = JSONObject.toJSONString(map);operLog.setOperParam(StringUtils.substring(params, 0, 2000));}/*** 是否存在注解,如果存在就获取*/private Log getAnnotationLog(JoinPoint joinPoint) throws Exception {Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null){return method.getAnnotation(Log.class);}return null;}}
使用@Log注解
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657@Controller@RequestMapping("/system/dept")public class DeptController extends BaseController {private String prefix = "system/dept";@Autowiredprivate IDeptService deptService;/*** 新增保存部门*/@Log(title = "部门管理", businessType = BusinessType.INSERT)@RequiresPermissions("system:dept:add")@PostMapping("/add")@ResponseBodypublic AjaxResult addSave(@Validated Dept dept) {if (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) {return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");}return toAjax(deptService.insertDept(dept));}/*** 保存*/@Log(title = "部门管理", businessType = BusinessType.UPDATE)@RequiresPermissions("system:dept:edit")@PostMapping("/edit")@ResponseBodypublic AjaxResult editSave(@Validated Dept dept) {if (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) {return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");} else if(dept.getParentId().equals(dept.getDeptId())) {return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");}return toAjax(deptService.updateDept(dept));}/*** 删除*/@Log(title = "部门管理", businessType = BusinessType.DELETE)@RequiresPermissions("system:dept:remove")@GetMapping("/remove/{deptId}")@ResponseBodypublic AjaxResult remove(@PathVariable("deptId") Long deptId) {if (deptService.selectDeptCount(deptId) > 0) {return AjaxResult.warn("存在下级部门,不允许删除");}if (deptService.checkDeptExistUser(deptId)) {return AjaxResult.warn("部门存在用户,不允许删除");}return toAjax(deptService.deleteDeptById(deptId));}// ...}
转自:https://zhuanlan.zhihu.com/p/546669151