feat: 添加商品数据初始化类和CORS配置优化
添加商品数据初始化类ProductDataInitializer,用于系统启动时创建初始商品分类和商品信息 优化CORS配置,从配置文件中读取跨域设置,提高灵活性 新增DTO类ProductsDataList和UserDataList 更新开发和生产环境的配置文件,添加CORS相关配置
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
5
src/main/java/com/qf/backend/dto/ProductsDataList.java
Normal file
5
src/main/java/com/qf/backend/dto/ProductsDataList.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.qf.backend.dto;
|
||||
|
||||
public class ProductsDataList {
|
||||
|
||||
}
|
||||
9
src/main/java/com/qf/backend/dto/UserDataList.java
Normal file
9
src/main/java/com/qf/backend/dto/UserDataList.java
Normal 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;
|
||||
}
|
||||
152
src/main/java/com/qf/backend/inti/ProductDataInitializer.java
Normal file
152
src/main/java/com/qf/backend/inti/ProductDataInitializer.java
Normal 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("商品信息初始化完成");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user