第四阶段10-添加类别,类别列表mapper层,service层,controller层
63. 添加类别–Mapper层
插入类别数据的功能此前已经完成!
64. 添加类别–Service层
在项目的根包下创建pojo.dto.CategoryAddNewDTO
类:
@Data
public class CategoryAddNewDTO implements Serializable {/*** 类别名称*/private String name;/*** 父级类别id,如果无父级,则为0*/private Long parentId;/*** 关键词列表,各关键词使用英文的逗号分隔*/private String keywords;/*** 排序序号*/private Integer sort;/*** 图标图片的URL*/private String icon;/*** 是否启用,1=启用,0=未启用*/private Integer enable;/*** 是否显示在导航栏中,1=启用,0=未启用*/private Integer isDisplay;}
在项目的根包下创建service.ICategoryService
接口,并在接口中添加抽象方法:
public interface ICategoryService {void addNew(CategoryAddNewDTO categoryAddNewDTO);
}
在项目的根包下创建service.impl.CategoryServiceImpl
类,实现以上接口,并在类上添加@Service
注解,然后,实现接口中的方法:
@Service
public class CategoryServiceImpl implements ICategoryService {public void addNew(CategoryAddNewDTO categoryAddNewDTO) {// 调用Mapper对象的countByName()检查类别名称是否已经被占用// 是:抛出异常(ERR_CONFLICT)// 如果parentId不是0,调用Mapper对象的getStandardById()查询类别详情// 判断查询结果是否为null// 是:父级类别不存在,抛出异常(NOT_FOUND)// depth(深度)的值:如果父级类别id为0,则depth为1,否则,depth为父级depth+1// 创建Category类的对象// 将参数对象中的各属性值复制到以上新创建的Category类的对象中// 补全Category类的对象的属性值:depth// 补全Category类的对象的属性值:isParent >>> 固定为0// 调用Mapper对象的insert()方法插入类别数据// 如果现在添加的类别的父级类别不是0,// 如果父级类别的isParent仍为0// 则将父级类别的isParent更新为1}}
具体实现为:
@Override
public void addNew(CategoryAddNewDTO categoryAddNewDTO) {log.debug("开始处理【添加类别】的业务,参数:{}", categoryAddNewDTO);// 调用Mapper对象的countByName()检查类别名称是否已经被占用String name = categoryAddNewDTO.getName();int countByName = categoryMapper.countByName(name);if (countByName > 0) {// 是:抛出异常(ERR_CONFLICT)String message = "添加类别失败,尝试添加的类别名称【" + name + "】已经被占用!";log.warn(message);throw new ServiceException(ServiceCode.ERR_CONFLICT, message);}Integer depth = 1;CategoryStandardVO parentCategory = null;Long parentId = categoryAddNewDTO.getParentId();if (parentId != 0) {// 如果parentId不是0,调用Mapper对象的getStandardById()查询类别详情parentCategory = categoryMapper.getStandardById(parentId);// 判断查询结果是否为nullif (parentCategory == null) {// 是:父级类别不存在,抛出异常(NOT_FOUND)String message = "添加类别失败,选定的父级类别不存在!";log.warn(message);throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);} else {depth = parentCategory.getDepth() + 1;}}// 创建Category类的对象Category category = new Category();// 将参数对象中的各属性值复制到以上新创建的Category类的对象中BeanUtils.copyProperties(categoryAddNewDTO, category);// 补全Category类的对象的属性值:depthcategory.setDepth(depth);// 补全Category类的对象的属性值:isParent >>> 固定为0category.setIsParent(0);// 调用Mapper对象的insert()方法插入类别数据categoryMapper.insert(category);// 如果现在添加的类别的父级类别不是0if (parentId != 0) {// 如果父级类别的isParent仍为0if (parentCategory.getIsParent() == 0) {// 则将父级类别的isParent更新为1Category updateParentCategory = new Category();updateParentCategory.setId(parentId);updateParentCategory.setIsParent(1);categoryMapper.update(updateParentCategory);}}
}
在项目的src/test/java
下的根包下创建CategoryServiceTests
类,对以上方法进行测试:
@Slf4j
@SpringBootTest
public class CategoryServiceTests {@AutowiredICategoryService service;@Testvoid addNew() {CategoryAddNewDTO categoryAddNewDTO = new CategoryAddNewDTO();categoryAddNewDTO.setParentId(74L);categoryAddNewDTO.setName("热带水果");try {service.addNew(categoryAddNewDTO);log.debug("添加类别成功!");} catch (ServiceException e) {log.debug("捕获到异常,其中的消息:{}", e.getMessage());}}}
65. 添加类别–Controller层
在项目的根包下创建controller.CategoryController
类,在类上添加@RestController
注解和@RequestMapping("/categories")
注解,在类中自动装配ICategoryService
类型的对象:
@RestController
@RequestMapping("/categories")
public class CategoryController {@Autowiredprivate ICategoryService categoryService;
}
然后,在此类中处理请求:
@PostMapping("/add-new")
public JsonResult<Void> addNew(CategoryAddNewDTO categoryAddNewDTO) {log.debug("xxx");categoryService.addNew(categoryAddNewDTO);return JsonResult.ok();
}
完成后,重启项目,可以通过在线API文档进行调试。
调试通过后,应该补充在线API文档的相关说明。
提示:接下来,在课上不再对请求参数的基本格式进行检查。
66. 删除类别–Mapper层
67. 删除类别–Service层
在ICategoryService
接口中添加抽象方法:
/*** 根据id删除类别** @param id 类别id*/
void delete(Long id);
在CategoryServiceImpl
中实现以上方法:
public void delete(Long id) {// 调用Mapper对象的getStandardById()执行查询// 判断查询结果是否为null// 是:数据已经不存在,抛出异常(NOT_FOUND)// 判断以上查询结果中的isParent是否为1// 是:当前尝试删除的是父级类别,抛出异常(CONFLICT)// 调用BrandCategoryMapper对象的countByCategory()执行统计// 判断统计结果是否大于0// 是:当前尝试删除的类别关联到了某些品牌,抛出异常(CONFLICT)// 调用CategoryAttributeTemplateMapper对象的countByCategory()执行统计// 判断统计结果是否大于0// 是:当前尝试删除的类别关联到了某些属性模板,抛出异常(CONFLICT)// 调用SpuMapper对象的countByCategory()执行统计// 判断统计结果是否大于0// 是:当前尝试删除的类别关联到了某些SPU,抛出异常(CONFLICT)// 调用Mapper对象的deleteById()执行删除// 从此前的查询结果中找到当前删除的类别的父级类别ID// 判断父级类别ID是否不为0// 调用Mapper对象的countByParentId()执行统计// 判断统计结果是否等于0// 是:将父级类别的isParent更新为0
}
具体实现为:
@Override
public void delete(Long id) {// 调用Mapper对象的getStandardById()执行查询CategoryStandardVO currentCategory = categoryMapper.getStandardById(id);// 判断查询结果是否为nullif (currentCategory == null) {// 是:数据已经不存在,抛出异常(NOT_FOUND)String message = "删除类别失败,尝试删除的类别不存在!";log.warn(message);throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);}// 判断以上查询结果中的isParent是否为1if (currentCategory.getIsParent() == 1) {// 是:当前尝试删除的是父级类别,抛出异常(CONFLICT)String message = "删除类别失败,尝试删除的类别仍包含子级类别!";log.warn(message);throw new ServiceException(ServiceCode.ERR_CONFLICT, message);}{// 调用BrandCategoryMapper对象的countByCategory()执行统计int count = brandCategoryMapper.countByCategory(id);// 判断统计结果是否大于0if (count > 0) {// 是:当前尝试删除的类别关联到了某些品牌,抛出异常(CONFLICT)String message = "删除类别失败,尝试删除的类别关联了某些品牌!";log.warn(message);throw new ServiceException(ServiceCode.ERR_CONFLICT, message);}}{// 调用CategoryAttributeTemplateMapper对象的countByCategory()执行统计int count = categoryAttributeTemplateMapper.countByCategory(id);// 判断统计结果是否大于0if (count > 0) {// 是:当前尝试删除的类别关联到了某些属性模板,抛出异常(CONFLICT)String message = "删除类别失败,尝试删除的类别关联了某些属性模板!";log.warn(message);throw new ServiceException(ServiceCode.ERR_CONFLICT, message);}}{// 调用SpuMapper对象的countByCategory()执行统计int count = spuMapper.countByCategory(id);// 判断统计结果是否大于0if (count > 0) {// 是:当前尝试删除的类别关联到了某些SPU,抛出异常(CONFLICT)String message = "删除类别失败,尝试删除的类别关联了某些SPU!";log.warn(message);throw new ServiceException(ServiceCode.ERR_CONFLICT, message);}}// 调用Mapper对象的deleteById()执行删除log.debug("即将执行删除类别,参数:{}", id);categoryMapper.deleteById(id);// 从此前的查询结果中找到当前删除的类别的父级类别IDLong parentId = currentCategory.getParentId();// 判断父级类别ID是否不为0if (parentId != 0) {// 调用Mapper对象的countByParentId()执行统计int count = categoryMapper.countByParentId(parentId);// 判断统计结果是否等于0if (count == 0) {// 是:将父级类别的isParent更新为0Category parentCategory = new Category();parentCategory.setId(parentId);parentCategory.setIsParent(0);categoryMapper.update(parentCategory);}}
}
在CategoryServiceTests
中编写并执行测试:
@Test
void delete() {Long id = 74L;try {service.delete(id);log.debug("删除类别成功!");} catch (ServiceException e) {log.debug("捕获到异常,其中的消息:{}", e.getMessage());}
}
相关文章:
第四阶段10-添加类别,类别列表mapper层,service层,controller层
63. 添加类别–Mapper层 插入类别数据的功能此前已经完成! 64. 添加类别–Service层 在项目的根包下创建pojo.dto.CategoryAddNewDTO类: Data public class CategoryAddNewDTO implements Serializable {/*** 类别名称*/private String name;/*** 父…...
linux内核启动分析(一)
文章目录1.HEAD1.preserve_boot_args1.1 __inval_dcache_area2.el2_setup3. set_cpu_boot_mode_flag4. __create_page_tables4.1map_memory5. __cpu_setup6. __primary_switch6.1 __enable_mmu6.2 __primary_switched最近工作中经常使用飞腾E2000的开发版,也遇到一些…...

wireshark常见使用操作讲解以及几个故障解决案例分享
(1)网卡选择 对于电脑本身有多个网卡的时候,选择网卡就成为了一个困惑的地方,其实这里很简单,只要把鼠标放在对应的网卡上面就可以看到地址等信息,就容易判断出来了。 (2)过滤器 直…...

利用逻辑分析仪解析串口通讯数据
利用逻辑分析仪解析串口通讯数据🔧采用的是市面上最为广泛使用的USB逻辑分析仪: 📚资料下载: 链接: https://pan.baidu.com/s/1c9lwWDbtJxaJED-kzSbiJg 提取码: 5vnr🔨测试工具为:Logic 2.4.6,也可以使用Pu…...
新整理的前端面试题
pinia和vuex的区别(1)pinia它没有mutation,他只有state,getters,action【同步、异步】使用他来修改state数据(2)pinia他默认也是存入内存中,如果需要使用本地存储,在配置上比vuex麻烦…...

数据仓库-数仓分层
层级 全拼 职责划分 ODS(源数据层) Operational DataStore ODS层存储最原始的数据, 对数据不做任何加工处理; 源数据主要来自业务数据库和日志,这些数据是用户操作业务系统产生,所以叫操作型数据(Operational Data) 。 DWD(…...

【Linux】Linux根文件系统扩容
场景:根文件系统需要至少100GB的剩余空间,但是目前就剩余91GB。因此,我们需要对根文件系统进行扩容。# df -h 文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 3.9G 0 3.9G 0% /dev tmpfs …...

RPC编程:Hessian RPC一个老的RPC框架(一)
RPC编程:Hessian RPC一个老的RPC框架一:Hessian RPC1:Hession RPC一个老的RPC框架2:老,为什么还要研究?3:Hession RPC概念二:Hessian RPC设计思想1:Hession依赖于服务器2…...

逆向 x蜂窝 zzzghostsigh
逆向 x蜂窝 zzzghostsigh 版本 9.3.7 新版本是64位的so charles 抓包 目标字段 zzzghostsigh frida java function hook_xPreAuthencode() {Java.perform(function() {var helper Java.use("com.mfw.tnative.AuthorizeHelper");helper.xPreAuthencode.implemen…...

QML 鼠标事件
作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 QML 中有一些元素本身是不具备交互能力的(例如:Rectangle、Text、Image 等),那么如何通过鼠标来控制它们的行为呢?这里就需要用到 MouseArea 元素了,它继承于 Item 且不可见,通常需要与可见元素结合使…...

极智项目 | 实战pytorch arcface人脸识别
欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文介绍 实战pytorch arcface人脸识别,并提供完整项目源码。 本文介绍的实战arcface人脸识别项目,提供完整的可以一键训练、测试的项目工程…...

【IP技术】ipv4和ipv6是什么?
IPv4和IPv6是两种互联网协议,用于在互联网上标识和寻址设备。IPv4(Internet Protocol version 4)是互联网协议的第四个版本,是当前广泛使用的互联网协议。IPv4地址由32位二进制数构成,通常表示为4个十进制数࿰…...

linux基本功系列之uniq命令实战
文章目录前言一. uniq的命令介绍二. 语法格式及常用选项三. 参考案例3.1 统计行数3.2 对文本进行去重3.3 显示不重复的行3.4 仅显示重复的行,且显示重复的行的所有行3.5 忽略字母大小写总结前言 大家好,又见面了,我是沐风晓月,本…...

六、SpringBoot项目搭建
日志 Java 主流日志工具库 统一接口 什么是 REST? Representational State Transfer——“表现层状态转化”。可以总结为一句话:REST 是所有 Web 应用都应该遵守的架构设计指导原则。面向资源是 REST 最明显的特征,对于同一个资源的一组不…...

【LeetCode】2363. 合并相似的物品
2363. 合并相似的物品 题目描述 给你两个二维整数数组 items1 和 items2 ,表示两个物品集合。每个数组 items 有以下特质: items[i] [valuei, weighti] 其中 valuei 表示第 i 件物品的 价值 ,weighti 表示第 i 件物品的 重量 。items 中每…...

华为OD机试题,用 Java 解【出租车计费】问题
最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…...

【人脸识别】DDL:数据分布知识蒸馏思想,提升困难样本(遮挡、低分辨率等)识别效果
论文题目:《Improving Face Recognition from Hard Samples via Distribution Distillation Loss》 论文地址:https://arxiv.org/pdf/2002.03662v3.pdf 代码地址:https://github.com/HuangYG123/DDL 1.前言及相关工作 Large facial variatio…...

如何管理好仓库/库房?
仓库管理是企业管理中不可缺少的一部分,事关企业能否正常运行的关键之一,古人有云:“三军未动粮草先行”,一个企业仓库管理做不好,他的生产管理肯定也是做不好的,不是说生产管理人员的管理能力不具备&#…...

Unity Lighting -- Unity的光源简介
在主菜单栏中,点击Window -> Rendering -> Light Explorer打开光源管理器,这个标签页可以看到场景中所有的光源,包括每个光源的类型,形状,模式,颜色,强度,阴影等信息。 在主菜…...

Android仿网易云音乐歌单详情页
效果图实现思路:1、Activity设置自定义Shared Element切换动画2、透明状态栏(透明Toolbar,使背景图上移)3、Toolbar底部增加和背景一样的高斯模糊图,并上移图片(为了使背景图的底部作为Toolbar的背景)4、上…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
ThreadLocal 源码
ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...

rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式
pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图,如果边框加在dom上面,pdf-lib导出svg的时候并不会导出边框,所以只能在echarts图上面加边框 grid的边框是在图里…...

CMS内容管理系统的设计与实现:多站点模式的实现
在一套内容管理系统中,其实有很多站点,比如企业门户网站,产品手册,知识帮助手册等,因此会需要多个站点,甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...

claude3.7高阶玩法,生成系统架构图,国内直接使用
文章目录 零、前言一、操作指南操作指导 二、提示词模板三、实战图书管理系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 在线考试系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 四、感受 零、前言 现在很多AI大模型可以…...