1. StringUtils
import org.springframework.util.StringUtils;
// 1. 判断是否为空(null 或 "")
StringUtils.isEmpty(null); // true
StringUtils.isEmpty(""); // true
StringUtils.isEmpty(" "); // false(纯空格不算空)
StringUtils.isEmpty("abc"); // false
// 2. 判断是否不为空
StringUtils.hasLength(null); // false
StringUtils.hasLength(""); // false
StringUtils.hasLength(" "); // true
// 3. 判断是否有实际内容(非null、非空、非纯空白)
StringUtils.hasText(null); // false
StringUtils.hasText(""); // false
StringUtils.hasText(" "); // false
StringUtils.hasText("abc"); // true
StringUtils.hasText("a b c"); // true
// 1. 去除首尾空白(null 安全,返回原值)
StringUtils.trim(null); // null
StringUtils.trim(" abc "); // "abc"
StringUtils.trim(""); // ""
// 2. 去除首尾空白,空结果转 null
StringUtils.trimWhitespace(null); // null
StringUtils.trimWhitespace(" "); // null
StringUtils.trimWhitespace("abc"); // "abc"
// 3. 清除所有空白(包括中间)
StringUtils.trimAllWhitespace(" a b c "); // "abc"
// 4. 压缩空白(中间多个空格变1个,首尾去除)
StringUtils.trimLeadingWhitespace(" abc def "); // "abc def "
StringUtils.trimTrailingWhitespace(" abc def "); // " abc def"
// 1. 数组转字符串(指定分隔符,null 元素自动忽略)
String[] arr = {"a", null, "b", "c"};
StringUtils.collectionToDelimitedString(List.of("a","b"), ","); // "a,b"
StringUtils.arrayToDelimitedString(arr, ","); // "a,b,c"
// 2. 字符串分割(自动去空、去空白)
StringUtils.commaDelimitedListToStringArray("a,, b , c");
// 结果:["a", "b", "c"]
StringUtils.delimitedListToStringArray("a-b-c", "-"); // ["a","b","c"]
// 1. 获取文件扩展名(不带.)
StringUtils.getFilenameExtension("test.jpg"); // "jpg"
StringUtils.getFilenameExtension("path/file.txt");// "txt"
StringUtils.getFilenameExtension("file"); // null
// 2. 去除文件扩展名
StringUtils.stripFilenameExtension("test.jpg"); // "test"
StringUtils.stripFilenameExtension("a/b/c.txt"); // "a/b/c"
// 3. 提取文件名(含扩展名)
StringUtils.getFilename("/path/test.txt"); // "test.txt"
// 4. 清理文件路径(统一分隔符)
StringUtils.cleanPath("C:\\test\\../file.txt"); // "C:/file.txt"
// 首字母大写
StringUtils.capitalize("spring"); // "Spring"
StringUtils.capitalize("Spring"); // "Spring"(不变)
// 首字母小写
StringUtils.uncapitalize("Spring"); // "spring"
StringUtils.uncapitalize("URL"); // "uRL"
// 1. 忽略大小写比较(null 安全)
StringUtils.equalsIgnoreCase(null, null); // true
StringUtils.equalsIgnoreCase("abc", "ABC"); // true
StringUtils.equalsIgnoreCase("abc", "def"); // false
// 2. 判断是否以指定前缀开头(忽略大小写)
StringUtils.startsWithIgnoreCase("SpringBoot", "spring"); // true
// 3. 判断是否包含任意一个子串
StringUtils.containsAny("abc123", "x", "b"); // true
// 判断是否全为空白(空格、制表符、换行)
StringUtils.containsWhitespace(" "); // true
StringUtils.containsWhitespace("a b"); // true
StringUtils.containsWhitespace("ab"); // false
// 1. 字符串数组去空(删除 null、""、纯空白)
String[] arr = {"a", "", " ", null, "b"};
StringUtils.trimArrayElements(arr); // ["a","","","","b"]
StringUtils.deleteWhitespace("a b c"); // "abc"
// 2. 把集合转为逗号分隔字符串
StringUtils.collectionToCommaDelimitedString(List.of("a","b","c"));
// "a,b,c"
// 左侧填充字符到指定长度
StringUtils.leftPad("123", 5, '0'); // "00123"
StringUtils.leftPad("12345", 3, '0');// "12345"(超过长度不截断)
// 拼接路径(自动处理分隔符)
StringUtils.applyRelativePath("/test/", "file.txt"); // "/test/file.txt"
2. AntPathMatcher
import org.springframework.util.AntPathMatcher;
// 1. 创建实例(默认大小写敏感)
AntPathMatcher matcher = new AntPathMatcher();
// --------------------------
// 【最常用】判断路径是否匹配规则
// --------------------------
boolean match1 = matcher.match("/user/**", "/user/123/info"); // true
boolean match2 = matcher.match("/user/*", "/user/123"); // true
boolean match3 = matcher.match("/user/?", "/user/a"); // true
boolean match4 = matcher.match("/user/?", "/user/ab"); // false
System.out.println("match1 = " + match1);
// --------------------------
// 匹配(末尾支持模糊匹配,/user 匹配 /user/*)
// --------------------------
boolean matchStart = matcher.matchStart("/user/123/info", "/user"); // true
System.out.println("matchStart = " + matchStart);
// --------------------------
// 提取路径中的变量(@PathVariable 底层原理)
// --------------------------
Map<String, String> uriVariables = matcher.extractUriTemplateVariables(
"/user/{id}/info/{name}", // 模板
"/user/10086/info/zhangsan" // 实际路径
);
System.out.println("id = " + uriVariables.get("id")); // 10086
System.out.println("name = " + uriVariables.get("name"));// zhangsan
// --------------------------
// 拼接路径(自动处理 / 符号)
// --------------------------
String combine = matcher.combine("/user", "info"); // /user/info
System.out.println("combine = " + combine);
// --------------------------
// 获取模式中的**单段通配符**内容(* 匹配的值)
// --------------------------
String pattern = "/user/*/info/*";
String path = "/user/123/info/zhangsan";
String[] patterns = matcher.extractMatchStrings(pattern, path);
for (String s : patterns) {
System.out.println("匹配值:" + s); // 123、zhangsan
}
// --------------------------
// 获取路径的“比较权重”(越精确权重越高)
// --------------------------
int weight1 = matcher.getPatternComparator("/user/123").compare("/user/*", "/user/**");
System.out.println("权重比较:" + weight1); // 正数:/user/* 更精确
// --------------------------
// 判断是否是**通配符模式**(包含 * ? ** { })
// --------------------------
boolean isPattern1 = matcher.isPattern("/user/**"); // true
boolean isPattern2 = matcher.isPattern("/user/123"); // false
System.out.println("isPattern1 = " + isPattern1);
// --------------------------
// 配置:设置路径分隔符(默认 /,可改 \ 用于 Windows 路径)
// --------------------------
matcher.setPathSeparator("/");
// --------------------------
// 配置:设置是否忽略大小写(默认 false)
// --------------------------
matcher.setCaseSensitive(false);
boolean matchIgnoreCase = matcher.match("/User", "/user"); // true
System.out.println("忽略大小写匹配:" + matchIgnoreCase);
3. PatternMatchUtils
import org.springframework.util.PatternMatchUtils;
// --------------------------
// 1. 【最常用】简单匹配 (pattern, str)
// 支持 * 号,任意位置
// --------------------------
boolean match1 = PatternMatchUtils.simpleMatch("hello*", "helloWorld"); // true(前缀匹配)
boolean match2 = PatternMatchUtils.simpleMatch("*world", "helloWorld"); // true(后缀匹配)
boolean match3 = PatternMatchUtils.simpleMatch("*test*", "abcTest123"); // true(包含匹配)
boolean match4 = PatternMatchUtils.simpleMatch("test", "test"); // true(完全匹配)
boolean match5 = PatternMatchUtils.simpleMatch("test*", "test"); // true(* 可匹配空)
boolean match6 = PatternMatchUtils.simpleMatch("a*c", "abc"); // true
boolean match7 = PatternMatchUtils.simpleMatch("a*c", "abdc"); // true
boolean match8 = PatternMatchUtils.simpleMatch("Test", "test"); // false(大小写敏感)
// null 处理
boolean matchNull1 = PatternMatchUtils.simpleMatch(null, null); // true
boolean matchNull2 = PatternMatchUtils.simpleMatch("*", null); // false
// --------------------------
// 2. 多模式匹配:任意一个匹配就返回 true
// 批量判断,业务极常用
// --------------------------
String[] patterns = {"user*", "admin*", "test"};
boolean matchAny1 = PatternMatchUtils.simpleMatch(patterns, "user123"); // true
boolean matchAny2 = PatternMatchUtils.simpleMatch(patterns, "guest"); // false
// --------------------------
// 3. 等值判断(无通配符,完全相等)
// 只是 equals 的包装,null 安全
// --------------------------
boolean isEqual1 = PatternMatchUtils.isEqual("test", "test"); // true
boolean isEqual2 = PatternMatchUtils.isEqual(null, null); // true
boolean isEqual3 = PatternMatchUtils.isEqual("test", null); // false
4. PropertyPlaceholderHelper
import org.springframework.util.PropertyPlaceholderHelper;
// ==========================
// 1. 创建占位符解析器
// 参数:前缀、后缀、默认值分隔符、是否忽略未解析的占位符
// ==========================
// 标准 ${key:default} 格式
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper(
"${", "}", ":", true // 忽略无法解析的占位符(true 推荐)
);
// ==========================
// 2. 定义占位符取值逻辑(核心)
// 两种方式:Lambda / 外部方法
// ==========================
// 待解析字符串
String text = "用户:${username}, 年龄:${age}, 地址:${address:未知}, 未定义:${none}";
// --------------------------
// 方式1:使用 Lambda 表达式(最常用)
// --------------------------
String result1 = helper.replacePlaceholders(text, placeholderName -> {
// 根据占位符名称返回对应值
return switch (placeholderName) {
case "username" -> "张三";
case "age" -> "25";
default -> null; // 未找到返回 null,会使用默认值或忽略
};
});
System.out.println("结果1:" + result1);
// 输出:用户:张三, 年龄:25, 地址:未知, 未定义:${none}
// --------------------------
// 方式2:使用 Properties 解析(Spring 原生支持)
// --------------------------
Properties props = new Properties();
props.setProperty("username", "李四");
props.setProperty("age", "30");
String result2 = helper.replacePlaceholders(text, props);
System.out.println("结果2:" + result2);
// 输出:用户:李四, 年龄:30, 地址:未知, 未定义:${none}
// ==========================
// 3. 嵌套占位符解析(自动递归解析)
// ==========================
String nestedText = "${outer:${inner:默认值}}";
String nestedResult = helper.replacePlaceholders(nestedText, p -> null);
System.out.println("嵌套解析:" + nestedResult); // 默认值
// ==========================
// 4. 自定义占位符格式(如 {{key}})
// ==========================
PropertyPlaceholderHelper customHelper = new PropertyPlaceholderHelper("{{", "}}", ":", true);
String customResult = customHelper.replacePlaceholders("{{msg}}", p -> "自定义占位符");
System.out.println("自定义格式:" + customResult); // 自定义占位符
String config = "jdbc:mysql://${host}:${port}/${db}";
Properties props = new Properties();
props.setProperty("host", "localhost");
props.setProperty("port", "3306");
props.setProperty("db", "test");
String result = helper.replacePlaceholders(config, props);
// jdbc:mysql://localhost:3306/test
String template = "尊敬的${user},您的验证码是${code},5分钟内有效";
String msg = helper.replacePlaceholders(template, placeholder -> {
if ("user".equals(placeholder)) return "小明";
if ("code".equals(placeholder)) return "123456";
return null;
});
5. CollectionUtils
import org.springframework.util.CollectionUtils;
// 测试数据
List<String> list1 = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> list2 = new ArrayList<>(Arrays.asList("b", "c", "d"));
List<String> emptyList = new ArrayList<>();
Map<String, String> map = new HashMap<>();
map.put("k1", "v1");
// ==========================
// 1. 【最常用】判空(null / 空集合)
// ==========================
boolean empty1 = CollectionUtils.isEmpty(emptyList); // true
boolean empty2 = CollectionUtils.isEmpty((List) null); // true
boolean empty3 = CollectionUtils.isEmpty(list1); // false
boolean notEmpty = CollectionUtils.isEmpty(list1); // false
boolean mapEmpty = CollectionUtils.isEmpty(map); // false
boolean mapNullEmpty = CollectionUtils.isEmpty((Map) null); // true
// ==========================
// 2. 集合合并(添加元素到目标集合)
// ==========================
Collection<String> target = new ArrayList<>();
CollectionUtils.mergeCollections(list1, target, (exist, add) -> exist); // 合并
System.out.println("合并后:" + target); // [a, b, c]
// ==========================
// 3. 查找第一个匹配元素
// ==========================
String first = CollectionUtils.findFirstMatch(list1, list2);
System.out.println("第一个交集元素:" + first); // b
// ==========================
// 4. 判断是否有交集(是否包含相同元素)
// ==========================
boolean hasIntersect = CollectionUtils.containsAny(list1, list2); // true
boolean hasIntersect2 = CollectionUtils.containsAny(list1, Arrays.asList("x", "y")); // false
// ==========================
// 5. 判断是否包含全部元素(子集判断)
// ==========================
boolean containsAll = CollectionUtils.containsAll(list1, Arrays.asList("a", "b")); // true
// ==========================
// 6. 获取第一个非空元素
// ==========================
String firstElement = CollectionUtils.firstElement(list1); // a
String firstNull = CollectionUtils.firstElement((List) null); // null
// ==========================
// 7. 获取最后一个元素
// ==========================
String last = CollectionUtils.lastElement(list1); // c
// ==========================
// 8. 数组转集合(自动去null)
// ==========================
String[] arr = {"a", null, "b"};
List<String> arrayToList = CollectionUtils.arrayToList(arr);
System.out.println("数组转List:" + arrayToList); // [a, null, b]
// ==========================
// 9. 多集合迭代(一次性迭代多个集合)
// ==========================
Iterator<String> iter = CollectionUtils.combinedIterator(list1, list2);
while (iter.hasNext()) {
System.out.print(iter.next() + " "); // a b c b c d
}
// ==========================
// 10. 安全创建集合(避免null)
// ==========================
List<String> safeList = CollectionUtils.createLinkedListIfNecessary(null);
Map<String, String> safeMap = CollectionUtils.createHashMapIfNecessary(null);
// ==========================
// 11. 过滤(保留符合条件的元素)
// ==========================
CollectionUtils.filter(list1, s -> s.equals("a"));
System.out.println("\n过滤后:" + list1); // [a]
// ==========================
// 12. 集合转为不可变集合
// ==========================
List<String> unmodifiable = CollectionUtils.unmodifiableList(list2);
// ==========================
// 13. 移除元素(按条件)
// ==========================
List<Integer> intList = new ArrayList<>(Arrays.asList(1,2,3,4));
CollectionUtils.removeElements(intList, 2, 4);
System.out.println("移除后:" + intList); // [1,3]
// 检查集合是否为空
boolean isEmpty = CollectionUtils.isEmpty(null); // true
boolean isEmpty2 = CollectionUtils.isEmpty(Collections.emptyList()); // true
// 集合操作
List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("b", "c", "d");
Collection<String> intersection = CollectionUtils.intersection(list1, list2); // [b, c]
// 合并集合
List<String> target = new ArrayList<>();
CollectionUtils.mergeArrayIntoCollection(new String[]{"a", "b"}, target);
6. MultiValueMap
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("colors", "red");
map.add("colors", "blue");
map.add("sizes", "large");
List<String> colors = map.get("colors"); // [red, blue]
7. ConcurrentReferenceHashMap
import org.springframework.util.ConcurrentReferenceHashMap;
// 创建高并发场景下的引用Map (类似WeakHashMap但线程安全)
Map<String, Object> cache = new ConcurrentReferenceHashMap<>();
cache.put("key1", new LargeObject());
8. SystemPropertyUtils
import org.springframework.util.SystemPropertyUtils;
// 解析含系统属性的字符串
String javaHome = SystemPropertyUtils.resolvePlaceholders("${java.home}");
String pathWithDefault = SystemPropertyUtils.resolvePlaceholders("${unknown.property:default}"); // "default"
9. ReflectionUtils
import org.springframework.util.ReflectionUtils;
// 获取类的字段
Field field = ReflectionUtils.findField(Person.class, "name");
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, person, "John");
// 调用方法
Method method = ReflectionUtils.findMethod(Person.class, "setAge", int.class);
ReflectionUtils.makeAccessible(method);
ReflectionUtils.invokeMethod(method, person, 30);
// 字段回调
ReflectionUtils.doWithFields(Person.class, field -> {
System.out.println(field.getName());
});
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionUtilsTest {
public static void main(String[] args) {
User user = new User();
// ==========================
// 1. 获取并设置私有字段
// ==========================
Field idField = ReflectionUtils.findField(User.class, "id");
// 设置可访问(Spring 内部会自动处理,但手动更稳)
ReflectionUtils.makeAccessible(idField);
ReflectionUtils.setField(idField, user, 1001L);
// 获取值
Long id = (Long) ReflectionUtils.getField(idField, user);
System.out.println("id = " + id); // 1001
// ==========================
// 2. 调用私有方法
// ==========================
Method sayHello = ReflectionUtils.findMethod(User.class, "sayHello", String.class);
ReflectionUtils.makeAccessible(sayHello);
ReflectionUtils.invokeMethod(sayHello, user, "ReflectionUtils");
// ==========================
// 3. 遍历所有字段
// ==========================
System.out.println("\n=== 遍历字段 ===");
ReflectionUtils.doWithFields(User.class, field -> {
System.out.println("字段: " + field.getName() + " 类型: " + field.getType());
});
// ==========================
// 4. 遍历所有方法
// ==========================
System.out.println("\n=== 遍历方法 ===");
ReflectionUtils.doWithMethods(User.class, method -> {
System.out.println("方法: " + method.getName());
});
}
}
// 统一给对象设置创建时间 / 更新时间
public void setCommonFields(Object obj) {
Field createTime = ReflectionUtils.findField(obj.getClass(), "createTime");
if (createTime != null) {
ReflectionUtils.makeAccessible(createTime);
ReflectionUtils.setField(createTime, obj, new Date());
}
}
// 动态调用指定方法
Method method = ReflectionUtils.findMethod(user.getClass(), "getId");
Object id = ReflectionUtils.invokeMethod(method, user);
// 遍历所有字段做脱敏 / 校验
ReflectionUtils.doWithFields(obj.getClass(), field -> {
// 跳过静态常量
if (ReflectionUtils.isPublicStaticFinal(field)) {
return;
}
// 处理逻辑...
});
10. ClassUtils
import org.springframework.util.ClassUtils;
// 获取类名
String shortName = ClassUtils.getShortName("org.example.MyClass"); // "MyClass"
// 检查类是否存在
boolean exists = ClassUtils.isPresent("java.util.List", null); // true
// 获取所有接口
Class<?>[] interfaces = ClassUtils.getAllInterfaces(ArrayList.class);
// 获取用户定义的类加载器
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
11. MethodInvoker
import org.springframework.util.MethodInvoker;
MethodInvoker invoker = new MethodInvoker();
invoker.setTargetObject(new MyService());
invoker.setTargetMethod("calculateTotal");
invoker.setArguments(new Object[]{100, 0.2});
invoker.prepare();
Object result = invoker.invoke();
12. BeanUtils
import org.springframework.beans.BeanUtils;
// 复制属性
Person source = new Person("John", 30);
Person target = new Person();
BeanUtils.copyProperties(source, target);
// 实例化类
Person newPerson = BeanUtils.instantiateClass(Person.class);
// 查找方法
Method method = BeanUtils.findMethod(Person.class, "setName", String.class);
13. FileCopyUtils
import org.springframework.util.FileCopyUtils;
// 复制文件内容
byte[] bytes = FileCopyUtils.copyToByteArray(new File("input.txt"));
FileCopyUtils.copy(bytes, new File("output.txt"));
// 读取文本
String content = FileCopyUtils.copyToString(
new InputStreamReader(new FileInputStream("input.txt"), "UTF-8"));
// 流复制
FileCopyUtils.copy(inputStream, outputStream);
public static void main(String[] args) throws IOException {
// ==========================
// 1. 【最常用】输入流 → 输出流(自动关流)
// ==========================
try (InputStream in = new FileInputStream("test.txt");
OutputStream out = new FileOutputStream("copy.txt")) {
// 一行复制流
FileCopyUtils.copy(in, out);
System.out.println("流复制成功");
}
// ==========================
// 2. 文件 → 文件 复制
// ==========================
File sourceFile = new File("test.txt");
File targetFile = new File("fileCopy.txt");
FileCopyUtils.copy(sourceFile, targetFile);
System.out.println("文件复制成功");
// ==========================
// 3. 字符串 → 文件(写入)
// ==========================
String content = "Hello Spring FileCopyUtils!";
FileCopyUtils.copy(
content.getBytes(StandardCharsets.UTF_8),
new FileOutputStream("string.txt")
);
System.out.println("字符串写入文件成功");
// ==========================
// 4. 文件 → 字节数组(读取)
// ==========================
byte[] bytes = FileCopyUtils.copyToByteArray(new FileInputStream("string.txt"));
String readContent = new String(bytes, StandardCharsets.UTF_8);
System.out.println("读取文件内容:" + readContent);
// ==========================
// 5. 文件 → 字符串(简洁读取)
// ==========================
String str = FileCopyUtils.copyToString(new FileReader("string.txt"));
System.out.println("直接读成字符串:" + str);
}
// 文件上传保存(极简写法)
@PostMapping("/upload")
public String upload(MultipartFile file) throws IOException {
// 上传文件流 → 目标文件(一行搞定)
try (InputStream in = file.getInputStream();
FileOutputStream out = new FileOutputStream("upload/" + file.getOriginalFilename())) {
FileCopyUtils.copy(in, out);
}
return "上传成功";
}
// 读取配置文件内容
// 读取 classpath 下文件成字符串
Resource resource = new ClassPathResource("application.yml");
String content = FileCopyUtils.copyToString(
new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)
);
// 响应文件下载
@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
File file = new File("test.txt");
response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
// 文件 → 响应输出流
try (FileInputStream in = new FileInputStream(file)) {
FileCopyUtils.copy(in, response.getOutputStream());
}
}
14. ResourceUtils
import org.springframework.util.ResourceUtils;
// 获取文件
File file = ResourceUtils.getFile("classpath:config.properties");
// 检查是否是URL
boolean isUrl = ResourceUtils.isUrl("http://example.com");
// 获取URL
URL url = ResourceUtils.getURL("classpath:data.json");
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
public class ResourceUtilsTest {
public static void main(String[] args) throws IOException {
// ==========================
// 1. 【最常用】从 classpath 读取文件(转 File)
// ==========================
File file = ResourceUtils.getFile("classpath:application.yml");
System.out.println("文件路径:" + file.getAbsolutePath());
System.out.println("文件是否存在:" + file.exists());
// 读取内容
String content = Files.readString(file.toPath(), StandardCharsets.UTF_8);
System.out.println("文件内容:\n" + content);
// ==========================
// 2. 读取文件系统路径
// ==========================
File sysFile = ResourceUtils.getFile("file:/D:/test.txt");
System.out.println("\n系统文件:" + sysFile.exists());
// ==========================
// 3. 判断路径类型
// ==========================
System.out.println("\n是否是classpath: " + ResourceUtils.isClasspathUrl("classpath:abc.txt")); // true
System.out.println("是否是file: " + ResourceUtils.isFileUrl("file:/abc.txt")); // true
System.out.println("是否是URL: " + ResourceUtils.isUrl("http://www.baidu.com")); // true
}
}
// 读取 classpath 下模板 / 配置文件
// 读取模板文件
File template = ResourceUtils.getFile("classpath:templates/email.html");
String html = Files.readString(template.toPath());
// 配合上传 / 下载使用
// 读取默认头像
File defaultAvatar = ResourceUtils.getFile("classpath:static/avatar.png");
// 项目启动时加载初始化数据
@Component
public class DataLoader {
@PostConstruct
public void load() throws Exception {
File jsonFile = ResourceUtils.getFile("classpath:data/init.json");
// 解析并插入数据库
}
}
// 兼容 JAR 包的正确写法
ClassPathResource resource = new ClassPathResource("application.yml");
InputStream in = resource.getInputStream(); // 永远可用
15. StreamUtils
import org.springframework.util.StreamUtils;
// 流操作
byte[] data = StreamUtils.copyToByteArray(inputStream);
String text = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
StreamUtils.copy(inputStream, outputStream);
StreamUtils.copy("Hello", StandardCharsets.UTF_8, outputStream);
16. FileSystemUtils
import org.springframework.util.FileSystemUtils;
// 删除目录
boolean deleted = FileSystemUtils.deleteRecursively(new File("/tmp/test"));
// 复制目录
FileSystemUtils.copyRecursively(new File("source"), new File("target"));
17. ResourcePatternUtils
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
// 获取匹配资源
Resource[] resources = ResourcePatternUtils.getResourcePatternResolver(
new PathMatchingResourcePatternResolver())
.getResources("classpath*:META-INF/*.xml");
18. WebUtils
import org.springframework.web.util.WebUtils;
import javax.servlet.http.HttpServletRequest;
// 获取Cookie
Cookie cookie = WebUtils.getCookie(request, "sessionId");
// 获取请求路径
String path = WebUtils.getLookupPathForRequest(request);
// 从请求中获取参数
int pageSize = WebUtils.getIntParameter(request, "pageSize", 10);
19. UriUtils
import org.springframework.web.util.UriUtils;
// 编解码URI组件
String encoded = UriUtils.encodePathSegment("path with spaces", "UTF-8");
String decoded = UriUtils.decode(encoded, "UTF-8");
20. UriComponentsBuilder
import org.springframework.web.util.UriComponentsBuilder;
// 构建URI
URI uri = UriComponentsBuilder.fromHttpUrl("http://example.com")
.path("/products")
.queryParam("category", "books")
.queryParam("sort", "price")
.build()
.toUri();
21. ContentCachingRequestWrapper
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.http.HttpServletRequest;
ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper(request);
// 请求处理后
byte[] body = wrapper.getContentAsByteArray();
22. HtmlUtils
import org.springframework.web.util.HtmlUtils;
// HTML转义
String escaped = HtmlUtils.htmlEscape("<script>alert('XSS')</script>");
// <script>alert('XSS')</script>
// HTML反转义
String unescaped = HtmlUtils.htmlUnescape("<b>Bold</b>");
// <b>Bold</b>
23. Assert
import org.springframework.util.Assert;
// 常用断言
Assert.notNull(object, "Object must not be null");
Assert.hasText(name, "Name must not be empty");
Assert.isTrue(amount > 0, "Amount must be positive");
Assert.notEmpty(items, "Items must not be empty");
Assert.state(isInitialized, "Service is not initialized");
24. ObjectUtils
import org.springframework.util.ObjectUtils;
// 对象工具
boolean isEmpty = ObjectUtils.isEmpty(null); // true
boolean isEmpty2 = ObjectUtils.isEmpty(new String[0]); // true
String nullSafe = ObjectUtils.nullSafeToString(null); // "null"
boolean equals = ObjectUtils.nullSafeEquals(obj1, obj2);
// 默认值
String value = ObjectUtils.getOrDefault(null, "default");
25. NumberUtils
import org.springframework.util.NumberUtils;
// 数字转换
Integer parsed = NumberUtils.parseNumber("42", Integer.class);
Double converted = NumberUtils.convertNumberToTargetClass(42, Double.class);
26. DateTimeUtils
import org.springframework.format.datetime.DateTimeFormatUtils;
import java.util.Date;
// 格式化日期
String formatted = DateTimeFormatUtils.getDateTimeInstance().format(new Date());
27. StopWatch
import org.springframework.util.StopWatch;
// 计时工具
StopWatch watch = new StopWatch("TaskName");
watch.start("phase1");
// 执行任务1
Thread.sleep(100);
watch.stop();
watch.start("phase2");
// 执行任务2
Thread.sleep(200);
watch.stop();
// 输出报告
System.out.println(watch.prettyPrint());
System.out.println("Total time: " + watch.getTotalTimeMillis() + "ms");
28. DigestUtils
import org.springframework.util.DigestUtils;
// MD5哈希
String md5 = DigestUtils.md5DigestAsHex("password".getBytes());
// 文件MD5
String fileMd5;
try (InputStream is = new FileInputStream("file.txt")) {
fileMd5 = DigestUtils.md5DigestAsHex(is);
}
29. Base64Utils
import org.springframework.util.Base64Utils;
// Base64编解码
byte[] data = "Hello World".getBytes();
String encoded = Base64Utils.encodeToString(data);
byte[] decoded = Base64Utils.decodeFromString(encoded);
30. CryptoUtils
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
// 文本加密
String password = "secret";
String salt = "deadbeef";
TextEncryptor encryptor = Encryptors.text(password, salt);
String encrypted = encryptor.encrypt("Message");
String decrypted = encryptor.decrypt(encrypted);
31. JsonUtils
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
// JSON解析
JsonParser parser = JsonParserFactory.getJsonParser();
Map<String, Object> parsed = parser.parseMap("{"name":"John", "age":30}");
List<Object> parsedList = parser.parseList("[1, 2, 3]");
32. TypeUtils
import org.springframework.core.ResolvableType;
// 类型解析
ResolvableType type = ResolvableType.forClass(List.class);
ResolvableType elementType = type.getGeneric(0);
// 泛型类型处理
ResolvableType mapType = ResolvableType.forClassWithGenerics(
Map.class, String.class, Integer.class);
33. MappingJackson2HttpMessageConverter
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
// 自定义JSON转换器
ObjectMapper mapper = new ObjectMapper();
// 配置mapper
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper);
34. RandomStringUtils
import org.apache.commons.lang3.RandomStringUtils;
// 随机字符串生成
String random = RandomStringUtils.randomAlphanumeric(10);
String randomLetters = RandomStringUtils.randomAlphabetic(8);
String randomNumeric = RandomStringUtils.randomNumeric(6);
35. CompletableFutureUtils
import java.util.concurrent.CompletableFuture;
import java.util.List;
import java.util.stream.Collectors;
// 合并多个CompletableFuture结果
List<CompletableFuture<String>> futures = /* 多个异步操作 */;
CompletableFuture<List<String>> allResults = CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0]))
.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList()));
36. CacheControl
import org.springframework.http.CacheControl;
import java.util.concurrent.TimeUnit;
// 缓存控制
CacheControl cacheControl = CacheControl.maxAge(1, TimeUnit.HOURS)
.noTransform()
.mustRevalidate();
String headerValue = cacheControl.getHeaderValue();
37. AnnotationUtils
import org.springframework.core.annotation.AnnotationUtils;
// 查找注解
Component annotation = AnnotationUtils.findAnnotation(MyClass.class, Component.class);
// 获取注解属性
String value = AnnotationUtils.getValue(annotation, "value").toString();
// 合并注解
Component mergedAnnotation = AnnotationUtils.synthesizeAnnotation(
annotation, MyClass.class);
38. DefaultConversionService
import org.springframework.core.convert.support.DefaultConversionService;
// 类型转换
DefaultConversionService conversionService = new DefaultConversionService();
String strValue = "42";
Integer intValue = conversionService.convert(strValue, Integer.class);
import org.springframework.http.HttpHeaders;
// HTTP头处理
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
headers.setContentLength(1024);
headers.setCacheControl("max-age=3600");
// 通用
HttpHeaders.CONTENT_TYPE // "Content-Type"
HttpHeaders.CONTENT_LENGTH // "Content-Length"
HttpHeaders.CONTENT_DISPOSITION // "Content-Disposition"
HttpHeaders.ACCEPT // "Accept"
HttpHeaders.AUTHORIZATION // "Authorization"
HttpHeaders.LOCATION // "Location"(重定向)
// 跨域 CORS
HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN
HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS
HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS
// 缓存
HttpHeaders.CACHE_CONTROL
HttpHeaders.EXPIRES
HttpHeaders.ETAG
// 安全
HttpHeaders.WWW_AUTHENTICATE
HttpHeaders.SET_COOKIE
HttpHeaders.COOKIE
// 范围请求(断点续传)
HttpHeaders.RANGE
HttpHeaders.CONTENT_RANGE
HttpHeaders headers = new HttpHeaders();
// 设置单个值
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
// 设置常用类型(专用方法)
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
headers.setAuthorization("Bearer token123");
headers.setLocation(URI.create("/redirect"));
// 添加多个值
headers.add(HttpHeaders.SET_COOKIE, "a=1");
headers.add(HttpHeaders.SET_COOKIE, "b=2");
// 设置 Content-Type
headers.setContentType(MediaType.APPLICATION_JSON);
// 设置 Accept
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
// 设置 Bearer Token
headers.setBearerAuth("jwt-token-here");
// 设置 Basic Auth
headers.setBasicAuth("username", "password");
// 设置文件下载头
headers.setContentDisposition(
ContentDisposition.attachment()
.filename("user.xlsx")
.build()
);
// 设置缓存
headers.setCacheControl("no-cache");
// 设置跨域
headers.setAccessControlAllowOrigin("*");
// 文件下载(最常用)
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaTypeFactory.getMediaType("file.pdf")
.orElse(MediaType.APPLICATION_OCTET_STREAM));
headers.setContentDisposition(
ContentDisposition.attachment()
.filename("report.pdf", StandardCharsets.UTF_8)
.build()
);
return ResponseEntity.ok()
.headers(headers)
.body(resource);
// 跨域响应头
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE");
// RestTemplate 带请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<>(bodyJson, headers);
restTemplate.postForObject(url, request, String.class);
// WebClient 带请求头
webClient.get()
.uri("/user")
.headers(h -> h.setBearerAuth("token123"))
.retrieve();
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import java.util.Optional;
// 根据文件名推断媒体类型
Optional<MediaType> mediaType = MediaTypeFactory.getMediaType("document.pdf");
// application/pdf
// 根据文件名(含后缀)获取媒体类型。
MediaTypeFactory.getMediaType("report.pdf")
.ifPresent(mediaType -> {
// mediaType = application/pdf
});
// 带默认值(推荐)
MediaType mediaType = MediaTypeFactory.getMediaType("data.xyz")
.orElse(MediaType.APPLICATION_OCTET_STREAM);
//根据 Spring Resource(文件 / 类路径资源)自动取文件名解析。
Resource file = new FileSystemResource("D:/images/avatar.png");
MediaType type = MediaTypeFactory.getMediaType(file)
.orElse(MediaType.APPLICATION_OCTET_STREAM);
// 返回所有匹配的媒体类型(List)。
List<MediaType> types = MediaTypeFactory.getMediaTypes("file.html");
// 文件下载 / 响应设置 Content-Type
String filename = "用户清单.xlsx";
// 自动识别类型
MediaTypeFactory.getMediaType(filename)
.ifPresent(mediaType -> {
response.setContentType(mediaType.toString());
});
// 或带默认值
response.setContentType(
MediaTypeFactory.getMediaType(filename)
.map(MediaType::toString)
.orElse(MediaType.APPLICATION_OCTET_STREAM_VALUE)
);
// WebFlux 静态资源 / 文件上传
// 文件上传时校验类型
String originalFilename = file.getOriginalFilename();
MediaType mediaType = MediaTypeFactory.getMediaType(originalFilename)
.orElse(MediaType.APPLICATION_OCTET_STREAM);
if (mediaType.isCompatibleWith(MediaType.IMAGE_PNG)) {
// 处理图片
}
// 接口返回文件流
@GetMapping("/download/{filename}")
public ResponseEntity<Resource> download(@PathVariable String filename) {
Resource resource = ...;
MediaType mediaType = MediaTypeFactory.getMediaType(filename)
.orElse(MediaType.APPLICATION_OCTET_STREAM);
return ResponseEntity.ok()
.contentType(mediaType)
.body(resource);
}
.html → text/html
.json → application/json
.xml → application/xml
.pdf → application/pdf
.png/.jpg → image/png / image/jpeg
.txt → text/plain
.zip → application/zip
.mp4 → video/mp4
.css/.js → text/css / application/javascript
41. MimeTypeUtils
import org.springframework.util.MimeTypeUtils;
// MIME类型常量和解析
boolean isCompatible = MimeTypeUtils.APPLICATION_JSON.isCompatibleWith(
MimeTypeUtils.APPLICATION_JSON_UTF8);
// 最常用
MimeTypeUtils.TEXT_HTML; // text/html
MimeTypeUtils.TEXT_PLAIN; // text/plain
MimeTypeUtils.APPLICATION_JSON; // application/json
MimeTypeUtils.APPLICATION_XML; // application/xml
MimeTypeUtils.MULTIPART_FORM_DATA; // multipart/form-data
// 其他
MimeTypeUtils.APPLICATION_OCTET_STREAM; // 二进制流
MimeTypeUtils.IMAGE_PNG; // image/png
MimeTypeUtils.IMAGE_JPEG; // image/jpeg
MimeTypeUtils.APPLICATION_FORM_URLENCODED; // form表单
public static void main(String[] args) {
// ==========================
// 1. 解析字符串为 MimeType 对象
// ==========================
MimeType mimeType = MimeTypeUtils.parseMimeType("application/json;charset=UTF-8");
System.out.println("类型:" + mimeType.getType()); // application
System.out.println("子类型:" + mimeType.getSubtype()); // json
System.out.println("编码:" + mimeType.getCharset()); // UTF-8
// ==========================
// 2. 批量解析
// ==========================
List<MimeType> mimeTypeList = MimeTypeUtils.parseMimeTypes(
"text/html,application/json,text/plain"
);
// ==========================
// 3. 判断是否包含指定类型(核心!)
// ==========================
// 用法:MimeTypeUtils.includes(支持的类型, 请求的类型)
// 例:支持 json,请求也是 json → true
boolean includes1 = MimeTypeUtils.includes(
MimeTypeUtils.APPLICATION_JSON,
MimeTypeUtils.parseMimeType("application/json")
);
// 例:支持 */*,请求任意类型 → true
boolean includes2 = MimeTypeUtils.includes(
MimeTypeUtils.ALL,
MimeTypeUtils.APPLICATION_JSON
);
// 例:支持 text/*,请求 text/plain → true
boolean includes3 = MimeTypeUtils.includes(
MimeTypeUtils.TEXT_HTML,
MimeTypeUtils.TEXT_PLAIN
);
// ==========================
// 4. 判断是否兼容(支持类型、通配符匹配)
// ==========================
boolean compatible = MimeTypeUtils.isCompatible(
MimeTypeUtils.parseMimeType("application/*"),
MimeTypeUtils.APPLICATION_JSON
); // true
// ==========================
// 5. 比较优先级(用于内容协商)
// ==========================
MimeTypeUtils.SPECIFICITY_COMPARATOR.compare(
MimeTypeUtils.APPLICATION_JSON,
MimeTypeUtils.ALL
);
// ==========================
// 6. 转换为字符串
// ==========================
String str = MimeTypeUtils.toString(
List.of(MimeTypeUtils.APPLICATION_JSON, MimeTypeUtils.TEXT_PLAIN)
);
// 输出:application/json, text/plain
// ==========================
// 7. 常用常量判断(最常用)
// ==========================
boolean isJson = mimeType.isCompatibleWith(MimeTypeUtils.APPLICATION_JSON);
boolean isText = mimeType.isCompatibleWith(MimeTypeUtils.TEXT_PLAIN);
}
// 判断接口请求是否为 JSON
String contentType = request.getContentType();
MimeType mimeType = MimeTypeUtils.parseMimeType(contentType);
if (mimeType.isCompatibleWith(MimeTypeUtils.APPLICATION_JSON)) {
// 处理 JSON
}
// 接口返回时设置正确 Content-Type
response.setContentType(MimeTypeUtils.APPLICATION_JSON_VALUE);
// 解析上传文件类型
if (contentType.isCompatibleWith(MimeTypeUtils.MULTIPART_FORM_DATA)) {
// 文件上传
}
// 内容协商(Spring 自动选择返回 JSON/XML)
List<MimeType> accepted = MimeTypeUtils.parseMimeTypes(
request.getHeader("Accept")
);
42. WebClientUtils
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
// 创建WebClient
WebClient webClient = WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader("Authorization", "Bearer token")
.filter(ExchangeFilterFunction.ofRequestProcessor(
clientRequest -> {
// 请求处理
return Mono.just(clientRequest);
}))
.build();
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
// 创建 WebClient(3 种方式)
// 1. 快速创建
WebClient client = WebClient.create();
// 2. 指定基础URL(最常用)
WebClient client = WebClient.create("http://localhost:8080");
// 3. 自定义(过滤器、默认Header、超时等)
WebClient customClient = WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader("token", "123456")
.filter(ExchangeFilterFunction.ofRequestProcessor(
req -> Mono.just(req.mutate().header("from", "webclient").build())
))
.build();
// GET 请求 异步(推荐)
Mono<String> mono = client.get()
.uri("/user/{id}", 100)
.retrieve()
.bodyToMono(String.class);
// 订阅获取结果
mono.subscribe(res -> System.out.println("结果:" + res));
// GET 请求 同步(block)
String res = client.get()
.uri("/user/100")
.retrieve()
.bodyToMono(String.class)
.block(); // 阻塞等待
// 获取对象
User user = client.get()
.uri("/user/100")
.retrieve()
.bodyToMono(User.class)
.block();
// 获取列表
List<User> list = client.get()
.uri("/users")
.retrieve()
.bodyToFlux(User.class)
.collectList()
.block();
// POST 请求(JSON)
// 构建参数
User user = new User();
user.setName("张三");
// 发送
User res = client.post()
.uri("/user")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(user) // 自动转JSON
.retrieve()
.bodyToMono(User.class)
.block();
// 设置请求头
client.get()
.uri("/test")
.header("Authorization", "Bearer token123")
.retrieve();
// QueryParam
client.get()
.uri(uriBuilder -> uriBuilder
.path("/search")
.queryParam("keyword", "webclient")
.queryParam("page", 1)
.build())
.retrieve();
// 错误处理(非常重要)
String res = client.get()
.uri("/user/999")
.retrieve()
// 4xx、5xx 转为异常
.onStatus(HttpStatus::isError, response ->
Mono.error(new RuntimeException("请求失败:" + response.statusCode()))
)
.bodyToMono(String.class)
.onErrorReturn("默认值")
.block();
// exchange () 高级用法(获取完整响应)
ResponseEntity<String> res = client.get()
.uri("/test")
.exchangeToMono(response -> {
HttpStatus status = response.statusCode();
return response.bodyToMono(String.class)
.map(body -> ResponseEntity.status(status).body(body));
})
.block();
// 文件上传(multipart)
File file = new File("test.txt");
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("file", new FileSystemResource(file));
client.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(parts)
.retrieve()
.bodyToMono(String.class)
.block();
// 文件下载
Resource resource = client.get()
.uri("/download")
.retrieve()
.bodyToMono(Resource.class)
.block();
43. PropertySourceUtils
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
// 添加属性源
StandardEnvironment env = new StandardEnvironment();
Map<String, Object> map = new HashMap<>();
map.put("app.name", "MyApp");
env.getPropertySources().addFirst(new MapPropertySource("my-properties", map));
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import java.util.HashMap;
import java.util.Map;
public class PropertySourceDemo {
public static void main(String[] args) {
// ==========================
// 1. 创建基于 Map 的配置源
// ==========================
Map<String, Object> configMap = new HashMap<>();
configMap.put("app.name", "demo");
configMap.put("app.port", 8080);
configMap.put("app.env", "dev");
// 创建 PropertySource:名称 + 数据源
PropertySource<?> propertySource = new MapPropertySource("myCustomConfig", configMap);
// ==========================
// 2. 核心方法
// ==========================
// 1. 获取配置源名称(用于区分优先级、日志)
String name = propertySource.getName();
System.out.println("配置源名称:" + name); // myCustomConfig
// 2. 获取原始数据源(Map/Properties等)
Object source = propertySource.getSource();
System.out.println("原始数据源:" + source);
// 3. 获取配置值(最核心方法)
String appName = (String) propertySource.getProperty("app.name");
Integer appPort = (Integer) propertySource.getProperty("app.port");
System.out.println("app.name = " + appName);
System.out.println("app.port = " + appPort);
// 4. 判断是否包含某个key
boolean contains = propertySource.containsProperty("app.env");
System.out.println("包含 app.env:" + contains); // true
// 5. 判断是否相等(基于名称)
boolean equals = propertySource.equals(new MapPropertySource("myCustomConfig", new HashMap<>()));
System.out.println("名称相等即相等:" + equals); // true
// ==========================
// 3. 把配置源加入 Spring 环境
// ==========================
// StandardEnvironment env = new StandardEnvironment();
// env.getPropertySources().addFirst(propertySource); // 优先级最高
// env.getPropertySources().addLast(propertySource); // 优先级最低
}
}
// ==========================
// 【进阶】自定义 PropertySource(从数据库/Redis加载配置)
// 用途:动态配置中心
// ==========================
class DbPropertySource extends PropertySource<Object> {
public DbPropertySource(String name) {
super(name);
}
// 从数据库读取配置
@Override
public Object getProperty(String name) {
// 模拟 DB 查询
if ("db.url".equals(name)) {
return "jdbc:mysql://localhost:3306/test";
}
return null;
}
// 是否包含key
@Override
public boolean containsProperty(String name) {
return "db.url".equals(name);
}
}
// 1. 自定义 PropertySource
// 2. 注册到 Spring 环境
@Configuration
public class DbConfig {
@Bean
public EnvironmentCustomizer environmentCustomizer() {
return env -> {
DbPropertySource dbSource = new DbPropertySource("dbConfig");
env.getPropertySources().addFirst(dbSource); // 最高优先级
};
}
}
// 读取系统环境变量
PropertySource<?> envSource = new SystemEnvironmentPropertySource("systemEnvironment", System.getenv());
String path = (String) envSource.getProperty("PATH");
// 读取 Properties 文件
Properties props = ...;
PropertySource<?> propSource = new PropertiesPropertySource("appProps", props);
44. EventPublishingUtils
import org.springframework.context.ApplicationEventPublisher;
// 发布事件
ApplicationEventPublisher publisher = /* 获取发布器 */;
publisher.publishEvent(new CustomEvent("Something happened"));
45. LocaleContextHolder
import org.springframework.context.i18n.LocaleContextHolder;
import java.util.Locale;
// 获取/设置当前语言环境
Locale currentLocale = LocaleContextHolder.getLocale();
LocaleContextHolder.setLocale(Locale.FRENCH);
public static void main(String[] args) {
// ==========================
// 1. 获取当前 Locale(最常用)
// ==========================
// 默认获取:无设置时返回系统默认 Locale
Locale currentLocale = LocaleContextHolder.getLocale();
System.out.println("当前语言:" + currentLocale); // 系统默认(如 zh_CN)
// ==========================
// 2. 设置当前 Locale
// ==========================
// 方式1:直接设置 Locale(推荐)
LocaleContextHolder.setLocale(Locale.US); // 英文
LocaleContextHolder.setLocale(Locale.CHINA); // 中文
LocaleContextHolder.setLocale(Locale.JAPAN); // 日文
// 方式2:带时区设置
LocaleContextHolder.setLocale(Locale.US, TimeZone.getTimeZone("America/New_York"));
// ==========================
// 3. 获取/设置 时区 TimeZone
// ==========================
TimeZone timeZone = LocaleContextHolder.getTimeZone();
LocaleContextHolder.setTimeZone(TimeZone.getTimeZone("GMT+8"));
// ==========================
// 4. 重置/清除(必须手动清除!)
// ==========================
// 重置为系统默认
LocaleContextHolder.resetLocaleContext();
// 直接清空(推荐在 finally 中调用)
LocaleContextHolder.setLocale(null);
// ==========================
// 5. 高级:获取完整上下文
// ==========================
var localeContext = LocaleContextHolder.getLocaleContext();
System.out.println("上下文区域:" + localeContext.getLocale());
}
@GetMapping("/hello")
public String hello() {
// 获取当前请求的语言(中文/英文/日文...)
Locale locale = LocaleContextHolder.getLocale();
if (locale.equals(Locale.CHINA)) {
return "你好";
} else if (locale.equals(Locale.US)) {
return "Hello";
}
return "Hi";
}
// 切换为中文
LocaleContextHolder.setLocale(Locale.CHINA);
// 执行业务...
// 必须清除!防止线程池复用导致错乱
LocaleContextHolder.resetLocaleContext();
@Autowired
private MessageSource messageSource;
public String getMessage(String code) {
// 自动获取当前 Locale 读取对应语言配置
return messageSource.getMessage(code, null, LocaleContextHolder.getLocale());
}
try {
LocaleContextHolder.setLocale(Locale.US);
// 业务逻辑
} finally {
// 必须清除
LocaleContextHolder.resetLocaleContext();
}
46. AopUtils
import org.springframework.aop.support.AopUtils;
// AOP工具方法
boolean isAopProxy = AopUtils.isAopProxy(bean);
boolean isCglibProxy = AopUtils.isCglibProxy(bean);
Class<?> targetClass = AopUtils.getTargetClass(bean);
// 1. 创建代理对象
UserService target = new UserService();
ProxyFactory factory = new ProxyFactory(target);
factory.setProxyTargetClass(true); // CGLIB
UserService proxy = (UserService) factory.getProxy();
// ======================================================
// 1. 判断是否是 Spring 代理对象(JDK/CGLIB)
// ======================================================
boolean isAopProxy = AopUtils.isAopProxy(proxy); // true
boolean isTargetProxy = AopUtils.isAopProxy(target); // false
// ======================================================
// 2. 判断是 JDK 代理还是 CGLIB 代理
// ======================================================
boolean isJdk = AopUtils.isJdkDynamicProxy(proxy); // false
boolean isCglib = AopUtils.isCglibProxy(proxy); // true
// ======================================================
// 3. 获取目标类(最常用!)
// ======================================================
Class<?> targetClass = AopUtils.getTargetClass(proxy);
System.out.println("目标类:" + targetClass); // UserService
// ======================================================
// 4. 获取最底层目标对象
// ======================================================
Object realTarget = AopUtils.getTargetObject(proxy);
System.out.println("真实对象:" + realTarget); // UserService@xxx
// ======================================================
// 5. 判断方法是否 equals / hashCode / toString
// ======================================================
try {
Method test = UserService.class.getMethod("test");
Method equals = Object.class.getMethod("equals", Object.class);
System.out.println(AopUtils.isEqualsMethod(test)); // false
System.out.println(AopUtils.isEqualsMethod(equals)); // true
System.out.println(AopUtils.isHashCodeMethod(test)); // false
System.out.println(AopUtils.isToStringMethod(test)); // false
} catch (NoSuchMethodException e) {}
// ======================================================
// 6. 判断方法是否适合被 AOP 拦截
// ======================================================
// 规则:非 static、非 final、非 private
try {
Method test = UserService.class.getMethod("test");
Method finalMethod = UserService.class.getMethod("finalMethod");
Method privateMethod = UserService.class.getDeclaredMethod("privateMethod");
System.out.println(AopUtils.isAopCandidate(test)); // true
System.out.println(AopUtils.isAopCandidate(finalMethod)); // false
System.out.println(AopUtils.isAopCandidate(privateMethod));// false
} catch (NoSuchMethodException e) {}
47. ProxyUtils
import org.springframework.aop.framework.ProxyFactory;
// 创建代理
ProxyFactory factory = new ProxyFactory(targetObject);
factory.addInterface(MyInterface.class);
factory.addAdvice(new MyMethodInterceptor());
MyInterface proxy = (MyInterface) factory.getProxy();
// ======================
// 1. 目标类(被代理对象)
// ======================
class UserService {
public void add() {
System.out.println("执行目标方法:添加用户");
}
}
// ======================
// 主程序:ProxyFactory 使用
// ======================
public class ProxyFactoryDemo {
public static void main(String[] args) {
// 1. 创建目标对象
UserService target = new UserService();
// 2. 创建 ProxyFactory 代理工厂
ProxyFactory factory = new ProxyFactory();
// ======================
// 核心方法设置
// ======================
factory.setTarget(target); // 设置目标对象
factory.addAdvice(aroundAdvice()); // 添加增强(通知)
factory.setProxyTargetClass(true); // 强制使用 CGLIB 代理(代理类)
// 3. 获取代理对象
UserService proxy = (UserService) factory.getProxy();
// 4. 执行代理方法(自动增强)
proxy.add();
}
// ======================
// 环绕通知(最常用)
// ======================
private static Advice aroundAdvice() {
return (MethodInterceptor) invocation -> {
System.out.println("【前置】方法执行前");
Object result = invocation.proceed(); // 执行目标方法
System.out.println("【后置】方法执行后");
return result;
};
}
// ======================
// 前置通知(示例)
// ======================
private static BeforeAdvice beforeAdvice() {
return new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) {
System.out.println("【前置通知】");
}
};
}
}
环绕通知(最强大)
MethodInterceptor around = invocation -> {
// 前
Object res = invocation.proceed();
// 后
return res;
};
前置通知
MethodBeforeAdvice before = (m,a,target)->{};
异常通知
ThrowsAdvice throwsAdvice = new ThrowsAdvice() {
public void afterThrowing(Exception ex) {}
};
后置通知
AfterReturningAdvice after = (returnValue, m,a,target)->{};
// 任意类都能被代理增强
YourService target = new YourService();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvice(aroundAdvice()); // 日志增强
YourService proxy = (YourService) factory.getProxy();
proxy.doBusiness();
factory.addAdvice(transactionAdvice()); // 事务通知
MethodInterceptor checkPermission = invocation -> {
if(!isLogin()) throw new RuntimeException("未登录");
return invocation.proceed();
};
48. ClassPathScanningCandidateComponentProvider
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
// 扫描类路径
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(true);
scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));
Set<BeanDefinition> beans = scanner.findCandidateComponents("org.example");
49. YamlUtils
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
// 解析YAML文件
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("application.yml"));
Properties properties = yaml.getObject();
// 1. 创建工厂实例
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
// 2. 设置 YAML 文件来源(类路径下)
factory.setResources(new ClassPathResource("application.yml"));
// 3. 解析并获取 Properties 对象
Properties props = factory.getObject();
// 使用
System.out.println(props.getProperty("spring.datasource.url"));
System.out.println(props.getProperty("my.list[0]")); // 读取列表第一个元素
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
// --- 核心方法 ---
// 1. 同时加载多个 YAML 文件(后面的会覆盖前面的同名键)
Resource resource1 = new ClassPathResource("config/application.yml");
Resource resource2 = new FileSystemResource("/etc/config/custom.yml");
factory.setResources(resource1, resource2);
// 2. 关闭单例模式(每次 getObject() 都重新解析)
factory.setSingleton(false);
// 3. 解析文档(第一次调用时执行,懒加载)
Properties props = factory.getObject();
// 4. 获取对象类型(固定返回 Properties.class)
Class<?> objectType = factory.getObjectType();
System.out.println("返回类型: " + objectType); // 输出:class java.util.Properties
// 5. 判断是否为单例
boolean isSingleton = factory.isSingleton();
System.out.println("是否单例: " + isSingleton); // 输出:false
// 直接读取并使用
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ClassPathResource("application.yml"));
Properties props = factory.getObject();
String url = props.getProperty("spring.datasource.url");
int timeout = Integer.parseInt(props.getProperty("server.timeout", "5000")); // 带默认值
@Configuration
public class AppConfig {
@Bean
public Properties yamlProperties() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ClassPathResource("application.yml"));
return factory.getObject();
}
}