【小家Spring】Spring Framework提供的实用纯Java工具类大合集(一)(中)

简介: 【小家Spring】Spring Framework提供的实用纯Java工具类大合集(一)(中)

FileCopyUtils、FileSystemUtils、StreamUtils


都是操作文件、操作流的一些工具类。这里就不做过多的介绍了,因为还是比较简单的。


LinkedCaseInsensitiveMap 、LinkedMultiValueMap


不区分大小写的有序map;底层代理了LinkedHashMap,因此它能保证有序。此Map的意义在于:在编写比如MaBatis这种类似的自动封装框架的时候,特备有用。


数据库本身对大小写不敏感(我使用的是mysql),但是创建表格的时候,数据库里面字段都会默认小写,所以MyBatis映射的时候,key也会映射成小写,可以用LinkedCaseInsensitiveMap(key值不区分大小写的LinkedMap)来处理。


LinkedCaseInsensitiveMap的key一定是String


现在我随手写个Demo,感受一下吧:

    @Test
    public void fun1() {
        Map<String, Object> map = new LinkedCaseInsensitiveMap<>();
        map.put("a", 1);
        map.put("A", 1);
        System.out.println(map); //{A=1}
        System.out.println(map.get("a")); //1 map里面key是小写的a,通过大写的A也能get出来结果
    }

LinkedMultiValueMap:见名之意,一个key对应多个value。废话不多说,直接感受一把就知道了


    @Test
    public void fun1() {
        //用Map接的时候  请注意第二个泛型 是个List哦
        //Map<String, List<Integer>> map = new LinkedMultiValueMap<>();
        LinkedMultiValueMap<String, Integer> map = new LinkedMultiValueMap<>();
        //此处务必注意,如果你还是用put方法  那是没有效果的 同一个key还是会覆盖
        //map.put("a", Arrays.asList(1));
        //map.put("a", Arrays.asList(1));
        //map.put("a", Arrays.asList(1));
        //System.out.println(map); //{a=[1]}
        //请用add方法
        map.add("a", 1);
        map.add("a", 1);
        map.add("a", 1);
        System.out.println(map); //{a=[1, 1, 1]}
    }



个人感觉没有Apache Common提供的好用。但是一般来说也足够用了~


PropertyPlaceholderHelper


作用:将字符串里的占位符内容,用我们配置的properties里的替换。这个是一个单纯的类,没有继承没有实现,而且也没简单,没有依赖Spring框架其他的任何类。


StringValueResolver是一个转化String类型数据的接口,真正更新属性的api实现竟然是在PropertyPlaceholderHelper#parseStringValue


因此现在知道此类的重要性了,下面演示一下Demo,知道怎么使用即可(其实在Spring容器环境下,这些都退调用者是透明的,除非自己要书写框架性的东西):

配置文件如下:


name=wangzha
age=18
sex=man
name18man=love


    public static void main(String[] args) throws Exception {
        String a = "{name}{age}{sex}";
        String b = "{name{age}{sex}}";
        PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("{", "}");
        InputStream in = new BufferedInputStream(new FileInputStream(new File("D:\\work\\remotegitcheckoutproject\\myprojects\\java\\boot2-demo1\\src\\main\\resources\\application.properties")));
        Properties properties = new Properties();
        properties.load(in);
        //==============开始解析此字符串==============
        System.out.println("替换前:" + a); //替换前:{name}{age}{sex}
        System.out.println("替换后:" + propertyPlaceholderHelper.replacePlaceholders(a, properties)); //替换后:wangzha18man
        System.out.println("====================================================");
        System.out.println("替换前:" + b); //替换前:{name{age}{sex}}
        System.out.println("替换后:" + properties); //替换后:love  最后输出love,证明它是从内往外一层一层解析的
    }


显然@Value注解或者其余spel表达式的东西,都得依赖于这个来做。


这个掌握了,让我们自定义支持的表达式的时候,我们也可以高大上的说,我的格式支持spel表达式SpelExpressionParser。更加的灵活了


SpringVersion、SpringBootVersion 获取当前Spring版本号


    public static void main(String[] args) {
        System.out.println(SpringVersion.getVersion()); //5.0.6.RELEASE
        System.out.println(SpringBootVersion.getVersion()); //2.0.2.RELEASE
    }


ReflectionUtils 反射工具类


反射在容器中使用是非常频繁的了,这些方法一般在Spring框架内部使用。当然现在Spring都成为实际的规范了,所以我们也可以直接拿来使用。

public static Field findField(Class<?> clazz, String name);
public static Field findField(Class<?> clazz, @Nullable String name, @Nullable Class<?> type);
public static void setField(Field field, @Nullable Object target, @Nullable Object value);


该方法是从类里面找到字段对象。(private以及父类的都会找哟,但是static的就不会啦)


public static Object getField(Field field, @Nullable Object target);


这个很明显,就是拿到该对象指定字段的值,示例如下:


    public static void main(String[] args) {
        Person person = new Person("fsx", 18);
        Field field = ReflectionUtils.findField(Person.class, "name");
        field.setAccessible(true); //注意,如果是private的属性,请加上这一句,否则抛出异常:can not access a member of class com.fsx.boot2demo1.bean.Person with modifiers "private"
        System.out.println(ReflectionUtils.getField(field, person)); //fsx
    }
public static Method findMethod(Class<?> clazz, String name);
public static Method findMethod(Class<?> clazz, String name, @Nullable Class<?>... paramTypes);
public static Object invokeMethod(Method method, @Nullable Object target); //这个不需要自己处理异常哦
public static Object invokeMethod(Method method, @Nullable Object target, @Nullable Object... args);

示例:

    public static void main(String[] args) {
        Person person = new Person("fsx", 18);
        System.out.println(ReflectionUtils.findMethod(Person.class, "clone")); //protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
        System.out.println(ReflectionUtils.findMethod(Person.class, "getName")); //public java.lang.String com.fsx.boot2demo1.bean.Person.getName()
        System.out.println(ReflectionUtils.findMethod(Person.class, "setName", String.class)); //public void com.fsx.boot2demo1.bean.Person.setName(java.lang.String)
        System.out.println(ReflectionUtils.findMethod(Person.class, "privateMethod")); //private void com.fsx.boot2demo1.bean.Person.privateMethod()
    }


也是一样非常的强大。private、父类方法都能获取到。


所有的反射相关的异常,其实都可以交给下面来处理:


public static void handleReflectionException(Exception ex);
public static void rethrowRuntimeException(Throwable ex);


boolean declaresException(Method method, Class<?> exceptionType); //判断一个方法上是否声明了指定类型的异常
boolean isPublicStaticFinal(Field field); //判断字段是否是public static final的
boolean isEqualsMethod(Method method); //判断该方法是否是equals方法
boolean isHashCodeMethod(Method method);
boolean isToStringMethod(Method method);
boolean isObjectMethod(Method method); //判断该方法是否是Object类上的方法
public static void makeAccessible(Field field); //将一个字段设置为可读写,主要针对private字段
void makeAccessible(Method method);
void makeAccessible(Constructor<?> ctor);


在AopUtils中也有这几个isXXX方法,是的,其实AopUtils中的isXXX方法就是调用的ReflectionUtils的这几个方法的;所以可见此工具类的强大


public static Method[] getAllDeclaredMethods(Class<?> leafClass);
public static Method[] getUniqueDeclaredMethods(Class<?> leafClass);


看个栗子:


    public static void main(String[] args) {
        Person person = new Person("fsx", 18);
        Method[] allDeclaredMethods = ReflectionUtils.getAllDeclaredMethods(Person.class);
        //我们发现  这个方法可以把所有的申明的方法都打印出来。包含private和父类的   备注:重复方法都会拿出来。比如此处的toString方法 子类父类的都有
        for (Method method : allDeclaredMethods) {
            System.out.println(method);
        }
        System.out.println("------------------------------------");
        //针对于上面的结果过滤。只会保留一个同名的方法(保留子类的)
        Method[] uniqueDeclaredMethods = ReflectionUtils.getUniqueDeclaredMethods(Person.class);
        for (Method method : uniqueDeclaredMethods) {
            System.out.println(method);
        }
    }


最后是这几个方法:


image.png


针对指定类型上的所有方法,依次调用MethodCallback回调;看个源码就知道这个方法的作用:


public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
    Method[] methods = getDeclaredMethods(clazz);
    for (Method method : methods) {
        try {
            mc.doWith(method);
        }catch (IllegalAccessException ex) {
            throw new IllegalStateException("...");
        }
    }
}


其实实现很简单,就是得到类上的所有方法,然后执行回调接口;这个方法在Spring针对bean的方法上的标签处理时大量使用,比如@Init,@Resource,@Autowire等标签的预处理;

Spring处理的源码如下:(仅供参考)


image.png


image.png


image.png


ResourceUtils

Spring 提供了一个 ResourceUtils 工具类,它支持“classpath:”和“file:”的地址前缀,它能够从指定的地址加载文件资源。(其实还支持“jar:和war:前缀”)

public abstract class ResourceUtils {
  public static final String CLASSPATH_URL_PREFIX = "classpath:";
  public static final String FILE_URL_PREFIX = "file:";
  public static final String JAR_URL_PREFIX = "jar:";
  public static final String WAR_URL_PREFIX = "war:";
  ...
  // 是否是一个URL
  public static boolean isUrl(@Nullable String resourceLocation) {
    if (resourceLocation == null) {
      return false;
    }
    // 对classpath:进行了特殊的照顾
    if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
      return true;
    }
    try {
      new URL(resourceLocation);
      return true;
    }
    catch (MalformedURLException ex) {
      return false;
    }
  }
  public static URL getURL(String resourceLocation) throws FileNotFoundException {...}
  public static File getFile(String resourceLocation) throws FileNotFoundException {...}
  public static File getFile(URL resourceUrl) throws FileNotFoundException {...}
  public static File getFile(URI resourceUri) throws FileNotFoundException {...}
  public static File getFile(URI resourceUri, String description) throws FileNotFoundException {...}
  // 判断
  public static boolean isFileURL(URL url) {
    // 均是和protocol 这个协议有关的~~~
    String protocol = url.getProtocol();
    return (URL_PROTOCOL_FILE.equals(protocol) || URL_PROTOCOL_VFSFILE.equals(protocol) ||
        URL_PROTOCOL_VFS.equals(protocol));
  }
  public static boolean isJarURL(URL url) {...}
  // @since 4.1
  public static boolean isJarFileURL(URL url) {...}
  // URL和URI的转换
  public static URI toURI(URL url) throws URISyntaxException {
    return toURI(url.toString());
  }
  public static URI toURI(String location) throws URISyntaxException {
    return new URI(StringUtils.replace(location, " ", "%20"));
  }
}

Demo:


    public static void main(String[] args) throws FileNotFoundException {
        File file = ResourceUtils.getFile("classpath:application.properties");
        System.out.println(file); //D:\work\remotegitcheckoutproject\myprojects\java\boot2-demo1\target\classes\application.properties
        System.out.println(ResourceUtils.isUrl("classpath:application.properties")); //true
        //注意此处输出的路径为正斜杠 ‘/’的  上面直接输出File是反斜杠的(和操作系统相关)
        System.out.println(ResourceUtils.getURL("classpath:application.properties")); //file:/D:/work/remotegitcheckoutproject/myprojects/java/boot2-demo1/target/classes/application.properties
    }

备注:若你在使用过程中,发现ResourceUtils.getFile()死活都找不到文件的话,那我提供一个建议:是否是在jar包内使用了此工具类,一般不建议在jar包内使用。另外,提供一个代替方案:可解决大多数问题


    public static void main(String[] args) {
        ClassPathResource resource = new ClassPathResource("application.properties");
        System.out.println(resource); //class path resource [application.properties]
    }

SerializationUtils


这个工具就不做过多解释了。提供了两个方法:对象<–>二进制的相互转化。(基于源生JDK的序列化方式)

public static byte[] serialize(@Nullable Object object);
public static Object deserialize(@Nullable byte[] bytes);


请注意,对象需要实现Serializable接口哦


SocketUtils


提供给我们去系统找可用的Tcp、Udp端口来使用。有的时候确实还蛮好用的,必进端口有时候不用写死了,提高灵活性


    public static void main(String[] args) {
        System.out.println(SocketUtils.PORT_RANGE_MAX); //65535 最大端口号
        System.out.println(SocketUtils.findAvailableTcpPort()); //45569 随便找一个可用的Tcp端口 每次执行值都不一样哦
        System.out.println(SocketUtils.findAvailableTcpPort(1000, 2000)); //1325 从指定范围内随便找一个端口
        //找一堆端口出来  并且是排好序的
        System.out.println(SocketUtils.findAvailableTcpPorts(10, 1000, 2000)); //[1007, 1034, 1287, 1483, 1494, 1553, 1577, 1740, 1963, 1981]
        //UDP端口的找寻 同上
        System.out.println(SocketUtils.findAvailableUdpPort()); //12007
    }

其长度都是16个bit,所以端口号范围是0到(2^16-1),即 0到 65535。其中0到1023是IANA规定的系统端口,即系统保留窗口。例如HTTP为80端口,DNS服务为53端口。下面列出常用tcp和udp重要协议端口号,供以参考


image.png


image.png

另外说明:TCP、UDP可以绑定同一端口来进行通信。每个端口都拥有一个叫端口号(port number)的整数型标识符,用于区别不同端口。由于TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立,如TCP有一个255号端口,UDP也可以有一个255号端口,二者并不冲突。

StringUtils


Spring提供的字符串处理类。再结合Apache提供的,绝对的够用了。因此平时code过程中,绝对禁止程序员再自定义StringUtils工具类。


Spring为了最依赖原则,自己实现了一个StringUtils,这里分类进行介绍:


判断类

属于该类别的方法都是在对字符串进行一些判定操作:

   //判断类:
    // boolean isEmpty(Object str):字符串是否为空或者空字符串:""
    // boolean hasLength(CharSequence str):字符串是否为空,或者长度为0
    // boolean hasText(String str):字符串是否有内容(不为空,且不全为空格)
    assertFalse(StringUtils.hasText("   "));
    // boolean containsWhitespace(String str):字符串是否包含空格
    assertTrue(StringUtils.containsWhitespace("a b"));



相关文章
|
3月前
|
IDE Java 数据库连接
解决Java环境中无法识别org.mybatis.spring.annotation.MapperScan的问题。
祝你好运,在这场MyBatis的魔法冒险中获得胜利!记住,魔法书(官方文档)永远是你最好的朋友。
247 18
|
2月前
|
Java 数据库连接 API
Java 8 + 特性及 Spring Boot 与 Hibernate 等最新技术的实操内容详解
本内容涵盖Java 8+核心语法、Spring Boot与Hibernate实操,按考试考点分类整理,含技术详解与代码示例,助力掌握最新Java技术与应用。
96 2
|
3月前
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
155 1
|
3月前
|
SQL Java 数据库
解决Java Spring Boot应用中MyBatis-Plus查询问题的策略。
保持技能更新是侦探的重要素质。定期回顾最佳实践和新技术。比如,定期查看MyBatis-Plus的更新和社区的最佳做法,这样才能不断提升查询效率和性能。
147 1
|
4月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
3月前
|
Java 调度 流计算
基于Java 17 + Spring Boot 3.2 + Flink 1.18的智慧实验室管理系统核心代码
这是一套基于Java 17、Spring Boot 3.2和Flink 1.18开发的智慧实验室管理系统核心代码。系统涵盖多协议设备接入(支持OPC UA、MQTT等12种工业协议)、实时异常检测(Flink流处理引擎实现设备状态监控)、强化学习调度(Q-Learning算法优化资源分配)、三维可视化(JavaFX与WebGL渲染实验室空间)、微服务架构(Spring Cloud构建分布式体系)及数据湖建设(Spark构建实验室数据仓库)。实际应用中,该系统显著提升了设备调度效率(响应时间从46分钟降至9秒)、设备利用率(从41%提升至89%),并大幅减少实验准备时间和维护成本。
250 0
|
3月前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
368 0
|
3月前
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
515 0