From f8bfa9925d63e6bce9547d209488a1eb78151310 Mon Sep 17 00:00:00 2001 From: ZhouXY108 Date: Tue, 6 Jun 2023 20:13:56 +0800 Subject: [PATCH] first commit. --- .gitignore | 35 ++ pom.xml | 360 ++++++++++++++++++ .../com/nantian/demo/DemoApplication.java | 20 + .../exception/handler/DefaultHandler.java | 14 + .../nantian/demo/servcie/Tapp002Service.java | 25 ++ .../mfp/framework/config/SecurityConfig.java | 333 ++++++++++++++++ .../mfp/framework/config/WebMvcConfig.java | 82 ++++ .../service/MfpRememberMeServices.java | 241 ++++++++++++ .../mfp/framework/utils/RequestUtils.java | 168 ++++++++ .../mfp/pub/service/DbSequenceService.java | 90 +++++ src/main/resources/application-dev.properties | 110 ++++++ .../resources/application-diff.properties | 8 + src/main/resources/application-dmy.properties | 5 + .../resources/application-flow.properties | 11 + src/main/resources/application-pro.properties | 3 + src/main/resources/application-uat.properties | 3 + src/main/resources/application.properties | 48 +++ src/main/resources/log4j2.xml | 52 +++ .../resources/template/common/SEND_B00001.ftl | 1 + .../resources/template/common/SEND_demo.ftl | 1 + .../resources/template/dummy/RECV_B00001.ftl | 1 + 21 files changed, 1611 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/nantian/demo/DemoApplication.java create mode 100644 src/main/java/com/nantian/demo/exception/handler/DefaultHandler.java create mode 100644 src/main/java/com/nantian/demo/servcie/Tapp002Service.java create mode 100644 src/main/java/com/nantian/mfp/framework/config/SecurityConfig.java create mode 100644 src/main/java/com/nantian/mfp/framework/config/WebMvcConfig.java create mode 100644 src/main/java/com/nantian/mfp/framework/security/service/MfpRememberMeServices.java create mode 100644 src/main/java/com/nantian/mfp/framework/utils/RequestUtils.java create mode 100644 src/main/java/com/nantian/mfp/pub/service/DbSequenceService.java create mode 100644 src/main/resources/application-dev.properties create mode 100644 src/main/resources/application-diff.properties create mode 100644 src/main/resources/application-dmy.properties create mode 100644 src/main/resources/application-flow.properties create mode 100644 src/main/resources/application-pro.properties create mode 100644 src/main/resources/application-uat.properties create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/log4j2.xml create mode 100644 src/main/resources/template/common/SEND_B00001.ftl create mode 100644 src/main/resources/template/common/SEND_demo.ftl create mode 100644 src/main/resources/template/dummy/RECV_B00001.ftl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6640241 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +*/**/http/*.http + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ +log/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..1767a64 --- /dev/null +++ b/pom.xml @@ -0,0 +1,360 @@ + + + + 4.0.0 + com.nantian + demo + 1.0 + jar + demo-cloud + Demo project for Spring Boot + + + com.alipay.sofa + sofaboot-dependencies + 3.4.6 + + + + + 1.8 + UTF-8 + UTF-8 + 1.8 + 1.8 + Greenwich.SR6 + 2.1.4.RELEASE + 2.15.2 + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${cloud.alibaba.version} + pom + import + + + + + + + + + com.nantian + mfp-cloud-starter + 5.1 + + + + org.springframework.boot + spring-boot-starter + + + spring-boot-starter-logging + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-test + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-logging + + + ch.qos.logback + logback-classic + + + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + + org.springframework.boot + spring-boot-starter-security + + + + + org.dom4j + dom4j + 2.1.3 + + + + + commons-beanutils + commons-beanutils + 1.9.4 + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + + com.alibaba + druid + 1.2.16 + + + + + mysql + mysql-connector-java + 8.0.29 + + + + + + + + + + + junit + junit + 4.12 + test + + + + + io.netty + netty-codec-http + 4.1.86.Final + + + + + org.apache.tomcat.embed + tomcat-embed-jasper + + + + org.bouncycastle + bcpkix-jdk15on + 1.57 + + + + + commons-io + commons-io + 2.8.0 + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.springframework.session + spring-session-core + 2.6.3 + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + + com.alibaba.csp + sentinel-datasource-nacos + 1.8.5 + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + org.apache.skywalking + apm-toolkit-trace + 8.7.0 + + + + + org.apache.skywalking + apm-toolkit-log4j-2.x + 8.7.0 + + + + + org.apache.mina + mina-core + 2.0.22 + + + + + cn.hutool + hutool-all + 5.8.14 + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + + com.alipay.sofa + healthcheck-sofa-boot-starter + + + org.springframework.boot + spring-boot-starter-logging + + + + + + xyz.zhouxy.plusone + plusone-commons + 0.1.0-SNAPSHOT + + + + + + mfp-cloud-starter-${project.version} + compile + src/main/java/ + + + + src/main/java + + **/*.ftl + + + + + + src/main/resources + + + **/*.* + + + + + + src/main/webapp + + **/*.* + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + + + + + diff --git a/src/main/java/com/nantian/demo/DemoApplication.java b/src/main/java/com/nantian/demo/DemoApplication.java new file mode 100644 index 0000000..28e3142 --- /dev/null +++ b/src/main/java/com/nantian/demo/DemoApplication.java @@ -0,0 +1,20 @@ +package com.nantian.demo; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +@SpringBootApplication(exclude = { ErrorMvcAutoConfiguration.class, FreeMarkerAutoConfiguration.class }) +public class DemoApplication extends SpringBootServletInitializer { + + private static final Logger log = LoggerFactory.getLogger(DemoApplication.class); + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + log.info("程序启动成功!"); + } +} diff --git a/src/main/java/com/nantian/demo/exception/handler/DefaultHandler.java b/src/main/java/com/nantian/demo/exception/handler/DefaultHandler.java new file mode 100644 index 0000000..add5bd8 --- /dev/null +++ b/src/main/java/com/nantian/demo/exception/handler/DefaultHandler.java @@ -0,0 +1,14 @@ +package com.nantian.demo.exception.handler; + +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import xyz.zhouxy.plusone.commons.util.RestfulResult; + +// @RestControllerAdvice +public class DefaultHandler { + @ExceptionHandler(Exception.class) + public RestfulResult handle(Exception e) { + return RestfulResult.error("2233", e); + } +} diff --git a/src/main/java/com/nantian/demo/servcie/Tapp002Service.java b/src/main/java/com/nantian/demo/servcie/Tapp002Service.java new file mode 100644 index 0000000..c099ea4 --- /dev/null +++ b/src/main/java/com/nantian/demo/servcie/Tapp002Service.java @@ -0,0 +1,25 @@ +package com.nantian.demo.servcie; + +import java.util.Map; + +import org.springframework.stereotype.Service; + +import com.nantian.mfp.pub.service.TxBaseService; + +import xyz.zhouxy.plusone.commons.util.RestfulResult; + +/** +* 外呼demo +* +* @author ganlaifei +* @date 2023/3/31 17:21 +*/ +@Service +public class Tapp002Service extends TxBaseService { + + @Override + public RestfulResult doService(Map env, Map p) { + // throw new NullPointerException(); + return RestfulResult.success("test"); + } +} diff --git a/src/main/java/com/nantian/mfp/framework/config/SecurityConfig.java b/src/main/java/com/nantian/mfp/framework/config/SecurityConfig.java new file mode 100644 index 0000000..5d12553 --- /dev/null +++ b/src/main/java/com/nantian/mfp/framework/config/SecurityConfig.java @@ -0,0 +1,333 @@ +package com.nantian.mfp.framework.config; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +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.configuration.AuthenticationConfiguration; +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.core.session.SessionRegistry; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.access.channel.ChannelProcessingFilter; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.LogoutFilter; +import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; +import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy; +import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; +import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy; +import org.springframework.security.web.header.HeaderWriterFilter; +import org.springframework.security.web.session.SessionManagementFilter; +import org.springframework.session.FindByIndexNameSessionRepository; +import org.springframework.session.security.SpringSessionBackedSessionRegistry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nantian.mfp.framework.security.encoder.Sm3PasswordEncoder; +import com.nantian.mfp.framework.security.filter.MfpEwaySafeFilter; +import com.nantian.mfp.framework.security.filter.MfpFlowctrlFilter; +import com.nantian.mfp.framework.security.filter.MfpSessionFilter; +import com.nantian.mfp.framework.security.filter.MfpTxCheckFilter; +import com.nantian.mfp.framework.security.filter.MfpTxXssFilter; +import com.nantian.mfp.framework.security.filter.MfpTxlogFilter; +import com.nantian.mfp.framework.security.filter.MfpUserLoginFilter; +import com.nantian.mfp.framework.security.provider.MfpAuthenticationProvider; +import com.nantian.mfp.framework.security.repository.MfpJdbcTokenRepositoryImpl; +import com.nantian.mfp.framework.security.service.MfpRememberMeServices; +import com.nantian.mfp.framework.security.strategy.MfpSessionControlStrategy; + +/** +* +* @desc 旧版本spring security配置 +* @author ganlaifei +* @date 2023/2/21 19:32 +*/ +@EnableWebSecurity +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Value("${security.login.url:/reCtrl/login}") + private String LOGIN_URL; + + @Value("${security.login.page:/index.jsp}") + private String LOGIN_PAGE; + + @Value("${ecurity.logout.url:/reCtrl/logout}") + private String LOGOUT_URL; + + @Value("${security.login.username:userid}") + private String LOGIN_USERNAME_PARAMTER; + + @Value("${security.login.password:entry_pwd}") + private String LOGIN_PASSWORD_PARAMETER; + + @Value("${security.rememberme.token:MFPToken}") + private String securityRememberMeToken; + + @Value("${security.token.validTime:1209600}") + private int securityTokenValidTime; + + @Value("${security.remeberme.parameter:autoLogin}") + private String securityRememberMeParameter; + + @Autowired + private MfpAuthenticationProvider mfpAuthenticationProvider; + + @Autowired + private UserDetailsService mfpUserDetailsService; + + @Autowired + private SavedRequestAwareAuthenticationSuccessHandler mfpAuthSuccessHandler; + + @Autowired + private SimpleUrlAuthenticationFailureHandler mfpAuthFailureHandler; + + @Autowired + private LogoutHandler mfpLogoutHandler; + + @Autowired + private LogoutSuccessHandler mfpLogoutSuccHandler; + + @Autowired + private FindByIndexNameSessionRepository sessionRepository; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().permitAll() + .and() + .formLogin() + .and() + .logout() + .logoutUrl(LOGOUT_URL) + .addLogoutHandler(mfpLogoutHandler) + .logoutSuccessHandler(mfpLogoutSuccHandler) + .permitAll() + .and() + .authenticationProvider(mfpAuthenticationProvider) + .rememberMe() + .rememberMeServices(mfpRememberMeServices()) + .and() + .csrf().disable() + .headers().frameOptions().disable(); + + // 日志过滤器,配置为spring security第一个过滤器 + http.addFilterBefore(mfpTxlogFilter(), ChannelProcessingFilter.class); + // 流控过滤器 + http.addFilterAfter(mfpFlowctrlFilter(), ChannelProcessingFilter.class); + // 加解密过滤器 + http.addFilterAfter(mfpEwaySafeFilter(), HeaderWriterFilter.class); + // 交易检查过滤器 + http.addFilterBefore(mfpTxCheckFilter(), LogoutFilter.class); + // xss过滤器 + http.addFilterAfter(mfpTxXssFilter(), LogoutFilter.class); + // 登录过滤器 + http.addFilterAt(mfpUserLoginFilter(http.getSharedObject(AuthenticationManager.class)), + UsernamePasswordAuthenticationFilter.class); + // session过滤器 + http.addFilterAt(mfpSessionFilter(), SessionManagementFilter.class); + } + + @Bean + MfpTxCheckFilter mfpTxCheckFilter(){ + return new MfpTxCheckFilter(); + } + + @Bean + MfpTxlogFilter mfpTxlogFilter(){ + return new MfpTxlogFilter(); + } + + @Bean + MfpFlowctrlFilter mfpFlowctrlFilter(){ + return new MfpFlowctrlFilter(); + } + + @Bean + MfpEwaySafeFilter mfpEwaySafeFilter(){ + return new MfpEwaySafeFilter(); + } + + @Bean + MfpTxXssFilter mfpTxXssFilter(){ + return new MfpTxXssFilter(); + } + + @Bean + MfpSessionFilter mfpSessionFilter(){ + return new MfpSessionFilter(sessionRegistry(),LOGIN_PAGE); + } + /** + * 当filter被spring管理后会自动注册到springmvc过滤器链中,如果再将filter添加到security过滤器链中 + * 会导致filter执行2次,此配置旨在让springboot不自动注册扫面到的filter + * @return + */ + @Bean + FilterRegistrationBean cancelMfpFlowctrlFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(mfpFlowctrlFilter()); + registration.setEnabled(false); + return registration; + } + + /** + * 当filter被spring管理后会自动注册到springmvc过滤器链中,如果再将filter添加到security过滤器链中 + * 会导致filter执行2次,此配置旨在让springboot不自动注册扫面到的filter + * @return + */ + @Bean + FilterRegistrationBean cancelMfpTxlogFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(mfpTxlogFilter()); + registration.setEnabled(false); + return registration; + } + + /** + * 当filter被spring管理后会自动注册到springmvc过滤器链中,如果再将filter添加到security过滤器链中 + * 会导致filter执行2次,此配置旨在让springboot不自动注册扫面到的filter + * @return + */ + @Bean + FilterRegistrationBean cancelMfpTxXssFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(mfpTxXssFilter()); + registration.setEnabled(false); + return registration; + } + + /** + * 当filter被spring管理后会自动注册到springmvc过滤器链中,如果再将filter添加到security过滤器链中 + * 会导致filter执行2次,此配置旨在让springboot不自动注册扫面到的filter + * @return + */ + @Bean + FilterRegistrationBean cancelMfpEwaySafeFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(mfpEwaySafeFilter()); + registration.setEnabled(false); + return registration; + } + + + /** + * 当filter被spring管理后会自动注册到springmvc过滤器链中,如果再将filter添加到security过滤器链中 + * 会导致filter执行2次,此配置旨在让springboot不自动注册扫面到的filter + * @return + */ + @Bean + FilterRegistrationBean cancelMfpTxCheckFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(mfpTxCheckFilter()); + registration.setEnabled(false); + return registration; + } + + /** + * 当filter被spring管理后会自动注册到springmvc过滤器链中,如果再将filter添加到security过滤器链中 + * 会导致filter执行2次,此配置旨在让springboot不自动注册扫面到的filter + * @return + */ + @Bean + FilterRegistrationBean cancelMfpSessionFilter(){ + FilterRegistrationBean registration = new FilterRegistrationBean<>(mfpSessionFilter()); + registration.setEnabled(false); + return registration; + } + + /** + * 当filter被spring管理后会自动注册到springmvc过滤器链中,如果再将filter添加到security过滤器链中 + * 会导致filter执行2次,此配置旨在让springboot不自动注册扫面到的filter + * @return + */ + @Bean + FilterRegistrationBean cancelMfpUserLoginFilter(@Autowired AuthenticationManager authenticationManager){ + FilterRegistrationBean registration = new FilterRegistrationBean<>(mfpUserLoginFilter(authenticationManager)); + registration.setEnabled(false); + return registration; + } + + + + @Bean + SessionRegistry sessionRegistry(){ + return new SpringSessionBackedSessionRegistry(sessionRepository); + } + + /** + * security session认证策略 + * @returns + */ + @Bean + CompositeSessionAuthenticationStrategy compositeSessionAuthenticationStrategy(){ + List list = new ArrayList(); + MfpSessionControlStrategy mfpSessionControlStrategy = new MfpSessionControlStrategy(sessionRegistry()); + mfpSessionControlStrategy.setMaximumSessions(1); + mfpSessionControlStrategy.setExceptionIfMaximumExceeded(false); + SessionFixationProtectionStrategy sessionFixationProtectionStrategy = new SessionFixationProtectionStrategy(); + RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy = new RegisterSessionAuthenticationStrategy(sessionRegistry()); + list.add(mfpSessionControlStrategy); + list.add(sessionFixationProtectionStrategy); + list.add(registerSessionAuthenticationStrategy); + return new CompositeSessionAuthenticationStrategy(list); + } + + + + @Bean + MfpUserLoginFilter mfpUserLoginFilter(AuthenticationManager authenticationManager){ + MfpUserLoginFilter mfpLoginFilter = new MfpUserLoginFilter(); + mfpLoginFilter.setPasswordParameter(LOGIN_PASSWORD_PARAMETER); + mfpLoginFilter.setUsernameParameter(LOGIN_USERNAME_PARAMTER); + mfpLoginFilter.setFilterProcessesUrl(LOGIN_URL); + mfpLoginFilter.setAuthenticationManager(authenticationManager); + mfpLoginFilter.setAuthenticationSuccessHandler(mfpAuthSuccessHandler); + mfpLoginFilter.setAuthenticationFailureHandler(mfpAuthFailureHandler); + mfpLoginFilter.setRememberMeServices(mfpRememberMeServices()); + mfpLoginFilter.setSessionAuthenticationStrategy(compositeSessionAuthenticationStrategy()); + return mfpLoginFilter; + } + + + @Bean + MfpRememberMeServices mfpRememberMeServices(){ + MfpRememberMeServices mfpRememberMeServices = new MfpRememberMeServices("mfp",securityTokenValidTime,mfpUserDetailsService,persistentTokenRepository()); + mfpRememberMeServices.setParameter(securityRememberMeParameter); + mfpRememberMeServices.setCookieName(securityRememberMeToken); + return mfpRememberMeServices; + } + + @Bean + PersistentTokenRepository persistentTokenRepository() { + MfpJdbcTokenRepositoryImpl tokenRepository = new MfpJdbcTokenRepositoryImpl(); + return tokenRepository; + } + + + @Bean + PasswordEncoder passwordEncoder() { + return new Sm3PasswordEncoder(); + } + + /** + * 获取AuthenticationManager(认证管理器),登录时认证使用 + * @param authenticationConfiguration + * @return + * @throws Exception + */ + @Bean + AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + @Bean + ObjectMapper objectMapper(){ + return new ObjectMapper(); + } +} diff --git a/src/main/java/com/nantian/mfp/framework/config/WebMvcConfig.java b/src/main/java/com/nantian/mfp/framework/config/WebMvcConfig.java new file mode 100644 index 0000000..810ac2d --- /dev/null +++ b/src/main/java/com/nantian/mfp/framework/config/WebMvcConfig.java @@ -0,0 +1,82 @@ +package com.nantian.mfp.framework.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nantian.mfp.framework.context.MfpContextHolder; +import com.nantian.mfp.framework.converter.MfpFormHttpMessageConverter; +import com.nantian.mfp.framework.utils.RequestUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.util.pattern.PathPattern; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author ganlaifei + * @desc springmvc配置 + * @date 2023/3/15 21:45 + */ +@Configuration +public class WebMvcConfig implements WebMvcConfigurer, CommandLineRunner { + + public Logger logger = LoggerFactory.getLogger(WebMvcConfig.class); + + public static final List patternList = new ArrayList<>(); + + /** + * 将自定义表单消息转换器添加到springmvc的消息转换器列表 + * + * @param converters + */ + @Override + public void configureMessageConverters(List> converters) { + MfpFormHttpMessageConverter converter = new MfpFormHttpMessageConverter(); + converter.setObjectMapper(new ObjectMapper()); + converters.add(converter); + } + + /** + * 启动时加载扫描到的 PathVariable路径 + */ + @Override + public void run(String... args) throws Exception { + try { + RequestMappingHandlerMapping mapping = MfpContextHolder.getBean(RequestMappingHandlerMapping.class); + //获取url与类和方法的对应信息 + Map map = mapping.getHandlerMethods(); + for (RequestMappingInfo info : map.keySet()) { + // 获取url + PatternsRequestCondition pathPatternsCondition = info.getPatternsCondition(); + if (pathPatternsCondition != null) { + Set patterns = pathPatternsCondition.getPatterns() + .stream() + .map(RequestUtils.defaultPathPatternParserInstance::parse) + .collect(Collectors.toSet()); + for (PathPattern pattern : patterns) { + Class aClass = pattern.getClass(); + Field field = aClass.getDeclaredField("capturedVariableCount"); + field.setAccessible(true); + int num = (int) field.get(pattern); + //不为0说明路径包含@PathVariable变量 + if (num != 0) { + patternList.add(pattern); + } + } + } + } + logger.info("加载到{}个PathVariable路径:{}", Integer.valueOf(patternList.size()), patternList); + } catch (Exception e) { + logger.error("加载PathVariable路径失败", e); + } + } +} diff --git a/src/main/java/com/nantian/mfp/framework/security/service/MfpRememberMeServices.java b/src/main/java/com/nantian/mfp/framework/security/service/MfpRememberMeServices.java new file mode 100644 index 0000000..0e13a29 --- /dev/null +++ b/src/main/java/com/nantian/mfp/framework/security/service/MfpRememberMeServices.java @@ -0,0 +1,241 @@ +package com.nantian.mfp.framework.security.service; + +import com.nantian.mfp.framework.constant.SafeConstants; +import com.nantian.mfp.framework.context.MfpContextHolder; +import com.nantian.mfp.framework.err.HttpException; +import com.nantian.mfp.framework.security.authention.MfpAuthenticationDetailsSource; +import com.nantian.mfp.framework.security.repository.MfpJdbcTokenRepositoryImpl; +import com.nantian.mfp.framework.utils.RequestUtils; +import com.nantian.mfp.pub.model.MfpRememberMeToken; +import org.springframework.dao.DataAccessException; +import org.springframework.security.authentication.AuthenticationDetailsSource; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.rememberme.*; +import org.springframework.util.Assert; +import org.springframework.util.Base64Utils; +import org.springframework.util.StringUtils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Date; + +/** + * 记住我自动登录 + * @author gnalaifei + * @date 2023.02.22 + */ +public class MfpRememberMeServices extends AbstractRememberMeServices { + + private PersistentTokenRepository tokenRepository = new InMemoryTokenRepositoryImpl(); + private AuthenticationDetailsSource authenticationDetailsSource = new MfpAuthenticationDetailsSource(); + + private SecureRandom random = new SecureRandom(); + public static final int DEFAULT_SERIES_LENGTH = 16; + public static final int DEFAULT_TOKEN_LENGTH = 16; + private int seriesLength = 16; + private int tokenLength = 16; + + private boolean alwaysRemember = false; + + public MfpRememberMeServices(String key,int tokenValiditySeconds, UserDetailsService userDetailsService, PersistentTokenRepository tokenRepository) { + super(key, userDetailsService); + super.setTokenValiditySeconds(tokenValiditySeconds); + setAuthenticationDetailsSource(authenticationDetailsSource); + this.tokenRepository = tokenRepository; + } + + @Override + protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request, HttpServletResponse response) { + + if (cookieTokens.length != 2) { + throw new InvalidCookieException("Cookie token did not contain " + 2 + + " tokens, but contained '" + Arrays.asList(cookieTokens) + "'"); + } + + String presentedSeries =""; + String presentedToken = cookieTokens[1]; + String clientType="browser"; + if (RequestUtils.isAjaxRequest(request)) { + presentedSeries = request.getHeader(SafeConstants.FW_SAFE_DEVICEID); + clientType="moclient"; + }else{ + presentedSeries = cookieTokens[0]; + } + + MfpRememberMeToken token=(MfpRememberMeToken) tokenRepository.getTokenForSeries(presentedSeries); + + if (token == null) { + // No series match, so we can't authenticate using this cookie + throw new HttpException(475,"tokenCheck105","自动登录身份过期,请重新登录"); + } + + // We have a match for this user/series combination + if (!presentedToken.equals(token.getTokenValue())) { + tokenRepository.removeUserTokens(token.getUsername()); + throw new HttpException(475,"tokenCheck115","自动登录身份异常,请重新登录"); + } + + if (token.getDate().getTime() + getTokenValiditySeconds()*1000L < System.currentTimeMillis()) { + throw new HttpException(475,"tokenCheck120","自动登录身份异常,请重新登录"); + } + + // Token also matches, so login is valid. Update the token value, keeping the *same* series number. + if (logger.isDebugEnabled()) { + logger.debug("Refreshing persistent login token for user '" + token.getUsername() + "', series '" + + token.getSeries() + "'"); + } + + //适应emm统一登录 + if(MfpContextHolder.getProps("server-level")!=null&&MfpContextHolder.getProps("server-level").equals("slave")){ + logger.debug("非主服务器登录,不刷新token"); + }else{ + MfpRememberMeToken newToken = new MfpRememberMeToken(token.getUsername(), token.getSeries(), generateTokenData(), new Date(),clientType); + + try { + tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate()); + addCookie(newToken, request, response); + } catch (DataAccessException e) { + logger.error("Failed to update token: ", e); + throw new RememberMeAuthenticationException("Autologin failed due to data access problem"); + } + } + return getUserDetailsService().loadUserByUsername(token.getUsername()); + } + + @Override + protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { + String username = successfulAuthentication.getName(); + + logger.info("创建token 用户名:" + username); + + MfpRememberMeToken persistentToken=null; + if (RequestUtils.isAjaxRequest(request)&&request.getHeader(SafeConstants.FW_SAFE_DEVICEID)!=null) { + persistentToken= new MfpRememberMeToken(username, request.getHeader(SafeConstants.FW_SAFE_DEVICEID),generateTokenData(), new Date(),"moclient"); + logger.debug("最新token值:"+persistentToken.getTokenValue()); + }else{ + persistentToken= new MfpRememberMeToken(username, generateSeriesData(), generateTokenData(), new Date(),"browser"); + } + + try { + MfpRememberMeToken exToken=((MfpJdbcTokenRepositoryImpl)tokenRepository).checkUserTokens(username); + if(exToken!=null&&exToken.getSeries().equals(persistentToken.getSeries())){ + tokenRepository.createNewToken(persistentToken); + }else{ + //如果同一个用户已经有了另外一台设备,则清楚该设备token + tokenRepository.removeUserTokens(username); + tokenRepository.createNewToken(persistentToken); + } + addCookie(persistentToken, request, response); + } catch (DataAccessException e) { + logger.error("Failed to save persistent token ", e); + } + } + + @Override + public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + super.logout(request, response, authentication); + if (authentication != null) { + this.tokenRepository.removeUserTokens(authentication.getName()); + } + + } + + protected String generateSeriesData() { + byte[] newSeries = new byte[this.seriesLength]; + this.random.nextBytes(newSeries); + return new String(Base64Utils.encode(newSeries)); + } + + protected String generateTokenData() { + byte[] newToken = new byte[this.tokenLength]; + this.random.nextBytes(newToken); + return new String(Base64Utils.encode(newToken)); + } + + private void addCookie(PersistentRememberMeToken token, HttpServletRequest request, HttpServletResponse response) { + this.setCookie(new String[]{token.getSeries(), token.getTokenValue()}, this.getTokenValiditySeconds(), request, response); + } + + public void setSeriesLength(int seriesLength) { + this.seriesLength = seriesLength; + } + + public void setTokenLength(int tokenLength) { + this.tokenLength = tokenLength; + } + + @Override + public void setTokenValiditySeconds(int tokenValiditySeconds) { + Assert.isTrue(tokenValiditySeconds > 0, "tokenValiditySeconds must be positive for this implementation"); + super.setTokenValiditySeconds(tokenValiditySeconds); + } + + + + private void addCookie(MfpRememberMeToken token, HttpServletRequest request, HttpServletResponse response) { + if (RequestUtils.isAjaxRequest(request)) { + setCookie(new String[] {generateSeriesData(), token.getTokenValue()}, getTokenValiditySeconds(), request, response); + }else{ + setCookie(new String[] {token.getSeries(), token.getTokenValue()}, getTokenValiditySeconds(), request, response); + } + } + + /** + * 重写自动登录参数获取,支持ajax请求及自定义参数 + * @param request + * @param parameter + * @return + */ + @Override + protected boolean rememberMeRequested(HttpServletRequest request, String parameter) { + if (this.alwaysRemember) { + return true; + } else { + String paramValue = null; + if(RequestUtils.isAjaxRequest(request)){ + paramValue = (String) request.getAttribute(parameter); + }else{ + paramValue = request.getParameter(parameter); + } + if (paramValue == null || !paramValue.equalsIgnoreCase("true") && !paramValue.equalsIgnoreCase("on") && !paramValue.equalsIgnoreCase("yes") && !paramValue.equals("1")) { + this.logger.debug(String.format("Did not send remember-me cookie (principal did not set parameter '%s')", parameter)); + return false; + } else { + return true; + } + } + } + + /** + * 重写rememberToken获取,支持从header中获取 + * @param request + * @return + */ + @Override + protected String extractRememberMeCookie(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (RequestUtils.isAjaxRequest(request)) { + if(!StringUtils.hasText(request.getHeader(SafeConstants.FW_SAFE_TOKEN))){ + logger.debug("ajax请求header获取MFPToken异常,不进行自动登录操作"); + return null; + } + return request.getHeader(SafeConstants.FW_SAFE_TOKEN); + }else{ + if ((cookies == null) || (cookies.length == 0)) { + return null; + } + for (Cookie cookie : cookies) { + if (super.getCookieName().equals(cookie.getName())) { + return cookie.getValue(); + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/nantian/mfp/framework/utils/RequestUtils.java b/src/main/java/com/nantian/mfp/framework/utils/RequestUtils.java new file mode 100644 index 0000000..69a08bb --- /dev/null +++ b/src/main/java/com/nantian/mfp/framework/utils/RequestUtils.java @@ -0,0 +1,168 @@ +package com.nantian.mfp.framework.utils; + +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; +import com.alibaba.csp.sentinel.slots.block.flow.FlowException; +import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nantian.mfp.framework.config.WebMvcConfig; +import com.nantian.mfp.framework.constant.MfpConstants; +import com.nantian.mfp.framework.context.MfpContextHolder; +import com.nantian.mfp.framework.err.BusinessException; +import com.nantian.mfp.framework.err.HttpException; +import com.nantian.mfp.framework.wrappers.NTNetResetRequestWrapper; +import com.nantian.mfp.pub.model.ResultData; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.MessageSource; +import org.springframework.http.MediaType; +import org.springframework.http.server.PathContainer; +import org.springframework.util.StringUtils; +import org.springframework.web.HttpMediaTypeNotAcceptableException; +import org.springframework.web.accept.HeaderContentNegotiationStrategy; +import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.util.pattern.PathPattern; +import org.springframework.web.util.pattern.PathPatternParser; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class RequestUtils { + + public static Log logger = LogFactory.getLog(RequestUtils.class); + + public static boolean isAjaxRequest(HttpServletRequest request){ + HeaderContentNegotiationStrategy header=new HeaderContentNegotiationStrategy(); + try { + List requestMediaTypes=header.resolveMediaTypes(new ServletWebRequest(request)); + for (MediaType requestMediaType : requestMediaTypes) { + if(MediaType.APPLICATION_JSON.includes(requestMediaType)){ + return true; + }; + } + + } catch (HttpMediaTypeNotAcceptableException e) { + e.printStackTrace(); + } + + return false; + + } + + + public static void writerOutErr(HttpServletRequest req, HttpServletResponse res, ObjectMapper objectMapper, Exception ex) throws IOException, ServletException { + + ResultData resultData=exceptionToResult(ex ,res); + res.setContentType("application/json;charset=UTF-8"); + objectMapper.writeValue(res.getOutputStream(), resultData); + } + + + + public static ResultData exceptionToResult(Exception ex,HttpServletResponse response){ + logger.error("====>>服务异常:",ex); + ResultData resultData = new ResultData(); + resultData.setStatus("-1"); + Object[] args=null; + if(ex instanceof BusinessException){ + BusinessException be=(BusinessException)ex; + args=be.getArgs(); + resultData.setErrCode(be.getTerrcode()); + response.setStatus(487); + }else if(ex instanceof HttpException){ + HttpException he=(HttpException)ex; + args=he.getArgs(); + resultData.setErrCode(he.getTerrcode()); + response.setStatus(he.getStatusCode()); + }else if(ex instanceof ParamFlowException||ex instanceof FlowException){ + ex = new Exception("服务器繁忙,请稍后再试!"); + resultData.setErrCode("FlowException"); + response.setStatus(470); + }else if(ex instanceof DegradeException){ + ex = new Exception("触发熔断规则,服务降级!"); + resultData.setErrCode("DegradeException"); + response.setStatus(470); + }else{ + resultData.setErrCode("SystemError"); + response.setStatus(500); + } + resultData.setTxcode(MfpContextHolder.getTxcode()); + resultData.setFlowNo(MfpContextHolder.getReqFlowNo()); + + MessageSource messageSource = MfpContextHolder.getBean(MessageSource.class); + //消息转义 + String msg = messageSource.getMessage(resultData.getErrCode(), args, ex.getMessage(), Locale.getDefault()); + logger.error("请求流水号["+resultData.getFlowNo()+"],http协议状态码["+response.getStatus()+"],交易码["+resultData.getTxcode()+"],技术错误码["+resultData.getErrCode()+"],转义后的消息["+msg+"]"); + resultData.setErrMsg(msg); + //设置错误码和错误信息到请求线程上下文 + MfpContextHolder.setTerrcode(resultData.getErrCode()); + MfpContextHolder.setErrMessage(msg); + + return resultData; + } + + public static NTNetResetRequestWrapper getRequestWrapper(HttpServletRequest request) { + if(request instanceof NTNetResetRequestWrapper){ + return (NTNetResetRequestWrapper)request; + } + NTNetResetRequestWrapper requestWrapper = null; + try { + requestWrapper = new NTNetResetRequestWrapper(request); + } catch (IOException e) { + logger.error("包装HttpServletRequest对象异常"); + } + return requestWrapper; + } + + /** + * 获取交易码,兼容restful风格 + * @param request + * @return + */ + public static String getTxcdoe(HttpServletRequest request){ + String txcode = request.getParameter(MfpConstants.TX_CODE); + //按照restful风格获取交易码 + if(!StringUtils.hasText(txcode)) { + for (PathPattern pattern : WebMvcConfig.patternList) { + //使用spring工具类判断当前请求路径是否符合缓存的pathPathPattern + String requestURI = request.getRequestURI(); + String contextPath = MfpContextHolder.getProps("server.servlet.context-path"); + //根据url截取项目名称 + if(StringUtils.hasText(contextPath)&&!"/".equals(contextPath)){ + requestURI = requestURI.substring(contextPath.length()); + } + boolean match = pattern.matches(PathContainer.parsePath(requestURI)); + if (match) { + //解析pathPathPattern uri获取txcode + PathPattern.PathMatchInfo pathMatchInfo = pattern.matchAndExtract(PathContainer.parsePath(requestURI)); + Map uriVariablesMap = pathMatchInfo.getUriVariables(); + return uriVariablesMap.get(MfpConstants.TX_CODE); + } + } + } + return txcode; + } + + public static final PathPatternParser defaultPathPatternParserInstance = new PathPatternParser() { + + @Override + public void setMatchOptionalTrailingSeparator(boolean matchOptionalTrailingSeparator) { + raiseError(); + } + + @Override + public void setCaseSensitive(boolean caseSensitive) { + raiseError(); + } + + private void raiseError() { + throw new UnsupportedOperationException( + "This is a read-only, shared instance that cannot be modified"); + } + }; + +} diff --git a/src/main/java/com/nantian/mfp/pub/service/DbSequenceService.java b/src/main/java/com/nantian/mfp/pub/service/DbSequenceService.java new file mode 100644 index 0000000..0ac1615 --- /dev/null +++ b/src/main/java/com/nantian/mfp/pub/service/DbSequenceService.java @@ -0,0 +1,90 @@ +package com.nantian.mfp.pub.service; + +import com.nantian.mfp.framework.config.DbSequenceConfig; +import com.nantian.mfp.framework.context.MfpContextHolder; +import com.nantian.mfp.pub.dao.SequenceDao; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +/** +* +* @desc 数据库sequence生成工具 +* @author ganlaifei +* @date 2023/4/7 21:33 +*/ +@Service +@ConditionalOnBean(DbSequenceConfig.class) +public class DbSequenceService { + + @Autowired + SequenceDao sequenceDao; + + static Log log= LogFactory.getLog(SequenceService.class); + + /** + * 交易流水号 + * @return + */ + public static String genTxFlowNo() { + String txFlowNo= UUID.randomUUID().toString(); + MfpContextHolder.setTxFlowNo(txFlowNo); + return txFlowNo; + } + /** + * 交易流水号 + * @return + */ + public String getTxFlowNo() { + return (String) MfpContextHolder.getTxFlowNo(); + } + public String getGlobalFlowNo() { + return sequenceDao.generate("全局事件跟踪号", "_globalFlowNo", 10, 1, "GL{yyyy}{mm}{dd}", ""); + } + + public String getTablePK(String tableName, String colunm) { + return sequenceDao.generate("数据库表格的某个字段的序号","_"+tableName+"_"+colunm , 10, 1, "TB", ""); + } + + /** + * 生成16位流水号,其中8位时间戳{yyyy}{mm}{dd},后八位为按日复位的递增序号如00000001,00000002,返回的序号为 2015032000000001等 + * @param tableName + * @param colunm + * @return 返回的流水号 其中8位时间戳{yyyy}{mm}{dd},后八位为按日复位的递增序号如00000001,00000002,返回的序号为 2015032000000001等 + */ + public String getTableFlowNo(String tableName, String colunm) { + return sequenceDao.generate("数据库表格的某个字段的序号","_"+tableName+"_"+colunm , 8, 4, "{yyyy}{mm}{dd}", ""); + } + + public String getTableSquence(String tableName, String colunm) { + return sequenceDao.generate("数据库表格的某个字段的序号","_"+tableName+"_"+colunm , 10, 1, "0", ""); + } + + public List getTableBatchSquence(String tableName, String colunm, int count) { + return sequenceDao.batchGenerate("数据库表格的某个字段的序号","_"+tableName+"_"+colunm , 10, 1, "0", "",count); + } + + + public String getReqFlowNo() { + return (String) MfpContextHolder.getReqFlowNo(); + } + + public String genReqFlowNo(){ + String reqFlowNo=getGlobalFlowNo(); + MfpContextHolder.setReqFlowNo(reqFlowNo); + return reqFlowNo; + + } + public String generate(String seqDefid) { + return sequenceDao.generate(seqDefid); + } + + public List batchGenerate(String seqDefid, int count) { + return sequenceDao.batchGenerate(seqDefid, count); + } +} diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties new file mode 100644 index 0000000..335ac59 --- /dev/null +++ b/src/main/resources/application-dev.properties @@ -0,0 +1,110 @@ +################################################# +##dev环境的配置 +################################################## +spring.application.name=MfpSofaBootDemo + +############数据库连接信息############## +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.url=jdbc:mysql://localhost:3306/sofa-mfp?characterEncoding=UTF-8&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8 +spring.datasource.username=root +spring.datasource.password=zhouxy108 +###################以下为druid增加的配置########################### +spring.datasource.type=com.alibaba.druid.pool.DruidDataSource +#初始化连接池大小 +spring.datasource.initialSize=5 +#最小空闲连接池数量 +spring.datasource.minIdle=5 +#最大连接数量 +spring.datasource.maxActive=60 +#配置获取连接等待超时的时间,单位毫秒 +spring.datasource.maxWait=20000 +#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 +spring.datasource.timeBetweenEvictionRunsMillis=60000 +#配置一个连接在池中最小生存的时间,单位是毫秒 +spring.datasource.minEvictableIdleTimeMillis=300000 +#验证查询 +spring.datasource.validationQuery=select 1 +#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。默认:true +spring.datasource.testWhileIdle=true +#申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能。默认:false(如果test-on-borrow为true,那么test-while-idle无效) +spring.datasource.testOnBorrow=false +#归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能。默认:false +spring.datasource.testOnReturn=false +#开启PreparedStatement缓存,该配置可提高性能 +spring.datasource.poolPreparedStatements=true +#指定PreparedStatements最大缓存大小 +spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 +# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 +spring.datasource.filters=stat,wall +# 通过connectProperties属性来打开mergeSql功能;慢SQL记录 +spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +# 合并多个DruidDataSource的监控数据 +#spring.datasource.useGlobalDataSourceStat=true + + +################spring data redis相关配置################ +#redis ip +#spring.redis.host=localhost +#redis port +#spring.redis.port=6379 +#redis密码 +#spring.redis.password= +#连接池最大连接数(使用负值表示没有限制) +#spring.redis.pool.max-active=50 +#连接池最大阻塞等待时间(使用负值表示没有限制) +#spring.redis.pool.max-wait=100 +#连接池中的最大空闲连接 +#spring.redis.pool.max-idle=10 +#连接池中的最小空闲连接 +#spring.redis.pool.min-idle=10 +#连接超时时间(毫秒) +#spring.redis.timeout=1000 + +########################nacos服务注册#################### +#服务注册名 +#spring.application.name=mfpcloud +#服务注册地址 +#spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 +#指定命令空间,同一命名空间下服务可相互发现,不指定命名空间默认所有服务可见 +#spring.cloud.nacos.discovery.namespace=d1ca7ebe-6f58-4669-aeec-8c3e62cd0ca3 + +########################nacos配置中心##################### +#spring.cloud.nacos.config.server-addr=127.0.0.1:8848 +#spring.config.import=nacos:mfpcloud.properties?group=DEFAULT_GROUP&&refreshEnabled=true + + + +#######################sentinel########################## +#配置sentinel控制台地址 +#spring.cloud.sentinel.transport.dashboard=localhost:8080 +#取消Sentinel控制台懒加载 +#spring.cloud.sentinel.eager=true +#配置sentinel日目录 +#spring.cloud.sentinel.log.dir=./logs/sentinel/ + +#流控 +#spring.cloud.sentinel.datasource.flow.nacos.server-addr=localhost:8848 +#spring.cloud.sentinel.datasource.flow.nacos.data-id=${spring.application.name}-flow-rules +#spring.cloud.sentinel.datasource.flow.nacos.group-id=SENTINEL_GROUP +#spring.cloud.sentinel.datasource.flow.nacos.rule-type=flow +#熔断 +#spring.cloud.sentinel.datasource.degrade.nacos.server-addr=localhost:8848 +#spring.cloud.sentinel.datasource.degrade.nacos.data-id=${spring.application.name}-degrade-rules +#spring.cloud.sentinel.datasource.degrade.nacos.group-id=SENTINEL_GROUP +#spring.cloud.sentinel.datasource.degrade.nacos.rule-type=degrade +#全局流控 +#spring.cloud.sentinel.datasource.system.nacos.server-addr=localhost:8848 +#spring.cloud.sentinel.datasource.system.nacos.data-id=${spring.application.name}-system-rules +#spring.cloud.sentinel.datasource.system.nacos.group-id=SENTINEL_GROUP +#spring.cloud.sentinel.datasource.system.nacos.rule-type=system +#授权 +#spring.cloud.sentinel.datasource.authority.nacos.server-addr=localhost:8848 +#spring.cloud.sentinel.datasource.authority.nacos.data-id=${spring.application.name}-authority-rules +#spring.cloud.sentinel.datasource.authority.nacos.group-id=SENTINEL_GROUP +#spring.cloud.sentinel.datasource.authority.nacos.rule-type=authority +#热点参数 +#spring.cloud.sentinel.datasource.param-flow.nacos.server-addr=localhost:8848 +#spring.cloud.sentinel.datasource.param-flow.nacos.data-id=${spring.application.name}-param-flow-rules +#spring.cloud.sentinel.datasource.param-flow.nacos.group-id=SENTINEL_GROUP +#spring.cloud.sentinel.datasource.param-flow.nacos.rule-type=param_flow + diff --git a/src/main/resources/application-diff.properties b/src/main/resources/application-diff.properties new file mode 100644 index 0000000..3af78a9 --- /dev/null +++ b/src/main/resources/application-diff.properties @@ -0,0 +1,8 @@ +############################################ +#该文件用来保存因部署环境不同导致的差异配置 +############################################ + +#整型机器id,最多不超过3位数字,分布式部署时每台机器id应保持不同 +machine.id=1 + + diff --git a/src/main/resources/application-dmy.properties b/src/main/resources/application-dmy.properties new file mode 100644 index 0000000..eb98682 --- /dev/null +++ b/src/main/resources/application-dmy.properties @@ -0,0 +1,5 @@ +################################################# +#外呼挡板配置文件,仅在测试环境使用 +#示例:dummy.T12345601=true +################################################# +dummy.B00001=false \ No newline at end of file diff --git a/src/main/resources/application-flow.properties b/src/main/resources/application-flow.properties new file mode 100644 index 0000000..f8ef3e8 --- /dev/null +++ b/src/main/resources/application-flow.properties @@ -0,0 +1,11 @@ +################################################# +#流控参数设置,单交易流控设置如下: +#flowctrl.tx.交易码=100 +################################################# + +#是否开启全局流控 on/off +flowctrl.globalEnable=on +#全局流控参数 +lowctrl.globalNum=200 +#是否开启单交易流控参数 +flowctrl.txEnable=off diff --git a/src/main/resources/application-pro.properties b/src/main/resources/application-pro.properties new file mode 100644 index 0000000..852328e --- /dev/null +++ b/src/main/resources/application-pro.properties @@ -0,0 +1,3 @@ +################################################# +#生产环境的配置 +################################################# \ No newline at end of file diff --git a/src/main/resources/application-uat.properties b/src/main/resources/application-uat.properties new file mode 100644 index 0000000..03a6a5d --- /dev/null +++ b/src/main/resources/application-uat.properties @@ -0,0 +1,3 @@ +################################################# +#uat环境的配置 +################################################# \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..6d908af --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,48 @@ +################################################# +#每个环境都相同的配置放在此配置文件中 +################################################# +spring.application.name=MfpSofaBootDemo +#加载指定环境的配置环境的配置文件 +spring.profiles.active=dev +#加载分布式部署时差异配置文件和流控文件 +spring.profiles.include=diff,flow,dmy +#服务端口 +server.port=8081 +#服务上下文 +server.servlet.context-path=/ +#开启spring循环依赖 +spring.main.allow-circular-references=true +#关闭freemarker模板位置检查 +spring.freemarker.checkTemplateLocation=false +#启动后加载dispatcher servlet +spring.mvc.servlet.load-on-startup=1 +#默认关闭sentinel限流 +spring.cloud.sentinel.enabled=false +#默认关闭nacos服务注册 +spring.cloud.nacos.discovery.enabled=false +#默认关闭nacos配置检查 +spring.cloud.nacos.config.import-check.enabled=false +#视图前缀 +spring.mvc.view.prefix=/WEB-INF/ +#视图后缀 +spring.mvc.view.suffix=.jsp +#开启数据库交易流水日志记录 +mfp.system.translog.switch=off +#spring session存储类型(jdbc或redis) +mfp.session.store-type=jdbc +#session超时时间(单位秒) +mfp.session.timeout=1200 +#是否启用jndi,on/off +mfp.datasource.jndi.switch=off +#jndi名称 +mfp.datasource.jndi.name=jdbc/fuws_bank +#开启数据库sequence生成 +mfp.database.sequence.allow=false +#使用自定义登录校验逻辑 +mfp.custom.login.check.service=false +#使用自定义登录成功回调 +mfp.custom.login.success.handler=false +#自定义登出业务逻辑处理 +mfp.custom.logout.deal.handler=false +#自定义登出成功的回调 +mfp.custom.logout.success.handler=false \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..af8681e --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,52 @@ + + + + + + + + [%-d{yyyyMMdd HHmmss}][%p][%X{reqFlowNo}][%X{txcode}][%F:%M:%L]%m%n + + logs + + mfpcloud + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/template/common/SEND_B00001.ftl b/src/main/resources/template/common/SEND_B00001.ftl new file mode 100644 index 0000000..d04be75 --- /dev/null +++ b/src/main/resources/template/common/SEND_B00001.ftl @@ -0,0 +1 @@ +{"abc":"${name}"} \ No newline at end of file diff --git a/src/main/resources/template/common/SEND_demo.ftl b/src/main/resources/template/common/SEND_demo.ftl new file mode 100644 index 0000000..da48119 --- /dev/null +++ b/src/main/resources/template/common/SEND_demo.ftl @@ -0,0 +1 @@ +${abc}${user} \ No newline at end of file diff --git a/src/main/resources/template/dummy/RECV_B00001.ftl b/src/main/resources/template/dummy/RECV_B00001.ftl new file mode 100644 index 0000000..1a0bdec --- /dev/null +++ b/src/main/resources/template/dummy/RECV_B00001.ftl @@ -0,0 +1 @@ +{"abc":"jack"} \ No newline at end of file