# Conflicts: # .gitignore # dq-framework-common/target/classes/com/daqing/framework/model/response/CommonCode.class # dq-govern-gateway/src/main/resources/application.ymlmaster
commit
827f6ee24d
55 changed files with 1435 additions and 541 deletions
@ -0,0 +1,95 @@ |
||||
### Java template |
||||
*.class |
||||
|
||||
# Mobile Tools for Java (J2ME) |
||||
.mtj.tmp/ |
||||
|
||||
# Package Files # |
||||
*.jar |
||||
*.war |
||||
*.ear |
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml |
||||
hs_err_pid* |
||||
### JetBrains template |
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm |
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 |
||||
|
||||
# User-specific stuff: |
||||
.idea/workspace.xml |
||||
.idea/tasks.xml |
||||
.idea/dictionaries |
||||
.idea/vcs.xml |
||||
.idea/jsLibraryMappings.xml |
||||
|
||||
# Sensitive or high-churn files: |
||||
.idea/dataSources.ids |
||||
.idea/dataSources.xml |
||||
.idea/dataSources.local.xml |
||||
.idea/sqlDataSources.xml |
||||
.idea/dynamic.xml |
||||
.idea/uiDesigner.xml |
||||
|
||||
# Gradle: |
||||
.idea/gradle.xml |
||||
.idea/ |
||||
|
||||
# Mongo Explorer plugin: |
||||
.idea/mongoSettings.xml |
||||
|
||||
## File-based project format: |
||||
*.iws |
||||
|
||||
## Plugin-specific files: |
||||
|
||||
# IntelliJ |
||||
/out/ |
||||
|
||||
# mpeltonen/sbt-idea plugin |
||||
.idea_modules/ |
||||
|
||||
# JIRA plugin |
||||
atlassian-ide-plugin.xml |
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ) |
||||
com_crashlytics_export_strings.xml |
||||
crashlytics.properties |
||||
crashlytics-build.properties |
||||
fabric.properties |
||||
### Windows template |
||||
# Windows image file caches |
||||
Thumbs.db |
||||
ehthumbs.db |
||||
|
||||
# Folder config file |
||||
Desktop.ini |
||||
|
||||
# Recycle Bin used on file shares |
||||
$RECYCLE.BIN/ |
||||
|
||||
# Windows Installer files |
||||
*.cab |
||||
*.msi |
||||
*.msm |
||||
*.msp |
||||
|
||||
# Windows shortcuts |
||||
*.lnk |
||||
### Maven template |
||||
target/ |
||||
pom.xml.tag |
||||
pom.xml.releaseBackup |
||||
pom.xml.versionsBackup |
||||
pom.xml.next |
||||
release.properties |
||||
dependency-reduced-pom.xml |
||||
buildNumber.properties |
||||
.mvn/timing.properties |
||||
# ignore eclipse files |
||||
.project |
||||
.classpath |
||||
.settings |
||||
.metadata |
||||
|
||||
.svn |
||||
|
@ -1,13 +1,13 @@ |
||||
package com.daqing.financial.crauth; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
||||
@SpringBootTest |
||||
class DqFinancialCrmsAuthApplicationTests { |
||||
|
||||
@Test |
||||
void contextLoads() { |
||||
} |
||||
|
||||
} |
||||
//package com.daqing.financial.crauth;
|
||||
//
|
||||
//import org.junit.Test;
|
||||
//import org.springframework.boot.test.context.SpringBootTest;
|
||||
//
|
||||
//@SpringBootTest
|
||||
//class DqFinancialCrmsAuthApplicationTests {
|
||||
//
|
||||
// @Test
|
||||
// void contextLoads() {
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
@ -1,36 +1,36 @@ |
||||
package com.daqing.financial.crms; |
||||
|
||||
import com.daqing.financial.crms.service.impl.CustomerServiceImpl; |
||||
import com.daqing.framework.domain.crms.CustomerEntity; |
||||
import com.daqing.framework.domain.crms.ext.CustomerTO; |
||||
import com.daqing.framework.domain.crms.request.CustomerRequest; |
||||
import com.daqing.framework.utils.PageUtils; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import java.util.List; |
||||
|
||||
@SpringBootTest |
||||
@RunWith(SpringRunner.class) |
||||
public class DqFinancialCrmsApplicationTests { |
||||
|
||||
@Autowired |
||||
private CustomerServiceImpl customerServiceimpl; |
||||
|
||||
CustomerRequest customerRequest = new CustomerRequest(); |
||||
|
||||
@Test |
||||
public void queryListTest(){ |
||||
customerRequest.setCodeOrName("20200909"); |
||||
/* customerRequest.setStartTime("2020-09-07"); |
||||
customerRequest.setEndTime("2020-09-10");*/ |
||||
customerRequest.setCustomerType(1); |
||||
customerRequest.setCreateTime(12); |
||||
PageUtils list = customerServiceimpl.queryList(1, 10, customerRequest); |
||||
List<CustomerTO> list1 = (List<CustomerTO>) list.getList(); |
||||
list1.forEach(customerEntity -> System.out.println(customerEntity)); |
||||
} |
||||
} |
||||
//package com.daqing.financial.crms;
|
||||
//
|
||||
//import com.daqing.financial.crms.service.impl.CustomerServiceImpl;
|
||||
//import com.daqing.framework.domain.crms.CustomerEntity;
|
||||
//import com.daqing.framework.domain.crms.ext.CustomerTO;
|
||||
//import com.daqing.framework.domain.crms.request.CustomerRequest;
|
||||
//import com.daqing.framework.utils.PageUtils;
|
||||
//import org.junit.Test;
|
||||
//import org.junit.runner.RunWith;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.boot.test.context.SpringBootTest;
|
||||
//import org.springframework.test.context.junit4.SpringRunner;
|
||||
//
|
||||
//import java.util.List;
|
||||
//
|
||||
//@SpringBootTest
|
||||
//@RunWith(SpringRunner.class)
|
||||
//public class DqFinancialCrmsApplicationTests {
|
||||
//
|
||||
// @Autowired
|
||||
// private CustomerServiceImpl customerServiceimpl;
|
||||
//
|
||||
// CustomerRequest customerRequest = new CustomerRequest();
|
||||
//
|
||||
// @Test
|
||||
// public void queryListTest(){
|
||||
// customerRequest.setCodeOrName("20200909");
|
||||
// /* customerRequest.setStartTime("2020-09-07");
|
||||
// customerRequest.setEndTime("2020-09-10");*/
|
||||
// customerRequest.setCustomerType(1);
|
||||
// customerRequest.setCreateTime(12);
|
||||
// PageUtils list = customerServiceimpl.queryList(1, 10, customerRequest);
|
||||
// List<CustomerTO> list1 = (List<CustomerTO>) list.getList();
|
||||
// list1.forEach(customerEntity -> System.out.println(customerEntity));
|
||||
// }
|
||||
//}
|
||||
|
@ -1,76 +0,0 @@ |
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-parent</artifactId> |
||||
<version>2.1.8.RELEASE</version> |
||||
<relativePath/> <!-- lookup parent from repository --> |
||||
</parent> |
||||
<groupId>com.daqing.financial</groupId> |
||||
<artifactId>dq-financial-guarantee</artifactId> |
||||
<version>0.0.1-SNAPSHOT</version> |
||||
<name>dq-financial-guarantee</name> |
||||
<description>大庆智慧金融平台-担保业务服务</description> |
||||
|
||||
<properties> |
||||
<java.version>1.8</java.version> |
||||
<spring-cloud.version>Greenwich.SR3</spring-cloud.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
<!-- <dependency> |
||||
<groupId>com.daqing.framework</groupId> |
||||
<artifactId>dq-framework-common</artifactId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
</dependency>--> |
||||
<dependency> |
||||
<groupId>com.daqing.framework</groupId> |
||||
<artifactId>dq-framework-model</artifactId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
</dependency> |
||||
<!-- <dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-web</artifactId> |
||||
</dependency>--> |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-starter-openfeign</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-test</artifactId> |
||||
<scope>test</scope> |
||||
<exclusions> |
||||
<exclusion> |
||||
<groupId>org.junit.vintage</groupId> |
||||
<artifactId>junit-vintage-engine</artifactId> |
||||
</exclusion> |
||||
</exclusions> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
<dependencyManagement> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-dependencies</artifactId> |
||||
<version>${spring-cloud.version}</version> |
||||
<type>pom</type> |
||||
<scope>import</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</dependencyManagement> |
||||
|
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
|
||||
</project> |
@ -1,13 +0,0 @@ |
||||
package com.daqing.financial.guarantee; |
||||
|
||||
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
||||
@SpringBootApplication |
||||
public class DqFinancialGuaranteeApplication { |
||||
|
||||
public static void main(String[] args) { |
||||
SpringApplication.run(DqFinancialGuaranteeApplication.class, args); |
||||
} |
||||
|
||||
} |
@ -1,47 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<configuration> |
||||
<!--定义日志文件的存储地址,使用绝对路径--> |
||||
<property name="LOG_HOME" value="d:/logs/daqing/guarantee"/> |
||||
|
||||
<!-- Console 输出设置 --> |
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> |
||||
<encoder> |
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> |
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
<charset>utf8</charset> |
||||
</encoder> |
||||
</appender> |
||||
|
||||
<!-- 按照每天生成日志文件 --> |
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||
<!--日志文件输出的文件名--> |
||||
<fileNamePattern>${LOG_HOME}/guarantee.%d{yyyy-MM-dd}.log</fileNamePattern> |
||||
</rollingPolicy> |
||||
<encoder> |
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
</encoder> |
||||
</appender> |
||||
|
||||
<!-- 异步输出 --> |
||||
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> |
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> |
||||
<discardingThreshold>0</discardingThreshold> |
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> |
||||
<queueSize>512</queueSize> |
||||
<!-- 添加附加的appender,最多只能添加一个 --> |
||||
<appender-ref ref="FILE"/> |
||||
</appender> |
||||
|
||||
|
||||
<logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false"> |
||||
<appender-ref ref="CONSOLE"/> |
||||
</logger> |
||||
<logger name="org.springframework.boot" level="DEBUG"/> |
||||
<root level="info"> |
||||
<!--<appender-ref ref="ASYNC"/>--> |
||||
<appender-ref ref="FILE"/> |
||||
<appender-ref ref="CONSOLE"/> |
||||
</root> |
||||
</configuration> |
@ -1,13 +0,0 @@ |
||||
package com.daqing.financial.guarantee; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
||||
@SpringBootTest |
||||
class DqFinancialGuaranteeApplicationTests { |
||||
|
||||
@Test |
||||
void contextLoads() { |
||||
} |
||||
|
||||
} |
@ -0,0 +1,64 @@ |
||||
package com.daqing.financial.hrauth; |
||||
|
||||
import org.springframework.beans.factory.DisposableBean; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ApplicationContextAware; |
||||
import org.springframework.context.annotation.Lazy; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
@Component |
||||
@Lazy(false) |
||||
public class SpringContextHolder implements ApplicationContextAware, DisposableBean { |
||||
|
||||
private static ApplicationContext applicationContext = null; |
||||
|
||||
|
||||
/** |
||||
* 取得存储在静态变量中的ApplicationContext. |
||||
*/ |
||||
public static ApplicationContext getApplicationContext() { |
||||
return applicationContext; |
||||
} |
||||
|
||||
/** |
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <T> T getBean(String name) { |
||||
return (T) applicationContext.getBean(name); |
||||
} |
||||
|
||||
/** |
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. |
||||
*/ |
||||
public static <T> T getBean(Class<T> requiredType) { |
||||
return applicationContext.getBean(requiredType); |
||||
} |
||||
|
||||
public static <T> T getBean(String name, Class<T> clazz) { |
||||
return getApplicationContext().getBean(name, clazz); |
||||
} |
||||
|
||||
/** |
||||
* 清除SpringContextHolder中的ApplicationContext为Null. |
||||
*/ |
||||
public static void clearHolder() { |
||||
applicationContext = null; |
||||
} |
||||
|
||||
/** |
||||
* 实现ApplicationContextAware接口, 注入Context到静态变量中. |
||||
*/ |
||||
@Override |
||||
public void setApplicationContext(ApplicationContext appContext) { |
||||
applicationContext = appContext; |
||||
} |
||||
|
||||
/** |
||||
* 实现DisposableBean接口, 在Context关闭时清理静态变量. |
||||
*/ |
||||
@Override |
||||
public void destroy() { |
||||
SpringContextHolder.clearHolder(); |
||||
} |
||||
} |
@ -0,0 +1,109 @@ |
||||
//package com.daqing.financial.hrauth.config;
|
||||
//
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.http.HttpMethod;
|
||||
//import org.springframework.security.authentication.AuthenticationManager;
|
||||
//import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
//import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
||||
//import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
|
||||
//import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||
//import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
//import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||
//import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||
//import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
|
||||
//import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
|
||||
//import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
||||
//import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
|
||||
//import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
//
|
||||
///**
|
||||
// * 配置OAuth2.0授权服务器
|
||||
// *
|
||||
// * @auther River
|
||||
// * @date 2020/9/21 17:49
|
||||
// */
|
||||
//@Configuration
|
||||
//@EnableAuthorizationServer
|
||||
//public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
|
||||
//
|
||||
// @Autowired
|
||||
// private TokenStore tokenStore;
|
||||
//
|
||||
// @Autowired
|
||||
// private ClientDetailsService clientDetailsService;
|
||||
//
|
||||
// @Autowired
|
||||
// private AuthenticationManager authenticationManager;
|
||||
//
|
||||
// @Autowired
|
||||
// private AuthorizationCodeServices authorizationCodeServices;
|
||||
// @Autowired
|
||||
// public PasswordEncoder passwordEncoder;
|
||||
//
|
||||
// /**
|
||||
// * 配置令牌的安全约束(允许哪些请求访问)
|
||||
// */
|
||||
// @Override
|
||||
// public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
|
||||
// security
|
||||
// .tokenKeyAccess("permitAll()") // 公开提供公钥加密的端点(就是使用jwt令牌的时候需要的)
|
||||
// .checkTokenAccess("permitAll()") // 校验令牌
|
||||
// .allowFormAuthenticationForClients(); //允许表单提交,允许客户端访问 OAuth2 授权接口,否则请求 token 会返回 401。
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 配置支持哪些客户端访问
|
||||
// */
|
||||
// @Override
|
||||
// public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
|
||||
// clients.inMemory()
|
||||
// .withClient("order-client")
|
||||
// .secret(passwordEncoder.encode("order-secret-8888"))
|
||||
// .authorizedGrantTypes("refresh_token", "authorization_code", "password")
|
||||
// .accessTokenValiditySeconds(3600)
|
||||
// .scopes("all")
|
||||
// .and()
|
||||
// .withClient("user-client")
|
||||
// .secret(passwordEncoder.encode("user-secret-8888"))
|
||||
// .authorizedGrantTypes("refresh_token", "authorization_code", "password")
|
||||
// .accessTokenValiditySeconds(3600)
|
||||
// .scopes("all");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 配置令牌(token)的访问端点
|
||||
// */
|
||||
// @Override
|
||||
// public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
|
||||
// endpoints
|
||||
// .authenticationManager(authenticationManager) // 密码模式需要
|
||||
// .authorizationCodeServices(authorizationCodeServices) // 授权码模式需要
|
||||
// .tokenServices(tokenServices()) // 令牌的管理方式
|
||||
// .allowedTokenEndpointRequestMethods(HttpMethod.POST); // 允许的请求方式
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 令牌服务
|
||||
// */
|
||||
// @Bean
|
||||
// public AuthorizationServerTokenServices tokenServices(){
|
||||
// DefaultTokenServices service = new DefaultTokenServices();
|
||||
// service.setClientDetailsService(clientDetailsService); // 客户端信息的服务
|
||||
// service.setSupportRefreshToken(true); // 是否产生刷新令牌
|
||||
// service.setTokenStore(tokenStore); // 令牌的存储策略
|
||||
// service.setAccessTokenValiditySeconds(7200); // 令牌有效期
|
||||
// service.setRefreshTokenValiditySeconds(259200); // 刷新令牌有效期
|
||||
// return service;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 授权码服务(设置授权码模式的授权码如何存取,暂时在内存,后期在数据库)
|
||||
// */
|
||||
// @Bean
|
||||
// public AuthorizationCodeServices authorizationCodeServices(){
|
||||
//
|
||||
// return new InMemoryAuthorizationCodeServices();
|
||||
// }
|
||||
//}
|
@ -0,0 +1,67 @@ |
||||
//package com.daqing.financial.hrauth.config;
|
||||
//
|
||||
//import com.daqing.financial.hrauth.service.impl.UserLoginServiceImpl;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.security.authentication.AuthenticationManager;
|
||||
//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
//import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
//import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
//
|
||||
///**
|
||||
// * @auther River
|
||||
// * @date 2020/9/22 10:26
|
||||
// */
|
||||
//@Configuration
|
||||
//@EnableWebSecurity // 开启security
|
||||
//public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
//
|
||||
// /**
|
||||
// * 不能直接new对象,否则会在注入之前被拦截器拦截
|
||||
// */
|
||||
// @Bean
|
||||
// public UserLoginServiceImpl customerLoginService(){
|
||||
//
|
||||
// return new UserLoginServiceImpl();
|
||||
// }
|
||||
//
|
||||
// // 定义用户信息(查询用户信息),security帮助我们查询,但是需要告诉他如何去查询
|
||||
// @Override
|
||||
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
//
|
||||
// auth.userDetailsService(customerLoginService());
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // 密码编码器,比对密码的方式
|
||||
// @Bean
|
||||
// public PasswordEncoder passwordEncoder(){
|
||||
//
|
||||
// return new BCryptPasswordEncoder();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 认证管理器
|
||||
// */
|
||||
// @Override
|
||||
// @Bean
|
||||
// public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
//
|
||||
// return super.authenticationManagerBean();
|
||||
// }
|
||||
//
|
||||
// // 安全拦截机制
|
||||
// @Override
|
||||
// protected void configure(HttpSecurity http) throws Exception {
|
||||
// http.authorizeRequests()
|
||||
// .antMatchers("/*").authenticated() // 该路径下所有请求都会被拦截
|
||||
// .anyRequest().permitAll() // 其余的请求可以通过
|
||||
// .and()
|
||||
// .formLogin() // 允许表单认证
|
||||
// .successForwardUrl("/customerLogin/loginSuccess"); // 登录成功跳转路径
|
||||
// }
|
||||
//}
|
||||
//
|
@ -0,0 +1,22 @@ |
||||
//package com.daqing.financial.hrauth.config;
|
||||
//
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
//import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
|
||||
//
|
||||
///**
|
||||
// * 令牌配置类
|
||||
// *
|
||||
// * @auther River
|
||||
// * @date 2020/9/22 9:54
|
||||
// */
|
||||
//@Configuration
|
||||
//public class TokenConfig {
|
||||
//
|
||||
// @Bean
|
||||
// public TokenStore tokenStore(){
|
||||
// // 内存生成,普通令牌
|
||||
// return new InMemoryTokenStore();
|
||||
// }
|
||||
//}
|
@ -0,0 +1,61 @@ |
||||
package com.daqing.financial.hrauth.controller; |
||||
|
||||
import com.daqing.financial.hrauth.service.UserLoginService; |
||||
import com.daqing.framework.domain.hrms.request.LoginRequest; |
||||
import com.daqing.framework.domain.hrms.request.UserLoginRequest; |
||||
import com.daqing.framework.model.response.ResponseResult; |
||||
import io.swagger.annotations.Api; |
||||
import io.swagger.annotations.ApiOperation; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.web.bind.annotation.*; |
||||
|
||||
import javax.validation.Valid; |
||||
|
||||
|
||||
/** |
||||
* @auther River |
||||
* @date 2020/9/22 15:27 |
||||
*/ |
||||
@RestController |
||||
@RequestMapping("/hrms/auth/userlogin") |
||||
@Api(tags = {"登录"}) |
||||
public class UserLoginController { |
||||
|
||||
@Autowired |
||||
private UserLoginService userLoginService; |
||||
|
||||
@PostMapping("/loginSuccess") |
||||
public String loginSuccess(){ |
||||
|
||||
return "success"; |
||||
} |
||||
|
||||
@GetMapping("/test") |
||||
public String test(){ |
||||
|
||||
return "Hello"; |
||||
} |
||||
|
||||
@PostMapping("/getBackPwd") |
||||
public ResponseResult getBackPwd(@RequestBody @Valid UserLoginRequest user){ |
||||
boolean result = userLoginService.getBackPwd(user); |
||||
return result ? ResponseResult.SUCCESS() : ResponseResult.FAIL(); |
||||
} |
||||
|
||||
@PostMapping(value = "/login") |
||||
@ApiOperation(value = "用户登录") |
||||
public ResponseResult login( |
||||
@RequestBody LoginRequest loginRequest |
||||
/* @RequestParam("password") String password, @RequestParam("phone") String phone, |
||||
@RequestParam("type")int type, @RequestParam("wechatId") String wechatId, |
||||
@RequestParam("tenDayEffective") int tenDayEffective*/ |
||||
){ |
||||
/* LoginRequest loginRequest = new LoginRequest(); |
||||
loginRequest.setTenDayEffective(tenDayEffective); |
||||
loginRequest.setType(type); |
||||
loginRequest.setWechatId(wechatId); |
||||
loginRequest.setPassword(password); |
||||
loginRequest.setPhone(phone);*/ |
||||
return userLoginService.login(loginRequest); |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
package com.daqing.financial.hrauth.dao; |
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
import com.daqing.framework.domain.hrms.UserEntity; |
||||
import com.daqing.framework.domain.hrms.request.LoginRequest; |
||||
import org.apache.ibatis.annotations.Mapper; |
||||
import org.apache.ibatis.annotations.Param; |
||||
|
||||
/** |
||||
* @auther River |
||||
* @date 2020/9/22 14:55 |
||||
*/ |
||||
@Mapper |
||||
public interface UserLoginDao extends BaseMapper<UserEntity> { |
||||
|
||||
UserEntity getUser(String code); |
||||
int selectCount(String phoneAccount); |
||||
int updatePasswordByPhoneAccount(@Param("phoneAccount") String phoneAccount, @Param("password") String password); |
||||
|
||||
UserEntity login(LoginRequest loginRequest); |
||||
UserEntity selectByPhoneAccount(String phoneAccount); |
||||
} |
@ -0,0 +1,18 @@ |
||||
package com.daqing.financial.hrauth.service; |
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService; |
||||
import com.daqing.framework.domain.hrms.UserEntity; |
||||
import com.daqing.framework.domain.hrms.request.LoginRequest; |
||||
import com.daqing.framework.domain.hrms.request.UserLoginRequest; |
||||
import com.daqing.framework.model.response.ResponseResult; |
||||
|
||||
/** |
||||
* @auther River |
||||
* @date 2020/9/22 15:00 |
||||
*/ |
||||
public interface UserLoginService extends IService<UserEntity> { |
||||
Boolean getBackPwd(UserLoginRequest user); |
||||
|
||||
//登录
|
||||
ResponseResult login(LoginRequest loginRequest); |
||||
} |
@ -0,0 +1,118 @@ |
||||
package com.daqing.financial.hrauth.service.impl; |
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
import com.daqing.financial.hrauth.dao.UserLoginDao; |
||||
import com.daqing.financial.hrauth.service.UserLoginService; |
||||
import com.daqing.financial.hrauth.util.JwtUtil; |
||||
import com.daqing.framework.domain.hrms.UserEntity; |
||||
import com.daqing.framework.domain.hrms.request.LoginRequest; |
||||
import com.daqing.framework.domain.hrms.request.UserLoginRequest; |
||||
import com.daqing.framework.domain.hrms.response.HrmsCode; |
||||
import com.daqing.framework.domain.hrms.response.LoginResponse; |
||||
import com.daqing.framework.exception.ExceptionCast; |
||||
import com.daqing.framework.model.response.CommonCode; |
||||
import com.daqing.framework.model.response.ResponseResult; |
||||
import com.daqing.framework.util.Md5Util; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
import javax.annotation.Resource; |
||||
|
||||
/** |
||||
* @auther River |
||||
* @date 2020/9/22 15:01 |
||||
*/ |
||||
@Service("userLoginService") |
||||
public class UserLoginServiceImpl extends ServiceImpl<UserLoginDao, UserEntity> implements UserLoginService{ |
||||
|
||||
@Resource |
||||
private UserLoginDao userLoginDao; |
||||
|
||||
/* @Autowired |
||||
private OdcProperties properties;*/ |
||||
|
||||
/* @Override |
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { |
||||
UserEntity user = userLoginDao.getUser(username); |
||||
List<SimpleGrantedAuthority> authorities = new ArrayList<>(); |
||||
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); |
||||
System.out.println(user); |
||||
UserDetails userDetails = new User(user.getAccount(),new BCryptPasswordEncoder().encode(user.getPassword()),authorities); |
||||
|
||||
return userDetails; |
||||
}*/ |
||||
|
||||
/** |
||||
* 忘记密码 |
||||
*/ |
||||
@Override |
||||
public Boolean getBackPwd(UserLoginRequest user){ |
||||
//判断重置密码参数是否为空
|
||||
if(StringUtils.isEmpty(user.getPhoneAccount())){ |
||||
ExceptionCast.cast(HrmsCode.PHNOE_ACCOUNT_NOT_EMPTY); |
||||
} |
||||
if(StringUtils.isEmpty(user.getVerifyCode())){ |
||||
ExceptionCast.cast(HrmsCode.VERIFY_CODE_ILLEGAL); |
||||
} |
||||
if(StringUtils.isEmpty(user.getNewPwd())){ |
||||
ExceptionCast.cast(HrmsCode.NEW_PASSWORD_NOT_EMPTY); |
||||
} |
||||
//校验手机账号是否存在
|
||||
/* int count = this.count(new QueryWrapper<UserEntity>() |
||||
.eq("phone_account", user.getPhoneAccount()));*/ |
||||
|
||||
int count = userLoginDao.selectCount(user.getPhoneAccount()); |
||||
if (count == 0) { |
||||
ExceptionCast.cast(HrmsCode.PHNOE_ACCOUNT_NOT_EXIST); |
||||
} |
||||
//根据手机号查询相关信息
|
||||
UserEntity userEntity = baseMapper.selectByPhoneAccount(user.getPhoneAccount()); |
||||
//判断验证码是否匹配
|
||||
String verify = "123456"; |
||||
if(!verify.equals(user.getVerifyCode())){ |
||||
ExceptionCast.cast(HrmsCode.VERIFY_CODE_ILLEGAL); |
||||
} |
||||
|
||||
String newMD5 = Md5Util.md5(user.getNewPwd()+userEntity.getId()); |
||||
//根据手机号码修改密码
|
||||
int i = userLoginDao.updatePasswordByPhoneAccount(user.getPhoneAccount(),newMD5); |
||||
return i > 0; |
||||
} |
||||
|
||||
public ResponseResult login(LoginRequest loginRequest) { |
||||
//判断用户登录方式
|
||||
UserEntity userEntity = baseMapper.login(loginRequest); |
||||
if(loginRequest.getType() == 1){//手机号码登录
|
||||
|
||||
if(userEntity == null){ |
||||
return ResponseResult.FAIL(CommonCode.USER_IS_NOT_EXIST.code(), CommonCode.USER_IS_NOT_EXIST.message()); |
||||
} |
||||
String newPassword = Md5Util.md5(loginRequest.getPassword()+userEntity.getId()); |
||||
if(!newPassword.equals(userEntity.getPassword())){ |
||||
return ResponseResult.FAIL(CommonCode.PASSWORD_IS_ERROR.code(), CommonCode.PASSWORD_IS_ERROR.message()); |
||||
} |
||||
|
||||
|
||||
}else {//微信登录
|
||||
|
||||
} |
||||
|
||||
//登录成功,token生成
|
||||
long times = 84600; |
||||
if(loginRequest.getTenDayEffective() == 1){ |
||||
times = 846000; |
||||
} |
||||
String token = JwtUtil.createJwtToken(userEntity.getId(), times); |
||||
if (true) { |
||||
JwtUtil.removeTokenByUserId(userEntity.getId()); |
||||
} |
||||
JwtUtil.putTokenToRedis(userEntity.getId(), token, times); |
||||
|
||||
//返回用户信息
|
||||
LoginResponse loginResponse = new LoginResponse(); |
||||
loginResponse.setAccount(userEntity.getAccount()); |
||||
loginResponse.setToken(token); |
||||
|
||||
return ResponseResult.SUCCESS(loginResponse); |
||||
} |
||||
} |
@ -0,0 +1,71 @@ |
||||
package com.daqing.financial.hrauth.util; |
||||
|
||||
|
||||
import com.daqing.framework.util.Md5Util; |
||||
|
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* @author zcw |
||||
* @version 1.0 |
||||
* @date 2019/11/23 11:06 |
||||
* @description jwt工具类 |
||||
*/ |
||||
public class JwtUtil { |
||||
|
||||
//private final static Algorithm algorithm = SpringContextHolder.getBean("algorithm", Algorithm.class);
|
||||
|
||||
//private final static OdcProperties properties = SpringContextHolder.getBean("odcProperties", OdcProperties.class);
|
||||
|
||||
/** |
||||
* 创建token |
||||
* |
||||
* @param userId; |
||||
* @param timeout; 单位是秒 |
||||
*/ |
||||
public static String createJwtToken(Long userId, long timeout) { |
||||
String token = Md5Util.md5("dq"+userId+timeout+System.currentTimeMillis()); |
||||
RedisUtil.setEx("dq:token:"+token, String.valueOf(userId), timeout); |
||||
return token; |
||||
/*return JWT.create() |
||||
.withClaim("member", userId) |
||||
.withExpiresAt(new Date(System.currentTimeMillis() + timeout * 1000)) |
||||
.sign(algorithm);*/ |
||||
} |
||||
|
||||
/** |
||||
* token正确且有效,则返回userId |
||||
*/ |
||||
/* public static Long verifyToken(String token) { |
||||
try { |
||||
String noBearerToken = token.replaceFirst("Bearer ", ""); |
||||
Long userId = JWT.require(algorithm) |
||||
.build() |
||||
.verify(noBearerToken) |
||||
.getClaim("member") |
||||
.asLong(); |
||||
if (RedisUtil.get(getRedisKey(userId, noBearerToken)) != null) { |
||||
return userId; |
||||
} |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return null; |
||||
} |
||||
return null; |
||||
}*/ |
||||
|
||||
public static String getRedisKey(Long userId, String token) { |
||||
return String.format("dq:token:"+token, token, String.valueOf(userId)); |
||||
} |
||||
|
||||
public static void putTokenToRedis(Long userId, String token, long times) { |
||||
RedisUtil.setEx(getRedisKey(userId, token), "nothing", times); |
||||
} |
||||
|
||||
public static void removeTokenByUserId(Long userId) { |
||||
Set<String> tokenSet = RedisUtil.keys(getRedisKey(userId, "*")); |
||||
for (String key : tokenSet) { |
||||
RedisUtil.del(key); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,298 @@ |
||||
package com.daqing.financial.hrauth.util; |
||||
|
||||
|
||||
import com.daqing.financial.hrauth.SpringContextHolder; |
||||
import org.springframework.data.redis.core.HashOperations; |
||||
import org.springframework.data.redis.core.ListOperations; |
||||
import org.springframework.data.redis.core.StringRedisTemplate; |
||||
import org.springframework.data.redis.core.ValueOperations; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* redis工具类 |
||||
*/ |
||||
public class RedisUtil { |
||||
|
||||
private final static StringRedisTemplate stringRedisTemplate = SpringContextHolder.getBean("stringRedisTemplate"); |
||||
|
||||
/** |
||||
* 匹配key |
||||
*/ |
||||
public static Set<String> keys(String pattern) { |
||||
return stringRedisTemplate.keys(pattern); |
||||
} |
||||
|
||||
/** |
||||
* 删除一个key |
||||
*/ |
||||
public static void del(String key) { |
||||
stringRedisTemplate.delete(key); |
||||
} |
||||
|
||||
/** |
||||
* 批量删除key |
||||
*/ |
||||
public static void delByPattern(String pattern) { |
||||
Set<String> keySet = keys(pattern); |
||||
stringRedisTemplate.delete(keySet); |
||||
} |
||||
|
||||
/** |
||||
* 设置过期时间,单位为秒 |
||||
*/ |
||||
public static boolean expire(String key, long seconds) { |
||||
return stringRedisTemplate.expire(key, seconds, TimeUnit.SECONDS); |
||||
} |
||||
|
||||
/** |
||||
* 获取自动过期时间 |
||||
*/ |
||||
public static long ttl(String key) { |
||||
return stringRedisTemplate.getExpire(key, TimeUnit.SECONDS); |
||||
} |
||||
|
||||
/** |
||||
* 移除过期时间 |
||||
*/ |
||||
public static boolean persist(String key) { |
||||
return stringRedisTemplate.persist(key); |
||||
} |
||||
|
||||
/////// String 操作
|
||||
|
||||
/** |
||||
* 给key赋值 |
||||
*/ |
||||
public static void set(String key, String value) { |
||||
ValueOperations<String, String> op = stringRedisTemplate.opsForValue(); |
||||
op.set(key, value); |
||||
} |
||||
|
||||
/** |
||||
* 给key赋值,并设置过期时间,单位为秒 |
||||
*/ |
||||
public static void setEx(String key, String value, long seconds) { |
||||
set(key, value); |
||||
expire(key, seconds); |
||||
} |
||||
|
||||
/** |
||||
* 将key的值加num |
||||
*/ |
||||
public static void incrBy(String key, long num) { |
||||
ValueOperations<String, String> op = stringRedisTemplate.opsForValue(); |
||||
op.increment(key, num); |
||||
} |
||||
|
||||
/** |
||||
* 获取key的值 |
||||
*/ |
||||
public static String get(String key) { |
||||
ValueOperations<String, String> op = stringRedisTemplate.opsForValue(); |
||||
return op.get(key); |
||||
} |
||||
|
||||
/////// list操作
|
||||
|
||||
/** |
||||
* 插入到表头 |
||||
*/ |
||||
public static void lPush(String key, String... values) { |
||||
ListOperations<String, String> listOp = stringRedisTemplate.opsForList(); |
||||
listOp.leftPushAll(key, values); |
||||
} |
||||
|
||||
/** |
||||
* 移除第一个 |
||||
*/ |
||||
public static String rPop(String key) { |
||||
ListOperations<String, String> listOp = stringRedisTemplate.opsForList(); |
||||
return listOp.rightPop(key); |
||||
} |
||||
|
||||
/** |
||||
* 获取list所有 |
||||
* |
||||
* @param key |
||||
* @param start |
||||
* @param end |
||||
* @return |
||||
*/ |
||||
public static List<String> lRange(String key, int start, int end) { |
||||
ListOperations<String, String> opsForList = stringRedisTemplate.opsForList(); |
||||
return opsForList.range(key, start, end); |
||||
} |
||||
|
||||
/////// hash
|
||||
|
||||
/* |
||||
* public static void hset(String key,String hashKey,String value){ |
||||
* HashOperations<String,String,String> opsForHash = |
||||
* stringRedisTemplate.opsForHash(); opsForHash.put(key, hashKey, value); } |
||||
*/ |
||||
/////// set
|
||||
/////// sorted set
|
||||
|
||||
/** |
||||
* 存放list |
||||
* @param key |
||||
* @param list |
||||
*/ |
||||
public static void setList(String key, List<String> list){ |
||||
ListOperations<String, String> opsForList = stringRedisTemplate.opsForList(); |
||||
opsForList.leftPushAll(key, list); |
||||
} |
||||
|
||||
/** |
||||
* HashGet |
||||
* @param key 键 不能为null |
||||
* @param item 项 不能为null |
||||
* @return 值 |
||||
*/ |
||||
public static Object hGet(String key,String item){ |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
return mapOp.get(key, item); |
||||
} |
||||
|
||||
/** |
||||
* 获取hashKey对应的所有键值 |
||||
* @param key 键 |
||||
* @return 对应的多个键值 |
||||
*/ |
||||
public static Map<Object,Object> hmGet(String key){ |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
return mapOp.entries(key); |
||||
} |
||||
|
||||
/** |
||||
* HashSet |
||||
* @param key 键 |
||||
* @param map 对应多个键值 |
||||
* @return true 成功 false 失败 |
||||
*/ |
||||
public static boolean hmSet(String key, Map<String,Object> map){ |
||||
try { |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
mapOp.putAll(key, map); |
||||
return true; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* HashSet 并设置时间 |
||||
* @param key 键 |
||||
* @param map 对应多个键值 |
||||
* @param time 时间(秒) |
||||
* @return true成功 false失败 |
||||
*/ |
||||
public static boolean hmset(String key, Map<String,Object> map, long time){ |
||||
try { |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
mapOp.putAll(key, map); |
||||
if(time>0){ |
||||
expire(key, time); |
||||
} |
||||
return true; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 向一张hash表中放入数据,如果不存在将创建 |
||||
* @param key 键 |
||||
* @param item 项 |
||||
* @param value 值 |
||||
* @return true 成功 false失败 |
||||
*/ |
||||
public static boolean hset(String key,String item,Object value) { |
||||
try { |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
mapOp.put(key, item, value); |
||||
return true; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 向一张hash表中放入数据,如果不存在将创建 |
||||
* @param key 键 |
||||
* @param item 项 |
||||
* @param value 值 |
||||
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 |
||||
* @return true 成功 false失败 |
||||
*/ |
||||
public static boolean hset(String key,String item,Object value,long time) { |
||||
try { |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
mapOp.put(key, item, value); |
||||
if(time>0){ |
||||
expire(key, time); |
||||
} |
||||
return true; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 删除hash表中的值 |
||||
* @param key 键 不能为null |
||||
* @param item 项 可以使多个 不能为null |
||||
*/ |
||||
public static void hdel(String key, Object... item){ |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
|
||||
mapOp.delete(key,item); |
||||
} |
||||
|
||||
/** |
||||
* 判断hash表中是否有该项的值 |
||||
* @param key 键 不能为null |
||||
* @param item 项 不能为null |
||||
* @return true 存在 false不存在 |
||||
*/ |
||||
public static boolean hHasKey(String key, String item){ |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
|
||||
return mapOp.hasKey(key, item); |
||||
} |
||||
|
||||
/** |
||||
* hash递增 如果不存在,就会创建一个 并把新增后的值返回 |
||||
* @param key 键 |
||||
* @param item 项 |
||||
* @param by 要增加几(大于0) |
||||
* @return |
||||
*/ |
||||
public static double hincr(String key, String item,double by){ |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
|
||||
return mapOp.increment(key, item, by); |
||||
} |
||||
|
||||
/** |
||||
* hash递减 |
||||
* @param key 键 |
||||
* @param item 项 |
||||
* @param by 要减少记(小于0) |
||||
* @return |
||||
*/ |
||||
public static double hdecr(String key, String item,double by){ |
||||
HashOperations<String, Object, Object> mapOp = stringRedisTemplate.opsForHash(); |
||||
|
||||
return mapOp.increment(key, item,-by); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,41 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
||||
<mapper namespace="com.daqing.financial.hrauth.dao.UserLoginDao"> |
||||
<!-- 可根据自己的需求,是否要使用 --> |
||||
<resultMap type="com.daqing.framework.domain.hrms.UserEntity" id="userMap"> |
||||
<result property="id" column="id"/> |
||||
<result property="account" column="account"/> |
||||
<result property="phoneAccount" column="phone_account"/> |
||||
<result property="password" column="password"/> |
||||
<result property="loginNum" column="login_num"/> |
||||
<result property="createTime" column="create_time"/> |
||||
<result property="motifyTime" column="motify_time"/> |
||||
</resultMap> |
||||
<update id="updatePasswordByPhoneAccount"> |
||||
update hrms_user set password = #{password} where phone_account = #{phoneAccount} |
||||
</update> |
||||
|
||||
<select id="getUser" parameterType="string" resultType="com.daqing.framework.domain.hrms.UserEntity"> |
||||
SELECT account,password FROM hrms_user WHERE account = #{account} |
||||
</select> |
||||
<select id="selectCount" resultType="java.lang.Integer"> |
||||
select count(1) from hrms_user where phone_account = #{phoneAccount} |
||||
</select> |
||||
|
||||
<select id="login" parameterType="com.daqing.framework.domain.hrms.request.LoginRequest" resultType="com.daqing.framework.domain.hrms.UserEntity"> |
||||
select id,account,phone_account,password,login_num from hrms_user |
||||
where del_or_not = 0 and status = 0 |
||||
<if test="phone != null and phone != '' "> |
||||
and phone_account = #{phone} |
||||
</if> |
||||
<if test="wechatId != null and wechatId != '' "> |
||||
and wechat_id = #{wechatId} |
||||
</if> |
||||
|
||||
</select> |
||||
<select id="selectByPhoneAccount" resultType="com.daqing.framework.domain.hrms.UserEntity"> |
||||
SELECT id,account FROM hrms_user WHERE phone_account = #{phoneAccount} |
||||
</select> |
||||
|
||||
</mapper> |
@ -1,13 +1,13 @@ |
||||
package com.daqing.financial.hrauth; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
||||
@SpringBootTest |
||||
class DqFinancialHrmsAuthApplicationTests { |
||||
|
||||
@Test |
||||
void contextLoads() { |
||||
} |
||||
|
||||
} |
||||
//package com.daqing.financial.hrauth;
|
||||
//
|
||||
//import org.junit.Test;
|
||||
//import org.springframework.boot.test.context.SpringBootTest;
|
||||
//
|
||||
//@SpringBootTest
|
||||
//class DqFinancialHrmsAuthApplicationTests {
|
||||
//
|
||||
// @Test
|
||||
// void contextLoads() {
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
@ -0,0 +1,47 @@ |
||||
package com.daqing.financial.hrms.config; |
||||
|
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; |
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; |
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; |
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; |
||||
import org.springframework.security.oauth2.provider.token.RemoteTokenServices; |
||||
|
||||
@Configuration |
||||
@EnableResourceServer |
||||
@EnableGlobalMethodSecurity(prePostEnabled = true) |
||||
public class ResourceServerConfig extends ResourceServerConfigurerAdapter { |
||||
|
||||
@Value("${security.oauth2.client.client-id}") |
||||
private String clientId; |
||||
|
||||
@Value("${security.oauth2.client.client-secret}") |
||||
private String secret; |
||||
|
||||
@Value("${security.oauth2.authorization.check-token-access}") |
||||
private String checkTokenEndpointUrl; |
||||
|
||||
/* @Autowired |
||||
private RedisConnectionFactory redisConnectionFactory;*/ |
||||
|
||||
/* @Bean |
||||
public TokenStore redisTokenStore (){ |
||||
return new RedisTokenStore(redisConnectionFactory); |
||||
}*/ |
||||
|
||||
@Bean |
||||
public RemoteTokenServices tokenService() { |
||||
RemoteTokenServices tokenService = new RemoteTokenServices(); |
||||
tokenService.setClientId(clientId); |
||||
tokenService.setClientSecret(secret); |
||||
tokenService.setCheckTokenEndpointUrl(checkTokenEndpointUrl); |
||||
return tokenService; |
||||
} |
||||
|
||||
@Override |
||||
public void configure(ResourceServerSecurityConfigurer resources) throws Exception { |
||||
resources.tokenServices(tokenService()); |
||||
} |
||||
} |
@ -1,38 +1,38 @@ |
||||
package com.daqing.financial.hrms; |
||||
|
||||
import com.daqing.financial.hrms.service.impl.EmployeeServiceImpl; |
||||
import com.daqing.framework.domain.crms.CustomerEntity; |
||||
import com.daqing.framework.domain.hrms.EmployeeEntity; |
||||
import com.daqing.framework.domain.hrms.ext.EmployeeTO; |
||||
import com.daqing.framework.utils.PageUtils; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.test.context.junit4.SpringRunner; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
@SpringBootTest |
||||
@RunWith(SpringRunner.class) |
||||
public class DqFinancialHrmsApplicationTests { |
||||
|
||||
@Autowired |
||||
private EmployeeServiceImpl employeeServiceimpl; |
||||
|
||||
List<Long> ids = new ArrayList<>(); |
||||
|
||||
@Test |
||||
public void contextLoads() { |
||||
ids.add(1L); |
||||
ids.add(2L); |
||||
ids.add(3L); |
||||
ids.add(4L); |
||||
List<EmployeeTO> list = employeeServiceimpl.getEmployeeAndDeptById(ids); |
||||
for (EmployeeTO employeeTO : list) { |
||||
System.out.println(employeeTO); |
||||
} |
||||
} |
||||
|
||||
} |
||||
//package com.daqing.financial.hrms;
|
||||
//
|
||||
//import com.daqing.financial.hrms.service.impl.EmployeeServiceImpl;
|
||||
//import com.daqing.framework.domain.crms.CustomerEntity;
|
||||
//import com.daqing.framework.domain.hrms.EmployeeEntity;
|
||||
//import com.daqing.framework.domain.hrms.ext.EmployeeTO;
|
||||
//import com.daqing.framework.utils.PageUtils;
|
||||
//import org.junit.Test;
|
||||
//import org.junit.runner.RunWith;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.boot.test.context.SpringBootTest;
|
||||
//import org.springframework.test.context.junit4.SpringRunner;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.List;
|
||||
//
|
||||
//@SpringBootTest
|
||||
//@RunWith(SpringRunner.class)
|
||||
//public class DqFinancialHrmsApplicationTests {
|
||||
//
|
||||
// @Autowired
|
||||
// private EmployeeServiceImpl employeeServiceimpl;
|
||||
//
|
||||
// List<Long> ids = new ArrayList<>();
|
||||
//
|
||||
// @Test
|
||||
// public void contextLoads() {
|
||||
// ids.add(1L);
|
||||
// ids.add(2L);
|
||||
// ids.add(3L);
|
||||
// ids.add(4L);
|
||||
// List<EmployeeTO> list = employeeServiceimpl.getEmployeeAndDeptById(ids);
|
||||
// for (EmployeeTO employeeTO : list) {
|
||||
// System.out.println(employeeTO);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
Binary file not shown.
@ -1,76 +0,0 @@ |
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-parent</artifactId> |
||||
<version>2.1.8.RELEASE</version> |
||||
<relativePath/> <!-- lookup parent from repository --> |
||||
</parent> |
||||
<groupId>com.daqing.financial</groupId> |
||||
<artifactId>dq-financial-workflow</artifactId> |
||||
<version>0.0.1-SNAPSHOT</version> |
||||
<name>dq-financial-workflow</name> |
||||
<description>大庆智慧金融平台-工作流服务</description> |
||||
|
||||
<properties> |
||||
<java.version>1.8</java.version> |
||||
<spring-cloud.version>Greenwich.SR3</spring-cloud.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.daqing.framework</groupId> |
||||
<artifactId>dq-framework-common</artifactId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.daqing.framework</groupId> |
||||
<artifactId>dq-framework-model</artifactId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-web</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-starter-openfeign</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-test</artifactId> |
||||
<scope>test</scope> |
||||
<exclusions> |
||||
<exclusion> |
||||
<groupId>org.junit.vintage</groupId> |
||||
<artifactId>junit-vintage-engine</artifactId> |
||||
</exclusion> |
||||
</exclusions> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
<dependencyManagement> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-dependencies</artifactId> |
||||
<version>${spring-cloud.version}</version> |
||||
<type>pom</type> |
||||
<scope>import</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</dependencyManagement> |
||||
|
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
|
||||
</project> |
@ -1,13 +0,0 @@ |
||||
package com.daqing.financial.workflow; |
||||
|
||||
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
||||
@SpringBootApplication |
||||
public class DqFinancialWorkflowApplication { |
||||
|
||||
public static void main(String[] args) { |
||||
SpringApplication.run(DqFinancialWorkflowApplication.class, args); |
||||
} |
||||
|
||||
} |
@ -1,47 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<configuration> |
||||
<!--定义日志文件的存储地址,使用绝对路径--> |
||||
<property name="LOG_HOME" value="d:/logs/daqing/workflow"/> |
||||
|
||||
<!-- Console 输出设置 --> |
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> |
||||
<encoder> |
||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> |
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
<charset>utf8</charset> |
||||
</encoder> |
||||
</appender> |
||||
|
||||
<!-- 按照每天生成日志文件 --> |
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||
<!--日志文件输出的文件名--> |
||||
<fileNamePattern>${LOG_HOME}/workflow.%d{yyyy-MM-dd}.log</fileNamePattern> |
||||
</rollingPolicy> |
||||
<encoder> |
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
</encoder> |
||||
</appender> |
||||
|
||||
<!-- 异步输出 --> |
||||
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> |
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> |
||||
<discardingThreshold>0</discardingThreshold> |
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> |
||||
<queueSize>512</queueSize> |
||||
<!-- 添加附加的appender,最多只能添加一个 --> |
||||
<appender-ref ref="FILE"/> |
||||
</appender> |
||||
|
||||
|
||||
<logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false"> |
||||
<appender-ref ref="CONSOLE"/> |
||||
</logger> |
||||
<logger name="org.springframework.boot" level="DEBUG"/> |
||||
<root level="info"> |
||||
<!--<appender-ref ref="ASYNC"/>--> |
||||
<appender-ref ref="FILE"/> |
||||
<appender-ref ref="CONSOLE"/> |
||||
</root> |
||||
</configuration> |
@ -1,13 +0,0 @@ |
||||
package com.daqing.financial.workflow; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
||||
@SpringBootTest |
||||
class DqFinancialWorkflowApplicationTests { |
||||
|
||||
@Test |
||||
void contextLoads() { |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
|
||||
package com.daqing.framework.util; |
||||
|
||||
import org.springframework.util.DigestUtils; |
||||
|
||||
/** |
||||
* @author zcw |
||||
* @version 1.0 |
||||
* @date 2020/1/6 17:03 |
||||
* @description md5工具类 |
||||
*/ |
||||
public class Md5Util { |
||||
|
||||
public static String md5(String str) { |
||||
if (str == null) { |
||||
return null; |
||||
} |
||||
return DigestUtils.md5DigestAsHex(str.getBytes()); |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
System.out.printf(md5("1234561")); |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
package com.daqing.framework.domain.hrms.request; |
||||
|
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.Data; |
||||
|
||||
@Data |
||||
public class LoginRequest { |
||||
|
||||
private int id; |
||||
|
||||
@ApiModelProperty(value = "手机号码") |
||||
private String phone; |
||||
|
||||
@ApiModelProperty(value = "登录类型(1:手机号 2:微信登录)") |
||||
private int type; |
||||
|
||||
@ApiModelProperty(value = "微信唯一编号") |
||||
private String wechatId; |
||||
|
||||
@ApiModelProperty(value = "密码") |
||||
private String password; |
||||
|
||||
@ApiModelProperty(value = "登录十天有效 1:有效 2:不处理") |
||||
private int tenDayEffective; |
||||
} |
@ -0,0 +1,33 @@ |
||||
package com.daqing.framework.domain.hrms.request; |
||||
|
||||
import lombok.Data; |
||||
|
||||
import javax.validation.constraints.Pattern; |
||||
import java.io.Serializable; |
||||
|
||||
/** |
||||
* 登录找回密码请求体对象 |
||||
* |
||||
* @author gongsj |
||||
* @email gongsj@gmail.com |
||||
* @date 2020-09-07 17:12:14 |
||||
*/ |
||||
@Data |
||||
public class UserLoginRequest implements Serializable { |
||||
|
||||
/** |
||||
* 手机账号 |
||||
*/ |
||||
@Pattern(regexp = "^1(3([0-35-9]\\d|4[1-8])|4[14-9]\\d|5([0125689]\\d|7[1-79])|66\\d|7[2-35-8]\\d|8\\d{2}|9[13589]\\d)\\d{7}$",message = "手机号格式不正确!") |
||||
private String phoneAccount; |
||||
|
||||
/** |
||||
* 验证码 |
||||
*/ |
||||
private String verifyCode; |
||||
/** |
||||
* 新密码 |
||||
*/ |
||||
@Pattern(regexp = "^(?=.*[0-9].*)(?=.*[A-Z].*)(?=.*[a-z].*).{6,20}$",message = "密码格式不正确!") |
||||
private String newPwd; |
||||
} |
@ -0,0 +1,12 @@ |
||||
package com.daqing.framework.domain.hrms.response; |
||||
|
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.Data; |
||||
|
||||
@Data |
||||
public class LoginResponse { |
||||
@ApiModelProperty(value = "用户名") |
||||
private String account; |
||||
@ApiModelProperty("token令牌") |
||||
private String token; |
||||
} |
Binary file not shown.
@ -1,25 +0,0 @@ |
||||
package com.daqing.financial.gateway.exception; |
||||
|
||||
import com.daqing.financial.gateway.util.ResultCodeEnum; |
||||
import lombok.Data; |
||||
|
||||
@Data |
||||
public class DqException extends RuntimeException { |
||||
|
||||
private int code; |
||||
|
||||
private ResultCodeEnum resultCodeEnum; |
||||
|
||||
public DqException(ResultCodeEnum codeEnum) { |
||||
super(codeEnum.getRemark()); |
||||
code = codeEnum.getCode(); |
||||
} |
||||
|
||||
public int getCode() { |
||||
return code; |
||||
} |
||||
|
||||
public ResultCodeEnum getResultCodeEnum() { |
||||
return resultCodeEnum; |
||||
} |
||||
} |
@ -1,62 +0,0 @@ |
||||
package com.daqing.financial.gateway.util; |
||||
|
||||
public enum ResultCodeEnum { |
||||
|
||||
SUCCESS(0, "请求成功"), |
||||
BAD_REQUEST(400, "错误请求"), |
||||
UN_AUTHORIZATION(401, "未授权"), |
||||
SERVER_EXCEPTION(500, "服务器异常"), |
||||
|
||||
ACCOUNT_NOT_EXIST(10000, "账号不存在"), |
||||
ACCOUNT_NOT_BIND(10001, "账号未绑定钱包"), |
||||
ACCOUNT_NOT_ACTIVE(10002, "账号未激活"), |
||||
ACCOUNT_EXIST(10003, "账号已存在,请登录"), |
||||
COIN_ADDRESS_IS_NOT_EXIST(10004, "该币种地址不存在"), |
||||
COIN_NAME_IS_NOT_EXIST(10005, "该币种不存在"), |
||||
|
||||
WALLET_BAD_PARAM(10100, "非法参数,禁止访问他人账号"), |
||||
WALLET_NOT_ENOUGH(10101, "可用余额不足"), |
||||
SUB_ACCOUNT_NOT_ALLOW_WITHDRAW(10102, "子账号不允许提币"), |
||||
USER_NAME_ALREADY_EXISTS(10103,"用户名已存在"), |
||||
USER_EMAIL_ALREADY_EXISTS(10104,"邮箱已存在"), |
||||
INVITATION_CODE_NOT_EXIST(10105,"邀请码不存在"), |
||||
DEVICE_EXIST(10106,"设备号相同"), |
||||
LOGINPASSWORD_ERROR(10107,"登录密码错误"), |
||||
ACCOUNT_DISABLED(10108,"账号已禁用"), |
||||
USER_NAME_IS_ENABLE(10109,"用户名不存在"), |
||||
USER_IS_ACTIVE(10111,"该用户已激活"), |
||||
PAY_PASSWORD_IS_ERROR(10112,"支付密码错误"), |
||||
USER_IS_ACTIVE_MAX(10113,"您的激活次数已上线"), |
||||
WITHDRAW_IS_ENABLE(10114,"该币种已关闭提币通道"), |
||||
WITHDRAW_IS_NOT_BEGIN_TIME(10115,"未到提币时间"), |
||||
WITHDRAW_IS_SUPER_END_TIME(10116,"提币时间已过"), |
||||
WITHDRAW_MIN_ERROR(10117,"不能小于最小提币金额"), |
||||
WITHDRAW_MAX_ERROR(10118,"不能大于最大提币金额"), |
||||
WITHDRAW_MAX_TODAY(10120,"当日提币金额已上限"), |
||||
TRANSFER_IS_ENABLE(10121,"该币种已关闭转账通道"), |
||||
TRANSFER_MIN_ERROR(10122,"不能小于最小转账金额"), |
||||
TRANSFER_MAX_ERROR(10123,"不能大于最大转账金额"), |
||||
TRANSFER_MAX_TODAY(10124,"当日转账金额已上限"), |
||||
USERNAME_AND_EMAIL_ERROR(10125,"用户名和邮箱不匹配"), |
||||
EMAIL_CODE_IS_ERROR(10126,"验证码错误"), |
||||
PAY_PASSWORD_IS_NULL(10127,"请先设置支付密码"), |
||||
CHAIN_IS_ERROR(10128,"链上异常请联系管理员"); |
||||
|
||||
|
||||
|
||||
private final int code; |
||||
private final String remark; |
||||
|
||||
ResultCodeEnum(int code, String remark) { |
||||
this.code = code; |
||||
this.remark = remark; |
||||
} |
||||
|
||||
public int getCode() { |
||||
return code; |
||||
} |
||||
|
||||
public String getRemark() { |
||||
return remark; |
||||
} |
||||
} |
@ -1 +1 @@ |
||||
jwt.ignoreUrlList=/api/hrms/employee/list,/route-api/refresh |
||||
jwt.ignoreUrlList=/apiHrmsAuth/hrms/auth/userlogin/getBackPwd,/apiHrmsAuth/hrms/auth/userlogin/login |
||||
|
@ -1,15 +1,15 @@ |
||||
package com.daqing.financial.gateway; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; |
||||
|
||||
@EnableDiscoveryClient |
||||
@SpringBootTest |
||||
class DqGovernGatewayApplicationTests { |
||||
|
||||
@Test |
||||
void contextLoads() { |
||||
} |
||||
|
||||
} |
||||
//package com.daqing.financial.gateway;
|
||||
//
|
||||
//import org.junit.Test;
|
||||
//import org.springframework.boot.test.context.SpringBootTest;
|
||||
//import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
//
|
||||
//@EnableDiscoveryClient
|
||||
//@SpringBootTest
|
||||
//class DqGovernGatewayApplicationTests {
|
||||
//
|
||||
// @Test
|
||||
// void contextLoads() {
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
Loading…
Reference in new issue