ソースを参照

create project.

deason 1 年間 前
コミット
39728d700a

+ 18 - 0
install/config.ini

@@ -0,0 +1,18 @@
+[app]
+name=¹ã¿ª±¨ÃûԤԼϵͳ
+version=1.0.0
+portal=http://localhost:8800/
+module=api
+depend=mysql,nginx
+
+[mysql]
+db=exam_reserve_db
+before=init.sql
+after=
+
+[upgrade]
+minmum_version=
+
+[api]
+port=8080
+exec=%QMTH_HOME%\common\jdk\bin\java -Xms8g -Xmx8g -Dqmth.home=%QMTH_HOME% -jar exam-reserve.jar

+ 179 - 0
install/mysql/init/exam_reserve_db.sql

@@ -0,0 +1,179 @@
+create table gk_user
+(
+    id          bigint      not null auto_increment,
+    create_time bigint      not null comment '创建时间',
+    update_time bigint      not null comment '更新时间',
+    enable      bit(1)      not null comment '是否启用',
+    role        varchar(20) not null comment '角色类型:学校管理员;教学点管理员',
+    name        varchar(50) not null comment '姓名',
+    login_name  varchar(50) not null comment '登录名',
+    password    varchar(32) not null comment '密码',
+    mobile      varchar(20) comment '联系方式',
+    category_id bigint comment '所属教学点ID,角色为教学点管理员,必填',
+    org_id      bigint comment '所属租户机构ID(预留字段)',
+    PRIMARY KEY (id)
+) comment '用户表';
+
+
+create table gk_student
+(
+    id              bigint      not null auto_increment,
+    create_time     bigint      not null comment '创建时间',
+    update_time     bigint      not null comment '更新时间',
+    name            varchar(50) not null comment '考生姓名',
+    identity_number varchar(20) not null comment '证件号',
+    student_code    varchar(20) not null comment '学号',
+    photo_path      varchar(100) comment '头像相对路径',
+    gender          varchar(10) comment '性别',
+    open_id         varchar(50) comment '微信OID',
+    uid             varchar(50) comment '微信UID',
+    apply_task_id   bigint      not null comment '所属预约任务ID',
+    category_id     bigint      not null comment '所属教学点ID',
+    apply_number    int         not null comment '允许预约时段数量',
+    apply_finished  bit(1)      not null comment '预约时段是否全部完成',
+    org_id          bigint comment '所属租户机构ID(预留字段)',
+    PRIMARY KEY (id)
+) comment '考生表';
+
+
+create table gk_category
+(
+    id          bigint      not null auto_increment,
+    create_time bigint      not null comment '创建时间',
+    update_time bigint      not null comment '更新时间',
+    enable      bit(1)      not null comment '是否启用',
+    parent_id   bigint      not null default 0 comment '父级ID,顶级值为0',
+    code        varchar(20) not null comment '分类代码',
+    name        varchar(50) not null comment '分类名称',
+    level       int         not null comment '层级,第一级值为1',
+    capacity    int         null     default 0 comment '容量',
+    PRIMARY KEY (id)
+) comment '数据分类表';
+
+
+create table gk_exam_site
+(
+    id          bigint       not null auto_increment,
+    create_time bigint       not null comment '创建时间',
+    update_time bigint       not null comment '更新时间',
+    enable      bit(1)       not null comment '是否启用',
+    code        varchar(20)  not null comment '考点代码',
+    name        varchar(100) not null comment '考点名称',
+    category_id bigint       not null comment '所属教学点ID',
+    capacity    int comment '机房容量',
+    address     varchar(200) comment '考点地址',
+    guide       longtext comment '考点指引',
+    PRIMARY KEY (id)
+) comment '考点表';
+
+
+create table gk_exam_room
+(
+    id           bigint       not null auto_increment,
+    create_time  bigint       not null comment '创建时间',
+    update_time  bigint       not null comment '更新时间',
+    enable       bit(1)       not null comment '是否启用',
+    code         varchar(20)  not null comment '考场代码',
+    name         varchar(100) not null comment '考场名称',
+    exam_site_id bigint       not null comment '所属考点ID',
+    address      varchar(200) comment '考场地址',
+    capacity     int comment '机房容量',
+    PRIMARY KEY (id)
+) comment '考场表';
+
+
+create table gk_apply_task
+(
+    id                      bigint      not null auto_increment,
+    create_time             bigint      not null comment '创建时间',
+    update_time             bigint      not null comment '更新时间',
+    enable                  bit(1)      not null comment '是否启用',
+    name                    varchar(50) not null comment '任务名称',
+    allow_apply_days        int         not null comment '考前多少天,禁止考生自主预约',
+    allow_apply_cancel_days int         not null comment '考前多少天,禁止考生自主取消预约',
+    self_apply_start_time   bigint      not null comment '自主预约起始时间,只能预约本教学点下的考点',
+    self_apply_end_time     bigint      not null comment '自主预约截止时间,只能预约本教学点下的考点',
+    open_apply_start_time   bigint      not null comment '开放式预约起始时间,可以在不同教学点间预约',
+    open_apply_end_time     bigint      not null comment '开放式预约截止时间,可以在不同教学点间预约',
+    notice                  longtext comment '考试说明',
+    PRIMARY KEY (id)
+) comment '预约任务表';
+
+
+create table gk_time_period
+(
+    id            bigint not null auto_increment,
+    create_time   bigint not null comment '创建时间',
+    update_time   bigint not null comment '更新时间',
+    apply_task_id bigint not null comment '所属预约任务ID',
+    start_time    bigint not null comment '预约起始时间',
+    end_time      bigint not null comment '预约截止时间',
+    PRIMARY KEY (id)
+) comment '预约任务的时段表';
+
+
+create table gk_student_apply
+(
+    id             bigint      not null auto_increment,
+    create_time    bigint      not null comment '创建时间',
+    update_time    bigint      not null comment '更新时间',
+    student_id     bigint      not null comment '考生ID',
+    exam_site_id   bigint      not null comment '预约的考点ID',
+    exam_room_id   bigint      not null comment '预约的考场ID',
+    time_period_id varchar(50) not null comment '预约时段ID',
+    cancel         bit(1)      not null comment '是否取消预约',
+    ticketNumber   varchar(50) comment '准考证号',
+    seatNumber     varchar(20) comment '座位号',
+    PRIMARY KEY (id)
+) comment '考生预约记录表';
+
+
+create table gk_student_import_task
+(
+    id          bigint       not null auto_increment,
+    create_time bigint       not null comment '创建时间',
+    update_time bigint       not null comment '更新时间',
+    operate_id  bigint       not null comment '操作人ID',
+    type        varchar(20)  not null comment '导入类型',
+    status      varchar(20)  not null comment '执行状态',
+    file_path   varchar(200) not null comment '导入文件相对路径',
+    message     text comment '执行结果信息',
+    PRIMARY KEY (id)
+) comment '考生导入任务表';
+
+
+create table gk_operate_log
+(
+    id          bigint      not null auto_increment,
+    create_time bigint      not null comment '创建时间',
+    update_time bigint      not null comment '更新时间',
+    operate_id  bigint      not null comment '操作人ID',
+    event_type  varchar(20) not null comment '事件类型,如:考生取消预约、用户登录等',
+    content     text comment '操作内容(JSON)',
+    PRIMARY KEY (id)
+) comment '操作日志表';
+
+
+create table gk_system_property
+(
+    id          bigint       not null auto_increment,
+    create_time bigint       not null comment '创建时间',
+    update_time bigint       not null comment '更新时间',
+    `key`       varchar(50)  not null comment '属性键',
+    value       varchar(500) not null comment '属性值',
+    PRIMARY KEY (id)
+) comment '系统属性表';
+
+
+
+insert into gk_system_property(`key`, value, create_time, update_time)
+values ('ORG_TITLE', '广东开发大学', now(), now());
+
+insert into gk_system_property(`key`, value, create_time, update_time)
+values ('CATEGORY_LEVEL', '[{"level":1,"title":"城市"},{"level":2,"title":"教学点"}]', now(), now());
+
+insert into gk_user (role, name, login_name, password, mobile, category_id, org_id, enable, create_time, update_time)
+values ('ADMIN', '学校管理员', 'admin', UPPER(SHA2('123456', 256)), null, null, 1, 1, now(), now());
+
+
+

+ 5 - 0
install/mysql/init/init.sql

@@ -0,0 +1,5 @@
+CREATE DATABASE IF NOT EXISTS exam_reserve_db default character set utf8mb4 collate utf8mb4_general_ci;
+
+GRANT ALL PRIVILEGES ON `exam_reserve_db`.* TO 'exam_reserve'@'%' IDENTIFIED BY 'exam_reserve';
+
+FLUSH PRIVILEGES;

+ 1 - 0
install/mysql/upgrade/ignore

@@ -0,0 +1 @@
+...

+ 27 - 0
install/nginx/exam_reserve.conf

@@ -0,0 +1,27 @@
+
+upstream exam-reserve {
+	server 127.0.0.1:8080;
+	keepalive 100;
+}
+
+server {
+        listen 8800;
+ 
+		location / {
+            root   ../../exam-reserve/web;
+            try_files  $uri  $uri/  /index.html;
+        }
+ 
+        location /file/ {
+                alias ../../exam-reserve/static/;
+                add_header Access-Control-Allow-Origin *;
+        }
+ 
+        location ^~ /api/ {
+                proxy_pass http://exam-reserve;
+                proxy_set_header Host   $http_host;
+                proxy_set_header X-Real-IP $remote_addr;
+                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        }
+
+}

+ 12 - 0
jenkins.sh

@@ -0,0 +1,12 @@
+#!/bin/bash
+pwd
+
+cp target/exam-reserve.jar ~/project/exam-reserve
+BUILD_ID=DONTKILLME
+
+cd ~/project/exam-reserve
+bash ./stop.sh
+
+sleep 5s
+bash ./start.sh
+echo "finished..."

+ 198 - 0
pom.xml

@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.qmth</groupId>
+    <artifactId>exam-reserve</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.12.RELEASE</version>
+        <relativePath/>
+    </parent>
+
+    <properties>
+        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
+        <mybatis-plus.version>3.4.3.3</mybatis-plus.version>
+        <maven-compiler-version>3.8.1</maven-compiler-version>
+        <maven-surefire-version>2.22.2</maven-surefire-version>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <qmth-boot-version>1.0.4</qmth-boot-version>
+    </properties>
+
+    <repositories>
+        <repository>
+            <id>nexus</id>
+            <name>nexus</name>
+            <url>http://192.168.10.201:8081/repository/maven-public/</url>
+        </repository>
+    </repositories>
+    <pluginRepositories>
+        <pluginRepository>
+            <id>nexus</id>
+            <name>nexus</name>
+            <url>http://192.168.10.201:8081/repository/maven-public/</url>
+        </pluginRepository>
+    </pluginRepositories>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-security</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>starter-api</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>data-mybatis-plus</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-schedule</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.jeffreyning</groupId>
+            <artifactId>mybatisplus-plus</artifactId>
+            <version>1.5.1-RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-solar</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-fss</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-cache</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-retrofit</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-concurrent</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>tools-poi</artifactId>
+            <version>${qmth-boot-version}</version>
+        </dependency>
+
+        <!-- Swagger jars start -->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.24</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.5.24</version>
+        </dependency>
+        <!-- Swagger jars end -->
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.83</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.4</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+            <version>1.10.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-math3</artifactId>
+            <version>3.6.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <testFailureIgnore>true</testFailureIgnore>
+                    <skipTests>true</skipTests>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 1 - 0
shell/start.args

@@ -0,0 +1 @@
+--spring.profiles.active=dev

+ 24 - 0
shell/start.sh

@@ -0,0 +1,24 @@
+#!/bin/bash
+
+FILE_PATH=$(cd `dirname $0`; pwd)
+
+APP_MAIN_JAR="exam-reserve.jar"
+
+JAVA_OPTS=`cat $FILE_PATH/start.vmoptions`
+APP_ARGS=`cat $FILE_PATH/start.args`
+
+PID_LIST=`ps -ef|grep $APP_MAIN_JAR|grep java|awk '{print $2}'`
+if [ ! -z "$PID_LIST" ]; then
+    echo "[ERROR] : APP is already running!"
+    exit -1
+fi
+
+echo "java options:"
+echo "$JAVA_OPTS"
+echo "args:"
+echo "$APP_ARGS"
+    
+nohup java $JAVA_OPTS -jar $FILE_PATH/$APP_MAIN_JAR $APP_ARGS >/dev/null 2>&1 &
+
+echo "starting......"
+exit 0

+ 1 - 0
shell/start.vmoptions

@@ -0,0 +1 @@
+-server -Xms256m -Xmx256m -XX:-UseGCOverheadLimit -Dlog.commonLevel=INFO

+ 17 - 0
shell/stop.sh

@@ -0,0 +1,17 @@
+#!/bin/bash
+FILE_PATH=$(cd `dirname $0`; pwd)
+
+APP_MAIN_JAR="exam-reserve.jar"
+
+PID_LIST=`ps -ef|grep $APP_MAIN_JAR|grep java|awk '{print $2}'`
+
+if [ ! -z "$PID_LIST" ]; then
+    echo "Runnable jar is $APP_MAIN_JAR."
+    for PID in $PID_LIST 
+    do
+        kill -9 $PID
+    done
+    echo "stopped !"
+fi
+
+exit 0

+ 23 - 0
src/main/java/com/qmth/exam/reserve/ApiApplication.java

@@ -0,0 +1,23 @@
+package com.qmth.exam.reserve;
+
+import com.github.jeffreyning.mybatisplus.conf.EnableMPP;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@EnableMPP
+@EnableAsync
+@EnableScheduling
+@Configuration
+@SpringBootApplication
+@MapperScan("com.qmth.exam.reserve.dao")
+public class ApiApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(ApiApplication.class, args);
+    }
+
+}

+ 22 - 0
src/main/java/com/qmth/exam/reserve/config/AsyncConfig.java

@@ -0,0 +1,22 @@
+package com.qmth.exam.reserve.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.AsyncTaskExecutor;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+@Configuration
+@EnableAsync
+public class AsyncConfig {
+
+    @Bean("task-executor")
+    public AsyncTaskExecutor taskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setBeanName("task-executor");
+        executor.setMaxPoolSize(5);
+        executor.setCorePoolSize(5);
+        return executor;
+    }
+
+}

+ 23 - 0
src/main/java/com/qmth/exam/reserve/config/FillMetaObjectHandler.java

@@ -0,0 +1,23 @@
+package com.qmth.exam.reserve.config;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+
+public class FillMetaObjectHandler implements MetaObjectHandler {
+
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        if (this.getFieldValByName("createTime", metaObject) == null) {
+            this.setFieldValByName("createTime", System.currentTimeMillis(), metaObject);
+        }
+        if (this.getFieldValByName("updateTime", metaObject) == null) {
+            this.setFieldValByName("updateTime", System.currentTimeMillis(), metaObject);
+        }
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        this.setFieldValByName("updateTime", System.currentTimeMillis(), metaObject);
+    }
+
+}

+ 15 - 0
src/main/java/com/qmth/exam/reserve/config/MyBatisPlusConfig.java

@@ -0,0 +1,15 @@
+package com.qmth.exam.reserve.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MyBatisPlusConfig {
+
+
+    @Bean
+    public FillMetaObjectHandler metaObjectHandler() {
+        return new FillMetaObjectHandler();
+    }
+
+}

+ 54 - 0
src/main/java/com/qmth/exam/reserve/config/SwaggerConfig.java

@@ -0,0 +1,54 @@
+package com.qmth.exam.reserve.config;
+
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@EnableSwagger2WebMvc
+@Configuration
+public class SwaggerConfig {
+
+    private static final Logger log = LoggerFactory.getLogger(SwaggerConfig.class);
+
+    @Bean
+    public Docket buildDocket() {
+        log.info("swagger init...");
+
+        List<Parameter> parameters = new ArrayList<>();
+        parameters.add(new ParameterBuilder().name("Authorization").modelRef(new ModelRef("String")).parameterType("header").required(false).build());
+        parameters.add(new ParameterBuilder().name("time").modelRef(new ModelRef("String")).parameterType("header").required(false).build());
+
+        return new Docket(DocumentationType.SWAGGER_2)
+                .groupName("default")
+                .apiInfo(buildApiInfo())
+                .globalOperationParameters(parameters)
+                .useDefaultResponseMessages(false)
+                .select()
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    public ApiInfo buildApiInfo() {
+        return new ApiInfoBuilder()
+                .title("接口文档")
+                .version("v1.0.0")
+                .build();
+    }
+
+}

+ 67 - 0
src/main/java/com/qmth/exam/reserve/controller/BaseController.java

@@ -0,0 +1,67 @@
+package com.qmth.exam.reserve.controller;
+
+import com.qmth.boot.core.exception.StatusException;
+import com.qmth.boot.tools.io.IOUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.util.Objects;
+
+public class BaseController {
+
+    protected HttpServletRequest currentRequest() {
+        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
+                .getRequest();
+    }
+
+    protected HttpServletResponse currentResponse() {
+        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
+                .getResponse();
+    }
+
+    protected void exportFile(String fileName, File file) {
+        OutputStream out = null;
+        InputStream in = null;
+        try {
+            in = new FileInputStream(file);
+            fileName = URLEncoder.encode(fileName, "UTF-8");
+            HttpServletResponse response = currentResponse();
+            response.reset();
+            response.setHeader("Content-Disposition", "inline; filename=" + fileName);
+            response.addHeader("Content-Length", "" + file.length());
+            response.setContentType("application/octet-stream;charset=UTF-8");
+            out = new BufferedOutputStream(response.getOutputStream());
+            IOUtils.copy(in, out);
+            out.flush();
+        } catch (IOException e) {
+            throw new StatusException(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(out);
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+    protected void exportFile(String fileName, InputStream in) {
+        OutputStream out = null;
+        try {
+            fileName = URLEncoder.encode(fileName, "UTF-8");
+            HttpServletResponse response = currentResponse();
+            response.reset();
+            response.setHeader("Content-Disposition", "inline; filename=" + fileName);
+            response.setContentType("application/octet-stream;charset=UTF-8");
+            out = new BufferedOutputStream(response.getOutputStream());
+            IOUtils.copy(in, out);
+            out.flush();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            IOUtils.closeQuietly(out);
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+}

+ 20 - 0
src/main/java/com/qmth/exam/reserve/controller/UserController.java

@@ -0,0 +1,20 @@
+package com.qmth.exam.reserve.controller;
+
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.exam.reserve.service.UserService;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@Api(tags = "用户相关接口")
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/user")
+@Aac(strict = false, auth = true)
+public class UserController extends BaseController {
+
+    @Autowired
+    private UserService userService;
+
+}

+ 8 - 0
src/main/java/com/qmth/exam/reserve/dao/UserDao.java

@@ -0,0 +1,8 @@
+package com.qmth.exam.reserve.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.exam.reserve.entity.UserEntity;
+
+public interface UserDao extends BaseMapper<UserEntity> {
+
+}

+ 56 - 0
src/main/java/com/qmth/exam/reserve/entity/UserEntity.java

@@ -0,0 +1,56 @@
+package com.qmth.exam.reserve.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.qmth.exam.reserve.entity.base.BaseEntity;
+import com.qmth.exam.reserve.enums.Role;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@TableName("gk_user")
+public class UserEntity extends BaseEntity {
+
+    private static final long serialVersionUID = 6770398649449396459L;
+
+    /**
+     * 角色类型
+     */
+    private Role role;
+
+    /**
+     * 姓名
+     */
+    private String name;
+
+    /**
+     * 登录名
+     */
+    private String loginName;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 联系方式
+     */
+    private String mobile;
+
+    /**
+     * 所属教学点ID,角色为教学点管理员,必填
+     */
+    private Long categoryId;
+
+    /**
+     * 所属租户机构ID(预留字段)
+     */
+    private Long orgId;
+
+    /**
+     * 是否启用
+     */
+    private Boolean enable;
+
+}

+ 56 - 0
src/main/java/com/qmth/exam/reserve/entity/base/BaseEntity.java

@@ -0,0 +1,56 @@
+package com.qmth.exam.reserve.entity.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+/**
+ * 实体类基类
+ */
+public abstract class BaseEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    protected Long id;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    protected Long createTime;
+
+    /**
+     * 修改时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    protected Long updateTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+
+    public Long getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Long updateTime) {
+        this.updateTime = updateTime;
+    }
+
+}

+ 31 - 0
src/main/java/com/qmth/exam/reserve/enums/Role.java

@@ -0,0 +1,31 @@
+package com.qmth.exam.reserve.enums;
+
+public enum Role {
+
+    SYSTEM("系统"),
+
+    ADMIN("学校管理员"),
+
+    TEACHING("教学点管理员");
+
+    private String title;
+
+    Role(String title) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+
+    public static Role getByTitle(String title) {
+        for (Role r : Role.values()) {
+            if (r.getTitle().equals(title)) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+}

+ 8 - 0
src/main/java/com/qmth/exam/reserve/service/UserService.java

@@ -0,0 +1,8 @@
+package com.qmth.exam.reserve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.exam.reserve.entity.UserEntity;
+
+public interface UserService extends IService<UserEntity> {
+
+}

+ 16 - 0
src/main/java/com/qmth/exam/reserve/service/impl/UserServiceImpl.java

@@ -0,0 +1,16 @@
+package com.qmth.exam.reserve.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.exam.reserve.dao.UserDao;
+import com.qmth.exam.reserve.entity.UserEntity;
+import com.qmth.exam.reserve.service.UserService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
+
+    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
+
+}

+ 42 - 0
src/main/resources/application.properties

@@ -0,0 +1,42 @@
+#
+# ********** server config **********
+#
+server.port=8080
+server.servlet.context-path=/
+server.servlet.session.timeout=PT2H
+spring.servlet.multipart.max-request-size=100MB
+spring.servlet.multipart.max-file-size=100MB
+spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
+spring.jackson.time-zone=GMT+8
+server.tomcat.threads.max=600
+server.tomcat.max-connections=20000
+server.tomcat.connection-timeout=90000
+#
+# ********** db config **********
+#
+db.host=192.168.10.30
+db.port=3306
+db.database=exam_reserve_db
+com.qmth.datasource.username=exam_reserve_dev
+com.qmth.datasource.password=exam_reserve_dev
+com.qmth.datasource.url=jdbc:mysql://${db.host}:${db.port}/${db.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2b8&rewriteBatchedStatements=true
+com.qmth.datasource.max-pool-size=200
+com.qmth.datasource.min-idle=10
+#
+# ********** file config **********
+#
+com.qmth.fss.config=/home/admin/project/exam-reserve/static
+com.qmth.fss.server=/file
+#
+# ********** sys config **********
+#
+com.qmth.mybatis.block-attack=false
+com.qmth.mybatis.log-level=info
+com.qmth.logging.root-level=info
+com.qmth.logging.file-path=logs/exam-reserve.log
+#
+# ********** auth config **********
+#
+com.qmth.auth.time-max-delay=10m
+com.qmth.auth.time-max-ahead=10m
+

+ 5 - 0
src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qmth.exam.reserve.dao.UserDao">
+
+</mapper>

+ 16 - 0
src/test/java/com/qmth/exam/reserve/test/ServerTest.java

@@ -0,0 +1,16 @@
+package com.qmth.exam.reserve.test;
+
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@SpringBootTest
+@RunWith(SpringRunner.class)
+public class ServerTest {
+
+    // @Test
+    public void demo() throws Exception {
+
+    }
+
+}