refactor(category): 统一分类名称字段从typename改为categoryname

fix(security): 添加CORS过滤器到安全配置最前面
fix(prod): 修改生产环境JPA配置为create模式
feat(admin): 添加管理员账户初始化功能
test: 删除无用的测试类
This commit is contained in:
qingfeng1121
2026-01-08 11:01:11 +08:00
parent fe3bff2642
commit 8a84ae7d9f
11 changed files with 95 additions and 46 deletions

View File

@@ -0,0 +1,57 @@
package com.qf.myafterprojecy.config;
import com.qf.myafterprojecy.pojo.Users;
import com.qf.myafterprojecy.repository.UsersRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* 管理员用户初始化器
* 在应用启动时检查是否存在管理员账户,如果不存在则创建
*/
@Component
public class AdminUserInitializer implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AdminUserInitializer.class);
@Autowired
private UsersRepository usersRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void run(String... args) throws Exception {
String adminUsername = "qf1121";
logger.info("开始执行管理员账户初始化...");
// 检查管理员账户是否已存在
if (!usersRepository.existsByUsername(adminUsername)) {
logger.info("管理员账户不存在,开始创建...");
// 创建管理员用户
Users adminUser = new Users();
adminUser.setUsername(adminUsername);
adminUser.setPassword(passwordEncoder.encode(adminUsername)); // 密码与用户名相同
adminUser.setEmail(adminUsername + "@example.com");
adminUser.setPhone("13800138000");
adminUser.setRole(1); // 1 表示管理员角色
adminUser.setCreateTime(LocalDateTime.now());
// 保存管理员用户
usersRepository.save(adminUser);
logger.info("管理员账户创建成功: {}", adminUsername);
} else {
logger.info("管理员账户已存在,跳过创建");
}
logger.info("管理员账户初始化完成");
}
}

View File

@@ -61,8 +61,6 @@ public class CorsConfig {
config.addExposedHeader("Content-Type"); config.addExposedHeader("Content-Type");
config.addExposedHeader("X-Requested-With"); config.addExposedHeader("X-Requested-With");
config.addExposedHeader("Accept"); config.addExposedHeader("Accept");
config.addExposedHeader("Access-Control-Allow-Origin");
config.addExposedHeader("Access-Control-Allow-Credentials");
config.addExposedHeader("X-Total-Count"); // 分页常用 config.addExposedHeader("X-Total-Count"); // 分页常用
config.addExposedHeader("Link"); // HATEOAS 常用 config.addExposedHeader("Link"); // HATEOAS 常用
// 设置预检请求的有效期(秒),从配置文件读取 // 设置预检请求的有效期(秒),从配置文件读取

View File

@@ -13,6 +13,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
/** /**
@@ -28,6 +29,9 @@ public class SecurityConfig {
@Autowired @Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter; private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private CorsFilter corsFilter;
/** /**
* 配置AuthenticationManager Bean * 配置AuthenticationManager Bean
* 使用AuthenticationConfiguration来获取认证管理器这是更现代的方式 * 使用AuthenticationConfiguration来获取认证管理器这是更现代的方式
@@ -81,6 +85,9 @@ public class SecurityConfig {
response.getWriter().write("{\"message\": \"未授权访问,请先登录\"}"); response.getWriter().write("{\"message\": \"未授权访问,请先登录\"}");
}); });
// 添加CORS过滤器到最前面确保CORS配置能够正确应用到所有请求
http.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class);
// 添加JWT认证过滤器 // 添加JWT认证过滤器
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

View File

@@ -68,7 +68,7 @@ public class CategoryController {
@PostMapping @PostMapping
@PreAuthorize("hasRole('ADMIN')") @PreAuthorize("hasRole('ADMIN')")
public ResponseMessage<Category> createCategory(@Valid @RequestBody CategoryDto categoryDto) { public ResponseMessage<Category> createCategory(@Valid @RequestBody CategoryDto categoryDto) {
log.info("接收创建分类的请求: {}", categoryDto.getTypename()); log.info("接收创建分类的请求: {}", categoryDto.getcategoryname());
return categoryService.saveCategory(categoryDto); return categoryService.saveCategory(categoryDto);
} }
@@ -83,7 +83,7 @@ public class CategoryController {
public ResponseMessage<Category> updateCategory( public ResponseMessage<Category> updateCategory(
@PathVariable Integer id, @PathVariable Integer id,
@Valid @RequestBody CategoryDto categoryDto) { @Valid @RequestBody CategoryDto categoryDto) {
log.info("接收更新分类的请求: ID={}, 分类名称={}", id, categoryDto.getTypename()); log.info("接收更新分类的请求: ID={}, 分类名称={}", id, categoryDto.getcategoryname());
return categoryService.updateCategory(id, categoryDto); return categoryService.updateCategory(id, categoryDto);
} }
@@ -101,12 +101,12 @@ public class CategoryController {
/** /**
* 根据分类名称搜索分类 * 根据分类名称搜索分类
* @param typename 分类名称 * @param categoryname 分类名称
* @return 返回符合条件的分类列表 * @return 返回符合条件的分类列表
*/ */
@GetMapping("/search") @GetMapping("/search")
public ResponseMessage<List<Category>> searchCategoriesByTypename(@RequestParam String typename) { public ResponseMessage<List<Category>> searchCategoriesBycategoryname(@RequestParam String categoryname) {
log.info("接收根据名称搜索分类的请求: {}", typename); log.info("接收根据名称搜索分类的请求: {}", categoryname);
return categoryService.searchCategoriesByTypename(typename); return categoryService.searchCategoriesBycategoryname(categoryname);
} }
} }

View File

@@ -13,8 +13,8 @@ public class Category {
private Integer categoryid; private Integer categoryid;
@NotBlank(message = "分类名称不能为空") @NotBlank(message = "分类名称不能为空")
@Column(name = "typename") @Column(name = "categoryname")
private String typename; private String categoryname;
@Column(name = "description") @Column(name = "description")
private String description; private String description;
@@ -34,12 +34,12 @@ public class Category {
this.categoryid = categoryid; this.categoryid = categoryid;
} }
public String getTypename() { public String getCategoryname() {
return typename; return categoryname;
} }
public void setTypename(String typename) { public void setCategoryname(String categoryname) {
this.typename = typename; this.categoryname = categoryname;
} }
public String getDescription() { public String getDescription() {

View File

@@ -7,7 +7,7 @@ public class CategoryDto {
private Integer Categoryid; private Integer Categoryid;
@NotBlank(message = "分类名称不能为空") @NotBlank(message = "分类名称不能为空")
private String typename; private String categoryname;
private String description; private String description;
@@ -24,12 +24,12 @@ public class CategoryDto {
this.Categoryid = Categoryid; this.Categoryid = Categoryid;
} }
public String getTypename() { public String getcategoryname() {
return typename; return categoryname;
} }
public void setTypename(String typename) { public void setcategoryname(String categoryname) {
this.typename = typename; this.categoryname = categoryname;
} }
public String getDescription() { public String getDescription() {

View File

@@ -11,16 +11,16 @@ public interface CategoryRepository extends JpaRepository<Category, Integer> {
/** /**
* 根据分类名称查询分类信息 * 根据分类名称查询分类信息
* @param typename 分类名称 * @param categoryname 分类名称
* @return 返回符合条件的分类列表 * @return 返回符合条件的分类列表
*/ */
List<Category> findByTypenameContaining(String typename); List<Category> findBycategorynameContaining(String categoryname);
/** /**
* 检查分类名称是否存在 * 检查分类名称是否存在
* @param typename 分类名称 * @param categoryname 分类名称
* @return 返回是否存在 * @return 返回是否存在
*/ */
boolean existsByTypename(String typename); boolean existsBycategoryname(String categoryname);
} }

View File

@@ -49,8 +49,8 @@ public interface ICategoryService {
/** /**
* 根据分类名称搜索分类 * 根据分类名称搜索分类
* @param typename 分类名称 * @param categoryname 分类名称
* @return 返回符合条件的分类列表 * @return 返回符合条件的分类列表
*/ */
ResponseMessage<List<Category>> searchCategoriesByTypename(String typename); ResponseMessage<List<Category>> searchCategoriesBycategoryname(String categoryname);
} }

View File

@@ -75,7 +75,7 @@ public class CategoryService implements ICategoryService {
public ResponseMessage<Category> saveCategory(CategoryDto categoryDto) { public ResponseMessage<Category> saveCategory(CategoryDto categoryDto) {
try { try {
// 检查分类名称是否已存在 // 检查分类名称是否已存在
if (categoryRepository.existsByTypename(categoryDto.getTypename())) { if (categoryRepository.existsBycategoryname(categoryDto.getcategoryname())) {
return ResponseMessage.badRequest( "分类名称已存在"); return ResponseMessage.badRequest( "分类名称已存在");
} }
@@ -104,8 +104,8 @@ public class CategoryService implements ICategoryService {
.orElseThrow(() -> new RuntimeException("分类不存在")); .orElseThrow(() -> new RuntimeException("分类不存在"));
// 如果修改了分类名称,检查新名称是否已存在 // 如果修改了分类名称,检查新名称是否已存在
if (!category.getTypename().equals(categoryDto.getTypename()) && if (!category.getCategoryname().equals(categoryDto.getcategoryname()) &&
categoryRepository.existsByTypename(categoryDto.getTypename())) { categoryRepository.existsBycategoryname(categoryDto.getcategoryname())) {
return ResponseMessage.badRequest("分类名称已存在"); return ResponseMessage.badRequest("分类名称已存在");
} }
@@ -150,13 +150,13 @@ public class CategoryService implements ICategoryService {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseMessage<List<Category>> searchCategoriesByTypename(String typename) { public ResponseMessage<List<Category>> searchCategoriesBycategoryname(String categoryname) {
try { try {
if (typename == null || typename.trim().isEmpty()) { if (categoryname == null || categoryname.trim().isEmpty()) {
return ResponseMessage.badRequest("分类名称不能为空"); return ResponseMessage.badRequest("分类名称不能为空");
} }
List<Category> categories = categoryRepository.findByTypenameContaining(typename); List<Category> categories = categoryRepository.findBycategorynameContaining(categoryname);
return ResponseMessage.success(categories, "搜索分类成功"); return ResponseMessage.success(categories, "搜索分类成功");
} catch (DataAccessException e) { } catch (DataAccessException e) {
log.error("搜索分类失败: {}", e.getMessage()); log.error("搜索分类失败: {}", e.getMessage());
@@ -189,7 +189,7 @@ public class CategoryService implements ICategoryService {
private CategoryTreeDto buildCategoryTreeNode(Category category) { private CategoryTreeDto buildCategoryTreeNode(Category category) {
CategoryTreeDto node = new CategoryTreeDto(); CategoryTreeDto node = new CategoryTreeDto();
node.setId(category.getCategoryid()); node.setId(category.getCategoryid());
node.setName(category.getTypename()); node.setName(category.getCategoryname());
List<Categoryattribute> categoryAttributes = categoryAttributeRepository.findByCategoryId(category.getCategoryid()); List<Categoryattribute> categoryAttributes = categoryAttributeRepository.findByCategoryId(category.getCategoryid());
List<CategoryAttributeDto> categoryAttributeDtos = categoryAttributes.stream() List<CategoryAttributeDto> categoryAttributeDtos = categoryAttributes.stream()
.map(attr -> { .map(attr -> {

View File

@@ -23,7 +23,7 @@ spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.pool-name=WebProjectHikariCP spring.datasource.hikari.pool-name=WebProjectHikariCP
# JPA配置生产环境禁用自动DDL避免意外修改表结构 # JPA配置生产环境禁用自动DDL避免意外修改表结构
spring.jpa.hibernate.ddl-auto=none spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=false spring.jpa.show-sql=false
spring.jpa.properties.hibernate.format_sql=false spring.jpa.properties.hibernate.format_sql=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,13 +0,0 @@
package com.qf.myafterprojecy;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MyAfterProjecyApplicationTests {
@Test
void contextLoads() {
}
}