分享几个在项目中经常用到的工具类
目录
前言
我们在进行项目开发的时候可能会经常用到一些字符串相关的操作,然后可能产生大量冗余的代码,这时候可以把我们用到的操作提取出来,放到一个单独的工具类里,比如命名为StringUtils,这个工具类里的方法几乎可以涵盖我们日常所需,接下来,我将个人的几个工具类分享给大家。
1、String工具类
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* String工具类
* @author heyunlin
* @version 1.0
*/
public class StringUtils {
/**
* 判断字符串是否为null或""
* 字符串为""或null返回true,否则返回false
* @param str 要判断的字符串
* @return boolean
*/
public static boolean isEmpty(String str) {
return isNullOrEmpty(str);
}
/**
* 判断字符串是否为""或null
* 字符串为""或null返回false,否则返回true
* @param str 要判断的字符串
* @return boolean
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* 判断字符串是否为空白字符
* 字符串为空白字符返回true,否则返回false
* @param str 要判断的字符串
* @return boolean
*/
public static boolean isBlank(String str) {
return str.trim().length() == 0;
}
/**
* 判断字符串是不是空白字符
* 字符串不是空白字符返回true,否则返回false
* @param str 要判断的字符串
* @return boolean
*/
public static boolean isNotBlank(String str) {
return !isBlank(str);
}
/**
* 判断字符串是否为null或""
* 字符串为""或null返回true,否则返回false
* @param str 要判断的字符串
* @return boolean
*/
public static boolean isNullOrEmpty(String str) {
return str == null || str.isEmpty();
}
/**
* 检查字符串是否包含空白字符
* 如果不包含空格返回true,否则返回false
* @param str 需要比较的字符串
* @return boolean
*/
public static boolean check(String str) {
// 去除空白字符后字符串的长度
int realLength = str.replaceAll("\\s", "").length();
// 字符串原来的长度
int originalLength = str.length();
return realLength == originalLength;
}
/**
* 根据当前时间生成UUID
* @return String
*/
public static String uuid() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
LocalDateTime localDate = LocalDateTime.now();
return localDate.format(formatter);
}
/**
* 通过文件名获取文件类型
* @param fileName 文件名
*/
public static String getFileType(String fileName) {
// 得到文件名中最后一次出现"."的位置
int index = fileName.lastIndexOf('.');
// 文件类型统一转换为小写
return fileName.substring(index).toLowerCase();
}
/**
* 获取文件名
* @param filename String
* @return String 由当前时间生成的新文件名
*/
public static String getFileName(String filename) {
// 返回uuid.文件类型,如:20220618131456.jpg
return uuid() + getFileType(filename);
}
/**
* 获取文件名
* @param file MultipartFile对象
* @return String 由当前时间生成的新文件名
*/
public static String getFileName(MultipartFile file) {
// 得到上传文件的原始文件名
String filename = file.getOriginalFilename();
// 判断文件名是否为空
if (isNullOrEmpty(filename)) {
throw new RuntimeException("获取文件名失败!");
}
// 返回uuid.文件类型,如:20220618131456.jpg
return uuid() + getFileType(filename);
}
/**
* 驼峰命名转下划线命名
* @param str 待转换的字符串
* @return String
*/
public static String toLowerCase(String str) {
// 小写和大写紧挨一起的地方加上分隔符_,然后全部转为小写
str = str.replaceAll("([a-z])([A-Z])", "$1_$2");
return str.toLowerCase();
}
/**
* 下划线命名转驼峰命名
* @param str 待转换的字符串
* @return String
*/
private static String toUpperCase(String str) {
// 将下划线替换为空格
StringBuilder under= new StringBuilder();
str = str.toLowerCase().replace("_", " ");
// 将字符串根据空格分割成数组
String[] array = str.split(" ");
// 将每个单词首字母大写
for (String s : array) {
String letter = s.substring(0, 1).toUpperCase() + s.substring(1);
under.append(letter);
}
return under.toString();
}
}
2、File工具类
package cn.edu.sgu.www.mhxysy.util;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
/**
* File工具类
* @author heyunlin
* @version 1.0
*/
@Slf4j
public class FileUtils {
/**
* 创建文件夹
* @param name 文件夹名
*/
public static void createFolder(String name) {
File file = new File(name);
if(file.exists()) {
log.debug("文件夹{}已存在···", name);
} else {
boolean result = file.mkdirs();
log.debug(("创建文件夹{}" + (result ? "成功": "失败") + ":"), name);
}
}
/**
* 删除文件,可以是文件或文件夹
* @param fileName 要删除的文件名
* @return 删除成功返回true,否则返回false
*/
public static boolean delete(String fileName) {
File file = new File(fileName);
if (!file.exists()) {
log.debug("删除文件失败:{}不存在!", fileName);
return false;
} else {
if (file.isFile()) {
return deleteFile(fileName);
} else {
return deleteDirectory(fileName);
}
}
}
/**
* 删除单个文件
* @param fileName 要删除的文件的文件名
* @return 单个文件删除成功返回true,否则返回false
*/
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
log.debug("成功删除文件:{}", fileName);
return true;
} else {
log.debug("删除文件{}失败!", fileName);
return false;
}
} else {
log.debug("删除文件失败!文件{}不存在!", fileName);
return false;
}
}
/**
* 删除目录及目录下的文件
* @param dir 要删除的目录的文件路径
* @return 目录删除成功返回true,否则返回false
*/
public static boolean deleteDirectory(String dir) {
File dirFile = new File(dir);
// 如果dir对应的文件不存在,或者不是一个目录,则退出
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
log.debug("删除目录失败!文件{}不存在!", dir);
return false;
}
boolean flag = true;
// 删除文件夹中的所有文件包括子目录
File[] files = dirFile.listFiles();
assert files != null;
for (File file : files) {
// 删除子文件
if (file.isFile()) {
flag = FileUtils.deleteFile(file.getAbsolutePath());
if (!flag)
break;
}
// 删除子目录
else if (file.isDirectory()) {
flag = FileUtils.deleteDirectory(file.getAbsolutePath());
if (!flag)
break;
}
}
if (!flag) {
log.debug("删除目录失败!");
return false;
}
// 删除当前目录
if (dirFile.delete()) {
log.debug("删除目录{}成功!", dir);
return true;
} else {
return false;
}
}
}
3、接口资源扫描工具类
这个工具类用于扫描项目中的Controller接口,扫描到的接口数据保存到数据库中,可以用来实现接口鉴权。
package cn.edu.sgu.www.mhxysy.util;
import cn.edu.sgu.www.mhxysy.MhxysyApplication;
import cn.edu.sgu.www.mhxysy.entity.system.Permission;
import cn.edu.sgu.www.mhxysy.enums.RequestMethod;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* 接口资源扫描工具类
* @author heyunlin
* @version 1.0
*/
@Component
public class ResourceScanner {
/**
* 服务名
*/
@Value("${spring.application.name}")
private String SERVICE_NAME;
private static List<String> classPaths = new ArrayList<>();
private static final List<Permission> resources = new ArrayList<>();
public List<Permission> scan(String basePackage) throws ClassNotFoundException {
// 删除掉上一次的数据
if (!resources.isEmpty()) {
resources.clear();
}
if (!classPaths.isEmpty()) {
classPaths.clear();
}
String classpath = MhxysyApplication.class.getResource("/").getPath().replaceFirst("/", "");
String searchPath = classpath + basePackage.replace(".", "/");
searchPath = searchPath.replace("test-classes", "classes");
classPaths = doPath(new File(searchPath));
for(String classPath : classPaths) {
classPath = classPath.replace(classpath.replace("/", "\\")
.replaceFirst("\\\\", ""), "")
.replace("\\", ".")
.replace(".class", "");
classpath = classPath.substring(classPath.indexOf(basePackage));
Class<?> cls = Class.forName(classpath);
RequestMapping requestMapping = cls.getAnnotation(RequestMapping.class);
// 判断多种注解的情况
String prefix = "";
Permission parent = new Permission();
if(requestMapping != null) {
// path或者value
prefix = requestMapping.value().length > 0 ? requestMapping.value()[0] : requestMapping.path()[0];
parent.setId(SERVICE_NAME + "_" + cls.getSimpleName());
parent.setType(0);
parent.setUrl(prefix);
// 设置value
if (cls.isAnnotationPresent(Api.class)) {
Api api = cls.getAnnotation(Api.class);
if (api != null) {
String name = api.tags()[0];
// 类的接口文档@Api注解的值以“控制器”或“控制器类”结束
parent.setName(name.substring(0, name.indexOf("控制器")).concat("管理"));
}
}
resources.add(parent);
}
Method[] methods = cls.getDeclaredMethods();
for (Method value : methods) {
getClassAnnotation(value, prefix, cls, parent.getId());
}
}
return resources;
}
/**
* 得到类上面的注解信息
* @param method Method
* @param prefix String
* @param cls Class<?>
* @param parentId String
*/
public void getClassAnnotation(Method method, String prefix, Class<?> cls, String parentId) {
String url = null;
Permission permission = new Permission();
if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
url = prefix + (requestMapping.value().length > 0 ? requestMapping.value()[0] : requestMapping.path()[0]);
String requestMethod = requestMapping.method().length > 0 ? requestMapping.method()[0].name() : "get";
permission.setMethod(RequestMethod.getValueByName(requestMethod));
} else if (method.isAnnotationPresent(GetMapping.class)) {
GetMapping getMapping = method.getAnnotation(GetMapping.class);
url = prefix + getMapping.value()[0];
permission.setMethod(RequestMethod.GET.getValue());
} else if (method.isAnnotationPresent(PostMapping.class)) {
PostMapping postMapping = method.getAnnotation(PostMapping.class);
url = prefix + postMapping.value()[0];
permission.setMethod(RequestMethod.POST.getValue());
}
// 处理URL
if(url != null && url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
permission.setUrl(url);
// 设置value
if (method.isAnnotationPresent(ApiOperation.class)) {
ApiOperation operation = method.getAnnotation(ApiOperation.class);
if (operation != null) {
String name = operation.value();
permission.setName(name);
}
}
permission.setType(1);
permission.setService("mhxysy");
permission.setParentId(parentId);
permission.setId(SERVICE_NAME + "_" + cls.getSimpleName() + "_" + method.getName());
resources.add(permission);
}
private List<String> doPath(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File f1 : files) {
doPath(f1);
}
}
} else {
if (file.getName().endsWith(".class")) {
classPaths.add(file.getPath());
}
}
return classPaths;
}
}
Permission.java
package cn.edu.sgu.www.mhxysy.entity.system;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* 权限表
* @author heyunlin
* @version 1.0
*/
@Data
@TableName("permission")
public class Permission implements Serializable {
private static final long serialVersionUID = 18L;
@TableId(value = "id", type = IdType.INPUT)
private String id;
/**
* 权限名称
*/
private String name;
/**
* 类型
* 0-顶级权限(控制器类)
* 1-子级权限(接口方法)
*/
private Integer type;
/**
* 请求路径
*/
private String url;
/**
* 请求方式:0-get;1-post
*/
private Integer method;
/**
* 服务名
*/
private String service;
/**
* 父级权限id
*/
private String parentId;
}
4、SQL脚本格式化工具类
该工具类用于将从mysql数据库导出的sql脚本格式化,让自增的ID替换为null,只需要调整一下sql语句的顺序之后就可以实现ID从1自增了(在这之前执行truncate语句重置表,注意:一定先备份表的数据再执行truncate)
package cn.edu.sgu.www.mhxysy.util;
import java.io.*;
/**
* 该类用于修改sql文件,把导出的sql脚本中values后面的id值替换为null
* truncate表之后重新执行生成的sql文件即可以实现表数据从1开始自动排序
* // 注意,SQL文件应该只包含sql的insert语句,多余的其他语句要全部删除
* @author heyunlin
* @version 1.0
*/
public class SqlResortUtil {
public static void main(String[] args) throws IOException {
InputStream fis = new FileInputStream("src/test.sql");
InputStream bis = new BufferedInputStream(fis);
InputStreamReader isr = new InputStreamReader(bis);
BufferedReader br = new BufferedReader(isr);
String line;
OutputStream fos = new FileOutputStream("src/test-cp.sql");
PrintWriter writer = new PrintWriter(fos);
while((line = br.readLine()) != null) {
int start = line.indexOf("(");
int end = line.indexOf(",");
String data = line.substring(0, start + 1) + "null" + line.substring(end);
writer.println(data);
writer.flush();
}
br.close();
fos.close();
}
}
sql脚本的内容应该是这种格式
insert into 数据库名.表名 values (编号, 字段1的值, 字段2的值, ...);
例如:
INSERT INTO `mhxysy`.`prop_category` VALUES (1, '珍品宠物', 0, NULL, NULL, 'chongwu', 100);
INSERT INTO `mhxysy`.`prop_category` VALUES (2, '珍品装备', 0, NULL, NULL, 'equipment', 200);
INSERT INTO `mhxysy`.`prop_category` VALUES (3, '器灵', 0, NULL, NULL, 'qiling', 300);
INSERT INTO `mhxysy`.`prop_category` VALUES (4, '装备打造', 0, NULL, NULL, NULL, 400);
INSERT INTO `mhxysy`.`prop_category` VALUES (5, '星印', 0, NULL, NULL, 'xingyin', 500);
INSERT INTO `mhxysy`.`prop_category` VALUES (6, '宠物装备', 0, NULL, NULL, NULL, 600);
INSERT INTO `mhxysy`.`prop_category` VALUES (7, '高级兽决', 0, NULL, NULL, 'msyj', 700);
INSERT INTO `mhxysy`.`prop_category` VALUES (8, '低级兽决', 0, NULL, NULL, 'msyj', 800);
INSERT INTO `mhxysy`.`prop_category` VALUES (9, '药品', 0, NULL, NULL, 'medicine', 900);
INSERT INTO `mhxysy`.`prop_category` VALUES (10, '烹饪', 0, NULL, NULL, 'cuisine', 1000);
5、ip地址工具类
package cn.edu.sgu.www.mhxysy.util;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* ip地址工具类
* @author heyunlin
* @version 1.0
*/
public class IpUtils {
/**
* 获取本机IP地址
*/
public static String getLocalHostAddress() {
InetAddress inetAddress = null;
try {
inetAddress = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return inetAddress == null ? null : inetAddress.getHostAddress();
}
/**
* 获取本机名称
*/
public static String getLocalHostName() {
InetAddress inetAddress = null;
try {
inetAddress = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return inetAddress == null ? null : inetAddress.getHostName();
}
/**
* 获取客户端IP
* @return String
*/
public static String getIp() {
HttpServletRequest request = getRequest();
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* 获取浏览器类型
* @param request HttpServletRequest
* @return String 浏览器类型
*/
public static String getBrowserType(HttpServletRequest request) {
String type = "其它";
String browserName = request.getHeader("USER-AGENT").toLowerCase();
if (browserName.indexOf("msie") > 0) {
type = "IE";
} else if (browserName.indexOf("firefox") > 0) {
type = "Firefox";
} else if (browserName.indexOf("chrome") > 0) {
type = "Chrome";
} else if (browserName.indexOf("opera") > 0) {
type = "Opera";
} else if (browserName.indexOf("gecko") > 0 && browserName.indexOf("rv:11") > 0) {
type = "IE11";
}
return type;
}
private static HttpServletRequest getRequest() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
assert attributes != null;
return ((ServletRequestAttributes) attributes).getRequest();
}
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress = InetAddress.getLocalHost();
// 本机IP地址
System.out.println("Local HostAddress:" + inetAddress.getHostAddress());
// 本机名称
System.out.println("Local host name: " + inetAddress.getHostName());
}
}
6、文件上传工具类
UploadUtils封装了本地文件上传的通用代码:
1、通过MultipartFile对象获取文件名
2、创建目标文件对象
3、保存文件
4、返回文件的相对路径,主要用于前端的图片回显
package cn.edu.sgu.www.mhxysy.util;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
/**
* 文件上传工具类
* @author heyunlin
* @version 1.0
*/
@Component
public class UploadUtils {
/**
* 文件上传根路径
*/
@Value("${uploads.path}")
private String root;
/**
* 图片文件名后缀
*/
@Value("${uploads.file.suffix}")
String picSuffix;
public String getRoot() {
return root;
}
/**
* 图片上传
* @param file MultipartFile对象
* @param directory 文件上传目录
* @return String 图片的相对路径
*/
public String upload(MultipartFile file, String directory) throws IOException {
boolean result = check(file);
if (result) {
// 获取文件名
String fileName = StringUtils.getFileName(file);
// 创建目标对象
File targetFile = new File(root + directory, fileName);
// 保存文件
file.transferTo(targetFile);
return directory + "/" + fileName;
}
return null;
}
/**
* 检查文件格式
* @param file MultipartFile
*/
private boolean check(MultipartFile file) {
if (file == null) {
throw new GlobalException(ResponseCode.BAD_REQUEST, "您未上传任何图片!");
}
String filename = file.getOriginalFilename();
if (StringUtils.isNotEmpty(filename)) {
String fileType = StringUtils.getFileType(filename).toLowerCase();
if (!picSuffix.contains(fileType)) {
throw new GlobalException(ResponseCode.BAD_REQUEST, "只允许上传格式为" + picSuffix + "的图片");
}
return true;
} else {
throw new GlobalException(ResponseCode.BAD_REQUEST, "获取上传的文件名失败~");
}
}
}
application.yml相关的配置,可以配置文件上传的路径,也就是静态资源路径,以及接受的文件类型
uploads:
# 文件上传路径
path: D:/uploads/mhxysy
# 上传文件的类型(文件名后缀)
file:
suffix: .webp,.jpeg,.jpg,.png
7、获取用户登录信息的工具类
该工具类仅适用于shiro安全框架
package cn.edu.sgu.www.mhxysy.util;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.entity.system.User;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
/**
* 获取用户信息的工具类
* @author heyunlin
* @version 1.0
*/
public class UserUtils {
/**
* 得到Subject对象
* @return Subject
*/
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
/**
* 获取登录的用户信息
* @return User
*/
public static User getUserInfo() {
Object object = getSubject().getPrincipal();
if (object == null) {
throw new GlobalException(ResponseCode.BAD_REQUEST, "获取登录信息失败,当前没有用户登录。");
}
return (User) object;
}
/**
* 获取登录的用户名
* @return String
*/
public static String getLoginUsername() {
return getUserInfo().getUsername();
}
}
User.java
package cn.edu.sgu.www.mhxysy.entity.system;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 用户
* @author heyunlin
* @version 1.0
*/
@Data
@TableName("user")
public class User implements Serializable {
private static final long serialVersionUID = 18L;
@TableId(value = "id", type = IdType.INPUT)
private String id;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private Integer gender;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 手机号
*/
private String phone;
/**
* 是否启用
*/
private Boolean isEnable;
/**
* 最后一次登录时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime lastLoginTime;
}
好了,这篇文章就分享到这里了,看完不要忘了点赞+收藏哦~