二刷苍穹外卖 day02

新增员工

DTO

将前端传递的参数列表通过对应的实体类接收
当前端提交的数据和实体类中对应的属性差别较大时,使用DTO来封装数据
![[Pasted image 20250611183830.png]]

@Data
public class EmployeeDTO implements Serializable {private Long id;private String username;private String name;private String phone;private String sex;private String idNumber;}

记得要implements Serializable,实现接口后,对象就具备了可序列化的能力

controller

/**  * 新增员工  */  
@PostMapping  
@ApiOperation("新增员工")  
public Result save(@RequestBody EmployeeDTO employeeDTO)  
{  log.info("新增员工:{}",employeeDTO);  employeeService.save(employeeDTO);  return Result.success();  
}

Result定义了后端的返回结果格式

Result

package com.sky.result;  import lombok.Data;  import java.io.Serializable;  /**  * 后端统一返回结果  * @param <T>  */  
@Data  
public class Result<T> implements Serializable {  private Integer code; //编码:1成功,0和其它数字为失败  private String msg; //错误信息  private T data; //数据  public static <T> Result<T> success() {  Result<T> result = new Result<T>();  result.code = 1;  return result;  }  public static <T> Result<T> success(T object) {  Result<T> result = new Result<T>();  result.data = object;  result.code = 1;  return result;  }  public static <T> Result<T> error(String msg) {  Result result = new Result();  result.msg = msg;  result.code = 0;  return result;  }  }

Result是一个通用的后端统一返回结果封装类,用于向前端返回统一格式的响应数据

泛型参数表示返回的数据类型,可以是任何对象
属性:
code 相应状态码,1表示成功,0或其他表示失败
msg:描述错误信息,成功则为空
data:封装返回给前端的具体数据,类型为泛型T

方法:
success()

只返回code=1
success(T object):静态方法,返回包含具体数据的成功响应(code=1,data=object)
error(String msg):返回错误信息和失败状态码

public static <T> Result<T>
是一个Java泛型方法的声明,前一个表明了泛型方法的类型参数声明部分
Result表示该方法返回一个Result类型的对象
static表示这是一个类方法,可通过类名调用

@Service

@Override  
public void save(EmployeeDTO employeeDTO) {  Employee employee = new Employee();  BeanUtils.copyProperties(employeeDTO,employee);  employee.setStatus(StatusConstant.ENABLE);  employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes());  employee.setCreateTime(LocalDateTime.now());  employee.setUpdateTime(LocalDateTime.now());  employee.setCreateUser(10L);  employee.setCreateUser(10L);employeeMapper.insert(employee);  
}

注意一下BeanUtils.copyProperties()方法,以后用的很多
用于将一个 JavaBean 对象(源对象)的属性值复制到另一个 JavaBean 对象(目标对象)中。这里它将 EmployeeDTO 对象 employeeDTO 的属性值复制到 Employee 对象 employee 中。通常,源对象和目标对象需有相同或兼容的属性名及类型,这样才能正确复制属性值,比如 EmployeeDTO 中的 name 属性若与 Employee 中的 name 属性类型匹配,就会将 employeeDTOname 值复制到 employeename 属性中 。

mapper

@Insert("insert into employee (name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user,status) " +  "values " +  "(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})")  
void insert(Employee employee);

上面的是的属性是数据库属性,下面的是后端
因为在application.yml中已经开启了驼峰命名,所以二者可以对应

mybatis:configuration:#开启驼峰命名map-underscore-to-camel-case: true

问题一 重名

使用全局异常处理器来解决问题

@ExceptionHandler
public 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);  }  
}

@ExceptionHandler 是一个注解,该方法用于处理特定类型的异常。比如在上述代码中,标记的方法 exceptionHandler 专门处理 SQLIntegrityConstraintViolationException 类型的异常。当程序执行过程中抛出此类型异常时,就会执行被 @ExceptionHandler 标记的方法,根据异常信息进行相应处理,比如提取异常信息中的用户名,返回特定的错误提示给前端,告知用户用户名已存在等。

![[Pasted image 20250611202502.png]]

问题二:

新增员工时,我们需要获得当前登录员工的id
使用JWT 令牌并相应给前端

当前端指令请求时,它所携带的JWT令牌可以解析出对应员工的登录id;

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;  }  
}

在拦截器中已经解析出了员工的id

Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);  Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());  

第一行调用JwtUtil工具类的parseJWT方法,使用配置文件中的管理员密钥对token令牌进行解析,将解析后的对象(包括id)存储在claim对象中
通过JwtClaimsContant.EMP_ID这个常量作为键,获取对应的用户ID,得到字符串之后再转换为Long类型

ThreadLocal

ThreadLocal是为每一个线程提供的一个单独的存储空间,具有线程隔离的效果,其他线程无法访问

常用方法

public void set(T value)设置
public T get()获取
public void remove()

解决流程

**![[Pasted image 20250611203416.png]]**

在初始工程中已经封装了对应类

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();  
}

在一个多线程的 Web 应用中,不同的请求线程可能需要各自独立的用户 ID 标识。可以在某个请求线程开始处理业务时,调用setCurrentId方法设置该线程的用户 ID,在处理业务过程中通过getCurrentId方法随时获取该线程的用户 ID,处理完成后调用removeCurrentId方法清理资源。

在拦截器中存储empid

 try {//.................Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());log.info("当前员工id:", empId);/将用户id存储到ThreadLocalBaseContext.setCurrentId(empId);//3、通过,放行return true;

在service中获取局部变量的值

    public void save(EmployeeDTO employeeDTO) {//.............................//设置当前记录创建人id和修改人idemployee.setCreateUser(BaseContext.getCurrentId());employee.setUpdateUser(BaseContext.getCurrentId());employeeMapper.insert(employee);}

员工分页查询

注意:
请求参数类型为Query,在路径后拼接/admin/employee/page?name=zhangsan

返回数据中records数组使用Employee实体类对属性进行了封装

Controller

  @GetMapping("/page")@ApiOperation("员工分页查询")public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO){log.info("员工分页查询,参数为:{}", employeePageQueryDTO);PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);//后续定义return Result.success(pageResult);}

方法返回值类型为Result<PageResult>Result是自定义的用于封装响应结果的类,PageResult则可能是包含分页数据的类。

PageResult是一个专用的数据载体
long total 总记录数
List records 当前页实际查询到的数据集合

Result
是泛型的具体类型实例,data字段的类型是PageResult

service

@Override  
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {  PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());  Page<Employee>page=employeeMapper.pageQuery(employeePageQueryDTO);  long total=page.getTotal();  List<Employee> records=page.getResult();  return new PageResult(total,records);  
}

mappe层

<select id="pageQuery" resultType="com.sky.entity.Employee">  select * from employee    <where>  <if test="name !=null and name !=''">  and name like concat('%',${name},'%');        </if>  </where>  order by create_time desc  
</select>

查询名字中间包含name的,不需要limit,分页由pagehelper插件进行处理

操作时间字段问题

在WebMvcConfiguration中扩展SpringMVC消息转换器
Spring Boot 默认使用 MappingJackson2HttpMessageConverter 处理 JSON 序列化 / 反序列化,但 Jackson 对日期类型的默认序列化规则会导致格式异常

  • 若实体类中是 DateLocalDateTime 等日期类型,Jackson 默认可能将其序列化为 时间戳拆分的数组(如 [年, 月, 日, 时, 分, 秒],与前端期望的格式(如 2022524112024)不匹配。
  • 将自定义的 MappingJackson2HttpMessageConverter 放到转换器列表的第一位,确保优先使用(覆盖默认的 Jackson 转换器)。
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {  log.info("扩展消息转换器...");  //创建一个消息转换器对象  MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();  //需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据  converter.setObjectMapper(new JacksonObjectMapper());  //将自己的消息转化器加入容器内  converters.add(0, converter);  
}

启用禁用员工账号

Controller

@PostMapping("/status/{status}")  
@ApiOperation("启用禁用员工账号")  
public Result startOrStop(@PathVariable Integer status,@RequestParam("id") Long id  // 显式声明id来自请求参数
)  
{  log.info("启用禁用员工账号");  employeeService.startOrStop(status,id);  return Result.success();  
}

注意讲义中当前方法中 Long id 参数未显式声明参数来源。在 Spring MVC 中,未标注@PathVariable/@RequestBody等注解的参数默认会尝试从请求参数(@RequestParam)获取,但如果请求中未传递id参数,会直接抛出MissingServletRequestParameterException(400 错误)。建议修改

编辑员工

回显员工信息

controller

/**  * 根据id查询员工信息  */  
@GetMapping("/{id}")  
@ApiOperation("根据id查询员工信息")  
public Result<Employee> getById(@PathVariable Long id) {  Employee employee = employeeService.getById(id);  return Result.success(employee);  
}

service层

@Override  
public Employee getById(Long id) {  Employee employee = employeeMapper.getById(id);  employee.setPassword("****");  return employee;  
}

密码主动修改很细节

修改信息

service

注意这里不能用builder(),因为builder只能是创建对象的时候使用

public void update(EmployeeDTO employeeDTO) {  Employee employee = new Employee();  BeanUtils.copyProperties(employeeDTO, employee);  employee.setUpdateTime(LocalDateTime.now());  employee.setUpdateUser(BaseContext.getCurrentId());  employeeMapper.update(employee);  }

在上一个功能中已经实现了可泛用的mapper,这里不需要再写了

导入代码

CategoryMapper.xml文件中注意到一个点
select 语句中使用where if test时需要"and",表示&
在update语句中set里不需要写表示| ,有就满足

<select id="pageQuery" resultType="com.sky.entity.Category">  select * from category    <where>  <if test="name != null and name != ''">  and name like concat('%',#{name},'%')        </if>  <if test="type != null">  and type = #{type}        </if>  </where>  order by sort asc , create_time desc</select>  <update id="update" parameterType="Category">  update category    <set>  <if test="type != null">  type = #{type},        </if>  <if test="name != null">  name = #{name},        </if>  <if test="sort != null">  sort = #{sort},        </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.DTO:

用来接受前端提交的数据以及不同层之间传递
当与实体类差别较大时使用

2.Result

通用后端统一返回结果封装类,向前端返回统一格式的响应数据

3.public static Result

是一个Java泛型方法的声明,前一个表明了泛型方法的类型参数声明部分
Result表示该方法返回一个Result类型的对象
static表示这是一个类方法,可通过类名调用

4.BeanUtils.copyProperties()

一般将DTO赋值给对应的对象

5.重名

ExceptionHandler注解,当程序抛出对应异常时,会执行被@ExceptionHandler标记的方法

6.JWT令牌

通过JwTUtil.parseJWT可以解析令牌

7.ThreadLocal

仅本线程可用存储空间
set get remove

8.分页查询

PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
第一个参数employeePageQueryDTO.getPage()获取到的是要查询的页码,第二个参数employeePageQueryDTO.getPageSize()获取到的是每页显示的记录数

方法返回值类型为Result
PageResult是专门的数据载体,包括List records,即当前页查询到的数据集合
records

9.操作时间字段

更换自定义的转换器覆盖原有

10.启用禁用员工账号

未表明数据来源会默认从请求参数(@RequestParam)获取,即带有查询参数(Query Parameters)的 URL 链接?xx=xx

11.xml文件 if条件

在select时要保证全满足,即&,所以if 后要加"and"
在update时满足一个修改一个,即 |,所以If 后不用加

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

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

相关文章

通过Heron Handoff 插件我们在figma设计中可以像sketch导出离线标注

一、设计交付的历史困境与破局契机 在数字产品开发的全流程中&#xff0c;设计标注的高效传递始终是连接创意与实现的关键纽带。传统设计工具如 Sketch 凭借 Bluebeam、Sketch Measure 等插件构建了成熟的离线标注体系&#xff0c;设计师可将标注文件打包交付&#xff0c;开发…

SSE 数据的传输无法流式获取

问题 调试过程中发现SSE数据返回的时间都是一样的&#xff0c;怀疑是接口问题。 参考 EventSource数据一次性出来&#xff0c;并未流式输出的原因_sourceevent为什么结果一下全部返回了-CSDN博客 处理 EventStream 不能流式返回的问题&#xff1a;Nginx 配置优化 解决方案 …

markdown文本转换时序图

好久没更新了~这篇是markdown文本转换时序图的常用方法 文章目录 前言一、Mermaid语法示例二、PlantUML语法示例三、在线工具快速转换总结 前言 使用专业工具如Mermaid或PlantUML可以直接在Markdown中绘制时序图。这些工具支持简洁的语法&#xff0c;生成可嵌入文档的图表&…

谷粒商城-分布式微服务 -集群部署篇[一]

十九、k8s 集群部署 19.1 k8s 快速入门 19.1.1 简介 Kubernetes 简称 k8s。是用于自动部署&#xff0c;扩展和管理容器化应用程序的开源系统。 中文官网 中文社区 官方文档 社区文档 概述 | Kubernetes 传统部署时代&#xff1a; 早期&#xff0c;各个组织是在物理服务器上…

微信小程序- 用canvas生成排行榜

设计功能不是很复杂&#xff0c;也不想用插件&#xff0c;最终出现现在版本&#xff0c;主要用到微信小程序 wx.canvasToTempFilePath方法 // 直接调用改方法 createQRCode() {const qrCodeCanvasId "qrcodeCanvas";drawQrcode({width: 200,height: 200,canvasId: …

深度剖析:UI 设计怎样为小程序构建极致轻量体验

内容摘要 在小程序的世界里&#xff0c;用户都追求快速、便捷的轻量体验。但你是否好奇&#xff0c;为啥有些小程序能让人轻松上手&#xff0c;快速达成目标&#xff0c;而有些却让人感觉繁琐、卡顿&#xff1f;这里的关键差异&#xff0c;往往就藏在 UI 设计中。UI 设计到底施…

【网络安全】Qt免杀样本分析

初步研判 SHA256&#xff1a;9090807bfc569bc8dd42941841e296745e8eb18b208942b3c826b42b97ea67ff 我们可以看到引擎0检出&#xff0c;是个免杀样本&#xff0c;不过通过微步云沙箱的行为分析&#xff0c;已经被判为恶意 行为分析 进程行为 可以看到demo显示调用了winver获…

window 显示驱动开发-如何查询视频处理功能(六)

D3DDDICAPS_FILTERPROPERTYRANGE请求类型 UMD 返回指向 DXVADDI_VALUERANGE 结构的指针&#xff0c;该结构包含传递D3DDDICAPS_FILTERPROPERTYRANGE请求类型时特定视频流上特定筛选器设置允许的值范围。 Direct3D 运行时在D3DDDIARG_GETCAPS的 pInfo 成员指向的变量中为特定视…

Oracle线上故障问题解决

----重启电脑找不到sid Listener refused the connection with the following error: ORA-12505, TNS:listener does not currently know of SID given in connect descriptor Could not open connection sqlplus "/as sysdba" SQL> shutdown immediate 数据库…

语音信号处理三十——高效多相抽取器(Polyphase+Noble)

文章目录 前言一、Polyphase 多项分解1.定义2.拆分公式3.推导过程1&#xff09;按模 M M M拆分求和项2&#xff09;提取因子 4.总结 二、Noble恒等式1. 定义2.Noble恒等式表达方式1&#xff09;抽取系统的 Noble 恒等式2&#xff09;插值系统的 Noble 恒等式 2.Nodble恒等式推导…

广告推荐系统中模型训练中模型的结构信息、Dense数据、Sparse数据

下面结合广告推荐系统常见的深度学习模型(比如 Wide & Deep、DeepFM、Two-Tower 等),介绍一下“模型的结构信息”、Dense 数据和 Sparse 数据在训练过程中的角色及处理方式。 模型结构信息 输入层(Input Layer) • Sparse 输入:各类离散高维特征(用户 ID、广告 ID、…

安全生产管理是什么?安全生产管理主要管什么?

安全生产管理是什么&#xff1f;安全生产管理主要管什么&#xff1f; 不管是制造业、建筑业&#xff0c;还是仓储、物流、化工等等&#xff0c;一聊到“安全事故”&#xff0c;大家脑子里最先冒出来的两个词&#xff0c;肯定就是&#xff1a; 人的不安全行为物的不安全状态 …

SecureRandom.getInstanceStrong() 与虚拟机的爱恨情仇

问题描述 使用Ruoyi-cloud 二开&#xff0c;将服务部署到虚拟机上后&#xff0c;准备登录&#xff0c;发现验证码一致加载不出来&#xff0c;接口请求超时! 解决步骤 telnet 虚拟机ipport 发现可以通.curl 接口&#xff0c;发现一致不返回&#xff0c;超时了./code 接口超时&am…

DEM 地形分析与水文建模:基于 ArcGIS 的流域特征提取

技术点目录 一、 GIS理论及ArcGIS认识二、ArcGIS数据管理与转换三、ArcGIS地图制作与发布四、ArcGIS数据制备与编辑五、ArcGIS矢量空间分析及应用六、ArcGIS栅格空间分析及应用七、ArcGIS空间插值及应用八、DEM数据与GIS三维分析九、ArcGIS高级建模及应用十、综合讲解了解更多 …

芯伯乐XBLW GT712选型及应用设计指南

前言 在电子工程领域&#xff0c;精准的电流测量对于众多电路设计与系统监控至关重要。芯伯乐推出的XBLW GT712电流传感器以其独特的优势&#xff0c;成为工程师在诸多应用中的首选工具。本文将深入剖析XBLW GT712的工作原理、性能特点以及应用要点&#xff0c;为工程师提供详…

MySQL查看连接情况

说明&#xff1a;本文介绍如何查看MySQL会话连接情况&#xff0c;方便排查MySQL占用CPU过高或其他问题。 连接数据库 首先&#xff0c;使用命令行连接到MySQL数据库 mysql -u[用户名] -p[密码] -h[主机IP] -P[端口号]如果MySQL就在本机上&#xff0c;那么如下即可 mysql -u…

图文教程——Deepseek最强平替工具免费申请教程——国内edu邮箱可用

亲测有效&#xff01;只需 4 步即可免费体验最新最强的 AI 助手&#xff01; 最强AI助手 This account isn’t eligible for Google AI Pro plan Google AI Pro plan isn’t available in some countries or for people under a certain age. 问题终极解决方案&#xff1a; ht…

java转PHP开发需要几步?

PHP基础入门指南&#xff08;面向Java开发者&#xff09; 作为Java开发者&#xff0c;你已经掌握了面向对象编程、变量类型和控制结构等核心概念&#xff0c;这将大大加速你学习PHP的过程。下面我将从语法差异和PHP特性两个方面&#xff0c;帮助你快速上手PHP开发。 语法差异…

一种使用 PowerToys 的键盘管理器工具重新映射按键实现在 Windows 上快捷输入字符的方式

文章目录 一、问题背景二、安装 PowerToys三、配置快捷键 一、问题背景 在之前的一篇文章中介绍了使用 Java 程序实现快捷键输入字符的方式&#xff08;https://blog.csdn.net/TeleostNaCl/article/details/148158298&#xff09;&#xff0c;其原理是利用 后台常驻的 Java 应…

Python环境搭建竞赛技术

Python环境搭建竞赛技术文章大纲 竞赛背景与意义 Python环境搭建竞赛旨在考察参赛者对Python开发环境的熟悉程度&#xff0c;包括工具选择、配置优化和问题解决能力。此类竞赛常见于编程教学、企业内训或技术社区活动&#xff0c;强调实践性和效率。 竞赛核心考察点 环境隔…