overlord-lxy

后端学习Day02

项目来源:B站黑马程序员《苍穹外卖》
本帖仅为学习日志

一、新增员工

(一)需求分析和设计

1.产品原型:

2.接口设计:

本项目约定:

  • 管理端发出的的请求,统一使用/admin作为前缀
  • 用户端发出的请求,统一使用/user作为前缀

3.数据库设计(employee表):

(二)代码开发

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

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

  • Controller层
/**
 * 新增员工
 *
 * @return
 */
@PostMapping
@ApiOperation("新增员工")
public Result save(@RequestBody EmployeeDTO employeeDTO){
    log.info("新增员工:{}",employeeDTO);
    //调用Service层新增员工
    employeeService.save(employeeDTO); //alt+enter 扩展方法
    return Result.success();
}
  • Service层
/**
 * 新增员工
 * @param employeeDTO
 * @return
 */
void save(EmployeeDTO employeeDTO);
/**
 * 新增员工
 * @param employeeDTO
 * @return
 */
public void save(EmployeeDTO employeeDTO){
    Employee employee = new Employee();
    //employee.setName(employeeDTO.getName());
    //使用对象属性拷贝,一次性将employeeDTO中的数据拷贝到employee中
    BeanUtils.copyProperties(employeeDTO,employee); //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);
}
  • Mapper层
/**
 * 插入员工数据
 * @param employee
 */
@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);

(三)功能测试

功能测试方法:

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

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

进行登录测试获取token,并将其存储为全局参数

接口文档测试成功

前后端联调测试成功

(四)代码完善

当前问题:

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

/**
 * 处理SQL异常
 * @param ex
 * @return
 */
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
    //Duplicate entry 'zhangsan' for key 'employee.idx_username'
    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并不是一个Thread,而是一个Thread的局部变量。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外无法访问。

ThreadLocal常用方法:

  • public void set(T value) 设置当前线程的线程局部变量的值
  • public T get() 返回当前线程所对应的线程局部变量的值
  • public void remove() 移除当前线程的线程局部变量
    //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);
        BaseContext.setCurrentId(empId);
        //3、通过,放行
        return true;
    } catch (Exception ex) {
        //4、不通过,响应401状态码
        response.setStatus(401);
        return false;
    }
    //设置当前记录创建人id和修改人id
    employee.setCreateUser(BaseContext.getCurrentId());
    employee.setUpdateUser(BaseContext.getCurrentId());

二、员工分页查询

(一)需求分析和设计

产品原型:

业务规则:

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

接口设计:

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

分页查询统一封装成PageResult对象:

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

(二)代码开发

pageHelper: 实现分页查询的mybatis插件

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
  • Controller
/**
 * 员工分页查询
 * @param employeePageQueryDTO
 * @return
 */
@GetMapping("/page")
@ApiOperation("员工分页查询")
public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO){
    log.info("员工分页查询,参数为:{}",employeePageQueryDTO);
    PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
    return Result.success(pageResult);
}

*Server

/**
 * 分页查询
 * @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);
}

*Mapper

/**
 * 分页查询
 * @param employeePageQueryDTO
 * @return
 */
PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
<!-- 动态xml -->
<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>

(三)功能测试

注:token有效时间为2小时。

# 设置jwt过期时间
admin-ttl: 7200000

接口文档测试成功

(四)代码完善

时间显示有问题

解决方式:

  • 方式一:在属性上加入注释,对日记进行格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;

只能处理单一属性

  • 方式二:在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());
    //将消息转换器添加到集合中
    //优先使用自定义的消息转换器
    converters.add(0,converter);
}

三、启用禁用员工账号

(一)需求分析和设计

产品原型:

业务规则:

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

接口设计:

(二)代码开发

该接口不涉及查询,不需要泛型

  • Controller层
/**
 * 启用/禁用员工账号
 * @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();
}

*Server层

/**
 * 启用/禁用员工账号
 * @param status
 * @param id
 */
void startOrStop(Integer status, Long id);
/**
 * 启用/禁用员工账号
 * @param status
 * @param id
 */
public void startOrStop(Integer status,Long id){
    // update employee set status = ? where id = ?

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

    //使用builder实现更简洁的构造
    Employee employee = Employee.builder()
            .status(status)
            .id(id)
            .build();
    employeeMapper.update(employee);
}
  • Mapper层
/**
 * 根据主键动态修改属性
 * @param employee
 */
// 使用动态sql
void update(Employee employee);
<update id="update" parameterType="Employee">
    update employee
    <set>
        <if test="name != null and name != ''"> name = #{name}, </if>
        <if test="username != null and username != ''"> username = #{username}, </if>
        <if test="password != null and password != ''"> password = #{password}, </if>
        <if test="phone != null and phone != ''"> phone = #{phone}, </if>
        <if test="sex != null">sex = #{sex},</if>
        <if test="idNumber != null and idNumber != ''"> 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>
    </set>
    <where>
        id = #{id}
    </where>
</update>

(三)功能测试

接口测试:

前后端联调测试:


四、编辑员工

(一)需求分析和设计

产品原型:

编辑员工功能涉及两个接口

  • 根据id查询员工信息
  • 编辑员工信息



(二)代码开发

根据id查询员工信息接口

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

*Server层

/**
 * 根据id查询员工
 * @param id
 * @return
 */
Employee getById(Long id);
/**
 * 根据id查询员工
 * @param id
 * @return
 */
public Employee getById(Long id) {
    Employee employee = employeeMapper.getById(id);
    //将密码设置不可见
    employee.setPassword("******");
    return employee;
}
  • Mapper层
/**
 * 根据id查询员工信息
 * @param id
 * @return
 */
@Select("select * from employee where id = #{id}")
Employee getById(Long id);

编辑员工信息接口:

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

*Server层

/**
 * 编辑员工信息
 * @param employeeDTO
 */
void update(EmployeeDTO employeeDTO);
/**
 * 编辑员工信息
 * @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);
}

(三)功能测试

根据id查询员工信息:
接口文档测试:

前后端联调测试:

编辑员工信息:
接口文档测试:

前后端联调测试:

五、导入分类模块功能代码

(一)需求分析

产品原型:

业务规则:

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

接口设计:

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

数据库设计(category表):

(二)代码导入

(三)功能测试

posted on 2024-04-01 22:20  李向宇  阅读(12)  评论(0编辑  收藏  举报

导航