I. Project background and demand analysis

The project address

Users implement simplified authentication under reliable authentication

Based on the existing user database

Traditional verification mode:

  1. Direct select == “user [unsafe/unreliable]
  2. User name + Password Query database ==

New check mode

  1. Third party tools, QQ/wechat scan code == users [trouble/instability without mobile phone]
  2. Biometric face/fingerprint recognition == user [convenient/reliable]

Therefore, based on various face recognition frameworks, baidu is selected as the interface to develop this system around it.

2. Technology stack

This is a full stack project with both front and back end separation

  • On the front desk, the mainstream Vue framework (completed by another student) was used for PC, Erupt framework was used for backstage management, And Baidu Amis framework and Bootstrap were used for web display
  • The back end adopts the mainstream Java SpringBoot to build, uses Schedule to complete dynamic timing tasks, and uses AOP to intercept messages and push wechat messages through pushPlus.
  • Other technologies, back-office management relies on rapid builds from the Framework Erupt, using Swagger to integrate API documentation. Using Baidu cloud face recognition interface based on Baidu face recognition SDK to complete the local database and cloud face library docking.
  • In addition, in order to ensure the stability and speed of access, redis is used to cache common information on the home page, reducing the query of the database; Using the view to build the relationship between the tables, reduce the background to the database table query, speed up the response time.

Iii. Module introduction

[name404.study.face] File structure │ FaceApplication. Java │ ├─ AOP custom annotations for tag Cutting │ logAsp.java │ WxPush ├ ─ config configuration package │ CompleteScheduleConfig. Java │ RedisConfig. Java │ Swagger2. Java │ ├ ─ controllers control layer │ FaceController. Java │ ├─ RouteController. │ ├─ RouteController. │ RouteController Java │ signLogDAo.java │ signLogDetailDao.java │ SystemVariablesDao.java │ userDAo.java │ userDetailDao.java │ GroupDao ├─ Entity Data layer │ ├─ Entity data layer │ ├─ Entity data layer │ ├─ Entity data layer │ Group ├ ─ handler handler layer │ FetchHandlerImpl. Java │ GlobalExceptionHandler. Java │ ├ ─ the service interface layer │ │ BaiduFaceService. Java │ │ GroupService. Java │ │ SignLogService. Java │ │ SystemVariablesService. Java │ │ UserService. Java │ │ VisitorService. Java │ │ │ │ └ ─ impl interface layer BaiduFaceServiceImpl. Java │ GroupServiceImpl. Java │ SignLogServiceImpl. Java │ SystemVariablesServiceImpl. Java │ UserServiceImpl. Java │ VisitorServiceImpl. Java │ └ ─ utils toolkit Base64Utils. Java OkHttpClientUtil.java RedisUtil.java Result.javaCopy the code

Database module

Basic four tables: user table, user group level 2 table, check-in log, system variables (user feedback is optional)

View part: use userDetail + signLogDetail to reduce the background query to the database

A large number of references exist in the database fields [in the user_Group level 2 classification menu], and the directly returned contents are inconvenient to use. Therefore, it takes too much space to query a table for multiple times. Therefore, create a reference based on the view at one time, which facilitates the direct invocation of the background and accelerates the background response

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` 
	)))
Copy the code

1. User module

[UserService][UserDao]

User-based services

[Dao Layer interface definition]

Database design

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;
Copy the code

Effect of module

Module process

2. System variable module

[SystemVariablesService][SystemVariablesDao]

System variable service

[Map stores complex system variables]

[Get json of value by key]

[Add, delete, change and check variables by modifying JSON]

[Simplified database, convenient unified processing constants]

Database design

-- ----------------------------
-- 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;
Copy the code

Module process

Effect of module

3. Log in to the log module

[SignLogService][SignLogDao]

Check-in log service

[Basic add, delete, change and check]

[Check-in logic processing]

[Dao Layer interface]

Database design

-- ----------------------------
-- 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;
Copy the code

Module process


Effect of module

4. Face recognition module + feedback module

[BaiduFaceService]

Module process


Effect of module

Face recognition service

[Add, delete, change and check face database]

[Face database docking local database]

5. Two-level menu module

[GroupService]

For some messy content set up secondary classification convenient unified management

Database design

-- ----------------------------
-- 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;
Copy the code

Module process


Effect of module

Module to be developed

Fingerprint recognition + tourist module

Four, technical point introduction

1. Baidu cloud face recognition access to the current system

Register baidu cloud to obtain AppId, API KEY Secret KEY as the KEY

Download the SDK to interconnect with the user database

SDK and API

API: Submit HTTP requests directly to the interface

SDK: A universal function library integrating an API based on JAVA/PYTHON languages, facilitating direct call and connection

Import the JAR package, initialize client, and start using it

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 (" initialize Baidu SDK "); client = new AipFace(app_id, api_key, secret_key); }}... }Copy the code

2. A scheduled task that can be dynamically modified

How to start

Creating a Configuration Class

@Configuration

@EnableScheduling

public class CompleteScheduleConfig implements SchedulingConfigurer

How to dynamically obtain the time of the next scheduled task? After the time of the next scheduled task is obtained not through local query but through database query, the background is combined to form a new time of the next scheduled task

@Configuration @EnableScheduling public class CompleteScheduleConfig implements SchedulingConfigurer { @Autowired private SystemVariablesService systemVariablesService; @Autowired private SignLogService signLogService; */ @override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.addTriggerTask( //1. Add tasks content (Runnable) () - > {try {/ / call sign in module timing mission signLogService. ScheduleTask (); } catch (ParseException e) { e.printStackTrace(); }}, TriggerContext -> {//2.1 Get the execution cycle from the database String time = systemVariablesService.getKey(SystemVariablesService.getEndTime); String[] HMS = time.split(":"); String cron = HMS[2] + " " + HMS[1] +" " + HMS[0] +" * * ?" ; System.out.println(" [next execution time] "+ cron); //2.3 Return execution period (Date) Return new CronTrigger(cron).nextexecutionTime (triggerContext); }); }}Copy the code

3. AOP cut custom annotations to achieve wechat push

Import aOP-related packages

Create annotations as marker points

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @target (ElementType.METHOD) public @interface WxPush {} @retention (retentionPolicy.runtime);Copy the code

Create an APO layer to cut the WxPush method

Wechat Push: Send directly via HTTP requests using the interface provided by PushPlus

  1. Get your own wechat token
  2. Use the interface provided by PushPlus
  1. Request push through the HTTP tool
@Aspect @Component public class LogAspect { @Autowired private SystemVariablesService systemVariablesService; @Autowired private SignLogService signLogService; @Autowired private OkHttpClientUtil okHttpClientUtil; / / the @pointcut annotation breakthrough point * * * * (" @ the 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){// If (res.getStatus() == 200){// If (res.getStatus() == 200){// If (res.getStatus() == 200){// If (res.getStatus() == 200){// If (res.getStatus() == 200){ String content = (String)res.getData(); content += "<br/><br/>"; String startTime =systemVariablesService.getKey(SystemVariablesService.getStartTime); String endTime = systemVariablesService.getKey(SystemVariablesService.getEndTime); Content + = "[clock time today]" + "-" + + startTime endTime + "< br / > < br / >"; Content + = "[today to the total number of clock]" + toDayMsg. Get (" allUser ") + "< br / >"; Content + = "[today's current number]" + toDayMsg. Get (" nowUser ") + "< br / >"; Content + = "[number] today sign back" + toDayMsg. Get (" leaveUser ") + "< br / >"; String url = "http://pushplus.hxtrip.com/send?token="+token+"&title="+title+"&content="+content+"&template=html&topic="+groupId; okHttpClientUtil.getData(url); }}}Copy the code

Use: simply prefacing method with @wxpush to cut interception to push result set

4. Redis is used to cache home page information to optimize access speed

The import package imports the utility class and creates the bean to import the configuration

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

Use the supplied toolkit directly as a map

Analogies to mysql databases

100 visit the same page to obtain 100 hop information, to query 100 times 100 data database library, the database bears 1W queries

Use Redis to check the database for the first time as long as the information does not change after all check the cache, the database only withstands 100 queries

Principle:

Check whether redisUtil contains the home page information before querying the database

P: Without data, the information obtained by querying the database is stored in Redis

Changed: The redis cache is cleared every time the database is changed, and the next query continues

5. Use Swagger integrated API for unified access management

Front and background separation

Multi-player collaboration: JSP is not feasible, use front and background separation

SSM: The data of the foreground must be provided by the background first, which will prolong the development period

Front and back end separation: Simple data packaging ensures separation of view and controller. Just distribute the data. Nobody takes it. The front and back can be carried out at the same time, and the final docking

Unified data management platform == “Swagger ==” convenient for foreground users to read and use

The introduction of the jar package

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

Configure the config

Configure the scan package to specify which controllers to scan

Configuration @enablesWagger2 // Whether to enable Swagger, formal environment generally need to be closed (avoid unnecessary vulnerability exposure!) . @conditionalonProperty (name = "swagger. Enable ", HavingValue = "true") public class Swagger2 {// Swagger2 Such as scanning bag and so on @ Bean public Docket createRestApi () {return new Docket (DocumentationType. SWAGGER_2). ApiInfo (apiInfo ()) .select() // indicates the current package path .apis(RequestHandlerSelectors.basePackage("name404.study.face.controllers")).paths(PathSelectors.any()) .build(); Private ApiInfo ApiInfo () {return new ApiInfoBuilder() // page title.title ("Spring Boot" Contact(new Contact("404name", "yuque.com/404name", "[email protected]")) // version number.version("1.0") // description.description ("API description ").build(); }Copy the code

V. Deficiencies and follow-up development plan

Basic framework, background framework and Swagger integration API have been completed

To be developed as follows.

Visitor access

  • ✅ Basic services for visitors [add, delete, change and check]
  • ✅ Visitors access basic check-in service
  • ✅ Import visitors

Face recognition module

  • ✅ face recognition basic services [add, delete, change and check]
  • 🔲 face recognition batch import [difficult to achieve, need to write algorithm processing]

Business requirement processing

  • ✅ dynamically add units, research groups and causes
  • 🔲 Fixed treatment of the cause [3 hours by default in the experiment, XXX will be treated for more than 30 minutes, and 0.5 will be recorded for less than 0.5 hours]
  • ✅ Common permission expiration time [directly set freeTime in user field]
  • 🔲 Can change the default expiration time [add the default implementation time in the system variable]

Detail processing

  • 🔲 Remind users to enter permission after login
  • 🔲 other

Fingerprint access

  • 🔲 undeveloped