当前位置: 首页 > news >正文

springboot项目外卖管理 day03-公共字段填充与新增删除分类

文章目录

  • 一、公共字段自动填充
    • 1.1、问题分析
    • 1.2、代码实现
      • 1.2.1、在实体类的属性上加入@TableField注解,指定自动填充的策略
      • 1.2.2按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口
      • 1.2.3 功能完善
      • 1.2.4实现步骤:
  • 2、新增分类
    • 2.1、需求分析
    • 2.2、数据模型
    • 2.3、整个程序的执行过程
  • 3、分类信息分页查询
    • 3.1、需求分析
    • 3.2、代码开发
  • 4、删除分类
    • 4.1、需求分析
    • 4.2、代码完善
  • 总结


一、公共字段自动填充

1.1、问题分析

前面我们已经完成了后台系统的员工管理功能开发,在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间和修改人等字段。这些字段属于公共字段,也就是很多表中都有这些字段,如下:
在这里插入图片描述

在这里插入图片描述

能不能对于这些公共字段在某个地方统一处理,来简化开发呢?答案就是使用Mybatis Plus提供的公共字段自动填充功能。

1.2、代码实现

Mybatis Plus公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。

实现步骤:

1.2.1、在实体类的属性上加入@TableField注解,指定自动填充的策略

这里记住一定要在每个有公共字段的表中都加上@TableField注解,否则自动填充不会失效

@TableField(fill = FieldFill.INSERT)//插入时填充字段
private LocalDateTime createTime;@TableField(fill = FieldFill.INSERT_UPDATE)//插入和更新时填充字段
private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)
private Long createUser;@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;

1.2.2按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {//插入时自动填充@Overridepublic void insertFill(MetaObject metaObject) {metaObject.setValue("createTime", LocalDateTime.now());metaObject.setValue("updateTime", LocalDateTime.now());metaObject.setValue("createUser",new Long(1));metaObject.setValue("updateUser",new Long(1));}//更新时自动填充@Overridepublic void updateFill(MetaObject metaObject) {log.info(metaObject.toString());metaObject.setValue("updateTime",LocalDateTime.now());metaObject.setValue("updateUser",new Long(1));}
}

1.2.3 功能完善

前面我们已经完成了公共字段自动填充功能的代码开发,但是还有一个问题没有解决,就是我们在自动填充createUser和updateUser时设置的用户id是固定值,现在我们需要改造成动态获取当前登录用户的id。
既然用户登录成功后我们将用户id存入了HttpSession中,现在我从HttpSession中获取不就行了?
注意,我们在MyMetaObjectHandler类中是不能获得HttpSession对象的,所以我们需要通过其他方式来获取登录用户id。

可以使用ThreadLocal来解决此问题,它是JDK中提供的一个类。

在学习ThreadLocal之前,我们需要先确认一个事情,就是客户端发送的每次http请求,对应的在服务端都会分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都属于相同的一个线程:

1、LoginCheckFilter的doFilter方法

2、EmployeeContraller的update方法

3、MyMetaObjectHandler的updateFill方法

可以在上面的三个方法中分别加入下面代码(获取当前线程id):

long id = Thread.currentThread().getId() ;
log.info("线程id:{}" ,id);

执行编辑员工功能进行验证,通过观察控制台输出可以发现,一次请求对应的线程id是相同的:
在这里插入图片描述
什么是ThreadLocal?

ThreadLocal并不是一个Thread,而是Thread的局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

ThreadLocal常用方法:

public void set(T value) 设置当前线程局部变量的值
public T get() 返回当前线程所对应的线程局部变量的值
我们可以在LoginCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值(用户id),然后在MyMetaObjectHandler的updateFill方法中调用ThreadLocal的get方法来获得当前线程所对应的线程局部变量的值(用户id)。

1.2.4实现步骤:

1、编写BaseContext工具类,基于ThreadLocal封装的工具类

/*** 基于ThreadLocal封装的工具类,用于保存和获取当前登录用户的id*/
public class BaseContext {private static ThreadLocal<Long> threadLocal=new ThreadLocal<>();public static void setCurrentId(Long id){threadLocal.set(id);}public static Long getCurrentId(){return threadLocal.get();}
}

2、在LogincheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id

if (request.getSession().getAttribute("employee") != null) {log.info("用户已登录,用户id为:{}", request.getSession().getAttribute("employee"));Long empId= (Long) request.getSession().getAttribute("employee");BaseContext.setCurrentId(empId);filterChain.doFilter(request, response);return;
}

3、在MyMeta0bjectHandler的方法中调用BaseContext获取登录用户的id

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {//插入时自动填充@Overridepublic void insertFill(MetaObject metaObject) {metaObject.setValue("createTime", LocalDateTime.now());metaObject.setValue("updateTime", LocalDateTime.now());metaObject.setValue("createUser",BaseContext.getCurrentId());metaObject.setValue("updateUser",BaseContext.getCurrentId());}//更新时自动填充@Overridepublic void updateFill(MetaObject metaObject) {log.info(metaObject.toString());metaObject.setValue("updateTime",LocalDateTime.now());metaObject.setValue("updateUser",BaseContext.getCurrentId());}
}

2、新增分类

2.1、需求分析

后台系统中可以管理分类信息,分类包括两种类型,分别是菜品分类和套餐分类。当我们在后台系统中添加菜品时需要选择一个菜品分类,当我们在后台系统中添加一个套餐时需要选择一个套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐。

在这里插入图片描述
在这里插入图片描述

2.2、数据模型

新增分类,其实就是将我们新增窗口录入的分类数据插入到category表,表结构如下:
在这里插入图片描述

2.3、整个程序的执行过程

1、页面(backend/page/category/list.html)发送ajax请求,将新增分类窗口输入的数据以json形式提交到服务端

2、服务端Controller接收页面提交的数据并调用Service将数据进行保存

3、Service调用Mapper操作数据库,保存数据

可以看到新增菜品分类和新增套餐分类请求的服务端地址和提交的json数据结构相同,所以服务端只需要提供一个方法统一处理即可

在这里插入图片描述
后端接收请求新增数据到数据库

//新增分类
@PostMapping
public R<String> save(@RequestBody Category category){log.info("category:{}",category);categoryService.save(category);return R.success("新增分类成功");
}

3、分类信息分页查询

3.1、需求分析

系统中的分类很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。

3.2、代码开发

在开发代码之前,需要梳理一下整个程序的执行过程:

1、页面发送ajax请求,将分页查询参数(page.pageSize)提交到服务端

2、服务端Controller接收页面提交的数据并调用Service查询数据

3、Service调用Mapper操作数据库,查询分页数据

4、Controller将查询到的分页数据响应给页面

5、页面接收到分页数据并通过ElementUI的Table组件展示到页面上

在这里插入图片描述

@GetMapping("/page")
public R<Page> page(int page, int pageSize) {//构造分页构造器Page<Category> pageInfo=new Page<>(page,pageSize);//构造条件构造器LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>();//添加排序条件,根据sort进行排序queryWrapper.orderByAsc(Category::getSort);//进行分页查询categoryService.page(pageInfo,queryWrapper);return R.success(pageInfo);
}

4、删除分类

4.1、需求分析

在分类管理列表页面,可以对某个分类进行删除操作。需要注意的是当分类关联了菜品或者套餐时,此分类不允许删除。

1、页面发送ajax请求,将参数(id)提交到服务端

在这里插入图片描述
2、服务端Controller接收页面提交的数据并调用Service删除数据

3、Service调用Mapper操作数据库

//根据id删除分类
@DeleteMapping
public R<String> delete(Long ids){log.info("删除分类,id为{}",ids);categoryService.removeById(ids);//代码完善之后categoryService.remove(ids);return R.success("分类信息删除成功");
}

4.2、代码完善

前面我们已经实现了根据id删除分类的功能,但是并没有检查删除的分类是否关联了菜品或者套餐,所以我们需要进行功能完善。
要完善分类删除功能。

在CategoryService添加remove方法

public interface CategoryService extends IService<Category> {public void remove(Long id);
}

在CategoryServicelmpl实现remove方法

@Service
public class CategoryServicelmpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {@Autowiredprivate DishService dishService;@Autowiredprivate SetmealService setmealService;@Overridepublic void remove(Long id) {LambdaQueryWrapper<Dish> dishLambdaQueryWrapper=new LambdaQueryWrapper<>();//添加查询条件,根据分类id进行查询dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);int count1 = dishService.count(dishLambdaQueryWrapper);//查询当前分类是否关联菜品,如果已经关联,抛出业务异常if(count1>0){//已经关联菜品,抛出业务异常throw new CustomException("已经关联菜品,不能删除");}//查询当前分类是否关联了套餐,如果已经关联,抛出业务异常LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper=new LambdaQueryWrapper<>();//添加查询条件,根据分类id进行查询setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);int count2 = setmealService.count(setmealLambdaQueryWrapper);if(count2>0){//已经关联套餐,抛出业务异常throw new CustomException("已经关联套餐,不能删除");}//正常删除分类super.removeById(id);}
}

定义异常类CustomException

public class CustomException extends RuntimeException{public CustomException(String message){super(message);}
}

在全局异常处理器GlobalExceptionHandler添加

//进行异常处理方法
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandler(CustomException ex){log.error(ex.getMessage());return R.error(ex.getMessage());
}

总结

day3完成的是公共字段填充与新增删除分类主要学习到的有
1、当多个表中有多个公共字段需要赋值可以使用mp提供的公共字段填充功能
2、ThreadLocal是什么,有什么作用
3、自定义异常

相关文章:

springboot项目外卖管理 day03-公共字段填充与新增删除分类

文章目录 一、公共字段自动填充1.1、问题分析1.2、代码实现1.2.1、在实体类的属性上加入TableField注解&#xff0c;指定自动填充的策略1.2.2按照框架要求编写元数据对象处理器&#xff0c;在此类中统一为公共字段赋值&#xff0c;此类需要实现MetaObjectHandler接口1.2.3 功能…...

Nginx:Tomcat部署及优化(一)

Nginx&#xff1a;Rewrite 一、Tomcat介绍1.1 Tomcat 简介1.2 Tomcat 核心的组件1.2.1 什么是 servlet1.2.2 什么是 JSP 1.3 Tomcat 功能组件结构1.3.1 Container 结构分析 1.4 Tomcat 请求过程 二、Tomcat 服务部署三、Tomcat 虚拟主机配置四、Tomcat多实例部署 一、Tomcat介绍…...

Docker Swarm 集群搭建和使用 —— 筑梦之路

简单介绍 swarm 集群由管理节点(Manager)和工作节点(Worker)构成。 管理节点:主要负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。诸如监控集群状态、分发任务至工作节点等操作。 工作节点:主要负责执行运行服务的任务。 官方文档:docker swarm…...

是否需要更换CRM系统如何评估?如何确保更换成功?

很多企业在使用CRM客户管理系统的过程中&#xff0c;并没有达到预期的效果&#xff0c;甚至出现了实施失败的情况。部分企业可能会考虑更换CRM系统&#xff0c;以期获得更好的结果。但是&#xff0c;更换CRM系统是否值得呢&#xff1f;下面我们就来说说。 一、是否该更换CRM …...

CSDN竞赛57期题解

总结 交卷时一看才六十多分还有点吃惊&#xff0c;一看非编程题部分还是丢了二十分。填空题是这类竞赛最大的诟病&#xff0c;答案是名词的必然不唯一&#xff0c;答案需要计算的给定的参考答案必然计算错误&#xff0c;更离谱的是题目出成这样&#xff0c;反馈后官方竟然一点…...

springboot+vue.js大学生竞赛报名作品评分管理系统

本文介绍了大学生竞赛管理系统的开发全过程。通过分析大学生竞赛管理系统管理的不足&#xff0c;创建了一个计算机管理大学生竞赛管理系统的方案。文章介绍了大学生竞赛管理系统的系统分析部分&#xff0c;包括可行性分析等&#xff0c;系统设计部分主要介绍了系统功能设计和数…...

Python爱好者的自我修养(1):简单输入与输出

Python简单输入与输出 1.输出1.1 简单输出1.2 转义字符1.2.1 定义1.2.2 常见的转义字符用法 2.输入3.温馨提示 终于…… 终于…… 我开始玩Python了 &#xff08;不是C不学了哈&#xff0c;C还是照更~&#xff09; 今天先来简单讲下输入和输出 1.输出 1.1 简单输出 输出的函…...

java SSM 摄影作品网站myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM 摄影作品网站系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…...

[Maven高级]->近万字文章带你深入了解Maven

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;JavaEE ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&…...

物联网Lora模块从入门到精通(五)光照与温湿度传感器

一、前言 在程序开发中&#xff0c;光照与温湿度的获取是十分常见与重要的&#xff0c;本文我们主要是使用M21温湿度光照三合一传感器&#xff0c;其中温湿度数据通过协议获取&#xff0c;而光照通过ADC获取。 二、代码实现 本文内容较为简单&#xff0c;且后续文章将在本文基…...

【网络编程】计算机网络基础知识总结 | 运输层 |TCP协议

文章目录 前言一、计算机网络层次结构二、网络层三、运输层3.1、TCP/IP协议介绍3.2、端口&#xff08;协议端口号&#xff09;3.3、套接字3.4、TCP实现原理3.4.1、TCP的特点3.4.2、停止等待协议3.4.3、滑动窗口协议3.4.4、拥塞控制3.4.5、TCP连接的三个阶段 3.5、UDP实现原理 前…...

python关键知识点

1. 变量&#xff1a;在程序中存储值或对象的名称。 2. 数据类型&#xff1a;指变量的数据类型&#xff0c;例如 str、int、float、list、tuple、dict、set 等。 3. 操作符&#xff1a;表示运算符号&#xff0c;例如加号 和减号 -。 4. 循环&#xff1a;通过重复执行某个代码…...

c# 从零到精通 数组的操作-将两个一维数组合并成一个二维数组

c# 从零到精通 数组的操作-将两个一维数组合并成一个二维数组 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Test07 { class Program { static void Main(string[] args) { //定义两个一维数组 int[] arr1 new int[] {…...

Linux目录结构(与window目录结构对比+绝对路径和相对路径)

一、Linux目录结构 Linux目录结构是一个标准化的文件系统层次结构&#xff0c;非常有组织性并且易于管理。而与Windows 操作系统不同&#xff0c;Linux将所有文件和设备都组织在一个单一的根目录下。以下是Linux的标准目录结构&#xff1a; /&#xff1a;根目录&#xff0c;包含…...

投票活动小程序开发搭建

由于小程序是基于微信开发者工具编写的&#xff0c;因此我先介绍一下需要使用的工具和技术&#xff1a; - 微信开发者工具&#xff1a;用于开发、调试和发布小程序。 - 小程序云开发&#xff1a;用于存储数据和进行后端逻辑处理。 - uni-app框架&#xff1a;uni-app 是一个使…...

代码随想录day18

513.找树左下角的值 本题用前中后序都可以&#xff08;都是先遍历左再遍历右&#xff0c;保证最后一定是左侧的节点&#xff09;&#xff0c;因为没有中节点的处理逻辑&#xff0c;用全局变量记录最大深度&#xff0c;只要遇到叶子结点并且当前深度比最大深度大&#xff0c;就更…...

QT+OpenGL高级光照 Blinn-Phong和Gamma校正

QTOpenGL高级光照1 本篇完整工程见gitee:QtOpenGL 对应点的tag&#xff0c;由turbolove提供技术支持&#xff0c;您可以关注博主或者私信博主 Blinn-Phong 冯氏光照&#xff1a;视线与反射方向之间的夹角不小于90度&#xff0c;镜面光分量会变成0.0&#xff08;不是很合理&am…...

【Ubuntu系统内核更新与卸载】

【Ubuntu系统内核更新与卸载】 1. 前言2. 内核安装2.1 系统更新2.2 官网下载 3. 内核卸载3.1 需求分析3.2 卸载方法 1. 前言 我们在搭建环境时常常遇到内核版本不匹配的问题&#xff0c;需要我们安装新的内核版本&#xff1b;有时又会遇到在安装软件时报错boot空间已满无法安装…...

RL - 强化学习 马尔可夫奖励过程 (MRP) 的状态价值

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131084795 GitHub 源码: https://github.com/SpikeKing/Reinforcement-Learning-Algorithm 马尔可夫奖励过程 (MRP) 的状态价值是指在某…...

Mybatis之批处理流式查询

文章目录 1 批处理查询1.1 引言1.2 流式查询1.2.1 定义1.2.2 流式查询接口1.2.3 使用流式查询关闭问题1.2.3.1 SqlSessionFactory1.2.3.2 TransactionTemplate1.2.3.3 Transactional 注解 1.2.4 完整示例1.2.4.1 mapper接口和SQL1.2.4.2 Service操作 1.3 游标查询1.3.1 定义1.3…...

ARM GICv5 ITS_CR1寄存器配置与中断优化实践

1. ARM GICv5 ITS架构概述中断控制器是现代计算机系统中的关键组件&#xff0c;负责管理和分发硬件中断请求。ARM GICv5架构中的Interrupt Translation Service (ITS)模块通过创新的设备ID和事件ID映射机制&#xff0c;实现了灵活高效的中断路由方案。ITS作为GICv5的可选扩展组…...

3PEAK思瑞浦 TP2262-TSR TSSOP8 运算放大器

特性 供电电压:3V至36V 低供电电流:每通道最大1000A差分输入电压范围至电源轨&#xff0c;可作为比较器工作 输入轨至-Vs&#xff0c;轨到轨输出快速响应:3.5MHz带宽&#xff0c;15V/us斜率&#xff0c;100ns过载恢复时间 低失调电压:-25C时最大2mV-2.5 mV在-40C至85C(最大) -3…...

基于Ansible Playbook的Kubernetes集群自动化部署实践

1. 项目概述&#xff1a;一个为Kubernetes集群部署而生的自动化剧本如果你和我一样&#xff0c;长期在运维和DevOps一线摸爬滚打&#xff0c;那么对Kubernetes集群的初始化部署一定又爱又恨。爱的是它带来的强大编排能力&#xff0c;恨的是那套繁琐、易错、文档分散的kubeadm i…...

深度相机三剑客:TOF、双目与结构光的场景化选型指南

1. 深度相机技术入门&#xff1a;从原理到应用 第一次接触深度相机时&#xff0c;我被各种技术名词搞得晕头转向。TOF、双目、结构光听起来都很高大上&#xff0c;但到底有什么区别&#xff1f;经过多年项目实战&#xff0c;我发现这三种技术就像不同的"眼睛"&#…...

3步解锁网易云音乐NCM文件:ncmdump让你的音乐自由播放

3步解锁网易云音乐NCM文件&#xff1a;ncmdump让你的音乐自由播放 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的加密NCM文件无法在其他设备播放而烦恼吗&#xff1f;ncmdump作为一款专业的网易云音乐NCM文件…...

ARM DAP调试架构核心机制与实践指南

1. ARM调试访问端口(DAP)架构解析调试访问端口(Debug Access Port, DAP)是ARM调试架构中的核心组件&#xff0c;它作为调试器与芯片内部调试资源的桥梁&#xff0c;提供了标准化的访问接口。DAP的设计遵循ARM Debug Interface v5.1(ADIv5.1)规范&#xff0c;支持两种物理接口协…...

从CMake报错到编译成功:一站式解决absl依赖配置难题

1. 当CMake突然报错&#xff1a;absl依赖缺失的紧急处理 第一次看到这个报错时&#xff0c;我正赶着在截止日期前完成gRPC服务的部署。控制台突然弹出的红色错误让我心头一紧&#xff1a;"Could not find a package configuration file provided by absl"。这种依赖缺…...

用LangChain Tools打造会自主查资料的GPT模型

1. 项目概述&#xff1a;为什么你需要一个“会自己查资料”的GPT模型&#xff1f;我第一次在ChatGPT里输入“2024年巴黎奥运会新增了哪些比赛项目&#xff1f;”时&#xff0c;得到的回复是&#xff1a;“我的训练数据截止于2021年9月&#xff0c;无法提供2024年的最新信息。”…...

别再死记硬背了!用这三个等效模型,轻松搞定二极管电路分析(附典型例题)

二极管电路分析的三大等效模型实战指南 在电子工程和嵌入式开发领域&#xff0c;二极管作为基础元件却常常成为初学者的"拦路虎"。面对复杂的二极管电路&#xff0c;很多人陷入死记硬背的困境——记住各种电路的输出结果&#xff0c;却无法理解背后的分析逻辑。这种学…...

libiec61850实战:客户端如何动态遍历未知设备的数据模型

1. 理解libiec61850动态模型遍历的核心场景 在工业自动化系统中&#xff0c;经常会遇到需要对接未知型号IED设备的情况。想象一下你作为系统集成商&#xff0c;现场新安装了一台保护装置或智能传感器&#xff0c;但手头没有它的SCL配置文件&#xff08;.cid或.scd&#xff09;。…...