添加功能

This commit is contained in:
曹鹏飞 2025-07-25 16:04:30 +08:00
parent 58637851e4
commit 6a54dd2a7a
17 changed files with 265 additions and 329 deletions

View File

@ -5,7 +5,7 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Sets;
import com.nflg.wms.admin.util.DateTimeUtil;
import com.nflg.wms.admin.util.NoUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
@ -113,7 +113,7 @@ public class NormalDeliverOrderController extends BaseController {
}
private String getDeliverNormalOrderNo() {
return "P" + DateTimeUtil.getForOrderNo() + RandomUtil.randomNumbers(4);
return "P" + NoUtil.getForOrderNo() + RandomUtil.randomNumbers(4);
}
/**
@ -161,7 +161,7 @@ public class NormalDeliverOrderController extends BaseController {
print.setBatchNum(order.getBatchNum());
print.setMinPackageNum(order.getMinPackageNum());
print.setLableNum(order.getLableNum());
print.setNo(DateTimeUtil.getForDeliverPrintNo());
print.setNo(NoUtil.getForOrderPrintNo());
prints.add(print);
for (int i = 0; i < order.getLableNum(); i++) {
DeliverNormalOrderItemDTO dto = Convert.convert(DeliverNormalOrderItemDTO.class, order);

View File

@ -12,7 +12,7 @@ import com.nflg.wms.admin.pojo.document.PackageMaterialScanRecordItem;
import com.nflg.wms.admin.pojo.dto.SAPMaterialInfoInOrderDTO;
import com.nflg.wms.admin.repository.PackageMaterialScanRecordRepository;
import com.nflg.wms.admin.service.SapService;
import com.nflg.wms.admin.util.DateTimeUtil;
import com.nflg.wms.admin.util.NoUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
@ -229,7 +229,7 @@ public class StructuralPackageOrderController extends BaseController {
private String getDeliverNormalOrderNo() {
Long index = stringRedisTemplate.opsForValue().increment("package:trayNo:index");
return "S" + DateTimeUtil.getForOrderNo() + StrUtil.padPre(String.valueOf(index), 4, "0");
return "S" + NoUtil.getForOrderNo() + StrUtil.padPre(String.valueOf(index), 4, "0");
}
/**
@ -534,14 +534,15 @@ public class StructuralPackageOrderController extends BaseController {
Long supplierId = trays.get(0).getSupplierId();
List<Long> tids = deliverStructuralPackageOrderTrayService.getIdsByMaterialAndExternalOrderNo(packageId, externalOrderNo);
VUtil.trueThrowBusinessError(tids.size() != ids.size()).throwMessage("数据未齐套");
String deliverOrderNo = RandomUtil.randomString(10);
String deliverOrderNo = NoUtil.getForDeliverNo();
WmsStructuralPackageDeliverOrder deliverOrder = new WmsStructuralPackageDeliverOrder()
.setNo(deliverOrderNo)
.setSupplierId(supplierId)
.setCreateBy(UserUtil.getUserName())
.setCreateTime(LocalDateTime.now());
structuralPackageDeliverOrderService.save(deliverOrder);
structuralPackageDeliverOrderMapService.saveBatch(ids.stream().map(id -> new WmsStructuralPackageDeliverOrderMap()
structuralPackageDeliverOrderMapService.saveBatch(trays.stream().map(DeliverStructuralPackageOrderExtendVO::getTrayId).distinct().map(id ->
new WmsStructuralPackageDeliverOrderMap()
.setDeliverId(deliverOrder.getId())
.setOrderId(id)).toList());
deliverStructuralPackageOrderTrayService.setStateByIds(ids, OrderState.InTransit);
@ -561,9 +562,9 @@ public class StructuralPackageOrderController extends BaseController {
* 根据送货单号查询订单信息PDA使用
* @param orderNo 送货单号
*/
@GetMapping("getInfoByExternalOrderNo")
public ApiResult<DeliverStructuralPackageOrderForPackageVO> getInfoByExternalOrderNo(@Valid @RequestParam @NotBlank String orderNo) {
List<DeliverStructuralPackageOrderForPackageItemVO> datas = deliverStructuralPackageOrderService.getInfoByExternalOrderNo(orderNo);
@GetMapping("getInfoByDeliverOrderNo")
public ApiResult<DeliverStructuralPackageOrderForPackageVO> getInfoByDeliverOrderNo(@Valid @RequestParam @NotBlank String orderNo) {
List<DeliverStructuralPackageOrderForPackageItemVO> datas = deliverStructuralPackageOrderService.getInfoByDeliverOrderNo(orderNo);
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(datas)).throwMessage("未找到数据");
datas.forEach(it -> {
it.setTrayNos(deliverStructuralPackageOrderTrayService.lambdaQuery()

View File

@ -1,15 +0,0 @@
package com.nflg.wms.admin.util;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class DateTimeUtil {
public static String getForOrderNo() {
return com.nflg.wms.common.util.DateTimeUtil.format(LocalDate.now(), "yyyyMMdd");
}
public static String getForDeliverPrintNo() {
return com.nflg.wms.common.util.DateTimeUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss");
}
}

View File

@ -0,0 +1,21 @@
package com.nflg.wms.admin.util;
import com.nflg.wms.common.util.DateTimeUtil;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class NoUtil {
public static String getForOrderNo() {
return DateTimeUtil.format(LocalDate.now(), "yyyyMMdd");
}
public static String getForOrderPrintNo() {
return DateTimeUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss");
}
public static String getForDeliverNo() {
return "SH"+DateTimeUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss");
}
}

View File

@ -17,6 +17,11 @@ public class DeliverStructuralPackageOrderExtendVO extends DeliverStructuralPack
@ExcelColumn(value = "序号",colIndex = 0)
private Integer index;
/**
* 托盘id
*/
private Long trayId;
/**
* 托盘号
*/

View File

@ -9,7 +9,7 @@ import java.time.LocalDateTime;
@Data
public class DeliverStructuralPackageOrderVO {
private Long id;
// private Long id;
/**
* 单据号

View File

@ -26,5 +26,5 @@ public interface WmsStructuralPackageOrderMapper extends BaseMapper<WmsStructura
DeliverStructuralPackageOrderVO getInfo(Long id);
List<DeliverStructuralPackageOrderForPackageItemVO> getInfoByExternalOrderNo(String orderNo);
List<DeliverStructuralPackageOrderForPackageItemVO> getInfoByDeliverOrderNo(String orderNo);
}

View File

@ -32,5 +32,5 @@ public interface IWmsStructuralPackageOrderService extends IService<WmsStructura
void deleteByIds(List<Long> deleteIds);
List<DeliverStructuralPackageOrderForPackageItemVO> getInfoByExternalOrderNo(@Valid @NotBlank String orderNo);
List<DeliverStructuralPackageOrderForPackageItemVO> getInfoByDeliverOrderNo(@Valid @NotBlank String orderNo);
}

View File

@ -82,8 +82,8 @@ public class WmsStructuralPackageOrderServiceImpl extends ServiceImpl<WmsStructu
}
@Override
public List<DeliverStructuralPackageOrderForPackageItemVO> getInfoByExternalOrderNo(String orderNo) {
return baseMapper.getInfoByExternalOrderNo(orderNo);
public List<DeliverStructuralPackageOrderForPackageItemVO> getInfoByDeliverOrderNo(String orderNo) {
return baseMapper.getInfoByDeliverOrderNo(orderNo);
}
private void add(WmsStructuralPackageOrder order){

View File

@ -3,9 +3,10 @@
<mapper namespace="com.nflg.wms.repository.mapper.WmsStructuralPackageDeliverOrderMapper">
<select id="search" resultType="com.nflg.wms.common.pojo.vo.StructuralPackageDeliverOrderVO">
select pdo.*, us.supplier_code, us.supplier_name
select pdo.*, us.supplier_code, us.supplier_name,di."name" AS "factory_no"
from wms_structural_package_deliver_order pdo
inner join user_supplier us on pdo.id=us.user_id
inner join user_supplier us on pdo.supplier_id=us.user_id
LEFT JOIN dictionary_item di ON pdo.factory_id=di."id"
<where>
<if test="externalOrderIds!=null">
and pdo.id in

View File

@ -60,14 +60,16 @@
order by id desc
</select>
<select id="getInfoByExternalOrderNo" resultType="com.nflg.wms.common.pojo.vo.DeliverStructuralPackageOrderForPackageItemVO">
<select id="getInfoByDeliverOrderNo" resultType="com.nflg.wms.common.pojo.vo.DeliverStructuralPackageOrderForPackageItemVO">
SELECT o.*,m.no||wb."no" AS "workbench_code",us.supplier_code,us.supplier_name,sp."no" AS "package_no"
,sp."name" AS "package_desc"
FROM wms_structural_package_order o
FROM wms_structural_package_deliver_order pdo
inner join wms_structural_package_deliver_order_map pdom on pdo.id=pdom.deliver_id
LEFT JOIN wms_structural_package_order o on o.id=pdom.order_id
LEFT JOIN wms_workbench wb ON o.workbench_id=wb."id"
LEFT JOIN wms_model m on o.model_id=m."id"
LEFT JOIN user_supplier us ON o.supplier_id=us.user_id
LEFT JOIN wms_structural_package sp ON o.package_id=sp."id"
where o.external_order_no=#{orderNo}
where pdo.no=#{orderNo}
</select>
</mapper>

View File

@ -37,8 +37,9 @@
</select>
<select id="getListByIds" resultType="com.nflg.wms.common.pojo.vo.DeliverStructuralPackageOrderExtendVO">
SELECT ROW_NUMBER() OVER (ORDER BY o.id desc) AS "index",ot.id,o.*,m.no||wb."no" AS "workbench_code",us.supplier_code,us.supplier_name,sp.order_no AS "package_order_no"
SELECT ROW_NUMBER() OVER (ORDER BY o.id desc) AS "index",o.*,m.no||wb."no" AS "workbench_code",us.supplier_code,us.supplier_name,sp.order_no AS "package_order_no"
,sp."no" AS "package_no",sp."name" AS "package_desc",m."no" AS "model_no",ot.no as "tray_no",ot.tray,ot.station,ot.state
,ot.id as "tray_id"
FROM wms_structural_package_order o
LEFT JOIN wms_workbench wb ON o.workbench_id=wb."id"
LEFT JOIN user_supplier us ON o.supplier_id=us.user_id

View File

@ -142,26 +142,26 @@ public class SyncStorageFromSAPProcessor implements BasicProcessor {
WmsWarehouse dbWarehouse = dbWarehouses.stream().filter(w -> StrUtil.equals(w.getNo(), dto.getWarehouseNo())).findFirst().get();
VStorage dbStorage = lv.stream().filter(l -> StrUtil.equals(l.getMaterialNo(), dto.getMaterialNo())
&& StrUtil.equals(l.getWarehouseNo(), dto.getWarehouseNo())).findFirst().orElse(null);
WmsBin dbBin = null;
if (StrUtil.isNotBlank(dto.getBinNo())) {
dbBin = dbBins.stream().filter(b -> StrUtil.equals(b.getNo(), dto.getBinNo())).findFirst().orElse(null);
List<String> sapBinNos = StrUtil.split(dto.getBinNos(), "/");
if (CollectionUtil.isNotEmpty(sapBinNos)){
for (String sapBinNo : sapBinNos){
WmsBin dbBin=dbBins.stream().filter(b ->StrUtil.equals(b.getNo(), sapBinNo)).findFirst().orElse(null);
if (Objects.isNull(dbBin)) {
dbBin = binService.lambdaQuery().eq(WmsBin::getNo, dto.getBinNo()).one();
dbBin = binService.lambdaQuery().eq(WmsBin::getNo, sapBinNo).one();
if (Objects.isNull(dbBin)) {
dbBin = new WmsBin()
.setId(IdUtil.getSnowflakeNextId())
.setWarehouseId(dbWarehouse.getId())
.setNo(dto.getBinNo())
.setName(dto.getBinNo())
.setNo(sapBinNo)
.setName(sapBinNo)
.setCreateBy("SAP同步")
.setCreateTime(LocalDateTime.now());
binsForAdd.add(dbBin);
}
dbBins.add(dbBin);
}
}
if (Objects.isNull(dbStorage)) {
log.info("添加,仓库:{},储位:{}", dto.getWarehouseNo(), dto.getBinNo());
log.info("添加,仓库:{},储位:{}", dto.getWarehouseNo(), sapBinNo);
WmsStorage storage = new WmsStorage()
.setId(IdUtil.getSnowflakeNextId())
.setMaterialNo(dto.getMaterialNo())
@ -171,13 +171,13 @@ public class SyncStorageFromSAPProcessor implements BasicProcessor {
.setCreateBy("SAP同步")
.setCreateTime(LocalDateTime.now());
storagesForAdd.add(storage);
if (StrUtil.isNotBlank(dto.getBinNo())) {
if (StrUtil.isNotBlank(sapBinNo)) {
storageBins.add(new WmsStorageBin()
.setStorageId(storage.getId())
.setBinId(dbBin.getId()));
}
} else {
log.info("更新,仓库:{},储位:{}", dto.getWarehouseNo(), dto.getBinNo());
log.info("更新,仓库:{},储位:{}", dto.getWarehouseNo(), sapBinNo);
if (!StrUtil.equals(dbStorage.getWarehouseNo(), dto.getWarehouseNo())) {
storagesForUpdate.add(new WmsStorage()
.setId(dbStorage.getId())
@ -185,12 +185,14 @@ public class SyncStorageFromSAPProcessor implements BasicProcessor {
.setUpdateBy("SAP同步")
.setUpdateTime(LocalDateTime.now()));
}
if (StrUtil.isNotBlank(dto.getBinNo())) {
if (StrUtil.isNotBlank(sapBinNo)) {
storageBins.add(new WmsStorageBin()
.setStorageId(dbStorage.getId())
.setBinId(dbBin.getId()));
}
}
}
}
});
if (CollectionUtil.isNotEmpty(storagesForAdd)) {
storageService.saveBatch(storagesForAdd);

View File

@ -56,7 +56,7 @@ public class SapService {
.setMaterialDesc(tOut.getString("MAKTX"))
.setWarehouseNo(tOut.getString("LGORT"))
.setWarehouseName(tOut.getString("LGOBE"))
.setBinNo(tOut.getString("LGPBE")))
.setBinNos(tOut.getString("LGPBE")))
;
}
log.debug("数据:{}", JSONUtil.toJsonStr(result));

View File

@ -1,208 +0,0 @@
package com.nflg.wms.scheduled.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nflg.wms.common.constant.Constant;
import com.nflg.wms.common.pojo.dto.SAPSyncFromDTO;
import com.nflg.wms.common.util.DateTimeUtil;
import com.nflg.wms.repository.entity.*;
import com.nflg.wms.repository.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import tech.powerjob.worker.core.processor.ProcessResult;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@Slf4j
@Component
public class SapTestService {
@Resource
private SapService sapService;
@Resource
private IWmsWarehouseService warehouseService;
@Resource
private IDictionaryItemService dictionaryItemService;
@Resource
private IWmsStorageService storageService;
@Resource
private IWmsStorageBinService storageBinService;
@Resource
private IVStorageService vStorageService;
@Resource
private IWmsBinService binService;
public ProcessResult process(String sss) {
List<String> params= StrUtil.split(sss, "|");
String factory = CollectionUtil.get(params, 0);
String warehouseNo = CollectionUtil.get(params, 1);
String beginDate = CollectionUtil.get(params, 2);
String endDate = CollectionUtil.get(params, 3);
List<DictionaryItem> dbFactorys=dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_FACTORY);
if (StrUtil.isNotBlank(factory)){
List<String> factorys = StrUtil.split(factory, ",");
dbFactorys.removeIf(d -> !factorys.contains(d.getValue()));
List<String> invalidFactorys=factorys.stream().filter(d -> dbFactorys.stream().noneMatch(s -> StrUtil.equals(s.getValue(), d))).toList();
if (CollectionUtil.isNotEmpty(invalidFactorys)){
return new ProcessResult(false, "工厂无效: " + StrUtil.join(",", invalidFactorys));
}
}
if (CollectionUtil.isEmpty(dbFactorys)) {
return new ProcessResult(false, "请先配置工厂");
}
log.info("工厂: {}", StrUtil.join(",", dbFactorys.stream().map(DictionaryItem::getValue).toList()));
List<String> warehouseNos = StrUtil.isNotBlank(warehouseNo) ? StrUtil.split(warehouseNo, ",") :
warehouseService.getList().stream().map(WmsWarehouse::getNo).toList();
if (CollectionUtil.isEmpty(warehouseNos)) {
return new ProcessResult(false, "请先配置仓库");
}
log.info("仓库: {}", StrUtil.join(",", warehouseNos));
boolean isInit=!storageService.lambdaQuery().exists();
if (StrUtil.isBlank(beginDate)){
if (!isInit){
beginDate= DateTimeUtil.format(LocalDate.now().minusDays(1),"yyyyMMdd");
}
}
log.info("开始时间: {}", beginDate);
if (StrUtil.isBlank(endDate)){
if (!isInit){
endDate= DateTimeUtil.format(LocalDate.now(),"yyyyMMdd");
}
}
log.info("结束时间: {}", endDate);
for (DictionaryItem fy: dbFactorys){
log.info("处理工厂:{}", fy.getValue());
try {
List<SAPSyncFromDTO> list = sapService.getStorage(fy.getValue(), warehouseNos, beginDate, endDate);
if (CollectionUtil.isEmpty(list)) {
log.info("没有获取到数据");
} else {
log.info("获取到{}条数据", list.size());
//同步仓库信息
warehouseNos = list.stream().map(SAPSyncFromDTO::getWarehouseNo).distinct().toList();
List<WmsWarehouse> dbWarehouses = warehouseService.lambdaQuery().eq(WmsWarehouse::getFactoryId, fy.getId()).in(WmsWarehouse::getNo, warehouseNos).list();
warehouseNos.forEach(wn -> {
String name=list.stream().filter(dto -> StrUtil.equals(dto.getWarehouseNo(), wn)).findFirst().get().getWarehouseName();
WmsWarehouse dbWarehouse = dbWarehouses.stream().filter(w -> StrUtil.equals(w.getNo(), wn)).findFirst().orElse(null);
if (Objects.isNull(dbWarehouse)) {
dbWarehouse=new WmsWarehouse()
.setNo(wn)
.setName(name)
.setFactoryId(fy.getId())
.setRemark("从SAP同步")
.setCreateBy("SAP同步")
.setCreateTime(LocalDateTime.now());
warehouseService.save(dbWarehouse);
dbWarehouses.add(dbWarehouse);
}else if (!StrUtil.equals(dbWarehouse.getName(), name)){
warehouseService.lambdaUpdate()
.set(WmsWarehouse::getId, dbWarehouse.getId())
.set(WmsWarehouse::getName, name)
.set(WmsWarehouse::getUpdateBy, "SAP同步")
.set(WmsWarehouse::getUpdateTime, LocalDateTime.now());
}
});
List<WmsBin> dbBins=new ArrayList<>();
List<WmsBin> binsForAdd=new ArrayList<>();
List<WmsStorage> storagesForAdd=new ArrayList<>();
List<WmsStorageBin> storageBins=new ArrayList<>();
List<WmsStorage> storagesForUpdate = new ArrayList<>();
List<String> materialNos = list.stream().map(SAPSyncFromDTO::getMaterialNo).toList();
List<VStorage> lv = vStorageService.lambdaQuery().eq(VStorage::getFactoryId, fy.getId()).in(VStorage::getMaterialNo, materialNos).list();
if(CollectionUtil.isNotEmpty(lv)) {
storageBinService.remove(new LambdaQueryWrapper<WmsStorageBin>().in(WmsStorageBin::getStorageId, lv.stream().map(VStorage::getId).toList()));
}
list.forEach(dto -> {
log.info("处理物料:{}", dto.getMaterialNo());
WmsWarehouse dbWarehouse = dbWarehouses.stream().filter(w -> StrUtil.equals(w.getNo(), dto.getWarehouseNo())).findFirst().get();
VStorage dbStorage = lv.stream().filter(l -> StrUtil.equals(l.getMaterialNo(), dto.getMaterialNo())
&& StrUtil.equals(l.getWarehouseNo(), dto.getWarehouseNo())).findFirst().orElse(null);
WmsBin dbBin = null;
if (StrUtil.isNotBlank(dto.getBinNo())) {
dbBin = dbBins.stream().filter(b -> StrUtil.equals(b.getNo(), dto.getBinNo())).findFirst().orElse(null);
if (Objects.isNull(dbBin)) {
dbBin = binService.lambdaQuery().eq(WmsBin::getNo, dto.getBinNo()).one();
if (Objects.isNull(dbBin)) {
dbBin = new WmsBin()
.setId(IdUtil.getSnowflakeNextId())
.setWarehouseId(dbWarehouse.getId())
.setNo(dto.getBinNo())
.setName(dto.getBinNo())
.setCreateBy("SAP同步")
.setCreateTime(LocalDateTime.now());
binsForAdd.add(dbBin);
}
dbBins.add(dbBin);
}
}
if (Objects.isNull(dbStorage)) {
log.info("添加,仓库:{},储位:{}", dto.getWarehouseNo(), dto.getBinNo());
WmsStorage storage = new WmsStorage()
.setId(IdUtil.getSnowflakeNextId())
.setMaterialNo(dto.getMaterialNo())
.setWarehouseId(dbWarehouse.getId())
.setMaterialDesc(dto.getMaterialDesc())
.setRemark("从SAP同步")
.setCreateBy("SAP同步")
.setCreateTime(LocalDateTime.now());
storagesForAdd.add(storage);
if (StrUtil.isNotBlank(dto.getBinNo())) {
storageBins.add(new WmsStorageBin()
.setStorageId(storage.getId())
.setBinId(dbBin.getId()));
}
}else {
log.info("更新,仓库:{},储位:{}", dto.getWarehouseNo(), dto.getBinNo());
if (!StrUtil.equals(dbStorage.getWarehouseNo(), dto.getWarehouseNo())){
storagesForUpdate.add(new WmsStorage()
.setId(dbStorage.getId())
.setWarehouseId(dbWarehouse.getId())
.setUpdateBy("SAP同步")
.setUpdateTime(LocalDateTime.now()));
}
if (StrUtil.isNotBlank(dto.getBinNo())){
storageBins.add(new WmsStorageBin()
.setStorageId(dbStorage.getId())
.setBinId(dbBin.getId()));
}
}
});
if (CollectionUtil.isNotEmpty(storagesForAdd)){
storageService.saveBatch(storagesForAdd);
}
if (CollectionUtil.isNotEmpty(storagesForUpdate)){
storageService.updateBatchById(storagesForUpdate);
}
if (CollectionUtil.isNotEmpty(storageBins)){
storageBinService.saveBatch(storageBins);
}
if (CollectionUtil.isNotEmpty(binsForAdd)){
binService.saveBatch(binsForAdd);
}
}
}catch (Exception ex){
log.error("发生异常:{}", ex.getMessage());
log.error(Arrays.toString(ex.getStackTrace()));
}finally {
log.info("处理工厂完成:{}", fy.getValue());
}
}
return new ProcessResult(true, "同步完成");
}
}

View File

@ -0,0 +1,167 @@
package com.nflg.wms.starter.filter;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.common.constant.Constant;
import com.nflg.wms.common.util.UserUtil;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Component
@ConditionalOnClass(Filter.class)
public class TraceFilter extends OncePerRequestFilter {
private static final String TRACE_ID_HEADER = "X-Trace-Id";
// 需要跳过的二进制内容类型
private static final List<String> BINARY_CONTENT_TYPES = Arrays.asList("image", "video", "audio", "stream", "pdf", "zip", "excel");
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
try {
// 从请求头获取或生成Trace ID
String traceId = requestWrapper.getHeader(TRACE_ID_HEADER);
if (StrUtil.isBlank(traceId)) {
traceId = IdUtil.getSnowflakeNextIdStr();
}
// 存入MDC和响应头
MDC.put(Constant.TRACE_ID, traceId);
responseWrapper.addHeader(TRACE_ID_HEADER, traceId);
filterChain.doFilter(requestWrapper, responseWrapper);
} finally {
logRequest(requestWrapper);
logResponse(responseWrapper);
responseWrapper.copyBodyToResponse();
// 请求结束时清除MDC
MDC.remove(Constant.TRACE_ID);
}
}
private void logResponse(ContentCachingResponseWrapper response) {
log.debug("【HTTP Response】");
log.debug("STATUS : {}", response.getStatus());
log.debug("BODY : {}", getResponseBody(response));
}
private String getResponseBody(ContentCachingResponseWrapper response) {
if (shouldSkipBodyLogging(response.getContentType())){
return "不记录"+response.getContentType();
}
byte[] buf = response.getContentAsByteArray();
if (buf.length > 0) {
return new String(buf, StandardCharsets.UTF_8);
}
return "无数据";
}
private void logRequest(ContentCachingRequestWrapper request) {
log.debug("【HTTP Request】");
log.debug("URL : {}", request.getRequestURI() + (StrUtil.isBlank(request.getQueryString()) ? "" : "?" + request.getQueryString()));
log.debug("HOST : {}", getHost(request));
log.debug("METHOD : {}", request.getMethod());
log.debug("HEADERS: {}", getHeadersAsString(request));
log.debug("USER : {}", getUserInfo(request));
log.debug("BODY : {}", getRequestBody(request));
}
private String getHost(HttpServletRequest request) {
String forwardedHost = request.getHeader("Host");
if (forwardedHost != null && !forwardedHost.isEmpty()) {
return forwardedHost.split(",")[0].trim();
}
String forwardedHeader = request.getHeader("Forwarded");
if (forwardedHeader != null) {
String host = parseForwardedHeader(forwardedHeader, "host");
if (host != null) return host;
}
return getHostFromRequestURL(request);
}
private String getHostFromRequestURL(HttpServletRequest request) {
StringBuffer requestURL = request.getRequestURL();
String urlString = requestURL.toString();
// 提取主机部分
try {
URI uri = new URI(urlString);
return uri.getAuthority(); // 返回格式: "example.com:8080"
} catch (URISyntaxException e) {
return "未知";
}
}
private String parseForwardedHeader(String header, String key) {
String[] parts = header.split(";");
for (String part : parts) {
part = part.trim();
if (part.startsWith(key + "=")) {
String value = part.substring(key.length() + 1);
return value.replace("\"", "");
}
}
return null;
}
private String getUserInfo(ContentCachingRequestWrapper request) {
String token=request.getHeader("authorization");
if (StrUtil.isBlank(token)){
return "未登录";
}
if (StpUtil.isLogin()) {
return StrUtil.format("id:{},姓名:{}", UserUtil.getUserId(), UserUtil.getUserName());
}
return "无效token或已过期";
}
private String getRequestBody(ContentCachingRequestWrapper request) {
if (shouldSkipBodyLogging(request.getContentType())){
return "[不记录]"+request.getContentType();
}
byte[] buf = request.getContentAsByteArray();
if (buf.length > 0) {
return new String(buf, StandardCharsets.UTF_8).replaceAll("\\s", "");
}
return "无数据";
}
private String getHeadersAsString(HttpServletRequest request) {
StringBuilder headers = new StringBuilder();
request.getHeaderNames().asIterator().forEachRemaining(headerName ->
headers.append(headerName)
.append("=")
.append(request.getHeader(headerName))
.append("; ")
);
return headers.toString();
}
private boolean shouldSkipBodyLogging(String contentType) {
if (contentType == null) return false;
return BINARY_CONTENT_TYPES.stream().anyMatch(contentType::contains);
}
}

View File

@ -1,41 +0,0 @@
package com.nflg.wms.starter.filter;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.common.constant.Constant;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
@ConditionalOnClass(Filter.class)
public class TraceIdFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
// 从请求头获取traceId如果没有则生成新的
String traceId = request.getHeader(Constant.TRACE_ID_HEADER);
if (StrUtil.isBlank(traceId)) {
traceId = IdUtil.getSnowflakeNextIdStr();
}
// 将traceId添加到MDC
MDC.put(Constant.TRACE_ID, traceId);
// 添加到响应头
response.addHeader(Constant.TRACE_ID_HEADER, traceId);
filterChain.doFilter(request, response);
} finally {
// 请求结束时清除MDC
MDC.remove(Constant.TRACE_ID);
}
}
}