第二天
-
管理端发来的请求 统一用/admin 用户端发来的请求 统一用/user
-
如何动态的获取当前登录的id来进行设置 添加员工有一个属性值是当前用户的id 就是当前是哪个管理员再添加员工 如果想要获取这个id 就要回到jwt令牌校验那里`//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);`
在jwt令牌校验的时候 已经获取到了empId了 但是问题就是如何将这个empId传递给service 因为具体的逻辑是在service中进行的开发 因此如果要完成这个功能 就要用到ThreadLocal ThreadLocal不是一个线程 而是线程的局部变量 ThreadLocal为每一个线程单独提供了一份存储空间 具有线程隔离的操作 只有在线程内才能获取到对应的值 线程外则不能访问 由于代码已经实现了ThreadLocal的实体类 在BaseContext中 因此在jwt校验的时候使用BaseContext.setCurrentId(empId)存储 然后在service中通过BaseContext.getCurrentId()拿到即可动态的设置值
- 分页查询实现 要实现分页查询 就需要封装前端传来的对象PageDTO 其中有必须参数 页码和每页的大小 不必须参数姓名 然后前端返回对象用PageResult进行数据封装 其中有总记录数和具体员工对象值 即返回
Result<PageResult>实现就是先要定义方法 然后在mapper.xml中实现动态sql查询 使用where标签 然后if判断如果name不为空或者空串 就加上name 并且用模糊查询like实现 然后再对查询的结果按照创建时间降序排序
代码实现为
<select id="pageQuery" resultType="com.sky.entity.Employee">
select * from employee
<where>
<if test="name != null and name != ''">
name like concat('%',#{name},'%')
</if>
</where>
order by creat_time desc
</select>
注意查完之后在service中是page对象返回 而page对象中有一堆属性 我们只要其中的记录数跟数据 因此需要再进行封装long total = page.getTotal(); List<Employee> records = page.getResult(); return new PageResult(total, records);
注意:返回的时间问题需要进一步的优化 其中一个就是在属性上标注@JsonFormat("yyyy-MM-dd HH:mm:ss")
第二种就是在WebMVCConfiguration中扩展springMVC消息转换器 统一对日期类型进行格式化处理
公共字段自动填充
前面在插入员工 修改员工 添加类别 修改类别 包括之后的添加菜品 修改菜品 都会进行修改时间和修改的id以及创建时间 创建的id 这些每一次进行修改和插入都要进行设置
比如这四句代码
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
employee.setCreateUser(BaseContext.getCurrentId());
employee.setUpdateUser(BaseContext.getCurrentId());
因此 就可以设计一个功能 对这种公共字段来进行自动填充
可以设计aop切面来对切入insert和update的方法 只要有这两种方法 就进行公共字段的填充 插入方法填充创建和修改四个公共字段 更改需要填充两个 如何监控这两种方法 可以再设计一个注解@AutoFill然后在插入和修改的方法上标注这个注解 切面方法就可以切入了
注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
//数据库操作类型:UPDATE INSERT
OperationType value();
}
上面代码的OperationType value();这个语句是规定注解中要有一个属性的值 就是OperationType枚举变量的值 然后就可以在修改和插入的方法上标注 @AutoFill(OperationType.UPDATE) void update(Employee employee);
因此切面就可以监控这个mapper类下的标注有@AutoFill的注解的方法 然后进行公共字段填充
因此aspect切面方法中的切入点就可以这样规定 @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut(){}只有同时满足这两个条件时 开始切入 条件是前置切入 因为要在mapper方法执行之前填入公共字段的值 然后再执行修改和插入方法
首先在方法中要获取到被拦截方法上的操作类型 是修改还是插入
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
OperationType value = autoFill.value();
先拿到方法签名 然后根据签名拿到方法getMethod 然后再拿到注解getAnnotation中的Autofill类 AutoFill类中的值就是操作类型 是insert还是update
然后获取被拦截方法的参数 就是实体对象 employee或者菜品或者类别
Object[] args = joinPoint.getArgs();
if(args == null || args.length == 0){
return;
}
Object entity = args[0];
先拿到所有参数 因为插入和修改的方法中的第一个参数都是实体对象 因此就是第一个参数就是实体类 比如void update(Employee employee);只有一个参数 就是实体类 即使有多个参数的话 默认把实体类放在前面
再定义准备赋值的数据
LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId();
最后就是根据不同的操作类型 根据反射来进行赋值
if(value == OperationType.INSERT){
//为四个属性赋值
try {
Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//通过反射为对象属性赋值
setCreateTime.invoke(entity, now);
setUpdateTime.invoke(entity, now);
setCreateUser.invoke(entity, currentId);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
e.printStackTrace();
}
}else if(value == OperationType.UPDATE){
//为两个属性赋值
try {
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//通过反射为对象属性赋值
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
e.printStackTrace();
}
}
如果是插入 就需要为四个属性赋值 如果是修改 就为两个属性赋值 先从实体类中getClass得到该对象 然后通过getDeclaredMethod得到方法 AutoFillConstant.SET_UPDATE_TIME'是方法名 用常量来表示了 本质的方法名是setCreateTime 去找到这个方法 然后再通过LocalDateTime.class来规定这个方法中的参数类型 如此一来 就设置好了setUpdateTime方法 然后通过反射invoke`来真正的调用这个对象的set方法来赋值 走到这里 就赋完值了 大体流程就是通过aop来监控标注了autofill注解的mapper方法 然后对插入和修改切入 先拿到方法签名 然后拿到注解中的属性就是操作类型 再拿到实体参数 再定义要填充的公共字段的值 然后根据这个实体类去拿到类 拿到方法 规定方法名 规定方法参数 去设置这个方法 最后调用invoke来真正的为这个对象赋值

浙公网安备 33010602011771号