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

springboot苍穹外卖实战:五、公共字段自动填充(aop切面实现)+新增菜品功能+oss

公共字段自动填充

不足

比起瑞吉外卖中的用自定义元数据类型+mybatisplus的实现,这里使用的是aop切面实现,会麻烦许多,建议升级为mp。

定义好数据库操作类型

sky-common中已经定义好,OperationType。

自定义注解 AutoFill

com.sky.annotation.AutoFill

/*** 自定义注解,用于标识某个方法需要进行功能字段自动填充处理*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//数据库操作类型:UPDATE INSERTOperationType value();
}

自定义切面 AutoFillAspect

com.sky.aspect.AutoFillAspect


@Slf4j
public class AutoFillAspect {/*** 切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut(){}/*** 前置通知,在通知中进行公共字段的赋值*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint){//可先进行调试,是否能进入该方法 提前在mapper方法添加AutoFill注解log.info("开始进行公共字段自动填充...");//步骤一:获取到当前被拦截的方法上的数据库操作类型MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获得方法签名对象AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象OperationType operationType = autoFill.value();//获得数据库操作类型//步骤二:获取到当前被拦截的方法的参数,即实体对象Object[] args = joinPoint.getArgs();if(args == null || args.length == 0){return;}Object entity = args[0];//步骤三:准备赋值的数据LocalDateTime now = LocalDateTime.now();Long currentid = BaseContext.getCurrentId();/*步骤四:根据当前不同的操作类型,为对应的属性通过反射来赋值。之所以不直接通过set等方法赋值,是因为获取到的实体类对象可能不一样。譬如这里该项目就可能为员工或者菜品使用set方法需要强转为某个实体类对象。*/if(operationType == OperationType.INSERT){try{Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为对象属性赋值setCreateTime.invoke(entity,now);setCreateUser.invoke(entity,currentid);setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentid);} catch (Exception e) {e.printStackTrace();}}else if(operationType == OperationType.UPDATE) {//为2个公共字段赋值try {Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为对象属性赋值setUpdateTime.invoke(entity, now);setUpdateUser.invoke(entity, currentid);} catch (Exception e) {e.printStackTrace();}}}
}

在mapper上增加自定义注解autofill

com.sky.mapper.CategoryMapper

    @AutoFill(value = OperationType.INSERT)void insert(Category category);@AutoFill(value = OperationType.UPDATE)void update(Category category);

com.sky.mapper.EmployeeMapper

 	@AutoFill(value = OperationType.INSERT)void insert(Employee employee);@AutoFill(value = OperationType.UPDATE)void update(Employee employee);

删除/注释掉业务层原先为公共字段赋值的语句

com.sky.service.impl.CategoryServiceImpl

/*** 分类业务层*/
@Service
@Slf4j
public class CategoryServiceImpl implements CategoryService {@Autowiredprivate CategoryMapper categoryMapper;@Autowiredprivate DishMapper dishMapper;@Autowiredprivate SetmealMapper setmealMapper;/*** 新增分类* @param categoryDTO*/public void save(CategoryDTO categoryDTO) {Category category = new Category();//属性拷贝BeanUtils.copyProperties(categoryDTO, category);//分类状态默认为禁用状态0category.setStatus(StatusConstant.DISABLE);//设置创建时间、修改时间、创建人、修改人
//        category.setCreateTime(LocalDateTime.now());
//        category.setUpdateTime(LocalDateTime.now());
//        category.setCreateUser(BaseContext.getCurrentId());
//        category.setUpdateUser(BaseContext.getCurrentId());categoryMapper.insert(category);}/*** 分页查询* @param categoryPageQueryDTO* @return*/public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {PageHelper.startPage(categoryPageQueryDTO.getPage(),categoryPageQueryDTO.getPageSize());//下一条sql进行分页,自动加入limit关键字分页Page<Category> page = categoryMapper.pageQuery(categoryPageQueryDTO);return new PageResult(page.getTotal(), page.getResult());}/*** 根据id删除分类* @param id*/public void deleteById(Long id) {//查询当前分类是否关联了菜品,如果关联了就抛出业务异常Integer count = dishMapper.countByCategoryId(id);if(count > 0){//当前分类下有菜品,不能删除throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_DISH);}//查询当前分类是否关联了套餐,如果关联了就抛出业务异常count = setmealMapper.countByCategoryId(id);if(count > 0){//当前分类下有菜品,不能删除throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL);}//删除分类数据categoryMapper.deleteById(id);}/*** 修改分类* @param categoryDTO*/public void update(CategoryDTO categoryDTO) {Category category = new Category();BeanUtils.copyProperties(categoryDTO,category);//        //设置修改时间、修改人
//        category.setUpdateTime(LocalDateTime.now());
//        category.setUpdateUser(BaseContext.getCurrentId());categoryMapper.update(category);}/*** 启用、禁用分类* @param status* @param id*/public void startOrStop(Integer status, Long id) {Category category = Category.builder().id(id).status(status)
//                .updateTime(LocalDateTime.now())
//                .updateUser(BaseContext.getCurrentId()).build();categoryMapper.update(category);}/*** 根据类型查询分类* @param type* @return*/public List<Category> list(Integer type) {return categoryMapper.list(type);}
}

com.sky.service.impl.EmployeeServiceImpl

@Service
public class EmployeeServiceImpl implements EmployeeService {@Autowiredprivate EmployeeMapper employeeMapper;/*** 员工登录** @param employeeLoginDTO* @return*/public Employee login(EmployeeLoginDTO employeeLoginDTO) {String username = employeeLoginDTO.getUsername();String password = employeeLoginDTO.getPassword();//1、根据用户名查询数据库中的数据Employee employee = employeeMapper.getByUsername(username);//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)if (employee == null) {//账号不存在throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);}//密码比对//后端md5加密password = DigestUtils.md5DigestAsHex(password.getBytes());if (!password.equals(employee.getPassword())) {//密码错误throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);}if (employee.getStatus() == StatusConstant.DISABLE) {//账号被锁定throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);}System.out.println("password"+password);System.out.println("username"+username);//3、返回实体对象return employee;}/*** 员工登录** @param employeeDTO* @return*/public void save(EmployeeDTO employeeDTO) {Employee employee = new Employee();BeanUtils.copyProperties(employeeDTO, employee);employee.setStatus(StatusConstant.ENABLE);employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));//        employee.setCreateTime(LocalDateTime.now());
//        employee.setUpdateTime(LocalDateTime.now());
//
//        employee.setCreateUser(BaseContext.getCurrentId());
//        employee.setUpdateUser(BaseContext.getCurrentId());employeeMapper.insert(employee);}/*** 分页查询* @param employeePageQueryDTO* @return*/public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);long total = page.getTotal();List<Employee> records = page.getResult();return new PageResult(total, records);}/*** 启用禁用员工账号*/public void startOrStop(Integer status, Long id){Employee employee = Employee.builder().id(id).status(status).build();employeeMapper.update(employee);}/*** 根据id查员工* @param id* @return*/public Employee getById(Long id){Employee employee = employeeMapper.getById(id);employee.setPassword("****");return employee;}/*** 编辑员工* @param employeeDTO*/public void update(EmployeeDTO employeeDTO){Employee employee = new Employee();BeanUtils.copyProperties(employeeDTO, employee);
//        employee.setUpdateTime(LocalDateTime.now());
//        employee.setUpdateUser(BaseContext.getCurrentId());employeeMapper.update(employee);}
}

新增菜品

接口设计

不懂为什么要设计成逻辑外键,而不是物理外键。

业务规则:

  • 菜品名称必须是唯一的
  • 菜品必须属于某个分类下,不能单独存在
  • 新增菜品时可以根据情况选择菜品的口味
  • 每个菜品必须对应一张图片

oss(两种方式)

看https://www.bilibili.com/video/BV1m84y1w7Tb的p147-p149就可以了。

在这里插入图片描述

在这里插入图片描述
bucket名称是唯一性的,所以很有可能出现“该名称已存在或已被其他占用”的情况,换个名字就好了。

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

相关文章:

springboot苍穹外卖实战:五、公共字段自动填充(aop切面实现)+新增菜品功能+oss

公共字段自动填充 不足 比起瑞吉外卖中的用自定义元数据类型mybatisplus的实现&#xff0c;这里使用的是aop切面实现&#xff0c;会麻烦许多&#xff0c;建议升级为mp。 定义好数据库操作类型 sky-common中已经定义好&#xff0c;OperationType。 自定义注解 AutoFill co…...

Go 语言中,golang结合 PostgreSQL 、MySQL驱动 开启数据库事务

Go 语言中&#xff0c;golang结合 PostgreSQL 、MySQL驱动 开启数据库事务 PostgreSQL代码说明&#xff1a; MySQL代码说明&#xff1a; PostgreSQL 在 Go 语言中&#xff0c;使用 database/sql 包结合 PostgreSQL 驱动&#xff08;如 github.com/lib/pq&#xff09;可以方便地…...

Git核心概念

目录 版本控制 什么是版本控制 为什么要版本控制 本地版本控制系统 集中化的版本控制系统 分布式版本控制系统 认识Git Git简史 Git与其他版本管理系统的主要区别 Git的三种状态 Git使用快速入门 获取Git仓库 记录每次更新到仓库 一个好的 Git 提交消息如下&#…...

网络安全技术在能源领域的应用

摘要 随着信息技术的飞速发展&#xff0c;能源领域逐渐实现了数字化、网络化和智能化。然而&#xff0c;这也使得能源系统面临着前所未有的网络安全威胁。本文从技术的角度出发&#xff0c;探讨了网络安全技术在能源领域的应用&#xff0c;分析了能源现状面临的网络安全威胁&a…...

这些场景不适合用Selenium自动化!看看你踩过哪些坑?

Selenium是自动化测试中的一大主力工具&#xff0c;其强大的网页UI自动化能力&#xff0c;让测试人员可以轻松模拟用户操作并验证系统行为。然而&#xff0c;Selenium并非万能&#xff0c;尤其是在某些特定场景下&#xff0c;可能并不适合用来自动化测试。本文将介绍Selenium不…...

PHP反序列化靶场(php-SER-libs-main 第一部分)

此次靶场为utools-php-unserialize-main。适合有一定基础的师傅&#xff0c;内容是比较全面的&#xff0c;含有我们的大部分ctf中PHP反序列化的题型。 level1&#xff1a; <?php highlight_file(__FILE__); class a{var $act;function action(){eval($this->act);} } …...

基于大数据爬虫+Python+SpringBoot+Hive的网络电视剧收视率分析与可视化平台系统(源码+论文+PPT+部署文档教程等)

博主介绍&#xff1a;CSDN毕设辅导第一人、全网粉丝50W,csdn特邀作者、博客专家、腾讯云社区合作讲师、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围…...

DHCP与FTP

DHCP dhcp&#xff1a;动态主机配置的协议&#xff0c;应用在大型的局域网环境中 服务端和客户端 服务端&#xff1a;提供IP地址&#xff0c;某种特定功能的提供者 客户端&#xff1a;请求IP地址&#xff0c;请求对应的功能的使用者 服务端的端口号&#xff1a;67 客户端的端…...

云渲染与云电脑,应用场景与技术特点全对比

很多朋友问&#xff0c;你们家一会宣传云渲染&#xff0c;一会宣传云电脑的&#xff0c;我到底用哪个&#xff1f;今天&#xff0c;渲染101云渲染和川翔云电脑就来对比下两者的区别&#xff01; 渲染101&川翔云电脑&#xff0c;都是我们的产品&#xff0c;邀请码6666 一、…...

RockPI 4A单板Linux 4.4内核下的RK3399 GPIO功能解析

RockPI 4A单板Linux 4.4内核下的RK3399 GPIO功能解析 摘要&#xff1a;本文将基于RockPI 4A单板&#xff0c;介绍Linux 4.4内核下RK3399 GPIO&#xff08;通用输入输出&#xff09;功能的使用方法。通过详细的代码解析和示例&#xff0c;帮助读者理解如何在Linux内核中使用GPI…...

【Vue】Vue3.0(二十三)Vue3.0中$attrs 的概念和使用场景

文章目录 一、$attrs的概念和使用场景概念使用场景 二、代码解释Father.vueChild.vueGrandChild.vue 三、另一个$attrs使用的例子 一、$attrs的概念和使用场景 概念 在Vue 3.0中&#xff0c;$attrs是一个组件实例属性&#xff0c;它包含了父组件传递给子组件的所有非props属性…...

RHEL/CENTOS 7 ORACLE 19C-RAC安装(纯命令版)

一 首先需要安装两个CENTOS 7虚拟机(此处省略)。 由于我们是要安装ORCLE-RAC双节点集群所以至少每个CENTOS虚拟机上需要两块网卡&#xff0c;并且两块网卡都是HOST-ONLY具体步骤请看视频一《为虚拟机添加网卡》 这里大家需要注意的是&#xff0c;我们需要绑定两台机器的IP一共…...

CCSK:面试云计算岗的高频问题

在竞争激烈的云计算岗位求职市场中&#xff0c;拥有 CCSK云计算安全知识认证无疑能为你增添强大的竞争力。而深入了解云计算面试中的高频问题并熟练掌握答案&#xff0c;更是迈向成功的关键一步。 一、AWS 相关问题 AWS 是重要考点&#xff0c;常被问到其关键特性&#xff0c…...

C++ String(1)

String的头文件是#include <string> String本质上是一个类&#xff0c;是C实现好的一个类 初学只用学重要的部分&#xff0c;不可能一次性全部学完 1.构造函数 我们先来看它的几个构造函数 首先&#xff08;1&#xff09;就是无参的构造 &#xff08;2&#xff09;是…...

ts 中 ReturnType 作用

ReturnType 用于获取函数的返回值类型。 一、基本概念和语法 1. 定义和语法结构 ReturnType是一个泛型类型&#xff0c;其语法为ReturnType<T>&#xff0c;其中T是一个函数类型。例如&#xff0c;如果有一个函数add&#xff0c;ReturnType<typeof add>就可以获取…...

Hadoop + Hive + Apache Ranger 源码编译记录

背景介绍 由于 CDH&#xff08;Clouderas Distribution Hadoop &#xff09;近几年已经开始收费并限制节点数量和版本升级&#xff0c;最近使用开源的 hadoop 搭了一套测试集群&#xff0c;其中的权限管理组件用到了Apache Ranger&#xff0c;所以记录一下编译打包过程。 组件…...

Java从入门到精通笔记篇(十二)

枚举类型与泛型 枚举类型可以取代以往常量的定义方式&#xff0c;即将常量封装在类或接口中 使用枚举类型设置常量 关键字为enum 枚举类型的常用方法 values()方法 枚举类型实例包含一个values()方法&#xff0c;该方法将枚举中所有的枚举值以数组的形式返回。 valueOf()可…...

入侵排查之Linux

目录 1.黑客入侵后的利用思路 2.入侵排查思路 2.1.账号安全 2.1.1.用户信息文件/etc/passwd 2.1.2.影子文件/etc/shadow 2.1.3.入侵排查 2.1.3.1.排查当前系统登录信息 2.1.4.2.查询可以远程登录的账号信息 2.2.历史命令 2.2.1.基本使用 2.2.1.1.root历史命令 2.2.…...

从0开始学习Linux——文件管理

往期目录&#xff1a; 从0开始学习Linux——简介&安装 从0开始学习Linux——搭建属于自己的Linux虚拟机 从0开始学习Linux——文本编辑器 从0开始学习Linux——Yum工具 从0开始学习Linux——远程连接工具 从0开始学习Linux——文件目录 从0开始学习Linux——网络配置 从0开…...

全面介绍软件安全测试分类,安全测试方法、安全防护技术、安全测试流程

一、软件系统设计开发运行安全 1、注重OpenSource组件安全检查和版本更新&#xff08;black duck&#xff09; 现在很多云、云服务器都是由开源的组件去搭成的&#xff0c;对于OpenSource组件应该去做一些安全检查和版本更新&#xff0c;尤其是版本管理&#xff0c;定期对在运…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

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

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

【C++】纯虚函数类外可以写实现吗?

1. 答案 先说答案&#xff0c;可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...