所有分类
  • 所有分类
  • 未分类

Spring-BeanUtils忽略空值拷贝

简介

说明

本文用示例介绍Spring(SpringBoot)如何使用BeanUtils拷贝对象属性(忽略空值)。

BeanUtils类所在的包

有两个包都提供了BeanUtils类:

  1. Spring的(推荐):org.springframework.beans.BeanUtils
  2. Apache的:org.apache.commons.beanutils.BeanUtils

为什么要忽略空值拷贝?

  1. 默认情况下,BeanUtils会覆盖数据
    • 在拷贝属性时,如果源数据的某个字段是null,会把目标数据的值给覆盖为null

忽略null值拷贝属性的用法

BeanUtils.copyProperties(Object source, Object target, String... ignoreProperties)

注意:由于BeanUtils这个方法是浅拷贝,所以本文不考虑对象里边有其他对象的这种情况。

获取null属性名(工具类)

见:SpringBoot-获得对象属性为空值的属性名 – 自学精灵

实例

本处为了全面,将以下情况都考虑进去:

  1. 继承了某个类

代码结构

Entity

公共Entity

package com.knife.example.common.entity;
 
import lombok.Data;
 
import java.time.LocalDateTime;
 
/**
 * 公共实体类
 */
@Data
public class CommonEntity {
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
 
    /**
     * 修改时间
     */
    private LocalDateTime updateTime;
}

ProductVO

package com.example.entity;

import lombok.Data;

@Data
public class User {
    private Long id;

    private String userName;

    private String nickName;

    // 0:正常 1:被锁定
    private Integer status;
}

工具类

package com.knife.example.common.util;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.StringUtils;

import java.beans.PropertyDescriptor;
import java.util.HashSet;
import java.util.Set;
public class PropertyUtil {
    public static String[] readEmptyPropertyNames(Object source) {
        BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<>();
        for (PropertyDescriptor pd : pds) {
            String filedName = pd.getName();
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(filedName);
            } else {
                if (srcValue instanceof String) {
                    if (!StringUtils.hasText((String) srcValue)) {
                        emptyNames.add(filedName);
                    }
                }
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }
}

Controller

package com.knife.example.business.product.controller;

import com.knife.example.business.product.vo.ProductVO;
import com.knife.example.common.util.PropertyUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Arrays;

@Api(tags = "商品")
@RestController
@RequestMapping("product")
public class ProductController {
    @ApiOperation("查询详情")
    @GetMapping("detail")
    public ProductVO detail(Long id) {
        // 源对象
        ProductVO productVO = new ProductVO();
        productVO.setId(10L);
        productVO.setName("");
        productVO.setStockQuantity(null);
        productVO.setCreateTime(LocalDateTime.now());
        productVO.setUpdateTime(null);

        System.out.println("------------------------------------------------");

        // 目标对象
        ProductVO productVOTarget = new ProductVO();
        productVOTarget.setId(9L);
        productVOTarget.setName("键盘");
        productVOTarget.setStockQuantity(150);
        productVOTarget.setCreateTime(LocalDateTime.now().minusHours(3));
        productVOTarget.setUpdateTime(LocalDateTime.now().minusHours(3));

        // 默认不忽略空值
        BeanUtils.copyProperties(productVO, productVOTarget);

        //读出空值字段名
        // String[] emptyPropertyNames = PropertyUtil.readEmptyPropertyNames(productVO);
        // System.out.println("空值字段名:" + Arrays.toString(emptyPropertyNames));
        // //忽略空值拷贝
        // BeanUtils.copyProperties(productVO, productVOTarget, emptyPropertyNames);

        return productVOTarget;
    }
}

测试1:默认情况

结论

  1. 默认情况下,null和空字符串会覆盖目标对象的属性

测试2:忽略空值拷贝

修改一下Controller,改为如下:

package com.knife.example.business.product.controller;

import com.knife.example.business.product.vo.ProductVO;
import com.knife.example.common.util.PropertyUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Arrays;

@Api(tags = "商品")
@RestController
@RequestMapping("product")
public class ProductController {
    @ApiOperation("查询详情")
    @GetMapping("detail")
    public ProductVO detail(Long id) {
        // 源对象
        ProductVO productVO = new ProductVO();
        productVO.setId(10L);
        productVO.setName("");
        productVO.setStockQuantity(null);
        productVO.setCreateTime(LocalDateTime.now());
        productVO.setUpdateTime(null);

        // 目标对象
        ProductVO productVOTarget = new ProductVO();
        productVOTarget.setId(9L);
        productVOTarget.setName("键盘");
        productVOTarget.setStockQuantity(150);
        productVOTarget.setCreateTime(LocalDateTime.now().minusHours(3));
        productVOTarget.setUpdateTime(LocalDateTime.now().minusHours(3));

        // 默认不忽略空值
        // BeanUtils.copyProperties(productVO, productVOTarget);

        //读出空值字段名
        String[] emptyPropertyNames = PropertyUtil.readEmptyPropertyNames(productVO);
        System.out.println("空值字段名:" + Arrays.toString(emptyPropertyNames));
        //忽略空值拷贝
        BeanUtils.copyProperties(productVO, productVOTarget, emptyPropertyNames);

        return productVOTarget;
    }
}

结果:

结论:

成功的避免了空值覆盖。

0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录