Java Web项目—餐饮管理系统Day04-公共字段填充与菜品分类管理

文章目录

      • 1. 公共字段填充
      • 菜品分类管理
        • 1. 搭建框架
        • 2. 编写功能
          • 2-1. 分页查询
          • 2-2 插入
          • 2-3 更新
          • 2-4 删除

1. 公共字段填充

前面我们已经完成了后台系统的员工管理功能开发,在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间和修改人等字段。这些字段属于公共字段,也就是很多表中都有这些字段. 因此可以设置一个自动填充的功能类.

基本步骤是:

  1. 为公共自动填充字段添加 @TableField 注解, 如下(Employee), 注意指明填充条件fill:
     @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;
    
  2. 编写 FFMetaObjHandler 类, 它交给 Bean 容器进行管理, 同时实现 MetaObjectHandler接口, 重写 insertFill 方法和 updateFill 方法.
    核心的方法是 setValue, 设置字段名对应的值
    package com.rain.reggie.common;
    @Component
    @Slf4j
    public class FFMetaObjHandler implements MetaObjectHandler {/*** 公共字段填充*/@Overridepublic void insertFill(MetaObject metaObject) {log.info("公共字段填充-[insert]: {}", metaObject.toString());metaObject.setValue("createTime", LocalDateTime.now());metaObject.setValue("updateTime", LocalDateTime.now());metaObject.setValue("createUser", BaseContext.getId());metaObject.setValue("updateUser", BaseContext.getId());}@Overridepublic void updateFill(MetaObject metaObject) {log.info("公共字段填充-[update]: {}", metaObject.toString());metaObject.setValue("updateTime", LocalDateTime.now());metaObject.setValue("updateUser", BaseContext.getId());}
    }
    
  3. 去掉 controller 层 insert update 方法中关于更新 这几个字段的操作:
    注意参数 HttpServletRequest request 也被删去了.
     @PutMappingpublic R<String> update(@RequestBody Employee employee){log.info("更新员工信息: {}", employee.toString());employeeService.updateById(employee);return R.success("更新成功");}@PostMappingpublic R<String> insert(@RequestBody Employee employee){log.info("新增员工信息: {}", employee.toString());String pwd = DigestUtils.md5DigestAsHex("123456".getBytes());employee.setPassword(pwd);employeeService.save(employee);return R.success("添加新员工成功");}
    

需要注意:
操作用户是当前登录的用户, 而为了获取当前登录用户的ID, 通常做法是通过 request 的 session 存储进行访问:

Long user_id = (Long) request.getSession().getAttribute("employee");

然而, FFMetaObjHandler 类并不在三层结构之内, 因此无法获取到 request 对象. 一种可行的解决方法是使用 ThreadLocal 变量.
ThreadLocal 变量的作用是保存线程的一个局部变量, 对于同一个线程其存取的变量是一致的, 可用于线程内的共享:

package com.rain.reggie.common;public class BaseContext {private static ThreadLocal<Long> idMemory = new ThreadLocal<>();public static void setId(Long id){idMemory.set(id);}public static Long getId(){return idMemory.get();}
}

其可行之处在于:

  1. 客户端发送的每次http请求, 对应的在服务端都会分配一个新的线程来处理.
  2. 在处理过程中以下方法都属于相同的一个线程:
    LoginCheckFilter.doFilter
    EmploveeController.update
    MyMetaObjectHandler.updateFill
    这一点可以在这些方法中打印线程id来验证. 对于前端的每次请求, 首先要经过过滤器验证是否已登录, 若已登录, 放行后来到控制层.
    依据请求的路径和请求方式进入对应方法体, 并传入携带的参数. 例如 update 方法, 它在调用 employeeService.updateById 方法时会去执行 FFMetaObjHandler.updateFill 方法, 该方法又调用 BaseContext 类的 get 方法获取到 idMemory 中存储的 id 值.
    注意一个细节, 也即调用 setId 的时机, 不同于 http-session, ThreadLocal 变量是针对于线程的, 因此每次请求都需要设置一遍, 而不是仅仅在登录请求(通过后)处理中设置一次. 也即应当在过滤器中设置:
if (null != request.getSession().getAttribute("employee")){log.info("已登录");Long user_id = (Long) request.getSession().getAttribute("employee");BaseContext.setId(user_id);filterChain.doFilter(request, response);return;
}

插入数据, 进行功能测试:

obyda
切换错误
17826534892
738391474891840291

菜品分类管理

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

id
type
name
sort
create_time
update_time
create_user
update_user

name 是分类名称, type 是分类类型, 1=菜品分类, 2=套餐分类.
sort 是在展示页面的展示顺序

1. 搭建框架

包括:

  1. 实体类 Category
package com.rain.reggie.entity;import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;import java.io.Serializable;
import java.time.LocalDateTime;@Data
public class Category implements Serializable {private static final long serialVersionUID = 1L;private Long id;//类型 1 菜品分类 2 套餐分类private Integer type;//分类名称private String name;//顺序private Integer sort;@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. Mapper
package com.rain.reggie.mapper;@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
  1. Service 接口及实现类
package com.rain.reggie.service;public interface CategoryService extends IService<Category> {
}

package com.rain.reggie.service.impl;@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
}
  1. controller 层
@RestController
@Slf4j
@RequestMapping("category")
public class CategoryController {@Autowiredprivate CategoryService service;
}
2. 编写功能
2-1. 分页查询

注意, 此前忽略(漏听??)了一个细节, 就是查询的总条目数量为0. 尽管页面上也能展示出记录
这是由于未设置 MybatisPlus 的配置类, 它规定了 MybatisPlus 进行分页参数填充的方式:

package com.rain.reggie.config;@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor paginationInterceptor() {MybatisPlusInterceptor  interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;}
}

加入配置类后, 接着编写分页方法:

@GetMapping("page")
public R<Page> page(int page, int pageSize){Page<Category> info = new Page<>(page, pageSize);LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();wrapper.orderByAsc(Category::getSort);service.page(info, wrapper);return R.success(info);
}
2-2 插入

注意公共字段已自动填充:

@PostMapping
public R<String> insert(@RequestBody Category category){log.info("category={}", category);service.save(category);return R.success("添加成功");
}   
2-3 更新
@PutMapping
public R<String> update(@RequestBody Category category){log.info("category={}", category);service.updateById(category);return R.success("更新成功 ");
}
2-4 删除

菜品分类: 是指菜品所属的类别, 例如: 浙菜、湘菜、川菜等等.
套餐分类: 是指菜品所属的套餐, 例如: 亲子套餐、极意双人餐、超值单人餐等等
在对分类的类别执行删除操作时, 通常的逻辑是:
假如某些菜品包含在某个分类下, 则该分类不应被删除(无法删除)
因此删除方法需要在 Service 层自己实现
为此, 需要查询在 dish 表中是否包含该 category 的条目.

建立 dish 的框架:

package com.rain.reggie.entity;@Data
public class Dish implements Serializable {private static final long serialVersionUID = 1L;private Long id;//菜品名称private String name;//菜品分类idprivate Long categoryId;//菜品价格private BigDecimal price;//商品码private String code;//图片private String image;//描述信息private String description;//0 停售 1 起售private Integer status;//顺序private Integer sort;@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;
}

当查询到记录时, 就抛出一个自定义业务异常:

package com.rain.reggie.common;public class BusinessException extends RuntimeException{public BusinessException(String mes){super(mes);}
}

在业务层添加 removeWithDish 方法:

@Override
@Transactional
public void removeWithDish(Long ids) {LambdaQueryWrapper<Dish> dishWrapper = new LambdaQueryWrapper<>();dishWrapper.eq(Dish::getCategoryId, ids);long cnt = dishService.count(dishWrapper);if (cnt > 0)throw new BusinessException("分类冲突");removeById(ids);
}

控制层则变得简单:

@DeleteMapping
public R<String> remove(Long ids){log.info("category to be del: {}", ids);service.removeWithDish(ids);return R.success("删除成功");
}

注意, 在此前的全局异常处理器中加入 BusinessException 处理逻辑:

@ExceptionHandler(BusinessException.class)
public R<String> exceptionHandler(BusinessException e){String message = e.getMessage();log.error("Exception occurred: {}", message);return R.error(message);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/748131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智慧工地管理平台APP源码基于物联网、云计算、大数据等技术

目录 ​系统特点 智慧工地云平台功能模块 1、基础数据管理 2、考勤管理 3、安全隐患管理 4、视频监控 5、塔吊监控 6、升降机监控 7、管理分析报表 8、移动端数据推送 9、数据接收管理 智慧工地管理平台系统基于物联网、云计算、大数据等技术&#xff0c;助力工地管理…

wsl ubuntu 安装cuda环境

wsl ubuntu 安装cuda环境: CUDA Toolkit 11.6 Downloads | NVIDIA DeveloperDownload CUDA Toolkit 11.6 for Linux and Windows operating systems.https://developer.nvidia.com/cuda-11-6-0-download-archive?target_os=Linux&target_arch=x86_64&Distribution=W…

前端工程化:提升开发效率的秘诀

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

安卓UI面试题 31-35

31. 简述 Paint类中主要绘制方法 ?1、图形绘制: setArgb(int a, int r, int g, int b):设置绘制的颜色,a表示透明度,r、g、b表示颜色值; setAlpha(int a):设置绘制的图形的透明度; setColor(int color):设置绘制的颜色; setAntiAlias(boolean a):设置是否使用抗锯齿…

Python Web开发记录 Day11:Django part5 管理员管理

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、创建管理员表2、管理员列表3、添加管理员①添…

神策分析 Copilot 成功通过网信办算法备案,数据分析 AI 化全面落地

近日&#xff0c;神策数据严格遵循《互联网信息服务深度合成管理规定》&#xff0c;已完成智能数据问答算法备案。该算法基于大模型技术&#xff0c;专注于为客户提供数据指标查询和数据洞察方面的专业回答。 神策分析 Copilot 运用神策数据智能数据问答算法&#xff0c;聚焦分…

stm32-定时器输出比较PWM

目录 一、输出比较简介 二、PWM简介 三、输出比较模式实现 1.输出比较框图(以通用定时器为例) 2.PWM基本结构 四、固件库实现 1.程序1&#xff1a;PWM呼吸灯 2.程序2&#xff1a;PWM驱动直流电机 3.程序3&#xff1a;控制舵机 一、输出比较简介 死区生成和互补输出一般…

(())双圆结构扩展

1.(())双圆结构扩展介绍 使用linux下(())双圆结构扩展并计算一个算术表达式的值时&#xff0c;如果表达式的结果为0&#xff0c;那么返回的退出状态码为1&#xff0c;或者是“假/false”&#xff1b;如果表达式的结果为一个非零值&#xff0c;那么返回的退出状态码为0&#xf…

深度学习每周学习总结P1(pytorch手写数字识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结1. 数据导入部分2. 模型构建部分3. 训练前的准备4. 定义训练函数5. 定义测试函数6. 训练过程 0. 总结 总结: 数据导入部分&a…

Hive中的explode函数、posexplode函数与later view函数

1.概述 在离线数仓处理通过HQL业务数据时&#xff0c;经常会遇到行转列或者列转行之类的操作&#xff0c;就像concat_ws之类的函数被广泛使用&#xff0c;今天这个也是经常要使用的拓展方法。 2.explode函数 2.1 函数语法 -- explode(a) - separates the elements of array …

014 Linux_同步

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;Linux &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多操作系统知识 文章目录 前言一、死锁&#xff08;1&#xff09;死锁概念 二、同步&#xff08;1&#xff09;同步概念&#xff…

计算机考研|双非一战135上岸,408经验分享+复盘

计算机专业的同学真的别想的太天真&#xff01; 相比于其他专业&#xff0c;计算机专业的同学其实还是很有优势的 但是现在随着计算机专业的同学越来越多&#xff0c;找工作的困难程度以及学历自然而然被卷起来了 以前的算法岗基本要求在本科以上&#xff0c;现在基本都是非92研…

Spring Boot 多媒体(音频/视频)文件处理FFmpegFrameGrabber 方法(例子:获取视频总时长)

1.pom.xml 坐标 <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.6</version></dependency> 2.FFmpegFrameGrabber类提供了多种方法来处理多媒体文件&#xff0c;以下是一…

主成分分析用于数据降维

主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;是一种常用的数据降维算法。它通过线性变换将原始数据转化为一组互相不相关的主成分&#xff0c;这些主成分能够最大程度地保留原始数据的信息。 数据降维是为了减少数据集中的特征数量&#x…

家电工厂5G智能制造数字孪生可视化平台,推进家电工业数字化转型

家电5G智能制造工厂数字孪生可视化平台&#xff0c;推进家电工业数字化转型。随着科技的飞速发展&#xff0c;家电行业正迎来一场前所未有的数字化转型。在这场制造业数字化转型中&#xff0c;家电5G智能制造工厂数字孪生可视化平台扮演着至关重要的角色。本文将从数字孪生技术…

【数据库】数据库介绍

文章目录 一、数据库介绍二、SQL分类 一、数据库介绍 什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a; 文件的安全性问题 文件不利于数据查询和管理 文件不利于存储海量数据 文件在程序中控制不方便 数据库存…

提交数据加快百度搜索引擎收录

百度站长工具做了更新&#xff0c;百度收录的地址分享如下&#xff0c;新站点提交后&#xff0c;可以加快百度收录。 普通收录_加快网站内容抓取&#xff0c;快速提交数据工具_站长工具_网站支持_百度搜索资源平台普通收录工具可实时向百度推送数据&#xff0c;创建并提交site…

git 安装、创建仓库、常用命令、克隆下载、上传项目、删除分支 -- 一篇文章总结

一、git安装 1、git安装地址&#xff1a;https://git-scm.com/downloads 2、选择操作系统 3、安装自己系统对应的操作位数 4、等待下载完&#xff0c;一路next安装就可以了 5、安装完成后&#xff0c;在任意文件夹点击右键&#xff0c;看到下图说明安装成功 二、创建仓库 1…

云原生(二)、Docker基础

Docker Docker 是一种开源的容器化平台&#xff0c;用于开发、部署和运行应用程序。它允许开发者将应用程序及其所有依赖项打包到一个可移植的容器中&#xff0c;这个容器可以在任何支持 Docker 的环境中运行&#xff0c;无论是开发人员的个人笔记本电脑、测试环境、生产服务器…

ROS Kinetic通信编程:话题、服务、动作编程

文章目录 一、话题编程二、服务编程三、动作编程 接上篇&#xff0c;继续学习ROS通信编程基础 一、话题编程 步骤&#xff1a; 创建发布者 初始化ROS节点向ROS Master注册节点信息&#xff0c;包括发布的话题名和话题中的消息类型按照一定频率循环发布消息 创建订阅者 初始化…