美文网首页Spring Boot 从入门到上瘾
SpringBoot 实现JPA的save方法不更新null属性

SpringBoot 实现JPA的save方法不更新null属性

作者: 一只袜子 | 来源:发表于2018-05-12 01:55 被阅读80次

    序言:直接调用原生Save方法会导致null属性覆盖到数据库,使用起来十分不方便。本文提供便捷方法解决此问题。

    核心思路

    如果现在保存某User对象,首先根据主键查询这个User的最新对象,然后将此User对象的非空属性覆盖到最新对象。

    核心代码

    直接修改通用JpaRepository的实现类,然后在启动类标记此实现类即可。

    一、通用CRUD实现类
    public class SimpleJpaRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID> {
    
        private final JpaEntityInformation<T, ?> entityInformation;
        private final EntityManager em;
    
        @Autowired
        public SimpleJpaRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
            super(entityInformation, entityManager);
            this.entityInformation = entityInformation;
            this.em = entityManager;
        }
    
        /**
         * 通用save方法 :新增/选择性更新
         */
        @Override
        @Transactional
        public <S extends T> S save(S entity) {
            //获取ID
            ID entityId = (ID) entityInformation.getId(entity);
            Optional<T> optionalT;
            if (StringUtils.isEmpty(entityId)) {
                String uuid = UUID.randomUUID().toString();
                //防止UUID重复
                if (findById((ID) uuid).isPresent()) {
                    uuid = UUID.randomUUID().toString();
                }
                //若ID为空 则设置为UUID
                new BeanWrapperImpl(entity).setPropertyValue(entityInformation.getIdAttribute().getName(), uuid);
                //标记为新增数据
                optionalT = Optional.empty();
            } else {
                //若ID非空 则查询最新数据
                optionalT = findById(entityId);
            }
            //获取空属性并处理成null
            String[] nullProperties = getNullProperties(entity);
            //若根据ID查询结果为空
            if (!optionalT.isPresent()) {
                em.persist(entity);//新增
                return entity;
            } else {
                //1.获取最新对象
                T target = optionalT.get();
                //2.将非空属性覆盖到最新对象
                BeanUtils.copyProperties(entity, target, nullProperties);
                //3.更新非空属性
                em.merge(target);
                return entity;
            }
        }
    
        /**
         * 获取对象的空属性
         */
        private static String[] getNullProperties(Object src) {
            //1.获取Bean
            BeanWrapper srcBean = new BeanWrapperImpl(src);
            //2.获取Bean的属性描述
            PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();
            //3.获取Bean的空属性
            Set<String> properties = new HashSet<>();
            for (PropertyDescriptor propertyDescriptor : pds) {
                String propertyName = propertyDescriptor.getName();
                Object propertyValue = srcBean.getPropertyValue(propertyName);
                if (StringUtils.isEmpty(propertyValue)) {
                    srcBean.setPropertyValue(propertyName, null);
                    properties.add(propertyName);
                }
            }
            return properties.toArray(new String[0]);
        }
    }
    
    二、启动类
    @EnableJpaRepositories(value = "com.hehe.repository", repositoryBaseClass = SimpleJpaRepositoryImpl.class)
    @SpringBootApplication
    public class JpaApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(JpaApplication.class, args);
        }
    }
    
    三、实体类和通用Save
    
    @Entity
    @Table(name = "T_USER")
    @JsonIgnoreProperties({"handler","hibernateLazyInitializer"})
    public class User {
        @Id
        private String userId;
        private String username;
        private String password;
        //省略GET/SET
    }
    public interface UserRepository extends JpaRepository<User, String> {
    }
    
    四、配置文件 application.yml
    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/socks?useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
    
    五、数据库脚本
    drop table if exists t_user;
    create table t_user (
      user_id  varchar(50),
      username varchar(50),
      password varchar(50)
    );
    
    insert into t_user values ('1', 'admin', 'admin');
    insert into t_user values ('2', 'yizhiwazi', '123456');
    
    六、测试代码
    @RestController
    public class UserController {
    
        @Autowired
        private UserRepository userRepository;
    
        @RequestMapping("/")
        public User get() {
    
            userRepository.save(new User("1", "", null));
    
            return userRepository.findById("1").get();
        }
    }
    
    
    

    整体结构图

    在实际项目中,可以直接复制SimpleJpaRepositoryImpl使用,并不影响原有的其它API。

    相关文章

      网友评论

        本文标题:SpringBoot 实现JPA的save方法不更新null属性

        本文链接:https://www.haomeiwen.com/subject/kqxcdftx.html