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

在今日的学习中,主要是更加熟悉crud,同时需求分析的能力相较于之前有了很大的提升。在进行编写的过程中,我对项目的一些相关知识点更加了解,如异常处理机制,同时整理了MyBatis XML相关操作。
作为涵盖了项目的机制,我主要学习了异常体系架构与具体业务异常类。
异常体系架构分为基础异常类与具体业务异常类。
基础异常类
基础异常类由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);
}同时,我们采用常量类存储异常,有着便于管理,可维护性强,灵活性高的优点

这里主要介绍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>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>本文为苍穹外卖项目学习笔记,持续更新中…
如果我的内容对你有帮助,希望可以收获你的点赞、评论、收藏。