员工管理
新增员工
Controller:
@PostMapping//post类型的请求
@ApiOperation("添加员工")
public Result save(@RequestBody EmployeeDTO employeeDTO) {
log.info("新增员工{}", employeeDTO);
employeeService.save(employeeDTO);
return Result.success();
}
代码完善–存在问题
问题1.控制台抛出异常,程序处理。使用全局异常处理器
处理sql异常 Duplicate entry 'zhangsan’ for key 'employee.idx username
全局异常处理器:GlobalExceptionHandler.java
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex) {
//处理sql异常 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);//未知错误提示信息
}
}
问题2.
动态获取登录用户ID
先看一下基于JWT令牌认证流程
ThreadLocal
并不是一个thread,而是Thread的局部变量。
每个县城独享一份存储空间,具有线程隔离的效果,只有在县城内才能获取到对应的值,线程外不行。
客户端发起的每一次请求,Tomcat服务器会分配一个进程,然后单独的执行代码。每次请求都是一个单独的线程。
也就是在这个线程内能共享一份存储空间。
所以我们可以讲给当前用户ID存到这个空间内。
JwtTokenAdminInterceptor.java // JWT拦截器
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断当前拦截到的是Controller的方法还是其他资源
if (!(handler instanceof HandlerMethod)) {
//当前拦截到的不是动态方法,直接放行
return true;
}
//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//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);//将ID放入线程空间
//3、通过,放行
return true;
} catch (Exception ex) {
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
上图就是调用这个方法类将员工ID存到当前线程空间中。
下图是添加员工信息Service中的方法实现,重点在于从线程空间取出登录用户ID
Service:
public void save(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
//提交给数据库的最好是entity
BeanUtils.copyProperties(employeeDTO, employee);//进行一个属性复制
//填充字段
employee.setStatus(StatusConstant.ENABLE);
employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//通过ThreadLocal获得当前用户的id
employee.setCreateUser(BaseContext.getCurrentId());
employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.insert(employee);
}
员工分页查询
Controller:
@GetMapping("/page")//get类型的请求
@ApiOperation("员工分页查询")
public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO) {//数据不是json,不需要注解
PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
return Result.success(pageResult);
}
PageHelper插件来辅助代码
Service:
@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
//select * from employee linit 0,10
//调用PageHelper 开始分页查询 页码,每页记录数
PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
Page<Employee> page = employeeMapper.selectByPage(employeePageQueryDTO);
//返回的是Page
//接下来处理一下,变成pageresult,需要两个参数
long total = page.getTotal();
List<Employee> result = page.getResult();
return new PageResult(total, result);
}
mapper:
不用注解,动态sql使用映射文件
在resource文件夹里都是xml文件
<select id="selectByPage" resultType="com.sky.entity.Employee">
select * from employee
<where>
<if test="name!=null and name !='' ">
and name like concat('%',#{name},'%') <!--模糊查询 like -->
</if>
</where>
order by create_time desc <!--创建时间降序-->
</select>
方式一:在实体类里加
//@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
//@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
方式二:扩展消息转换器,在配置类中
重写父类方法
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//创建一个消息转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
converter.setObjectMapper(new JacksonObjectMapper());
//将自己的消息转化器加入容器中
converters.add(0, converter);//0为索引,让这个转换器排前面
}
启用禁用员工账号
Controller:
@PostMapping("/status/{status}")
@ApiOperation("启用禁用员工账号")
public Result startOrStop(@PathVariable("status") Integer status, Long id) {
employeeService.startOrStop(status, id);
return Result.success();
}
Service:本质是修改员工Status 即update
public void startOrStop(Integer status, Long id) {
Employee employee =//本质就是创建一个实体类对象
Employee.builder()// 构建器对象
.id(id)// 方法名和属性名一致
.status(status)
.build();
employeeMapper.update(employee);
}
根据主键动态修改,所以又到xml里
<!--因为在yml文件中声明了别名包的扫描,所以此处可以不使用全类名-->
<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>
编辑员工
查询员工信息:
@GetMapping("/{id}")
@ApiOperation("根据Id查询员工")
public Result<Employee> getById(@PathVariable Long id) {//加个路径参数的注解@PathVariable来得到id
Employee employee = employeeService.getById(id);
return Result.success(employee);
}
@Override
public Employee getById(Long id) {
Employee employee = employeeMapper.getById(id);
employee.setPassword("****");// 查出的密码,给前端传****
return employee;
}
@Select("select * from employee where id=#{id}")
Employee getById(Long id);
编辑员工信息:
@PutMapping
@ApiOperation("编辑员工信息")
public Result update(@RequestBody EmployeeDTO employeeDTO) {
employeeService.update(employeeDTO);
return Result.success();
}
public void update(EmployeeDTO employeeDTO) {
Employee employee = new Employee();//对象属性拷贝
BeanUtils.copyProperties(employeeDTO,employee);
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.update(employee);
}
导入分类模块功能代码
直接粘贴到对应文件夹(在IDEA里操作)
导入完手动编译一下