| @@ -12,8 +12,8 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN" | |||||
| <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 --> | <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 --> | ||||
| <setting name="defaultExecutorType" value="SIMPLE" /> | <setting name="defaultExecutorType" value="SIMPLE" /> | ||||
| <!-- 指定 MyBatis 所用日志的具体实现 --> | <!-- 指定 MyBatis 所用日志的具体实现 --> | ||||
| <!--<setting name="logImpl" value="SLF4J" />--> | |||||
| <setting name="logImpl" value="com.ruoyi.common.dev.mybatis.MybatisStdOutputLog" /> <!-- 控制台详细输出 --> | |||||
| <setting name="logImpl" value="SLF4J" /> | |||||
| <!--<setting name="logImpl" value="com.ruoyi.common.dev.mybatis.MybatisStdOutputLog" />--> <!-- 控制台详细输出 --> | |||||
| <!-- 使用驼峰命名法转换字段 --> | <!-- 使用驼峰命名法转换字段 --> | ||||
| <!-- <setting name="mapUnderscoreToCamelCase" value="true"/> --> | <!-- <setting name="mapUnderscoreToCamelCase" value="true"/> --> | ||||
| </settings> | </settings> | ||||
| @@ -2,6 +2,7 @@ package com.ruoyi.file.object; | |||||
| import cn.hutool.core.bean.BeanUtil; | import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.hutool.core.bean.copier.CopyOptions; | import cn.hutool.core.bean.copier.CopyOptions; | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | |||||
| import java.util.Date; | import java.util.Date; | ||||
| import java.util.List; | import java.util.List; | ||||
| @@ -15,8 +16,11 @@ public final class ProjectState | |||||
| public long numUpload = 0; // 上传文件数 | public long numUpload = 0; // 上传文件数 | ||||
| public long numWrite = 0; // 写入文件数 | public long numWrite = 0; // 写入文件数 | ||||
| public long numError = 0; // 处理错误数 | public long numError = 0; // 处理错误数 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastUploadTime; // 最近上传时间 | public Date lastUploadTime; // 最近上传时间 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastWriteTime; // 最近写入时间 | public Date lastWriteTime; // 最近写入时间 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastErrorTime; // 最近错误时间 | public Date lastErrorTime; // 最近错误时间 | ||||
| public long maxUploadSize = 0; // 最大上传字节数 | public long maxUploadSize = 0; // 最大上传字节数 | ||||
| public long maxWriteSize = 0; // 最大写入字节数 | public long maxWriteSize = 0; // 最大写入字节数 | ||||
| @@ -96,9 +100,9 @@ public final class ProjectState | |||||
| if(state.maxUploadSize > maxUploadSize) | if(state.maxUploadSize > maxUploadSize) | ||||
| maxUploadSize = state.maxUploadSize; | maxUploadSize = state.maxUploadSize; | ||||
| if(state.maxWriteSize > maxWriteSize) | if(state.maxWriteSize > maxWriteSize) | ||||
| maxWriteSize += state.maxWriteSize; | |||||
| maxWriteSize = state.maxWriteSize; | |||||
| if(state.maxHandleDuration > maxHandleDuration) | if(state.maxHandleDuration > maxHandleDuration) | ||||
| maxHandleDuration += state.maxHandleDuration; | |||||
| maxHandleDuration = state.maxHandleDuration; | |||||
| } | } | ||||
| public String ToString(String split) | public String ToString(String split) | ||||
| @@ -2,6 +2,7 @@ package com.ruoyi.file.object; | |||||
| import cn.hutool.core.bean.BeanUtil; | import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.hutool.core.bean.copier.CopyOptions; | import cn.hutool.core.bean.copier.CopyOptions; | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | |||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.Date; | import java.util.Date; | ||||
| @@ -16,18 +17,26 @@ public final class StateMachine | |||||
| public long numUpload = 0; // 上传文件数 | public long numUpload = 0; // 上传文件数 | ||||
| public long numWrite = 0; // 写入文件数 | public long numWrite = 0; // 写入文件数 | ||||
| public long numError = 0; // 处理错误数 | public long numError = 0; // 处理错误数 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastUploadTime; // 最近上传时间 | public Date lastUploadTime; // 最近上传时间 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastWriteTime; // 最近写入时间 | public Date lastWriteTime; // 最近写入时间 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastErrorTime; // 最近错误时间 | public Date lastErrorTime; // 最近错误时间 | ||||
| public long maxUploadSize = 0; // 最大上传字节数 | public long maxUploadSize = 0; // 最大上传字节数 | ||||
| public long maxWriteSize = 0; // 最大写入字节数 | public long maxWriteSize = 0; // 最大写入字节数 | ||||
| public long maxHandleDuration = 0; // 最长处理时间 | public long maxHandleDuration = 0; // 最长处理时间 | ||||
| public long gcCount; // GC次数 | public long gcCount; // GC次数 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastGCTime; // 最近GC时间 | public Date lastGCTime; // 最近GC时间 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date startTime = new Date(); // 本次开始时间 | public Date startTime = new Date(); // 本次开始时间 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastEndTime; // 上次结束时间 | public Date lastEndTime; // 上次结束时间 | ||||
| @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") | |||||
| public Date lastDumpTime; // 上次dump时间 | |||||
| private final Map<String, ProjectState> stateMap = new LinkedHashMap<>(); | private final Map<String, ProjectState> stateMap = new LinkedHashMap<>(); | ||||
| public static final StateMachine INSTANCE = new StateMachine(); | public static final StateMachine INSTANCE = new StateMachine(); | ||||
| @@ -58,9 +67,9 @@ public final class StateMachine | |||||
| if(state.maxUploadSize > this.maxUploadSize) | if(state.maxUploadSize > this.maxUploadSize) | ||||
| this.maxUploadSize = state.maxUploadSize; | this.maxUploadSize = state.maxUploadSize; | ||||
| if(state.maxWriteSize > this.maxWriteSize) | if(state.maxWriteSize > this.maxWriteSize) | ||||
| this.maxWriteSize += state.maxWriteSize; | |||||
| this.maxWriteSize = state.maxWriteSize; | |||||
| if(state.maxHandleDuration > this.maxHandleDuration) | if(state.maxHandleDuration > this.maxHandleDuration) | ||||
| this.maxHandleDuration += state.maxHandleDuration; | |||||
| this.maxHandleDuration = state.maxHandleDuration; | |||||
| } | } | ||||
| private ProjectState State(String token) | private ProjectState State(String token) | ||||
| @@ -187,7 +196,7 @@ public final class StateMachine | |||||
| public void FromMap(Map<?, ?> parms) | public void FromMap(Map<?, ?> parms) | ||||
| { | { | ||||
| CopyOptions options = CopyOptions.create(); | CopyOptions options = CopyOptions.create(); | ||||
| options.setIgnoreProperties("startTime"); | |||||
| options.setIgnoreProperties("startTime", "gcCount", "lastGCTime"); | |||||
| options.setIgnoreError(true); | options.setIgnoreError(true); | ||||
| BeanUtil.fillBeanWithMap(parms, this, options); | BeanUtil.fillBeanWithMap(parms, this, options); | ||||
| Object obj = parms.get("stateMap"); | Object obj = parms.get("stateMap"); | ||||
| @@ -210,9 +219,15 @@ public final class StateMachine | |||||
| public void Finish() | public void Finish() | ||||
| { | { | ||||
| Save(); | |||||
| lastEndTime = new Date(); | lastEndTime = new Date(); | ||||
| } | } | ||||
| public void Save() | |||||
| { | |||||
| lastDumpTime = new Date(); | |||||
| } | |||||
| public String ToString(String split) | public String ToString(String split) | ||||
| { | { | ||||
| StringBuilder sb = new StringBuilder(); | StringBuilder sb = new StringBuilder(); | ||||
| @@ -246,6 +261,8 @@ public final class StateMachine | |||||
| sb.append(split); | sb.append(split); | ||||
| sb.append("上次结束时间: ").append(lastEndTime); | sb.append("上次结束时间: ").append(lastEndTime); | ||||
| sb.append(split); | sb.append(split); | ||||
| sb.append("上次dump时间: ").append(lastDumpTime); | |||||
| sb.append(split); | |||||
| sb.append("记录数: ").append(stateMap.size()); | sb.append("记录数: ").append(stateMap.size()); | ||||
| return sb.toString(); | return sb.toString(); | ||||
| } | } | ||||
| @@ -39,7 +39,6 @@ import javax.servlet.http.HttpServletResponse; | |||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||
| import java.util.LinkedHashMap; | import java.util.LinkedHashMap; | ||||
| import java.util.Map; | import java.util.Map; | ||||
| import java.util.TimerTask; | |||||
| @Service | @Service | ||||
| public class FileService | public class FileService | ||||
| @@ -234,7 +233,6 @@ public class FileService | |||||
| if(session.result.isSuccess()) | if(session.result.isSuccess()) | ||||
| { | { | ||||
| state.AddNumWrite(1); | state.AddNumWrite(1); | ||||
| state.AddUploadSize(session.task.UploadSize()); | |||||
| state.AddWriteSize(session.result.getFileSize()); | state.AddWriteSize(session.result.getFileSize()); | ||||
| state.AddWriteSize(session.result.getThumbnailFileSize()); | state.AddWriteSize(session.result.getThumbnailFileSize()); | ||||
| state.SetLastWriteTime(session.result.getTime()); | state.SetLastWriteTime(session.result.getTime()); | ||||
| @@ -45,7 +45,25 @@ public class StateService | |||||
| public void dump() | public void dump() | ||||
| { | { | ||||
| destroy(); | |||||
| StateMachine.INSTANCE.Save(); | |||||
| save(); | |||||
| } | |||||
| private void save() | |||||
| { | |||||
| try | |||||
| { | |||||
| Map<?, ?> map = StateMachine.INSTANCE.ToMap(); | |||||
| String json = JSON.toJSONString(map); | |||||
| RedisCache redisCache = SpringUtils.getBean(RedisCache.class); | |||||
| redisCache.setCacheObject(STATE_MACHINE_KEY, json); | |||||
| log.info("备份持久化状态机信息: "); | |||||
| log.info(StateMachine.INSTANCE.ToString("; ")); | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | } | ||||
| @PostConstruct | @PostConstruct | ||||
| @@ -72,19 +90,7 @@ public class StateService | |||||
| @PreDestroy | @PreDestroy | ||||
| public void destroy() | public void destroy() | ||||
| { | { | ||||
| try | |||||
| { | |||||
| StateMachine.INSTANCE.Finish(); | |||||
| Map<?, ?> map = StateMachine.INSTANCE.ToMap(); | |||||
| String json = JSON.toJSONString(map); | |||||
| RedisCache redisCache = SpringUtils.getBean(RedisCache.class); | |||||
| redisCache.setCacheObject(STATE_MACHINE_KEY, json); | |||||
| log.info("备份持久化状态机信息: "); | |||||
| log.info(StateMachine.INSTANCE.ToString("; ")); | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| } | |||||
| StateMachine.INSTANCE.Finish(); | |||||
| save(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,6 +2,8 @@ | |||||
| /* 文件大小格式化 */ | /* 文件大小格式化 */ | ||||
| export function formatFileSize(size) { | export function formatFileSize(size) { | ||||
| if(size === null || size === undefined) | |||||
| return '0'; | |||||
| const Unit = ["Bytes", "Kb", "Mb", "Gb", "Tb"]; | const Unit = ["Bytes", "Kb", "Mb", "Gb", "Tb"]; | ||||
| //const Unit = ["byte", "K", "M", "G", "T"]; | //const Unit = ["byte", "K", "M", "G", "T"]; | ||||
| let s, i; | let s, i; | ||||
| @@ -1,15 +1,15 @@ | |||||
| <template> | <template> | ||||
| <Descriptions> | <Descriptions> | ||||
| <el-descriptions-item label="上传字节数">{{state.uploadSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="写入字节数">{{state.writeSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="上传字节数">{{state.uploadSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="写入字节数">{{state.writeSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="上传文件数">{{state.numUpload}}</el-descriptions-item> | <el-descriptions-item label="上传文件数">{{state.numUpload}}</el-descriptions-item> | ||||
| <el-descriptions-item label="写入文件数">{{state.numWrite}}</el-descriptions-item> | <el-descriptions-item label="写入文件数">{{state.numWrite}}</el-descriptions-item> | ||||
| <el-descriptions-item label="处理错误数">{{state.numError}}</el-descriptions-item> | <el-descriptions-item label="处理错误数">{{state.numError}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最近上传时间">{{state.lastUploadTime}}</el-descriptions-item> | <el-descriptions-item label="最近上传时间">{{state.lastUploadTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最近写入时间">{{state.lastWriteTime}}</el-descriptions-item> | <el-descriptions-item label="最近写入时间">{{state.lastWriteTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最近错误时间">{{state.lastErrorTime}}</el-descriptions-item> | <el-descriptions-item label="最近错误时间">{{state.lastErrorTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最大上传字节数">{{state.maxUploadSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最大写入字节数">{{state.maxWriteSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最大上传字节数">{{state.maxUploadSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最大写入字节数">{{state.maxWriteSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最长处理时间">{{state.maxHandleDuration}}</el-descriptions-item> | <el-descriptions-item label="最长处理时间">{{state.maxHandleDuration}}</el-descriptions-item> | ||||
| </Descriptions> | </Descriptions> | ||||
| </template> | </template> | ||||
| @@ -18,6 +18,7 @@ | |||||
| import Descriptions from "@/components/common/Descriptions.vue"; | import Descriptions from "@/components/common/Descriptions.vue"; | ||||
| import {stateDetail} from "@/api/file/state"; | import {stateDetail} from "@/api/file/state"; | ||||
| import {formatFileSize} from "@/utils/file"; | |||||
| export default { | export default { | ||||
| name: 'ProjectState', | name: 'ProjectState', | ||||
| @@ -57,6 +58,9 @@ export default { | |||||
| this.getStateDetail(); | this.getStateDetail(); | ||||
| }, | }, | ||||
| }, | }, | ||||
| filters: { | |||||
| formatFileSize, | |||||
| }, | |||||
| } | } | ||||
| </script> | </script> | ||||
| @@ -18,21 +18,22 @@ | |||||
| </el-row> | </el-row> | ||||
| <Descriptions> | <Descriptions> | ||||
| <el-descriptions-item label="上传字节数">{{state.uploadSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="写入字节数">{{state.writeSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="上传字节数">{{state.uploadSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="写入字节数">{{state.writeSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="上传文件数">{{state.numUpload}}</el-descriptions-item> | <el-descriptions-item label="上传文件数">{{state.numUpload}}</el-descriptions-item> | ||||
| <el-descriptions-item label="写入文件数">{{state.numWrite}}</el-descriptions-item> | <el-descriptions-item label="写入文件数">{{state.numWrite}}</el-descriptions-item> | ||||
| <el-descriptions-item label="处理错误数">{{state.numError}}</el-descriptions-item> | <el-descriptions-item label="处理错误数">{{state.numError}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最近上传时间">{{state.lastUploadTime}}</el-descriptions-item> | <el-descriptions-item label="最近上传时间">{{state.lastUploadTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最近写入时间">{{state.lastWriteTime}}</el-descriptions-item> | <el-descriptions-item label="最近写入时间">{{state.lastWriteTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最近错误时间">{{state.lastErrorTime}}</el-descriptions-item> | <el-descriptions-item label="最近错误时间">{{state.lastErrorTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最大上传字节数">{{state.maxUploadSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最大写入字节数">{{state.maxWriteSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最大上传字节数">{{state.maxUploadSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最大写入字节数">{{state.maxWriteSize | formatFileSize}}</el-descriptions-item> | |||||
| <el-descriptions-item label="最长处理时间">{{state.maxHandleDuration}}</el-descriptions-item> | <el-descriptions-item label="最长处理时间">{{state.maxHandleDuration}}</el-descriptions-item> | ||||
| <el-descriptions-item label="GC次数">{{state.gcCount}}</el-descriptions-item> | <el-descriptions-item label="GC次数">{{state.gcCount}}</el-descriptions-item> | ||||
| <el-descriptions-item label="最近GC时间">{{state.lastGCTime}}</el-descriptions-item> | <el-descriptions-item label="最近GC时间">{{state.lastGCTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="本次开始时间">{{state.startTime}}</el-descriptions-item> | <el-descriptions-item label="本次开始时间">{{state.startTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="上次结束时间">{{state.lastEndTime}}</el-descriptions-item> | <el-descriptions-item label="上次结束时间">{{state.lastEndTime}}</el-descriptions-item> | ||||
| <el-descriptions-item label="上次dump时间">{{state.lastDumpTime}}</el-descriptions-item> | |||||
| <el-descriptions-item label="记录数">{{total}}</el-descriptions-item> | <el-descriptions-item label="记录数">{{total}}</el-descriptions-item> | ||||
| </Descriptions> | </Descriptions> | ||||
| @@ -41,11 +42,11 @@ | |||||
| <el-table-column type="index" label="序号" width="50" align="center" /> | <el-table-column type="index" label="序号" width="50" align="center" /> | ||||
| <!--<el-table-column label="ID" align="center" prop="id" min-width="60" />--> | <!--<el-table-column label="ID" align="center" prop="id" min-width="60" />--> | ||||
| <el-table-column label="标识" align="center" prop="token" /> | <el-table-column label="标识" align="center" prop="token" /> | ||||
| <el-table-column label="上传字节数" align="center" prop="uploadSize" /> | |||||
| <el-table-column label="上传字节数" align="center" prop="uploadSize" :formatter="fileSizeFormatter" /> | |||||
| <el-table-column label="上传文件数" align="center" prop="numUpload" /> | <el-table-column label="上传文件数" align="center" prop="numUpload" /> | ||||
| <el-table-column label="处理错误数" align="center" prop="numError" /> | <el-table-column label="处理错误数" align="center" prop="numError" /> | ||||
| <el-table-column label="最近上传时间" align="center" prop="lastUploadTime" /> | <el-table-column label="最近上传时间" align="center" prop="lastUploadTime" /> | ||||
| <el-table-column label="最大上传字节数" align="center" prop="maxUploadSize" /> | |||||
| <el-table-column label="最大上传字节数" align="center" prop="maxUploadSize" :formatter="fileSizeFormatter" /> | |||||
| <el-table-column label="最长处理时间" align="center" prop="maxHandleDuration" /> | <el-table-column label="最长处理时间" align="center" prop="maxHandleDuration" /> | ||||
| <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
| <template slot-scope="scope"> | <template slot-scope="scope"> | ||||
| @@ -68,6 +69,7 @@ import FullscreenDialog from "@/components/FullscreenDialog.vue"; | |||||
| import ProjectState from "@/views/file/state/ProjectState.vue"; | import ProjectState from "@/views/file/state/ProjectState.vue"; | ||||
| import {stateList, gc, stateMachine, dump} from "@/api/file/state"; | import {stateList, gc, stateMachine, dump} from "@/api/file/state"; | ||||
| import Descriptions from "@/components/common/Descriptions.vue"; | import Descriptions from "@/components/common/Descriptions.vue"; | ||||
| import {formatFileSize} from "@/utils/file"; | |||||
| export default { | export default { | ||||
| @@ -185,6 +187,7 @@ export default { | |||||
| gc() { | gc() { | ||||
| gc().then((resp) => { | gc().then((resp) => { | ||||
| this.$message.success('成功'); | this.$message.success('成功'); | ||||
| this.getStateMachine(); | |||||
| }); | }); | ||||
| }, | }, | ||||
| getStateMachine() { | getStateMachine() { | ||||
| @@ -196,8 +199,15 @@ export default { | |||||
| dump() { | dump() { | ||||
| dump().then((resp) => { | dump().then((resp) => { | ||||
| this.$message.success('成功'); | this.$message.success('成功'); | ||||
| this.getStateMachine(); | |||||
| }); | }); | ||||
| }, | }, | ||||
| fileSizeFormatter(row, col, val) { | |||||
| return formatFileSize(val); | |||||
| }, | |||||
| }, | |||||
| filters: { | |||||
| formatFileSize, | |||||
| }, | }, | ||||
| }; | }; | ||||
| </script> | </script> | ||||