本文章记录学习苍穹外卖的过程和遇到的问题。
首次接手苍穹外卖这个项目,可以发现并不是让我们从零开始建立的,我们是在一定基础上进行后续的功能开发的。并且提供了前端所有的源码以便于我们进行前后端联调测试,而且把先把学习重心放到后端实现上来。
我首先关注到的是这个项目的结构,跟目录下分了3个包,分别是common(普通类)、pojo(实体类等)和server(业务逻辑类等),把前端用nginx启动后,直接在server包下的SkyApplication类启动这个项目。发现这个项目运行在本地的8080上,登录和登出功能已经是做好了的。
然后老师带我们进行了需求分析,导入需要实现的功能接口,老师演示的是Yapi导入的接口,由于它已经停止服务我便使用apifox进行了接口导入。
第一个功能->新增员工 查看接口
在控制层EmployeeController类新增一个方法作为对外的接口
1 2 3 4 5 6 7 8 9 10 11 12 @PostMapping @ApiOperation("新增员工") public Result save (@RequestBody EmployeeDTO employeeDTO) { log.info("新增员工: {}" , employeeDTO); employeeService.save(employeeDTO); return Result.success(); }
具体的实现交给业务逻辑层的employeeService接口和它的实现类,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Override public void save (EmployeeDTO employeeDTO) { 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(BaseContext.getCurrentId()); employee.setUpdateUser(BaseContext.getCurrentId()); employeeMapper.insert(employee); }
至于数据库的相关操作交给Mapper层处理
1 2 3 4 5 6 7 8 @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) ;
做了两个优化
问题有:
1.录入的用户名重复抛出的异常没有处理
2.新增员工的创建人id和修改人id设置为了固定值
第一个 查看控制台的报错,”Duplicate entry…”,在全局的异常处理器handler的GlobalExceptionHandler.java统一捕获处理异常
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.AlREDY_EXISTS; return Result.error(msg); }else { return Result.error(MessageConstant.UNKNOWN_ERROR); } } }
第二个
生成jwt令牌的时候用到了用户的id,把它反解析出来
1 Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
利用每一次请求都是同一线程的特点,使用ThreadLocal保存并在需要的时候调用即可。以下是这个类的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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(); } }
于是可以在生成jwt令牌时保存
1 2 3 4 Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());log.info("当前员工id:" , empId); BaseContext.setCurrentId(empId);
在实现类里面调用
1 2 3 4 employee.setCreateUser(BaseContext.getCurrentId()); employee.setUpdateUser(BaseContext.getCurrentId());
第二个功能员工分页查询 控制层EmployeeController类
1 2 3 4 5 6 7 8 9 10 11 12 @GetMapping("/page") @ApiOperation("员工分页查询") public Result<PageResult> page (EmployeePageQueryDTO employeePageQueryDTO) { log.info("员工分页查询,参数为:{}" ,employeePageQueryDTO); PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO); return Result.success(pageResult); }
业务逻辑层的实现类EmployeeServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @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); }
数据库交互层EmployeeMapper类
1 2 3 4 5 6 Page<Employee> pageQuery (EmployeePageQueryDTO employeePageQueryDTO) ;
EmployeeMapper.xml
1 2 3 4 5 6 7 8 9 <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 >
做了一个优化
问题是:前端显示的时间格式不美观
通过在WebMvcConfiguration中扩展Spring MVC的消息转换器,统一对日期进行格式化处理
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); }
具体格式在JacksonObjectMapper类中自定义。