ruoyi的spring cloud项目详解(十三)-CSDN博客
接着上一篇我们继续学习
com/ruoyi/common/utils/StringUtils.java
package com.ruoyi.common.utils;
import java.util.Collection;
import java.util.Map;
import com.ruoyi.common.core.text.StrFormatter;
/**
* 字符串工具类
*
* @author ruoyi
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils
{
/** 空字符串 */
private static final String NULLSTR = "";
/** 下划线 */
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue;
}
/**
* * 判断一个Collection是否为空, 包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty();
}
/**
* * 判断一个Collection是否非空,包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
** @return true:为空 false:非空
*/
public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:为空 false:非空
*/
public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true:非空串 false:空串
*/
public static boolean isNotEmpty(String str)
{
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true:为空 false:非空
*/
public static boolean isNull(Object object)
{
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true:非空 false:空
*/
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
/**
* * 判断一个对象是否是数组类型(Java基本型别的数组)
*
* @param object 对象
* @return true:是数组 false:不是数组
*/
public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str)
{
return (str == null ? "" : str.trim());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start)
{
if (str == null)
{
return NULLSTR;
}
if (start < 0)
{
start = str.length() + start;
}
if (start < 0)
{
start = 0;
}
if (start > str.length())
{
return NULLSTR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end)
{
if (str == null)
{
return NULLSTR;
}
if (end < 0)
{
end = str.length() + end;
}
if (start < 0)
{
start = str.length() + start;
}
if (end > str.length())
{
end = str.length();
}
if (start > end)
{
return NULLSTR;
}
if (start < 0)
{
start = 0;
}
if (end < 0)
{
end = 0;
}
return str.substring(start, end);
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params)
{
if (isEmpty(params) || isEmpty(template))
{
return template;
}
return StrFormatter.format(template, params);
}
/**
* 下划线转驼峰命名
*/
public static String toUnderScoreCase(String str)
{
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
}
else
{
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR);
}
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs)
{
if (str != null && strs != null)
{
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty())
{
// 没必要转换
return "";
}
else if (!name.contains("_"))
{
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty())
{
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法 例如:user_name->userName
*/
public static String toCamelCase(String s)
{
if (s == null)
{
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c == SEPARATOR)
{
upperCase = true;
}
else if (upperCase)
{
sb.append(Character.toUpperCase(c));
upperCase = false;
}
else
{
sb.append(c);
}
}
return sb.toString();
}
}
以下是对这段 Java 代码的分析:
类的功能:
这个名为StringUtils
的类是一个工具类,主要提供了一系列与字符串处理相关的方法,包括判断字符串和各种集合、对象是否为空,截取字符串、格式化字符串、进行字符串命名格式转换(下划线转驼峰、驼峰转下划线等)以及判断字符串是否在给定的字符串数组中等功能。
主要方法分析:
nvl(T value, T defaultValue)
:用于获取参数不为空值,如果传入的第一个参数不为空则返回第一个参数,否则返回默认值。- 一系列判断集合、数组、Map 和字符串是否为空的方法,如
isEmpty(Collection<?>)
、isNotEmpty(Object[])
等,通过判断对象是否为 null 或者特定集合是否为空来确定。 trim(String str)
:去除字符串两端的空格。substring(final String str, int start)
和substring(final String str, int start, int end)
:用于截取字符串。format(String template, Object... params)
:格式化文本,将模板中的占位符{}
按照顺序替换为传入的参数。toUnderScoreCase(String str)
:将字符串从驼峰命名转换为下划线命名。inStringIgnoreCase(String str, String... strs)
:判断一个字符串是否在给定的字符串数组中,不区分大小写。convertToCamelCase(String name)
和toCamelCase(String s)
:将下划线大写方式命名的字符串转换为驼峰式命名,以及将字符串从下划线命名转换为驼峰命名。
以下是对这段代码的解析,并将解析写在代码外面:
一、工具类概述
StringUtils
类是一个用于处理字符串的工具类,它扩展了org.apache.commons.lang3.StringUtils
类,提供了一系列实用的方法来判断字符串和各种集合、对象的空状态,进行字符串截取、格式化、命名格式转换等操作。
二、空值判断和默认值获取方法解析
// 获取参数不为空值
public static <T> T nvl(T value, T defaultValue) {
return value!= null? value : defaultValue;
}
这个方法用于在给定一个值和一个默认值的情况下,如果值不为空则返回该值,否则返回默认值。这在处理可能为 null 的值并需要提供默认值的场景中非常有用。
三、集合、数组、Map 和字符串的空判断方法解析
// 判断一个 Collection 是否为空
public static boolean isEmpty(Collection<?> coll) {
return isNull(coll) || coll.isEmpty();
}
// 判断一个 Collection 是否非空
public static boolean isNotEmpty(Collection<?> coll) {
return!isEmpty(coll);
}
// 判断一个对象数组是否为空
public static boolean isEmpty(Object[] objects) {
return isNull(objects) || (objects.length == 0);
}
// 判断一个对象数组是否非空
public static boolean isNotEmpty(Object[] objects) {
return!isEmpty(objects);
}
// 判断一个 Map 是否为空
public static boolean isEmpty(Map<?,?> map) {
return isNull(map) || map.isEmpty();
}
// 判断一个 Map 是否非空
public static boolean isNotEmpty(Map<?,?> map) {
return!isEmpty(map);
}
// 判断一个字符串是否为空串
public static boolean isEmpty(String str) {
return isNull(str) || NULLSTR.equals(str.trim());
}
// 判断一个字符串是否为非空串
public static boolean isNotEmpty(String str) {
return!isEmpty(str);
}
// 判断一个对象是否为空
public static boolean isNull(Object object) {
return object == null;
}
// 判断一个对象是否非空
public static boolean isNotNull(Object object) {
return!isNull(object);
}
// 判断一个对象是否是数组类型
public static boolean isArray(Object object) {
return isNotNull(object) && object.getClass().isArray();
}
这些方法用于判断各种数据结构(集合、数组、Map 和字符串)是否为空。对于集合和 Map,先判断是否为 null,再判断是否为空集合或空 Map。对于字符串,判断是否为 null 或者去除两端空格后是否为空字符串。对于对象,直接判断是否为 null。对于判断是否为数组类型,先判断对象是否非 null,然后检查其类是否为数组类型。
四、字符串处理方法解析
// 去空格
public static String trim(String str) {
return (str == null? "" : str.trim());
}
// 截取字符串(从指定位置开始)
public static String substring(final String str, int start) {
if (str == null) {
return NULLSTR;
}
// 一系列处理逻辑
//...
return str.substring(start);
}
// 截取字符串(指定开始和结束位置)
public static String substring(final String str, int start, int end) {
if (str == null) {
return NULLSTR;
}
// 一系列处理逻辑
//...
return str.substring(start, end);
}
trim
方法用于去除字符串两端的空格,如果字符串为 null,则返回空字符串。substring
方法用于截取字符串,根据传入的开始位置或开始和结束位置进行截取,如果字符串为 null,则返回空字符串。
五、格式化文本方法解析
// 格式化文本
public static String format(String template, Object... params) {
if (isEmpty(params) || isEmpty(template)) {
return template;
}
return StrFormatter.format(template, params);
}
这个方法用于格式化文本,将模板中的占位符{}
按照顺序替换为传入的参数。如果参数为空或者模板为空,则直接返回模板。实际的格式化操作是通过调用StrFormatter.format
方法来完成的。
六、命名格式转换方法解析
// 下划线转驼峰命名
public static String toUnderScoreCase(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
// 处理逻辑
//...
return sb.toString();
}
// 是否包含字符串(不区分大小写)
public static boolean inStringIgnoreCase(String str, String... strs) {
if (str!= null && strs!= null) {
for (String s : strs) {
if (str.equalsIgnoreCase(trim(s))) {
return true;
}
}
}
return false;
}
// 将下划线大写方式命名的字符串转换为驼峰式
public static String convertToCamelCase(String name) {
StringBuilder result = new StringBuilder();
if (name == null || name.isEmpty()) {
return "";
}
// 处理逻辑
//...
return result.toString();
}
// 驼峰式命名法(从下划线命名转换为驼峰命名)
public static String toCamelCase(String s) {
if (s == null) {
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// 处理逻辑
//...
}
return sb.toString();
}
这些方法用于进行字符串命名格式的转换。toUnderScoreCase
方法将字符串从驼峰命名转换为下划线命名。inStringIgnoreCase
方法用于判断一个字符串是否在给定的字符串数组中,不区分大小写。convertToCamelCase
方法将下划线大写方式命名的字符串转换为驼峰式命名。toCamelCase
方法将字符串从下划线命名转换为驼峰命名。
com/ruoyi/common/utils/Threads.java
package com.ruoyi.common.utils;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 线程相关工具类.
*
* @author ruoyi
*/
public class Threads
{
private static final Logger logger = LoggerFactory.getLogger(Threads.class);
/**
* sleep等待,单位为毫秒
*/
public static void sleep(long milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
return;
}
}
/**
* 停止线程池
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
* 如果仍人超時,則強制退出.
* 另对在shutdown时线程本身被调用中断做了处理.
*/
public static void shutdownAndAwaitTermination(ExecutorService pool)
{
if (pool != null && !pool.isShutdown())
{
pool.shutdown();
try
{
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
{
pool.shutdownNow();
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
{
logger.info("Pool did not terminate");
}
}
}
catch (InterruptedException ie)
{
pool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
/**
* 打印线程异常信息
*/
public static void printException(Runnable r, Throwable t)
{
if (t == null && r instanceof Future<?>)
{
try
{
Future<?> future = (Future<?>) r;
if (future.isDone())
{
future.get();
}
}
catch (CancellationException ce)
{
t = ce;
}
catch (ExecutionException ee)
{
t = ee.getCause();
}
catch (InterruptedException ie)
{
Thread.currentThread().interrupt();
}
}
if (t != null)
{
logger.error(t.getMessage(), t);
}
}
}
以下是对这段代码的分析:
一、类的整体功能
这个名为Threads
的类是一个工具类,主要提供了与线程相关的实用方法,包括让当前线程睡眠一段时间、安全地停止线程池以及打印线程执行过程中出现的异常信息。
二、主要方法分析
-
sleep(long milliseconds)
:- 功能:使当前线程睡眠指定的毫秒数。如果在睡眠过程中被中断,会捕获
InterruptedException
异常并直接返回,不进行进一步处理。 - 用途:在需要暂停线程执行一段时间的场景中使用,比如等待某个条件满足或者控制线程执行的节奏。
- 功能:使当前线程睡眠指定的毫秒数。如果在睡眠过程中被中断,会捕获
-
shutdownAndAwaitTermination(ExecutorService pool)
:- 功能:安全地停止给定的线程池。首先调用线程池的
shutdown
方法,停止接收新任务并尝试完成所有已存在的任务。如果在 120 秒内没有完成所有任务,则调用shutdownNow
方法,取消在工作队列中等待的任务,并中断所有阻塞的函数。如果仍然在 120 秒内没有完成所有任务,则打印日志表示线程池没有正常终止。同时,该方法还处理了在shutdown
过程中当前线程被中断的情况,会中断当前线程并继续执行。 - 用途:在需要优雅地停止线程池的场景中使用,确保所有任务都有机会完成,并且不会留下未处理的任务或资源泄漏。
- 功能:安全地停止给定的线程池。首先调用线程池的
-
printException(Runnable r, Throwable t)
:- 功能:打印线程执行过程中出现的异常信息。如果传入的
Throwable
对象为null
,并且传入的Runnable
对象是一个Future
类型,会尝试从Future
对象中获取结果,如果在获取结果过程中出现CancellationException
、ExecutionException
或InterruptedException
异常,会将异常设置为Throwable
对象并进行处理。最后,如果Throwable
对象不为null
,会使用日志记录器打印异常信息。 - 用途:在多线程环境中,用于捕获和打印线程执行过程中出现的异常,方便进行错误排查和调试
- 功能:打印线程执行过程中出现的异常信息。如果传入的
以下是对这段代码的解析:
一、工具类概述
Threads
类是一个用于处理线程相关操作的工具类,提供了让线程睡眠、安全关闭线程池以及打印线程异常信息的方法。
二、导入包的作用
java.util.concurrent.CancellationException
、java.util.concurrent.ExecutionException
、java.util.concurrent.Future
、java.util.concurrent.ExecutorService
和java.util.concurrent.TimeUnit
:这些包中的类和接口用于处理并发编程中的线程执行、异步任务和线程池管理。org.slf4j.Logger
和org.slf4j.LoggerFactory
:用于日志记录,方便在工具类的方法中输出信息和错误消息。
三、定义类和日志记录器
/**
* 线程相关工具类.
*
* @author ruoyi
*/
public class Threads {
private static final Logger logger = LoggerFactory.getLogger(Threads.class);
Threads
类被标注为作者为 “ruoyi”,表示这个类可能是特定项目中的一部分,作者为 “ruoyi”。logger
是一个静态的Logger
对象,通过LoggerFactory.getLogger(Threads.class)
获取与Threads
类相关联的日志记录器。这使得在工具类的方法中可以方便地记录日志信息,用于调试和错误跟踪。
四、线程睡眠方法(sleep)
/**
* sleep等待,单位为毫秒
*/
public static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
return;
}
}
- 功能:这个方法用于让当前线程睡眠指定的毫秒数。它接受一个
long
类型的参数milliseconds
,表示要睡眠的时间长度。 - 处理异常:在方法内部,使用
try-catch
块捕获InterruptedException
异常。如果在睡眠过程中线程被中断,方法会捕获这个异常并直接返回,不进行进一步的处理。这是一种常见的处理方式,当线程被中断时,通常表示有更高优先级的事件需要处理,此时可以选择放弃睡眠并继续执行后续的代码。
五、停止线程池方法(shutdownAndAwaitTermination)
/**
* 停止线程池
* 先使用 shutdown, 停止接收新任务并尝试完成所有已存在任务.
* 如果超时, 则调用 shutdownNow, 取消在 workQueue 中 Pending 的任务,并中断所有阻塞函数.
* 如果仍超时,则强制退出.
* 另对在 shutdown 时线程本身被调用中断做了处理.
*/
public static void shutdownAndAwaitTermination(ExecutorService pool) {
if (pool!= null &&!pool.isShutdown()) {
pool.shutdown();
try {
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
logger.info("Pool did not terminate");
}
}
} catch (InterruptedException ie) {
pool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
- 功能:这个方法用于安全地停止给定的线程池。它接受一个
ExecutorService
类型的参数pool
,表示要停止的线程池。 - 停止过程:首先,检查线程池是否为
null
并且没有已经处于关闭状态。如果满足条件,调用线程池的shutdown
方法,这会停止接收新任务并尝试完成所有已存在的任务。然后,使用awaitTermination
方法等待线程池完成所有任务,等待时间为 120 秒。如果在这个时间内线程池没有完成所有任务,调用shutdownNow
方法,这会取消在工作队列中等待的任务,并中断所有阻塞的函数。再次使用awaitTermination
方法等待 120 秒,如果仍然没有完成所有任务,通过日志记录器输出 “Pool did not terminate” 的消息。 - 中断处理:在等待过程中,如果当前线程被中断,会捕获
InterruptedException
异常。在异常处理中,再次调用shutdownNow
方法,并中断当前线程,以确保线程池能够尽快停止并且不会因为中断而出现不一致的状态。
六、打印线程异常信息方法(printException)
/**
* 打印线程异常信息
*/
public static void printException(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
try {
Future<?> future = (Future<?>) r;
if (future.isDone()) {
future.get();
}
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (t!= null) {
logger.error(t.getMessage(), t);
}
}
- 功能:这个方法用于打印线程执行过程中出现的异常信息。它接受两个参数,一个是
Runnable
类型的对象r
,表示要执行的任务;另一个是Throwable
类型的对象t
,表示可能的异常。 - 处理
Future
对象:如果传入的Throwable
对象为null
,并且传入的Runnable
对象是一个Future
类型,方法会尝试从Future
对象中获取结果。如果Future
对象表示的任务已经完成,调用future.get()
方法获取结果。在获取结果的过程中,如果出现CancellationException
,表示任务被取消,将异常设置为t
;如果出现ExecutionException
,获取其原因并设置为t
;如果出现InterruptedException
,中断当前线程。 - 打印异常:如果最终
Throwable
对象不为null
,使用日志记录器的error
方法打印异常的消息和堆栈跟踪信息。这样可以方便地在日志中查看线程执行过程中出现的错误,便于调试和错误排查。
com/ruoyi/common/utils/ToolUtil.java
package com.ruoyi.common.utils;
import java.io.File;
/**
* <p>Title: </p>
* <p>Description: 高频方法集合类</p>
* <p>Copyright: Copyright (c) 2019-08-19 14:51</p>
* <p>Company: </p>
* @version 1.0
* @author: zmr
*/
public class ToolUtil
{
/**
* 获取临时目录
* @author zmr
*/
public static String getTempPath()
{
return System.getProperty("java.io.tmpdir");
}
/**
* 获取当前项目工作目录
* @return
* @author zmr
*/
public static String getUserDir()
{
return System.getProperty("user.dir");
}
/**
* 获取临时下载目录
* @return
* @author zmr
*/
public static String getDownloadPath()
{
return getTempPath() + File.separator + "download" + File.separator;
}
}
以下是对这段代码的解析:
一、工具类概述
ToolUtil
类是一个工具类,提供了一些与系统路径相关的常用方法,主要用于获取临时目录、当前项目工作目录和临时下载目录。
二、方法解析
-
getTempPath()
:- 功能:获取系统的临时目录路径。通过调用
System.getProperty("java.io.tmpdir")
获取临时目录的路径字符串。 - 用途:在需要临时存储文件或进行临时操作时,可以使用这个方法获取临时目录,确保文件的存储位置不会影响到系统的正常运行。
- 功能:获取系统的临时目录路径。通过调用
-
getUserDir()
:- 功能:获取当前项目的工作目录路径。通过调用
System.getProperty("user.dir")
获取当前项目所在的工作目录路径字符串。 - 用途:在需要确定项目的当前位置或进行与项目相关的文件操作时,可以使用这个方法获取工作目录路径。
- 功能:获取当前项目的工作目录路径。通过调用
-
getDownloadPath()
:- 功能:获取临时下载目录路径。它首先调用
getTempPath()
获取临时目录路径,然后在临时目录下拼接"download"
文件夹的路径,以File.separator
作为路径分隔符,确保在不同操作系统下都能正确构建路径。 - 用途:在需要指定一个临时的下载目录时,可以使用这个方法获取统一的下载路径,方便管理下载的文件。
- 功能:获取临时下载目录路径。它首先调用
以下是对这段代码的分析,按照代码块和解析分别展示:
代码块 1:包声明和类注释
package com.ruoyi.common.utils;
import java.io.File;
/**
* <p>Title: </p>
* <p>Description: 高频方法集合类</p>
* <p>Copyright: Copyright (c) 2019-08-19 14:51</p>
* <p>Company: </p>
* @version 1.0
* @author: zmr
*/
public class ToolUtil {
解析:
这段代码声明了工具类所在的包为com.ruoyi.common.utils
,并导入了java.io.File
类,用于后续处理文件路径。类的注释部分提供了一些关于该类的基本信息,包括标题、描述、版权信息、公司信息、版本号和作者。表明这个类是一个用于收集高频使用方法的工具类。
代码块 2:获取临时目录方法
/**
* 获取临时目录
* @author zmr
*/
public static String getTempPath() {
return System.getProperty("java.io.tmpdir");
}
解析:
这个方法用于获取系统的临时目录路径。通过调用System.getProperty("java.io.tmpdir")
,可以获取到操作系统为当前运行的 Java 程序分配的临时存储区域的路径。作者标注为 “zmr”。这个方法可以在需要临时存储文件或者进行一些临时操作时使用,确保不会对系统的其他部分造成不必要的影响。
代码块 3:获取当前项目工作目录方法
/**
* 获取当前项目工作目录
* @return
* @author zmr
*/
public static String getUserDir() {
return System.getProperty("user.dir");
}
解析:
此方法获取当前项目的工作目录路径。通过System.getProperty("user.dir")
可以获取到启动 Java 程序时的当前工作目录,通常是项目的根目录或者启动脚本所在的目录。这个方法在需要确定项目的当前位置或者进行与项目相关的文件操作时非常有用。同样,作者为 “zmr”。
代码块 4:获取临时下载目录方法
/**
* 获取临时下载目录
* @return
* @author zmr
*/
public static String getDownloadPath() {
return getTempPath() + File.separator + "download" + File.separator;
}
解析:
这个方法用于获取临时下载目录路径。它首先调用getTempPath()
方法获取系统临时目录路径,然后使用File.separator
获取当前操作系统的文件路径分隔符,拼接上 “download” 字符串,再加上一个文件路径分隔符,从而构建出临时下载目录的路径。这样可以确保在不同的操作系统下都能正确构建路径。这个方法在项目中需要指定一个临时的下载目录时非常方便,可以统一管理下载的文件。作者同样是 “zmr”
com/ruoyi/common/utils/ValidatorUtils.java
package com.ruoyi.common.utils;
import com.ruoyi.common.exception.base.BaseException;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
/**
* hibernate-validator校验工具类
* 参考文档:http://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/
*/
public class ValidatorUtils
{
private static Validator validator;
static
{
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
/**
* 校验对象
* @param object 待校验对象
* @param groups 待校验的组
* @throws BaseException 校验不通过,则报BaseException异常
*/
public static void validateEntity(Object object, Class<?> ... groups) throws BaseException
{
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty())
{
ConstraintViolation<Object> constraint = (ConstraintViolation<Object>) constraintViolations.iterator()
.next();
throw new BaseException(constraint.getMessage());
}
}
}
以下是对这段代码的汇总分析:
一、功能概述
这段 Java 代码定义了一个名为ValidatorUtils
的工具类,用于进行对象的校验操作,主要基于 Hibernate Validator(实现了 Java Bean Validation 规范)。
二、主要组成部分
-
导入的类和接口:
com.ruoyi.common.exception.base.BaseException
:用于在校验不通过时抛出自定义异常。java.util.Set
:用于存储校验结果集合。javax.validation.ConstraintViolation
、javax.validation.Validation
和javax.validation.Validator
:来自 Java Bean Validation 规范,用于执行对象校验和处理校验结果。
-
静态变量和初始化块:
- 创建了一个静态的
Validator
对象validator
。在静态初始化块中,通过调用Validation.buildDefaultValidatorFactory()
创建一个默认的校验器工厂,然后从工厂获取一个Validator
实例,用于后续的校验操作。
- 创建了一个静态的
-
校验对象方法:
validateEntity
方法接受一个待校验的对象object
和一个可变参数的校验组groups
。- 该方法使用静态的
validator
对象对传入的对象进行校验,并传入校验组参数。结果存储在一个Set<ConstraintViolation<Object>>
集合中。 - 如果校验结果集合不为空,表示对象校验不通过。此时,从集合中取出第一个校验违规对象,获取其错误消息,并抛出一个
BaseException
异常。
三、用途
这个工具类可以在应用程序中方便地对对象进行校验,并在不通过时进行统一的异常处理,确保数据的有效性和完整性。例如,在数据输入、业务逻辑处理等场景中,可以使用这个工具类对输入的对象进行校验,以保证数据符合特定的规则和约束。
以下是对这段代码的分析,按照代码块和解析分别展示:
代码块 1:包声明和导入类
package com.ruoyi.common.utils;
import com.ruoyi.common.exception.base.BaseException;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
解析:
这段代码声明了工具类所在的包为com.ruoyi.common.utils
。导入了com.ruoyi.common.exception.base.BaseException
,用于在后续的校验不通过时抛出异常。还导入了java.util.Set
用于存储校验结果集合。javax.validation.ConstraintViolation
、javax.validation.Validation
和javax.validation.Validator
是 Java Bean Validation(JSR 380)规范中的类和接口,用于进行对象的校验操作。
代码块 2:静态变量和初始化块
public class ValidatorUtils
{
private static Validator validator;
static
{
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
解析:
在这个工具类中定义了一个静态的Validator
对象validator
。在静态初始化块中,通过Validation.buildDefaultValidatorFactory()
创建一个默认的校验器工厂,然后调用工厂的getValidator()
方法获取一个Validator
实例,用于后续的对象校验操作。
代码块 3:校验对象方法
/**
* 校验对象
* @param object 待校验对象
* @param groups 待校验的组
* @throws BaseException 校验不通过,则报BaseException异常
*/
public static void validateEntity(Object object, Class<?>... groups) throws BaseException
{
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty())
{
ConstraintViolation<Object> constraint = (ConstraintViolation<Object>) constraintViolations.iterator()
.next();
throw new BaseException(constraint.getMessage());
}
}
}
解析:
这个方法用于校验一个对象。它接受一个待校验的对象object
和一个可变参数的校验组groups
。首先,使用静态初始化的validator
对象调用validate
方法对传入的对象进行校验,并传入校验组参数。如果校验结果集合constraintViolations
不为空,表示对象校验不通过。在这种情况下,从集合中取出第一个校验违规对象constraint
,并抛出一个自定义的BaseException
异常,异常信息为校验违规的错误消息。这样可以在应用中方便地对对象进行校验,并在不通过时进行统一的异常处理。
com/ruoyi/common/utils/YamlUtil.java
package com.ruoyi.common.utils;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import com.ruoyi.common.utils.StringUtils;
/**
* 配置处理工具类
*
* @author yml
*/
public class YamlUtil
{
public static Map<?, ?> loadYaml(String fileName) throws FileNotFoundException
{
InputStream in = YamlUtil.class.getClassLoader().getResourceAsStream(fileName);
return StringUtils.isNotEmpty(fileName) ? (LinkedHashMap<?, ?>) new Yaml().load(in) : null;
}
public static void dumpYaml(String fileName, Map<?, ?> map) throws IOException
{
if (StringUtils.isNotEmpty(fileName))
{
FileWriter fileWriter = new FileWriter(YamlUtil.class.getResource(fileName).getFile());
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(options);
yaml.dump(map, fileWriter);
}
}
public static Object getProperty(Map<?, ?> map, Object qualifiedKey)
{
if (map != null && !map.isEmpty() && qualifiedKey != null)
{
String input = String.valueOf(qualifiedKey);
if (!"".equals(input))
{
if (input.contains("."))
{
int index = input.indexOf(".");
String left = input.substring(0, index);
String right = input.substring(index + 1, input.length());
return getProperty((Map<?, ?>) map.get(left), right);
}
else if (map.containsKey(input))
{
return map.get(input);
}
else
{
return null;
}
}
}
return null;
}
@SuppressWarnings("unchecked")
public static void setProperty(Map<?, ?> map, Object qualifiedKey, Object value)
{
if (map != null && !map.isEmpty() && qualifiedKey != null)
{
String input = String.valueOf(qualifiedKey);
if (!input.equals(""))
{
if (input.contains("."))
{
int index = input.indexOf(".");
String left = input.substring(0, index);
String right = input.substring(index + 1, input.length());
setProperty((Map<?, ?>) map.get(left), right, value);
}
else
{
((Map<Object, Object>) map).put(qualifiedKey, value);
}
}
}
}
}
以下是对这段 Java 代码的汇总分析:
一、功能概述
YamlUtil
是一个工具类,主要用于处理 YAML 格式的配置文件。它提供了加载 YAML 文件内容到Map
、将Map
内容写入 YAML 文件、从Map
中获取特定属性值以及在Map
中设置属性值的功能。
二、主要方法及功能
-
loadYaml(String fileName)
:- 功能:接受一个文件名作为参数,通过类加载器获取指定 YAML 文件的输入流,然后使用
snakeyaml
库加载 YAML 内容并返回一个LinkedHashMap
。如果文件名为空,则返回null
。 - 用途:用于读取 YAML 配置文件并将其转换为易于操作的
Map
结构。
- 功能:接受一个文件名作为参数,通过类加载器获取指定 YAML 文件的输入流,然后使用
-
dumpYaml(String fileName, Map<?,?> map)
:- 功能:接受一个文件名和一个
Map
对象作为参数。如果文件名不为空,创建文件写入器,设置 YAML 的输出风格为块风格,然后将Map
内容写入到指定的 YAML 文件中。 - 用途:用于将内存中的
Map
数据结构保存为 YAML 格式的文件。
- 功能:接受一个文件名和一个
-
getProperty(Map<?,?> map, Object qualifiedKey)
:- 功能:从给定的
Map
中获取特定属性值。如果属性路径以点分隔表示嵌套结构,则递归地查找子Map
中的属性值。如果属性不存在,则返回null
。 - 用途:方便从复杂的
Map
结构中获取特定的属性值,特别是处理具有嵌套结构的 YAML 配置数据。
- 功能:从给定的
-
setProperty(Map<?,?> map, Object qualifiedKey, Object value)
:- 功能:在给定的
Map
中设置特定属性值。如果属性路径以点分隔表示嵌套结构,则递归地设置子Map
中的属性值。 - 用途:用于修改复杂
Map
结构中的特定属性值,可用于动态修改 YAML 配置数据在内存中的表示。
- 功能:在给定的
三、整体作用
这个工具类在处理 YAML 配置文件时提供了方便的方法,使得在 Java 应用程序中可以轻松地读取、修改和保存 YAML 配置数据,增强了应用程序对配置文件的操作能力。
以下是对这段代码的分析,按照代码块和解析分别展示:
代码块 1:包声明和导入类
package com.ruoyi.common.utils;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import com.ruoyi.common.utils.StringUtils;
解析:
这段代码声明了工具类所在的包为com.ruoyi.common.utils
。导入了多个用于处理文件操作和 YAML 解析的类和接口。包括用于处理文件未找到异常的FileNotFoundException
、用于文件写入的FileWriter
、用于处理输入输出异常的IOException
、用于读取输入流的InputStream
、用于存储键值对的Map
和LinkedHashMap
、来自 YAML 处理库snakeyaml
的DumperOptions
和Yaml
,以及自定义的字符串工具类StringUtils
。
代码块 2:加载 YAML 文件方法
public static Map<?,?> loadYaml(String fileName) throws FileNotFoundException
{
InputStream in = YamlUtil.class.getClassLoader().getResourceAsStream(fileName);
return StringUtils.isNotEmpty(fileName)? (LinkedHashMap<?,?>) new Yaml().load(in) : null;
}
解析:
这个方法用于加载一个 YAML 文件。它接受一个文件名作为参数。首先,通过类加载器获取指定文件名的输入流。如果文件名不为空,使用new Yaml().load(in)
加载 YAML 内容,并将结果强制转换为LinkedHashMap<?,?>
类型返回。如果文件名为空,则返回null
。
代码块 3:写入 YAML 文件方法
public static void dumpYaml(String fileName, Map<?,?> map) throws IOException
{
if (StringUtils.isNotEmpty(fileName))
{
FileWriter fileWriter = new FileWriter(YamlUtil.class.getResource(fileName).getFile());
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(options);
yaml.dump(map, fileWriter);
}
}
解析:
这个方法用于将一个Map
对象写入到 YAML 文件中。它接受一个文件名和一个Map
对象作为参数。如果文件名不为空,首先创建一个FileWriter
对象,用于写入文件。然后创建一个DumperOptions
对象,并设置默认的流风格为块风格。接着创建一个Yaml
对象,并使用设置好的选项。最后,使用yaml.dump(map, fileWriter)
将Map
对象写入到文件中。
代码块 4:获取属性方法
public static Object getProperty(Map<?,?> map, Object qualifiedKey)
{
if (map!= null &&!map.isEmpty() && qualifiedKey!= null)
{
String input = String.valueOf(qualifiedKey);
if (!"".equals(input))
{
if (input.contains("."))
{
int index = input.indexOf(".");
String left = input.substring(0, index);
String right = input.substring(index + 1, input.length());
return getProperty((Map<?,?>) map.get(left), right);
}
else if (map.containsKey(input))
{
return map.get(input);
}
else
{
return null;
}
}
}
return null;
}
解析:
这个方法用于从一个Map
对象中获取特定的属性值。它接受一个Map
对象和一个表示属性路径的键作为参数。如果Map
不为空且不包含空键,首先将键转换为字符串。如果字符串不为空,并且字符串中包含 “.”,表示是嵌套的属性路径。此时,将字符串按照 “.” 分割,递归地调用getProperty
方法获取子属性的值。如果字符串不包含 “.”,并且Map
中包含这个键,则返回对应的值。如果Map
中不包含这个键,则返回null
。
代码块 5:设置属性方法
@SuppressWarnings("unchecked")
public static void setProperty(Map<?,?> map, Object qualifiedKey, Object value)
{
if (map!= null &&!map.isEmpty() && qualifiedKey!= null)
{
String input = String.valueOf(qualifiedKey);
if (!input.equals(""))
{
if (input.contains("."))
{
int index = input.indexOf(".");
String left = input.substring(0, index);
String right = input.substring(index + 1, input.length());
setProperty((Map<?,?>) map.get(left), right, value);
}
else
{
((Map<Object, Object>) map).put(qualifiedKey, value);
}
}
}
}
解析:
这个方法用于在一个Map
对象中设置特定的属性值。它接受一个Map
对象、一个表示属性路径的键和一个值作为参数。如果Map
不为空且不包含空键,首先将键转换为字符串。如果字符串不为空,并且字符串中包含 “.”,表示是嵌套的属性路径。此时,将字符串按照 “.” 分割,递归地调用setProperty
方法设置子属性的值。如果字符串不包含 “.”,则直接在Map
中设置对应键的值。使用了@SuppressWarnings("unchecked")
注解来抑制未经检查的类型转换警告。