diff --git a/modules/test/src/main/resources/domains/OperateType.xml b/modules/test/src/main/resources/domains/OperateType.xml index aaea4e3..8feda08 100644 --- a/modules/test/src/main/resources/domains/OperateType.xml +++ b/modules/test/src/main/resources/domains/OperateType.xml @@ -1,7 +1,7 @@ - + @@ -10,5 +10,6 @@ + diff --git a/modules/test/src/main/resources/views/actionGroup.xml b/modules/test/src/main/resources/views/actionGroup.xml index 7f27303..a448e72 100644 --- a/modules/test/src/main/resources/views/actionGroup.xml +++ b/modules/test/src/main/resources/views/actionGroup.xml @@ -33,4 +33,13 @@ + + + + + + + + + diff --git a/modules/test/src/main/resources/views/menu.xml b/modules/test/src/main/resources/views/menu.xml index 9785193..55c6af0 100644 --- a/modules/test/src/main/resources/views/menu.xml +++ b/modules/test/src/main/resources/views/menu.xml @@ -5,6 +5,6 @@ - + diff --git a/src/main/java/com/system/log/LogTypeEnum.java b/src/main/java/com/system/log/LogTypeEnum.java new file mode 100644 index 0000000..7549cfe --- /dev/null +++ b/src/main/java/com/system/log/LogTypeEnum.java @@ -0,0 +1,23 @@ +package com.system.log; + +import com.hypaas.db.ValueEnum; +import java.util.Objects; + +public enum LogTypeEnum implements ValueEnum { + Interface("Interface"), + + Exception("Exception"), + + Null(""); + + private final String value; + + private LogTypeEnum(String value) { + this.value = Objects.requireNonNull(value); + } + + @Override + public String getValue() { + return value; + } +} diff --git a/src/main/java/com/system/log/SystemLog.java b/src/main/java/com/system/log/SystemLog.java new file mode 100644 index 0000000..e444d31 --- /dev/null +++ b/src/main/java/com/system/log/SystemLog.java @@ -0,0 +1,22 @@ +package com.system.log; + +import static java.nio.file.StandardWatchEventKinds.*; + +import groovy.util.logging.Log4j; +import java.io.*; +import java.nio.file.*; + +@Log4j +public class SystemLog { + + public static void main(String[] args) throws Exception { + // String password = "zqy19."; + // //String regex = " ^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$"; + // //String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@#$%^&+=]){6,16}$"; + // String regex = + // "^(?![0-9A-Za-z]+$)(?![0-9A-Z\\W]+$)(?![0-9a-z\\W]+$)(?![A-Za-z\\W]+$)[0-9A-Za-z~!@#$%^&*()_+`\\-={}|\\[\\]\\\\:\";'<>?,./]{6,16}$"; + // Pattern pattern = Pattern.compile(regex); + // Matcher matcher = pattern.matcher(password); + // System.out.println(matcher.find()); + } +} diff --git a/src/main/java/com/system/log/controller/LogController.java b/src/main/java/com/system/log/controller/LogController.java new file mode 100644 index 0000000..6f36091 --- /dev/null +++ b/src/main/java/com/system/log/controller/LogController.java @@ -0,0 +1,73 @@ +package com.system.log.controller; + +import com.alibaba.fastjson.JSONObject; +import com.google.inject.Inject; +import com.google.inject.servlet.RequestScoped; +import com.hypaas.db.JpaSupport; +import com.hypaas.rpc.ActionRequest; +import com.hypaas.rpc.ActionResponse; +import com.system.log.core.FileUtils; +import com.system.log.service.LogService; +import java.io.File; +import java.io.IOException; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +/** + * @author zhangqiyang + * @description LogManage + * @date 2024/3/12 + */ +@RequestScoped +@Produces(MediaType.APPLICATION_JSON) +@Path("/log") +public class LogController extends JpaSupport { + + @Inject LogService logService; + + // 过滤查询日志接口 + /* + * logType 日志类型 + * startTime 需要过滤的日志的开始时间 + * endTime 需要过滤的日志的结束时间 + * keyWord 关键字 + */ + @GET + @Path("/getDirContent") + public JSONObject getDirContent( + @QueryParam("logType") String logType, + @QueryParam("startTime") String startTime, + @QueryParam("endTime") String endTime, + @QueryParam("keyWord") String keyWord) + throws IOException { + return logService.getDirContent(logType, startTime, endTime, keyWord); + } + + // 以zip形式导出日志文件,并设置解压密码 + /* + * password 密码 + * conditionPassword 确认密码 + * logType 日志类型 + * startTime 需要过滤的日志的开始时间 + * endTime 需要过滤的日志的结束时间 + * keyWord 关键字 + */ + + @POST + @Path("/getFileZip") + public void getFileZip(ActionRequest request, ActionResponse response) { + File file = logService.getFileZip(request, response); + FileUtils.downloadFile(response, file); + } + + // @GET + // @Path("/getFile") + // public JSONObject getFileChange() { + // return logService.getFileChange(); + // } + + public void exportLog(ActionRequest request, ActionResponse response) { + File file = logService.exportLog(request, response); + FileUtils.downloadFile(response, file); + } +} diff --git a/src/main/java/com/system/log/core/FileUtils.java b/src/main/java/com/system/log/core/FileUtils.java new file mode 100644 index 0000000..279cce7 --- /dev/null +++ b/src/main/java/com/system/log/core/FileUtils.java @@ -0,0 +1,97 @@ +package com.system.log.core; + +import com.hypaas.db.Query; +import com.hypaas.i18n.I18n; +import com.hypaas.inject.Beans; +import com.hypaas.meta.MetaFiles; +import com.hypaas.meta.db.MetaFile; +import com.hypaas.meta.db.repo.MetaFileRepository; +import com.hypaas.meta.schema.actions.ActionView; +import com.hypaas.rpc.ActionResponse; +import groovy.util.logging.Slf4j; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import javax.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** 文件工具类 获取项目中的文件 */ +@Slf4j +public class FileUtils { + + private static Logger logger = LoggerFactory.getLogger(FileUtils.class); + + @Inject MetaFileRepository metaFileRepository; + + /** 文件-导出File */ + public static void downloadFile(ActionResponse response, File file) { + if (file == null) { + response.setError("文件不存在"); + return; + } + try { + // 通过文件名查询是否存在 + MetaFile metaFile = + Query.of(MetaFile.class) + .filter("self.fileName = :fileName") + .bind("fileName", file.getName()) + .fetchOne(); + if (metaFile == null) { + FileInputStream fileInputStream = new FileInputStream(file); + metaFile = Beans.get(MetaFiles.class).upload(file); + fileInputStream.close(); + } + + // 判断更改时间是否超过文件创建时间 + long lastModified = file.lastModified(); + LocalDateTime updateOn = metaFile.getUpdatedOn(); + if (updateOn == null) { + updateOn = metaFile.getCreatedOn(); + } + long createdOn = updateOn.toInstant(ZoneOffset.of("+8")).toEpochMilli(); + if (lastModified > createdOn) { + FileInputStream fileInputStream = new FileInputStream(file); + metaFile = Beans.get(MetaFiles.class).upload(file, metaFile); + fileInputStream.close(); + } + + downloadMetaFile(response, metaFile); + } catch (FileNotFoundException fileNotFoundException) { + // logger.error("下载File文件时报错:", ExceptionUtils.getExceptionInfo(fileNotFoundException)); + } catch (IOException ioException) { + // logger.error("下载File文件时报错:", ExceptionUtils.getExceptionInfo(ioException)); + } + } + + /** + * 文件-导出metaFile + * + * @param response: + * @param metaFile: + * @return + * @author huabiao + * @description + * @create 2022/2/18 8:52 + */ + public static void downloadMetaFile(ActionResponse response, MetaFile metaFile) { + if (metaFile == null) { + response.setError("文件不存在"); + return; + } + response.setView( + ActionView.define(I18n.get("Export file")) + .model(MetaFile.class.getName()) + .add( + "html", + "ws/rest/com.hypaas.meta.db.MetaFile/" + + metaFile.getId() + + "/content/download?v=" + + metaFile.getVersion()) + .param("download", "log.zip") + .map()); + } +} diff --git a/src/main/java/com/system/log/listener/FileListener.java b/src/main/java/com/system/log/listener/FileListener.java new file mode 100644 index 0000000..ce96b11 --- /dev/null +++ b/src/main/java/com/system/log/listener/FileListener.java @@ -0,0 +1,27 @@ +package com.system.log.listener; + +import java.io.File; +import org.apache.commons.io.monitor.FileAlterationListenerAdaptor; +import org.apache.commons.io.monitor.FileAlterationObserver; + +public class FileListener extends FileAlterationListenerAdaptor { + + @Override + public void onStart(FileAlterationObserver observer) { + super.onStart(observer); + System.out.println("onStart"); + } + + @Override + public void onFileChange(File file) { + super.onFileChange(file); + String compressedPath = file.getAbsolutePath(); + System.out.println("修改:" + compressedPath); + } + + @Override + public void onStop(FileAlterationObserver observer) { + super.onStop(observer); + System.out.println("onStop"); + } +} diff --git a/src/main/java/com/system/log/listener/FileMonitor.java b/src/main/java/com/system/log/listener/FileMonitor.java new file mode 100644 index 0000000..a08a1ee --- /dev/null +++ b/src/main/java/com/system/log/listener/FileMonitor.java @@ -0,0 +1,83 @@ +package com.system.log.listener; + +import java.io.File; +import java.util.concurrent.TimeUnit; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.HiddenFileFilter; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.monitor.FileAlterationMonitor; +import org.apache.commons.io.monitor.FileAlterationObserver; + +public class FileMonitor { + + private FileMonitor() {} + + private static FileMonitor instance; + + public static final FileMonitor getInstance() { + if (instance == null) { + synchronized (FileMonitor.class) { + if (instance == null) { + instance = new FileMonitor(); + } + } + } + return instance; + } + + // 设置监听路径 + private final String monitorDir = + "C:\\Users\\张齐杨\\AppData\\Local\\JetBrains\\IntelliJIdea2023.2\\tomcat\\00f36d27-250c-4912-a029-744fef843e7c\\logs\\localhost_access_log.2024-03-21.txt"; + + // 设置轮询间隔 + private final long interval = TimeUnit.SECONDS.toMillis(1); + + public FileAlterationMonitor getMonitor() { + // 创建过滤器 + // 1. 过滤可见目录 + IOFileFilter directories = + FileFilterUtils.and(FileFilterUtils.directoryFileFilter(), HiddenFileFilter.VISIBLE); + // 2. 过滤以.txt结尾的文件,当该类型文件增删改时就会被监听到 + IOFileFilter files = + FileFilterUtils.and( + FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(".txt")); + // 两个筛选条件满足一个时就监听 + IOFileFilter filter = FileFilterUtils.or(directories, files); + + // 装配过滤器 + FileAlterationObserver observer = new FileAlterationObserver(new File(monitorDir), filter); + + // 向监听者添加监听器,并注入业务服务 + observer.addListener(new FileListener()); + + // 返回监听者 + return new FileAlterationMonitor(interval, observer); + } + + // private FileAlterationMonitor monitor; + // + // public FileMonitor(long interval) { + // monitor = new FileAlterationMonitor(interval); + // } + // + // /** + // * 给文件添加监听 + // * + // * @param path 文件路径 + // * @param listener 文件监听器 + // */ + // public void monitor(String path, FileAlterationListener listener) { + // FileAlterationObserver observer = new FileAlterationObserver(new File(path)); + // observer.addListener(listener); + // monitor.addObserver(observer); + // } + // + // public void stop() throws Exception { + // monitor.stop(); + // } + // + // public void start() throws Exception { + // monitor.start(); + // + // } +} diff --git a/src/main/java/com/system/log/service/LogService.java b/src/main/java/com/system/log/service/LogService.java new file mode 100644 index 0000000..d2a9046 --- /dev/null +++ b/src/main/java/com/system/log/service/LogService.java @@ -0,0 +1,440 @@ +package com.system.log.service; + +import Log.LogEntity; +import Log.repo.LogEntityRepository; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.inject.Inject; +import com.hypaas.rpc.ActionRequest; +import com.hypaas.rpc.ActionResponse; +import com.system.log.LogTypeEnum; +import com.system.log.vo.LogRecordVO; +import java.io.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import net.lingala.zip4j.core.ZipFile; +import net.lingala.zip4j.exception.ZipException; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.util.Zip4jConstants; +import org.apache.commons.lang3.StringUtils; + +public class LogService { + + @Inject LogEntityRepository logEntityRepository; + + public JSONObject getDirContent(String logType, String startTime, String endTime, String keyWord) + throws IOException { + // 定义集合,存放文件名称 + List fileList; + // 获取Tomcat的CATALINA_BASE属性 + String catalinaBase = System.getProperty("catalina.base"); + // 获取localhost_access_log所在文件目录 + String accessLogDir = catalinaBase + "\\logs"; + // 找到过滤出的localhost_access_log文件,将文件的绝对路径放入集合中 + fileList = getFilePath(accessLogDir, startTime, endTime); + // 获取所有文件下符合过滤条件内容并返回 + return getFileContent(fileList, logType, startTime, endTime, keyWord); + } + + // 找出文件夹下指定日志文件名并返回 + private List getFilePath(String accessLogDir, String startTime, String endTime) { + // 定义集合,存放当前符合筛选条件的文件名 + List filePathList = new ArrayList<>(); + // 如果不传开始时间与结束时间,指定为null即可,默认输出当天的日志 + if (StringUtils.isEmpty(startTime) && StringUtils.isEmpty(endTime)) { + // 以yyyy-MM-dd格式获取当天日期 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(new Date(System.currentTimeMillis())); + File LogFile = new File(accessLogDir); + File[] file = LogFile.listFiles(); + for (File file1 : file) { + if (file1.toString().contains("localhost_access_log") && file1.toString().contains(date)) { + // 如果此文件是localhost_access_log文件并且是当天的文件,将其放入集合返回 + filePathList.add(file1.getPath()); + return filePathList; + } + } + } else { + filePathList = getFile(accessLogDir, startTime, endTime); + } + return filePathList; + } + + // 使用日历类将符合条件的日志文件放入集合中返回 + private List getFile(String accessLogDir, String startTime, String endTime) { + // 获取传入的开始时间与结束时间的毫秒数,开始时间直接将时分秒置零处理,结束时间将其加上一天后再将其置零处理, + // 这样做的目的是保证取出符合本次过滤时间的所有文件 + List fileList = new ArrayList<>(); + long[] time = getZeroLongTime(startTime, endTime); + // 遍历指定目录中的文件,筛选出符合条件的日志文件 + File LogFile = new File(accessLogDir); + File[] file = LogFile.listFiles(); + for (File file1 : file) { + if (file1.toString().contains("localhost_access_log")) { + // 如果文件名包含"localhost_access_log",则判断时间是否符合要求,如果符合,放入集合中 + if ((getFileLongTime(file1.toString()) + 1000 > time[0]) + && (getFileLongTime(file1.toString()) + 1000 < time[1])) { + fileList.add(file1.getPath()); + } + } + } + return fileList; + } + + // 获取文件名中的时间毫秒值 + private long getFileLongTime(String fileName) { + Date date; + long milliseconds = 0; + String regex = "\\d{4}-\\d{2}-\\d{2}"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(fileName); + if (matcher.find()) { + String time = matcher.group(0); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + + try { + date = simpleDateFormat.parse(time); + } catch (ParseException e) { + throw new RuntimeException(e); + } + milliseconds = date.getTime(); + } + return milliseconds; + } + + // 输入开始时间与结束时间获得对应的零点毫秒数,方便筛选日志文件,必须以"yyyy-MM-dd HH:mm:ss"的形式输入 + private long[] getZeroLongTime(String startTime, String endTime) { + // 用于存放毫秒数结果的数组 + long[] longTime = new long[2]; + Calendar calendar = Calendar.getInstance(); + // 开始处理开始时间,得到毫秒值 + calendar.set(Calendar.YEAR, Integer.parseInt(startTime.substring(0, 4))); + // 日历类中,00表示1月, 01表示2月,故应该减1 + calendar.set(Calendar.MONTH, Integer.parseInt(startTime.substring(5, 7)) - 1); + calendar.set(Calendar.DATE, Integer.parseInt(startTime.substring(8, 10))); + // 这是将当天的【秒】设置为0 + calendar.set(Calendar.SECOND, 0); + // 这是将当天的【分】设置为0 + calendar.set(Calendar.MINUTE, 0); + // 这是将当天的【时】设置为0 + calendar.set(Calendar.HOUR_OF_DAY, 0); + longTime[0] = calendar.getTimeInMillis(); + // 开始处理结束时间,得到毫秒值 + calendar.set(Calendar.YEAR, Integer.parseInt(endTime.substring(0, 4))); + calendar.set(Calendar.MONTH, Integer.parseInt(endTime.substring(5, 7)) - 1); + calendar.set(Calendar.DATE, Integer.parseInt(endTime.substring(8, 10)) + 1); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.HOUR_OF_DAY, 0); + longTime[1] = calendar.getTimeInMillis(); + return longTime; + } + + // 输入开始时间与结束时间获得对应的标准毫秒数,方便筛选每个日志文件中的数据,必须以"yyyy-MM-dd HH:mm:ss"的形式输入 + private long getLongTime(String time) { + Date date; + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + date = simpleDateFormat.parse(time); + } catch (ParseException e) { + throw new RuntimeException(e); + } + return date.getTime(); + } + + // 获取 + private long getLogContentLongTime(String logContent) { + Date date; + SimpleDateFormat simpleDateFormat = + new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.ENGLISH); + try { + // 取出日志文件中例如22/Feb/2024:10:04:32 +0800的部分,转化为毫秒 + date = + simpleDateFormat.parse( + logContent.substring(logContent.indexOf("[") + 1, logContent.indexOf("[") + 21)); + } catch (ParseException e) { + throw new RuntimeException(e); + } + return date.getTime(); + } + + // 返回日志文件的详细内容(StringBuffer) + private JSONObject getFileContent( + List fileList, String logType, String startTime, String endTime, String keyWord) { + JSONArray jsonArray = new JSONArray(); + if (StringUtils.isEmpty(logType)) { + logType = ""; + } + if (StringUtils.isEmpty(keyWord)) { + keyWord = ""; + } + for (String file : fileList) { + try { + // 设置读取器,读取fileList中的文件 + BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); + String line; + // 如果开始时间与结束时间为空,则fileList里只有一个当天的日志文件,不需要时间过滤,只过滤日志类型与关键字即可 + if (StringUtils.isEmpty(startTime) && StringUtils.isEmpty(endTime)) { + // 判断下一行不为空就读取出来进行条件判断 + while ((line = bufferedReader.readLine()) != null) { + // 判断本行数据是否包含输入的日志类型与关键字信息,如果包含,写入文件 + if (LogTypeEnum.Interface.getValue().equals(logType)) { + if ((!line.contains(LogTypeEnum.Exception.getValue())) && line.contains(keyWord)) { + jsonArray.add(logAnalysis(line, file)); + } + } else { + if (line.contains(logType) && line.contains(keyWord)) { + jsonArray.add(logAnalysis(line, file)); + } + } + } + } else { + // 如果开始时间与结束时间不为空,则fileList里不确定有几个日志文件,由于考虑精确到时分秒,需要时间过滤, + // 还需要过滤日志类型与关键字 + while ((line = bufferedReader.readLine()) != null) { + if (LogTypeEnum.Interface.getValue().equals(logType)) { + if (getLongTime(startTime) <= getLogContentLongTime(line) + && getLongTime(endTime) >= getLogContentLongTime(line) + && ((!line.contains(LogTypeEnum.Exception.getValue())) + && line.contains(keyWord))) { + jsonArray.add(logAnalysis(line, file)); + } + } else { + if (getLongTime(startTime) <= getLogContentLongTime(line) + && getLongTime(endTime) >= getLogContentLongTime(line) + && (line.contains(logType) && line.contains(keyWord))) { + jsonArray.add(logAnalysis(line, file)); + } + } + } + } + } catch (Exception e) { + e.getStackTrace(); + } + } + JSONObject jsonObject = new JSONObject(); + JSONObject selectContent = new JSONObject(); + jsonObject.put("code", 200); + jsonObject.put("msg", "操作成功"); + selectContent.put("content", jsonArray); + jsonObject.put("data", selectContent); + return jsonObject; + } + + // 解析日志,提取关键信息 + private JSONObject logAnalysis(String logContent, String fileName) { + JSONObject logDetail = new JSONObject(); + LogRecordVO logRecordVO = new LogRecordVO(); + SimpleDateFormat simpleDateFormat = + new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.ENGLISH); + try { + // 以yyyy-MM-dd HH:mm:ss形式提取时间 + long l = + simpleDateFormat + .parse( + logContent.substring(logContent.indexOf("[") + 1, logContent.indexOf("[") + 21)) + .getTime(); + SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = simpleDateFormat1.format(l); + logRecordVO.setTime(date); + // 提取ip地址 + String ipAddress = logContent.substring(0, logContent.indexOf("-") - 1); + logRecordVO.setIpAddress(ipAddress); + // 写入文件名l + logRecordVO.setFileSource(fileName); + // 写入文件内容 + String log = + logContent.substring(logContent.indexOf("]") + 2, logContent.length()).replace("\"", ""); + logRecordVO.setLogContent(log); + return (JSONObject) JSONObject.toJSON(logRecordVO); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public File getFileZip(ActionRequest request, ActionResponse response) { + String password = request.getContext().get("password").toString(); + String confirmPassword = request.getContext().get("confirmPassword").toString(); + String startTime = request.getContext().get("startTime").toString(); + String endTime = request.getContext().get("endTime").toString(); + String logType = request.getContext().get("logType").toString(); + String keyWord = request.getContext().get("keyWord").toString(); + // 判断密码和确认密码是否都不为空且一致,如果不一致直接返回null + if (StringUtils.isEmpty(password) + || StringUtils.isEmpty(confirmPassword) + || !password.equals(confirmPassword)) { + return null; + } + + // 定义集合,存放文件名称 + List fileList; + // 获取Tomcat的CATALINA_BASE属性 + String catalinaBase = System.getProperty("catalina.base"); + // 获取localhost_access_log所在文件目录 + String accessLogDir = catalinaBase + "\\logs"; + // 找到过滤出的localhost_access_log文件,将文件的绝对路径放入集合中 + fileList = getFilePath(accessLogDir, startTime, endTime); + // 查询出所有的记录 + JSONObject selectResult = getFileContent(fileList, logType, startTime, endTime, keyWord); + + try { + // 创建临时文件,将查询的结果写入临时文件 + File tempFile = File.createTempFile("log", ".txt"); + FileWriter writer = new FileWriter(tempFile); + writer.write(selectResult.toString()); + writer.close(); + + // 根据时间设定输出文件名 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + String date = simpleDateFormat.format(new Date(System.currentTimeMillis())); + + // 获取临时文件目录 + String tempDir = System.getProperty("java.io.tmpdir"); + String tempFilePath = tempDir + "/" + date + ".zip"; + System.out.println(tempFilePath); + // 在临时文件目录中创建一个随机名称的zip文件 + File file = new File(tempFilePath); + ZipFile zipFile = new ZipFile(file); + ZipParameters parameters = new ZipParameters(); // 设置zip包的一些参数集合 + parameters.setEncryptFiles(true); // 是否设置密码(此处设置为:是) + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式(默认值) + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 普通级别(参数很多) + parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密级别 + parameters.setPassword(password); // 压缩包密码 + // 向zip文件中根据设置的参数写入数据 + zipFile.createZipFile(tempFile, parameters); + return file; + } catch (ZipException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // public JSONObject getFileChange() { + // // 定义集合,存放文件名称 + // List fileList; + // // 获取Tomcat的CATALINA_BASE属性 + // String catalinaBase = System.getProperty("catalina.base"); + // // 获取localhost_access_log所在文件目录 + // String accessLogDir = catalinaBase + "\\logs"; + // // 找到过滤出的localhost_access_log文件,将文件的绝对路径放入集合中 + // fileList = getFilePath(accessLogDir, null, null); + // // 返回当天日志文件 + // return getFileContent(fileList, null, null, null, null); + // } + + public File exportLog(ActionRequest request, ActionResponse response) { + String password = request.getContext().get("password").toString(); + String confirmPassword = request.getContext().get("confirmPassword").toString(); + String startTime = request.getContext().get("exportStartTime").toString(); + String endTime = request.getContext().get("exportEndTime").toString(); + if (!password.equals(confirmPassword)) { + return null; + } + // 密码正则表达式校验 + String regex = + "^(?![0-9A-Za-z]+$)(?![0-9A-Z\\W]+$)(?![0-9a-z\\W]+$)(?![A-Za-z\\W]+$)[0-9A-Za-z~!@#$%^&*()_+`\\-={}|\\[\\]\\\\:\";'<>?,./]{6,16}$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(password); + if (!matcher.find()) { + // 密码不通过正则校验 + response.setAlert("密码需要包含6-16位数字+大写字母+小写字母+特殊字符!"); + } + + List selectResult = new ArrayList<>(); + List logEntitiesList = logEntityRepository.all().fetch(); + if (startTime != null && endTime != null) { + // 如果输入的开始时间与结束时间都不为空,则输出时间范围内的所有记录 + for (LogEntity logEntity : logEntitiesList) { + if ((getSqlLongTime(logEntity.getTime()) > getSqlLongTime(startTime)) + && (getSqlLongTime(logEntity.getTime()) < getSqlLongTime(endTime))) { + selectResult.add(logEntity); + } + } + } + + if (startTime == null && endTime != null) { + // 如果输入的开始时间为空,则输出结束时间之前的所有记录 + for (LogEntity logEntity : logEntitiesList) { + if ((getSqlLongTime(logEntity.getTime()) < getSqlLongTime(endTime))) { + selectResult.add(logEntity); + } + } + } + + if (startTime != null && endTime == null) { + // 如果输入的结束时间为空,则输出开始时间之后的所有记录 + for (LogEntity logEntity : logEntitiesList) { + if ((getSqlLongTime(logEntity.getTime()) > getSqlLongTime(startTime))) { + selectResult.add(logEntity); + } + } + } + + if (startTime == null && endTime == null) { + // 如果输入的时间都为空,则输出所有记录 + for (LogEntity logEntity : logEntitiesList) { + selectResult.add(logEntity); + } + } + Object jsonObject = JSONObject.toJSON(selectResult); + return exportLogZip(jsonObject, password); + } + + private long getSqlLongTime(Object time) { + // logEntity.getTime()形式 "2024-02-04T14:03:45.114" + // startTime()形式 "2024-02-04 14:03" + Date date; + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + if (time.toString().length() < 19) { + time = time.toString().replace("T", " ") + ":00"; + } else { + time = time.toString().substring(0, 19).replace("T", " "); + } + try { + date = simpleDateFormat.parse(time.toString()); + } catch (ParseException e) { + throw new RuntimeException(e); + } + return date.getTime(); + } + + public File exportLogZip(Object selectResult, String password) { + try { + // 创建临时文件,将查询的结果写入临时文件 + File tempFile = File.createTempFile("log", ".txt"); + FileWriter writer = new FileWriter(tempFile); + writer.write(selectResult.toString()); + writer.close(); + + // 根据时间设定输出文件名 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + String date = simpleDateFormat.format(new Date(System.currentTimeMillis())); + + // 获取临时文件目录 + String tempDir = System.getProperty("java.io.tmpdir"); + String tempFilePath = tempDir + "/" + date + ".zip"; + System.out.println(tempFilePath); + // 在临时文件目录中创建一个随机名称的zip文件 + File file = new File(tempFilePath); + ZipFile zipFile = new ZipFile(file); + ZipParameters parameters = new ZipParameters(); // 设置zip包的一些参数集合 + parameters.setEncryptFiles(true); // 是否设置密码(此处设置为:是) + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式(默认值) + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 普通级别(参数很多) + parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密级别 + parameters.setPassword(password); // 压缩包密码 + // 向zip文件中根据设置的参数写入数据 + zipFile.createZipFile(tempFile, parameters); + return file; + } catch (ZipException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/system/log/vo/LogRecordVO.java b/src/main/java/com/system/log/vo/LogRecordVO.java new file mode 100644 index 0000000..1b3fa9a --- /dev/null +++ b/src/main/java/com/system/log/vo/LogRecordVO.java @@ -0,0 +1,43 @@ +package com.system.log.vo; + +import lombok.Data; + +@Data +public class LogRecordVO { + private String time; + private String ipAddress; + private String fileSource; + private String logContent; + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getFileSource() { + return fileSource; + } + + public void setFileSource(String fileSource) { + this.fileSource = fileSource; + } + + public String getLogContent() { + return logContent; + } + + public void setLogContent(String logContent) { + this.logContent = logContent; + } +} diff --git a/src/main/java/com/system/log/vo/ZipInfo.java b/src/main/java/com/system/log/vo/ZipInfo.java new file mode 100644 index 0000000..75541f7 --- /dev/null +++ b/src/main/java/com/system/log/vo/ZipInfo.java @@ -0,0 +1,9 @@ +package com.system.log.vo; + +import lombok.Data; + +@Data +public class ZipInfo { + private String fileName; + private String filePath; +}