1.员工退出
清除登录时存入的session
/**
* 员工退出方法
*
* @param request
* @return
*/
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request) {
//清除session
request.getSession().removeAttribute("emp");
return R.success("退出成功");
}
2.后端拦截器(防止用户直接访问后台页面,不经过登录)
* 全局异常处理
* ControllerAdvice控制器通知(AOP)
* @RequestBody和@ControllerAdvice
**/
@Slf4j
@RestControllerAdvice(annotations = {Controller.class, RestController.class})
public class GlobalExceptionHandler {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException exception){
log.info(exception.getMessage());
if(exception.getMessage().contains("Duplicate entry")){
String[] s = exception.getMessage().split(" ");
String msg = "账号" + s[2] + "已存在";
return R.error(msg);
}
return R.error("未知的错误");
}
}
3.新增员工
/**
* 新增员工
*
* @param employee
* @return
*/
@PostMapping()
public R<String> save(HttpServletRequest request, @RequestBody Employee employee) {
log.info("新增员工:{}", employee.toString());
//设置初始密码,加密
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
//设置创建时间
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//设置创建人
Long empID = (Long) request.getSession().getAttribute("emp");
employee.setCreateUser(empID);
employee.setUpdateUser(empID);
employeeService.save(employee);
return R.success("添加员工成功");
}
4.分页查询
/**
* 分页查询
*/
@GetMapping("/page")
public R<Page> page(HttpServletRequest request, Integer page, Integer pageSize, String name){
log.info("员工{} page: {} pageSize:{}",(Long)request.getSession().getAttribute("emp"),page,pageSize);
//创建分页构造器
Page pageInfo = new Page(page,pageSize);
//如果查询条件name不为空,则添加过滤条件 like
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
if(name != null){
queryWrapper.like(Employee::getName,name);
}
//排序条件orderBy
queryWrapper.orderByDesc(Employee::getUpdateTime);
//执行查询(查询之后page里面就封装了此次查询的所有结果包括总记录数等等...前端可以自取)
employeeService.page(pageInfo, queryWrapper);
return R.success(pageInfo);
}
5.修改员工状态
@PutMapping
public R<String> update(HttpServletRequest request,@RequestBody Employee employee){
log.info("修改用户{}",employee.toString());
//修改 修改记录
Long updateUserId = (Long) request.getSession().getAttribute("emp");
employee.setUpdateUser(updateUserId);
employee.setUpdateTime(LocalDateTime.now());
//修改信息
employeeService.updateById(employee);
return R.success("员工信息修改成功");
}
6.修改员工状态时的bug
之前新创建员工id时使用的雪花算法,有19位数字,当数据传给前端之后后面的数字会被四舍五入,导致需要修改信息的时候无法根据id查询.
解决:
1.加入对象映射器
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
2.扩展MVC的转换器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 扩展MVC转换器
* @param converters
*/
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("配置扩展MVC消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//把上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
}
7.修改信息数据回显
/**
* 修改员工信息时,数据回显
* @param id
* @return
*/
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable Long id){
log.info("用户id:{}数据已回显",id);
Employee employee = employeeService.getById(id);
if(employee!=null){
return R.success(employee);
}
return R.error("未查询到员工信息");
}
8.设置修改人和修改时间会出现重复代码
MP提供解决方法
1.在实体类加入TableField注解,指定自动填充策略
2.编写元数据对象处理器,在此类统一为公共字段赋值,此类实现MetaObjectHandler接口
//FieldFill.INSERT插入时填充 FieldFill.INSERT_UPDATE插入和修改时自动填充
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
/**
* @author MaiDou
* @version 1.0
* @date 2022/11/7 22:04
* 自定义元数据对象处理器
**/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入时自动填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
Long id = BaseContext.getCurrentId();
log.info("公共字段自动填充 Insert {}",metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("createUser", id);
metaObject.setValue("updateUser", id);
}
@Override
public void updateFill(MetaObject metaObject) {
Long id = BaseContext.getCurrentId();
log.info("公共字段自动填充 update {}",metaObject.toString());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", id);
}
}
而获取修改人id时需要ThreadLocal类(线程的局部变量)可以携带信息(每次请求会开启一个线程处理,dofilter 和 登录拦截器可以验证)
1.创建BaseContext工具类
public class BaseContext {
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id){
threadLocal.set(id);
}
public static Long getCurrentId(){
return threadLocal.get();
}
}
2.在登录拦截器里给BaseContext工具类里的ThreadLocal赋值
//3.判断是不是已经登录,已经登录,放行
if (request.getSession().getAttribute("emp") != null) {
Long id = (Long) request.getSession().getAttribute("emp");
BaseContext.setCurrentId(id);
log.info("请求:{}用户id{}已登录,已放行",requestURI,request.getSession().getAttribute("emp"));
filterChain.doFilter(request, response);
return;
}
3.在元对象处理器里获取id,并赋值
@Override
public void insertFill(MetaObject metaObject) {
Long id = BaseContext.getCurrentId();
log.info("公共字段自动填充 Insert {}",metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("createUser", id);
metaObject.setValue("updateUser", id);
}
@Override
public void updateFill(MetaObject metaObject) {
Long id = BaseContext.getCurrentId();
log.info("公共字段自动填充 update {}",metaObject.toString());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", id);
}
写完,睡觉去咯~