员工的增删改查
1、新增员工
1.1、保存员工方法
创建save方法,路径:com/itheima/reggie/controller/EmployeeController.java
@PostMapping
public R<String> save(HttpServletRequest request, @RequestBody Employee employee) {
log.info("新增员工,员工信息:{}", employee.toString());
// 设置初始密码123456,需要进行md5加密处理
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
// 获得当前登陆用户的id
Long empId = (Long) request.getSession().getAttribute("employee");
// 设置添加该员工信息的人的id
employee.setCreateUser(empId);
employee.setUpdateUser(empId);
// 将员工信息存入数据库
employeeService.save(employee);
return R.success("新增员工");
}
1.2、全局异常
创建全局异常捕获类GlobalExceptionHandler,对标注了指定注解的类的异常进行捕获
package com.itheima.reggie.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* @Author: xjhqre
* @DateTime: 2022/6/17 14:17
*/
// 对标上了RestController和Controller注解的类进行拦截
@Slf4j
@RestControllerAdvice(annotations = {RestController.class, Controller.class})
public class GlobalExceptionHandler {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
log.error(ex.getMessage());
if (ex.getMessage().contains("Duplicate entry")) {
String[] split = ex.getMessage().split(" ");
String msg = split[2] + "已存在";
return R.error(msg);
}
return R.error("未知错误");
}
}
2、员工列表的分页查询
2.1、配置mybatis-plus的分页插件
在config目录下创建MybatisPlusConfig
package com.itheima.reggie.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: xjhqre
* @DateTime: 2022/6/17 14:45
*/
@Configuration
public class MybatisPlusConfig {
/**
* 配置分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
2.2 查询方法编写
创建page方法,路径:com/itheima/reggie/controller/EmployeeController.java
// 分页查询员工信息
@GetMapping("/page")
public R<Page<Employee>> page(int page, int pageSize, String name) {
log.info("page = {}, pageSize = {}, name = {}", page, pageSize, name);
// 构造分页构造器
Page<Employee> pageInfo = new Page<>(page, pageSize);
// 构造条件构造器
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
// 添加过滤条件
queryWrapper.like(StringUtils.isNotEmpty(name), Employee::getName, name);
// 添加排序条件
queryWrapper.orderByDesc(Employee::getUpdateTime);
// 执行查询
employeeService.page(pageInfo, queryWrapper);
return R.success(pageInfo);
}
2.3 测试分页
如果想要测试分页按钮功能,可以添加多条数据或者修改每页的显示数量
若要修改每页显示数量可以修改前端list.html
文件,路径:backend/page/member/list.html
修改以下两处数值:
3、启用/禁用员工账号
在查询员工列表时,后端会传给前端每个员工的信息,但由于员工的id属性是Long类型并且长度超过了js能处理的最大长度,导致精度丢失。
解决方法:
自定义消息转换器替换默认的消息转换器,在自定义转换器中把Long类型转成String类型后在发给前端。
3.1 编写JacksonObjectMapper类
在common
目录下创建JacksonObjectMapper
。
package com.itheima.reggie.common;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 对象映射器:基于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);
}
}
3.2、扩展Spring MVC的消息转换器
在WebMvcConfig
中重写extendMessageConverters
方法
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
// 创建消息转环器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
// 设置对象转环器,底层使用Jackson将java对象转换为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
// 将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0, messageConverter);
}
3.3 编写更新方法
在EmployeeController
里创建update
方法
在代码里没有看到修改status,是因为该值是从前端传入的,已经封装在了形参employee里
/**
* 更新员工信息
* @param request
* @param employee
* @return
*/
@PutMapping
public R<String> update(HttpServletRequest request, @RequestBody Employee employee) {
Long empId = (Long) request.getSession().getAttribute("employee");
employee.setUpdateUser(empId);
employee.setUpdateTime(LocalDateTime.now());
employeeService.updateById(employee);
return R.success("员工信息修改成功");
}
4、编辑员工信息
流程说明:
- 点击编辑按钮时,页面跳转到add.html,并在url中携带参数[员工id]
- 在add.html页面获取url中的参数
- 发送ajax请求,请求服务端,同时提交员工id参数
- 服务端接收请求,根据员工id查询员工信息,将员工信息以JSON形式响应给页面
- 页面接收服务端响应的JSON数据,通过vue的数据绑定进行员工信息回显
- 点击保存按钮,发送ajax请求,将页面中的员工信息以JSON方式提交给服务端,调用的是update方法
- 服务端接收员工信息,并进行处理,完成后给页面响应
- 页面接收到服务端响应信息后进行响应处理
add.html页面为公共页面,新增员工和编辑员工都是在此页面操作
4.1 创建回显数据的方法
在EmployeeController
类中创建getById
方法
/**
* 根据id查询员工信息
* @param id
* @return
*/
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable(value = "id") Long id) {
log.info("根据id查询员工信息...");
Employee employee = employeeService.getById(id);
if (employee != null) {
return R.success(employee);
}
return R.error("没有查询到对应的员工信息");
}