|
|
@ -16,17 +16,30 @@ import java.util.List;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 这个类名为 `CategoryServiceImpl`,它实现了 `ICategoryService` 接口,是品类相关业务逻辑的具体实现类。
|
|
|
|
|
|
|
|
* 主要负责处理与品类操作相关的各种业务功能,例如获取品类信息、添加品类、更新品类名称、递归获取品类及其子节点信息以及获取品类详细信息等,
|
|
|
|
|
|
|
|
* 通过调用 `CategoryMapper` 接口提供的数据库操作方法与数据库进行交互,并根据业务规则进行相应的逻辑处理,最终返回合适的响应给调用方。
|
|
|
|
|
|
|
|
* 同时,它使用了Spring框架的 `@Service` 注解将自身注册为一个服务层组件,方便在其他地方进行依赖注入使用,并且使用 `@Slf4j` 注解来引入日志记录功能,便于记录业务处理过程中的相关信息。
|
|
|
|
|
|
|
|
*
|
|
|
|
* @Author swg.
|
|
|
|
* @Author swg.
|
|
|
|
* @Date 2019/1/2 12:54
|
|
|
|
* @Date 2019/1/2 12:54
|
|
|
|
* @CONTACT 317758022@qq.com
|
|
|
|
* @CONTACT 317758022@qq.com
|
|
|
|
* @DESC
|
|
|
|
* @DESC
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@Service
|
|
|
|
@Service
|
|
|
|
|
|
|
|
// `@Service` 注解是Spring框架提供的,用于将当前类标记为服务层组件,表明这个类包含了业务逻辑处理的相关代码,
|
|
|
|
|
|
|
|
// 会被Spring容器自动扫描并管理,使得其他类可以通过依赖注入的方式使用这个类的实例,方便业务逻辑的分层和复用。
|
|
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
@Slf4j
|
|
|
|
|
|
|
|
// `@Slf4j` 是Lombok库提供的注解,用于自动生成一个名为 `log` 的SLF4J日志记录器,在类中可以方便地使用这个日志记录器记录各种级别的日志信息,
|
|
|
|
|
|
|
|
// 例如记录业务操作的关键步骤、异常情况等,有助于后续的问题排查和系统监控。
|
|
|
|
public class CategoryServiceImpl implements ICategoryService {
|
|
|
|
public class CategoryServiceImpl implements ICategoryService {
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
@Autowired
|
|
|
|
private CategoryMapper categoryMapper;
|
|
|
|
private CategoryMapper categoryMapper;
|
|
|
|
|
|
|
|
// 通过Spring的依赖注入(Dependency Injection)机制,使用 `@Autowired` 注解自动注入 `CategoryMapper` 类型的实例,
|
|
|
|
|
|
|
|
// `CategoryMapper` 是数据访问层接口,它定义了一系列操作品类数据的数据库方法,在这里注入后,服务层的业务方法就可以调用这些方法来与数据库进行交互,
|
|
|
|
|
|
|
|
// 实现对品类数据的增删改查等操作。
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public ServerResponse getCategory(Integer categoryId) {
|
|
|
|
public ServerResponse getCategory(Integer categoryId) {
|
|
|
@ -34,12 +47,23 @@ public class CategoryServiceImpl implements ICategoryService{
|
|
|
|
if (categoryId == null) {
|
|
|
|
if (categoryId == null) {
|
|
|
|
throw new SnailmallException("未找到该品类");
|
|
|
|
throw new SnailmallException("未找到该品类");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 首先对传入的品类 `id` 参数进行合法性校验,如果 `id` 为 `null`,说明参数不合法,此时抛出 `SnailmallException` 异常,
|
|
|
|
|
|
|
|
// 告知调用方没有找到对应的品类,遵循了先进行参数校验再进行业务操作的良好编程习惯,避免后续因参数问题导致的潜在错误。
|
|
|
|
|
|
|
|
|
|
|
|
// 2.根据父亲id获取这个父亲下一级所有子ID
|
|
|
|
// 2.根据父亲id获取这个父亲下一级所有子ID
|
|
|
|
List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
|
|
|
|
List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
|
|
|
|
|
|
|
|
// 调用 `CategoryMapper` 接口的 `selectCategoryChildrenByParentId` 方法,根据传入的 `categoryId`(作为父品类 `id`),
|
|
|
|
|
|
|
|
// 从数据库中查询获取该父品类下一级的所有子品类记录,返回的结果是一个 `List<Category>` 类型的列表,包含了符合条件的子品类对象集合。
|
|
|
|
|
|
|
|
|
|
|
|
if (CollectionUtils.isEmpty(categoryList)) {
|
|
|
|
if (CollectionUtils.isEmpty(categoryList)) {
|
|
|
|
log.info("该节点下没有任何子节点");
|
|
|
|
log.info("该节点下没有任何子节点");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 使用Apache Commons Collections工具类的 `CollectionUtils.isEmpty` 方法判断获取到的子品类列表是否为空,
|
|
|
|
|
|
|
|
// 如果为空,则通过日志记录器 `log` 记录一条信息日志,表示当前节点下没有任何子节点,方便后续查看业务执行情况进行调试和监控。
|
|
|
|
|
|
|
|
|
|
|
|
return ServerResponse.createBySuccess(categoryList);
|
|
|
|
return ServerResponse.createBySuccess(categoryList);
|
|
|
|
|
|
|
|
// 最后,使用 `ServerResponse` 类的静态方法 `createBySuccess` 创建一个表示成功的响应对象,并将获取到的子品类列表作为数据传入,
|
|
|
|
|
|
|
|
// 返回给调用方,告知操作成功并携带相应的子品类数据,如果列表为空则表示没有子品类数据可返回,但操作本身是成功执行的。
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@ -48,17 +72,28 @@ public class CategoryServiceImpl implements ICategoryService{
|
|
|
|
if (StringUtils.isBlank(categoryName)) {
|
|
|
|
if (StringUtils.isBlank(categoryName)) {
|
|
|
|
throw new SnailmallException("品类名字不能为空");
|
|
|
|
throw new SnailmallException("品类名字不能为空");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 对传入的品类名称参数进行校验,使用Apache Commons Lang3工具类的 `StringUtils.isBlank` 方法判断名称是否为空(包括 `null` 或者空字符串情况),
|
|
|
|
|
|
|
|
// 如果为空则抛出 `SnailmallException` 异常,提示品类名字不能为空,确保添加品类时必须有合法的名称。
|
|
|
|
|
|
|
|
|
|
|
|
// 2.创建类目
|
|
|
|
// 2.创建类目
|
|
|
|
Category category = new Category();
|
|
|
|
Category category = new Category();
|
|
|
|
category.setName(categoryName);
|
|
|
|
category.setName(categoryName);
|
|
|
|
category.setParentId(parentId);
|
|
|
|
category.setParentId(parentId);
|
|
|
|
category.setStatus(true);
|
|
|
|
category.setStatus(true);
|
|
|
|
|
|
|
|
// 创建一个 `Category` 实体对象,将传入的品类名称和父品类 `id` 设置到该对象的对应属性上,并默认将品类的状态设置为 `true`(表示启用、可用状态等),
|
|
|
|
|
|
|
|
// 准备将这个对象插入到数据库中,完成添加品类的操作。
|
|
|
|
|
|
|
|
|
|
|
|
int resultCount = categoryMapper.insert(category);
|
|
|
|
int resultCount = categoryMapper.insert(category);
|
|
|
|
|
|
|
|
// 调用 `CategoryMapper` 接口的 `insert` 方法,将创建好的 `Category` 实体对象插入到数据库中,该方法会返回受影响的行数,
|
|
|
|
|
|
|
|
// 用于判断插入操作是否成功执行,正常情况下如果成功插入一条记录,返回值应该为 `1`。
|
|
|
|
|
|
|
|
|
|
|
|
if (resultCount > 0) {
|
|
|
|
if (resultCount > 0) {
|
|
|
|
return ServerResponse.createBySuccessMessage("添加品类成功");
|
|
|
|
return ServerResponse.createBySuccessMessage("添加品类成功");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ServerResponse.createByErrorMessage("添加品类失败");
|
|
|
|
return ServerResponse.createByErrorMessage("添加品类失败");
|
|
|
|
|
|
|
|
// 根据插入操作返回的受影响行数判断,如果大于 `0`,说明插入成功,使用 `ServerResponse` 类的静态方法 `createBySuccessMessage` 创建一个表示成功的响应对象,
|
|
|
|
|
|
|
|
// 并传入提示消息 "添加品类成功" 返回给调用方;如果插入失败(返回值不大于 `0`),则使用 `createByErrorMessage` 方法创建一个表示失败的响应对象,
|
|
|
|
|
|
|
|
// 传入 "添加品类失败" 消息返回给调用方,告知调用方添加品类的操作结果情况。
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@ -67,28 +102,51 @@ public class CategoryServiceImpl implements ICategoryService{
|
|
|
|
if (StringUtils.isBlank(categoryName)) {
|
|
|
|
if (StringUtils.isBlank(categoryName)) {
|
|
|
|
throw new SnailmallException("品类名字不能为空");
|
|
|
|
throw new SnailmallException("品类名字不能为空");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 同样先对传入的品类名称参数进行校验,确保名称不为空,若为空则抛出 `SnailmallException` 异常,提示品类名字不能为空,
|
|
|
|
|
|
|
|
// 保证只有合法的名称才能进行后续的更新操作。
|
|
|
|
|
|
|
|
|
|
|
|
// 2.根据id获取品类
|
|
|
|
// 2.根据id获取品类
|
|
|
|
Category tmpCat = categoryMapper.selectByPrimaryKey(categoryId);
|
|
|
|
Category tmpCat = categoryMapper.selectByPrimaryKey(categoryId);
|
|
|
|
|
|
|
|
// 调用 `CategoryMapper` 接口的 `selectByPrimaryKey` 方法,根据传入的品类 `id` 从数据库中查询获取对应的 `Category` 实体对象,
|
|
|
|
|
|
|
|
// 如果能找到则返回该对象,若找不到(即 `tmpCat` 为 `null`)则说明要更新的品类不存在。
|
|
|
|
|
|
|
|
|
|
|
|
if (tmpCat == null) {
|
|
|
|
if (tmpCat == null) {
|
|
|
|
throw new SnailmallException("品类不存在");
|
|
|
|
throw new SnailmallException("品类不存在");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 如果根据 `id` 查询不到对应的品类对象,则抛出 `SnailmallException` 异常,告知调用方品类不存在,无法进行名称更新操作。
|
|
|
|
|
|
|
|
|
|
|
|
// 3.更新品类名称
|
|
|
|
// 3.更新品类名称
|
|
|
|
Category category = new Category();
|
|
|
|
Category category = new Category();
|
|
|
|
category.setId(categoryId);
|
|
|
|
category.setId(categoryId);
|
|
|
|
category.setName(categoryName);
|
|
|
|
category.setName(categoryName);
|
|
|
|
|
|
|
|
// 创建一个新的 `Category` 实体对象,将传入的品类 `id` 和要更新的品类名称设置到该对象的对应属性上,
|
|
|
|
|
|
|
|
// 准备用这个对象来更新数据库中对应品类的名称信息,这里只设置了 `id` 和 `name` 属性,其他属性可能保持原有值不变(根据数据库操作逻辑)。
|
|
|
|
|
|
|
|
|
|
|
|
int resultCount = categoryMapper.updateByPrimaryKeySelective(category);
|
|
|
|
int resultCount = categoryMapper.updateByPrimaryKeySelective(category);
|
|
|
|
|
|
|
|
// 调用 `CategoryMapper` 接口的 `updateByPrimaryKeySelective` 方法,根据创建的 `Category` 实体对象中设置的非空属性值(这里主要是 `name` 属性),
|
|
|
|
|
|
|
|
// 对数据库中主键为对应 `id` 的品类记录进行选择性更新操作,即只更新设置了值的属性,该方法返回受影响的行数用于判断更新操作是否成功执行。
|
|
|
|
|
|
|
|
|
|
|
|
if (resultCount > 0) {
|
|
|
|
if (resultCount > 0) {
|
|
|
|
return ServerResponse.createBySuccessMessage("更新品类名称成功");
|
|
|
|
return ServerResponse.createBySuccessMessage("更新品类名称成功");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ServerResponse.createByErrorMessage("更新品类名称失败");
|
|
|
|
return ServerResponse.createByErrorMessage("更新品类名称失败");
|
|
|
|
|
|
|
|
// 根据更新操作返回的受影响行数判断,如果大于 `0`,说明更新成功,使用 `ServerResponse` 类的静态方法 `createBySuccessMessage` 创建一个表示成功的响应对象,
|
|
|
|
|
|
|
|
// 传入提示消息 "更新品类名称成功" 返回给调用方;如果更新失败(返回值不大于 `0`),则使用 `createByErrorMessage` 方法创建一个表示失败的响应对象,
|
|
|
|
|
|
|
|
// 传入 "更新品类名称失败" 消息返回给调用方,告知调用方更新品类名称的操作结果情况。
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public ServerResponse selectCategoryAndDeepChildrenById(Integer categoryId) {
|
|
|
|
public ServerResponse selectCategoryAndDeepChildrenById(Integer categoryId) {
|
|
|
|
// 1、创建一个空Set用来存放不重复的品类对象--去重
|
|
|
|
// 1、创建一个空Set用来存放不重复的品类对象--去重
|
|
|
|
Set<Category> categorySet = Sets.newHashSet();
|
|
|
|
Set<Category> categorySet = Sets.newHashSet();
|
|
|
|
|
|
|
|
// 使用Google Guava库的 `Sets.newHashSet` 方法创建一个空的 `Set` 集合,用于存放品类对象,这里的 `Set` 集合特性可以保证元素的唯一性,
|
|
|
|
|
|
|
|
// 目的是在后续递归获取品类及其子节点信息的过程中避免重复添加相同的品类对象,起到去重的作用。
|
|
|
|
|
|
|
|
|
|
|
|
// 2、递归获取所有的子节点(儿子、孙子、等等),包括自己也添加进去
|
|
|
|
// 2、递归获取所有的子节点(儿子、孙子、等等),包括自己也添加进去
|
|
|
|
findChildCategory(categorySet, categoryId);
|
|
|
|
findChildCategory(categorySet, categoryId);
|
|
|
|
|
|
|
|
// 调用私有方法 `findChildCategory`,传入创建好的 `categorySet` 和要查询的品类 `id`,开始递归地获取指定品类及其所有层级的子品类对象,
|
|
|
|
|
|
|
|
// 将获取到的品类对象添加到 `categorySet` 集合中,实现深度遍历品类树结构的功能。
|
|
|
|
|
|
|
|
|
|
|
|
// 3、将递归获取到的品类id取出来放进list中
|
|
|
|
// 3、将递归获取到的品类id取出来放进list中
|
|
|
|
List<Integer> categoryIdList = new ArrayList<>();
|
|
|
|
List<Integer> categoryIdList = new ArrayList<>();
|
|
|
|
if (categoryId!= null) {
|
|
|
|
if (categoryId!= null) {
|
|
|
@ -96,7 +154,13 @@ public class CategoryServiceImpl implements ICategoryService{
|
|
|
|
categoryIdList.add(category.getId());
|
|
|
|
categoryIdList.add(category.getId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 创建一个 `List<Integer>` 类型的列表,用于存放从 `categorySet` 集合中提取出来的品类 `id` 值,
|
|
|
|
|
|
|
|
// 如果传入的 `categoryId` 不为 `null`,则遍历 `categorySet` 中的每个品类对象,将其 `id` 属性值添加到 `categoryIdList` 列表中,
|
|
|
|
|
|
|
|
// 这样最终得到的列表就是包含了指定品类及其所有子品类的 `id` 集合,方便后续业务使用或者返回给调用方等操作。
|
|
|
|
|
|
|
|
|
|
|
|
return ServerResponse.createBySuccess(categoryIdList);
|
|
|
|
return ServerResponse.createBySuccess(categoryIdList);
|
|
|
|
|
|
|
|
// 使用 `ServerResponse` 类的静态方法 `createBySuccess` 创建一个表示成功的响应对象,并将包含品类 `id` 列表的 `categoryIdList` 作为数据传入,
|
|
|
|
|
|
|
|
// 返回给调用方,告知操作成功并携带相应的品类 `id` 数据,方便调用方根据这些 `id` 进一步获取详细的品类信息等操作。
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Set<Category> findChildCategory(Set<Category> categorySet, Integer categoryId) {
|
|
|
|
private Set<Category> findChildCategory(Set<Category> categorySet, Integer categoryId) {
|
|
|
@ -105,26 +169,46 @@ public class CategoryServiceImpl implements ICategoryService{
|
|
|
|
if (category!= null) {
|
|
|
|
if (category!= null) {
|
|
|
|
categorySet.add(category);
|
|
|
|
categorySet.add(category);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 首先根据传入的品类 `id` 通过 `CategoryMapper` 接口的 `selectByPrimaryKey` 方法从数据库中查询对应的 `Category` 实体对象,
|
|
|
|
|
|
|
|
// 如果查询到的对象不为 `null`,说明该品类存在,则将其添加到传入的 `categorySet` 集合中,这是递归过程中的一个基础操作,
|
|
|
|
|
|
|
|
// 同时如果查询结果为空,说明已经遍历到品类树的叶子节点或者不存在该 `id` 对应的品类,此时这个递归分支就结束,符合递归的停止条件设定。
|
|
|
|
|
|
|
|
|
|
|
|
// 5、根据父亲id获取下一级所有品类(即先获取儿子们)
|
|
|
|
// 5、根据父亲id获取下一级所有品类(即先获取儿子们)
|
|
|
|
List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
|
|
|
|
List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
|
|
|
|
|
|
|
|
// 调用 `CategoryMapper` 接口的 `selectCategoryChildrenByParentId` 方法,根据当前品类的 `id`(作为父品类 `id`),
|
|
|
|
|
|
|
|
// 从数据库中查询获取该父品类下一级的所有子品类记录,返回的结果是一个 `List<Category>` 类型的列表,包含了符合条件的子品类对象集合,
|
|
|
|
|
|
|
|
// 这些就是当前品类的“儿子”品类。
|
|
|
|
|
|
|
|
|
|
|
|
// 6、根据每一个儿子再获取儿子的儿子们,递归下去
|
|
|
|
// 6、根据每一个儿子再获取儿子的儿子们,递归下去
|
|
|
|
for (Category categoryItem : categoryList) {
|
|
|
|
for (Category categoryItem : categoryList) {
|
|
|
|
findChildCategory(categorySet, categoryItem.getId());
|
|
|
|
findChildCategory(categorySet, categoryItem.getId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 遍历获取到的“儿子”品类列表,对于每个“儿子”品类,再次调用 `findChildCategory` 方法,传入当前的 `categorySet` 和“儿子”品类的 `id`,
|
|
|
|
|
|
|
|
// 继续递归地获取“儿子”品类的子品类(即“孙子”品类等),如此循环下去,实现深度优先遍历整个品类树结构,将所有层级的品类对象添加到 `categorySet` 集合中。
|
|
|
|
|
|
|
|
|
|
|
|
return categorySet;
|
|
|
|
return categorySet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public ServerResponse getCategoryDetail(Integer categoryId) {
|
|
|
|
public ServerResponse getCategoryDetail(Integer categoryId) {
|
|
|
|
if (categoryId == null) {
|
|
|
|
if (categoryId == null) {
|
|
|
|
return ServerResponse.createByErrorMessage("参数不能为空");
|
|
|
|
return ServerResponse.createByErrorMessage("参数不能为空");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 先对传入的品类 `id` 参数进行合法性校验,如果 `id` 为 `null`,说明参数不合法,此时使用 `ServerResponse` 类的静态方法 `createByErrorMessage` 创建一个表示失败的响应对象,
|
|
|
|
|
|
|
|
// 传入提示消息 "参数不能为空" 返回给调用方,告知调用方参数不符合要求。
|
|
|
|
|
|
|
|
|
|
|
|
Category category = categoryMapper.selectByPrimaryKey(categoryId);
|
|
|
|
Category category = categoryMapper.selectByPrimaryKey(categoryId);
|
|
|
|
|
|
|
|
// 调用 `CategoryMapper` 接口的 `selectByPrimaryKey` 方法,根据传入的品类 `id` 从数据库中查询获取对应的 `Category` 实体对象,
|
|
|
|
|
|
|
|
// 如果能找到则返回该对象,若找不到则说明要获取详细信息的品类不存在。
|
|
|
|
|
|
|
|
|
|
|
|
if (category == null) {
|
|
|
|
if (category == null) {
|
|
|
|
return ServerResponse.createByErrorMessage("品类不存在");
|
|
|
|
return ServerResponse.createByErrorMessage("品类不存在");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 如果根据 `id` 查询不到对应的品类对象,则使用 `ServerResponse` 类的静态方法 `createByErrorMessage` 创建一个表示失败的响应对象,
|
|
|
|
|
|
|
|
// 传入提示消息 "品类不存在" 返回给调用方,告知调用方要获取详细信息的品类不存在;如果查询到了品类对象,则继续下一步操作。
|
|
|
|
|
|
|
|
|
|
|
|
return ServerResponse.createBySuccess(category);
|
|
|
|
return ServerResponse.createBySuccess(category);
|
|
|
|
|
|
|
|
// 使用 `ServerResponse` 类的静态方法 `createBySuccess` 创建一个表示成功的响应对象,并将查询到的 `Category` 实体对象作为数据传入,
|
|
|
|
|
|
|
|
// 返回给调用方,告知操作成功并携带相应的品类详细信息,方便调用方获取和使用该品类的具体数据内容。
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|