工具
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 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);}}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);// 没有文件,不需要文件的copyzipOutputStream.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);}}}
}
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.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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;import java.text.DateFormat;
import java.util.ArrayList;
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 {@Overridepublic 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语句的idString id = mappedStatement.getId();// BoundSql就是封装myBatis最终产生的sql类BoundSql boundSql = mappedStatement.getBoundSql(parameter);// 获取节点的配置Configuration configuration = mappedStatement.getConfiguration();// 获取到最终的sql语句try {String sql = showSql(configuration, boundSql);log.info("{} ==> : Preparing: {}", id, sql);} catch (Exception e) {log.error("{} ==> : Preparing error: {}", id, e.getMessage());}long start = System.currentTimeMillis();// 执行完上面的任务后,不改变原有的sql执行过程Object result = invocation.proceed();long time = System.currentTimeMillis() - start;// 获取到最终的结果数try {String total = shownTotal(result);log.info("{} <== : Total: {} , time: {}ms", id, total, time);} catch (Exception e) {log.error("{} <== : Total 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)) {// 该分支是动态sqlObject 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(new Date()) + "'";} else {if (obj != null) {value = obj.toString();} else {value = "";}}return value;}
}