瑞吉外卖 - 启用与禁用员工账号功能(8)

news2025/1/20 0:54:26

某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548

文章目录

    • 1.需求分析
    • 2.代码开发
      • 2.1 分析页面效果
      • 2.2 分析执行过程
      • 2.2.3 代码实现
    • 3.功能测试
    • 4.代码修复

1.需求分析

在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统,启用后的员工可以正常登录。需要注意的是,只有管理员(admin 用户)可以对其他普通用户进行启用、禁用操作,所以普通用户登录系统后启用禁用按钮不显示。

下面是管理员登陆后的界面:

下面是普通员工登陆后的页面:

2.代码开发

2.1 分析页面效果

那么页面中是如何做到只有管理员(admin)才能够看到启用、禁用员工按钮的呢?我们可以追踪到 static/backend/page/member/list.html 中的如下位置:

可以看到,代码中会判断模型数据 user 的值是否为 admin,如果是则展示当前按钮,否则不展示。对应的 user 我们可以往上追踪到如下位置:

可以看到,前端会从 localStorage 获取当前登陆员工的 username,并赋值给模型数据 user。

2.2 分析执行过程

在代码开发之前,我们需要先梳理一下整个程序的执行过程:

  1. 客户端发送 ajax 请求,将参数(id,status)提交到服务端;
  2. 服务端 Controller 接收客户端提交的数据并调用 Service 更新数据;
  3. Service 调用 Mapper 操作数据库。

我们可以使用 admin 账户点击启用禁用按钮,然后查看浏览器调试工具对应的请求 URL 和携带的参数:

可以看出,当管理员点击禁用或启用按钮时,会发送一个 POST 请求,请求 URL 为 /employee,同时携带 json 数据为 id(员工 id)和 status(员工状态)。

2.2.3 代码实现

对应的 EmployeeController 中的处理方法如下:

@RestController
@RequestMapping("/employee")
public class EmployeeController {
    /**
     * 处理更新员工请求
     * @param request 请求对象
     * @param employee 员工对象
     * @return 响应对象
     */
    @PutMapping
    public R<String> update(HttpServletRequest request,@RequestBody Employee employee){
        // 设置更新时间
        employee.setUpdateTime(LocalDateTime.now());

        // 获取当前登录的员工 id,作为更新人
        Long empId = (Long) request.getSession().getAttribute("employee");
        employee.setUpdateUser(empId);

        // 更新员工信息
        employeeService.updateById(employee);

        // 返回更新成功结果
        return R.success("更新员工成功");
    }
}

实现思路比较简单,就是将客户端传送的 json 数据通过 @RequestBody 注解封装为 Employee 对象,在完成更新员工信息的同时也更新了对应的更新时间(update_time)和更新人(update_user)。

3.功能测试

下面我们直接进行功能测试,以 admin 账户登陆后点击【禁用】按钮:

可以看到,更新操作成功了,但是为什么状态仍旧是正常呢?我们不妨再查看数据库端的对应数据:

咦?这是为什么呢?我们接着来看看 IDEA 控制台的 SQL 日志:

执行结果是 Updates:0 ,也就意味着没有匹配到对应的记录,然而从 SQL 语句中不难看出,该语句是根据 id 进行匹配的。那我们重点关注传入的 id,值为 1658001441572294700,重点关注后三位 “700”。

然后我们再查看数据库中对应的 id:

发现端倪了吗?后三位居然与数据库的值不一样!我们再看看客户端请求中携带的 id 值:

可见当执行修改操作时客户端发送的 id 就是错的,我们在服务端通过该 id 值进行修改操作,自然是修改不成功的。那么是不是因为在进行分页操作的时候拿到的响应就是错的呢?我们对应找到分页完成客户端的响应数据:

很明显客户端返回的数据是没有问题的,该 id 与数据库中的一致。可是在我们点击【编辑】或【启用、禁用】按钮时获取到的 id 确实是错的,那么问题出来哪儿呢?

其实是因为服务端在进行分页查询时,响应给客户端的员工 id 是一个 long 类型的 19 位整数值,从上面的截图也能看出来了。但是问题就出现在,前端页面中是通过 js 去处理 long 类型的数值的,但是只能精确到 16 位,也就意味着后三位进行了四舍五入,因此最终通过 ajax 请求提交给服务端时 id 的后三位就由 “657”变成了 “700”,自然也就不可能更新成功了。

针对这个问题,为了避免 js 处理 long 类型数值时出现精度丢失,我们可以将原本响应给客户端的 long 类型的 id,将 long 型的数据进行处理转为 String 类型即可。

4.代码修复

具体实现步骤如下:

  1. 提供对象转换器 JacksonObjectMapper,基于 jackson 进行 Java 对象到 json 数据的转换;

    资料位置:瑞吉外卖\瑞吉外卖项目\资料\对象映射器\JacksonObjectMapper.java

  2. 在 WebMvcConfig 配置类中扩展 Spring MVC 的消息转换器,在此消息转换器中使用提供的对象转换器进行 Java 对象到 jason 数据的转换。

我们直接将准备好的 JacksonObjectMapper.java 复制到项目的 common 包下即可,对应的完整代码如下:

package cn.javgo.reggie_take_out.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 对象
 * 说明:
 * 1.将 JSON 解析为 Java 对象的过程称为 [从 JSON 反序列化 Java 对象]
 * 2.从 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)))

            	// 将 BigInteger、Long 类型的数据序列化为字符串类型
                .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);
    }
}

接下来新建 config 包用于存放各种配置类,然后新建一个 WebMvcConfig 类继承 WebMvcConfigurationSupport 类,并在中扩展 Spring MVC 的消息转换器即可,其实就是重写父类的 extendMessageConverters() 方法从而替换 Spring MVC 默认的消息转换器。

完整代码如下:

package cn.javgo.reggie_take_out.config;

import cn.javgo.reggie_take_out.common.JacksonObjectMapper;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;

/**
 * @author: JavGo
 * @description: TODO
 * @date: 2023/5/16 12:49
 */
@SpringBootConfiguration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    /**
     * 配置静态资源映射
     * @param registry 静态资源注册器
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 配置静态资源映射(将所有的静态资源都映射到 classpath:/static/ 目录下)
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }

    /**
     * 扩展 Spring MVC 消息转换器
     *
     * @param converters 消息转换器列表
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 创建 Jackson 消息转换器
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        // 设置具体的序列化和反序列化器(其实就是对象映射器)
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        // 通过设置消息转换器的顺序,来改变 Spring MVC 消息转换器的优先级,从而实现自定义消息转换器的优先级高于默认的消息转换器
        converters.add(0, messageConverter);
    }
}

上述代码中笔者同时重写 addResourceHandlers() 方法进行了静态资源映射的处理,否则点击【编辑】按钮跳转静态资源页面时会显示 404。

在 Spring Boot 应用程序启动时会自动调用上述方法进行消息转换器的注册,我们可以在该方法上打上断点:

OK,现在以 Debug 方式重启应用再次进行测试,当执行完该方法后可以看到我们扩展的消息转换器被放到了第一个位置,具有最高优先级:

跳过调试,项目启动完成后再进行客户端功能测试,就能测试成功:

此时分页查询返回的 id 也加上了双引号作为字符串,并且与数据库端的 id 一致:

对应更新操作的客户端请求的 json 数据也获取到的正确的 id:

禁用后,我们将管理员账户退出登录,使用被禁用的 zhangsan 进行登录(默认密码为 12346)就会登陆失败:

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

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

相关文章

最新入河排污口设置论证、水质影响预测与模拟、污水处理工艺分析及典型建设项目入河排污口方案报告书

随着水资源开发利用量不断增大&#xff0c;全国废污水排放量与日俱增&#xff0c;部分河段已远远超出水域纳污能力。近年来,部分沿岸入河排污口设置不合理&#xff0c;超标排污、未经同意私设排污口等问题逐步显现&#xff0c;已威胁到供水安全、水环境安全和水生态安全&#x…

Packet Tracer – 配置 VLAN

Packet Tracer – 配置 VLAN 地址分配表 设备 接口 IP 地址 子网掩码 VLAN PC1 NIC 172.17.10.21 255.255.255.0 10 PC2 NIC 172.17.20.22 255.255.255.0 20 PC3 NIC 172.17.30.23 255.255.255.0 30 PC4 NIC 172.17.10.24 255.255.255.0 10 PC5 NI…

open3d 表面重建

目录 1. create_from_point_cloud_ball_pivoting 2. create_from_point_cloud_alpha_shape 3. create_from_point_cloud_poisson 从以下效果来看&#xff0c;第三个方法最好。 1. create_from_point_cloud_ball_pivoting 关键代码&#xff1a; rec_mesh o3d.geometry.T…

面试被问麻了....

前几天组了一个软件测试面试的群&#xff0c;没想到效果直接拉满&#xff0c;看来大家对面试这块的需求还是挺迫切的。昨天我就看到群友们发的一些面经&#xff0c;感觉非常有参考价值&#xff0c;于是我就问他还有没有。 结果他给我整理了一份非常硬核的面筋&#xff0c;打开…

2022年美国大学生数学建模竞赛F题人人为我,我为人人解题全过程文档及程序

2022年美国大学生数学建模竞赛 F题 人人为我&#xff0c;我为人人 原题再现&#xff1a; 背景:   世界上大多数国家签署了1967年联合国《外层空间条约》&#xff0c;条约内容包括同意探索和利用外层空间&#xff0c;包括月球和其他天体&#xff0c;不论各国经济或科学发展程…

低成本挖出电商API接口-程序员要注意那些事项-技术分享

在开发电商应用的过程中&#xff0c;获取天猫API接口是非常必要的一步。天猫API提供了丰富的商品数据获取、订单管理、支付管理等功能&#xff0c;但是天猫API一般需要进行开发者认证&#xff0c;而认证需要企业资质和若干费用支出&#xff0c;这对个人开发者和小型业务开发者来…

Postgresql数组与Oracle嵌套表的使用区别

oracle中的多维数组 Oracle中常说的数组就是嵌套表&#xff0c;下面给出两个多维使用实例&#xff0c;引出和PG的差异&#xff1a; 一维赋值&#xff08;第一行给1列&#xff09; set serveroutput on; declaretype arr_num is table of number;type arr_arr_num is table o…

任务队列的Java实现

一、需求背景 当前项目中遇到这样一个需求: 将需要审核的文本提交给人工智能模型接口审核&#xff0c;等待模型接口审核完毕以后拿到审核结果返回给前端展示给用户&#xff08;另&#xff1a;模型处理数据所消耗的时间会随着用户提交数据的复杂度有所变化&#xff09;。 以上需…

毫米波雷达系列 | 传统CFAR检测(自适应类)

毫米波雷达系列 | 传统CFAR检测&#xff08;自适应类&#xff09; VI-CFAR [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dV34CKJt-1684215839850)(毫米波雷达系列 传统CFAR检测&#xff08;自适应类&#xff09;.assets/image-20230516131206695…

Recognizing Micro-Expression in Video Clip with Adaptive Key-Frame Mining阅读笔记

本文主要贡献 据我们所知&#xff0c;这是第一项旨在将视频剪辑中的信息时间子集的端到端学习与单个网络中的微表情识别相结合的工作。 此外&#xff0c;所提出网络中所有模块的设计都与输入视频剪辑的长度无关。 换句话说&#xff0c;网络容忍各种长度的微表情剪辑。 本文的贡…

水利工程电子(数字)沙盘

水利工程电子&#xff08;数字&#xff09;沙盘利用三维地理信息系统、遥感技术、海量数据管理技术、虚拟现实技术、网络通讯技术和高性能计算机技术等现代高新信息技术&#xff0c;采用高精度DEM地形数据、遥感影像、航拍影像和基础地理矢量数据&#xff0c;建立三维空间场景&…

SAAS 与 IAAS 云渲染农场比较

渲染时&#xff0c;最重要的是需要的时间和硬件可用的。此渲染过程需要大量计算能力才能快速创建图像或视频。GPU&#xff08;图形处理单元&#xff09;是图形的计算能力&#xff0c;越来越多地用于渲染CAD模型。GPU中有特殊的处理器&#xff0c;可以执行用于快速编辑和显示图像…

TCP的拥塞控制

为了避免发送方无节制地发送数据&#xff0c;从而造成网络拥堵&#xff0c;所以 TCP 有一个拥塞控制。 流量控制&#xff1a;作用于接收方&#xff0c;控制发送者发送速度&#xff0c;从而使接收者来得及接收&#xff0c;防止分组丢失。 拥塞控制&#xff1a;作用于网络&#…

【星戈瑞】Sulfo-Cyanine5 mal红色荧光Cy5-maleimide

Sulfo-Cyanine5 mal是一种具有强荧光信号的染料&#xff0c;主要应用于生物荧光成像领域。它的化学式为C38H43KN4O9S2&#xff0c;分子量为803.00。这种染料具有良好的水溶性&#xff0c;可在水溶液中稳定存在。它的光学特性包括吸收峰位于646 nm和发射峰位于662 nm&#xff0c…

公司新来了个00后软件测试工程师,一副毛头小子的样儿,哪想到是新一代的卷王...

内卷&#xff0c;是现在热度非常高的一个词汇&#xff0c;随着热度不断攀升&#xff0c;隐隐到了“万物皆可卷”的程度。 在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是…

计算机组成简答题整理

作者&#xff1a;爱塔居 多模块交叉存储器是如何加速CPU与存储器之间有效传输&#xff1f; 解&#xff1a;CPU同时访问多个模块&#xff0c;由存储器控制部件控制它们分别使用数据总线进行信息传递。对每一个存储模块来说&#xff0c;从CPU给出访存命令直到读出信息仍然使用了…

同惠 LCR数字电桥测试仪 TH2830

TH283X系列是新一代低成本,高性能紧凑型LCR数字电桥,采用最新工艺和高密度电路设计,浓缩大型LCR测试仪的精华,紧凑,小巧.取消传统机械电源开关,采用软件控制电源开关.0.05%的基本精度和良好的测试稳定性可与高端机型媲美.配备4.3寸LCD显示屏和全新升级的界面系统.美观大方,操作…

EXCEL: 查找符合多个条件,并且不重复的数据的个数的3种方法:公式,数据透视表,数组公式

1 目标问题&#xff1a;想筛选出(在a列月份为5)且不重复的b列数据有几个 有2个条件 查找第1列月份为5月的并且第2列不重复的数据个数 方法1&#xff1a;用加辅助列简单公式的办法 其实逻辑是更清晰的&#xff0c;就是显得步骤繁琐 第1个辅助列1&#xff0c;查找日期中的月份…

vps赚钱的小项目,通过售卖流量赚钱

文章目录 vps赚钱的小项目&#xff0c;通过售卖流量赚钱问题来源为什么能赚钱&#xff1f;赚钱速度呢&#xff1f;注册流程注册复制token 设置vps更新系统组件安装docker通过docker启动项目设置开机自启删掉容器 windows使用方法 查看网页端提现操作总结 vps赚钱的小项目&#…

Arc 打断拆分成多个线段

公司插件的梁齐斜板功能更新&#xff0c;设计师提出需求可以拆分弧梁&#xff0c;并能对齐到板顶。 本文只讨论拆分弧梁&#xff0c;椭圆再后续更新。 首先看以下弧形的创建api API中提供了三种方法 第一种时指定起点与终点&#xff0c;最后选择顶点形成的弧形 第二种是指定面…