Skip to content

基于springboot + jpa + Erupt后台框架开发的综合签到打卡系统,支持人脸识别(百度云),指纹识别(本地指纹仪+websocket),签到数据展示,签到情况微信推送;支持docker-compose一键部署

Notifications You must be signed in to change notification settings

404name/face-check-in-system

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

2023年4月21日21:06:13 修复部分bug & 重构补全前端源码 12345 (1)

快速开始

默认账号

  • 管理员 admin admin
  • 默认人脸(手机找个照片然后对着电脑就行)[王思聪、蔡徐坤、马云]

项目页面

  1. 管理员界面 http://localhost:8080
  2. 客户端界面 http://localhost:8080/front.html
  3. swagger接口界面 http://localhost:8080/swagger-ui.html#/

项目启动

  1. 创建数据库face_sign_in并导入/src/face_sign_in.sql
  2. 修改/src/main/resources/application-dev.yml里面的配置
  3. 对于idea需要配置lombok插件&jdk1.8 | project structure里面level设置成8及以上
  4. 使用idea maven 刷新后右上角启动即可

功能使用

  1. 注册人脸:先创建新用户再前往录入界面录入(不能太模糊,也可以使用明星的照片)
  2. 更新人脸:选择已经录入的人脸然后覆盖
  3. 录入访客:后端管理界面手动录入或者excel导入
  4. 推送手机:前往http://pushplus.hxtrip.com/send配置对应的key,去后端管理配置出覆盖
  5. 百度人脸识别:本项目已经接入了我的百度人脸库,如需要自己创建,前往百度控制中心申请覆盖application的配置

项目开发

  1. 后端基于erupt框架
  2. 后端管理页面也基于erupt框架自动生成,开发请前往erupt官网阅读文档
  3. 客户端基于uniapp开发,源码打包发布在项目的release里面,将项目导入hbuilder即可直接点击运行,打包后将产物覆盖front文件夹即可

一 、项目背景及需求分析

docker-compose一键部署(仅需下载docker-compose文件夹运行即可)

用户在可靠验证下实现简化身份确认

在已有用户数据库基础上
传统校验方式:

  1. 直接选择 ==》 用户 【不安全/不可靠】
  2. 用户名 + 密码 查询数据库 ==》 用户 【麻烦/】

新型校验方式

  1. 第三方工具、qq/微信扫码 ==》 用户 【没手机时麻烦/不稳定】
  2. 生物特征人脸/指纹识别 ==》 用户 【方便/可靠】

因此基于各家人脸识别框架,选用百度作为接口,围绕其开发此系统;
动画.gif
image.png

image.png

image.png

image.png

image.png

二、技术栈

这是一个前后端兼备的前后台分离全栈项目

  • 前台上,PC端选择用主流Vue框架[另一位同学完成]、后台管理采用Erupt框架搭建、web显示采用百度Amis框架及bootstrap完成

  • 后端选用主流的Java SpringBoot搭建,使用Schedule完成动态定时任务,使用AOP拦截消息通过pushPlus进行微信推送。

  • 其他技术,后台管理依靠框架Erupt进行的快速构建,使用swagger集成api文档。采用百度云人脸识别接口基于百度人脸识别SDK完成本地数据库与云人脸库的对接。

  • 此外,为了保障访问的稳定及速率,采用redis对首页常用信息进行缓存,减少了对数据库的查询;采用视图构建表间关系,减少后台对数据库的连表查询,加速响应时间。

三、模块介绍

【name404.study.face】文件结构
│  FaceApplication.java
│
├─aop                自定义注解实现标记切割
│      LogAspect.java
│      WxPush.java
│
├─common             公共包、存放公共文件 
├─config             配置包
│      CompleteScheduleConfig.java
│      RedisConfig.java
│      Swagger2.java
│
├─controllers        控制层
│      FaceController.java
│      RouteController.java
│      SignInController.java
│      UserContorller.java
│      VisitorContorller.java
│
├─dao                Dao层
│      GroupDao.java
│      SignLogDao.java
│      SignLogDetailDao.java
│      SystemVariablesDao.java
│      UserDao.java
│      UserDetailDao.java
│
├─entity              数据层
│      Group.java
│      SignLog.java
│      SignLogDetail.java
│      SystemVariables.java
│      User.java
│      UserDetail.java
│
├─handler              handler层
│      FetchHandlerImpl.java
│      GlobalExceptionHandler.java
│
├─service              接口层  
│  │  BaiduFaceService.java
│  │  GroupService.java
│  │  SignLogService.java
│  │  SystemVariablesService.java
│  │  UserService.java
│  │  VisitorService.java
│  │
│  └─impl              接口实现层  
│          BaiduFaceServiceImpl.java
│          GroupServiceImpl.java
│          SignLogServiceImpl.java
│          SystemVariablesServiceImpl.java
│          UserServiceImpl.java
│          VisitorServiceImpl.java
│
└─utils              工具包
        Base64Utils.java
        OkHttpClientUtil.java
        RedisUtil.java
        Result.java

image.png

数据库模块

基础四个表:用户表、用户组别二级表、签到日志、系统变量(用户反馈可有可无)

image.png

视图部分:使用userDetail + signLogDetail减少后台对数据库的连表查询

数据库字段中存在大量引用[存在user_group二级分类菜单中],直接返回的内容不方便使用,使用时连表查询,多次太费空间,因此基于视图一次性创建好引用,方便后台直接调用,加速后台响应

SELECT
	`sign_log`.`id` AS `id`,
	`sign_log`.`user_name` AS `user_name`,
	`sign_log`.`in_time` AS `in_time`,
	`sign_log`.`out_time` AS `out_time`,
	`sign_log`.`msg` AS `msg`,
	`sign_log`.`date` AS `date`,
	`a`.`name` AS `user_group`,
	`d`.`name` AS `to_do`,
	`b`.`name` AS `class_group`,
	`c`.`name` AS `unit_group`,
	`sign_log`.`sign_time` AS `sign_time` 
FROM
	((((
					`sign_log`
					LEFT JOIN `user_group` `a` ON ((
							`sign_log`.`user_group` = `a`.`id` 
						)))
				LEFT JOIN `user_group` `b` ON ((
						`sign_log`.`class_group` = `b`.`id` 
					)))
			LEFT JOIN `user_group` `c` ON ((
					`sign_log`.`unit_group` = `c`.`id` 
				)))
		LEFT JOIN `user_group` `d` ON ((
			`sign_log`.`to_do` = `d`.`id` 
	)))

image.pngimage.png

1. 用户模块

[UserService][UserDao]

用户基础服务 [Dao层接口定义]

数据库设计

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `real_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0',
  `face_id` int(11) NULL DEFAULT NULL,
  `user_group` int(11) NULL DEFAULT 5,
  `now_sign_id` int(11) NULL DEFAULT NULL,
  `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `telphone` int(11) NULL DEFAULT NULL,
  `expired_time` datetime NULL DEFAULT NULL,
  `sign_state` bit(1) NULL DEFAULT b'0',
  `class_group` bigint(20) NULL DEFAULT 0,
  `unit_group` bigint(20) NULL DEFAULT 0,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `FK5ixd8ou7x5sln7b00u8qpf7il`(`group_id`) USING BTREE,
  CONSTRAINT `FK5ixd8ou7x5sln7b00u8qpf7il` FOREIGN KEY (`group_id`) REFERENCES `user_group` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;

模块效果
image.png
模块流程
image.png

2. 系统变量模块

[SystemVariablesService][SystemVariablesDao]

系统变量服务 [map存储复杂的系统变量] [通过key获取value的json] [通过对json修改实现变量增删改查] [简化数据库,方便统一处理常量]

数据库设计

-- ----------------------------
-- Table structure for system_variables
-- ----------------------------
DROP TABLE IF EXISTS `system_variables`;
CREATE TABLE `system_variables`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `my_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `my_value` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;

模块流程
image.png
模块效果
image.png

3. 签到日志模块

[SignLogService][SignLogDao]

签到日志服务 [基本增删改查] [签到逻辑处理] [Dao层接口]

数据库设计

-- ----------------------------
-- Table structure for sign_log
-- ----------------------------
DROP TABLE IF EXISTS `sign_log`;
CREATE TABLE `sign_log`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `in_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `msg` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `out_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `sign_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `to_do` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `user_group` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `date` datetime NULL DEFAULT NULL,
  `from_user_id` bigint(20) NULL DEFAULT NULL,
  `user_class` bit(1) NULL DEFAULT NULL,
  `class_group` bigint(20) NULL DEFAULT NULL,
  `unit_group` bigint(20) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 90 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;

模块流程
image.png

模块效果
image.png

4. 人脸识别模块+反馈模块

[BaiduFaceService]
模块流程
image.png

模块效果

人脸识别服务 [人脸库的增删改查] [人脸库对接本地数据库]

5. 二级菜单模块

[GroupService]

对于一些杂乱的内容设置二级分类方便统一管理

数据库设计

-- ----------------------------
-- Table structure for user_group
-- ----------------------------
DROP TABLE IF EXISTS `user_group`;
CREATE TABLE `user_group`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `group_class` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `message` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;

模块流程
image.png

模块效果
image.png

待开发模块

指纹识别 + 游客模块

四、技术点介绍

1. 百度云人脸识别接入当前系统

注册百度云获取AppId ,API KEY Secret key作为密钥

image.png

下载SDK对接用户数据库 SDK和API区别 API:直接面向接口提交http请求 SDK:基于JAVA/PYTHON等语言集成一门API的通用函数库,方便直接调用对接

image.png

引入jar包,初始化client,开始使用

ConfigurationProperties(prefix = "baidu")
public class BaiduFaceServiceImpl implements BaiduFaceService {
    private String app_id;
    private String api_key;
    private String secret_key;
    private  AipFace client = null;

    void initClient(){
        if(client == null){
            System.out.println("初始化百度sdk");
            client = new AipFace(app_id, api_key, secret_key);
        }
    }
    
    ...
}

2. 可动态修改的定时任务

怎么启动

创建配置类

@Configuration @EnableScheduling public class CompleteScheduleConfig implements SchedulingConfigurer

怎么动态:在执行定时任务下一次获取时间不是通过本地查询,而是通过数据库查询后后台拼接形成新的下一次时间

@Configuration
@EnableScheduling
public class CompleteScheduleConfig implements SchedulingConfigurer {

    @Autowired
    private SystemVariablesService systemVariablesService;
    @Autowired
    private SignLogService signLogService;
    /**
     * 执行定时任务.
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(
                //1.添加任务内容(Runnable)
                () -> {
                    try {
                        //调用签到模块的定时执行任务
                        signLogService.scheduleTask();
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                },
                //2.设置执行周期(Trigger)
                triggerContext -> {
                    //2.1 从数据库获取执行周期
                    String time = systemVariablesService.getKey(SystemVariablesService.getEndTime);
                    String[] HMS = time.split(":");
                    String cron = HMS[2] + " " + HMS[1] +" " + HMS[0] +" * * ?";
                    System.out.println("【下一次执行时间】" + cron);
                    //2.2 合法性校验.
                    //2.3 返回执行周期(Date)
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
    }

}

3. AOP切自定义注解实现微信推送

导入AOP相关的包

创建注解作为标记点

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;//表示运行时开启@Retention(RetentionPolicy.RUNTIME)//表示定义在方法上@Target(ElementType.METHOD)public @interface WxPush {}

创建APO层去切割WxPush方法 微信推送:使用pushplus提供的接口直接通过http请求发送

  1. 获取自己微信token
  2. 使用pushplus提供的接口
  3. 通过http工具请求推送
@Aspect@Componentpublic class LogAspect {    @Autowired    private SystemVariablesService systemVariablesService;    @Autowired    private SignLogService signLogService;    @Autowired    private OkHttpClientUtil okHttpClientUtil;    /**     * 注解切入点     */    @Pointcut("@annotation(name404.study.face.aop.WxPush)")    public void pointCut(){    }	    @AfterReturning(value = "pointCut()",returning = "result")    public void wxPush(Object result){        Result res = (Result)result;        //是成功的返回类型        if(res.getStatus() == 200){            // 根据返回结果进行微信推送            String title ="【每日打卡消息】  当前:" +toDayMsg.get("nowUser") + "人";            String content = (String)res.getData();            content += "<br/><br/>";            String startTime =systemVariablesService.getKey(SystemVariablesService.getStartTime);            String endTime = systemVariablesService.getKey(SystemVariablesService.getEndTime);            content += "[今日打卡时间段] " + startTime + "-" + endTime + "<br/><br/>";            content += "[今日总打卡数] " +  toDayMsg.get("allUser") + "<br/>";            content += "[今日当前人数] " + toDayMsg.get("nowUser") + "<br/>";            content += "[今日签退人数] " + toDayMsg.get("leaveUser") + "<br/>";            String url = "http://pushplus.hxtrip.com/send?token="+token+"&title="+title+"&content="+content+"&template=html&topic="+groupId;            okHttpClientUtil.getData(url);        }    }}

使用:直接在方法前加上@WxPush即可切割拦截进行结果集的推送了

4. 采用redis缓存首页信息优化访问速度

导入包导入工具类,创建bean引入配置

<!-- redis --><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency>

当作map直接使用提供好的工具包

image.png

类比mysql数据库 100 访问同一个页面获取100跳信息,要查询100次 100数据的数据库库,数据库承受1w次查询 用redis 第一次查数据库 后面只要信息不变全部查缓存 ,数据库只承受100次查询

原理:
查:在查询数据库之前判断redisUtil里面存了首页信息没,有就直接返回
增:没有数据就查询数据库得到的信息存redis
改:每次数据库修改就清空redis缓存,下次查询就继续执行上面操作

5. 采用swagger集成api统一访问管理

前后台分离 多人合作:jsp不可行,要采用前后台分离 SSM:前台的数据一定要有后台先提供,导致开发工期延长 前后端分离:通过简单的数据包装,确保了视图和控制器的分离。只负责分发数据,谁拿不管。可以前后台同时进行,最后对接

统一的数据管理平台 ==》 swagger ==》 方便前台用户阅读 使用

引入jar包

<!-- swagger --><dependency>    <groupId>io.springfox</groupId>    <artifactId>springfox-swagger-ui</artifactId>    <version>2.9.2</version></dependency><dependency>    <groupId>io.springfox</groupId>    <artifactId>springfox-swagger2</artifactId>    <version>2.9.2</version></dependency>

配置config 配置扫描包指定扫描那些controller

@Configuration@EnableSwagger2//是否开启swagger,正式环境一般是需要关闭的(避免不必要的漏洞暴露!),可根据springboot的多环境配置进行设置@ConditionalOnProperty(name = "swagger.enable",  havingValue = "true")public class Swagger2 {     // swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等     @Bean     public Docket createRestApi() {          return new Docket(DocumentationType.SWAGGER_2)                   .apiInfo(apiInfo())                   .select()                   // 为当前包路径                   .apis(RequestHandlerSelectors.basePackage("name404.study.face.controllers")).paths(PathSelectors.any())                   .build();     }     // 构建 api文档的详细信息函数,注意这里的注解引用的是哪个     private ApiInfo apiInfo() {          return new ApiInfoBuilder()                   // 页面标题                   .title("Spring Boot 测试使用 Swagger2 构建RESTful API")                   // 创建人信息                   .contact(new Contact("404name",  "yuque.com/404name",  "1308964967@qq.com"))                   // 版本号                   .version("1.0")                   // 描述                   .description("API 描述")                   .build();     }

image.png

五、 不足及后续开发计划

已完成基础框架,后台框架,swagger集成api 待开发如下。

访客的接入

  • 访客基础服务[增删改查]
  • 访客对接进基础签到服务
  • 访客的导入

人脸识别模块

  • 人脸识别基础服务[增删改查]
  • 人脸识别的批量导入[难实现,需要格外写算法处理]

业务需求处理

  • 动态增添单位、课题组、事由
  • 事由的固定处理[实验默认3小时,其他超过30分钟处理为xxx,未达0.5小时按0.5记录]
  • 常见权限失效时间[直接在用户字段设置freeTime]
  • 可修改默认失效时间[在系统变量里面添加默认实现时间]

细节处理

  • 用户登录后提醒权限录入
  • 其他

指纹识别接入

  • 未开发

About

基于springboot + jpa + Erupt后台框架开发的综合签到打卡系统,支持人脸识别(百度云),指纹识别(本地指纹仪+websocket),签到数据展示,签到情况微信推送;支持docker-compose一键部署

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published