范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

我使用SpringAOP实现了用户操作日志功能

  今天项目完了,复盘了一下系统,发现还是有一些东西值得拿出来和大家分享一下。需求分析
  系统需要对用户的操作进行记录,方便未来溯源
  首先想到的就是在每个方法中,去实现记录的逻辑,但是这样做肯定是不现实的,首先工作量大,其次违背了软件工程设计原则(开闭原则)
  这种需求显然是对代码进行增强,首先想到的是使用 SpringBoot 提供的 AOP 结合注解的方式来实现 功能实现1、 需要一张记录日志的 Log 表
  导出的 sql 如下:-- mcams.t_log definition  CREATE TABLE `t_log` (   `log_id` int NOT NULL AUTO_INCREMENT COMMENT "日志编号",   `user_id` int NOT NULL COMMENT "操作人id",   `operation` varchar(128) NOT NULL COMMENT "用户操作",   `method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT "操作的方法",   `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT "方法的参数",   `ip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT "用户的ip",   `create_time` timestamp NULL DEFAULT NULL COMMENT "操作时间",   `cost_time` int DEFAULT NULL COMMENT "花费时间",   PRIMARY KEY (`log_id`) ) ENGINE=InnoDB AUTO_INCREMENT=189 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;2、我使用的是 Spring Boot 所以需要引入 spring aop 的 starter#                     org.springframework.boot             spring-boot-starter-aop         
  如果是使用 spring 框架的,引入 spring-aop 即可 3、Log 实体类#package com.xiaofengstu.mcams.web.entity;  import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.time.LocalDateTime;  import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Getter; import lombok.Setter;  /**  * 

* * * * @author fengzeng * @since 2022-05-21 */ @Getter @Setter @TableName("t_log") public class TLog implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "log_id", type = IdType.AUTO) private Integer logId; /** * 操作人id */ @TableField("user_id") private Integer userId; /** * 用户操作 */ @TableField("operation") private String operation; @TableField("method") private String method; @TableField("params") private String params; @TableField("ip") private String ip; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField("create_time") private LocalDateTime createTime; @TableField("cost_time") private Long costTime; }   需要 lombok 插件(@getter && @setter 注解) 4、ILog 注解#package com.xiaofengstu.mcams.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Author FengZeng * @Date 2022-05-21 00:48 * @Description TODO */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ILog { String value() default ""; }5、切面类 LogAspect#package com.xiaofengstu.mcams.aspect; import com.xiaofengstu.mcams.annotation.ILog; import com.xiaofengstu.mcams.util.ThreadLocalUtils; import com.xiaofengstu.mcams.web.entity.TLog; import com.xiaofengstu.mcams.web.service.TLogService; import lombok.RequiredArgsConstructor; 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.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.time.LocalDateTime; /** * @Author FengZeng * @Date 2022-05-21 00:42 * @Description TODO */ @Aspect @Component @RequiredArgsConstructor public class LogAspect { private final TLogService logService; @Pointcut("@annotation(com.xiaofengstu.mcams.annotation.ILog)") public void pointcut() { } @Around("pointcut()") public Object around(ProceedingJoinPoint point) { Object result = null; long beginTime = System.currentTimeMillis(); try { result = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } long costTime = System.currentTimeMillis() - beginTime; saveLog(point, costTime); return result; } private void saveLog(ProceedingJoinPoint point, long costTime) { // 通过 point 拿到方法签名 MethodSignature methodSignature = (MethodSignature) point.getSignature(); // 通过方法签名拿到被调用的方法 Method method = methodSignature.getMethod(); TLog log = new TLog(); // 通过方法区获取方法上的 ILog 注解 ILog logAnnotation = method.getAnnotation(ILog.class); if (logAnnotation != null) { log.setOperation(logAnnotation.value()); } String className = point.getTarget().getClass().getName(); String methodName = methodSignature.getName(); log.setMethod(className + "." + methodName + "()"); // 获取方法的参数 Object[] args = point.getArgs(); LocalVariableTableParameterNameDiscoverer l = new LocalVariableTableParameterNameDiscoverer(); String[] parameterNames = l.getParameterNames(method); if (args != null && parameterNames != null) { StringBuilder param = new StringBuilder(); for (int i = 0; i < args.length; i++) { param.append(" ").append(parameterNames[i]).append(":").append(args[i]); } log.setParams(param.toString()); } ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); log.setIp(request.getRemoteAddr()); log.setUserId(ThreadLocalUtils.get()); log.setCostTime(costTime); log.setCreateTime(LocalDateTime.now()); logService.save(log); } }   因为我使用的是 Mybatis-plus,所以 logService.save(log); 是 mybatis-plus 原生的 save operation   这步其实就是把 log 插入到数据库   6、使用   只需要在方法上加上 @ILog 注解,并设置它的 value 即可(value 就是描述当前 method 作用) package com.xiaofengstu.mcams.web.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xiaofengstu.mcams.annotation.ILog; import com.xiaofengstu.mcams.dto.BasicResultDTO; import com.xiaofengstu.mcams.enums.RespStatusEnum; import com.xiaofengstu.mcams.web.entity.TDept; import com.xiaofengstu.mcams.web.service.TDeptService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** *

* 前端控制器 * * * @author fengzeng * @since 2022-05-07 */ @RestController @RequestMapping("/web/dept") @RequiredArgsConstructor public class TDeptController { private final TDeptService deptService; @ILog("获取部门列表") @GetMapping("/list") public BasicResultDTO> getDeptListByCampId(@RequestParam("campusId") Integer campusId) { return new BasicResultDTO(RespStatusEnum.SUCCESS, deptService.list(new QueryWrapper().eq("campus_id", campusId))); } @ILog("通过角色获取部门列表") @GetMapping("/listByRole") public BasicResultDTO> getDeptListByRole() { return new BasicResultDTO<>(RespStatusEnum.SUCCESS, deptService.listByRole()); } }   数据库:   总结   如果要对现有代码进行功能扩展,使用 AOP + 注解不妨为一种优雅的方式   对 AOP 不熟悉的小伙伴,可以深入了解一下,毕竟是 spring 最重要的特性之一。


区块链暴跌,LUNA,NFT,大饼,到底何去何从仅仅提供参考,不建议投资理财!从区块链的诞生,区块链一直就在生与死之中徘徊。区块链本次由于LUNA带动死亡螺旋,整个区块链下跌趋势十分明显。但同时,在韩国依旧有很多人相信LUNA会架构师必备多维度查询的最佳实践背景有2种常见的多维度查询场景,分别是带多个筛选条件的列表查询不含分库分表列的其他维度查询普通的数据库查询,很难实现上述需求场景,更不用提模糊查询全文检索了。下面结合楼主的经验和知从0到1体验JenkinsDockerGitRegistry实现CI自动化发布阅读目录一前言二发布流程三环境准备四部署思路梳理五三台机器上操作六Git机器上操作七Docker机器上操作八Jenkins机器上操作九上传JAVA项目代码到Git仓库十JenkinJAVA语法算术运算符2。1算术运算符2。1。1运算符和表达式(了解)运算符对常量或者变量进行操作的符号表达式用运算符把常量或者变量连接起来符合java语法的式子就可以称为表达式。不同运算符连接的表达式Linux下C程序符号延迟绑定动态库使用方式分为隐式链接(隐式加载),编译时通过编译选项指定动态库显式链接(显式加载),通过代码调用dlopendlsymdlclose指定动态库动态库的符号解析分为立即绑定延迟笔记本电脑需求正旺!盘点三款热门轻薄本,好评率都在90以上进入5月份以后,笔记本电脑市场呈现了一番热闹景象,不仅有各路新品上市,许多经典产品也迎来了较大幅度的降价,尤其是这段时间不少地方的防疫措施严格,居家办公和学习的用户明显增多,这也进IP猫腻被曝光,各大平台下架忙文法人杂志全媒体记者姚瑶近半个月来,随着多个互联网平台公开显示IP属地,不少账号频频翻车。某些海外代购账号,其实IP属地在国内一些本地网红账号,其运营地相隔十万八千里。为应对显示IiPhone15或将采用USBC接口比特币跌破2。7万美元,为16个月最低iPhone15或将采用USBC接口5月11日,郭明錤发布推文称,苹果计划在2023年下半年发布的iPhone15产品线中使用usbc接口,并放弃自己的lightning接口。他认索尼佳能尼康松下和富士等微单,各有什么缺点和不足?现在购买微单的小伙伴们越来越多了,不过毕竟微单属于高价格商品,而且各种不同的型号品牌存在着很大的差异,为了尽量多地全面了解自己所要购买型号的特点,很多小伙伴都从各种渠道去多方面了解vivoS系列再添新人,打造新一代的年轻人潮品vivo的旗下拥有许多价位覆盖面很广的机型,在经过了4月的旗舰推出高潮之后,在5月又带来了全新的vivoS15系列新品。就在今天,vivo官博发布了关于新品的全家福海报,这似乎意味EUV光刻机,中科院官宣,这相当于确认了当芯片的制造工艺进入到7纳米或者5纳米时,就需要EUV光刻机上场,到不是因为DUV光刻机无法完成制造任务,主要是考虑到商业成本,EUV光刻机是一个更好的选择。所以从商业量产的角度来
如果倪光南院士加入华为,强强联合,能够超越最大芯片玩家英特尔吗?倪光南作为1名院士,在从联想出局后加入华为至今,很可能华为也是现在这样,也是部分拥有自主性关键核心技术和世界第一,但,联想及其原掌门恐怕藉藉无名,说不定懊悔不已。谈不上强强联合,院英特尔致信供应商禁用新疆产品头部消息1英特尔致信供应商禁用新疆产品12月21日查询英特尔官网发现,该公司以简体中文繁体中文英语日语等语言向供应商写信称,英特尔需要确保其供应链不使用任何来自新疆地区的劳工采购产为什么我感受不到1500元的手机比四五千的差?就是小青年玩游戏的事,不玩游戏的人,啥价位的也一样等你买了四五千的手机后就感受到了我干过PCB板电镀的工作,就是手机啊电脑啊里面的电路板的加工工作。同一条生产线,上1500的手机板国产电动车又遭断供,欧美垄断核心雷达芯片,我们该如何出手突围现在对于电动车的使用可以说极其的广泛,尤其在现在提倡环境保护的同时,电动车还具有节能的特点,尤其它不会像电动车一样耗费非常多的油,做到了对环境的保护,再加上大家使用它出行也更加的便倪光南正式发声,阿里已经行动,华为该做出选择了文C君科讯排版C君科讯头条号原创文章,禁止抄袭,违者必究倪光南正式发声倪光南院士一直以来都是专注于技术发展的科学家,在联想任职期间,更是帮助联想开发出了联想汉卡,帮助国内用户解决了从这件事就能看出华为为什么能做到今天的成就任正非说,2001年当时就想把华为卖掉。为什么要卖掉华为?原因就是为了避免和米国碰撞。当时华为和摩托罗拉已经达成了协议,摩托罗拉出100亿美元收购华为。当时摩托罗拉的董事长是高尔文假如中国有一百个联想,会怎么样?这个问题提的好,我想,假如中国有一百个联想,不用美国打压,中国经济会彻底的沦为西方附属加工厂了。联想的经营理念在改革开放初期无可厚非,但在现在国际形势下,该让它进入历史了。我这样说助听器常见误区有哪些?常见的误区有一大声说还能听见,不用戴助听器。不少人不愿承认自己听力有问题,总认为自己听力还行,家人大声说话还能听见,看电视时,将电视音量开大也能听见,不需要佩戴助听器。实际上,只要传导性耳聋戴助听器要注意什么?传导性耳聋戴助听器要注意传导性耳聋听力一般不超过60dBnHL。传导性耳聋患者选配助听器时要注意首先要到医院就诊,通过治疗后听力稳定无波动再进行助听器验配,传导性耳聋声增益的要求相薇娅直播间凉凉了,那么她身后的那些工厂怎么办?没有薇娅的时候,难道没有工厂吗?她是太阳还是空气?一个偷税漏税的资本家而已!怎么被捧的那么高?还好国家税务查出她的违法行为了,不然巨额资金还不知道被转到哪里去!不过90亿的富豪而言关于手机麦克风产品使用动圈式咪芯或电容式咪芯都有哪些区别?动圈式咪芯或电容式咪芯由于声学结构,工作原理,材料组成的不同,往往应用在不同的场合。相对来说,动圈式咪芯一般体积较大,重量较重。灵敏度较低,基本上不需要电路配合,只需要通过简单的放