一、系统架构设计
1. 整体架构
- 前端层:Web端(Vue/React)+移动端(小程序/APP)
- 服务层:Spring Cloud微服务架构
- 数据层:MySQL(主数据)+Redis(缓存)+Elasticsearch(搜索)
- 基础设施:Docker容器化部署+K8s集群管理
2. 商品分类服务模块
```
com.meicai.goods
├── category-service 分类核心服务
│ ├── controller 接口层
│ ├── service 业务逻辑
│ ├── repository 数据访问
│ └── config 配置类
├── category-api 分类对外接口
└── category-client 分类Feign客户端
```
二、核心功能实现
1. 分类数据模型设计
```java
// 分类实体类
@Entity
@Table(name = "goods_category")
public class GoodsCategory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name; // 分类名称
private String code; // 分类编码
private Integer level; // 分类层级(1-4级)
private Long parentId; // 父分类ID
private String iconUrl; // 分类图标
private Integer sortOrder; // 排序字段
private Boolean isActive; // 是否启用
private String path; // 分类路径(如:1,2,3)
// getters & setters
}
```
2. 分类树结构实现
递归查询实现
```java
@Service
public class CategoryServiceImpl implements CategoryService {
@Autowired
private CategoryRepository categoryRepository;
@Override
public List
getCategoryTree(Long parentId) {
List categories = categoryRepository.findByParentIdAndIsActive(
parentId != null ? parentId : 0L, true);
return categories.stream().map(category -> {
CategoryTreeDTO treeNode = new CategoryTreeDTO();
BeanUtils.copyProperties(category, treeNode);
// 递归查询子分类
List children = getCategoryTree(category.getId());
if (!children.isEmpty()) {
treeNode.setChildren(children);
}
return treeNode;
}).collect(Collectors.toList());
}
}
```
缓存优化版本
```java
@Override
public List getCategoryTreeWithCache(Long parentId) {
String cacheKey = "category:tree:" + (parentId != null ? parentId : "root");
// 先从缓存获取
String cachedJson = redisTemplate.opsForValue().get(cacheKey);
if (StringUtils.isNotBlank(cachedJson)) {
return JSON.parseArray(cachedJson, CategoryTreeDTO.class);
}
// 缓存不存在则查询数据库
List tree = buildCategoryTree(parentId);
// 存入缓存,设置过期时间
redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(tree),
1, TimeUnit.HOURS);
return tree;
}
```
3. 分类管理API接口
```java
@RestController
@RequestMapping("/api/categories")
public class CategoryController {
@Autowired
private CategoryService categoryService;
// 获取分类树
@GetMapping("/tree")
public Result> getCategoryTree(
@RequestParam(required = false) Long parentId) {
return Result.success(categoryService.getCategoryTree(parentId));
}
// 添加分类
@PostMapping
public Result addCategory(@RequestBody @Valid CategoryAddDTO dto) {
categoryService.addCategory(dto);
return Result.success();
}
// 更新分类
@PutMapping("/{id}")
public Result updateCategory(
@PathVariable Long id,
@RequestBody @Valid CategoryUpdateDTO dto) {
categoryService.updateCategory(id, dto);
return Result.success();
}
// 删除分类(逻辑删除)
@DeleteMapping("/{id}")
public Result deleteCategory(@PathVariable Long id) {
categoryService.deleteCategory(id);
return Result.success();
}
}
```
三、关键业务逻辑实现
1. 分类添加验证逻辑
```java
@Override
public void addCategory(CategoryAddDTO dto) {
// 验证分类名称是否重复
if (categoryRepository.existsByNameAndParentId(dto.getName(), dto.getParentId())) {
throw new BusinessException("同级分类下名称已存在");
}
// 验证父分类是否存在
if (dto.getParentId() != null &&
!categoryRepository.existsById(dto.getParentId())) {
throw new BusinessException("父分类不存在");
}
// 构建分类路径
String path = buildCategoryPath(dto.getParentId());
// 保存分类
GoodsCategory category = new GoodsCategory();
BeanUtils.copyProperties(dto, category);
category.setPath(path);
categoryRepository.save(category);
// 清除相关缓存
clearCategoryCache(category.getParentId());
}
private String buildCategoryPath(Long parentId) {
if (parentId == null || parentId == 0) {
return "0";
}
GoodsCategory parent = categoryRepository.findById(parentId)
.orElseThrow(() -> new BusinessException("父分类不存在"));
return parent.getPath() + "," + parentId;
}
```
2. 分类移动逻辑
```java
@Override
@Transactional
public void moveCategory(Long categoryId, Long newParentId) {
// 验证分类是否存在
GoodsCategory category = categoryRepository.findById(categoryId)
.orElseThrow(() -> new BusinessException("分类不存在"));
// 验证新父分类是否存在
if (newParentId != null && !categoryRepository.existsById(newParentId)) {
throw new BusinessException("目标父分类不存在");
}
// 不能移动到自己的子分类下
if (isDescendant(categoryId, newParentId)) {
throw new BusinessException("不能移动到自己的子分类下");
}
// 构建新路径
String newPath = buildCategoryPath(newParentId);
// 更新分类路径
category.setParentId(newParentId);
category.setPath(newPath);
categoryRepository.save(category);
// 更新所有子分类路径
updateChildrenPath(categoryId, newPath);
// 清除缓存
clearCategoryCache(categoryId);
if (newParentId != null) {
clearCategoryCache(newParentId);
}
}
private boolean isDescendant(Long parentId, Long childId) {
GoodsCategory category = categoryRepository.findById(childId)
.orElseThrow(() -> new BusinessException("分类不存在"));
String[] pathParts = category.getPath().split(",");
return Arrays.asList(pathParts).contains(parentId.toString());
}
```
四、前端展示实现
1. 分类树组件(Vue示例)
```vue
:data="categoryTree"
node-key="id"
:props="defaultProps"
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
{{ node.label }}
type="text"
size="mini"
@click.stop="handleAdd(data)"
>
添加
type="text"
size="mini"
@click.stop="handleEdit(data)"
>
编辑
type="text"
size="mini"
@click.stop="handleDelete(data)"
>
删除
<script>
export default {
data() {
return {
categoryTree: [],
defaultProps: {
children: children,
label: name
}
}
},
created() {
this.fetchCategoryTree();
},
methods: {
async fetchCategoryTree() {
const { data } = await this.$http.get(/api/categories/tree);
this.categoryTree = data;
},
handleNodeClick(data) {
this.$emit(category-select, data);
},
handleAdd(data) {
this.$prompt(请输入分类名称, 添加分类, {
confirmButtonText: 确定,
cancelButtonText: 取消,
inputPattern: /.+/,
inputErrorMessage: 分类名称不能为空
}).then(({ value }) => {
this.$http.post(/api/categories, {
name: value,
parentId: data.id
}).then(() => {
this.$message.success(添加成功);
this.fetchCategoryTree();
});
});
},
// 其他方法...
}
}
```
五、性能优化方案
1. 缓存策略:
- 使用Redis缓存分类树结构,设置合理的过期时间
- 对热点分类数据采用本地缓存(如Caffeine)
2. 数据库优化:
- 为分类表添加索引:`(parent_id, sort_order)`复合索引
- 使用预加载查询减少N+1问题
3. 异步处理:
- 分类移动等耗时操作采用消息队列异步处理
- 使用Saga模式保证数据一致性
4. 搜索优化:
- 使用Elasticsearch实现分类的快速搜索和模糊匹配
- 实现分类的拼音搜索和别名搜索
六、扩展功能考虑
1. 多级分类权限控制:
- 不同角色可管理的分类层级不同
- 分类数据权限隔离
2. 分类属性管理:
- 不同分类可配置不同的属性模板
- 属性值可配置验证规则
3. 分类关联分析:
- 统计各分类下商品的销售情况
- 分析分类间的关联关系
4. 智能分类建议:
- 基于商品名称自动推荐分类
- 使用NLP技术提高分类准确率
以上方案可根据美菜生鲜的实际业务需求进行调整和扩展,实现高效、稳定的商品分类管理系统。