瀏覽代碼

first submit

Administrator 2 年之前
當前提交
996d1d7a99
共有 100 個文件被更改,包括 6931 次插入0 次删除
  1. 2 0
      .gitignore
  2. 275 0
      pom.xml
  3. 35 0
      src/main/java/com/sysu/admin/MarkApplication.java
  4. 281 0
      src/main/java/com/sysu/admin/controller/MainController.java
  5. 22 0
      src/main/java/com/sysu/admin/controller/analyse/Analyse.java
  6. 32 0
      src/main/java/com/sysu/admin/controller/analyse/AnalyseController.java
  7. 23 0
      src/main/java/com/sysu/admin/controller/analyse/AnalyseRow.java
  8. 14 0
      src/main/java/com/sysu/admin/controller/analyse/AnalyseService.java
  9. 33 0
      src/main/java/com/sysu/admin/controller/analyse/AnalyseServiceManager.java
  10. 26 0
      src/main/java/com/sysu/admin/controller/analyse/AnalyseTable.java
  11. 34 0
      src/main/java/com/sysu/admin/controller/analyse/AnalyseType.java
  12. 112 0
      src/main/java/com/sysu/admin/controller/analyse/CropAnalyseService.java
  13. 69 0
      src/main/java/com/sysu/admin/controller/analyse/TownsAnalyseService.java
  14. 70 0
      src/main/java/com/sysu/admin/controller/analyse/VillageAnalyseService.java
  15. 35 0
      src/main/java/com/sysu/admin/controller/geo/CityLand.java
  16. 15 0
      src/main/java/com/sysu/admin/controller/geo/CityLandRepository.java
  17. 20 0
      src/main/java/com/sysu/admin/controller/geo/CityLandService.java
  18. 72 0
      src/main/java/com/sysu/admin/controller/geo/PostGisInfoController.java
  19. 24 0
      src/main/java/com/sysu/admin/controller/geo/SldStyleController.java
  20. 50 0
      src/main/java/com/sysu/admin/controller/geo/qyz/QyzController.java
  21. 4 0
      src/main/java/com/sysu/admin/controller/resource/Resource.java
  22. 70 0
      src/main/java/com/sysu/admin/controller/upload/UploadRecord.java
  23. 55 0
      src/main/java/com/sysu/admin/controller/upload/UploadRecordController.java
  24. 8 0
      src/main/java/com/sysu/admin/controller/upload/UploadRecordRepository.java
  25. 35 0
      src/main/java/com/sysu/admin/support/base/BaseComponent.java
  26. 100 0
      src/main/java/com/sysu/admin/support/base/BaseService.java
  27. 42 0
      src/main/java/com/sysu/admin/support/base/BaseVo.java
  28. 33 0
      src/main/java/com/sysu/admin/support/base/RepositoryContext.java
  29. 79 0
      src/main/java/com/sysu/admin/support/base/ServiceContext.java
  30. 40 0
      src/main/java/com/sysu/admin/support/cfg/CorsConfig.java
  31. 30 0
      src/main/java/com/sysu/admin/support/cfg/GoCfg.java
  32. 135 0
      src/main/java/com/sysu/admin/support/cfg/ShiroCfg.java
  33. 33 0
      src/main/java/com/sysu/admin/support/cfg/ThreadContext.java
  34. 28 0
      src/main/java/com/sysu/admin/support/shiro/ShiroAuditorAware.java
  35. 183 0
      src/main/java/com/sysu/admin/support/shiro/ShiroAuthenRealm.java
  36. 32 0
      src/main/java/com/sysu/admin/support/shiro/ShiroPrincipal.java
  37. 43 0
      src/main/java/com/sysu/admin/support/shiro/ShiroRestExceptionAdvice.java
  38. 158 0
      src/main/java/com/sysu/admin/support/shiro/ShiroService.java
  39. 33 0
      src/main/java/com/sysu/admin/support/shiro/ShiroToken.java
  40. 28 0
      src/main/java/com/sysu/admin/support/system/config/ActiveContext.java
  41. 54 0
      src/main/java/com/sysu/admin/support/system/config/SConfig.java
  42. 116 0
      src/main/java/com/sysu/admin/support/system/config/SConfigController.java
  43. 18 0
      src/main/java/com/sysu/admin/support/system/config/SConfigRepository.java
  44. 39 0
      src/main/java/com/sysu/admin/support/system/config/SConfigService.java
  45. 84 0
      src/main/java/com/sysu/admin/support/system/menu/SMenu.java
  46. 143 0
      src/main/java/com/sysu/admin/support/system/menu/SMenuController.java
  47. 18 0
      src/main/java/com/sysu/admin/support/system/menu/SMenuRepository.java
  48. 50 0
      src/main/java/com/sysu/admin/support/system/menu/SMenuResBO.java
  49. 95 0
      src/main/java/com/sysu/admin/support/system/menu/SMenuService.java
  50. 107 0
      src/main/java/com/sysu/admin/support/system/menu/SMenuTreeHelper.java
  51. 150 0
      src/main/java/com/sysu/admin/support/system/organ/Organ.java
  52. 206 0
      src/main/java/com/sysu/admin/support/system/organ/OrganController.java
  53. 19 0
      src/main/java/com/sysu/admin/support/system/organ/OrganRepository.java
  54. 69 0
      src/main/java/com/sysu/admin/support/system/organ/OrganService.java
  55. 88 0
      src/main/java/com/sysu/admin/support/system/region/Region.java
  56. 16 0
      src/main/java/com/sysu/admin/support/system/region/RegionRepository.java
  57. 80 0
      src/main/java/com/sysu/admin/support/system/role/SRole.java
  58. 147 0
      src/main/java/com/sysu/admin/support/system/role/SRoleController.java
  59. 6 0
      src/main/java/com/sysu/admin/support/system/role/SRoleRepository.java
  60. 45 0
      src/main/java/com/sysu/admin/support/system/role_permission/PKRP.java
  61. 45 0
      src/main/java/com/sysu/admin/support/system/role_permission/RolePermission.java
  62. 12 0
      src/main/java/com/sysu/admin/support/system/role_permission/RolePermissionRepository.java
  63. 48 0
      src/main/java/com/sysu/admin/support/system/role_permission/RolePermissionService.java
  64. 157 0
      src/main/java/com/sysu/admin/support/system/user/User.java
  65. 351 0
      src/main/java/com/sysu/admin/support/system/user/UserController.java
  66. 37 0
      src/main/java/com/sysu/admin/support/system/user/UserRepository.java
  67. 22 0
      src/main/java/com/sysu/admin/support/system/user/UserService.java
  68. 28 0
      src/main/java/com/sysu/admin/support/system/user/UserTreeNode.java
  69. 32 0
      src/main/java/com/sysu/admin/support/system/user/UserTreeNodeUtil.java
  70. 43 0
      src/main/java/com/sysu/admin/support/system/user_role/PKUR.java
  71. 34 0
      src/main/java/com/sysu/admin/support/system/user_role/UserRole.java
  72. 15 0
      src/main/java/com/sysu/admin/support/system/user_role/UserRoleRepository.java
  73. 52 0
      src/main/java/com/sysu/admin/support/tree/MenuTree.java
  74. 55 0
      src/main/java/com/sysu/admin/support/tree/NavigTree.java
  75. 46 0
      src/main/java/com/sysu/admin/support/tree/Tree.java
  76. 30 0
      src/main/java/com/sysu/admin/support/validated/BindExceptionHanlder.java
  77. 24 0
      src/main/java/com/sysu/admin/support/validated/EmailValidation.java
  78. 23 0
      src/main/java/com/sysu/admin/support/validated/EmailValidationValidator.java
  79. 24 0
      src/main/java/com/sysu/admin/support/validated/NameValidation.java
  80. 20 0
      src/main/java/com/sysu/admin/support/validated/NameValidationValidator.java
  81. 24 0
      src/main/java/com/sysu/admin/support/validated/PhoneValidation.java
  82. 23 0
      src/main/java/com/sysu/admin/support/validated/PhoneValidationValidator.java
  83. 84 0
      src/main/java/com/sysu/admin/utils/CheckUtil.java
  84. 93 0
      src/main/java/com/sysu/admin/utils/ChineseCharacterUtil.java
  85. 46 0
      src/main/java/com/sysu/admin/utils/CopyUtil.java
  86. 71 0
      src/main/java/com/sysu/admin/utils/FileUtils.java
  87. 187 0
      src/main/java/com/sysu/admin/utils/GenericsUtil.java
  88. 44 0
      src/main/java/com/sysu/admin/utils/MySimpleDateFormat.java
  89. 242 0
      src/main/java/com/sysu/admin/utils/TextUtil.java
  90. 31 0
      src/main/java/com/sysu/admin/utils/file/FileUtil.java
  91. 135 0
      src/main/java/com/sysu/admin/utils/file/Snippet.java
  92. 186 0
      src/main/java/com/sysu/admin/utils/http/HttpUtil.java
  93. 29 0
      src/main/java/com/sysu/admin/utils/i18n/MessageUtils.java
  94. 21 0
      src/main/java/com/sysu/admin/utils/queue/MyQueue.java
  95. 7 0
      src/main/java/com/sysu/admin/utils/queue/MyQueueContext.java
  96. 55 0
      src/main/java/com/sysu/admin/utils/queue/MyQueueSimple.java
  97. 56 0
      src/main/java/com/sysu/admin/utils/shape/CommonMethod.java
  98. 78 0
      src/main/java/com/sysu/admin/utils/shape/CoordinateConversion.java
  99. 93 0
      src/main/java/com/sysu/admin/utils/shape/DataTypeConvert.java
  100. 365 0
      src/main/java/com/sysu/admin/utils/shape/FileFormat.java

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/.idea
+target

+ 275 - 0
pom.xml

@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.sysu</groupId>
+    <artifactId>sysu_emap</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+<!-- 打包类型 -->
+	<packaging>war</packaging>
+
+	<!-- 父类 -->
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.3.4.RELEASE</version>
+		<relativePath />
+	</parent>
+
+	<!-- 配置 -->
+	<properties>
+		<!-- 文件拷贝时的编码 -->
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+		<!-- 编译时的编码 -->
+		<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
+		<!-- JAVA版本 -->
+		<java.version>1.8</java.version>
+		<!-- FAST版本 -->
+		<fast.version>2.2.1</fast.version>
+	</properties>
+
+	<!-- 版本管理,会引入jar -->
+	<dependencies>
+
+		<!-- ==========================gotv-core========================== -->
+		<dependency>
+			<groupId>com.xiesx.fast</groupId>
+			<artifactId>fast-boot</artifactId>
+			<version>${fast.version}</version>
+		</dependency>
+
+		<!-- ==========================spring-boot========================== -->
+		<!-- web -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+			<exclusions><!-- 去掉默认配置 -->
+				<exclusion>
+					<groupId>org.springframework.boot</groupId>
+					<artifactId>spring-boot-starter-logging</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>org.springframework.boot</groupId>
+					<artifactId>spring-boot-starter-tomcat</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<!-- data-jdbc -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-jdbc</artifactId>
+		</dependency>
+		<!-- data-jpa -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-jpa</artifactId>
+		</dependency>
+		<!-- config -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-configuration-processor</artifactId>
+			<optional>true</optional>
+		</dependency>
+		<!-- quartz -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-quartz</artifactId>
+		</dependency>
+		<!-- log4j2 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-log4j2</artifactId>
+		</dependency>
+		<!-- aop -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-aop</artifactId>
+		</dependency>
+
+		<!-- ==========================view========================== -->
+		<!-- jsp支持 -->
+		<dependency>
+			<groupId>org.apache.tomcat.embed</groupId>
+			<artifactId>tomcat-embed-jasper</artifactId>
+			<!-- <scope>provided</scope> -->
+		</dependency>
+		<!-- jstl标签库 -->
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>jstl</artifactId>
+		</dependency>
+		<!-- ==========================shiro========================== -->
+		<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
+		<dependency>
+			<groupId>org.apache.shiro</groupId>
+			<artifactId>shiro-spring</artifactId>
+			<version>1.5.3</version>
+		</dependency>
+		<!-- ==========================持久层========================== -->
+		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>5.1.8</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/com.querydsl/querydsl-jpa -->
+		<dependency>
+			<groupId>com.querydsl</groupId>
+			<artifactId>querydsl-jpa</artifactId>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/com.querydsl/querydsl-apt -->
+		<dependency>
+			<groupId>com.querydsl</groupId>
+			<artifactId>querydsl-apt</artifactId>
+		</dependency>
+		<!-- ==========================测试•========================== -->
+		<!-- https://mvnrepository.com/artifact/junit/junit -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.mylib</groupId>
+			<artifactId>GeoLib</artifactId>
+			<version>1.0</version>
+		</dependency>
+
+
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>easyexcel</artifactId>
+			<version>2.2.6</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-devtools</artifactId>
+			<!-- optional=true, 依赖不会传递, 该项目依赖devtools;
+            之后依赖boot项目的项目如果想要使用devtools, 需要重新引入 -->
+			<optional>true</optional>
+		</dependency>
+
+		<dependency>
+			<groupId>com.squareup.okhttp3</groupId>
+			<artifactId>okhttp</artifactId>
+			<version>3.10.0</version>
+		</dependency>
+
+		<dependency>
+			<groupId>com.belerweb</groupId>
+			<artifactId>pinyin4j</artifactId>
+			<version>2.5.0</version>
+		</dependency>
+
+
+
+
+
+
+	</dependencies>
+
+	<!-- 开发者(非必须) -->
+	<developers>
+		<developer>
+			<name>136305973</name>
+			<email>136305973.@qq.com</email>
+		</developer>
+	</developers>
+
+	<repositories>
+		<repository>
+			<id>osgeo</id>
+			<name>OSGeo Release Repository</name>
+			<url>https://repo.osgeo.org/repository/release/</url>
+			<snapshots><enabled>false</enabled></snapshots>
+			<releases><enabled>false</enabled></releases>
+		</repository>
+		<repository>
+			<id>osgeo-snapshot</id>
+			<name>OSGeo Snapshot Repository</name>
+			<url>https://repo.osgeo.org/repository/snapshot/</url>
+			<snapshots><enabled>false</enabled></snapshots>
+			<releases><enabled>false</enabled></releases>
+		</repository>
+	</repositories>
+
+	<!-- 编译 -->
+	<build>
+		<finalName>sysu_emap</finalName>
+		<plugins>
+			<!-- 打包 -->
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+			<!-- 测试 -->
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<skipTests>true</skipTests><!-- 忽略测试 -->
+				</configuration>
+			</plugin>
+			<!-- DSL -->
+			<plugin>
+				<groupId>com.mysema.maven</groupId>
+				<artifactId>apt-maven-plugin</artifactId>
+				<version>1.1.3</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>process</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>target/generated-sources/java</outputDirectory>
+							<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
+						</configuration>
+					</execution>
+				</executions>
+				<dependencies>
+					<dependency>
+						<groupId>com.querydsl</groupId>
+						<artifactId>querydsl-apt</artifactId>
+						<version>${querydsl.version}</version>
+					</dependency>
+				</dependencies>
+			</plugin>
+
+<!--			<plugin>-->
+<!--				<groupId>org.apache.maven.plugins</groupId>-->
+<!--				<artifactId>maven-assembly-plugin</artifactId>-->
+<!--				<configuration>-->
+<!--					<descriptors>-->
+<!--						&lt;!&ndash;这里的意思是依据指定的配置文件进行打包&ndash;&gt;-->
+<!--						<descriptor>src/main/resources/assembly.xml</descriptor>-->
+<!--					</descriptors>-->
+<!--				</configuration>-->
+<!--				<executions>-->
+<!--					<execution>-->
+<!--						<id>make-assembly</id>-->
+<!--						<phase>package</phase>-->
+<!--						<goals>-->
+<!--							<goal>single</goal>-->
+<!--						</goals>-->
+<!--					</execution>-->
+<!--				</executions>-->
+<!--			</plugin>-->
+		</plugins>
+<!--		<resources>-->
+<!--			<resource>-->
+<!--				<directory>lib</directory>-->
+<!--				<targetPath>/BOOT-INF/lib/</targetPath>-->
+<!--				<includes>-->
+<!--					<include>**/*.jar</include>-->
+<!--				</includes>-->
+<!--			</resource>-->
+<!--		</resources>-->
+	</build>
+
+</project>

+ 35 - 0
src/main/java/com/sysu/admin/MarkApplication.java

@@ -0,0 +1,35 @@
+package com.sysu.admin;
+
+import com.xiesx.fastboot.core.jpa.annotation.EnableJpaPlusDataSourceRepositories;
+import org.springframework.boot.Banner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import com.xiesx.fastboot.core.jpa.annotation.EnableJpaPlusRepositories;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @title ZeduApplication
+ * @description SpringBoot启动入口
+ * @author XIE
+ * @date 2020年1月6日下午2:06:58
+ */
+@Slf4j
+@EnableJpaAuditing
+@EnableJpaPlusDataSourceRepositories
+@SpringBootApplication(exclude = {ValidationAutoConfiguration.class, DataSourceAutoConfiguration.class})
+public class MarkApplication extends SpringBootServletInitializer {
+
+    public static void main(String[] args) {
+        SpringApplication app = new SpringApplication(MarkApplication.class);
+        app.setBannerMode(Banner.Mode.CONSOLE);
+        app.run(args);
+        log.info("Started ZeduApplication 启动成功");
+    }
+
+}

+ 281 - 0
src/main/java/com/sysu/admin/controller/MainController.java

@@ -0,0 +1,281 @@
+package com.sysu.admin.controller;
+
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+
+import com.sysu.admin.support.shiro.ShiroToken;
+import com.sysu.admin.support.system.menu.SMenuService;
+import com.sysu.admin.support.system.role.SRoleRepository;
+import com.sysu.admin.support.system.role_permission.RolePermissionService;
+import com.sysu.admin.support.system.user.User;
+import com.sysu.admin.support.system.user.UserRepository;
+import com.sysu.admin.support.system.user_role.UserRole;
+import com.sysu.admin.support.system.user_role.UserRoleRepository;
+import com.sysu.admin.utils.i18n.MessageUtils;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authc.pam.UnsupportedTokenException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import com.sysu.admin.support.base.ServiceContext;
+
+/**
+ * @title MainController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:08:06
+ */
+@Controller
+public class MainController extends ServiceContext {
+
+    @Autowired
+    SMenuService mMenuService;
+    @Autowired
+    UserRepository mUserRepository;
+    @Autowired
+    UserRoleRepository mUserRoleRepository;
+    @Autowired
+    SRoleRepository mSRoleRepository;
+    @Autowired
+    RolePermissionService mRolePermissionService;
+    @Autowired
+    ServletContext servletContext;
+
+
+    /**
+     * 登录页
+     * @return
+     */
+    @RequestMapping(value = "/")
+    public String index() {
+        if(mShiroService.isAuthenticated()){
+            return admin();
+        }
+        return "comm/login";
+    }
+
+
+    /**
+     * 登录页
+     * @return
+     */
+    @RequestMapping(value = "/login")
+    public String login() {
+        return "comm/login";
+    }
+
+    /**
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "/init")
+    public BaseResult init() {
+        int row = 0;
+        List<User> list = mUserRepository.findAll();
+        for (User user : list) {
+            String password = DigestUtils.md5Hex(user.getUsername() + "123456");
+            user.setPassword(password);
+            row = row + mUserRepository.insertOrUpdate(user);
+        }
+        return R.succ(row);
+    }
+
+
+    /**
+     * 用户登录
+     *
+     * @param username
+     * @param password
+     * @param returnUrl
+     * @return
+     */
+    @ResponseBody
+    @PostMapping(value = "/admin/login")
+    public BaseResult login(HttpServletRequest request, String username, String password, @RequestParam("redirect_url") String returnUrl) {
+        try {
+            // 密码加密
+            password = DigestUtils.md5Hex(username + password);
+            // 创建用户验证身份令牌
+            ShiroToken token = new ShiroToken(username, password);
+            SecurityUtils.getSubject().login(token);
+            // 重定向路径
+            if (StringUtils.isEmpty(returnUrl)) {
+                returnUrl = request.getContextPath() + "/admin2";
+            }
+            // 登录成功
+            return R.succ(BaseResult.SUCCESS, MessageUtils.get("main.loginSuccess"), returnUrl);
+        } catch (UnsupportedTokenException e) {
+            return R.fail(MessageUtils.get("main.vcode_error"));
+        } catch (UnknownAccountException e) {
+            return R.fail(MessageUtils.get("main.u_and_p_error"));
+        } catch (IncorrectCredentialsException e) {
+            return R.fail(MessageUtils.get("main.u_and_p_error"));
+        } catch (ExcessiveAttemptsException e) {
+            return R.fail(MessageUtils.get("main.failed_login_times"));
+        } catch (LockedAccountException e) {
+            return R.fail(MessageUtils.get("main.locked"));
+        } catch (DisabledAccountException e) {
+            return R.fail(MessageUtils.get("main.disabled"));
+        }
+    }
+
+    /**
+     * 注销登录
+     *
+     * @param request
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping("/admin/logout")
+    public BaseResult logout(HttpServletRequest request) {
+        // shiro 退出
+        SecurityUtils.getSubject().logout();
+        // session 失效
+        request.getSession().invalidate();
+        return R.succ();
+    }
+
+    /**
+     * 管理页
+     *
+     * @return
+     */
+    @RequestMapping(value = "/admin")
+    public String admin() {
+        return "comm/admin";
+    }
+
+    /**
+     * 管理页
+     *
+     * @return
+     */
+    @RequestMapping(value = "/admin2")
+    public String admin2(Model model) {
+        String vector_wmts = mSConfigService.getV("vector_wmts");
+        String img_wmts = mSConfigService.getV("img_wmts");
+        String qyz = mSConfigService.getV("qyz");
+        String qysdcj = mSConfigService.getV("qysdcj");
+        String ext1 = mSConfigService.getV("ext1");
+        String ext2 = mSConfigService.getV("ext2");
+        String ext3 = mSConfigService.getV("ext3");
+        String ext4 = mSConfigService.getV("ext4");
+
+        model.addAttribute("vector_wmts",vector_wmts);
+        model.addAttribute("img_wmts",img_wmts);
+        model.addAttribute("qyz",qyz);
+        model.addAttribute("qysdcj",qysdcj);
+        model.addAttribute("ext1",ext1);
+        model.addAttribute("ext2",ext2);
+        model.addAttribute("ext3",ext3);
+        model.addAttribute("ext4",ext4);
+        servletContext.setAttribute("geoserver", mGeoServerConfig.getText());
+
+        User user = mShiroService.getCurrentUser();
+        model.addAttribute("user", user);
+        model.addAttribute("roles", mSRoleRepository.findAll());
+        model.addAttribute("userRoles", mUserRoleRepository.getRoleByUsers(mShiroService.getCurrentUserId()));// 这里用户对角色1v1
+        model.addAttribute("organ", mOrganService.findOne(user.getOrganId()));
+
+        return "comm/admin2";
+    }
+
+    /**
+     * 修改密码页面
+     *
+     * @return
+     */
+    @RequestMapping(value = "/admin/password")
+    public String setUserPassword(Model model) {
+        model.addAttribute("user", mShiroService.getCurrentUser());
+        return "comm/password";
+    }
+
+    /**
+     * 提交密码修改
+     *
+     * @return
+     */
+    @PostMapping(value = "/admin/submitUpdatePassword")
+    @ResponseBody
+    public BaseResult submitUpdatePassword(@RequestParam("oldPassword") String oldPassword, @RequestParam("newPassword")String newPassword) {
+        try {
+            User user = mShiroService.getCurrentUser();
+            // 密码加密
+            oldPassword = DigestUtils.md5Hex(user.getUsername() + oldPassword);
+            // 创建用户验证身份令牌
+            ShiroToken token = new ShiroToken(user.getUsername(), oldPassword);
+            SecurityUtils.getSubject().login(token);
+            // 验证成功生成新的密码,并修改密码
+            user.setCode(newPassword);
+            newPassword = DigestUtils.md5Hex(user.getUsername() + newPassword);
+            user.setPassword(newPassword);
+            int result = mUserRepository.insertOrUpdate(user);
+            if(result > 0){
+                return R.succ(MessageUtils.get("main.pwd_succ"));
+            }
+        } catch (UnsupportedTokenException e) {
+            return R.fail(MessageUtils.get("main.vcode_error"));
+        } catch (UnknownAccountException e) {
+            return R.fail(MessageUtils.get("main.u_and_p_error"));
+        } catch (IncorrectCredentialsException e) {
+            return R.fail(MessageUtils.get("main.u_and_p_error"));
+        } catch (ExcessiveAttemptsException e) {
+            return R.fail(MessageUtils.get("main.failed_login_times"));
+        } catch (LockedAccountException e) {
+            return R.fail(MessageUtils.get("main.locked"));
+        } catch (DisabledAccountException e) {
+            return R.fail(MessageUtils.get("main.disabled"));
+        }
+        return R.fail(MessageUtils.get("main.failed_pwd"));
+    }
+
+    /**
+     * 控制台
+     *
+     * @return
+     */
+    @RequestMapping(value = "/console")
+    public String console(Model model) {
+        User user = mShiroService.getCurrentUser();
+        model.addAttribute("user", user);
+        model.addAttribute("roles", mSRoleRepository.findAll());
+        model.addAttribute("userRoles", mUserRoleRepository.getRoleByUsers(mShiroService.getCurrentUserId()));// 这里用户对角色1v1
+        model.addAttribute("organ", mOrganService.findOne(user.getOrganId()));
+        return "comm/console";
+    }
+
+    /**
+     * 用户导航
+     *
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "/admin/navigation")
+    public BaseResult navigation() {
+        User user = mUserRepository.findOne(mShiroService.getCurrentUserId());
+        if (ObjectUtils.isNotEmpty(user)) {
+            // 查询当前用户角色
+            UserRole userRole = mUserRoleRepository.getRoleByUser(user.getId());
+            if (ObjectUtils.isNotEmpty(userRole)) {
+                // 查询当前用户角色权限
+                String[] permissions = mRolePermissionService.getPermissions(userRole.getPk().roles());
+                return R.succ(mMenuService.getNavigTree(permissions));
+            }
+        }
+        return R.fail();
+    }
+}

+ 22 - 0
src/main/java/com/sysu/admin/controller/analyse/Analyse.java

@@ -0,0 +1,22 @@
+package com.sysu.admin.controller.analyse;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+import org.locationtech.jts.geom.Coordinate;
+import org.opengis.feature.Feature;
+import org.opengis.feature.simple.SimpleFeature;
+
+import java.util.List;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 13:03
+ */
+@Data
+public class Analyse {
+
+    private Integer type;
+    private String wkt;
+
+}

+ 32 - 0
src/main/java/com/sysu/admin/controller/analyse/AnalyseController.java

@@ -0,0 +1,32 @@
+package com.sysu.admin.controller.analyse;
+
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.io.IOException;
+import java.sql.SQLException;
+
+/**
+ * 用于画图分析
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 11:30
+ */
+@RequestMapping("/analyse")
+@Controller
+public class AnalyseController {
+
+    @Autowired
+    AnalyseServiceManager analyseServiceManager;
+
+    @RequestMapping("analyse")
+    @ResponseBody
+    public BaseResult analyse(Analyse analyse) throws IOException, SQLException {
+        AnalyseTable table = analyseServiceManager.newInstance(AnalyseType.valueOf(analyse.getType())).analyse(analyse.getWkt());
+        return R.succ(table);
+    }
+}

+ 23 - 0
src/main/java/com/sysu/admin/controller/analyse/AnalyseRow.java

@@ -0,0 +1,23 @@
+package com.sysu.admin.controller.analyse;
+
+import lombok.Data;
+
+import java.util.Map;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 16:03
+ */
+@Data
+public class AnalyseRow {
+    public AnalyseRow(){}
+
+    public AnalyseRow(String featureJson, Map<String, Object> values) {
+        this.featureJson = featureJson;
+        this.values = values;
+    }
+
+    String featureJson;
+    Map<String, Object> values;
+}

+ 14 - 0
src/main/java/com/sysu/admin/controller/analyse/AnalyseService.java

@@ -0,0 +1,14 @@
+package com.sysu.admin.controller.analyse;
+
+import java.io.IOException;
+import java.sql.SQLException;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 15:21
+ */
+public interface AnalyseService {
+
+    AnalyseTable analyse(String wkt) throws IOException, SQLException;
+}

+ 33 - 0
src/main/java/com/sysu/admin/controller/analyse/AnalyseServiceManager.java

@@ -0,0 +1,33 @@
+package com.sysu.admin.controller.analyse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 16:32
+ */
+@Component
+public class AnalyseServiceManager {
+
+    @Autowired
+    private TownsAnalyseService townsAnalyseService;
+    @Autowired
+    private VillageAnalyseService villageAnalyseService;
+    @Autowired
+    private CropAnalyseService cropAnalyseService;
+
+    public AnalyseService newInstance(AnalyseType analyseType) {
+        switch (analyseType){
+            case towns:
+                return townsAnalyseService;
+            case village:
+                return villageAnalyseService;
+            case crop:
+                return cropAnalyseService;
+        }
+        throw new RuntimeException("无效的 AnalyseType");
+    }
+
+}

+ 26 - 0
src/main/java/com/sysu/admin/controller/analyse/AnalyseTable.java

@@ -0,0 +1,26 @@
+package com.sysu.admin.controller.analyse;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 16:16
+ */
+@Data
+public class AnalyseTable {
+
+    public AnalyseTable(){}
+
+    public AnalyseTable(List<AnalyseRow> analyseResults, Double sumArea) {
+        this.analyseRows = analyseResults;
+        this.sumArea = sumArea;
+    }
+
+    private Double sumArea;
+
+    List<AnalyseRow> analyseRows;
+
+}

+ 34 - 0
src/main/java/com/sysu/admin/controller/analyse/AnalyseType.java

@@ -0,0 +1,34 @@
+package com.sysu.admin.controller.analyse;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 16:38
+ */
+public enum  AnalyseType {
+    towns,village,crop ;
+    public static AnalyseType valueOf(int i){
+        switch (i){
+            case 0:
+                return towns;
+            case 1:
+                return village;
+            case 2:
+                return crop;
+        }
+        return null;
+    }
+
+    public static Integer valueOf(AnalyseType analyseType){
+        switch (analyseType){
+            case towns:
+                return 0;
+            case village:
+                return 1;
+            case crop:
+                return 2;
+        }
+        return null;
+    }
+
+}

+ 112 - 0
src/main/java/com/sysu/admin/controller/analyse/CropAnalyseService.java

@@ -0,0 +1,112 @@
+package com.sysu.admin.controller.analyse;
+
+import com.sysu.admin.support.base.ServiceContext;
+import com.sysu.admin.utils.shape.DataTypeConvert;
+import com.sysu.admin.utils.shape.GeoServerCQLECQL;
+import com.sysu.admin.utils.shape.postgis.PostGisUtil;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.locationtech.jts.geom.*;
+import org.locationtech.jts.operation.overlay.snap.SnapOverlayOp;
+import org.opengis.feature.simple.SimpleFeature;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/23 15:51
+ */
+@Service
+public class CropAnalyseService extends ServiceContext implements AnalyseService{
+    @Override
+    public AnalyseTable analyse(String wkt) throws IOException, SQLException {
+        DecimalFormat df = new DecimalFormat("######0.00");
+        Geometry geometry = DataTypeConvert.wkt2Geometry(wkt);
+
+        Double sumArea = DataTypeConvert.getArea(geometry);
+        if(sumArea.intValue() > 1000000){
+            throw new RuntimeException("耕地分析面积不能超过100万亩");
+        }
+        PostGisUtil postGisUtil = new PostGisUtil();
+        postGisUtil.connPostGis();
+        postGisUtil.openConnection();
+
+        //查询出与测量面积相交的区域
+        StringBuffer filter = new StringBuffer(500);
+        filter.append(" FROM \"qingyuan_crop_2_cast\"  WHERE ST_Relate(geom,'")
+                .append(wkt )
+                .append("','T********') = true");
+        System.out.println("长度:"+filter.length());
+
+        List<AnalyseRow> analyseResults = new ArrayList<>();
+        SimpleFeatureTypeBuilder simpleFeatureTypeBuilder = new SimpleFeatureTypeBuilder();
+        simpleFeatureTypeBuilder.add("objectid", Integer.class);
+        simpleFeatureTypeBuilder.add("the_geom", MultiPolygon.class);
+        simpleFeatureTypeBuilder.setName("temp");
+        simpleFeatureTypeBuilder.setCRS(DefaultGeographicCRS.WGS84);
+        SimpleFeatureBuilder simpleFeatureBuilder = new SimpleFeatureBuilder(simpleFeatureTypeBuilder.buildFeatureType());
+        //耕地的数据
+        List<SimpleFeature> cropFeatureList = null;
+        GeometryCollection cropGeometry = null;
+        {
+            try {
+                cropFeatureList = postGisUtil.queryMethod(filter.toString(), null, "qingyuan_crop_2_cast", true);
+            } catch (SQLException throwables) {
+                throwables.printStackTrace();
+            } finally {
+                postGisUtil.closeConnection();
+                postGisUtil.dispose();
+            }
+            List<Geometry> geometries = new ArrayList<>(cropFeatureList.size());
+
+            //合并查询到的耕地
+            for (SimpleFeature feature : cropFeatureList) {
+                Geometry temp = (Geometry) feature.getDefaultGeometry();
+                try {
+                    temp = SnapOverlayOp.intersection(geometry, temp);
+                }catch (TopologyException e){
+                    temp = SnapOverlayOp.intersection(geometry, temp.intersection(temp));
+                }
+                if(temp == null)
+                    continue;
+                geometries.add(temp);
+            }
+            if(geometries.size() > 0) {
+                GeometryFactory geometryFactory = new GeometryFactory();
+                cropGeometry = new GeometryCollection(geometries.toArray(new Geometry[0]), geometryFactory);
+                Map<String, Object> map = new HashMap();
+                SimpleFeature simpleFeature = simpleFeatureBuilder.buildFeature("1", new Object[]{1});
+                simpleFeature.setDefaultGeometry(cropGeometry);
+                map.put("name", "耕地");
+                map.put("objectid", 1);
+                Double area = DataTypeConvert.getArea(cropGeometry);
+                map.put("area", df.format(area));
+                map.put("percent", df.format(area / sumArea * 100));
+                String json = GeoServerCQLECQL.featureToGeoJson(simpleFeature);
+                analyseResults.add(new AnalyseRow(json, map));
+            }
+        }
+        //其他的数据
+        Geometry ohterGeometry =  SnapOverlayOp.difference(geometry, cropGeometry);
+        SimpleFeature simpleFeature = simpleFeatureBuilder.buildFeature("2", new Object[]{2});
+        simpleFeature.setDefaultGeometry(ohterGeometry);
+        Map<String, Object> map = new HashMap();
+        map.put("name", "其他");
+        map.put("objectid", 2);
+        Double area = DataTypeConvert.getArea(ohterGeometry);
+        map.put("area", df.format(area));
+        map.put("percent", df.format(area / sumArea * 100));
+        String json = GeoServerCQLECQL.featureToGeoJson(simpleFeature);
+        analyseResults.add(new AnalyseRow(json, map));
+        return new AnalyseTable(analyseResults, Double.parseDouble(df.format(sumArea)));
+    }
+}

+ 69 - 0
src/main/java/com/sysu/admin/controller/analyse/TownsAnalyseService.java

@@ -0,0 +1,69 @@
+package com.sysu.admin.controller.analyse;
+
+import com.sysu.admin.support.base.ServiceContext;
+import com.sysu.admin.utils.shape.DataTypeConvert;
+import com.sysu.admin.utils.shape.GeoServerCQLECQL;
+import com.sysu.admin.utils.shape.postgis.PostGisUtil;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.operation.overlay.snap.SnapOverlayOp;
+import org.opengis.feature.simple.SimpleFeature;
+import org.springframework.stereotype.Service;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.text.DecimalFormat;
+import java.util.*;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/19 15:27
+ */
+@Service
+public class TownsAnalyseService extends ServiceContext implements AnalyseService{
+    @Override
+    public AnalyseTable analyse(String wkt) throws IOException {
+        DecimalFormat df = new DecimalFormat("######0.00");
+        PostGisUtil postGisUtil = new PostGisUtil();
+        postGisUtil.connPostGis();
+        postGisUtil.openConnection();
+        Geometry geometry = DataTypeConvert.wkt2Geometry(wkt);
+
+//        List<Param> params = new ArrayList<>();
+//        params.add(new Param(new String[]{}, new Object[]{}));
+//        FileFormat.toShp(Arrays.asList(new Geometry[]{geometry}), "E:\\zcjy\\bhjc\\test.shp", new ParamType[0], params);
+
+        //查询出与测量面积相交的区域
+        StringBuffer filter = new StringBuffer(500);
+        filter.append(" FROM \"qy-z\"  WHERE ST_Relate(geom,'")
+                .append(wkt )
+                .append("','T********') = true");
+        System.out.println("长度:"+filter.length());
+
+        List<SimpleFeature> featureList = null;
+        try {
+            featureList = postGisUtil.queryMethod(filter.toString(),null,"qy-z", true);
+        } catch (SQLException throwables) {
+            throwables.printStackTrace();
+        }finally {
+            postGisUtil.closeConnection();
+            postGisUtil.dispose();
+        }
+        List<AnalyseRow> analyseResults = new ArrayList<>();
+        Double sumArea = DataTypeConvert.getArea(geometry);
+
+        for(SimpleFeature feature : featureList) {
+            Map<String, Object> map = new HashMap();
+            map.put("name", feature.getAttribute("name").toString());
+            map.put("objectid", feature.getAttribute("objectid").toString());
+            Geometry newGeometry = SnapOverlayOp.intersection(geometry,(Geometry)feature.getDefaultGeometry());
+
+            Double area = DataTypeConvert.getArea(newGeometry);
+            map.put("area", df.format(area));
+            map.put("percent", df.format(area / sumArea * 100));
+            feature.setDefaultGeometry(newGeometry);
+            String json = GeoServerCQLECQL.featureToGeoJson(feature);
+            analyseResults.add(new AnalyseRow(json, map));
+        }
+        return new AnalyseTable(analyseResults, Double.parseDouble(df.format(sumArea)));
+    }
+}

+ 70 - 0
src/main/java/com/sysu/admin/controller/analyse/VillageAnalyseService.java

@@ -0,0 +1,70 @@
+package com.sysu.admin.controller.analyse;
+
+import com.sysu.admin.support.base.ServiceContext;
+import com.sysu.admin.utils.shape.DataTypeConvert;
+import com.sysu.admin.utils.shape.GeoServerCQLECQL;
+import com.sysu.admin.utils.shape.postgis.PostGisUtil;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.operation.overlay.snap.SnapOverlayOp;
+import org.opengis.feature.simple.SimpleFeature;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/20 15:50
+ */
+@Component
+public class VillageAnalyseService extends ServiceContext implements AnalyseService{
+    @Override
+    public AnalyseTable analyse(String wkt) throws IOException, SQLException {
+        DecimalFormat df = new DecimalFormat("######0.00");
+        PostGisUtil postGisUtil = new PostGisUtil();
+        postGisUtil.connPostGis();
+        postGisUtil.openConnection();
+        Geometry geometry = DataTypeConvert.wkt2Geometry(wkt);
+
+        //查询出与测量面积相交的区域
+        StringBuffer filter = new StringBuffer(500);
+        filter.append(" FROM \"qysdcj\"  WHERE ST_Relate(geom,'")
+                .append(wkt )
+                .append("','T********') = true");
+        System.out.println("长度:"+filter.length());
+
+        List<SimpleFeature> featureList = null;
+        try {
+            featureList = postGisUtil.queryMethod(filter.toString(),null,"qysdcj", true);
+        } catch (SQLException throwables) {
+            throwables.printStackTrace();
+        }finally {
+            postGisUtil.closeConnection();
+            postGisUtil.dispose();
+        }
+        List<AnalyseRow> analyseResults = new ArrayList<>();
+        int i = 0;
+        Double sumArea = DataTypeConvert.getArea(geometry);
+
+        for(SimpleFeature feature : featureList) {
+            Map<String, Object> map = new HashMap();
+            map.put("name", feature.getAttribute("zldwmc").toString());
+            map.put("objectid", feature.getAttribute("objectid").toString());
+            Geometry newGeometry = SnapOverlayOp.intersection(geometry.intersection(geometry),(Geometry)feature.getDefaultGeometry());
+
+            Double area = DataTypeConvert.getArea(newGeometry);
+            map.put("area", df.format(area));
+            map.put("percent", df.format(area / sumArea * 100));
+            feature.setDefaultGeometry(newGeometry);
+            String json = GeoServerCQLECQL.featureToGeoJson(feature);
+            analyseResults.add(new AnalyseRow(json, map));
+        }
+        return new AnalyseTable(analyseResults,  Double.parseDouble(df.format(sumArea)));
+    }
+}

+ 35 - 0
src/main/java/com/sysu/admin/controller/geo/CityLand.java

@@ -0,0 +1,35 @@
+package com.sysu.admin.controller.geo;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+
+import javax.persistence.*;
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "gdcityland30")
+@Entity
+@DynamicInsert
+@DynamicUpdate
+public class CityLand {
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "gridcode")
+    private Long gridcode;
+
+    @Column(name = "geom")
+    private String geom;
+
+
+}

+ 15 - 0
src/main/java/com/sysu/admin/controller/geo/CityLandRepository.java

@@ -0,0 +1,15 @@
+package com.sysu.admin.controller.geo;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+
+public interface CityLandRepository extends JpaPlusRepository<CityLand, Long> {
+
+
+    @Query(value = "SELECT \"id\",ST_AsEWKT(\"geom\") as \"geom\",\"gridcode\" FROM \"gdcityland30\" where St_within(st_geomfromtext(?1,4526), geom) limit 1", nativeQuery = true)
+    CityLand findIdByPoint(String pointWKT);
+
+}

+ 20 - 0
src/main/java/com/sysu/admin/controller/geo/CityLandService.java

@@ -0,0 +1,20 @@
+package com.sysu.admin.controller.geo;
+
+import com.sysu.admin.support.base.BaseService;
+import com.xiesx.fastboot.core.jpa.annotation.TargetDataSource;
+import com.xiesx.fastboot.core.jpa.cfg.DataSourceEnum;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CityLandService {
+
+    @Autowired
+    CityLandRepository cityLandRepository;
+
+    @TargetDataSource(DataSourceEnum.slave)
+    public CityLand findByPoint(double x, double y){
+        return cityLandRepository.findIdByPoint("Point("+x+" "+y+")");
+    }
+
+}

+ 72 - 0
src/main/java/com/sysu/admin/controller/geo/PostGisInfoController.java

@@ -0,0 +1,72 @@
+package com.sysu.admin.controller.geo;
+
+import com.sysu.admin.utils.shape.CoordinateConversion;
+import com.sysu.admin.utils.shape.GeoCastUtil;
+import com.sysu.admin.utils.shape.postgis.PostGisUtil;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import org.geotools.data.postgis.TWKBReader;
+import org.geotools.geojson.feature.FeatureJSON;
+import org.geotools.geometry.jts.WKBReader;
+import org.geotools.geometry.jts.WKTWriter2;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.io.ParseException;
+import org.opengis.feature.simple.SimpleFeature;
+import org.postgresql.util.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 读取地图数据信息
+ */
+@RequestMapping("/postGisInfo")
+@RestController
+public class PostGisInfoController {
+
+    @Autowired
+    CityLandService cityLandService;
+
+    @RequestMapping("/getInfo")
+    public BaseResult getInfo(String layerName, Double x, Double y){
+        CityLand cityLand = cityLandService.findByPoint(x,y);
+        return R.succ(cityLand);
+    }
+
+//    @RequestMapping("/getInfo")
+    public BaseResult getInfo2(String layerName, Double x, Double y){
+        PostGisUtil postGisUtil = new PostGisUtil();
+        postGisUtil.connPostGis();
+        postGisUtil.openConnection();
+        List<SimpleFeature> featureList = null;
+        try {
+            featureList = postGisUtil.queryMethod(
+                    " FROM \""+layerName+"\" where St_within(st_geomfromtext('Point("+(x)+" "+(y)+")',4526), geom)", null, layerName, true);
+        } catch (SQLException | IOException throwables) {
+            throwables.printStackTrace();
+        } finally {
+            postGisUtil.closeConnection();
+            postGisUtil.dispose();
+        }
+        List<String> geoJsonList = new ArrayList<>();
+        FeatureJSON fjson = new FeatureJSON();
+        StringWriter writer = new StringWriter();
+        featureList.stream().forEach(simpleFeature -> {
+            try {
+                fjson.writeFeature(simpleFeature, writer);
+                geoJsonList.add(writer.toString());
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        });
+        return R.succ(geoJsonList);
+    }
+
+}

+ 24 - 0
src/main/java/com/sysu/admin/controller/geo/SldStyleController.java

@@ -0,0 +1,24 @@
+package com.sysu.admin.controller.geo;
+
+import com.sysu.admin.support.base.ServiceContext;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * 读取样式信息
+ */
+@RequestMapping("/sld_style")
+@Controller
+public class SldStyleController extends ServiceContext {
+
+    @RequestMapping(value = "/sign")
+    @ResponseBody
+    public BaseResult sign(String styleName){
+        String sldXmlJson =  mSConfigService.getV(styleName);
+        return R.succ(sldXmlJson);
+    }
+
+}

+ 50 - 0
src/main/java/com/sysu/admin/controller/geo/qyz/QyzController.java

@@ -0,0 +1,50 @@
+package com.sysu.admin.controller.geo.qyz;
+
+import com.sysu.admin.utils.shape.GeoServerCQLECQL;
+import com.sysu.admin.utils.shape.postgis.PostGisUtil;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import org.geotools.geometry.jts.WKTReader2;
+import org.geotools.geometry.jts.WKTWriter2;
+import org.locationtech.jts.geom.Geometry;
+import org.opengis.feature.simple.SimpleFeature;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 镇区域
+ */
+@RequestMapping("/qyz")
+@Controller
+public class QyzController {
+
+    @RequestMapping(value = "/findJson")
+    @ResponseBody
+    public BaseResult findJson(String code){
+        PostGisUtil postGisUtil = new PostGisUtil();
+        postGisUtil.connPostGis();
+        postGisUtil.openConnection();
+        List<SimpleFeature> cropFeatureList = null;
+        try {
+            cropFeatureList = postGisUtil.queryMethod("pac like '"+code+"%'", null, "qy-z", false);
+        } catch (SQLException | IOException throwables) {
+            throwables.printStackTrace();
+        } finally {
+            postGisUtil.closeConnection();
+            postGisUtil.dispose();
+        }
+        WKTWriter2 writer2 = new WKTWriter2();
+        List<String> wktList = new ArrayList<>();
+        cropFeatureList.stream().forEach(simpleFeature -> {
+            wktList.add(writer2.write((Geometry)simpleFeature.getDefaultGeometry()));
+        });
+        return R.succ(wktList);
+    }
+
+}

+ 4 - 0
src/main/java/com/sysu/admin/controller/resource/Resource.java

@@ -0,0 +1,4 @@
+package com.sysu.admin.controller.resource;
+
+public class Resource {
+}

+ 70 - 0
src/main/java/com/sysu/admin/controller/upload/UploadRecord.java

@@ -0,0 +1,70 @@
+package com.sysu.admin.controller.upload;
+
+
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * @title 上传记录
+ * @description
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "upload_record")
+@Entity
+@EntityListeners(AuditingEntityListener.class)
+@DynamicInsert
+@DynamicUpdate
+public class UploadRecord extends JpaPlusEntity<UploadRecord> {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column
+    private String filename;
+
+    /**
+     * 创建时间
+     */
+    @CreatedDate
+    @Column(updatable = false, nullable = false)
+    private Date createDate;
+
+    /**
+     * 纬度
+     */
+    @Column
+    private String latitude;
+
+    /**
+     * 经度
+     */
+    @Column
+    private String longitude;
+
+    @Column
+    private String alpha;
+
+    @Column
+    private String beta;
+
+    @Column
+    private String gamma;
+}

+ 55 - 0
src/main/java/com/sysu/admin/controller/upload/UploadRecordController.java

@@ -0,0 +1,55 @@
+package com.sysu.admin.controller.upload;
+
+import com.sysu.admin.support.base.ServiceContext;
+import com.sysu.admin.utils.TextUtil;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+@RequestMapping("/uploadRecord")
+@Controller
+public class UploadRecordController extends ServiceContext {
+
+    @Autowired
+    UploadRecordRepository mUploadRecordRepository;
+
+    /**
+     * 上传图片
+     */
+    @RequestMapping("uploadImg")
+    @ResponseBody
+    public BaseResult uploadImg(@RequestParam("file") MultipartFile file) {
+        if(file != null) {
+            String imageDirPath =  mSConfigService.getV("imageDirPath");
+            String hz = TextUtil.rightSubstring(".",file.getOriginalFilename());
+            String newFileName = System.currentTimeMillis() + "_" + mShiroService.getPrincipalId()+"." + hz;
+            try {
+                //复制到零时文件
+                File target = new File(imageDirPath + newFileName);
+                file.transferTo(target);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            UploadRecord uploadRecord = new UploadRecord().setFilename(newFileName);
+            mUploadRecordRepository.save(uploadRecord);
+            Map<String,Object> map = new HashMap();
+            map.put("filename",newFileName);
+            map.put("id",uploadRecord.getId());
+            map.put("type",hz);
+            return R.succ(map);
+        }else {
+            return R.fail();
+        }
+    }
+
+}

+ 8 - 0
src/main/java/com/sysu/admin/controller/upload/UploadRecordRepository.java

@@ -0,0 +1,8 @@
+package com.sysu.admin.controller.upload;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+
+
+public interface UploadRecordRepository extends JpaPlusRepository<UploadRecord, Long> {
+
+}

+ 35 - 0
src/main/java/com/sysu/admin/support/base/BaseComponent.java

@@ -0,0 +1,35 @@
+package com.sysu.admin.support.base;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.apache.shiro.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.persistence.EntityManager;
+import javax.validation.ConstraintViolation;
+import javax.validation.Valid;
+import javax.validation.Validation;
+import java.util.Set;
+
+public class BaseComponent {
+
+    @Autowired
+    public JPAQueryFactory mJPAQueryFactory;
+    @Autowired
+    public EntityManager mEntityManager;
+
+
+
+    protected void validate(@Valid Object obj) {
+        Set<ConstraintViolation<Object>> validateSet = Validation.buildDefaultValidatorFactory()
+                .getValidator()
+                .validate(obj, new Class[0]);
+        if (!CollectionUtils.isEmpty(validateSet)) {
+            String messages = validateSet.stream()
+                    .map(ConstraintViolation::getMessage)
+                    .reduce((m1, m2) -> m1 + ";" + m2)
+                    .orElse("参数输入有误!");
+            throw new IllegalArgumentException(messages);
+        }
+    }
+
+}

+ 100 - 0
src/main/java/com/sysu/admin/support/base/BaseService.java

@@ -0,0 +1,100 @@
+package com.sysu.admin.support.base;
+
+import com.querydsl.core.types.Predicate;
+import com.querydsl.jpa.impl.JPAQuery;
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+
+import java.util.List;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/6 8:38
+ */
+public abstract class BaseService<T,ID> extends RepositoryContext {
+
+    public abstract JpaPlusRepository<T, ID> r();
+
+    public T findOne(ID id){
+        if(id == null){
+            return null;
+        }
+        return r().findOne(id);
+    }
+
+    public List<T> findAll(Predicate predicate){
+        return r().findAll(predicate);
+    }
+
+    public Page<T> findAll(Predicate predicate,  Pageable pageable){
+        return r().findAll(predicate, pageable);
+    }
+
+    public List<T> findAll(Predicate predicate, Sort sort){
+        return r().findAll(predicate,sort);
+    }
+
+    public <S> Page<S> findAll(JPAQuery<S> query, Pageable pageable){
+        return r().findAll(query,pageable);
+    }
+
+    public <S> Page<S> findAllNoCount(JPAQuery<S> query, Pageable pageable, long count){
+        return r().findAllNoCount(query, pageable, count);
+    }
+
+
+    public int insertOrUpdate(T entity){
+        return r().insertOrUpdate(entity);
+    }
+
+    public int delete(ID... ids){
+        return r().delete(ids);
+    }
+
+    public  void deleteAll(Iterable<? extends T> var1){
+        r().deleteAll(var1);
+    }
+
+    public List<T> findAll(){
+        return r().findAll();
+    }
+
+    public List<T> findAll(Sort sort){
+        return r().findAll(sort);
+    }
+
+
+    public List<T> findAllById(List<ID> ids){
+        return r().findAllById(ids);
+    }
+
+
+    public <S extends T> List<S> saveAll(List<S> entities){
+        return r().saveAll(entities);
+    }
+
+
+    public <S extends T> S saveAndFlush(S entity){
+        return r().saveAndFlush(entity);
+    }
+
+    public <S extends T> S save(S entity){
+        return r().save(entity);
+    }
+
+    public boolean existsById(ID id){
+        return r().existsById(id);
+    }
+
+    public long count(){
+        return r().count();
+    }
+
+    @Autowired
+    public ServiceContext serviceContext;
+
+}

+ 42 - 0
src/main/java/com/sysu/admin/support/base/BaseVo.java

@@ -0,0 +1,42 @@
+package com.sysu.admin.support.base;
+
+import lombok.Data;
+
+/**
+ * @title BaseVo
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:01:10
+ */
+@Data
+public class BaseVo {
+
+    /** 参数id */
+    private Long id = -1L;
+
+    /** 被删除的参数的ID **/
+    private Long[] ids;
+
+    /** 搜索词 **/
+    private String keyword = "";
+
+    /** 是否启用 */
+    private Integer isEnable;
+
+    /** 是否删除 */
+    private Integer isDel;
+
+    /** 排序 **/
+    private Integer sort;
+    /** 省市区 **/
+    private String region;
+
+    private Long organId;
+
+    private Integer page;
+
+    private Integer isBureau = 0;
+
+    private String cityName;
+
+}

+ 33 - 0
src/main/java/com/sysu/admin/support/base/RepositoryContext.java

@@ -0,0 +1,33 @@
+package com.sysu.admin.support.base;
+
+
+import com.sysu.admin.support.system.user_role.UserRoleRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import com.sysu.admin.support.system.config.SConfigRepository;
+import com.sysu.admin.support.system.region.RegionRepository;
+import com.sysu.admin.support.system.user.UserRepository;
+
+/**
+ * @title BaseController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:01:01
+ */
+public class RepositoryContext extends BaseComponent{
+
+    @Autowired
+    public RegionRepository mRegionRepository;
+
+    @Autowired
+    public SConfigRepository mSConfigRepository;
+
+    @Autowired
+    public UserRepository mUserRepository;
+
+    @Autowired
+    public UserRoleRepository mUserRoleRepository;
+
+    @Autowired
+    public ServiceContext serviceContext;
+
+}

+ 79 - 0
src/main/java/com/sysu/admin/support/base/ServiceContext.java

@@ -0,0 +1,79 @@
+package com.sysu.admin.support.base;
+
+import com.querydsl.core.types.ExpressionUtils;
+import com.querydsl.core.types.Predicate;
+import com.querydsl.core.types.dsl.DateTimePath;
+import com.sysu.admin.support.system.organ.OrganService;
+import com.sysu.admin.support.shiro.ShiroService;
+import com.sysu.admin.support.system.config.SConfigService;
+import com.sysu.admin.support.system.user.UserService;
+import com.sysu.admin.utils.shape.geoserver.GeoServerConfig;
+import org.apache.shiro.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Valid;
+import javax.validation.Validation;
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * @title BaseController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:01:01
+ */
+@Component
+public class ServiceContext {
+
+    @Autowired
+    public JPAQueryFactory mJPAQueryFactory;
+
+    @Autowired
+    public ShiroService mShiroService;
+
+    @Lazy
+    @Autowired
+    public OrganService mOrganService;
+    @Lazy
+    @Autowired
+    public UserService mUserService;
+    @Lazy
+    @Autowired
+    public GeoServerConfig mGeoServerConfig;
+    @Lazy
+    @Autowired
+    public SConfigService mSConfigService;
+
+    /**
+     * 构造日期条件
+     * @param predicate 条件对象
+     * @param stringPath
+     * @param beforeOrAfter 查询时间之前 还是 之后的数据
+     * @param val 时间
+     * @return
+     */
+    protected Predicate createDateWhere(Predicate predicate, DateTimePath<Date> stringPath, boolean beforeOrAfter, Date val){
+        if(beforeOrAfter)
+            return ExpressionUtils.and(predicate, stringPath.before(val));
+        else
+            return ExpressionUtils.and(predicate, stringPath.after(val));
+    }
+
+    protected void validate(@Valid Object obj) {
+        Set<ConstraintViolation<Object>> validateSet = Validation.buildDefaultValidatorFactory()
+                .getValidator()
+                .validate(obj, new Class[0]);
+        if (!CollectionUtils.isEmpty(validateSet)) {
+            String messages = validateSet.stream()
+                    .map(ConstraintViolation::getMessage)
+                    .reduce((m1, m2) -> m1 + ";" + m2)
+                    .orElse("参数输入有误!");
+            throw new IllegalArgumentException(messages);
+        }
+    }
+
+}

+ 40 - 0
src/main/java/com/sysu/admin/support/cfg/CorsConfig.java

@@ -0,0 +1,40 @@
+package com.sysu.admin.support.cfg;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+/**
+ * @title CorsCfg.java
+ * @description 跨域设置 (@CrossOrigin(origins = "*", allowedHeaders = "*",methods = {RequestMethod.GET,
+ *              RequestMethod.HEAD, RequestMethod.POST, RequestMethod.PUT, RequestMethod.PATCH,
+ *              RequestMethod.DELETE, RequestMethod.OPTIONS, RequestMethod.TRACE}))
+ * @author Sixian.xie
+ * @date 2020年6月18日下午5:44:02
+ */
+@Configuration
+public class CorsConfig {
+
+    private CorsConfiguration buildConfig() {
+        CorsConfiguration corsConfiguration = new CorsConfiguration();
+        // 1 设置访问源地址
+        corsConfiguration.addAllowedOrigin("*");
+        // 2 设置访问源请求头
+        corsConfiguration.addAllowedHeader("*");
+        // 3 设置访问源请求方法
+        corsConfiguration.addAllowedMethod("*");
+        return corsConfiguration;
+    }
+
+    @Bean
+    public CorsFilter corsFilter() {
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        // 4 对接口配置跨域设置
+        source.registerCorsConfiguration("/site/**", buildConfig());
+        source.registerCorsConfiguration("/api/**", buildConfig());
+        source.registerCorsConfiguration("/WEB-INF/static/**", buildConfig()); // 4 对接口配置跨域设置
+        return new CorsFilter(source);
+    }
+}

+ 30 - 0
src/main/java/com/sysu/admin/support/cfg/GoCfg.java

@@ -0,0 +1,30 @@
+package com.sysu.admin.support.cfg;
+
+import org.springframework.context.annotation.Configuration;
+
+import com.xiesx.fastboot.core.body.annotation.GoEnableBody;
+import com.xiesx.fastboot.core.exception.annotation.GoEnableException;
+import com.xiesx.fastboot.core.fastjson.annotation.GoEnableFastJson;
+import com.xiesx.fastboot.core.sign.annotation.GoEnableSign;
+import com.xiesx.fastboot.core.token.annotation.GoEnableToken;
+
+/**
+ * @title GoCfg
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:01:20
+ */
+@Configuration
+// 启用统一返回
+@GoEnableBody
+// 启用令牌
+@GoEnableToken
+// 启用签名
+@GoEnableSign
+// 启用FastJson
+@GoEnableFastJson
+// 启用全局异常
+@GoEnableException
+public class GoCfg {
+
+}

+ 135 - 0
src/main/java/com/sysu/admin/support/cfg/ShiroCfg.java

@@ -0,0 +1,135 @@
+package com.sysu.admin.support.cfg;
+
+import java.util.Map;
+
+import org.apache.shiro.cache.MemoryConstrainedCacheManager;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.google.common.collect.Maps;
+import com.sysu.admin.support.shiro.ShiroAuthenRealm;
+
+/**
+ * @title ShiroConfig
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:01:25
+ */
+@Configuration
+public class ShiroCfg {
+
+    /**
+     * 开启注解式 权限拦截
+     *
+     * @param securityManager
+     * @return
+     */
+    @Bean
+    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
+        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
+        return authorizationAttributeSourceAdvisor;
+    }
+
+    /**
+     * Aop
+     *
+     * @return
+     */
+    @Bean
+    @ConditionalOnMissingBean
+    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
+        defaultAAP.setProxyTargetClass(true);
+        return defaultAAP;
+    }
+
+    /**
+     * 权限管理
+     *
+     * @return
+     */
+    @Bean
+    public ShiroAuthenRealm myShiroRealm() {
+        ShiroAuthenRealm realm = new ShiroAuthenRealm();
+        return realm;
+    }
+
+    // /**
+    // * 记住密码
+    // *
+    // * @return
+    // */
+    // @Bean
+    // public SimpleCookie rememberMeCookie() {
+    // SimpleCookie simpleCookie = new SimpleCookie("shiro-cookie");
+    // simpleCookie.setHttpOnly(true);
+    // simpleCookie.setMaxAge(60 * 60 * 24);// 单位(秒)1天
+    // return simpleCookie;
+    // }
+    //
+    // /**
+    // * 记住密码(管理器)
+    // *
+    // * @return
+    // */
+    // @Bean
+    // public CookieRememberMeManager cookieRememberMeManager() {
+    // CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
+    // cookieRememberMeManager.setCipherKey(Base64.decode("Z3VucwAAAAAAAAAAAAAAAA=="));
+    // cookieRememberMeManager.setCookie(rememberMeCookie());
+    // return cookieRememberMeManager;
+    // }
+
+    /**
+     * 权限管理(管理器)
+     *
+     * @return
+     */
+    @Bean
+    public SecurityManager securityManager() {
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        securityManager.setRealm(myShiroRealm());
+        securityManager.setCacheManager(new MemoryConstrainedCacheManager());
+        // securityManager.setRememberMeManager(cookieRememberMeManager());
+        return securityManager;
+    }
+
+    /**
+     * 设置对应的过滤条件和跳转条件
+     *
+     * @param securityManager
+     * @return
+     */
+    @Bean
+    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
+        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+        shiroFilterFactoryBean.setSecurityManager(securityManager);
+        Map<String, String> map = Maps.newConcurrentMap();
+        // 登录
+        shiroFilterFactoryBean.setLoginUrl("/login");
+        // 首页
+        shiroFilterFactoryBean.setSuccessUrl("/admin");
+        // 未授权
+        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
+        // 登出
+        map.put("/logout", "logout");
+        // 认证
+        map.put("/**", "authc");
+        // 匿名
+        map.put("/admin/**", "anon");// 后台页面
+        map.put("/api/**", "anon");// api请求
+        map.put("/reg/**", "anon");// 注册
+        map.put("/static/**", "anon");// 静态资源
+        map.put("/images/**", "anon");// 静态资源
+        map.put("/geojson/**", "anon");// 静态资源
+        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
+        return shiroFilterFactoryBean;
+    }
+}

+ 33 - 0
src/main/java/com/sysu/admin/support/cfg/ThreadContext.java

@@ -0,0 +1,33 @@
+package com.sysu.admin.support.cfg;
+
+import java.util.Arrays;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2021/12/30 14:21
+ */
+public class ThreadContext {
+
+    static public ExecutorService executor = Executors.newFixedThreadPool(5);
+
+
+    public static void main(String[] args) {
+
+        int[] arr = { 5 , 6 , 4 , 3 , 5 , 1};
+        for(int i=0;i < arr.length - 1;i++){
+            for(int j = i + 1; j < arr.length; j++){
+                if(arr[i] > arr[j]) {
+                    int temp = arr[i];
+                    arr[i] = arr[j];
+                    arr[j] = temp;
+                }
+            }
+        }
+        System.out.println(Arrays.toString(arr));
+
+    }
+
+}

+ 28 - 0
src/main/java/com/sysu/admin/support/shiro/ShiroAuditorAware.java

@@ -0,0 +1,28 @@
+package com.sysu.admin.support.shiro;
+
+import com.xiesx.fastboot.SpringHelper;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.data.domain.AuditorAware;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@Component
+public class ShiroAuditorAware implements AuditorAware<Long> {
+
+    ShiroService mShiroService = SpringHelper.getBean(ShiroService.class);
+
+    @Override
+    public Optional<Long> getCurrentAuditor() {
+        Subject subject = SecurityUtils.getSubject();
+        if (ObjectUtils.isNotEmpty(subject)) {
+            ShiroPrincipal principal = (ShiroPrincipal) subject.getPrincipal();
+            if (ObjectUtils.isNotEmpty(principal)) {
+                return Optional.of(principal.getId());
+            }
+        }
+        return Optional.empty();
+    }
+}

+ 183 - 0
src/main/java/com/sysu/admin/support/shiro/ShiroAuthenRealm.java

@@ -0,0 +1,183 @@
+package com.sysu.admin.support.shiro;
+
+import com.google.common.collect.Lists;
+import com.sysu.admin.support.system.organ.OrganRepository;
+import com.sysu.admin.support.system.role.SRole;
+import com.sysu.admin.support.system.role.SRoleRepository;
+import com.sysu.admin.support.system.role_permission.RolePermission;
+import com.sysu.admin.support.system.role_permission.RolePermissionRepository;
+import com.sysu.admin.support.system.user.User;
+import com.sysu.admin.support.system.user.UserRepository;
+import com.sysu.admin.support.system.user_role.UserRole;
+import com.sysu.admin.support.system.user_role.UserRoleRepository;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authc.pam.UnsupportedTokenException;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ * @title ShiroAuthenRealm
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:09:47
+ */
+public class ShiroAuthenRealm extends AuthorizingRealm {
+
+    @Autowired
+    UserRepository mUserRepository;
+
+    @Autowired
+    UserRoleRepository mUserRoleRepository;
+
+    @Autowired
+    SRoleRepository mRoleRepository;
+
+    @Autowired
+    RolePermissionRepository mRolePermissionRepository;
+
+    @Autowired
+    OrganRepository organRepository;
+
+    /**
+     * 认证
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
+        try {
+            // 获取到当前线程绑定的请求对象
+            ServletRequestAttributes servlet = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+            // 获取Request
+            HttpServletRequest request = servlet.getRequest();
+            // 获取Session
+            HttpSession session = request.getSession();
+            // 获取凭据
+            ShiroToken mShiroAuthenToken = (ShiroToken) token;
+            String username = mShiroAuthenToken.getUsername();
+            String password = new String(mShiroAuthenToken.getPassword());
+            // 是否访客登录
+            if (username.equals("guest") && password.equals("guest")) {
+                String nickname = "游客";
+                session.setAttribute(User.FIELDS.nickname, nickname);
+                ShiroPrincipal mPrincipal = new ShiroPrincipal(-1L, username, nickname);
+                return new SimpleAuthenticationInfo(mPrincipal, password, getName());
+            }
+            // 判断验证码
+            // if (!Captcha.get().validate("login", captcha, true).equals(Status.MATCHED)) {
+            // throw new UnsupportedTokenException();
+            // }
+            // 登录失败次数
+            int i;
+            // 判断是否为空
+            if ((username != null) && (password != null)) {
+                // 查找用户
+                User user = mUserRepository.findByUsername(username);
+                // 判断是否存在
+                if (ObjectUtils.isEmpty(user)) {
+                    throw new UnknownAccountException();
+                }
+                // 判断密码
+                if (!password.equals(user.getPassword())) {
+                    i = user.getLastLoginFailures() + 1;
+                    if (i > 0 && i < 3) {
+                        // 输错1-2次,"用户名密码错误"
+                        user.setLastLoginFailures(i);
+                        mUserRepository.insertOrUpdate(user);
+                        throw new IncorrectCredentialsException();
+                    } else if (i >= 3 && i < 5) {
+                        // 输错3-4次,"登录失败次数过多"
+                        user.setLastLoginFailures(i);
+                        mUserRepository.insertOrUpdate(user);
+                        throw new ExcessiveAttemptsException();
+                    } else if (i >= 5) {
+                        // 输错5次,"帐号被锁定"
+                        user.setIsEnable(1);
+                        user.setLastLoginFailures(i);
+                        mUserRepository.insertOrUpdate(user);
+                        throw new LockedAccountException();
+                    }
+                }
+                // 判断是否启用
+                if (user.getIsEnable() == 1) {
+                    throw new DisabledAccountException();
+                }
+                // 判断是否黑名单
+                if (user.getIsBlack() == 1) {
+                    throw new LockedAccountException();
+                }
+                user.setLastLoginFailures(0);
+                user.setLastLoginDate(new Timestamp(System.currentTimeMillis()));
+                if(user.getOrganId() == null){
+                    user.setOrganId(organRepository.findFirstId());
+                }
+                mUserRepository.insertOrUpdate(user);
+                // 创建新的用户会话对象
+                session.setAttribute(User.FIELDS.nickname, user.getNickname());
+                return new SimpleAuthenticationInfo(new ShiroPrincipal(user.getId(), username, user.getNickname()), password, getName());
+            }
+        } catch (Exception e) {
+            if (e instanceof UnknownAccountException) {
+                throw new UnknownAccountException();// 帐号
+            } else if (e instanceof IncorrectCredentialsException) {
+                throw new IncorrectCredentialsException();// 密码
+            } else if (e instanceof UnsupportedTokenException) {
+                throw new UnsupportedTokenException();// 验证码
+            } else if (e instanceof ExcessiveAttemptsException) {
+                throw new ExcessiveAttemptsException();// 登录次数
+            } else if (e instanceof DisabledAccountException) {
+                throw new DisabledAccountException();// 禁用
+            } else if (e instanceof LockedAccountException) {
+                throw new LockedAccountException();// 锁定
+            } else if (e instanceof AuthenticationException) {
+                throw new AuthenticationException();// 认证
+            } else {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 授权
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        // 角色列表
+        List<String> roles = Lists.newArrayList();
+        // 权限列表
+        List<String> permissions = Lists.newArrayList();
+        // 获取凭据
+        ShiroPrincipal localPrincipal = (ShiroPrincipal) principals.fromRealm(getName()).iterator().next();
+        if (localPrincipal != null) {
+            // 查询用户角色信息
+            List<UserRole> userRoles = mUserRoleRepository.getRoleByUsers(localPrincipal.getId());
+            for (UserRole ur : userRoles) {
+                // 查询角色
+                SRole role = mRoleRepository.findOne(ur.getPk().roles());
+                // 循环添加角色
+                roles.add(role.getRole());
+                // 查询角色权限
+                List<RolePermission> rolePermissions = mRolePermissionRepository.getListByRole(ur.getPk().roles());
+                // 循环添加角色权限
+                for (RolePermission rolePermission : rolePermissions) {
+                    permissions.add(rolePermission.getPermission());
+                }
+            }
+            SimpleAuthorizationInfo localSimpleAuthorizationInfo = new SimpleAuthorizationInfo();
+            localSimpleAuthorizationInfo.addStringPermissions(permissions);
+            localSimpleAuthorizationInfo.addRoles(roles);
+            return localSimpleAuthorizationInfo;
+        }
+        return null;
+    }
+}

+ 32 - 0
src/main/java/com/sysu/admin/support/shiro/ShiroPrincipal.java

@@ -0,0 +1,32 @@
+package com.sysu.admin.support.shiro;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @title ShiroPrincipal
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:09:43
+ */
+@Data
+public class ShiroPrincipal implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+
+
+    private Long id;
+
+    private String username;
+
+    private String nickname;
+
+    public ShiroPrincipal(Long id, String username, String nickname) {
+        super();
+        this.id = id;
+        this.username = username;
+        this.nickname = nickname;
+    }
+}

+ 43 - 0
src/main/java/com/sysu/admin/support/shiro/ShiroRestExceptionAdvice.java

@@ -0,0 +1,43 @@
+package com.sysu.admin.support.shiro;
+
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.UnauthenticatedException;
+import org.apache.shiro.authz.UnauthorizedException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @title ShiroRestExceptionAdvice
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:09:38
+ */
+@Slf4j
+@RestControllerAdvice
+public class ShiroRestExceptionAdvice {
+
+    /**
+     * 认知授权错误
+     *
+     * @param request
+     * @param e
+     * @return
+     */
+    @ExceptionHandler({UnauthorizedException.class, UnauthenticatedException.class})
+    public BaseResult shiroException(HttpServletRequest request, Exception e) {
+        log.error("shiroException ......", e);
+        String msg = "";
+        if (e instanceof UnauthenticatedException) {
+            msg = "未认证:" + e.getMessage();
+        } else if (e instanceof UnauthorizedException) {
+            msg = "未授权:" + e.getMessage();
+        } else {
+            msg = "未知";
+        }
+        return R.error(msg);
+    }
+}

+ 158 - 0
src/main/java/com/sysu/admin/support/shiro/ShiroService.java

@@ -0,0 +1,158 @@
+package com.sysu.admin.support.shiro;
+
+import com.sysu.admin.support.system.organ.Organ;
+import com.sysu.admin.support.system.organ.OrganRepository;
+import com.sysu.admin.support.system.role.SRole.RoleEnum;
+import com.sysu.admin.support.system.user.User;
+import com.sysu.admin.support.system.user.UserRepository;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @title ShiroService
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:09:55
+ */
+@Service
+public class ShiroService {
+
+    @Autowired
+    UserRepository mUserRepository;
+
+    @Autowired
+    OrganRepository mOrganRepository;
+
+    /**
+     * 获取当前昵称
+     */
+    public String getCurrentNickName() {
+        User user = getCurrentUser();
+        if (ObjectUtils.isNotEmpty(user)) {
+            return user.getNickname();
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前系统用户
+     */
+    @SneakyThrows
+    public Organ getCurrentOrgan() {
+        User user = getCurrentUser();
+        return mOrganRepository.findOne(user.getOrganId());
+    }
+
+    /**
+     * 获取当前用户本地用户
+     */
+    public ShiroPrincipal getCurrentPrincipal() {
+        Subject localSubject = SecurityUtils.getSubject();
+        if (localSubject != null) {
+            ShiroPrincipal localPrincipal = (ShiroPrincipal) localSubject.getPrincipal();
+            if (localPrincipal != null) {
+                return localPrincipal;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前系统用户
+     */
+    @SneakyThrows
+    public User getCurrentUser() {
+        Subject subject = SecurityUtils.getSubject();
+        if (ObjectUtils.isNotEmpty(subject)) {
+            ShiroPrincipal principal = (ShiroPrincipal) subject.getPrincipal();
+            if (ObjectUtils.isNotEmpty(principal)) {
+                return mUserRepository.findOne(principal.getId());
+            }
+        }
+        return null;
+    }
+
+    public Long getPrincipalId(){
+        Subject subject = SecurityUtils.getSubject();
+        if (ObjectUtils.isNotEmpty(subject)) {
+            ShiroPrincipal principal = (ShiroPrincipal) subject.getPrincipal();
+            if (ObjectUtils.isNotEmpty(principal)) {
+                return principal.getId();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前编号
+     */
+    public Long getCurrentUserId() {
+        User user = getCurrentUser();
+        if (ObjectUtils.isNotEmpty(user)) {
+            return user.getId();
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前帐号
+     */
+    public String getCurrentUserName() {
+        User user = getCurrentUser();
+        if (ObjectUtils.isNotEmpty(user)) {
+            return user.getUsername();
+        }
+        return null;
+    }
+
+    /**
+     * 用一个角色与当前用户角色比较
+     */
+    public boolean hasRole(String roleIdentifier) {
+        Subject subject = SecurityUtils.getSubject();
+        return subject.hasRole(roleIdentifier);
+    }
+
+    public boolean isAdmin(){
+        return hasRole(RoleEnum.admin.name());
+    }
+
+    /**
+     * 是否是县级执法
+     * @return
+     */
+    public boolean isXjzf(){
+        return hasRole(RoleEnum.xjzf.name());
+    }
+
+    /**
+     * 是否是县级执法
+     * @return
+     */
+    public boolean isZjxc(){
+        return hasRole(RoleEnum.zjxc.name());
+    }
+
+    /**
+     * 是否是市级执法
+     * @return
+     */
+    public boolean isSjzf(){
+        return hasRole(RoleEnum.sjzf.name());
+    }
+
+    /**
+     * 是否通过认证
+     */
+    public boolean isAuthenticated() {
+        Subject localSubject = SecurityUtils.getSubject();
+        if (localSubject != null) {
+            return localSubject.isAuthenticated();
+        }
+        return false;
+    }
+}

+ 33 - 0
src/main/java/com/sysu/admin/support/shiro/ShiroToken.java

@@ -0,0 +1,33 @@
+package com.sysu.admin.support.shiro;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.shiro.authc.UsernamePasswordToken;
+
+/**
+ * @title ShiroAuthenToken
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:09:51
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class ShiroToken extends UsernamePasswordToken {
+
+    private static final long serialVersionUID = 5898441540965086534L;
+
+    private String captcha;
+
+    public ShiroToken(String username, String password) {
+        super(username, password);
+    }
+
+    public ShiroToken(String username, String password, boolean rememberMe) {
+        super(username, password, rememberMe);
+    }
+
+    public ShiroToken(String username, String password, boolean rememberMe, String captcha) {
+        super(username, password, rememberMe);
+        this.captcha = captcha;
+    }
+}

+ 28 - 0
src/main/java/com/sysu/admin/support/system/config/ActiveContext.java

@@ -0,0 +1,28 @@
+package com.sysu.admin.support.system.config;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties("spring.profiles")
+public class ActiveContext {
+
+    private static String active;
+
+    public void setActive(String active) {
+        this.active = active;
+    }
+
+    public static boolean isApi() {
+        return active.trim().equals("api");
+    }
+
+
+    public  static boolean isAdm() {
+        return active.trim().equals("adm");
+    }
+
+    public static boolean isDev() {
+        return active.trim().equals("dev");
+    }
+
+}

+ 54 - 0
src/main/java/com/sysu/admin/support/system/config/SConfig.java

@@ -0,0 +1,54 @@
+package com.sysu.admin.support.system.config;
+
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * @title Config
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:02:21
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "sys_config")
+@Entity
+@DynamicInsert
+@DynamicUpdate
+public class SConfig extends JpaPlusEntity<SConfig> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 键
+     */
+    @Id
+    private String k;
+
+    /**
+     * 值
+     */
+    @Column
+    private String v;
+
+    @Column
+    private String title;
+
+    @Column
+    private String remark;
+
+    @Column
+    private Integer sort;
+}

+ 116 - 0
src/main/java/com/sysu/admin/support/system/config/SConfigController.java

@@ -0,0 +1,116 @@
+package com.sysu.admin.support.system.config;
+
+import com.querydsl.core.types.ExpressionUtils;
+import com.querydsl.core.types.Predicate;
+import com.sysu.admin.support.base.BaseVo;
+import com.sysu.admin.support.base.ServiceContext;
+import com.xiesx.fastboot.base.pagination.PaginationHelper;
+import com.xiesx.fastboot.base.pagination.PaginationResult;
+import com.xiesx.fastboot.base.pagination.PaginationVo;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import com.xiesx.fastboot.core.exception.RunException;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.authz.annotation.Logical;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @title ConfigController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:02:30
+ */
+@Validated
+@Controller
+@RequestMapping(value = "config/")
+public class SConfigController extends ServiceContext {
+
+    /**
+     * 页面
+     *
+     * @return
+     */
+    @RequestMapping(value = "index")
+    @RequiresPermissions("config:view")
+    public String index() {
+        return "system/config/index";
+    }
+
+    /**
+     * 分页
+     *
+     * @param base
+     * @param page
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "page")
+    @RequiresPermissions("config:select")
+    public PaginationResult page(BaseVo base, PaginationVo page) {
+        // 对象
+        QSConfig qConfig = QSConfig.sConfig;
+        // 条件
+        Predicate predicate = qConfig.k.isNotNull();
+        if (ObjectUtils.isNotEmpty(base.getKeyword())) {
+            Predicate p1 = qConfig.title.likeIgnoreCase("%" + base.getKeyword() + "%");
+            Predicate p2 = qConfig.k.likeIgnoreCase("%" + base.getKeyword() + "%");
+            predicate = ExpressionUtils.and(predicate, ExpressionUtils.anyOf(p1, p2));
+        }
+        // 排序
+        Sort sort = Sort.by(Direction.ASC, SConfig.FIELDS.sort);
+        // 分页
+        Pageable pageable = PageRequest.of(page.getPage(), page.getLimit(), sort);
+        // 查询数据
+        Page<SConfig> data = mSConfigService.findAll(predicate, pageable);
+        // 构造
+        return PaginationHelper.create(data);
+    }
+
+    /**
+     * 详情
+     *
+     * @param model
+     * @return
+     * @throws RunException
+     */
+    @RequestMapping(value = "form")
+    @RequiresPermissions("config:select")
+    public String form(String k, Model model) {
+        SConfig config = mSConfigService.get(k);
+        if (ObjectUtils.isEmpty(config)) {
+            config = new SConfig();
+        }
+        model.addAttribute("json", config.toJSONString());
+        return "system/config/form";
+    }
+
+    /**
+     * 添加/修改
+     *
+     * @param base
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "submit")
+    @RequiresPermissions(value = {"config:insert", "config:update"}, logical = Logical.OR)
+    public BaseResult submit(BaseVo base, SConfig req) {
+        SConfig config = mSConfigService.get(req.getK());
+        if (ObjectUtils.isEmpty(config)) {
+            return R.succ((mSConfigService.insertOrUpdate(req) == 1) ? "添加成功" : "添加失败");
+        } else {
+            return R.succ((mSConfigService.insertOrUpdate(req) == 1) ? "修改成功" : "修改失败");
+        }
+    }
+
+
+}

+ 18 - 0
src/main/java/com/sysu/admin/support/system/config/SConfigRepository.java

@@ -0,0 +1,18 @@
+package com.sysu.admin.support.system.config;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+
+public interface SConfigRepository extends JpaPlusRepository<SConfig, String> {
+
+    @Query(value = "select * from sys_config where k=?1", nativeQuery = true)
+    SConfig get(String k);
+
+    @Transactional
+    @Modifying
+    @Query(value = "update sys_config set k=?1 where v=?2", nativeQuery = true)
+    void set(String k, String v);
+}

+ 39 - 0
src/main/java/com/sysu/admin/support/system/config/SConfigService.java

@@ -0,0 +1,39 @@
+package com.sysu.admin.support.system.config;
+
+import com.sysu.admin.support.base.BaseService;
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/4/1 14:26
+ */
+@Service
+public class SConfigService extends BaseService<SConfig, String> {
+
+    @Autowired
+    SConfigRepository mSConfigRepository;
+
+    public String getV(String key){
+        SConfig config = mSConfigRepository.get(key);
+        if(config == null){
+            return "";
+        }
+        return config.getV();
+    }
+
+    @Override
+    public JpaPlusRepository<SConfig, String> r() {
+        return mSConfigRepository;
+    }
+
+    public SConfig get(String k){
+        return mSConfigRepository.get(k);
+    }
+
+    public void set(String k, String v){
+         mSConfigRepository.set(k,v);
+    }
+}

+ 84 - 0
src/main/java/com/sysu/admin/support/system/menu/SMenu.java

@@ -0,0 +1,84 @@
+package com.sysu.admin.support.system.menu;
+
+import com.sysu.admin.utils.i18n.MessageUtils;
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * @title Menu
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:03:32
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "sys_menu")
+@Entity
+@EntityListeners(AuditingEntityListener.class)
+@DynamicInsert
+@DynamicUpdate
+public class SMenu extends JpaPlusEntity<SMenu> {
+
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @CreatedDate
+    @Column(updatable = false, nullable = false)
+    private Date createDate;
+
+    @LastModifiedDate
+    @Column(nullable = false)
+    private Date updateDate;
+
+    @Column
+    private Long parent;
+
+    @Column
+    private String name;
+
+    public String getName(){
+        int index = name.indexOf("menu.");
+        if(index > -1){
+            return MessageUtils.get(name);
+        }
+        return name;
+    }
+
+    @Column
+    private String href;
+
+    @Column
+    private String icon;
+
+    @Column
+    private Integer sort;
+
+    @Column
+    private String permission;
+
+    @Column
+    private Integer isMenu;
+
+    @Column
+    private Integer isOpen;
+
+    @Column
+    private Integer isEnable;
+
+}

+ 143 - 0
src/main/java/com/sysu/admin/support/system/menu/SMenuController.java

@@ -0,0 +1,143 @@
+package com.sysu.admin.support.system.menu;
+
+import com.google.common.collect.Maps;
+import com.sysu.admin.support.base.BaseVo;
+import com.sysu.admin.support.base.ServiceContext;
+import com.xiesx.fastboot.base.pagination.PaginationVo;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import com.xiesx.fastboot.utils.CopyUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @title MenuController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:04:02
+ */
+@Validated
+@Controller
+@RequestMapping(value = "menu/")
+public class SMenuController extends ServiceContext {
+
+    @Autowired
+    SMenuRepository mMenuRepository;
+
+    @Autowired
+    SMenuService mMenuService;
+
+    /**
+     * 页面
+     *
+     * @return
+     */
+    @RequestMapping(value = "index")
+    @RequiresPermissions("menu:insert")
+    public String index() {
+        return "system/menu/index";
+    }
+
+    /**
+     * 添加编辑页面
+     * @return
+     */
+    @RequestMapping(value = "form")
+    @RequiresPermissions("menu:view")
+    public String form(BaseVo baseVo, Model model) {
+        SMenu sMenu = mMenuRepository.getOne(baseVo.getId());
+        SMenu parent = mMenuRepository.getOne(sMenu.getParent());
+        if (ObjectUtils.isEmpty(sMenu)) {
+            sMenu = new SMenu();
+        }
+        model.addAttribute("json", sMenu.toJSONString());
+        if(sMenu.getParent() > -1) {
+            model.addAttribute("parentName", parent.getName());
+        }
+        return "system/menu/form";
+    }
+
+    /**
+     * 添加子节点
+     * @return
+     */
+    @RequiresPermissions("menu:insert")
+    @RequestMapping(value = "addChildForm")
+    public String addChildForm(BaseVo baseVo, Model model) {
+        SMenu sMenu = mMenuRepository.getOne(baseVo.getId());
+        List<SMenu> childList = mMenuRepository.findByParent(baseVo.getId());
+        model.addAttribute("parent", sMenu);
+        model.addAttribute("sort", childList.size() + 1);
+        return "system/menu/addChildForm";
+    }
+
+    /**
+     * 添加根菜单
+     * @return
+     */
+    @RequiresPermissions("menu:insert")
+    @RequestMapping(value = "addRoot")
+    public String addRoot(Model model) {
+        List<SMenu> childList = mMenuRepository.findByParent(-1L);
+        model.addAttribute("sort", childList.size() + 1);
+        return "system/menu/addRoot";
+    }
+
+    /**
+     * 添加编辑页面
+     * @return
+     */
+    @RequiresPermissions("menu:update")
+    @RequestMapping(value = "submit")
+    @ResponseBody
+    public BaseResult submit(SMenu req) {
+        req.setIsMenu(req.getIsMenu() == null ? 0 : 1);
+        if(req.getId() == null){
+            mMenuRepository.insertOrUpdate(req);
+        }else{
+            SMenu sMenu = mMenuRepository.findOne(req.getId());
+            BeanUtils.copyProperties(req, sMenu, CopyUtils.ignoreNullNames(req));
+            mMenuRepository.insertOrUpdate(sMenu);
+        }
+        return R.succ();
+    }
+
+    /**
+     * 分页列表
+     *
+     * @param base
+     * @param page
+     * @return
+     */
+    @ResponseBody
+    @RequiresPermissions("menu:view")
+    @RequestMapping(value = "list")
+    public Map<String, Object> list(BaseVo base, PaginationVo page) {
+        List<SMenuResBO.MenuBO> menus = mMenuService.getMenuList();
+        // 构造分页
+        Map<String, Object> maps = Maps.newHashMap();
+        maps.put("code", 0);
+        maps.put("msg", "操作成功");
+        maps.put("count", menus.size());
+        maps.put("data", menus);
+        return maps;
+    }
+
+    @ResponseBody
+    @RequestMapping(value = "delete")
+    @RequiresPermissions("menu:delete")
+    public BaseResult delete(Long id) {
+        Integer row = mMenuRepository.delete(id);
+        return (row >= 1) ? R.succ() : R.fail();
+    }
+}

+ 18 - 0
src/main/java/com/sysu/admin/support/system/menu/SMenuRepository.java

@@ -0,0 +1,18 @@
+package com.sysu.admin.support.system.menu;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface SMenuRepository extends JpaPlusRepository<SMenu, Long> {
+
+    SMenu findByPermission(String permission);
+    List<SMenu> findByParent(Long parent);
+
+    @Query(value = "select * from sys_menu where is_enable = 0 order by sort asc,id asc", nativeQuery = true)
+    List<SMenu> getMenuList();
+
+    @Query(value = "select * from sys_menu where is_enable = 0 and is_menu = 0 order by sort asc,id asc", nativeQuery = true)
+    List<SMenu> getNavigList();
+}

+ 50 - 0
src/main/java/com/sysu/admin/support/system/menu/SMenuResBO.java

@@ -0,0 +1,50 @@
+package com.sysu.admin.support.system.menu;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * @title MenuResBO
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:03:28
+ */
+@Data
+public class SMenuResBO {
+
+    @Data
+    @Builder
+    public static class MenuBO {
+
+        @JSONField(ordinal = 1)
+        public Long id;
+
+        @JSONField(ordinal = 2)
+        public String name;
+
+        @JSONField(ordinal = 3)
+        public String menuIcon;
+
+        @JSONField(ordinal = 4)
+        public String menuUrl;
+
+        @JSONField(ordinal = 5)
+        public String authority;
+
+        @JSONField(ordinal = 6)
+        public Integer orderNumber;
+
+        @JSONField(ordinal = 7)
+        public Long parent;
+
+        @JSONField(ordinal = 8)
+        public Integer checked;
+
+        @JSONField(ordinal = 9)
+        public Integer isMenu;
+
+        @JSONField(ordinal = 10)
+        public Boolean open;
+    }
+}

+ 95 - 0
src/main/java/com/sysu/admin/support/system/menu/SMenuService.java

@@ -0,0 +1,95 @@
+package com.sysu.admin.support.system.menu;
+
+import com.google.common.collect.Lists;
+import com.sysu.admin.support.tree.MenuTree;
+import com.sysu.admin.support.tree.NavigTree;
+import com.sysu.admin.support.system.menu.SMenuResBO.MenuBO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @title MenuService
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:03:38
+ */
+@Service
+public class SMenuService {
+
+    @Autowired
+    SMenuRepository mMenuRepository;
+
+    /**
+     * 查询MenuList
+     *
+     * @return
+     */
+    public List<MenuBO> getMenuList() {
+        List<MenuBO> menus = Lists.newArrayList();
+        List<SMenu> lists = mMenuRepository.getMenuList();
+        for (SMenu menu : lists) {
+            menus.add(
+                    MenuBO.builder().id(menu.getId())
+                        .name(menu.getName())
+                        .menuIcon(menu.getIcon())
+                        .menuUrl(menu.getHref())
+                        .authority(menu.getPermission())
+                        .orderNumber(menu.getSort())
+                        .parent(menu.getParent())
+                        .checked(0)
+                        .isMenu(menu.getIsMenu())
+                        .open(menu.getIsOpen() == 1).build()
+            );
+        }
+        return menus;
+    }
+
+    /**
+     * 查询MenuTree
+     *
+     * @return
+     */
+    public List<MenuTree> getMenuTree() {
+        List<SMenu> list = mMenuRepository.getMenuList();
+        List<MenuTree> trees = Lists.newArrayList();
+        for (SMenu p : list) {
+            trees.add(
+                    MenuTree.builder().id(p.getId())
+                    .name(p.getName())
+                    .value(String.valueOf(p.getId()))
+                    .disabled(false)
+                    .selected(false)
+                    .parent(p.getParent())
+                    .sort(p.getSort())
+                    .build()
+            );
+        }
+        return SMenuTreeHelper.getMenuTree(trees);
+    }
+
+    /**
+     * 查询NavigTree
+     *
+     * @return
+     */
+    public List<NavigTree> getNavigTree(String[] permissions) {
+        Arrays.sort(permissions);
+        List<SMenu> list = mMenuRepository.getNavigList();
+        List<NavigTree> trees = Lists.newArrayList();
+        for (SMenu p : list) {
+            int index = Arrays.binarySearch(permissions, p.getPermission());
+            if (index > -1) {
+                trees.add(NavigTree.builder().id(p.getId())
+                        .title(p.getName())
+                        .icon(p.getIcon())
+                        .href(p.getHref())
+                        .spread(p.getIsOpen() == 1)
+                        .parent(p.getParent())
+                        .sort(p.getSort()).build());
+            }
+        }
+        return SMenuTreeHelper.getNavigTree(trees);
+    }
+}

+ 107 - 0
src/main/java/com/sysu/admin/support/system/menu/SMenuTreeHelper.java

@@ -0,0 +1,107 @@
+package com.sysu.admin.support.system.menu;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+import com.sysu.admin.support.tree.MenuTree;
+import com.sysu.admin.support.tree.NavigTree;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @title TreeUtils
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:03:57
+ */
+public class SMenuTreeHelper {
+
+    /**
+     * 找出子节点
+     *
+     * @param parentNode
+     * @param nodes
+     */
+    private static void findMenuChildNodes(MenuTree parentNode, List<MenuTree> nodes) {
+        List<MenuTree> children = Lists.newArrayList();
+        parentNode.setChildren(children);
+        for (MenuTree node : nodes) {
+            if (Objects.equal(node.getParent(), parentNode.getId())) {
+                children.add(node);
+                findMenuChildNodes(node, nodes);
+            }
+        }
+        // 对子节点进行排序
+        Collections.sort(children);
+    }
+
+    /**
+     * 找出根节点
+     *
+     * @param nodes
+     * @return
+     */
+    private static List<MenuTree> findMenuRootNodes(List<MenuTree> nodes) {
+        List<MenuTree> rootNodes = Lists.newArrayList();
+        for (MenuTree node : nodes) {
+            if (-1 == node.getParent()) {
+                rootNodes.add(node);
+                findMenuChildNodes(node, nodes);
+            }
+        }
+        // 对父节点进行排序
+        Collections.sort(rootNodes);
+        return rootNodes;
+    }
+
+    /**
+     * 找出子节点
+     *
+     * @param parentNode
+     * @param nodes
+     */
+    private static void findNavigChildNodes(NavigTree parentNode, List<NavigTree> nodes) {
+        List<NavigTree> children = Lists.newArrayList();
+        for (NavigTree node : nodes) {
+            if (Objects.equal(node.getParent(), parentNode.getId())) {
+                children.add(node);
+                findNavigChildNodes(node, nodes);
+            }
+        }
+        if (!children.isEmpty()) {
+            parentNode.setList(children);
+            // 对子节点进行排序
+            Collections.sort(children);
+        }
+    }
+
+    //
+
+    /**
+     * 找出根节点
+     *
+     * @param nodes
+     * @return
+     */
+    private static List<NavigTree> findNavigRootNodes(List<NavigTree> nodes) {
+        List<NavigTree> rootNodes = Lists.newArrayList();
+        for (NavigTree node : nodes) {
+            if (-1 == node.getParent()) {
+                rootNodes.add(node);
+                findNavigChildNodes(node, nodes);
+            }
+        }
+        // 对父节点进行排序
+        Collections.sort(rootNodes);
+        return rootNodes;
+    }
+
+    public static List<MenuTree> getMenuTree(List<MenuTree> nodes) {
+        return findMenuRootNodes(nodes);
+    }
+
+    public static List<NavigTree> getNavigTree(List<NavigTree> nodes) {
+        return findNavigRootNodes(nodes);
+    }
+
+}

+ 150 - 0
src/main/java/com/sysu/admin/support/system/organ/Organ.java

@@ -0,0 +1,150 @@
+package com.sysu.admin.support.system.organ;
+
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.*;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedBy;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * @title Organ.java (generator)
+ * @description 机构表
+ * @author 谢思贤
+ * @date 2020-04-25
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "sys_organ")
+@Entity
+@EntityListeners(AuditingEntityListener.class)
+@DynamicInsert
+@DynamicUpdate
+@Where(clause = "is_del=0")
+@SQLDelete(sql = "update sys_organ set is_del=1 where id = ?")
+@SQLDeleteAll(sql = "update sys_organ set is_del=1 where id = ?")
+public class Organ extends JpaPlusEntity<Organ> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+
+
+    @Column(name = "parent_id")
+    private Long parentId;
+
+    @ManyToOne(cascade= CascadeType.REFRESH)
+    @JoinColumn(name = "parent_id",insertable = false,updatable = false)
+    private Organ parent;
+
+    /**
+     * 是否是县市级单位
+     */
+    @Column(name = "is_bureau")
+    private Integer isBureau;
+
+    /**
+     * 创建时间
+     */
+    @CreatedDate
+    @Column(updatable = false, nullable = false)
+    private Date createDate;
+
+    /**
+     * 创建人
+     */
+    @CreatedBy
+    @Column(updatable = false, nullable = false)
+    private Long createBy;
+
+    /**
+     * 修改时间
+     */
+    @LastModifiedDate
+    @Column(nullable = false)
+    private Date updateDate;
+
+    /**
+     * 修改人
+     */
+    @LastModifiedBy
+    @Column(nullable = false)
+    private Long updateBy;
+
+    /**
+     * 省
+     */
+    @Column
+    private Long provinceId;
+
+    @Column
+    private String provinceName;
+
+    /**
+     * 市
+     */
+    @Column
+    private Long cityId;
+
+    @Column
+    private String cityName;
+
+    /**
+     * 区
+     */
+    @Column
+    private Long districtId;
+
+    @Column
+    private String districtName;
+
+    /**
+     * 公司
+     */
+    @Column
+    private String company;
+
+
+    /**
+     * 联系人
+     */
+    @Column
+    private String contacts;
+
+
+    /**
+     * 地址
+     */
+    @Column
+    private String address;
+
+    /**
+     * 是否删用(0:正常、1:删除)
+     */
+    @Column
+    private Integer isDel;
+
+
+    // ==========================================
+
+
+}

+ 206 - 0
src/main/java/com/sysu/admin/support/system/organ/OrganController.java

@@ -0,0 +1,206 @@
+package com.sysu.admin.support.system.organ;
+
+import com.google.common.base.Objects;
+import com.querydsl.core.types.ExpressionUtils;
+import com.querydsl.core.types.Predicate;
+import com.sysu.admin.support.base.BaseVo;
+import com.sysu.admin.support.base.ServiceContext;
+import com.xiesx.fastboot.base.pagination.PaginationHelper;
+import com.xiesx.fastboot.base.pagination.PaginationResult;
+import com.xiesx.fastboot.base.pagination.PaginationVo;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import com.xiesx.fastboot.core.exception.RunException;
+import com.xiesx.fastboot.utils.CopyUtils;
+import com.sysu.admin.support.system.user.User;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.BeanUtils;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @title OrganController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:04:18
+ */
+@Controller
+@RequestMapping("/organ")
+public class OrganController extends ServiceContext {
+
+    /**
+     * 页面
+     *
+     * @return
+     */
+    @RequestMapping(value = "index")
+    @RequiresPermissions("organ:select")
+    public String index(Model model) {
+        return "system/organ/index";
+    }
+
+    /**
+     * 分页
+     *
+     * @param base
+     * @param page
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "page")
+    @RequiresPermissions("organ:select")
+    public PaginationResult page(BaseVo base, PaginationVo page) {
+        // 对象
+        QOrgan qOrgan = QOrgan.organ;
+        // 条件
+        Predicate predicate = qOrgan.id.isNotNull();
+        if (ObjectUtils.isNotEmpty(base.getKeyword())) {
+            Predicate p1 = qOrgan.id.like("%" + base.getKeyword() + "%");
+            Predicate p2 = qOrgan.company.likeIgnoreCase("%" + base.getKeyword() + "%");
+            Predicate p3 = qOrgan.contacts.likeIgnoreCase("%" + base.getKeyword() + "%");
+
+            predicate = ExpressionUtils.and(predicate, ExpressionUtils.anyOf(p1, p2, p3));
+        }
+
+        User currentUser = mShiroService.getCurrentUser();
+
+        //县级执法权限可以看下级的部门
+        if(mShiroService.isXjzf()){
+            predicate = ExpressionUtils.and(predicate, qOrgan.parentId.eq(currentUser.getOrganId()));
+        }
+
+
+        // 排序
+        Sort sort = Sort.by(Direction.DESC, Organ.FIELDS.id);
+        // 分页
+        Pageable pageable = PageRequest.of(page.getPage(), page.getLimit(), sort);
+        // 查询数据
+        Page<Organ> data = mOrganService.findAll(predicate, pageable);
+        // 构造
+        return PaginationHelper.create(data);
+    }
+
+
+    /**
+     * 中心选择器数据
+     * @param base
+     * @param page
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "centerSelect")
+    public PaginationResult centerSelect(BaseVo base, PaginationVo page){
+        // 对象
+        QOrgan qOrgan = QOrgan.organ;
+        // 条件
+        Predicate predicate = qOrgan.id.isNotNull();
+        if (ObjectUtils.isNotEmpty(base.getKeyword())) {
+            Predicate p1 = qOrgan.id.like("%" + base.getKeyword() + "%");
+            Predicate p2 = qOrgan.company.likeIgnoreCase("%" + base.getKeyword() + "%");
+            Predicate p3 = qOrgan.contacts.likeIgnoreCase("%" + base.getKeyword() + "%");
+            predicate = ExpressionUtils.and(predicate, ExpressionUtils.anyOf(p1, p2, p3));
+        }
+
+        //县级执法权限可以看下级的部门
+        if(mShiroService.isXjzf()){
+            User currentUser = mShiroService.getCurrentUser();
+            predicate = ExpressionUtils.and(predicate, qOrgan.parentId.eq(currentUser.getOrganId()));
+        }
+
+        if(ObjectUtils.isNotEmpty(base.getCityName())){
+            predicate = ExpressionUtils.and(predicate, qOrgan.cityName.like(base.getCityName() + "%"));
+        }
+
+        predicate = ExpressionUtils.and(predicate, qOrgan.isBureau.eq(base.getIsBureau()));
+
+
+        // 排序
+        Sort sort = Sort.by(Direction.DESC, Organ.FIELDS.updateDate);
+        // 分页
+        Pageable pageable = PageRequest.of(page.getPage(), page.getLimit(), sort);
+        // 查询数据
+        Page<Organ> data = mOrganService.findAll(predicate, pageable);
+        // 构造
+        return PaginationHelper.create(data);
+
+    }
+
+    /**
+     * 详情
+     *
+     * @param base
+     * @param model
+     * @return
+     * @throws RunException
+     */
+    @RequestMapping(value = "form")
+    @RequiresPermissions("organ:select")
+    public String form(BaseVo base, Model model) {
+        Organ organ = new Organ().setId(base.getId());
+        if (!Objects.equal(organ.getId(), -1L)) {
+            organ = mOrganService.findOne(organ.getId());
+        }
+        model.addAttribute("organ", organ);
+        model.addAttribute("json", organ.toJSONString());
+        return "system/organ/form";
+    }
+
+    /**
+     * 更新,添加
+     *
+     * @param req
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "submit")
+    @RequiresPermissions("organ:update")
+    public BaseResult submit(BaseVo base, Organ req) {
+        Organ organ = new Organ().setId(req.getId());
+        if (Objects.equal(organ.getId(), -1L)) {
+            BeanUtils.copyProperties(req, organ);
+        } else {
+            organ = mOrganService.findOne(base.getId());
+            BeanUtils.copyProperties(req, organ, CopyUtils.ignoreNullNames(req));
+        }
+
+        // 区县
+        if (ObjectUtils.isNotEmpty(req.getCityName())) {
+            organ.setCityName(req.getCityName());
+        } else {
+            organ.setCityName(null);
+        }
+
+        // 先保存
+        organ = mOrganService.saveAndFlush(organ);
+        Integer row = mOrganService.insertOrUpdate(organ);
+        return (row >= 1) ? R.succ() : R.fail();
+    }
+
+    @ResponseBody
+    @RequestMapping(value = "batchTestUser")
+    public BaseResult batchTestUser(Integer isBureau){
+        mOrganService.batchTestUser(isBureau);
+        return R.succ();
+    }
+
+    /**
+     * 删除
+     *
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "delete")
+    @RequiresPermissions("organ:delete")
+    public BaseResult delete(BaseVo base) {
+        Integer row = mOrganService.delete(base.getIds());
+        return (row >= 1) ? R.succ() : R.fail();
+    }
+}

+ 19 - 0
src/main/java/com/sysu/admin/support/system/organ/OrganRepository.java

@@ -0,0 +1,19 @@
+package com.sysu.admin.support.system.organ;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface OrganRepository extends JpaPlusRepository<Organ, Long> {
+
+
+
+
+    @Query(value = "SELECT id FROM sys_organ order by id asc limit 1", nativeQuery = true)
+    Long findFirstId();
+
+    @Query(value = "SELECT id FROM sys_organ where parent_id = ?1 and is_del = 0", nativeQuery = true)
+    List<Long> findIdByParentId(Long parentId);
+
+}

+ 69 - 0
src/main/java/com/sysu/admin/support/system/organ/OrganService.java

@@ -0,0 +1,69 @@
+package com.sysu.admin.support.system.organ;
+
+import com.querydsl.core.types.Predicate;
+import com.sysu.admin.support.base.BaseService;
+import com.sysu.admin.utils.ChineseCharacterUtil;
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import com.sysu.admin.support.system.role.SRole;
+import com.sysu.admin.support.system.user.User;
+import com.sysu.admin.support.system.user_role.PKUR;
+import com.sysu.admin.support.system.user_role.UserRole;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/16 17:40
+ */
+@Service
+public class OrganService extends BaseService<Organ, Long> {
+
+    @Autowired
+    public OrganRepository mOrganRepository;
+
+    @Override
+    public JpaPlusRepository<Organ, Long> r() {
+        return mOrganRepository;
+    }
+
+    public List<Long> findIdByParentId(Long parentId){
+        return mOrganRepository.findIdByParentId(parentId);
+    }
+
+    public void batchTestUser(Integer isBureau){
+        Predicate predicate = QOrgan.organ.isBureau.eq(isBureau);
+        List<Organ> list = mOrganRepository.findAll(predicate);
+        list.stream().forEach(organ -> {
+            User user = new User();
+
+            String usernameHz = isBureau == 1
+                    ? organ.getCityName().substring(0,2)
+                    : organ.getCityName().substring(0,2) + organ.getCompany().substring(0,2);
+
+            String username = ChineseCharacterUtil.convertHanzi2Pinyin(usernameHz,false)
+                    + "_001";
+
+            if(serviceContext.mUserService.findByUsername(username) != null){
+                return;
+            }
+
+            user.setOrganId(organ.getId());
+            user.setUsername(username);
+            user.setCode(username);
+            String pwd = DigestUtils.md5Hex(username + username);
+            user.setPassword(pwd);
+            user.setNickname(username);
+            serviceContext.mUserService.saveAndFlush(user);
+
+            UserRole userRole = new UserRole().setPk(new PKUR().users(user.getId())
+                    .roles(organ.getIsBureau() == 1 ?
+                            SRole.RoleEnum.valueOf(SRole.RoleEnum.xjzf) :
+                            SRole.RoleEnum.valueOf(SRole.RoleEnum.zjxc)));
+            mUserRoleRepository.save(userRole);
+        });
+    }
+}

+ 88 - 0
src/main/java/com/sysu/admin/support/system/region/Region.java

@@ -0,0 +1,88 @@
+package com.sysu.admin.support.system.region;
+
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.*;
+
+/**
+ * @title Area.java (generator)
+ * @description 参数配置
+ * @author 谢思贤
+ * @date 2020-06-04
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "sys_region")
+@Entity
+@EntityListeners(AuditingEntityListener.class)
+@DynamicInsert
+@DynamicUpdate
+public class Region extends JpaPlusEntity<Region> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    /**
+     * 代码
+     */
+    @Column
+    private Long code;
+
+    /**
+     * 名称
+     */
+    @Column
+    private String name;
+
+    /**
+     * 简称
+     */
+    @Column
+    private String nameShort;
+
+    /**
+     * 级别
+     */
+    @Column
+    private Integer level;
+
+
+    /**
+     * 经度
+     */
+    @Column
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    @Column
+    private String lat;
+
+    /**
+     * 上级代码
+     */
+    @Column
+    private Long parent;
+
+    /**
+     * 排序
+     */
+    @Column
+    private Integer sort;
+}

+ 16 - 0
src/main/java/com/sysu/admin/support/system/region/RegionRepository.java

@@ -0,0 +1,16 @@
+package com.sysu.admin.support.system.region;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface RegionRepository extends JpaPlusRepository<Region, Long> {
+
+    Region findByCode(Long code);
+
+    Region findByNameShortAndParent(String nameShort, Long parentCode);
+
+    @Query(value = "SELECT * FROM (SELECT * FROM sys_region a WHERE a.`parent` = ?2) b WHERE b.code IN (?1)", nativeQuery = true)
+    List<Region> findByCodeIsInParent(Long child, Long parent);
+}

+ 80 - 0
src/main/java/com/sysu/admin/support/system/role/SRole.java

@@ -0,0 +1,80 @@
+package com.sysu.admin.support.system.role;
+
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * @title Role
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:25
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "sys_role")
+@Entity
+@EntityListeners(AuditingEntityListener.class)
+@DynamicInsert
+@DynamicUpdate
+public class SRole extends JpaPlusEntity<SRole> {
+
+    public enum RoleEnum {
+        admin, sjzf, xjzf, zjxc;
+
+        public static long valueOf(RoleEnum roleEnum){
+            switch (roleEnum){
+                case admin:
+                    return 1;
+                case sjzf:
+                    return 2;
+                case xjzf:
+                    return 3;
+                case zjxc:
+                    return 4;
+            }
+            throw new RuntimeException();
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @CreatedDate
+    @Column(updatable = false, nullable = false)
+    private Date createDate;
+
+    @LastModifiedDate
+    @Column(nullable = false)
+    private Date updateDate;
+
+    @Column
+    private String name;
+
+    @Column
+    private String description;
+
+    @Column
+    private String role;
+
+    @Column
+    private Integer isSystem;
+
+    @Column
+    private Integer sort;
+}

+ 147 - 0
src/main/java/com/sysu/admin/support/system/role/SRoleController.java

@@ -0,0 +1,147 @@
+package com.sysu.admin.support.system.role;
+
+import com.alibaba.fastjson.JSON;
+import com.google.common.base.Objects;
+import com.querydsl.core.types.ExpressionUtils;
+import com.querydsl.core.types.Predicate;
+import com.sysu.admin.support.base.BaseVo;
+import com.sysu.admin.support.base.ServiceContext;
+import com.sysu.admin.support.system.menu.SMenu;
+import com.sysu.admin.support.system.menu.SMenuRepository;
+import com.sysu.admin.support.system.menu.SMenuService;
+import com.xiesx.fastboot.base.pagination.PaginationHelper;
+import com.xiesx.fastboot.base.pagination.PaginationResult;
+import com.xiesx.fastboot.base.pagination.PaginationVo;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import com.sysu.admin.support.system.role_permission.PKRP;
+import com.sysu.admin.support.system.role_permission.RolePermission;
+import com.sysu.admin.support.system.role_permission.RolePermissionRepository;
+import com.sysu.admin.support.system.role_permission.RolePermissionService;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * @title RoleController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:33
+ */
+@Controller
+@RequestMapping("/role")
+public class SRoleController extends ServiceContext {
+
+    @Autowired
+    SRoleRepository mRoleRepository;
+
+    @Autowired
+    RolePermissionRepository mRolePermissionRepository;
+
+    @Autowired
+    SMenuRepository mMenuRepository;
+
+    @Autowired
+    SMenuService mMenuService;
+
+    @Autowired
+    RolePermissionService mRolePermissionService;
+
+    /**
+     * 页面
+     *
+     * @return
+     */
+    @RequiresPermissions("rule:view")
+    @RequestMapping(value = "index")
+    public String index(Model model) {
+        return "system/role/index";
+    }
+
+    /**
+     * 分页
+     *
+     * @param base
+     * @param page
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "page")
+    @RequiresPermissions("rule:view")
+    public PaginationResult page(BaseVo base, PaginationVo page) {
+        // 对象
+        QSRole qRole = QSRole.sRole;
+        // 条件
+        Predicate predicate = qRole.id.isNotNull();
+        if (ObjectUtils.isNotEmpty(base.getKeyword())) {
+            Predicate p1 = qRole.id.like("%" + base.getKeyword() + "%");
+            Predicate p2 = qRole.name.likeIgnoreCase("%" + base.getKeyword() + "%");
+            Predicate p3 = qRole.description.likeIgnoreCase("%" + base.getKeyword() + "%");
+            predicate = ExpressionUtils.and(predicate, ExpressionUtils.anyOf(p1, p2, p3));
+        }
+        // 排序
+        Sort sort = Sort.by(Direction.ASC, SRole.FIELDS.sort);
+        // 分页
+        Pageable pageable = PageRequest.of(page.getPage(), page.getLimit(), sort);
+        // 查询数据
+        Page<SRole> data = mRoleRepository.findAll(predicate, pageable);
+        // 构造
+        return PaginationHelper.create(data);
+    }
+
+    /**
+     * 详情
+     *
+     * @param base
+     * @param model
+     * @return @
+     */
+    @RequestMapping(value = "form")
+    @RequiresPermissions("rule:view")
+    public String form(BaseVo base, Model model) {
+        SRole role = new SRole().setId(base.getId());
+        if (!Objects.equal(role.getId(), -1L)) {
+            role = mRoleRepository.findOne(role.getId());
+        }
+        model.addAttribute("role", role);
+        model.addAttribute("json", role.toJSONString());
+        model.addAttribute("rolePermissions", JSON.toJSONString(mRolePermissionService.getIds(base.getId())));
+        model.addAttribute("menus", JSON.toJSONString(mMenuService.getMenuTree()));
+        return "system/role/form";
+    }
+
+    /**
+     * 添加
+     *
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "submit")
+    @RequiresPermissions("rule:update")
+    public BaseResult submit(BaseVo base, SRole req) {
+        // 删除所有
+        List<RolePermission> rolePermissions = mRolePermissionRepository.getListByRole(base.getId());
+        for (RolePermission rolePermission : rolePermissions) {
+            mRolePermissionRepository.delete(rolePermission);
+        }
+        // 更新权限
+        for (Long permissionId : base.getIds()) {
+            SMenu menu = mMenuRepository.findOne(permissionId);
+            RolePermission rp = new RolePermission().setPk(new PKRP().roles(base.getId()).menu(menu.getId()));
+            rp.setPermission(menu.getPermission());
+            mRolePermissionRepository.save(rp);
+        }
+        return R.succ();
+    }
+}

+ 6 - 0
src/main/java/com/sysu/admin/support/system/role/SRoleRepository.java

@@ -0,0 +1,6 @@
+package com.sysu.admin.support.system.role;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+
+public interface SRoleRepository extends JpaPlusRepository<SRole, Long> {
+}

+ 45 - 0
src/main/java/com/sysu/admin/support/system/role_permission/PKRP.java

@@ -0,0 +1,45 @@
+package com.sysu.admin.support.system.role_permission;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import java.io.Serializable;
+
+/**
+ * @title RolePermission
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:17
+ */
+@Data
+@Accessors(fluent = true)
+@NoArgsConstructor
+@Embeddable
+public class PKRP implements Serializable {
+
+    /** 序列化 */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 角色
+     */
+    @Column
+    private Long roles;
+
+    /**
+     * 菜单
+     */
+    @Column
+    private Long menu;
+
+    public Long getMenu() {
+        return menu;
+    }
+
+    public Long getRoles() {
+        return roles;
+    }
+}

+ 45 - 0
src/main/java/com/sysu/admin/support/system/role_permission/RolePermission.java

@@ -0,0 +1,45 @@
+package com.sysu.admin.support.system.role_permission;
+
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * @title RolePermission
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:17
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Table(name = "sys_role_permission")
+@Entity
+@DynamicInsert
+@DynamicUpdate
+public class RolePermission extends JpaPlusEntity<RolePermission> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 联合主键
+     */
+    @EmbeddedId
+    private PKRP pk;
+
+    /**
+     * 权限
+     */
+    @Column
+    private String permission;
+}

+ 12 - 0
src/main/java/com/sysu/admin/support/system/role_permission/RolePermissionRepository.java

@@ -0,0 +1,12 @@
+package com.sysu.admin.support.system.role_permission;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface RolePermissionRepository extends JpaPlusRepository<RolePermission, Long> {
+
+    @Query(value = "select * from sys_role_permission where roles=?1", nativeQuery = true)
+    List<RolePermission> getListByRole(Long roesId);
+}

+ 48 - 0
src/main/java/com/sysu/admin/support/system/role_permission/RolePermissionService.java

@@ -0,0 +1,48 @@
+package com.sysu.admin.support.system.role_permission;
+
+import lombok.NonNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @title RolePermissionService
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:21
+ */
+@Service
+public class RolePermissionService {
+
+    @Autowired
+    RolePermissionRepository mRolePermissionRepository;
+
+    /**
+     * 查询Ids
+     *
+     * @return
+     */
+    public String[] getIds(@NonNull Long roleId) {
+        List<RolePermission> list = mRolePermissionRepository.getListByRole(roleId);
+        String[] ids = new String[list.size()];
+        for (int i = 0; i < ids.length; i++) {
+            ids[i] = String.valueOf(list.get(i).getPk().menu());
+        }
+        return ids;
+    }
+
+    /**
+     * 查询Permissions
+     *
+     * @return
+     */
+    public String[] getPermissions(@NonNull Long roleId) {
+        List<RolePermission> list = mRolePermissionRepository.getListByRole(roleId);
+        String[] permissions = new String[list.size()];
+        for (int i = 0; i < permissions.length; i++) {
+            permissions[i] = list.get(i).getPermission();
+        }
+        return permissions;
+    }
+}

+ 157 - 0
src/main/java/com/sysu/admin/support/system/user/User.java

@@ -0,0 +1,157 @@
+package com.sysu.admin.support.system.user;
+
+import com.sysu.admin.support.system.organ.Organ;
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+import org.hibernate.annotations.*;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @title User
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:55
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Entity
+@EntityListeners(AuditingEntityListener.class)
+@Table(name = "sys_user")
+@DynamicInsert
+@DynamicUpdate
+@Where(clause = "is_del=0")
+@SQLDelete(sql = "update sys_user set is_del=1 where id = ?")
+@SQLDeleteAll(sql = "update sys_user set is_del=1 where id = ?")
+public class User extends JpaPlusEntity<User> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    /**
+     * 创建时间
+     */
+    @CreatedDate
+    @Column(updatable = false, nullable = false)
+    private Date createDate;
+
+    /**
+     * 更新时间
+     */
+    @LastModifiedDate
+    @Column(nullable = false)
+    private Date updateDate;
+
+    /**
+     * 帐号
+     */
+    @Column
+    private String username;
+
+
+    /**
+     * 密码明码
+     */
+    @Column(name = "`code`")
+    private String code;
+
+    /**
+     * 密码
+     */
+    @Column
+    private String password;
+
+    /**
+     * 昵称
+     */
+    @Column
+    private String nickname;
+
+    /**
+     * 登录失败次数
+     */
+    @Column
+    private Integer lastLoginFailures;
+
+    /**
+     * 最后登录时间
+     */
+    @Column
+    private Date lastLoginDate;
+
+    /**
+     * 是否拉黑(0:启用、1:禁用)
+     */
+    @Column
+    private Integer isBlack;
+
+    /**
+     * 是否启用(0:启用、1:禁用)
+     */
+    @Column
+    private Integer isEnable;
+
+    /**
+     * 是否删用(0:正常、1:删除)
+     */
+    @Column
+    private Integer isDel;
+
+    @Column(name="organ_id")
+    @NotNull(message = "organId not null")
+    private Long organId;
+
+    @ManyToOne(cascade= CascadeType.REFRESH,fetch=FetchType.LAZY)
+    @JoinColumn(name="organ_id" ,insertable = false, updatable = false)//加入一列作为外键
+    private Organ organ;
+
+    @Column
+    private String openId;
+
+    // ==========================================
+    /**
+     * 机构名称
+     */
+    @Transient
+    private String organName;
+    /**
+     * 角色
+     */
+    @Transient
+    private Long roleId;
+
+    /**
+     * 角色名称
+     */
+    @Transient
+    private String roleName;
+
+    /**
+     * 角色名称
+     */
+    @Transient
+    private String session_key;
+
+    @Transient
+    private Map<String , Object> extData;
+}

+ 351 - 0
src/main/java/com/sysu/admin/support/system/user/UserController.java

@@ -0,0 +1,351 @@
+package com.sysu.admin.support.system.user;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Maps;
+import com.querydsl.core.BooleanBuilder;
+import com.querydsl.core.types.ExpressionUtils;
+import com.querydsl.core.types.Predicate;
+import com.querydsl.core.types.Projections;
+import com.querydsl.core.types.QBean;
+import com.querydsl.jpa.impl.JPAQuery;
+import com.sysu.admin.support.system.organ.Organ;
+import com.sysu.admin.support.system.organ.OrganRepository;
+import com.sysu.admin.support.base.BaseVo;
+import com.sysu.admin.support.base.ServiceContext;
+import com.sysu.admin.support.system.role.SRole;
+import com.sysu.admin.support.system.role.SRoleRepository;
+import com.sysu.admin.utils.i18n.MessageUtils;
+import com.xiesx.fastboot.base.pagination.PaginationHelper;
+import com.xiesx.fastboot.base.pagination.PaginationResult;
+import com.xiesx.fastboot.base.pagination.PaginationVo;
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import com.xiesx.fastboot.core.exception.RunException;
+import com.sysu.admin.support.system.organ.QOrgan;
+import com.sysu.admin.support.system.role.QSRole;
+import com.sysu.admin.support.system.user_role.PKUR;
+import com.sysu.admin.support.system.user_role.QUserRole;
+import com.sysu.admin.support.system.user_role.UserRole;
+import com.sysu.admin.support.system.user_role.UserRoleRepository;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @title UserController
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:08:02
+ */
+@Validated
+@Controller
+@RequestMapping(value = "user/")
+public class UserController extends ServiceContext {
+
+    @Autowired
+    UserRepository mUserRepository;
+
+    @Autowired
+    SRoleRepository mRoleRepository;
+
+    @Autowired
+    UserRoleRepository mUserRoleRepository;
+
+    @Autowired
+    OrganRepository mOrganRepository;
+
+    /**
+     * 页面
+     *
+     * @return
+     */
+    @RequestMapping(value = "index")
+    public String index() {
+        return "system/user/index";
+    }
+
+    /**
+     * 页面
+     *
+     * @return
+     */
+    @RequestMapping(value = "indexTree")
+    public String indexTree() {
+        return "system/user/indexTree";
+    }
+
+    /**
+     * 分页
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "tree")
+    @RequiresPermissions("user:view")
+    public Map<String, Object> tree() {
+        QOrgan qOrgan = QOrgan.organ;
+        QUser qUser = QUser.user;
+        QSRole qRole = QSRole.sRole;
+        QUserRole qUserRole = QUserRole.userRole;
+        // 条件
+        Predicate predicate = qUser.id.isNotNull();
+
+        User currentUser = mShiroService.getCurrentUser();
+
+        //县级执法权限可以看下级的部门
+        if(mShiroService.isXjzf()){
+            predicate = ExpressionUtils.and(predicate, qOrgan.parentId.eq(currentUser.getOrganId()));
+        }
+
+        // 查询字段
+        QBean<User> selectBean = Projections.fields(User.class, qUser.id.longValue(), qUser.username, qUser.nickname,
+                qUser.isEnable, qUser.createDate, qUser.updateDate, qRole.id.longValue().as(User.FIELDS.roleId),
+                qRole.name.as(User.FIELDS.roleName),qOrgan.company.as(User.FIELDS.organName),qOrgan.id.as(User.FIELDS.organId));
+        // 构造查询
+        JPAQuery<User> jpaQuery = mJPAQueryFactory.select(selectBean)
+                .from(qUser)
+                .leftJoin(qUserRole)
+                .on(qUser.id.eq(qUserRole.pk.users))
+                .leftJoin(qRole)
+                .on(qRole.id.eq(qUserRole.pk.roles))
+                .leftJoin(qOrgan)
+                .on(qOrgan.id.eq(qUser.organId))
+                .where(predicate);
+        List<User> userList = jpaQuery.fetch();
+
+        List<UserTreeNode> userTreeNodes = UserTreeNodeUtil.UserToTreeNode(userList);
+
+        Map<String, Object> maps = Maps.newHashMap();
+        maps.put("code", 0);
+        maps.put("msg", MessageUtils.get("OP_MSG_SUCC"));
+        maps.put("count", userTreeNodes.size());
+        maps.put("data", userTreeNodes);
+        return maps;
+    }
+
+    /**
+     * 分页
+     * @param base
+     * @param page
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "page")
+    @RequiresPermissions("user:view")
+    public PaginationResult page(BaseVo base, PaginationVo page) {
+        User currentUser = mShiroService.getCurrentUser();
+        // 对象
+        QOrgan qOrgan = QOrgan.organ;
+        QUser qUser = QUser.user;
+        QSRole qRole = QSRole.sRole;
+        QUserRole qUserRole = QUserRole.userRole;
+        // 条件
+        Predicate predicate = new BooleanBuilder();
+
+        if (ObjectUtils.isNotEmpty(base.getKeyword())) {
+            Predicate p1 = qUser.id.like("%" + base.getKeyword() + "%");
+            Predicate p2 = qUser.username.likeIgnoreCase("%" + base.getKeyword() + "%");
+            Predicate p3 = qUser.nickname.likeIgnoreCase("%" + base.getKeyword() + "%");
+            predicate = ExpressionUtils.and(predicate, ExpressionUtils.anyOf(p1, p2, p3));
+        }
+
+        // 分页
+        Pageable pageable = PageRequest.of(page.getPage(), page.getLimit(), Sort.by(Direction.DESC, User.FIELDS.createDate));
+        // 查询字段
+        QBean<User> selectBean = Projections.fields(User.class, qUser.id.longValue(), qUser.username, qUser.nickname,
+                qUser.isEnable, qUser.createDate, qUser.updateDate, qRole.id.longValue().as(User.FIELDS.roleId),
+                qRole.name.as(User.FIELDS.roleName),qOrgan.company.as(User.FIELDS.organName));
+        // 构造查询
+        JPAQuery<User> jpaQuery = mJPAQueryFactory.select(selectBean)
+                .from(qUser)
+                .leftJoin(qUserRole)
+                .on(qUser.id.eq(qUserRole.pk.users))
+                .leftJoin(qRole)
+                .on(qRole.id.eq(qUserRole.pk.roles))
+                .leftJoin(qOrgan)
+                .on(qOrgan.id.eq(qUser.organId))
+                .where(predicate);
+        // 分页查询
+        Page<User> data = mUserRepository.findAll(jpaQuery, pageable);
+        //
+        return PaginationHelper.create(data);
+    }
+
+    /**
+     * 用户选择
+     * @param base
+     * @param page
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "select")
+    @RequiresPermissions("user:view")
+    public PaginationResult select(BaseVo base, PaginationVo page) {
+        User currentUser = mShiroService.getCurrentUser();
+        // 对象
+        QOrgan qOrgan = QOrgan.organ;
+        QUser qUser = QUser.user;
+        // 条件
+        Predicate predicate = new BooleanBuilder();
+
+        if(mShiroService.isXjzf()){
+            List<Long> ids = mOrganRepository.findIdByParentId(currentUser.getOrganId());
+            ids.add(currentUser.getOrganId());
+            predicate = ExpressionUtils.and(predicate, qUser.organId.in(ids));
+        }
+        //镇级可以看到自己下面的任务
+        if(mShiroService.isZjxc()){
+            predicate = ExpressionUtils.and(predicate, qUser.organId.eq(currentUser.getOrganId()));
+        }
+
+        if (ObjectUtils.isNotEmpty(base.getKeyword())) {
+            Predicate p1 = qUser.id.like("%" + base.getKeyword() + "%");
+            Predicate p2 = qUser.username.likeIgnoreCase("%" + base.getKeyword() + "%");
+            Predicate p3 = qUser.nickname.likeIgnoreCase("%" + base.getKeyword() + "%");
+            predicate = ExpressionUtils.and(predicate, ExpressionUtils.anyOf(p1, p2, p3));
+        }
+
+
+        // 分页
+        Pageable pageable = PageRequest.of(page.getPage(), page.getLimit(), Sort.by(Direction.DESC, User.FIELDS.createDate));
+        // 查询字段
+        QBean<User> selectBean = Projections.fields(User.class, qUser.id.longValue(), qUser.username, qUser.nickname,
+                qUser.isEnable, qUser.createDate, qUser.updateDate,qOrgan.company.as(User.FIELDS.organName));
+        // 构造查询
+        JPAQuery<User> jpaQuery = mJPAQueryFactory.select(selectBean)
+                .from(qUser)
+                .leftJoin(qOrgan)
+                .on(qOrgan.id.eq(qUser.organId))
+                .where(predicate);
+        // 分页查询
+        Page<User> data = mUserRepository.findAll(jpaQuery, pageable);
+        //
+        return PaginationHelper.create(data);
+    }
+
+    /**
+     * 详情
+     * @param base
+     * @param model
+     * @return
+     * @throws RunException
+     */
+    @RequestMapping(value = "form")
+    @RequiresPermissions("user:view")
+    public String form(BaseVo base, Model model) {
+        User user = new User().setId(base.getId());
+        List<SRole> sRoles = mRoleRepository.findAll();
+        if (!Objects.equal(user.getId(), -1L)) {
+            user = mUserRepository.findOne(user.getId());
+            Organ organ = mOrganRepository.findOne(user.getOrganId());
+            user.setOrganName(organ.getCompany());
+        }
+
+        model.addAttribute("user", user);
+        model.addAttribute("json", user.toJSONString());
+        if(Objects.equal(user.getId(), -1L)){
+            Organ organ = mShiroService.getCurrentOrgan();
+            user.setOrganId(organ.getId()).setOrganName(organ.getCompany());
+            model.addAttribute("userRoles", new UserRole[]{ new UserRole().setPk(new PKUR().roles(4L))});// 这里用户对角色1v1
+        }else {
+            model.addAttribute("userRoles", mUserRoleRepository.getRoleByUsers(user.getId()));// 这里用户对角色1v1
+        }
+        model.addAttribute("roles", sRoles);
+        return "system/user/form";
+    }
+
+    /**
+     * 添加/修改用户信息
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "submit")
+    @RequiresPermissions("user:update")
+    public BaseResult submit(BaseVo base, @Validated User req, String pwd) {
+        User user = new User().setId(req.getId());
+        //根据传入的用户id 是不是-1来判断是添加还是更新
+        if (Objects.equal(user.getId(), -1L)) {
+            BeanUtils.copyProperties(req, user);
+            user.setCode(pwd);
+            user.setPassword(DigestUtils.md5Hex(req.getUsername() + pwd));
+        } else {
+            //获取用户
+            user = mUserRepository.findOne(user.getId());
+            if (ObjectUtils.isNotEmpty(user)) {
+                // 当前帐号/密码是否发生变动
+                if (!user.getUsername().equals(req.getUsername())) {
+                    user.setUsername(req.getUsername());
+                }
+                if (ObjectUtils.isNotEmpty(pwd) && (pwd = pwd.trim()).length() > 0) {
+                    user.setCode(pwd);
+                    String password = DigestUtils.md5Hex(req.getUsername() + pwd);
+                    user.setPassword(password);
+                }
+                user.setNickname(req.getNickname());
+                user.setOrganId(req.getOrganId());
+            }
+
+        }
+
+        if(mUserRepository.findFirstByUsernameAndIdNot(req.getUsername(), req.getId()) != null){
+            throw new RuntimeException(MessageUtils.get("user.repet_username"));
+        }
+
+        // 先保存
+        user = mUserRepository.saveAndFlush(user);
+        //  更新用户的角色权限
+        List<UserRole> userRoles = mUserRoleRepository.getRoleByUsers(user.getId());
+        for (UserRole userRole : userRoles) {
+            mUserRoleRepository.delete(userRole);
+        }
+        for (Long roleId : base.getIds()) {
+            UserRole userRole = new UserRole().setPk(new PKUR().users(user.getId()).roles(roleId));
+            mUserRoleRepository.save(userRole);
+        }
+        return R.succ();
+    }
+
+    /**
+     * 修改启用
+     *
+     * @param base
+     * @param base
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "updateEnable")
+    @RequiresPermissions("user:update")
+    public BaseResult updateEnable(BaseVo base) {
+        Integer row = mUserRepository.enable(base.getIsEnable(), base.getId());
+        return (row >= 1) ? R.succ() : R.fail();
+    }
+
+    /**
+     * 删除状态
+     *
+     * @param base
+     *
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping(value = "delete")
+    @RequiresPermissions("user:delete")
+    public BaseResult delete(BaseVo base) {
+        Integer row = mUserRepository.delete(base.getIds());
+        return (row >= 1) ? R.succ() : R.fail();
+    }
+}

+ 37 - 0
src/main/java/com/sysu/admin/support/system/user/UserRepository.java

@@ -0,0 +1,37 @@
+package com.sysu.admin.support.system.user;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+
+public interface UserRepository extends JpaPlusRepository<User, Long> {
+
+    @Transactional
+    @Modifying
+    @Query(value = "update sys_user set is_enable=?1 where id=?2", nativeQuery = true)
+    int enable(Integer isEnable, Long userId);
+
+    User findByUsername(String username);
+
+
+    User findFirstByOrganIdOrderByCreateDateAsc(Long organId);
+
+    /**
+     * 查重复username
+     * @param username
+     * @param id
+     * @return
+     */
+    User findFirstByUsernameAndIdNot(String username, Long id);
+
+    /**
+     * @param openId
+     * @return
+     */
+    User findFirstByOpenId(String openId);
+
+    @Query(value = "select * from sys_user where id = 75", nativeQuery = true)
+    User findTestUser();
+}

+ 22 - 0
src/main/java/com/sysu/admin/support/system/user/UserService.java

@@ -0,0 +1,22 @@
+package com.sysu.admin.support.system.user;
+
+import com.sysu.admin.support.base.BaseService;
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author shu hao
+ * @description:
+ * @date 2022/5/16 17:42
+ */
+@Service
+public class UserService extends BaseService<User, Long> {
+    @Override
+    public JpaPlusRepository<User, Long> r() {
+        return mUserRepository;
+    }
+
+    public User findByUsername(String username){
+        return mUserRepository.findByUsername(username);
+    }
+}

+ 28 - 0
src/main/java/com/sysu/admin/support/system/user/UserTreeNode.java

@@ -0,0 +1,28 @@
+package com.sysu.admin.support.system.user;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class UserTreeNode {
+
+    public String id;
+
+    public String name;
+
+    public String company;
+
+
+    public String parent;
+
+    public String roleName;
+
+    public Integer isEnable;
+
+    public Date createDate;
+
+
+    public Boolean open;
+}

+ 32 - 0
src/main/java/com/sysu/admin/support/system/user/UserTreeNodeUtil.java

@@ -0,0 +1,32 @@
+package com.sysu.admin.support.system.user;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserTreeNodeUtil {
+
+    public static List<UserTreeNode> UserToTreeNode(List<User> userList){
+        List<UserTreeNode> result = new ArrayList<UserTreeNode>(userList.size() + (userList.size() >> 1));
+        List<String> organIdList = new ArrayList<>(userList.size() >> 1);
+        for(User user : userList){
+            String pId = "o_" + user.getOrganId();
+            if(!organIdList.contains(pId)){
+                organIdList.add(pId);
+                UserTreeNode userTreeNode = new UserTreeNode();
+                userTreeNode.setId(pId);
+                userTreeNode.setCompany(user.getOrganName());
+                result.add(userTreeNode);
+            }
+            UserTreeNode userTreeNode = new UserTreeNode();
+            userTreeNode.setId(user.getId().toString());
+            userTreeNode.setName(user.getUsername());
+            userTreeNode.setParent(pId);
+            userTreeNode.setRoleName(user.getRoleName());
+            userTreeNode.setIsEnable(user.getIsEnable());
+            userTreeNode.setCreateDate(user.getCreateDate());
+            result.add(userTreeNode);
+        }
+        return result;
+    }
+
+}

+ 43 - 0
src/main/java/com/sysu/admin/support/system/user_role/PKUR.java

@@ -0,0 +1,43 @@
+package com.sysu.admin.support.system.user_role;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import java.io.Serializable;
+
+/**
+ * @title RolePermission
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:17
+ */
+@Data
+@Accessors(fluent = true)
+@Embeddable
+public class PKUR implements Serializable {
+
+    /** 序列化 */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户
+     */
+    @Column
+    private Long users;
+
+    /**
+     * 角色
+     */
+    @Column
+    private Long roles;
+
+    public Long getRoles() {
+        return roles;
+    }
+
+    public Long getUsers() {
+        return users;
+    }
+}

+ 34 - 0
src/main/java/com/sysu/admin/support/system/user_role/UserRole.java

@@ -0,0 +1,34 @@
+package com.sysu.admin.support.system.user_role;
+
+import com.xiesx.fastboot.core.jpa.entity.JpaPlusEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldNameConstants;
+
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * @title UserRole
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:07:46
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@FieldNameConstants(innerTypeName = "FIELDS")
+@Entity
+@Table(name = "sys_user_role")
+public class UserRole extends JpaPlusEntity<UserRole> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户
+     */
+    @EmbeddedId
+    private PKUR pk;
+}

+ 15 - 0
src/main/java/com/sysu/admin/support/system/user_role/UserRoleRepository.java

@@ -0,0 +1,15 @@
+package com.sysu.admin.support.system.user_role;
+
+import com.xiesx.fastboot.core.jpa.JpaPlusRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface UserRoleRepository extends JpaPlusRepository<UserRole, Long> {
+
+    @Query(value = "select * from sys_user_role where users=?1", nativeQuery = true)
+    UserRole getRoleByUser(Long userId);
+
+    @Query(value = "select * from sys_user_role where users=?1", nativeQuery = true)
+    List<UserRole> getRoleByUsers(Long userId);
+}

+ 52 - 0
src/main/java/com/sysu/admin/support/tree/MenuTree.java

@@ -0,0 +1,52 @@
+package com.sysu.admin.support.tree;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title MenuTree
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:03:43
+ */
+@Data
+@Builder
+public class MenuTree implements Comparable<MenuTree> {
+
+    @JSONField(ordinal = 1)
+    private Long id;
+
+    @JSONField(ordinal = 2)
+    private Long parent;
+
+    @JSONField(ordinal = 3)
+    private Integer sort;
+
+    //
+
+    @JSONField(ordinal = 4)
+    private String name;
+
+    @JSONField(ordinal = 5)
+    private String value;
+
+    @JSONField(ordinal = 6)
+    private Boolean disabled;
+
+    @JSONField(ordinal = 7)
+    private Boolean selected;
+
+    @JSONField(ordinal = 8)
+    private List<MenuTree> children;
+
+    @Override
+    public int compareTo(MenuTree o) {
+        if (null == o) {
+            return 1;
+        }
+        return this.sort - o.sort;
+    }
+}

+ 55 - 0
src/main/java/com/sysu/admin/support/tree/NavigTree.java

@@ -0,0 +1,55 @@
+package com.sysu.admin.support.tree;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title NavigTree
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:03:47
+ */
+@Data
+@Builder
+public class NavigTree implements Comparable<NavigTree> {
+
+    @JSONField(ordinal = 1)
+    private Long id;
+
+    @JSONField(ordinal = 2)
+    private Long parent;
+
+    @JSONField(ordinal = 3)
+    private Integer sort;
+
+    //
+
+    @JSONField(ordinal = 4)
+    private String name;
+
+    @JSONField(ordinal = 5)
+    private String title;
+
+    @JSONField(ordinal = 6)
+    private String icon;
+
+    @JSONField(ordinal = 7)
+    private String href;
+
+    @JSONField(ordinal = 8)
+    private Boolean spread;
+
+    @JSONField(ordinal = 9)
+    private List<NavigTree> list;
+
+    @Override
+    public int compareTo(NavigTree o) {
+        if (null == o) {
+            return 1;
+        }
+        return this.sort - o.sort;
+    }
+}

+ 46 - 0
src/main/java/com/sysu/admin/support/tree/Tree.java

@@ -0,0 +1,46 @@
+package com.sysu.admin.support.tree;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title Tree
+ * @description
+ * @author XIE
+ * @date 2020年4月24日下午10:01:15
+ */
+@Data
+@Builder
+public class Tree {
+
+    // 节点唯一索引
+    @JSONField(ordinal = 1)
+    public String id;
+
+    // 节点标题
+    @JSONField(ordinal = 2)
+    public String title;
+
+    // 子节点
+    @JSONField(ordinal = 3)
+    public List<Tree> children;
+
+    // 节点是否初始展开
+    @JSONField(ordinal = 4)
+    public Boolean spread;
+
+    // 初始为选中状态
+    @JSONField(ordinal = 5)
+    public Boolean checked;
+
+    // 初始为禁用状态
+    @JSONField(ordinal = 6)
+    public Boolean disabled;
+
+    // 级别
+    @JSONField(ordinal = 7)
+    private Integer grade;
+}

+ 30 - 0
src/main/java/com/sysu/admin/support/validated/BindExceptionHanlder.java

@@ -0,0 +1,30 @@
+package com.sysu.admin.support.validated;
+
+import com.xiesx.fastboot.base.result.BaseResult;
+import com.xiesx.fastboot.base.result.R;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * 统一校验异常处理类
+ */
+@RestControllerAdvice
+public class BindExceptionHanlder {
+
+
+    @ExceptionHandler(BindException.class)
+    public BaseResult handleBindException(HttpServletRequest request, BindException exception) {
+        List<FieldError> allErrors = exception.getFieldErrors();
+        StringBuilder sb = new StringBuilder(100);
+        for (FieldError errorMessage : allErrors) {
+            sb.append(errorMessage.getDefaultMessage());
+            break;
+        }
+        return R.fail(sb.toString());
+    }
+}

+ 24 - 0
src/main/java/com/sysu/admin/support/validated/EmailValidation.java

@@ -0,0 +1,24 @@
+package com.sysu.admin.support.validated;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+@Documented
+@Constraint(validatedBy = EmailValidationValidator.class)
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EmailValidation {
+    String message() default "不是合法的邮箱";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+
+    @Target({ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
+    @Retention(RetentionPolicy.RUNTIME)
+    @Documented
+    @interface List {
+        EmailValidation[] value();
+    }
+}

+ 23 - 0
src/main/java/com/sysu/admin/support/validated/EmailValidationValidator.java

@@ -0,0 +1,23 @@
+package com.sysu.admin.support.validated;
+
+import com.sysu.admin.utils.CheckUtil;
+import org.apache.commons.lang3.ObjectUtils;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class EmailValidationValidator implements ConstraintValidator<EmailValidation, String> {
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext context) {
+        if(ObjectUtils.isNotEmpty(value) && CheckUtil.isEmail(value)){
+            return true;
+        }
+        String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
+        System.out.println("default message :" + defaultConstraintMessageTemplate);
+        //禁用默认提示信息
+        //context.disableDefaultConstraintViolation();
+        //设置提示语
+        //context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
+        return false;
+    }
+}

+ 24 - 0
src/main/java/com/sysu/admin/support/validated/NameValidation.java

@@ -0,0 +1,24 @@
+package com.sysu.admin.support.validated;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+@Documented
+@Constraint(validatedBy = NameValidationValidator.class)
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NameValidation {
+    String message() default "不是合法的名字";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+
+    @Target({ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
+    @Retention(RetentionPolicy.RUNTIME)
+    @Documented
+    @interface List {
+        NameValidation[] value();
+    }
+}

+ 20 - 0
src/main/java/com/sysu/admin/support/validated/NameValidationValidator.java

@@ -0,0 +1,20 @@
+package com.sysu.admin.support.validated;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class NameValidationValidator implements ConstraintValidator<NameValidation, String> {
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext context) {
+        if ("shuhao".equalsIgnoreCase(value)) {
+            return true;
+        }
+        String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
+        System.out.println("default message :" + defaultConstraintMessageTemplate);
+        //禁用默认提示信息
+        //context.disableDefaultConstraintViolation();
+        //设置提示语
+        //context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
+        return false;
+    }
+}

+ 24 - 0
src/main/java/com/sysu/admin/support/validated/PhoneValidation.java

@@ -0,0 +1,24 @@
+package com.sysu.admin.support.validated;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+@Documented
+@Constraint(validatedBy = PhoneValidationValidator.class)
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PhoneValidation {
+    String message() default "不是合法的手机号";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+
+    @Target({ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
+    @Retention(RetentionPolicy.RUNTIME)
+    @Documented
+    @interface List {
+        PhoneValidation[] value();
+    }
+}

+ 23 - 0
src/main/java/com/sysu/admin/support/validated/PhoneValidationValidator.java

@@ -0,0 +1,23 @@
+package com.sysu.admin.support.validated;
+
+import com.sysu.admin.utils.CheckUtil;
+import org.apache.commons.lang3.ObjectUtils;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class PhoneValidationValidator implements ConstraintValidator<PhoneValidation, String> {
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext context) {
+        if(ObjectUtils.isNotEmpty(value) && CheckUtil.isPhone(value)){
+            return true;
+        }
+        String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
+        System.out.println("default message :" + defaultConstraintMessageTemplate);
+        //禁用默认提示信息
+        //context.disableDefaultConstraintViolation();
+        //设置提示语
+        //context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
+        return false;
+    }
+}

+ 84 - 0
src/main/java/com/sysu/admin/utils/CheckUtil.java

@@ -0,0 +1,84 @@
+package com.sysu.admin.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * 表单验证工具类
+ * @author 86137
+ *
+ */
+public class CheckUtil {
+	
+	
+	/**
+	 * 验证是不是数字
+	 * @param text
+	 * @return
+	 */
+	public static boolean isNumber(String text) {
+		if(text == null || text.length() == 0) {
+			return false;
+		}
+		int i = text.length() - 1;
+		while(i > -1) {
+			int c = text.charAt(i);
+			if(c  < '0' || c > '9' ) {
+				return false;
+			}
+			i--;
+		}
+		return true;
+	}
+	
+	public static void main(String[] args) {
+		System.out.println();
+	}
+	
+	
+	/**
+	 * 验证不为null 或 ""  或 "    "
+	 * @param text
+	 * @return
+	 */
+	public static boolean notNull(String text) {
+		if(text == null || text.trim().equals("")) {
+			return  false;
+		}
+		return true;
+	}
+	
+	public static boolean isPhone(String phone) {
+		String regex = "^((13[0-9])|(14[0-9])|(15([0-9]))|(16([0-9]))|(17[0-9])|(18[0-9])|(19[0-9]))\\d{8}$";
+		if (phone.length() != 11) {
+//			System.out.println("手机号应为11位数");
+			return false;
+		}
+		Pattern p = Pattern.compile(regex);
+		Matcher m = p.matcher(phone);
+		boolean isMatch = m.matches();
+		if (isMatch) {
+//			System.out.println("您的手机号" + phone + "是正确格式@——@");
+			return true;
+		} else {
+//			System.out.println("您的手机号" + phone + "是错误格式!!!");
+			return false;
+		}
+	}
+
+	public static boolean isEmail(String email) {
+		String regex = "^[a-z0-9_\\+-]+(\\.[a-z0-9_\\+-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,4})$";
+		Pattern p = Pattern.compile(regex);
+		Matcher m = p.matcher(email);
+		boolean isMatch = m.matches();
+		if (isMatch) {
+//			System.out.println("您的手机号" + phone + "是正确格式@——@");
+			return true;
+		} else {
+//			System.out.println("您的手机号" + phone + "是错误格式!!!");
+			return false;
+		}
+	}
+	
+}

+ 93 - 0
src/main/java/com/sysu/admin/utils/ChineseCharacterUtil.java

@@ -0,0 +1,93 @@
+package com.sysu.admin.utils;
+
+import net.sourceforge.pinyin4j.PinyinHelper;
+import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
+import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 获取首字母工具
+ *
+ * @author 
+ * @Date 
+ */
+public class ChineseCharacterUtil {
+
+    /**
+     * 将汉字转成拼音
+     * <P>
+     * 取首字母或全拼
+     *
+     * @param hanzi 汉字字符串
+     * @param isFull 是否全拼 true:表示全拼 false表示:首字母
+     *
+     * @return 拼音
+     */
+    public static String convertHanzi2Pinyin(String hanzi, boolean isFull){
+        /***
+         * ^[\u2E80-\u9FFF]+$ 匹配所有东亚区的语言
+         * ^[\u4E00-\u9FFF]+$ 匹配简体和繁体
+         * ^[\u4E00-\u9FA5]+$ 匹配简体
+         */
+        StringBuffer sb=new StringBuffer();
+        String pinyin = null;
+        for(int i=0;i<hanzi.length();i++){
+            char unit = hanzi.charAt(i);
+            pinyin = convertSingleHanzi2Pinyin(unit);
+            if(isFull){
+                sb.append(pinyin);
+            } else{
+                sb.append(pinyin.charAt(0));
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 将单个汉字转成拼音
+     *
+     * @param hanzi 汉字字符
+     *
+     * @return 拼音
+     */
+    private static String convertSingleHanzi2Pinyin(char hanzi){
+        HanyuPinyinOutputFormat outputFormat = new HanyuPinyinOutputFormat();
+        outputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
+        String[] res;
+        StringBuffer sb=new StringBuffer();
+        try {
+            res = PinyinHelper.toHanyuPinyinStringArray(hanzi,outputFormat);
+            sb.append(res[0]);//对于多音字,只用第一个拼音
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+        return sb.toString();
+    }
+
+    /***
+     * 匹配
+     * <P>
+     * 根据字符和正则表达式进行匹配
+     *
+     * @param str 源字符串
+     * @param regex 正则表达式
+     *
+     * @return true:匹配成功  false:匹配失败
+     */
+    private static boolean match(String str,String regex){
+        Pattern pattern=Pattern.compile(regex);
+        Matcher matcher=pattern.matcher(str);
+        return matcher.find();
+    }
+
+    /**
+     * 测试方法
+     */
+    public static void main(String[] args) {
+        System.out.println(convertHanzi2Pinyin("弗格森的广东省",false).toUpperCase());
+    }
+}
+

+ 46 - 0
src/main/java/com/sysu/admin/utils/CopyUtil.java

@@ -0,0 +1,46 @@
+package com.sysu.admin.utils;
+
+import com.google.common.collect.Sets;
+import lombok.NonNull;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+
+import java.beans.PropertyDescriptor;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class CopyUtil {
+
+    public static String[] notNullNames(@NonNull Object source) {
+        final BeanWrapper beanWrapper = new BeanWrapperImpl(source);
+        PropertyDescriptor[] pds = beanWrapper.getPropertyDescriptors();
+        Set<String> noValuePropertySet = Sets.newHashSet();
+        Arrays.stream(pds).forEach(pd -> {
+            Object propertyValue = beanWrapper.getPropertyValue(pd.getName());
+            if (ObjectUtils.isNotEmpty(propertyValue)) {
+                noValuePropertySet.add(pd.getName());
+            }
+        });
+        String[] result = new String[noValuePropertySet.size()];
+        return noValuePropertySet.toArray(result);
+    }
+
+
+    public static Long[] toLongArray(String[] a){
+        Long[] ls = new Long[a.length];
+        for(int i=0;i<a.length;i++){
+            ls[i] = Long.valueOf(a[i]);
+        }
+        return ls;
+    }
+
+    public static Long[] clear(Long[] a){
+        Set<Long> set = new HashSet<>();
+        for(Long l : a){
+            set.add(l);
+        }
+        return set.toArray(new Long[0]);
+    }
+}

+ 71 - 0
src/main/java/com/sysu/admin/utils/FileUtils.java

@@ -0,0 +1,71 @@
+package com.sysu.admin.utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FileUtils {
+
+    public static List<String> getFiles(String directoryPath, boolean isAddDirectory) {
+        List<String> list = new ArrayList<>();
+        File baseFile = new File(directoryPath);
+        if (baseFile.isFile() || !baseFile.exists()) {
+            return list;
+        }
+        File[] files = baseFile.listFiles();
+        for (File file : files) {
+            if (file.isDirectory()) {
+                if (isAddDirectory) {
+                    list.add(file.getAbsolutePath());
+                }
+                list.addAll(getFiles(file.getAbsolutePath(), isAddDirectory));
+            } else {
+                list.add(file.getAbsolutePath());
+            }
+        }
+        return list;
+    }
+
+    public static String getFileMD5(File file) {
+        if (!file.isFile()) {
+            return null;
+        }
+        InputStream fis = null;
+        try {
+            fis = new FileInputStream(file);
+
+            byte[] buffer = new byte[1024];
+            MessageDigest complete = MessageDigest.getInstance("MD5");
+            int numRead;
+            do {
+                numRead = fis.read(buffer);
+                if (numRead > 0) {
+                    complete.update(buffer, 0, numRead);
+                }
+            } while (numRead != -1);
+            fis.close();
+            byte[] b = complete.digest();
+            StringBuilder result = new StringBuilder();
+            for (byte value : b) {
+                result.append(Integer.toString((value & 0xff) + 0x100, 16).substring(1));
+            }
+            return result.toString();
+        } catch (NoSuchAlgorithmException | IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return null;
+    }
+}

+ 187 - 0
src/main/java/com/sysu/admin/utils/GenericsUtil.java

@@ -0,0 +1,187 @@
+package com.sysu.admin.utils;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * 泛型工具类(数据的copy 查找 复制等等)
+ * @author 86137
+ * @param <T>
+ */
+public class GenericsUtil<T> {
+	
+	Class<T> clazz;
+	
+	public GenericsUtil(Class<T> clazz) {
+		this.clazz=clazz;
+	}
+	
+	/**
+	 * 在集合 中找到与values 每个值相等的元素 
+	 * @param dataSource  (数据源)
+	 * @param fieldString (要匹配的字段名)
+	 * @param values  格式例子 111,222,333
+	 * @return 返回找到的元素集合
+	 */
+	public List<T> findListItems(List<T> dataSource,String fieldString,String values) {
+		String[] valueArray= values.split(",");
+		List<T> resultList=new ArrayList<T>(valueArray.length);
+		for(T t:dataSource) {
+			try {
+				Field field= clazz.getDeclaredField(fieldString);
+				field.setAccessible(true);
+				for(int i=0;i<valueArray.length;i++) {
+					if(valueArray[i]!=null && valueArray[i].equals(field.get(t))){
+						resultList.add(t);
+						valueArray[i]=null;
+						break;
+					}
+				}
+			} catch (NoSuchFieldException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (SecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			}
+		}
+		return resultList;
+	}
+	
+	/**
+	   *   找到集合中的某个字段的拼接字符串
+	 * @param dataSource
+	 * @param fieldString
+	 * @return 格式例子 111,222,333
+	 */
+	public String findListIds(List<T> dataSource,String fieldString) {
+		StringBuffer ids=new StringBuffer();
+		for(T t:dataSource) {
+			try {
+				Field field= clazz.getDeclaredField(fieldString);
+				field.setAccessible(true);
+				ids.append(",").append(field.get(t));
+			} catch (NoSuchFieldException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (SecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			}
+		}
+		if(ids.length()>0) {
+			ids.delete(0,1);
+		}
+		return ids.toString();
+	}
+	
+	/**
+	 * 找到集合中的某个字段的数组
+	 * @param dataSource
+	 * @param fieldString
+	 * @return
+	 */
+	public Long[] findNumberArray(List<T> dataSource,String fieldString) {
+		Long[] nunmberArray = new Long[dataSource.size()];
+		for(Integer i = 0 ; i < dataSource.size() ;i++) {
+			T t = dataSource.get(i);
+			try {
+				Field field = clazz.getDeclaredField(fieldString);
+				field.setAccessible(true);
+				nunmberArray[i] = (Long)field.get(t);
+				
+			} catch (NoSuchFieldException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (SecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			}
+		}
+		return nunmberArray;
+	}
+	
+	/**
+	 * 找到集合中的某个字段的数组
+	 * @param dataSource
+	 * @param fieldString
+	 * @return
+	 */
+	public List<Integer> findNumberList(List<T> dataSource,String fieldString) {
+		List<Integer> nunmberArray = new ArrayList(dataSource.size());
+		for(Integer i = 0 ; i < dataSource.size() ;i++) {
+			T t = dataSource.get(i);
+			try {
+				Field field = clazz.getDeclaredField(fieldString);
+				field.setAccessible(true);
+				nunmberArray.add((Integer)field.get(t));
+				
+			} catch (NoSuchFieldException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (SecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			}
+		}
+		return nunmberArray;
+	}
+	
+	/**
+	   *   找到集合中的某个字段的拼接字符串
+	 * @param dataSource
+	 * @param fieldString
+	 * @param clearRepeat 是否去除重复
+	 * @return 格式例子 111,222,333
+	 */
+	public String findListIds(T[] dataSource,String fieldString,boolean clearRepeat) {
+		StringBuffer ids=new StringBuffer();
+		Set set=null;
+		if(clearRepeat) {
+			set=new HashSet();
+		}
+		for(T t:dataSource) {
+			try {
+				Field field= clazz.getDeclaredField(fieldString);
+				field.setAccessible(true);
+				if(clearRepeat) {
+					if(!set.contains(field.get(t))) {
+						ids.append(",").append(field.get(t));
+						set.add(field.get(t));
+					}
+				}else {
+					ids.append(",").append(field.get(t));
+				}
+			} catch (NoSuchFieldException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (SecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			}
+		}
+		if(ids.length()>0) {
+			ids.delete(0,1);
+		}
+		return ids.toString();
+	}
+
+	
+	
+	
+
+}

+ 44 - 0
src/main/java/com/sysu/admin/utils/MySimpleDateFormat.java

@@ -0,0 +1,44 @@
+package com.sysu.admin.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class MySimpleDateFormat{
+	
+	
+	private final static SimpleDateFormat formatDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+	
+	private final static SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
+	
+	public static String formatDateTime(Date date) {
+		return formatDateTime.format(date);
+	}
+	
+	public static String formatDate(Date date) {
+		return formatDate.format(date);
+	}
+	
+	public static Date parseDate(String source) {
+		try {
+			return formatDate.parse(source);
+		} catch (ParseException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return null;
+	}
+
+	public static Date parseDateTime(String source) {
+		try {
+			return formatDateTime.parse(source);
+		} catch (ParseException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return null;
+	}
+
+	
+
+}

+ 242 - 0
src/main/java/com/sysu/admin/utils/TextUtil.java

@@ -0,0 +1,242 @@
+package com.sysu.admin.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class TextUtil {
+	
+	/**
+	 * 把10000(第一位代表小时,第二位三位代表分,第四位 五位代表秒)
+	 * 把这种格式转换为秒
+	 * @param time
+	 * @return
+	 * @throws ParseException 
+	 */
+	public static Integer timeConvert(String time,String format){
+		time=time.trim();
+		SimpleDateFormat f=new SimpleDateFormat(format);
+		try {
+			f.parse(time);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		Calendar c= f.getCalendar();
+		return c.get(Calendar.HOUR)*3600+c.get(Calendar.MINUTE)*60+c.get(Calendar.SECOND);
+	}
+	
+	/**
+	 * 把10000(第一位代表小时,第二位三位代表分,第四位 五位代表秒)
+	 * 把这种格式转换为秒
+	 * 以上意思相反
+	 * @param second
+	 * @return
+	 * @throws ParseException 
+	 */
+	public static String timeConvert(Integer second){
+		int h,m,s;
+		h=second/3600;
+		m=second%3600/60;
+		s=second%60;
+		return h+save2w(m)+save2w(s);
+	}
+	
+	/**
+	 * 保留两位
+	 * @param number (例如输入9)
+	 * @return 返回09
+	 */
+	public static String save2w(Integer number) {
+		return number > 9 ? (number + "") : "0" + number;
+	}
+	
+	
+	
+	/**
+	 * 逗号分隔符添加字符串
+	 */
+	public static String appendText(String mainContent,String text) {
+		if(mainContent == null || mainContent.equals("")) {
+			return text;
+		}else {
+			return new StringBuffer(mainContent).append(",").append(text).toString();
+		}
+	}
+	
+	
+	/**
+	 * 找到字符串中的数字  例子‘胡椒粉00’  返回00 只会匹配第一个
+	 * @return
+	 */
+	public static String findNumber(String text) {
+		Pattern p=Pattern.compile("\\d+"); 
+		Matcher m=p.matcher(text);
+		if(m.find()) {//匹配2223 
+//		m.start();//返回3 
+//		m.end();//返回7,返回的是2223后的索引号 
+			return m.group();
+		}else {
+			return null;
+		}
+	}
+	
+	
+	/**
+	 * 找到字符串中的数字  例子‘胡椒粉00’  返回胡椒粉 只会匹配第一个
+	 * @return
+	 */
+	public static String findNotNumber(String text) {
+		Pattern p=Pattern.compile("[^0-9]+"); 
+		Matcher m=p.matcher(text);
+		if(m.find()) {//匹配
+//		m.start();//返回3
+//		m.end();//返回7,返回的是后的索引号 
+			return m.group();
+		}else {
+			return null;
+		}
+	}
+	
+	
+	/**
+	 * 取出两个标识符中间的字符串
+	 * @param left
+	 * @param right
+	 * @param text
+	 * @return
+	 */
+	public static String substring(String left,String right ,String text) {
+		int start = text.indexOf(left);
+		int end = text.indexOf(right);
+		if(start >- 1 && end >- 1) {
+			return text.substring(start+1, end).trim();
+		}
+		return null;
+	}
+	
+	/**
+	 * 取标识符前面的字符串
+	 * @param left
+	 * @return
+	 */
+	public static String leftSubstring(String left,String text) {
+		int index= text.indexOf(left);
+		if(index > -1) {
+			return text.substring(0, index).trim();
+		}
+		return null;
+	}
+	
+	
+	/**
+	 * 取标识符后面的字符串
+	 * @param right
+	 * @return
+	 */
+	public static String rightSubstring(String right,String text) {
+		int index = text.indexOf(right);
+		if(index > -1) {
+			return text.substring(index + 1, text.length()).trim();
+		}
+		return null;
+	}
+	
+	/**
+	 * 将xml 字符串转化为json 对象
+	 * @param xmlString
+	 * @return
+	 */
+	public static JSONObject xmlToJson(String xmlString) {
+		Document document = null;
+		try {
+			document = DocumentHelper.parseText(xmlString);
+		} catch (DocumentException e) {
+			e.printStackTrace();
+		}
+		Element root = document.getRootElement();
+		List<Element> elements = root.elements();
+		JSONObject jsonObject = new JSONObject();
+		for(Element element : elements) {
+			jsonObject.put(element.getName(), element.getText());
+		}
+		return jsonObject;
+	}
+
+	public static String[] split(String text,String regex) {
+		int index = 0;
+		if(text == null) {
+			return new String[0];
+		}
+		String[] codeArray = text.split(regex);
+
+		if(text.equals("") || codeArray.length == 0) {
+			return new String[0];
+		}
+
+		String[] tempArray=new String[codeArray.length];
+		for(int i = 0;i < codeArray.length; i++) {
+
+			if(!codeArray[i].trim().equals("")) {
+
+				tempArray[index] = codeArray[i];
+				index++;
+			}
+
+		}
+		String[] resArray = new String[index];
+		for(int i = 0; i < index; i++) {
+			resArray[i] = tempArray[i];
+		}
+		return resArray;
+	}
+
+	public static Long[] splitIds(String text,String regex) {
+		int index = 0;
+		if(text == null) {
+			return new Long[0];
+		}
+		String[] codeArray = text.split(regex);
+
+		if(text.equals("") || codeArray.length == 0) {
+			return new Long[0];
+		}
+
+		Long[] tempArray=new Long[codeArray.length];
+		for(int i = 0;i < codeArray.length; i++) {
+
+			if(!codeArray[i].trim().equals("")) {
+
+				tempArray[index] = Long.valueOf(codeArray[i]);
+				index++;
+			}
+
+		}
+		Long[] resArray = new Long[index];
+		for(int i = 0; i < index; i++) {
+			resArray[i] = tempArray[i];
+		}
+		return resArray;
+	}
+
+	public static void main(String[] args) {
+		Stack<Integer> stack = new Stack<>();
+		for(int i=0;i<5;i++){
+			System.out.println("push : " + i);
+			stack.push(i);
+		}
+		for(int i=0;i<5;i++){
+			System.out.println("pop :" + stack.pop());
+		}
+	}
+}

+ 31 - 0
src/main/java/com/sysu/admin/utils/file/FileUtil.java

@@ -0,0 +1,31 @@
+package com.sysu.admin.utils.file;
+
+import org.springframework.web.multipart.MultipartFile;
+import java.io.File;
+
+/**
+ * 文件处理工具类
+ */
+public class FileUtil {
+
+    /**
+     * 保存图片
+     * @param file
+     */
+    public static File saveImage(MultipartFile file,String dirPath, String newName){
+        if(file == null)
+            return null;
+
+        File dir = new File(dirPath);
+        if(!dir.exists()) {
+            dir.mkdir();
+        }
+        File image = new File(dir, newName);
+        try {
+            file.transferTo(image);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return image;
+    }
+}

+ 135 - 0
src/main/java/com/sysu/admin/utils/file/Snippet.java

@@ -0,0 +1,135 @@
+package com.sysu.admin.utils.file;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * 压缩和解压 ZIP文件
+ */
+public class Snippet {
+	
+	/**
+     * 压缩成ZIP 
+     * @param srcFiles 需要压缩的文件列表
+     * @param zipFile  目标文件
+     * @throws RuntimeException 压缩失败会抛出运行时异常
+     */
+    public void toZip(List<File> srcFiles , File zipFile)throws RuntimeException {
+        long start = System.currentTimeMillis();
+        ZipOutputStream zos = null ;
+        try {
+            zos = new ZipOutputStream(new FileOutputStream(zipFile));
+            for (File srcFile : srcFiles) {
+                byte[] buf = new byte[2*1024];
+                zos.putNextEntry(new ZipEntry(srcFile.getName()));
+                int len;
+                FileInputStream in = new FileInputStream(srcFile);
+                while ((len = in.read(buf)) != -1){
+                    zos.write(buf, 0, len);
+                }
+                zos.closeEntry();
+                in.close();
+            }
+            long end = System.currentTimeMillis();
+            System.out.println("压缩完成,耗时:" + (end - start) +" ms");
+        } catch (Exception e) {
+            throw new RuntimeException("zip error from ZipUtils",e);
+        }finally{
+            if(zos != null){
+                try {
+                    zos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+	
+	/**
+	 * zip解压
+	 * @param srcFile     zip源文件
+	 * @param destDir 解压后的目标文件夹
+	 * @throws RuntimeException 解压失败会抛出运行时异常
+	 */
+	public List<File> unZip(File srcFile, File destDir, boolean override) throws RuntimeException {
+		List<File> files = null;
+		long start = System.currentTimeMillis();
+		// 判断源文件是否存在
+		if (!srcFile.exists()) {
+			throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
+		}
+		existName = new StringBuffer(100);
+		// 开始解压
+		ZipFile zipFile = null;
+		int len;
+		byte[] buf = new byte[4096];
+		try {
+			Charset gbk = Charset.forName("GBK");
+			zipFile = new ZipFile(srcFile, gbk);
+			Enumeration<?> entries = zipFile.entries();
+
+			files = new ArrayList<>(zipFile.size());
+
+			while (entries.hasMoreElements()) {
+				ZipEntry entry = (ZipEntry) entries.nextElement();
+				if (entry.isDirectory()) {//遇到文件夹直接跳过
+                    continue;
+                }
+				String entryName = entry.getName();
+				while(true) {  //保留最后的文件名
+					int index = entryName.indexOf("/");
+					if(index > -1) {
+						entryName = entryName.substring(index+1);
+					}else {
+						break;
+					}
+				}
+				
+				File targetFile = new File(destDir, entryName);
+				if(override == false){//当override = false 需要检查文件是否存在
+					if(targetFile.exists()) {//如果存在 则跳过
+						existName.append(entryName).append(",");
+						continue;
+					}
+				}
+				files.add(targetFile);
+				targetFile.createNewFile();
+				// 将压缩文件内容写入到这个文件中
+				InputStream is = zipFile.getInputStream(entry);
+				FileOutputStream fos = new FileOutputStream(targetFile);
+				while ((len = is.read(buf)) != -1) {
+					fos.write(buf, 0, len);
+				}
+				fos.flush();
+				fos.close();
+			}
+
+			long end = System.currentTimeMillis();
+			System.out.println(new StringBuffer("解压完成,耗时:").append((end - start)).append(" ms").toString());
+		} catch (Exception e) {
+			throw new RuntimeException("unzip error from ZipUtils", e);
+		} finally {
+			if (zipFile != null) {
+				try {
+					zipFile.close();
+					srcFile.delete();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		return files;
+	}
+
+	StringBuffer existName = null;
+	public StringBuffer getExistName(){
+		return existName;
+	}
+}

+ 186 - 0
src/main/java/com/sysu/admin/utils/http/HttpUtil.java

@@ -0,0 +1,186 @@
+package com.sysu.admin.utils.http;
+
+import okhttp3.*;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+import org.dom4j.io.XMLWriter;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class HttpUtil {
+	/**
+	 * 提供post 重定向的方法 (该方法只可用于web端)
+	 * @param url
+	 * @param response
+	 * @param parameter
+	 * @throws IOException
+	 */
+	public static void sendByPost(String url, HttpServletResponse response, Map<String, String> parameter) {
+		response.setContentType("text/html");
+		PrintWriter out = null;
+		try {
+			out = response.getWriter();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
+		out.println("<HTML>");
+		out.println(" <HEAD><TITLE>sender</TITLE></HEAD>");
+		out.println(" <BODY>");
+		out.println("<form name=\"submitForm\" action=\"" + url + "\" method=\"post\">");
+		if(parameter!=null) {
+			Iterator<String> it = parameter.keySet().iterator();
+			while (it.hasNext()) {
+				String key = it.next();
+				String val = parameter.get(key);
+				if(val != null && !val.isEmpty()) {
+					out.println("<input type=\"hidden\" name=\"" + key + "\" value=\"" + val + "\"/>");
+				}
+			}
+		}
+		out.println("</from>");
+		out.println("<script>window.document.submitForm.submit();</script> ");
+		out.println(" </BODY>");
+		out.println("</HTML>");
+		out.flush();
+		out.close();
+	}
+	
+	/**
+	 * 用传统的URI类进行请求
+	 * 
+	 * @param urlStr
+	 */
+	public static String httpPost(String urlStr,String xmlInfo) {
+		try {
+			URL url = new URL(urlStr);
+			HttpURLConnection con = (HttpURLConnection)url.openConnection();
+			con.setDoOutput(true);
+			con.setRequestProperty("Content-Type", "text/xml");
+
+
+			OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream(),"UTF-8");
+			out.write(xmlInfo);
+			out.flush();
+			out.close();
+			
+			BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(),"UTF-8"));
+			StringBuffer line = new StringBuffer();
+			while(br.ready()) {
+				line.append(br.readLine());
+			}
+			return line.toString();
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return null;
+	}
+	
+	/**
+	 * map 转 xml字符串
+	 * @param map
+	 * @return
+	 */
+    public static String mapToXml(Map<String, String> map) {
+        Document d = DocumentHelper.createDocument();
+        Element root = d.addElement("xml");
+        Set<String> keys = map.keySet();
+        for(String key:keys) {
+        	
+            root.addElement(key).addCDATA(map.get(key));
+
+        }
+        StringWriter sw = new StringWriter();
+        XMLWriter xw = new XMLWriter(sw);
+        xw.setEscapeText(false);
+       
+        try {
+			xw.write(d);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+        return sw.toString();
+    }
+	
+    
+    /**
+     * 同步访问
+     * @param address
+     * @param paramsMap
+     * @return
+     */
+    public  static String httpPost2(String address, Map<String,String> paramsMap) {
+        OkHttpClient client = new OkHttpClient().newBuilder()
+                .connectTimeout(15, TimeUnit.SECONDS)
+                .readTimeout(15, TimeUnit.SECONDS)
+                .writeTimeout(15, TimeUnit.SECONDS)
+                .build();
+
+        FormBody.Builder builder = new FormBody.Builder();
+        if (paramsMap!=null) {
+            for (String key : paramsMap.keySet()) {
+                builder.add(key, paramsMap.get(key));
+            }
+        }
+        RequestBody requestBody=builder.build();
+        Request request = new Request.Builder()
+                .url(address).post(requestBody)
+                .build();
+        try {
+            Response response=  client.newCall(request).execute();
+            if(response.isSuccessful()){
+                return response.body().string();
+            }else{
+                return null;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+    
+    
+    /**
+     * 同步访问
+     * @param address
+     * @return
+     */
+    public  static String httpGet(String address) {
+        OkHttpClient client = new OkHttpClient().newBuilder()
+                .connectTimeout(15, TimeUnit.SECONDS)
+                .readTimeout(15, TimeUnit.SECONDS)
+                .writeTimeout(15, TimeUnit.SECONDS)
+                .build();
+
+        Request request = new Request.Builder()
+                .url(address).get()
+                .build();
+        try {
+            Response response=  client.newCall(request).execute();
+            if(response.isSuccessful()){
+                return response.body().string();
+            }else{
+                return null;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+	
+
+	
+	
+
+
+}

+ 29 - 0
src/main/java/com/sysu/admin/utils/i18n/MessageUtils.java

@@ -0,0 +1,29 @@
+package com.sysu.admin.utils.i18n;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.stereotype.Component;
+
+/**
+ * 国际化工具类
+ */
+@Component
+public class MessageUtils {
+
+    private static MessageSource messageSource;
+
+    public MessageUtils(MessageSource messageSource) {
+        this.messageSource = messageSource;
+    }
+
+    /**
+     * 获取单个国际化翻译值
+     */
+    public static String get(String msgKey) {
+        try {
+            return messageSource.getMessage(msgKey, null, LocaleContextHolder.getLocale());
+        } catch (Exception e) {
+            return msgKey;
+        }
+    }
+}

+ 21 - 0
src/main/java/com/sysu/admin/utils/queue/MyQueue.java

@@ -0,0 +1,21 @@
+package com.sysu.admin.utils.queue;
+
+import java.util.List;
+
+
+public interface MyQueue<T> {
+
+
+    int size();
+
+    void add(T o);
+
+    void get(ResultListener listener);
+
+    interface ResultListener<E>{
+        void get(List<E> list);
+    }
+
+
+
+}

+ 7 - 0
src/main/java/com/sysu/admin/utils/queue/MyQueueContext.java

@@ -0,0 +1,7 @@
+package com.sysu.admin.utils.queue;
+
+
+
+public class MyQueueContext {
+
+}

+ 55 - 0
src/main/java/com/sysu/admin/utils/queue/MyQueueSimple.java

@@ -0,0 +1,55 @@
+package com.sysu.admin.utils.queue;
+
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+@Slf4j
+public class MyQueueSimple<T> implements MyQueue<T>{
+
+    Executor executor;
+    private int getCount;
+    private int warning = 10000;
+    private  LinkedList<T> queue;
+
+    protected MyQueueSimple(int getCount){
+        this.getCount = getCount;
+        queue = new LinkedList();
+        executor = Executors.newSingleThreadExecutor();
+    }
+
+    public int size(){
+        return queue.size();
+    }
+
+    public void add(T o){
+        executor.execute(()->{
+            queue.addFirst(o);
+            if(queue.size() > warning){
+                log.warn("当前数据【" + queue.size() + "】条超过预警值【"+warning+"】");
+                warning *= 1.5;
+                getCount *= 1.5;
+                log.warn("预警值自动扩容到:" + warning+", 返回数量扩容到:" + getCount);
+            }
+        });
+    }
+
+    public void get(ResultListener listener){
+        executor.execute(()-> {
+            int l = queue.size() < getCount ? queue.size() : getCount;
+            List<T> list = new ArrayList<>(l);
+            for (int i = 0; i < l; i++) {
+                list.add(queue.removeLast());
+            }
+            listener.get(list);
+        });
+    }
+
+
+
+}

+ 56 - 0
src/main/java/com/sysu/admin/utils/shape/CommonMethod.java

@@ -0,0 +1,56 @@
+package com.sysu.admin.utils.shape;
+
+import java.io.*;
+
+public class CommonMethod {
+
+    public static void append2File(String file, String content, boolean isApppend) {
+        FileWriter fw = null;
+
+        try {
+            //如果文件存在,则追加内容;如果文件不存在,则创建文件
+            File f = new File(file);
+            fw = new FileWriter(f, isApppend);
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        PrintWriter pw = new PrintWriter(fw);
+        pw.println(content);
+        pw.flush();
+
+        try {
+            fw.flush();
+            pw.close();
+            fw.close();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static String getFileContent(String path) throws IOException {
+        BufferedReader bufferedReader = null;
+        StringBuffer result = new StringBuffer();
+        try {
+            FileInputStream inputStream = new FileInputStream(path);
+            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
+            while(bufferedReader.ready()){
+                result.append(bufferedReader.readLine());
+            }
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }finally {
+            if(bufferedReader != null){
+                try {
+                    bufferedReader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return result.toString();
+    }
+
+}

+ 78 - 0
src/main/java/com/sysu/admin/utils/shape/CoordinateConversion.java

@@ -0,0 +1,78 @@
+package com.sysu.admin.utils.shape;
+
+import com.sysu.admin.utils.shape.postgis.PostGisConfig;
+import com.sysu.admin.utils.shape.postgis.PostGisUtil;
+import org.locationtech.jts.geom.Coordinate;
+
+import java.io.File;
+
+public class CoordinateConversion {
+
+
+    /**
+     * 经纬度转墨卡托
+     * @param mercator 经纬度坐标
+     * @return
+     */
+    public static Coordinate lonLatToMercator(Coordinate mercator){
+        double x =  (mercator.getX() * 20037508.342789 / 180);
+        double y =  (Math.log(Math.tan((90 + mercator.getY()) * Math.PI / 360)) / (Math.PI / 180));
+        y =  (double)(y * 20037508.342789 / 180);
+        mercator.setX(x);
+        mercator.setY(y);
+        return mercator;
+    }
+
+    /**
+     * 墨卡托转经纬度
+     * @param mercator 墨卡托坐标
+     * @return
+     */
+    public static Coordinate mercatorToLonLat(Coordinate mercator){
+        double x =   (mercator.getX() / 20037508.342789 * 180);
+        double y =  (mercator.getY() / 20037508.342789 * 180);
+        y = (double) (180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2));
+        mercator.setX(x);
+        mercator.setY(y);
+        return mercator;
+    }
+
+
+    /**
+     *   url: localhost
+     *   port: 5432
+     *   database: nyc
+     *   user: postgres
+     *   password: root
+     * @param filePath
+     */
+    public static void mercatorToLonLat(String filePath){
+        File file = new File(filePath);
+        PostGisUtil postGisUtil = new PostGisUtil();
+        PostGisConfig postGisConfig = new PostGisConfig();
+        postGisConfig.setUrl("localhost");
+        postGisConfig.setPort(5432);
+        postGisConfig.setPassword("root");
+        postGisConfig.setUser("postgres");
+        postGisConfig.setDatabase("nyc");
+        postGisUtil.connPostGis(postGisConfig);
+        postGisUtil.openConnection();
+
+        postGisUtil.insertShp("qingyuan_crop_2", file, geometry -> {
+            Coordinate[] coordinates = geometry.getCoordinates();
+            for(Coordinate coordinate : coordinates){
+                mercatorToLonLat(coordinate);
+            }
+            return geometry;
+        }, false);
+
+        postGisUtil.closeConnection();
+        postGisUtil.dispose();
+    }
+
+    public static void main(String[] args) {
+        mercatorToLonLat("E:\\zcjy\\bhjc\\QY_crop\\qingyuan_crop_2.shp");
+    }
+
+
+}

+ 93 - 0
src/main/java/com/sysu/admin/utils/shape/DataTypeConvert.java

@@ -0,0 +1,93 @@
+package com.sysu.admin.utils.shape;
+
+import org.geotools.geojson.geom.GeometryJSON;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.referencing.CRS;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Polygon;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKTReader;
+import org.locationtech.jts.io.WKTWriter;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+import java.io.*;
+
+public class DataTypeConvert {
+    public static Geometry geojson2Geometry(String geojson) throws IOException {
+        GeometryJSON gjson = new GeometryJSON(7);
+        return gjson.read(new StringReader(geojson));
+    }
+
+    public static String geometry2Geojson(Geometry geometry) throws IOException {
+        GeometryJSON gjson = new GeometryJSON(7);
+        StringWriter writer = new StringWriter();
+        gjson.write(geometry, writer);
+        return writer.toString();
+    }
+
+    public static Geometry wkt2Geometry(String wkt){
+        WKTReader reader = new WKTReader();
+        try {
+            return reader.read(wkt);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    public static String geometry2Wkt(Geometry geometry) throws ParseException {
+        WKTWriter writer = new WKTWriter();
+        return writer.write(geometry);
+    }
+
+    static CoordinateReferenceSystem source = null;
+    static CoordinateReferenceSystem target = null;
+
+    /**
+     * 根据多边形类型计算出多边形面积,单位(亩)
+     * @param geometry 多边形对象
+     * @return 面积
+     */
+    public static double getArea(Geometry geometry){
+        if(source == null) {
+            try {
+                source = CRS.parseWKT("GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]");
+            } catch (FactoryException e) {
+                e.printStackTrace();
+            }
+        }
+        if(target == null) {
+            try {
+                target = CRS.parseWKT("PROJCS[\"CGCS2000 / 3-degree Gauss-Kruger zone 38\",GEOGCS[\"China Geodetic Coordinate System 2000\",DATUM[\"China_2000\",SPHEROID[\"CGCS2000\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"1024\"]],AUTHORITY[\"EPSG\",\"1043\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4490\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",114],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",38500000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AUTHORITY[\"EPSG\",\"4526\"]]");
+            } catch (FactoryException e) {
+                e.printStackTrace();
+            }
+        }
+        MathTransform transform = null;
+        try {
+            transform = CRS.findMathTransform(source, target, true);
+        } catch (FactoryException e) {
+            e.printStackTrace();
+        }
+        Geometry transform1 = null;
+        try {
+            transform1 = JTS.transform(geometry, transform);
+        } catch (TransformException e) {
+            e.printStackTrace();
+        }
+        double area = (transform1.getArea() + transform1.getArea() / 2) / 1000;
+        return area;
+    }
+
+
+
+
+}
+
+

+ 365 - 0
src/main/java/com/sysu/admin/utils/shape/FileFormat.java

@@ -0,0 +1,365 @@
+package com.sysu.admin.utils.shape;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.sysu.admin.utils.shape.vo.Param;
+import com.sysu.admin.utils.shape.vo.ParamType;
+import com.sysu.admin.utils.shape.vo.*;
+import net.sourceforge.pinyin4j.PinyinHelper;
+import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
+import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
+import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
+import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
+import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
+import org.geotools.data.*;
+import org.geotools.data.shapefile.ShapefileDataStore;
+import org.geotools.data.shapefile.ShapefileDataStoreFactory;
+import org.geotools.data.store.ContentFeatureCollection;
+import org.geotools.data.store.ContentFeatureSource;
+import org.geotools.feature.FeatureIterator;
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
+import org.geotools.geojson.feature.FeatureJSON;
+import org.geotools.geojson.geom.GeometryJSON;
+import org.geotools.jdbc.JDBCDataStore;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.locationtech.jts.geom.*;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.referencing.FactoryException;
+
+
+public class FileFormat {
+
+
+
+
+	/**
+	 * geojson转换为shp文件
+	 * @param jsonPath
+	 * @param shpPath
+	 * @return
+	 */
+	public static Map geojson2Shape(String jsonPath, String shpPath){
+		Map map = new HashMap();
+		GeometryJSON gjson = new GeometryJSON();
+		try{
+			String strJson = CommonMethod.getFileContent(jsonPath);
+			JSONObject json = JSON.parseObject(strJson);
+			JSONArray features = (JSONArray) json.get("features");
+			JSONObject feature0 = JSON.parseObject(features.get(0).toString());
+			System.out.println(feature0.toString());
+			String strType = ((JSONObject)feature0.get("geometry")).getString("type").toString();
+
+			Class<?> geoType = null;
+			switch(strType){
+				case "Point":
+					geoType = Point.class;
+				case "MultiPoint":
+					geoType = MultiPoint.class;
+				case "LineString":
+					geoType = LineString.class;
+				case "MultiLineString":
+					geoType = MultiLineString.class;
+				case "Polygon":
+					geoType = Polygon.class;
+				case "MultiPolygon":
+					geoType = MultiPolygon.class;
+			}
+			//创建shape文件对象
+			File file = new File(shpPath);
+			Map<String, Serializable> params = new HashMap<String, Serializable>();
+			params.put( ShapefileDataStoreFactory.URLP.key, file.toURI().toURL() );
+			ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
+			//定义图形信息和属性信息
+			SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
+			tb.setCRS(DefaultGeographicCRS.WGS84);
+			tb.setName("shapefile");
+			tb.add("the_geom", geoType);
+			tb.add("POIID", Long.class);
+			ds.createSchema(tb.buildFeatureType());
+			//设置编码
+			Charset charset = Charset.forName("GBK");
+			ds.setCharset(charset);
+			//设置Writer
+			FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
+
+			for(int i=0,len=features.size();i<len;i++){
+				String strFeature = features.get(i).toString();
+				Reader reader = new StringReader(strFeature);
+				SimpleFeature feature = writer.next();
+				feature.setAttribute("the_geom",GeoCastUtil.readGeometry(reader, strType, gjson));
+				feature.setAttribute("POIID",i);
+				writer.write();
+			}
+			writer.close();
+			ds.dispose();
+			map.put("status", "success");
+			map.put("message", shpPath);
+		}
+		catch(Exception e){
+			map.put("status", "failure");
+			map.put("message", e.getMessage());
+			e.printStackTrace();
+		}
+		return map;
+	}
+
+	public static void toShp(List<Geometry> geometryList, String shpPath, ParamType[] paramTypes, List<Param> params) throws IOException {
+		GeometryJSON fjson = new GeometryJSON();
+		File file = new File(shpPath);
+		Map<String, Serializable> map = new HashMap<String, Serializable>();
+		map.put( ShapefileDataStoreFactory.URLP.key, file.toURI().toURL() );
+		ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(map);
+		//定义图形信息和属性信息
+		SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
+		//设置坐标系
+		//创建
+		try {
+			tb.setCRS(CRS.decode("EPSG:4326"));
+		} catch (FactoryException e) {
+			e.printStackTrace();
+		}
+		tb.setName("shapefile");
+		tb.add("the_geom", MultiPolygon.class);
+		for(ParamType paramType : paramTypes){
+			tb.add(paramType.getName(), paramType.getType());
+		}
+		ds.createSchema(tb.buildFeatureType());
+		//设置编码
+		ds.setCharset(Charset.forName("GBK"));
+		//设置Writer
+		FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriterAppend(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
+
+		for(int i=0,len=geometryList.size();i<len;i++){
+			Geometry geometry = geometryList.get(i);
+			SimpleFeature feature = writer.next();
+			feature.setAttribute("the_geom", GeoSwapXYUtil.swap(fjson, geometry));
+			Param param = params.get(i);
+			for(int j = 0;j < param.getNames().length;j++){
+				feature.setAttribute(param.getNames()[j], param.getValues()[j]);
+			}
+			writer.write();
+		}
+		writer.close();
+		ds.dispose();
+	}
+
+	public static void toShpPostGis(List<Geometry> geometryList, JDBCDataStore ds, ParamType[] paramTypes, List<Param> params) throws IOException {
+		GeometryJSON fjson = new GeometryJSON();
+		String typeName = "shapefile";
+
+		if(!ds.hasSchema(typeName)) {
+			//定义图形信息和属性信息
+			SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
+			//设置坐标系
+			//创建
+			tb.setCRS(DefaultGeographicCRS.WGS84);
+			tb.setName(typeName);
+			tb.add("the_geom", GeometryCollection.class);
+			for (ParamType paramType : paramTypes) {
+				tb.add(paramType.getName(), paramType.getType());
+			}
+			ds.createSchema(tb.buildFeatureType());
+		}
+		FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriterAppend(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
+
+		for(int i=0,len=geometryList.size();i<len;i++){
+			Geometry geometry = geometryList.get(i);
+			SimpleFeature feature = writer.next();
+			feature.setAttribute("the_geom", GeoCastUtil.castGeometryCollection(fjson, geometry));
+			Param param = params.get(i);
+			for (int j = 0; j < param.getNames().length; j++) {
+				feature.setAttribute(param.getNames()[j], param.getValues()[j]);
+			}
+			writer.write();
+		}
+		writer.close();
+		ds.dispose();
+	}
+
+
+	/**
+	 * shp转换为Geojson
+	 * @param shpPath
+	 * @return
+	 */
+	public static Map shape2Geojson(String shpPath, String jsonPath){
+		Map map = new HashMap();
+		FeatureJSON fjson = new FeatureJSON();
+		try{
+			StringBuffer sb = new StringBuffer();
+			sb.append("{\"type\": \"FeatureCollection\",\"features\": ");
+			File file = new File(shpPath);
+			ShapefileDataStore shpDataStore = new ShapefileDataStore(file.toURL());
+			FeatureIterator<SimpleFeature> itertor = getFeatures(shpDataStore);
+			JSONArray array = new JSONArray();
+			while (itertor.hasNext())
+			{
+				SimpleFeature feature = itertor.next();
+				StringWriter writer = new StringWriter();
+				fjson.writeFeature(feature, writer);
+				JSONObject json = JSON.parseObject(writer.toString());
+				array.add(json);
+			}
+			itertor.close();
+			sb.append(array.toString());
+			sb.append("}");
+			//写入文件
+			CommonMethod.append2File(jsonPath, sb.toString(), false);
+
+			map.put("status", "success");
+			map.put("message", sb.toString());
+		}
+		catch(Exception e){
+			map.put("status", "failure");
+			map.put("message", e.getMessage());
+			e.printStackTrace();
+
+		}
+		return map;
+	}
+
+	public static FeatureIterator<SimpleFeature> getFeatures(ShapefileDataStore shpDataStore) throws IOException {
+		//设置编码
+		Charset charset = Charset.forName("GBK");
+		shpDataStore.setCharset(charset);
+		String typeName = shpDataStore.getTypeNames()[0];
+		ContentFeatureSource featureSource = null;
+		featureSource =  shpDataStore.getFeatureSource (typeName);
+		ContentFeatureCollection result = featureSource.getFeatures();
+		FeatureIterator<SimpleFeature> itertor = result.features();
+		return itertor;
+	}
+
+
+	/**
+	 * shp转换为Geojson
+	 * @param shpPath
+	 * @return
+	 */
+	public Map shape2GeoJsonList(String shpPath, String jsonPathDir, String numberPropertyName){
+		Map map = new HashMap();
+		FeatureJSON fjson = new FeatureJSON();
+		try{
+			File file = new File(shpPath);
+			ShapefileDataStore shpDataStore = new ShapefileDataStore(file.toURL());
+			FeatureIterator<SimpleFeature> itertor = getFeatures(shpDataStore);
+			while (itertor.hasNext())
+			{
+				StringBuffer sb = new StringBuffer();
+				sb.append("{\"type\": \"FeatureCollection\",\"features\": [");
+				SimpleFeature feature = itertor.next();
+				StringWriter writer = new StringWriter();
+				fjson.writeFeature(feature, writer);
+				JSONObject json = JSON.parseObject(writer.toString());
+				sb.append(json.toJSONString());
+				sb.append("]}");
+				//写入文件
+				String path = jsonPathDir + "\\" + getPinyin(file.getName().substring(0, 2)) + "_" + feature.getProperty(numberPropertyName).getValue()  + ".geojson";
+				CommonMethod.append2File(path, sb.toString(), false);
+			}
+			itertor.close();
+
+
+			map.put("status", "success");
+		}
+		catch(Exception e){
+			map.put("status", "failure");
+			e.printStackTrace();
+
+		}
+		return map;
+	}
+
+
+
+	/**
+	 * @param china (字符串 汉字)
+	 * @return 汉字转拼音 其它字符不变
+	 */
+	public static String getPinyin(String china){
+		HanyuPinyinOutputFormat formart = new HanyuPinyinOutputFormat();
+		formart.setCaseType(HanyuPinyinCaseType.LOWERCASE);
+		formart.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
+		formart.setVCharType(HanyuPinyinVCharType.WITH_V);
+		char[] arrays = china.trim().toCharArray();
+		String result = "";
+		try {
+			for (int i=0;i<arrays.length;i++) {
+				char ti = arrays[i];
+				if(Character.toString(ti).matches("[\\u4e00-\\u9fa5]")){ //匹配是否是中文
+					String[] temp = PinyinHelper.toHanyuPinyinStringArray(ti,formart);
+					result += temp[0];
+				}else{
+					result += ti;
+				}
+			}
+		} catch (BadHanyuPinyinOutputFormatCombination e) {
+			e.printStackTrace();
+		}
+
+		return result;
+	}
+	/**
+	 * 工具类测试方法
+	 * @param args
+	 */
+	public static void main(String[] args){
+		no3();
+	}
+
+
+	public static void no3(){
+		String shpPath = "C:\\Users\\Administrator\\Desktop\\改建\\";
+		geojson2Shape(shpPath + "districts.geojson",shpPath + "districts.shp");
+	}
+
+	public static void no2(){
+		geojson2Shape("E:\\zcjy\\intersections.geojson",
+				"E:\\zcjy\\intersections.shp");
+//		shape2Geojson("E:\\zcjy\\intersections.shp","E:\\zcjy\\intersections.geojson");
+	}
+
+	public static void no1(){
+		FileFormat fileFormat = new FileFormat();
+		long start = System.currentTimeMillis();
+		String shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\采矿权数据.shp";
+		String jsonPath = "E:\\zcjy\\workspace2\\change_det\\src\\main\\webapp\\geojson";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"OBJECTID");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\英德最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\阳山最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\清新最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\清城最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\连州最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\连山最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\连南最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		shpPath = "E:\\zcjy\\bhjc\\清远裸露山体\\佛冈最终裸露山体地块8.11new.shp";
+		fileFormat.shape2GeoJsonList(shpPath, jsonPath,"地块编号");
+
+		System.out.println(jsonPath+",共耗时"+(System.currentTimeMillis() - start)+"ms");
+	}
+
+
+}

部分文件因文件數量過多而無法顯示