From b32111b52e6c0b08bbdde2a5dd747d6fe3489e3d Mon Sep 17 00:00:00 2001 From: qingfeng1121 Date: Thu, 8 Jan 2026 16:13:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=95=86=E5=93=81?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=88=9D=E5=A7=8B=E5=8C=96=E7=B1=BB=E5=92=8C?= =?UTF-8?q?CORS=E9=85=8D=E7=BD=AE=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加商品数据初始化类ProductDataInitializer,用于系统启动时创建初始商品分类和商品信息 优化CORS配置,从配置文件中读取跨域设置,提高灵活性 新增DTO类ProductsDataList和UserDataList 更新开发和生产环境的配置文件,添加CORS相关配置 --- .../com/qf/backend/config/CorsConfig.java | 54 +++++-- .../com/qf/backend/dto/ProductsDataList.java | 5 + .../java/com/qf/backend/dto/UserDataList.java | 9 ++ .../backend/inti/ProductDataInitializer.java | 152 ++++++++++++++++++ src/main/resources/application-dev.properties | 7 +- .../resources/application-prod.properties | 11 +- 6 files changed, 218 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/qf/backend/dto/ProductsDataList.java create mode 100644 src/main/java/com/qf/backend/dto/UserDataList.java create mode 100644 src/main/java/com/qf/backend/inti/ProductDataInitializer.java diff --git a/src/main/java/com/qf/backend/config/CorsConfig.java b/src/main/java/com/qf/backend/config/CorsConfig.java index 71cf70c..ef59ea2 100644 --- a/src/main/java/com/qf/backend/config/CorsConfig.java +++ b/src/main/java/com/qf/backend/config/CorsConfig.java @@ -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("*"); - // 允许携带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("*"); - + // 允许的来源,从配置中分割 + String[] originStrings = allowedOrigins.split(","); + for (String origin : originStrings) { + configuration.addAllowedOriginPattern(origin.trim()); + } + //允许携带cookie + 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(); diff --git a/src/main/java/com/qf/backend/dto/ProductsDataList.java b/src/main/java/com/qf/backend/dto/ProductsDataList.java new file mode 100644 index 0000000..6f7a90c --- /dev/null +++ b/src/main/java/com/qf/backend/dto/ProductsDataList.java @@ -0,0 +1,5 @@ +package com.qf.backend.dto; + +public class ProductsDataList { + +} diff --git a/src/main/java/com/qf/backend/dto/UserDataList.java b/src/main/java/com/qf/backend/dto/UserDataList.java new file mode 100644 index 0000000..d0efe01 --- /dev/null +++ b/src/main/java/com/qf/backend/dto/UserDataList.java @@ -0,0 +1,9 @@ +package com.qf.backend.dto; + +import java.util.List; + +import com.qf.backend.entity.Users; + +public class UserDataList { + private List userDataList; +} diff --git a/src/main/java/com/qf/backend/inti/ProductDataInitializer.java b/src/main/java/com/qf/backend/inti/ProductDataInitializer.java new file mode 100644 index 0000000..b834533 --- /dev/null +++ b/src/main/java/com/qf/backend/inti/ProductDataInitializer.java @@ -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 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 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("商品信息初始化完成"); + } +} \ No newline at end of file diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index da43b5f..63c95bb 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,4 +1,9 @@ # JWT 配置 - 开发用(方便调试) jwt.secret=your_very_strong_secret_key_that_is_at_least_32_characters_long! jwt.expiration=3600000 -jwt.token-prefix=Bearer \ No newline at end of file +jwt.token-prefix=Bearer +# CORS 配置 - 开发用(允许所有来源) +cors.allowed-origins=* +cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS,PATCH +cors.allowed-headers=* +cors.exposed-headers=Authorization \ No newline at end of file diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index c0fc115..79a023d 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -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} \ No newline at end of file +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