1. 增加日志功能

This commit is contained in:
梁州 2025-05-27 16:58:14 +08:00
parent 2c5e6feee1
commit 8153741de8
26 changed files with 1128 additions and 225 deletions

View File

@ -1,13 +1,19 @@
import request from "@/http/request";
const queryLogs = (params) => {
// 分页查询接收日志
export const queryLogsByPage = (params) => {
return request({
url: '/log/queryWmsLog',
url: '/log/queryLogsByPage',
method: 'post',
data: params
})
}
export {
queryLogs
// 分页查询发送日志
export const queryApisByPage = (params) => {
return request({
url: '/log/queryApisByPage',
method: 'post',
data: params
})
}

View File

@ -1,221 +1,350 @@
<template>
<div style="margin-bottom: 10px">
<el-config-provider :locale="zhCn">
<el-container class="content">
<div class="work-area">
<fieldset class="search-area">
<el-form ref="searchQueryFormRef" :model="searchQueryFormEntity" :label-position="labelPosition"
label-width="158px" style="max-width: 100%" status-icon>
<div style="display: flex;justify-content: space-between;">
<el-row>
<el-input v-model="queryKey" style="width: 256px; margin-right: 10px;" placeholder="请输入搜索信息" />
<el-button type="primary" @click="search()">搜索</el-button>
<el-button type="warning" @click="reset()">重置</el-button>
<el-form-item label="任务类型">
<el-select-v2 style="width: 196px" v-model="searchQueryFormEntity.logType" placeholder="任务类型"
:options="logTypeOptions"
@change="search()"></el-select-v2>
</el-form-item>
<el-form-item label="查询字符">
<el-input v-model="searchQueryFormEntity.queryStr" @keyup.enter="search()" clearable/>
</el-form-item>
</el-row>
<br />
<el-table :data="wmsLogs" stripe border v-loading="loading" class="table-class" max-height="650px"
highlight-current-row @row-click="getCurrentRow" :header-cell-style="{ 'text-align': 'center' }"
:cell-style="{ 'text-align': 'center' }">
<div style="align-content: center;">
<el-row>
<el-button type="primary" class="btn-search" @click="search()">查询</el-button>
<el-button type="warning" class="btn-search" @click="clearQuery()">清除输入</el-button>
</el-row>
</div>
</div>
</el-form>
</fieldset>
<div class="table-area">
<el-table :data="tableData" stripe border v-loading="tableLoading" class="table-class"
:max-height="maxHeight" highlight-current-row @row-click="getCurrentRow"
:header-cell-style="{ 'text-align': 'center' }" :cell-style="{ 'text-align': 'center' }"
@sort-change="handleSortChange">
<el-table-column width="65px" fixed="left">
<template v-slot="scope">
<el-radio :label="scope.row.logId" v-model="logId">&nbsp;</el-radio>
</template>
</el-table-column>
<el-table-column prop="logId" label="请求id" fixed="left" min-width="120px" show-overflow-tooltip />
<el-table-column prop="logTitle" label="请求名称" fixed="left" min-width="120px" show-overflow-tooltip />
<el-table-column prop="logMethod" label="请求接口" fixed="left" min-width="120px" show-overflow-tooltip />
<el-table-column prop="logRequest" label="请求信息" :formatter="jsonFormat" min-width="180px"
<el-table-column prop="logId" label="日志id" fixed="left" min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column prop="logResponse" label="响应信息" :formatter="jsonFormat" min-width="180px" show-overflow-tooltip />
<el-table-column prop="logIp" label="请求ip" min-width="120px" />
<el-table-column prop="logTime" label="请求时间" :formatter="timeFormat" show-overflow-tooltip
min-width="120px" />
<el-table-column prop="logUser" label="请求用户" min-width="120px" />
<el-table-column fixed="right" label="操作" width="120px">
<template v-slot="scope">
<el-button plain type="primary" @click="detailCurrentRowLog(scope.row)">查看详情</el-button>
</template>
</el-table-column>
<el-table-column prop="logTime" label="记录时间" fixed="right" :formatter="timeFormat" min-width="120px"
sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 1" prop="method" label="请求方式" fixed="left"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 1" prop="uri" label="请求地址" min-width="120px"
sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 1" prop="remoteHost" label="客户端主机"
fixed="left" min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 1" prop="remoteAddr" label="客户端地址"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 1" prop="requestContent" label="请求数据"
fixed="left" min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 1" prop="status" label="响应状态" min-width="120px"
sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 1" prop="responseContent" label="响应数据"
fixed="left" min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="url" label="请求地址" fixed="left"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="timeout" label="超时时间"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="method" label="请求方式"
min-width="120px" sortable="custom" show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="contentType" label="数据类型"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="data" label="请求数据" min-width="120px"
sortable="custom" show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="token" label="token" fixed="left"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="success" label="是否成功"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="responseCode" label="响应码"
min-width="120px" sortable="custom" show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="requestMessage" label="请求信息"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="responseMessage" label="响应信息"
min-width="120px"
sortable="custom" show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="requestTime" label="请求时间" fixed="left"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="responseTime" label="响应时间"
min-width="120px" sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="useTime" label="耗时" min-width="120px"
sortable="custom"
show-overflow-tooltip/>
<el-table-column v-if="searchQueryFormEntity.logType === 2" prop="exceptionMessage" label="异常信息"
min-width="120px"
sortable="custom" show-overflow-tooltip/>
</el-table>
<br/>
<el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[10, 25, 50]"
:small="false" :disabled="false" :background="false" :default-page-size="10"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="search"
@current-change="search" />
<el-dialog v-model="dialogVisible" title="日志详情" width="40%" draggable :show-close="false">
<el-form ref="wmsLogFormRef" :model="wmsLogEntity" :label-position="labelPosition" label-width="100px"
style="max-width: 100%" :rules="rules" status-icon>
<el-row :gutter="16">
<el-col :span="12" :offset="0">
<el-form-item label="请求id" prop="logId">
<el-input v-model="wmsLogEntity.logId" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求名称" prop="logTitle">
<el-input v-model="wmsLogEntity.logTitle" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12" :offset="0">
<el-form-item label="请求接口" prop="logMethod">
<el-input v-model="wmsLogEntity.logMethod" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求ip" prop="logIp">
<el-input v-model="wmsLogEntity.logIp" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12" :offset="0">
<el-form-item label="请求信息" prop="logRequest">
<el-input type="textarea" :rows="2" v-model="wmsLogEntity.logRequest" placeholder=""
:maxlength="-1" :show-word-limit="false" :autosize="{ minRows: 2, maxRows: 4 }" readonly>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="响应信息" prop="logResponse">
<el-input type="textarea" :rows="2" v-model="wmsLogEntity.logResponse" :maxlength="-1"
:show-word-limit="false" :autosize="{ minRows: 2, maxRows: 4 }" readonly>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12" :offset="0">
<el-form-item label="请求时间" prop="logTime">
<el-input v-model="wmsLogEntity.logTime" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求用户" prop="logUser">
<el-input v-model="wmsLogEntity.logUser" readonly />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
</el-config-provider>
<el-pagination v-model:current-page="baseTableQuery.currentPage"
v-model:page-size="baseTableQuery.pageSize" :page-sizes="[10, 25, 50]" :small="false"
:disabled="false" :background="false" :default-page-size="10" @size-change="search"
@current-change="search" layout="total, sizes, prev, pager, next, jumper"
:total="baseTableQuery.total"/>
</div>
</div>
</el-container>
</el-config-provider>
</template>
<script setup>
import store from '@/store'
import { queryLogs } from '@/api/wmsLog.js'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import { errorBox } from '@/utils/myMessageBox.js'
import { timeFormatter, jsonFormatter } from '@/utils/formatter.js'
import { ref, reactive } from 'vue'
</script>
<script>
export default {
name: 'wmsLog',
data() {
return {
wmsLogs: [],
pageInfo: {},
import {timeFormatter} from '@/utils/formatter.js'
import {ref, reactive, onMounted, nextTick, onBeforeUnmount} from 'vue'
import {ElMessage} from 'element-plus'
import {genTableRequest} from '@/utils/generator.js'
import {labelPosition} from '@/constant/form.js'
import {queryApisByPage, queryLogsByPage} from "@/api/wmsLog";
/**
* 常量定义
*/
const STAND_ID = store.getters.getStandId
const USER_NAME = store.getters.getUserName
/**
* 变量定义
*/
let maxHeight = ref(window.innerHeight * 0.55)
let tableLoading = ref(false)
let tableData = ref([])
let baseTableQuery = reactive({
currentPage: 1,
pageSize: 10,
total: 0,
queryKey: '',
loading: true,
dialogVisible: false,
logId: '',
wmsLogEntity: reactive({}),
labelPosition: 'top',
wmsLogFormRef: ref(),
rules: reactive({})
}
sortBy: new Map([['logTime', false]]),//
standId: STAND_ID,
userName: USER_NAME
})
let searchQueryFormEntity = reactive({
logType: 1,
queryStr: ''
})
let searchQueryFormRef = ref()
let logId = ''
const logTypeOptions = [
{
label: '接收日志',
value: 1
},
mounted() {
this.search()
},
methods: {
search() {
this.loading = true
const tableRequest = {
pageNo: this.currentPage,
pageSize: this.pageSize,
queryParam: this.queryKey.trim(),
userName: store.getters.getUserName
{
label: '发送日志',
value: 2
}
queryLogs(tableRequest).then(res => {
const tableResponse = res.data
if (tableResponse.code == 0) {
this.wmsLogs = tableResponse.returnData.lists
this.total = tableResponse.returnData.total
]
/**
* 系统方法
*/
onMounted(() => {
nextTick(() => {
window.addEventListener('resize', resizeHeight)
search()
})
})
onBeforeUnmount(() => {
nextTick(() => {
window.removeEventListener('resize', resizeHeight)
})
})
const resizeHeight = () => {
maxHeight.value = window.innerHeight * 0.55
}
/**
* 自定义方法
*/
//
const search = () => {
let request = genTableRequest(baseTableQuery)
//
request.queryStr = searchQueryFormEntity.queryStr.trim()
if (searchQueryFormEntity.logType === 1) {
//
queryReceiveLog(request)
} else {
errorBox(tableResponse.message)
//
querySendLog(request)
}
}
const queryReceiveLog = (request) => {
tableLoading.value = true
queryLogsByPage(request).then((res) => {
const response = res.data
if (response.code === 0) {
const data = response.data
if (data != null) {
tableData.value = data.lists
baseTableQuery.total = data.total
} else {
tableData.value = []
baseTableQuery.total = 0
}
} else {
ElMessage.error(response.message)
}
}).catch(err => {
console.log(err)
errorBox('查询日志错误')
ElMessage.error('查询数据异常。')
}).finally(() => {
tableLoading.value = false
})
this.loading = false
},
timeFormat: (row, column, cellValue, index) => {
return timeFormatter(cellValue)
},
jsonFormat: (row, column, cellValue, index) => {
return jsonFormatter(cellValue)
},
reset() {
this.queryKey = ''
this.search
},
detailCurrentRowLog(row) {
this.wmsLogEntity = {
logId: row.logId,
logTitle: row.logTitle,
logMethod: row.logMethod,
logRequest: jsonFormatter(row.logRequest),
logResponse: jsonFormatter(row.logResponse),
logTime: row.logTime,
logUser: row.logUser,
logIp: row.logIp,
}
this.dialogVisible = true
},
getCurrentRow(row) {
this.logId = row.logId
},
},
const querySendLog = (request) => {
tableLoading.value = true
queryApisByPage(request).then((res) => {
const response = res.data
if (response.code === 0) {
const data = response.data
if (data != null) {
tableData.value = data.lists
baseTableQuery.total = data.total
} else {
tableData.value = []
baseTableQuery.total = 0
}
} else {
ElMessage.error(response.message)
}
}).catch(err => {
console.log(err)
ElMessage.error('查询数据异常。')
}).finally(() => {
tableLoading.value = false
})
}
const clearQuery = () => {
searchQueryFormEntity.vehicleId = ''
searchQueryFormEntity.goodsId = ''
}
const handleSortChange = (data) => {
if (baseTableQuery.sortBy.has(data.prop)) {
baseTableQuery.sortBy.delete(data.prop)
}
baseTableQuery.sortBy.set(data.prop, data.order === 'ascending')
search()
}
const getCurrentRow = (row) => {
logId = row.logId
}
const timeFormat = (row, column, cellValue, index) => {
return timeFormatter(cellValue)
}
</script>
<style scoped>
.content {
display: flex;
width: 100%;
}
.work-area {
width: 100%;
/* padding: 5px; */
}
.search-area {
margin: auto;
min-height: fit-content;
max-height: 40%;
margin-bottom: 10px;
min-width: inherit;
border: solid 1px;
border-radius: 10px;
box-shadow: 0px 15px 10px -15px #000;
overflow: auto;
padding: 10px;
}
.table-area {
margin: auto;
min-height: fit-content;
max-height: 60%;
margin-bottom: 10px;
min-width: inherit;
border: solid 1px;
border-radius: 10px;
box-shadow: 0px 15px 10px -15px #000;
overflow: auto;
padding: 10px;
}
.el-form-item {
margin: 5px 5px 5px 5px;
}
.el-form-item .el-input {
width: 196px;
}
.el-form-item .el-input-number {
width: 196px;
}
.table-class {
margin: 5px 5px 5px 5px;
width: inherit;
}
.el-pagination {
padding-left: 5px;
}
.el-row .el-button {
width: 72px;
margin-left: 0px;
margin-right: 5px;
.my-autocomplete li {
width: 196px;
line-height: normal;
padding: 7px;
}
.table-class {
width: 100%;
.my-autocomplete li .name {
text-overflow: ellipsis;
overflow: hidden;
}
.el-row .el-form-item {
width: 10% inherit;
justify-content: center;
.my-autocomplete li .addr {
font-size: 12px;
color: #b4b4b4;
}
.el-row .el-form-item .el-select-v2 {
width: 100% !important;
.my-autocomplete li .highlighted .addr {
color: #ddd;
}
.el-row .el-form-item .el-input-number {
width: 100% !important;
.my-autocomplete li .goods_id {
color: brown;
}
.el-row .el-form-item .el-button {
margin: auto;
.my-autocomplete li .goods_name {
color: cornflowerblue;
}
.btn-search {
height: 30px;
width: 80px;
margin: auto 5px 5px auto;
color: black;
}
</style>

View File

@ -0,0 +1,43 @@
package com.wms_main.controller.wms;
import com.wms_main.model.dto.query.SysApiQuery;
import com.wms_main.model.dto.query.SysLogQuery;
import com.wms_main.model.dto.response.wms.WmsApiResponse;
import com.wms_main.model.vo.wms.PageVo;
import com.wms_main.model.vo.wms.SysApiVo;
import com.wms_main.model.vo.wms.SysLogVo;
import com.wms_main.service.controller.ILogControllerService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
* 日志控制类
*/
@RestController
@ResponseBody
@CrossOrigin
@RequiredArgsConstructor
@RequestMapping("/wms/log")
public class LogController {
private final ILogControllerService logControllerService;
/**
* 查询接口接收日志
* @param logQuery 查询参数
* @return 查询结果
*/
@PostMapping("/queryLogsByPage")
public WmsApiResponse<PageVo<SysLogVo>> queryLogsByPage(@RequestBody SysLogQuery logQuery) {
return logControllerService.queryLogsByPage(logQuery);
}
/**
* 查询接口发送日志
* @param apiQuery 查询参数
* @return 查询结果
*/
@PostMapping("/queryApisByPage")
public WmsApiResponse<PageVo<SysApiVo>> queryApisByPage(@RequestBody SysApiQuery apiQuery) {
return logControllerService.queryApisByPage(apiQuery);
}
}

View File

@ -0,0 +1,18 @@
package com.wms_main.dao;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wms_main.model.po.TSysApi;
import com.wms_main.repository.http.entity.HttpRequest;
import com.wms_main.repository.http.entity.HttpResponse;
/**
* api表服务
*/
public interface ITSysApiService extends IService<TSysApi> {
/**
* 存储api接口请求日志
* @param request 请求参数
* @param response 响应参数
*/
void insertApiLog(HttpRequest request, HttpResponse response);
}

View File

@ -0,0 +1,10 @@
package com.wms_main.dao;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wms_main.model.po.TSysLog;
/**
* 日志服务接口
*/
public interface ITSysLogService extends IService<TSysLog> {
}

View File

@ -0,0 +1,75 @@
package com.wms_main.dao.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wms_main.dao.ITSysApiService;
import com.wms_main.mapper.SysApiMapper;
import com.wms_main.model.po.TSysApi;
import com.wms_main.repository.http.entity.HttpRequest;
import com.wms_main.repository.http.entity.HttpResponse;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
/**
* api表服务实现
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class TSysApiServiceImpl extends ServiceImpl<SysApiMapper, TSysApi> implements ITSysApiService {
/**
*
* @param request 请求参数
* @param response 响应参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void insertApiLog(HttpRequest request, HttpResponse response) {
TSysApi apiLog = new TSysApi();
apiLog.setLogId(UUIDUtils.getNewUUID());
apiLog.setLogTime(LocalDateTime.now());
// 设置请求相关信息
if (request != null) {
apiLog.setUrl(request.getUrl());
apiLog.setTimeout(request.getTimeout());
apiLog.setMethod(request.getMethod().name());
apiLog.setContentType(request.getContentType());
apiLog.setData(StringUtils.formatStringWithMaxLength(request.getData(), 2048));
apiLog.setToken(StringUtils.formatStringWithMaxLength(request.getToken(), 2048));
}
// 设置响应相关信息
if (response != null) {
apiLog.setSuccess(response.isSuccess() ? "成功" : "失败");
apiLog.setResponseCode(response.getResponseCode());
apiLog.setRequestMessage(StringUtils.formatStringWithMaxLength(response.getRequestMessage(), 2048));
apiLog.setResponseMessage(StringUtils.formatStringWithMaxLength(response.getResponseMessage(), 2048));
apiLog.setRequestTime(response.getRequestTime());
apiLog.setResponseTime(response.getResponseTime());
apiLog.setRequestUrl(response.getRequestUrl());
apiLog.setUseTime(response.getUseTime());
apiLog.setExceptionMessage(StringUtils.formatStringWithMaxLength(response.getException().getMessage(), 2048));
}
// 保存api日志
save(apiLog);
// 记录文本日志
log.info(logText(apiLog));
}
/**
* 生成日志文本
* @param apiLog 日志对象
* @return 字符串
*/
private String logText(TSysApi apiLog) {
return "\n请求方式" + apiLog.getMethod()
+ "\n请求地址" + apiLog.getUrl()
+ "\n请求数据" + apiLog.getData()
+ "\n响应状态" + apiLog.getSuccess()
+ "\n响应数据" + apiLog.getRequestMessage();
}
}

View File

@ -0,0 +1,14 @@
package com.wms_main.dao.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wms_main.dao.ITSysLogService;
import com.wms_main.mapper.SysLogMapper;
import com.wms_main.model.po.TSysLog;
import org.springframework.stereotype.Service;
/**
* 日志服务实现类
*/
@Service
public class TSysLogServiceImpl extends ServiceImpl<SysLogMapper, TSysLog> implements ITSysLogService {
}

View File

@ -1,23 +1,36 @@
package com.wms_main.filter;
import com.wms_main.dao.ITSysLogService;
import com.wms_main.model.po.TSysLog;
import com.wms_main.model.pojo.log.RequestLog;
import com.wms_main.repository.utils.UUIDUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import java.io.IOException;
import java.time.LocalDateTime;
import static com.wms_main.repository.utils.StringUtils.formatStringWithMaxLength;
@Slf4j
@Component
@WebFilter(filterName = "requestLogFilter", urlPatterns = "/*")
@RequiredArgsConstructor
public class RequestLogFilter extends HttpFilter {
/**
* 日志服务
*/
private final ITSysLogService sysLogService;
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// Wrapper封装request和response
@ -40,26 +53,31 @@ public class RequestLogFilter extends HttpFilter {
// 响应体
byte[] responseContent = responseWrapper.getContentAsByteArray();
// 记录日志信息
String requestContentString = formatContentString(new String(requestContent));
String responseContentString = formatContentString(new String(responseContent));
String requestContentString = formatStringWithMaxLength(new String(requestContent), 2048);
String responseContentString = formatStringWithMaxLength(new String(responseContent), 2048);
RequestLog logInfo = new RequestLog(method, uri, remoteHost, remoteAddr, requestContentString, String.valueOf(status), responseContentString);
log.info(logInfo.toString());
// TODO 增加存储数据库的操作
// 增加存储数据库的操作
new Thread(() -> {
try {
TSysLog logForDb = new TSysLog(
UUIDUtils.getNewUUID(),
logInfo.getMethod(),
logInfo.getUri(),
logInfo.getRemoteHost(),
logInfo.getRemoteAddr(),
logInfo.getRequestContent(),
logInfo.getStatus(),
logInfo.getResponseContent(),
LocalDateTime.now()
);
sysLogService.save(logForDb);
} catch (Exception e) {
log.error("记录日志失败。", e);
}
}).start();
// 把缓存的响应数据响应给客户端
responseWrapper.copyBodyToResponse();
}
/**
* 格式化内容string
* @param contentString 原始字符串
* @return 格式化之后的字符串
*/
private String formatContentString (String contentString) {
String newContentString = contentString.replaceAll("\\s*", "");
if (newContentString.length() > 1024) {
newContentString = newContentString.substring(0, 1024) + "...";
}
return newContentString;
}
}

View File

@ -0,0 +1,12 @@
package com.wms_main.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wms_main.model.po.TSysApi;
import org.apache.ibatis.annotations.Mapper;
/**
* api表映射mapper
*/
@Mapper
public interface SysApiMapper extends BaseMapper<TSysApi> {
}

View File

@ -0,0 +1,12 @@
package com.wms_main.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wms_main.model.po.TSysLog;
import org.apache.ibatis.annotations.Mapper;
/**
* 日志mapper接口
*/
@Mapper
public interface SysLogMapper extends BaseMapper<TSysLog> {
}

View File

@ -0,0 +1,22 @@
package com.wms_main.model.dto.query;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 接口发送日志查询参数
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysApiQuery extends PageQuery {
/**
* 查询字符串
*/
@JsonProperty("queryStr")
private String queryStr;
}

View File

@ -0,0 +1,22 @@
package com.wms_main.model.dto.query;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 接口接收日志查询参数
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysLogQuery extends PageQuery {
/**
* 查询字符串
*/
@JsonProperty("queryStr")
private String queryStr;
}

View File

@ -0,0 +1,105 @@
package com.wms_main.model.po;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 数据库Api表映射
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "t_sys_api", autoResultMap = true)
public class TSysApi {
/**
* id
*/
@TableId(value = "log_id")
private String logId;
/**
* url
*/
@TableField(value = "url")
private String url;
/**
* 超时时长
*/
@TableField(value = "timeout")
private Integer timeout;
/**
* 请求方式
*/
@TableField(value = "method")
private String method;
/**
* 请求头
*/
@TableField(value = "content_type")
private String contentType;
/**
* 数据
*/
@TableField(value = "data")
private String data;
/**
* token
*/
@TableField(value = "token")
private String token;
/**
* 请求是否成功
*/
@TableField(value = "success")
private String success;
/**
* 响应码
*/
@TableField(value = "response_code")
private int responseCode;
/**
* 请求信息
*/
@TableField(value = "request_message")
private String requestMessage;
/**
* 响应信息
*/
@TableField(value = "response_message")
private String responseMessage;
/**
* 请求时间
*/
@TableField(value = "request_time")
private LocalDateTime requestTime;
/**
* 响应时间
*/
@TableField(value = "response_time")
private LocalDateTime responseTime;
/**
* 请求地址
*/
@TableField(value = "request_url")
private String requestUrl;
/**
* 请求耗时
*/
@TableField(value = "use_time")
private long useTime;
/**
* 异常
*/
@TableField(value = "exception_message")
private String exceptionMessage;
/**
* 记录时间
*/
@TableField(value = "log_time")
private LocalDateTime logTime;
}

View File

@ -0,0 +1,65 @@
package com.wms_main.model.po;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 数据库Log表映射
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "t_sys_log", autoResultMap = true)
public class TSysLog {
/**
* 日志Id
*/
@TableId(value = "log_id")
private String logId;
/**
* 请求方式
*/
@TableField(value = "method")
private String method;
/**
* 请求地址
*/
@TableField(value = "uri")
private String uri;
/**
* 客户端主机
*/
@TableField(value = "remote_host")
private String remoteHost;
/**
* 客户端地址
*/
@TableField(value = "remote_addr")
private String remoteAddr;
/**
* 请求数据
*/
@TableField(value = "request_content")
private String requestContent;
/**
* 响应状态
*/
@TableField(value = "status")
private String status;
/**
* 响应数据
*/
@TableField(value = "response_content")
private String responseContent;
/**
* 日志记录时间
*/
@TableField(value = "log_time")
private LocalDateTime logTime;
}

View File

@ -0,0 +1,102 @@
package com.wms_main.model.vo.wms;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 接口发送日志
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysApiVo {
/**
* id
*/
@JsonProperty("logId")
private String logId;
/**
* url
*/
@JsonProperty("url")
private String url;
/**
* 超时时长
*/
@JsonProperty("timeout")
private Integer timeout;
/**
* 请求方式
*/
@JsonProperty("method")
private String method;
/**
* 请求头
*/
@JsonProperty("contentType")
private String contentType;
/**
* 数据
*/
@JsonProperty("data")
private String data;
/**
* token
*/
@JsonProperty("token")
private String token;
/**
* 请求是否成功
*/
@JsonProperty("success")
private String success;
/**
* 响应码
*/
@JsonProperty("responseCode")
private int responseCode;
/**
* 请求信息
*/
@JsonProperty("requestMessage")
private String requestMessage;
/**
* 响应信息
*/
@JsonProperty("responseMessage")
private String responseMessage;
/**
* 请求时间
*/
@JsonProperty("requestTime")
private LocalDateTime requestTime;
/**
* 响应时间
*/
@JsonProperty("responseTime")
private LocalDateTime responseTime;
/**
* 请求地址
*/
@JsonProperty("requestUrl")
private String requestUrl;
/**
* 请求耗时
*/
@JsonProperty("useTime")
private long useTime;
/**
* 异常
*/
@JsonProperty("exceptionMessage")
private String exceptionMessage;
/**
* 记录时间
*/
@JsonProperty("logTime")
private LocalDateTime logTime;
}

View File

@ -0,0 +1,62 @@
package com.wms_main.model.vo.wms;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 接口接收日志
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysLogVo {
/**
* 日志Id
*/
@JsonProperty("logId")
private String logId;
/**
* 请求方式
*/
@JsonProperty("method")
private String method;
/**
* 请求地址
*/
@JsonProperty("uri")
private String uri;
/**
* 客户端主机
*/
@JsonProperty("remoteHost")
private String remoteHost;
/**
* 客户端地址
*/
@JsonProperty("remoteAddr")
private String remoteAddr;
/**
* 请求数据
*/
@JsonProperty("requestContent")
private String requestContent;
/**
* 响应状态
*/
@JsonProperty("status")
private String status;
/**
* 响应数据
*/
@JsonProperty("responseContent")
private String responseContent;
/**
* 日志记录时间
*/
@JsonProperty("logTime")
private LocalDateTime logTime;
}

View File

@ -1,8 +1,12 @@
package com.wms_main.repository.http;
import com.wms_main.dao.ITSysApiService;
import com.wms_main.model.po.TSysLog;
import com.wms_main.repository.http.entity.HttpRequest;
import com.wms_main.repository.http.entity.HttpResponse;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
@ -24,7 +28,9 @@ import java.time.LocalDateTime;
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class HttpClient {
private final ITSysApiService sysApiService;
/**
* 发送一个 Get 请求
@ -39,6 +45,8 @@ public class HttpClient {
response.setSuccess(false);
response.setResponseCode(999);
response.setException(new Exception("请求地址为空"));
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
}
if(StringUtils.isNotEmpty(request.getData())) {
@ -74,16 +82,19 @@ public class HttpClient {
httpClient.close();
response.setSuccess(true);
response.setResponseMessage(result.toString());
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
} catch (Exception e) {
response.setSuccess(false);
response.setResponseCode(999);
response.setException(e);
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
}
}
/**
* 发送一个 Post 请求
* @param request 请求数据
@ -98,6 +109,8 @@ public class HttpClient {
response.setSuccess(false);
response.setResponseCode(999);
response.setException(new Exception("请求地址为空"));
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
}
if(StringUtils.isEmpty(request.getData())) {
@ -134,11 +147,15 @@ public class HttpClient {
httpClient.close();
response.setSuccess(true);
response.setResponseMessage(result.toString());
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
} catch (Exception e) {
response.setSuccess(false);
response.setResponseCode(999);
response.setException(e);
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
}
}
@ -156,6 +173,8 @@ public class HttpClient {
response.setSuccess(false);
response.setResponseCode(999);
response.setException(new Exception("请求地址为空"));
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
}
if(!StringUtils.isEmpty(request.getData())) {
@ -191,12 +210,30 @@ public class HttpClient {
httpClient.close();
response.setSuccess(true);
response.setResponseMessage(result.toString());
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
} catch (Exception e) {
response.setSuccess(false);
response.setResponseCode(999);
response.setException(e);
// 增加存储数据库的操作 TODO 后续想办法增加多线程执行存储数据库
insertApiLogToDb(request, response);
return response;
}
}
/**
* 存储api日志信息
* @param request 请求信息
* @param response 响应信息
*/
void insertApiLogToDb(HttpRequest request, HttpResponse response) {
try {
sysApiService.insertApiLog(request, response);
} catch (Exception e) {
log.error("插入日志失败{}", StringUtils.objectToString(e));
}
}
}

View File

@ -1,11 +1,13 @@
package com.wms_main.repository.http.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* http请求方式
*/
@Getter
@AllArgsConstructor
public enum HttpMethodEnum {
GET("GET"),
@ -13,9 +15,5 @@ public enum HttpMethodEnum {
PUT("PUT"),
DELETE("DELETE");
private String method;
HttpMethodEnum(String method) {
this.method = method;
}
private final String method;
}

View File

@ -72,6 +72,11 @@ public class StringUtils {
return str.matches("^\\d+$");
}
/**
* 判断一个字符串是否为小数
* @param str 要判断的字符串
* @return 结果
*/
public static boolean isDecimal(String str) {
if (isEmpty(str)) return false;
return str.matches("^\\d+\\.?\\d*$");
@ -245,4 +250,22 @@ public class StringUtils {
}
return ip;
}
/**
* 截取字符串---依据最大程度并去除空白与换行符
* @param originStr 原始字符串
* @param maxLength 最大长度
* @return 格式化之后的字符串
*/
public static String formatStringWithMaxLength(String originStr, int maxLength) {
if (StringUtils.isEmpty(originStr)) {
// 防止NULL异常
return "";
}
String newContentString = originStr.replaceAll("\\s*", "");
if (newContentString.length() > maxLength) {
newContentString = newContentString.substring(0, maxLength) + "...";
}
return newContentString;
}
}

View File

@ -0,0 +1,27 @@
package com.wms_main.service.controller;
import com.wms_main.model.dto.query.SysApiQuery;
import com.wms_main.model.dto.query.SysLogQuery;
import com.wms_main.model.dto.response.wms.WmsApiResponse;
import com.wms_main.model.vo.wms.PageVo;
import com.wms_main.model.vo.wms.SysApiVo;
import com.wms_main.model.vo.wms.SysLogVo;
/**
* 日志控制类服务
*/
public interface ILogControllerService {
/**
* 查询接口接收日志数据---分页
* @param logQuery 查询参数
* @return 查询结果
*/
WmsApiResponse<PageVo<SysLogVo>> queryLogsByPage(SysLogQuery logQuery);
/**
* 查询接口发送日志数据---分页
* @param apiQuery 查询参数
* @return 查询结果
*/
WmsApiResponse<PageVo<SysApiVo>> queryApisByPage(SysApiQuery apiQuery);
}

View File

@ -0,0 +1,91 @@
package com.wms_main.service.controller.serviceImpl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms_main.dao.ITSysApiService;
import com.wms_main.dao.ITSysLogService;
import com.wms_main.model.dto.query.SysApiQuery;
import com.wms_main.model.dto.query.SysLogQuery;
import com.wms_main.model.dto.response.wms.WmsApiResponse;
import com.wms_main.model.po.TSysApi;
import com.wms_main.model.po.TSysLog;
import com.wms_main.model.vo.wms.PageVo;
import com.wms_main.model.vo.wms.SysApiVo;
import com.wms_main.model.vo.wms.SysLogVo;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.service.controller.ILogControllerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 日志服务类接口实现
*/
@RequiredArgsConstructor
@Slf4j
@Service
public class LogControllerServiceImpl implements ILogControllerService {
private final ITSysLogService sysLogService;// 接口接收日志服务
private final ITSysApiService sysApiService;// 接口发送日志服务
/**
* 查询接口接收日志---实现
* @param logQuery 查询参数
* @return 查询结果
*/
@Override
public WmsApiResponse<PageVo<SysLogVo>> queryLogsByPage(SysLogQuery logQuery) {
if (logQuery == null) {
return WmsApiResponse.error("查询参数不能为NULL", null);
}
Page<TSysLog> page = logQuery.toMpPage();
LambdaQueryWrapper<TSysLog> lambdaQueryWrapper = new LambdaQueryWrapper<TSysLog>()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getMethod, logQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getUri, logQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getRemoteHost, logQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getRemoteAddr, logQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getRequestContent, logQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getStatus, logQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getResponseContent, logQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(logQuery.getQueryStr()), TSysLog::getLogTime, logQuery.getQueryStr());
Page<TSysLog> logsPage = sysLogService.page(page, lambdaQueryWrapper);
PageVo<SysLogVo> pageVo = PageVo.of(logsPage, logPo -> BeanUtil.toBean(logPo, SysLogVo.class));
return WmsApiResponse.success("查询接口接收日志成功。", pageVo);
}
/**
* 查询接口发送日志---实现
* @param apiQuery 查询参数
* @return 查询结果
*/
@Override
public WmsApiResponse<PageVo<SysApiVo>> queryApisByPage(SysApiQuery apiQuery) {
if (apiQuery == null) {
return WmsApiResponse.error("查询参数不能为NULL", null);
}
Page<TSysApi> page = apiQuery.toMpPage();
LambdaQueryWrapper<TSysApi> lambdaQueryWrapper = new LambdaQueryWrapper<TSysApi>()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getUrl, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getTimeout, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getMethod, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getContentType, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getData, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getToken, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getSuccess, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getResponseCode, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getRequestMessage, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getResponseMessage, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getRequestTime, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getResponseTime, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getRequestUrl, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getUseTime, apiQuery.getQueryStr()).or()
.like(StringUtils.isNotEmpty(apiQuery.getQueryStr()), TSysApi::getExceptionMessage, apiQuery.getQueryStr());
Page<TSysApi> logsPage = sysApiService.page(page, lambdaQueryWrapper);
PageVo<SysApiVo> pageVo = PageVo.of(logsPage, logPo -> BeanUtil.toBean(logPo, SysApiVo.class));
return WmsApiResponse.success("查询接口发送日志成功。", pageVo);
}
}

View File

@ -0,0 +1,4 @@
package com.wms_main.service.quartz_job;
public interface IDataSolverService {
}

View File

@ -19,8 +19,7 @@ public class DataSolver implements Job {
*/
@Override
public void execute(JobExecutionContext jobExecutionContext) {
// 获取定时配置信息
// 获取
// 获取各种需要处理的数据
}

View File

@ -17,7 +17,8 @@ import org.quartz.PersistJobDataAfterExecution;
// 以下注解用于实现fixed_delay
@DisallowConcurrentExecution
@RequiredArgsConstructor
public class OutsRepair implements Job {
public class
OutsRepair implements Job {
private final IOutsExecutorService outsExecutorService;// 出库单解析服务
/**

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wms_main.mapper.SysApiMapper">
</mapper>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wms_main.mapper.SysLogMapper">
</mapper>