【小家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"));



相关文章
|
11天前
|
前端开发 Java API
Java入门教程:掌握Spring MVC的双向数据绑定技术
以上步骤展示了如何利用 Spring MVC 实现双向数据绑定:从显示表单、提交表单、验证输入、直至返回结果页面都涉及到不同层次间交互过程,在整个过程都无需手动去编写繁琐代码去手动获取或设置每一项值。
93 20
|
13天前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
97 3
|
13天前
|
人工智能 Java API
构建基于Java的AI智能体:使用LangChain4j与Spring AI实现RAG应用
当大模型需要处理私有、实时的数据时,检索增强生成(RAG)技术成为了核心解决方案。本文深入探讨如何在Java生态中构建具备RAG能力的AI智能体。我们将介绍新兴的Spring AI项目与成熟的LangChain4j框架,详细演示如何从零开始构建一个能够查询私有知识库的智能问答系统。内容涵盖文档加载与分块、向量数据库集成、语义检索以及与大模型的最终合成,并提供完整的代码实现,为Java开发者开启构建复杂AI智能体的大门。
403 58
|
17天前
|
监控 Java 数据库
从零学 Dropwizard:手把手搭轻量 Java 微服务,告别 Spring 臃肿
Dropwizard 整合 Jetty、Jersey 等成熟组件,开箱即用,无需复杂配置。轻量高效,启动快,资源占用少,内置监控、健康检查与安全防护,搭配 Docker 部署便捷,是构建生产级 Java 微服务的极简利器。
95 2
|
2月前
|
前端开发 Java 开发者
Java新手指南:在Spring MVC中使用查询字符串与参数
通过结合实际的需求和业务逻辑,开发者可以灵活地利用这些机制,为用户提供更丰富而高效的Web应用体验。
87 15
|
2月前
|
Cloud Native Java API
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
319 0
|
3月前
|
安全 Java 微服务
Java 最新技术和框架实操:涵盖 JDK 21 新特性与 Spring Security 6.x 安全框架搭建
本文系统整理了Java最新技术与主流框架实操内容,涵盖Java 17+新特性(如模式匹配、文本块、记录类)、Spring Boot 3微服务开发、响应式编程(WebFlux)、容器化部署(Docker+K8s)、测试与CI/CD实践,附完整代码示例和学习资源推荐,助你构建现代Java全栈开发能力。
404 0
|
3月前
|
JSON 前端开发 Java
Java新手指南:如何在Spring MVC中处理请求参数
处理Spring MVC中的请求参数是通过控制器方法中的注解来完成的。这些注解包括 `@RequestParam`, `@PathVariable`, `@ModelAttribute`, `@RequestBody`, `@RequestHeader`, `@Valid`, 和 `@RequestMapping`。使用这些注解可以轻松从HTTP请求中提取所需信息,例如URL参数、表单数据或者JSON请求体,并将其转换成Java对象以供进一步处理。
244 17
|
3月前
|
前端开发 Java API
基于 Spring Boot 3 与 React 的 Java 学生信息管理系统从入门到精通实操指南
本项目基于Spring Boot 3与React 18构建学生信息管理系统,涵盖前后端开发、容器化部署及测试监控,提供完整实操指南与源码,助你掌握Java全栈开发技能。
152 0
|
3月前
|
Java 数据库连接 API
Java 8 + 特性及 Spring Boot 与 Hibernate 等最新技术的实操内容详解
本内容涵盖Java 8+核心语法、Spring Boot与Hibernate实操,按考试考点分类整理,含技术详解与代码示例,助力掌握最新Java技术与应用。
112 2

热门文章

最新文章