当前位置 : 首页 » 文章分类 :  开发  »  Spring-Utils

Spring-Utils

Spring 中的工具类


Spring BeanUtils

org.springframework.beans.BeanUtils

public abstract class BeanUtils
extends java.lang.Object

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html

getPropertyDescriptors() 获取全部属性描述符

public static java.beans.PropertyDescriptor[] getPropertyDescriptors(java.lang.Class<?> clazz) throws BeansException

获取一个 Bean 的全部属性描述符

getPropertyDescriptor() 获取指定属性描述符

@Nullable
public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) throws BeansException

获取指定的属性描述符

copyProperties() 拷贝属性值(浅拷贝)

public static void copyProperties(Object source, Object target) throws BeansException
public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansExceptio
public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansExceptio

拷贝属性值,从 source 到 target
原类型和目标类型不需要相同,只要属性名匹配就会拷贝。原类型有但目标类没有的属性会被忽略。

copyProperties 是浅拷贝,只是调用子对象的set方法
如果都是单一的属性,那么不涉及到深拷贝的问题,适合用BeanUtils。
如果有子对象但子对象不需要改动,也可以使用 BeanUtils

editable:只设置 editable 类型指定的属性
ignoreProperties:指定要忽略的属性名数组

方法有一个不足的地方,就是 当 source 里的属性对应的属性值为 null 时,也会覆盖掉 target 里相同属性名的属性,即使target中该属性值已存在且不为null的属性值

自定义Bean字段比较和拷贝工具类

比较source bean和target bean各个字段,若发生改变则覆盖target bean字段,返回是否有改变

package com.masikkk.utils;

import com.nio.uds.common.utils.Comparators;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

public class MyBeanUtils {

    /**
     * 比较source bean和target bean各个字段,若发生改变则覆盖target bean字段
     * @param source
     * @param target
     * @param ignoreProperties
     * @return 返回是否有字段发生变化
     */
    public static boolean copyProperties(Object source, Object target, String... ignoreProperties) {
        boolean hasChanged = false;
        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");

        Class<?> actualEditable = target.getClass();
        PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
        List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;

        for (PropertyDescriptor targetPd : targetPds) {
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
                PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    Method targetReadMethod = targetPd.getReadMethod();
                    if (readMethod != null && (ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()))) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            // 原bean的值
                            Object sourceValue = readMethod.invoke(source);
                            // 目标bean的值
                            Object targetValue = targetReadMethod.invoke(target);
                            if (!Comparators.equals(sourceValue, targetValue)) {
                                hasChanged = true;
                                writeMethod.invoke(target, sourceValue);
                            }
                        } catch (Throwable ex) {
                            throw new FatalBeanException( "Could not copy property '" + targetPd.getName() + "' from source to target", ex);
                        }
                    }
                }
            }
        }
        return hasChanged;
    }
}

Apache BeanUtils

Map 和 Bean 互相转换

1 Map 转 Bean

Map<String, Object> map = new HashMap();
MyBean myBean = new MyBean();
org.apache.commons.beanutils.BeanUtils.populate(myBean, map);

2 Bean 转 Map
commons-beanutils 中的 BeanMap 类继承自 AbstractMap<Object, Object> ,本身就是一个 Map,所以直接 new 一个 BeanMap 传入 object 对象即可。

Map<Object, Object> beanMap = new BeanMap(humanDataVO);

需要添加

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>

StopWatch

使用示例

StopWatch stopWatch = new StopWatch("My Stop Watch");

stopWatch.start("initializing");
Thread.sleep(2000); // simulated work
stopWatch.stop();

stopWatch.start("processing");
Thread.sleep(5000); // simulated work
stopWatch.stop();

stopWatch.start("finalizing");
Thread.sleep(3000); // simulated work
stopWatch.stop();

System.out.println(stopWatch.prettyPrint());

从 Spring Framework 5.2 开始,以纳秒为单位跟踪和报告运行时间


DigestUtils

spring-core 包中的 MessageDigest 内部也是使用 jdk 自带的 MessageDigest

String md5Str = DigestUtils.md5DigestAsHex("字符串".getBytes(StandardCharsets.UTF_8));

MultiValueMap

一个 key 中可以存放多个 value 的 Map,类似 Apache-Commons-Collections 中的 MultiValuedMap

@Test
public void testMultiValueMap() {
    MultiValueMap<String, String> mvm = new LinkedMultiValueMap<>();
    String key1 = "key1";
    mvm.add(key1, "value1");
    mvm.add(key1, "value2");
    List<String> values = mvm.get(key1);
    Assertions.assertNotNull(values);
    Assertions.assertEquals(2, values.size());
    Assertions.assertEquals("value1", mvm.getFirst(key1));
    System.out.println(mvm);
}

结果:
{key1=[value1, value2]}


上一篇 Caffeine 缓存

下一篇 MapStruct

阅读
评论
993
阅读预计5分钟
创建日期 2021-05-31
修改日期 2023-03-06
类别
标签

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论