后台系统中管理员工信息,通过新增员工来添加后台系统用户。点击[添加员工]按钮跳转到新增页面,如下:
新增员工,其实就是将新增页面录入的员工数据插入到employee表中。需要注意,employee表中对username字段加入了唯一约束,因为username是员工的登录账户,必须是唯一的。employee表中的status字段已经设置了默认值1,表示状态正常。
在开发代码之前,需要梳理以下整个程序的执行过程:
1.页面发送ajax请求,将新增员工页面中的输入的数据以json的形式提交到服务端;
2.服务端Controller接收页面提交的数据并调用Service将数据进行保存;
3.Service调用Mapper操作数据库,保存数据。
存在的问题:
在common包中添加异常处理器进行全局异常捕获,如果使用try、catch需要重复书写
package com.huangzx.reggie.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 全局异常处理
*/
@ControllerAdvice(annotations = {RestController.class, Controller.class}) //拦截带有这些Controller注解的类
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 异常处理方法
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class) //捕获的异常类别
public R ExceptionHandler(SQLIntegrityConstraintViolationException ex){
log.error(ex.getMessage());
if(ex.getMessage().contains("Duplicate entry")){ //该类型报错中含有的字段
String[] split = ex.getMessage().split(" "); //对报的错误Duplicate entry 'zhangsan' for key 'employee.idx_username' 进行分割
String msg = split[2] + "已存在!";
return R.error(msg); //返回页面信息
}
return R.error("未知错误!");
}
}
当添加重复的账户,会报错
系统中的员工很多的时候,如果在一个页面中全部展示处理会显得比较乱,不便于查看,所以一般的系统中都会以分页的形式来展示列表数据。
整个程序的执行过程:
1.页面发送ajax请求,将分页查询参数(page、pagesize、name)提交到服务端;
2.服务端Controller接收页面提交的数据并调用Service查询数据;
3.Service调用Mapper操作数据库,查询分页数据;
4.Controller将查询到的分页数据响应给页面;
5.页面接收到分页数据并通过ElementUI的Table组件展示到页面上。
前端页面需要服务端返回的数据,R中使用Page泛型
创建MybatisPlus分页查询插件
/**
* 员工信息分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R page(int page,int pageSize,String name){ //前端页面需要服务端返回的数据是res.data.records,res.data.total,所以这里使用Page泛型在进行分页查询的时候,会查询名字,所以加入name
log.info("page={},pageSize={},name={}",page,pageSize,name);
//构造分页构造器
Page pageInfo = new Page();
//构造条件构造器
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper();
//添加过滤条件
queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name); //判断查询name是否为空
//添加排序条件
queryWrapper.orderByDesc(Employee::getUpdateTime);
//执行查询
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
在员工管理表页面,可以对某个员工账户进行启用或者禁用操作,账户禁用的员工不能登录系统,启用后的员工可以正常登录。需要注意:只有管理员(admin用户)可以对其他普通用户进行启用、禁用操作,所以普通用户登录系统后启用、禁用按钮不显示。
如果某个员工账户状态为正常,则按钮显示为“禁用”,如果员工账户状态为已禁用,则按钮显示为“启用”。
页面如何做到只有管理员admin能够看到启用、禁用按钮的?
如果账户状态为正常,则按钮显示为禁用,否则为启用。
程序执行过程:
1.页面发送ajax请求,将参数(id、status)提交到服务端;
2.服务端Controller接收页面提交的数据并调用Service更新数据;
3.Service调用Mapper操作数据库。
页面中ajax请求是如何发送的?
启用、禁用员工账户,本质上就是一个更新操作,也就是对status状态字段进行操作,在Controller中创建update方法,此方法是一个通用的修改员工信息的方法。
测试过程中没有报错,但是功能并没有实现,查看数据库中的数据也没有变化。查看控制台输出的SQL:
通过观察控制台输出的SQL发现页面传递过来的员工的id的值和数据库中的id值不一致,这是因为分页查询时服务端响应给页面的数据中的id的值为19位数字,类型为long,而页面中js处理long型数字只能精确到前16位,所以最终通过ajax请求提交给服务端的时候id变了。
如何解决问题:
可以在服务端给页面响应json数据时进行处理,将long型数据统一转为String字符串。
实现步骤:
1.提供对象转换器JacksonObjectMapper,基于Jackson进行Java对象到json对象数据的转换;
2.在WebMvcConfig配置类中扩展Spring mvc的消息转换器,在此消息转换器中使用提供的对象转换器进行Java对象到json数据的转换。
通用类Common中添加JacksonObjectMapper类
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);
}
}
在WebmvcConfig类中添加消息转换器
在员工管理列表页面点击编辑按钮,跳转到编辑页面,在编辑页面回显员工信息并进行修改,最后点击保存按钮完成操作。
程序执行流程:
1.点击编辑按钮时,页面跳转到add.html,并在url中携带参数(员工id) add.html页面为公共页面,新增员工和编辑员工都是在此页面操作
2.在add.html页面获取url中的参数(员工id);
3.发送ajax请求,请求服务端,同时提交员工id参数;
4.服务端接收请求,根据员工id查询员工信息,将员工信息以json形式响应给页面;
5.页面接收服务端响应的json数据,通过VUE的数据绑定进行员工信息回显;
6.点击保存按钮,发送ajax请求,将页面中的员工信息以json方式提交给服务端;
7.服务端接收员工信息,并进行处理,完成后给页面响应;
8.页面接收到服务端响应信息后进行相应处理。
前端add.html中,传入id后判断是要修改员工信息,还是要添加员工信息;如果修改员工信息,init()中传入员工信息,在性别属性中,通过状态0或者1判断是男还是女
修改员工信息后,点击保存,此时相当于公用之前的添加员工信息操作。