当前位置:网站首页>Auditing相关注解
Auditing相关注解
2022-07-25 17:50:00 【InfoQ】
Auditing 指的是什么?
- @CreatedBy 是哪个用户创建的。
- @CreatedDate 创建的时间。
- @LastModifiedBy 最后修改实体的用户。
- @LastModifiedDate 最后一次修改的时间。
Auditing 如何实现?
第一种方式:直接在实例里面添加上述四个注解
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "addresses")
@EntityListeners(AuditingEntityListener.class)
public class User implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
private String name;
private String email;
@Enumerated(EnumType.STRING)
private SexEnum sex;
private Integer age;
@OneToMany(mappedBy = "user")
@JsonIgnore
private List<UserAddress> addresses;
private Boolean deleted;
@CreatedBy
private Integer createUserId;
@CreatedDate
private Date createTime;
@LastModifiedBy
private Integer lastModifiedUserId;
@LastModifiedDate
private Date lastModifiedTime;
}
@CreatedBy
private Integer createUserId;
@CreatedDate
private Date createTime;
@LastModifiedBy
private Integer lastModifiedUserId;
@LastModifiedDate
private Date lastModifiedTime;
@EntityListeners(AuditingEntityListener.class)
public class MyAuditorAware implements AuditorAware<Integer> {
//需要实现AuditorAware接口,返回当前的用户ID
@Override
public Optional<Integer> getCurrentAuditor() {
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Integer userId = (Integer) servletRequestAttributes.getRequest().getSession().getAttribute("userId");
return Optional.ofNullable(userId);
}
}
public interface AuditorAware<T> {
T getCurrentAuditor();
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
Integer userId = ((LoginUserInfo) authentication.getPrincipal()).getUser().getId();
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(JpaAuditingRegistrar.class)
public @interface EnableJpaAuditing {
//auditor用户的获取方法,默认是找AuditorAware的实现类;
String auditorAwareRef() default "";
//是否在创建修改的时候设置时间,默认是true
boolean setDates() default true;
//在创建的时候是否同时作为修改,默认是true
boolean modifyOnCreate() default true;
//时间的生成方法,默认是取当前时间(为什么提供这个功能呢?因为测试的时候有可能希望时间保持不变,它提供了一种自定义的方法);
String dateTimeProviderRef() default "";
}
@Configuration
@EnableJpaAuditing
public class JpaConfiguration {
@Bean
@ConditionalOnMissingBean(name = "myAuditorAware")
MyAuditorAware myAuditorAware() {
return new MyAuditorAware();
}
}
- 这里说一个 Congifuration 的最佳实践的写法。我们为什么要单独写一个JpaConfiguration的配置文件,而不是把@EnableJpaAuditing 放在 JpaApplication 的类里面呢?因为这样的话 JpaConfiguration 文件可以单独加载、单独测试,如果都放在 Appplication 类里面的话,岂不是每次测试都要启动整个应用吗?
- MyAuditorAware 也可以通过 @Component 注解进行加载,我为什么推荐 @Bean 的方式呢?因为这种方式可以让使用的人直接通过我们的配置文件知道我们自定义了哪些组件,不会让用的人产生不必要的惊讶,这是一点写 framework 的经验,供你参考。
@DataJpaTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Import(JpaConfiguration.class)
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@MockBean
MyAuditorAware myAuditorAware;
@Test
public void testAuditing() {
//由于测试用例模拟web context环境不是我们的重点,我们这里利用@MockBean,mock掉我们的方法,期待返回13这个用户ID
Mockito.when(myAuditorAware.getCurrentAuditor()).thenReturn(Optional.of(13));
//我们没有显式的指定更新时间、创建时间、更新人、创建人
User user = User.builder()
.name("jack")
.email("[email protected]")
.sex(SexEnum.BOY)
.age(20)
.build();
userRepository.save(user);
//验证是否有创建时间、更新时间,UserID是否正确;
List<User> users = userRepository.findAll();
Assertions.assertEquals(13,users.get(0).getCreateUserId());
Assertions.assertNotNull(users.get(0).getLastModifiedTime());
System.out.println(users.get(0));
}
}
- 我们利用 @MockBean 模拟 MyAuditorAware 返回结果 13 这个 UserID;
- 我们测试并验证 create_user_id 是否是我们预期的。
User(id=1, name=jack, [email protected], sex=BOY, age=20, deleted=null, createUserId=13, createTime=Sat Oct 03 21:19:57 CST 2020, lastModifiedUserId=13, lastModifiedTime=Sat Oct 03 21:19:57 CST 2020)
第二种方式:实体里面实现Auditable 接口
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "addresses")
@EntityListeners(AuditingEntityListener.class)
public class User implements Auditable<Integer,Long, Instant> {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
private String name;
private String email;
@Enumerated(EnumType.STRING)
private SexEnum sex;
private Integer age;
@OneToMany(mappedBy = "user")
@JsonIgnore
private List<UserAddress> addresses;
private Boolean deleted;
private Integer createUserId;
private Instant createTime;
private Integer lastModifiedUserId;
private Instant lastModifiedTime;
@Override
public Optional<Integer> getCreatedBy() {
return Optional.ofNullable(this.createUserId);
}
@Override
public void setCreatedBy(Integer createdBy) {
this.createUserId = createdBy;
}
@Override
public Optional<Instant> getCreatedDate() {
return Optional.ofNullable(this.createTime);
}
@Override
public void setCreatedDate(Instant creationDate) {
this.createTime = creationDate;
}
@Override
public Optional<Integer> getLastModifiedBy() {
return Optional.ofNullable(this.lastModifiedUserId);
}
@Override
public void setLastModifiedBy(Integer lastModifiedBy) {
this.lastModifiedUserId = lastModifiedBy;
}
@Override
public void setLastModifiedDate(Instant lastModifiedDate) {
this.lastModifiedTime = lastModifiedDate;
}
@Override
public Optional<Instant> getLastModifiedDate() {
return Optional.ofNullable(this.lastModifiedTime);
}
@Override
public boolean isNew() {
return id==null;
}
}
第三种方式:利用 @MappedSuperclass 注解

package com.example.jpa.example1.base;
import org.springframework.data.annotation.*;
import javax.persistence.MappedSuperclass;
import java.time.Instant;
@Data
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {
@CreatedBy
private Integer createUserId;
@CreatedDate
private Instant createTime;
@LastModifiedBy
private Integer lastModifiedUserId;
@LastModifiedDate
private Instant lastModifiedTime;
}
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "addresses")
public class User extends BaseEntity {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
private String name;
private String email;
@Enumerated(EnumType.STRING)
private SexEnum sex;
private Integer age;
@OneToMany(mappedBy = "user")
@JsonIgnore
private List<UserAddress> addresses;
private Boolean deleted;
}
- 去掉了 @EntityListeners(AuditingEntityListener.class);
- 去掉了 @CreatedBy、@CreatedDate、@LastModifiedBy、@LastModifiedDate 四个注解的公共字段。
边栏推荐
- I2C通信——时序图
- Tkinter module advanced operations (I) -- transparent buttons, transparent text boxes, custom buttons and custom text boxes
- Installation and operation instructions of SVN client (TortoiseSVN)
- How many points did NPDP pass? How to pass with high scores?
- Nineteen year old summary
- MySQL数据库常用命令
- SLA 、SLO & SLI
- [cadence Allegro PCB design] permanently modify the shortcut key (customized) ~ it is valid for personal test~
- Mock服务moco系列(一)- 简介、第一个Demo、Get请求、Post请求
- Ultimate doll 2.0 | cloud native delivery package
猜你喜欢

Sorting also needs to know the information and linked list

自动化测试 PO设计模型

SVN客户端(TortoiseSVN)安装及使用说明

Tkinter module advanced operations (I) -- transparent buttons, transparent text boxes, custom buttons and custom text boxes

Lwip之内存与包缓冲管理

Food safety | eight questions and eight answers take you to know crayfish again! This is the right way to eat!

2022/7/23

Redis源码与设计剖析 -- 15.RDB持久化机制

【解决方案】Microsoft Edge 浏览器 出现“无法访问该页面”问题

I'm also drunk. Eureka delayed registration and this pit!
随机推荐
I'm also drunk. Eureka delayed registration and this pit!
2022/7/23
Creation of unity Bezier curve
我也是醉了,Eureka 延迟注册还有这个坑!
OSPF---开放式最短优先路径协议
2022/7/23
走马卒
PHP解决并发问题的几种实现
Dating activity records
Ultimate doll 2.0 | cloud native delivery package
Notes on Flickr's dataset
交友活动记录
【解决方案】Microsoft Edge 浏览器 出现“无法访问该页面”问题
ROS learning notes (IV) ROS cannot solve rosdep init or update
[Hardware Engineer] can't select components?
电子产品“使用”和“放置”哪个寿命更长??
Take you to a preliminary understanding of multiparty secure computing (MPC)
Tme2022 campus recruitment background development / operation development / business operation and maintenance / application development written examination (I) a little self analysis of programming q
绘制pdf表格 (二) 通过itext实现在pdf中绘制excel表格样式设置中文字体、水印、logo、页眉、页码
What financial products can you buy to make money with only 1000 yuan?