文章目录
1.新增员工
1.1项目约定
- 管理端发出的请求,统一使用/admin作为前缀
- 用户端发出的请求,统一使用/user作为前缀
1.2代码开发
根据新增员工接口设计对应的DTO:
**注意:**当前端提交的数据和实体类中对应的属性差别比较大时,建议使用DTO来封装数据
EmployeeController中创建新增员工方法
/**
* 新增员工
* @param employeeDTO
* @return
*/
@PostMapping
@ApiOperation("新增人员")
public Result save(@RequestBody EmployeeDTO employeeDTO) {
//{}占位符,运行时动态的将employeeDTO放在{}
log.info("新增员工:{}", employeeDTO);
//调用service
employeeService.save(employeeDTO);
return Result.success();
}
在EmployeeService接口中声明新增员工方法
/**
* 新增员工
* @param employeeDTO
*/
void save(EmployeeDTO employeeDTO);
}
在EmployeeServiceImpl中实现新增员工方法
/**
* 新增员工
* @param employeeDTO
*/
public void save(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
//对象属性拷贝
//从 DTO 到实体类的数据传递。
BeanUtils.copyProperties(employeeDTO, employee);
//设置账号的状态,默认正常状态 1表示正常,0表示锁定
//使用常量而不是硬编码的字符串值可以减少错误,并使代码更易于更新。
//如果将来状态的表示方式发生变化,只需要在一个地方(即 StatusConstant 中)进行修改即可
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方法
/**
* 插入员工数据
* @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);
1.3功能测试
通过Apipost测试:
点击调试,填写请求参数,点击发送后,程序好像没什么反应,而是直接返回响应码 401。HTTP状态码 401 表示未经授权,表示请求需要进行身份验证,但请求没有提供所需的凭据:
这是因为项目中写了一个拦截器,在收到请求后,都会被其拦截,拦截器会先从请求头中获取 jwt 令牌并校验令牌,通过校验才可以进行后续操作;否则直接返回。
因为刚才并没有传令牌给服务端,所以请求失败了。
但是每一次我们发送请求测试都要传递令牌,其实是很麻烦的,所以我们的想法是在接口文档中统一添加一个令牌,这样在后续调试都会自动将令牌提交给服务端。(在项目的配置文件中,我们设置了 jwt 令牌的有效时间为 2 小时,每次过时都得重新获取复制)
首先,我们需要先获取一个令牌,很简单,我们通过员工登录这个接口即可获取,将其token复制:
将token设置为全局变量后,点击发送则成功录入数据库
前后端联调
从前端添加员工
1.4 代码完善
程序尚存问题
- 录入用户名已存在,抛出异常后未处理
- 新增员工时,创建人id和修改人id设置了固定值
解决问题一
在GlobalExceptionHandler中添加方法
/**
*处理sql异常
* @param ex
* @return
*/
@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_EXISTS;
return Result.error(msg);
} else {
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
在MessageConstant中添加
public static final String ALREADY_EXISTS = "已存在";
解决问题二
针对此问题,则需通过某种方式动态获取当前登录员工的id:
解析出登录员工 id 后,如何将其传递给 Service 的 save 方法?
- ThreadLocal 并不是一个 Thread,而是 Thread 的局部变量。
- ThreadLocal 为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问
- 其是通道技术,是不同线程之间通讯用
ThreadLocal 常用方法: - public void set(T value) 设置当前线程的线程局部变量的值
- public T get() 返回当前线程所对应的线程局部变量的值
- public void remove() 移除当前线程的线程局部变量
在拦截器JwtTokenAdminInterceptor中解析出当前登录员工id,并放入线程局部变量中:
BaseContext.setCurrentId(empId);
EmployeeServiceImpl中获取线程局部变量值:
employee.setCreateUser(BaseContext.getCurrentId());
employee.setUpdateUser(BaseContext.getCurrentId());
2.员工分页查询
2.1需求分析与设计
产品原型
接口路径
业务规则
- 根据页码展示员工信息
- 每页展示10条数据
- 分页查询时可根据需要,输入员工姓名进行查询
2.2 代码开发
- 根据分页查询接口设计对应的DTO:
在EmployeeController层创建分页查询方法
@GetMapping("/page")
@ApiOperation("员工分页查询")
public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO) {
log.info("员工分页查询,参数为:{}", employeePageQueryDTO);
//调用service
PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
return Result.success(pageResult);
}
在EmployeeService接口中声明pageQuery 方法
/**
* 分页查询
* @param employeePageQueryDTO
* @return
*/
PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
在 EmployeeServiceImpl 中实现 pageQuery 方法
/**
* 分页查询
* @param employeePageQueryDTO
* @return
*/
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO){
//select * from employee limit 0, 10
//开始分页查询
//mybatis的动态拼接
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方法
/**
* 分页查询的方法
* @param employeePageQueryDTO
* @return
*///需要动态sql
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 != ''">
and name like concat('%',#{name}, '%')
</if>
</where>
order by create_time desc
</select>
2.3 功能测试
通过Apipost测试
发现updatetime格式不对,需要代码完善
2.4 代码完善
时间格式有误
-
解决方法一:在属性上加入注解,对日期进行格式化(一个个加,当数据多了非常繁琐)
-
方式二:在 WebMvcConfiguration 中扩展 SpringMVC 的消息转换器,统一对日期类型进行格式化处理
/**
* 扩展SpringMVC框架的消息转化器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转化器...");
//创建一个消息转化器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
converter.setObjectMapper(new JacksonObjectMapper());
//将自己的消息转化器加入容器中
//添加索引 index:0 使得自己的消息转化器为第一位使用
converters.add(0,converter);
}
3.启用禁用员工账号
3.1产品原型与设计
业务规则
- 对状态为“启用”的员工账号进行“禁用”操作
- 对状态为“禁用”的员工账号进行“启用”操作
- 状态为“禁用”的员工账号不能登录系统
接口设计
3.2代码设计
在EmployeeController层创建方法
/**
* 启用禁用员工账号
* @param status
* @param id
* @return
*/
@PostMapping("/status/{status}")
@ApiOperation("启用禁用员工账号")
//Result<T> 泛型不是强制的,查询类要返回date数据的就加泛型<T>,而我们返回的是code
//通过@PathVariable获取{status}路径参数
public Result startOrStop(@PathVariable Integer status, Long id) {//传过来一个路径参数,一个id
log.info("启用禁用员工账号:{},{}", status, id);
employeeService.startorstop(status,id);
return Result.success();
}
在EmployeeService接口
/**
* 启用禁用员工账号
* @param status
* @param id
*/
void startorstop(Integer status, Long id);
在EmployeeService层实现方法
/**
* 启用禁用员工账号
* @param status
* @param id
*/
@Override
public void startorstop(Integer status, Long id) {
//update employee set status = ? where id = ?
// Employee employee = new Employee();
// employee.setId(id);
// employee.setStatus(status);
Employee employee = Employee.builder()
.id(id)
.status(status)
.build();
employeeMapper.update(employee);
}
在EmployeeMapper接口中声明update方法
/**
* 根据主键动态修改属性
* @param employee
*/
void update(Employee employee);
在EmployeeMapper.xml中编写sql
<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>
3.3 功能测试
3.4 前后端联调
4. 编辑员工
4.1 产品原型与设计
业务规则
- 根据id查询员工信息
- 编辑员工信息
接口设计
4.2 代码开发
根据id查询员工信息、编辑员工
EmployeeController层
/**
* 根据id查询员工信息
* @param id
* @return
*/
@GetMapping("/{id}")
@ApiOperation("根据id查询员工信息")
public Result<Employee> getById(@PathVariable Long id) {
Employee employee = employeeService.getById(id);
return Result.success(employee);
}
/**
* 编辑员工信息
* @param employeeDTO
* @return
*/
@PutMapping
@ApiOperation("编辑员工信息")
public Result update(@RequestBody EmployeeDTO employeeDTO){
log.info("编辑员工信息,{}", employeeDTO);
employeeService.update(employeeDTO);
return Result.success();
}
EmployeeService接口
/**
* 根据id查询员工
* @param id
* @return
*/
Employee getById(Long id);
/**
* 编辑员工信息
* @param employeeDTO
*/
void update(EmployeeDTO employeeDTO);
EmployeeService层
/**
* 根据id查询员工
* @param id
* @return
*/
public Employee getById(Long id) {
Employee employee = employeeMapper.getById(id);
employee.setPassword("****");
return employee;
}
/**
* 编辑员工信息
* @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);
}
EmployeeMapper层
注:在启用禁用员工账号时已经完成编辑员工的代码(相同的)
/**
* 根据id查询员工
* @param id
* @return
*/
@Select("select * from employee where id = #{id}")
Employee getById(Long id);
4.3 功能测试
根据id查询员工信息
编辑信息
前后端联调
5.分类管理
5.1 产品原型与设计
产品原型
业务规则
- 分类名称必须是唯一的
- 分类按照类型可以分为菜品分类和套餐分类
- 新添加的分类状态默认为 “禁用”
接口设计
- 新增分类
- 分类分页查询
- 根据 id 删除分类
- 修改分类
- 启用禁用分类
- 根据类型查询分类
5.2 代码导入
与员工管理类似,导入代码并调试就行