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 getAllConfigs() { return configMapper.selectList( new LambdaQueryWrapper() .orderByDesc(ThirdPartyDbConfig::getCreateTime) ); } /** * 获取配置详情 */ public ThirdPartyDbConfig getConfigById(Long id) { return configMapper.selectById(id); } /** * 获取启用的配置 */ public ThirdPartyDbConfig getEnabledConfig() { return configMapper.selectOne( new LambdaQueryWrapper() .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 checkInventory(String barcode) { ThirdPartyDbConfig config = getEnabledConfig(); if (config == null) { throw new BusinessException("未配置第三方数据库或配置未启用"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; Map 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 checkInventoryForTask(String barcode) { Map inventoryResult = checkInventory(barcode); Map 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; } }