工具
工具记载
Zip
操作
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@Slf4j
public class FileZipUtils {
private static final String POINT = ".";
private static final String SUFFIX = POINT + "zip";
/**
* 创建压缩文件
*
* @param filePath 文件路径
*/
public static void zip(String filePath) {
zip(new File(filePath));
}
/**
* 创建压缩文件
*
* @param file 文件
*/
public static void zip(File file) {
String filePath = file.getAbsolutePath();
String zipFilePath;
if (file.isDirectory()) {
zipFilePath = filePath + SUFFIX;
} else {
zipFilePath = filePath.substring(0, filePath.lastIndexOf(POINT)) + SUFFIX;
}
log.debug("zipFilePath:{}", zipFilePath);
zip(file, zipFilePath);
}
/**
* 创建压缩文件
*
* @param filePath 文件路径
* @param zipFilePath 压缩文件路径
*/
public static void zip(String filePath, String zipFilePath) {
File file = new File(filePath);
zip(file, zipFilePath);
}
/**
* 创建压缩文件
*
* @param file 文件
* @param zipFilePath 压缩文件路径
*/
public static void zip(File file, String zipFilePath) {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(Paths.get(zipFilePath)))) {
// 添加文件到压缩包
if (file.isDirectory()) {
compressFolder(file, zipOutputStream);
} else {
addToZipFile(file, zipOutputStream);
}
} catch (IOException e) {
log.error("创建压缩文件 error", e);
}
}
/**
* 创建压缩文件
*
* @param files 文件集合
* @param zipFilePath 压缩文件路径
*/
public static void zip(File[] files, String zipFilePath) {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(Paths.get(zipFilePath)))) {
// 添加文件到压缩包
for (File file : files) {
if (file.isDirectory()) {
compressFolder(file, zipOutputStream);
} else {
addToZipFile(file, zipOutputStream);
}
}
} catch (IOException e) {
log.error("创建压缩文件 error", e);
}
}
/**
* 解压缩文件
*
* @param zipFilePath zip文件路径
*/
public static void unzip(String zipFilePath) {
File zipFile = new File(zipFilePath);
unzip(zipFilePath, zipFile.getParentFile().getAbsolutePath());
}
/**
* 解压缩文件
*
* @param zipFile zip文件
*/
public static void unzip(File zipFile) {
String zipFilePath = zipFile.getAbsolutePath();
unzip(zipFilePath, zipFile.getParentFile().getAbsolutePath());
}
/**
* 解压缩文件
*
* @param zipFilePath zip文件路径
* @param filePath 文件路径
*/
public static void unzip(String zipFilePath, String filePath) {
try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(Paths.get(zipFilePath)))) {
// 解压缩文件
unzipFiles(zipInputStream, filePath);
} catch (IOException e) {
log.error("解压缩文件 error", e);
}
}
/**
* 解压缩文件
*
* @param zipInputStream zip文件
* @param filePath 文件
* @throws IOException IOException
*/
private static void unzipFiles(ZipInputStream zipInputStream, String filePath) throws IOException {
byte[] buffer = new byte[1024];
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
String fileName = entry.getName();
File outputFile = new File(getPath(filePath, fileName));
// 创建文件夹
// entry.isDirectory() 的 判断逻辑为 name.endsWith("/"),受到系统限制,故不使用
if (fileName.endsWith(File.separator)) {
outputFile.mkdirs();
} else {
// 创建文件并写入内容
new File(outputFile.getParent()).mkdirs();
try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
int bytesRead;
while ((bytesRead = zipInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, bytesRead);
}
}
}
zipInputStream.closeEntry();
}
}
/**
* 添加文件夹到zip文件
*
* @param folder 文件夹
* @param zipOutputStream zip文件
* @throws IOException IOException
*/
private static void compressFolder(File folder, ZipOutputStream zipOutputStream) throws IOException {
compressFolder(folder, folder.getName(), zipOutputStream);
}
/**
* 添加文件夹到zip文件
*
* @param folder 文件夹
* @param zipEntryName zip压缩文件名称
* @param zipOutputStream zip文件
* @throws IOException IOException
*/
private static void compressFolder(File folder, String zipEntryName, ZipOutputStream zipOutputStream) throws IOException {
File[] folderFiles = folder.listFiles();
if (folderFiles != null && folderFiles.length > 0) {
for (File folderFile : folderFiles) {
String name = folderFile.getName();
String folderFileEntryName = getPath(zipEntryName, name);
if (folderFile.isDirectory()) {
// 压缩子文件夹
compressFolder(folderFile, folderFileEntryName, zipOutputStream);
} else {
// 压缩文件
addToZipFile(folderFile, folderFileEntryName, zipOutputStream);
}
}
} else {
// 空文件夹处理
emptyFolder(zipEntryName, zipOutputStream);
}
}
/**
* 空文件夹处理
*
* @param zipEntryName zip压缩文件名称
* @param zipOutputStream zip文件
* @throws IOException IOException
*/
private static void emptyFolder(String zipEntryName, ZipOutputStream zipOutputStream) throws IOException {
// // 空文件夹的处理
ZipEntry entry = new ZipEntry(getSepPath(zipEntryName));
zipOutputStream.putNextEntry(entry);
// 没有文件,不需要文件的copy
zipOutputStream.closeEntry();
}
/**
* 添加文件到zip文件
*
* @param file 文件
* @param zipOutputStream zip文件
* @throws IOException IOException
*/
private static void addToZipFile(File file, ZipOutputStream zipOutputStream) throws IOException {
addToZipFile(file, file.getName(), zipOutputStream);
}
/**
* 添加文件到zip文件
*
* @param file 文件
* @param zipEntryName zip压缩文件名称
* @param zipOutputStream zip文件
* @throws IOException IOException
*/
private static void addToZipFile(File file, String zipEntryName, ZipOutputStream zipOutputStream) throws IOException {
// 创建ZipEntry对象并设置文件名
ZipEntry entry = new ZipEntry(zipEntryName);
zipOutputStream.putNextEntry(entry);
// 读取文件内容并写入Zip文件
try (FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
zipOutputStream.write(buffer, 0, bytesRead);
}
}
// 完成当前文件的压缩
zipOutputStream.closeEntry();
}
/**
* 获取 separator结尾 路径
*
* @param path 获取 separator结尾 路径
* @return separator结尾 路径
*/
private static String getSepPath(String... path) {
return getPath(path) + File.separator;
}
/**
* 获取路径
*
* @param path 获取路径
* @return 路径
*/
private static String getPath(String... path) {
return String.join(File.separator, path);
}
/**
* 创建文件
*
* @param file 文件
*/
private static void createNewFile(File file) {
String path = file.getAbsolutePath();
if (!file.exists()) {
try {
boolean create = file.createNewFile();
log.info("createNewFile:{} -> path:{}", create, path);
} catch (IOException e) {
log.error("createNewFile -> path:{}, error", path);
}
}
}
}
GZIP
操作
可用于压缩超大的
json
串 等
import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* GZIPUtils
*
* @author JunJian
* @since 2024/7/8 14:52
*/
@Slf4j
public class GZIPUtils {
public static final String GZIP_ENCODE_UTF_8 = "UTF-8";
/**
* 字符串压缩为GZIP字节数组
*
* @param str 字符串
* @return GZIP压缩后的字节数组(base64编码)
*/
public static String compressToString(String str) {
byte[] bytes = compress(str, GZIP_ENCODE_UTF_8);
if (bytes == null || bytes.length == 0) {
return null;
}
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(bytes);
}
/**
* 字符串压缩为GZIP字节数组
*
* @param str 字符串
* @return GZIP压缩后的字节数组
*/
public static byte[] compress(String str) {
return compress(str, GZIP_ENCODE_UTF_8);
}
/**
* 字符串压缩为GZIP字节数组
*
* @param str 字符串
* @param encoding 编码方式
* @return GZIP压缩后的字节数组
*/
public static byte[] compress(String str, String encoding) {
if (str == null || str.isEmpty()) {
return null;
}
byte[] bytes = null;
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(out)) {
gzip.write(str.getBytes(encoding));
gzip.finish();
bytes = out.toByteArray();
} catch (IOException e) {
log.error("压缩失败!", e);
}
return bytes;
}
/**
* GZIP解压缩
*
* @param bytes GZIP压缩后的字节数组
* @return 原字符串字节数组
*/
public static byte[] unCompress(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
byte[] origBytes = null;
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
GZIPInputStream unGzip = new GZIPInputStream(in)) {
byte[] buffer = new byte[256];
int n;
while ((n = unGzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
origBytes = out.toByteArray();
} catch (IOException e) {
log.error("解压失败!", e);
}
return origBytes;
}
/**
* 解压并返回String
*
* @param str GZIP压缩后的字节数组(base64编码)
* @return 原字符串字节数组(转String)
*/
public static String unCompressString(String str) {
if (str == null || str.isEmpty()) {
return null;
}
BASE64Decoder decoder = new BASE64Decoder();
byte[] bytes = null;
try {
bytes = decoder.decodeBuffer(str);
} catch (IOException e) {
log.error("BASE64Decoder 异常", e);
}
return unCompressToString(bytes, GZIP_ENCODE_UTF_8);
}
/**
* 解压并返回String
*
* @param bytes GZIP压缩后的字节数组
* @return 原字符串字节数组(转String)
*/
public static String unCompressToString(byte[] bytes) {
return unCompressToString(bytes, GZIP_ENCODE_UTF_8);
}
/**
* GZIP解压缩
*
* @param bytes GZIP压缩后的字节数组
* @return 原字符串字节数组
*/
public static byte[] unCompressToByteArray(byte[] bytes) {
return unCompressToByteArray(bytes, GZIP_ENCODE_UTF_8);
}
/**
* 解压成字符串
*
* @param bytes 压缩后的字节数组
* @param encoding 编码方式
* @return 解压后的字符串
*/
public static String unCompressToString(byte[] bytes, String encoding) {
byte[] origBytes = unCompressToByteArray(bytes, encoding);
if (origBytes == null || origBytes.length == 0) {
return null;
}
return new String(origBytes);
}
/**
* 解压成字节数组
*
* @param bytes 压缩后的字节数组
* @param encoding 编码方式
* @return 解压后的字符串
*/
public static byte[] unCompressToByteArray(byte[] bytes, String encoding) {
if (bytes == null || bytes.length == 0) {
return null;
}
byte[] byteArray = null;
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
GZIPInputStream unGzip = new GZIPInputStream(in)) {
byte[] buffer = new byte[256];
int n;
while ((n = unGzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
byteArray = out.toByteArray();
} catch (IOException e) {
log.error("解压缩失败!", e);
throw new RuntimeException(e);
}
return byteArray;
}
/**
* 将字节流转换成文件
*
* @param file 文件
* @param data 字节流
*/
public static void saveFile(File file, byte[] data) {
if (data != null) {
if (file.exists()) {
boolean delete = file.delete();
log.debug("{} - {}", file.getPath(), delete);
}
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(data, 0, data.length);
fos.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
临时文件
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
/**
* TempFileUtils
*
* @author JunJian
* @since 2024/7/8 14:52
*/
@Slf4j
public class TmpFileUtils {
/**
* 创建服务临时文件
*
* @param fileName 文件名称
* @return 服务临时文件
*/
public static File createTmpFile(String fileName) {
return createTmpFile(fileName, createTmpDir());
}
/**
* 创建服务临时文件
*
* @param fileName 文件名称
* @param dir 目录
* @return 服务临时文件
*/
public static File createTmpFile(String fileName, File dir) {
File file = new File(dir, fileName);
if (!file.exists()) {
boolean create = false;
try {
create = file.createNewFile();
} catch (IOException e) {
log.error("临时文件 - 创建 - 异常: path:{}", file.getPath(), e);
}
log.debug("临时文件 - 创建: path:{} - create:{}", file.getPath(), create);
}
return file;
}
/**
* 创建服务临时文件夹目录
*
* @return 服务临时文件夹目录
*/
public static File createTmpDir() {
String path = UUID.randomUUID().toString().replace("-", "");
return createTmpDir(path);
}
/**
* 创建服务临时文件夹目录
*
* @param dirName 路径名称
* @return 服务临时文件夹目录
*/
public static File createTmpDir(String dirName) {
File file = new File(getTmp(), dirName);
if (!file.exists()) {
boolean create = file.mkdirs();
log.debug("临时文件夹 - 创建: path:{} - create:{}", file.getPath(), create);
}
return file;
}
/**
* 获取系统临时文件夹目录
*
* @return 系统临时文件夹目录
*/
public static String getTmp() {
return System.getProperty("java.io.tmpdir");
}
/**
* 删除文件
*
* @param folder 文件
*/
public static void deleteFolder(File folder) {
String path = folder.getPath();
boolean delete = delete(folder);
log.debug("临时文件 - 删除: path:{} - delete:{}", path, delete);
}
/**
* 删除文件
*
* @param folder 文件
* @return 是否删除
*/
private static boolean delete(File folder) {
if (folder.isDirectory()) {
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
delete(file);
}
}
}
return folder.delete();
}
}
Mybatis
Mybatis
日志替换?
并打印耗时
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.stereotype.Component;
import java.text.DateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Matcher;
/**
* MyBatis拦截器打印不带问号的完整sql语句
*/
@Slf4j
@Component
// 只在开发环境下执行
// @ConditionalOnProperty(value = "spring.profiles.active", havingValue = "dev")
// @ConditionalOnProperty(value = "com.mybatis.showSql", havingValue = "1")
@Intercepts({
// update 包括了最常用的 insert/update/delete 三种操作
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class,
Object.class, RowBounds.class, ResultHandler.class})})
public class MybatisSQLResolverInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取xml中的一个select/update/insert/delete节点,是一条SQL语句
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object parameter = null;
// 获取参数,if语句成立,表示sql语句有参数,参数格式是map形式
if (invocation.getArgs().length > 1) {
parameter = invocation.getArgs()[1];
}
// 获取到节点的id,即sql语句的id
String id = mappedStatement.getId();
// BoundSql就是封装myBatis最终产生的sql类
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
// 获取节点的配置
Configuration configuration = mappedStatement.getConfiguration();
// 判断是否是查询
boolean isSelect = SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType());
// 获取到最终的sql语句
try {
String sql = showSql(configuration, boundSql);
log.info("{} : ==> Preparing: {}", id, sql);
} catch (Exception e) {
log.error("{} : ==> showSql error: {}", id, e.getMessage());
}
long start = System.currentTimeMillis();
// 执行完上面的任务后,不改变原有的sql执行过程
Object result = invocation.proceed();
long time = System.currentTimeMillis() - start;
// 获取到最终的结果数
try {
String total = shownTotal(result);
if (isSelect) {
log.info("{} : <== Total: {} , time: {}ms", id, total, time);
} else {
log.info("{} : <== Updates: {} , time: {}ms", id, total, time);
}
} catch (Exception e) {
log.error("{} : <== shownTotal error: {}", id, e.getMessage());
}
return result;
}
/**
* 进行?的替换
*/
public static String showSql(Configuration configuration, BoundSql boundSql) {
// 获取参数
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// sql语句中多个空格都用一个空格代替
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (CollectionUtils.isNotEmpty(parameterMappings) && parameterObject != null) {
// 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
// 如果根据parameterObject.getClass()可以找到对应的类型,则替换
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?",
Matcher.quoteReplacement(getParameterValue(parameterObject)));
} else {
// MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?",
Matcher.quoteReplacement(getParameterValue(obj)));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
// 该分支是动态sql
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?",
Matcher.quoteReplacement(getParameterValue(obj)));
} else {
// 未知参数,替换?防止错位
sql = sql.replaceFirst("\\?", "unknown");
}
}
}
}
return sql;
}
/**
* 获取结果数
*/
private String shownTotal(Object result) {
if (Objects.nonNull(result)) {
if (result instanceof Collection<?>) {
int size = ((Collection<?>) result).size();
return String.valueOf(size);
}
if (result instanceof Number) {
return String.valueOf(result);
}
if (result instanceof Page<?>) {
int size = ((Page<?>) result).getRecords().size();
return String.valueOf(size);
}
}
return "0";
}
/**
* 如果参数是String,则添加单引号
* 如果参数是日期,则转换为时间格式器并加单引号; 对参数是null和不是null的情况作了处理
*/
private static String getParameterValue(Object obj) {
String value;
if (obj instanceof String) {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT,
DateFormat.DEFAULT, Locale.CHINA);
value = "'" + formatter.format(obj) + "'";
} else {
if (obj != null) {
value = obj.toString();
} else {
value = "null";
}
}
return value;
}
}