Day02 员工管理,分类管理

新增员工

需求分析和设计

产品原型:

接口设计:

本项目约定:

        管理端发出的请求,统一使用 /admin 作为前缀

        用户端发出的请求,统一使用 /user 作为前缀

数据库表设计:

代码开发

根据新增员工接口设计对应的 DTO:

package com.sky.dto;import lombok.Data;import java.io.Serializable;@Data
public class EmployeeDTO implements Serializable {private Long id;private String username;private String name;private String phone;private String sex;private String idNumber;}
    @PostMapping@ApiOperation("新增员工")public Result save(@RequestBody EmployeeDTO employeeDTO){log.info("新增了员工: {}", employeeDTO);employeeService.save(employeeDTO);return Result.success();}
    @Overridepublic void save(EmployeeDTO employeeDTO) {Employee employee = new Employee();//对象属性拷贝BeanUtils.copyProperties(employeeDTO,employee);//设置账号状态,默认正常状态,1表示正常,0表示锁定employee.setStatus(StatusConstant.ENABLE);//设置加密后的密码employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));//设置当前记录的创建时间employee.setUpdateTime(LocalDateTime.now());employee.setCreateTime(LocalDateTime.now());//设置当前记录的创建人id和修改人id//TODO 后期更改为当前登录用户的 idemployee.setCreateUser(10L);employee.setUpdateUser(10L);log.info("新增了员工: {}", employee);employeeMapper.save(employee);}
    @Insert("insert into sky_take_out.employee (name, username, password, phone, sex, id_number, status, create_time, update_time, create_user, update_user) " +"values (#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})")void save(Employee employee);
}

功能测试

功能测试方法:
通过接口文档测试

        通过前后端联调测试

注意:由于开发阶段前端和后端是并行开发的,后端完成某个功能后,此时前端对应的功能可能还没有开发完成,导致无法进行前后端联调测试,所以在开发阶段,后端测试主要以接口文档测试为主。

代码完善

程序存在的问题:
录入的用户名已存在,抛出异常后没有处理

        新增员工时,创建人 id 和 修改人 id 设置了固定值

先在全局异常处理类中完成第一个问题

    @ExceptionHandlerpublic Result exceptionHandler(BaseException ex){log.error("异常信息:{}", ex.getMessage());return Result.error(ex.getMessage());}@ExceptionHandlerpublic Result exceptionHandler(SQLIntegrityConstraintViolationException ex){// Duplicate entry 'zhangsan' for key 'employee.idx_username'String message = ex.getMessage();if(message.contains("Duplicate entry")){String[] split = message.split(" ");String username = split[2];String msg = username + MessageConstant.ALREADY_EXISTS;return Result.error(msg);}else{return Result.error(MessageConstant.UNKNOWN_ERROR);}}
}

这里用到了方法重载

针对第二个问题,需要通过某种方式动态获取当前登录员工的 id

当登录成功时,我们的 id 就已经在 claims 里面了,所以如果我们想反向拿出来也是可以办到的

package com.sky.interceptor;import com.sky.constant.JwtClaimsConstant;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** jwt令牌校验的拦截器*/
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {@Autowiredprivate JwtProperties jwtProperties;/*** 校验jwt** @param request* @param response* @param handler* @return* @throws Exception*/public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断当前拦截到的是Controller的方法还是其他资源if (!(handler instanceof HandlerMethod)) {//当前拦截到的不是动态方法,直接放行return true;}//1、从请求头中获取令牌String token = request.getHeader(jwtProperties.getAdminTokenName());//2、校验令牌try {log.info("jwt校验:{}", token);Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());log.info("当前员工id:", empId);//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}}
}

注意第48行,就是我们需要的 empId,那么现在的问题就是怎么将这个 id 传给我们的 service

的 save 方法。这里需要用到一个重要的知识 ThreadLocal

ThreadLocal 并不是一个 Thread,而是 Thread 的局部变量。

ThreadLocal 为每一个线程提供单独一份存储空间,具有线程隔离效果,只有在线程内才能获取到对应的值,线程外则不能访问

        

我们需要一个工具类用来调用 ThreadLocal 方法

package com.sky.context;public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}}

然后在校验令牌时取出 empId,,并将他放入 threadlocal

最后要用的时候拿出来

员工分页查询

需求分析和设计

产品原型

接口设计

代码开发

和前面新增员工一样,我们需要一个与接口设计相对应的 DTO:

package com.sky.dto;import lombok.Data;import java.io.Serializable;@Data
public class EmployeePageQueryDTO implements Serializable {//员工姓名private String name;//页码private int page;//每页显示记录数private int pageSize;}

    @GetMapping("/page")@ApiOperation("分页查询")public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO){log.info("分页查询:{}", employeePageQueryDTO);PageResult pageResult = employeeService.page(employeePageQueryDTO);return Result.success(pageResult);}

    @Overridepublic PageResult page(EmployeePageQueryDTO employeePageQueryDTO) {PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());Page<Employee> page = employeeMapper.pagequery(employeePageQueryDTO);return new PageResult(page.getTotal(), page.getResult());}

拓展:PageHelper 的底层时 ThreadLocal 实现的

    <select id="pagequery" resultType="com.sky.entity.Employee">select * from sky_take_out.employee<where><if test="name != null and name != ' '">and name like concat('%', #{name}, '%')</if></where></select>

功能测试

这里会发现日期这边看起来不舒服,接下来完善代码解决这个问题

代码完善

package com.sky.json;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
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.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_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";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(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);}
}

解决方式:

        方式一:在属性上加入注解,对日期进行格式化  

        方式二:在 WebMvcConfiguration 中拓展 Spring MVC 的消息转换器,统一对日期类型进行                         格式化处理

建议使用第二种,这个方法是固定的,是我们这个配置类继承的父类里面就有的

启用禁用员工账号

需求分析和设计

产品原型

接口设计

代码开发

    @PostMapping("/status/{status}")@ApiOperation("启用或禁用员工")public Result start_or_stop(@PathVariable Integer status, Long id){log.info("启用或禁用员工:{},{}", status, id);employeeService.start_or_stop(status, id);return Result.success();}
    @Overridepublic void start_or_stop(Integer status, Long id) {Employee employee = Employee.builder().status(status).id(id).build();employeeMapper.update(employee);}
    <update id="update">UPDATE sky_take_out.employee<set><if test="name != null and name != ''">name = #{name},</if><if test="username != null and username != ''">username = #{username},</if><if test="password != null and password != ''">password = #{password},</if><if test="phone != null and phone != ''">phone = #{phone},</if><if test="sex != null and sex != ''">sex = #{sex},</if><if test="idNumber != null and idNumber != ''">id_number = #{idNumber},</if><if test="status != null">status = #{status},</if><if test="updateTime != null">update_time = #{updateTime},</if><if test="updateUser!= null">update_user = #{updateUser}</if></set>WHERE id = #{id}</update>

功能测试

编辑员工

需求分析和设计

产品原型

接口设计

注意这里需要两个接口

1:根据 id 查询员工信息,也就是查询回显

2:编辑员工信息

代码开发

首先是查询回显

    @GetMapping("/{id}")@ApiOperation("根据 id 查询员工")public Result<Employee> queryById(@PathVariable Long id){log.info("查询的员工的 id 为:{}", id);Employee employee = employeeService.queryById(id);return Result.success(employee);}
    @Overridepublic Employee queryById(Long id) {Employee employee = employeeMapper.queryById(id);return employee;}
    <select id="queryById" resultType="com.sky.entity.Employee">select * from sky_take_out.employee where id = #{id}</select>

然后是更新员工

    @PutMapping@ApiOperation("修改员工数据")public Result update(@RequestBody EmployeeDTO employeeDTO){log.info("修改员工:{}", employeeDTO);employeeService.update(employeeDTO);return Result.success();}
    @Overridepublic void update(EmployeeDTO employeeDTO) {Employee employee = new Employee();BeanUtils.copyProperties(employeeDTO,employee);employee.setUpdateUser(BaseContext.getCurrentId());employee.setUpdateTime(LocalDateTime.now());employeeMapper.update(employee);}
    <update id="update">UPDATE sky_take_out.employee<set><if test="name != null and name != ''">name = #{name},</if><if test="username != null and username != ''">username = #{username},</if><if test="password != null and password != ''">password = #{password},</if><if test="phone != null and phone != ''">phone = #{phone},</if><if test="sex != null and sex != ''">sex = #{sex},</if><if test="idNumber != null and idNumber != ''">id_number = #{idNumber},</if><if test="status != null">status = #{status},</if><if test="updateTime != null">update_time = #{updateTime},</if><if test="updateUser!= null">update_user = #{updateUser}</if></set>WHERE id = #{id}</update>


功能测试

导入分类模块功能代码

需求分析和设计

产品原型:

接口设计

代码导入

因为这里和之前员工管理的部分基本一样,所以直接导入即可,注意最好从后往前导入,也就是从Mapper 层开始导入,这样会减少报错,导入完之后记得手动编译

功能测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918190.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[SC]SystemC 常见的编译/语法错误与解法(三)

SystemC 常见的编译/语法错误与解法(三) 摘要:下面按“现象/编译信息 → 成因 → 解决方案”的结构,归纳 SystemC 建模在 SoC 验证中常见的“编译期/语法层面”问题,并补充如何根据编译信息快速定位与如何在流程上避免这些问题。 一、SystemC 常见的编译/语法错误与…

06-docker容器常用命令

文章目录一.docker容器相关指令概述二.生产环境中常用的 docker容器相关指令1.创建容器(create)2.查看已创建的容器(ps&#xff0c;ls&#xff0c;list)3.运行一个已创建的容器(start)4.停止一个正在运行的容器(stop)5.重启容器(restart)6.创建并启动一个容器(run&#xff0c;等…

Xiphos Q8 摄像头板 高性能图像处理板

我们的高性能图像处理板设计用于与具有两个 Camera Link 接口&#xff08;2x Base 或 1x Medium&#xff09;的 Q8 混合处理器卡配合使用。接口&#xff1a; 2个Camera Link接口 4个SpaceWire接口 4个USB 2.0主端口 串行接口和 GPIO 多个 Vcc 输出&#xff08;5.0、3.3 和 1.8V…

Rocky Linux 10 搭建 NFS 服务详细步骤

1.NFS描述 NFS&#xff0c;全称为Network File System&#xff0c;即网络文件系统&#xff0c;是一种分布式文件系统协议&#xff0c;允许一个系统在网络上与他人共享目录和文件。通过NFS&#xff0c;用户和程序可以像访问本地文件一样访问远端系统上的文件。以下是NFS的一些主…

Android MediaMetadataRetriever取视频封面,Kotlin(1)

Android MediaMetadataRetriever取视频封面&#xff0c;Kotlin&#xff08;1&#xff09; <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE&qu…

qt的元对象系统详解

Qt 的元对象系统&#xff08;Meta-Object System&#xff09;&#xff0c;这是 Qt 框架最核心、最强大的特性之一。 1.什么是 Qt 的元对象系统&#xff1f; Qt 的元对象系统&#xff08;Meta-Object System&#xff09;是 Qt 在标准 C 基础上扩展的一套机制&#xff0c;它为 C …

Nginx 性能优化与动态内容处理

一、压缩功能 实验目的&#xff1a;通过启用 Nginx 的 Gzip 压缩功能&#xff0c;对传输的文件&#xff08;如 HTML、日志等&#xff09;进行压缩&#xff0c;减少网络传输数据量&#xff0c;提升用户访问速度&#xff08;尤其适用于带宽有限的场景&#xff09;&#xff0c;同…

ComfyUI——舒服地让大模型为我所用

主页&#xff1a;ComfyUI | 用AI生成视频、图像、音频 https://github.com/comfyanonymous/ComfyUI 安装环境 我的环境是mac&#xff0c;芯片为M4pro。首先从github中下载工程&#xff0c;clone失败就直接下载zip压缩包。在model文件夹中&#xff0c;可以看到很多大名鼎鼎的…

【Visual Studio】使用VS调试(Debug)

确保在Debug模式下而不是Release 打断点(break point) 直接在有代码的行前单击&#xff0c;会出现红色的点(再次单击会取消)&#xff1b;或者光标停留在某行&#xff0c;按F9 这意味着程序当执行到这一行时会终止 在打完断点后点击”本地Windows调试器“或者按F5 往下翻会有代码…

B2.0:对硬件学习的一些个人心得感悟

对于硬件学习&#xff0c;所有人都会迷茫的找不到学习的路径和方向&#xff0c;都是自我摸索或者老师带领或者其他情况&#xff0c;而我倒是没有机会接触到现实的老师带我领进这个门&#xff0c;自然走的弯路比较多&#xff0c;所以引申出这篇文章&#xff0c;来聊聊硬件学习的…

Cursor设置

一&#xff1a;设置 Port: 7890TUN Mode&#xff1a;开启二&#xff1a;Editor Settings值为http://127.0.0.1:7890三&#xff1a;Cursor 测试一下

Windows下使用PyInstaller打包PyQt项目

在 Windows 环境下&#xff0c;使用 PyQt 开发的项目可以通过多种工具打包成 可执行文件&#xff08;.exe&#xff09;&#xff0c;以下是几种常见的方法及详细步骤&#xff1a;1. 使用 PyInstallerPyInstaller 是最常用的 Python 打包工具&#xff0c;支持 PyQt5/PyQt6/PySide…

AI大语言模型在生活场景中的应用日益广泛,主要包括四大类需求:文本处理、信息获取、决策支持和创意生成。

一、AI大语言模型生活应用全景图&#xff08;Mermaid流程图&#xff09;graph TDA[生活小事需求] --> B{需求分类}B --> C[文本处理类]B --> D[信息获取类]B --> E[决策支持类]B --> F[创意生成类]C --> C1[邮件写作]C --> C2[内容润色]C --> C3[文档总…

物奇路由器Wi-Fi芯片荣膺2025中国创新IC-强芯领航奖,并亮相第五届RISC-V中国峰会

近日&#xff0c;第五届中国集成电路设计创新大会在苏州举办&#xff0c;物奇携多款高性能网络通信与终端人工智能芯片亮相展会&#xff0c;其中首颗路由器Wi-Fi6芯片WQ9301凭借独特的架构创新和领先的性能优势&#xff0c;在国产IC强芯评选中脱颖而出&#xff0c;荣膺2025中国…

【已解决】npm install报错

~/autodl-tmp/App/magic_conch_frontend# npm install报错内容&#xff1a;WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: vitejs/plugin-vue5.1.4, npm WARN EBADENGINE required: { node: ^18.0.0 || >20.0.0 }, npm WARN EBADENGINE current: { no…

IPC总结

IPC 是 Inter-Process Communication&#xff08;进程间通信&#xff09;的缩写&#xff0c;指的是操作系统中不同进程之间传递数据、交换信息或同步行为的机制。由于进程在内存中拥有独立的地址空间&#xff0c;无法直接访问彼此的内存&#xff0c;因此需要通过操作系统提供的…

java之父-新特性

目录 一.函数式接口Functional Interface 1. Supplier接口 --供给型接口 2. Consumer接口 --消费型接口 3.Function接口 --转换型接口 4. Predicate接口--断言型接口 5. Comparator接口--比较器接口 一.函数式接口Functional Interface 只有一个抽象方法的接口&#xff…

GPT-5的多模态能力如何?

GPT-5的多模态能力如何&#xff1f;概述问题1-非整点闹钟问题2-数数问题一问题3-数数问题二小结概述 2025年&#xff0c;8月8日凌晨&#xff0c;OpenAI 发布了 GPT-5&#xff0c;让我们看看其多模态能力如何&#xff0c;用之前大模型无法解决的题目测试&#xff0c;数数问题时…

多模态RAG赛题实战--Datawhale AI夏令营

参考自科大讯飞AI大赛&#xff08;多模态RAG方向&#xff09; - Datawhale 赛题意义&#xff1a; 我们正处在一个信息爆炸的时代&#xff0c;但这些信息并非以整洁的纯文本形式存在。它们被封装在各种各样的载体中&#xff1a;公司的年度财报、市场研究报告、产品手册、学术论…

SQL Server 创建 PostgreSQL 数据库 链接服务器指南

SQL Server 创建 PostgreSQL 数据库 链接服务器指南SQL Server 创建 PostgreSQL 数据库 链接服务器指南一、准备工作二、创建链接服务器三、测试连接四、常见问题解决五、注意事项SQL Server 创建 PostgreSQL 数据库 链接服务器指南 一、准备工作 安装 PostgreSQL ODBC 驱动&a…