diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e586a6d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,50 @@
+# ---> Java
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..2377d93
--- /dev/null
+++ b/META-INF/MANIFEST.MF
@@ -0,0 +1,92 @@
+Manifest-Version: 1.0
+Main-Class:
+Class-Path: antlr-2.7.7.jar org.w3.xlink-28.0.jar okhttp-3.14.9.jar ejml
+ -ddense-0.41.jar slf4j-api-1.7.36.jar httpclient-4.5.13.jar hibernate-s
+ patial-5.6.15.Final.jar gt-metadata-28.0.jar tea-util-0.2.16.jar reacto
+ r-netty-http-1.0.25.jar spring-boot-starter-webflux-2.6.14.jar spring-b
+ oot-2.6.14.jar netty-all-4.1.86.Final.jar jakarta.websocket-api-1.1.2.j
+ ar netty-codec-http-4.1.85.Final.jar netty-resolver-dns-native-macos-4.
+ 1.85.Final-osx-x86_64.jar postgresql-42.3.8.jar dom4j-2.0.3.jar net.ope
+ ngis.ows-28.0.jar httpmime-4.5.14.jar log4j-jul-2.17.2.jar GeographicLi
+ b-Java-1.49.jar prefixmap-2.0.jar snakeyaml-1.29.jar spring-boot-starte
+ r-undertow-2.6.14.jar spring-jdbc-5.3.24.jar micrometer-registry-promet
+ heus-1.10.2.jar netty-resolver-dns-4.1.85.Final.jar uom-lib-common-2.0.
+ jar netty-codec-xml-4.1.85.Final.jar spring-orm-5.3.24.jar spring-secur
+ ity-core-5.6.9.jar spring-boot-starter-data-redis-2.6.14.jar spring-dat
+ a-commons-2.6.10.jar checker-qual-3.5.0.jar openapiutil-0.2.0.jar sprin
+ g-expression-5.3.24.jar spring-aspects-5.3.24.jar ejml-core-0.41.jar co
+ mmons-io-2.4.jar spring-boot-starter-json-2.6.14.jar jackson-datatype-j
+ sr310-2.13.4.jar spring-boot-starter-reactor-netty-2.6.14.jar netty-tra
+ nsport-rxtx-4.1.85.Final.jar si-quantity-2.0.1.jar error_prone_annotati
+ ons-2.10.0.jar gt-main-28.0.jar HdrHistogram-2.1.12.jar reactor-core-3.
+ 4.25.jar undertow-core-2.2.20.Final.jar spring-security-config-5.6.9.ja
+ r jakarta.persistence-api-2.2.3.jar commons-codec-1.15.jar netty-resolv
+ er-dns-classes-macos-4.1.85.Final.jar jgridshift-core-1.3.jar spring-bo
+ ot-actuator-autoconfigure-2.6.14.jar spring-boot-starter-websocket-2.6.
+ 14.jar endpoint-util-0.0.7.jar org.jacoco.agent-0.8.4-runtime.jar netty
+ -transport-4.1.85.Final.jar netty-transport-native-kqueue-4.1.85.Final-
+ osx-aarch_64.jar caffeine-2.9.3.jar unit-api-2.0.jar netty-codec-memcac
+ he-4.1.85.Final.jar commons-text-1.10.0.jar tea-openapi-0.2.8.jar aspec
+ tjweaver-1.9.7.jar commons-dbcp-1.4.jar netty-codec-4.1.85.Final.jar js
+ oup-1.15.3.jar lettuce-core-6.1.10.RELEASE.jar jakarta.transaction-api-
+ 1.3.3.jar jackson-annotations-2.13.4.jar dysmsapi20170525-2.0.23.jar ne
+ tty-transport-native-kqueue-4.1.85.Final-osx-x86_64.jar jts-core-1.18.2
+ .jar jandex-2.4.2.Final.jar LatencyUtils-2.0.3.jar netty-codec-haproxy-
+ 4.1.85.Final.jar netty-transport-native-epoll-4.1.85.Final-linux-aarch_
+ 64.jar spring-boot-starter-jdbc-2.6.14.jar jakarta.annotation-api-1.3.5
+ .jar spring-boot-starter-security-2.6.14.jar spring-boot-autoconfigure-
+ 2.6.14.jar HikariCP-4.0.3.jar httpclient5-5.1.4.jar spring-webmvc-5.3.2
+ 4.jar jakarta.validation-api-2.0.2.jar ini4j-0.5.4.jar jaxb-impl-2.3.0.
+ jar org.eclipse.emf.ecore.xmi-2.15.0.jar netty-codec-smtp-4.1.85.Final.
+ jar hibernate-core-5.6.14.Final.jar alibabacloud-gateway-spi-0.0.1.jar
+ hutool-all-5.8.10.jar netty-resolver-dns-native-macos-4.1.85.Final-osx-
+ aarch_64.jar mysql-connector-j-8.0.31.jar hibernate-types-55-2.15.2.jar
+ log4j-api-2.17.2.jar wildfly-common-1.5.4.Final.jar jakarta.activation
+ -api-1.2.2.jar netty-transport-udt-4.1.85.Final.jar netty-handler-4.1.8
+ 5.Final.jar javax.inject-1.jar micrometer-core-1.8.12.jar gt-shapefile-
+ 28.0.jar spring-context-5.3.24.jar gt-jdbc-postgis-28.0.jar hibernate-c
+ ommons-annotations-5.1.2.Final.jar spring-oxm-5.3.24.jar wildfly-client
+ -config-1.0.1.Final.jar netty-codec-stomp-4.1.85.Final.jar spring-boot-
+ starter-data-jpa-2.6.14.jar undertow-servlet-2.2.20.Final.jar tea-1.2.0
+ .jar jackson-databind-2.13.4.2.jar httpcore5-5.1.5.jar spring-security-
+ crypto-5.6.9.jar spring-web-5.3.24.jar jakarta.servlet-api-4.0.4.jar co
+ mmons-pool2-2.11.1.jar simpleclient_common-0.12.0.jar jboss-threads-3.1
+ .0.Final.jar spring-data-jpa-2.6.10.jar httpcore-4.4.15.jar gt-referenc
+ ing-28.0.jar systems-common-2.0.2.jar xnio-nio-3.8.7.Final.jar org.ecli
+ pse.emf.ecore-2.15.0.jar spring-boot-starter-2.6.14.jar undertow-websoc
+ kets-jsr-2.2.20.Final.jar netty-handler-ssl-ocsp-4.1.86.Final.jar jsr30
+ 5-3.0.2.jar netty-common-4.1.85.Final.jar sqlite-jdbc-3.36.0.3.jar spri
+ ng-websocket-5.3.24.jar jaxb-core-2.3.0.jar javax.activation-api-1.2.0.
+ jar bcprov-jdk15on-1.65.jar spring-boot-starter-actuator-2.6.14.jar hib
+ ernate-validator-7.0.5.Final.jar jakarta.activation-1.2.2.jar spring-tx
+ -5.3.24.jar txw2-2.3.7.jar gt-http-28.0.jar simpleclient-0.12.0.jar log
+ 4j-web-2.19.0.jar gt-jdbc-28.0.jar org.eclipse.emf.common-2.15.0.jar is
+ tack-commons-runtime-3.0.12.jar jul-to-slf4j-1.7.36.jar spring-boot-act
+ uator-2.6.14.jar yauaa-7.9.0.jar spring-data-redis-2.6.10.jar netty-buf
+ fer-4.1.85.Final.jar classmate-1.5.1.jar netty-handler-proxy-4.1.85.Fin
+ al.jar tomcat-embed-el-9.0.69.jar tea-xml-0.1.5.jar simpleclient_tracer
+ _otel_agent-0.12.0.jar spring-aop-5.3.24.jar bcpkix-jdk15on-1.65.jar sp
+ ring-beans-5.3.24.jar simpleclient_tracer_otel-0.12.0.jar jai_core-1.1.
+ 3.jar indriya-2.0.2.jar netty-codec-http2-4.1.85.Final.jar jackson-data
+ type-jdk8-2.13.4.jar mbtiles4j-1.2.0.jar netty-transport-classes-epoll-
+ 4.1.85.Final.jar xnio-api-3.8.7.Final.jar log4j-slf4j-impl-2.17.2.jar l
+ og4j-core-2.17.2.jar netty-codec-redis-4.1.85.Final.jar disruptor-3.4.4
+ .jar spring-jcl-5.3.24.jar commons-pool-1.6.jar spring-core-5.3.24.jar
+ spring-boot-starter-aop-2.6.14.jar httpcore5-h2-5.1.5.jar netty-resolve
+ r-4.1.85.Final.jar commons-lang3-3.12.0.jar gson-2.8.9.jar netty-codec-
+ dns-4.1.85.Final.jar jaxb-runtime-2.3.7.jar reactive-streams-1.0.4.jar
+ spring-security-web-5.6.9.jar spring-webflux-5.3.24.jar jackson-core-2.
+ 13.4.jar jackson-module-jaxb-annotations-2.13.4.jar netty-transport-nat
+ ive-unix-common-4.1.85.Final.jar simpleclient_tracer_common-0.12.0.jar
+ byte-buddy-1.11.22.jar java-jwt-4.2.2.jar si-units-2.0.1.jar spring-boo
+ t-starter-log4j2-2.6.14.jar spring-boot-devtools-2.6.14.jar spring-data
+ -keyvalue-2.6.10.jar reactor-netty-core-1.0.25.jar jakarta.xml.bind-api
+ -2.3.3.jar spring-messaging-5.3.24.jar commons-collections4-4.4.jar net
+ ty-codec-mqtt-4.1.85.Final.jar credentials-java-0.2.4.jar re2j-1.6.jar
+ spring-boot-starter-web-2.6.14.jar jackson-module-parameter-names-2.13.
+ 4.jar jaxb-api-2.3.1.jar netty-transport-native-epoll-4.1.85.Final-linu
+ x-x86_64.jar okio-1.17.2.jar geolatte-geom-1.8.2.jar netty-codec-socks-
+ 4.1.85.Final.jar jboss-logging-3.4.3.Final.jar netty-transport-sctp-4.1
+ .85.Final.jar spring-context-support-5.3.24.jar gt-opengis-28.0.jar net
+ ty-transport-classes-kqueue-4.1.85.Final.jar
+
diff --git a/README.md b/README.md
index 4c48ae9..cf80a00 100644
Binary files a/README.md and b/README.md differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..97d0f70
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,299 @@
+
+
+ 4.0.0
+
+ com.xkrs.microservice
+ gsm_gui
+ 1.0.0
+ jar
+
+ GSM_GUI
+ GSM_GUI
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.14
+
+
+
+
+ 7.9.0
+ 4.2.2
+ 2.19.0
+ 4.5.14
+ 7.0.5.Final
+ 5.6.15.Final
+ 3.4.4
+ 1.15.3
+ 2.0.23
+ 4.1.86.Final
+ 2.15.2
+ 1.10.2
+ 3.12.0
+ 5.8.10
+ 1.2.0
+ 28.0
+ UTF-8
+ UTF-8
+ 17
+ 17
+ 17
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+
+
+ org.apache.logging.log4j
+ log4j-web
+ ${log4j-web.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+ spring-boot-starter-tomcat
+ org.springframework.boot
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
+ org.apache.commons
+ commons-pool2
+
+
+ org.postgresql
+ postgresql
+
+
+ com.mysql
+ mysql-connector-j
+
+
+ com.auth0
+ java-jwt
+ ${java-jwt.version}
+
+
+ io.netty
+ netty-all
+ ${netty-all.version}
+
+
+ ch.poole.geo
+ mbtiles4j
+ ${mbtiles4j.version}
+
+
+
+ nl.basjes.parse.useragent
+ yauaa
+ ${yauaa.version}
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+ ${micrometer-registry-prometheus.version}
+
+
+ com.vladmihalcea
+ hibernate-types-55
+ ${hibernate-types-55.version}
+
+
+ org.apache.httpcomponents
+ httpmime
+ ${httpmime.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+ org.hibernate.validator
+ hibernate-validator
+ ${hibernate-validator.version}
+
+
+ org.hibernate
+ hibernate-spatial
+ ${hibernate-spatial.version}
+
+
+ com.lmax
+ disruptor
+ ${disruptor.version}
+
+
+ org.jsoup
+ jsoup
+ ${jsoup.version}
+
+
+ com.aliyun
+ dysmsapi20170525
+ ${dysmsapi20170525.version}
+
+
+ org.geotools
+ gt-shapefile
+ ${geotools.version}
+
+
+ org.geotools.jdbc
+ gt-jdbc-postgis
+ ${geotools.version}
+
+
+ cn.hutool
+ hutool-all
+ ${hutool-all.version}
+
+
+
+
+
+
+
+
+
+ alimaven
+ aliyun maven
+ https://maven.aliyun.com/nexus/content/groups/public/
+
+
+ osgeo
+ Open Source Geospatial Foundation Repository
+ https://repo.osgeo.org/repository/release/
+
+
+
+
+
+ src/main/java
+
+ **/*.properties
+ **/*.xml
+
+ false
+
+
+ src/main/resources
+
+ **/*.properties
+ **/*.xml
+ **/*.txt
+
+ false
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/xkrs/microservice/MicroserviceApplication.java b/src/main/java/com/xkrs/microservice/MicroserviceApplication.java
new file mode 100644
index 0000000..16fd5d1
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/MicroserviceApplication.java
@@ -0,0 +1,28 @@
+package com.xkrs.microservice;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+/**
+ * 微服务入口
+ * @author tajochen
+ */
+@SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
+@EnableAsync
+public class MicroserviceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MicroserviceApplication.class, args);
+ }
+
+ @Bean
+ MeterRegistryCustomizer configurer(@Value("${spring.application.name}") String applicationName){
+ return registry -> registry.config().commonTags("application", applicationName);
+ }
+
+}
diff --git a/src/main/java/com/xkrs/microservice/common/account/AccountCredentials.java b/src/main/java/com/xkrs/microservice/common/account/AccountCredentials.java
new file mode 100644
index 0000000..5944932
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/account/AccountCredentials.java
@@ -0,0 +1,29 @@
+package com.xkrs.microservice.common.account;
+
+/**
+ * 账户实体
+ * @author tajochen
+ */
+public class AccountCredentials {
+
+ private String userName;
+
+ private String password;
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+}
diff --git a/src/main/java/com/xkrs/microservice/common/account/CustomAuthenticationProvider.java b/src/main/java/com/xkrs/microservice/common/account/CustomAuthenticationProvider.java
new file mode 100644
index 0000000..ec0cd4d
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/account/CustomAuthenticationProvider.java
@@ -0,0 +1,109 @@
+package com.xkrs.microservice.common.account;
+
+import com.xkrs.microservice.model.entity.SysAuthorityEntity;
+import com.xkrs.microservice.model.entity.SysUserEntity;
+import com.xkrs.microservice.service.SysAuthorityService;
+import com.xkrs.microservice.service.SysRoleService;
+import com.xkrs.microservice.service.SysUserService;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.xkrs.microservice.util.EncryptDecryptUtil.encrypt256;
+
+/**
+ * 自定义认证Provider
+ * @author tajochen
+ */
+@Component
+public class CustomAuthenticationProvider implements AuthenticationProvider {
+
+ @Resource
+ private SysUserService sysUserService;
+
+ @Resource
+ private SysRoleService sysRoleService;
+
+ @Resource
+ private SysAuthorityService sysAuthorityService;
+
+ /**
+ * 初使化时将已静态化的Service实例化
+ */
+ protected static CustomAuthenticationProvider customAuthenticationProvider;
+
+ /**
+ * 通过@PostConstruct实现初始化bean之前进行的操作
+ */
+ @PostConstruct
+ public void init() {
+ customAuthenticationProvider = this;
+ customAuthenticationProvider.sysUserService = this.sysUserService;
+ customAuthenticationProvider.sysRoleService = this.sysRoleService;
+ customAuthenticationProvider.sysAuthorityService = this.sysAuthorityService;
+ }
+
+ /**
+ * 用户认证授权
+ * @param authentication 认证类
+ */
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ // 获取认证的用户名 & 密码
+ String userName = authentication.getName();
+ String password = authentication.getCredentials().toString();
+
+ SysUserEntity userEntity = customAuthenticationProvider.sysUserService.getSysUserByUserName(userName);
+
+ // 检查用户是否存在
+ if(userEntity == null){
+ throw new BadCredentialsException("user don't exist");
+ }
+
+ // 检查用户是否激活
+ if(userEntity.getActiveFlag() != 0){
+ throw new DisabledException("user not activated");
+ }
+
+ //检查用户状态是否正常
+ if(userEntity.getStatusCode() != 0){
+ throw new DisabledException("user state exception");
+ }
+
+ // 认证逻辑
+ String encryptPassword = encrypt256(password + userEntity.getSalt());
+ if (encryptPassword.equals(userEntity.getPassword())) {
+ // 设置权限列表
+ ArrayList permissions = new ArrayList<>();
+ List permissionList = customAuthenticationProvider.sysAuthorityService.
+ getSysAuthorityListByUserName(userName);
+ for(SysAuthorityEntity sysAuthorityEntity : permissionList) {
+ permissions.add(new CustomGrantedAuthority(sysAuthorityEntity.getAuthorityName()));
+ }
+ // 生成令牌
+ return new UsernamePasswordAuthenticationToken(userName, encryptPassword, permissions);
+ }
+ else {
+ throw new BadCredentialsException("user password error");
+ }
+ }
+
+ /**
+ * 是否可以提供输入类型的认证服务
+ * @param authentication 认证类
+ */
+ @Override
+ public boolean supports(Class> authentication) {
+ return authentication.equals(UsernamePasswordAuthenticationToken.class);
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/account/CustomGrantedAuthority.java b/src/main/java/com/xkrs/microservice/common/account/CustomGrantedAuthority.java
new file mode 100644
index 0000000..6e1d18e
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/account/CustomGrantedAuthority.java
@@ -0,0 +1,25 @@
+package com.xkrs.microservice.common.account;
+
+import org.springframework.security.core.GrantedAuthority;
+
+/**
+ * 权限认证服务
+ * @author tajochen
+ */
+public class CustomGrantedAuthority implements GrantedAuthority {
+
+ private String authority;
+
+ public CustomGrantedAuthority(String authority) {
+ this.authority = authority;
+ }
+
+ public void setAuthority(String authority) {
+ this.authority = authority;
+ }
+
+ @Override
+ public String getAuthority() {
+ return this.authority;
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/account/JwtAuthenticationFilter.java b/src/main/java/com/xkrs/microservice/common/account/JwtAuthenticationFilter.java
new file mode 100644
index 0000000..9d1d8d2
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/account/JwtAuthenticationFilter.java
@@ -0,0 +1,28 @@
+package com.xkrs.microservice.common.account;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * 拦截所有需要JWT的请求,然后调用TokenAuthenticationService类的静态方法去做JWT验证
+ * @author tajochen
+ */
+public class JwtAuthenticationFilter extends GenericFilterBean {
+
+ @Override
+ public void doFilter(ServletRequest request,
+ ServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+ Authentication authentication = TokenAuthenticationProvider.inspectAuthentication((HttpServletRequest)request);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ filterChain.doFilter(request,response);
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/account/JwtLoginFilter.java b/src/main/java/com/xkrs/microservice/common/account/JwtLoginFilter.java
new file mode 100644
index 0000000..2613b9b
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/account/JwtLoginFilter.java
@@ -0,0 +1,146 @@
+package com.xkrs.microservice.common.account;
+
+import com.xkrs.microservice.common.encapsulation.PromptMessageEnum;
+import com.xkrs.microservice.service.SysUserService;
+import com.xkrs.microservice.util.IpUtil;
+import com.xkrs.microservice.common.encapsulation.OutputEncapsulation;
+import nl.basjes.parse.useragent.UserAgent;
+import nl.basjes.parse.useragent.UserAgentAnalyzer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import javax.annotation.Resource;
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.util.Locale;
+
+/**
+ * jwt登录过滤器
+ * @author tajochen
+ */
+public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {
+
+ private static final Logger logger = LoggerFactory.getLogger(JwtLoginFilter.class);
+
+
+ @Resource
+ private SysUserService sysUserService;
+
+ public JwtLoginFilter(String url, AuthenticationManager authManager) {
+ super(new AntPathRequestMatcher(url));
+ setAuthenticationManager(authManager);
+ }
+
+ /**
+ * 登录时验证
+ * @param req 请求
+ * @param res 响应
+ */
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) {
+ try {
+ req.setCharacterEncoding("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ logger.error(String.valueOf(e));
+ }
+ res.setHeader("Access-Control-Allow-Origin","*");
+ res.setHeader("Access-Control-Allow-Credentials", "false");
+ AccountCredentials cred = new AccountCredentials();
+ //获取表单数据
+ String userName = req.getParameter("userName");
+ String password = req.getParameter("password");
+ String rememberMe = req.getParameter("remember");
+ //如果用户名密码为空
+ if(userName == null||password == null|| userName.trim().isEmpty()||password.trim().isEmpty()){
+ throw new BadCredentialsException("user or password is null");
+ }
+ if(rememberMe == null||rememberMe.isEmpty()){
+ rememberMe = "false";
+ }
+ cred.setUserName(userName.trim());
+ cred.setPassword(password.trim());
+ // 返回一个验证令牌
+ return getAuthenticationManager().authenticate(
+ new UsernamePasswordAuthenticationToken(
+ cred.getUserName(),
+ cred.getPassword()
+ )
+ );
+ }
+
+ /**
+ * 验证成功后调用
+ * @param req 请求
+ * @param response 响应
+ * @param chain 过滤器声明
+ * @param auth 认证
+ */
+ @Override
+ protected void successfulAuthentication(
+ HttpServletRequest req, HttpServletResponse response, FilterChain chain, Authentication auth) {
+ if(sysUserService==null){
+ ServletContext servletContext = req.getServletContext();
+ WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
+ assert webApplicationContext != null;
+ sysUserService = webApplicationContext.getBean(SysUserService.class);
+ }
+ UserAgentAnalyzer uaa = UserAgentAnalyzer
+ .newBuilder()
+ .hideMatcherLoadStats()
+ .withCache(5000)
+ .build();
+ UserAgent agent = uaa.parse(req.getHeader("User-Agent"));
+ System.out.println("获取 UA 信息:");
+ for (String fieldName: agent.getAvailableFieldNamesSorted()) {
+ System.out.println(fieldName + " = " + agent.getValue(fieldName));
+ }
+ //更新用户登录信息
+ sysUserService.updateSysUserLogin(auth.getName(), IpUtil.getIpAddr(req));
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.setHeader("Access-Control-Allow-Credentials", "false");
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ TokenAuthenticationProvider.createAuthentication(response, auth.getName(),auth.getAuthorities());
+ }
+
+ /**
+ * 验证失败后调用
+ * @param request 请求
+ * @param response 响应
+ * @param failed 失败
+ */
+ @Override
+ protected void unsuccessfulAuthentication(HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException failed) {
+ Locale locale = LocaleContextHolder.getLocale();
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.setHeader("Access-Control-Allow-Credentials", "false");
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ // 将 JWT 写入 body
+ PrintWriter out = null;
+ try {
+ out = response.getWriter();
+ } catch (IOException e) {
+ e.printStackTrace();
+ logger.warn(String.valueOf(e));
+ }
+ assert out != null;
+ out.append(OutputEncapsulation.outputEncapsulationObject(PromptMessageEnum.DATA_WRONG, failed.getLocalizedMessage(), locale));
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/account/TokenAuthenticationProvider.java b/src/main/java/com/xkrs/microservice/common/account/TokenAuthenticationProvider.java
new file mode 100644
index 0000000..de73851
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/account/TokenAuthenticationProvider.java
@@ -0,0 +1,125 @@
+package com.xkrs.microservice.common.account;
+
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.Claim;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.xkrs.microservice.common.encapsulation.PromptMessageEnum;
+import com.xkrs.microservice.common.encapsulation.OutputEncapsulation;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.*;
+
+/**
+ * token认证服务
+ * @author tajochen
+ */
+public class TokenAuthenticationProvider {
+
+ private static final Logger logger = LoggerFactory.getLogger(TokenAuthenticationProvider.class);
+
+ /**
+ * Token前缀
+ */
+ static public final String TOKEN_PREFIX = "Bearer ";
+
+ /**
+ * 过期时间6小时
+ */
+ static public final long EXPIRATIONTIME = 21_600_000;
+
+ /**
+ * 加密密钥
+ */
+ static public final String SECRET_KEY = "J928A503V4wmF05Ka0HWN2dmW11hTfwqU97sR9E4DpF82B52542033Ok785x8173";
+
+ /**
+ * 存放Token的Header Key
+ */
+ static final String HEADER_STRING = "Authorization";
+
+ /**
+ * JWT生成方法
+ * @param response 响应
+ * @param userName 用户名
+ * @param authorities 认证
+ */
+ static void createAuthentication(HttpServletResponse response, String userName,
+ Collection extends GrantedAuthority > authorities) {
+
+ Locale locale = new Locale("zh", "CN");
+ StringBuilder auths = new StringBuilder();
+ String authsList = "";
+ for(GrantedAuthority r : authorities) {
+ auths.append(",").append(r.getAuthority());
+ }
+ authsList = auths.toString();
+ if(authsList.length()>1){
+ authsList=authsList.substring(1);
+ } else {
+ logger.warn(userName +" has no permission!");
+ }
+ // 加密算法
+ Algorithm algorithm = Algorithm.HMAC384(SECRET_KEY);
+ // 生成JWT
+ String jwt = JWT.create().withSubject(userName).
+ withIssuer("https://www.star-rising.com").
+ withAudience(userName).
+ withClaim("auths", authsList).
+ withNotBefore(new Date(System.currentTimeMillis())).
+ withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATIONTIME)).
+ sign(algorithm);
+ // 将 JWT 写入 body
+ PrintWriter out = null;
+ response.setStatus(HttpServletResponse.SC_OK);
+ try {
+ out = response.getWriter();
+ out.append(OutputEncapsulation.outputEncapsulationObject(PromptMessageEnum.SUCCESS, jwt, locale));
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * JWT验证方法
+ * @param request 请求体
+ */
+ static Authentication inspectAuthentication(HttpServletRequest request) {
+ // 从Header中拿到token
+ String token = request.getHeader(HEADER_STRING);
+ if (token != null) {
+ try {
+ String realToken = token.replace(TOKEN_PREFIX, "");
+ Algorithm algorithm = Algorithm.HMAC384(SECRET_KEY);
+ JWTVerifier verifier = JWT.require(algorithm)
+ .withIssuer("https://www.star-rising.com")
+ .build();
+ DecodedJWT jwt = verifier.verify(realToken);
+ // 获取用户名
+ String userName = jwt.getSubject();
+ // 获取权限
+ Claim claim = jwt.getClaim("auths");
+ List authorities = AuthorityUtils.commaSeparatedStringToAuthorityList( claim.asString());
+ return new UsernamePasswordAuthenticationToken(userName, null, authorities);
+ } catch(Exception e) {
+ // 数据域丢失或者没有值
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/config/ConfigConstant.java b/src/main/java/com/xkrs/microservice/common/config/ConfigConstant.java
new file mode 100644
index 0000000..48fd05c
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/config/ConfigConstant.java
@@ -0,0 +1,36 @@
+package com.xkrs.microservice.common.config;
+
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring 静态工具类里读取配置文件
+ * @author tajochen
+ */
+@Component
+public class ConfigConstant {
+
+ @Resource
+ private Environment env;
+
+ @PostConstruct
+ public void readConfig() throws Exception {
+ String prefix = "my.";
+ Field[] fields = ConfigConstant.class.getFields();
+ for(Field field : fields ){
+ field.set(null, getProperty(prefix + field.getName()));
+ }
+ }
+
+ private String getProperty(String key) {
+ return new String(Objects.requireNonNull(env.getProperty(key)).getBytes(StandardCharsets.ISO_8859_1),
+ StandardCharsets.UTF_8);
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/config/CorsConfig.java b/src/main/java/com/xkrs/microservice/common/config/CorsConfig.java
new file mode 100644
index 0000000..f5f908b
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/config/CorsConfig.java
@@ -0,0 +1,32 @@
+package com.xkrs.microservice.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+/**
+ * 跨域配置
+ * @author tajochen
+ */
+public class CorsConfig {
+
+ private CorsConfiguration buildConfig() {
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ // 允许任何域名
+ corsConfiguration.addAllowedOrigin("*");
+ // 允许任何头
+ corsConfiguration.addAllowedHeader("*");
+ // 允许任何方法
+ corsConfiguration.addAllowedMethod("*");
+ return corsConfiguration;
+ }
+
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ // 注册
+ source.registerCorsConfiguration("/**", buildConfig());
+ return new CorsFilter(source);
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/config/MetricsRepositoryMethodConfig.java b/src/main/java/com/xkrs/microservice/common/config/MetricsRepositoryMethodConfig.java
new file mode 100644
index 0000000..73c0786
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/config/MetricsRepositoryMethodConfig.java
@@ -0,0 +1,18 @@
+package com.xkrs.microservice.common.config;
+
+import io.micrometer.prometheus.PrometheusMeterRegistry;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Prometheus 度量设置
+ * @author tajochen
+ */
+public class MetricsRepositoryMethodConfig {
+
+ @Bean
+ InitializingBean forcePrometheusPostProcessor(BeanPostProcessor meterRegistryPostProcessor, PrometheusMeterRegistry registry) {
+ return () -> meterRegistryPostProcessor.postProcessAfterInitialization(registry, "");
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/config/MvcConfig.java b/src/main/java/com/xkrs/microservice/common/config/MvcConfig.java
new file mode 100644
index 0000000..e3b4618
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/config/MvcConfig.java
@@ -0,0 +1,37 @@
+package com.xkrs.microservice.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * WebMVC配置
+ * @author Tajochen
+ */
+@Configuration
+public class MvcConfig implements WebMvcConfigurer {
+
+ /**
+ * 放行跨域请求
+ */
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*")
+ .allowedMethods("*")
+ .allowedHeaders("*");
+ }
+
+ /**
+ * 定时任务线程池更改,防止多个任务并行
+ */
+ @Bean
+ public TaskScheduler taskScheduler() {
+ final ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
+ scheduler.setPoolSize(5);
+ return scheduler;
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/config/RedisCacheAutoConfiguration.java b/src/main/java/com/xkrs/microservice/common/config/RedisCacheAutoConfiguration.java
new file mode 100644
index 0000000..e1980d8
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/config/RedisCacheAutoConfiguration.java
@@ -0,0 +1,30 @@
+package com.xkrs.microservice.common.config;
+
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.io.Serializable;
+
+/**
+ * Redis 缓存自动配置
+ * @author tajochen
+ */
+@Configuration
+@AutoConfigureAfter(RedisAutoConfiguration.class)
+public class RedisCacheAutoConfiguration {
+
+ @Bean
+ public RedisTemplate redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setKeySerializer(new StringRedisSerializer());
+ template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+ template.setConnectionFactory(redisConnectionFactory);
+ return template;
+ }
+}
diff --git a/src/main/java/com/xkrs/microservice/common/config/RedisConfig.java b/src/main/java/com/xkrs/microservice/common/config/RedisConfig.java
new file mode 100644
index 0000000..61793ab
--- /dev/null
+++ b/src/main/java/com/xkrs/microservice/common/config/RedisConfig.java
@@ -0,0 +1,196 @@
+package com.xkrs.microservice.common.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.CacheErrorHandler;
+import org.springframework.cache.interceptor.CacheResolver;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+import org.springframework.data.redis.serializer.*;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.time.Duration;
+
+/**
+ * redis配置
+ * @author tajochen
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig extends CachingConfigurerSupport{
+
+ private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);
+
+ @Resource
+ private LettuceConnectionFactory lettuceConnectionFactory;
+
+ private static final Duration TIME_TO_LIVE = Duration.ofSeconds(3600*6);
+
+ @Bean
+ @Override
+ public KeyGenerator keyGenerator() {
+
+ // 设置自动key的生成规则,配置spring boot的注解,进行方法级别的缓存
+ return (target, method, params) -> {
+ StringBuilder sb = new StringBuilder();
+ sb.append(target.getClass().getName());
+ sb.append(":");
+ sb.append(method.getName());
+ for (Object obj : params) {
+ sb.append(":").append(obj);
+ }
+ // logger.info("自动生成Redis Key -> [{}]", rsToUse);
+ return String.valueOf(sb);
+ };
+ }
+
+ @Bean
+ @Override
+ public CacheManager cacheManager() {
+ // 关键点,spring cache的注解使用的序列化都从这来,没有这个配置的话使用的jdk自己的序列化
+ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
+ //key序列化方式
+ .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
+ //value序列化方式
+ .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
+ .disableCachingNullValues()
+ .entryTtl(TIME_TO_LIVE);
+
+ RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
+ .fromConnectionFactory(lettuceConnectionFactory)
+ .cacheDefaults(config)
+ .transactionAware();
+
+ return builder.build();
+ }
+
+ @Bean
+ public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
+ RedisMessageListenerContainer container = new RedisMessageListenerContainer();
+ container.setConnectionFactory(connectionFactory);
+ // 根据需要添加其他配置,例如设置消息监听器
+ return container;
+ }
+
+
+ /**
+ * RedisTemplate配置 在单独使用redisTemplate的时候 重新定义序列化方式
+ */
+ @Bean(name = "redisTemplate")
+ public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
+ // 设置序列化
+ Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+ ObjectMapper om = new ObjectMapper();
+ // 配置null值序列化成空字符串
+ om.getSerializerProvider().setNullValueSerializer(new JsonSerializer<>() {
+ @Override
+ public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
+ jsonGenerator.writeString("");
+ }
+ });
+ // 解决jackson无法反序列化LocalDateTime的问题,引入jsr310标准
+ JavaTimeModule javaTimeModule = new JavaTimeModule();
+ om.registerModule(javaTimeModule);
+ om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ // 其他设置
+ om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+ om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
+ ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+ jackson2JsonRedisSerializer.setObjectMapper(om);
+ // 配置redisTemplate
+ RedisTemplate redisTemplate = new RedisTemplate<>();
+ redisTemplate.setConnectionFactory(lettuceConnectionFactory);
+ RedisSerializer> stringSerializer = new StringRedisSerializer();
+ redisTemplate.setKeySerializer(stringSerializer);
+ redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+ redisTemplate.setHashKeySerializer(stringSerializer);
+ redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
+ redisTemplate.afterPropertiesSet();
+ return redisTemplate;
+ }
+
+ private RedisSerializer keySerializer() {
+ return new StringRedisSerializer();
+ }
+
+ private RedisSerializer