Commit 0f777461 by yw

项目初始化

parent 0723460c
<?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>datax-cloud</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-auth</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-core</artifactId>
<version>${app.version}</version>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-mybatis</artifactId>
<version>${app.version}</version>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-security</artifactId>
<version>${app.version}</version>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-redis</artifactId>
<version>${app.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.datax.auth;
import cn.datax.common.mybatis.annotation.EnableDataMybatis;
import cn.datax.common.redis.annotation.EnableDataRedis;
import cn.datax.common.security.annotation.EnableDataAuthExceptionHandler;
import cn.datax.common.security.annotation.EnableDataServerProtect;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableDataAuthExceptionHandler
@EnableDataServerProtect
@EnableDataMybatis
@EnableDataRedis
@EnableFeignClients
@SpringBootApplication
//@SpringBootApplication(scanBasePackages = {"cn.datax"})
//@EnableFeignClients(basePackages = {"cn.datax"})
public class DataAuthApplication {
public static void main(String[] args) {
SpringApplication.run(DataAuthApplication.class, args);
}
}
package cn.datax.auth.config;
import cn.datax.auth.service.DataUserDetailService;
import cn.datax.auth.translator.DataWebResponseExceptionTranslator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
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.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataUserDetailService userDetailService;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Autowired
private DataWebResponseExceptionTranslator exceptionTranslator;
/**
* 配置客户端详情服务
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).clients(clientDetails());
}
/**
* 用来配置令牌端点(Token Endpoint)的安全约束.
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").allowFormAuthenticationForClients();
}
/**
* 用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.userDetailsService(userDetailService)
.authenticationManager(authenticationManager)
.exceptionTranslator(exceptionTranslator);
}
@Bean
public ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}
@Bean
public TokenStore tokenStore(){
return new RedisTokenStore(redisConnectionFactory);
}
@Bean
@Primary
public DefaultTokenServices defaultTokenServices(){
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetails());
tokenServices.setTokenEnhancer(tokenEnhancer());
// token有效期自定义设置,默认12小时
tokenServices.setAccessTokenValiditySeconds(60 * 60 * 24 * 1);
// refresh_token默认30天
tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);
return tokenServices;
}
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
final Map<String, Object> additionalInfo = new HashMap<>();
// Object principal = authentication.getUserAuthentication().getPrincipal();
// if (principal instanceof DataUserDetail) {
// DataUserDetail user = (DataUserDetail) principal;
// additionalInfo.put("user", user);
// }
additionalInfo.put("license", "datax");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
};
}
}
package cn.datax.auth.config;
import cn.datax.common.security.handler.DataAccessDeniedHandler;
import cn.datax.common.security.handler.DataAuthExceptionEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* 资源服务配置<br>
*
* 注解@EnableResourceServer帮我们加入了org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter<br>
* 该filter帮我们从request里解析出access_token<br>
* 并通过org.springframework.security.oauth2.provider.token.DefaultTokenServices根据access_token和认证服务器配置里的TokenStore从redis或者jwt里解析出用户
*
* 注意认证中心的@EnableResourceServer和别的微服务里的@EnableResourceServer有些不同<br>
* 别的微服务是通过org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices来获取用户的
*/
@Configuration
@EnableResourceServer
public class DataResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private DataAccessDeniedHandler accessDeniedHandler;
@Autowired
private DataAuthExceptionEntryPoint exceptionEntryPoint;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().permitAll()
.and().httpBasic();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.authenticationEntryPoint(exceptionEntryPoint)
.accessDeniedHandler(accessDeniedHandler);
}
}
package cn.datax.auth.config;
import cn.datax.auth.service.DataUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class DataWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private DataUserDetailService userDetailService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/actuator/**",
"/v2/api-docs/**",
"/swagger-ui.html",
"/swagger-resources/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder);
}
/**
* 不定义没有password grant_type,密码模式需要AuthenticationManager支持
*
* @return
* @throws Exception
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
package cn.datax.auth.config;
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.DefaultAuthenticationKeyGenerator;
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 java.util.*;
public class RedisTokenStore 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 DefaultAuthenticationKeyGenerator();
private RedisTokenStoreSerializationStrategy serializationStrategy = new JdkSerializationStrategy();
private String prefix = "";
public RedisTokenStore(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);
}
}
package cn.datax.auth.service;
import cn.hutool.core.util.StrUtil;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;
@Service
public class DataUserDetailService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//远程获取用户
if (!StrUtil.equals("admin", s)) {
throw new UsernameNotFoundException(s);
}
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
// 可用性 :true:可用 false:不可用
boolean enabled = true;
// 过期性 :true:没过期 false:过期
boolean accountNonExpired = true;
// 有效性 :true:凭证有效 false:凭证无效
boolean credentialsNonExpired = true;
// 锁定性 :true:未锁定 false:已锁定
boolean accountNonLocked = true;
// for (Role role : member.getRoles()) {
// //角色必须是ROLE_开头,可以在数据库中设置
// GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleName());
// grantedAuthorities.add(grantedAuthority);
// //获取权限
// for (Permission permission : role.getPermissions()) {
// GrantedAuthority authority = new SimpleGrantedAuthority(permission.getUri());
// grantedAuthorities.add(authority);
// }
// }
// userRoleDao.selectAll(new UserRole().setUsername(username))
// .stream()
// .map(userRole -> new SimpleGrantedAuthority(userRole.getRole()))
// .collect(Collectors.toList());
String encode = new BCryptPasswordEncoder().encode("123456");
//123456 "$2a$10$3rV8TA7XlfVkZrP0kA0t7OqKoQa93Mw/VZii6nP62pqiD.AjKSUja"
User user = new User("admin", encode,
enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorities);
// new DataUserDetail(null, grantedAuthorities);
return user;
}
}
package cn.datax.auth.translator;
import cn.datax.common.core.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class DataWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
@Override
public ResponseEntity translate(Exception e) {
ResponseEntity.BodyBuilder status = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
String message = "认证失败";
log.error(message, e);
if (e instanceof UnsupportedGrantTypeException) {
message = "不支持该认证类型";
return status.body(R.error(message));
}
if (e instanceof InvalidGrantException) {
if (StringUtils.containsIgnoreCase(e.getMessage(), "Invalid refresh token")) {
message = "refresh token无效";
return status.body(R.error(message));
}
if (StringUtils.containsIgnoreCase(e.getMessage(), "locked")) {
message = "用户已被锁定,请联系管理员";
return status.body(R.error(message));
}
message = "用户名或密码错误";
return status.body(R.error(message));
}
return status.body(R.error(message));
}
}
server:
port: 8613
spring:
application:
name: datax-auth
profiles:
active: dev
cloud:
config:
fail-fast: true
# uri: http://localhost:8611
name: ${spring.application.name}
profile: ${spring.profiles.active}
discovery:
enabled: true
service-id: datax-config
# 注册中心配置
eureka:
instance:
lease-renewal-interval-in-seconds: 20
client:
register-with-eureka: true
fetch-registry: true
instance-info-replication-interval-seconds: 30
registry-fetch-interval-seconds: 3
service-url:
defaultZone: http://localhost:8610/eureka
\ No newline at end of file
<?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>datax-common</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-common-core</artifactId>
<dependencies>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
<!--io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<!--文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons.beanutils.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--jackson模块-->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.datax.common.base;
public abstract class BaseController {
}
package cn.datax.common.base;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface BaseDao<T> extends BaseMapper<T> {
}
package cn.datax.common.base;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 创建人
*/
@TableField(value = "create_by", fill = FieldFill.INSERT)
private String createBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/**
* 更新人
*/
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/**
* 状态(0不启用,1启用)
*/
@TableField(value = "status", fill = FieldFill.INSERT)
private Integer status;
/**
* 逻辑删除(1正常,0已删除)
*/
@TableLogic
@TableField(value = "deleted", fill = FieldFill.INSERT)
@JsonIgnore
private Integer deleted;
}
package cn.datax.common.base;
import com.baomidou.mybatisplus.extension.service.IService;
public interface BaseService<T> extends IService<T> {
}
package cn.datax.common.base;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
public abstract class BaseServiceImpl<M extends BaseDao<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {
}
package cn.datax.common.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.TimeZone;
@Configuration
public class JacksonConfig {
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder){
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
ObjectMapper objectMapper = builder.createXmlMapper(false)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.timeZone(TimeZone.getTimeZone("Asia/Shanghai"))
.build();
objectMapper
.setLocale(Locale.CHINA)
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
// 忽略未知字段
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// 该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常。JSON标准说明书要求所有控制符必须使用引号,因此这是一个非标准的特性
.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true)
// 忽略不能转移的字符
.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true)
// 单引号处理
.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)
// 日期格式
.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 反序列化时,属性不存在的兼容处理
objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(Long.TYPE, ToStringSerializer.instance)
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(BigDecimal.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule());
return objectMapper;
}
}
package cn.datax.common.core;
public class DataConstant {
/**
* Gateway请求头TOKEN名称(不要有空格)
*/
public static final String GATEWAY_TOKEN_HEADER = "GatewayToken";
/**
* Gateway请求头TOKEN值
*/
public static final String GATEWAY_TOKEN_VALUE = "datax:gateway:123456";
/**
* OAUTH2 令牌类型
*/
public static final String OAUTH2_TOKEN_TYPE = "bearer ";
}
package cn.datax.common.core;
import lombok.Getter;
import java.io.Serializable;
@Getter
public class R implements Serializable {
private static final long serialVersionUID = 1L;
private boolean success;
private int code;
private String msg;
private Object data;
private long timestamp;
private R() {}
public static R error() {
return error(null);
}
public static R error(String message) {
return error(null, message);
}
public static R error(Integer code, String message) {
if(code == null) {
code = 500;
}
if(message == null) {
message = "服务器内部错误";
}
return build(code, false, message);
}
public static R ok() {
return ok(null);
}
public static R ok(String message) {
return ok(null, message);
}
public static R ok(Integer code, String message) {
if(code == null) {
code = 200;
}
if(message == null) {
message = "操作成功";
}
return build(code, true, message);
}
public static R build(int code, boolean success, String message) {
return new R()
.setCode(code)
.setSuccess(success)
.setMessage(message)
.setTimestamp(System.currentTimeMillis());
}
public R setCode(int code) {
this.code = code;
return this;
}
public R setSuccess(boolean success) {
this.success = success;
return this;
}
public R setMessage(String msg) {
this.msg = msg;
return this;
}
public R setData(Object data) {
this.data = data;
return this;
}
public R setTimestamp(long timestamp) {
this.timestamp = timestamp;
return this;
}
}
package cn.datax.common.exception;
public class DataException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DataException() {
super();
}
public DataException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public DataException(String message, Throwable cause) {
super(message, cause);
}
public DataException(String message) {
super(message);
}
public DataException(Throwable cause) {
super(cause);
}
}
package cn.datax.common.exception;
import cn.datax.common.core.R;
import cn.datax.common.utils.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理自定义异常
*/
@ExceptionHandler(DataException.class)
public R handleWithException(DataException e) {
log.error("自定义异常信息 ex={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(e.getMessage());
}
/**
* 请求的 JSON 参数在请求体内的参数校验
*/
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
String message = StringUtils.collectionToCommaDelimitedString(
e.getBindingResult().getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.toList()));
log.error("参数校验异常信息 ex={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(message);
}
/**
* 请求的 URL 参数检验
*/
@ExceptionHandler(ConstraintViolationException.class)
public R handleConstraintViolationException(ConstraintViolationException e) {
String message = StringUtils.collectionToCommaDelimitedString(
e.getConstraintViolations()
.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toList()));
log.error("参数校验异常信息 ex={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(message);
}
@ExceptionHandler(Exception.class)
public R handleException(Exception e) {
log.error("全局异常信息 ex={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(e.getMessage());
}
}
\ No newline at end of file
package cn.datax.common.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* 获取 HttpServletRequest
*
*/
public class RequestHolder {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
}
package cn.datax.common.utils;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ResponseUtil {
/**
* 设置响应
*
* @param response HttpServletResponse
* @param contentType content-type
* @param status http状态码
* @param value 响应内容
* @throws IOException IOException
*/
public static void makeResponse(HttpServletResponse response, String contentType,
int status, Object value) throws IOException {
response.setContentType(contentType);
response.setStatus(status);
response.getOutputStream().write(JSONObject.toJSONString(value).getBytes());
}
}
package cn.datax.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
if (logger.isDebugEnabled()) {
logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() throws Exception {
SpringContextHolder.clearHolder();
}
}
package cn.datax.common.utils;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 异常工具
*/
public class ThrowableUtil {
/**
* 获取堆栈信息
* @param throwable
* @return
*/
public static String getStackTrace(Throwable throwable){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
throwable.printStackTrace(pw);
return sw.toString();
} finally {
pw.close();
}
}
}
package cn.datax.common.validate;
public interface ValidateGroupForSave {
}
package cn.datax.common.validate;
public interface ValidateGroupForUpdate {
}
<?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>datax-common</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-common-mybatis</artifactId>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic-datasource.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.datax.common.mybatis.annotation;
import cn.datax.common.mybatis.config.AutoConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({AutoConfiguration.class})
public @interface EnableDataMybatis {
}
package cn.datax.common.mybatis.config;
import org.springframework.context.annotation.ComponentScan;
/**
* 扫描注入bean
* @author yuwei
* @since 2019/10/25
*/
@ComponentScan({"cn.datax.common.mybatis"})
public class AutoConfiguration {
}
package cn.datax.common.mybatis.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@MapperScan("cn.datax.service.**.mapper")
@EnableTransactionManagement
@Import({DataMetaObjectHandler.class})
public class DataBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
package cn.datax.common.mybatis.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import java.time.LocalDateTime;
public class DataMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject);
this.setInsertFieldValByName("updateTime", LocalDateTime.now(), metaObject);
this.setInsertFieldValByName("status", 1, metaObject);
this.setInsertFieldValByName("deleted", 1, metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
}
<?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>datax-common</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-common-redis</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.datax.common.redis.annotation;
import cn.datax.common.redis.config.AutoConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({AutoConfiguration.class})
public @interface EnableDataRedis {
}
package cn.datax.common.redis.config;
import org.springframework.context.annotation.ComponentScan;
/**
* 扫描注入bean
* @author yuwei
* @since 2019/10/25
*/
@ComponentScan({"cn.datax.common.redis"})
public class AutoConfiguration {
}
package cn.datax.common.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 在没有指定缓存Key的情况下,key生成策略
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append("#"+method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
@Bean
public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
//spring cache注解序列化配置
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
//key序列化方式
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getKeySerializer()))
//value序列化方式
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()))
//不缓存null值
.disableCachingNullValues()
//默认缓存过期时间
.entryTtl(Duration.ofSeconds(60));
//设置一个初始化的缓存名称set集合
Set<String> cacheNames = new HashSet<>();
// cacheNames.add("user");
//对每个缓存名称应用不同的配置,自定义过期时间
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
// configMap.put("user", redisCacheConfiguration.entryTtl(Duration.ofMinutes(30)));
RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisTemplate.getConnectionFactory())
.cacheDefaults(redisCacheConfiguration)
.transactionAware()
//注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
.initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap)
.build();
return redisCacheManager;
}
/**
* 实例化 RedisTemplate 对象
*
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
\ No newline at end of file
<?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>datax-common</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-common-security</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<!--feign 依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-core</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.datax.common.security.annotation;
import cn.datax.common.security.config.DataAuthExceptionConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({DataAuthExceptionConfiguration.class})
public @interface EnableDataAuthExceptionHandler {
}
package cn.datax.common.security.annotation;
import cn.datax.common.security.config.DataOAuth2FeignConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({DataOAuth2FeignConfiguration.class})
public @interface EnableDataOauth2FeignClient {
}
package cn.datax.common.security.annotation;
import cn.datax.common.security.config.DataSecurityApplicationSelector;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({DataSecurityApplicationSelector.class})
public @interface EnableDataSecurityApplication {
}
package cn.datax.common.security.annotation;
import cn.datax.common.security.config.DataServerProtectConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({DataServerProtectConfiguration.class})
public @interface EnableDataServerProtect {
}
package cn.datax.common.security.config;
import cn.datax.common.security.handler.DataAccessDeniedHandler;
import cn.datax.common.security.handler.DataAuthExceptionEntryPoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
/**
* 异常翻译配置
*
* @author yuwei
*/
@ComponentScan({"cn.datax.common.security.handler"})
public class DataAuthExceptionConfiguration {
@Bean
@ConditionalOnMissingBean(name = "accessDeniedHandler")
public DataAccessDeniedHandler accessDeniedHandler() {
return new DataAccessDeniedHandler();
}
@Bean
@ConditionalOnMissingBean(name = "authenticationEntryPoint")
public DataAuthExceptionEntryPoint authenticationEntryPoint() {
return new DataAuthExceptionEntryPoint();
}
}
package cn.datax.common.security.config;
import cn.datax.common.security.feign.DataFeignRequestInterceptor;
import cn.datax.common.security.handler.DataAccessDeniedHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
/**
* OAuth2 Feign配置
*
* @author yuwei
*/
@ComponentScan({"cn.datax.common.security.feign"})
public class DataOAuth2FeignConfiguration {
@Bean
public DataFeignRequestInterceptor dataFeignRequestInterceptor() {
return new DataFeignRequestInterceptor();
}
}
package cn.datax.common.security.config;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class DataSecurityApplicationSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{
DataAuthExceptionConfiguration.class.getName(),
DataOAuth2FeignConfiguration.class.getName(),
DataServerProtectConfiguration.class.getName()
};
}
}
package cn.datax.common.security.config;
import cn.datax.common.security.interceptor.DataServerProtectInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 微服务防护配置
*
* @author yuwei
*/
@Slf4j
public class DataServerProtectConfiguration implements WebMvcConfigurer {
@Bean
@ConditionalOnMissingBean(value = PasswordEncoder.class)
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public HandlerInterceptor dataServerProtectInterceptor() {
log.debug("开启dataServerProtectInterceptor解析");
return new DataServerProtectInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(dataServerProtectInterceptor());
}
}
package cn.datax.common.security.feign;
import cn.datax.common.core.DataConstant;
import com.google.common.net.HttpHeaders;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.util.Base64Utils;
public class DataFeignRequestInterceptor {
@Bean
public RequestInterceptor oauth2FeignRequestInterceptor() {
return requestTemplate -> {
// 请求头中添加 Gateway Token
String zuulToken = new String(Base64Utils.encode(DataConstant.GATEWAY_TOKEN_VALUE.getBytes()));
requestTemplate.header(DataConstant.GATEWAY_TOKEN_HEADER, zuulToken);
// 请求头中添加原请求头中的 Token
Object details = SecurityContextHolder.getContext().getAuthentication().getDetails();
if (details instanceof OAuth2AuthenticationDetails) {
String authorizationToken = ((OAuth2AuthenticationDetails) details).getTokenValue();
requestTemplate.header(HttpHeaders.AUTHORIZATION, DataConstant.OAUTH2_TOKEN_TYPE + authorizationToken);
}
};
}
}
package cn.datax.common.security.feign;
import feign.Feign;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient.Builder()
// 连接超时
.connectTimeout(60, TimeUnit.SECONDS)
// 读超时
.readTimeout(60, TimeUnit.SECONDS)
// 写超时
.writeTimeout(60, TimeUnit.SECONDS)
// 是否自动重连
.retryOnConnectionFailure(true)
.connectionPool(new ConnectionPool())
.build();
}
}
package cn.datax.common.security.feign;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
package cn.datax.common.security.handler;
import cn.datax.common.core.R;
import cn.datax.common.utils.ResponseUtil;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DataAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
ResponseUtil.makeResponse(
response, MediaType.APPLICATION_JSON_UTF8_VALUE,
HttpServletResponse.SC_FORBIDDEN, R.error("没有权限访问该资源"));
}
}
package cn.datax.common.security.handler;
import cn.datax.common.core.R;
import cn.datax.common.utils.ResponseUtil;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DataAuthExceptionEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
ResponseUtil.makeResponse(
response, MediaType.APPLICATION_JSON_UTF8_VALUE,
HttpServletResponse.SC_UNAUTHORIZED, R.error("token无效"));
}
}
package cn.datax.common.security.interceptor;
import cn.datax.common.core.DataConstant;
import cn.datax.common.core.R;
import cn.datax.common.utils.ResponseUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.http.MediaType;
import org.springframework.util.Base64Utils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DataServerProtectInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
// 从请求头中获取 Zuul Token
String token = request.getHeader(DataConstant.GATEWAY_TOKEN_HEADER);
String zuulToken = new String(Base64Utils.encode(DataConstant.GATEWAY_TOKEN_VALUE.getBytes()));
// 校验 Zuul Token的正确性
if (StrUtil.equals(zuulToken, token)) {
return true;
} else {
ResponseUtil.makeResponse(
response, MediaType.APPLICATION_JSON_UTF8_VALUE,
HttpServletResponse.SC_FORBIDDEN, R.error("请通过网关获取资源"));
return false;
}
}
}
<?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>datax-cloud</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-common</artifactId>
<modules>
<module>datax-common-redis</module>
<module>datax-common-core</module>
<module>datax-common-mybatis</module>
<module>datax-common-security</module>
</modules>
</project>
\ No newline at end of file
<?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>datax-cloud</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-config</artifactId>
<description>Datax-Config微服务配置中心</description>
<dependencies>
<!--配置中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--web 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.datax.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;
@EnableDiscoveryClient
@EnableConfigServer
@SpringBootApplication
public class DataxConfigApplication {
public static void main(String[] args) {
SpringApplication.run(DataxConfigApplication.class, args);
}
}
server:
port: 8611
spring:
application:
name: datax-config
profiles:
active: native
# 配置中心
cloud:
config:
server:
native:
search-locations: classpath:/config/
# 注册中心配置
eureka:
instance:
lease-renewal-interval-in-seconds: 20
client:
register-with-eureka: true
fetch-registry: true
instance-info-replication-interval-seconds: 30
registry-fetch-interval-seconds: 3
service-url:
defaultZone: http://localhost:8610/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: '*'
logging:
level:
com.data.cloud: info
\ No newline at end of file
# Spring 相关
spring:
mvc:
throw-exception-if-no-handler-found: true
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
# zipkin
# zipkin:
# enabled: true
# base-url: http://localhost:9411/
# sleuth:
# web:
# client:
# enabled: true
# sampler:
# # 默认的采样比率为0.1,不能看到所有请求数据
# # 更改采样比率为1,就能看到所有的请求数据了,但是这样会增加接口调用延迟
# probability: 0.5
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: '*'
# feign 配置
feign:
hystrix:
enabled: true
okhttp:
enabled: true
httpclient:
enabled: false
client:
config:
default:
connectTimeout: 10000
readTimeout: 10000
compression:
request:
enabled: true
response:
enabled: true
# hystrix 配置
hystrix:
command:
default:
execution:
isolation:
strategy: SEMAPHORE
thread:
timeoutInMilliseconds: 60000
shareSecurityContext: true
#请求处理的超时时间
ribbon:
ReadTimeout: 10000
ConnectTimeout: 10000
\ No newline at end of file
# 数据源配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/data_cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 1234@abcd
type: com.zaxxer.hikari.HikariDataSource
hikari:
auto-commit: false
connection-timeout: 30000
idle-timeout: 25000
login-timeout: 5
max-lifetime: 30000
read-only: false
validation-timeout: 3000
maximum-pool-size: 15
minimum-idle: 5
pool-name: ExpendHikariCP
connection-test-query: SELECT 1 FROM DUAL
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
#data:
# file-server:
# type: fastdfs
# fdfs:
# web-url: ${data.fdfs.web-url}
#oss配置
#oss:
# access-key: tpi8mObnfzZi4ggBX8Bw7zydjoTQ0WeML3RkPKsX
# accessKeySecret: HZBXmSyUTy-haYp0KbBTtsil-GoKjVS2kDKT8Yow
# endpoint: http://pkqtmn0p1.bkt.clouddn.com
# bucketName: public-oss
# domain:
#fastDFS配置
#fdfs:
# soTimeout: 1500
# connectTimeout: 600
# trackerList: ${data.fdfs.trackerList}
mybatis-plus:
mapper-locations: classpath*:mapper/*Mapper.xml
type-aliases-package: cn.data.cloud.service.file.api.entity
global-config:
db-config:
id-type: ID_WORKER_STR
logic-delete-value: -1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)
banner: false
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
# 数据源配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/data_cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 1234@abcd
type: com.zaxxer.hikari.HikariDataSource
hikari:
auto-commit: false
connection-timeout: 30000
idle-timeout: 25000
login-timeout: 5
max-lifetime: 30000
read-only: false
validation-timeout: 3000
maximum-pool-size: 15
minimum-idle: 5
pool-name: ExpendHikariCP
connection-test-query: SELECT 1 FROM DUAL
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
\ No newline at end of file
# 数据源配置
spring:
redis:
database: 1
host: x.x.x.x
port: 6379
password: # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
lettuce:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://x.x.x.x:3306/data_cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: x.x.x.x
password: x.x.x.x
type: com.zaxxer.hikari.HikariDataSource
hikari:
auto-commit: false
connection-timeout: 30000
idle-timeout: 25000
login-timeout: 5
max-lifetime: 30000
read-only: false
validation-timeout: 3000
maximum-pool-size: 15
minimum-idle: 5
pool-name: ExpendHikariCP
connection-test-query: SELECT 1 FROM DUAL
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
mybatis-plus:
mapper-locations: classpath*:mapper/*Mapper.xml
type-aliases-package: cn.data.cloud.service.system.api.entity
global-config:
db-config:
id-type: ID_WORKER_STR
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
banner: false
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
# 数据源配置
spring:
redis:
database: 1
host: 127.0.0.1
port: 6379
password: # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
lettuce:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/data_cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 1234@abcd
type: com.zaxxer.hikari.HikariDataSource
hikari:
auto-commit: false
connection-timeout: 30000
idle-timeout: 25000
login-timeout: 5
max-lifetime: 30000
read-only: false
validation-timeout: 3000
maximum-pool-size: 15
minimum-idle: 5
pool-name: ExpendHikariCP
connection-test-query: SELECT 1 FROM DUAL
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
tio:
websocket:
server:
# websocket port default 9876
port: 9876
# 心跳时间
heartbeat-timeout: 60000
use-scanner: false
# 集群配置 默认关闭
cluster:
enabled: false
# 集群是通过redis的Pub/Sub实现,所以需要配置Redis
redis:
config-path:
ip: 127.0.0.1
port: 6379
all: true
group: true
ip: true
user: true
# SSL配置
ssl:
enabled: false
key-store: test
password: test
trust-store: test
#security:
# oauth2:
# client:
# access-token-uri: http://localhost:8612/auth/oauth/token
# user-authorization-uri: http://localhost:8612/auth/oauth/authorize
# client-id: cloudx
# client-secret: 123456
# scope: server
# # 默认放行url,如果子模块重写这里的配置就会被覆盖
# ignore-urls:
# - /actuator/**
# - /v2/api-docs/**
# - /swagger-resources/**
# - /swagger-ui.html
# - /webjars/**
\ No newline at end of file
# 数据源配置
spring:
redis:
database: 1
host: 127.0.0.1
port: 6379
password: # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
lettuce:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
datasource:
dynamic:
type: com.zaxxer.hikari.HikariDataSource
hikari:
auto-commit: false
connection-timeout: 30000
idle-timeout: 25000
login-timeout: 5
max-lifetime: 30000
read-only: false
validation-timeout: 3000
maximum-pool-size: 15
minimum-idle: 5
pool-name: DataxHikariCP
connection-test-query: SELECT 1 FROM DUAL
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
primary: mysql
datasource:
mysql:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/data_cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 1234@abcd
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
allowCredentials: true
discovery:
locator:
lowerCaseServiceId: true
enabled: true
default-filters:
- StripPrefix=1
routes:
# 认证中心
- id: datax-auth
uri: lb://datax-auth
predicates:
- Path=/auth/**
filters:
- name: Hystrix
args:
name: authFallback
fallbackUri: forward:/fallback/data-auth
# 系统配置中心
- id: datax-service-system
uri: lb://datax-service-system
predicates:
- Path=/system/**
filters:
- name: Hystrix
args:
name: systemFallback
fallbackUri: forward:/fallback/data-service-system
# 邮件中心
- id: datax-service-mail
uri: lb://datax-service-mail
predicates:
- Path=/mail/**
filters:
- name: Hystrix
args:
name: mailFallback
fallbackUri: forward:/fallback/data-service-mail
# 即时通讯消息中心
- id: datax-websocket-server
uri: ws://localhost:9876
predicates:
- Path=/websocket/**
\ No newline at end of file
# 数据源配置
spring:
redis:
database: 1
host: 127.0.0.1
port: 6379
password: # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
lettuce:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
datasource:
dynamic:
type: com.zaxxer.hikari.HikariDataSource
hikari:
auto-commit: false
connection-timeout: 30000
idle-timeout: 25000
login-timeout: 5
max-lifetime: 30000
read-only: false
validation-timeout: 3000
maximum-pool-size: 15
minimum-idle: 5
pool-name: DataxHikariCP
connection-test-query: SELECT 1 FROM DUAL
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
primary: mysql
datasource:
mysql:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/data_cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 1234@abcd
mybatis-plus:
mapper-locations: classpath*:mapper/*Mapper.xml
type-aliases-package: cn.datax.system.api.entity
global-config:
db-config:
id-type: ID_WORKER_STR
logic-delete-value: 0 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)
banner: false
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# spring security 配置
security:
oauth2:
client:
access-token-uri: http://localhost:8612/auth/oauth/token
user-authorization-uri: http://localhost:8612/auth/oauth/authorize
client-id: datax
client-secret: 123456
scope: all
resource:
loadBalanced: true
token-info-uri: http://localhost:8612/auth/oauth/check_token
\ No newline at end of file
<?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>datax-cloud</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-eureka</artifactId>
<description>Datax-Cloud服务注册中心</description>
<dependencies>
<!--服务中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.datax.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class DataxEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(DataxEurekaApplication.class, args);
}
}
server:
port: 8610
spring:
application:
name: datax-eureka
eureka:
instance:
hostname: localhost
lease-renewal-interval-in-seconds: 20
lease-expiration-duration-in-seconds: 60
prefer-ip-address: true
client:
registerWithEureka: false
fetchRegistry: false
instance-info-replication-interval-seconds: 30
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>datax</contextName>
<property name="log.path" value="log/datax-eureka" />
<property name="log.maxHistory" value="15" />
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %thread %logger %msg%n"/>
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!--输出到文件-->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/error.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="debug">
<appender-ref ref="console" />
</root>
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>
\ No newline at end of file
<?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>datax-cloud</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-gateway</artifactId>
<dependencies>
<!--web 模块-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
<!--配置中心客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--gateway 网关依赖,内置webflux 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-core</artifactId>
<version>${app.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>cn.datax</groupId>-->
<!-- <artifactId>datax-common-security</artifactId>-->
<!-- <version>${app.version}</version>-->
<!-- </dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.datax.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class DataGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(DataGatewayApplication.class, args);
}
}
package cn.datax.gateway.config;
import cn.datax.gateway.handler.DataGatewayExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import java.util.Collections;
import java.util.List;
@Configuration
public class DataGatewayErrorConfigure {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public DataGatewayErrorConfigure(ServerProperties serverProperties,
ResourceProperties resourceProperties,
ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
DataGatewayExceptionHandler exceptionHandler = new DataGatewayExceptionHandler(
errorAttributes,
this.resourceProperties,
this.serverProperties.getError(),
this.applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
}
package cn.datax.gateway.controller;
import cn.datax.common.core.R;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
public class FallbackController {
@RequestMapping("fallback/{name}")
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Mono<R> systemFallback(@PathVariable String name) {
String response = String.format("访问%s超时或者服务不可用", name);
return Mono.just(R.error(response));
}
}
package cn.datax.gateway.filter;
import cn.datax.common.core.DataConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.time.LocalDateTime;
import java.util.LinkedHashSet;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.*;
@Slf4j
@Component
@Order(0)
public class DataGatewayRequestFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
printLog(exchange);
byte[] token = Base64Utils.encode((DataConstant.GATEWAY_TOKEN_VALUE).getBytes());
String headerValues = new String(token);
ServerHttpRequest build = request.mutate().header(DataConstant.GATEWAY_TOKEN_HEADER, headerValues).build();
ServerWebExchange newExchange = exchange.mutate().request(build).build();
return chain.filter(newExchange);
}
private void printLog(ServerWebExchange exchange) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
LinkedHashSet<URI> uris = exchange.getAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
URI originUri = null;
if (uris != null) {
originUri = uris.stream().findFirst().orElse(null);
}
if (url != null && route != null && originUri != null) {
log.info("转发请求:{}://{}{} --> 目标服务:{},目标地址:{}://{}{},转发时间:{}",
originUri.getScheme(), originUri.getAuthority(), originUri.getPath(),
route.getId(), url.getScheme(), url.getAuthority(), url.getPath(), LocalDateTime.now()
);
}
}
}
package cn.datax.gateway.handler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.cloud.gateway.support.TimeoutException;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class DataGatewayExceptionHandler extends DefaultErrorWebExceptionHandler {
public DataGatewayExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
ErrorProperties errorProperties, ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
/**
* 异常处理,定义返回报文格式
*/
@Override
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Throwable error = super.getError(request);
log.error(
"请求发生异常,请求URI:{},请求方法:{},异常信息:{}",
request.path(), request.methodName(), error.getMessage()
);
String errorMessage;
if (error instanceof NotFoundException) {
String serverId = StringUtils.substringAfterLast(error.getMessage(), "Unable to find instance for ");
serverId = StringUtils.replace(serverId, "\"", StringUtils.EMPTY);
errorMessage = String.format("无法找到%s服务", serverId);
} else if (StringUtils.containsIgnoreCase(error.getMessage(), "connection refused")) {
errorMessage = "目标服务拒绝连接";
} else if (error instanceof TimeoutException) {
errorMessage = "访问服务超时";
} else if (error instanceof ResponseStatusException
&& StringUtils.containsIgnoreCase(error.getMessage(), HttpStatus.NOT_FOUND.toString())) {
errorMessage = "未找到该资源";
} else {
errorMessage = "网关转发异常";
}
Map<String, Object> errorAttributes = new HashMap<>(3);
errorAttributes.put("message", errorMessage);
return errorAttributes;
}
@Override
@SuppressWarnings("all")
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
@Override
protected HttpStatus getHttpStatus(Map<String, Object> errorAttributes) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
server:
port: 8612
spring:
application:
name: datax-gateway
profiles:
active: dev
cloud:
config:
fail-fast: true
uri: http://localhost:8611
name: ${spring.application.name}
profile: ${spring.profiles.active}
discovery:
enabled: true
service-id: datax-config
# 注册中心配置
eureka:
instance:
lease-renewal-interval-in-seconds: 20
client:
register-with-eureka: true
fetch-registry: true
instance-info-replication-interval-seconds: 30
registry-fetch-interval-seconds: 3
service-url:
defaultZone: http://localhost:8610/eureka
\ No newline at end of file
<?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>datax-modules</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>file-service-parent</artifactId>
</project>
\ No newline at end of file
<?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>datax-cloud</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>datax-modules</artifactId>
<modules>
<module>system-service-parent</module>
<module>file-service-parent</module>
</modules>
</project>
\ No newline at end of file
<?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>datax-modules</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>system-service-parent</artifactId>
<modules>
<module>system-service</module>
<module>system-service-api</module>
</modules>
</project>
\ No newline at end of file
<?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>system-service-parent</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>system-service-api</artifactId>
<dependencies>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-core</artifactId>
<version>${app.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.datax.system.api.dto;
import cn.datax.common.validate.ValidateGroupForSave;
import cn.datax.common.validate.ValidateGroupForUpdate;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class DeptDto implements Serializable {
private static final long serialVersionUID=1L;
@NotBlank(message = "主键ID不能为空", groups = {ValidateGroupForUpdate.class})
private String id;
@NotBlank(message = "父部门ID不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String parentId;
@NotBlank(message = "部门名称不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String deptName;
}
package cn.datax.system.api.dto;
import cn.datax.common.validate.ValidateGroupForSave;
import cn.datax.common.validate.ValidateGroupForUpdate;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@Data
public class MenuDto implements Serializable {
private static final long serialVersionUID=1L;
@NotBlank(message = "主键ID不能为空", groups = {ValidateGroupForUpdate.class})
private String id;
@NotBlank(message = "父资源ID不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String parentId;
@NotBlank(message = "资源名称不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String menuName;
private String menuPath;
private String menuComponent;
private String menuPerms;
private String menuIcon;
@NotNull(message = "类型不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private Integer menuType;
@NotNull(message = "排序不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private Integer menuSort;
}
package cn.datax.system.api.dto;
import cn.datax.common.validate.ValidateGroupForSave;
import cn.datax.common.validate.ValidateGroupForUpdate;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class PostDto implements Serializable {
private static final long serialVersionUID=1L;
@NotBlank(message = "主键ID不能为空", groups = {ValidateGroupForUpdate.class})
private String id;
@NotBlank(message = "岗位名称不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String postName;
}
package cn.datax.system.api.dto;
import cn.datax.common.validate.ValidateGroupForSave;
import cn.datax.common.validate.ValidateGroupForUpdate;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class RoleDto implements Serializable {
private static final long serialVersionUID=1L;
@NotBlank(message = "主键ID不能为空", groups = {ValidateGroupForUpdate.class})
private String id;
@NotBlank(message = "角色名称不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String roleName;
@NotBlank(message = "角色编码不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String roleCode;
}
package cn.datax.system.api.dto;
import cn.datax.common.validate.ValidateGroupForSave;
import cn.datax.common.validate.ValidateGroupForUpdate;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.List;
@Data
public class UserDto implements Serializable {
private static final long serialVersionUID=1L;
@NotBlank(message = "主键ID不能为空", groups = {ValidateGroupForUpdate.class})
private String id;
@NotBlank(message = "用户名不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
@Length(min=3, max = 12, message="用户名长度必须位于{min}-{max}之间")
private String username;
@NotBlank(message = "昵称不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String nickname;
@NotBlank(message = "密码不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String password;
@NotBlank(message = "电子邮箱不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
@Email(message = "请输入正确的邮箱")
private String email;
@NotBlank(message = "手机号码不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
private String phone;
@NotNull(message = "出生日期不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthday;
@NotEmpty(message = "部门不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
@Size(min = 1, max = 1, message="部门长度必须位于{min}-{max}之间")
private List<String> depts;
@NotEmpty(message = "角色不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
@Size(min = 1, max = 5, message="角色长度必须位于{min}-{max}之间")
private List<String> roles;
@NotEmpty(message = "岗位不能为空", groups = {ValidateGroupForSave.class, ValidateGroupForUpdate.class})
@Size(min = 1, max = 1, message="岗位长度必须位于{min}-{max}之间")
private List<String> posts;
}
package cn.datax.system.api.entity;
import cn.datax.common.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_dept")
public class DeptEntity extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 父部门ID
*/
private String parentId;
/**
* 部门名称
*/
private String deptName;
}
package cn.datax.system.api.entity;
import cn.datax.common.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_menu")
public class MenuEntity extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 父资源ID
*/
private String parentId;
/**
* 资源名称
*/
private String menuName;
/**
* 对应路由path
*/
private String menuPath;
/**
* 对应路由组件component
*/
private String menuComponent;
/**
* 权限标识
*/
private String menuPerms;
/**
* 图标
*/
private String menuIcon;
/**
* 类型(0模块,1菜单,2按钮)
*/
private Integer menuType;
/**
* 排序
*/
private Integer menuSort;
}
package cn.datax.system.api.entity;
import cn.datax.common.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_post")
public class PostEntity extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 岗位名称
*/
private String postName;
}
package cn.datax.system.api.entity;
import cn.datax.common.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_role")
public class RoleEntity extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 角色名称
*/
private String roleName;
/**
* 角色编码
*/
private String roleCode;
}
package cn.datax.system.api.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@Accessors(chain = true)
@TableName("sys_role_menu")
public class RoleMenuEntity implements Serializable {
private static final long serialVersionUID=1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
/**
* 角色ID
*/
private String roleId;
/**
* 菜单ID
*/
private String menuId;
}
package cn.datax.system.api.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@Accessors(chain = true)
@TableName("sys_user_dept")
public class UserDeptEntity implements Serializable {
private static final long serialVersionUID=1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
/**
* 用户ID
*/
private String userId;
/**
* 部门ID
*/
private String deptId;
}
package cn.datax.system.api.entity;
import cn.datax.common.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalDate;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_user")
public class UserEntity extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 用户名
*/
private String username;
/**
* 昵称
*/
private String nickname;
/**
* 密码
*/
private String password;
/**
* 电子邮箱
*/
private String email;
/**
* 手机号码
*/
private String phone;
/**
* 出生日期
*/
private LocalDate birthday;
}
package cn.datax.system.api.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@Accessors(chain = true)
@TableName("sys_user_post")
public class UserPostEntity implements Serializable {
private static final long serialVersionUID=1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
/**
* 用户ID
*/
private String userId;
/**
* 岗位ID
*/
private String postId;
}
package cn.datax.system.api.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author yuwei
* @since 2019-09-11
*/
@Data
@Accessors(chain = true)
@TableName("sys_user_role")
public class UserRoleEntity implements Serializable {
private static final long serialVersionUID=1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
/**
* 用户ID
*/
private String userId;
/**
* 角色ID
*/
private String roleId;
}
package cn.datax.system.api.vo;
import cn.datax.system.api.entity.DeptEntity;
import cn.datax.system.api.entity.PostEntity;
import cn.datax.system.api.entity.RoleEntity;
import cn.datax.system.api.entity.UserEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
public class UserVo extends UserEntity {
private List<DeptEntity> depts;
private List<PostEntity> posts;
private List<RoleEntity> roles;
}
<?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>system-service-parent</artifactId>
<groupId>cn.datax</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>system-service</artifactId>
<dependencies>
<!--配置中心客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--web 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>${swagger-bootstrap.version}</version>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-mybatis</artifactId>
<version>${app.version}</version>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-redis</artifactId>
<version>${app.version}</version>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>datax-common-security</artifactId>
<version>${app.version}</version>
</dependency>
<dependency>
<groupId>cn.datax</groupId>
<artifactId>system-service-api</artifactId>
<version>${app.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.datax.system;
import cn.datax.common.mybatis.annotation.EnableDataMybatis;
import cn.datax.common.redis.annotation.EnableDataRedis;
import cn.datax.common.security.annotation.EnableDataAuthExceptionHandler;
import cn.datax.common.security.annotation.EnableDataServerProtect;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableDataAuthExceptionHandler
@EnableDataServerProtect
@EnableDataMybatis
@EnableDataRedis
@EnableFeignClients
@SpringBootApplication
public class DataSystemApplication {
public static void main(String[] args) {
SpringApplication.run(DataSystemApplication.class);
}
}
package cn.datax.system.config;
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.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Autowired
private RemoteTokenServices tokenService;
@Bean
public TokenStore redisTokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.tokenStore(redisTokenStore())
.tokenServices(tokenService);
}
}
package cn.datax.system.controller;
import cn.datax.common.base.BaseController;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
/**
* <p>
* 前端控制器
* </p>
*
* @author yuwei
* @since 2019-09-04
*/
@RestController
@RequestMapping("/user")
public class UserController extends BaseController {
@GetMapping("/token")
public Principal currentUser(Principal principal) {
return principal;
}
}
server:
port: 8810
spring:
application:
name: datax-service-system
profiles:
active: dev
cloud:
config:
fail-fast: true
uri: http://localhost:8611
name: ${spring.application.name}
profile: ${spring.profiles.active}
discovery:
enabled: true
service-id: datax-config
# 注册中心配置
eureka:
instance:
lease-renewal-interval-in-seconds: 20
client:
register-with-eureka: true
fetch-registry: true
instance-info-replication-interval-seconds: 30
registry-fetch-interval-seconds: 3
service-url:
defaultZone: http://localhost:8610/eureka
\ No newline at end of file
<?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>
<groupId>cn.datax</groupId>
<artifactId>datax-cloud</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<name>datax-cloud</name>
<description>云数据管理平台</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
<app.version>1.0.0</app.version>
<spring-boot.version>2.1.9.RELEASE</spring-boot.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
<fastjson.version>1.2.62</fastjson.version>
<hutool.version>5.0.3</hutool.version>
<mybatis-plus.version>3.2.0</mybatis-plus.version>
<dynamic-datasource.version>2.5.7</dynamic-datasource.version>
<velocity.version>2.1</velocity.version>
<commons.io.version>2.6</commons.io.version>
<commons.fileupload.version>1.4</commons.fileupload.version>
<commons.lang3.version>3.9</commons.lang3.version>
<commons.codec.version>1.13</commons.codec.version>
<commons.beanutils.version>1.9.4</commons.beanutils.version>
<common-pool.version>2.7.0</common-pool.version>
<swagger2.version>2.9.2</swagger2.version>
<swagger-bootstrap.version>1.9.6</swagger-bootstrap.version>
</properties>
<modules>
<module>datax-eureka</module>
<module>datax-config</module>
<module>datax-common</module>
<module>datax-gateway</module>
<module>datax-auth</module>
<module>datax-modules</module>
</modules>
<dependencies>
<!--eureka 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--配置文件处理器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--自省和监控的集成功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--断路器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--服务链路追踪-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-zipkin</artifactId>-->
<!-- </dependency>-->
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>
<finalName>${project.name}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<finalName>${project.build.finalName}</finalName>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<target>${maven.compiler.target}</target>
<source>${maven.compiler.source}</source>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment