xiatian 2 年之前
父節點
當前提交
c34a51f5c5
共有 53 個文件被更改,包括 3766 次插入0 次删除
  1. 136 0
      db/init.sql
  2. 24 0
      src/main/java/cn/com/qmth/mps/ApiApplication.java
  3. 27 0
      src/main/java/cn/com/qmth/mps/bean/TreeNode.java
  4. 115 0
      src/main/java/cn/com/qmth/mps/bean/User.java
  5. 35 0
      src/main/java/cn/com/qmth/mps/config/FillMetaObjectHandler.java
  6. 15 0
      src/main/java/cn/com/qmth/mps/config/MyBatisPlusConfig.java
  7. 27 0
      src/main/java/cn/com/qmth/mps/config/ScanWebMvcConfigurer.java
  8. 42 0
      src/main/java/cn/com/qmth/mps/config/SwaggerConfig.java
  9. 25 0
      src/main/java/cn/com/qmth/mps/config/SysProperty.java
  10. 41 0
      src/main/java/cn/com/qmth/mps/entity/CourseEntity.java
  11. 35 0
      src/main/java/cn/com/qmth/mps/entity/ExamEntity.java
  12. 110 0
      src/main/java/cn/com/qmth/mps/entity/PaperEntity.java
  13. 208 0
      src/main/java/cn/com/qmth/mps/entity/PrivilegeEntity.java
  14. 35 0
      src/main/java/cn/com/qmth/mps/entity/RolePrivilegeRelationEntity.java
  15. 62 0
      src/main/java/cn/com/qmth/mps/entity/SchoolEntity.java
  16. 84 0
      src/main/java/cn/com/qmth/mps/entity/UserEntity.java
  17. 42 0
      src/main/java/cn/com/qmth/mps/entity/base/AuditingEntity.java
  18. 42 0
      src/main/java/cn/com/qmth/mps/entity/base/AuditingWithoutIdEntity.java
  19. 43 0
      src/main/java/cn/com/qmth/mps/entity/base/BaseEntity.java
  20. 26 0
      src/main/java/cn/com/qmth/mps/entity/base/IdEntity.java
  21. 21 0
      src/main/java/cn/com/qmth/mps/enums/ExamStatus.java
  22. 64 0
      src/main/java/cn/com/qmth/mps/enums/HttpServletRequestAttribute.java
  23. 32 0
      src/main/java/cn/com/qmth/mps/enums/Role.java
  24. 110 0
      src/main/java/cn/com/qmth/mps/interceptor/FirstInterceptor.java
  25. 118 0
      src/main/java/cn/com/qmth/mps/support/ApiInfo.java
  26. 148 0
      src/main/java/cn/com/qmth/mps/support/ApiInfoHolder.java
  27. 29 0
      src/main/java/cn/com/qmth/mps/support/BaseResponse.java
  28. 254 0
      src/main/java/cn/com/qmth/mps/support/ControllerAspect.java
  29. 13 0
      src/main/java/cn/com/qmth/mps/support/ExchangeBean.java
  30. 40 0
      src/main/java/cn/com/qmth/mps/support/HttpMethodProcessor.java
  31. 23 0
      src/main/java/cn/com/qmth/mps/support/HttpMethodProcessorImpl.java
  32. 7 0
      src/main/java/cn/com/qmth/mps/support/JsonSerializable.java
  33. 40 0
      src/main/java/cn/com/qmth/mps/support/LogProperties.java
  34. 74 0
      src/main/java/cn/com/qmth/mps/support/SpringContextHolder.java
  35. 55 0
      src/main/java/cn/com/qmth/mps/support/StatusResponse.java
  36. 21 0
      src/main/java/cn/com/qmth/mps/support/WithoutStackTrace.java
  37. 22 0
      src/main/java/cn/com/qmth/mps/util/AuthorizationCreateUtil.java
  38. 53 0
      src/main/java/cn/com/qmth/mps/util/BatchGetDataUtil.java
  39. 29 0
      src/main/java/cn/com/qmth/mps/util/BatchSetDataUtil.java
  40. 214 0
      src/main/java/cn/com/qmth/mps/util/DateUtil.java
  41. 90 0
      src/main/java/cn/com/qmth/mps/util/FileUtil.java
  42. 64 0
      src/main/java/cn/com/qmth/mps/util/IpUtil.java
  43. 255 0
      src/main/java/cn/com/qmth/mps/util/JsonMapper.java
  44. 171 0
      src/main/java/cn/com/qmth/mps/util/JsonUtil.java
  45. 93 0
      src/main/java/cn/com/qmth/mps/util/MD5Util.java
  46. 69 0
      src/main/java/cn/com/qmth/mps/util/ObjectUtil.java
  47. 88 0
      src/main/java/cn/com/qmth/mps/util/PageUtil.java
  48. 45 0
      src/main/java/cn/com/qmth/mps/util/PagerQuery.java
  49. 37 0
      src/main/java/cn/com/qmth/mps/util/ResouceUtil.java
  50. 126 0
      src/main/java/cn/com/qmth/mps/util/ServletUtil.java
  51. 121 0
      src/main/java/cn/com/qmth/mps/util/ThreadLocalUtil.java
  52. 33 0
      src/main/resources/application-test.properties
  53. 33 0
      src/main/resources/application.properties

+ 136 - 0
db/init.sql

@@ -0,0 +1,136 @@
+
+-- ----------------------------
+-- Table structure for mps_course
+-- ----------------------------
+DROP TABLE IF EXISTS `mps_course`;
+CREATE TABLE `mps_course` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `create_time` bigint DEFAULT NULL,
+  `update_time` bigint DEFAULT NULL,
+  `creator_id` bigint DEFAULT NULL,
+  `updater_id` bigint DEFAULT NULL,
+  `code` varchar(255) COLLATE utf8_bin NOT NULL,
+  `name` varchar(255) COLLATE utf8_bin NOT NULL,
+  `school_id` bigint NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `IDX_COURSE_01` (`school_id`,`code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- ----------------------------
+-- Table structure for mps_exam
+-- ----------------------------
+DROP TABLE IF EXISTS `mps_exam`;
+CREATE TABLE `mps_exam` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `create_time` bigint DEFAULT NULL,
+  `update_time` bigint DEFAULT NULL,
+  `creator_id` bigint DEFAULT NULL,
+  `updater_id` bigint DEFAULT NULL,
+  `exam_status` varchar(255) COLLATE utf8_bin NOT NULL,
+  `name` varchar(255) COLLATE utf8_bin NOT NULL,
+  `school_id` bigint NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `IDX_EXAM_01` (`school_id`,`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- ----------------------------
+-- Table structure for mps_paper
+-- ----------------------------
+DROP TABLE IF EXISTS `mps_paper`;
+CREATE TABLE `mps_paper` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `create_time` bigint DEFAULT NULL,
+  `update_time` bigint DEFAULT NULL,
+  `creator_id` bigint DEFAULT NULL,
+  `updater_id` bigint DEFAULT NULL,
+  `course_id` bigint NOT NULL,
+  `exam_id` bigint NOT NULL,
+  `group_finish` bit(1) DEFAULT NULL,
+  `group_info` text COLLATE utf8_bin,
+  `objective_score` double DEFAULT NULL,
+  `paper_type` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `school_id` bigint NOT NULL,
+  `struct_info` text COLLATE utf8_bin,
+  `subjective_score` double DEFAULT NULL,
+  `total_score` double DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `IDX_PAPER_01` (`school_id`,`exam_id`,`course_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- ----------------------------
+-- Table structure for mps_privilege
+-- ----------------------------
+DROP TABLE IF EXISTS `mps_privilege`;
+CREATE TABLE `mps_privilege` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `create_time` bigint DEFAULT NULL,
+  `update_time` bigint DEFAULT NULL,
+  `creator_id` bigint DEFAULT NULL,
+  `updater_id` bigint DEFAULT NULL,
+  `code` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `description` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `ext1` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `ext2` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `ext3` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `ext4` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `ext5` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `parent_id` bigint DEFAULT NULL,
+  `seq` int DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `IDX_PRIVILEGE_01` (`code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- ----------------------------
+-- Table structure for mps_role_privilege_relation
+-- ----------------------------
+DROP TABLE IF EXISTS `mps_role_privilege_relation`;
+CREATE TABLE `mps_role_privilege_relation` (
+  `role` varchar(255) COLLATE utf8_bin NOT NULL,
+  `privilege_id` bigint NOT NULL,
+  `create_time` bigint DEFAULT NULL,
+  `update_time` bigint DEFAULT NULL,
+  `creator_id` bigint DEFAULT NULL,
+  `updater_id` bigint DEFAULT NULL,
+  PRIMARY KEY (`role`,`privilege_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- ----------------------------
+-- Table structure for mps_school
+-- ----------------------------
+DROP TABLE IF EXISTS `mps_school`;
+CREATE TABLE `mps_school` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `create_time` bigint DEFAULT NULL,
+  `update_time` bigint DEFAULT NULL,
+  `creator_id` bigint DEFAULT NULL,
+  `updater_id` bigint DEFAULT NULL,
+  `contacts` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `enable` bit(1) NOT NULL,
+  `name` varchar(255) COLLATE utf8_bin NOT NULL,
+  `region` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `telephone` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `IDX_SCHOOL_01` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- ----------------------------
+-- Table structure for mps_user
+-- ----------------------------
+DROP TABLE IF EXISTS `mps_user`;
+CREATE TABLE `mps_user` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `create_time` bigint DEFAULT NULL,
+  `update_time` bigint DEFAULT NULL,
+  `creator_id` bigint DEFAULT NULL,
+  `updater_id` bigint DEFAULT NULL,
+  `course` text COLLATE utf8_bin,
+  `enable` bit(1) NOT NULL,
+  `login_name` varchar(255) COLLATE utf8_bin NOT NULL,
+  `name` varchar(255) COLLATE utf8_bin NOT NULL,
+  `password` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `role` varchar(255) COLLATE utf8_bin NOT NULL,
+  `school_id` bigint NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `IDX_USER_01` (`school_id`,`login_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

+ 24 - 0
src/main/java/cn/com/qmth/mps/ApiApplication.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.mps;
+
+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;
+
+import com.github.jeffreyning.mybatisplus.conf.EnableMPP;
+
+@EnableMPP
+@SpringBootApplication
+@EnableAsync
+@EnableScheduling
+@Configuration
+@MapperScan("cn.com.qmth.mps.dao")
+public class ApiApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(ApiApplication.class, args);
+    }
+
+}

+ 27 - 0
src/main/java/cn/com/qmth/mps/bean/TreeNode.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.mps.bean;
+
+/**
+ * 树节点接口
+ *
+ * @author 
+ * @date 2018年2月7日
+ */
+public interface TreeNode {
+
+	String getNodeId();
+
+	void setNodeId(String nodeId);
+
+	String getNodeName();
+
+	void setNodeName(String nodeName);
+
+	String getNodeCode();
+
+	void setNodeCode(String nodeCode);
+
+	String getParentNodeId();
+
+	void setParentNodeId(String parentNodeId);
+
+}

+ 115 - 0
src/main/java/cn/com/qmth/mps/bean/User.java

@@ -0,0 +1,115 @@
+package cn.com.qmth.mps.bean;
+
+import com.qmth.boot.core.security.model.AccessEntity;
+
+import cn.com.qmth.mps.enums.Role;
+
+public class User implements AccessEntity{
+
+    private Long id;
+
+    private String name;
+
+    private String account;
+
+    private String sessionId;
+
+    private String accessToken;
+
+    private Role role;
+
+    private Long activeTime;
+
+    private Long schoolId;
+    
+    private String markingCloudToken;
+
+    public String buildKey() {
+        this.sessionId = new StringBuilder().append(role.name()).append("_").append(account).toString();
+        return this.sessionId;
+    }
+
+    public String getAccount() {
+        return account;
+    }
+
+    public void setAccount(String account) {
+        this.account = account;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSessionId() {
+        return sessionId;
+    }
+
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public Role getRole() {
+        return role;
+    }
+
+    public void setRole(Role role) {
+        this.role = role;
+    }
+
+    public Long getActiveTime() {
+        return activeTime;
+    }
+
+    public void setActiveTime(Long activeTime) {
+        this.activeTime = activeTime;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Long schoolId) {
+        this.schoolId = schoolId;
+    }
+    @Override
+    public String getIdentity() {
+        return sessionId;
+    }
+
+    @Override
+    public String getSecret() {
+        return accessToken;
+    }
+
+    
+    public String getMarkingCloudToken() {
+        return markingCloudToken;
+    }
+
+    
+    public void setMarkingCloudToken(String markingCloudToken) {
+        this.markingCloudToken = markingCloudToken;
+    }
+    
+}

+ 35 - 0
src/main/java/cn/com/qmth/mps/config/FillMetaObjectHandler.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.mps.config;
+
+import java.util.Date;
+
+import org.apache.ibatis.reflection.MetaObject;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+
+import cn.com.qmth.mps.bean.User;
+import cn.com.qmth.mps.util.ServletUtil;
+
+public class FillMetaObjectHandler implements MetaObjectHandler {
+
+	@Override
+	public void insertFill(MetaObject metaObject) {
+		User user = ServletUtil.getSessionUser();
+		if (user != null) {
+			this.setFieldValByName("creatorId", user.getId(), metaObject);
+		}
+		if(this.getFieldValByName("createTime", metaObject)==null) {
+			this.setFieldValByName("createTime", new Date().getTime(), metaObject);
+		}
+		this.setFieldValByName("updateTime", new Date().getTime(), metaObject);
+	}
+
+	@Override
+	public void updateFill(MetaObject metaObject) {
+		User user = ServletUtil.getSessionUser();
+		if (user != null) {
+			this.setFieldValByName("updaterId", user.getId(), metaObject);
+		}
+		this.setFieldValByName("updateTime", new Date().getTime(), metaObject);
+	}
+
+}

+ 15 - 0
src/main/java/cn/com/qmth/mps/config/MyBatisPlusConfig.java

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

+ 27 - 0
src/main/java/cn/com/qmth/mps/config/ScanWebMvcConfigurer.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.mps.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import cn.com.qmth.mps.interceptor.FirstInterceptor;
+
+/**
+ * WebMvcConfigurer
+ */
+@Configuration
+public class ScanWebMvcConfigurer implements WebMvcConfigurer {
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**");
+    }
+
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**").allowedOrigins("*").allowCredentials(false).allowedMethods("*").maxAge(3600);
+    }
+
+}
+

+ 42 - 0
src/main/java/cn/com/qmth/mps/config/SwaggerConfig.java

@@ -0,0 +1,42 @@
+package cn.com.qmth.mps.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.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+@EnableSwagger2WebMvc
+@Configuration
+public class SwaggerConfig {
+
+    private static final Logger log = LoggerFactory.getLogger(SwaggerConfig.class);
+
+    @Bean
+    public Docket buildDocket() {
+        log.info("swagger init...");
+        return new Docket(DocumentationType.SWAGGER_2)
+                .groupName("default")
+                .apiInfo(buildApiInfo())
+                .useDefaultResponseMessages(false)
+                .select()
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    public ApiInfo buildApiInfo() {
+        return new ApiInfoBuilder()
+                .title("接口文档")
+                .version("v1.0.0")
+                .build();
+    }
+
+}

+ 25 - 0
src/main/java/cn/com/qmth/mps/config/SysProperty.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.mps.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SysProperty {
+
+	/**
+	 * 会话超时时间(秒)
+	 */
+	@Value("${session-timeout}")
+    private Integer sessionTimeout;
+
+	public Integer getSessionTimeout() {
+		return sessionTimeout;
+	}
+
+	public void setSessionTimeout(Integer sessionTimeout) {
+		this.sessionTimeout = sessionTimeout;
+	}
+    
+
+	
+}

+ 41 - 0
src/main/java/cn/com/qmth/mps/entity/CourseEntity.java

@@ -0,0 +1,41 @@
+package cn.com.qmth.mps.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import cn.com.qmth.mps.entity.base.AuditingEntity;
+@TableName("mps_course")
+public class CourseEntity extends AuditingEntity {
+
+	private static final long serialVersionUID = -6261302618070108336L;
+
+	private Long schoolId;
+	private String code;
+	private String name;
+
+
+	
+	public Long getSchoolId() {
+		return schoolId;
+	}
+
+	public void setSchoolId(Long schoolId) {
+		this.schoolId = schoolId;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+}

+ 35 - 0
src/main/java/cn/com/qmth/mps/entity/ExamEntity.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.mps.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import cn.com.qmth.mps.entity.base.AuditingEntity;
+import cn.com.qmth.mps.enums.ExamStatus;
+@TableName("mps_exam")
+public class ExamEntity extends AuditingEntity {
+	private static final long serialVersionUID = 3104183197745226731L;
+	private Long schoolId;
+	private String name;
+	private ExamStatus examStatus;
+	
+	
+	public Long getSchoolId() {
+		return schoolId;
+	}
+	public void setSchoolId(Long schoolId) {
+		this.schoolId = schoolId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public ExamStatus getExamStatus() {
+		return examStatus;
+	}
+	public void setExamStatus(ExamStatus examStatus) {
+		this.examStatus = examStatus;
+	}
+
+	
+}

+ 110 - 0
src/main/java/cn/com/qmth/mps/entity/PaperEntity.java

@@ -0,0 +1,110 @@
+package cn.com.qmth.mps.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import cn.com.qmth.mps.entity.base.AuditingEntity;
+@TableName("mps_paper")
+public class PaperEntity extends AuditingEntity {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -8681575737341326402L;
+	private Long schoolId;
+	private Long examId;
+	private Long courseId;
+	private Double totalScore;
+	private Double objectiveScore;
+
+	private Double subjectiveScore;
+	
+	private String structInfo;
+	private String groupInfo;
+
+	private String paperType;
+	
+	private Boolean groupFinish;
+
+	public Long getSchoolId() {
+		return schoolId;
+	}
+
+	public void setSchoolId(Long schoolId) {
+		this.schoolId = schoolId;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public Long getCourseId() {
+		return courseId;
+	}
+
+	public void setCourseId(Long courseId) {
+		this.courseId = courseId;
+	}
+
+	public Double getTotalScore() {
+		return totalScore;
+	}
+
+	public void setTotalScore(Double totalScore) {
+		this.totalScore = totalScore;
+	}
+
+	public Double getObjectiveScore() {
+		return objectiveScore;
+	}
+
+	public void setObjectiveScore(Double objectiveScore) {
+		this.objectiveScore = objectiveScore;
+	}
+
+	public Double getSubjectiveScore() {
+		return subjectiveScore;
+	}
+
+	public void setSubjectiveScore(Double subjectiveScore) {
+		this.subjectiveScore = subjectiveScore;
+	}
+
+
+	public String getStructInfo() {
+		return structInfo;
+	}
+
+	public void setStructInfo(String structInfo) {
+		this.structInfo = structInfo;
+	}
+
+	public String getGroupInfo() {
+		return groupInfo;
+	}
+
+	public void setGroupInfo(String groupInfo) {
+		this.groupInfo = groupInfo;
+	}
+
+	public String getPaperType() {
+		return paperType;
+	}
+
+	public void setPaperType(String paperType) {
+		this.paperType = paperType;
+	}
+
+	public Boolean getGroupFinish() {
+		return groupFinish;
+	}
+
+	public void setGroupFinish(Boolean groupFinish) {
+		this.groupFinish = groupFinish;
+	}
+
+	
+	
+}

+ 208 - 0
src/main/java/cn/com/qmth/mps/entity/PrivilegeEntity.java

@@ -0,0 +1,208 @@
+package cn.com.qmth.mps.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import cn.com.qmth.mps.bean.TreeNode;
+import cn.com.qmth.mps.entity.base.AuditingEntity;
+@TableName("mps_privilege")
+public class PrivilegeEntity extends AuditingEntity implements TreeNode {
+
+	private static final long serialVersionUID = -6288949236298877031L;
+	
+	/**
+	 * 权限码
+	 */
+	private String code;
+
+	/**
+	 * 权限名称
+	 */
+	private String name;
+
+	/**
+	 * 父权限ID
+	 */
+	private Long parentId;
+
+
+	/**
+	 * 描述
+	 */
+	private String description;
+
+	/**
+	 * 排序
+	 */
+	private Integer seq = 0;
+
+	/**
+	 * 扩展属性
+	 */
+	private String ext1;
+
+	/**
+	 * 扩展属性
+	 */
+	private String ext2;
+
+	/**
+	 * 扩展属性
+	 */
+	private String ext3;
+
+	/**
+	 * 扩展属性
+	 */
+	private String ext4;
+
+	/**
+	 * 扩展属性
+	 */
+	private String ext5;
+
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Long getParentId() {
+		return parentId;
+	}
+
+	public void setParentId(Long parentId) {
+		this.parentId = parentId;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+
+	public Integer getSeq() {
+		return seq;
+	}
+
+	public void setSeq(Integer seq) {
+		this.seq = seq;
+	}
+
+	public String getExt1() {
+		return ext1;
+	}
+
+	public void setExt1(String ext1) {
+		this.ext1 = ext1;
+	}
+
+	public String getExt2() {
+		return ext2;
+	}
+
+	public void setExt2(String ext2) {
+		this.ext2 = ext2;
+	}
+
+	public String getExt3() {
+		return ext3;
+	}
+
+	public void setExt3(String ext3) {
+		this.ext3 = ext3;
+	}
+
+	public String getExt4() {
+		return ext4;
+	}
+
+	public void setExt4(String ext4) {
+		this.ext4 = ext4;
+	}
+
+	public String getExt5() {
+		return ext5;
+	}
+
+	public void setExt5(String ext5) {
+		this.ext5 = ext5;
+	}
+
+	@Override
+	public String getNodeId() {
+		if (null == this.id) {
+			return null;
+		}
+		return String.valueOf(this.id);
+	}
+
+	@Override
+	public void setNodeId(String nodeId) {
+		if (null == nodeId) {
+			this.id = null;
+		}
+		this.id = Long.parseLong(nodeId);
+	}
+
+	@Override
+	public String getNodeName() {
+		if (null == this.name) {
+			return null;
+		}
+		return String.valueOf(this.name);
+	}
+
+	@Override
+	public void setNodeName(String nodeName) {
+		this.name = nodeName;
+	}
+
+	@Override
+	public String getParentNodeId() {
+		if (null == this.parentId) {
+			return null;
+		}
+		return String.valueOf(this.parentId);
+	}
+
+	@Override
+	public void setParentNodeId(String parentNodeId) {
+		if (null == parentNodeId) {
+			this.parentId = null;
+		}
+		this.parentId = Long.parseLong(parentNodeId);
+	}
+
+	@Override
+	public String getNodeCode() {
+		return this.code;
+	}
+
+	@Override
+	public void setNodeCode(String code) {
+		this.code = code;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+}

+ 35 - 0
src/main/java/cn/com/qmth/mps/entity/RolePrivilegeRelationEntity.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.mps.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.github.jeffreyning.mybatisplus.anno.MppMultiId;
+
+import cn.com.qmth.mps.entity.base.AuditingWithoutIdEntity;
+import cn.com.qmth.mps.enums.Role;
+@TableName("mps_role_privilege_relation")
+public class RolePrivilegeRelationEntity extends AuditingWithoutIdEntity {
+
+	private static final long serialVersionUID = 8849214483955278647L;
+
+	@MppMultiId
+	private Role role;
+
+	@MppMultiId
+	private Long privilegeId;
+
+	public Role getRole() {
+		return role;
+	}
+
+	public void setRole(Role role) {
+		this.role = role;
+	}
+
+	public Long getPrivilegeId() {
+		return privilegeId;
+	}
+
+	public void setPrivilegeId(Long privilegeId) {
+		this.privilegeId = privilegeId;
+	}
+
+}

+ 62 - 0
src/main/java/cn/com/qmth/mps/entity/SchoolEntity.java

@@ -0,0 +1,62 @@
+package cn.com.qmth.mps.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import cn.com.qmth.mps.entity.base.AuditingEntity;
+@TableName("mps_school")
+public class SchoolEntity extends AuditingEntity {
+
+	private static final long serialVersionUID = -592353272256492483L;
+	private String name;
+	private Boolean enable;
+
+	private String telephone;
+
+	private String contacts;
+	
+	private String region;
+	
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public String getTelephone() {
+		return telephone;
+	}
+
+	public void setTelephone(String telephone) {
+		this.telephone = telephone;
+	}
+
+	public String getContacts() {
+		return contacts;
+	}
+
+	public void setContacts(String contacts) {
+		this.contacts = contacts;
+	}
+
+	public String getRegion() {
+		return region;
+	}
+
+	public void setRegion(String region) {
+		this.region = region;
+	}
+
+	
+
+}

+ 84 - 0
src/main/java/cn/com/qmth/mps/entity/UserEntity.java

@@ -0,0 +1,84 @@
+package cn.com.qmth.mps.entity;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+
+import cn.com.qmth.mps.entity.base.AuditingEntity;
+import cn.com.qmth.mps.enums.Role;
+@TableName("mps_user")
+public class UserEntity extends AuditingEntity {
+
+	private static final long serialVersionUID = 6770398649449396459L;
+	private Long schoolId;
+	private String name;
+	private String loginName;
+
+	private String password;
+	private Boolean enable;
+	
+	@TableField(value = "params", typeHandler = JacksonTypeHandler.class)
+	private List<Long> course;
+	private Role role;
+
+	public Long getSchoolId() {
+		return schoolId;
+	}
+
+	public void setSchoolId(Long schoolId) {
+		this.schoolId = schoolId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getLoginName() {
+		return loginName;
+	}
+
+	public void setLoginName(String loginName) {
+		this.loginName = loginName;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public Role getRole() {
+		return role;
+	}
+
+	public void setRole(Role role) {
+		this.role = role;
+	}
+
+	public List<Long> getCourse() {
+		return course;
+	}
+
+	public void setCourse(List<Long> course) {
+		this.course = course;
+	}
+	
+
+	
+}

+ 42 - 0
src/main/java/cn/com/qmth/mps/entity/base/AuditingEntity.java

@@ -0,0 +1,42 @@
+package cn.com.qmth.mps.entity.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+/**
+ * 实体类基类
+ */
+public abstract class AuditingEntity extends IdEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 创建人
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long creatorId;
+
+    /**
+     * 更新人
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updaterId;
+
+
+    public Long getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Long creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public Long getUpdaterId() {
+        return updaterId;
+    }
+
+    public void setUpdaterId(Long updaterId) {
+        this.updaterId = updaterId;
+    }
+
+}

+ 42 - 0
src/main/java/cn/com/qmth/mps/entity/base/AuditingWithoutIdEntity.java

@@ -0,0 +1,42 @@
+package cn.com.qmth.mps.entity.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+/**
+ * 实体类基类
+ */
+public abstract class AuditingWithoutIdEntity extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 创建人
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long creatorId;
+
+    /**
+     * 更新人
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updaterId;
+
+
+    public Long getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Long creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public Long getUpdaterId() {
+        return updaterId;
+    }
+
+    public void setUpdaterId(Long updaterId) {
+        this.updaterId = updaterId;
+    }
+
+}

+ 43 - 0
src/main/java/cn/com/qmth/mps/entity/base/BaseEntity.java

@@ -0,0 +1,43 @@
+package cn.com.qmth.mps.entity.base;
+
+import java.io.Serializable;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+/**
+ * 实体类基类
+ */
+public abstract class BaseEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    protected Long createTime;
+
+    /**
+     * 修改时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    protected Long updateTime;
+
+    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;
+    }
+
+}

+ 26 - 0
src/main/java/cn/com/qmth/mps/entity/base/IdEntity.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.mps.entity.base;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+/**
+ * 实体类基类
+ */
+public abstract class IdEntity extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    protected Long id;
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+
+}

+ 21 - 0
src/main/java/cn/com/qmth/mps/enums/ExamStatus.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.mps.enums;
+
+public enum ExamStatus {
+
+	EDIT("开放上报"),
+
+    FINISH("停止上报"),
+
+    CLOSE("关闭考试");
+
+    private String name;
+
+    ExamStatus(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+}

+ 64 - 0
src/main/java/cn/com/qmth/mps/enums/HttpServletRequestAttribute.java

@@ -0,0 +1,64 @@
+package cn.com.qmth.mps.enums;
+
+/**
+ * servlet请求属性
+ *
+ */
+public enum HttpServletRequestAttribute {
+
+    /**
+     * 请求映射
+     */
+    $_MAPPING,
+
+    /**
+     * API 信息
+     */
+    $_API_INFO,
+
+    /**
+     * http status恒为200
+     */
+    $_ALWAYS_OK,
+
+    /**
+     * 接入用户
+     */
+    $_ACCESS_USER,
+
+    /**
+     * 自定义顺序锁
+     */
+    $_CUSTOM_SEQUENCE_LOCK,
+
+    /**
+     * 已鉴权(其他拦截器处理)
+     */
+    $_AUTHORIZED_BY_OTHER_INTERCEPTOR,
+
+    /**
+     * 企业顶级机构(对外服务接口)
+     */
+    $_ENTERPRISE_ROOT_ORG_ID,
+
+    /**
+     * 接口调用异常
+     */
+    $_EXCEPTION_HAPPENED,
+
+    /**
+     * METRICS Timer context
+     */
+    $_METRICS_TIMER_CTX,
+
+    /**
+     * ApiStatisticInterceptor 开始时间
+     */
+    API_STATISTIC_INTERCEPTOR_START_TIME,
+
+    /**
+     * 数据权限
+     */
+    $_USER_DATA_RULE
+
+}

+ 32 - 0
src/main/java/cn/com/qmth/mps/enums/Role.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.mps.enums;
+
+public enum Role {
+
+    SUPPER_ADMIN("超级管理员"),
+
+    SCHOOL_ADMIN("机构管理员"),
+
+    SECTION_LEADER("科组长"),
+
+    ;
+
+    private String name;
+
+    Role(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public static Role getByName(String name) {
+        for (Role r : Role.values()) {
+            if (r.getName().equals(name)) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+}

+ 110 - 0
src/main/java/cn/com/qmth/mps/interceptor/FirstInterceptor.java

@@ -0,0 +1,110 @@
+package cn.com.qmth.mps.interceptor;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.google.common.collect.Maps;
+
+import cn.com.qmth.mps.enums.HttpServletRequestAttribute;
+import cn.com.qmth.mps.support.ApiInfo;
+import cn.com.qmth.mps.support.ApiInfoHolder;
+import cn.com.qmth.mps.support.StatusResponse;
+import cn.com.qmth.mps.util.JsonUtil;
+import cn.com.qmth.mps.util.ServletUtil;
+import cn.com.qmth.mps.util.ThreadLocalUtil;
+
+/**
+ * 首发拦截器
+ *
+ */
+public class FirstInterceptor implements HandlerInterceptor {
+
+	private static final Logger LOG = LoggerFactory.getLogger(FirstInterceptor.class);
+
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+			throws Exception {
+		ThreadLocalUtil.clearAll();
+		String traceId = request.getHeader("Trace-Id");
+		if (StringUtils.isBlank(traceId)) {
+			traceId = ThreadLocalUtil.next();
+		} else {
+			ThreadLocalUtil.setTraceId(traceId);
+		}
+
+		// 设置log4j线程上下文
+		ThreadContext.put("TRACE_ID", traceId);
+		ThreadContext.put("CALLER", "$$$$$");
+
+		String path = request.getServletPath();
+		String method = request.getMethod();
+
+		Set<String> headerNames = new HashSet<>(20);
+
+		if (LOG.isDebugEnabled()) {
+			Map<String, String> headers = Maps.newHashMap();
+			Enumeration<String> e = request.getHeaderNames();
+			while (e.hasMoreElements()) {
+				String name = e.nextElement();
+				String value = request.getHeader(name);
+				headers.put(name, value);
+				headerNames.add(name);
+			}
+
+			LOG.debug(String.format("[%s] - %s, headers = %s", method, path, JsonUtil.toJson(headers)));
+		}
+
+		if (path.equals("/error")) {
+			response.setStatus(HttpStatus.NOT_FOUND.value());
+			ServletUtil.returnJson(new StatusResponse(HttpStatus.NOT_FOUND.value(),
+					HttpStatus.NOT_FOUND.getReasonPhrase()), response);
+			return false;
+		}
+
+		if ((!org.springframework.http.HttpMethod.OPTIONS.matches(method)) && handler instanceof HandlerMethod) {
+			HandlerMethod handlerMethod = (HandlerMethod) handler;
+
+			ApiInfo apiInfo = ApiInfoHolder.getApiInfo(handlerMethod.getMethod());
+
+			String mapping = apiInfo.getMapping();
+			request.setAttribute(HttpServletRequestAttribute.$_API_INFO.name(), apiInfo);
+
+			LOG.debug("[mapping] ==> " + mapping);
+			request.setAttribute(HttpServletRequestAttribute.$_MAPPING.name(), mapping);
+		} else {
+			String mapping = StringUtils.join("_[", path, "][", method, "]");
+
+			LOG.debug("[mapping] --> " + mapping);
+			request.setAttribute(HttpServletRequestAttribute.$_MAPPING.name(), mapping);
+		}
+
+		return true;
+	}
+
+	@Override
+	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
+			ModelAndView modelAndView) throws Exception {
+	}
+
+	@Override
+	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
+			throws Exception {
+		// 清理log4j线程上下文
+		ThreadContext.clearAll();
+	}
+
+}

+ 118 - 0
src/main/java/cn/com/qmth/mps/support/ApiInfo.java

@@ -0,0 +1,118 @@
+package cn.com.qmth.mps.support;
+
+import java.io.Serializable;
+
+/**
+ * 接口
+ *
+ */
+
+public class ApiInfo implements Serializable {
+
+	private static final long serialVersionUID = 1553810211239843543L;
+
+	/**
+	 * ID
+	 */
+	private Integer id;
+
+	/**
+	 * 映射
+	 */
+	private String mapping;
+
+	/**
+	 * mapping路径
+	 */
+	private String requestPath;
+
+	/**
+	 * http方法
+	 */
+	private String httpMethod;
+
+	/**
+	 * 接口描述
+	 */
+	private String description;
+
+	/**
+	 * 请求处理类
+	 */
+	private transient Class<?> beanType;
+
+	/**
+	 * 接口日志忽略堆栈
+	 */
+	private boolean withoutStackTrace;
+
+	/**
+	 * 接口裸奔
+	 */
+	private boolean naked;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getMapping() {
+		return mapping;
+	}
+
+	public void setMapping(String mapping) {
+		this.mapping = mapping;
+	}
+
+	public String getRequestPath() {
+		return requestPath;
+	}
+
+	public void setRequestPath(String requestPath) {
+		this.requestPath = requestPath;
+	}
+
+	public String getHttpMethod() {
+		return httpMethod;
+	}
+
+	public void setHttpMethod(String httpMethod) {
+		this.httpMethod = httpMethod;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Class<?> getBeanType() {
+		return beanType;
+	}
+
+	public void setBeanType(Class<?> beanType) {
+		this.beanType = beanType;
+	}
+
+	public boolean isWithoutStackTrace() {
+		return withoutStackTrace;
+	}
+
+	public void setWithoutStackTrace(boolean withoutStackTrace) {
+		this.withoutStackTrace = withoutStackTrace;
+	}
+
+	public boolean isNaked() {
+		return naked;
+	}
+
+	public void setNaked(boolean naked) {
+		this.naked = naked;
+	}
+
+}

+ 148 - 0
src/main/java/cn/com/qmth/mps/support/ApiInfoHolder.java

@@ -0,0 +1,148 @@
+package cn.com.qmth.mps.support;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
+import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import io.swagger.annotations.ApiOperation;
+
+@Component
+@Order(100)
+public class ApiInfoHolder implements ApplicationRunner {
+
+	private static final Map<String, ApiInfo> INDEX_BY_MAPPING = Maps.newConcurrentMap();
+
+	private static final Map<Method, ApiInfo> INDEX_BY_METHOD = Maps.newConcurrentMap();
+
+	private static Set<ApiInfo> apiInfoSet = Sets.newHashSet();
+
+	@Autowired
+	private RequestMappingHandlerMapping requestMappingHandlerMapping;
+
+
+	/**
+	 * 通过方法获取ApiInfo
+	 *
+	 * @author 
+	 * @param method
+	 * @return
+	 */
+	public static ApiInfo getApiInfo(Method method) {
+		return INDEX_BY_METHOD.get(method);
+	}
+
+	/**
+	 * 通过mapping获取ApiInfo
+	 *
+	 * @author 
+	 * @param mapping
+	 * @return
+	 */
+	public static ApiInfo getApiInfo(String mapping) {
+		return INDEX_BY_MAPPING.get(mapping);
+	}
+
+	/**
+	 * 获取@ApiId注解的ApiInfo集合
+	 *
+	 * @author 
+	 * @return
+	 */
+	public static Set<ApiInfo> getApiInfoSet() {
+		return apiInfoSet;
+	}
+
+	@Override
+	public void run(ApplicationArguments args) throws Exception {
+
+		Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping
+				.getHandlerMethods();
+
+		for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
+			RequestMappingInfo requestMappingInfo = entry.getKey();
+			HandlerMethod handlerMethod = entry.getValue();
+
+			Class<?> beanType = handlerMethod.getBeanType();
+
+			RequestMapping requestMappingAnnotationOfClass = AnnotationUtils
+					.findAnnotation(beanType, RequestMapping.class);
+
+			RequestMapping requestMappingAnnotationOfMethod = handlerMethod
+					.getMethodAnnotation(RequestMapping.class);
+
+			WithoutStackTrace withoutStackTrace = handlerMethod
+					.getMethodAnnotation(WithoutStackTrace.class);
+
+			ApiOperation apiOperation = handlerMethod.getMethodAnnotation(ApiOperation.class);
+
+			RequestMethodsRequestCondition requestMethodsRequestCondition = requestMappingInfo
+					.getMethodsCondition();
+			Set<RequestMethod> requestMethodSet = requestMethodsRequestCondition.getMethods();
+
+			String[] mappingURIsOfClass = null;
+			String[] mappingURIsOfMethod = null;
+
+			if (null != requestMappingAnnotationOfClass) {
+				mappingURIsOfClass = requestMappingAnnotationOfClass.path();
+			}
+			if (null != requestMappingAnnotationOfMethod) {
+				mappingURIsOfMethod = requestMappingAnnotationOfMethod.path();
+			}
+
+			String mappingIdentifyOfClass = null;
+			String mappingIdentifyOfMethod = null;
+
+			if (null != mappingURIsOfClass) {
+				mappingIdentifyOfClass = StringUtils.join(mappingURIsOfClass, ",");
+			}
+			if (null != mappingURIsOfMethod) {
+				mappingIdentifyOfMethod = StringUtils.join(mappingURIsOfMethod, ",");
+			}
+
+			String methods = StringUtils.join(requestMethodSet, ",");
+
+			String mapping = StringUtils.join("[", mappingIdentifyOfClass, "][",
+					mappingIdentifyOfMethod, "][", methods, "]");
+
+			PatternsRequestCondition patternsRequestCondition = requestMappingInfo
+					.getPatternsCondition();
+
+			String requestPath = StringUtils.join(patternsRequestCondition.getPatterns(), ",");
+
+			ApiInfo apiInfo = new ApiInfo();
+			if (null != apiOperation) {
+				apiInfo.setDescription(apiOperation.value());
+			}
+			apiInfo.setHttpMethod(methods);
+			apiInfo.setMapping(mapping);
+			apiInfo.setRequestPath(requestPath);
+			apiInfo.setBeanType(beanType);
+			if (null != withoutStackTrace) {
+				apiInfo.setWithoutStackTrace(withoutStackTrace.value());
+			}
+
+			INDEX_BY_METHOD.put(handlerMethod.getMethod(), apiInfo);
+
+			INDEX_BY_MAPPING.put(mapping, apiInfo);
+		}
+	}
+
+}

+ 29 - 0
src/main/java/cn/com/qmth/mps/support/BaseResponse.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.mps.support;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 响应体基类
+ * 
+ * @author 
+ *
+ */
+public abstract class BaseResponse extends ExchangeBean {
+
+	private static final long serialVersionUID = 1755304211766414171L;
+
+	/**
+	 * 耗时(毫秒)
+	 */
+	@ApiModelProperty(value = "耗时(毫秒)", example = "500", required = true)
+	private Long cost;
+
+	public Long getCost() {
+		return cost;
+	}
+
+	public void setCost(Long cost) {
+		this.cost = cost;
+	}
+
+}

+ 254 - 0
src/main/java/cn/com/qmth/mps/support/ControllerAspect.java

@@ -0,0 +1,254 @@
+package cn.com.qmth.mps.support;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.mps.enums.HttpServletRequestAttribute;
+import cn.com.qmth.mps.util.JsonMapper;
+import cn.com.qmth.mps.util.ObjectUtil;
+import cn.com.qmth.mps.util.ServletUtil;
+import cn.com.qmth.mps.util.ThreadLocalUtil;
+
+
+/**
+ * spring mvc controller aspect.
+ *
+ */
+@Component
+@Aspect
+public class ControllerAspect {
+
+	private static final Logger LOG = LoggerFactory.getLogger(ControllerAspect.class);
+
+	@Autowired(required = false)
+	HttpMethodProcessor httpMethodProcessor;
+
+	@Autowired
+	LogProperties logProperties;
+
+	/**
+	 * 构造函数
+	 */
+	public ControllerAspect() {
+		super();
+		LOG.info("ControllerAspect init...");
+	}
+
+	private static String[] excludeFields = new String[] { "password", ".*Password" };
+
+	/**
+	 * handlerMethods
+	 *
+	 * @author
+	 */
+	@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) "
+			+ "|| @annotation(org.springframework.web.bind.annotation.GetMapping) "
+			+ "|| @annotation(org.springframework.web.bind.annotation.PostMapping)"
+			+ "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)"
+			+ "|| @annotation(org.springframework.web.bind.annotation.PutMapping)")
+	public void handlerMethods() {
+
+	}
+
+	/**
+	 * 接口处理
+	 *
+	 * @param joinPoint
+	 * @return
+	 * @author
+	 * @throws Throwable 
+	 */
+	@Around("handlerMethods()")
+	public Object doAroundWebRequests(ProceedingJoinPoint joinPoint) throws Throwable {
+		// 获取request对象
+		HttpServletRequest request = ServletUtil.getRequest();
+		String path = request.getServletPath();
+		try {
+			if ("/".equals(request.getServletPath())) {
+				return joinPoint.proceed();
+			}
+		} catch (Throwable e) {
+			LOG.error(e.getMessage());
+			throw e;
+		}
+
+		long startTime = System.currentTimeMillis();
+		String method = request.getMethod();
+		Object[] args = joinPoint.getArgs();
+
+		if (LOG.isInfoEnabled()) {
+			StringBuilder params = new StringBuilder();
+
+			// api method params
+			if (ArrayUtils.isNotEmpty(args)) {
+				params.append(" methodParams: ");
+				for (int i = 0; i < args.length; i++) {
+					Object curArg = args[i];
+					String content = this.parseContent(curArg);
+					params.append(content);
+
+					if (i < args.length - 1) {
+						params.append(" | ");
+					}
+				}
+			}
+
+			// api url params
+			Map<String, String[]> paramMaps = request.getParameterMap();
+			if (MapUtils.isNotEmpty(paramMaps)) {
+				params.append(" urlParams: ");
+				for (Map.Entry<String, String[]> entry : paramMaps.entrySet()) {
+					String name = entry.getKey();
+					String[] values = entry.getValue();
+					params.append("&").append(name).append("=");
+
+					if (ArrayUtils.isNotEmpty(values)) {
+						if (name.toLowerCase().indexOf(excludeFields[0]) >= 0) {
+							params.append("***");
+						} else {
+							params.append(values[0]);
+						}
+					}
+				}
+			}
+			if (!isWithoutStackTrace()) {
+				LOG.info(String.format("[request][%s] - %s %s", method, path, params.toString()));
+			}
+		}
+
+		Object ret;
+		try {
+			if (null != httpMethodProcessor) {
+				httpMethodProcessor.beforeMethod(request, args);
+			}
+
+			// 执行
+			ret = joinPoint.proceed();
+
+			request.setAttribute(HttpServletRequestAttribute.$_EXCEPTION_HAPPENED.name(), new Boolean(false));
+		} catch (Throwable e) {
+			request.setAttribute(HttpServletRequestAttribute.$_EXCEPTION_HAPPENED.name(), new Boolean(true));
+
+			if (null != httpMethodProcessor) {
+				try {
+					httpMethodProcessor.onException(request, args, e);
+				} catch (Exception ex) {
+					LOG.error("processor1 - " + ex.getMessage(), ex);
+				}
+			}
+
+			LOG.error(String.format("[execute fail][%s] - %s, cost %sms, err is %s", method, path,
+					System.currentTimeMillis() - startTime, e.getMessage()));
+			throw e;
+		}
+
+		if (null != httpMethodProcessor) {
+			try {
+				httpMethodProcessor.onSuccess(request, args, ret);
+			} catch (Exception ex) {
+				LOG.error("processor2 - " + ex.getMessage(), ex);
+			}
+		}
+
+		if (null != ret && BaseResponse.class.isAssignableFrom(ret.getClass())) {
+			BaseResponse baseResponse = (BaseResponse) ret;
+			baseResponse.setCost(System.currentTimeMillis() - startTime);
+		}
+
+		if (LOG.isDebugEnabled() && logProperties.isNormalResponseLogEnable()) {
+			if (ret == null) {
+				LOG.debug("status = ok, responseMsg = void");
+			} else if (ret instanceof ResponseEntity) {
+				ResponseEntity<?> re = (ResponseEntity<?>) ret;
+				Object body = re.getBody();
+
+				String content = this.parseContent(body);
+				LOG.debug(String.format("status = %s, responseMsg = %s", re.getStatusCodeValue(), content));
+			} else {
+				String content = this.parseContent(ret);
+				LOG.debug(String.format("status = ok, responseMsg = %s", content));
+			}
+		}
+
+		HttpServletResponse response = ServletUtil.getResponse();
+		response.setHeader("Trace-Id", ThreadLocalUtil.getTraceId());
+		response.setHeader("cost", String.valueOf(System.currentTimeMillis() - startTime));
+		if (!isWithoutStackTrace()) {
+			LOG.info(String.format("[response][%s] - %s, cost %sms", method, path,
+					System.currentTimeMillis() - startTime));
+		}
+		return ret;
+	}
+	
+	private boolean isWithoutStackTrace() {
+		HttpServletRequest request = ServletUtil.getRequest();
+		ApiInfo apiInfo = (ApiInfo) request.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
+		return apiInfo.isWithoutStackTrace();
+	}
+
+	private String parseContent(Object obj) {
+		if (obj == null) {
+			// content empty...
+			return "";
+		}
+
+		if (ObjectUtil.isBaseDataType(obj.getClass()) || obj instanceof String) {
+			return obj.toString();
+		}
+
+		boolean jsonEnable = false;
+		if (obj instanceof Collection) {
+			jsonEnable = true;
+		} else if (obj instanceof Map) {
+			jsonEnable = true;
+		} else if (obj instanceof Serializable) {
+			String classPath = obj.getClass().getName();
+
+			if (classPath.startsWith("org.springframework.data.domain.PageImpl") || classPath.startsWith("cn.com.qmth")
+					|| classPath.startsWith("com.qmth")) {
+				jsonEnable = true;
+			}
+		}
+
+		if (!jsonEnable) {
+			// content ignore...
+			return "...";
+		}
+
+		String content = null;
+		try {
+			// content to json
+			content = new JsonMapper().toJson(obj);
+		} catch (Exception e) {
+			LOG.warn("parseContent " + e.getMessage());
+		}
+
+		if (content == null) {
+			return "......";
+		}
+
+		if (content.length() > logProperties.getResponseLogJsonMaxSize()) {
+			// content too large...
+			return content.substring(0, logProperties.getResponseLogJsonMaxSize()) + " [MORE...]";
+		}
+
+		return content;
+	}
+
+}

+ 13 - 0
src/main/java/cn/com/qmth/mps/support/ExchangeBean.java

@@ -0,0 +1,13 @@
+package cn.com.qmth.mps.support;
+
+/**
+ * bean 基类
+ * 
+ * @author 
+ *
+ */
+public abstract class ExchangeBean implements JsonSerializable {
+
+	private static final long serialVersionUID = 3913250969569367810L;
+
+}

+ 40 - 0
src/main/java/cn/com/qmth/mps/support/HttpMethodProcessor.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.mps.support;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * spring mvc 方法前校验器
+ *
+ */
+public interface HttpMethodProcessor {
+
+	/**
+	 * 方法前处理
+	 *
+	 * @author 
+	 * @param request
+	 * @param args
+	 */
+	void beforeMethod(HttpServletRequest request, Object[] args);
+
+	/**
+	 * 方法执行未抛出异常时执行
+	 *
+	 * @author 
+	 * @param request
+	 * @param args
+	 * @param ret
+	 */
+	void onSuccess(HttpServletRequest request, Object[] args, Object ret);
+
+	/**
+	 * 方法执行抛出异常时执行
+	 *
+	 * @author 
+	 * @param request
+	 * @param args
+	 * @param e
+	 */
+	void onException(HttpServletRequest request, Object[] args, Throwable e);
+
+}

+ 23 - 0
src/main/java/cn/com/qmth/mps/support/HttpMethodProcessorImpl.java

@@ -0,0 +1,23 @@
+package cn.com.qmth.mps.support;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class HttpMethodProcessorImpl implements HttpMethodProcessor {
+
+	@Override
+	public void beforeMethod(HttpServletRequest request, Object[] args) {
+
+	}
+
+	@Override
+	public void onSuccess(HttpServletRequest request, Object[] args, Object ret) {
+	}
+
+	@Override
+	public void onException(HttpServletRequest request, Object[] args, Throwable e) {
+	}
+
+}

+ 7 - 0
src/main/java/cn/com/qmth/mps/support/JsonSerializable.java

@@ -0,0 +1,7 @@
+package cn.com.qmth.mps.support;
+
+import java.io.Serializable;
+
+public interface JsonSerializable extends Serializable {
+
+}

+ 40 - 0
src/main/java/cn/com/qmth/mps/support/LogProperties.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.mps.support;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 日志属性
+ *
+ */
+@Component
+@ConfigurationProperties("scan.web.log")
+public class LogProperties {
+
+	/**
+	 * 是否记录正常相应信息
+	 */
+	private boolean normalResponseLogEnable = true;
+
+	/**
+	 * 正常响应信息json长度限制
+	 */
+	private int responseLogJsonMaxSize = 200;
+
+	public boolean isNormalResponseLogEnable() {
+		return normalResponseLogEnable;
+	}
+
+	public void setNormalResponseLogEnable(boolean normalResponseLogEnable) {
+		this.normalResponseLogEnable = normalResponseLogEnable;
+	}
+
+	public int getResponseLogJsonMaxSize() {
+		return responseLogJsonMaxSize;
+	}
+
+	public void setResponseLogJsonMaxSize(int responseLogJsonMaxSize) {
+		this.responseLogJsonMaxSize = responseLogJsonMaxSize;
+	}
+
+}

+ 74 - 0
src/main/java/cn/com/qmth/mps/support/SpringContextHolder.java

@@ -0,0 +1,74 @@
+package cn.com.qmth.mps.support;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.ResolvableType;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring context holder.
+ *
+ */
+@Component
+public class SpringContextHolder implements ApplicationContextAware {
+
+	private static ApplicationContext ctx = null;
+
+	@Override
+	public void setApplicationContext(ApplicationContext ctx) {
+		SpringContextHolder.ctx = ctx;
+	}
+
+	public static ApplicationContext getApplicationContext() {
+		return ctx;
+	}
+
+	public static Object getBean(String name) {
+		return ctx.getBean(name);
+	}
+
+	public static <T> T getBean(String name, Class<T> requiredType) {
+		return ctx.getBean(name, requiredType);
+	}
+
+	public static <T> T getBean(Class<T> requiredType) {
+		return ctx.getBean(requiredType);
+	}
+
+	public static Object getBean(String name, Object... args) {
+		return ctx.getBean(name, args);
+	}
+
+	public static <T> T getBean(Class<T> requiredType, Object... args) {
+		return ctx.getBean(requiredType, args);
+	}
+
+	public static boolean containsBean(String name) {
+		return ctx.containsBean(name);
+	}
+
+	public static boolean isSingleton(String name) {
+		return ctx.isSingleton(name);
+	}
+
+	public static boolean isPrototype(String name) {
+		return ctx.isPrototype(name);
+	}
+
+	public static boolean isTypeMatch(String name, ResolvableType typeToMatch) {
+		return ctx.isTypeMatch(name, typeToMatch);
+	}
+
+	public static boolean isTypeMatch(String name, Class<?> typeToMatch) {
+		return ctx.isTypeMatch(name, typeToMatch);
+	}
+
+	public static Class<?> getType(String name) {
+		return ctx.getType(name);
+	}
+
+	public static String[] getAliases(String name) {
+		return ctx.getAliases(name);
+	}
+
+}

+ 55 - 0
src/main/java/cn/com/qmth/mps/support/StatusResponse.java

@@ -0,0 +1,55 @@
+package cn.com.qmth.mps.support;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 状态响应实体
+ *
+ */
+public class StatusResponse implements JsonSerializable {
+
+	private static final long serialVersionUID = 8393074113722405560L;
+
+	@ApiModelProperty(value = "响应编码", example = "001001", required = true)
+	private Integer code;
+
+	@ApiModelProperty(value = "响应描述", example = "密码错误", required = true)
+	private String desc;
+
+	/**
+	 * 构造函数
+	 *
+	 */
+	public StatusResponse() {
+		super();
+	}
+
+	/**
+	 * 构造函数
+	 *
+	 * @param code
+	 * @param desc
+	 */
+	public StatusResponse(Integer code, String desc) {
+		super();
+		this.code = code;
+		this.desc = desc;
+	}
+
+	public Integer getCode() {
+		return code;
+	}
+
+	public void setCode(Integer code) {
+		this.code = code;
+	}
+
+	public String getDesc() {
+		return desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+
+}

+ 21 - 0
src/main/java/cn/com/qmth/mps/support/WithoutStackTrace.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.mps.support;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 接口注解 <br>
+ * 忽略接口日志堆栈<br>
+ *
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WithoutStackTrace {
+
+	boolean value() default true;
+
+}

+ 22 - 0
src/main/java/cn/com/qmth/mps/util/AuthorizationCreateUtil.java

@@ -0,0 +1,22 @@
+package cn.com.qmth.mps.util;
+
+import com.qmth.boot.tools.signature.SignatureEntity;
+import com.qmth.boot.tools.signature.SignatureType;
+
+/**
+ * 后台生成签名工具类
+ */
+public class AuthorizationCreateUtil {
+
+    
+    public static void main(String[] args) {
+    	long time = System.currentTimeMillis();
+    	String identity="SCANNER_127.0.0.1";//登录后user属性
+    	String token="x3m8G4i5qzZ3bemrcDNQYFcx3i4v2I7K";//登录后user属性
+    	String url="/api/admin/check/absent/query";//请求路径
+    	String s = SignatureEntity.build(SignatureType.TOKEN, "post", url, time, identity, token);
+    	System.out.println("time:"+time);
+    	System.out.println("Authorization:"+s);
+	}
+
+}

+ 53 - 0
src/main/java/cn/com/qmth/mps/util/BatchGetDataUtil.java

@@ -0,0 +1,53 @@
+package cn.com.qmth.mps.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+/**
+ *	多次批量获取数据
+ * @author xiatian
+ * @param <R> 结果类
+ * @param <P> 参数类
+ */
+public abstract  class BatchGetDataUtil<R,P> {
+	/**
+	 * @param resultList 全部结果集合
+	 * @param paramList 全部参数集合
+	 * @param batchSize 每批参数数量
+	 */
+	public final List<R> getDataForBatch(List<P> paramList,int batchSize) {
+		if(CollectionUtils.isEmpty(paramList)) {
+			return null;
+		}
+		List<R> resultList=new ArrayList<>();
+		if(paramList.size()<=batchSize) {
+			List<R> temlist = getData(paramList);
+			if(temlist!=null&&temlist.size()>0) {
+				resultList.addAll(temlist);
+			}
+		}else {
+			int size = paramList.size();
+			int len=batchSize;
+			int count = (size + len - 1) / len;
+
+			for (int i = 0; i < count; i++) {
+				List<P> subList = paramList.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1)));
+				List<R> temlist = getData(subList);
+				if(temlist!=null&&temlist.size()>0) {
+					resultList.addAll(temlist);
+				}
+			}
+		}
+		return resultList;
+	}
+	/**
+	 * 	每批获取数据方法
+	 * @param <R>
+	 * @param <P>
+	 * @param paramList 获取每批数据时参数
+	 * @return
+	 */
+	protected abstract  List<R> getData(List<P> paramList);
+}

+ 29 - 0
src/main/java/cn/com/qmth/mps/util/BatchSetDataUtil.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.mps.util;
+
+import java.util.List;
+
+public abstract class BatchSetDataUtil<P> {
+	/**
+	 * @param dataList 待填充的对象集合
+	 * @param batchSize 每批数量
+	 */
+	public final void setDataForBatch(List<P> dataList, int batchSize) {
+		if (dataList == null || dataList.size() == 0) {
+			return;
+		}
+		if (dataList.size() <= batchSize) {
+			setData(dataList);
+		} else {
+			int size = dataList.size();
+			int len = batchSize;
+			int count = (size + len - 1) / len;
+
+			for (int i = 0; i < count; i++) {
+				List<P> subList = dataList.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1)));
+				setData(subList);
+			}
+		}
+	}
+
+	protected abstract void setData(List<P> dataList);
+}

+ 214 - 0
src/main/java/cn/com/qmth/mps/util/DateUtil.java

@@ -0,0 +1,214 @@
+package cn.com.qmth.mps.util;
+
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import com.qmth.boot.core.exception.StatusException;
+
+
+/**
+ * 日期工具
+ * 
+ * @author 
+ */
+public class DateUtil {
+
+	/**
+	 * patterns describing the date and time format
+	 *
+	 * @author 
+	 */
+	public interface DatePatterns {
+
+		public static final String DEFAULT = "yyyyMMddHHmmss";
+
+		public static final String YYYY = "yyyy";
+
+		public static final String YYYYMM = "yyyyMM";
+
+		public static final String YYYYMMDD = "yyyyMMdd";
+
+		public static final String YYYYMMDDHH = "yyyyMMddHH";
+
+		public static final String YYYYMMDDHHMM = "yyyyMMddHHmm";
+
+		public static final String CHINA_DEFAULT = "yyyy-MM-dd HH:mm:ss";
+
+		public static final String YYYY_MM = "yyyy-MM";
+
+		public static final String YYYY_MM_DD = "yyyy-MM-dd";
+
+		public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
+
+		public static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
+	}
+
+	/**
+	 * get now date.
+	 * 
+	 * @param pattern
+	 * @return
+	 */
+	public static String now(String pattern) {
+		return format(new Date(), pattern);
+	}
+
+	/**
+	 * get now china date.
+	 * 
+	 * @return
+	 */
+	public static String chinaNow() {
+		return format(new Date(), DatePatterns.CHINA_DEFAULT);
+	}
+
+	/**
+	 * format date.
+	 * 
+	 * @param date
+	 * @param pattern
+	 * @return
+	 */
+	public static String format(Date date, String pattern) {
+		if(date==null) {
+			return null;
+		}
+		try {
+			SimpleDateFormat df = new SimpleDateFormat(pattern);
+			return df.format(date);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * format now date.
+	 *
+	 * @author 
+	 * @param pattern
+	 * @return
+	 */
+	public static String formatNow(String pattern) {
+		try {
+			SimpleDateFormat df = new SimpleDateFormat(pattern);
+			return df.format(new Date());
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * parse date.
+	 * 
+	 * @param source
+	 * @param pattern
+	 * @return
+	 */
+	public static Date parse(String source, String pattern) {
+		SimpleDateFormat df = new SimpleDateFormat(pattern);
+		try {
+			return df.parse(source);
+		} catch (ParseException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * parse date randomly.
+	 *
+	 * @author 
+	 * @param s
+	 * @return
+	 */
+	public static Date parseRandomly(String s) {
+		if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
+			return parse(s, "yyyy/MM/dd HH:mm:ss");
+		} else if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{1,2}")) {
+			return parse(s, "yyyy/MM/dd HH:mm");
+		} else if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}")) {
+			return parse(s, "yyyy/MM/dd");
+		} else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
+			return parse(s, "yyyy-MM-dd HH:mm:ss");
+		} else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}")) {
+			return parse(s, "yyyy-MM-dd HH:mm");
+		} else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
+			return parse(s, "yyyy-MM-dd");
+		} else {
+			throw new StatusException("unsupported date string.");
+		}
+	}
+
+	/**
+	 * 解析excel日期
+	 *
+	 * @author 
+	 * @param number
+	 * @return
+	 */
+	public static Date parseExcel(String number) {
+
+		BigDecimal bd = new BigDecimal(number);
+		int days = bd.intValue();
+		int mills = (int) Math.round(bd.subtract(new BigDecimal(days)).doubleValue() * 24 * 3600);
+
+		Calendar c = Calendar.getInstance();
+		c.set(1900, 0, 1);
+		c.add(Calendar.DATE, days - 2);
+		int hour = mills / 3600;
+		int minute = (mills - hour * 3600) / 60;
+		int second = mills - hour * 3600 - minute * 60;
+		c.set(Calendar.HOUR_OF_DAY, hour);
+		c.set(Calendar.MINUTE, minute);
+		c.set(Calendar.SECOND, second);
+
+		Date date = c.getTime();
+
+		return date;
+	}
+
+	/**
+	 * 是否同一天
+	 *
+	 * @author 
+	 * @param date1
+	 * @param date2
+	 * @return
+	 */
+	public static boolean isSameDay(Date date1, Date date2) {
+		if (null == date1) {
+			throw new StatusException("first argument must not be null");
+		}
+		if (null == date2) {
+			throw new StatusException("second argument must not be null");
+		}
+
+		Calendar cal1 = Calendar.getInstance();
+		cal1.setTime(date1);
+		Calendar cal2 = Calendar.getInstance();
+		cal2.setTime(date2);
+		return isSameDay(cal1, cal2);
+	}
+
+	/**
+	 * 是否同一天
+	 *
+	 * @author 
+	 * @param calendar1
+	 * @param calendar2
+	 * @return
+	 */
+	public static boolean isSameDay(Calendar calendar1, Calendar calendar2) {
+		if (null == calendar1) {
+			throw new StatusException("first argument must not be null");
+		}
+		if (null == calendar2) {
+			throw new StatusException("second argument must not be null");
+		}
+		return calendar1.get(0) == calendar2.get(0) && calendar1.get(1) == calendar2.get(1)
+				&& calendar1.get(6) == calendar2.get(6);
+	}
+
+}

+ 90 - 0
src/main/java/cn/com/qmth/mps/util/FileUtil.java

@@ -0,0 +1,90 @@
+package cn.com.qmth.mps.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import com.qmth.boot.core.exception.StatusException;
+
+public class FileUtil {
+
+	public static String readFileContent(InputStream in) {
+		StringBuilder content = new StringBuilder();
+		InputStreamReader streamReader = null;
+		BufferedReader bufferedReader = null;
+		try {
+			String encoding = "UTF-8";
+			streamReader = new InputStreamReader(in, encoding);
+			bufferedReader = new BufferedReader(streamReader);
+			String line;
+			while ((line = bufferedReader.readLine()) != null) {
+				content.append(line);
+			}
+			return content.toString();
+		} catch (IOException e) {
+			throw new StatusException("出错", e);
+		} finally {
+			if(streamReader!=null) {
+				try {
+					streamReader.close();
+				} catch (IOException e) {
+				}
+			}
+			if(bufferedReader!=null) {
+				try {
+					bufferedReader.close();
+				} catch (IOException e) {
+				}
+			}
+			if(in!=null) {
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+			}
+		}
+	}
+
+	/**
+	 * 获得文件的byte数组
+	 * 
+	 * @param filePath
+	 * @return
+	 * @throws IOException
+	 */
+	public static byte[] getBytes(String filePath) throws IOException {
+		File file = new File(filePath);
+		if (!file.exists()) {
+			throw new FileNotFoundException(filePath);
+		}
+
+		ByteArrayOutputStream bos = new ByteArrayOutputStream(((int) file.length()));
+		BufferedInputStream in = null;
+		try {
+			in = new BufferedInputStream(new FileInputStream(file));
+			int bufSize = 1024;
+			byte[] buffer = new byte[bufSize];
+			int len = 0;
+			while (-1 != (len = in.read(buffer, 0, bufSize))) {
+				bos.write(buffer, 0, len);
+			}
+			return bos.toByteArray();
+		} finally {
+			try {
+				if (in != null) {
+					in.close();
+				}
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			bos.close();
+		}
+	}
+
+}

+ 64 - 0
src/main/java/cn/com/qmth/mps/util/IpUtil.java

@@ -0,0 +1,64 @@
+package cn.com.qmth.mps.util;
+
+import org.apache.commons.lang3.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @Description 获取ip工具类
+ */
+public class IpUtil {
+
+    /**
+     * 获取过程ip(默认不包含代理ip)
+     *
+     * @param request
+     * @return
+     */
+    public static String getRemoteIp(HttpServletRequest request) {
+        return getRemoteIp(request, true);
+    }
+
+    /**
+     * excludeProxyIp
+     *
+     * @param request
+     * @param excludeProxyIp 是否排除代理ip
+     * @return
+     */
+    public static String getRemoteIp(HttpServletRequest request, boolean excludeProxyIp) {
+        String ip = request.getHeader("X-Forwarded-For");
+        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("x-real-ip");
+        }
+        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_CLIENT_IP");
+        }
+        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+        }
+        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+
+        if (excludeProxyIp) {
+            //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+            if (ip != null && ip.length() > 15) { //"***.***.***.***".length() = 15
+                if (ip.indexOf(",") > 0) {
+                    ip = ip.substring(0, ip.indexOf(","));
+                }
+            }
+        }
+        if("0:0:0:0:0:0:0:1".equals(ip)) {
+        	ip="127.0.0.1";
+        }
+        return ip;
+    }
+
+}

+ 255 - 0
src/main/java/cn/com/qmth/mps/util/JsonMapper.java

@@ -0,0 +1,255 @@
+package cn.com.qmth.mps.util;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.util.JSONPObject;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 简单封装Jackson,实现JSON 与 Java Object互相转换的Mapper
+ * 封装不同的输出风格, 使用不同的builder函数创建实例
+ */
+@SuppressWarnings({"rawtypes","unchecked"})
+public class JsonMapper {
+
+    private static Logger log = LoggerFactory.getLogger(JsonMapper.class);
+
+    private ObjectMapper mapper;
+
+    /**
+     * 默认构造JsonMapper
+     */
+    public JsonMapper() {
+        this(null);
+    }
+
+    /**
+     * 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式
+     */
+    public static JsonMapper nonDefaultMapper() {
+        return new JsonMapper(Include.NON_DEFAULT);
+    }
+
+    /**
+     * 创建只输出非Null且非Empty的属性到Json字符串的Mapper
+     */
+    public static JsonMapper nonEmptyMapper() {
+        return new JsonMapper(Include.NON_EMPTY);
+    }
+
+    /**
+     * 创建只输出非Null的属性到Json字符串的Mapper
+     */
+    public static JsonMapper nonNullMapper() {
+        return new JsonMapper(Include.NON_NULL);
+    }
+
+    /**
+     * 构造JsonMapper
+     */
+    public JsonMapper(Include include) {
+        mapper = new ObjectMapper();
+
+        //设置输出时包含属性的风格
+        if (include != null) {
+            mapper.setSerializationInclusion(include);
+        }
+
+        //设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
+        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+        //忽略无法转换的对象
+        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+
+        //设置默认日期格式
+        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+    }
+
+    /**
+     * Object可以是POJO,也可以是Collection或数组
+     * 如果对象为Null, 返回"null"
+     * 如果集合为空集合, 返回"[]"
+     */
+    public String toJson(Object object) {
+        if (object == null) {
+            return null;
+        }
+
+        try {
+            return mapper.writeValueAsString(object);
+        } catch (IOException e) {
+            log.error("toJson error!" + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 反序列化POJO或简单Collection如List<String>
+     * 如果JSON字符串为Null或"null"字符串, 返回Null
+     * 如果JSON字符串为"[]", 返回空集合
+     * 如需反序列化复杂Collection如List<MyBean>, 请使用parseJson(String, JavaType)
+     */
+    public <T> T parseJson(String jsonStr, Class<T> clazz) {
+        if (StringUtils.isEmpty(jsonStr)) {
+            return null;
+        }
+
+        try {
+            return mapper.readValue(jsonStr, clazz);
+        } catch (IOException e) {
+            log.error("parseJson error!" + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 反序列化复杂Collection如List<Bean>, 先使用createCollectionType()或constructMapType()构造类型, 然后调用本函数
+     */
+	public <T> T parseJson(String jsonStr, JavaType javaType) {
+        if (StringUtils.isEmpty(jsonStr)) {
+            return null;
+        }
+
+        try {
+            return (T) mapper.readValue(jsonStr, javaType);
+        } catch (IOException e) {
+            log.error("parseJson error!" + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 反序列化复杂的对象,如Page<Bean>
+     */
+	public <T> T parseJson(String jsonStr, TypeReference javaType) {
+        if (StringUtils.isEmpty(jsonStr)) {
+            return null;
+        }
+
+        try {
+            return (T) mapper.readValue(jsonStr, javaType);
+        } catch (IOException e) {
+            log.error("parseJson error!" + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Json to List
+     */
+    public <T> List<T> toList(String jsonStr, Class<T> bean) {
+        if (StringUtils.isEmpty(jsonStr)) {
+            return null;
+        }
+
+        try {
+            JavaType javaType = constructCollectionType(List.class, bean);
+            return mapper.readValue(jsonStr, javaType);
+        } catch (IOException e) {
+            log.error("parseJson error!" + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Json to HashMap
+     */
+    public <T> Map<String, T> toHashMap(String jsonStr, Class<T> bean) {
+        if (StringUtils.isEmpty(jsonStr)) {
+            return null;
+        }
+
+        try {
+            JavaType javaType = constructMapType(HashMap.class, String.class, bean);
+            return mapper.readValue(jsonStr, javaType);
+        } catch (IOException e) {
+            log.error("parseJson error!" + e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 构造Collection类型
+     */
+    public JavaType constructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
+        return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
+    }
+
+    /**
+     * 构造Map类型
+     */
+    public JavaType constructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
+        return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
+    }
+
+    /**
+     * 当JSON里只含有Bean的部分属性時,更新一個已存在Bean,只覆盖該部分的属性
+     */
+    public void update(String jsonStr, Object object) {
+        if (jsonStr == null) {
+            return;
+        }
+
+        try {
+            mapper.readerForUpdating(object).readValue(jsonStr);
+        } catch (JsonProcessingException e) {
+            log.error("updateJson error!" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 輸出JSONP格式数据
+     */
+    public String toJsonP(String functionName, Object object) {
+        if (object == null) {
+            return null;
+        }
+
+        return toJson(new JSONPObject(functionName, object));
+    }
+
+    /**
+     * 設定是否使用Enum的toString函数來读写Enum
+     * 为False時使用Enum的name()函数來读写Enum, 默认为False
+     * 注意本函数一定要在Mapper創建後, 所有的读写動作之前調用
+     */
+    public void enableEnumUseToString() {
+        mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
+        mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+    }
+
+    /**
+     * 取出Mapper做进一步的设置或使用其他序列化API
+     */
+    public ObjectMapper getMapper() {
+        return mapper;
+    }
+
+    /***
+     * 把Json字符串转换成Node对象
+     */
+    public JsonNode getNode(String jsonStr) {
+        if (jsonStr == null) {
+            return null;
+        }
+
+        try {
+            //mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
+            return mapper.readTree(jsonStr);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+    }
+
+}

+ 171 - 0
src/main/java/cn/com/qmth/mps/util/JsonUtil.java

@@ -0,0 +1,171 @@
+package cn.com.qmth.mps.util;
+
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import com.google.common.collect.Maps;
+import com.google.gson.ExclusionStrategy;
+import com.google.gson.FieldAttributes;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import cn.com.qmth.mps.util.DateUtil.DatePatterns;
+
+/**
+ * json tool
+ *
+ * @author 
+ * @param <T>
+ * @date 2019年1月16日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class JsonUtil {
+
+	/**
+	 * to json
+	 *
+	 * @author 
+	 * @param obj
+	 * @return
+	 */
+	public static String toJson(Object obj) {
+		GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().serializeNulls()
+				.setDateFormat(DatePatterns.CHINA_DEFAULT);
+		return builder.create().toJson(obj);
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author 
+	 * @param obj
+	 * @param excludeFields
+	 * @return
+	 */
+	public static String toJson(Object obj, String... excludeFields) {
+		GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().serializeNulls()
+				.setDateFormat(DatePatterns.CHINA_DEFAULT);
+
+		builder.setExclusionStrategies(new ExclusionStrategy() {
+			@Override
+			public boolean shouldSkipField(FieldAttributes f) {
+				for (String field : excludeFields) {
+					if (f.getName().matches(field)) {
+						return true;
+					}
+				}
+
+				return false;
+			}
+
+			@Override
+			public boolean shouldSkipClass(Class<?> clazz) {
+				return false;
+			}
+		});
+
+		return builder.create().toJson(obj);
+	}
+
+	/**
+	 * to pretty json
+	 *
+	 * @author 
+	 * @param obj
+	 * @return
+	 */
+	public static String toPrettyJson(Object obj) {
+		GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
+				.serializeNulls().setDateFormat(DatePatterns.CHINA_DEFAULT);
+		return builder.create().toJson(obj);
+	}
+
+	/**
+	 * 格式化json
+	 *
+	 * @author 
+	 * @param json
+	 * @return
+	 */
+	public static String format(String json) {
+		if (null == json) {
+			return json;
+		}
+		JsonElement jsonEl = JsonParser.parseString(json);
+		return toPrettyJson(jsonEl);
+	}
+
+	/**
+	 * json转对象
+	 *
+	 * @author 
+	 * @param json
+	 * @param c
+	 * @return
+	 */
+	public static <T> T fromJson(String json, Class<T> c) {
+		Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
+				.setDateFormat(DatePatterns.CHINA_DEFAULT).create();
+		return gson.fromJson(json, c);
+	}
+
+	/**
+	 * json数组转list
+	 *
+	 * @author 
+	 * @param json
+	 * @param elementType
+	 * @return
+	 */
+	public static <T> List<T> fromJsonArray(String json, Class<T[]> elementType) {
+		Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
+				.setDateFormat(DatePatterns.CHINA_DEFAULT).create();
+		T[] array = gson.fromJson(json, elementType);
+		return Arrays.asList(array);
+	}
+
+	/**
+	 * simple json to map
+	 *
+	 * @author 
+	 * @param s
+	 * @return
+	 */
+	public static Map<String, String> json2Map(String s) {
+		JsonElement jsonElement = JsonParser.parseString(s);
+		JsonObject jsonObject = jsonElement.getAsJsonObject();
+		Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
+
+		Map<String, String> map = Maps.newHashMap();
+		for (Entry<String, JsonElement> entry : entrySet) {
+			JsonElement e = entry.getValue();
+			if (!e.isJsonNull()) {
+				String v = e.getAsString();
+				map.put(entry.getKey(), v);
+			}
+		}
+		return map;
+	}
+
+	/**
+	 * json转对象
+	 *
+	 * @author 
+	 * @param json
+	 * @param type
+	 * @return
+	 */
+	public static <T> T fromJson(String json, Type type) {
+		Gson gson = new GsonBuilder().disableHtmlEscaping()
+				.setDateFormat(DatePatterns.CHINA_DEFAULT).create();
+		return gson.fromJson(json, type);
+	}
+
+}

+ 93 - 0
src/main/java/cn/com/qmth/mps/util/MD5Util.java

@@ -0,0 +1,93 @@
+package cn.com.qmth.mps.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.commons.codec.digest.DigestUtils;
+
+/**
+ * @Description: MD5加密工具类
+ */
+public class MD5Util {
+	public static final String CHARSET_NAME = "UTF-8";
+
+    public static final Charset CHARSET = Charset.forName(CHARSET_NAME);
+    
+    public static final String MD5 = "MD5";
+
+    /**
+     * MD5加密
+     *
+     * @param text
+     * @return
+     * @throws Exception
+     */
+    public static String encoder(String text) throws NoSuchAlgorithmException {
+        text = Optional.of(text).get();
+        MessageDigest digest = MessageDigest.getInstance(MD5);
+        digest.update(text.getBytes(CHARSET));
+        byte s[] = digest.digest();
+        StringJoiner result = new StringJoiner("");
+        for (int i = 0; i < s.length; i++) {
+            result.add(Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6));
+        }
+        return result.toString();
+    }
+
+    /**
+     * MD5校验
+     *
+     * @param text
+     * @param md5
+     * @return
+     * @throws Exception
+     */
+    public static boolean verify(String text, String md5) throws NoSuchAlgorithmException {
+        text = Optional.of(text).get();
+        md5 = Optional.of(md5).get();
+        //根据传入的密钥进行验证
+        String md5Text = encoder(text);
+        if (md5Text.equalsIgnoreCase(md5)) {
+            return true;
+        }
+        return false;
+    }
+    
+	public static String md5Hex(File file) {
+		FileInputStream in = null;
+		try {
+			in = new FileInputStream(file);
+			return DigestUtils.md5Hex(in);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		} finally {
+			if(in!=null)
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+		}
+	}
+	
+	public static String md5Hex(InputStream in) {
+		try {
+			return DigestUtils.md5Hex(in);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		} finally {
+			if(in!=null)
+				try {
+					in.close();
+				} catch (IOException e) {
+				}
+		}
+	}
+}
+

+ 69 - 0
src/main/java/cn/com/qmth/mps/util/ObjectUtil.java

@@ -0,0 +1,69 @@
+package cn.com.qmth.mps.util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 对象工具
+ *
+ * @author 
+ */
+public final class ObjectUtil {
+
+	/**
+	 * 判断对象或对象数组中每一个对象是否为空: 对象为null,字符序列长度为0,集合类、Map为empty
+	 *
+	 * @author 
+	 * @param obj
+	 * @return
+	 */
+	public static boolean isNullOrEmpty(Object obj) {
+		if (obj == null)
+			return true;
+
+		if (obj instanceof CharSequence)
+			return ((CharSequence) obj).length() == 0;
+
+		if (obj instanceof Collection)
+			return ((Collection<?>) obj).isEmpty();
+
+		if (obj instanceof Map)
+			return ((Map<?, ?>) obj).isEmpty();
+
+		if (obj instanceof Object[]) {
+			Object[] object = (Object[]) obj;
+			if (object.length == 0) {
+				return true;
+			}
+			boolean empty = true;
+			for (int i = 0; i < object.length; i++) {
+				if (!isNullOrEmpty(object[i])) {
+					empty = false;
+					break;
+				}
+			}
+			return empty;
+		}
+		return false;
+	}
+
+	/**
+	 * 判断一个类是否为基本数据类型
+	 *
+	 * @author 
+	 * @param clazz
+	 * @return
+	 */
+	public static boolean isBaseDataType(Class<?> clazz) {
+		Boolean isBaseType = (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class)
+				|| clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
+				|| clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)
+				|| clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class)
+				|| clazz.isPrimitive());
+		return isBaseType;
+	}
+
+}

+ 88 - 0
src/main/java/cn/com/qmth/mps/util/PageUtil.java

@@ -0,0 +1,88 @@
+package cn.com.qmth.mps.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.boot.core.collection.PageResult;
+
+public class PageUtil {
+	public static <T> PageResult<T> of(IPage<T> iPage) {
+        PageResult<T> result = new PageResult<>();
+        result.setResult(iPage.getRecords());
+        result.setPageNumber(iPage.getCurrent());
+        result.setPageSize(iPage.getPages());
+        result.setTotalCount(iPage.getTotal());
+        result.setPageCount(iPage.getPages());
+        return result;
+	}
+	
+	
+	 /**
+     * 开始分页
+     * 
+     * @param list
+     * @param pageNum
+     *            页码
+     * @param pageSize
+     *            每页多少条数据
+     * @return
+     */
+    public static <T> List<T> startPage(List<T> list, Integer pageNum, Integer pageSize) {
+        if (list == null) {
+            return null;
+        }
+        if (list.size() == 0) {
+            return null;
+        }
+
+        Integer count = list.size(); // 记录总数
+        Integer pageCount = pageCount(list, pageNum, pageSize);
+
+        int fromIndex = 0; // 开始索引
+        int toIndex = 0; // 结束索引
+
+        if (pageCount < pageNum) {
+            return null;
+        }
+        if (pageCount - pageNum != 0) {
+            fromIndex = (pageNum - 1) * pageSize;
+            toIndex = fromIndex + pageSize;
+        } else {
+            fromIndex = (pageNum - 1) * pageSize;
+            toIndex = count;
+        }
+
+        List<T> pageList = list.subList(fromIndex, toIndex);
+
+        return pageList;
+    }
+
+    public static <T> Integer pageCount(List<T> list, Integer pageNum, Integer pageSize) {
+        if (list == null) {
+            return 0;
+        }
+        if (list.size() == 0) {
+            return 0;
+        }
+        Integer count = list.size(); // 记录总数
+        Integer pageCount = 0; // 页数
+        if (count % pageSize == 0) {
+            pageCount = count / pageSize;
+        } else {
+            pageCount = count / pageSize + 1;
+        }
+
+        return pageCount;
+    }
+    
+	public static <T> PageResult<T> emptyPage(){
+    	PageResult<T> page=new PageResult<>();
+    	page.setPageCount(0);
+    	page.setPageNumber(1);
+    	page.setPageSize(10);
+    	page.setTotalCount(0);
+    	page.setResult(new ArrayList<>());
+    	return page;
+    }
+}

+ 45 - 0
src/main/java/cn/com/qmth/mps/util/PagerQuery.java

@@ -0,0 +1,45 @@
+/*
+ * *************************************************
+ * Copyright (c) 2019 QMTH. All Rights Reserved. Created by Deason on 2019-09-24
+ * 14:10:50. *************************************************
+ */
+
+package cn.com.qmth.mps.util;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class PagerQuery {
+
+    @ApiModelProperty(value = "第几页(从1开始)")
+    protected Integer pageNumber;
+
+    @ApiModelProperty(value = "每页条数")
+    protected Integer pageSize;
+
+    public Integer getPageNumber() {
+        // 默认值
+        if (pageNumber == null || pageNumber < 1) {
+        	pageNumber = 1;
+        }
+
+        return pageNumber;
+    }
+
+    public Integer getPageSize() {
+        // 默认值
+        if (pageSize == null || pageSize < 1) {
+            pageSize = 10;
+        }
+
+        return pageSize;
+    }
+
+    public void setPageNumber(Integer pageNumber) {
+        this.pageNumber = pageNumber;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+}

+ 37 - 0
src/main/java/cn/com/qmth/mps/util/ResouceUtil.java

@@ -0,0 +1,37 @@
+package cn.com.qmth.mps.util;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class ResouceUtil {
+	public static URL getUrl(String path) {
+		try {
+			ClassLoader classLoader = ResouceUtil.class.getClassLoader();
+
+			URL url = classLoader.getResource(path);
+			return url;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+	public static InputStream getStream(String path) {
+		try {
+			ClassLoader classLoader = ResouceUtil.class.getClassLoader();
+
+			URL url = classLoader.getResource(path);
+			return url.openStream();
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+	public static String getContent(String path) {
+		try {
+			ClassLoader classLoader = ResouceUtil.class.getClassLoader();
+
+			URL url = classLoader.getResource(path);
+			return FileUtil.readFileContent(url.openStream());
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+}

+ 126 - 0
src/main/java/cn/com/qmth/mps/util/ServletUtil.java

@@ -0,0 +1,126 @@
+package cn.com.qmth.mps.util;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import cn.com.qmth.mps.bean.User;
+
+
+/**
+ * servlet 工具
+ *
+ */
+public class ServletUtil {
+
+	/**
+	 * 接口日志
+	 */
+	private static final Logger LOG = LoggerFactory.getLogger(ServletUtil.class);
+
+	public static User getSessionUser() {
+		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
+				.getRequestAttributes();
+		if (requestAttributes == null) {
+			return null;
+		}
+		HttpServletRequest request = requestAttributes.getRequest();
+		if (request == null) {
+			return null;
+		}
+		User user = (User) ServletUtil.getRequest().getAttribute("accessEntity");
+		if (null == user) {
+			return null;
+		}
+		return user;
+	}
+
+	/**
+	 * 获取request对象
+	 *
+	 * @return
+	 */
+	public static HttpServletRequest getRequest() {
+		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
+				.getRequestAttributes();
+		if (requestAttributes == null) {
+			return null;
+		}
+		HttpServletRequest request = requestAttributes.getRequest();
+		return request;
+	}
+
+	/**
+	 * 获取response对象
+	 *
+	 * @return
+	 */
+	public static HttpServletResponse getResponse() {
+		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
+				.getRequestAttributes();
+		HttpServletResponse response = requestAttributes.getResponse();
+		return response;
+	}
+
+	/**
+	 * 输出响应流
+	 *
+	 * @param response
+	 * @author
+	 */
+	public static void returnJson(Object body, HttpServletResponse response) {
+		response.setContentType("application/json;charset=utf-8");
+		PrintWriter writer = null;
+		try {
+			writer = response.getWriter();
+			String json = "{}";
+			if (null != body) {
+				json = JsonUtil.toJson(body);
+			}
+			writer.write(json);
+
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("responseMsg = " + json);
+			}
+		} catch (IOException e) {
+			LOG.error("returnJson fail... " + e.getMessage(), e);
+		} finally {
+			if (writer != null) {
+				writer.close();
+			}
+		}
+	}
+
+	/**
+	 * 输出响应流(无日志)
+	 *
+	 * @param response
+	 * @author
+	 */
+	public static void returnJsonWithoutLog(Object body, HttpServletResponse response) {
+		response.setContentType("application/json;charset=utf-8");
+		PrintWriter writer = null;
+		try {
+			writer = response.getWriter();
+			String json = "{}";
+			if (null != body) {
+				json = JsonUtil.toJson(body);
+			}
+			writer.write(json);
+		} catch (IOException e) {
+			// ignore
+		} finally {
+			if (writer != null) {
+				writer.close();
+			}
+		}
+	}
+
+}

+ 121 - 0
src/main/java/cn/com/qmth/mps/util/ThreadLocalUtil.java

@@ -0,0 +1,121 @@
+package cn.com.qmth.mps.util;
+
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.google.common.collect.Maps;
+import com.qmth.boot.tools.uuid.FastUUID;
+
+/**
+ * 线程本地化工具
+ *
+ * @author 
+ */
+public class ThreadLocalUtil {
+	/**
+	 * trace ID
+	 */
+	private static final ThreadLocal<String> LOCAL_TRACE_ID = new ThreadLocal<String>() {
+		@Override
+		public String initialValue() {
+			return null;
+		}
+	};
+
+	/**
+	 * map
+	 */
+	private static final ThreadLocal<Map<String, Object>> LOCAL_TRACE_MAP = new ThreadLocal<Map<String, Object>>() {
+		@Override
+		public Map<String, Object> initialValue() {
+			return null;
+		}
+	};
+
+	/**
+	 * 重新初始化
+	 *
+	 * @author 
+	 * @return
+	 */
+	public static String next() {
+		LOCAL_TRACE_MAP.set(null);
+		String traceID = FastUUID.get();
+		setTraceId(traceID);
+		return traceID;
+	}
+
+	/**
+	 * 获取 trace ID
+	 *
+	 * @author 
+	 * @return
+	 */
+	public static String getTraceId() {
+		String traceID = LOCAL_TRACE_ID.get();
+		if (traceID == null) {
+			traceID = next();
+		} else {
+			return traceID;
+		}
+
+		return traceID;
+	}
+
+	/**
+	 * 设置 trace ID
+	 *
+	 * @author 
+	 * @param traceId
+	 */
+	public static void setTraceId(String traceId) {
+		if (!(StringUtils.isNotBlank(traceId)))
+			return;
+		LOCAL_TRACE_ID.set(traceId);
+	}
+
+	/**
+	 * 设置属性
+	 *
+	 * @author 
+	 * @param key
+	 * @param value
+	 */
+	public static void set(String key, Object value) {
+		Map<String, Object> map = LOCAL_TRACE_MAP.get();
+
+		if (null == map) {
+			map = Maps.newHashMap();
+			LOCAL_TRACE_MAP.set(map);
+		}
+		map.put(key, value);
+	}
+
+	/**
+	 * 获取属性
+	 *
+	 * @author 
+	 * @param key
+	 * @return
+	 */
+	public static Object get(String key) {
+		Map<String, Object> map = LOCAL_TRACE_MAP.get();
+		if (null == map) {
+			return null;
+		}
+		return map.get(key);
+	}
+
+	/**
+	 * 清理属性
+	 *
+	 * @author 
+	 */
+	public static void clearAll() {
+		Map<String, Object> map = LOCAL_TRACE_MAP.get();
+		if (null != map) {
+			map.clear();
+		}
+	}
+}

+ 33 - 0
src/main/resources/application-test.properties

@@ -0,0 +1,33 @@
+#
+# ********** server config **********
+#
+server.port=7102
+server.servlet.session.timeout=PT2H
+server.servlet.context-path=/
+spring.servlet.multipart.max-request-size=100MB
+spring.servlet.multipart.max-file-size=100MB
+com.qmth.mybatis.logLevel=debug
+#
+# ********** db config **********
+#
+db.host=localhost
+db.port=3306
+db.database=union_question_dev
+com.qmth.datasource.username=root
+com.qmth.datasource.password=123456
+com.qmth.datasource.url=jdbc:mysql://${db.host}:${db.port}/${db.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2b8&rewriteBatchedStatements=true
+
+#
+# ********** sys config **********
+#
+com.qmth.logging.root-level=info
+com.qmth.logging.file-path=/home/admin/project/union-question/log/union-question.log
+
+#DISK
+com.qmth.fss.config=/home/admin/project/union-question/static
+com.qmth.fss.server=http://localhost:7001/file
+
+spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
+spring.jackson.time-zone=GMT+8
+
+heartbeat-timeout=600

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

@@ -0,0 +1,33 @@
+#
+# ********** server config **********
+#
+server.port=7102
+server.servlet.session.timeout=PT2H
+server.servlet.context-path=/
+spring.servlet.multipart.max-request-size=100MB
+spring.servlet.multipart.max-file-size=100MB
+com.qmth.mybatis.logLevel=debug
+#
+# ********** db config **********
+#
+db.host=localhost
+db.port=3306
+db.database=union_question_dev
+com.qmth.datasource.username=root
+com.qmth.datasource.password=123456
+com.qmth.datasource.url=jdbc:mysql://${db.host}:${db.port}/${db.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2b8&rewriteBatchedStatements=true
+
+#
+# ********** sys config **********
+#
+com.qmth.logging.root-level=info
+com.qmth.logging.file-path=/home/admin/project/union-question/log/union-question.log
+
+#DISK
+com.qmth.fss.config=/home/admin/project/union-question/static
+com.qmth.fss.server=http://localhost:7001/file
+
+spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
+spring.jackson.time-zone=GMT+8
+
+session-timeout=600