项目介绍

本项目(苍穹外卖)是专门为餐饮企业(餐厅、饭店)定制的一款软件产品,包括 系统管理后台 和 小程序端应用 两部分。其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐厅的分类、菜品、套餐、订单、员工等进行管理维护,对餐厅的各类数据进行统计,同时也可进行来单语音播报功能。小程序端主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单、支付、催单等。

项目架构

功能架构图

管理端功能

员工登录/退出 , 员工信息管理 , 分类管理 , 菜品管理 , 套餐管理 , 菜品口味管理 , 订单管理 ,数据统计,来单提醒

功能列表

模块描述
登录/退出内部员工必须登录后,才可以访问系统管理后台
员工管理管理员可以在系统后台对员工信息进行管理,包含查询、新增、编辑、禁用等功能
分类管理主要对当前餐厅经营的 菜品分类 或 套餐分类 进行管理维护, 包含查询、新增、修改、删除等功能
菜品管理主要维护各个分类下的菜品信息,包含查询、新增、修改、删除、启售、停售等功能
套餐管理主要维护当前餐厅中的套餐信息,包含查询、新增、修改、删除、启售、停售等功能
订单管理主要维护用户在移动端下的订单信息,包含查询、取消、派送、完成,以及订单报表下载等功能
数据统计主要完成对餐厅的各类数据统计,如营业额、用户数量、订单等

用户端功能

微信登录 , 收件人地址管理 , 用户历史订单查询 , 菜品规格查询 , 购物车功能 , 下单 , 支付、分类及菜品浏览

功能列表

模块描述
登录/退出用户需要通过微信授权后登录使用小程序进行点餐
点餐-菜单在点餐界面需要展示出菜品分类/套餐分类, 并根据当前选择的分类加载其中的菜品信息, 供用户查询选择
点餐-购物车用户选中的菜品就会加入用户的购物车, 主要包含 查询购物车、加入购物车、删除购物车、清空购物车等功能
订单支付用户选完菜品/套餐后, 可以对购物车菜品进行结算支付, 这时就需要进行订单的支付
个人信息在个人中心页面中会展示当前用户的基本信息, 用户可以管理收货地址, 也可以查询历史订单数据

技术栈

关于本项目的技术选型, 我们将会从 用户层、网关层、应用层、数据层 这几个方面进行介绍,主要用于展示项目中使用到的技术框架和中间件等。

应用层

  • SpringBoot: 快速构建Spring项目, 采用 "约定优于配置" 的思想, 简化Spring项目的配置开发
  • SpringMVC:SpringMVC是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合,可以无缝集成
  • Spring Task: 由Spring提供的定时任务框架
  • httpclient: 主要实现了对http请求的发送
  • Spring Cache: 由Spring提供的数据缓存框
  • JWT: 用于对应用程序上的用户进行身份验证的标记
  • 阿里云OSS: 对象存储服务,在项目中主要存储文件,如图片等
  • Swagger: 可以自动的帮助开发人员生成接口文档,并对接口进行测试
  • POI: 封装了对Excel表格的常用操作
  • WebSocket: 一种通信网络协议,使客户端和服务器之间的数据交换更加简单,用于项目的来单、催单功能实现

数据层

  • MySQL: 关系型数据库, 本项目的核心业务数据都会采用MySQL进行存储
  • Redis: 基于key-value格式存储的内存数据库, 访问速度快, 经常使用它做缓存
  • Mybatis: 本项目持久层将会使用Mybatis开发
  • pagehelper: 分页插件
  • spring data redis: 简化java代码操作Redis的API

开发环境

后端环境

后端工程基于 maven 进行项目构建,并且进行分模块开发。

整体结构

对工程的每个模块作用说明:

作用说明

序号名称说明
1sky-take-outmaven父工程,统一管理依赖版本,聚合其他子模块
2sky-common子模块,存放公共类,例如:工具类、常量类、异常类等
3sky-pojo子模块,存放实体类、VO、DTO等
4sky-server子模块,后端服务,存放配置文件、Controller、Service、Mapper等

sky-common

模块中存放的是一些公共类,可以供其他模块使用

分析sky-common模块的每个包的作用:

作用说明

名称说明
constant存放相关常量类
context存放上下文类
enumeration项目的枚举类存储
exception存放自定义异常类
json处理json转换的类
properties存放SpringBoot相关的配置属性类
result返回结果类的封装
utils常用工具类

sky-pojo:

模块中存放的是一些 entity、DTO、VO

分析sky-pojo模块的每个包的作用:

作用说明

名称说明
Entity实体,通常和数据库中的表对应
DTO数据传输对象,通常用于程序中各层之间传递数据
VO视图对象,为前端展示数据提供的对象
POJO普通Java对象,只有属性和对应的getter和setter

sky-server

模块中存放的是 配置文件、配置类、拦截器、controller、service、mapper、启动类等

分析sky-server模块的每个包的作用:

作用说明

名称说明
config存放配置类
controller存放controller类
interceptor存放拦截器类
mapper存放mapper接口
service存放service类
SkyApplication启动类

数据库环境

整体结构

整体结构

序号数据表名中文名称
1employee员工表
2category分类表
3dish菜品表
4dish_flavor菜品口味表
5setmeal套餐表
6setmeal_dish套餐菜品关系表
7user用户表
8address_book地址表
9shopping_cart购物车表
10orders订单表
11order_detail订单明细表

employee

具体结构

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)姓名
usernamevarchar(32)用户名唯一
passwordvarchar(64)密码
phonevarchar(11)手机号
sexvarchar(2)性别
id_numbervarchar(18)身份证号
statusint账号状态1正常 0锁定
create_timedatetime创建时间
update_timedatetime最后修改时间
create_userbigint创建人id
update_userbigint最后修改人id

category

category表为分类表,用于存储商品的分类信息。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)分类名称唯一
typeint分类类型1菜品分类 2套餐分类
sortint排序字段用于分类数据的排序
statusint状态1启用 0禁用
create_timedatetime创建时间
update_timedatetime最后修改时间
create_userbigint创建人id
update_userbigint最后修改人id

dish

dish表为菜品表,用于存储菜品的信息。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)菜品名称唯一
category_idbigint分类id逻辑外键
pricedecimal(10,2)菜品价格
imagevarchar(255)图片路径
descriptionvarchar(255)菜品描述
statusint售卖状态1起售 0停售
create_timedatetime创建时间
update_timedatetime最后修改时间
create_userbigint创建人id
update_userbigint最后修改人id

dish_flavor

dish_flavor表为菜品口味表,用于存储菜品的口味信息。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
dish_idbigint菜品id逻辑外键
namevarchar(32)口味名称
valuevarchar(255)口味值

setmeal

setmeal表为套餐表,用于存储套餐的信息。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)套餐名称唯一
category_idbigint分类id逻辑外键
pricedecimal(10,2)套餐价格
imagevarchar(255)图片路径
descriptionvarchar(255)套餐描述
statusint售卖状态1起售 0停售
create_timedatetime创建时间
update_timedatetime最后修改时间
create_userbigint创建人id
update_userbigint最后修改人id

setmeal_dish

setmeal_dish表为套餐菜品关系表,用于存储套餐和菜品的关联关系。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
setmeal_idbigint套餐id逻辑外键
dish_idbigint菜品id逻辑外键
namevarchar(32)菜品名称冗余字段
pricedecimal(10,2)菜品单价冗余字段
copiesint菜品份数

user

user表为用户表,用于存储C端用户的信息。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
openidvarchar(45)微信用户的唯一标识
namevarchar(32)用户姓名
phonevarchar(11)手机号
sexvarchar(2)性别
id_numbervarchar(18)身份证号
avatarvarchar(500)微信用户头像路径
create_timedatetime注册时间

address_book

address_book表为地址表,用于存储C端用户的收货地址信息。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
user_idbigint用户id逻辑外键
consigneevarchar(50)收货人
sexvarchar(2)性别
phonevarchar(11)手机号
province_codevarchar(12)省份编码
province_namevarchar(32)省份名称
city_codevarchar(12)城市编码
city_namevarchar(32)城市名称
district_codevarchar(12)区县编码
district_namevarchar(32)区县名称
detailvarchar(200)详细地址信息具体到门牌号
labelvarchar(100)标签公司、家、学校
is_defaulttinyint(1)是否默认地址1是 0否

shopping_cart

shopping_cart表为购物车表,用于存储C端用户的购物车信息。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)商品名称
imagevarchar(255)商品图片路径
user_idbigint用户id逻辑外键
dish_idbigint菜品id逻辑外键
setmeal_idbigint套餐id逻辑外键
dish_flavorvarchar(50)菜品口味
numberint商品数量
amountdecimal(10,2)商品单价
create_timedatetime创建时间

orders

orders表为订单表,用于存储C端用户的订单数据。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
numbervarchar(50)订单号
statusint订单状态1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
user_idbigint用户id逻辑外键
address_book_idbigint地址id逻辑外键
order_timedatetime下单时间
checkout_timedatetime付款时间
pay_methodint支付方式1微信支付 2支付宝支付
pay_statustinyint支付状态0未支付 1已支付 2退款
amountdecimal(10,2)订单金额
remarkvarchar(100)备注信息
phonevarchar(11)手机号
addressvarchar(255)详细地址信息
user_namevarchar(32)用户姓名
consigneevarchar(32)收货人
cancel_reasonvarchar(255)订单取消原因
rejection_reasonvarchar(255)拒单原因
cancel_timedatetime订单取消时间
estimated_delivery_timedatetime预计送达时间
delivery_statustinyint配送状态1立即送出 0选择具体时间
delivery_timedatetime送达时间
pack_amountint打包费
tableware_numberint餐具数量
tableware_statustinyint餐具数量状态1按餐量提供 0选择具体数量

order_detail

order_detail表为订单明细表,用于存储C端用户的订单明细数据。具体表结构如下:

具体结构

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)商品名称
imagevarchar(255)商品图片路径
order_idbigint订单id逻辑外键
dish_idbigint菜品id逻辑外键
setmeal_idbigint套餐id逻辑外键
dish_flavorvarchar(50)菜品口味
numberint商品数量
amountdecimal(10,2)商品单价

业务实现

新增员工

新增员工,就是将我们新增页面录入的员工数据插入到employee表

employee表为员工表,用于存储商家内部的员工信息。具体表结构如下:

设计DTO类

前端传递参数列表:

image-20221111164002448

其中,Employee类中的数据远多于提交的数据

image-20221111164453341

当前端提交的数据和实体类中对应的属性差别比较大时,建议使用DTO来封装数据

所以自定义DTO类

package com.sky.dto;
import lombok.Data;
import java.io.Serializable;

@Data
public class EmployeeDTO implements Serializable {
    private Long id;
    private String username;
    private String name;
    private String phone;
    private String sex;
    private String idNumber;

}
其中,Serializable 是一个标记接口,它表示一个类的对象可以被序列化,EmployeeDTO 类实现了 Serializable 接口,这意味着 EmployeeDTO 类的对象可以被序列化,例如保存到文件中或者通过网络传输

Controller层

进入到sky-server模块中,在com.sky.controller.admin包下,在EmployeeController中创建新增员工方法,接收前端提交的参数。

@PostMapping
    public Result save(@RequestBody EmployeeDTO employeeDTO){
        log.info("新增员工:{}",employeeDTO);
        employeeService.save(employeeDTO);//调用Server层中的save函数,传递employeeDTO
        return Result.success();
    }

其中,Result类定义了后端统一返回结果格式。

进入sky-common模块,在com.sky.result包下定义了Result.java

package com.sky.result;
import lombok.Data;
import java.io.Serializable;

@Data
public class Result<T> implements Serializable {

    private Integer code; //编码:1成功,0和其它数字为失败
    private String msg; //错误信息
    private T data; //数据

    public static <T> Result<T> success() {
        Result<T> result = new Result<T>();
        result.code = 1;
        return result;
    }

    public static <T> Result<T> success(T object) {
        Result<T> result = new Result<T>();
        result.data = object;
        result.code = 1;
        return result;
    }

    public static <T> Result<T> error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }

}
<t>表示泛型,返回的类型由调用者提供的数据决定,如果你调用 Result.success("Hello, World!"),这里的 T 是 String,那么返回的 Result 对象的 data 字段将是一个 String 类型的数据。如果你调用 Result.success(123),这里的 T 是 Integer,那么返回的 Result 对象的 data 字段将是一个 Integer 类型的数据

Service层接口

在EmployeeService接口中声明新增员工方法

进入到sky-server模块中,com.sky.server.EmployeeService

void save(EmployeeDTO employeeDTO);

Service层实现类

在EmployeeServiceImpl中实现新增员工方法

com.sky.server.impl.EmployeeServiceImpl中创建方法

public void save(EmployeeDTO employeeDTO) {
        Employee employee = new Employee();

        //对象属性拷贝,将employeeDTO的值复制到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
        employee.setCreateUser(10L);//目前写个假数据,后期修改
        employee.setUpdateUser(10L);

        employeeMapper.insert(employee);//后续步骤定义
    }

在sky-common模块com.sky.constants包下已定义StatusConstant.java,引用这个包来表示是否开启用户

package com.sky.constant;

public class StatusConstant {

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

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

Mapper层

在EmployeeMapper中声明insert方法

com.sky.EmployeeMapper中添加方法

@Insert("insert into employee (name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user,status) " +
            "values " +
            "(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})")
    void insert(Employee employee);

在application.yml中已开启驼峰命名,故id_number和idNumber可对应。

mybatis:
  configuration:
    #开启驼峰命名
    map-underscore-to-camel-case: true

处理抛出异常

录入的用户名已存,抛出的异常后没有处理

image-20221111193700895

后台报错信息:

image-20221111194049620

查看employee表结构:

image-20221111194131787

发现,username已经添加了唯一约束,不能重复。

解决:

通过全局异常处理器来处理。

进入到sky-server模块,com.sky.hander包下,GlobalExceptionHandler.java添加方法

@ExceptionHandler
    public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){=
        String message = ex.getMessage();
        //获取到的内容即Duplicate entry 'zhangsan' for key 'employee.idx_username'
        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);
        }
    }

进入到sky-common模块,在MessageConstant.java添加

public static final String ALREADY_EXISTS = "已存在";

再次,接口测试:

生成JWT

在Service层实现类中我们设置的Id的方式为

employee.setCreateUser(10L);
employee.setUpdateUser(10L);

此值为固定值,但我们需要获取当前修改人的id,并且将其设置进去,需要一种动态的方式获取员工的Id

利用JWT令牌可完成需求

员工登录成功后会生成JWT令牌并响应给前端,后续请求中,前端会携带JWT令牌,通过JWT令牌可以解析出当前登录员工id

token生成逻辑代码:

Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                claims);

配置拦截器

package com.sky.interceptor;

/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       
        //..............
        
        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}

ThreadLocal传递信息

ThreadLocal 并不是一个Thread,而是Thread的局部变量。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

  • public void set(T value) 设置当前线程的线程局部变量的值
  • public T get() 返回当前线程所对应的线程局部变量的值
  • public void remove() 移除当前线程的线程局部变量

初始工程中已经封装了 ThreadLocal 操作的工具类:

在sky-common模块

package com.sky.context;

public class BaseContext {
    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }

    public static void removeCurrentId() {
        threadLocal.remove();
    }
}

在拦截器中解析出当前登录员工id,并放入线程局部变量中:

在sky-server模块中,拦截器:

package com.sky.interceptor;

@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        //.............................
       
        //2、校验令牌
        try {
            //.................
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);
            /////将用户id存储到ThreadLocal////////
            BaseContext.setCurrentId(empId);
            ////////////////////////////////////
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //......................
        }
    }
}

在Service中获取线程局部变量中的值:

public void save(EmployeeDTO employeeDTO) {
        //.............................

        //设置当前记录创建人id和修改人id
        employee.setCreateUser(BaseContext.getCurrentId());//目前写个假数据,后期修改
        employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.insert(employee);
    }

员工分页查询

设计DTO类

  • 请求参数类型为Query,不是json格式提交,在路径后直接拼接。/admin/employee/page?name=zhangsan
  • 返回数据中records数组中使用Employee实体类对属性进行封装。
package com.sky.dto;
import lombok.Data;
import java.io.Serializable;

@Data
public class EmployeePageQueryDTO implements Serializable {
    //员工姓名
    private String name;
    //页码
    private int page;
    //每页显示记录数
    private int pageSize;

}

封装PageResult

后面所有的分页查询,统一都封装为PageResult对象。

在sky-common模块

package com.sky.result;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {

    private long total; //总记录数

    private List records; //当前页数据集合

}

员工信息分页查询后端返回的对象类型为: Result<PageResult>

Controller层

在sky-server模块中,com.sky.controller.admin.EmployeeController中添加分页查询方法。

@GetMapping("/page")
    @ApiOperation("员工分页查询")
    public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO){
        log.info("员工分页查询,参数为:{}", employeePageQueryDTO);
        PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);//后续定义
        return Result.success(pageResult);
    }

Service层接口

在EmployeeService接口中声明pageQuery方法:

PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);

Service层实现类

在EmployeeServiceImpl中实现pageQuery方法:

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

注意:此处使用 mybatis 的分页插件 PageHelper 来简化分页代码的开发。底层基于 mybatis 的拦截器实现。

故在pom.xml文中添加依赖(初始工程已添加)

<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper-spring-boot-starter</artifactId>
   <version>${pagehelper}</version>
</dependency>

Mapper层

在 EmployeeMapper 中声明 pageQuery 方法:

Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);

在 src/main/resources/mapper/EmployeeMapper.xml 中编写SQL:

<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>

SpringMVC的消息转换器处理日期格式

操作时间字段显示有问题

可以在WebMvcConfiguration中扩展SpringMVC的消息转换器,统一对日期类型进行格式处理

protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器...");
        //创建一个消息转换器对象
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        //需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
        converter.setObjectMapper(new JacksonObjectMapper());
        //将自己的消息转化器加入容器中
        converters.add(0,converter);
    }

时间格式定义,sky-common模块中

package com.sky.json;
public class JacksonObjectMapper extends ObjectMapper {
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";

    }
}

根据id查询员工信息

image-20221112145607939 image-20221112145619775

Controller层

在 EmployeeController 中创建 getById 方法:

@GetMapping("/{id}")
    @ApiOperation("根据id查询员工信息")
    public Result<Employee> getById(@PathVariable Long id){
        Employee employee = employeeService.getById(id);
        return Result.success(employee);
    }

其中,@PathVariable 是一个注解,表示这个参数的值会从HTTP请求的URL路径中提取

Service层

在 EmployeeService 接口中声明 getById 方法:

Employee getById(Long id);

Service层实现类

在 EmployeeServiceImpl 中实现 getById 方法:

public Employee getById(Long id) {
        Employee employee = employeeMapper.getById(id);
        return employee;
    }

Mapper层

在 EmployeeMapper 接口中声明 getById 方法:

/**
     * 根据id查询员工信息
     * @param id
     * @return
     */
    @Select("select * from employee where id = #{id}")
    Employee getById(Long id);

编辑员工信息

注:因为是修改功能,请求方式可设置为PUT。

Controller层

在 EmployeeController 中创建 update 方法:

@PutMapping
    @ApiOperation("编辑员工信息")
    public Result update(@RequestBody EmployeeDTO employeeDTO){
        log.info("编辑员工信息:{}", employeeDTO);
        employeeService.update(employeeDTO);
        return Result.success();
    }

Service层接口

在 EmployeeService 接口中声明 update 方法:

void update(EmployeeDTO employeeDTO);

Service层实现类

在 EmployeeServiceImpl 中实现 update 方法:

public void update(EmployeeDTO employeeDTO) {
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO, employee);

        employee.setUpdateTime(LocalDateTime.now());
        employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.update(employee);
    }

Mapper层

在 EmployeeMapper 接口中声明 update 方法:

void update(Employee employee);

在 EmployeeMapper.xml 中编写SQL:

<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>
最后修改:2025 年 08 月 01 日
如果觉得我的文章对你有用,请随意赞赏