boot实战-员工管理
员工管理功能
新增员工
首先来优化下员工的表
1.使其用户名唯一
2.设置状态默认值为启用(0是禁用,1是启用)
来分析功能请求逻辑
接下来在前端代码中找需要写的接口
<el-button type="primary" @click="addMemberHandle('add')" >
// 添加 addMemberHandle (st) { if (st === 'add'){ window.parent.menuHandle({ id: '2', url: '/backend/page/member/add.html', name: '添加员工' },true) } else { window.parent.menuHandle({ id: '2', url: '/backend/page/member/add.html?id='+st, name: '修改员工' },true) } },
submitForm (formName, st) { this.$refs[formName].validate((valid) => { if (valid) { if (this.actionType === 'add') { //将表单数据封装成JSON对象 const params = { ...this.ruleForm, sex: this.ruleForm.sex === '女' ? '0' : '1' } //真正调用的方法(参数传的是上面封装的数据) addEmployee(params).then(res => { //后端主要是返回code值让前端判断该员工是否存在或者被禁用 if (res.code === 1) { this.$message.success('员工添加成功!') if (!st) {
这样跟着代码找很慢我们直接去页面上点看控制台的输出
而且我们去找前端代码上面发现后端只需要给前端返回code值就好了
步骤开发如下
1.书写基础的获取数据封装好成Employee对象,传给service层方法完成数据的添加
/** * 新增员工 * @param employee * @return */ @PostMapping public R<String> save(HttpServletRequest request,@RequestBody Employee employee){ //测试是否正常接收到员工信息 log.info("新增员工,员工信息:{}",employee.toString()); // 设置初始密码为123456,但是需要md5加密 String password=DigestUtils.md5DigestAsHex("123456".getBytes(StandardCharsets.UTF_8)); employee.setPassword(password); employee.setCreateTime(LocalDateTime.now()); employee.setUpdateTime(LocalDateTime.now()); // 获得当前登录用户的id Long empId =(Long) request.getSession().getAttribute("employee"); employee.setCreateUser(empId); employee.setUpdateUser(empId); // service对象调用新增方法 employeeService.save(employee); return null; }
目前没有给前端返回值所以前端不会给出成功提示,重复添加相同用户名的员工会抛出异常,我们要对异常进行处理,一般是用try catch环绕,但是以后这种异常较多我们采用全局异常捕获的方式
2.全局异常捕获处理器
我们可以看到抛出的异常种类
/* * 全局异常处理 * 定义要管理的注解层*/ @ControllerAdvice(annotations = {RestController.class, Controller.class}) //要向前端传数据 @ResponseBody @Slf4j public class GlobalExceptionHandler { /** * SQLIntegrityConstraintViolationException异常处理方法 * @return */ @ExceptionHandler(SQLIntegrityConstraintViolationException.class) public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){ // 日志中打印异常信息 log.error(ex.getMessage()); //给前端返回失败提示 return R.error("失败了"); } }
优化异常处理逻辑
// 日志中打印异常信息 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("未知错误"); }
员工信息分页查询
当员工过多或者其他数据过多的时候就要用到分页查询
首先也要去看相应的请求路径及方式以及前端请求完了之后要拿到哪种数据
通过拦截器配置MP分页插件
/* * 配置MP的分页插件 * */ @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ // 创建拦截器对象 MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor( new PaginationInnerInterceptor()); return mybatisPlusInterceptor; } }
接收前端数据
/** * 员工信息的分页查询 * @param page * @param pageSize * @param name * @return */ @GetMapping("/page") public R<Page> page(int page,int pageSize,String name){ // 日志打印看是否能接收数据 log.info("page={},pageSize={},name={}",page,pageSize,name); return null; }
这里我们使用的是MP提供的分页插件完成分页功能,具体用法查看官网
逻辑实现
/** * 员工信息的分页查询 * @param page * @param pageSize * @param name * @return */ @GetMapping("/page") public R<Page> page(int page,int pageSize,String name){ // 日志打印看是否能接收数据 log.info("page={},pageSize={},name={}",page,pageSize,name); // 构造分页构造器 Page pageInfo=new Page(page,pageSize); // 构造条件构造器(给sql查询语句添加条件) LambdaQueryWrapper<Employee> queryWrapper=new LambdaQueryWrapper(); // 添加过滤条件 queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name); // 添加排序条件 queryWrapper.orderByDesc(Employee::getUpdateTime); // 执行查询,执行完之后会自己将数据封装到page对象中 employeeService.page(pageInfo,queryWrapper); return R.success(pageInfo); }
启用&禁用&编辑员工信息
启用禁用员工功能
首先去分析前端的请求路径及方式,点击禁用
携带参数
这个其实就是个更新员工信息的请求,后面我们有编辑员工信息也是更新操作所以我们可以写一个动态的更新
注意只要不是查询操作我们后端给前端返回的一般都是一个提示,所以直接返回R
/** * 根据id修改员工信息 * @param employee * @return */ @PutMapping public R<String> update(HttpServletRequest request,@RequestBody Employee employee){ log.info(employee.toString()); Long empId = (Long)request.getSession().getAttribute("employee"); employee.setUpdateTime(LocalDateTime.now()); employee.setUpdateUser(empId); employeeService.updateById(employee); return R.success("员工状态更改成功"); }
但是我们测试功能的时候不报错却不能够修改成功找原因发现,前端传给我们的id和数据库中id不匹配
这是因为前端js对long型数据处理时只有前多少位会保留,后几位会四舍五入(就是有误差)
解决方式:
在服务端给页面响应json数据时进行处理,将long型数据统一转为String字符串(就是将id用双引号引起来)
添加自定义转换器
这里使用到了MVC中自定义转换器的知识
我们直接导入了网上提供的转换器类
package com.ember.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); } }
这只是添加了这么个类,要去mvc对应的配置类中配置添加该转换器
/** * 扩展MVC框架的消息转化器 * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { log.info("拓展自己的消息转换器"); // 创建消息转换器对象 MappingJackson2HttpMessageConverter messageConverter=new MappingJackson2HttpMessageConverter(); // 设置对象转换器,底层使用jsckson将java对象转为json messageConverter.setObjectMapper(new JacksonObjectMapper()); // 将上面的消息转换器对象追加到mvc框架转换器中 converters.add(0,messageConverter); super.extendMessageConverters(converters); }
编辑员工信息
首先分析前端
点击编辑跳转到表单根据id回显员工信息,在点击保存更新员工数据
因为我们上面写的更新操作是全局的,这里就不用写更新操作了直接使用上面的就好了,主要是完成根据id查询的操作,这就很简单了
/** * 根据id查询员工信息 * @param id * @return */ @GetMapping("/{id}") public R<Employee> getById(@PathVariable Long id){ Employee employee = employeeService.getById(id); if(employee!=null) { return R.success(employee); } return R.error("未查到相关数据"); }
测试功能成功
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构