第一章 配置

01 整体代码

先不着急写代码,先对整体项目分析一下

image-20250312094039356

可以看见项目被分成了三个部分

  1. sky-common
image-20250312093957625
1
2
3
点进去细看可以看出这里面是一些功能类,用来应对报错,返回结果,以及项目进行的各种需求
result: 是为了向前端返回固定的格式,因此我们写后端代码都需要返回result
//TODO 还没学完,后续补充
  1. sky-pojo

    image-20250312094227669
    1
    2
    这里就是项目所需要的所有对象,entity是对象的全貌,带有所有属性,而dto则是为了方便处理项目所创建的小对象,包含有entity的一部分属性
    //TODO vo还没学完,后续补充
  2. sky-server

    image-20250312094724712
    1
    后端项目的具体内容,也是我们要干的活

02 配置环境

准备好

1
2
3
4
1. maven
2. mysql
3. git
4. nginx

001 maven

1
2
第一步:下载,然后配置环境变量,记得JAVA_HOME,java环境变量记得配置,不然用不了maven,在进入path填入
%MAVEN_HOME%\bin,就可以了,之后进入cmd 输入mvn -version查看是否配置成功
image-20250312095744454
1
第二步:进入C:\soft\apache-maven-3.9.9\conf  ,maven下载处的conf

image-20250312101225116

  1. 镜像

    image-20250312101353347
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!-- 阿里云仓库 -->
    <mirror>
    <id>alimaven</id>
    <mirrorOf>central</mirrorOf>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
    </mirror>

    <mirror>
    <id>maven-default-http-blocker</id>
    <mirrorOf>external:http:*</mirrorOf>
    <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
    <url>http://0.0.0.0/</url>
    <blocked>true</blocked>
    </mirror>
    </mirrors>

    把如上代码输入到指定位置,一定位置要对

  2. 版本

    往下滑

    image-20250312101507277

    改成你现在使用的版本

    查看版本在idea中点击

    image-20250312101539839

    可以看见当前你使用的版本

    image-20250312101603946
1
最后在idea点击这个compile就可以了
image-20250312095550094

002 mysql

先配置mysql

手把手教你安装MySQL(最新版本安装)_哔哩哔哩_bilibili

这位up主超级详细,直接安装那个版本就行

记得每次使用之前需要在cmd打开

image-20250312103729691

输入

1
mysql -u root -p

之后进入idea 新建mysql数据源

image-20250312100509330

设置如下

image-20250312100625210

数据库可以不填,我后面写代码的时候报错了,才加上这个,用户密码填上面mysql配置的,点击最下方测试连接,连接成功即可

然后运行一下黑马程序员的image-20250312100538899

就可以成功连接数据库,

003 git

以前搭建博客的时候用了git,就不写下载过程了

image-20250312100910273

选择vcs的创建git仓库,之后只要在master里提交加推送就好了

image-20250312101651818

004 nginx

直接双击day1中的

image-20250312103847005

即可

第二章 员工管理

01 新增员工

一个后端工程师,只要把需求做出来就好了,先看接口

image-20250311091739831

1
2
3
开头地址:@RequestMapping("/admin/employee")
由于是Post,因此需要在所有函数的前头加上@PostMapping
最好在每个函数再加上注释 @ApiOperation("员工退出"),以及注解/**
image-20250312102236269

他就这么点属性,而我的Employee有这么多属性

image-20250312102337473

这里就要使用DTO,把需要的属性封装成一个小的DTO

  • 对象属性拷贝:

    1
    2
    3
    //对象属性拷贝
    BeanUtils.copyProperties(employeeDTO,employee);
    从前面的源拷到后面的目的地
  • 为1为0的类似常量值最好用常量代替

    1
    2
    3
    4
    5
    6
    7
    8
    public class StatusConstant {

    //启用
    public static final Integer ENABLE = 1;

    //禁用
    public static final Integer DISABLE = 0;
    }

001 测试功能

当前端还没做好时可以使用接口来测试功能

在前面配置的时候swagger是这个地址

1
http://localhost:8080/doc.html#/

image-20250311104321759

新增返回401,是因为需要jwt验证,而我们前面定义的是token,在管理员处登录一下得到token

image-20250311104414846

在全局参数处设置,之后就可以得到200

002 代码说明

​ 首先是要求我们做出新增员工的后端代码

很显然是在sky-server中的

image-20250312102038268
1
2
3
4
5
6
7
@PostMapping
@ApiOperation("新增员工")
public Result save(@RequestBody EmployeeDTO employeeDTO){
log.info("新增员工: {}",employeeDTO);
employeeService.save(employeeDTO);
return Result.success();
}
1
2
3
4
5
还是一样,
1. Post请求函数前加上@PostMapping
2. Swagger用@ApiOperation("新增员工")来说明我要干什么
3. log.info意思是成功提示,其实跟sout差不多,{}里是employeeDTO
4. employeeService.save(employeeDTO); 新增员工具体实现,alt+enter创建函数,中键进入,再点击左边绿色向下的按钮实现具体函数
image-20250312102546512

函数代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void save(EmployeeDTO employeeDTO) {
System.out.println("当前线程的id:"+Thread.currentThread().getId());
Employee employee=new Employee();

//对象属性拷贝
BeanUtils.copyProperties(employeeDTO,employee);

//设置帐号状态,默认正常状态 1表示正常,0表示锁定
employee.setStatus(StatusConstant.ENABLE);

//设置密码,默认密码123456
employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));

//设置当前记录的创建时间和修改时间
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());

//设置当前记录创建人id和修改人id
//TODO 后期需要改为当前登录用户id
employee.setCreateUser(BaseContext.getCurrentId());
employee.setUpdateUser(BaseContext.getCurrentId());

employeeMapper.insert(employee);
}
1
2
3
4
1. BeanUtils.copyProperties(employeeDTO,employee);一个一个get放入很麻烦,因此我们使用这个函数
2. employee.setStatus(StatusConstant.ENABLE); ,把状态置1,常数用常数表示
3. DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()),存入数据库之前要转成md5加密
4. 为了获取当前登录用户的id,我们往上看,发现jwt验证代码中有存在
image-20250312103201995

进入jwt代码中:

image-20250312103247108

有个Long empId,我们用log.info输出一波,发现确实是id

1
2
3
4
!现在的问题就是如何把这个应用到我们这个项目中,我们使用这样一个函数
BaseContext.setCurrentId(empId);
我们就可以在当前线程中使用
Thread.currentThread().getId()来获取,由此实现

003 功能测试

至此第二章第一节结束,测试一波

image-20250312103933627

点击添加员工

image-20250312104034193

保存

image-20250312104107614

查看数据库

image-20250312104131366

成功添加

02 员工分页查询

001 功能需求

先在接口处看看他的接受以及返回

image-20250312110423554 image-20250312110444986

他需要

1
员工姓名,页码,每页记录数

他返回

1
一个code和data,data里有total和record,record里是一个employee的属性

002 代码实现

非常的格式化,跟01新增员工一样,post是上传数据,而get是请求数据

image-20250312111852481

要求都写好了,因此我们直接开写基本的代码

1
2
3
4
5
6
7
8
9
10
11
/**
* 员工分页查询
* @param employeepageQueryDTO
* @return
*/
@GetMapping("/page")
@ApiOperation("员工分页查询")
public Result<PageResult> page(EmployeePageQueryDTO employeepageQueryDTO){
log.info("员工分页查询,参数为:{}",employeepageQueryDTO);
return null;
}

老样子 注释 map 注释 具体函数 log正确判断 return

然后进入概述写个注释

image-20250312112441208

最后进入具体实现

image-20250312112502168

分页查询,原来需要我们会mysql的语句去自己写,现在都搞好了,直接用pagehelper就好了

PageHelper.startPage() 的作用

  • 启动分页
    在执行 SQL 查询之前调用 PageHelper.startPage(),它会为接下来的 ​第一条 SQL 查询 自动添加分页逻辑。
  • 自动分页
    你不需要手动在 SQL 中写 LIMIT,PageHelper 会自动根据传入的页码和每页大小,生成分页 SQL。
  • 封装结果
    查询结果会被封装到 Page 对象中,包含分页信息(如总记录数、总页数等)。

形式如下:开始分页(页码,每页大小)

1
PageHelper.startPage(employeepageQueryDTO.getPage(),employeepageQueryDTO.getPageSize());

之后根据DTO的信息去查询员工信息,并封装到page中

1
Page<Employee> page=employeeMapper.pageQuery(employeepageQueryDTO);

做完之后去具体实现pageQuery,这里需要下载mybatis插件

image-20250313171013392

alt+回车创建

image-20250313171120855

选择select

image-20250318101710861

最后在这里去实现具体的sql查询语句

1
2
3
4
5
6
7
8
9
<select id="pageQuery" resultType="com.sky.entity.Employee">
select * from employee
<where>
<if test="name != null and name !=''">
and name like concat('%',#{name},'%')
</if>
</where>
order by create_time desc
</select>
  • 从employee提取全部

  • <where> 标签是 MyBatis 动态 SQL 中的一个重要标签,用于生成 WHERE 子句。它的主要作用是:

    1. 自动添加 WHERE 关键字
      如果 <where> 标签内有条件成立,它会自动在 SQL 中添加 WHERE 关键字。
    2. **智能处理 ANDOR**:
      如果条件前面有 ANDOR,它会自动去掉这些多余的连接词,避免 SQL 语法错误。
    3. 忽略空条件
      如果所有条件都不成立,它会忽略整个 WHERE 子句,避免生成无效的 SQL
  • 判断姓名不为空,进行模糊查询

    模糊查询 是一种在数据库中查找 部分匹配 数据的查询方式。它的特点是:不需要完全匹配查询条件,而是通过匹配部分内容来查找相关记录。

    在 SQL 中,模糊查询通常使用 LIKE 关键字和通配符来实现。

    模糊查询的核心

    • LIKE 关键字
      用于指定模糊查询的条件。
    • 通配符
      用于匹配部分内容的特殊字符,常用的通配符有:
      • %:匹配任意长度的任意字符(包括空字符)。
      • _:匹配单个任意字符。
  • ORDER BY create_time DESC 是 SQL 中的一个 排序子句,用于根据 create_time 字段对查询结果进行 降序排序。以下是详细解释:

具体代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 分页查询
* @param employeepageQueryDTO
* @return
*/
public PageResult pageQuery(EmployeePageQueryDTO employeepageQueryDTO) {
// select * from employee limit 0,10
// 开始分页查询
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);
}

003 功能测试

image-20250318102418759

可以发现正确的跑起来了

image-20250318102646620

004 代码完善

但是时间的格式不是很好

image-20250318102906634
  • 1.加上注解:image-20250318103246605
image-20250318103356745
  • 2.统一
    在他给的源码中已经存在

    image-20250318104210362 只需要在里面去进行配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * 扩展spring mvc框架的消息转化器
    * @param converters
    */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    log.info("扩展消息转换器");
    //创建一个消息转化器对象
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    //需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
    converter.setObjectMapper(new JacksonObjectMapper());
    //将自己的消息转换器加入到容器中,0的意思是排在第一位
    converters.add(0,converter);
    }

    对象转换器在common里也有

    image-20250318104408926 就可以了

03 禁用员工账号

001 功能需求

简单来说就是通过id设置员工的status,1为启用,0为禁用

002 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 启用禁用员工账号
* @param status
* @param id
* @return
*/
@PostMapping("/status/{status}")
@ApiOperation("启用禁用员工账号")
public Result StartOrStop(@PathVariable Integer status,Long id){
log.info("启用禁用员工账号:{},{}",status,id);
employeeService.StartOrStop(status,id);
return Result.success();
}

要传来的内容不多可以不使用DTO,括号里写@PathVariable说明是从URL传来的,上面的@RequestBody是从http请求的json格式传来,因为不是一个查询的操作,因此Result不需要<>里的东西

之后进入StartOrStop实现代码,具体操作就是通过id改status,说是为了方便,因此将传入的参数设为employee,这样之后的查询就可以直接用这个update,不然只为了这一个属性写一个很麻烦

1
2
3
4
5
6
7
8
9
public void StartOrStop(Integer status,Long id){
//update employee set status = ? where id = ? ;

Employee employee=new Employee();
employee.setStatus(status);
employee.setId(id);

employeeMapper.update(employee);
}

去mapper中具体实现update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<update id="update" parameterType="Employee">
update employee
<set>
<if test ="name != null">name = #{name},</if>
<if test ="username != null">username = #{username},</if>
<if test ="password != null">password = #{password},</if>
<if test ="phone != null">phone = #{phone},</if>
<if test ="sex != null">sex = #{sex},</if>
<if test ="idNumber != null">id_number = #{idNumber},</if>
<if test ="updateTime != null">update_time = #{updateTime},</if>
<if test ="updateUser != null">update_user = #{updateUser},</if>
<if test ="status != null">status = #{status},</if>
</set>
where id = #{id}
</update>

003 功能测试

image-20250319090918979

功能正常使用

快速滑动代码

1
shift+alt+方向键

04 编辑员工信息

001 通过id查询用户信息

写到现在已经很清晰了,

  • 根据接口在控制层( EmployeeController)写 获取数据,接口提示 正确的返回格式
  • 在服务层( [EmployeeController] ) 写函数的定义,以及在 ([EmployeeController.java]) 写具体的函数实现
  • 最后在持久层 ([EmployeeController.java]) 写有关数据库的操作

这次有两个接口需求,一个是通过id查询用户信息,另一个是编辑员工信息

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 根据id查询员工信息
    * @param id
    * @return
    */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询员工信息")
    public Result<Employee> getById(@PathVariable Long id){
    Employee employee=employeeService.getById(id);
    return Result.success(employee);
    }
  • 服务层

    1
    2
    3
    4
    5
    6
    7
    /**
    * 根据id查询员工信息
    * @param id
    * @return
    */
    Employee getById(Long id);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 根据id查询员工信息
    * @param id
    * @return
    */
    public Employee getById(Long id){
    Employee employee=employeeMapper.getById(id);
    employee.setPassword("****");
    return employee;
    }
    }
  • 持久层

    1
    2
    3
    4
    5
    6
    7
    /**
    * 根据id查询员工信息
    * @param id
    * @return
    */
    @Select("select * from sky_take_out.employee where id = #{id}")
    Employee getById(Long id);

002 编辑用户信息

image-20250319103521898

json格式,@RequestBody

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 编辑员工信息
    * @param employeeDTO
    * @return
    */
    @PutMapping
    @ApiOperation("编辑员工信息")
    public Result update(@RequestBody EmployeeDTO employeeDTO){
    log.info("编辑员工信息:{}",employeeDTO);
    employeeService.update(employeeDTO);
    return Result.success();
    }
  • 服务层

    1
    2
    3
    4
    5
    6
    /**
    * 编辑员工信息
    * @param employeeDTO
    */
    void update(EmployeeDTO employeeDTO);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**
    * 编辑员工信息
    * @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);
    }
  • 持久层

    1
    就是前面写的update复用

003 功能测试

点击修改

image-20250319104952926 image-20250319105016756

可以看到调用sql语句并且回显出信息

image-20250319105043469

前面设置密码为”*”是为了防止偷看,

image-20250319105255990

点击保存

image-20250319105320150

信息修改成功

第三章 分类管理

这章用来学习上面自写练习

  • 先创建Service,Servicelmpl,Controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //这是Controller的头部
    @RestController
    @RequestMapping("/admin/category")
    @Api(tags="分类相关接口")
    @Slf4j
    public class CategoryController {

    @Autowired
    private CategoryService categoryService;
    }
  • 接口可以直接写,不用什么特殊的,Servicelmpl就需要在开头写一个@Service

001 新增分类

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 新增分类
    * @param categoryDTO
    * @return
    */
    @PostMapping
    @ApiOperation("新增分类")
    public Result save(@RequestBody CategoryDTO categoryDTO){
    log.info("新增分类:{}",categoryDTO);
    categoryService.save(categoryDTO);
    return Result.success();
    }
  • 服务层

    1
    2
    3
    4
    5
    /**
    * 新增分类
    * @param categoryDTO
    */
    void save(CategoryDTO categoryDTO);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /**
    * 新增分类
    * @param categoryDTO
    */
    public void save(CategoryDTO categoryDTO) {
    Category category=new Category();

    //对象属性拷贝
    BeanUtils.copyProperties(categoryDTO,category);

    //设置分类状态
    category.setStatus(StatusConstant.DISABLE);

    //设置当前记录的创建时间和修改时间
    category.setCreateTime(LocalDateTime.now());
    category.setUpdateTime(LocalDateTime.now());

    //设置当前记录创建人id和修改人id
    category.setCreateUser(BaseContext.getCurrentId());
    category.setUpdateUser(BaseContext.getCurrentId());

    categoryMapper.insert(category);

    }
    }
  • 持久层

    1
    2
    3
    4
    5
    6
    7
    /**
    * 插入分类数据
    * @param category
    */
    @Insert("INSERT INTO sky_take_out.category (type, name, sort, status, create_time, update_time, create_user, update_user) " +
    "VALUES (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
    void insert(Category category);

接口调试返回200即可,返回500极大概率就是持久层错了

002 分类分页查询

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 分类分页查询
    * @param categoryPageQueryDTO
    * @return
    */
    @GetMapping("/page")
    @ApiOperation("分类分页查询")
    public Result<PageResult> page(CategoryPageQueryDTO categoryPageQueryDTO){
    log.info("分类分页查询,参数为:{}",categoryPageQueryDTO);
    PageResult pageResult=categoryService.pageQuery(categoryPageQueryDTO);
    return Result.success(pageResult);
    }
  • 服务层

    1
    2
    3
    4
    5
    6
    /**
    * 分页查询
    * @param categoryPageQueryDTO
    * @return
    */
    PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * 分页查询
    * @param categoryPageQueryDTO
    * @return
    */
    public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {
    PageHelper.startPage(categoryPageQueryDTO.getPage(),categoryPageQueryDTO.getPageSize());
    Page<Category> page = categoryMapper.pageQuery(categoryPageQueryDTO);

    long total = page.getTotal();
    List<Category> records = page.getResult();

    return new PageResult(total,records);
    }
  • 持久层

    持久层这里需要特别注意,由于我们后面还有按照类型搜索,不能直接按照员工的按名字查询,需要加上这一串代码

    1
    2
    3
    <if test="type != null">
    and type = #{type}
    </if>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <select id="pageQuery" resultType="com.sky.entity.Category">
    select * from category
    <where>
    <if test="name != null and name !=''">
    and name like concat('%',#{name},'%')
    </if>
    <if test="type != null">
    and type = #{type}
    </if>
    </where>
    order by create_time desc
    </select>

003 修改分类

从上面编辑员工可得

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 修改分类
    * @param categoryDTO
    * @return
    */
    @PutMapping
    @ApiOperation("修改分类")
    public Result update(@RequestBody CategoryDTO categoryDTO){
    log.info("修改分类:{}",categoryDTO);
    categoryService.update(categoryDTO);
    return Result.success();
    }
  • 服务层

    1
    2
    3
    4
    5
    6
    /**
    * 修改分类
    * @param categoryDTO
    */
    void update(CategoryDTO categoryDTO);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**
    * 修改分类
    * @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);
    }
  • 持久层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <update id="update" parameterType="Category">
    update category
    <set>
    <if test ="name != null">name = #{name},</if>
    <if test ="id != null">id = #{id},</if>
    <if test ="sort != null">sort = #{sort},</if>
    <if test ="type != null">type = #{type},</if>
    <if test ="updateTime != null">update_time = #{updateTime},</if>
    <if test ="updateUser != null">update_user = #{updateUser},</if>
    <if test ="status != null">status = #{status},</if>
    </set>
    where id = #{id}
    </update>

004 启用禁用分类

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**
    * 启用禁用分类
    * @param status
    * @param id
    * @return
    */
    @PostMapping("/status/{status}")
    @ApiOperation("启用禁用分类")
    public Result StartOrStop(@PathVariable Integer status ,Long id){
    log.info("启用禁用分类:{},{}",status,id);
    categoryService.StartOrStop(status,id);
    return Result.success();
    }
  • 服务层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 启用禁用分类
    * @param status
    * @param id
    */
    public void StartOrStop(Integer status, Long id) {
    Category category=new Category();
    category.setId(id);
    category.setStatus(status);

    categoryMapper.update(category);
    }
  • 持久层

    就是上面写的update

005 删除分类

删除分类我们要考虑分类下是否存在套餐或者菜品,如果存在则不能删除

image-20250324104344531 image-20250324104407792

可以看到dishsetmeal都存在category_id,也就是在这俩个表里查询即可,查到count++

count>0报错,不能删除

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 删除分类
    * @param id
    * @return
    */
    @DeleteMapping
    @ApiOperation("删除分类")
    public Result deleteById(Long id){
    log.info("删除分类");
    categoryService.deleteById(id);
    return Result.success();
    }
  • 服务层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /**
    * 删除分类
    * @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.countByCategotyId(id);
    if(count>0){
    throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL);
    }

    categoryMapper.deleteById(id);
    }
  • 持久层

    • dish

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      @Mapper
      public interface DishMapper {

      /**
      * 根据ID查询菜品数量
      * @param categoryId
      * @return
      */
      @Select("select count(id) from dish where category_id = #{categoryId}")
      Integer countByCategoryId(Long categoryId);
      }
    • setmeal

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      @Mapper
      public interface SetmealMapper {

      /**
      * 通过id查询套餐数量
      * @param categoryId
      * @return
      */
      @Select("select count(id) from dish where category_id = #{categoryId}")
      Integer countByCategotyId(Long categoryId);
      }
    • 删除

      1
      2
      3
      4
      5
      6
      /**
      * 删除分类
      * @param id
      */
      @Delete("delete from category where id = #{id}")
      void deleteById(Long id);

006 根据类型查询分类

在sql表中有一个type,实际上就是写一个sql语句查询status=1 并且type=#{type}就行了

  • 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 根据类型查询分类
    * @param type
    * @return
    */
    @GetMapping("/list")
    @ApiOperation("根据类型查询分类")
    public Result<List<Category>> list(Integer type){
    List<Category> list= categoryService.list(type);
    return Result.success(list);
    }

    这个list还不是很懂

  • 服务层

    1
    2
    3
    4
    5
    6
    7
    8
    /**
    * 根据类型查询分类
    * @param type
    * @return
    */
    public List<Category> list(Integer type) {
    return categoryMapper.list(type);
    }
  • 持久层

    1
    2
    3
    4
    5
    6
    7
    8
    <select id="list" resultType="Category">
    select * from category
    where status = 1
    <if test="type != null">
    and type = #{type}
    </if>
    order by sort ,create_time desc
    </select>

007 功能体验

分类这章到此结束

image-20250324110902060

第四章 公共字段自动填充

01 思路

在前面的代码中,员工管理和分类管理同时拥有create_time/user update_time/user

这样每次都要去set会很麻烦代码也会变得冗余

image-20250324141926323

只要在持久层返回做一个切面,统一处理这几个值,现在问题就是如何去判断要不要加上这几个值,

image-20250324142157165

001 @Retention

  • 翻译是保留的意思,这个注解的意思其实就是在什么阶段去保留
  • @Retention(RetentionPolicy.RUNTIME) 的作用是确保注解在运行时可用,基本上使用这个
  • @Retention(RetentionPolicy.SOURCE) 的作用是在源码时保留
  • @Retention(RetentionPolicy.CLASS) 的作用是在CLASS时可用

002 @Target

  • 这个的意思是指作用域在哪里
  • @Target(ElementType.METHOD) 作用在方法上
  • @Target(ElementType.TYPE) 作用在类型上
  • @Target(ElementType.LOCA_VARIABLE) 作用在变量上
  • 就可以让这个注解去注解别人

02 注解以及切面

  • 数据库操作类型写在这里

    image-20250326100958133
  • 这两注解学一下注解和反射就懂了

    1
    2
    3
    4
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AutoFill {
    }
  • 再创建注解类和切面类

    image-20250326101731347
  • 在切面创建AutoFillAspect

    image-20250326102415446

    1. @Aspect(Spring AOP 切面注解)

    作用

    • 声明当前类是一个 AOP 切面类,用于定义 横切关注点(如日志、事务、权限校验等)。
    • 通常配合 @Before@After@Around 等通知注解使用,拦截目标方法。

    2. @Component(Spring 组件注解)

    作用

    • 将当前类标记为 Spring 管理的 Bean,由 Spring 容器负责创建和依赖注入。
    • @Controller@Service@Repository 的通用父注解。

    为什么切面类需要 @Component

    • @Aspect 仅定义切面逻辑,但切面类本身需要被 Spring 容器实例化才能生效。
    • 所以 @Aspect@Component 通常一起使用