本文记录了苍穹外卖项目第四天的学习内容,重点介绍了项目异常处理机制以及MyBatis的精细化SQL控制技术。

请添加图片描述



完成任务清单

  • 新增套餐接口
  • 套餐分页查询接口
  • 删除套餐接口
  • 修改套餐接口
  • 起售停售套餐功能

主要功能展示

在今日的学习中,主要是更加熟悉crud,同时需求分析的能力相较于之前有了很大的提升。在进行编写的过程中,我对项目的一些相关知识点更加了解,如异常处理机制,同时整理了MyBatis XML相关操作

1. 异常处理机制

作为涵盖了项目的机制,我主要学习了异常体系架构具体业务异常类

异常体系架构

异常体系架构分为基础异常类具体业务异常类

基础异常类
基础异常类由BaseException组成,因为只有该异常作为基础异常类,因此便于全局异常处理器统一管理。

public class BaseException extends RuntimeException {
    public BaseException() {}
    public BaseException(String msg) {
        super(msg);
    }
}

具体业务异常类
具体业务异常类多以具体业务命名,且每个异常类只处理特定类型错误,因此有着异常分类明确语义化命名单一职责的特征。

// 登录相关异常
public class LoginFailedException extends BaseException {
    public LoginFailedException(String msg) {
        super(msg);
    }
}

// 业务操作异常
public class DeletionNotAllowedException extends BaseException {
    public DeletionNotAllowedException(String msg) {
        super(msg);
    }
}
异常信息传递

这里了解了正常传递流程全局异常处理器异常管理几个方面。

正常传递流程
参数验证异常以及业务操作异常时,我们将抛出具体异常。

throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);

此时调用该异常内的有参构造函数,进行层层传递

AccountNotFoundException(String msg)
    ↓ 调用super(msg)
BaseException(String msg)
    ↓ 调用super(msg)
RuntimeException(String message)
    ↓ 调用super(message)
Exception(String message)
    ↓ 调用super(message)
Throwable(String message)

全局异常处理器
全局异常处理器不仅可以处理指定的异常类型,还可以处理其他未被单独捕获的异常

全局异常处理器通过@RestControllerAdivce扫描文件,@ExceptionHandler指定异常类型,同时将异常都转为Result对象返回,并记录异常信息,便于问题排查。

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    
    /**
     * 捕获业务异常
     */
    @ExceptionHandler
    public Result exceptionHandler(BaseException ex){
        log.error("异常信息:{}", ex.getMessage());
        return Result.error(ex.getMessage());
    }
    
    /**
     * 捕获数据库约束异常
     */
    @ExceptionHandler
    public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
        log.info("错误信息:{}",ex.getMessage());
        String message = ex.getMessage();
        if (message.contains("Duplicate entry")){
            String[] split = message.split(" ");
            String username = split[2];
            String msg = username + MessageConstant.ALREADY_EXISTS;
            return Result.error(msg);
        }else{
            return Result.error(MessageConstant.UNKNOWN_ERROR);
        }
    }
}

@ExceptionHandler(Exception.class)
public Result handleException(Exception ex) {
    // 处理所有未被其他@ExceptionHandler捕获的异常
}

异常管理
在发生问题时,我们采用调用异常处理,有着可读性强便于统一管理便于复用的优点。

// 使用异常处理
if (employee == null) {
    throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
}

// 不使用异常处理(传统方式)
if (employee == null) {
    return Result.error(MessageConstant.ACCOUNT_NOT_FOUND);
}

同时,我们采用常量类存储异常,有着便于管理可维护性强灵活性高的优点
在这里插入图片描述

2. MyBatis XML相关操作

批量插入操作

这里主要介绍foreach标签功能

collection:指定要遍历的集合
item:当前遍历的元素别名
separator:元素间的分隔符
open/close:开始和结束符号

<insert id="insertBatch" parameterType="list">
    insert into setmeal_dish
    (setmeal_id,dish_id,name,price,copies)
    values
    <foreach collection="setmealDishes" item="sd" separator=",">
        (#{sd.setmealId},#{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
    </foreach>
</insert>
动态SQL查询

where标签动态条件

where标签:自动处理AND关键字
if标签:条件判断
test属性:判断条件表达式

<select id="page" resultType="com.sky.entity.Setmeal">
    select * from setmeal
    <where>
        <if test="name != null and name !=''">
            AND name like concat('%',#{name},'%')
        </if>
    </where>
    order by create_time desc
</select>

set标签动态更新

set标签:自动处理逗号(专门用于 UPDATE 语句中的 SET 部分)

<update id="update" parameterType="SetMeal">
    update setmeal
    <set>
        <if test="name != null">
            name = #{name},
        </if>
        <if test="categoryId != null">
            category_id = #{categoryId},
        </if>
        <if test="price != null">
            price = #{price},
        </if>
        <if test="status != null">
            status = #{status},
        </if>
        <if test="description != null">
            description = #{description},
        </if>
        <if test="image != null">
            image = #{image},
        </if>
        <if test="updateTime != null">
            update_time = #{updateTime},
        </if>
        <if test="updateUser != null">
            update_user = #{updateUser}
        </if>
    </set>
    where id = #{id}
</update>
参数绑定与结果映射

#{}:预编译参数,防止SQL注入
useGeneratedKeys:获取自增主键
keyProperty:指定主键属性名

参数绑定

<!-- 基本参数绑定 -->
<select id="getById" resultType="com.sky.vo.SetmealVO">
    select * from setmeal where id=#{id}
</select>

<!-- 对象参数绑定 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    insert into setmeal(category_id,name,price,status,description,image)
    values(#{categoryId},#{name},#{price},#{status},#{description},#{image})
</insert>

结果映射

<!-- 基本结果映射 -->
<select id="list" resultType="Setmeal">
    select * from setmeal
</select>

<!-- 复杂结果映射 -->
<select id="page" resultType="com.sky.vo.DishVO">
    select d.* , c.name as categoryName 
    from dish d left outer join category c on d.category_id = c.id
</select>

本文为苍穹外卖项目学习笔记,持续更新中…

如果我的内容对你有帮助,希望可以收获你的点赞、评论、收藏。

请添加图片描述

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐