外卖开发(三)开发笔记——AOP实现实现公共字段填充、主键回显、抛异常和事务管理

news2024/12/5 10:02:59

外卖开发(三)开发笔记

  • 一、AOP实现实现公共字段填充(减少重复工作)
    • 实现思路
    • 自定义注解AutoFill
    • 自定义切面AutoFillAspect
    • 在Mapper接口上添加`@AutoFill`注解
  • 二、主键回显情况
  • 三、抛异常 和 事务管理

一、AOP实现实现公共字段填充(减少重复工作)

在这里插入图片描述

实现思路

在这里插入图片描述
1、自定义注解@AutoFill,用于表示需要进行公共字段填充的方法
2、自定义切面类,AutoFillAspect ,统一拦截加入了@AutoFill注解的方法,通过反射为公共字段赋值。
3、在Mapper方法上加入@AutoFill注解,因为这里我们的公共字段是更新时间、更新人、创建时间、创建人,所以只在insert、和update操作时才需要进行AutoFill。在进行Mapper方法前,先将实体类对象的相关属性填充,然后在进行insertupdate(before前置通知)

自定义注解AutoFill

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
     /**
     * 定义注解的value值,对应数据操作类型insert 和 update
     * @return
     */
    OperationType value();
}

自定义枚举

/**
 * 数据库操作类型
 */
public enum OperationType {

    /**
     * 更新操作
     */
    UPDATE,

    /**
     * 插入操作
     */
    INSERT

}

自定义切面AutoFillAspect

/**
 * 自定义通知类,实现公共字段填充
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    @Pointcut("@annotation(com.sky.annotation.AutoFill)")
    public void pointCut(){}

    @Before("pointCut()")
    public void autoFill(JoinPoint joinPoint) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        log.info("开始进行字段填充");

        //获取当前被拦截方法的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
        OperationType operationType = autoFill.value();
        //获取当前方法的参数--实体类对象   反射
        Object[] pointArgs = joinPoint.getArgs();
        if(pointArgs[0] == null){
            return;
        }
        Object entity = pointArgs[0];

        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();
        //根据不同的操作类型,为对应的属性通过反射来赋值
        if(operationType == OperationType.INSERT){
            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);
        }
        else if(operationType == OperationType.UPDATE){

            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);
        }

    }
}

在Mapper接口上添加@AutoFill注解

在这里插入图片描述
此时,我们就不需要在service中重复进行字段的填充。

二、主键回显情况

如:新增菜品
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

涉及到了两张表,dish表和dish_flavor表。

dish表
在这里插入图片描述

dish_flavor表

在这里插入图片描述
DishDTO.java

public class DishDTO implements Serializable {

    private Long id;
    //菜品名称
    private String name;
    //菜品分类id
    private Long categoryId;
    //菜品价格
    private BigDecimal price;
    //图片
    private String image;
    //描述信息
    private String description;
    //0 停售 1 起售
    private Integer status;
    //口味
    private List<DishFlavor> flavors = new ArrayList<>();

}

分析:新增dish操作,需要进行两次insert,分别插入dish表和dish_flavor表,但是我们从前端接收到的数据中(DishDTO)List<DishFlavor>中只包含了我们新增的口味名称口味值,并不会包含对应的dish_id,那么我们就需要把第一次向dish表中插入新数据时自动生成的id回显(带回来),并付给List<DishFlavor>中的dish_id。

DishService.java

/**
     * 新增菜品
     * @param dishDTO
     */
    @Override
    public void insertDish(DishDTO dishDTO) {
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO,dish);
        dishMapper.insert(dish);
        //获取inser之后的主键
        Long dishId = dish.getId();

        List<DishFlavor> flavors = dishDTO.getFlavors();
        if(flavors != null && flavors.size()>0){
            flavors.forEach(dishFlavor -> {
                dishFlavor.setDishId(dishId);  //将回显的主键id赋给flavir中的dish_id
            });
            dishFlavorMapper.insertBatch(flavors);
        }
    }
	/**
     * 批量新增dish
     * @param flavors
     */
 	@AutoFill(OperationType.INSERT)
    void insert(Dish dish);
 	/**
     * 批量新增dish_flavor
     * @param flavors
     */
    void insertBatch(List<DishFlavor> flavors);
<!--插入新菜品-->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">  <!--主键回显-->
        insert into dish (name,category_id,price,image,description,status,create_time,update_time,create_user,update_user)
        values
        (#{name},#{categoryId},#{price},#{image},#{description},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})
    </insert>

三、抛异常 和 事务管理

在删除某个菜品的时候,如果这个菜品的状态为起售(status=1)时,就无法进行删除,需要停止删除操作,并抛出相关异常。如果这个菜品正在被一些套餐关联,那么也不能删除。

在删除菜品的时候,也要删除相关的菜品对应的口味,所以需要删除两个表。显而易见,我们需要进行事务管理

/**
     * 批量删除菜品
     * @param ids
     */
    @Override
    @Transactional  //开启事务
    public void deleteDish(List<Long> ids) {
        //是否存在起售中的 存在就不能删除
        //利用count(1)计算出准备删除的菜品中status=1 的数量,如果大于0,说明存在起售中的
        Integer status = dishMapper.queryStatus(ids); 
        if (status > 0)
        {
        	//抛出自定义的异常和异常信息:无法删除存在起售的菜品
            throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
        }
        //查询有没有关联套餐 关联就不能删除
        //使用count(1)查询套餐中对应dish是否存在,如果大于0则不能删除
        Integer integer = setmealDishMapper.countDish(ids);
        if(integer > 0){
        	//抛出自定义的异常和异常信息:无法删除存在关联的菜品
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }
        //删除dish表中的数据
        dishMapper.deleteDish(ids);
        //删除dish-flavor表
        dishFlavorMapper.deleteByDishId(ids);
    }

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

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

相关文章

Flutter 1.2:flutter配置gradle环境

1、在android的模块中进行gradle环境配置 ①在 gradle-wrapper.properties文件中将url配置为阿里云镜像&#xff0c;因为gradle的服务器在国外&#xff0c;国内下载非常慢&#xff0c;也可在官网进行下载 gradle版本下载 gradle版本匹配 阿里云镜像gradle下载 可以通过复制链…

神经网络入门实战:(九)分类问题 → 神经网络模型搭建模版和训练四步曲

(一) 神经网络模型搭建官方文档 每一层基本都有权重和偏置&#xff0c;可以仔细看官方文档。 pytorch 官网的库&#xff1a;torch.nn — PyTorch 2.5 documentation Containers库&#xff1a;用来搭建神经网络框架&#xff08;包含所有的神经网络的框架&#xff09;&#xff1b…

达梦数据库文件故障的恢复方法

目录 1、概述 1.1 概述 1.2 环境介绍 2、使用备份集的恢复方法 2.1 实验准备 2.2 误删除“用户表空间数据文件” 2.3 误删除SYSTEM.DBF 2.4 误删除ROLL.DBF 2.5 REDO日志文件 3、无备份集的恢复方法 3.1 误删除“表空间数据文件” 3.2误删除控制文件 3.3 误删除RO…

uniapp进阶技巧:如何优雅地封装request实例

在uniapp开发过程中&#xff0c;合理封装网络请求是提高代码质量和开发效率的关键。本文将介绍一种更为优雅的封装方式&#xff0c;通过创建一个request实例来管理不同类型的HTTP请求。 一、准备工作 在开始封装之前&#xff0c;请确保你的项目中已经安装了uniapp开发环境&…

45 基于单片机的信号选择与温度变化

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用DS18B20检测温度&#xff0c;通过三种LED灯代表不同状态。 采用DAC0832显示信号脉冲&#xff0c;通过8位数码管显示温度。 信号脉冲可以根据两个按键分别调整为正弦…

yagmail邮件发送库:如何用Python实现自动化邮件营销?

&#x1f3a5; 作者简介&#xff1a; CSDN\阿里云\腾讯云\华为云开发社区优质创作者&#xff0c;专注分享大数据、Python、数据库、人工智能等领域的优质内容 &#x1f338;个人主页&#xff1a; 长风清留杨的博客 &#x1f343;形式准则&#xff1a; 无论成就大小&#xff0c;…

付费版-多媒体云转码视频处理工具-付费系统完整源码搭建-先到先得-本文带完整搭建步骤-优雅草央千澈

付费版-多媒体云转码视频处理工具-付费系统完整源码搭建-先到先得-本文带完整搭建步骤-优雅草央千澈 环境 linuxnginxphp7.1mysql5.6 安装步骤 以下适用于宝塔已经安装好的情况 1.上传源码到你的网站目录 2.访问你的域名&#xff0c;按操作提示进行安装配置&#xff08;如…

java基础概念46-数据结构1

一、引入 List集合的三种实现类使用了不同的数据结构&#xff01; 二、数据结构的定义 三、常见的数据结构 3-1、栈 特点&#xff1a;先进后出&#xff0c;后进先出。 java内存容器&#xff1a; 3-2、队列 特点&#xff1a;先进先出、后进后出。 栈VS队列-小结 3-3、数组 3-…

朗迪锋亮相2024人因工程与智能系统交互国际会议

2024年11月28日至30日&#xff0c;2024人因工程与智能系统交互国际会议在深圳隆重举办。此次大会以推动我国人因工程学科发展为目标&#xff0c;致力于加强国际学术交流&#xff0c;深入探讨人工智能时代的智能系统交互&#xff0c;旨在培育新质生产力&#xff0c;助力经济社会…

Java基础之控制语句:开启编程逻辑之门

一、Java控制语句概述 Java 中的控制语句主要分为选择结构、循环结构和跳转语句三大类&#xff0c;它们在程序中起着至关重要的作用&#xff0c;能够决定程序的执行流程。 选择结构用于根据不同的条件执行不同的代码路径&#xff0c;主要包括 if 语句和 switch 语句。if 语句有…

如何部署vue项目到Github Pages

1.创建vue项目 npm create vitelatest my-vue-app -- --template vue 2.创建github仓库 3.连接仓库 在项目根目录右键选择open git base here&#xff0c;如果没有安装git请先安装git。 初始化仓库 $ git init $ git add . $ git commit -m "init"将项目与仓库连…

Jenkins升级到最新版本后无法启动

1. 场景还原 最近在web界面将jenkins升级到最新版本后&#xff0c;后台无法启动jenkins服务&#xff0c;服务状态如下&#xff1a; 运行jenkins命令提示invalid Java version jenkins --version jenkins: invalid Java version: java version "1.8.0_202" Java(TM)…

「计算机网络性能指标」

速率 速率&#xff08;Speed&#xff09;&#xff1a;指连接到网络上的节点在信道上的传输数据的速率。也称数据率或比特率&#xff0c;数据传输速率 信道&#xff08;Channel&#xff09;&#xff1a;表示向某一方向传送信息的通道&#xff08;信道 ≠ 通信线路&#xff09;…

HTTP协议详解:从HTTP/1.0到HTTP/3的演变与优化

深入浅出&#xff1a;从头到尾全面解析HTTP协议 一、HTTP协议概述 1.1 HTTP协议简介 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是互联网上应用最广泛的通信协议之一。它用于客户端与服务器之间的数据传输&#xff0c;尤其是在Web…

【Docker】Docker 容器日志过大导致磁盘爆满

docker容器的日志文件目录位于/var/lib/docker/containers/容器/容器-json.log 查看日志大小 cd /var/lib/docker/containers/ du -h --max-depth1 临时删一点 cd xxxxxxx/ tail -100 xxxxxxx-json.log > xxxxxxx-json.log 如图 解决方式&#xff08;全局&#xff09; …

MySQL 索引创建 大数据查询 性能测试 SQL优化 慢查询

介绍 索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些 数据结构以某种方式引用(指向)数据&#xff0c; 这样就可以在这些数据结构上实现高级查找算法&#xff0c;这种数据结构就是…

JAVA:Springboot 集成 WebSocket 和 STOMP 实时消息的技术指南

1、简述 随着互联网应用的复杂性和实时性需求的增加&#xff0c;传统的 HTTP 请求响应模式已不能满足某些场景的需求。WebSocket 和 STOMP 协议为构建实时消息传输提供了极大的便利。本文将介绍如何在 Spring Boot 中使用 WebSocket 和 STOMP 创建一个实时消息应用&#xff0c…

华为仓颉编程环境搭建

1、仓颉介绍 摘自华为官方&#xff1a;仓颉编程语言作为一款面向全场景应用开发的现代编程语言&#xff0c;通过现代语言特性的集成、全方位的编译优化和运行时实现、以及开箱即用的 IDE 工具链支持&#xff0c;为开发者打造友好开发体验和卓越程序性能。 其具体特性表现为&am…

Vue+Elementui el-tree树只能选择子节点并且支持检索

效果&#xff1a; 只能选择子节点 添加配置添加检索代码 源码&#xff1a; <template><div><el-button size"small" type"primary" clearable :disabled"disabled" click"showSign">危险点评估</el-button>…

【前端】安装hadoop后,前端启动报错,yarn命令

新安装hadoop后&#xff0c;前端启动项目用yarn命令&#xff0c;报错。 报错&#xff1a;系统找不到指定的路径。 No HADOOP_CONF_DIR set. Please specify it either in yarn-env.cmd or in the environment. 解决&#xff1a;删掉hadoop目录下yarn的文件 检查&#xff1a;…