spring里的工具类
所属分类 spring
浏览量 109
org.springframework.util
org.springframework.web.util
ObjectUtils:提供了对象操作的方法,如判断对象是否为空、比较对象等。
StringUtils:提供了丰富的字符串操作方法,如字符串拼接、替换、截取等。
CollectionUtils:提供了集合操作的方法,如集合的非空判断、转换、合并、查找等。
ArrayUtils:提供了数组操作的方法,如数组的复制、查找、排序等。
Assert:提供了断言功能,用于在代码中进行条件检查,确保程序的正确性。
ResourceUtils:提供了资源文件操作的方法,如获取资源文件的路径、读取资源文件内容等。
ReflectionUtils:提供了反射操作的方法,如获取类的字段、方法、注解等。
FileCopyUtils:提供了文件复制操作的方法,如文件的读取、写入、复制等。
DigestUtils:提供了摘要算法操作的方法,如MD5、SHA等算法的计算。
SerializationUtils:提供了序列化和反序列化操作的方法,如对象的序列化、反序列化等。
org.springframework.web.util.HtmlUtils
org.springframework.util.PropertyPlaceholderHelper
org.springframework.core.annotation.AnnotationUtils
org.springframework.core.io.support.PropertiesLoaderUtils
Spring常用工具类
一、工具类
1、断言
2、对象、数组、集合
2.1 Collections/Lists/Objects
2.2 ObjectUtils
2.3 StringUtils
2.4 CollectionUtils
2.5 BooleanUtils
3、文件、资源、IO 流
3.1 IOUtils(常用)
3.2 FileCopyUtils
3.3 ResourceUtils
3.4 StreamUtils
4、反射、AOP
4.1 ReflectionUtils
4.2 AopUtils
4.3 AopContext
4.4 AOP举例
4.5 ClassUtils(常用)
4.6 BeanUtils(常用)
5、编解码、字符编码
5.1 Base64Utils
5.2 StandardCharsets
5.3 DigestUtils
5.4 SerializationUtils
6、日志与网络
6.1 MDC
6.2 HttpStatus
1、断言
断言是一个逻辑判断,用于检查不应该发生的情况
Assert 关键字在 JDK1.4 中引入,可通过 JVM 参数-enableassertions开启
SpringBoot 中提供了 Assert 断言工具类,通常用于数据合法性检查
// 要求参数 object 必须为非空(Not Null),否则抛出异常,不予放行
// 参数 message 参数用于定制异常信息。
void notNull(Object object, String message)
// 要求参数必须空(Null),否则抛出异常,不予『放行』。
// 和 notNull() 方法断言规则相反
void isNull(Object object, String message)
// 要求参数必须为真(True),否则抛出异常,不予『放行』。
void isTrue(boolean expression, String message)
// 要求参数(List/Set)必须非空(Not Empty),否则抛出异常,不予放行
void notEmpty(Collection collection, String message)
// 要求参数(String)必须有长度(即,Not Empty),否则抛出异常,不予放行
void hasLength(String text, String message)
// 要求参数(String)必须有内容(即,Not Blank),否则抛出异常,不予放行
void hasText(String text, String message)
// 要求参数是指定类型的实例,否则抛出异常,不予放行
void isInstanceOf(Class type, Object obj, String message)
// 要求参数 `subType` 必须是参数 superType 的子类或实现类,否则抛出异常,不予放行
void isAssignable(Class superType, Class subType, String message)
2、对象、数组、集合
2.1 Collections/Lists/Objects
/**===========Collections==================*/
// java.util包下的Collections类,该类主要用于操作集合或者返回集合
// 降序
Collections.reverse(list);
// 获取最大值
Integer max = Collections.max(list);
// 将ArrayList转换成线程安全集合
List integers = Collections.synchronizedList(list);
// 返回空集合
Collections.emptyList();
//二分查找
int i = Collections.binarySearch(list, 3);
// 转换成不可修改集合
List integers = Collections.unmodifiableList(list);
/**===========Lists==================*/
// com.google.common.collect包下的集合工具:Lists 会更加好用
// 快速初始化
List list = Lists.newArrayList(1, 2, 3);
//将两个集合做笛卡尔积
List> productList = Lists.cartesianProduct(list1,list2);
// 分页
List> partitionList = Lists.partition(list, 2);
// 流处理
List transformList = Lists.transform(list, x -> x.toUpperCase());
// 反转
List reverseList = Lists.reverse(list);
/**===========Objects==================*/
Objects.isNull(integer)
Objects.nonNull(integer)
// 对象为空抛异常
Objects.requireNonNull(integer1, () -> "参数不能为空");
2.2 ObjectUtils
获取对象的基本信息
// 获取对象的类名。参数为 null 时,返回字符串:"null"
String nullSafeClassName(Object obj)
// 参数为 null 时,返回 0
int nullSafeHashCode(Object object)
// 参数为 null 时,返回字符串:"null"
String nullSafeToString(boolean[] array)
// 获取对象 HashCode(十六进制形式字符串)。参数为 null 时,返回 0
String getIdentityHexString(Object obj)
// 获取对象的类名和 HashCode。 参数为 null 时,返回字符串:""
String identityToString(Object obj)
// 相当于 toString()方法,但参数为 null 时,返回字符串:""
String getDisplayString(Object obj)
判断工具
// 判断数组是否为空
boolean isEmpty(Object[] array)
// 判断参数对象是否是数组
boolean isArray(Object obj)
// 判断数组中是否包含指定元素
boolean containsElement(Object[] array, Object element)
// 相等,或同为 null时,返回 true
boolean nullSafeEquals(Object o1, Object o2)
/*
判断参数对象是否为空,判断标准为:
Optional: Optional.empty()
Array: length == 0
CharSequence: length == 0
Collection: Collection.isEmpty()
Map: Map.isEmpty()
*/
boolean isEmpty(Object obj)
其他工具方法
// 向参数数组的末尾追加新元素,并返回一个新数组
A[] addObjectToArray(A[] array, O obj)
// 原生基础类型数组 --> 包装类数组
Object[] toObjectArray(Object source)
2.3 StringUtils
字符串判断工具
// 判断字符串是否为 null,或 ""。注意,包含空白符的字符串为非空
boolean isEmpty(Object str)
// 判断字符串是否是以指定内容结束。忽略大小写
boolean endsWithIgnoreCase(String str, String suffix)
// 判断字符串是否已指定内容开头。忽略大小写
boolean startsWithIgnoreCase(String str, String prefix) // 是否包含空白符
boolean containsWhitespace(String str)
// 判断字符串非空且长度不为 0,即,Not Empty
boolean hasLength(CharSequence str)
// 判断字符串是否包含实际内容,即非仅包含空白符,也就是 Not Blank
boolean hasText(CharSequence str)
// 判断字符串指定索引处是否包含一个子串。
boolean substringMatch(CharSequence str, int index, CharSequence substring)
// 计算一个字符串中指定子串的出现次数
int countOccurrencesOf(String str, String sub)
字符串操作工具
// 查找并替换指定子串
String replace(String inString, String oldPattern, String newPattern)
// 去除尾部的特定字符
String trimTrailingCharacter(String str, char trailingCharacter) // 去除头部的特定字符
String trimLeadingCharacter(String str, char leadingCharacter)
// 去除头部的空白符
String trimLeadingWhitespace(String str)
// 去除头部的空白符
String trimTrailingWhitespace(String str)
// 去除头部和尾部的空白符
String trimWhitespace(String str)
// 删除开头、结尾和中间的空白符
String trimAllWhitespace(String str)
// 删除指定子串
String delete(String inString, String pattern)
// 删除指定字符(可以是多个)
String deleteAny(String inString, String charsToDelete)
// 对数组的每一项执行 trim() 方法
String[] trimArrayElements(String[] array)
// 将 URL 字符串进行解码
String uriDecode(String source, Charset charset)
路径相关工具方法
// 解析路径字符串,优化其中的 “..”
String cleanPath(String path)
// 解析路径字符串,解析出文件名部分
String getFilename(String path)
// 解析路径字符串,解析出文件后缀名
String getFilenameExtension(String path)
// 比较两个两个字符串,判断是否是同一个路径。会自动处理路径中的 “..”
boolean pathEquals(String path1, String path2)
// 删除文件路径名中的后缀部分
String stripFilenameExtension(String path) // 以 “. 作为分隔符,获取其最后一部分
String unqualify(String qualifiedName)
// 以指定字符作为分隔符,获取其最后一部分
String unqualify(String qualifiedName, char separator)
2.4 CollectionUtils
集合判断工具
// 判断 List/Set 是否为空
boolean isEmpty(Collection> collection)
// 判断 Map 是否为空
boolean isEmpty(Map,?> map)
// 判断 List/Set 中是否包含某个对象
boolean containsInstance(Collection> collection, Object element)
// 以迭代器的方式,判断 List/Set 中是否包含某个对象
boolean contains(Iterator> iterator, Object element)
// 判断 List/Set 是否包含某些对象中的任意一个
boolean containsAny(Collection> source, Collection> candidates)
// 判断 List/Set 中的每个元素是否唯一。即 List/Set 中不存在重复元素
boolean hasUniqueObject(Collection> collection)
集合操作工具
// 将 Array 中的元素都添加到 List/Set 中
// 将 Properties 中的键值对都添加到 Map 中
void mergeArrayIntoCollection(Object array, Collection collection)
void mergePropertiesIntoMap(Properties props, Map map)
// 返回 List 中最后一个元素
T lastElement(List list) // 返回 Set 中最后一个元素
T lastElement(Set set) // 返回参数 candidates 中第一个存在于参数 source 中的元素
E findFirstMatch(Collection> source, Collection candidates)
// 返回 List/Set 中指定类型的元素。
T findValueOfType(Collection> collection, Class type)
// 返回 List/Set 中指定类型的元素。如果第一种类型未找到,则查找第二种类型,以此类推
Object findValueOfType(Collection> collection, Class>[] types)
// 返回 List/Set 中元素的类型
Class> findCommonElementType(Collection> collection)
2.5 BooleanUtils
布尔判断工具(无须判空了)
// 判断某个参数的值是true或false
BooleanUtils.isTrue(aBoolean)
BooleanUtils.isFalse(aBoolean)
// 判断某个参数不为true,即是null或者false
BooleanUtils.isNotTrue(aBoolean)
BooleanUtils.isNotFalse(aBoolean)
// 转换成数字
BooleanUtils.toInteger(aBoolean)
// 转成boolean对象
BooleanUtils.toBoolean(aBoolean)
3、文件、资源、IO 流
3.1 IOUtils(常用)
// 读取文件,读取某个txt文件中的数据
String str = IOUtils.toString(new FileInputStream("/temp/a.txt"), StandardCharsets.UTF_8);
// 写入文件,将某个字符串的内容,写入到指定文件当中
String str = "abcde";
IOUtils.write(str, new FileOutputStream("/temp/b.tx"), StandardCharsets.UTF_8);
// 文件拷贝,将某个文件中的所有内容,都拷贝到另一个文件当中
IOUtils.copy(new FileInputStream("/temp/a.txt"), new FileOutputStream("/temp/b.txt"));
// 读取文件内容到字节数组
byte[] bytes = IOUtils.toByteArray(new FileInputStream("/temp/a.txt"));
// 读取文件,读取某个txt文件中的数据
String str = IOUtils.toString(new FileInputStream("/temp/a.txt"), StandardCharsets.UTF_8);
// 写入文件,将某个字符串的内容,写入到指定文件当中
String str = "abcde";
IOUtils.write(str, new FileOutputStream("/temp/b.tx"), StandardCharsets.UTF_8);
// 文件拷贝,将某个文件中的所有内容,都拷贝到另一个文件当中
IOUtils.copy(new FileInputStream("/temp/a.txt"), new FileOutputStream("/temp/b.txt"));
// 读取文件内容到字节数组
byte[] bytes = IOUtils.toByteArray(new FileInputStream("/temp/a.txt"));
3.2 FileCopyUtils
输入
// 从文件中读入到字节数组中
byte[] copyToByteArray(File in)
// 从输入流中读入到字节数组中
byte[] copyToByteArray(InputStream in)
// 从输入流中读入到字符串中
String copyToString(Reader in)
// 从字节数组到文件
void copy(byte[] in, File out)
// 从文件到文件
int copy(File in, File out)
// 从字节数组到输出流
void copy(byte[] in, OutputStream out) // 从输入流到输出流
int copy(InputStream in, OutputStream out) // 从输入流到输出流
int copy(Reader in, Writer out)
// 从字符串到输出流
void copy(String in, Writer out)
3.3 ResourceUtils
从资源路径获取文件
// 判断字符串是否是一个合法的 URL 字符串。
static boolean isUrl(String resourceLocation)
// 获取 URL
// 获取文件(在 JAR 包内无法正常使用,需要是一个独立的文件)
static URL getURL(String resourceLocation)
static File getFile(String resourceLocation)
Resource
// 文件系统资源 D:...
FileSystemResource
// URL 资源,如 file://... http://...
UrlResource
// 类路径下的资源,classpth:...
ClassPathResource
// Web 容器上下文中的资源(jar 包、war 包)
ServletContextResource
// 判断资源是否存在
boolean exists()
// 从资源中获得 File 对象
File getFile()
// 从资源中获得 URI 对象
URI getURI()
// 从资源中获得 URI 对象
URL getURL()
// 获得资源的 InputStream
InputStream getInputStream()
// 获得资源的描述信息
String getDescription()
3.4 StreamUtils
输入
void copy(byte[] in, OutputStream out)
int copy(InputStream in, OutputStream out)
void copy(String in, Charset charset, OutputStream out)
long copyRange(InputStream in, OutputStream out, long start, long end)
输出
byte[] copyToByteArray(InputStream in)
String copyToString(InputStream in, Charset charset)
// 舍弃输入流中的内容
int drain(InputStream in)
4、反射、AOP
4.1 ReflectionUtils
获取方法
// 在类中查找指定方法
Method findMethod(Class> clazz, String name)
// 同上,额外提供方法参数类型作查找条件
Method findMethod(Class> clazz, String name, Class>... paramTypes)
// 获得类中所有方法,包括继承而来的
Method[] getAllDeclaredMethods(Class> leafClass)
// 在类中查找指定构造方法
Constructor accessibleConstructor(Class clazz, Class>... parameterTypes)
// 是否是 equals() 方法
boolean isEqualsMethod(Method method)
// 是否是 hashCode() 方法
boolean isHashCodeMethod(Method method)
// 是否是 toString() 方法
boolean isToStringMethod(Method method)
// 是否是从 Object 类继承而来的方法
boolean isObjectMethod(Method method)
// 检查一个方法是否声明抛出指定异常
boolean declaresException(Method method, Class> exceptionType)
// 执行方法
Object invokeMethod(Method method, Object target)
// 同上,提供方法参数
Object invokeMethod(Method method, Object target, Object... args)
// 取消 Java 权限检查。以便后续执行该私有方法
void makeAccessible(Method method)
// 取消 Java 权限检查。以便后续执行私有构造方法
void makeAccessible(Constructor> ctor)
获取字段
// 在类中查找指定属性
Field findField(Class> clazz, String name)
// 同上,多提供了属性的类型
Field findField(Class> clazz, String name, Class> type)
// 是否为一个 "public static final" 属性
boolean isPublicStaticFinal(Field field)
设置字段
// 获取 target 对象的 field 属性值
Object getField(Field field, Object target)
// 设置 target 对象的 field 属性值,值为 value
void setField(Field field, Object target, Object value)
// 同类对象属性对等赋值
void shallowCopyFieldState(Object src, Object dest)
// 取消 Java 的权限控制检查。以便后续读写该私有属性
void makeAccessible(Field field)
// 对类的每个属性执行 callback
void doWithFields(Class> clazz, ReflectionUtils.FieldCallback fc)
// 同上,多了个属性过滤功能。
void doWithFields(Class> clazz, ReflectionUtils.FieldCallback fc,
ReflectionUtils.FieldFilter ff)
// 同上,但不包括继承而来的属性
void doWithLocalFields(Class> clazz, ReflectionUtils.FieldCallback fc)
4.2 AopUtils
判断代理类型
// 判断是不是 Spring 代理对象
boolean isAopProxy()
// 判断是不是 jdk 动态代理对象
isJdkDynamicProxy()
// 判断是不是 CGLIB 代理对象
boolean isCglibProxy()
获取被代理对象的 class
// 获取被代理的目标 class
Class> getTargetClass()
4.3 AopContext
获取当前对象的代理对象
Object currentProxy()
4.4 AOP举例
演示对象
package com.zstu.student;
import java.io.IOException;
public class DemoObject {
private String field01 = "这是字段1";
public static final String field02 = "这是字段2";
public DemoObject() {
}
public DemoObject(String field01) {
this.field01 = field01;
}
public Object method01() {
return "无参方法1";
}
public void method01(String name) {
System.out.println("有参方法1" + name);
}
public void method02() throws IOException {
System.out.println("异常方法2");
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
反射举例
System.out.println("---------- findMethod ----------");
// 获取方法
Method method1 = ReflectionUtils.findMethod(DemoObject.class, "method01");
Method method2 = ReflectionUtils.findMethod(DemoObject.class, "method02");
// public java.lang.Object com.zstu.student.DemoObject.method01()
System.out.println(method1);
System.out.println("---------- findField ----------");
// 获取属性
Field field1 = ReflectionUtils.findField(DemoObject.class, "field01");
Field field2 = ReflectionUtils.findField(DemoObject.class, "field02");
// private java.lang.String com.zstu.student.DemoObject.field01
System.out.println(field1);
System.out.println("---------- accessibleConstructor ----------");
// 获取构造方法
Constructor constructor1 = ReflectionUtils.accessibleConstructor(DemoObject.class);
Constructor constructor2 = ReflectionUtils.accessibleConstructor(DemoObject.class, String.class);
// [public com.zstu.student.DemoObject(), public com.zstu.student.DemoObject(java.lang.String)]
System.out.println(Arrays.toString(new String[] { constructor1.toString(), constructor2.toString() }));
System.out.println("---------- declaresException ----------");
// 方法是否存在指定的抛出异常
assert method2 != null;
boolean existIOException = ReflectionUtils.declaresException(method2, IOException.class);
boolean existException = ReflectionUtils.declaresException(method2, Exception.class);
// true - false
System.out.println(existIOException + " - " + existException);
System.out.println("---------- doWithFields ----------");
// 返回所有字段,通过回调
//private java.lang.String com.zstu.student.DemoObject.field01
//public static final java.lang.String com.zstu.student.DemoObject.field02
ReflectionUtils.doWithFields(DemoObject.class, System.out::println);
System.out.println("---------- doWithLocalMethods ----------");
// 返回当前类所有方法,通过回调
ReflectionUtils.doWithLocalMethods(DemoObject.class, System.out::println);
System.out.println("---------- doWithMethods ----------");
// 返回所有方法包括继承类,通过回调
ReflectionUtils.doWithMethods(DemoObject.class, System.out::println);
System.out.println("---------- getAllDeclaredMethods ----------");
// 返回所有方法包括继承
Method[] methods = ReflectionUtils.getAllDeclaredMethods(DemoObject.class);
System.out.println(Arrays.toString(methods));
System.out.println("---------- getDeclaredMethods ----------");
// 返回所有当前类的方法
methods = ReflectionUtils.getDeclaredMethods(DemoObject.class);
System.out.println(Arrays.toString(methods));
System.out.println("---------- doWithLocalFields ----------");
// 当前类的所有方法,通过回调
// private java.lang.String com.zstu.student.DemoObject.field01
// public static final java.lang.String com.zstu.student.DemoObject.field02
ReflectionUtils.doWithLocalFields(DemoObject.class, System.out::println);
System.out.println("---------- getUniqueDeclaredMethods ----------");
// 若在子类重新父类方法则该方法将被移除
methods = ReflectionUtils.getUniqueDeclaredMethods(DemoObject.class);
System.out.println(Arrays.toString(methods));
System.out.println("---------- getField ----------");
// 获取字段的值
Object ret1 = ReflectionUtils.getField(field2, new DemoObject());
// 这是字段2
System.out.println(ret1);
System.out.println("---------- invokeMethod ----------");
// 调用方法
Object ret2 = ReflectionUtils.invokeMethod(method1, new DemoObject());
// 无参方法1
System.out.println(ret2);
System.out.println("---------- isxxx----------");
// 是toString方法吗? true是,false不是
boolean isString = ReflectionUtils.isToStringMethod(ReflectionUtils.findMethod(DemoObject.class, "toString"));
// true
System.out.println(isString);
// 是否公共静态final修饰属性吗? true是,false不是
boolean isPublicStatic = ReflectionUtils.isPublicStaticFinal(field2);
// true
System.out.println(isPublicStatic);
// 是Object类声明的方法吗? true是,false不是
boolean isObject = ReflectionUtils.isObjectMethod(ReflectionUtils.findMethod(DemoObject.class, "toString"));
// true
System.out.println(isObject);
// 是equals方法吗? true是,false不是
boolean isEquals = ReflectionUtils.isEqualsMethod(ReflectionUtils.findMethod(DemoObject.class, "equals", Object.class));
// true
System.out.println(isEquals);
// 是hashCode方法吗? true是,false不是
boolean isHashCode = ReflectionUtils.isHashCodeMethod(ReflectionUtils.findMethod(DemoObject.class, "hashCode"));
// true
System.out.println(isHashCode);
// 清空缓存,每次查询(方法,参数)时都会做缓存。
ReflectionUtils.clearCache();
// 是Cglib重命名的方法吗? TODO test
// ReflectionUtils.isCglibRenamedMethod()
4.5 ClassUtils(常用)
spring的org.springframework.util包下的ClassUtils类
// 获取对象的所有接口
Class>[] allInterfaces = ClassUtils.getAllInterfaces(new User());
// 获取某个类的包名
String packageName = ClassUtils.getPackageName(User.class);
// 判断某个类是否内部类
System.out.println(ClassUtils.isInnerClass(User.class));
// 判断对象是否代理对象
System.out.println(ClassUtils.isCglibProxy(new User()));
4.6 BeanUtils(常用)
// 拷贝对象的属性
BeanUtils.copyProperties(user1, user2);
// 实例化某个类
BeanUtils.instantiateClass(User.class);
// 获取指定类的指定方法
Method declaredMethod = BeanUtils.findDeclaredMethod(User.class, "getId");
System.out.println(declaredMethod.getName());
// 获取指定方法的参数
Method declaredMethod = BeanUtils.findDeclaredMethod(User.class, "getId");
PropertyDescriptor propertyForMethod = BeanUtils.findPropertyForMethod(declaredMethod);
System.out.println(propertyForMethod.getName());
5、编解码、字符编码
5.1 Base64Utils
String str = "abc";
String encode = new String(Base64Utils.encode(str.getBytes()));
System.out.println("加密后:" + encode);
try {
String decode = new String(Base64Utils.decode(encode.getBytes()), "utf8");
System.out.println("解密后:" + decode);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
5.2 StandardCharsets
字符编码,比如:UTF-8、ISO-8859-1等,
可使用java.nio.charset包下的StandardCharsets类中静态变量。
String str = "abc";
String encode = new String(Base64Utils.encode(str.getBytes()));
System.out.println("加密后:" + encode);
String decode = new String(Base64Utils.decode(encode.getBytes())
, StandardCharsets.UTF_8);
System.out.println("解密后:" + decode);
5.3 DigestUtils
对数据进行加密处理,比如:md5或sha256,可以使用apache的org.apache.commons.codec.digest包下的DigestUtils类
// md5加密
String md5Hex = DigestUtils.md5Hex("shawn222");
System.out.println(md5Hex);
// sha256加密
String md5Hex = DigestUtils.sha256Hex("shawn222");
System.out.println(md5Hex);
5.4 SerializationUtils
序列化和反序列 实现Serializable接口,writeObject和readObject方法
Map map = Maps.newHashMap();
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
byte[] serialize = SerializationUtils.serialize(map);
Object deserialize = SerializationUtils.deserialize(serialize);
System.out.println(deserialize);
6、日志与网络
6.1 MDC
MDC是org.slf4j包下的一个类,它的全称是Mapped Diagnostic Context,可以认为它是一个线程安全的存放诊断日志的容器。
MDC的底层是用了ThreadLocal来保存数据的,可以用它传递参数。
例如现在有这样一种场景:
使用RestTemplate调用远程接口时,有时需要在header中传递信息,比如:traceId,source等,
便于在查询日志时能够串联一次完整的请求链路,快速定位问题。
这种业务场景就能通过ClientHttpRequestInterceptor接口实现,具体做法如下:
第一步,定义一个LogFilter拦截所有接口请求,在MDC中设置traceId:
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
MdcUtil.add(UUID.randomUUID().toString());
System.out.println("记录请求日志");
chain.doFilter(request, response);
System.out.println("记录响应日志");
}
@Override
public void destroy() {
}
}
第二步,实现ClientHttpRequestInterceptor接口,MDC中获取当前请求的traceId,然后设置到header中:
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().set("traceId", MdcUtil.get());
return execution.execute(request, body);
}
}
第三步,定义配置类,配置上面定义的RestTemplateInterceptor类:
@Configuration
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList(restTemplateInterceptor()));
return restTemplate;
}
@Bean
public RestTemplateInterceptor restTemplateInterceptor() {
return new RestTemplateInterceptor();
}
}
其中MdcUtil其实是利用MDC工具在ThreadLocal中存储和获取traceId
public class MdcUtil {
private static final String TRACE_ID = "TRACE_ID";
public static String get() {
return MDC.get(TRACE_ID);
}
public static void add(String value) {
MDC.put(TRACE_ID, value);
}
}
当然,这个例子中没有演示MdcUtil类的add方法具体调的地方,可以在filter中执行接口方法之前,生成traceId,调用MdcUtil类的add方法添加到MDC中,
然后在同一个请求的其他地方就能通过MdcUtil类的get方法获取到该traceId。
能使用MDC保存traceId等参数的根本原因是,用户请求到应用服务器,Tomcat会从线程池中分配一个线程去处理该请求。
那么该请求的整个过程中,保存到MDC的ThreadLocal中的参数,也是该线程独享的,所以不会有线程安全问题。
6.2 HttpStatus
org.springframework.http包下的HttpStatus枚举,或者org.apache.http包下的HttpStatus接口,已经把常用的http返回码定义好了
上一篇
下一篇
少儿体态体能姿势
xxljob2.4.1 表结构
flink-doris-connector 和 flink-cdc-pipeline-connector-doris 的区别
flinkcdc3 数据同步测试
flink currentEmitEventTimeLag
flink集群停止和启动