refactor(config): 重构数据源配置并优化产品请求DTO
- 移除旧的application.properties和application.yml配置文件 - 新增Druid数据源配置类,支持主从数据源手动配置 - 调整CreateProductRequestDTO中size字段的长度限制从200到500 - 更新size字段注释,明确JSON格式示例 - 修复因配置加载方式变更引起的应用启动异常问题
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.time.LocalDateTime;
|
||||
/**
|
||||
* 支付订单实体
|
||||
*/
|
||||
@TableName(value = "payment_order", resultMap = "BaseResultMap")
|
||||
@TableName(value = "payment_order")
|
||||
@Data
|
||||
public class PaymentOrder {
|
||||
|
||||
|
||||
@@ -28,5 +28,12 @@ public interface ProductService {
|
||||
* @return 商品详情页URL
|
||||
*/
|
||||
String getProductUrl(Long id);
|
||||
|
||||
/**
|
||||
* 根据链接码获取商品ID(用于前端通过链接码访问商品详情页)
|
||||
* @param linkCode 链接码
|
||||
* @return 商品ID
|
||||
*/
|
||||
Long getProductIdByLinkCode(String linkCode);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user