266 lines
9.4 KiB
Java
266 lines
9.4 KiB
Java
package com.designhub.service;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||
import com.designhub.entity.ThirdPartyDbConfig;
|
||
import com.designhub.exception.BusinessException;
|
||
import com.designhub.mapper.ThirdPartyDbConfigMapper;
|
||
import lombok.RequiredArgsConstructor;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import java.sql.*;
|
||
import java.time.LocalDateTime;
|
||
import java.util.HashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 第三方数据库服务
|
||
*/
|
||
@Slf4j
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class ThirdPartyDbService {
|
||
|
||
private final ThirdPartyDbConfigMapper configMapper;
|
||
|
||
// 静态初始化块:移除 TLS 和证书算法限制,以支持旧版 SQL Server
|
||
static {
|
||
try {
|
||
// 完全移除 TLS 算法禁用限制
|
||
java.security.Security.setProperty("jdk.tls.disabledAlgorithms", "");
|
||
// 完全移除证书路径算法禁用限制(解决 Certificates do not conform to algorithm constraints 错误)
|
||
java.security.Security.setProperty("jdk.certpath.disabledAlgorithms", "");
|
||
// 设置允许的 TLS 协议
|
||
System.setProperty("jdk.tls.client.protocols", "TLSv1,TLSv1.1,TLSv1.2");
|
||
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
|
||
log.info("已移除 TLS 和证书算法限制,支持旧版 SQL Server 连接");
|
||
} catch (Exception e) {
|
||
log.warn("移除算法限制失败: {}", e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取所有配置
|
||
*/
|
||
public List<ThirdPartyDbConfig> getAllConfigs() {
|
||
return configMapper.selectList(
|
||
new LambdaQueryWrapper<ThirdPartyDbConfig>()
|
||
.orderByDesc(ThirdPartyDbConfig::getCreateTime)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 获取配置详情
|
||
*/
|
||
public ThirdPartyDbConfig getConfigById(Long id) {
|
||
return configMapper.selectById(id);
|
||
}
|
||
|
||
/**
|
||
* 获取启用的配置
|
||
*/
|
||
public ThirdPartyDbConfig getEnabledConfig() {
|
||
return configMapper.selectOne(
|
||
new LambdaQueryWrapper<ThirdPartyDbConfig>()
|
||
.eq(ThirdPartyDbConfig::getEnabled, 1)
|
||
.last("LIMIT 1")
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 创建配置
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public ThirdPartyDbConfig createConfig(ThirdPartyDbConfig config) {
|
||
config.setCreateTime(LocalDateTime.now());
|
||
config.setUpdateTime(LocalDateTime.now());
|
||
configMapper.insert(config);
|
||
return config;
|
||
}
|
||
|
||
/**
|
||
* 更新配置
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public ThirdPartyDbConfig updateConfig(ThirdPartyDbConfig config) {
|
||
config.setUpdateTime(LocalDateTime.now());
|
||
configMapper.updateById(config);
|
||
return config;
|
||
}
|
||
|
||
/**
|
||
* 删除配置
|
||
*/
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public void deleteConfig(Long id) {
|
||
configMapper.deleteById(id);
|
||
}
|
||
|
||
/**
|
||
* 测试数据库连接
|
||
*/
|
||
public boolean testConnection(ThirdPartyDbConfig config) {
|
||
Connection conn = null;
|
||
try {
|
||
conn = getConnection(config);
|
||
return conn != null && !conn.isClosed();
|
||
} catch (Exception e) {
|
||
log.error("数据库连接测试失败: {}", e.getMessage());
|
||
return false;
|
||
} finally {
|
||
closeConnection(conn);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取数据库连接
|
||
*/
|
||
private Connection getConnection(ThirdPartyDbConfig config) throws SQLException {
|
||
String url;
|
||
String driverClass;
|
||
|
||
switch (config.getDbType().toLowerCase()) {
|
||
case "sqlserver":
|
||
driverClass = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
|
||
// 旧版SQL Server只支持TLS 1.0,强制使用TLS 1.0协议
|
||
url = String.format("jdbc:sqlserver://%s:%d;databaseName=%s;encrypt=false;trustServerCertificate=true;sslProtocol=TLSv1",
|
||
config.getHost(), config.getPort(), config.getDatabase());
|
||
// 设置系统属性以启用TLS 1.0
|
||
System.setProperty("jdk.tls.client.protocols", "TLSv1,TLSv1.1,TLSv1.2");
|
||
break;
|
||
case "mysql":
|
||
driverClass = "com.mysql.cj.jdbc.Driver";
|
||
url = String.format("jdbc:mysql://%s:%d/%s?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai",
|
||
config.getHost(), config.getPort(), config.getDatabase());
|
||
break;
|
||
case "postgresql":
|
||
driverClass = "org.postgresql.Driver";
|
||
url = String.format("jdbc:postgresql://%s:%d/%s",
|
||
config.getHost(), config.getPort(), config.getDatabase());
|
||
break;
|
||
default:
|
||
throw new BusinessException("不支持的数据库类型: " + config.getDbType());
|
||
}
|
||
|
||
try {
|
||
Class.forName(driverClass);
|
||
} catch (ClassNotFoundException e) {
|
||
throw new SQLException("数据库驱动未找到: " + driverClass);
|
||
}
|
||
|
||
int timeout = config.getConnectionTimeout() != null ? config.getConnectionTimeout() : 10;
|
||
DriverManager.setLoginTimeout(timeout);
|
||
|
||
return DriverManager.getConnection(url, config.getUsername(), config.getPassword());
|
||
}
|
||
|
||
/**
|
||
* 关闭连接
|
||
*/
|
||
private void closeConnection(Connection conn) {
|
||
if (conn != null) {
|
||
try {
|
||
conn.close();
|
||
} catch (SQLException e) {
|
||
log.error("关闭数据库连接失败", e);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 查询商品库存信息
|
||
* @param barcode 商品条码 (sku_id)
|
||
* @return 库存数量,如果未找到返回0
|
||
*/
|
||
public Map<String, Object> checkInventory(String barcode) {
|
||
ThirdPartyDbConfig config = getEnabledConfig();
|
||
if (config == null) {
|
||
throw new BusinessException("未配置第三方数据库或配置未启用");
|
||
}
|
||
|
||
Connection conn = null;
|
||
PreparedStatement pstmt = null;
|
||
ResultSet rs = null;
|
||
Map<String, Object> result = new HashMap<>();
|
||
result.put("barcode", barcode);
|
||
result.put("quantity", 0);
|
||
result.put("found", false);
|
||
|
||
try {
|
||
conn = getConnection(config);
|
||
|
||
// 查询聚水潭库存信息表
|
||
// 可用库存 = qty - order_lock - lock_qty
|
||
// 条件:wms_co_id='14138566',根据sku_id查询
|
||
String sql = "SELECT sku_id, qty, order_lock, lock_qty, " +
|
||
"qty - ISNULL(order_lock, 0) - ISNULL(lock_qty, 0) AS available_qty " +
|
||
"FROM jst_inventoryInfo WITH(NOLOCK) " +
|
||
"WHERE wms_co_id = '14138566' AND sku_id = ?";
|
||
|
||
pstmt = conn.prepareStatement(sql);
|
||
pstmt.setString(1, barcode);
|
||
|
||
rs = pstmt.executeQuery();
|
||
|
||
if (rs.next()) {
|
||
int availableQty = rs.getInt("available_qty");
|
||
result.put("found", true);
|
||
result.put("skuId", rs.getString("sku_id"));
|
||
result.put("quantity", rs.getInt("qty"));
|
||
result.put("orderLock", rs.getInt("order_lock"));
|
||
result.put("lockQty", rs.getInt("lock_qty"));
|
||
result.put("availableQty", availableQty);
|
||
|
||
log.info("查询到商品库存: sku_id={}, qty={}, order_lock={}, lock_qty={}, available={}",
|
||
barcode, rs.getInt("qty"), rs.getInt("order_lock"), rs.getInt("lock_qty"), availableQty);
|
||
} else {
|
||
log.info("未找到商品库存信息: sku_id={}", barcode);
|
||
}
|
||
|
||
} catch (SQLException e) {
|
||
log.error("查询库存失败: sku_id={}, error={}", barcode, e.getMessage());
|
||
throw new BusinessException("查询库存失败: " + e.getMessage());
|
||
} finally {
|
||
try {
|
||
if (rs != null) rs.close();
|
||
if (pstmt != null) pstmt.close();
|
||
} catch (SQLException e) {
|
||
log.error("关闭资源失败", e);
|
||
}
|
||
closeConnection(conn);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 检查库存是否足够(库存大于1才能发布任务)
|
||
* @param barcode 商品条码
|
||
* @return 检查结果
|
||
*/
|
||
public Map<String, Object> checkInventoryForTask(String barcode) {
|
||
Map<String, Object> inventoryResult = checkInventory(barcode);
|
||
Map<String, Object> result = new HashMap<>(inventoryResult);
|
||
|
||
boolean found = (boolean) inventoryResult.get("found");
|
||
int availableQty = found ? (int) inventoryResult.getOrDefault("availableQty", 0) : 0;
|
||
|
||
// 库存大于1才允许发布
|
||
boolean canPublish = found && availableQty > 1;
|
||
result.put("canPublish", canPublish);
|
||
|
||
if (!found) {
|
||
result.put("message", "未找到该商品库存信息,请先申请样品");
|
||
} else if (availableQty <= 1) {
|
||
result.put("message", "商品库存不足(可用库存: " + availableQty + "),请先申请样品");
|
||
} else {
|
||
result.put("message", "库存充足(可用库存: " + availableQty + "),可以发布任务");
|
||
}
|
||
|
||
return result;
|
||
}
|
||
}
|
||
|