Bootstrap

3.员工的增删改查

员工的增删改查

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

修改以下两处数值:

image-20220617150553491

image-20220617150609264

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、编辑员工信息

流程说明:

  1. 点击编辑按钮时,页面跳转到add.html,并在url中携带参数[员工id]
  2. 在add.html页面获取url中的参数
  3. 发送ajax请求,请求服务端,同时提交员工id参数
  4. 服务端接收请求,根据员工id查询员工信息,将员工信息以JSON形式响应给页面
  5. 页面接收服务端响应的JSON数据,通过vue的数据绑定进行员工信息回显
  6. 点击保存按钮,发送ajax请求,将页面中的员工信息以JSON方式提交给服务端,调用的是update方法
  7. 服务端接收员工信息,并进行处理,完成后给页面响应
  8. 页面接收到服务端响应信息后进行响应处理

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("没有查询到对应的员工信息");
}

4.2 测试修改员工信息

;