外卖项目–Springboot回顾Day2
任务:
- 新增员工
- 员工分页查询
- 启用禁用员工账号
- 编辑员工
- 导入分类模块功能代码
每一个任务的完成逻辑:
- 需求分析和设计(接口设计)
- 代码开发(根据新增员工接口设计对应DTO)
- 功能测试
- 代码完善
本项目约定:
管理端发出的请求,统一使用/admin作为前缀
用户端发出的请求,统一使用/user作为前缀
新增员工
需求分析和设计
1. 在Controller中写方法save
接受前端的数据并封装为EmployeeDTO类
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@PostMapping @ApiOperation("新增员工") public Result save(@RequestBody EmployeeDTO employeeDTO){ log.info("新增员工{}",employeeDTO); System.out.println("当前线程的id:" + Thread.currentThread().getId()); employeeService.save(employeeDTO); return Result.success(); }
|
2. 在Service层中的接口声明方法save,并在实现类中实现
需要在Service层中将EmployeeDTO类转为实体类,方便插入到数据库
EmployeeService.java
1 2 3 4 5
|
void save(EmployeeDTO employeeDTO);
|
EmployeeServicelmpl.java
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 26 27 28
|
public void save(EmployeeDTO employeeDTO) { System.out.println("当前线程的id:" + Thread.currentThread().getId()); Employee employee= new Employee();
BeanUtils.copyProperties(employeeDTO,employee);
employee.setStatus(StatusConstant.ENABLE);
employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
employee.setCreateTime(LocalDateTime.now()); employee.setUpdateTime(LocalDateTime.now());
employee.setCreateUser(10L); employee.setUpdateUser(10L);
employeeMapper.insert(employee); }
|
在Service持久层中使用实体类
所以需要将EmployeeDTO转换为实体类,通过使用对象属性拷贝,来避免过多的get,set方法造成代码冗余
3. 在Mapper层中实现数据插入
由于操作较为简洁,我通过@Insert注解的方式直接在EmployeeMapper.java中实现
EmployeeMapper.java
1 2 3 4 5 6 7 8
|
@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);
|
功能测试
代码完善
问题:
- 录入的用户名若已存在,抛出异常后没有处理
- 新增员工时,创建人id和修改人id设为了固定值”10L”
解决:
重载方法exceptionHandler
在全局异常处理器GlobalExceptionHandler.java中重载方法exceptionHandler来处理报出的SQLIntegrityConstraintViolationException类异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
@ExceptionHandler public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){ String message = ex.getMessage(); if(message.contains("Duplicate entry")){ String[] split = message.split(" "); String username =split[2]; String msg = username + MessageConstant.ALREADY_EXIST; return Result.error(msg); }else{ return(Result.error(MessageConstant.UNKNOWN_ERROR)); } }
|
使用TreadLocal来保存真实创建人id和修改人id
思路:
- 员工登录成功后会生成Jwt令牌并响应给前端
- 后续请求中,前端会携带Jwt令牌,通过令牌可以解析出当前员工id
- 通过TreadLocal将解析出的当前员工id传递给Service的save方法
Treadlocal:并不是一个线程,而是线程的一个局部变量:为每个线程单独提供一份存储空间,具有县城隔离效果,只有在同一线程内才能获取到对应的值
Treadlocal常用方法:
- public void set(T value) //设置当前线程的局部变量的值
- public T get() //得到当前线程的局部变量的值
- public void remove() //移除当前线程的局部变量的值
本项目已经把这三个方法封装到了工具类BaseContext
员工分类查询
需求分析和设计
代码开发
依据分页查询接口设计对应的DTO
后面所有的分页查询,统一封装成PageResult对象,再封装为Result,返回给前端
PageResult.java
1 2 3 4 5 6 7 8 9 10 11 12
|
@Data @AllArgsConstructor @NoArgsConstructor public class PageResult implements Serializable {
private long total;
private List records; }
|
之后完成剩余代码
EmployeeServicelmpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO){ PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());
Page<Employee> page=employeeMapper.pageQuery(employeePageQueryDTO);
long total = page.getTotal(); List<Employee> record = page.getResult();
return new PageResult(total,record); }
|
问题:返回给前端的日期显示不明确,eg:202309221823,期望显示则是2023年9月22日18:23
解决方法:
- 在属性上加入注释,对日期进行格式化
- 在WebMvcConfignration中拓展Spring MVC的消息转换器,统一对日期类型进行格式化处理
WebMvcConfignration.java
1 2 3 4 5 6 7 8 9 10 11 12 13
|
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters){ log.info("扩展消息转换器..."); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setObjectMapper(new JacksonObjectMapper()); converters.add(0,converter); }
|
序列化:Java对象—–>Json对象
启用/禁用员工账号
需求分析和设计
代码开发
EmployeeController.java
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@PostMapping("/status/{status}") @ApiOperation("启用或禁用员工账号") public Result startOrStop(@PathVariable("status") Integer status,Long id){ log.info("启用或禁用员工账号:{},{}",status,id); employeeService.startOrStop(status,id); return Result.success(); }
|
EmployeeServicelmpl.java
1 2 3 4 5 6 7 8
| public void startOrStop(Integer status, Long id) { Employee employee = Employee.builder() .status(status) .id(id) .build();
employeeMapper.update(employee); }
|
EmployeeMapper.xml
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>
|
编辑员工
EmployeeController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
@GetMapping("/{id}") @ApiOperation("根据id查询员工信息") public Result<Employee> getById(@PathVariable("id") Long id){ Employee employee = employeeService.getById(id); return Result.success(employee); }
@PutMapping @ApiOperation("编辑员工信息") public Result update(@RequestBody EmployeeDTO employeeDTO){ log.info("编辑员工信息:{}",employeeDTO); employeeService.update(employeeDTO); return Result.success(); }
|
EmployeeServicelmpl.java
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
|
public Employee getById(Long id){ Employee employee = employeeMapper.getById(id); employee.setPassword("******"); return employee; }
public void update(EmployeeDTO employeeDTO) { Employee employee = new Employee(); BeanUtils.copyProperties(employeeDTO,employee);
employee.setUpdateTime(LocalDateTime.now()); employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.update(employee); }
|