后端部分代码

This commit is contained in:
sunxingye 2023-07-28 14:54:28 +08:00
parent 939ee40433
commit b6ee6ad658
117 changed files with 11674 additions and 0 deletions

311
.gitignore vendored
View File

@ -21,3 +21,314 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Created by https://www.toptal.com/developers/gitignore/api/java,maven,vuejs,node,jetbrains
# Edit at https://www.toptal.com/developers/gitignore?templates=java,maven,vuejs,node,jetbrains
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
### JetBrains ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### JetBrains Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/
# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml
# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
.idea/**/azureSettings.xml
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# Eclipse m2e generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Node ###
# Logs
logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
### Vuejs ###
# Recommended template: Node.gitignore
dist/
npm-debug.log
yarn-error.log
# End of https://www.toptal.com/developers/gitignore/api/java,maven,vuejs,node,jetbrains
.idea/

95
joint-cloud-auth/pom.xml Normal file
View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>joint-cloud</artifactId>
<groupId>com.joint.cloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>joint-cloud-auth</artifactId>
<name>joint-cloud-auth</name>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- mysqljdbc驱动 ,这个是数据库连接池需要的-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,14 @@
package com.joint.cloud.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class AuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServerApplication.class, args);
}
}

View File

@ -0,0 +1,85 @@
package com.joint.cloud.auth.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@Configuration
public class AccessCheckRedisConfig {
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Bean({"licenseRedisTemplate"})
public RedisTemplate<String, Object> redisTemplate() {
//配置项目应该与license信息保持一致
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//key采用String序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//value采用fast-json序列化方式
RedisSerializer<Object> fastJson2JsonRedisSerializer = fastJson2JsonRedisSerializer();
redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
return container;
}
private RedisSerializer<Object> fastJson2JsonRedisSerializer() {
return new FastJson2JsonRedisSerializer<>(Object.class);
}
static class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz, Feature.SupportAutoType);
}
}
}

View File

@ -0,0 +1,24 @@
package com.joint.cloud.auth.config;
import com.joint.cloud.auth.config.custom.CustomAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter;
/**
* @author keets
* @date 2017/9/25
*/
@Configuration
public class AuthenticationManagerConfig extends GlobalAuthenticationConfigurerAdapter {
@Autowired
CustomAuthenticationProvider customAuthenticationProvider;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
}

View File

@ -0,0 +1,100 @@
package com.joint.cloud.auth.config;
import com.joint.cloud.auth.config.custom.CustomJwtAccessTokenConverter;
import com.joint.cloud.auth.config.custom.CustomRedisTokenStore;
import com.joint.cloud.auth.config.impl.ClientDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
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.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
/**
* @description:
* @author: super.wu
* @date: Created in 2018/5/4 0004
* @modified By:
* @version: 1.0
**/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
/**
* 认证管理器当你选择了资源所有者密码password授权类型的时候
* 请设置这个属性注入一个 AuthenticationManager 对象
*/
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
RedisConnectionFactory redisConnectionFactory;
/**
* 配置令牌端点(Token Endpoint)的安全约束.
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
/**
* 配置客户端详情服务ClientDetailsService客户端详情信息在这里进行初始化你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(getClientDetailsService());
}
/**
* 配置授权authorization以及令牌token的访问端点和令牌服务(token services)
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
/**
* 使用Jwt的方式生成token
* @return
*/
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
CustomJwtAccessTokenConverter converter = new CustomJwtAccessTokenConverter();
converter.setSigningKey("secret");
return converter;
}
@Bean
public TokenStore tokenStore() {
return new CustomRedisTokenStore(redisConnectionFactory);
}
@Bean
public ClientDetailsService getClientDetailsService() {
return new ClientDetailsServiceImpl();
}
}

View File

@ -0,0 +1,37 @@
package com.joint.cloud.auth.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import javax.servlet.http.HttpServletResponse;
/**
* @description:
* @author: super.wu
* @date: Created in 2018/5/25 0025
* @modified By:
* @version: 1.0
**/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET,"/health/**").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}

View File

@ -0,0 +1,53 @@
package com.joint.cloud.auth.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class WebLogAspect {
private final Logger logger = LoggerFactory.getLogger("apiLogger");
@Pointcut("execution(public * com.joint.cloud.auth.controller..*.*(..))")//切入点描述 这个是controller包的切入点
public void controllerLog(){}//签名可以理解成这个切入点的一个名称
// @Pointcut("execution(public * com.stuPayment.uiController..*.*(..))")//切入点描述这个是uiController包的切入点
// public void uiControllerLog(){}
@Before("controllerLog()") //在切入点的方法run之前要干的
public void logBeforeController(JoinPoint joinPoint) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//这个RequestContextHolder是Springmvc提供来获得请求的东西
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
// 过滤 health check
if ("com.joint.cloud.auth.controller.HealthController".equals(joinPoint.getSignature().getDeclaringTypeName())) {
return;
}
// 记录下请求内容
logger.info("### URL : " + request.getRequestURL().toString());
logger.info("### HTTP_METHOD : " + request.getMethod());
logger.info("### IP : " + request.getRemoteAddr());
// logger.info("################THE ARGS OF THE CONTROLLER : " + Arrays.toString(joinPoint.getArgs()));
//下面这个getSignature().getDeclaringTypeName()是获取包+类名的 然后后面的joinPoint.getSignature.getName()获取了方法名
logger.info("### CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//logger.info("################TARGET: " + joinPoint.getTarget());//返回的是需要加强的目标类的对象
//logger.info("################THIS: " + joinPoint.getThis());//返回的是经过加强后的代理类的对象
}
}

View File

@ -0,0 +1,47 @@
package com.joint.cloud.auth.config;
import com.joint.cloud.auth.config.encoder.MyPasswordEncoder;
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.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.password.PasswordEncoder;
/**
* @description:
* @author: super.wu
* @date: Created in 2018/5/4 0004
* @modified By:
* @version: 1.0
**/
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
/**
* 设置获取token的url
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated().and()
.httpBasic().and().csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new MyPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

View File

@ -0,0 +1,65 @@
package com.joint.cloud.auth.config.custom;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeSet;
/**
* @author lilengyi
* @date 2020/8/11 16:17
*/
public class CustomAuthenticationKeyGenerator implements AuthenticationKeyGenerator {
private static final String CLIENT_ID = "client_id";
private static final String SCOPE = "scope";
private static final String USERNAME = "username";
public CustomAuthenticationKeyGenerator() {
}
@Override
public String extractKey(OAuth2Authentication authentication) {
Map<String, String> values = new LinkedHashMap();
OAuth2Request authorizationRequest = authentication.getOAuth2Request();
if (!authentication.isClientOnly()) {
values.put("username", authentication.getName());
}
values.put("client_id", authorizationRequest.getClientId());
if (authorizationRequest.getScope() != null) {
values.put("scope", OAuth2Utils.formatParameterList(new TreeSet(authorizationRequest.getScope())));
}
CustomUserDetails userDetails = (CustomUserDetails) authentication.getUserAuthentication().getPrincipal();
if (null != userDetails.getUserId()) {
values.put("userId", userDetails.getUserId());
}
Map<String, String> parameters = authorizationRequest.getRequestParameters();
if (null != parameters && parameters.containsKey("client")) {
values.put("client", parameters.get("client"));
}
return this.generateKey(values);
}
protected String generateKey(Map<String, String> values) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bytes = digest.digest(values.toString().getBytes("UTF-8"));
return String.format("%032x", new BigInteger(1, bytes));
} catch (NoSuchAlgorithmException var4) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).", var4);
} catch (UnsupportedEncodingException var5) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).", var5);
}
}
}

View File

@ -0,0 +1,102 @@
package com.joint.cloud.auth.config.custom;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Map;
/**
* 认证管理
*
* @author keets
* @date 2017/8/5
*/
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Resource(name = "licenseRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;
private HashOperations<String, String, Object> hashOperations;
@PostConstruct
private void init() {
hashOperations = redisTemplate.opsForHash();
}
private static final String CMP_LICENSE_CHECK = "CMP_ACCESS_CHECK";
private final static String LICENSE_STATUS = "LICENSE_STATUS";
private final static String LICENSE_INVALID = "LICENSE_INVALID";
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
Map data;
if (authentication.getDetails() instanceof Map) {
data = (Map) authentication.getDetails();
} else {
return null;
}
String clientId = (String) data.get("client");
Assert.hasText(clientId, "clientId must have value");
String password = (String) authentication.getCredentials();
try {
userDetailsService.loadUserByUsername(username);
} catch (NoSuchClientException | UsernameNotFoundException e) {
throw new BadCredentialsException("用户名错误");
}
CustomUserDetails customUserDetails = checkUsernameAndPassword(username, password);
if (customUserDetails == null) {
throw new BadCredentialsException("用户名或密码错误");
}
/**
* 如果是非超级管理员 && 证书过期不允许登录
* 如果是超级管理员 && 证书过期允许登录只访问许可证书菜单
*/
String licenseStatus = this.getCheckStatus(LICENSE_STATUS);
// if(!StringUtils.hasLength(licenseStatus)){
// throw new LicenseStatusException("后台服务未启动,请稍后重试");
// } else if (LICENSE_INVALID.equals(licenseStatus) && !customUserDetails.getRoles().contains("SUPER_ADMIN_ROLE")) {
// throw new LicenseStatusException("许可证书已过期");
// }
customUserDetails.setClientId(clientId);
return new CustomAuthenticationToken(customUserDetails);
}
private CustomUserDetails checkUsernameAndPassword(String username, String password) {
CustomUserDetails userDetails = (CustomUserDetails) userDetailsService.loadUserByUsername(username);
if (userDetails == null || !userDetails.getPassword().equals(password)) {
return null;
}
return userDetails;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
private String getCheckStatus(String id) {
return (String) hashOperations.get(CMP_LICENSE_CHECK, id);
}
}

View File

@ -0,0 +1,28 @@
package com.joint.cloud.auth.config.custom;
import org.springframework.security.authentication.AbstractAuthenticationToken;
/**
* Created by keets on 2017/8/5.
*/
public class CustomAuthenticationToken extends AbstractAuthenticationToken {
private CustomUserDetails userDetails;
public CustomAuthenticationToken(CustomUserDetails userDetails) {
super(null);
this.userDetails = userDetails;
super.setAuthenticated(true);
}
@Override
public Object getPrincipal() {
return this.userDetails;
}
@Override
public Object getCredentials() {
return this.userDetails.getPassword();
}
}

View File

@ -0,0 +1,44 @@
package com.joint.cloud.auth.config.custom;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import java.util.HashMap;
import java.util.Map;
/**
* @description: 自定义token生成
* @author: super.wu
* @date: Created in 2018/5/7 0007
* @modified By:
* @version: 1.0
**/
public class CustomJwtAccessTokenConverter extends JwtAccessTokenConverter {
private static final int authenticateCodeExpiresTime = 10 * 60;
private static final String TOKEN_SEG_USER_ID = "X-AOHO-UserId";
private static final String TOKEN_SEG_CLIENT = "X-AOHO-ClientId";
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
CustomUserDetails userDetails = (CustomUserDetails) authentication.getUserAuthentication().getPrincipal();
authentication.getUserAuthentication().getPrincipal();
Map<String, Object> info = new HashMap<String, Object>(2) {{
put(TOKEN_SEG_USER_ID, userDetails.getUserId());
put("roles", String.join(",", userDetails.getRoles()));
put("name",userDetails.getName());
}};
DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
customAccessToken.setAdditionalInformation(info);
OAuth2AccessToken enhancedToken = super.enhance(customAccessToken, authentication);
enhancedToken.getAdditionalInformation().put(TOKEN_SEG_CLIENT, userDetails.getClientId());
return enhancedToken;
}
}

View File

@ -0,0 +1,396 @@
package com.joint.cloud.auth.config.custom;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.JdkSerializationStrategy;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStoreSerializationStrategy;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* <Description> 重写tokenStore .因为最新版中RedisTokenStore的set已经被弃用了
* 所以我就只能自定义一个代码和RedisTokenStore一样
* 只是把所有conn.set()都换成conn..stringCommands().set()
* <br>
*
* @author fb<br>
* @version 1.0<br>
* @taskId <br>
* @CreateDate Create in 10:59 2018/2/13
* @since V1.0<br>
*/
@Component
public class CustomRedisTokenStore implements TokenStore {
private static final String ACCESS = "access:";
private static final String AUTH_TO_ACCESS = "auth_to_access:";
private static final String AUTH = "auth:";
private static final String REFRESH_AUTH = "refresh_auth:";
private static final String ACCESS_TO_REFRESH = "access_to_refresh:";
private static final String REFRESH = "refresh:";
private static final String REFRESH_TO_ACCESS = "refresh_to_access:";
private static final String CLIENT_ID_TO_ACCESS = "client_id_to_access:";
private static final String UNAME_TO_ACCESS = "uname_to_access:";
private final RedisConnectionFactory connectionFactory;
private AuthenticationKeyGenerator authenticationKeyGenerator = new CustomAuthenticationKeyGenerator();
private RedisTokenStoreSerializationStrategy serializationStrategy = new JdkSerializationStrategy();
private String prefix = "";
public CustomRedisTokenStore(RedisConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public void setAuthenticationKeyGenerator(AuthenticationKeyGenerator authenticationKeyGenerator) {
this.authenticationKeyGenerator = authenticationKeyGenerator;
}
public void setSerializationStrategy(RedisTokenStoreSerializationStrategy serializationStrategy) {
this.serializationStrategy = serializationStrategy;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
private RedisConnection getConnection() {
return this.connectionFactory.getConnection();
}
private byte[] serialize(Object object) {
return this.serializationStrategy.serialize(object);
}
private byte[] serializeKey(String object) {
return this.serialize(this.prefix + object);
}
private OAuth2AccessToken deserializeAccessToken(byte[] bytes) {
return (OAuth2AccessToken)this.serializationStrategy.deserialize(bytes, OAuth2AccessToken.class);
}
private OAuth2Authentication deserializeAuthentication(byte[] bytes) {
return (OAuth2Authentication)this.serializationStrategy.deserialize(bytes, OAuth2Authentication.class);
}
private OAuth2RefreshToken deserializeRefreshToken(byte[] bytes) {
return (OAuth2RefreshToken)this.serializationStrategy.deserialize(bytes, OAuth2RefreshToken.class);
}
private byte[] serialize(String string) {
return this.serializationStrategy.serialize(string);
}
private String deserializeString(byte[] bytes) {
return this.serializationStrategy.deserializeString(bytes);
}
@Override
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
String key = this.authenticationKeyGenerator.extractKey(authentication);
byte[] serializedKey = this.serializeKey(AUTH_TO_ACCESS + key);
byte[] bytes = null;
RedisConnection conn = this.getConnection();
try {
bytes = conn.get(serializedKey);
} finally {
conn.close();
}
OAuth2AccessToken accessToken = this.deserializeAccessToken(bytes);
if (accessToken != null) {
OAuth2Authentication storedAuthentication = this.readAuthentication(accessToken.getValue());
if (storedAuthentication == null || !key.equals(this.authenticationKeyGenerator.extractKey(storedAuthentication))) {
this.storeAccessToken(accessToken, authentication);
}
}
return accessToken;
}
@Override
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
return this.readAuthentication(token.getValue());
}
@Override
public OAuth2Authentication readAuthentication(String token) {
byte[] bytes = null;
RedisConnection conn = this.getConnection();
try {
bytes = conn.get(this.serializeKey("auth:" + token));
} finally {
conn.close();
}
OAuth2Authentication auth = this.deserializeAuthentication(bytes);
return auth;
}
@Override
public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
return this.readAuthenticationForRefreshToken(token.getValue());
}
public OAuth2Authentication readAuthenticationForRefreshToken(String token) {
RedisConnection conn = getConnection();
try {
byte[] bytes = conn.get(serializeKey(REFRESH_AUTH + token));
OAuth2Authentication auth = deserializeAuthentication(bytes);
return auth;
} finally {
conn.close();
}
}
@Override
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
byte[] serializedAccessToken = serialize(token);
byte[] serializedAuth = serialize(authentication);
byte[] accessKey = serializeKey(ACCESS + token.getValue());
byte[] authKey = serializeKey(AUTH + token.getValue());
byte[] authToAccessKey = serializeKey(AUTH_TO_ACCESS + authenticationKeyGenerator.extractKey(authentication));
byte[] approvalKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(authentication));
byte[] clientId = serializeKey(CLIENT_ID_TO_ACCESS + authentication.getOAuth2Request().getClientId());
RedisConnection conn = getConnection();
try {
conn.openPipeline();
conn.stringCommands().set(accessKey, serializedAccessToken);
conn.stringCommands().set(authKey, serializedAuth);
conn.stringCommands().set(authToAccessKey, serializedAccessToken);
if (!authentication.isClientOnly()) {
conn.rPush(approvalKey, serializedAccessToken);
}
conn.rPush(clientId, serializedAccessToken);
if (token.getExpiration() != null) {
int seconds = token.getExpiresIn();
conn.expire(accessKey, seconds);
conn.expire(authKey, seconds);
conn.expire(authToAccessKey, seconds);
conn.expire(clientId, seconds);
conn.expire(approvalKey, seconds);
}
OAuth2RefreshToken refreshToken = token.getRefreshToken();
if (refreshToken != null && refreshToken.getValue() != null) {
byte[] refresh = serialize(token.getRefreshToken().getValue());
byte[] auth = serialize(token.getValue());
byte[] refreshToAccessKey = serializeKey(REFRESH_TO_ACCESS + token.getRefreshToken().getValue());
conn.stringCommands().set(refreshToAccessKey, auth);
byte[] accessToRefreshKey = serializeKey(ACCESS_TO_REFRESH + token.getValue());
conn.stringCommands().set(accessToRefreshKey, refresh);
if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
ExpiringOAuth2RefreshToken expiringRefreshToken = (ExpiringOAuth2RefreshToken) refreshToken;
Date expiration = expiringRefreshToken.getExpiration();
if (expiration != null) {
int seconds = Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L)
.intValue();
conn.expire(refreshToAccessKey, seconds);
conn.expire(accessToRefreshKey, seconds);
}
}
}
conn.closePipeline();
} finally {
conn.close();
}
}
private static String getApprovalKey(OAuth2Authentication authentication) {
String userName = authentication.getUserAuthentication() == null ? "": authentication.getUserAuthentication().getName();
return getApprovalKey(authentication.getOAuth2Request().getClientId(), userName);
}
private static String getApprovalKey(String clientId, String userName) {
return clientId + (userName == null ? "" : ":" + userName);
}
@Override
public void removeAccessToken(OAuth2AccessToken accessToken) {
this.removeAccessToken(accessToken.getValue());
}
@Override
public OAuth2AccessToken readAccessToken(String tokenValue) {
byte[] key = serializeKey(ACCESS + tokenValue);
byte[] bytes = null;
RedisConnection conn = getConnection();
try {
bytes = conn.get(key);
} finally {
conn.close();
}
OAuth2AccessToken accessToken = deserializeAccessToken(bytes);
return accessToken;
}
public void removeAccessToken(String tokenValue) {
byte[] accessKey = serializeKey(ACCESS + tokenValue);
byte[] authKey = serializeKey(AUTH + tokenValue);
byte[] accessToRefreshKey = serializeKey(ACCESS_TO_REFRESH + tokenValue);
RedisConnection conn = getConnection();
try {
conn.openPipeline();
conn.get(accessKey);
conn.get(authKey);
conn.del(accessKey);
conn.del(accessToRefreshKey);
// Don't remove the refresh token - it's up to the caller to do that
conn.del(authKey);
List<Object> results = conn.closePipeline();
byte[] access = (byte[]) results.get(0);
byte[] auth = (byte[]) results.get(1);
OAuth2Authentication authentication = deserializeAuthentication(auth);
if (authentication != null) {
String key = authenticationKeyGenerator.extractKey(authentication);
byte[] authToAccessKey = serializeKey(AUTH_TO_ACCESS + key);
byte[] unameKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(authentication));
byte[] clientId = serializeKey(CLIENT_ID_TO_ACCESS + authentication.getOAuth2Request().getClientId());
conn.openPipeline();
conn.del(authToAccessKey);
conn.lRem(unameKey, 1, access);
conn.lRem(clientId, 1, access);
conn.del(serialize(ACCESS + key));
conn.closePipeline();
}
} finally {
conn.close();
}
}
@Override
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
byte[] refreshKey = serializeKey(REFRESH + refreshToken.getValue());
byte[] refreshAuthKey = serializeKey(REFRESH_AUTH + refreshToken.getValue());
byte[] serializedRefreshToken = serialize(refreshToken);
RedisConnection conn = getConnection();
try {
conn.openPipeline();
conn.stringCommands().set(refreshKey, serializedRefreshToken);
conn.stringCommands().set(refreshAuthKey, serialize(authentication));
if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
ExpiringOAuth2RefreshToken expiringRefreshToken = (ExpiringOAuth2RefreshToken) refreshToken;
Date expiration = expiringRefreshToken.getExpiration();
if (expiration != null) {
int seconds = Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L)
.intValue();
conn.expire(refreshKey, seconds);
conn.expire(refreshAuthKey, seconds);
}
}
conn.closePipeline();
} finally {
conn.close();
}
}
@Override
public OAuth2RefreshToken readRefreshToken(String tokenValue) {
byte[] key = serializeKey(REFRESH + tokenValue);
byte[] bytes = null;
RedisConnection conn = getConnection();
try {
bytes = conn.get(key);
} finally {
conn.close();
}
OAuth2RefreshToken refreshToken = deserializeRefreshToken(bytes);
return refreshToken;
}
@Override
public void removeRefreshToken(OAuth2RefreshToken refreshToken) {
this.removeRefreshToken(refreshToken.getValue());
}
public void removeRefreshToken(String tokenValue) {
byte[] refreshKey = serializeKey(REFRESH + tokenValue);
byte[] refreshAuthKey = serializeKey(REFRESH_AUTH + tokenValue);
byte[] refresh2AccessKey = serializeKey(REFRESH_TO_ACCESS + tokenValue);
byte[] access2RefreshKey = serializeKey(ACCESS_TO_REFRESH + tokenValue);
RedisConnection conn = getConnection();
try {
conn.openPipeline();
conn.del(refreshKey);
conn.del(refreshAuthKey);
conn.del(refresh2AccessKey);
conn.del(access2RefreshKey);
conn.closePipeline();
} finally {
conn.close();
}
}
@Override
public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
this.removeAccessTokenUsingRefreshToken(refreshToken.getValue());
}
private void removeAccessTokenUsingRefreshToken(String refreshToken) {
byte[] key = serializeKey(REFRESH_TO_ACCESS + refreshToken);
List<Object> results = null;
RedisConnection conn = getConnection();
try {
conn.openPipeline();
conn.get(key);
conn.del(key);
results = conn.closePipeline();
} finally {
conn.close();
}
if (results == null) {
return;
}
byte[] bytes = (byte[]) results.get(0);
String accessToken = deserializeString(bytes);
if (accessToken != null) {
removeAccessToken(accessToken);
}
}
@Override
public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
byte[] approvalKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(clientId, userName));
List<byte[]> byteList = null;
RedisConnection conn = getConnection();
try {
byteList = conn.lRange(approvalKey, 0, -1);
} finally {
conn.close();
}
if (byteList == null || byteList.size() == 0) {
return Collections.<OAuth2AccessToken> emptySet();
}
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>(byteList.size());
for (byte[] bytes : byteList) {
OAuth2AccessToken accessToken = deserializeAccessToken(bytes);
accessTokens.add(accessToken);
}
return Collections.<OAuth2AccessToken> unmodifiableCollection(accessTokens);
}
@Override
public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
byte[] key = serializeKey(CLIENT_ID_TO_ACCESS + clientId);
List<byte[]> byteList = null;
RedisConnection conn = getConnection();
try {
byteList = conn.lRange(key, 0, -1);
} finally {
conn.close();
}
if (byteList == null || byteList.size() == 0) {
return Collections.<OAuth2AccessToken> emptySet();
}
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>(byteList.size());
for (byte[] bytes : byteList) {
OAuth2AccessToken accessToken = deserializeAccessToken(bytes);
accessTokens.add(accessToken);
}
return Collections.<OAuth2AccessToken> unmodifiableCollection(accessTokens);
}
}

View File

@ -0,0 +1,152 @@
package com.joint.cloud.auth.config.custom;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
public class CustomUserDetails implements UserDetails {
static final long serialVersionUID = -7588980448693010399L;
private String userId;
private String username;
private String name;
private String password;
private boolean enabled = true;
private String clientId;
private List<String> roles;
private Collection<? extends GrantedAuthority> authorities;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getUserId() {
return userId;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static class CustomUserDetailsBuilder {
private CustomUserDetails userDetails = new CustomUserDetails();
public CustomUserDetailsBuilder withUsername(String username) {
userDetails.setUsername(username);
userDetails.setAuthorities(null);
return this;
}
public CustomUserDetailsBuilder withName(String name) {
userDetails.setName(name);
return this;
}
public CustomUserDetailsBuilder withPassword(String password) {
userDetails.setPassword(password);
return this;
}
public CustomUserDetailsBuilder withClientId(String clientId) {
userDetails.setClientId(clientId);
return this;
}
public CustomUserDetailsBuilder withUserId(String userId) {
userDetails.setUserId(userId);
return this;
}
public CustomUserDetailsBuilder withRoles(List<String> roles) {
userDetails.setRoles(roles);
return this;
}
public CustomUserDetails build() {
return userDetails;
}
}
}

View File

@ -0,0 +1,24 @@
package com.joint.cloud.auth.config.encoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @description: Client Password Encoder
* @author: super.wu
* @date: Created in 2018/5/25 0025
* @modified By:
* @version: 1.0
* 此处可重新定义密码的加密算法例如和可以采用BASE64或者MD5加salt的方式在数据库中进行加密匹配密码的做同样的处理
**/
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence arg0) {
return arg0.toString();
}
@Override
public boolean matches(CharSequence arg0, String arg1) {
return arg1.equals(arg0.toString());
}
}

View File

@ -0,0 +1,69 @@
package com.joint.cloud.auth.config.impl;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @description: 自定义添加了缓存配置
* @author: super.wu
* @date: Created in 2018/5/8 0008
* @modified By:
* @version: 1.0
**/
@Service
public class ClientDetailsServiceImpl implements ClientDetailsService {
@Resource
DataSource dataSource;
@Resource
RedisTemplate<String, Object> redisTemplate;
private final String CACHE_KEY = "CACHE_CLIENT_DETAILS";
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException{
return getClientDetails(clientId);
}
private ClientDetails getClientDetails(String clientId) {
if (redisTemplate.hasKey(CACHE_KEY)) {
Map<String, ClientDetails> map = (Map<String, ClientDetails>) redisTemplate.opsForValue().get(CACHE_KEY);
if (map.containsKey(clientId)) {
return map.get(clientId);
}
}
return loadClientDetails(clientId);
}
private ClientDetails loadClientDetails(String clientId) {
JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
ClientDetails clientDetails = jdbcClientDetailsService.loadClientByClientId(clientId);
if(clientDetails == null) {
throw new ClientRegistrationException("应用" + clientId + "不存在!");
}
cacheClientDetails(clientDetails);
return clientDetails;
}
private void cacheClientDetails(ClientDetails clientDetails) {
Map<String, ClientDetails> map;
if (redisTemplate.hasKey(CACHE_KEY)) {
map = (Map<String, ClientDetails>) redisTemplate.opsForValue().get(CACHE_KEY);
} else {
map = new HashMap<>(1);
}
map.put(clientDetails.getClientId(), clientDetails);
redisTemplate.opsForValue().set(CACHE_KEY, map);
}
}

View File

@ -0,0 +1,41 @@
package com.joint.cloud.auth.config.impl;
import com.joint.cloud.auth.config.custom.CustomUserDetails;
import com.joint.cloud.auth.config.service.JdbcUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* @description:
* @author: super.wu
* @date: Created in 2018/5/25 0025
* @modified By:
* @version: 1.0
**/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
JdbcUserDetailsService jdbcUserDetailsService;
/**
* 根据用户名获取登录用户信息
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
CustomUserDetails customUserDetails = jdbcUserDetailsService.loadUserDetailsByUserName(username);
if(customUserDetails == null){
throw new UsernameNotFoundException("用户名:"+ username + "不存在!");
}
customUserDetails.setRoles(jdbcUserDetailsService.loadUserRolesByUsername(customUserDetails.getName()));
return customUserDetails;
}
}

View File

@ -0,0 +1,82 @@
package com.joint.cloud.auth.config.service;
import com.joint.cloud.auth.config.custom.CustomUserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
/**
* @description:
* @author: super.wu
* @date: Created in 2018/5/25 0025
* @modified By:
* @version: 1.0
**/
@Repository
public class JdbcUserDetailsService {
private String selectUserDetailsSql;
private String selectUserDetailsRoleSql;
@Autowired
private JdbcTemplate jdbcTemplate;
public JdbcUserDetailsService() {
this.selectUserDetailsSql = "select u.user_id as userId, u.login_name as username, u.show_name as name,u.password,u.user_type,u.head_image_url,u.dept_id ,u.user_status from zz_sys_user AS u where login_name = ? and deleted_flag = 1";
this.selectUserDetailsRoleSql = "select r.role_id FROM zz_sys_user u,zz_sys_user_role ur, zz_sys_role r WHERE u.user_id=ur.user_id AND r.role_id=ur.role_id AND u.login_name = ?";
}
public CustomUserDetails loadUserDetailsByUserName(String username) throws InvalidClientException {
try {
CustomUserDetails details = this.jdbcTemplate.queryForObject(this.selectUserDetailsSql, new UserDetailsRowMapper(), new Object[]{username});
return details;
} catch (EmptyResultDataAccessException var4) {
throw new NoSuchClientException("No client with requested username: " + username);
}
}
public List<String> loadUserRolesByUserId(Long userId) {
List<String> roles = this.jdbcTemplate.query(this.selectUserDetailsRoleSql, new RoleRowMapper(), new Object[]{userId, userId});
return roles;
}
public List<String> loadUserRolesByUsername(String username) {
List<String> roles = this.jdbcTemplate.query(this.selectUserDetailsRoleSql, new RoleRowMapper(), new Object[]{username});
return roles;
}
private static class UserDetailsRowMapper implements RowMapper<CustomUserDetails> {
@Override
public CustomUserDetails mapRow(ResultSet resultSet, int i) throws SQLException {
CustomUserDetails customUserDetails = new CustomUserDetails();
customUserDetails.setUserId(resultSet.getString(1));
customUserDetails.setUsername(resultSet.getString(2));
customUserDetails.setPassword(resultSet.getString(4));
customUserDetails.setEnabled(true);
customUserDetails.setAuthorities(new HashSet<>());
customUserDetails.setName(resultSet.getString(3));
return customUserDetails;
}
}
private static class RoleRowMapper implements RowMapper<String> {
@Override
public String mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString(1);
}
}
}

View File

@ -0,0 +1,16 @@
package com.joint.cloud.auth.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
public class HealthController {
@GetMapping("/health")
public String health() {
return "I'm health now " + (new Date()).toString();
}
}

View File

@ -0,0 +1,19 @@
package com.joint.cloud.auth.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
/**
* Created by wangyunfei on 2017/6/12.
*/
@RestController
public class UserController {
@GetMapping("/user")
public Principal user(Principal user){
return user;
}
}

View File

@ -0,0 +1,10 @@
package com.joint.cloud.auth.exception;
import org.springframework.security.authentication.AccountStatusException;
public class LicenseStatusException extends AccountStatusException {
public LicenseStatusException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,14 @@
package com.joint.cloud.auth.exception;
/**
* @description: 参数异常
* @author: super.wu
* @date: Created in 2018/4/28 0028
* @modified By:
* @version: 1.0
**/
public class ParamException extends Exception{
private static final long serialVersionUID = -4970436179123713406L;
}

View File

@ -0,0 +1,8 @@
spring:
cloud:
consul:
host: ${CONSUL_ADDR:10.4.79.107}
datasource:
url: jdbc:postgresql://${DB_ADDR:10.4.79.103}:5432/jc_admin?useUnicode=true&characterEncoding=utf-8
redis:
host: ${REDIS_ADDR:10.4.79.103}

View File

@ -0,0 +1,40 @@
server:
port: 8095
spring:
application:
name: joint-cloud-auth
profiles:
active: dev
cloud:
consul:
port: 8500
discovery:
enabled: true
register: true
health-check-path: /health
health-check-interval: 60s
health-check-critical-timeout: 30s
instance-id: ${spring.application.name}:${spring.cloud.consul.discovery.ip-address}:${server.port}
ip-address: ${REGISTRY_ADDR:${spring.cloud.client.ip-address}}
prefer-ip-address: true
datasource:
driverClassName: org.postgresql.Driver
type: com.alibaba.druid.pool.DruidDataSource
username: postgres
password: aaa123+-*/
redis:
database: 2
password: Aaa123+-*/
timeout: 3000
jedis:
pool:
max-active: 5
min-idle: 0
max-wait: 1
max-idle: 8
port: 6379
logging:
config: classpath:logback.xml
ribbon:
ConnectTimeout: 5000
ReadTimeout: 10000

View File

@ -0,0 +1,83 @@
<configuration>
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
<!-- appender是configuration的子节点是负责写日志的组件。 -->
<!-- ConsoleAppender把日志输出到控制台 -->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %p (%file:%line\)- %m%n</pattern>
<!-- 控制台也要使用UTF-8不要使用GBK否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- RollingFileAppender滚动记录文件先将日志记录到指定文件当符合某个条件时将日志记录到其他文件 -->
<!-- 以下的大概意思是1.先按日期存日志日期变了将前一天的日志文件名重命名为XXX%日期%索引新的日志仍然是aclome.log -->
<!-- 2.如果日期没有发生变化但是当前日志的文件大小超过10M时对当前日志进行分割 重命名-->
<appender name="filelog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/aclome-cmp-auth-server.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名log/sys.2017-12-05.0.log -->
<fileNamePattern>logs/aclome-cmp-auth-server-%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小默认值是10MB,本篇设置为1KB只是为了演示 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点用来设置日志的输入格式 -->
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<!-- 记录日志的编码 -->
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<appender name="apiAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/aclome-cmp-auth-api.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名log/sys.2017-12-05.0.log -->
<fileNamePattern>logs/aclome-cmp-auth-api-%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小默认值是10MB,本篇设置为1KB只是为了演示 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点用来设置日志的输入格式 -->
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<!-- 记录日志的编码 -->
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<logger name="apiLogger" additivity="false">
<!--使用哪一个Appender-->
<appender-ref ref="apiAppender" />
</logger>
<!-- 控制台输出日志级别 -->
<root level="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="filelog" />
</root>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- com.appley为根包也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
<!-- 级别依次为【从高到低】FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
<!-- <logger name="com.neusoft.aclome" level="DEBUG">-->
<!-- <appender-ref ref="filelog" />-->
<!-- </logger>-->
</configuration>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>joint-cloud</artifactId>
<groupId>com.joint.cloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>joint-cloud-common</artifactId>
<name>joint-cloud-common</name>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,13 @@
package com.joint.cloud.common.constants;
/**
* @author lilengyi
* @date 2021/11/18 15:42
* 系统对象类型枚举类
*/
public enum AIOpsObjectType {
USER, ROLE,
// 告警相关
ALERT_RULE
}

View File

@ -0,0 +1,35 @@
package com.joint.cloud.common.constants;
public enum NotificationType {
/**
* 事件
*/
EVENT,
/**
* 问题
*/
PROBLEM,
/**
* 变更
*/
CHANGE,
/**
* 请求
*/
REQUEST,
/**
* 被动运维
*/
PASV,
/**
* 主动运维
*/
ACTIVE,
QUESTION,
/**
* 中山档案馆-被动
*/
ZSPASSTIVE,
ZSACTIVE
}

View File

@ -0,0 +1,45 @@
package com.joint.cloud.common.constants;
public enum ResponseCode {
/**
* 成功返回的状态码
*/
SUCCESS(200, "SUCCESS"),
/**
* 非法参数
*/
BAD_REQUEST(400, "非法参数"),
/**
* 资源不存在的状态码
*/
RESOURCES_NOT_EXIST(404, "资源不存在"),
/**
* 所有无法识别的异常默认的返回状态码
*/
SERVICE_ERROR(500, "服务器异常");
/**
* 状态码
*/
private int code;
/**
* 返回信息
*/
private String msg;
ResponseCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}

View File

@ -0,0 +1,65 @@
package com.joint.cloud.common.constants;
import java.io.Serializable;
public class ResponseResult<T> implements Serializable {
/**
* 返回状态码
*/
private Integer code;
/**
* 返回信息
*/
private String msg;
/**
* 数据
*/
private T data;
/**
* 发生异常时回显
*/
private String stack;
public ResponseResult(Integer code, String msg, T data, String stack) {
this.code = code;
this.msg = msg;
this.data = data;
this.stack = stack;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getStack() {
return stack;
}
public void setStack(String stack) {
this.stack = stack;
}
}

View File

@ -0,0 +1,19 @@
package com.joint.cloud.common.constants;
/**
* @description:
* @author: super.wu
* @date: Created in 2018/6/13 0013
* @modified By:
* @version: 1.0
**/
public class SysConstant {
/** 超级管理员角色编码 **/
public static final String SUPER_ADMIN_ROLE_CODE = "SUPER_ADMIN_ROLE";
/** api前缀, 此前缀用做拦截器判断不需要做权限过滤 **/
public static final String API_NO_PERMISSION = "/noPermission/";
}

View File

@ -0,0 +1,68 @@
package com.joint.cloud.common.exception;
import com.joint.cloud.common.constants.ResponseCode;
import com.joint.cloud.common.exception.msg.BaseAIOpsExceptionErrorMsg;
import org.springframework.util.StringUtils;
public class AIOpsException extends RuntimeException {
private final ResponseCode code;
private final BaseAIOpsExceptionErrorMsg errorMsg;
public AIOpsException(ResponseCode code) {
super(code.getMsg());
this.code = code;
this.errorMsg = null;
}
public AIOpsException(ResponseCode code, BaseAIOpsExceptionErrorMsg errorMsg) {
super(errorMsg.getErrorMsgLocal());
this.code = code;
this.errorMsg = errorMsg;
}
public AIOpsException(BaseAIOpsExceptionErrorMsg errorMsg) {
super(errorMsg.getErrorMsgLocal());
this.code = ResponseCode.SERVICE_ERROR;
this.errorMsg = errorMsg;
}
public static AIOpsException newInstance(Class<? extends BaseAIOpsExceptionErrorMsg> errorMsgClass) {
BaseAIOpsExceptionErrorMsg baseAIOpsExceptionErrorMsg = null;
try {
baseAIOpsExceptionErrorMsg = errorMsgClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return new AIOpsException(ResponseCode.SERVICE_ERROR, baseAIOpsExceptionErrorMsg);
}
public ResponseCode getCode() {
return code;
}
public String getErrorMsg() {
if (errorMsg != null) {
if (StringUtils.hasLength(errorMsg.getErrorMsg())) {
return errorMsg.getErrorMsg();
} else if (StringUtils.hasLength(errorMsg.getErrorMsgLocal())) {
return errorMsg.getErrorMsgLocal();
}
}
return null;
}
public String getErrorMsgLocal() {
if (errorMsg != null) {
if (StringUtils.hasLength(errorMsg.getErrorMsgLocal())) {
return errorMsg.getErrorMsgLocal();
} else if (StringUtils.hasLength(errorMsg.getErrorMsg())) {
return errorMsg.getErrorMsg();
}
}
return null;
}
}

View File

@ -0,0 +1,30 @@
package com.joint.cloud.common.exception;
import com.joint.cloud.common.constants.ResponseCode;
public class BusinessException extends RuntimeException {
private final ResponseCode code;
private final String msg;
public BusinessException(ResponseCode code) {
super(code.getMsg());
this.code = code;
this.msg = null;
}
public BusinessException(ResponseCode code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
public ResponseCode getCode() {
return code;
}
public String getMsg() {
return msg;
}
}

View File

@ -0,0 +1,104 @@
package com.joint.cloud.common.exception;
import com.joint.cloud.common.constants.ResponseCode;
import com.joint.cloud.common.constants.ResponseResult;
import com.joint.cloud.common.response.BaseResponse;
import com.joint.cloud.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@ControllerAdvice(annotations = BaseResponse.class)
@ResponseBody
public class ExceptionHandlerAdvice {
private static final Logger log = LoggerFactory.getLogger(ExceptionHandlerAdvice.class);
/**
* 处理未捕获的Exception
*
* @param e 异常
* @return 统一响应体
*/
@ExceptionHandler(Exception.class)
public ResponseResult handleException(Exception e) {
log.error(e.getMessage(), e);
return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(), ResponseCode.SERVICE_ERROR.getMsg(), null, StringUtils.getStackMessage(e));
}
/**
* 处理未捕获的RuntimeException
*
* @param e 运行时异常
* @return 统一响应体
*/
@ExceptionHandler(RuntimeException.class)
public ResponseResult handleRuntimeException(RuntimeException e) {
log.error(e.getMessage(), e);
return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(), ResponseCode.SERVICE_ERROR.getMsg(), null, StringUtils.getStackMessage(e));
}
/**
* 处理业务异常BaseException
*
* @param e 业务异常
* @return 统一响应体
*/
@ExceptionHandler(BusinessException.class)
public ResponseResult handleBaseException(BusinessException e) {
ResponseCode code = e.getCode();
if (e.getMsg() != null) {
return new ResponseResult(code.getCode(), e.getMsg(), null, null);
}
return new ResponseResult(code.getCode(), code.getMsg(), null, null);
}
/**
* 处理业务异常BaseException
*
* @param e 业务异常
* @return 统一响应体
*/
@ExceptionHandler(AIOpsException.class)
public ResponseResult handleBaseException(AIOpsException e) {
log.error(e.getMessage(), e);
ResponseCode code = e.getCode();
if (e.getErrorMsgLocal() != null) {
return new ResponseResult(code.getCode(), e.getErrorMsgLocal(), null, null);
}
return new ResponseResult(code.getCode(), code.getMsg(), null, null);
}
/**
* 参数校验异常MethodArgumentNotValidException
*
* @param e 业务异常
* @return 统一响应体
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseResult handleBindException(MethodArgumentNotValidException e) {
BindingResult result = e.getBindingResult();
String message = "";
if (result.hasErrors()) {
List<ObjectError> errors = result.getAllErrors();
errors.forEach(p -> {
FieldError fieldError = (FieldError) p;
log.error("Data check failure : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() +
"},errorMessage{" + fieldError.getDefaultMessage() + "}");
});
if (errors.size() > 0) {
FieldError fieldError = (FieldError) errors.get(0);
message = fieldError.getDefaultMessage();
}
}
return new ResponseResult(ResponseCode.BAD_REQUEST.getCode(), message, null, null);
}
}

View File

@ -0,0 +1,58 @@
package com.joint.cloud.common.exception.msg;
import org.springframework.util.StringUtils;
/**
* @author lilengyi
* @date 2021/11/12 10:48
*
*/
public abstract class BaseAIOpsExceptionErrorMsg {
private String errorCode;
private String errorMsg;
private String errorMsgLocal;
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public void setErrorMsgLocal(String errorMsgLocal) {
this.errorMsgLocal = errorMsgLocal;
}
public String getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
if (!StringUtils.hasLength(this.errorMsg)) {
this.errorMsg = generateErrorMsg();
}
if (!StringUtils.hasLength(this.errorMsg)) {
this.errorMsg = generateErrorMsgLocal();
}
return errorMsg;
}
public String getErrorMsgLocal() {
if (!StringUtils.hasLength(this.errorMsgLocal)) {
this.errorMsgLocal = generateErrorMsgLocal();
}
if (!StringUtils.hasLength(this.errorMsgLocal)) {
this.errorMsgLocal = generateErrorMsg();
}
return errorMsgLocal;
}
public abstract String generateErrorMsg();
public abstract String generateErrorMsgLocal();
}

View File

@ -0,0 +1,20 @@
package com.joint.cloud.common.exception.msg;
public class InvalidParameterValueExceptionErrorMsg extends BaseAIOpsExceptionErrorMsg {
private String invalidParamKey;
public InvalidParameterValueExceptionErrorMsg(String invalidParamKey) {
this.invalidParamKey = invalidParamKey;
}
@Override
public String generateErrorMsg() {
return "Invalid Parameter: "+invalidParamKey;
}
@Override
public String generateErrorMsgLocal() {
return "参数非法: "+invalidParamKey;
}
}

View File

@ -0,0 +1,20 @@
package com.joint.cloud.common.exception.msg;
public class NullParameterExceptionErrorMsg extends BaseAIOpsExceptionErrorMsg {
private String invalidParamKey;
public NullParameterExceptionErrorMsg(String invalidParamKey) {
this.invalidParamKey = invalidParamKey;
}
@Override
public String generateErrorMsg() {
return "Parameter '" + invalidParamKey + "' can not be null or empty.";
}
@Override
public String generateErrorMsgLocal() {
return "参数'" + invalidParamKey + "'不能为空";
}
}

View File

@ -0,0 +1,23 @@
package com.joint.cloud.common.exception.msg;
public class ResourceAlreadyExistExceptionErrorMsg extends BaseAIOpsExceptionErrorMsg {
private String resourceType;
private Object resourceName;
public ResourceAlreadyExistExceptionErrorMsg(String resourceType, Object resourceName) {
this.resourceType = resourceType;
this.resourceName = resourceName;
}
@Override
public String generateErrorMsg() {
return "Resource '" + resourceType + "' ( with Name " + resourceName.toString() + " ) Already Exists!";
}
@Override
public String generateErrorMsgLocal() {
return "资源'" + resourceType + "'(名称为" + resourceName.toString() + ")已存在!";
}
}

View File

@ -0,0 +1,23 @@
package com.joint.cloud.common.exception.msg;
public class ResourceNotExistExceptionErrorMsg extends BaseAIOpsExceptionErrorMsg {
private String resourceType;
private Object resourceId;
public ResourceNotExistExceptionErrorMsg(String resourceType, Object resourceId) {
this.resourceType = resourceType;
this.resourceId = resourceId;
}
@Override
public String generateErrorMsg() {
return "Resource '" + resourceType + "' ( with ID " + resourceId.toString() + " ) Not Exists!";
}
@Override
public String generateErrorMsgLocal() {
return "资源'" + resourceType + "'ID为" + resourceId.toString() + ")不存在!";
}
}

View File

@ -0,0 +1,15 @@
package com.joint.cloud.common.exception.msg;
public class UnknownExceptionErrorMsg extends BaseAIOpsExceptionErrorMsg {
@Override
public String generateErrorMsg() {
return "Unknown system exception. Contact your administrator";
}
@Override
public String generateErrorMsgLocal() {
return "未知系统异常,请联系管理员";
}
}

View File

@ -0,0 +1,30 @@
package com.joint.cloud.common.model.dto;
/**
* @description:
* @date: Created in 2018/5/9 0009
* @modified By:
* @version: 1.0
**/
public class RequestDto {
private int size = Integer.MAX_VALUE;
private int page = 1;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public RequestDto(){
}
}

View File

@ -0,0 +1,22 @@
package com.joint.cloud.common.model.wrapper;
import java.util.List;
/**
* @author lilengyi
* @date 2020/1/20 15:04
*
* Data Transfer Object数据传输对象与Entity实体类相互转换
* @param <DTO>
* @param <Entity>
*/
public interface BaseDTOEntityWrapper<DTO, Entity> {
DTO toDTOFromEntity(Entity entity, DTO dto);
Entity toEntityFromDTO(DTO dto, Entity entity);
List<DTO> toDTOListFromEntity(List<Entity> entities);
List<Entity> toEntityListFromDTO(List<DTO> dtos);
}

View File

@ -0,0 +1,22 @@
package com.joint.cloud.common.model.wrapper;
import java.util.List;
/**
* @author lilengyi
* @date 2020/1/20 15:04
*
* Persistent Object持久化对象与Entity实体类转换
* @param <PO>
* @param <Entity>
*/
public interface BasePOEntityWrapper<PO, Entity> {
PO toPOFromEntity(Entity entity, PO po);
Entity toEntityFromPO(PO po, Entity entity);
List<PO> toPOListFromEntity(List<Entity> entities);
List<Entity> toEntityListFromPO(List<PO> pos);
}

View File

@ -0,0 +1,19 @@
package com.joint.cloud.common.model.wrapper;
import java.util.List;
/**
* @author lilengyi
* @date 2020/1/20 15:04
*
* View Object视图类与Entity实体类转换
* @param <VO>
* @param <Entity>
*/
public interface BaseVOEntityWrapper<VO, Entity> {
VO toVOFromEntity(Entity entity, VO vo);
List<VO> toVOListFromEntity(List<Entity> entities);
}

View File

@ -0,0 +1,11 @@
package com.joint.cloud.common.response;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface BaseResponse {
}

View File

@ -0,0 +1,36 @@
package com.joint.cloud.common.response;
import com.joint.cloud.common.constants.ResponseCode;
import com.joint.cloud.common.constants.ResponseResult;
import com.joint.cloud.common.utils.JsonUtil;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice(annotations = BaseResponse.class)
public class ResponseResultHandlerAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof String) {
return JsonUtil.serialize(new ResponseResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMsg(), body, null));
} else if (body instanceof ResponseResult) {
return body;
}
if (MediaType.APPLICATION_JSON.equals(selectedContentType)) {
return new ResponseResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMsg(), body, null);
}
return body;
}
}

View File

@ -0,0 +1,131 @@
package com.joint.cloud.common.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.Date;
/**
* @description:
* @author: 王浩彬
* @date: Created in 2018/5/10 0010
* @modified By:
* @version: 1.0
**/
public class EntityUtils {
/**
* 快速将bean的crtUsercrtHostcrtTimeupdUserupdHostupdTime附上相关值
*
* @param entity 实体bean
* @author 王浩彬
*/
public static <T> void setCreateAndUpdateInfo(T entity) {
try {
setCreateInfo(entity);
setUpdatedInfo(entity);
} catch (Exception e) {
}
}
/**
* 快速将bean的crtUsercrtHostcrtTime附上相关值
*
* @param entity 实体bean
* @author 王浩彬
*/
public static <T> void setCreateInfo(T entity) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String hostIp = "";
String name = "";
String id = "";
if(request!=null) {
hostIp = request.getHeader("userHost");
name = request.getHeader("userName");
try {
name = URLDecoder.decode(name, "utf-8");
} catch (Exception e) {
}
id = String.valueOf(request.getHeader("userId"));
}
// 默认属性
String[] fields = {"crtName","crtUser","crtHost","crtTime"};
Field field = ReflectionUtils.getAccessibleField(entity, "crtTime");
// 默认值
Object [] value = null;
if(field!=null&&field.getType().equals(Date.class)){
value = new Object []{name,id,hostIp,new Date()};
}
// 填充默认属性值
setDefaultValues(entity, fields, value);
}
/**
* 快速将bean的updUserupdHostupdTime附上相关值
*
* @param entity 实体bean
* @author 王浩彬
*/
public static <T> void setUpdatedInfo(T entity) {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
String hostIp = "";
String name = "";
String id = "";
if(request!=null) {
hostIp = request.getHeader("userHost");
name = request.getHeader("userName");
try {
name = URLDecoder.decode(name, "utf-8");
} catch (Exception e) {
}
id = String.valueOf(request.getHeader("userId"));
}
// 默认属性
String[] fields = {"updName","updUser","updHost","updTime"};
Field field = ReflectionUtils.getAccessibleField(entity, "updTime");
Object [] value = null;
if(field!=null&&field.getType().equals(Date.class)){
value = new Object []{name,id,hostIp,new Date()};
}
// 填充默认属性值
setDefaultValues(entity, fields, value);
}
/**
* 依据对象的属性数组和值数组对对象的属性进行赋值
*
* @param entity 对象
* @param fields 属性数组
* @param value 值数组
* @author 王浩彬
*/
private static <T> void setDefaultValues(T entity, String[] fields, Object[] value) {
for(int i=0;i<fields.length;i++){
String field = fields[i];
if(ReflectionUtils.hasField(entity, field)){
ReflectionUtils.invokeSetter(entity, field, value[i]);
}
}
}
/**
* 根据主键属性判断主键是否值为空
*
* @param entity
* @param field
* @return 主键为空则返回false主键有值返回true
* @author 王浩彬
* @date 2016年4月28日
*/
public static <T> boolean isPKNotNull(T entity,String field){
if(!ReflectionUtils.hasField(entity, field)) {
return false;
}
Object value = ReflectionUtils.getFieldValue(entity, field);
return value!=null&&!"".equals(value);
}
}

View File

@ -0,0 +1,45 @@
package com.joint.cloud.common.utils;
import org.springframework.cglib.beans.BeanCopier;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: lilengyi
* @date: 2020/1/15 14:32
* 模型同类型同名参数转换工具
*/
public class FieldUtils {
private static final Map<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();
public static Object convertModel(Object source, Object target) {
BeanCopier copier = getBeanCopier(source.getClass(), target.getClass());
copier.copy(source, target, null);
return target;
}
private static BeanCopier getBeanCopier(Class sourceClass, Class targetClass) {
String beanKey = generateKey(sourceClass, targetClass);
BeanCopier copier = null;
if (!BEAN_COPIER_CACHE.containsKey(beanKey)) {
copier = BeanCopier.create(sourceClass, targetClass, false);
BEAN_COPIER_CACHE.put(beanKey, copier);
} else {
copier = BEAN_COPIER_CACHE.get(beanKey);
}
return copier;
}
/**
* 两个类的全限定名拼接起来构成Key
*
* @param sourceClass
* @param targetClass
* @return
*/
private static String generateKey(Class<?> sourceClass, Class<?> targetClass) {
return sourceClass.getName() + targetClass.getName();
}
}

View File

@ -0,0 +1,86 @@
package com.joint.cloud.common.utils;
import org.springframework.util.StringUtils;
import java.util.Random;
import java.util.UUID;
/**
* @author lilengyi
* @date 2019/4/26
*/
public class IDUtil {
private static final String[] chars = new String[] { "a", "b", "c", "d",
"e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q",
"r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3",
"4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z" };
public static String UUID() {
return UUID.randomUUID().toString().replace("-", "");
}
public static String Short_UUID() {
StringBuffer shortBuffer = new StringBuffer();
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < 8; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]);
}
return shortBuffer.toString();
}
/**
* 名称后添加n位随机串
* @param name
* @param maxlength
* @return
*/
public static String generateName(String name, int maxlength) {
if (!StringUtils.hasLength(name)) {
throw new RuntimeException("generate name failed, name is null");
}
return name.concat("_").concat(getRandomString(maxlength));
}
/**
* 构成规律生成随机串 数字字母组合
*
* *
*/
private static String getRandomString(int length){
//产生随机数
Random random=new Random();
StringBuffer sb=new StringBuffer();
//循环length次
for(int i=0; i<length; i++){
//产生0-2个随机数既与a-zA-Z0-9三种可能
int number=random.nextInt(3);
long result=0;
switch(number){
//如果number产生的是数字0
case 0:
//产生A-Z的ASCII码
result=Math.round(Math.random()*25+65);
//将ASCII码转换成字符
sb.append(String.valueOf((char)result));
break;
case 1:
//产生a-z的ASCII码
result=Math.round(Math.random()*25+97);
sb.append(String.valueOf((char)result));
break;
case 2:
//产生0-9的数字
sb.append(String.valueOf
(new Random().nextInt(10)));
break;
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,115 @@
package com.joint.cloud.common.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
public class JsonUtil {
private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
MAPPER.setTimeZone(TimeZone.getTimeZone("GMT+8"));
}
private JsonUtil() {
}
public static ObjectMapper getMapper() {
return MAPPER;
}
/**
* json serialization.
*
* @param obj 要进行序列化的对象
* @return 返回序列化之后的字符串
*/
public static String serialize(final Object obj) {
if (obj == null) {
return null;
}
try {
return MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException ex) {
log.error("failed serialize object to json string", ex);
throw new RuntimeException(ex);
}
}
/**
* json deserialization.
*
* @param jsonStr 序列化字符串
* @param cls 指定反序列化之后的类信息
* @return 返回反序列化之后的实例对象
*/
public static <T> T deserialize(final String jsonStr, final Class<T> cls) {
return deserialize(jsonStr, MAPPER.getTypeFactory().constructType(cls));
}
public static <T> T deserialize(final String jsonStr, final JavaType type) {
if (jsonStr == null) {
return null;
}
try {
return MAPPER.readValue(jsonStr, type);
} catch (IOException ex) {
log.error("failed deserialize string: {} to Class {}'s instance!", jsonStr, type);
throw new RuntimeException(ex);
}
}
/**
* 获取泛型的Collection Type
*
* @param collectionClass 泛型的Collection
* @param elementClasses 元素类
* @return JavaType Java类型
* @since 1.0
*/
public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
/**
* 转换Json到List
*
* @param cls映射的类 json字符串转换成list.
*/
public static <T> List<T> getList(String serialize, Class<T> cls) throws IOException {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(ArrayList.class, cls);
return MAPPER.readValue(serialize, javaType);
}
public static JsonNode jsonNode(final String jsonStr) {
try {
return MAPPER.readTree(jsonStr);
} catch (IOException ex) {
log.error("failed deserialize string: {} to JsonNode", jsonStr);
}
return null;
}
public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
return MAPPER.convertValue(fromValue, toValueType);
}
}

View File

@ -0,0 +1,67 @@
package com.joint.cloud.common.utils;
import java.util.*;
/**
* @author: zhanglc
* @date: 2020/4/17 11:35
*/
public class ListUtil {
public static <E>boolean isListEqual(List<E> list1, List<E> list2) {
// 两个list引用相同包括两者都为空指针的情况
if (list1 == list2) {
return true;
}
if((list1 == null && list2!=null && list2.size()!=0)
|| (list2 == null && list1 != null && list1.size() != 0)){
return false;
}
// 两个list都为空包括空指针元素个数为0
if ((list1 == null && list2 != null && list2.size() == 0)
|| (list2 == null && list1 != null && list1.size() == 0)) {
return true;
}
// 两个list元素个数不相同
if (list1.size() != list2.size()) {
return false;
}
// 两个list元素个数已经相同再比较两者内容
// 采用这种可以忽略list中的元素的顺序
// 涉及到对象的比较是否相同时确保实现了equals()方法
if (!list1.containsAll(list2) || !list2.containsAll(list1)) {
return false;
}
return true;
}
public static boolean isRepeatInCollection(Collection<?> datas) {
if (datas == null) {// 为空则认为不含重复元素
return false;
}
if (datas instanceof Set) {//如果是set则不含有重复元素
return false;
}
Set<?> noRepeatSet = new HashSet<>(datas);
return !(datas.size() == noRepeatSet.size());
}
public static <T> List<T> findRepeat(Collection<T> datas) {
if (datas instanceof Set) {
return new ArrayList<>();
}
HashSet<T> set = new HashSet<T>();
List<T> repeatEles = new ArrayList<T>();
for (T t : datas) {
if (set.contains(t)) {
repeatEles.add(t);
} else {
set.add(t);
}
}
return repeatEles;
}
}

View File

@ -0,0 +1,97 @@
/**
*
*/
package com.joint.cloud.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class MD5Util {
private static final Logger s_logger = LoggerFactory.getLogger(MD5Util.class);
private static final String MD5_ALGORITHM = "MD5";
private static final int HEX_NUM = 0xff;
/**
* md5加密
*
* @param str
* @return
* @author wangyzh
* @date 2012-12-7 下午12:54:02
*/
public static String md5Encode(String str) {
if (str == null) {
s_logger.warn("String is null for md5 encoder.");
return null;
}
try {
MessageDigest mdEncoder = MessageDigest.getInstance(MD5_ALGORITHM);
mdEncoder.update(str.getBytes());
byte[] bytes = mdEncoder.digest();
return convertToHEX(bytes);
} catch (NoSuchAlgorithmException e) {
s_logger.warn("Failed to encode string . There is no such algorithm.", e);
return null;
}
}
/**
* 二进制转换成十六进制
*
* @param bytes
* @return
* @author wangyzh
* @date 2012-12-7 下午12:58:26
*/
private static String convertToHEX(byte[] bytes) {
if (bytes == null) {
return null;
}
StringBuffer stringBuilder = new StringBuffer();
for (byte b : bytes) {
int value = b & HEX_NUM;
if (value < 16) {
stringBuilder.append(0);
}
stringBuilder.append(Integer.toHexString(value));
}
return stringBuilder.toString();
}
public static String genMD5(List<String> stringList){
try {
StringBuffer sb = new StringBuffer();
for (String s : stringList) {
sb.append(s);
}
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(sb.toString().getBytes());
byte b[] = md.digest();
int i;
StringBuffer buf = new StringBuffer();
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0) {
i += 256;
}
if (i < 16) {
buf.append("0");
}
buf.append(Integer.toHexString(i));
}
String result = buf.toString();
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,340 @@
package com.joint.cloud.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import java.lang.reflect.*;
/**
* @description:
* @author: Mr.Ag
* @date: Created in 2018/5/10 0010
* @modified By:
* @version: 1.0
**/
public class ReflectionUtils {
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);
/**
* 调用Getter方法.
* 支持多级对象名.对象名.方法
*/
public static Object invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")){
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
return object;
}
/**
* 调用Setter方法, 仅匹配方法名
* 支持多级对象名.对象名.方法
*/
public static void invokeSetter(Object obj, String propertyName, Object value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}else{
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[] { value });
}
}
}
/**
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
public static Object getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
Object result = null;
try {
result = field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
}
/**
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
*/
public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
logger.error("Could not find field [" + fieldName + "] on target [" + obj + "]");
return;
//throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
try {
field.set(obj, convert(value, field.getType()));
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常:{}", e.getMessage());
}
}
public static Object convert(Object object, Class<?> type) {
if (object instanceof Number) {
Number number = (Number) object;
if (type.equals(byte.class) || type.equals(Byte.class)) {
return number.byteValue();
}
if (type.equals(short.class) || type.equals(Short.class)) {
return number.shortValue();
}
if (type.equals(int.class) || type.equals(Integer.class)) {
return number.intValue();
}
if (type.equals(long.class) || type.equals(Long.class)) {
return number.longValue();
}
if (type.equals(float.class) || type.equals(Float.class)) {
return number.floatValue();
}
if (type.equals(double.class) || type.equals(Double.class)) {
return number.doubleValue();
}
}
if(type.equals(String.class)){
return object==null?"":object.toString();
}
return object;
}
/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况否则应使用getAccessibleMethod()函数获得Method后反复调用.
* 同时匹配方法名+参数类型
*/
public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}
try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
}
/**
* 直接调用对象方法, 无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
* 只匹配函数名如果有多个同名函数调用第一个
*/
public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}
try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
}
/**
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
*
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
// Validate.notNull(obj, "object can't be null");
// Validate.notEmpty(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 匹配函数名+参数类型
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
// Validate.notNull(obj, "object can't be null");
// Validate.notEmpty(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
// Method不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 只匹配函数名
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
// Validate.notNull(obj, "object can't be null");
// Validate.notEmpty(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* 改变private/protected的方法为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}
/**
* 改变private/protected的成员变量为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨
*/
public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}
/**
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
* 如无法找到, 返回Object.class.
* eg.
* public UserDao extends HibernateDao<User>
*
* @param clazz The class to introspect
* @return the first generic declaration, or Object.class if cannot be determined
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType(final Class clazz) {
return getClassGenricType(clazz, 0);
}
/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*
* 如public UserDao extends HibernateDao<User,Long>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
* @return the index generic declaration, or Object.class if cannot be determined
*/
public static Class getClassGenricType(final Class clazz, final int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
public static Class<?> getUserClass(Object instance) {
Assert.notNull(instance, "Instance must not be null");
Class clazz = instance.getClass();
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
}
return clazz;
}
/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(((InvocationTargetException) e).getTargetException());
} else if (e instanceof RuntimeException) {
return (RuntimeException) e;
}
return new RuntimeException("Unexpected Checked Exception.", e);
}
/**
* 判断某个对象是否拥有某个属性
*
* @param obj 对象
* @param fieldName 属性名
* @return 有属性返回true
* 无属性返回false
*/
public static boolean hasField(final Object obj, final String fieldName){
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,63 @@
package com.joint.cloud.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;
import java.beans.Introspector;
@Component
public class SpringUtil implements ApplicationContextAware {
private static Logger logger = LoggerFactory.getLogger(SpringUtil.class);
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContextParam) throws BeansException {
applicationContext = applicationContextParam;
}
public static Object getObject(String id) {
Object object = null;
object = applicationContext.getBean(id);
return object;
}
public static <T> T getObject(Class<T> tClass) {
return applicationContext.getBean(tClass);
}
public static Object getBean(String tClass) {
return applicationContext.getBean(tClass);
}
public static <T> T getBean(Class<T> tClass) {
return applicationContext.getBean(tClass);
}
public static <T> T getBean(String beanId, Class<T> requiredType) {
if (applicationContext == null) {
logger.warn("Spring context has not bean initilaized!");
return null;
}
return applicationContext.getBean(beanId, requiredType);
}
public static String toBeanName(String simpleClassName) {
//参照Spring Context中AnnotationBeanNameGenerator的方法
return Introspector.decapitalize(simpleClassName);
// return simpleClassName.substring(0, 1).toLowerCase()
// + simpleClassName.substring(1);
}
public static void publishEvent(ApplicationEvent event){
applicationContext.publishEvent(event);
}
}

View File

@ -0,0 +1,71 @@
package com.joint.cloud.common.utils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.lang.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author lilengyi
* @date 2020/3/30 18:33
*/
public class StringUtils extends org.springframework.util.StringUtils {
public static String getStackMessage(Throwable throwable) {
String fullStackTrace = ExceptionUtils.getStackTrace(throwable);
if (fullStackTrace.length() > 500) {
fullStackTrace = fullStackTrace.substring(0, 500);
}
return fullStackTrace;
}
public static String[] split(@Nullable String toSplit, @Nullable String delimiter) {
if (!hasLength(toSplit) || !hasLength(delimiter)) {
return null;
}
int offset = toSplit.indexOf(delimiter);
if (offset < 0) {
return new String[]{toSplit};
}
String[] values = toSplit.split(delimiter);
return values;
}
public static String removeFromString(String values, String value) {
// 返回结果
String result = "";
// 判断是否存在如果存在移除指定用户 ID如果不存在则直接返回空
if(values.indexOf(",") != -1) {
// 拆分成数组
String[] array = values.split(",");
// 数组转集合
List<String> list = new ArrayList<String>(Arrays.asList(array));
// 移除指定值
list.remove(value);
// 把剩下的值再拼接起来
result = StringUtils.collectionToDelimitedString(list, ",");
}
// 返回
return result;
}
public static String addToString(String values, String value) {
// 返回结果
String result = "";
// 拆分成数组
if(hasLength(values)) {
String[] array = values.split(",");
// 数组转集合
List<String> list = new ArrayList<String>(Arrays.asList(array));
// 移除指定值
list.add(value);
// 把剩下的值再拼接起来
result = StringUtils.collectionToDelimitedString(list, ",");
}else{
result = value;
}
// 返回
return result;
}
}

View File

@ -0,0 +1,249 @@
package com.joint.cloud.common.utils;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* @author lilengyi
* @date 2020/1/20 15:04
*/
public class TimeUtil {
public static final String dateFormat = "yyyyMMddHHmmss";
public static String toTimeString(Date time) {
DateFormat df = new SimpleDateFormat(dateFormat);
return df.format(time);
}
public static Date fromTimeString(String timeStr) {
DateFormat df = new SimpleDateFormat(dateFormat);
try {
return df.parse(timeStr);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
/**
* 向下取整小时
* @param time
* @return
*/
public static Date toHourRoundDown(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String hour = df.format(time);
hour = hour.substring(0, 10).concat("0000");
try {
return df.parse(hour);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
/**
* 向上取整小时
* @param time
* @return
*/
public static Date toHourRoundUp(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String timeStr = df.format(time);
if (!"0000".equals(timeStr.substring(10, 14))){
Calendar c = Calendar.getInstance();
c.setTime(toHourRoundDown(time));
c.add(Calendar.HOUR_OF_DAY, 1);// +1天
return c.getTime();
} else {
return time;
}
}
/**
* 取下一小时
* @param time
* @return
*/
public static Date toNextHour(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.HOUR_OF_DAY, 1);// +1天
return c.getTime();
}
/**
* 取前一小时
* @param time
* @return
*/
public static Date toPreHour(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.HOUR_OF_DAY, -1);// +1天
return c.getTime();
}
/**
* 向下取整天数设为当天0点
* @param time
* @return
*/
public static Date toDayRoundDown(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String dayTime = df.format(time);
dayTime = dayTime.substring(0, 8).concat("000000");
try {
return df.parse(dayTime);
} catch (ParseException e) {
e.printStackTrace();
}
return time;
}
/**
* 向上取整天数如果时间不为整天设为第二天0点
* @param time
* @return
*/
public static Date toDayRoundUp(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String timeStr = df.format(time);
if (!"000000".equals(timeStr.substring(8, 14))){
Calendar c = Calendar.getInstance();
c.setTime(toDayRoundDown(time));
c.add(Calendar.DAY_OF_MONTH, 1);// +1天
return c.getTime();
} else {
return time;
}
}
/**
* 取下一天日期
* @param time
* @return
*/
public static Date toNextDay(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.DAY_OF_MONTH, 1);// +1天
return c.getTime();
}
/**
* 取前一天日期
* @param time
* @return
*/
public static Date toPreDay(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.DAY_OF_MONTH, -1);// +1天
return c.getTime();
}
/**
* 向下取整月数设为当月1日0点
* @param time
* @return
*/
public static Date toMonthRoundDown(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String monthTime = df.format(time);
monthTime = monthTime.substring(0, 6).concat("01000000");
try {
return df.parse(monthTime);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
/**
* 向上取整天数如果时间不为整月设为下个月1号0点
* @param time
* @return
*/
public static Date toMonthRoundUp(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String timeStr = df.format(time);
if (!"01000000".equals(timeStr.substring(6, 14))){
return toNextMonth(toMonthRoundDown(time));
} else {
return time;
}
}
/**
* 取下一月日期
* @param time
* @return
*/
public static Date toNextMonth(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.MONTH, 1);// +1月
return c.getTime();
}
/**
* 取上一月日期
* @param time
* @return
*/
public static Date toPreMonth(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.MONTH, -1);// -1月
return c.getTime();
}
/**
* 向下取整年设为当年1日0点
* @param time
* @return
*/
public static Date toYearRoundDown(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String monthTime = df.format(time);
monthTime = monthTime.substring(0, 4).concat("0101000000");
try {
return df.parse(monthTime);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
/**
* 向下取整年设为当年1日0点
* @param time
* @return
*/
public static Date toYearRoundUp(Date time){
DateFormat df = new SimpleDateFormat(dateFormat);
String timeStr = df.format(time);
if (!"0101000000".equals(timeStr.substring(4, 14))){
return toNextYear(toYearRoundDown(time));
} else {
return time;
}
}
/**
* 取下一年日期
* @param time
* @return
*/
public static Date toNextYear(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.YEAR, 1);// +1月
return c.getTime();
}
}

View File

@ -0,0 +1,39 @@
package com.joint.cloud.common.utils;
/**
* @author: zhanglc
* @date: 2020/1/3 14:49
*/
public class UnitUtil {
public static final long B = 1;
public static final long KB = B * 1024;
public static final long MB = KB * 1024;
public static final long GB = MB * 1024;
public static final long TB = GB * 1024;
public static final String B_STRING = "B";
public static final String KB_STRING = "KB";
public static final String MB_STRING = "MB";
public static final String GB_STRING = "GB";
public static final String CORE_STRING = "Core";
public static final double ONE = 1.0d;
public static final long SECOND = 1000;
public static final long MINUTE = 60 * SECOND;
public static final long HOUR = 60 * MINUTE;
public static final long DAY = 24 * HOUR;
}

View File

@ -0,0 +1,38 @@
package com.joint.cloud.common.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @author lilengyi
* @date 2020/4/10 15:50
*/
public class UserUtil {
public static String getCurrentUser(){
if (null != RequestContextHolder.getRequestAttributes()) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
if (null != request.getHeader("username")) {
// 也可获取到roles userId
// request.getHeader("roles");
// request.getHeader("userId");
return request.getHeader("username");
}
}
return "system";
}
public static String getCurrentIp(){
if(null != RequestContextHolder.getRequestAttributes()) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip =request.getHeader("X-Real-IP");
if(!StringUtils.hasLength(ip)) {
return null;
}
return ip;
}
return "system";
}
}

View File

@ -0,0 +1,24 @@
package com.joint.cloud.common.utils;
import com.joint.cloud.common.exception.AIOpsException;
import com.joint.cloud.common.exception.msg.NullParameterExceptionErrorMsg;
/**
* @author lilengyi
* @date 2020/1/3 14:58
*/
public class ValidatorUtil {
/**
* 参数校验判断是否为空
*
* @param param
* @param paramName
*/
public static void paramNotNull(Object param, String paramName) {
if (param == null) {
throw new AIOpsException(
new NullParameterExceptionErrorMsg(paramName));
}
}
}

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>joint-cloud</artifactId>
<groupId>com.joint.cloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>joint-cloud-gateway</artifactId>
<name>joint-cloud-gateway</name>
<version>${joint.cloud.version}</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</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>
</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>

View File

@ -0,0 +1,41 @@
package com.joint.cloud.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@EnableFeignClients
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,31 @@
package com.joint.cloud.gateway.config;
import com.joint.cloud.gateway.security.HeaderEnhanceFilter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
/**
* @author super.wu
*/
@Configuration
@EnableAutoConfiguration
public class FilterConfig {
//
@Bean
public FilterRegistrationBean<HeaderEnhanceFilter> filterRegistrationBean() {
FilterRegistrationBean<HeaderEnhanceFilter> registrationBean = new FilterRegistrationBean<HeaderEnhanceFilter>();
registrationBean.setFilter(headerEnhanceFilter());
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
@Bean
public HeaderEnhanceFilter headerEnhanceFilter() {
return new HeaderEnhanceFilter();
}
}

View File

@ -0,0 +1,51 @@
package com.joint.cloud.gateway.config;
import com.joint.cloud.gateway.properties.PermitAllUrlProperties;
import com.joint.cloud.gateway.security.CustomRemoteTokenServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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;
/**
* @author super.wu
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private ResourceServerProperties resource;
@Autowired
private PermitAllUrlProperties permitAllUrlProperties;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatchers().antMatchers("/**")
.and()
.authorizeRequests()
.antMatchers(permitAllUrlProperties.getPermitallPatterns()).permitAll()
.anyRequest().authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
CustomRemoteTokenServices resourceServerTokenServices = new CustomRemoteTokenServices();
resourceServerTokenServices.setCheckTokenEndpointUrl(resource.getTokenInfoUri());
resourceServerTokenServices.setClientId(resource.getClientId());
resourceServerTokenServices.setClientSecret(resource.getClientSecret());
resourceServerTokenServices.setLoadBalancerClient(loadBalancerClient);
resources.tokenServices(resourceServerTokenServices);
}
}

View File

@ -0,0 +1,27 @@
package com.joint.cloud.gateway.config;
import com.joint.cloud.gateway.properties.PermitAllUrlProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author keets
* @date 2017/9/29
*/
@Configuration
public class ServiceConfig {
@Value("${server.port}")
private int securePort;
@Bean
@ConfigurationProperties(prefix = "auth")
public PermitAllUrlProperties getPermitAllUrlProperties() {
return new PermitAllUrlProperties();
}
}

View File

@ -0,0 +1,53 @@
package com.joint.cloud.gateway.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class WebLogAspect {
private final Logger logger = LoggerFactory.getLogger("apiLogger");
@Pointcut("execution(public * com.joint.cloud.gateway.controller..*.*(..))")//切入点描述 这个是controller包的切入点
public void controllerLog(){}//签名可以理解成这个切入点的一个名称
// @Pointcut("execution(public * com.stuPayment.uiController..*.*(..))")//切入点描述这个是uiController包的切入点
// public void uiControllerLog(){}
@Before("controllerLog()") //在切入点的方法run之前要干的
public void logBeforeController(JoinPoint joinPoint) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//这个RequestContextHolder是Springmvc提供来获得请求的东西
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
// 过滤 health check
if ("com.joint.cloud.gateway.controller.HealthController".equals(joinPoint.getSignature().getDeclaringTypeName())) {
return;
}
// 记录下请求内容
logger.info("### URL : " + request.getRequestURL().toString());
logger.info("### HTTP_METHOD : " + request.getMethod());
logger.info("### IP : " + request.getRemoteAddr());
// logger.info("################THE ARGS OF THE CONTROLLER : " + Arrays.toString(joinPoint.getArgs()));
//下面这个getSignature().getDeclaringTypeName()是获取包+类名的 然后后面的joinPoint.getSignature.getName()获取了方法名
logger.info("### CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//logger.info("################TARGET: " + joinPoint.getTarget());//返回的是需要加强的目标类的对象
//logger.info("################THIS: " + joinPoint.getThis());//返回的是经过加强后的代理类的对象
}
}

View File

@ -0,0 +1,42 @@
package com.joint.cloud.gateway.config;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class WebSocketFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String upgradeHeader = request.getHeader("Upgrade");
if (null == upgradeHeader) {
upgradeHeader = request.getHeader("upgrade");
}
if (null != upgradeHeader && "websocket".equalsIgnoreCase(upgradeHeader)) {
context.addZuulRequestHeader("connection", "Upgrade");
}
return null;
}
}

View File

@ -0,0 +1,45 @@
package com.joint.cloud.gateway.constants;
/**
* Created by keets on 2017/12/9.
*/
//@Component
//@Configuration
public class SecurityConstants {
// public static final String USER_ID_IN_HEADER = "X-AOHO-UserId";
// public static final String AUTH_SERVICE = "nycloud-auth-server";
// @Value("${authserver.user-id-in-header}")
private String userIdInHeader = "X-AOHO-UserId";
private String realIPInHeader = "X-Real-IP";
// @Value("${authserver.service-id}")
private String authServerServiceId = "joint-cloud-auth";
public String getUserIdInHeader() {
return userIdInHeader;
}
public void setUserIdInHeader(String userIdInHeader) {
this.userIdInHeader = userIdInHeader;
}
public String getAuthServerServiceId() {
return authServerServiceId;
}
public void setAuthServerServiceId(String authServerServiceId) {
this.authServerServiceId = authServerServiceId;
}
public String getRealIPInHeader() {
return realIPInHeader;
}
public void setRealIPInHeader(String realIPInHeader) {
this.realIPInHeader = realIPInHeader;
}
}

View File

@ -0,0 +1,16 @@
package com.joint.cloud.gateway.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
public class HealthController {
@GetMapping("/health")
public String health() {
return "I'm health now " + (new Date()).toString();
}
}

View File

@ -0,0 +1,75 @@
package com.joint.cloud.gateway.properties;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author keets
* @date 2017/9/25
*/
public class PermitAllUrlProperties {
private static List<Pattern> permitAllUrlPattern;
private List<url> permitAll;
public String[] getPermitallPatterns() {
List<String> urls = new ArrayList<String>();
Iterator<url> iterator = permitAll.iterator();
while (iterator.hasNext()) {
urls.add(iterator.next().getPattern());
}
return urls.toArray(new String[0]);
}
public static List<Pattern> getPermitallUrlPattern() {
return permitAllUrlPattern;
}
public static class url {
private String pattern;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
@PostConstruct
public void init() {
if (permitAll != null && permitAll.size() > 0) {
permitAllUrlPattern = new ArrayList<Pattern>();
Iterator<url> iterator = permitAll.iterator();
while (iterator.hasNext()) {
String currentUrl = iterator.next().getPattern().replaceAll("\\*\\*", "(.*?)");
Pattern currentPattern = Pattern.compile(currentUrl, Pattern.CASE_INSENSITIVE);
permitAllUrlPattern.add(currentPattern);
}
}
}
public boolean isPermitAllUrl(String url) {
for (Pattern pattern : permitAllUrlPattern) {
if (pattern.matcher(url).find()) {
return true;
}
}
return false;
}
public List<url> getPermitAll() {
return permitAll;
}
public void setPermitAll(List<url> permitAll) {
this.permitAll = permitAll;
}
}

View File

@ -0,0 +1,146 @@
package com.joint.cloud.gateway.security;
/**
* Created by keets on 2017/12/9.
*/
import com.joint.cloud.gateway.constants.SecurityConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Map;
public class CustomRemoteTokenServices implements ResourceServerTokenServices {
private SecurityConstants securityConstants=new SecurityConstants();
private LoadBalancerClient loadBalancerClient;
protected final Log logger = LogFactory.getLog(getClass());
private RestOperations restTemplate;
private String checkTokenEndpointUrl;
private String clientId;
private String clientSecret;
private String tokenName = "token";
private AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
public CustomRemoteTokenServices() {
restTemplate = new RestTemplate();
((RestTemplate) restTemplate).setErrorHandler(new DefaultResponseErrorHandler() {
@Override
// Ignore 400
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getRawStatusCode() != 400) {
super.handleError(response);
}
}
});
}
public void setRestTemplate(RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
public void setCheckTokenEndpointUrl(String checkTokenEndpointUrl) {
this.checkTokenEndpointUrl = checkTokenEndpointUrl;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public void setAccessTokenConverter(AccessTokenConverter accessTokenConverter) {
this.tokenConverter = accessTokenConverter;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
@Override
public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(1);
formData.add(tokenName, accessToken);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", getAuthorizationHeader(clientId, clientSecret));
String authServerServiceId=securityConstants.getAuthServerServiceId();
ServiceInstance serviceInstance = loadBalancerClient.choose(authServerServiceId);
if (serviceInstance == null) {
throw new RuntimeException("Failed to choose an auth instance.");
}
Map<String, Object> map = postForMap(serviceInstance.getUri().toString() + checkTokenEndpointUrl, formData, headers);
if (map.containsKey("error")) {
logger.debug("check_token returned error: " + map.get("error"));
throw new InvalidTokenException(accessToken);
}
Assert.state(map.containsKey("client_id"), "Client id must be present in response from auth server");
return tokenConverter.extractAuthentication(map);
}
public void setLoadBalancerClient(LoadBalancerClient loadBalancerClient) {
this.loadBalancerClient = loadBalancerClient;
}
@Override
public OAuth2AccessToken readAccessToken(String accessToken) {
throw new UnsupportedOperationException("Not supported: read access token");
}
private String getAuthorizationHeader(String clientId, String clientSecret) {
String creds = String.format("%s:%s", clientId, clientSecret);
try {
return new StringBuilder("Basic ").append(Base64.getEncoder().encodeToString(creds.getBytes("utf-8"))).toString();
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Could not convert String");
}
}
private Map<String, Object> postForMap(String path, MultiValueMap<String, String> formData, HttpHeaders headers) {
if (headers.getContentType() == null) {
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
}
@SuppressWarnings("rawtypes")
Map map = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class).getBody();
@SuppressWarnings("unchecked")
Map<String, Object> result = map;
return result;
}
}

View File

@ -0,0 +1,151 @@
package com.joint.cloud.gateway.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.context.RequestContext;
import com.joint.cloud.gateway.constants.SecurityConstants;
import com.joint.cloud.gateway.properties.PermitAllUrlProperties;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
/**
* @author super.wu
*/
public class HeaderEnhanceFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(HeaderEnhanceFilter.class);
private static final String ANONYMOUS_USER_ID = "d4a65d04-a5a3-465c-8408-405971ac3346";
private static final String AuthorizationKey = "Authorization";
private SecurityConstants securityConstants=new SecurityConstants();
@Autowired
private PermitAllUrlProperties permitAllUrlProperties;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String authorization = ((HttpServletRequest) servletRequest).getHeader(AuthorizationKey);
String requestURI = ((HttpServletRequest) servletRequest).getRequestURI();
// test if request url is permit all , then remove authorization from header
LOGGER.info(String.format("Enhance request URI : %s.", requestURI));
if(isPermitAllUrl(requestURI) && isNotOAuthEndpoint(requestURI)) {
HttpServletRequest resetRequest = removeValueFromRequestHeader((HttpServletRequest) servletRequest);
filterChain.doFilter(resetRequest, servletResponse);
return;
} else {
if (StringUtils.isNotEmpty(authorization)) {
// 判断是否是jwt token
if (isJwtBearerToken(authorization)) {
try {
authorization = StringUtils.substringBetween(authorization, ".");
String decoded = new String(Base64.decodeBase64(authorization));
Map<?, ?> properties = new ObjectMapper().readValue(decoded, Map.class);
String userId = (String) properties.get(securityConstants.getUserIdInHeader());
RequestContext.getCurrentContext().addZuulRequestHeader("userId", userId);
RequestContext.getCurrentContext().addZuulRequestHeader("username", (String)properties.get("user_name"));
RequestContext.getCurrentContext().addZuulRequestHeader("name", URLEncoder.encode((String)properties.get("name"),"UTF-8"));
RequestContext.getCurrentContext().addZuulRequestHeader("roles", (String)properties.get("roles"));
String realIp =((HttpServletRequest) servletRequest).getHeader("X-Real-IP");
if(realIp != null) {
RequestContext.getCurrentContext().addZuulRequestHeader(securityConstants.getRealIPInHeader(), realIp);
}
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("Failed to customize header for the request, but still release it as the it would be regarded without any user details.", e);
}
}
} else {
LOGGER.info("Regard this request as anonymous request, so set anonymous user_id in the header.");
RequestContext.getCurrentContext().addZuulRequestHeader(securityConstants.getUserIdInHeader(), ANONYMOUS_USER_ID);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
private boolean isJwtBearerToken(String token) {
return StringUtils.countMatches(token, ".") == 2 && (token.startsWith("Bearer") || token.startsWith("bearer"));
}
private boolean isNotOAuthEndpoint(String requestURI) {
return !requestURI.contains("/login");
}
private HttpServletRequestWrapper removeValueFromRequestHeader(HttpServletRequest request) {
HttpServletRequestWrapper httpServletRequestWrapper = new HttpServletRequestWrapper(request) {
private Set<String> headerNameSet;
private Set<String> headerSet;
@Override
public Enumeration<String> getHeaderNames() {
if (headerNameSet == null) {
// first time this method is called, cache the wrapped request's header names:
headerNameSet = new HashSet<String>();
Enumeration<String> wrappedHeaderNames = super.getHeaderNames();
while (wrappedHeaderNames.hasMoreElements()) {
String headerName = wrappedHeaderNames.nextElement();
if (!AuthorizationKey.equalsIgnoreCase(headerName)) {
headerNameSet.add(headerName);
}
}
//set default header name value of tenant id and user id
headerNameSet.add(securityConstants.getUserIdInHeader());
}
return Collections.enumeration(headerNameSet);
}
@Override
public Enumeration<String> getHeaders(String name) {
if (AuthorizationKey.equalsIgnoreCase(name)) {
return Collections.emptyEnumeration();
}
if (securityConstants.getUserIdInHeader().equalsIgnoreCase(name)) {
headerSet = new HashSet<String>();
headerSet.add(ANONYMOUS_USER_ID);
return Collections.enumeration(headerSet);
}
return super.getHeaders(name);
}
@Override
public String getHeader(String name) {
if (AuthorizationKey.equalsIgnoreCase(name)) {
return null;
}
if (securityConstants.getUserIdInHeader().equalsIgnoreCase(name)) {
return ANONYMOUS_USER_ID;
}
return super.getHeader(name);
}
};
return httpServletRequestWrapper;
}
private boolean isPermitAllUrl(String url) {
return permitAllUrlProperties.isPermitAllUrl(url);
}
}

View File

@ -0,0 +1,4 @@
spring:
cloud:
consul:
host: ${CONSUL_ADDR:10.4.79.107}

View File

@ -0,0 +1,85 @@
server:
port: 8090
spring:
application:
name: joint-cloud-gateway
profiles:
active: dev
cloud:
consul:
port: 8500
discovery:
instance-id: ${spring.application.name}:${spring.cloud.consul.discovery.ip-address}:${server.port}
prefer-ip-address: true
health-check-path: /health
health-check-interval: 60s
health-check-critical-timeout: 30s
ip-address: ${REGISTRY_ADDR:${spring.cloud.client.ip-address}}
authserver:
service-id: joint-cloud-auth
user-id-in-header: X-AOHO-UserId
zuul:
ribbon:
eager-load:
enabled: true
#不加此参数第一次调用很有可能超时
ignored-headers: Access-Control-Allow-Credentials, Access-Control-Allow-Origin
set-content-length: true
prefix: /
routes:
auth:
path: /user/**
serviceId: ${authserver.service-id}
sensitiveHeaders: Cookie,Set-Cookie
login:
path: /login/**
serviceId: ${authserver.service-id}
sensitiveHeaders: Cookie,Set-Cookie
admin:
path: /joint/admin/**
serviceId: joint-cloud-admin
# url: http://10.4.79.107:8096
sensitiveHeaders: Cookie,Set-Cookie
subject1:
path: /subject1/**
serviceId: joint-cloud-subject1-gateway
sensitiveHeaders: Cookie,Set-Cookie
subject2:
path: /subject2/**
serviceId: joint-cloud-subject2-gateway
sensitiveHeaders: Cookie,Set-Cookie
subject3:
path: /subject3/**
serviceId: joint-cloud-subject3-gateway
sensitiveHeaders: Cookie,Set-Cookie
subject4:
path: /subject4/**
serviceId: joint-cloud-subject4-gateway
sensitiveHeaders: Cookie,Set-Cookie
ribbon:
ConnectTimeout: 3000
ReadTimeout: 300000
auth:
permitall:
- pattern: /health/**
- pattern: /login/**
- pattern: /**/public/**
- pattern: /**/download/**
- pattern: /message/**
security:
oauth2:
client:
clientId: frontend
clientSecret: frontend
accessTokenUri: /oauth/token
userAuthorizationUri: /oauth/authorize
#clientAuthenticationScheme: form
resource:
userInfoUri: /userinfo
tokenInfoUri: /oauth/check_token
#preferTokenInfo: false
logging:
config: classpath:logback.xml

View File

@ -0,0 +1,84 @@
<configuration>
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
<!-- appender是configuration的子节点是负责写日志的组件。 -->
<!-- ConsoleAppender把日志输出到控制台 -->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %p (%file:%line\)- %m%n</pattern>
<!-- 控制台也要使用UTF-8不要使用GBK否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- RollingFileAppender滚动记录文件先将日志记录到指定文件当符合某个条件时将日志记录到其他文件 -->
<!-- 以下的大概意思是1.先按日期存日志日期变了将前一天的日志文件名重命名为XXX%日期%索引新的日志仍然是aclome.log -->
<!-- 2.如果日期没有发生变化但是当前日志的文件大小超过10M时对当前日志进行分割 重命名-->
<appender name="filelog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/joint-cloud-gateway.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名log/sys.2017-12-05.0.log -->
<fileNamePattern>logs/joint-cloud-gateway-%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小默认值是10MB,本篇设置为1KB只是为了演示 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点用来设置日志的输入格式 -->
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<!-- 记录日志的编码 -->
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<appender name="apiAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/joint-cloud-gateway-api.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名log/sys.2017-12-05.0.log -->
<fileNamePattern>logs/joint-cloud-gateway-api-%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小默认值是10MB,本篇设置为1KB只是为了演示 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点用来设置日志的输入格式 -->
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<!-- 记录日志的编码 -->
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<logger name="apiLogger" additivity="false">
<!--使用哪一个Appender-->
<appender-ref ref="apiAppender" />
</logger>
<!-- 控制台输出日志级别 -->
<root level="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="filelog" />
<appender-ref ref="apiAppender" />
</root>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- com.appley为根包也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
<!-- 级别依次为【从高到低】FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
<!-- <logger name="com.neusoft.aclome" level="DEBUG">-->
<!-- <appender-ref ref="filelog" />-->
<!-- </logger>-->
</configuration>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>joint-cloud</artifactId>
<groupId>com.joint.cloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>joint-cloud-subject-gateway</artifactId>
<name>joint-cloud-subject-gateway</name>
<version>${joint.cloud.version}</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</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>

View File

@ -0,0 +1,13 @@
package com.joint.cloud.subject.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewaySubjectApplication {
public static void main(String[] args) {
SpringApplication.run(GatewaySubjectApplication.class, args);
}
}

View File

@ -0,0 +1,16 @@
package com.joint.cloud.subject.gateway.contorller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
public class HealthController {
@GetMapping("/health")
public String health() {
return "I'm health now " + (new Date()).toString();
}
}

View File

@ -0,0 +1,15 @@
server:
port: 8091
spring:
application:
name: joint-cloud-subject1-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: 1-1-1
uri: lb://1-1-1-helloworld
predicates:
- Path=/1-1-1/**

View File

@ -0,0 +1,15 @@
server:
port: 8092
spring:
application:
name: joint-cloud-subject2-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: 2-1-1
uri: lb://2-1-1-helloworld
predicates:
- Path=/2-1-1/**

View File

@ -0,0 +1,15 @@
server:
port: 8093
spring:
application:
name: joint-cloud-subject3-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: 3-1-1
uri: lb://3-1-1-helloworld
predicates:
- Path=/3-1-1/**

View File

@ -0,0 +1,23 @@
server:
port: 8094
spring:
application:
name: joint-cloud-subject4-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: 4-1-1
uri: lb://subject4-1-1-helloworld
predicates:
- Path=/4-1-1/**
filters:
- StripPrefix=1
- id: 4-1-2
uri: lb://subject4-1-1-abc
predicates:
- Path=/4-1-2/**
filters:
- StripPrefix=1

View File

@ -0,0 +1,18 @@
server:
port: 9001
spring:
application:
name: joint-cloud-top-gateway
profiles:
active: subject4
cloud:
consul:
host: 10.4.79.107
port: 8500
discovery:
instance-id: ${spring.application.name}:${spring.cloud.consul.discovery.ip-address}:${server.port}
prefer-ip-address: true
health-check-path: /health
health-check-interval: 60s
health-check-critical-timeout: 30s
ip-address: ${REGISTRY_ADDR:${spring.cloud.client.ip-address}}

292
pom.xml Normal file
View File

@ -0,0 +1,292 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>joint-cloud-gateway</module>
<module>joint-cloud-subject-gateway</module>
<module>joint-cloud-common</module>
<module>joint-cloud-auth</module>
<module>subject4-1-1-helloworld</module>
<module>subject4-1-1-bc</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.joint.cloud</groupId>
<artifactId>joint-cloud</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<!-- jdk config -->
<java.version>1.8</java.version>
<!--maven config-->
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<!-- spring config -->
<spring-boot-admin.version>2.1.4</spring-boot-admin.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<!-- main version config -->
<joint.cloud.version>1.0.0-SNAPSHOT</joint.cloud.version>
<!-- conmmon jar config -->
</properties>
<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>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-dependencies</artifactId>
<version>${spring-boot-admin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-jpa</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- easypoi-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!--文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>3.9.1</version>
</dependency>
<!--Token生成与解析 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.19</version>
</dependency>
<!-- mysqljdbc驱动 ,这个是数据库连接池需要的-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.13</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>1.3.70</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.github.housepower</groupId>
<artifactId>clickhouse-native-jdbc-shaded</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>com.github.jsonzou</groupId>
<artifactId>jmockdata</artifactId>
<version>4.2.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

View File

@ -0,0 +1,202 @@
import request from '@/utils/request'
const testApi = {
getUsageHostInfo: getUsageHostInfo,
getTaskAllocationChartData: getTaskAllocationChartData,
getExpenseLists: getExpenseLists,
chooseSet: chooseSet,
getHostNums: getHostNums,
getGailanInfo: getGailanInfo,
getAbnormalDataList: getAbnormalDataList,
getManufacturerChartData: getManufacturerChartData,
getCpuChartData: getCpuChartData,
getDiskChartData: getDiskChartData,
getMemoryChartData: getMemoryChartData,
getPerformanceChartData: getPerformanceChartData,
getLineChartByOrgName: getLineChartByOrgName,
getAlarmTableData: getAlarmTableData,
getAbnormalInfoList: getAbnormalInfoList,
getEventResponseChartData: getEventResponseChartData,
getIllegalInfoList: getIllegalInfoList,
getIllegalPublicityChartData: getIllegalPublicityChartData,
getTransactionInfoList: getTransactionInfoList,
getSupplierList: getSupplierList,
getSupplierInfoById: getSupplierInfoById,
searchHostInfoById: searchHostInfoById,
getHostChartsById: getHostChartsById
}
// kt2/taskAllocation
function getUsageHostInfo() {
return request({
url: `/cloud/v1.0/kt2/taskAllocation/getUsageHostInfo`,
method: 'get'
})
}
function getTaskAllocationChartData() {
return request({
url: `/cloud/v1.0/kt2/taskAllocation/getTaskAllocationChartData`,
method: 'get'
})
}
function getExpenseLists() {
return request({
url: `/cloud/v1.0/kt2/taskAllocation/getExpenseLists`,
method: 'get'
})
}
function chooseSet(data) {
return request({
url: `/cloud/v1.0/kt2/taskAllocation/chooseSet`,
data: data,
method: 'post'
})
}
// kt3/screen
function getHostNums() {
return request({
url: `/cloud/v1.0/kt3/screen/getHostNums`,
method: 'get'
})
}
function getGailanInfo() {
return request({
url: `/cloud/v1.0/kt3/screen/getGailanInfo`,
method: 'get'
})
}
function getManufacturerChartData() {
return request({
url: `/cloud/v1.0/kt3/screen/getManufacturerChartData`,
method: 'get'
})
}
function getCpuChartData(params) {
return request({
url: `/cloud/v1.0/kt3/screen/getCpuChartData`,
method: 'get',
params: params
})
}
function getDiskChartData(params) {
return request({
url: `/cloud/v1.0/kt3/screen/getDiskChartData`,
method: 'get',
params: params
})
}
function getMemoryChartData(params) {
return request({
url: `/cloud/v1.0/kt3/screen/getMemoryChartData`,
method: 'get',
params: params
})
}
function getPerformanceChartData(params) {
return request({
url: `/cloud/v1.0/kt3/screen/getPerformanceChartData`,
method: 'get',
params: params
})
}
function getLineChartByOrgName(params) {
return request({
url: `/cloud/v1.0/kt3/screen/getLineChartByOrgName`,
method: 'get',
params: params
})
}
function getAlarmTableData(params) {
return request({
url: `/cloud/v1.0/kt3/screen/getAlarmTableData`,
method: 'get',
params: params
})
}
function getAbnormalDataList() {
return request({
url: `/cloud/v1.0/kt3/screen/getAbnormalDataList`,
method: 'get'
})
}
// kt3/eventResponse
function getAbnormalInfoList() {
return request({
url: `/cloud/v1.0/kt3/eventResponse/getAbnormalInfoList`,
method: 'get'
})
}
function getEventResponseChartData() {
return request({
url: `/cloud/v1.0/kt3/eventResponse/getEventResponseChartData`,
method: 'get'
})
}
// kt3/illegalPublicity
function getIllegalInfoList() {
return request({
url: `/cloud/v1.0/kt3/illegalPublicity/getIllegalInfoList`,
method: 'get'
})
}
function getIllegalPublicityChartData() {
return request({
url: `/cloud/v1.0/kt3/illegalPublicity/getIllegalPublicityChartData`,
method: 'get'
})
}
// kt3/supplierManagement
function getTransactionInfoList() {
return request({
url: `/cloud/v1.0/kt3/supplierManagement/getTransactionInfoList`,
method: 'get'
})
}
function getSupplierList() {
return request({
url: `/cloud/v1.0/kt3/supplierManagement/getSupplierList`,
method: 'get'
})
}
function getSupplierInfoById(params) {
return request({
url: `/cloud/v1.0/kt3/supplierManagement/getSupplierInfoById`,
method: 'get',
params: params
})
}
// kt3/hostPerformance
function searchHostInfoById(params) {
return request({
url: `/cloud/v1.0/kt3/hostPerformance/searchHostInfoById`,
method: 'get',
params: params
})
}
function getHostChartsById(params) {
return request({
url: `/cloud/v1.0/kt3/hostPerformance/searchHostInfoById`,
method: 'get',
params: params
})
}
export default testApi

View File

@ -0,0 +1,235 @@
#taskAllocation {
.top_row_button{
margin-top:1.8vh;
}
#top-row-button-box {
.el-button--primary {
background-color: #1890ff1f
}
}
.top_row_text{
color: #FFFFFF;
margin-top:1.8vh;
}
.title_row {
display: flex;
display: -webkit-flex;
justify-content: center;
}
.title_box {
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.title_box_text {
font-family: 'Alternate';
font-size: 30px;
color: white;
}
.title_box_hr {
border-bottom: 2px solid;
opacity: 0.2;
color: white;
width: 120%;
margin-top: 2%;
margin-left: -10%;
}
.el-card {
border-radius: 4px;
border: 1px solid #ffffff;
background-color: rgba(255, 255, 255, 0);
}
.el-card__header {
padding: 3px 10px;
border-bottom: 1px solid #EBEEF5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
height: 4vh;
}
.el-card__body, .el-main {
padding: 5px;
}
.el-card__body{
padding: 5px;
height: 20vh;
}
.card1{
height:30vh;
margin: 20px 20px 20px 20px;
padding: 10px 20px 0 20px;
}
.card2{
height:30vh;
margin: 20px 20px 20px 20px;
padding: 10px 20px 0 20px;
}
.card3{
height:26vh;
margin: 20px 20px 20px 20px;
padding: 10px 20px 0 20px;
}
.card3-box{
display: flex;
display: -webkit-flex;
height:25vh;
}
.chart_box {
width: 90%;
margin-left: 10%;
}
.tableBox {
width: 100%;
overflow: hidden
}
.tableInner {
height: auto;
}
.card1-inner{
height:24vh;
padding-bottom:80px;
color: #FFFFFF;
}
.card1_inner_row{
height:5vh;
display: flex;
display: -webkit-flex;
align-items: center;
justify-content: center;
}
.card1_inner_num {
font-family: 'Alternate';
color: #FFFFFF;
letter-spacing: 0;
text-shadow: 0 0 6px #26A2FF;
font-size: 11pt;
}
.card1_inner_img {
margin-top:-2px;
height: 25px;
width: 25px;
}
.card2-inner{
height:25vh;
padding-bottom:80px;
color: #FFFFFF;
flex-wrap: wrap;
margin-top: -1vh;
}
.card-chart-box{
width: 103%;
margin-top: -5vh;
margin-left: 2%;
}
.card3-inner-box{
height:100%;
padding-bottom:80px;
color: #FFFFFF;
width: 23.8%;
flex-shrink: 0;
margin-right: 1.8%;
}
.card3-inner{
height:19vh;
color: #FFFFFF;
width: 100%;
}
.card3_inner_img {
margin-top:-2px;
height: 20px;
width: 20px;
}
.card3_detail_box{
margin-left: 20px;
overflow: auto;
height:13vh
}
.el-dialog {
background: rgba(0, 0, 0, 0.3);
border-radius: 10px;
}
.el-dialog > .el-dialog__body {
padding: 0px;
border-left: 2px solid #FFFFFF;
border-right: 2px solid #FFFFFF;
background-color: rgba(0, 0, 0, 0.3);
color: white;
margin: 0 0 0 0;
}
.el-dialog__title {
color: #FFFFFF;
}
.el-dialog__header {
border-top: 2px solid #FFFFFF;
border-left: 2px solid #FFFFFF;
border-right: 2px solid #FFFFFF;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
background-color: rgba(0, 0, 0, 0.3);
color: white;
}
.el-dialog__footer {
border-bottom: 2px solid #FFFFFF;
border-left: 2px solid #FFFFFF;
border-right: 2px solid #FFFFFF;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
background-color: rgba(0, 0, 0, 0.3);
color: white;
}
.top_button_box {
margin-top: 1%;
margin-left: auto;
display: flex;
display: -webkit-flex;
align-items: center;
}
.title_class {
font-family: 'Alternate';
font-weight: bold;
font-size: 11pt;
color: white;
}
.el-descriptions {
background: rgba(255, 255, 255, 0);
margin-left: 3%;
}
.el-descriptions__body {
color: #ffffff;
background-color: rgba(255, 255, 255, 0);
}
.el-descriptions__title {
color: white;
font-size: 11pt;
}
el-descriptions-item el-descriptions-item__cell {
height: 15px;
}
}

View File

@ -0,0 +1,383 @@
<template>
<div id="taskAllocation" >
<!--右上角按钮-->
<div style='position:absolute;right:55px;top:12.5%;z-index: 99'>
<div class='top_button_box'>
<i style="margin-left:5px;color: white;font-size: 30px;opacity: 0.5;z-index: 98" @click="fullScreen" class="el-icon-full-screen"></i>
</div>
</div>
<div id="entirety" style="background-image: url('/static/background/background.png');padding: 10px">
<!--标题行-->
<el-row :gutter="30">
<el-col :span='8'>
<div id= "top-row-button-box" style='margin-left: 30px'>
<el-button type="primary" size="small" class='top_row_button' @click='upDateResults'>预测结果更新</el-button>
<el-button type="primary" size="small" class='top_row_button'>资源调度更新</el-button>
<el-button type="primary" size="small" class='top_row_button'>任务分配更新</el-button>
</div>
</el-col>
<el-col :span='8'>
<div class="title_row">
<div class='title_box'>
<div class="title_box_text">
任务分配与资源调度平台
</div>
<div class="title_box_hr"></div>
</div>
</div>
</el-col>
<el-col :span='8' >
<div class='top_row_text' style='float: right;margin-right: 80px'>
<span>滚动播放</span>
<el-radio-group v-model="scrollValue" size="small" @change='scrollChange'>
<el-radio-button label="开"></el-radio-button>
<el-radio-button label="关"></el-radio-button>
</el-radio-group>
</div>
</el-col>
</el-row>
<!-- card1 -->
<el-card class="card1">
<div class="title_class" style='margin-top: -5px'>当前资源使用情况</div>
<el-row :gutter="20">
<el-col :span="6">
<el-card class='card1-inner'>
<div slot="header" class="clearfix">
<span>CPU使用率</span>
</div>
<div class="tableInnerCpu">
<div v-for="item in usageDataList" :key="item.id" class="card1_inner_row">
<el-row style="width:80%;margin-left: 15%">
<el-col :span='12'>
<img class="card1_inner_img" :src='item.icon'>
<span class="card1_inner_num" style='margin-left:5%'>{{item.label}}: </span>
</el-col>
<el-col :span='12'>
<span class="card1_inner_num" >{{item.cpuUsage}}</span>
<span class="card1_inner_num">/ </span>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.cpuTotal }}</span>
</el-col>
</el-row>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class='card1-inner'>
<div slot="header" class="clearfix">
<span>内存使用率</span>
</div>
<div class="tableInnerMemory">
<div v-for="item in usageDataList" :key="item.id" class="card1_inner_row">
<el-row style="width:80%;margin-left: 10%">
<el-col :span='12'>
<img class="card1_inner_img" :src='item.icon'>
<span class="card1_inner_num" style='margin-left:5%;'>{{item.label}}: </span>
</el-col>
<el-col :span='12'>
<span class="card1_inner_num" >{{item.memoryUsage}}</span>
<span class="card1_inner_num" >/ </span>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.memoryTotal }}</span>
</el-col>
</el-row>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class='card1-inner'>
<div slot="header" class="clearfix">
<span>带宽使用率</span>
</div>
<div class="tableInnerBandWidth">
<div v-for="item in usageDataList" :key="item.id" class="card1_inner_row">
<el-row style="width:90%;margin-left: 5%">
<el-col :span='10'>
<img class="card1_inner_img" :src='item.icon'>
<span class="card1_inner_num" style='margin-left:5%;'>{{item.label}}: </span>
</el-col>
<el-col :span='14'>
<span class="card1_inner_num" >{{item.bandWidthUsage}}</span>
<span class="card1_inner_num" >/ </span>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.bandWidthTotal }}</span>
</el-col>
</el-row>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class='card1-inner'>
<div slot="header" class="clearfix">
<span>存储使用率</span>
</div>
<div class="tableInnerDisk">
<div v-for="item in usageDataList" :key="item.id" class="card1_inner_row">
<el-row style="width:80%;margin-left: 10%">
<el-col :span='12'>
<img class="card1_inner_img" :src='item.icon'>
<span class="card1_inner_num" style='margin-left:5%;'>{{item.label}}: </span>
</el-col>
<el-col :span='12'>
<span class="card1_inner_num" >{{item.diskUsage}}</span>
<span class="card1_inner_num" >/ </span>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.diskTotal }}</span>
</el-col>
</el-row>
</div>
</div>
</el-card>
</el-col>
</el-row>
</el-card>
<el-card class="card2">
<div class="title_class" style='margin-top: -5px'>云际平台未来费用预测</div>
<el-row :gutter="20">
<el-col :span="6">
<div id="chart_real" style="height: 29vh;"></div>
</el-col>
<el-col :span="6">
<el-card class='card2-inner'>
<div slot="header" class="clearfix">
<span>短期套餐</span>
<el-button style="float: right; padding: 3px 0" type="text" @click='openDetailDialog(`shortTerm`)'>详情</el-button>
<el-button style="float: right; padding: 3px 0;margin-right: 10px" type="text" :disabled='chooseBtnFlag' @click='chooseSet(`shortTerm`)'>选择</el-button>
</div>
<div style='text-align: center;margin-top: 1vh'>
<span class='card1_inner_num'>总费用</span>
<span class='card1_inner_num'>${{expenseLists.shortTermExpenseDetail.totalExpense}}</span>
</div>
<div class='card-chart-box'>
<div id='short_term_chart' style="height: 24vh"> </div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class='card2-inner'>
<div slot="header" class="clearfix">
<span>中期套餐</span>
<el-button style="float: right; padding: 3px 0" type="text" @click='openDetailDialog(`mediumTerm`)'>详情</el-button>
<el-button style="float: right; padding: 3px 0;margin-right: 10px" type="text" :disabled='chooseBtnFlag' @click='chooseSet(`mediumTerm`)'>选择</el-button>
</div>
<div style="text-align: center;margin-top: 1vh">
<span class='card1_inner_num'>总费用</span>
<span class='card1_inner_num'>${{expenseLists.mediumTermExpenseDetail.totalExpense}}</span>
</div>
<div class='card-chart-box'>
<div id='medium_term_chart' style="height: 24vh"> </div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class='card2-inner'>
<div slot="header" class="clearfix">
<span>长期套餐</span>
<el-button style="float: right; padding: 3px 0" type="text" @click='openDetailDialog(`longTerm`)'>详情</el-button>
<el-button style="float: right; padding: 3px 0;margin-right: 10px" type="text" :disabled='chooseBtnFlag' @click='chooseSet(`longTerm`)'>选择</el-button>
</div>
<div style='text-align: center;margin-top: 1vh'>
<span class='card1_inner_num'>总费用</span>
<span class='card1_inner_num'>${{expenseLists.longTermExpenseDetail.totalExpense}}</span>
</div>
<div class='card-chart-box'>
<div id='long_term_chart' style="height: 24vh"> </div>
</div>
</el-card>
</el-col>
</el-row>
</el-card>
<el-card class="card3">
<div class="title_class" style='margin-top: -5px'>资源调度及任务分配结果</div>
<div class='card3-box'>
<div v-for="item in usageDataList" :key="item.id" class='card3-inner-box' >
<el-card class='card3-inner' >
<div slot="header" class="clearfix">
<img class="card3_inner_img" :src='item.icon'>
<span>{{ item.label }}</span>
</div>
<div v-if='item.showAll'>
<el-row style="width:90%;margin-left: 10%;margin-top: 2%">
<el-col :span='6'>
<span class="card1_inner_num" style='margin-left:5%;'>cpu: </span>
</el-col>
<el-col :span='12'>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.cpuTotal }}</span>
</el-col>
<el-col :span='6'>
<el-button style="padding: 3px 0" type="text" @click='showCpuDetail(item)'>详情</el-button>
</el-col>
</el-row>
<el-row style="width:90%;margin-left: 10%">
<el-col :span='6'>
<span class="card1_inner_num" style='margin-left:5%;'>内存: </span>
</el-col>
<el-col :span='12'>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.memoryTotal }}</span>
</el-col>
<el-col :span='6'>
<el-button style="padding: 3px 0" type="text" @click='showMemoryDetail(item)'>详情</el-button>
</el-col>
</el-row>
<el-row style="width:90%;margin-left: 10%">
<el-col :span='6'>
<span class="card1_inner_num" style='margin-left:5%;'>带宽: </span>
</el-col>
<el-col :span='12'>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.bandWidthTotal }}</span>
</el-col>
<el-col :span='6'>
<el-button style="padding: 3px 0" type="text" @click='showBandWidthDetail(item)'>详情</el-button>
</el-col>
</el-row>
<el-row style="width:90%;margin-left: 10%">
<el-col :span='6'>
<span class="card1_inner_num" style='margin-left:5%;'>存储: </span>
</el-col>
<el-col :span='12'>
<span class="card1_inner_num" style="color:#87CEFA;"> {{item.diskTotal }}</span>
</el-col>
<el-col :span='6'>
<el-button style="padding: 3px 0" type="text" @click='showDiskDetail(item)'>详情</el-button>
</el-col>
</el-row>
</div>
<div v-if='item.showCpuDetail' class="card3_detail_box">
<el-row class="card1_inner_num" style='margin-top: 2%'>
<el-col :span='12'>
<span>CPU</span>
</el-col>
<el-col :span='12'>
<el-button style="padding: 3px 0" type="text" @click='quitDetail(item)'>退出详情</el-button>
</el-col>
</el-row>
<div v-for="detailItem in item.cpuList" :key="detailItem" class="card1_inner_num">
<span> {{detailItem.num}}</span>
<span> vCPU</span>
<span> {{detailItem.detail}}</span>
</div>
</div>
<div v-if='item.showMemoryDetail' class="card3_detail_box">
<el-row class="card1_inner_num" style='margin-top: 2%'>
<el-col :span='12'>
<span>内存</span>
</el-col>
<el-col :span='12'>
<el-button style="padding: 3px 0" type="text" @click='quitDetail(item)'>退出详情</el-button>
</el-col>
</el-row>
<div v-for="detailItem in item.memoryList" :key="detailItem" class="card1_inner_num" >
<span> {{detailItem.num}}</span>
<span style='margin-left: 10%'> {{detailItem.detail}}</span>
</div>
</div>
<div v-if='item.showBandWidthDetail' class="card3_detail_box">
<el-row class="card1_inner_num" style='margin-top: 2%'>
<el-col :span='12'>
<span>带宽</span>
</el-col>
<el-col :span='12'>
<el-button style="padding: 3px 0" type="text" @click='quitDetail(item)'>退出详情</el-button>
</el-col>
</el-row>
<div v-for="detailItem in item.bandWidthList" :key="detailItem" >{{detail}}</div>
</div>
<div v-if='item.showDiskDetail' class="card3_detail_box">
<el-row class="card1_inner_num" style='margin-top: 2%'>
<el-col :span='12'>
<span>存储</span>
</el-col>
<el-col :span='12'>
<el-button style="padding: 3px 0" type="text" @click='quitDetail(item)'>退出详情</el-button>
</el-col>
</el-row>
<div v-for="detailItem in item.diskList" :key="detailItem" class="card1_inner_num">
<span> {{detailItem.num}}</span>
<span> {{detailItem.detail}}</span>
</div>
</div>
</el-card>
</div>
</div>
</el-card>
<!--折线图详情-->
<el-dialog
title="详情"
:visible.sync="chartDialogVisible"
width="40%"
>
<el-descriptions title="对象存储">
<el-descriptions-item label="存储量">{{expenseInDialog.objectStorage.storageCapacity}}</el-descriptions-item>
<el-descriptions-item label="存储时长">{{expenseInDialog.objectStorage.storageDuration}}h</el-descriptions-item>
<el-descriptions-item label="单价">{{expenseInDialog.objectStorage.unitPrice}}</el-descriptions-item>
<el-descriptions-item label="总费用">{{expenseInDialog.objectStorage.cost}}</el-descriptions-item>
</el-descriptions>
<el-divider></el-divider>
<el-descriptions title="数据传输">
<el-descriptions-item label="传输量">{{expenseInDialog.dataTransfer.transferCapacity}}</el-descriptions-item>
<el-descriptions-item label="单价">{{expenseInDialog.dataTransfer.unitPrice}}</el-descriptions-item>
<el-descriptions-item label="总费用">{{expenseInDialog.dataTransfer.cost}}</el-descriptions-item>
</el-descriptions>
<el-divider></el-divider>
<el-descriptions title=" 数据库服务">
<el-descriptions-item label="数据库类型">{{expenseInDialog.databaseService.databaseType}}</el-descriptions-item>
<el-descriptions-item label="存储量">{{expenseInDialog.databaseService.storageCapacity}}</el-descriptions-item>
<el-descriptions-item label="使用时长">{{expenseInDialog.databaseService.duration}}h</el-descriptions-item>
<el-descriptions-item label="单价">{{expenseInDialog.databaseService.unitPrice}}</el-descriptions-item>
<el-descriptions-item label="总费用">{{expenseInDialog.databaseService.cost}}</el-descriptions-item>
</el-descriptions>
<el-divider></el-divider>
<el-descriptions title=" 负载均衡">
<el-descriptions-item label="实例数">{{expenseInDialog.loadBalancer.instancesNum}}</el-descriptions-item>
<el-descriptions-item label="使用时长">{{expenseInDialog.loadBalancer.duration}}h</el-descriptions-item>
<el-descriptions-item label="单价">{{expenseInDialog.loadBalancer.unitPrice}}/h/实例</el-descriptions-item>
<el-descriptions-item label="总费用">{{expenseInDialog.loadBalancer.cost}}</el-descriptions-item>
</el-descriptions>
<el-divider></el-divider>
<el-descriptions title=" 总费用">
<el-descriptions-item label="对象存储">{{expenseInDialog.objectStorage.cost}}</el-descriptions-item>
<el-descriptions-item label="数据传输">{{expenseInDialog.dataTransfer.cost}}</el-descriptions-item>
<el-descriptions-item label="数据库服务">{{expenseInDialog.databaseService.cost}}</el-descriptions-item>
<el-descriptions-item label="负载均衡">{{expenseInDialog.loadBalancer.cost}}</el-descriptions-item>
<el-descriptions-item label="总计">{{expenseInDialog.totalExpense}}</el-descriptions-item>
</el-descriptions>
<el-divider></el-divider>
<div id='chartInDialog' style='margin:0px 20px 0px 20px;height: 30vh;width:80%'></div>
<span slot="footer" class="dialog-footer">
</span>
</el-dialog>
</div>
</div>
</template>
<script src='./js/index.js'>
</script>
<style lang="scss">
@font-face {
font-family: 'Alternate';
//src: url('../../assets/iconfont/Alternate.ttf');
font-style: normal;
font-width: normal;
}
@import './css/taskAllocation.scss';
</style>

View File

@ -0,0 +1,702 @@
import echarts from 'echarts'
import $ from 'jQuery'
import testApi from '@/api/testApi'
export default {
name: 'businessScreen',
data() {
return {
scrollValue: '开',
intervalCpu: '',
intervalMemory: '',
intervalDisk: '',
intervalBandWidth: '',
intervalDispatch: '',
// 第一个card
usageDataList: [],
usageDataList1: [], // 没用
// 第二个card
chartDialogVisible: false,
chooseBtnFlag: false,
recentExpense: [],
shortTermExpense: [],
longTermExpense: [],
mediumTermExpense: [],
chartShortOption: '',
chartMediumOption: '',
chartLongOption: '',
expenseLists: {},
expenseInDialog: {}
}
},
created() {
},
beforeDestroy() {
if (this.intervalCpu !== '') {
clearInterval(this.intervalCpu)
}
if (this.intervalMemory !== '') {
clearInterval(this.intervalMemory)
}
if (this.intervalBandWidth !== '') {
clearInterval(this.intervalBandWidth)
}
if (this.intervalDisk !== '') {
clearInterval(this.intervalDisk)
}
if (this.intervalDispatch !== '') {
clearInterval(this.intervalDispatch)
}
},
async mounted() {
await this.getUsageHostInfo()
await this.upDateResults()
this.scrollChange()
},
methods: {
async upDateResults() {
const self = this
this.getCharts()
await this.getExpenseLists()
this.chooseBtnFlag = false
setTimeout(function() {
self.chooseBtnFlag = true
}, 10000)
},
async getUsageHostInfo() {
await testApi.getUsageHostInfo().then((res) => {
this.usageDataList = res.data
}).catch(() => {
this.usageDataList = [
{ id: 0, label: '阿里云', icon: '/static/hostPerformance/阿里云.png', cpuUsage: '4', cpuTotal: '10', memoryUsage: '4GB', memoryTotal: '116GB', diskUsage: '1TB', diskTotal: '10TB', bandWidthUsage: '2Mbps', bandWidthTotal: '10Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 1, label: '华为云', icon: '/static/hostPerformance/华为云.png', cpuUsage: '2', cpuTotal: '10', memoryUsage: '4GB', memoryTotal: '48GB', diskUsage: '8TB', diskTotal: '15TB', bandWidthUsage: '20Mbps', bandWidthTotal: '50Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 4, detail: '2.5GHz' }, { num: 2, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 4, detail: '8GB RAM' }, { num: 2, detail: '4GB RAM' }, { num: 4, detail: '2GB RAM' }],
diskList: [{ num: '10TB', detail: 'SSD' }, { num: '5TB', detail: 'HDD' }] },
{ id: 2, label: '联通云', icon: '/static/hostPerformance/联通云.png', cpuUsage: '3', cpuTotal: '10', memoryUsage: '8GB', memoryTotal: '48GB', diskUsage: '5TB', diskTotal: '8TB', bandWidthUsage: '60Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 6, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '6TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 3, label: '火山云', icon: '/static/hostPerformance/火山云.png', cpuUsage: '5', cpuTotal: '10', memoryUsage: '16GB', memoryTotal: '116GB', diskUsage: '4TB', diskTotal: '20TB', bandWidthUsage: '10Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 2, detail: '3GHz' }, { num: 6, detail: '3.7GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '16TB', detail: 'SSD' }, { num: '4TB', detail: 'HDD' }] },
{ id: 4, label: 'test1', icon: '/static/hostPerformance/火山云.png', cpuUsage: '4', cpuTotal: '10', memoryUsage: '16GB', memoryTotal: '128GB', diskUsage: '3TB', diskTotal: '10TB', bandWidthUsage: '40Mbps', bandWidthTotal: '200Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 4, detail: '2.4GHz' }, { num: 4, detail: '3GHz' }, { num: 2, detail: '3.7GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 5, label: 'test2', icon: '/static/hostPerformance/火山云.png', cpuUsage: '2', cpuTotal: '10', memoryUsage: '16GB', memoryTotal: '128GB', diskUsage: '4.5TB', diskTotal: '10TB', bandWidthUsage: '20Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 6, label: 'test3', icon: '/static/hostPerformance/火山云.png', cpuUsage: '5', cpuTotal: '10', memoryUsage: '12GB', memoryTotal: '128GB', diskUsage: '2.5TB', diskTotal: '10TB', bandWidthUsage: '20Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 7, label: 'test4', icon: '/static/hostPerformance/火山云.png', cpuUsage: '4', cpuTotal: '10', memoryUsage: '16GB', memoryTotal: '128GB', diskUsage: '1TB', diskTotal: '10TB', bandWidthUsage: '20Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] }
]
this.usageDataList1 = [{ id: 0, label: '阿里云', icon: '/static/hostPerformance/阿里云.png', cpuUsage: '4', cpuTotal: '15', memoryUsage: '4GB', memoryTotal: '48GB', diskUsage: '1TB', diskTotal: '15TB', bandWidthUsage: '2Mbps', bandWidthTotal: '20Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 1, label: '华为云', icon: '/static/hostPerformance/华为云.png', cpuUsage: '2', cpuTotal: '8', memoryUsage: '4GB', memoryTotal: '112GB', diskUsage: '8TB', diskTotal: '10TB', bandWidthUsage: '20Mbps', bandWidthTotal: '20Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 4, detail: '2.5GHz' }, { num: 2, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 4, detail: '8GB RAM' }, { num: 2, detail: '4GB RAM' }, { num: 4, detail: '2GB RAM' }],
diskList: [{ num: '10TB', detail: 'SSD' }, { num: '5TB', detail: 'HDD' }] },
{ id: 2, label: '联通云', icon: '/static/hostPerformance/联通云.png', cpuUsage: '3', cpuTotal: '15', memoryUsage: '8GB', memoryTotal: '128GB', diskUsage: '5TB', diskTotal: '10TB', bandWidthUsage: '60Mbps', bandWidthTotal: '200Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 6, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '6TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 3, label: '火山云', icon: '/static/hostPerformance/火山云.png', cpuUsage: '5', cpuTotal: '8', memoryUsage: '16GB', memoryTotal: '116GB', diskUsage: '4TB', diskTotal: '8TB', bandWidthUsage: '10Mbps', bandWidthTotal: '50Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 2, detail: '3GHz' }, { num: 6, detail: '3.7GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '16TB', detail: 'SSD' }, { num: '4TB', detail: 'HDD' }] },
{ id: 4, label: 'test1', icon: '/static/hostPerformance/火山云.png', cpuUsage: '4', cpuTotal: '10', memoryUsage: '16GB', memoryTotal: '128GB', diskUsage: '3TB', diskTotal: '15TB', bandWidthUsage: '40Mbps', bandWidthTotal: '200Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 4, detail: '2.4GHz' }, { num: 4, detail: '3GHz' }, { num: 2, detail: '3.7GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 5, label: 'test2', icon: '/static/hostPerformance/火山云.png', cpuUsage: '2', cpuTotal: '10', memoryUsage: '16GB', memoryTotal: '128GB', diskUsage: '4.5TB', diskTotal: '10TB', bandWidthUsage: '20Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 6, label: 'test3', icon: '/static/hostPerformance/火山云.png', cpuUsage: '5', cpuTotal: '10', memoryUsage: '12GB', memoryTotal: '128GB', diskUsage: '2.5TB', diskTotal: '10TB', bandWidthUsage: '20Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] },
{ id: 7, label: 'test4', icon: '/static/hostPerformance/火山云.png', cpuUsage: '4', cpuTotal: '10', memoryUsage: '16GB', memoryTotal: '128GB', diskUsage: '1TB', diskTotal: '10TB', bandWidthUsage: '20Mbps', bandWidthTotal: '100Mbps',
showAll: true, showCpuDetail: false, showMemoryDetail: false, showBandWidthDetail: false, showDiskDetail: false,
cpuList: [{ num: 2, detail: '2.5GHz' }, { num: 4, detail: '3GHz' }, { num: 4, detail: '3.6GHz' }],
memoryList: [{ num: 1, detail: '64GB RAM' }, { num: 10, detail: '2GB RAM' }, { num: 4, detail: '8GB RAM' }],
diskList: [{ num: '8TB', detail: 'SSD' }, { num: '2TB', detail: 'HDD' }] }]
})
},
async getExpenseLists() {
await testApi.getExpenseLists().then((res) => {
this.expenseLists = res.data
}).catch(() => {
this.expenseLists = {
recentExpenseDetail: {
totalExpense: '200',
objectStorage: {
storageCapacity: '100GB',
storageDuration: 720,
unitPrice: '$0.02/GB/h',
cost: '$14.40'
},
dataTransfer: {
transferCapacity: '500GB',
unitPrice: '$0.10/GB',
cost: '$50.00'
},
databaseService: {
databaseType: 'MySQL',
storageCapacity: '50GB',
duration: 720,
unitPrice: '$0.02/GB/h',
cost: '$28.80'
},
loadBalancer: {
instancesNum: 2,
duration: 720,
unitPrice: '$0.02',
cost: '$28.80'
}
},
shortTermExpenseDetail: {
totalExpense: '122',
objectStorage: {
storageCapacity: '100GB',
storageDuration: 720,
unitPrice: '$0.02/GB/h',
cost: '$14.40'
},
dataTransfer: {
transferCapacity: '500GB',
unitPrice: '$0.10/GB',
cost: '$50.00'
},
databaseService: {
databaseType: 'MySQL',
storageCapacity: '50GB',
duration: 720,
unitPrice: '$0.02/GB/h',
cost: '$28.80'
},
loadBalancer: {
instancesNum: 2,
duration: 720,
unitPrice: '$0.02',
cost: '$28.80'
}
},
mediumTermExpenseDetail: {
totalExpense: '158',
objectStorage: {
storageCapacity: '100GB',
storageDuration: 720,
unitPrice: '$0.02/GB/h',
cost: '$14.40'
},
dataTransfer: {
transferCapacity: '500GB',
unitPrice: '$0.10/GB',
cost: '$50.00'
},
databaseService: {
databaseType: 'MySQL',
storageCapacity: '50GB',
duration: 720,
unitPrice: '$0.02/GB/h',
cost: '$28.80'
},
loadBalancer: {
instancesNum: 2,
duration: 720,
unitPrice: '$0.02',
cost: '$28.80'
}
},
longTermExpenseDetail: {
totalExpense: '158',
objectStorage: {
storageCapacity: '100GB',
storageDuration: 720,
unitPrice: '$0.02/GB/h',
cost: '$14.40'
},
dataTransfer: {
transferCapacity: '500GB',
unitPrice: '$0.10/GB',
cost: '$50.00'
},
databaseService: {
databaseType: 'MySQL',
storageCapacity: '50GB',
duration: 720,
unitPrice: '$0.02/GB/h',
cost: '$28.80'
},
loadBalancer: {
instancesNum: 2,
duration: 720,
unitPrice: '$0.02',
cost: '$28.80'
}
}
}
this.expenseLists.shortTermExpenseDetail.totalExpense = (Math.abs(Math.random() * 100) + 100).toFixed(2)
this.expenseLists.longTermExpenseDetail.totalExpense = (Math.abs(Math.random() * 100) + 100).toFixed(2)
this.expenseLists.mediumTermExpenseDetail.totalExpense = (Math.abs(Math.random() * 100) + 100).toFixed(2)
})
},
scrollChange() {
const self = this
if (self.scrollValue === '开') {
const doscrollDispatch = function() {
const $parent = $('.card3-box')
const $first = $parent.find('div:first')
console.log($first)
const width = $first.width()
$first.animate({
width: 0
}, 500, function() {
$first.css('width', width).appendTo($parent)
})
}
this.intervalDispatch = setInterval(function() { doscrollDispatch() }, 5000)
const doscrollCpu = function() {
const $parent = $('.tableInnerCpu')
const $first = $parent.find('div:first')
console.log($first)
const height = $first.height()
$first.animate({
height: 0
}, 500, function() {
$first.css('height', height).appendTo($parent)
})
}
const doscrollMemory = function() {
const $parent = $('.tableInnerMemory')
const $first = $parent.find('div:first')
const height = $first.height()
$first.animate({
height: 0
}, 500, function() {
$first.css('height', height).appendTo($parent)
})
}
const doscrollBandWidth = function() {
const $parent = $('.tableInnerBandWidth')
const $first = $parent.find('div:first')
const height = $first.height()
$first.animate({
height: 0
}, 500, function() {
$first.css('height', height).appendTo($parent)
})
}
const doscrollDisk = function() {
const $parent = $('.tableInnerDisk')
const $first = $parent.find('div:first')
const height = $first.height()
$first.animate({
height: 0
}, 500, function() {
$first.css('height', height).appendTo($parent)
})
}
console.log(this.intervalCpu)
console.log(this.intervalMemory)
self.intervalCpu = setInterval(function() { doscrollCpu() }, 5000)
self.intervalMemory = setInterval(function() { doscrollMemory() }, 5000)
self.intervalBandWidth = setInterval(function() { doscrollBandWidth() }, 5000)
self.intervalDisk = setInterval(function() { doscrollDisk() }, 5000)
} else if (this.scrollValue === '关') {
if (this.intervalCpu !== '') {
clearInterval(self.intervalCpu)
}
if (this.intervalMemory !== '') {
clearInterval(self.intervalMemory)
}
if (this.intervalBandWidth !== '') {
clearInterval(self.intervalBandWidth)
}
if (this.intervalDisk !== '') {
clearInterval(self.intervalDisk)
}
if (this.intervalDispatch !== '') {
clearInterval(self.intervalDispatch)
}
}
},
makeData() {
const base = +new Date()
const oneDay = 24 * 3600 * 1000
// const data = [[base, Math.random() * 300]]
const data = []
for (let i = -49; i < 50; i++) {
const now = new Date((base + i * oneDay))
data.push([+now, Math.abs(Math.random() * 300).toFixed(2)])
}
return data
},
async getChartsData() {
await testApi.getTaskAllocationChartData().then((res) => {
this.recentExpense = res.data.recentExpense
this.shortTermExpense = res.data.shortTermExpense
this.mediumTermExpense = res.data.mediumTermExpense
this.longTermExpense = res.data.longTermExpense
}).catch(() => {
this.recentExpense = this.makeData()
this.shortTermExpense = this.makeData()
this.mediumTermExpense = this.makeData()
this.longTermExpense = this.makeData()
})
},
getCharts() {
this.getChartsData().then(r => {
const chart_real = echarts.init(document.getElementById('chart_real'), 'dark')
const chartRealOption = {
tooltip: {
trigger: 'axis'
},
title: {
left: 'center',
text: ''
},
backgroundColor: 'transparent',
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none'
},
restore: {},
saveAsImage: {}
}
},
xAxis: {
type: 'time',
boundaryGap: false
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%']
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100
},
{
type: 'inside',
start: 0,
end: 100
}
],
series: [
{
name: '费用(元)',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {},
data: this.recentExpense,
itemStyle: {
color: '#6495ED'
}
}
]
}
chart_real.setOption(chartRealOption)
const short_term_chart = echarts.init(document.getElementById('short_term_chart'), 'dark')
this.chartShortOption = {
tooltip: {
trigger: 'axis'
},
title: {
left: 'center',
text: ''
},
backgroundColor: 'transparent',
xAxis: {
type: 'time',
boundaryGap: false
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%']
},
dataZoom: [
{
type: 'inside',
start: 46,
end: 54
},
{
type: 'inside',
start: 46,
end: 54
}
],
series: [
{
name: '当前费用(元)',
type: 'line',
smooth: true,
symbol: 'none',
data: this.recentExpense,
itemStyle: {
color: '#6495ED'
}
}, {
name: '短期套餐费用(元)',
type: 'line',
smooth: true,
symbol: 'none',
data: this.shortTermExpense,
itemStyle: {
color: '#f5b000'
}
}
]
}
short_term_chart.setOption(this.chartShortOption)
const medium_term_chart = echarts.init(document.getElementById('medium_term_chart'), 'dark')
this.chartMediumOption = {
tooltip: {
trigger: 'axis'
},
title: {
left: 'center',
text: ''
},
backgroundColor: 'transparent',
xAxis: {
type: 'time',
boundaryGap: false
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%']
},
dataZoom: [
{
type: 'inside',
start: 46,
end: 54
},
{
type: 'inside',
start: 46,
end: 54
}
],
series: [
{
name: '当前费用(元)',
type: 'line',
smooth: true,
symbol: 'none',
data: this.recentExpense,
itemStyle: {
color: '#6495ED'
}
}, {
name: '中期套餐费用(元)',
type: 'line',
smooth: true,
symbol: 'none',
data: this.mediumTermExpense,
itemStyle: {
color: '#f5b000'
}
}
]
}
medium_term_chart.setOption(this.chartMediumOption)
const long_term_chart = echarts.init(document.getElementById('long_term_chart'), 'dark')
this.chartLongOption = {
tooltip: {
trigger: 'axis'
},
title: {
left: 'center',
text: ''
},
backgroundColor: 'transparent',
xAxis: {
type: 'time',
boundaryGap: false
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%']
},
dataZoom: [
{
type: 'inside',
start: 46,
end: 54
},
{
type: 'inside',
start: 46,
end: 54
}
],
series: [
{
name: '当前费用(元)',
type: 'line',
smooth: true,
symbol: 'none',
data: this.recentExpense,
itemStyle: {
color: '#6495ED'
}
}, {
name: '长期套餐费用(元)',
type: 'line',
smooth: true,
symbol: 'none',
data: this.longTermExpense,
itemStyle: {
color: '#f5b000'
}
}
]
}
long_term_chart.setOption(this.chartLongOption)
})
},
openDetailDialog(termType) {
this.chartDialogVisible = true
this.$nextTick(() => {
const dialogChart = echarts.init(document.getElementById('chartInDialog'), 'dark')
let chartOption
if (termType === `shortTerm`) {
chartOption = this.chartShortOption
this.expenseInDialog = this.expenseLists.shortTermExpenseDetail
} else if (termType === `mediumTerm`) {
chartOption = this.chartMediumOption
this.expenseInDialog = this.expenseLists.mediumTermExpenseDetail
} else if (termType === `longTerm`) {
chartOption = this.chartLongOption
this.expenseInDialog = this.expenseLists.longTermExpenseDetail
}
dialogChart.setOption(chartOption)
})
},
async chooseSet(termType) {
await testApi.chooseSet({ termType: termType }).then((res) => {
this.getUsageHostInfo()
this.upDateResults()
}).catch(() => {
this.getUsageHostInfo()
this.upDateResults()
const tempData = this.usageDataList
this.usageDataList = this.usageDataList1
this.usageDataList1 = tempData
})
},
showCpuDetail(item) {
for (let i = 0; i < this.usageDataList.length; i++) {
if (this.usageDataList[i].id === item.id) {
this.usageDataList[i].showAll = false
this.usageDataList[i].showCpuDetail = true
this.usageDataList[i].showBandWidthDetail = false
this.usageDataList[i].showDiskDetail = false
this.usageDataList[i].showMemoryDetail = false
}
}
},
showBandWidthDetail(item) {
for (let i = 0; i < this.usageDataList.length; i++) {
if (this.usageDataList[i].id === item.id) {
this.usageDataList[i].showAll = false
this.usageDataList[i].showCpuDetail = false
this.usageDataList[i].showBandWidthDetail = true
this.usageDataList[i].showDiskDetail = false
this.usageDataList[i].showMemoryDetail = false
}
}
},
showDiskDetail(item) {
for (let i = 0; i < this.usageDataList.length; i++) {
if (this.usageDataList[i].id === item.id) {
this.usageDataList[i].showAll = false
this.usageDataList[i].showCpuDetail = false
this.usageDataList[i].showBandWidthDetail = false
this.usageDataList[i].showDiskDetail = true
this.usageDataList[i].showMemoryDetail = false
}
}
},
showMemoryDetail(item) {
for (let i = 0; i < this.usageDataList.length; i++) {
if (this.usageDataList[i].id === item.id) {
this.usageDataList[i].showAll = false
this.usageDataList[i].showCpuDetail = false
this.usageDataList[i].showBandWidthDetail = false
this.usageDataList[i].showDiskDetail = false
this.usageDataList[i].showMemoryDetail = true
}
}
},
quitDetail(item) {
for (let i = 0; i < this.usageDataList.length; i++) {
if (this.usageDataList[i].id === item.id) {
this.usageDataList[i].showAll = true
this.usageDataList[i].showCpuDetail = false
this.usageDataList[i].showBandWidthDetail = false
this.usageDataList[i].showDiskDetail = false
this.usageDataList[i].showMemoryDetail = false
}
}
},
fullScreen() {
const element = document.getElementById('entirety')
if (element.requestFullscreen) {
element.requestFullscreen()
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen()
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen()
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen()
}
}
}
}

19
subject4-1-1-bc/pom.xml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>joint-cloud</artifactId>
<groupId>com.joint.cloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>subject4-1-1-bc</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>joint-cloud</artifactId>
<groupId>com.joint.cloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>subject4-1-1-helloworld</artifactId>
<name>subject4-1-1-helloworld</name>
<version>1.0.1</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.joint.cloud</groupId>
<artifactId>joint-cloud-common</artifactId>
<version>${joint.cloud.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,17 @@
package com.joint.cloud.subject4_1_1.helloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = {"com.joint.cloud.*"})
@SpringBootApplication
@EnableDiscoveryClient
public class HelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}
}

View File

@ -0,0 +1,34 @@
package com.joint.cloud.subject4_1_1.helloworld.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
public static final String SWAGGER_TITLE = "云际项目API";
public static final String SWAGGER_DESC = "云际项目";
@Bean
public Docket documentation() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(metadata())
.select()
.apis(RequestHandlerSelectors.basePackage("com.joint.cloud.subject4_1_1.helloworld.controller"))
.build();
}
private ApiInfo metadata() {
return new ApiInfoBuilder().title(SWAGGER_TITLE)
.description(SWAGGER_DESC)
.version("1.0").build();
}
}

View File

@ -0,0 +1,6 @@
package com.joint.cloud.subject4_1_1.helloworld.constants;
public class ApiConstant {
public static final String VERSION = "/v1";
}

View File

@ -0,0 +1,56 @@
package com.joint.cloud.subject4_1_1.helloworld.controller;
import com.joint.cloud.common.constants.ResponseCode;
import com.joint.cloud.common.exception.BusinessException;
import com.joint.cloud.common.response.BaseResponse;
import com.joint.cloud.subject4_1_1.helloworld.constants.ApiConstant;
import com.joint.cloud.subject4_1_1.helloworld.controller.request.DemoParam;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(ApiConstant.VERSION + "/demo")
@Slf4j
@Api(tags = {"示例"})
@BaseResponse
public class DemoController {
@ApiOperation("URL入参示例")
@GetMapping("/param/1/{id}")
@ResponseBody
public Long paramTest1(@ApiParam("测试入参id") @PathVariable("id") Long id) {
log.info("接到入参: {}", id);
log.warn("接到入参: {}", id);
log.debug("接到入参: {}", id);
log.error("接到入参: {}", id);
return id;
}
@ApiOperation("param入参示例")
@GetMapping("/param/2")
public Object paramTest2(@ApiParam("测试入参key") @RequestParam("key") Long key) {
return key;
}
@ApiOperation("body入参示例")
@PostMapping("/param/3")
public DemoParam paramTest3(@Validated @ApiParam("测试入参demoParam") @RequestBody DemoParam demoParam) {
return demoParam;
}
@ApiOperation("统一返回、统一异常示例")
@GetMapping("/{userId}")
public Object getUserById(@PathVariable Long userId) {
if (userId.equals(0L)) {
throw new BusinessException(ResponseCode.BAD_REQUEST, "提示信息");
} else if (userId.equals(1L)) {
int i = 1 / 0;
}
return userId;
}
}

View File

@ -0,0 +1,16 @@
package com.joint.cloud.subject4_1_1.helloworld.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
public class HealthController {
@GetMapping("/health")
public String health() {
return "I'm health now " + (new Date()).toString();
}
}

View File

@ -0,0 +1,20 @@
package com.joint.cloud.subject4_1_1.helloworld.controller.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
@Data
@ApiModel("测试DEMO入参")
public class DemoParam {
@ApiModelProperty(value = "主键", required = true)
private Long id;
@ApiModelProperty("名称")
@NotEmpty(message = "名称不能为空")
private String name;
}

View File

@ -0,0 +1,4 @@
spring:
cloud:
consul:
host: ${CONSUL_ADDR:10.4.79.107}

View File

@ -0,0 +1,19 @@
server:
port: 40101
spring:
application:
name: subject4-1-1-helloworld
profiles:
active: dev
cloud:
consul:
port: 8500
discovery:
service-name: ${spring.application.name}
instance-id: ${spring.application.name}:${spring.cloud.consul.discovery.ip-address}:${server.port}
ip-address: ${REGISTRY_ADDR:${spring.cloud.client.ip-address}}
prefer-ip-address: true
health-check-path: /health
health-check-interval: 10s
health-check-critical-timeout: 30s
host: 10.4.79.107

View File

Some files were not shown because too many files have changed in this diff Show More