苍穹外卖day02


前言

苍穹外卖day02,主要开发员工模块代码,包含新增员工、员工分页查询、启用禁用员工账号和编辑员工接口。
觉得有帮助的可以看下我的个人网站 www.yucan.dev


提示:以下是本篇文章正文内容,下面案例可供参考

一、新增员工

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

需求分析和设计

产品原型

新增员工产品原型

接口设计

新增员工接口设计

数据库设计(employee表)

员工表设计

代码开发

根据新增员工接口设计对应的DTO
用DTO封装数据而不是直接使用实体类,使用DTO可以方便在参数类上添加注解,有助于数据校验,实体类封装数据会产生不需要的变量是对性能的浪费

/**
 * 新增员工
 * @param employeeDTO
 * @return
 */
@PostMapping                // 该接口是post
@ApiOperation("新增员工")     // Swagger接口文档注解, @ApiOperation用在方法上,例如Controller的方法,说明方法的用途、作用
public Result save(@RequestBody EmployeeDTO employeeDTO) {   /*
                                                             *  @RequestBody 注解用于将 HTTP 请求体中的 JSON 数据转换为 Java 对象
                                                             *  @RequestBody 是 Spring Framework 中用于处理 HTTP 请求体的注解。
                                                             *  通常用于 RESTful Web 服务的控制器方法中,以便将请求体内容自动反序列化为 Java 对象
                                                             */
    log.info("新增员工:{}", employeeDTO);   // 增加日志方便调试
                                            // 使用 SLF4J(Simple Logging Facade for Java)或者 Log4j 等日志框架时,使用 {} 占位符来格式化日志信息
                                            // SLF4J 会自动将后面的参数替换到占位符位置。
    employeeService.save(employeeDTO);
    return Result.success();
}

employeeService.save()方法

/**
 * 新增员工
 * @param employeeDTO
 */
@Override
public void save(EmployeeDTO employeeDTO) {
    // 转DTO,传入Mapping层需要是实体类
    Employee employee = new Employee();

    // employee.setUsername(employeeDTO.getUsername());         // 直接设置属性过于繁琐

    // 这里使用了 对象属性拷贝 ,Spring提供了BeanUtils工具类, 使用该工具类要确保属性名称保持一致
    BeanUtils.copyProperties(employeeDTO, employee);

    // employee实体类中属性比DTO中更多,所以需要继续将剩下属性填充
    // 设置账号状态,默认正常状态 1表示正常 0表示锁定
    employee.setStatus(StatusConstant.ENABLE);

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

    // 设置创建时间,更新时间
    employee.setCreateTime(LocalDateTime.now());
    employee.setUpdateTime(LocalDateTime.now());

    // 设置d当前记录创建人id,修改人id
    // TODO 创建人和修改人应该从前端传过来,动态获取,后期改变为当前用户id
    employee.setCreateUser(10L);
    employee.setUpdateUser(10L);

    employeeMapper.insert(employee);
}

功能测试

  • 通过接口文档测试
  • 前后端联调测试
    由于前后端是并行开发,往往后端开发某个功能后,前端对应功能未完成,导致无法进行前后端联调测试,所以在开发阶段,后端测试主要以接口文档测试为主。
    token处理
  • 调用员工登录接口获得一个合法的JWT令牌
  • 将合法的JWT令牌添加到全局参数中
    通过接口文档测试时token处理

代码完善

程序存在问题:

  • 录入的用户名已经存在,抛出异常之后没有处理 - 数据库中用户名字段设置成unique
  • 新增员工时,creatUser和updateUser设置为了固定值
  1. 解决异常,通过全局异常器处理
    解决录入的用户名已经存在的异常
  2. 2.针对第二个问题,可以通过JWT Token动态获取当前登陆员工id
    JWT Token登陆流程
    JWT Token登陆流程
    在拦截请求验证JWT Token环节可以反向解析Token,获取当前登陆用户id,因为在生成JWT Token环节是一个已经登陆的状态,token中包含登陆id信息。
    employeeController.java
    employeeController.java
    JwtTokenAdminInterceptor.java
    JwtTokenAdminInterceptor.java
    解析出员工登陆id后,如何传递给Service的save方法?
    ThreadLocal 并不是一个Thread,而是Thread的局部变量。
    ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
    注意:客户端发送的每次请求,后端的Tomcat服务器都会分配一个单独的线程来处理请求
    所以我们可以在请求验证JWT Token环节将id存储到ThreadLocal中,然后在service中的save读取id
    ThreadLocal常用方法:
public void set(T value)   设置当前线程的线程局部变量的值
public T get()   返回当前线程所对应的线程局部变量的值
public void remove()        移除当前线程的线程局部变量

我们在实际中使用ThreadLocal会进行一个简单的封装,包装成一个工具类,使用起来会更方便,初始工程中sky-common部分的 com.sky.context

二、员工分页查询

需求分析

在这里插入图片描述
在这里插入图片描述

代码开发

  • 根据分页查询接口设计对应的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
    data里存放的就是PageResult对象
    员工分页查询接口文档中返回数据
    首先在EmployeeControl.java中增加员工分页方法
/**
 * 员工分页查询
 * @param employeePageQueryDTO
 * @return
 */
@GetMapping("/page")     // 接口是GET方式请求
@ApiOperation("员工分页查询")     // Swagger接口文档注解
public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO) {  //前端请求数据格式是Query
    log.info("员工分页查询,参数为:{}", employeePageQueryDTO);
    PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
    return Result.success(pageResult);
}

然后在EmployeeService.java声明pageQuery接口和EmployeeServiceImpl.java中实现pageQuery接口

/**
 * 员工分页查询
 * @param employeePageQueryDTO
 * @return
 */
@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
    // select * from employee limit 0, 10
    // 开始分页查询,使用pagehelper插件,这里能使用PageHelper插件是因为在项目描述文件pom.xml中添加了pagehelper依赖
    PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());       // 基于MyBatis拦截器实现

    // 在pageQuery()中似乎没有实现分页的SQL语句,而这里又没有将PageHelper的返回结果传递给pageQuery()方法,那么分页查询的SQL语句是如何实现的?
    // 是因为,PageHelper底层是通过ThreadLocal实现的,在pageQuery中实现数据库语句之前会通过ThreadLocal将实现分页的语句拼接起来
    Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);

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

    return new PageResult(total, records);
}

在这里插入图片描述
在这里插入图片描述

代码完善

日期显示是数组形式,格式不对
日期格式显示错误
解决方法

  • 方法一:在属性上加入注解,对日期进行格式化
  • 方法二:在WebMvcConfiguration中扩展Spring MVC的消息转换器,统一对日期进行格式化处理
/**
 * 扩展spring MVC框架的消息转换器
 * @param converters
 */
//对后端返回前端的数据统一
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    log.info("开始拓展消息转换器...");
    // 创建一个消息转化器对象
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    // 需要为消息转换器设置一个对象转换器,对象转换器将Java对象序列化为json对象
    converter.setObjectMapper(new JacksonObjectMapper());
    // 将写好的对象转换器放入Spring MVC框架的容器 converters中
    converters.add(0, converter);
}

三、启用禁用员工账号

需求分析

业务规则:

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

代码开发

/**
 * 启用禁用员工账号
 * @param id
 * @param status
 * @return
 */
@PostMapping("/status/{status}")        // 请求方式是POST,请求路径 /admin/employee/status/{status}
@ApiOperation("启用禁用员工账号")
// 两个参数,分别为路径参数status和地址栏传参id
public Result startOrStop(@PathVariable("status") Integer status, long id) {            // 查询功能,返回范型,非查询功能返回result即可
    log.info("启用禁用员工账号: {},{}", status, id);
    employeeService.startOrStop(status, id);
    return Result.success();
}

employServiceImp.java

    /**
     * 启用禁用员工账号
     * @param status
     * @param id
     */
    public void startOrStop(Integer status, long id) {
        // update employee set status = ? where id =?
        // 在这里希望设置成动态SQL修改语句,根据传进来的参数不同可以修改不同的数据
//        Employee employee = new Employee();
//        employee.setId(id);
//        employee.setStatus(status);

        // Employee实体添加了  @Builder 构建器注解,也可以通过Employee.builder()创建对象
        Employee employee = Employee.builder()
                        .status(status)
                        .id(id)
                        .build();

        employeeMapper.update(employee);
    }

EmployMapper.xml

<update id="update" parameterType="Employee">    <!--这里可以不带路径指定参数,是因为在application.yml配置文件中指明了mapper配置路径和映射路径 -->
    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="status != null"> status = #{status},</if>
        <if test="updateTime != null"> update_time = #{updateTime},</if>
        <if test="updateUser != null"> update_user = #{updateUser},</if>       <!-- MySQL语句不区分大小写-->
    </set>
    where id = #{id}
</update>

总结

day02主要是根据需求设计接口,然后通过接口文档开发代码即可,大部分内容还是通俗易懂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值