service 层代码:
import org.springframework.beans.BeanUtils;
import javax.transaction.Transactional;
@Transactional
public User update( User user ){
User userInDB = findById( user.getId() );
BeanUtils.copyProperties( user, userInDB, CommonUtils.getNullPropertyNames(user) );
return userDAO.save( userInDB ); // 注意 save 的参数是 userInDB,而不是 user
}
// BeanUtils.copyProperties( sourceBean, targetBean, ignoreProperties ) 方法的作用是:Copy the property values of the given source bean into the given target bean, ignoring the given "ignoreProperties".
------------------------
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
public class CommonUtils {
// get Null Property Names, return String[] 挑出 bean 里空的属性,返回属性名的数组
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) {
emptyNames.add(pd.getName());
}
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
}
用以上方法可以实现对象属性动态更新进数据库
2019-2-1 今天发现上面这种网上找来的实现 jpa 动态更新实体类属性的方法存在问题:如果页面里把一个属性修改为 null,提交到后台进行修改,用这种方法会漏掉改为 null 的属性。
所以需要修改写法,把数据库里没有传到前台的属性(本例子中是 createDate 和 status)查出来,设置到前台传回到后台的对象里,避免更新操作后,这类字段变为 null。
修改后写法为:
service 层代码:
@Transactional
public User update(User user){
user.setUpdateDate(new Date());
// 把数据库里没有传到前台的属性获取出来,设置到前台传回来的 user 对象里
User userInDB = findById(user.getId());
user.setCreateDate(userInDB.getCreateDate());
user.setStatus(userInDB.getStatus());
return userDAO.save(user); // user 对象只要包含 id,就能实现更新效果
}