commit
9643742e91
|
@ -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/
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());//返回的是经过加强后的代理类的对象
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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}
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.joint.cloud.common.constants;
|
||||
|
||||
public enum NotificationType {
|
||||
/**
|
||||
* 事件
|
||||
*/
|
||||
EVENT,
|
||||
/**
|
||||
* 问题
|
||||
*/
|
||||
PROBLEM,
|
||||
/**
|
||||
* 变更
|
||||
*/
|
||||
CHANGE,
|
||||
/**
|
||||
* 请求
|
||||
*/
|
||||
REQUEST,
|
||||
/**
|
||||
* 被动运维
|
||||
*/
|
||||
PASV,
|
||||
/**
|
||||
* 主动运维
|
||||
*/
|
||||
ACTIVE,
|
||||
QUESTION,
|
||||
/**
|
||||
* 中山档案馆-被动
|
||||
*/
|
||||
ZSPASSTIVE,
|
||||
ZSACTIVE
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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/";
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 + "'不能为空";
|
||||
}
|
||||
}
|
|
@ -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() + ")已存在!";
|
||||
}
|
||||
}
|
|
@ -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() + ")不存在!";
|
||||
}
|
||||
}
|
|
@ -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 "未知系统异常,请联系管理员";
|
||||
}
|
||||
}
|
|
@ -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(){
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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的crtUser、crtHost、crtTime、updUser、updHost、updTime附上相关值
|
||||
*
|
||||
* @param entity 实体bean
|
||||
* @author 王浩彬
|
||||
*/
|
||||
public static <T> void setCreateAndUpdateInfo(T entity) {
|
||||
try {
|
||||
setCreateInfo(entity);
|
||||
setUpdatedInfo(entity);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速将bean的crtUser、crtHost、crtTime附上相关值
|
||||
*
|
||||
* @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的updUser、updHost、updTime附上相关值
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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-z,A-Z,0-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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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());//返回的是经过加强后的代理类的对象
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
spring:
|
||||
cloud:
|
||||
consul:
|
||||
host: ${CONSUL_ADDR:10.4.79.107}
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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/**
|
|
@ -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/**
|
|
@ -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/**
|
|
@ -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
|
|
@ -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}}
|
|
@ -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>
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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>
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.joint.cloud.subject4_1_1.helloworld.constants;
|
||||
|
||||
public class ApiConstant {
|
||||
|
||||
public static final String VERSION = "/v1";
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
spring:
|
||||
cloud:
|
||||
consul:
|
||||
host: ${CONSUL_ADDR:10.4.79.107}
|
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue