作者:一夕十六川
希望本篇内容能对大家有所帮助
一、jpa自动填充字段
实体类
@Data
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = -47539914963692882L;
/**
* 主键id
*/
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* 姓名
*/
@Column(name = "name")
private String name;
/**
* 登录账号
*/
@Column(name = "login_name")
private String loginName;
/**
* 登录密码
*/
@Column(name = "password")
private String password;
/**
* 创建人id
*/
private Integer createUserId;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新人id
*/
@Column(name = "update_user_id")
private Integer updateUserId;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
以上实体中 创建人、创建时间、更新人、更新时间是我们想要自动填充的字段
我们可以使用监听器来填充上述四个字段
字段填充监听器
@Component
@Log4j2
public class DataBaseAuditListener {
/**
* 新增数据时,填充创建人和创建时间
*/
@PrePersist
public void prePersist(Object object)
throws IllegalArgumentException, IllegalAccessException {
// 如果填充字段被分装在一个父类中: Class<?> aClass = object.getClass().getSuperclass();
Class<?> aClass = object.getClass();
try {
// 填充创建用户Id
addUserId(object, aClass, "createUserId");
// 填充创建时间
addOperateTime(object, aClass, "createTime");
} catch (NoSuchFieldException e) {
log.error("反射获取属性异常:", e);
}
}
/**
* 更新数据时,填充更新人和更新时间
*/
@PreUpdate
public void preUpdate(Object object)
throws IllegalArgumentException, IllegalAccessException {
Class<?> aClass = object.getClass();
try {
// 填充更新用户Id
addUserId(object, aClass, "updateUserId");
// 填充更新时间
addOperateTime(object, aClass, "updateTime");
} catch (NoSuchFieldException e) {
log.error("反射获取属性异常:", e);
}
}
/**
* 新增数据之后的操作
*/
@PostPersist
public void postPersist(Object object)
throws IllegalArgumentException, IllegalAccessException {
}
/**
* 更新数据之后的操作
*/
@PostUpdate
public void postUpdate(Object object)
throws IllegalArgumentException, IllegalAccessException {
}
/**
* 填充用户id
*
* @param object
* @param aClass
* @param propertyName 属性名(对应实体类中的属性)
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
protected void addUserId(Object object, Class<?> aClass, String propertyName) throws NoSuchFieldException, IllegalAccessException {
Field userId = aClass.getDeclaredField(propertyName);
userId.setAccessible(true);
// 获取userId值
Object userIdValue = userId.get(object);
if (userIdValue == null) {
// 在此处使用当前用户id或默认用户id
Integer id = CommonData.userId;
userId.set(object, id);
}
}
/**
* 填充操作时间
*
* @param object
* @param aClass
* @param propertyName 属性名(对应实体类中的属性)
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
protected void addOperateTime(Object object, Class<?> aClass, String propertyName) throws NoSuchFieldException, IllegalAccessException {
Field time = aClass.getDeclaredField(propertyName);
time.setAccessible(true);
// 获取time值
Object createdTimeValue = time.get(object);
if(createdTimeValue == null) {
// 使用当前时间进行填充
time.set(object, new Date());
}
}
}
在想要自动填充属性的实体类上加注解@EntityListeners
@EntityListeners(DataBaseAuditListener.class)
public class User implements Serializable {
// 实体内容省略
...
}
服务类中的保存方法
@Override
public void save(User user) {
userDao.save(user);
}
我们来测试一下:
创建成功:
更新成功:
至此,jpa字段填充完成
但是这时也出现了新的问题:
创建人和创建时间消失了
这是因为jpa在更新时将所有字段全部更新了,即使字段传了null值
这时就需要用到第二部分内容了
二、jpa忽略更新字段
为了避免创建人和创建时间被覆盖,我们需要改进一下实体类:
在@Column注解中使用updatable = false
/**
* 创建人id
*/
@Column(name = "create_user_id", updatable = false)
private Integer createUserId;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Column(name = "create_time", updatable = false)
private Date createTime;
这时再更新实体,就不会更新创建人和创建时间这两个属性了