通过Annotation将用户操作记录到数据库表功能实现

这篇具有很好参考价值的文章主要介绍了通过Annotation将用户操作记录到数据库表功能实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、背景

        在用户对我们所开发的系统访问的时候,需要我们的系统具有强大的健壮性,使得给与用户的体验感十足。在业务开发的过程中,我们通过将几个相关的操作绑定成一个事件,使得安全性以及数据的前后一致性得到提高。但是在溯源方面,我们往往没有很好的解决方案,我们无法得知错误的具体信息,这给后期的debug带来了一定的负担,那么我们如果将用户的操作具体信息可以记录到数据库中,那么是不是就可以溯源了?

二、任务:将一个员工管理系统中的增删改相关接口的操作日志记录到数据库中。

三、实现

3.1 我们需要插入一个数据表:log代表着插入数据的格式(数据表中不需要有任何数据):

-- 操作日志表
create table operate_log(
    id int unsigned primary key auto_increment comment 'ID',
    operate_user int unsigned comment '操作人ID',
    operate_time datetime comment '操作时间',
    class_name varchar(100) comment '操作的类名',
    method_name varchar(100) comment '操作的方法名',
    method_params varchar(1000) comment '方法参数',
    return_value varchar(2000) comment '返回值',
    cost_time bigint comment '方法执行耗时, 单位:ms'
) comment '操作日志表';


除此之外,我们需要在pom文件中引入fastjson和aop的依赖:

<!--        aop依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

3.2 目录结构如下所示:

通过Annotation将用户操作记录到数据库表功能实现,JWT,java,springboot,Annotation,操作溯源,AOP

 3.3 首先我们需要定义一个操作类OperateLog

package com.bytedance.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
    private Integer id; //ID
    private Integer operateUser; //操作人ID
    private LocalDateTime operateTime; //操作时间
    private String className; //操作类名
    private String methodName; //操作方法名
    private String methodParams; //操作方法参数
    private String returnValue; //操作方法返回值
    private Long costTime; //操作耗时
}

3.4 其次我们需要定义一个注解文件Log

package com.bytedance.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) // 当前注解什么时候生效
@Target(ElementType.METHOD) // 注解有效的地方

//定义一个注解
public @interface Log {
}

3.5 接着我们定义一个LogAspect的切面,这一部分是将这些代码从主干(controller)中抽离出来,以便于复用和改动,如果我们在每个类或对象中都重复实现这些行为,那么会导致代码的冗余、复杂和难以维护。

package com.bytedance.aop;
import com.alibaba.fastjson.JSONObject;
import com.bytedance.mapper.OperateLogMapper;
import com.bytedance.pojo.OperateLog;
import com.bytedance.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Array;
import java.time.LocalDateTime;
import java.util.Arrays;

// 定义切面类
@Component
@Aspect // 这是一个切面类
@Slf4j
public class LogAspect {
    // 注入OperateLogMapper的bean对象
    @Autowired
    private OperateLogMapper operateLogMapper;
    @Autowired
    private HttpServletRequest request;
    // 定义一个通知方法
    @Around("@annotation(com.bytedance.anno.Log)") // 匹配的是方法上的加有Log注解的方法
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取操作人id - 当前登陆的员工的id 即获得请求头中的jwt令牌,解析
        String jwt = request.getHeader("token");
        Claims claims = JwtUtils.parseJWT(jwt);
        Integer operateUserId = (Integer) claims.get("id");
        // 操作时间
        LocalDateTime operateTime = LocalDateTime.now();
        // 操作类名
        String className = joinPoint.getTarget().getClass().getName();
        // 操作方法名
        String methodName = joinPoint.getSignature().getName();
        // 操作方法参数
//        String methodParams = joinPoint.getArgs().toString();注意不能这么写
        Object[] args = joinPoint.getArgs();
        String methodParams = Arrays.toString(args);
        // 方法开始时间
        long start = System.currentTimeMillis();
        // 调用原始方法运行
        Object res = joinPoint.proceed();
        // 方法返回值
        String returnValue = JSONObject.toJSONString(res);
        // 方法结束时间
        long end = System.currentTimeMillis();
        // 操作耗时
        long costTime = end - start;

        // 记录操作日志 需要调用OperateLogMapper中的insert方法,所以得注入bean对象
        OperateLog operateLog = new OperateLog(null , operateUserId,operateTime,className,methodName,methodParams,returnValue,costTime);
        operateLogMapper.insert(operateLog);
        log.info("AOP记录操作日志:{}",operateLog);
        return res;
    }
}

3.6 OperateLogMapper负责将改动的数据写入数据库中

package com.bytedance.mapper;

import com.bytedance.pojo.OperateLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface OperateLogMapper {

    //插入日志数据
    @Insert("insert into operate_log (operate_user, operate_time, class_name, method_name, method_params, return_value, cost_time) " +
            "values (#{operateUser}, #{operateTime}, #{className}, #{methodName}, #{methodParams}, #{returnValue}, #{costTime});")
    public void insert(OperateLog log);

}

3.7 最后将EmpController中需要记录日志的操作上打上@Log的标注即可。

package com.bytedance.controller;

import com.bytedance.anno.Log;
import com.bytedance.pojo.Emp;
import com.bytedance.pojo.PageBean;
import com.bytedance.pojo.Result;
import com.bytedance.service.DeptService;
import com.bytedance.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;

@RestController
@Slf4j
@RequestMapping("/emps")
public class EmpController {

    @Autowired
    private EmpService empService;

    @GetMapping
    public Result page(@RequestParam(defaultValue = "1") Integer page ,
                       @RequestParam(defaultValue = "10") Integer pageSize,
                       String name, Short gender, @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin , @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("分页参数为:{},{},{},{},{},{}",page,pageSize,name,gender,begin,end);
        PageBean pageBean = empService.page(page,pageSize,name,gender,begin,end);
        return Result.success(pageBean);
    }

    // 批量删除员工信息
    @Log
    @DeleteMapping("/{ids}")
    public Result delete(@PathVariable List<Integer> ids){
        log.info("批量删除员工参数为:{}",ids);
        empService.delete(ids);
        return Result.success();
    }

    // 添加员工信息
//    @PostMapping
//    public Result add(@RequestBody Emp emp){
//        log.info("新增员工信息为:{emp}",emp);
//        empService.add(emp);
//        return Result.success();
//    }

    // 根据id查询员工信息
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id){
        log.info("根据ID查询员工信息:{}",id);
        Emp emp = empService.getById(id);
        return Result.success(emp);
    }


    // 修改员工信息
    @Log
    @PutMapping
    public Result update(@RequestBody Emp emp){
        log.info("前端传过来的员工信息:{}",emp);
        empService.update(emp);
        return Result.success();
    }

}

尝试一下,成功! 

通过Annotation将用户操作记录到数据库表功能实现,JWT,java,springboot,Annotation,操作溯源,AOP

注:1、记得将引入的包名换成自己的名字。

2、如果在LogAspect切面中报错,可能你没有jwt的实现类

package com.bytedance.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;

public class JwtUtils {

    private static String signKey = "itheima";
    private static Long expire = 432000000L; // 240小时候过期

    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS256, signKey)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}

3、如果这里的params对象是这样的,那可能是切面中获取params的方法写的不对:

通过Annotation将用户操作记录到数据库表功能实现,JWT,java,springboot,Annotation,操作溯源,AOP文章来源地址https://www.toymoban.com/news/detail-839460.html

 // 操作方法参数
//        String methodParams = joinPoint.getArgs().toString();注意不能这么写
        Object[] args = joinPoint.getArgs();
        String methodParams = Arrays.toString(args);

到了这里,关于通过Annotation将用户操作记录到数据库表功能实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java--用户登录/注册界面(连接Mysql数据库)并可以通过验证码登录

    1 效果展示 (1)登录界面 (2)注册界面 (3)动图展示 2 内容说明 (1)开发前,需引入一个连接Mysql 数据库驱动mysql-connector-java-5.1.30-bin.jar包 提取码:6666 (2)构建路径 (3)需要下载xampp软件 xampp软件下载 提取码:2255 xampp软件包含 Apache Web服务器、 Mysql Web服务器、Filezilla

    2024年02月09日
    浏览(60)
  • Oracle rac环境的数据库导入操作记录

    搞某一大项目的性能测试,将Oracle数据库dmp文件(211G)导入性能测试环境。 因为Oracle部署方式为rac,数据存储到共享磁盘。但由于对rac了解不足,这个过程中犯了两个错误: ① 表空间、临时表空间没有创建到共享磁盘,而是创建到了数据库服务本地磁盘; ② 发现应该创建

    2024年02月08日
    浏览(44)
  • Python 通过pymssql访问查询操作 SQL Server数据库

    在企业应用开发中,经常用到应用程序访问数据库的开发模式,中小企业使用的数据库中,以ms SQL Server居多。本文就以一个简单的实例模型,简单介绍一下python访问ms sql sever数据库的方法。 本文中以下面的本地SQL Server数据库为例进行数据库连接,数据表的查询、增加、删除

    2024年02月10日
    浏览(96)
  • 手把手教你实现:Android注册登录功能,通过本地服务器保存用户账号密码到数据库

    代码我放到文章最后面了 首先你需要电脑一台:如果没有电脑将会很难办呢 -----沃兹基硕德 下载并安装以下开发工具 Android Studio 官网最新版 用来开发 安卓App IntelliJ IDEA 官网最新版 用来开发 后端 ,处理安卓APP的请求 Navicat for MySql 官网最新版 数据库可视化工具,用来查看数

    2024年01月16日
    浏览(49)
  • java通过JDBC连接mysql8.0数据库,并对数据库中的表进行增删改查操作

    目录 一、JDBC简介 二、添加依赖 三、JDBC操作数据库的步骤 四、JDBC操作数据库——增删改查 (一)新增数据 (二)删除数据 (三)修改数据 (四)查询数据 (五)多表连接查询         Java数据库连接,(Java Database Connectivity,简称JDBC)是java语言中用来规范客户端程序如何来访问数

    2024年02月03日
    浏览(133)
  • MySQL 数据库查询与数据操作:使用 ORDER BY 排序和 DELETE 删除记录

    使用 ORDER BY 语句按升序或降序对结果进行排序。 ORDER BY 默认按升序排序。要按降序排序结果,使用 DESC 。 示例按名称按字母顺序排序结果: ORDER BY DESC 使用 DESC 以降序排序结果。 示例按名称以字母逆序排序结果: 您可以使用\\\"DELETE FROM\\\"语句从现有表格中

    2024年02月05日
    浏览(78)
  • Vue项目通过node连接MySQL数据库并实现增删改查操作

    1.创建Vue项目 Vue项目创建的详细步骤,有需要的可移步这里 2.下载安装需要的插件 下载express 下载cors,用于处理接口跨域问题 下载mysql 下载axios 3.在项目中创建server文件夹,用于搭建本地服务器 新建/server/app.js,用于配置服务器相关信息 新建/server/db/index.js,用于配置数据库

    2024年02月16日
    浏览(62)
  • Django学习记录:使用ORM操作MySQL数据库并完成数据的增删改查

    数据库操作 MySQL数据库+pymysql Django开发操作数据库更简单,内部提供了ORM框架。 安装第三方模块 ORM可以做的事: 1、创建、修改、删除数据库中的表(不用写SQL语句)。【无法创建数据库】 2、操作表中的数据(不用写SQL语句)。 1、自己创建数据库 1)启动MySQL服务 2)自带

    2024年02月14日
    浏览(59)
  • 通过Studio 3T对Mongodb进行 创建数据库/集合 增删查改集合文档操作

    首先 你需要安装Studio 3T 以及启动 Mongodb服务 具体可以参考我的文章 Studio 3T客户端连接Mongodb数据库服务 我们之前 通过 随便输切换是可以的 但除了这里能看到的 它们都仅存在于内存 我们右键顶部菜单 选择 添加数据库/创建数据库 这里 我们输入数据库名称 然后 点击OK 这样

    2024年02月01日
    浏览(58)
  • 通过一个实际例子说明Django中的数据库操作方法OneToOneField()的用法【数据表“一对一”关系】

    当我们在Django中定义一个模型时,可以使用 OneToOneField 来建立一个一对一的关系。这种关系表示两个模型之间的一种特殊关联,其中一个模型的实例只能与另一个模型的实例关联。 让我们以一个简单的示例来说明 OneToOneField 的用法。假设我们正在构建一个简单的博客应用,其

    2024年02月13日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包