首页 > 其他分享 >苍穹外卖学习笔记——第二天

苍穹外卖学习笔记——第二天

时间:2024-04-09 14:01:20浏览次数:15  
标签:update 笔记 员工 public 接口 外卖 employee 苍穹 id

员工管理、分类管理

新增员工

需求分析和设计

产品原型

新增员工产品原型

业务规则

  • 账号必须是唯一的。
  • 手机号为合法的11位手机号码。
  • 身份证号为合法的18位身份证号码。
  • 密码默认为123456。

接口设计

新增员工接口设计
  • 本项目约定:管理端发出的请求,统一使用/admin作为前缀,用户端发出的请求,统一使用/user作为前缀。

数据库设计(employee表)

字段名 数据类型 说明 备注
id bigint 主键 自增
name varchar(32) 姓名
username varchar(32) 用户名 唯一
password varchar(64) 密码
phone varchar(11) 手机号
sex varchar(2) 性别
id_number varchar(18) 身份证号
status int 账号状态 1正常 0锁定
create_time datetime 创建时间
update_time datetime 最后修改时间
create_user bigint 创建人id
update_user bigint 最后修改人id

代码开发

根据新增员工接口设计对应的DTO

@Data
public class EmployeeDTO implements Serializable {

    private Long id;

    private String username;

    private String name;

    private String phone;

    private String sex;

    private String idNumber;

}

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

在EmployeeController中创建新增员工方法,接收前端提交的参数

@PostMapping
@ApiOperation("新增员工")
public Result add(@RequestBody EmployeeDTO employeeDTO) {
    log.info("新增员工:{}", employeeDTO);
    employeeService.save(employeeDTO);
    return Result.success();
}

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

void save(EmployeeDTO employeeDTO);

在EmployeeServiceImpl中实现新增员工方法

@Override
public void save(EmployeeDTO employeeDTO) {
    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(10L);
    employee.setUpdateUser(10L);

    employeeMapper.insert(employee);
}

在EmployeeMapper中声明insert方法

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

功能测试

功能测试方式

  • 通过接口文档测试。
  • 通过前后端联调测试。

注意:由于开发阶段前端和后端是并行开发的,后端完成某个功能后,此时前端对应的功能可能还没有开发完成,导致无法进行前后端联调测试。所以在开发阶段,后端测试主要以接口文档测试为主。

接口文档测试

  • 通过Swagger接口文档进行功能测试。
  • 调用员工登录接口获得一个合法的JWT令牌,再添加到全局参数中,就可以正常进行测试了。

代码完善

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

  • 在全局异常处理器中进行处理:
//GlobalExceptionHandler.java中

@ExceptionHandler
public Result usernameExistHandler(SQLIntegrityConstraintViolationException ex) {
    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);
    }
}

新增员工时,创建人id和修改人id设置为了固定值

  • 通过ThreadLocal来保存和获取当前登录员工id。
ThreadLocal
  • ThreadLocal 并不是一个Thread,而是Thread的局部变量。
  • ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
ThreadLocal常用方法
方法 说明
public void set(T value) 设置当前线程的线程局部变量的值
public T get() 返回当前线程所对应的线程局部变量的值
public void remove() 移除当前线程的线程局部变量
  • 注意:客户端发送的每次请求,后端的Tomcat服务器都会分配一个单独的线程来处理请求。

代码完善

  • 初始工程中已经封装了 ThreadLocal 操作的工具类:
//BaseContext.java中


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,并放入线程局部变量中:
//JwtTokenAdminInterceptor中

//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());

//2、校验令牌
try{
    Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
    Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
    BaseContext.setCurrentId(empId); //在拦截器中解析出当前登录员工id,并放入线程局部变量中
    //3、通过,放行
    return true;
}catch (Exception ex){
    //4、不通过,响应401状态码
    response.setStatus(401);
    return false;
}
  • 在Service中获取线程局部变量中的值:
public void save(EmployeeDTO employeeDTO) {
    Employee employee = new Employee();
    //属性拷贝
    BeanUtils.copyProperties(employeeDTO, employee);
    //账号状态默认为1,正常状态
    employee.setStatus(StatusConstant.ENABLE);
    //默认密码为123456
    employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
    //创建人、创建时间、修改人、修改时间
    employee.setCreateTime(LocalDateTime.now());
    employee.setUpdateTime(LocalDateTime.now());
    employee.setCreateUser(BaseContext.getCurrentId()); //从线程局部变量中当前登录员工id并存入新增员工对象
    employee.setUpdateUser(BaseContext.getCurrentId()); //从线程局部变量中当前登录员工id并存入新增员工对象
    
    employeeMapper.insert(employee);
}

员工分页查询

需求分析和设计

产品原型

员工分页查询产品原型

业务规则

  • 根据页码展示员工信息。
  • 每页展示10条数据。
  • 分页查询时可以根据需要,输入员工姓名进行查询。

接口设计

员工分页查询接口设计

代码开发

根据分页查询接口设计对应的DTO

@Data
public class EmployeePageQueryDTO implements Serializable {

    //员工姓名
    private String name;

    //页码
    private int page;

    //每页显示记录数
    private int pageSize;

}

所有的分页查询,统一都封装成PageResult对象

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

    private long total; //总记录数

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

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

根据接口定义创建分页查询方法

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

在EmployeeService接口中声明pageQuery方法

PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);

在 EmployeeServiceImpl 中实现 pageQuery 方法

@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
    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 的拦截器实现。

在 EmployeeMapper 中声明 pageQuery 方法

Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);

在 EmployeeMapper.xml 中编写SQL

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

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。

代码完善

操作时间字段展示有问题

解决方式一
  • 在属性上加入注解,对日期进行格式化:
//employee.java中

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
解决方式二
  • 在 WebMvcConfiguration 中扩展Spring MVC的消息转换器,统一对日期类型进行格式化处理:
/**
 * 扩展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);
}

启用禁用员工账号

产品原型

启用禁用员工账号产品原型

业务规则

  • 可以对状态为“启用”的员工账号进行“禁用”操作。
  • 可以对状态为“禁用”的员工账号进行“启用”操作。
  • 状态为“禁用”的员工账号不能登录系统。

接口设计

启用禁用员工账号接口设计

代码开发

根据接口设计中的请求参数形式对应的在 EmployeeController 中创建启用禁用员工账号的方法

@PostMapping("/status/{status}")
@ApiOperation("启用禁用员工账号")
public Result startOrStop(@PathVariable Integer status, Long id) {
    log.info("启用禁用员工账号:{},{}", status, id);
    employeeService.startOrStop(status, id);
    return Result.success();
}

在 EmployeeService 接口中声明启用禁用员工账号的业务方法

void startOrStop(Integer status, Long id);

在 EmployeeServiceImpl 中实现启用禁用员工账号的业务方法

@Override
public void startOrStop(Integer status, Long id) {
    Employee employee = Employee.builder()
            .status(status)
            .id(id)
            .updateTime(LocalDateTime.now())
            .updateUser(BaseContext.getCurrentId())
            .build();

    employeeMapper.update(employee);
}

在 EmployeeMapper 接口中声明 update 方法

void update(Employee employee);

在 EmployeeMapper.xml 中编写SQL

<update id="update">
    update employee
    <set>
        <if test="username != null">username = #{username},</if>
        <if test="name != null">name = #{name},</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="status != null">status = #{status},</if>
        <if test="createTime != null">create_time = #{createTime},</if>
        <if test="updateTime != null">update_time = #{updateTime},</if>
        <if test="createUser != null">create_user = #{createUser},</if>
        <if test="updateUser != null">update_user = #{updateUser},</if>
    </set>
    where id = #{id}

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。

编辑员工

产品原型

编辑员工产品原型

接口设计

  • 编辑员工功能涉及到两个接口:根据id查询员工信息、编辑员工信息。
根据id查询员工信息
编辑员工接口设计
编辑员工信息
编辑员工接口设计

代码开发

在 EmployeeController 中创建 getById 方法

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

在 EmployeeService 接口中声明 getById 方法

Employee getById(Long id);

在 EmployeeServiceImpl 中实现 getById 方法

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

在 EmployeeMapper 接口中声明 getById 方法

@Select("select * from employee where id = #{id}")
Employee getById(Long id);
  • 可以先通过接口测试确认数据回显是否有问题,如果没有问题再继续开发。

在 EmployeeController 中创建 update 方法

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

在 EmployeeService 接口中声明 update 方法

void update(EmployeeDTO employeeDTO);

在 EmployeeServiceImpl 中实现 update 方法

@Override
public void update(EmployeeDTO employeeDTO) {
    Employee employee = new Employee();

    BeanUtils.copyProperties(employeeDTO, employee);

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

    employeeMapper.update(employee);
}

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。

导入分类模块功能代码

需求分析和设计

产品原型

编辑员工产品原型

业务规则

  • 分类名称必须是唯一的。
  • 分类按照类型可以分为菜品分类和套餐分类。
  • 新添加的分类状态默认为“禁用”。

接口设计

有以下接口:

  • 新增分类
  • 分类分页查询
  • 根据id删除分类
  • 修改分类
  • 启用禁用分类
  • 根据类型查询分类

数据库设计(category表)

字段名 数据类型 说明 备注
id bigint 主键 自增
name varchar(32) 分类名称 唯一
type int 分类类型 1菜品分类 2套餐分类
sort int 排序字段 用于分类数据的排序
status int 状态 1启用 0禁用
create_time datetime 创建时间
update_time datetime 最后修改时间
create_user bigint 创建人id
update_user bigint 最后修改人id

代码导入

  • 导入资料中的分类管理模块功能代码即可。

功能测试

  • 直接进行前后端联调测试即可。

标签:update,笔记,员工,public,接口,外卖,employee,苍穹,id
From: https://www.cnblogs.com/zgg1h/p/18123833

相关文章

  • C++笔记:STL容器库的使用
    前置:    对于stl容器库,我只做了一些常用的笔记,关于更详细的使用可以参考:https://cppreference.com/https://cppreference.com/一.string--字符串对于C++中string字符串会比C语言的字符数组使用起来会顺手许多。命名空间:std关于迭代器可以理解为指针,和指针的使......
  • UE中UPROPERTY的用法(UEC++个人学习笔记)
    UPROPERTY设置可视//仅在类默认设置可见(即里面面板) UPROPERTY(VisibleDefaultsOnly) int32VisibleDefaultsOnlyInt; //仅在实例化细节面板可见(即外面面板) UPROPERTY(VisibleInstanceOnly) FStringVisibleInstancestring; //类默认设置和实例化细节面板都可见......
  • 【论文笔记-4】Cross-lingual learning for text processing: A survey
    跨语言知识迁移学习分类:转移资源:“什么”正在帮助转移multilingualwordembeddings:即来自多种语言的词汇共享一个语义向量空间。已经提出了许多用于训练多语言词嵌入(MWE)的模型(Mikolov,Le,&Sutskever,2013;Ammaretal.,2016;Gouws&Søgaard,2015)。Ruder(2017)提......
  • 狂神说Java Web学习笔记_Servlet
    Servlet简介Servlet是sun公司开发的动态web的一门技术。提供的其中一个接口叫Servlet。把实现了Servlet接口的Java程序叫Servlet。HelloServletServlet在Sun公司有两个默认实现类,HttpServlet,GenericServlet。importjavax.servlet.ServletException;importjavax.servlet.ht......
  • aardio学习笔记
    1.console.dump 这个函数,是可以显示类型和值的,比如:console.dump(type);  //显示type类型和值,这里的type就是一个类这个函数的主要作用是:主要功能用为显示变量或字符的类型2.所有变量的默认初始值是null,也就是定义一个变量不给他任何值,它就是nullvara;console.log(type(a)......
  • Python基础笔记02-while、字符串格式化、运算符、基础概念与数据类型
    前言!!!注意:本系列所写的文章全部是学习笔记,来自于观看视频的笔记记录,防止丢失。观看的视频笔记来自于:哔哩哔哩武沛齐老师的视频:2022Python的web开发(完整版)入门全套教程,零基础入门到项目实战1.条件语句补充1.1基本语句if条件: ...else:...1.2多条件if条件1:......
  • OpenStack学习笔记07-网络服务Neutron
    OpenStack学习笔记07-网络服务NeutronOpenStackLinux根据《云操作系统(OpenStack)》第七章来做的。一、基本概念Neutron需要至少配置一个外部网络,可以配置一个或多个内部网络二、安装并配置控制节点1.数据库配置1-1.登录MySQL数据库mysql-uroot-p0000001......
  • Datacom HCIP笔记-MPLS协议 之一
    MPLS标签放在二层头和IP头之间可以称之为2.5层的位置LSP(LabelSwitchedPath):标签交换路径,艮即到达同一目的地址的报文在MPLS网络中经过的路径。FEC(ForwardingEquivalentClass):一般指具有相同转发处理方式的报文。在MPLS网络中,到达同一目的地址的所有报文就是一个FEC。......
  • HTML笔记
    HTML​ 引言:HTML(超文本标记语言),可以理解为是网页的一个骨架,支撑着整个网页。标签分为双标签和单标签(自闭合标签),HTML中绝大多数都是双标签;在HTML中通过CSS选择器对网页元素进行样式,通过JavaScript进行网页的交互效果。标签名汇总1、网页的基本HTML结构:<!DOCTYPEhtml><htmlla......
  • 苍穹外卖学习笔记——第一天
    项目概述、环境搭建软件开发整体介绍软件开发流程步骤任务或输出文件需求分析需求规格说明书、产品原型设计UI设计、数据库设计、接口设计编码项目代码、单元测试测试测试用例、测试报告上线运维软件环境安装、配置角色分工角色分工处于流......