refactor(config): 重构数据源配置并优化产品请求DTO

- 移除旧的application.properties和application.yml配置文件
- 新增Druid数据源配置类,支持主从数据源手动配置
- 调整CreateProductRequestDTO中size字段的长度限制从200到500
- 更新size字段注释,明确JSON格式示例
- 修复因配置加载方式变更引起的应用启动异常问题
This commit is contained in:
2025-12-22 13:10:51 +08:00
parent 014cf4626b
commit f0e78c0814
19 changed files with 3014 additions and 750 deletions

View File

@@ -2,8 +2,9 @@ package com.mtkj.mtpay.config;
import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@@ -16,19 +17,74 @@ import javax.sql.DataSource;
*/
@Slf4j
@Configuration
@EnableConfigurationProperties({DruidMasterProperties.class, DruidSlaveProperties.class})
public class DruidDataSourceConfig {
@Autowired
private DruidMasterProperties masterProperties;
/**
* 主数据源配置
* 使用@Primary注解确保这是默认数据源
*/
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
public DataSource masterDataSource() {
log.info("初始化Druid主数据源");
log.info("配置属性 - URL: {}, Username: {}", masterProperties.getUrl(), masterProperties.getUsername());
if (masterProperties.getUrl() == null || masterProperties.getUrl().isEmpty()) {
log.error("数据源URL未配置请检查 application-dev.yml 中的 spring.datasource.druid.master.url 配置");
throw new IllegalStateException("数据源URL未配置");
}
DruidDataSource dataSource = new DruidDataSource();
log.info("Druid主数据源配置完成");
// 手动设置配置属性
dataSource.setUrl(masterProperties.getUrl());
dataSource.setUsername(masterProperties.getUsername());
dataSource.setPassword(masterProperties.getPassword());
if (masterProperties.getInitialSize() != null) {
dataSource.setInitialSize(masterProperties.getInitialSize());
}
if (masterProperties.getMinIdle() != null) {
dataSource.setMinIdle(masterProperties.getMinIdle());
}
if (masterProperties.getMaxActive() != null) {
dataSource.setMaxActive(masterProperties.getMaxActive());
}
if (masterProperties.getMaxWait() != null) {
dataSource.setMaxWait(masterProperties.getMaxWait());
}
if (masterProperties.getConnectTimeout() != null) {
dataSource.setConnectTimeout(masterProperties.getConnectTimeout());
}
if (masterProperties.getSocketTimeout() != null) {
dataSource.setSocketTimeout(masterProperties.getSocketTimeout());
}
if (masterProperties.getTimeBetweenEvictionRunsMillis() != null) {
dataSource.setTimeBetweenEvictionRunsMillis(masterProperties.getTimeBetweenEvictionRunsMillis());
}
if (masterProperties.getMinEvictableIdleTimeMillis() != null) {
dataSource.setMinEvictableIdleTimeMillis(masterProperties.getMinEvictableIdleTimeMillis());
}
if (masterProperties.getMaxEvictableIdleTimeMillis() != null) {
dataSource.setMaxEvictableIdleTimeMillis(masterProperties.getMaxEvictableIdleTimeMillis());
}
if (masterProperties.getValidationQuery() != null) {
dataSource.setValidationQuery(masterProperties.getValidationQuery());
}
if (masterProperties.getTestWhileIdle() != null) {
dataSource.setTestWhileIdle(masterProperties.getTestWhileIdle());
}
if (masterProperties.getTestOnBorrow() != null) {
dataSource.setTestOnBorrow(masterProperties.getTestOnBorrow());
}
if (masterProperties.getTestOnReturn() != null) {
dataSource.setTestOnReturn(masterProperties.getTestOnReturn());
}
log.info("Druid主数据源配置完成URL: {}", dataSource.getUrl());
return dataSource;
}
@@ -38,10 +94,54 @@ public class DruidDataSourceConfig {
*/
@Bean(name = "slaveDataSource")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
@ConfigurationProperties(prefix = "spring.datasource.druid.slave")
public DataSource slaveDataSource() {
public DataSource slaveDataSource(@Autowired DruidSlaveProperties slaveProperties) {
log.info("初始化Druid从数据源");
DruidDataSource dataSource = new DruidDataSource();
// 手动设置配置属性
dataSource.setUrl(slaveProperties.getUrl());
dataSource.setUsername(slaveProperties.getUsername());
dataSource.setPassword(slaveProperties.getPassword());
if (slaveProperties.getInitialSize() != null) {
dataSource.setInitialSize(slaveProperties.getInitialSize());
}
if (slaveProperties.getMinIdle() != null) {
dataSource.setMinIdle(slaveProperties.getMinIdle());
}
if (slaveProperties.getMaxActive() != null) {
dataSource.setMaxActive(slaveProperties.getMaxActive());
}
if (slaveProperties.getMaxWait() != null) {
dataSource.setMaxWait(slaveProperties.getMaxWait());
}
if (slaveProperties.getConnectTimeout() != null) {
dataSource.setConnectTimeout(slaveProperties.getConnectTimeout());
}
if (slaveProperties.getSocketTimeout() != null) {
dataSource.setSocketTimeout(slaveProperties.getSocketTimeout());
}
if (slaveProperties.getTimeBetweenEvictionRunsMillis() != null) {
dataSource.setTimeBetweenEvictionRunsMillis(slaveProperties.getTimeBetweenEvictionRunsMillis());
}
if (slaveProperties.getMinEvictableIdleTimeMillis() != null) {
dataSource.setMinEvictableIdleTimeMillis(slaveProperties.getMinEvictableIdleTimeMillis());
}
if (slaveProperties.getMaxEvictableIdleTimeMillis() != null) {
dataSource.setMaxEvictableIdleTimeMillis(slaveProperties.getMaxEvictableIdleTimeMillis());
}
if (slaveProperties.getValidationQuery() != null) {
dataSource.setValidationQuery(slaveProperties.getValidationQuery());
}
if (slaveProperties.getTestWhileIdle() != null) {
dataSource.setTestWhileIdle(slaveProperties.getTestWhileIdle());
}
if (slaveProperties.getTestOnBorrow() != null) {
dataSource.setTestOnBorrow(slaveProperties.getTestOnBorrow());
}
if (slaveProperties.getTestOnReturn() != null) {
dataSource.setTestOnReturn(slaveProperties.getTestOnReturn());
}
log.info("Druid从数据源配置完成");
return dataSource;
}

View File

@@ -40,7 +40,7 @@ public class ProductController {
}
/**
* 获取商品详情
* 获取商品详情通过商品ID
*/
@GetMapping("/{id}")
public Result<ProductResponseDTO> getProduct(@PathVariable Long id) {
@@ -49,6 +49,24 @@ public class ProductController {
return Result.success(product);
}
/**
* 根据链接码获取商品详情(用于通过短链接访问商品)
*/
@GetMapping("/link/{linkCode}")
public Result<ProductResponseDTO> getProductByLinkCode(@PathVariable String linkCode) {
log.info("根据链接码获取商品详情,链接码:{}", linkCode);
try {
// 根据链接码获取商品ID
Long productId = productService.getProductIdByLinkCode(linkCode);
// 获取商品详情
ProductResponseDTO product = productService.getProductById(productId);
return Result.success(product);
} catch (Exception e) {
log.error("根据链接码获取商品详情失败,链接码:{}", linkCode, e);
return Result.fail("链接无效或已过期");
}
}
/**
* 获取商品详情页URL
*/

View File

@@ -108,9 +108,9 @@ public class CreateProductRequestDTO implements Serializable {
private BigDecimal weight;
/**
* 大小/尺寸JSON格式
* 大小/尺寸JSON格式,如:{"length":30,"width":30,"height":30,"unit":"cm"}
*/
@Size(max = 200, message = "尺寸JSON长度不能超过200")
@Size(max = 500, message = "尺寸JSON长度不能超过500")
private String size;
/**

View File

@@ -32,9 +32,10 @@ public class MtProduct {
private BigDecimal price;
/**
* 主图URL最大4000字符)
* 主图URL支持JSON数组格式存储多张主图["url1","url2"]或单个URL字符
* 数据库字段类型TEXT
*/
@TableField(value = "main_image", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
@TableField(value = "main_image", jdbcType = org.apache.ibatis.type.JdbcType.LONGVARCHAR)
private String mainImage;
/**

View File

@@ -68,7 +68,8 @@ public class MtProductSku {
private BigDecimal weight;
/**
* 大小/尺寸JSON格式{"length":10,"width":5,"height":3},单位:厘米)
* 大小/尺寸JSON格式{"length":30,"width":30,"height":30,"unit":"cm"},单位:厘米)
* 数据库字段类型VARCHAR(500)
*/
@TableField(value = "size", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String size;

View File

@@ -9,7 +9,7 @@ import java.time.LocalDateTime;
/**
* 支付订单实体
*/
@TableName(value = "payment_order", resultMap = "BaseResultMap")
@TableName(value = "payment_order")
@Data
public class PaymentOrder {

View File

@@ -28,5 +28,12 @@ public interface ProductService {
* @return 商品详情页URL
*/
String getProductUrl(Long id);
/**
* 根据链接码获取商品ID用于前端通过链接码访问商品详情页
* @param linkCode 链接码
* @return 商品ID
*/
Long getProductIdByLinkCode(String linkCode);
}

View File

@@ -42,6 +42,9 @@ public class ProductServiceImpl implements ProductService {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private com.mtkj.mtpay.service.ProductLinkService productLinkService;
@Value("${server.port:8082}")
private String serverPort;
@@ -67,9 +70,10 @@ public class ProductServiceImpl implements ProductService {
product.setPrice(request.getPrice());
// 处理主图优先使用mainImages多图如果没有则使用mainImage单图兼容旧版本
// 前端会同时发送mainImage和mainImages优先使用mainImages
String mainImageValue = null;
if (request.getMainImages() != null && !request.getMainImages().isEmpty()) {
// 多个主图转换为JSON数组存储
// 多个主图转换为JSON数组存储到数据库
try {
mainImageValue = objectMapper.writeValueAsString(request.getMainImages());
log.debug("商品主图(多图): {}", mainImageValue);
@@ -78,7 +82,7 @@ public class ProductServiceImpl implements ProductService {
throw new BusinessException(ResultCode.SYSTEM_ERROR, "主图数据格式错误");
}
} else if (StringUtils.hasText(request.getMainImage())) {
// 单个主图,兼容旧版本
// 单个主图,兼容旧版本如果没有mainImages但有mainImage
mainImageValue = request.getMainImage();
log.debug("商品主图(单图): {}", mainImageValue);
}
@@ -121,6 +125,16 @@ public class ProductServiceImpl implements ProductService {
}
}
// 创建商品链接自动生成有效期90天
try {
com.mtkj.mtpay.entity.MtProductLink productLink = productLinkService.createOrGetProductLink(product.getId(), 90);
log.info("商品链接创建成功商品ID: {}, 链接码: {}, URL: {}",
product.getId(), productLink.getLinkCode(), productLink.getFullUrl());
} catch (Exception e) {
log.error("创建商品链接失败商品ID: {}", product.getId(), e);
// 链接创建失败不影响商品创建,只记录日志
}
log.info("商品创建成功商品ID: {}, 商品名称: {}, SKU数量: {}",
product.getId(), product.getName(),
request.getSkus() != null ? request.getSkus().size() : 0);
@@ -205,11 +219,31 @@ public class ProductServiceImpl implements ProductService {
throw new BusinessException(ResultCode.DATA_NOT_FOUND, "商品不存在");
}
// 构建商品详情页URL使用前端地址
// 格式http://前端地址/product/{id}
String productUrl = frontendUrl + "/product/" + id;
log.info("生成商品URL成功商品ID: {}, URL: {}", id, productUrl);
return productUrl;
// 创建或获取商品链接有效期90天
com.mtkj.mtpay.entity.MtProductLink productLink = productLinkService.createOrGetProductLink(id, 90);
log.info("获取商品URL成功商品ID: {}, 链接码: {}, URL: {}",
id, productLink.getLinkCode(), productLink.getFullUrl());
return productLink.getFullUrl();
}
/**
* 根据链接码获取商品ID用于前端通过链接码访问商品详情页
* @param linkCode 链接码
* @return 商品ID
*/
public Long getProductIdByLinkCode(String linkCode) {
log.debug("根据链接码获取商品ID链接码: {}", linkCode);
Long productId = productLinkService.getProductIdByLinkCode(linkCode);
if (productId == null) {
log.warn("链接无效或已过期,链接码: {}", linkCode);
throw new BusinessException(ResultCode.DATA_NOT_FOUND, "链接无效或已过期");
}
log.debug("根据链接码获取商品ID成功链接码: {}, 商品ID: {}", linkCode, productId);
return productId;
}
}