Spring Boot 中的审计(Auditing)功能

审计(Auditing)在 Spring Boot 中指的是自动跟踪和管理应用程序中实体的创建和修改的能力。它是一个强大的功能,提供了有关数据生命周期的宝贵信息,例如谁创建或最后修改了记录以及这些操作发生的时间。这对于需要问责、可追溯性和符合审计标准的应用程序尤其有用。

关键注解

  1. @CreatedDate:用于标记实体类中的字段,该字段应在实体创建时自动填充日期和时间。

  2. @LastModifiedDate:用于标记实体类中的字段,该字段应在实体最后修改时自动更新日期和时间。

  3. @CreatedBy:用于标记实体类中的字段,该字段应填充创建实体的用户。这需要自定义实现来提供用户信息。

  4. @LastModifiedBy:用于标记实体类中的字段,该字段应更新为最后修改实体的用户。这也需要自定义实现来提供用户信息。

实现示例

让我们创建一个简单的 Spring Boot 应用程序,演示如何使用上述注解进行审计。我们将构建一个简单的“用户”实体,跟踪谁创建和修改了它,以及何时进行的操作。

第一步:设置 Spring Boot 应用程序

  1. 使用 Spring Initializr 创建一个新的 Spring Boot 项目,并添加以下依赖项:

    • Spring Web

    • Spring Data JPA

    • H2 数据库(用于测试)

    • Spring Boot DevTools

应用程序结构

以下是应用程序的简要结构:

src
└── main
    └── java
        └── com
            └── example
                └── demo
                    ├── DemoApplication.java
                    ├── config
                    │   └── AuditingConfig.java
                    ├── controller
                    │   └── UserController.java
                    ├── entity
                    │   └── User.java
                    └── repository
                        └── UserRepository.java
└── resources
    ├── application.properties
    └── data.sql

第二步:定义用户实体

创建一个带有审计注解的 User 实体。

import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@EntityListeners(AuditingEntityListener.class)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @CreatedDate
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime lastModifiedDate;

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String lastModifiedBy;

    // Getters and Setters

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LocalDateTime getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(LocalDateTime createdDate) {
        this.createdDate = createdDate;
    }

    public LocalDateTime getLastModifiedDate() {
        return lastModifiedDate;
    }

    public void setLastModifiedDate(LocalDateTime lastModifiedDate) {
        this.lastModifiedDate = lastModifiedDate;
    }

    public String getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(String createdBy) {
        this.createdBy = createdBy;
    }

    public String getLastModifiedBy() {
        return lastModifiedBy;
    }

    public void setLastModifiedBy(String lastModifiedBy) {
        this.lastModifiedBy = lastModifiedBy;
    }
}
  • @Entity:指定该类是一个实体,并映射到数据库表。

  • @EntityListeners(AuditingEntityListener.class):启用实体的审计功能。

  • @Id 和 @GeneratedValue:指定主键及其生成策略。

  • @CreatedDate 和 @LastModifiedDate:自动设置创建和修改时间戳。

  • @CreatedBy 和 @LastModifiedBy:自动设置创建或最后修改实体的用户。


第三步:启用审计

创建一个配置类以启用 JPA 审计。

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import java.util.Optional;

@Configuration
@EnableJpaAuditing
public class AuditingConfig {

    @Bean
    public AuditorAware<String> auditorProvider() {
        return () -> Optional.of("system"); // You can replace "system" with the actual user
    }
}
 
  • @Configuration:指定该类包含应用程序的配置。

  • @EnableJpaAuditing:启用 JPA 审计。

  • auditorProvider():提供一个 AuditorAware bean,返回当前用户。在此示例中,它始终返回 “system”。

第四步:为用户实体创建存储库

为 User 实体创建一个存储库接口。

package com.example.demo.repository;

import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {

@Transactional
@Modifying
@Query("UPDATE User u SET u.name = :name, u.lastModifiedDate = CURRENT_TIMESTAMP, u.lastModifiedBy = :modifiedBy WHERE u.id = :id")
int updateUserName(@Param("id") Long id, @Param("name") String name, @Param("modifiedBy") String modifiedBy);

}

 

第五步:为用户实体创建控制器

创建一个控制器来处理 HTTP 请求。

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userRepository.save(user);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User userDetails) {
        User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
        user.setName(userDetails.getName());
        return userRepository.save(user);
    }

    // or

    // you can native query also
   // @PutMapping("/{id}")
   // public User updateUser(@PathVariable Long id, @RequestBody User userDetails) {
   //     int rowsUpdated = userRepository.updateUserName(id, userDetails.getName(), "system");
   //     if (rowsUpdated == 0) {
   //         throw new RuntimeException("User not found");
   //     }
    //    return userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
   // }
}

第六步:使用 Postman 进行测试

  1. 启动应用程序:运行 Spring Boot 应用程序。

  2. 创建用户

    • URL: POST http://localhost:8080/users

    • Body:

      {
        "name": "John Doe"
      }
    • 响应:

      {
        "id": 1,
        "name": "John Doe",
        "createdDate": "2023-10-10T10:00:00",
        "lastModifiedDate": "2023-10-10T10:00:00",
        "createdBy": "system",
        "lastModifiedBy": "system"
      }
  3. 更新用户

    • URL: PUT http://localhost:8080/users/1

    • Body:

      {
        "name": "Jane Doe"
      }
    • 响应:

      {
        "id": 1,
        "name": "Jane Doe",
        "createdDate": "2023-10-10T10:00:00",
        "lastModifiedDate": "2023-10-10T10:05:00",
        "createdBy": "system",
        "lastModifiedBy": "system"
      }

总结

通过使用 Spring Boot 的审计功能,你可以轻松地跟踪实体的创建和修改时间以及操作者。这对于需要记录数据变更历史的应用场景非常有用,例如合规性审计、数据追踪等。通过结合 @CreatedDate@LastModifiedDate@CreatedBy 和 @LastModifiedBy 注解,你可以实现强大的审计功能,而无需编写大量代码。

请登录后发表评论

    没有回复内容