我们实现员工管理功能:
员工管理效果:
明确新增员工接口的请求路径、请求方式、请求参数、返回数据。
新增员工,其实就是将我们新增页面录入的员工数据插入到employee表。
根据新增员工接口设计对应的DTO
前端传递参数列表:
**思考:**是否可以使用对应的实体类来接收呢?
结论 : 当前端提交的数据和实体类中对应的属性差别比较大时,建议使用DTO来封装数据
由于上述传入参数和实体类有较大差别,所以自定义DTO类。
EmployeeController中创建新增员工方法
/**
* 新增员工
* @param employeeDTO
* @return
*/
@PostMapping
@ApiOperation("新增员工")
public Result save(@RequestBody EmployeeDTO employeeDTO){
log.info("新增员工:{}",employeeDTO);
employeeService.save(employeeDTO);//该方法后续步骤会定义
return Result.success();
}
在EmployeeService接口中声明新增员工方法
在EmployeeServiceImpl中实现新增员工方法
/**
* 新增员工
*
* @param employeeDTO
*/
public void save(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
//对象属性拷贝
BeanUtils.copyProperties(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
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);
使用lombok简化操作
只需要加入下面依赖 就可以达成操作
(1) 在Sky_take_out数据库中建立employee表
(2) 在Springboot工程中引入起步依赖
(3) Mapper中以注解方式编写SQL语句
完成引入mybatis操作
注意 : 若以XML方式配置映射文件须遵守一下要求
当我们把四个参数传给yml属性配置文件进行集中的配置管理
如果我们想在工具类中使用这四个参数就要在类中变量上加上注解 来注入这四个参数
但这样无疑很繁琐
@Component: 标注Spring管理的Bean,使用@Component注解在一个类上,表示将此类标记为Spring容器中的一个Bean。
改进办法:
使用@ConfigurationProperties注解来指定前缀
条件:
1. yml 文件和类中变量名必须一致
2. 加入@Data注解 方便调用类中变量, 设置类中变量
3. 加入@Component 将这个类交给IOC容器管理
4. 加入@ConfigurationProperties 补全前缀
改进结果:
只在对象上需要加上@Autowired 注入上面这个Bean对象, 再调用 Get()方法就可拿到参数值
两种方法对比:
@Component @ConfigurationProperties(prefix = "sky.jwt") @Data public class JwtProperties { /** * 管理端员工生成jwt令牌相关配置 */ private String adminSecretKey; private long adminTtl; private String adminTokenName; /** * 用户端微信用户生成jwt令牌相关配置 */ private String userSecretKey; private long userTtl; private String userTokenName; }
描述:新增员工时,创建人id和修改人id设置为固定值
//当前设置的id为固定值10//
employee.setCreateUser(10L);
employee.setUpdateUser(10L);
//
解决:
通过某种方式动态获取当前登录员工的id。
员工登录成功后会生成JWT令牌并响应给前端:
claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
后续请求中,前端会携带JWT令牌,通过JWT令牌可以解析出当前登录员工id:
JwtTokenAdminInterceptor.java
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
**思考:**解析出登录员工id后,如何传递给Service的save方法?
答 : ThreadLocal
介绍:
ThreadLocal 并不是一个Thread,而是Thread的局部变量。 ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
常用方法:
对ThreadLocal有了一定认识后,接下来继续解决问题
在拦截器中解析出当前登录员工id,并放入线程局部变量中:
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 校验jwt
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//.............................
//2、校验令牌
try {
//.................
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
log.info("当前员工id:", empId);
/将用户id存储到ThreadLocal
threadLocal.set(empId);
//3、通过,放行
return true;
} catch (Exception ex) {
//......................
}
}
}
在Service中获取线程局部变量中的值:
/**
* 新增员工
*
* @param employeeDTO
*/
public void save(EmployeeDTO employeeDTO) {
//.............................
//设置当前记录创建人id和修改人id
employee.setCreateUser(threadLocal.get());//目前写个假数据,后期修改
employee.setUpdateUser(threadLocal.get());
employeeMapper.insert(employee);
}