feat: 添加商品数据初始化类和CORS配置优化

添加商品数据初始化类ProductDataInitializer,用于系统启动时创建初始商品分类和商品信息
优化CORS配置,从配置文件中读取跨域设置,提高灵活性
新增DTO类ProductsDataList和UserDataList
更新开发和生产环境的配置文件,添加CORS相关配置
This commit is contained in:
qingfeng1121
2026-01-08 16:13:50 +08:00
parent c5f631d043
commit b32111b52e
6 changed files with 218 additions and 20 deletions

View File

@@ -1,35 +1,55 @@
package com.qf.backend.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
/**
* 跨域配置
*/
// 从配置文件中读取CORS配置
@Value("${cors.allowed-origins}")
private String allowedOrigins;
@Value("${cors.allowed-methods}")
private String allowedMethods;
@Value("${cors.allowed-headers}")
private String allowedHeaders;
@Value("${cors.allow-credentials}")
private Boolean allowCredentials;
@Value("${cors.max-age}")
private Long maxAge;
@Bean
public CorsFilter corsFilter(){
// 创建跨域配置对象
CorsConfiguration configuration = new CorsConfiguration();
// 允许的来源使用通配符,允许所有来源
configuration.addAllowedOriginPattern("*");
// 允许的来源,从配置中分割
String[] originStrings = allowedOrigins.split(",");
for (String origin : originStrings) {
configuration.addAllowedOriginPattern(origin.trim());
}
//允许携带cookie
configuration.setAllowCredentials(true);
// 明确列出允许的HTTP方法比使用通配符更安全
configuration.addAllowedMethod("GET");
configuration.addAllowedMethod("POST");
configuration.addAllowedMethod("PUT");
configuration.addAllowedMethod("DELETE");
configuration.addAllowedMethod("OPTIONS");
configuration.addAllowedMethod("PATCH");
// 允许所有请求头(新增)
configuration.addAllowedHeader("*");
configuration.setAllowCredentials(allowCredentials);
// 允许的HTTP方法。从配置文件分割提取
String[] methodStrings = allowedMethods.split(",");
for (String method : methodStrings) {
configuration.addAllowedMethod(method.trim());
}
// 允许的请求头。从配置文件分割提取
String[] headerStrings = allowedHeaders.split(",");
for (String header : headerStrings) {
configuration.addAllowedHeader(header.trim());
}
// 明确暴露的响应头对于JWT认证很重要
configuration.addExposedHeader("Authorization");
configuration.addExposedHeader("Content-Type");
@@ -37,7 +57,7 @@ public class CorsConfig {
configuration.addExposedHeader("Accept");
configuration.addExposedHeader("Access-Control-Allow-Origin");
// 设置最大缓存时间为1小时减少预检请求次数
configuration.setMaxAge(3600L);
configuration.setMaxAge(maxAge);
// 创建基于URL的CORS配置源
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

View File

@@ -0,0 +1,5 @@
package com.qf.backend.dto;
public class ProductsDataList {
}

View File

@@ -0,0 +1,9 @@
package com.qf.backend.dto;
import java.util.List;
import com.qf.backend.entity.Users;
public class UserDataList {
private List<Users> userDataList;
}

View File

@@ -0,0 +1,152 @@
package com.qf.backend.inti;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qf.backend.entity.ProductCategories;
import com.qf.backend.entity.Products;
import com.qf.backend.service.ProductCategoriesService;
import com.qf.backend.service.ProductsService;
/**
* 商品数据初始化配置类,用于在系统启动时创建初始商品分类和商品信息
* @author 30803
*/
@Component
public class ProductDataInitializer {
private static final Logger logger = LoggerFactory.getLogger(ProductDataInitializer.class);
@Autowired
private ProductCategoriesService productCategoriesService;
@Autowired
private ProductsService productsService;
/**
* 系统启动时初始化商品数据
*/
// @PostConstruct
public void initProductData() {
logger.info("开始初始化商品数据...");
// 初始化商品分类
initProductCategories();
// 初始化商品信息
initProducts();
logger.info("商品数据初始化完成");
}
/**
* 初始化商品分类
*/
private void initProductCategories() {
logger.info("开始初始化商品分类...");
// 定义初始分类信息
Object[][] categoryInfos = {
// 顶级分类
{"1", "电子产品", "0", 1, "electronics", "electronics-banner.jpg", 1, 1},
{"2", "服装鞋包", "0", 1, "clothing", "clothing-banner.jpg", 2, 1},
{"3", "家居用品", "0", 1, "home", "home-banner.jpg", 3, 1},
// 二级分类 - 电子产品
{"4", "手机数码", "1", 2, "phone", "phone-banner.jpg", 1, 1},
{"5", "电脑办公", "1", 2, "computer", "computer-banner.jpg", 2, 1},
{"6", "家用电器", "1", 2, "appliance", "appliance-banner.jpg", 3, 1},
// 二级分类 - 服装鞋包
{"7", "男装", "2", 2, "men", "men-banner.jpg", 1, 1},
{"8", "女装", "2", 2, "women", "women-banner.jpg", 2, 1},
{"9", "鞋靴", "2", 2, "shoes", "shoes-banner.jpg", 3, 1},
// 三级分类 - 手机数码
{"10", "手机", "4", 3, "mobile", "mobile-banner.jpg", 1, 1},
{"11", "耳机", "4", 3, "headphone", "headphone-banner.jpg", 2, 1},
{"12", "相机", "4", 3, "camera", "camera-banner.jpg", 3, 1},
};
for (Object[] categoryInfo : categoryInfos) {
String categoryName = (String) categoryInfo[1];
Long parentId = Long.parseLong((String) categoryInfo[2]);
// 检查分类是否已存在
QueryWrapper<ProductCategories> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("category_name", categoryName)
.eq("parent_id", parentId);
ProductCategories existingCategory = productCategoriesService.getOne(queryWrapper);
if (existingCategory == null) {
// 创建新分类
ProductCategories category = new ProductCategories();
category.setCategoryName(categoryName);
category.setParentId(parentId);
category.setLevel((Integer) categoryInfo[3]);
category.setIcon((String) categoryInfo[4]);
category.setBanner((String) categoryInfo[5]);
category.setSort((Integer) categoryInfo[6]);
category.setStatus((Integer) categoryInfo[7]);
productCategoriesService.save(category);
logger.info("成功创建商品分类: {}", categoryName);
} else {
logger.info("商品分类 {} 已存在,跳过创建", categoryName);
}
}
logger.info("商品分类初始化完成");
}
/**
* 初始化商品信息
*/
private void initProducts() {
logger.info("开始初始化商品信息...");
// 定义初始商品信息
Object[][] productInfos = {
{"iPhone 16 Pro", 1, 10, "最新款iPhone搭载A18处理器", 8999.00, 7999.00, 0, 1, "iphone16.jpg"},
{"华为 Mate 70 Pro", 1, 10, "华为旗舰手机搭载麒麟9100处理器", 7999.00, 6999.00, 0, 1, "huawei-mate70.jpg"},
{"小米 15 Pro", 1, 10, "小米旗舰手机搭载骁龙8 Gen 4处理器", 5999.00, 4999.00, 0, 1, "xiaomi-15.jpg"},
{"MacBook Pro 14", 1, 5, "苹果笔记本M3 Pro芯片", 14999.00, 13999.00, 0, 1, "macbook-pro.jpg"},
{"ThinkPad X1 Carbon", 1, 5, "商务笔记本,高性能低功耗", 12999.00, 11999.00, 0, 1, "thinkpad-x1.jpg"},
{"索尼 WH-1000XM5", 1, 11, "索尼降噪耳机,顶级音质", 2999.00, 2499.00, 0, 1, "sony-wh1000xm5.jpg"},
{"AirPods Pro 2", 1, 11, "苹果降噪耳机,支持空间音频", 1899.00, 1599.00, 0, 1, "airpods-pro.jpg"},
{"男士休闲裤", 1, 7, "舒适透气,适合日常穿着", 299.00, 199.00, 0, 1, "men-pants.jpg"},
{"女士连衣裙", 1, 8, "时尚优雅,适合各种场合", 399.00, 299.00, 0, 1, "women-dress.jpg"},
{"智能手表", 1, 4, "多功能智能手表,健康监测", 1599.00, 1299.00, 0, 1, "smartwatch.jpg"},
};
for (Object[] productInfo : productInfos) {
String productName = (String) productInfo[0];
// 检查商品是否已存在
QueryWrapper<Products> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("product_name", productName);
Products existingProduct = productsService.getOne(queryWrapper);
if (existingProduct == null) {
// 创建新商品
Products product = new Products();
product.setProductName(productName);
product.setShopId(Long.valueOf((Integer) productInfo[1]));
product.setCategoryId(Long.valueOf((Integer) productInfo[2]));
product.setDescription((String) productInfo[3]);
product.setOriginalPrice(new java.math.BigDecimal(Double.toString((Double) productInfo[4])));
product.setCurrentPrice(new java.math.BigDecimal(Double.toString((Double) productInfo[5])));
product.setSalesVolume((Integer) productInfo[6]);
product.setStatus((Integer) productInfo[7]);
product.setMainImage((String) productInfo[8]);
product.setIsDeleted(0);
productsService.save(product);
logger.info("成功创建商品: {}", productName);
} else {
logger.info("商品 {} 已存在,跳过创建", productName);
}
}
logger.info("商品信息初始化完成");
}
}

View File

@@ -2,3 +2,8 @@
jwt.secret=your_very_strong_secret_key_that_is_at_least_32_characters_long!
jwt.expiration=3600000
jwt.token-prefix=Bearer
# CORS 配置 - 开发用(允许所有来源)
cors.allowed-origins=*
cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS,PATCH
cors.allowed-headers=*
cors.exposed-headers=Authorization

View File

@@ -1,4 +1,11 @@
# JWT 配置 - 生产用(敏感信息从环境变量读取)
jwt.secret=${JWT_SECRET}
jwt.secret=${JWT_SECRET:defaultSecret}
jwt.expiration=${JWT_EXPIRATION:3600000}
jwt.token-prefix=${JWT_TOKEN_PREFIX:Bearer}
# CORS 配置 - 生产用(允许所有来源)
cors.allowed-origins=*
cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS,PATCH
cors.allowed-headers=*
cors.exposed-headers=Authorization
cors.allow-credentials=true
cors.max-age=3600