今天项目完了,复盘了一下系统,发现还是有一些东西值得拿出来和大家分享一下。需求分析 系统需要对用户的操作进行记录,方便未来溯源 首先想到的就是在每个方法中,去实现记录的逻辑,但是这样做肯定是不现实的,首先工作量大,其次违背了软件工程设计原则(开闭原则) 这种需求显然是对代码进行增强,首先想到的是使用SpringBoot提供的AOP结合注解的方式来实现功能实现1、需要一张记录日志的Log表 导出的sql如下:mcams。tlogdefinitionCREATETABLEtlog(logidintNOTNULLAUTOINCREMENTCOMMENT日志编号,useridintNOTNULLCOMMENT操作人id,operationvarchar(128)NOTNULLCOMMENT用户操作,methodvarchar(255)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciDEFAULTNULLCOMMENT操作的方法,paramsvarchar(255)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciDEFAULTNULLCOMMENT方法的参数,ipvarchar(40)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciDEFAULTNULLCOMMENT用户的ip,createtimetimestampNULLDEFAULTNULLCOMMENT操作时间,costtimeintDEFAULTNULLCOMMENT花费时间,PRIMARYKEY(logid))ENGINEInnoDBAUTOINCREMENT189DEFAULTCHARSETutf8mb4COLLATEutf8mb40900aici;2、我使用的是SpringBoot所以需要引入springaop的starterdependencygroupIdorg。springframework。bootgroupIdspringbootstarteraopartifactIddependency 如果是使用spring框架的,引入springaop即可3、Log实体类packagecom。xiaofengstu。mcams。web。entity;importcom。baomidou。mybatisplus。annotation。IdType;importcom。baomidou。mybatisplus。annotation。TableField;importcom。baomidou。mybatisplus。annotation。TableId;importcom。baomidou。mybatisplus。annotation。TableName;importjava。io。Serializable;importjava。time。LocalDateTime;importcom。fasterxml。jackson。annotation。JsonFormat;importlombok。Getter;importlombok。Setter;pauthorfengzengsince20220521GetterSetterTableName(tlog)publicclassTLogimplementsSerializable{privatestaticfinallongserialVersionUID1L;TableId(valuelogid,typeIdType。AUTO)privateIntegerlogId;操作人idTableField(userid)privateIntegeruserId;用户操作TableField(operation)privateStringoperation;TableField(method)privateStringmethod;TableField(params)privateStringparams;TableField(ip)privateStringip;JsonFormat(patternyyyyMMddHH:mm:ss)TableField(createtime)privateLocalDateTimecreateTime;TableField(costtime)privateLongcostTime;} 需要lombok插件(gettersetter注解)4、ILog注解packagecom。xiaofengstu。mcams。annotation;importjava。lang。annotation。ElementType;importjava。lang。annotation。Retention;importjava。lang。annotation。RetentionPolicy;importjava。lang。annotation。Target;AuthorFengZengDate2022052100:48DescriptionTODOTarget(ElementType。METHOD)Retention(RetentionPolicy。RUNTIME)publicinterfaceILog{Stringvalue()default;}5、切面类LogAspectpackagecom。xiaofengstu。mcams。aspect;importcom。xiaofengstu。mcams。annotation。ILog;importcom。xiaofengstu。mcams。util。ThreadLocalUtils;importcom。xiaofengstu。mcams。web。entity。TLog;importcom。xiaofengstu。mcams。web。service。TLogService;importlombok。RequiredArgsConstructor;importorg。aspectj。lang。ProceedingJoinPoint;importorg。aspectj。lang。annotation。Around;importorg。aspectj。lang。annotation。Aspect;importorg。aspectj。lang。annotation。Pointcut;importorg。aspectj。lang。reflect。MethodSignature;importorg。springframework。core。LocalVariableTableParameterNameDiscoverer;importorg。springframework。stereotype。Component;importorg。springframework。web。context。request。RequestContextHolder;importorg。springframework。web。context。request。ServletRequestAttributes;importjavax。servlet。http。HttpServletRequest;importjava。lang。reflect。Method;importjava。time。LocalDateTime;AuthorFengZengDate2022052100:42DescriptionTODOAspectComponentRequiredArgsConstructorpublicclassLogAspect{privatefinalTLogServicelogService;Pointcut(annotation(com。xiaofengstu。mcams。annotation。ILog))publicvoidpointcut(){}Around(pointcut())publicObjectaround(ProceedingJoinPointpoint){Objectresultnull;longbeginTimeSystem。currentTimeMillis();try{resultpoint。proceed();}catch(Throwablee){e。printStackTrace();}longcostTimeSystem。currentTimeMillis()beginTime;saveLog(point,costTime);returnresult;}privatevoidsaveLog(ProceedingJoinPointpoint,longcostTime){通过point拿到方法签名MethodSignaturemethodSignature(MethodSignature)point。getSignature();通过方法签名拿到被调用的方法MethodmethodmethodSignature。getMethod();TLoglognewTLog();通过方法区获取方法上的ILog注解ILoglogAnnotationmethod。getAnnotation(ILog。class);if(logAnnotation!null){log。setOperation(logAnnotation。value());}StringclassNamepoint。getTarget()。getClass()。getName();StringmethodNamemethodSignature。getName();log。setMethod(className。methodName());获取方法的参数Object〔〕argspoint。getArgs();LocalVariableTableParameterNameDiscovererlnewLocalVariableTableParameterNameDiscoverer();String〔〕parameterNamesl。getParameterNames(method);if(args!nullparameterNames!null){StringBuilderparamnewStringBuilder();for(inti0;iargs。length;i){param。append()。append(parameterNames〔i〕)。append(:)。append(args〔i〕);}log。setParams(param。toString());}ServletRequestAttributesattributes(ServletRequestAttributes)RequestContextHolder。getRequestAttributes();HttpServletRequestrequestattributes。getRequest();log。setIp(request。getRemoteAddr());log。setUserId(ThreadLocalUtils。get());log。setCostTime(costTime);log。setCreateTime(LocalDateTime。now());logService。save(log);}} 因为我使用的是Mybatisplus,所以logService。save(log);是mybatisplus原生的saveoperation 这步其实就是把log插入到数据库 6、使用 只需要在方法上加上ILog注解,并设置它的value即可(value就是描述当前method作用)packagecom。xiaofengstu。mcams。web。controller;importcom。baomidou。mybatisplus。core。conditions。query。QueryWrapper;importcom。xiaofengstu。mcams。annotation。ILog;importcom。xiaofengstu。mcams。dto。BasicResultDTO;importcom。xiaofengstu。mcams。enums。RespStatusEnum;importcom。xiaofengstu。mcams。web。entity。TDept;importcom。xiaofengstu。mcams。web。service。TDeptService;importlombok。RequiredArgsConstructor;importorg。springframework。web。bind。annotation。GetMapping;importorg。springframework。web。bind。annotation。RequestMapping;importorg。springframework。web。bind。annotation。RequestParam;importorg。springframework。web。bind。annotation。RestController;importjava。util。List;p前端控制器authorfengzengsince20220507RestControllerRequestMapping(webdept)RequiredArgsConstructorpublicclassTDeptController{privatefinalTDeptServicedeptService;ILog(获取部门列表)GetMapping(list)publicBasicResultDTOListTDeptgetDeptListByCampId(RequestParam(campusId)IntegercampusId){returnnewBasicResultDTO(RespStatusEnum。SUCCESS,deptService。list(newQueryWrapperTDept()。eq(campusid,campusId)));}ILog(通过角色获取部门列表)GetMapping(listByRole)publicBasicResultDTOListTDeptgetDeptListByRole(){returnnewBasicResultDTO(RespStatusEnum。SUCCESS,deptService。listByRole());}} 数据库: 总结 如果要对现有代码进行功能扩展,使用AOP注解不妨为一种优雅的方式 对AOP不熟悉的小伙伴,可以深入了解一下,毕竟是spring最重要的特性之一。