本文主要是介绍苍穹外卖新增员工,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、需求分析和设计
接口设计:
数据库设计(employee表):
2、代码开发
根据新增员工接口设计对应的 DTO:
为什么使用DTO呢,就是当前端提交的数据和实体类中对应的属性差别比较大时,建议使用DTO来封装数据。
EmployeeController:
@PostMapping@ApiOperation("新增员工")public Result save(@RequestBody EmployeeDTO employeeDTO){log.info("新增员工:{}",employeeDTO);employeeService.save(employeeDTO);return Result.success();}
EmployeeServiceImpl:
/*** 新增员工* @param employeeDTO*/@Overridepublic void save(EmployeeDTO employeeDTO) {Employee employee = new Employee();//对象属性拷贝BeanUtils.copyProperties(employeeDTO,employee);//设置账号的状态,默认正常状态 1表示正常 0表示禁用employee.setStatus(StatusConstant.ENABLE);//设置密码,默认密码123456employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));//设置当前记录时间和修改时间employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());//设置当前记录创建人id和修改人id// TODO 后期需要改未当前登录用户employee.setCreateUser(10L);employee.setUpdateUser(10L);employeeMapper.insert(employee);}
对象属性拷贝:BeanUtils.copyProperties(employeeDTO,employee);
md5加密:DigestUtils.md5DigestAsHex("123456".getBytes());
获取当前时间:LocalDateTime.now()
EmployeeMapper:
一般单表操作直接用注解的方式进行sql操作。
/*** 插入员工数据* @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);
mybatis配置
mybatis:#mapper配置文件mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.sky.entityconfiguration:#开启驼峰命名map-underscore-to-camel-case: true
开启驼峰命名:map-underscore-to-camel-case:true
3、测试
4、代码完善
程序存在的问题:
- 录入的用户名已存在,抛出异常后没有处理
- 新增员工时,创建人 id 和修改人 id 设置为了固定值(10L)
第一个问题:
GlobalExceptionHandle:
/*** 处理SQL异常* @param ex* @return*/@ExceptionHandlerpublic 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);}}
对sql异常进行处理。
第二个问题:
员工登录成功后会生成 JWT 令牌并响应给前端:
//登录成功后,生成jwt令牌Map<String, Object> claims = new HashMap<>();claims.put(JwtClaimsConstant.EMP_ID, employee.getId());String token = JwtUtil.createJWT(jwtProperties.getAdminSecretKey(),jwtProperties.getAdminTtl(),claims);
后续请求中,前端会携带 JWT 令牌,通过 JWT 令牌可以解析出当前登录员id:
//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);//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}
// 1、从请求头中获取令牌String token = request.getHeader(jwtProperties.getAdminTokenName());
-
这行代码的目的是从HTTP请求头中获取一个名为“令牌”的字符串。
jwtProperties.getAdminTokenName()
返回的是令牌在请求头中的键名,然后通过request.getHeader()
方法获取对应的令牌值。
// 2、校验令牌try {log.info("jwt校验:{}", token);
-
这部分代码开始一个
try
块,用于尝试执行可能会抛出异常的代码。首先,它记录一条日志,表明开始进行JWT(JSON Web Token)的校验,并打印出待校验的令牌。
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
-
这行代码调用
JwtUtil.parseJWT()
方法来解析和校验JWT。这个方法需要两个参数:一个是密钥(用于验证令牌的签名),另一个是待校验的令牌。如果令牌是有效的,并且签名匹配,该方法将返回一个Claims
对象,其中包含了令牌中的声明(例如,用户的ID、角色等)。
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
-
这行代码从
Claims
对象中获取员工ID。JwtClaimsConstant.EMP_ID
是一个常量,表示在JWT中存储员工ID的键。该值被转换为字符串,然后再转换为Long
类型。
log.info("当前员工id:", empId);
-
记录一条日志,显示当前请求对应的员工ID。但请注意,这里的
log.info
调用可能有一个小错误,因为通常日志框架的info
方法接受一个字符串模板和一系列参数。如果这是SLF4J或类似的日志框架,正确的调用可能是log.info("当前员工id:{}", empId);
。
// 3、通过,放行return true;
-
如果令牌校验成功,并且没有抛出任何异常,这段代码将返回
true
,表示请求应该被放行。
接下来的部分是 catch
块,用于处理在 try
块中可能抛出的任何异常:
} catch (Exception ex) {// 4、不通过,响应401状态码response.setStatus(401);return false;}
-
如果在令牌校验过程中发生异常(例如,令牌格式错误、签名不匹配、令牌过期等),则执行这个
catch
块。这里,它将HTTP响应的状态码设置为401(未授权),并返回false
,表示请求不应该被放行。
总的来说,这段代码的目的是从HTTP请求头中获取一个JWT令牌,校验其有效性,并根据校验结果决定是否放行该请求。如果令牌有效,请求被放行;如果无效,则返回一个401未授权状态码。
解析出来 id 之后,如何传递给Service 的save方法?
ThreadLocal 并不是一个Thread,而是Thread的局部变量。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
ThreadLocal常用方法:
public void set(T value) 设置当前线程的线程局部变量的值。
public T get() 返回当前线程所对应的线程局部变量的值
public void remove() 移除当前线程的线程局部变量
JwtTokenAdminIntercepter:
BaseContext.setCurrentId(empId);
EmployeeServiceImpl:
employee.setCreateUser(BaseContext.getCurrentId());employee.setUpdateUser(BaseContext.getCurrentId());
这篇关于苍穹外卖新增员工的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!