首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

手把手教你打造基于RuoYi-Vue-Plus框架的考勤管理系统

  • 25-04-20 02:20
  • 4086
  • 11067
juejin.cn

一、摘要

本文档将详细阐述如何使用RuoYi-Vue-Plus框架快速搭建一个基于SpringBoot和Vue3的前后端分离的考勤管理系统。本文档不仅涵盖了框架的基本使用和技术点介绍,还包括了详细的准备工作步骤、项目启动指南,以及如何连接mqtt服务器以实现实时考勤数据的传输和处理。更重要的是,本文将深入讲解如何对代码进行自定义和扩展,以满足企业实际的考勤管理需求。

二、技术点和准备工作

1.后端技术点

  1. Java17
  2. Mysql 8.0 / mongo数据库 (安装教程自行百度)
  3. MyBatis Plus:作为持久层框架,实现了数据库的CRUD操作,简化了与数据库的交互
  4. Redis : 作为缓存中间件,提高了系统性能和响应速度
  5. Spring Boot :作为核心框架,提供了一系列开箱即用的功能,如数据访问、消息传递、任务调度等
  6. Sa Token: 提供了强大的安全认证和授权功能
  7. Easy Excel: 快速、简洁、解决大文件内存溢出的Excel处理工具

2.前端技术点

  1. vue3
  2. Element Plus
  3. vite

3.软件和开发环境

jdk17
Mysql 8 / mongo 7.0.2
Redis5
Maven3.9.6
Node 20.10.0

开发工具的话这里选择idea开发,以及我们项目需要使用docker拉取镜像,大家百度自行下载即可。

三、拉取项目并启动项目

1.拉取项目

访问 RuoYi-Vue-Plus 仓库地址

下载方法有很多,

  1. 是本地安装了git 直接在目录输入以下命令
js
代码解读
复制代码
git clone https://gitee.com/dromara/RuoYi-Vue-Plus.git

2.是打开idea,记得登录gitee,直接克隆项目

js
代码解读
复制代码
https://gitee.com/dromara/RuoYi-Vue-Plus.git
  1. 是直接点击下载ZIP

下载方式就仁者见仁智者见智,大家挑喜欢的就好。

2.启动项目

动手能力强的可以参考文档地址: plus-doc 一步到位!

第一步我们先创建数据库;然后导入Sql,修改yml参数。修改mysql和redis连接信息即可 image-20250304100639065.png

image.png

image.png

搞定这些我们就可以启动项目了!

至于前端部分,我们直接访问前端项目地址: plus-ui;克隆下来即可。

js
代码解读
复制代码
# 克隆项目 git clone https://gitee.com/JavaLionLi/plus-ui.git # 安装依赖 npm install --registry=https://registry.npmmirror.com # 启动服务 npm run dev # 构建生产环境 npm run build:prod # 前端访问地址 http://localhost:80

3.完善文件上传,minio方式

#ps: 博主是直接在win安装的docker所以用的命令是win的

第一步拉取镜像

js
代码解读
复制代码
docker pull minio/minio

第二步创建文件夹,我是直接创建在d盘

js
代码解读
复制代码
# 直接进入命令行,D:进入d盘 D: # 创建minio文件夹 mkdir minio # 进入minio文件夹 cd minio # 创建data文件夹 mkdir data # 创建config文件夹 mkdir config

第三步直接执行启动命令

js
代码解读
复制代码
docker run --name minio -p 9000:9000 -p 9999:9999 -d --restart=always -e "MINIO_ROOT_USER=admin" -e "MINIO_ROOT_PASSWORD=admin123" -v D:\minio\data:/data -v D:\minio\config:/root/.minio minio/minio server /data --console-address 0.0.0.0:9999

看到下图就启动成功了!

image-20250304103353376.png

接下来我们输入 http://127.0.0.1:9000/ 他会直接 转发到MinIO Console;登录用户名和密码是admin/admin123。先创建桶,在创建key。记得不要把桶改成私密哦!然后我们去RuoYi-Vue-Plus 系统管理->文件管理->配置管理,填号对应的数据就行了!

image-20250304103948564.png

然后自行上传图片测试一下即可!

四、MQTT服务器部署

在开始之前可能就有很多小伙伴不理解,mqtt是什么?为什么要部署这个呢?

mqtt简介

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种轻量级的、基于发布/订阅模式的消息传输协议,专为低带宽、高延迟或不可靠网络环境下的设备通信设计。MQTT由IBM于1999年开发,现已成为ISO/IEC 20922国际标准,广泛应用于物联网(IoT)、小型设备、移动应用等领域。

MQTT的核心特点包括:

  1. 轻量级:MQTT协议非常轻便,适用于带宽有限和资源受限的环境。
  2. 异步通信:发布者(Publisher)和订阅者(Subscriber)之间通过消息代理(Broker)进行异步通信,解耦了消息发送方与接收方,提升了系统的扩展性。
  3. 低功耗:MQTT协议设计简洁,消息传输开销小,有助于降低设备的能耗。
  4. 可靠性:通过不同的服务质量(QoS)级别,确保消息传递的可靠性。
  5. 灵活性:支持持久化会话、遗嘱消息等功能,适应不同需求。

MQTT的核心组件包括:

  1. 发布者(Publisher):负责将消息发布到特定的主题(Topic)。
  2. 订阅者(Subscriber):订阅特定的主题,接收并处理与该主题相关的消息。
  3. 消息代理(Broker):位于发布者和订阅者之间,负责接收来自客户端的消息并将其分发给相应的订阅者。

看到这里还不了解的小伙伴可以去百度或者哔哩哔哩大学了解一下!

mqtt部署

  1. 访问EMQX官网

  2. 获取 Docker 镜像

    js
    代码解读
    复制代码
    docker pull emqx/emqx:5.8.5
  3. 启动 Docker 容器

    js
    代码解读
    复制代码
    docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.8.5

我们可以通过浏览器访问 http://localhost:18083/ 以访问 EMQX Dashboard管理控制台,默认用户名及密码:admin/public。

到这里我们的mqtt服务器就部署好了,是不是很简单!!!

五、接入MQTT

1.新建mqtt模块

动手能力强的直接看文档!!!

在ruoyi-modules模块鼠标右键,新建->新模块->新建模块。 image-20250304110103088.png

image-20250304110226199.png

这里要注意父项不要选择错了!注意父项不要选择错了!注意父项不要选择错了!重要的事情说三遍

然后注意 ruoyi-modules 的 pom.xml、父项目的 pom.xml、以及ruoyi-admin的 pom.xml是否一致!

image-20250304111238112.png

image-20250304111353059.png

image-20250304111437290.png

最后我们只需要导入我们需要的包就OK了!

2.接入mqtt

第一步先导入maven坐标

xml
代码解读
复制代码
<dependency> <groupId>net.dreamlugroupId> <artifactId>mica-mqtt-client-spring-boot-starterartifactId> <version>2.2.10version> dependency>

第二步在yml文件里面填写mqtt连接信息

js
代码解读
复制代码
--- # mqtt配置信息 mqtt: client: enabled: true # 是否开启客户端,默认:true ip: 192.168.158.12 # 连接的服务端 ip ,默认:broker.emqx.io port: 1883 # 端口:默认:1883 name: Mica-Mqtt-Client # 名称,默认:Mica-Mqtt-Client client-id: orange # 客户端Id(非常重要,一般为设备 sn,不可重复) user-name: orange-test # 认证的用户名 password: mqtt # 认证的密码 global-subscribe: # 全局订阅的 topic,可被全局监听到,保留 session 停机重启,依然可以接受到消息。(2.2.9开始支持) timeout: 5 # 超时时间,单位:秒,默认:5秒 reconnect: false # 是否重连,默认:true re-interval: 5000 # 重连时间,默认 5000 毫秒 version: mqtt_3_1_1 # mqtt 协议版本,可选 MQTT_3_1、mqtt_3_1_1、mqtt_5,默认:mqtt_3_1_1 read-buffer-size: 100KB # 接收数据的 buffer size,默认:8k max-bytes-in-message: 10MB # 消息解析最大 bytes 长度,默认:10M buffer-allocator: heap # 堆内存和堆外内存,默认:堆内存 keep-alive-secs: 60 # keep-alive 时间,单位:秒 clean-session: true # mqtt clean session,默认:true ssl: enabled: false # 是否开启 ssl 认证,2.1.0 开始支持双向认证 keystore-path: # 可选参数:ssl 双向认证 keystore 目录,支持 classpath:/ 路径。 keystore-pass: # 可选参数:ssl 双向认证 keystore 密码 truststore-path: # 可选参数:ssl 双向认证 truststore 目录,支持 classpath:/ 路径。 truststore-pass: # 可选参数:ssl 双向认证 truststore 密码

第三步我们重启项目,就能连接上EMQX了!

image-20250304142223014.png 到此为止我们就成功接入MQTT!!!

六、创建考勤机表以及设备连接MQTT服务器

1.创建考勤机表

建表SQL,大家参考自己的业务修改。

sql
代码解读
复制代码
CREATE TABLE `你的数据库名称`.`你的表名` ( `attendance_machine_id` bigint NOT NULL COMMENT '考勤机id', `tenant_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT '000000' COMMENT '项目编号', `device_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '设备名称', `sn` varchar(30) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT '' COMMENT '设备编号', `status` char(1) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT '0' COMMENT '状态(0正常 1离线)', `lock_in_out_status` char(1) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT '' COMMENT '入出状态(0=入,1=出)', `model` char(2) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT '0' COMMENT '设备型号(1=图深人脸机,2=宇泛人脸机)', `del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注', `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`attendance_machine_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '考勤设备表' ROW_FORMAT = Dynamic;

之后就没什么难的,代码生成就行了,前后端代码。

2.设备连接MQTT服务器

这里我是图深考勤机的演示,因为没有其他考勤机。连接方法都大同小异,大家百度一下的都应该可以解决。

image-20250304151503706.png

mqtt地址、端口就是MQTT服务器ip、端口,mqtt用户名最好用考勤机sn码,密码自定义即可,要注意mqtt推送路径和订阅路径,需是device/tushen/设备sn码/Upstream、device/tushen/设备sn码/Downstream,记得勾上上报考勤和图片!!!

七、完善考勤机页面

在第六步我们代码生成了考勤机的前后端代码,在菜单添加上权限即可。我们要做的是第一步工作是添加上考勤机然后在检测它的状态。EMQX自带REST-API可以查询考勤机状态。关于EMQX的REST-API部分,大家自行参考官网。

刷新考勤机状态java代码

java
代码解读
复制代码
/** * 刷新考勤机状态 * * @return */ @SaCheckPermission("mqtt:devices:refresh") @GetMapping("/refresh") public R refreshAttendanceMachineStatus() { return toAjax(attendanceDevicesService.refreshAttendanceMachineStatus()); } /** * 刷新考勤机状态 * * @return */ @Override public Boolean refreshAttendanceMachineStatus() { List devices = baseMapper.selectList(); if (devices.isEmpty()) { return false; } String host = sysConfigServiceApi.getConfigKey("mqtt.host"); String apiKey = sysConfigServiceApi.getConfigKey("mqtt.apiKey"); String secretKey = sysConfigServiceApi.getConfigKey("mqtt.secretKey"); String url = String.format(MqttApiConstants.GET_ALL_MQTT_CLIENTS_URL, host, 1, devices.size() * 10); Object result = exchange(url, apiKey, secretKey); Map statusInfoMap = parseDeviceStatusInfo(result); if (statusInfoMap.isEmpty()) { return false; } devices.stream() .forEach(device -> { device.setStatus("1"); DeviceStatusInfo info = statusInfoMap.get(device.getSn()); if (info != null && info.getConnected()) { device.setStatus("0"); } }); return baseMapper.updateBatchById(devices); } /** * 解析MQTT响应,将结果转换为DeviceStatusInfo列表 * * @param result * @return */ private Map parseDeviceStatusInfo(Object result) { Map statusInfoMap = new HashMap<>(); if (result != null) { try { if (result instanceof JSONObject) { JSONObject object = (JSONObject) result; // 从JSON对象中提取数据并解析为DeviceStatusInfo对象列表 List list = JSONArray.parseArray(object.getString("data"), DeviceStatusInfo.class); for (DeviceStatusInfo info : list) { statusInfoMap.put(info.getClientid(), info); } } else if (result instanceof JSONArray) { JSONArray array = (JSONArray) result; // 将JSONArray直接转换为DeviceStatusInfo对象列表 List list = array.toJavaList(DeviceStatusInfo.class); for (DeviceStatusInfo info : list) { statusInfoMap.put(info.getClientid(), info); } } } catch (Exception e) { log.error("解析MQTT响应出错: {}", e); } } return statusInfoMap; } /** * 交换数据 * * @param url * @param apiKey * @param secretKey * @return */ private Object exchange(String url, String apiKey, String secretKey) { HttpResponse response = HttpRequest.get(url) .basicAuth(apiKey, secretKey) .header("Accept", "application/json") .timeout(10000) .execute(); if (response.getStatus() == 200 && response.body() != null) { String body = response.body(); if (body.startsWith("{")) { // JSON 对象 return JSONObject.parseObject(body); } else if (body.startsWith("[")) { // JSON 数组 return JSONArray.parseArray(body); } } return null; }

这里前端代码过于简单就不展示了QWQ

到这里我们的考勤机页面就算完工了!!!

八、考勤机推送消息给服务端

我这里使用的是图深的人脸机进行测试,图深在线文档地址 大家可以自行观看文档进行定制化开发。

这里我直接提供代码大家粘贴即可!!!

1.MqttClientConnectListener代码

java
代码解读
复制代码
/** * 监听MQTT客户端连接和断开连接的事件 * * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ @RequiredArgsConstructor @Service public class MqttClientConnectListener { private static final Logger logger = LoggerFactory.getLogger(MqttClientConnectListener.class); @Value("${mqtt.client.client-id}") private String clientId; @Value("${mqtt.client.user-name}") private String userName; @Value("${mqtt.client.password}") private String password; /** * MQTT客户端创建器注入 */ private final MqttClientCreator mqttClientCreator; /** * 监听MQTT连接事件 * * @param event */ @EventListener public void onConnected(MqttConnectedEvent event) { // 打印MqttConnectedEvent信息 logger.info("MqttConnectedEvent:{}", event); } /** * 监听MQTT断开连接事件 * @param event */ @EventListener public void onDisconnect(MqttDisconnectEvent event) { // 离线时更新重连时的密码,适用于类似阿里云 mqtt clientId 连接带时间戳的方式 logger.info("MqttDisconnectEvent:{}", event); // 在断线时更新 clientId、username、password mqttClientCreator.clientId(clientId + System.currentTimeMillis()) .username(userName) .password(password); } }

2.MqttClientSubscribeListener 代码

java
代码解读
复制代码
/** * 启动时订阅MQTT主题 * * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ @Component @Slf4j public class MqttClientSubscribeListener implements ApplicationRunner { @Autowired private MqttClientTemplate client; @Autowired private IAttendanceDevicesService attendanceDevicesService; @Autowired private IDepthMqttMessageService depthMqttMessageService; /** * ApplicationRunner 接口的核心方法 * 应用启动时会自动调用该方法 * * @param args * @throws Exception */ @Override public void run(ApplicationArguments args) throws Exception { // 查询考勤设备列表 List attendanceDevicesVos = attendanceDevicesService.queryList(null); for (AttendanceDevicesVo vo : attendanceDevicesVos) { // 图深 if (AttendanceDevicesModel.TUSHEN.equals(vo.getModel())) { // 上行主题 String upstreamTopic = "device/tushen/" + vo.getSn() + "/Upstream"; // 下行主题 String downstreamTopic = "device/tushen/" + vo.getSn() + "/Downstream"; // 去除主题中的非法字符 upstreamTopic = upstreamTopic.replaceAll("[^a-zA-Z0-9_/]", ""); downstreamTopic = upstreamTopic.replaceAll("[^a-zA-Z0-9_/]", ""); // 订阅上行主题 client.subQos0(upstreamTopic, (context, topic, message, payload) -> { // 将payload转换为字符串 String data = new String(payload, StandardCharsets.UTF_8); // 将字符串转换为DepthMqttMessage对象 DepthMqttMessage mqttMessage = JSONObject.parseObject(data, DepthMqttMessage.class); // 处理DepthMqttMessage对象 depthMqttMessageService.handle(mqttMessage, topic); }); // 订阅下行主题 client.subQos0(downstreamTopic, (context, topic, message, payload) -> { // 打印下行主题和payload log.info(topic + '\t' + new String(payload, StandardCharsets.UTF_8)); }); } } } }

3.DepthMqttMessage代码

java
代码解读
复制代码
/** * 图深mqtt消息 * * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ @Data public class DepthMqttMessage { /** * 会话 ID */ private String msgId; /** * 指令 */ private String cmd; /** * 设备ID */ private String devID; /** * 具体请求参数 */ private Object param; /** * 状态码 0成功,其他失败 */ private String code; /** * ok或失败时错误信息 */ private String msg; /** * 返回的消息 */ private Object data; }

4.IDepthMqttMessageService代码

java
代码解读
复制代码
/** * 图深处理回复 客户端消息 * * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ public interface IDepthMqttMessageService { /** * 处理mqtt消息 * * @param mqttMessage mqtt 实体参数 * @param topic 订阅的主题 */ void handle(DepthMqttMessage mqttMessage, String topic); }

5.DepthMqttMessageServiceImpl代码

java
代码解读
复制代码
/** * 图深回复客户端接口实现类 * * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ @Service @Slf4j public class DepthMqttMessageServiceImpl implements IDepthMqttMessageService { @Override public void handle(DepthMqttMessage mqttMessage, String topic) { String cmd = mqttMessage.getCmd(); log.info("收到图深设备消息:{}", cmd); } }

重启项目我们就能收到设备给我们发送的mqtt消息了!!!

相信仔细看代码的小伙伴就知道我们在6.2为什么注意mqtt推送路径和订阅路径路径了。

九、存储考勤信息到mongo数据库

我们之前的配置已经能够成功接收设备发送的MQTT消息。接下来,为了实现考勤功能,设备将主动推送考勤消息到我们的Java后端。我们只需接收这些消息并将其存储起来即可。在这里,我们选择了MongoDB作为存储数据库,当然,根据业务需求,大家也可以选择MySQL等其他数据库。对于MongoDB的CRUD操作,我们决定使用Mongo Plus这款工具来简化开发过程。

动手能力强的可以直接看文档:Mongo Plus文档地址

1.maven导入mongo plus

xml
代码解读
复制代码
<dependency> <groupId>com.mongoplusgroupId> <artifactId>mongo-plus-boot-starterartifactId> <version>2.1.7version> dependency> <dependency> <groupId>com.mongoplusgroupId> <artifactId>mongo-plus-solon-pluginartifactId> <version>2.1.7version> dependency>

2.yml配置mongo plus连接信息

yaml
代码解读
复制代码
# mongo-plus mongo-plus: data: mongodb: host: 127.0.0.1 #ip port: 27017 #端口 database: ry-vue-plus #数据库名 username: ry-vue-plus #用户名,没有可不填(若账号中出现@,!等等符号,不需要再进行转码!!!) password: ry-vue-plus #密码,同上(若密码中出现@,!等等符号,不需要再进行转码!!!) authenticationDatabase: ry-vue-plus #验证数据库 connectTimeoutMS: 50000 #在超时之前等待连接打开的最长时间(以毫秒为单位) log: true pretty: true configuration: collection: mappingStrategy: CLASS_NAME block-attack-inner: true

3.存储考勤信息

mongo plus 无需手动建立集合,建好实体就行了。这里我也是直接粘贴代码给大家看,大家依次建立好就行了。

(1).Record代码

java
代码解读
复制代码
/** * 识别记录表 * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ @Data @CollectionName("record") public class Record { /** * id */ @ID(type = IdTypeEnum.ASSIGN_UUID) private String id; /** * 项目编号 */ @NotNull(message = "项目编号不能为空") private String tenantId; /** * 出/入 */ private String lockInOutStatus; /** * 人脸机设备sn */ @NotNull(message = "考勤机编号不能为空") private String sn; /** * 识别记录 ID */ private String recordId; /** * 人员 ID */ private String personId; /** * 人员姓名 */ private String name; /** * 图片长度 */ private String imgLength; /** * 图片内容(base64) */ private String imgData; /** * 卡号 * 刷卡进入 */ private String cardId; /** * 识别方式 * 刷脸认证:0 * 人卡合一认证:1 * 人证比对:2 * 刷卡认证:3 * 按钮开门:4 * 远程开门:5 * 密码开门:6 * 人 + 密码开门:7 */ private String type; /** * 创建时间 */ private Long createdAt; }

(2).RecordController代码

java
代码解读
复制代码
/** * 考勤表控制器 * * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ @Validated @RequiredArgsConstructor @RestController @RequestMapping("/mqtt/record") public class RecordController { private final IRecordServiceApi recordServiceApi; /** * 分页查询考勤记录 * @param bo * @param pageQuery * @return */ @SaCheckPermission("mqtt:record:list") @GetMapping("/list") public TableDataInfo list(RecordBo bo, PageQuery pageQuery) { return recordServiceApi.queryPageList(bo, pageQuery); } }

(3).IRecordServiceApi代码

java
代码解读
复制代码
/** * 考勤表 * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ public interface IRecordServiceApi { /** * 分页查询考勤记录 * @param bo * @param pageQuery * @return */ TableDataInfo queryPageList(RecordBo bo, PageQuery pageQuery); }

(4).RecordServiceApiImpl代码

java
代码解读
复制代码
/** * 考勤表接口实现类 * * @Author: 陈江灿 * @CreateTime: 2025-03-05 */ @RequiredArgsConstructor @Service public class RecordServiceApiImpl extends ServiceImpl implements IRecordServiceApi { /** * 分页查询考勤记录 * @param bo * @param pageQuery * @return */ @Override public TableDataInfo queryPageList(RecordBo bo, PageQuery pageQuery) { LambdaQueryChainWrapper lwq = this.lambdaQuery(); lwq.eq(StringUtils.isNotEmpty(bo.getPersonId()), Record::getPersonId, bo.getPersonId()); lwq.like(StringUtils.isNotEmpty(bo.getName()), Record::getName, bo.getName()); lwq.like(StringUtils.isNotEmpty(bo.getSn()), Record::getSn, bo.getSn()); String tenantId = LoginHelper.getTenantId(); lwq.eq(StringUtils.isNotEmpty(tenantId), Record::getTenantId, tenantId); if (bo.getBeginCreateTime() != null && bo.getEndCreateTime() != null) { lwq.between(true, Record::getCreatedAt, bo.getBeginCreateTime(), bo.getEndCreateTime(), false); } lwq.orderByDesc(Record::getCreatedAt); PageResult page = this.page(lwq, pageQuery.getPageNum(), pageQuery.getPageSize()); TableDataInfo tableDataInfo = new TableDataInfo<>(); tableDataInfo.setTotal(page.getTotalSize()); tableDataInfo.setRows(page.getContentData()); tableDataInfo.setMsg("查询成功"); tableDataInfo.setCode(HttpStatus.HTTP_OK); return tableDataInfo; } }

(5).vue页面代码

vue
代码解读
复制代码

到这里我们就可以看见我们的考勤记录列表了!!!

4.打卡信息存储mongo数据库

老规矩展示代码!!!

java
代码解读
复制代码
@Override public void handle(DepthMqttMessage mqttMessage, String topic) { String cmd = mqttMessage.getCmd(); log.info("收到图深设备消息:{}", cmd); // 识别信息自动推送 if ("reportVisitRecord".equals(cmd)) { String param = String.valueOf(mqttMessage.getParam()); JSONObject jsonObject = parseObject(param); if (ObjectUtil.isNotNull(jsonObject)) { LambdaQueryWrapper lwq = Wrappers.lambdaQuery(); lwq.eq(AttendanceDevices::getSn, mqttMessage.getDevID()); AttendanceDevices attendanceDevicesVo = attendanceDevicesMapper.selectOne(lwq); Record record = new Record(); record.setLockInOutStatus(attendanceDevicesVo.getLockInOutStatus()); record.setTenantId(attendanceDevicesVo.getTenantId()); record.setName(jsonObject.getString("UserName")); record.setImgData(jsonObject.getString("FaceImgBase64")); record.setSn(mqttMessage.getDevID()); record.setCreatedAt(jsonObject.getLong("TimeStamp")); record.setPersonId(jsonObject.getString("CustomID")); record.setRecordId(mqttMessage.getMsgId()); record.setType("0"); recordServiceApi.addRecord(record); DepthMqttMessage message = new DepthMqttMessage(); message.setMsgId(UUID.randomUUID().toString()); message.setCmd("reportVisitRecord"); message.setDevID(mqttMessage.getDevID()); message.setMsg("ok"); message.setCode("0"); String topicDownstream = "device/Uface/" + mqttMessage.getDevID() + "/Downstream"; client.publish(topicDownstream, JSONObject.toJSONString(message).getBytes(StandardCharsets.UTF_8)); } } }

这时候我们打卡就能在页面上看见考勤记录了!!!

image-20250305145816756.png

到这里我们的考勤系统就先告一段落了,后续会补充和填充计算考勤明细和考勤统计的代码。

需要源代码的同学可以添加我vx:chenbai0511

有什么不懂的也可以加微交流哦qwq

注:本文转载自juejin.cn的杰尼龟会保护orange的文章"https://juejin.cn/post/7478109057044283426"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

103
后端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top