diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..7e8d17b3
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1,2 @@
+package com.jmsoftware.maf.apigateway
+
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.java b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.java
deleted file mode 100644
index 96a736f5..00000000
--- a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.jmsoftware.maf.apigateway.security.impl;
-
-import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-/**
- * Description: GatewayServerAccessDeniedHandlerImpl
- *
- * Implementation os gateway server access denied handler
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:56 AM
- **/
-@Slf4j
-@RequiredArgsConstructor
-public class GatewayServerAccessDeniedHandlerImpl implements ServerAccessDeniedHandler {
- private final ResponseUtil responseUtil;
-
- @Override
- public Mono handle(ServerWebExchange exchange, AccessDeniedException denied) {
- log.error("Access denied! Exception message: {}. Request URL: [{}] {}", denied.getMessage(),
- exchange.getRequest().getMethod(), exchange.getRequest().getURI());
- return this.responseUtil.renderJson(exchange, HttpStatus.FORBIDDEN, denied.getMessage(), null);
- }
-}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.kt b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.kt
new file mode 100644
index 00000000..31492442
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/GatewayServerAccessDeniedHandlerImpl.kt
@@ -0,0 +1,32 @@
+package com.jmsoftware.maf.apigateway.security.impl
+
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil
+import org.springframework.http.HttpStatus
+import org.springframework.security.access.AccessDeniedException
+import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler
+import org.springframework.web.server.ServerWebExchange
+import reactor.core.publisher.Mono
+
+/**
+ * # GatewayServerAccessDeniedHandlerImpl
+ *
+ * Implementation os gateway server access denied handler
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 8:03 PM
+ */
+open class GatewayServerAccessDeniedHandlerImpl(
+ private val responseUtil: ResponseUtil
+) : ServerAccessDeniedHandler {
+ companion object {
+ private val log = logger()
+ }
+
+ override fun handle(exchange: ServerWebExchange, denied: AccessDeniedException): Mono {
+ log.error(
+ "Access denied! Exception message: {}. Request URL: [{}] {}", denied.message,
+ exchange.request.method, exchange.request.uri
+ )
+ return responseUtil.renderJson(exchange, HttpStatus.FORBIDDEN, denied.message, null)
+ }
+}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.java b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.java
deleted file mode 100644
index 5adcaad6..00000000
--- a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.jmsoftware.maf.apigateway.security.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.jmsoftware.maf.apigateway.remote.AuthCenterRemoteApi;
-import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
-import com.jmsoftware.maf.common.exception.BizException;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.authentication.*;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsChecker;
-import reactor.core.publisher.Mono;
-
-/**
- * Description: JwtReactiveAuthenticationManagerImpl
- *
- * Implementation of JWT reactive authentication manager
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:57 AM
- **/
-@Slf4j
-@RequiredArgsConstructor
-public class JwtReactiveAuthenticationManagerImpl implements ReactiveAuthenticationManager {
- private final AuthCenterRemoteApi authCenterRemoteApi;
-
- private final UserDetailsChecker preAuthenticationChecks = user -> {
- if (!user.isAccountNonLocked()) {
- log.error("User account is locked");
- throw new LockedException("User account is locked");
- }
-
- if (!user.isEnabled()) {
- log.error("User account is disabled");
- throw new DisabledException("User is disabled");
- }
-
- if (!user.isAccountNonExpired()) {
- log.error("User account is expired");
- throw new AccountExpiredException("User account has expired");
- }
- };
-
- private final UserDetailsChecker postAuthenticationChecks = user -> {
- if (!user.isCredentialsNonExpired()) {
- log.error("User account credentials have expired");
- throw new CredentialsExpiredException("User credentials have expired");
- }
- };
-
- private Mono retrieveUser(String username) {
- if (StrUtil.isBlank(username)) {
- log.warn("Authentication failure! Cause: the username mustn't be blank");
- return Mono.error(
- new SecurityException(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, "Username mustn't be blank"));
- }
- return this.authCenterRemoteApi.getUserByLoginToken(username)
- .switchIfEmpty(Mono.error(new BizException("Authentication failure! Cause: User not found")))
- .map(data -> {
- log.info("Authentication success! Found {}", data);
- return UserPrincipal.create(data, null, null);
- });
- }
-
- @Override
- public Mono authenticate(Authentication authentication) {
- return this.retrieveUser(authentication.getName())
- .doOnNext(this.preAuthenticationChecks::check)
- .doOnNext(this.postAuthenticationChecks::check)
- .map(userDetails -> new UsernamePasswordAuthenticationToken(userDetails, null));
- }
-}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.kt b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.kt
new file mode 100644
index 00000000..b50d9f75
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveAuthenticationManagerImpl.kt
@@ -0,0 +1,73 @@
+package com.jmsoftware.maf.apigateway.security.impl
+
+import cn.hutool.core.util.StrUtil
+import com.jmsoftware.maf.apigateway.remote.AuthCenterWebClientService
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse
+import com.jmsoftware.maf.common.exception.InternalServerException
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import org.springframework.http.HttpStatus
+import org.springframework.security.authentication.*
+import org.springframework.security.core.Authentication
+import org.springframework.security.core.userdetails.UserDetails
+import org.springframework.security.core.userdetails.UserDetailsChecker
+import reactor.core.publisher.Mono
+
+/**
+ * # JwtReactiveAuthenticationManagerImpl
+ *
+ * Implementation of JWT reactive authentication manager
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 8:03 PM
+ */
+open class JwtReactiveAuthenticationManagerImpl(
+ private val authCenterWebClientService: AuthCenterWebClientService
+) : ReactiveAuthenticationManager {
+ companion object {
+ private val log = logger()
+ }
+
+ private val preAuthenticationChecks = UserDetailsChecker { user: UserDetails ->
+ if (!user.isAccountNonLocked) {
+ log.error("User account is locked")
+ throw LockedException("User account is locked")
+ }
+ if (!user.isEnabled) {
+ log.error("User account is disabled")
+ throw DisabledException("User is disabled")
+ }
+ if (!user.isAccountNonExpired) {
+ log.error("User account is expired")
+ throw AccountExpiredException("User account has expired")
+ }
+ }
+ private val postAuthenticationChecks = UserDetailsChecker { user: UserDetails ->
+ if (!user.isCredentialsNonExpired) {
+ log.error("User account credentials have expired")
+ throw CredentialsExpiredException("User credentials have expired")
+ }
+ }
+
+ private fun retrieveUser(username: String): Mono {
+ if (StrUtil.isBlank(username)) {
+ log.warn("Authentication failure! Cause: the username mustn't be blank")
+ return Mono.error(
+ SecurityException(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, "Username mustn't be blank")
+ )
+ }
+ return authCenterWebClientService.getUserByLoginToken(username)
+ .switchIfEmpty(Mono.error(InternalServerException("Authentication failure! Cause: User not found")))
+ .map { data: GetUserByLoginTokenResponse ->
+ log.info("Authentication success! Found $data")
+ UserPrincipal.create(data)
+ }
+ }
+
+ override fun authenticate(authentication: Authentication): Mono {
+ return retrieveUser(authentication.name)
+ .doOnNext { toCheck: UserDetails -> preAuthenticationChecks.check(toCheck) }
+ .doOnNext { toCheck: UserDetails -> postAuthenticationChecks.check(toCheck) }
+ .map { userDetails: UserDetails -> UsernamePasswordAuthenticationToken(userDetails, null) }
+ }
+}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.java b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.java
deleted file mode 100644
index 2b18c879..00000000
--- a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.jmsoftware.maf.apigateway.security.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.jmsoftware.maf.apigateway.remote.AuthCenterRemoteApi;
-import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import com.jmsoftware.maf.reactivespringcloudstarter.property.JwtConfigurationProperties;
-import com.jmsoftware.maf.reactivespringcloudstarter.property.MafConfigurationProperties;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.authentication.ReactiveAuthenticationManager;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextImpl;
-import org.springframework.security.web.server.context.ServerSecurityContextRepository;
-import org.springframework.util.AntPathMatcher;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-/**
- * Description: JwtReactiveServerSecurityContextRepositoryImpl
- *
- * Implementation of JWT reactive server security context repository
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:58 AM
- **/
-@Slf4j
-@RequiredArgsConstructor
-public class JwtReactiveServerSecurityContextRepositoryImpl implements ServerSecurityContextRepository {
- private final MafConfigurationProperties mafConfigurationProperties;
- private final ReactiveAuthenticationManager authenticationManager;
- private final AntPathMatcher antPathMatcher = new AntPathMatcher();
- private final AuthCenterRemoteApi authCenterRemoteApi;
-
- @Override
- public Mono save(ServerWebExchange exchange, SecurityContext context) {
- log.error("Unsupported operation exception: Not supported yet.");
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public Mono load(ServerWebExchange exchange) {
- val request = exchange.getRequest();
- // Ignore allowed URL
- for (val ignoredUrl : this.mafConfigurationProperties.flattenIgnoredUrls()) {
- if (this.antPathMatcher.match(ignoredUrl, request.getURI().getPath())) {
- return Mono.empty();
- }
- }
- val authorization = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
- if (StrUtil.isBlank(authorization) || !StrUtil.startWith(authorization, JwtConfigurationProperties.TOKEN_PREFIX)) {
- log.warn("Pre-authentication failure! Cause: `{}` in HTTP headers not found. Request URL: [{}] {}",
- HttpHeaders.AUTHORIZATION, request.getMethod(), request.getURI());
- return Mono.error(new SecurityException(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, "JWT Required"));
- }
- return this.authCenterRemoteApi.parse(authorization)
- .map(parseJwtResponse -> {
- log.info("parseJwtResponse: {}", parseJwtResponse);
- val userPrincipal = UserPrincipal.createByUsername(parseJwtResponse.getUsername());
- userPrincipal.setId(parseJwtResponse.getId());
- val authentication = new UsernamePasswordAuthenticationToken(userPrincipal, null);
- log.warn("About to authenticate… Authentication is created. {}", authentication);
- return authentication;
- }).flatMap(authentication -> this.authenticationManager.authenticate(authentication)
- .map(SecurityContextImpl::new));
- }
-}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.kt b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.kt
new file mode 100644
index 00000000..48848acb
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/JwtReactiveServerSecurityContextRepositoryImpl.kt
@@ -0,0 +1,76 @@
+package com.jmsoftware.maf.apigateway.security.impl
+
+import cn.hutool.core.util.StrUtil
+import com.jmsoftware.maf.apigateway.remote.AuthCenterWebClientService
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal.Companion.createByUsername
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.reactivespringcloudstarter.property.JwtConfigurationProperties.Companion.TOKEN_PREFIX
+import com.jmsoftware.maf.reactivespringcloudstarter.property.MafConfigurationProperties
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
+import org.springframework.security.authentication.ReactiveAuthenticationManager
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
+import org.springframework.security.core.Authentication
+import org.springframework.security.core.context.SecurityContext
+import org.springframework.security.core.context.SecurityContextImpl
+import org.springframework.security.web.server.context.ServerSecurityContextRepository
+import org.springframework.util.AntPathMatcher
+import org.springframework.web.server.ServerWebExchange
+import reactor.core.publisher.Mono
+
+/**
+ * # JwtReactiveServerSecurityContextRepositoryImpl
+ *
+ * Implementation of JWT reactive server security context repository
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 8:04 PM
+ */
+open class JwtReactiveServerSecurityContextRepositoryImpl(
+ private val mafConfigurationProperties: MafConfigurationProperties,
+ private val authenticationManager: ReactiveAuthenticationManager,
+ private val authCenterWebClientService: AuthCenterWebClientService
+) : ServerSecurityContextRepository {
+ private val antPathMatcher = AntPathMatcher()
+
+ companion object {
+ private val log = logger()
+ }
+
+ override fun save(exchange: ServerWebExchange, context: SecurityContext): Mono {
+ log.error("Unsupported operation exception: Not supported yet.")
+ throw UnsupportedOperationException("Not supported yet.")
+ }
+
+ override fun load(exchange: ServerWebExchange): Mono {
+ val request = exchange.request
+ // Ignore allowed URL
+ for (ignoredUrl in mafConfigurationProperties.flattenIgnoredUrls()) {
+ if (antPathMatcher.match(ignoredUrl, request.uri.path)) {
+ return Mono.empty()
+ }
+ }
+ val authorization = request.headers.getFirst(HttpHeaders.AUTHORIZATION)
+ if (StrUtil.isBlank(authorization) || !StrUtil.startWith(authorization, TOKEN_PREFIX)) {
+ log.warn("Pre-authentication failure! Cause: `${HttpHeaders.AUTHORIZATION}` in HTTP headers not found. Request URL: [${request.method}] ${request.uri}")
+ return Mono.error(SecurityException(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, "JWT Required"))
+ }
+ return authCenterWebClientService.parse(authorization!!)
+ .map { parseJwtResponse: ParseJwtResponse ->
+ log.info("parseJwtResponse: {}", parseJwtResponse)
+ val userPrincipal = createByUsername(parseJwtResponse.username)
+ userPrincipal.id = parseJwtResponse.id
+ val authentication = UsernamePasswordAuthenticationToken(userPrincipal, null)
+ log.warn("About to authenticate… Authentication is created. $authentication")
+ authentication
+ }.flatMap { authentication: UsernamePasswordAuthenticationToken ->
+ authenticationManager.authenticate(authentication)
+ .map { authentication2: Authentication ->
+ SecurityContextImpl(
+ authentication2
+ )
+ }
+ }
+ }
+}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.java b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.java
deleted file mode 100644
index 708d51aa..00000000
--- a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.jmsoftware.maf.apigateway.security.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.google.common.collect.Lists;
-import com.jmsoftware.maf.apigateway.remote.AuthCenterRemoteApi;
-import com.jmsoftware.maf.common.constant.MafHttpHeader;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
-import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.security.authorization.AuthorizationDecision;
-import org.springframework.security.authorization.ReactiveAuthorizationManager;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.web.server.authorization.AuthorizationContext;
-import org.springframework.stereotype.Component;
-import org.springframework.util.AntPathMatcher;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-/**
- * Description: RbacReactiveAuthorizationManagerImpl
- *
- * Implementation of RBAC (Role-based access control) reactive authorization manager
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 9:54 AM
- * @see Role-based access control
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class RbacReactiveAuthorizationManagerImpl implements ReactiveAuthorizationManager {
- private final AntPathMatcher antPathMatcher = new AntPathMatcher();
- private final AuthCenterRemoteApi authCenterRemoteApi;
-
- /**
- * Retrieve roles flux.
- *
- * @param userPrincipalMono the user principal mono
- * @return the flux
- */
- private Flux retrieveRoles(Mono userPrincipalMono) {
- // Get role list by user ID, and then convert to Flux>
- return userPrincipalMono
- .flatMap(userPrincipal -> this.authCenterRemoteApi.getRoleListByUserId(userPrincipal.getId()))
- .flatMapMany(Flux::fromIterable)
- .switchIfEmpty(Flux.error(new SecurityException(HttpStatus.UNAUTHORIZED, "Roles not assigned!")));
- }
-
- /**
- * Filter roles mono.
- *
- * @param roleFlux the role flux
- * @return the mono
- */
- private Mono> mapRole(Flux roleFlux) {
- return roleFlux
- .map(GetRoleListByUserIdSingleResponse::getId)
- .collectList()
- .switchIfEmpty(roleFlux.map(GetRoleListByUserIdSingleResponse::getId).collectList());
- }
-
- /**
- * Retrieve permissions mono.
- *
- * @param roleIdListMono the role id list mono
- * @return the mono
- */
- private Mono> retrievePermissions(Mono> roleIdListMono) {
- // Get permission list based on the Mono>
- // auth-center will respond /** for role "admin"
- return roleIdListMono.flatMap(
- roleIdList -> {
- val payload = new GetPermissionListByRoleIdListPayload();
- payload.setRoleIdList(roleIdList);
- payload.setPermissionTypeList(Lists.newArrayList(PermissionType.BUTTON));
- return this.authCenterRemoteApi.getPermissionListByRoleIdList(payload);
- })
- .switchIfEmpty(Mono.error(new SecurityException(HttpStatus.FORBIDDEN, "Permission not found!")));
- }
-
- @Override
- public Mono check(Mono authentication, AuthorizationContext object) {
- val request = object.getExchange().getRequest();
- val userPrincipalMono = authentication.map(auth -> (UserPrincipal) auth.getPrincipal());
- val roleFlux = this.retrieveRoles(userPrincipalMono);
- val roleIdListMono = this.mapRole(roleFlux);
- val permissionListMono = this.retrievePermissions(roleIdListMono);
- // Aggregate 2 Mono
- val zip = Mono.zip(permissionListMono, userPrincipalMono);
- return zip.map(mapper -> {
- val permissionList = mapper.getT1();
- val buttonPermissionList = permissionList.stream()
- .filter(permission -> StrUtil.isNotBlank(permission.getUrl()))
- .filter(permission -> StrUtil.isNotBlank(permission.getMethod()))
- .collect(Collectors.toList());
- val userPrincipal = mapper.getT2();
- for (var buttonPermission : buttonPermissionList) {
- if (this.checkRestfulAccess(buttonPermission, request)) {
- log.info("Authorization success! Resource [{}] {} is accessible for user(username: {})",
- request.getMethod(), request.getURI(), userPrincipal.getUsername());
- request
- .mutate()
- .headers(httpHeaders -> {
- httpHeaders.set(MafHttpHeader.X_ID.getHeader(), String.valueOf(userPrincipal.getId()));
- httpHeaders.set(MafHttpHeader.X_USERNAME.getHeader(), userPrincipal.getUsername());
- })
- .build();
- return new AuthorizationDecision(true);
- }
- }
- log.warn("Authorization failure! Resource [{}] {} is not accessible for user(username: {})",
- request.getMethod(), request.getURI(), userPrincipal.getUsername());
- return new AuthorizationDecision(false);
- });
- }
-
- /**
- * Check Restful access.
- *
- * Check if the URL is matched
- * Check if the HTTP method is matched
- *
- *
- * @param buttonPermission the button permission
- * @param request the request
- * @return true: accessible; false: not accessible
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 1/13/2021 11:04 AM
- */
- private boolean checkRestfulAccess(GetPermissionListByRoleIdListResponse.Permission buttonPermission,
- ServerHttpRequest request) {
- val urlMatched = this.antPathMatcher.match(buttonPermission.getUrl(), request.getURI().getPath());
- // "*" is for super user. Super user's permission is like URL: "/**", method: "*"
- val allMethods = StrUtil.equals(buttonPermission.getMethod(), "*");
- if (allMethods) {
- return urlMatched;
- }
- val methodMatched = Objects.requireNonNull(request.getMethod()).matches(buttonPermission.getMethod());
- return urlMatched && methodMatched;
- }
-}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.kt b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.kt
new file mode 100644
index 00000000..2cbc8577
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/RbacReactiveAuthorizationManagerImpl.kt
@@ -0,0 +1,148 @@
+package com.jmsoftware.maf.apigateway.security.impl
+
+import cn.hutool.core.util.StrUtil
+import com.jmsoftware.maf.apigateway.remote.AuthCenterWebClientService
+import com.jmsoftware.maf.common.constant.MafHttpHeader.X_ID
+import com.jmsoftware.maf.common.constant.MafHttpHeader.X_USERNAME
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.authcenter.permission.Permission
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
+import org.springframework.http.server.reactive.ServerHttpRequest
+import org.springframework.security.authorization.AuthorizationDecision
+import org.springframework.security.authorization.ReactiveAuthorizationManager
+import org.springframework.security.core.Authentication
+import org.springframework.security.web.server.authorization.AuthorizationContext
+import org.springframework.util.AntPathMatcher
+import reactor.core.publisher.Flux
+import reactor.core.publisher.Mono
+import reactor.util.function.Tuple2
+
+/**
+ * # RbacReactiveAuthorizationManagerImpl
+ *
+ * Implementation of RBAC (Role-based access control) reactive authorization manager
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 8:57 PM
+ * @see [Role-based access control](https://en.wikipedia.org/wiki/Role-based_access_control)
+ */
+open class RbacReactiveAuthorizationManagerImpl(
+ private val authCenterWebClientService: AuthCenterWebClientService
+) : ReactiveAuthorizationManager {
+ companion object {
+ private val log = logger()
+ }
+
+ private val antPathMatcher = AntPathMatcher()
+
+ /**
+ * Retrieve roles flux.
+ *
+ * @param userPrincipalMono the user principal mono
+ * @return the flux
+ */
+ private fun retrieveRoles(userPrincipalMono: Mono): Flux {
+ // Get role list by user ID, and then convert to Flux>
+ return userPrincipalMono
+ .flatMap { userPrincipal: UserPrincipal -> authCenterWebClientService.getRoleListByUserId(userPrincipal.id!!) }
+ .flatMapMany { Flux.fromIterable(it) }
+ .switchIfEmpty(Flux.error(SecurityException(HttpStatus.UNAUTHORIZED, "Roles not assigned!")))
+ }
+
+ /**
+ * Filter roles mono.
+ *
+ * @param roleFlux the role flux
+ * @return the mono
+ */
+ private fun mapRole(roleFlux: Flux): Mono> {
+ return roleFlux
+ .map(GetRoleListByUserIdSingleResponse::id)
+ .collectList()
+ .switchIfEmpty(roleFlux.map(GetRoleListByUserIdSingleResponse::id).collectList())
+ }
+
+ /**
+ * Retrieve permissions mono.
+ *
+ * @param roleIdListMono the role id list mono
+ * @return the mono
+ */
+ private fun retrievePermissions(roleIdListMono: Mono>): Mono> {
+ // Get permission list based on the Mono>
+ // auth-center will respond /** for role "admin"
+ return roleIdListMono.flatMap { roleIdList: List ->
+ val payload = GetPermissionListByRoleIdListPayload()
+ payload.roleIdList = roleIdList
+ payload.permissionTypeList = listOf(PermissionType.BUTTON)
+ authCenterWebClientService.getPermissionListByRoleIdList(payload)
+ }
+ .switchIfEmpty(Mono.error(SecurityException(HttpStatus.FORBIDDEN, "Permission not found!")))
+ }
+
+ override fun check(
+ authentication: Mono,
+ `object`: AuthorizationContext
+ ): Mono {
+ val request = `object`.exchange.request
+ val userPrincipalMono = authentication.map { auth: Authentication -> auth.principal as UserPrincipal }
+ val roleFlux = retrieveRoles(userPrincipalMono)
+ val roleIdListMono = mapRole(roleFlux)
+ val permissionListMono = retrievePermissions(roleIdListMono)
+ // Aggregate 2 Mono
+ val zip = Mono.zip(permissionListMono, userPrincipalMono)
+ return zip.map { mapper: Tuple2, UserPrincipal> ->
+ val userPrincipal = mapper.t2
+ val anyMatched = mapper.t1.stream()
+ .filter { permission: Permission -> StrUtil.isNotBlank(permission.url) }
+ .filter { permission: Permission -> StrUtil.isNotBlank(permission.method) }
+ .anyMatch { permission: Permission ->
+ checkRestfulAccess(permission, request)
+ }
+ if (anyMatched) {
+ log.info("Authorization success! Resource [${request.method}] ${request.uri} is accessible for user(username: ${userPrincipal.username})")
+ request.mutate()
+ .headers { httpHeaders: HttpHeaders ->
+ httpHeaders[X_ID.header] = userPrincipal.id.toString()
+ httpHeaders[X_USERNAME.header] = userPrincipal.username
+ }.build()
+ AuthorizationDecision(true)
+ } else {
+ log.warn("Authorization failure! Resource [${request.method}] ${request.uri} is not accessible for user(username: ${userPrincipal.username})")
+ AuthorizationDecision(false)
+ }
+ }
+ }
+
+ /**
+ *
+ * Check Restful access.
+ *
+ * * Check if the URL is matched
+ * * Check if the HTTP method is matched
+ *
+ *
+ * @param buttonPermission the button permission
+ * @param request the request
+ * @return true: accessible; false: not accessible
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 1/13/2021 11:04 AM
+ */
+ private fun checkRestfulAccess(
+ buttonPermission: Permission,
+ request: ServerHttpRequest
+ ): Boolean {
+ val urlMatched = antPathMatcher.match(buttonPermission.url!!, request.uri.path)
+ // "*" is for super user. Super user's permission is like URL: "/**", method: "*"
+ val allMethods = StrUtil.equals(buttonPermission.method, "*")
+ if (allMethods) {
+ return urlMatched
+ }
+ val methodMatched = request.method!!.matches(buttonPermission.method!!)
+ return urlMatched && methodMatched
+ }
+}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.java b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.java
deleted file mode 100644
index b18b581a..00000000
--- a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.jmsoftware.maf.apigateway.security.impl;
-
-import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-/**
- * Description: ServerAuthenticationEntryPointImpl, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/21/2020 9:48 AM
- **/
-@Slf4j
-@RequiredArgsConstructor
-public class ServerAuthenticationEntryPointImpl implements ServerAuthenticationEntryPoint {
- private final ResponseUtil responseUtil;
-
- @Override
- public Mono commence(ServerWebExchange exchange, AuthenticationException e) {
- log.error("Exception occurred when authenticating! Exception message: {}. Request URL: [{}] {}", e.getMessage(),
- exchange.getRequest().getMethod(), exchange.getRequest().getURI());
- return this.responseUtil.renderJson(exchange, HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, e.getMessage(), null);
- }
-}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.kt b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.kt
new file mode 100644
index 00000000..1332d393
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/impl/ServerAuthenticationEntryPointImpl.kt
@@ -0,0 +1,29 @@
+package com.jmsoftware.maf.apigateway.security.impl
+
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil
+import org.springframework.http.HttpStatus
+import org.springframework.security.core.AuthenticationException
+import org.springframework.security.web.server.ServerAuthenticationEntryPoint
+import org.springframework.web.server.ServerWebExchange
+import reactor.core.publisher.Mono
+
+/**
+ * # ServerAuthenticationEntryPointImpl
+ *
+ * Description: ServerAuthenticationEntryPointImpl, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 8:57 PM
+ */
+open class ServerAuthenticationEntryPointImpl(
+ private val responseUtil: ResponseUtil
+) : ServerAuthenticationEntryPoint {
+ companion object {
+ private val log = logger()
+ }
+
+ override fun commence(exchange: ServerWebExchange, e: AuthenticationException): Mono {
+ log.error("Exception occurred when authenticating! Exception message: ${e.message}. Request URL: [${exchange.request.method}] ${exchange.request.uri}")
+ return responseUtil.renderJson(exchange, HttpStatus.NETWORK_AUTHENTICATION_REQUIRED, e.message, null)
+ }
+}
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/package-info.java b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/package-info.java
deleted file mode 100644
index 30dd5fd2..00000000
--- a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway.security;
diff --git a/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/package-info.kt b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/package-info.kt
new file mode 100644
index 00000000..f519c1cf
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/main/java/com/jmsoftware/maf/apigateway/security/package-info.kt
@@ -0,0 +1,2 @@
+package com.jmsoftware.maf.apigateway.security
+
diff --git a/api-gateway/api-gateway-biz/src/test/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-biz/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-biz/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-biz/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-biz/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..238d8d7a
--- /dev/null
+++ b/api-gateway/api-gateway-biz/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway
diff --git a/api-gateway/api-gateway-bootstrap/pom.xml b/api-gateway/api-gateway-bootstrap/pom.xml
index fdbda28e..8d1bc2d1 100644
--- a/api-gateway/api-gateway-bootstrap/pom.xml
+++ b/api-gateway/api-gateway-bootstrap/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
api-gateway
- 0.0.8.1
+ 0.0.9
@@ -30,44 +30,6 @@
-
- org.apache.maven.plugins
- maven-pmd-plugin
- ${maven-pmd-plugin.version}
-
- ${project.build.sourceEncoding}
- ${java.version}
- true
-
- rulesets/java/ali-comment.xml
- rulesets/java/ali-concurrent.xml
- rulesets/java/ali-constant.xml
- rulesets/java/ali-exception.xml
- rulesets/java/ali-flowcontrol.xml
- rulesets/java/ali-naming.xml
- rulesets/java/ali-oop.xml
- rulesets/java/ali-orm.xml
- rulesets/java/ali-other.xml
- rulesets/java/ali-set.xml
-
-
-
-
- verify
-
- check
-
-
-
-
-
- com.alibaba.p3c
- p3c-pmd
- ${p3c-pmd.version}
-
-
-
-
com.google.cloud.tools
@@ -100,12 +62,16 @@
-
- adoptopenjdk/openjdk11:${adoptopenjdk11.tag}
+
+ eclipse-temurin:${temurin.tag}
docker.io/ijohnnymiller/${project.baseArtifactId}.${project.parent.artifactId}
+
${git.commit.id.abbrev}-${project.version}
@@ -132,31 +98,6 @@
-
-
-
- io.github.git-commit-id
- git-commit-id-maven-plugin
- 5.0.0
-
-
- get-the-git-info
-
- revision
-
- initialize
-
-
-
- true
- ${project.build.outputDirectory}/git.properties
-
- ^git.build.(time|version)$
- ^git.commit.id.(abbrev|full)$
-
- full
-
-
diff --git a/api-gateway/api-gateway-bootstrap/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.java b/api-gateway/api-gateway-bootstrap/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.java
deleted file mode 100644
index b148d84f..00000000
--- a/api-gateway/api-gateway-bootstrap/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.jmsoftware.maf.apigateway;
-
-import com.jmsoftware.maf.reactivespringcloudstarter.helper.SpringBootStartupHelper;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.util.StopWatch;
-
-/**
- * ApiGatewayApplication
- *
- * Change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/22/2020 3:39 PM
- **/
-@Slf4j
-@EnableDiscoveryClient
-@SpringBootApplication
-@SuppressWarnings("scwjava_Createprivateconstructorforutilityclassallfieldsmethodsarestatic")
-public class ApiGatewayApplication {
- public static void main(String[] args) {
- val stopWatch = new StopWatch();
- stopWatch.start();
- val configurableApplicationContext = SpringApplication.run(ApiGatewayApplication.class, args);
- val springBootStartupHelper = configurableApplicationContext.getBean(SpringBootStartupHelper.class);
- springBootStartupHelper.stop(stopWatch);
- }
-}
diff --git a/api-gateway/api-gateway-bootstrap/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.kt b/api-gateway/api-gateway-bootstrap/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.kt
new file mode 100644
index 00000000..ed6638eb
--- /dev/null
+++ b/api-gateway/api-gateway-bootstrap/src/main/java/com/jmsoftware/maf/apigateway/ApiGatewayApplication.kt
@@ -0,0 +1,28 @@
+package com.jmsoftware.maf.apigateway
+
+import com.jmsoftware.maf.reactivespringcloudstarter.helper.SpringBootStartupHelper
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.runApplication
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient
+import org.springframework.util.StopWatch
+
+/**
+ * # ApiGatewayApplication
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/17/22 8:48 AM
+ */
+@EnableDiscoveryClient
+@SpringBootApplication
+class ApiGatewayApplication
+
+fun main(args: Array) {
+ StopWatch().let {
+ it.start()
+ runApplication(*args)
+ .getBean(SpringBootStartupHelper::class.java)
+ .stop(it)
+ }
+}
+
diff --git a/api-gateway/api-gateway-bootstrap/src/main/resources/application.yml b/api-gateway/api-gateway-bootstrap/src/main/resources/application.yml
index ffcfe31a..e5eba1d9 100644
--- a/api-gateway/api-gateway-bootstrap/src/main/resources/application.yml
+++ b/api-gateway/api-gateway-bootstrap/src/main/resources/application.yml
@@ -21,7 +21,7 @@ spring:
config:
# `default-context` should not be modified, keeps "application" for common configuration.
# Properties in the config/application folder are applicable to all applications using consul for configuration.
- profile-separator: "::"
+ profile-separator: "@"
format: YAML
data-key: "data"
watch:
diff --git a/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/ApiGatewayApplicationTests.java b/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/ApiGatewayApplicationTests.java
deleted file mode 100644
index 2ffb2727..00000000
--- a/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/ApiGatewayApplicationTests.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.jmsoftware.maf.apigateway;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class ApiGatewayApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
-}
diff --git a/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.java b/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.java
deleted file mode 100644
index d5f826ce..00000000
--- a/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.jmsoftware.maf.apigateway;
-
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.util.AntPathMatcher;
-
-/**
- * Description: AuthorizationTests, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 1/13/2021 11:27 AM
- **/
-@Slf4j
-@SpringBootTest
-class AuthorizationTests {
- @Test
- void antPathMatcherTests() {
- val antPathMatcher = new AntPathMatcher();
- val urlMatched = antPathMatcher.match("/**", "/spring-boot-admin/common/app-info");
- log.info("urlMatched: {}", urlMatched);
- Assertions.assertTrue(urlMatched);
- }
-}
diff --git a/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.kt b/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.kt
new file mode 100644
index 00000000..efd74a74
--- /dev/null
+++ b/api-gateway/api-gateway-bootstrap/src/test/java/com/jmsoftware/maf/apigateway/AuthorizationTests.kt
@@ -0,0 +1,30 @@
+package com.jmsoftware.maf.apigateway
+
+import com.jmsoftware.maf.common.util.logger
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+import org.springframework.util.AntPathMatcher
+
+/**
+ * # AuthorizationTests
+ *
+ * Description: AuthorizationTests, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 10:15 PM
+ */
+internal class AuthorizationTests {
+ companion object {
+ private val log = logger()
+ }
+
+ @Test
+ fun antPathMatcherTests() {
+ val antPathMatcher = AntPathMatcher()
+ val urlMatched1 = antPathMatcher.match("/spring-boot-admin/**", "/spring-boot-admin/common/app-info")
+ log.info("urlMatched1: $urlMatched1")
+ assertTrue(urlMatched1)
+ val urlMatched2 = antPathMatcher.match("/**", "/spring-boot-admin/common/app-info")
+ log.info("urlMatched2: $urlMatched2")
+ assertTrue(urlMatched2)
+ }
+}
diff --git a/api-gateway/api-gateway-domain/pom.xml b/api-gateway/api-gateway-domain/pom.xml
index 4c558fee..12820d7b 100644
--- a/api-gateway/api-gateway-domain/pom.xml
+++ b/api-gateway/api-gateway-domain/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
api-gateway
- 0.0.8.1
+ 0.0.9
diff --git a/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..238d8d7a
--- /dev/null
+++ b/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway
diff --git a/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterWebClientService.kt b/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterWebClientService.kt
new file mode 100644
index 00000000..cf2ed24a
--- /dev/null
+++ b/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterWebClientService.kt
@@ -0,0 +1,57 @@
+package com.jmsoftware.maf.apigateway.remote
+
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.authcenter.permission.Permission
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse
+import org.springframework.validation.annotation.Validated
+import reactor.core.publisher.Mono
+import javax.validation.Valid
+import javax.validation.constraints.Min
+import javax.validation.constraints.NotBlank
+import javax.validation.constraints.NotNull
+
+/**
+ * # AuthCenterWebClientService
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, 4/16/22 9:37 PM
+ **/
+@Validated
+interface AuthCenterWebClientService {
+ /**
+ * Get user by login token
+ *
+ * @param loginToken
+ * @return
+ */
+ fun getUserByLoginToken(loginToken: @NotBlank String): Mono
+
+ /**
+ * Get role list by user id
+ *
+ * @param userId
+ * @return role list
+ */
+ fun getRoleListByUserId(userId: @NotNull @Min(1L) Long): Mono>
+
+ /**
+ * Get permission list by role id list
+ *
+ * @param payload
+ * @return permission list
+ */
+ fun getPermissionListByRoleIdList(
+ payload: @Valid @NotNull GetPermissionListByRoleIdListPayload
+ ): Mono>
+
+ /**
+ * Parse
+ *
+ * @param authorization
+ * @return jwt
+ */
+ fun parse(authorization: @NotBlank String): Mono
+}
diff --git a/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/remote/impl/AuthCenterWebClientServiceImpl.kt b/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/remote/impl/AuthCenterWebClientServiceImpl.kt
new file mode 100644
index 00000000..b84e777f
--- /dev/null
+++ b/api-gateway/api-gateway-domain/src/main/java/com/jmsoftware/maf/apigateway/remote/impl/AuthCenterWebClientServiceImpl.kt
@@ -0,0 +1,39 @@
+package com.jmsoftware.maf.apigateway.remote.impl
+
+import com.jmsoftware.maf.apigateway.remote.AuthCenterWebClient
+import com.jmsoftware.maf.apigateway.remote.AuthCenterWebClientService
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.authcenter.permission.Permission
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse
+import org.springframework.stereotype.Service
+import reactor.core.publisher.Mono
+import javax.validation.Valid
+import javax.validation.constraints.Min
+import javax.validation.constraints.NotBlank
+import javax.validation.constraints.NotNull
+
+/**
+ * # AuthCenterWebClientServiceImpl
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, 4/16/22 9:40 PM
+ **/
+@Service
+class AuthCenterWebClientServiceImpl(
+ private val authCenterWebClient: AuthCenterWebClient
+) : AuthCenterWebClientService {
+ override fun getUserByLoginToken(loginToken: @NotBlank String): Mono =
+ authCenterWebClient.getUserByLoginToken(loginToken)
+
+ override fun getRoleListByUserId(userId: @NotNull @Min(1L) Long): Mono> =
+ authCenterWebClient.getRoleListByUserId(userId)
+
+ override fun getPermissionListByRoleIdList(
+ payload: @Valid @NotNull GetPermissionListByRoleIdListPayload
+ ): Mono> = authCenterWebClient.getPermissionListByRoleIdList(payload)
+
+ override fun parse(authorization: String): Mono = authCenterWebClient.parse(authorization)
+}
diff --git a/api-gateway/api-gateway-domain/src/test/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-domain/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-domain/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-domain/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-domain/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..238d8d7a
--- /dev/null
+++ b/api-gateway/api-gateway-domain/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway
diff --git a/api-gateway/api-gateway-infra/pom.xml b/api-gateway/api-gateway-infra/pom.xml
index cd6697ee..fb19a183 100644
--- a/api-gateway/api-gateway-infra/pom.xml
+++ b/api-gateway/api-gateway-infra/pom.xml
@@ -10,6 +10,6 @@
com.jmsoftware.maf
api-gateway
- 0.0.8.1
+ 0.0.9
diff --git a/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..7e8d17b3
--- /dev/null
+++ b/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1,2 @@
+package com.jmsoftware.maf.apigateway
+
diff --git a/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterRemoteApi.java b/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterRemoteApi.java
deleted file mode 100644
index 86f2799a..00000000
--- a/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterRemoteApi.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package com.jmsoftware.maf.apigateway.remote;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONUtil;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
-import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpHeaders;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Mono;
-
-import javax.validation.Valid;
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import java.util.List;
-
-/**
- * AuthCenterRemoteApi
- *
- * Change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
- * @date 5/10/20 4:50 PM
- */
-@Slf4j
-@Service
-@Validated
-@RequiredArgsConstructor
-public class AuthCenterRemoteApi {
- private static final String SERVICE_NAME = "auth-center";
- private final WebClient webClient;
-
- /**
- * Gets user by login token.
- *
- * @param loginToken the login token, e.q. username, email or phone number
- * @return the user by login token
- */
- public Mono getUserByLoginToken(@NotBlank String loginToken) {
- return this.webClient
- .get()
- .uri(String.format("http://%s/user-remote-api/users/{loginToken}", SERVICE_NAME), loginToken)
- .retrieve()
- .bodyToMono(ResponseBodyBean.class)
- .map(ResponseBodyBean::getData)
- .map(data -> JSONUtil.toBean(JSONUtil.parseObj(data), GetUserByLoginTokenResponse.class));
- }
-
- /**
- * Gets role list by user id.
- *
- * @param userId the user id
- * @return the role list by user id
- */
- public Mono> getRoleListByUserId(@NotNull @Min(1L) Long userId) {
- return this.webClient
- .get()
- .uri(String.format("http://%s/role-remote-api/roles/{userId}", SERVICE_NAME), userId)
- .retrieve()
- .bodyToMono(ResponseBodyBean.class)
- .map(ResponseBodyBean::getData)
- .map(data -> JSONUtil.toList(JSONUtil.parseObj(data).getJSONArray("roleList"),
- GetRoleListByUserIdSingleResponse.class));
- }
-
- /**
- * Get permission list by role id list
- *
- * @param payload the payload
- * @return the response body bean
- */
- public Mono> getPermissionListByRoleIdList(
- @Valid @NotNull GetPermissionListByRoleIdListPayload payload
- ) {
- return this.webClient
- .get()
- .uri(uriBuilder -> uriBuilder
- .host(SERVICE_NAME)
- .path("/permission-remote-api/permissions")
- .queryParam("roleIdList", StrUtil.join(",", payload.getRoleIdList()))
- .queryParam("permissionTypeList", StrUtil.join(",", payload.getPermissionTypeList()))
- .build())
- .retrieve()
- .bodyToMono(ResponseBodyBean.class)
- .map(ResponseBodyBean::getData)
- .map(data -> JSONUtil.toList(JSONUtil.parseObj(data).getJSONArray("permissionList"),
- GetPermissionListByRoleIdListResponse.Permission.class));
- }
-
- /**
- * Parse JWT.
- *
- * @param authorization the authorization
- * @return the mono
- */
- @GetMapping("/jwt-remote-api/parse")
- public Mono parse(@NotBlank String authorization) {
- return this.webClient
- .get()
- .uri("http://auth-center/jwt-remote-api/parse")
- .headers(httpHeaders -> httpHeaders.set(HttpHeaders.AUTHORIZATION, authorization))
- .retrieve()
- .bodyToMono(ResponseBodyBean.class).map(ResponseBodyBean::getData)
- .map(data -> JSONUtil.toBean(JSONUtil.parseObj(data), ParseJwtResponse.class));
- }
-}
diff --git a/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterWebClient.kt b/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterWebClient.kt
new file mode 100644
index 00000000..b19ef257
--- /dev/null
+++ b/api-gateway/api-gateway-infra/src/main/java/com/jmsoftware/maf/apigateway/remote/AuthCenterWebClient.kt
@@ -0,0 +1,121 @@
+package com.jmsoftware.maf.apigateway.remote
+
+import cn.hutool.json.JSONUtil
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.authcenter.permission.Permission
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse
+import org.springframework.http.HttpHeaders
+import org.springframework.stereotype.Service
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.reactive.function.client.WebClient
+import org.springframework.web.util.UriBuilder
+import reactor.core.publisher.Mono
+import javax.validation.Valid
+import javax.validation.constraints.Min
+import javax.validation.constraints.NotBlank
+import javax.validation.constraints.NotNull
+
+/**
+ * # AuthCenterWebClient
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 9:36 PM
+ */
+@Service
+@Validated
+@Suppress("HttpUrlsUsage")
+class AuthCenterWebClient(
+ private val webClient: WebClient
+) {
+ companion object {
+ private const val SERVICE_NAME = "auth-center"
+ }
+
+ /**
+ * Gets user by login token.
+ *
+ * @param loginToken the login token, e.q. username, email or phone number
+ * @return the user by login token
+ */
+ fun getUserByLoginToken(loginToken: @NotBlank String): Mono {
+ return webClient
+ .get()
+ .uri("http://$SERVICE_NAME/user-remote-api/users/{loginToken}", loginToken)
+ .retrieve()
+ .bodyToMono(ResponseBodyBean::class.java)
+ .mapNotNull(ResponseBodyBean<*>::data)
+ .map { data: Any? -> JSONUtil.toBean(JSONUtil.parseObj(data), GetUserByLoginTokenResponse::class.java) }
+ }
+
+ /**
+ * Gets role list by user id.
+ *
+ * @param userId the user id
+ * @return the role list by user id
+ */
+ fun getRoleListByUserId(userId: @NotNull @Min(1L) Long): Mono> {
+ return webClient
+ .get()
+ .uri("http://$SERVICE_NAME/role-remote-api/roles/{userId}", userId)
+ .retrieve()
+ .bodyToMono(ResponseBodyBean::class.java)
+ .mapNotNull(ResponseBodyBean<*>::data)
+ .map { data: Any? ->
+ JSONUtil.toList(
+ JSONUtil.parseObj(data).getJSONArray("roleList"),
+ GetRoleListByUserIdSingleResponse::class.java
+ )
+ }
+ }
+
+ /**
+ * Get permission list by role id list
+ *
+ * @param payload the payload
+ * @return the response body bean
+ */
+ fun getPermissionListByRoleIdList(
+ payload: @Valid @NotNull GetPermissionListByRoleIdListPayload
+ ): Mono> {
+ return webClient
+ .get()
+ .uri { uriBuilder: UriBuilder ->
+ uriBuilder
+ .host(SERVICE_NAME)
+ .path("/permission-remote-api/permissions")
+ .queryParam("roleIdList", payload.roleIdList.joinToString(","))
+ .queryParam("permissionTypeList", payload.permissionTypeList.joinToString(","))
+ .build()
+ }
+ .retrieve()
+ .bodyToMono(ResponseBodyBean::class.java)
+ .mapNotNull(ResponseBodyBean<*>::data)
+ .map { data: Any? ->
+ JSONUtil.toList(
+ JSONUtil.parseObj(data).getJSONArray("permissionList"),
+ Permission::class.java
+ )
+ }
+ }
+
+ /**
+ * Parse JWT.
+ *
+ * @param authorization the authorization
+ * @return the mono
+ */
+ fun parse(authorization: @NotBlank String): Mono {
+ return webClient
+ .get()
+ .uri("http://auth-center/jwt-remote-api/parse")
+ .headers { httpHeaders: HttpHeaders -> httpHeaders[HttpHeaders.AUTHORIZATION] = authorization }
+ .retrieve()
+ .bodyToMono(ResponseBodyBean::class.java)
+ .mapNotNull(ResponseBodyBean<*>::data)
+ .map { data: Any? -> JSONUtil.toBean(JSONUtil.parseObj(data), ParseJwtResponse::class.java) }
+ }
+}
diff --git a/api-gateway/api-gateway-infra/src/test/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-infra/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-infra/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-infra/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-infra/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..238d8d7a
--- /dev/null
+++ b/api-gateway/api-gateway-infra/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway
diff --git a/api-gateway/api-gateway-message/pom.xml b/api-gateway/api-gateway-message/pom.xml
index a1332911..4b881bbb 100644
--- a/api-gateway/api-gateway-message/pom.xml
+++ b/api-gateway/api-gateway-message/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
api-gateway
- 0.0.8.1
+ 0.0.9
diff --git a/api-gateway/api-gateway-message/src/main/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-message/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-message/src/main/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-message/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-message/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..238d8d7a
--- /dev/null
+++ b/api-gateway/api-gateway-message/src/main/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway
diff --git a/api-gateway/api-gateway-message/src/test/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-message/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-message/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-message/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-message/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..238d8d7a
--- /dev/null
+++ b/api-gateway/api-gateway-message/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway
diff --git a/api-gateway/api-gateway-web/pom.xml b/api-gateway/api-gateway-web/pom.xml
index 5d43cd7b..69bab109 100644
--- a/api-gateway/api-gateway-web/pom.xml
+++ b/api-gateway/api-gateway-web/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
api-gateway
- 0.0.8.1
+ 0.0.9
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/DiscoveryRouteConfiguration.java b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/DiscoveryRouteConfiguration.java
deleted file mode 100644
index dec84897..00000000
--- a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/DiscoveryRouteConfiguration.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.jmsoftware.maf.apigateway.configuration;
-
-import cn.hutool.core.util.ObjectUtil;
-import com.jmsoftware.maf.apigateway.property.RedisRateLimiterConfigurationProperties;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
-import org.springframework.cloud.gateway.filter.FilterDefinition;
-import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
-import reactor.core.publisher.Mono;
-
-import javax.annotation.PostConstruct;
-
-/**
- * Description: DiscoveryRouteConfiguration, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 2/7/2021 1:15 PM
- **/
-@Slf4j
-@Configuration
-@RequiredArgsConstructor
-public class DiscoveryRouteConfiguration {
- public static final String REQUEST_RATE_LIMITER_FILTER_NAME = "RequestRateLimiter";
- /**
- * The redis-rate-limiter.replenishRate
property is how many requests per second you want a user to
- * be allowed to do, without any dropped requests. This is the rate at which the token bucket is filled.
- */
- public static final String REPLENISH_RATE_KEY = "redis-rate-limiter.replenishRate";
- /**
- * The redis-rate-limiter.burstCapacity
property is the maximum number of requests a user is allowed
- * to do in a single second. This is the number of tokens the token bucket can hold. Setting this value to zero
- * blocks all requests.
- */
- public static final String BURST_CAPACITY_KEY = "redis-rate-limiter.burstCapacity";
- /**
- * The redis-rate-limiter.requestedTokens
property is how many tokens a request costs. This is the
- * number of tokens taken from the bucket for each request and defaults to 1
.
- */
- public static final String REQUESTED_TOKENS_KEY = "redis-rate-limiter.requestedTokens";
- private final DiscoveryLocatorProperties discoveryLocatorProperties;
- private final RedisRateLimiterConfigurationProperties redisRateLimiterConfigurationProperties;
-
- /**
- * Configure
- * The Redis RateLimiter
.
- *
- * The algorithm used is the Token Bucket Algorithm .
- *
- * Rate limits bellow 1 request/s
are accomplished by setting replenishRate
to the
- * wanted number of requests, requestedTokens
to the timespan in seconds and
- * burstCapacity
to the product of replenishRate
and requestedTokens
, e.g.
- * setting replenishRate=1
, requestedTokens=60
and burstCapacity=60
will
- * result in a limit of 1 request/min
.
- *
- * @see
- * The Redis RateLimiter
- */
- @PostConstruct
- void postConstruct() {
- val filter = new FilterDefinition();
- filter.setName(REQUEST_RATE_LIMITER_FILTER_NAME);
- filter.addArg(REPLENISH_RATE_KEY, this.redisRateLimiterConfigurationProperties.getReplenishRate());
- filter.addArg(BURST_CAPACITY_KEY, this.redisRateLimiterConfigurationProperties.getBurstCapacity());
- filter.addArg(REQUESTED_TOKENS_KEY, this.redisRateLimiterConfigurationProperties.getRequestedTokens());
- this.discoveryLocatorProperties.getFilters().add(filter);
- log.info("Added filter [{}] for discovery services, filters: {}", REQUEST_RATE_LIMITER_FILTER_NAME,
- this.discoveryLocatorProperties.getFilters());
- }
-
- @Bean
- @Primary
- public KeyResolver ipKeyResolver() {
- return exchange -> {
- val remoteAddress = exchange.getRequest().getRemoteAddress();
- if (ObjectUtil.isNotNull(remoteAddress)) {
- return Mono.just(remoteAddress.getHostName());
- }
- return Mono.just("unknown-address");
- };
- }
-}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/DiscoveryRouteConfiguration.kt b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/DiscoveryRouteConfiguration.kt
new file mode 100644
index 00000000..6cd8d302
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/DiscoveryRouteConfiguration.kt
@@ -0,0 +1,112 @@
+package com.jmsoftware.maf.apigateway.configuration
+
+import com.jmsoftware.maf.apigateway.property.RedisRateLimiterConfigurationProperties
+import com.jmsoftware.maf.common.util.logger
+import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties
+import org.springframework.cloud.gateway.filter.FilterDefinition
+import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.context.annotation.Primary
+import org.springframework.web.server.ServerWebExchange
+import reactor.core.publisher.Mono
+import javax.annotation.PostConstruct
+
+/**
+ * # DiscoveryRouteConfiguration
+ *
+ * Description: DiscoveryRouteConfiguration, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 10:19 PM
+ */
+@Configuration
+class DiscoveryRouteConfiguration(
+ private val discoveryLocatorProperties: DiscoveryLocatorProperties,
+ private val redisRateLimiterConfigurationProperties: RedisRateLimiterConfigurationProperties
+) {
+ companion object {
+ private val log = logger()
+ const val REQUEST_RATE_LIMITER_FILTER_NAME = "RequestRateLimiter"
+
+ /**
+ * The `redis-rate-limiter.replenishRate` property is how many requests per second you want a user to
+ * be allowed to do, without any dropped requests. This is the rate at which the token bucket is filled.
+ */
+ const val REPLENISH_RATE_KEY = "redis-rate-limiter.replenishRate"
+
+ /**
+ * The `redis-rate-limiter.burstCapacity` property is the maximum number of requests a user is allowed
+ * to do in a single second. This is the number of tokens the token bucket can hold. Setting this value to zero
+ * blocks all requests.
+ */
+ const val BURST_CAPACITY_KEY = "redis-rate-limiter.burstCapacity"
+
+ /**
+ * The `redis-rate-limiter.requestedTokens` property is how many tokens a request costs. This is the
+ * number of tokens taken from the bucket for each request and defaults to `1`.
+ */
+ const val REQUESTED_TOKENS_KEY = "redis-rate-limiter.requestedTokens"
+ }
+
+ /**
+ * Configure
+ * [The Redis `RateLimiter`](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-redis-ratelimiter).
+ *
+ * ## Algorithm
+ *
+ * The token bucket algorithm can be conceptually understood as follows:
+ *
+ * - A token is added to the bucket every 1 / r {\\displaystyle 1/r} ![1/r](https://wikimedia.org/api/rest_v1/media/math/render/svg/2ab96580d23ec5eff6bb0e666531eccb7a8035d6) seconds.
+ * - The bucket can hold at the most b {\\displaystyle b} ![b](https://wikimedia.org/api/rest_v1/media/math/render/svg/f11423fbb2e967f986e36804a8ae4271734917c3) tokens. If a token arrives when the bucket is full, it is discarded.
+ * - When a packet (network layer [PDU](https://en.wikipedia.org/wiki/Protocol_data_unit "Protocol data unit")) of _n_ bytes arrives,
+ * - if at least _n_ tokens are in the bucket, _n_ tokens are removed from the bucket, and the packet is sent to the network.
+ * - if fewer than _n_ tokens are available, no tokens are removed from the bucket, and the packet is considered to be _non-conformant_.
+ *
+ * ### Variations
+ *
+ * Implementers of this algorithm on platforms lacking the clock resolution necessary to add a single token to the bucket every 1 / r {\\displaystyle 1/r} ![1/r](https://wikimedia.org/api/rest_v1/media/math/render/svg/2ab96580d23ec5eff6bb0e666531eccb7a8035d6) seconds may want to consider an alternative formulation. Given the ability to update the token bucket every S milliseconds, the number of tokens to add every S milliseconds = ( r ∗ S ) / 1000 {\\displaystyle (r\*S)/1000} ![(r*S)/1000](https://wikimedia.org/api/rest_v1/media/math/render/svg/8346b25098bc785ea08018e719e9073e308d1bed) .
+ *
+ * ### Properties
+ *
+ * #### Average rate
+ *
+ * Over the long run the output of conformant packets is limited by the token rate, r {\\displaystyle r} ![r](https://wikimedia.org/api/rest_v1/media/math/render/svg/0d1ecb613aa2984f0576f70f86650b7c2a132538) .
+ *
+ * #### Burst size
+ *
+ * Let M {\\displaystyle M} ![M](https://wikimedia.org/api/rest_v1/media/math/render/svg/f82cade9898ced02fdd08712e5f0c0151758a0dd) be the maximum possible transmission rate in bytes/second.
+ *
+ * Then T max \= { b / ( M − r ) if r < M ∞ otherwise {\\displaystyle T\_{\\text{max}}={\\begin{cases}b/(M-r)&{\\text{ if }}rThe Redis RateLimiter
+ */
+ @PostConstruct
+ fun postConstruct() {
+ val filter = FilterDefinition()
+ filter.name = REQUEST_RATE_LIMITER_FILTER_NAME
+ filter.addArg(REPLENISH_RATE_KEY, redisRateLimiterConfigurationProperties.replenishRate)
+ filter.addArg(BURST_CAPACITY_KEY, redisRateLimiterConfigurationProperties.burstCapacity)
+ filter.addArg(REQUESTED_TOKENS_KEY, redisRateLimiterConfigurationProperties.requestedTokens)
+ discoveryLocatorProperties.filters.add(filter)
+ log.info("Added filter [$REQUEST_RATE_LIMITER_FILTER_NAME] for discovery services, filters: ${discoveryLocatorProperties.filters}")
+ }
+
+ @Bean
+ @Primary
+ fun ipKeyResolver(): KeyResolver {
+ return KeyResolver { exchange: ServerWebExchange ->
+ val remoteAddress = exchange.request.remoteAddress
+ if (remoteAddress != null) {
+ Mono.just(remoteAddress.hostName)
+ } else {
+ Mono.just("unknown-address")
+ }
+ }
+ }
+}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/OpenApiConfiguration.java b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/OpenApiConfiguration.java
deleted file mode 100644
index 9f2ac4ce..00000000
--- a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/OpenApiConfiguration.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.jmsoftware.maf.apigateway.configuration;
-
-import cn.hutool.core.collection.CollUtil;
-import com.jmsoftware.maf.apigateway.property.SwaggerConfigurationProperties;
-import com.jmsoftware.maf.reactivespringcloudstarter.property.MafProjectProperties;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Contact;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.info.License;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springdoc.core.AbstractSwaggerUiConfigProperties;
-import org.springdoc.core.GroupedOpenApi;
-import org.springdoc.core.SwaggerUiConfigProperties;
-import org.springframework.cloud.client.discovery.DiscoveryClient;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.util.List;
-
-/**
- * OpenApiConfiguration
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com, 2/1/22 11:51 PM
- **/
-@Slf4j
-@Configuration
-@RequiredArgsConstructor
-public class OpenApiConfiguration {
- private static final String SWAGGER_API_URI = "/v3/api-docs";
- private final SwaggerConfigurationProperties swaggerConfigurationProperties;
- private final SwaggerUiConfigProperties swaggerUiConfigProperties;
- private final MafProjectProperties mafProjectProperties;
- private final DiscoveryClient discoveryClient;
-
- @Bean
- public OpenAPI openApi() {
- val projectArtifactId = this.mafProjectProperties.getProjectArtifactId();
- val version = this.mafProjectProperties.getVersion();
- val developerEmail = this.mafProjectProperties.getDeveloperEmail();
- val developerUrl = this.mafProjectProperties.getDeveloperUrl();
- return new OpenAPI()
- .info(
- new Info()
- .title(String.format("API for %s@%s", projectArtifactId, version))
- .description(
- String.format("%s, artifact ID: %s, environment: %s",
- this.mafProjectProperties.getDescription(),
- projectArtifactId,
- this.mafProjectProperties.getEnvironment())
- )
- .contact(
- new Contact()
- .name(this.mafProjectProperties.getDeveloperName())
- .email(developerEmail)
- .url(developerUrl)
- )
- .version(version)
- .license(new License().name("LinkedIn").url(developerUrl))
- );
- }
-
- @Bean
- public List groupedOpenApiList() {
- val services = CollUtil.newArrayList(this.discoveryClient.getServices());
- services.add(this.mafProjectProperties.getProjectArtifactId());
- val groups = CollUtil.newArrayList();
- this.swaggerUiConfigProperties.setUrls(CollUtil.newHashSet());
- services.forEach(serviceName -> {
- if (!CollUtil.contains(this.swaggerConfigurationProperties.getIgnoredServiceIds(), serviceName)) {
- log.warn("Found discovery client. Service name: {}", serviceName);
- groups.add(GroupedOpenApi.builder().pathsToMatch("/" + serviceName + "/**").group(serviceName).build());
- val swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl();
- swaggerUrl.setUrl(serviceName + SWAGGER_API_URI);
- swaggerUrl.setName(serviceName);
- this.swaggerUiConfigProperties.getUrls().add(swaggerUrl);
- }
- });
- return groups;
- }
-}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/OpenApiConfiguration.kt b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/OpenApiConfiguration.kt
new file mode 100644
index 00000000..92cedeea
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/OpenApiConfiguration.kt
@@ -0,0 +1,79 @@
+package com.jmsoftware.maf.apigateway.configuration
+
+import cn.hutool.core.collection.CollUtil
+import com.jmsoftware.maf.apigateway.property.SwaggerConfigurationProperties
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.reactivespringcloudstarter.property.MafProjectProperties
+import io.swagger.v3.oas.models.OpenAPI
+import io.swagger.v3.oas.models.info.Contact
+import io.swagger.v3.oas.models.info.Info
+import io.swagger.v3.oas.models.info.License
+import org.springdoc.core.AbstractSwaggerUiConfigProperties.SwaggerUrl
+import org.springdoc.core.GroupedOpenApi
+import org.springdoc.core.SwaggerUiConfigProperties
+import org.springframework.cloud.client.discovery.DiscoveryClient
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+
+/**
+ * OpenApiConfiguration
+ *
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com, 2/1/22 11:51 PM
+ */
+@Configuration
+class OpenApiConfiguration(
+ private val swaggerConfigurationProperties: SwaggerConfigurationProperties,
+ private val swaggerUiConfigProperties: SwaggerUiConfigProperties,
+ private val mafProjectProperties: MafProjectProperties,
+ private val discoveryClient: DiscoveryClient
+) {
+ companion object {
+ private const val SWAGGER_API_URI = "/v3/api-docs"
+ private val log = logger()
+ }
+
+ @Bean
+ fun openApi(): OpenAPI {
+ val projectArtifactId = mafProjectProperties.projectArtifactId
+ val version = mafProjectProperties.version
+ val developerEmail = mafProjectProperties.developerEmail
+ val developerUrl = mafProjectProperties.developerUrl
+ return OpenAPI()
+ .info(
+ Info()
+ .title("API for $projectArtifactId@$version")
+ .description("$mafProjectProperties.description, artifact ID: $projectArtifactId, environment: ${mafProjectProperties.environment}")
+ .contact(
+ Contact()
+ .name(mafProjectProperties.developerName)
+ .email(developerEmail)
+ .url(developerUrl)
+ )
+ .version(version)
+ .license(License().name("LinkedIn").url(developerUrl))
+ )
+ }
+
+ @Bean
+ fun groupedOpenApiList(): List {
+ val groups = mutableListOf()
+ swaggerUiConfigProperties.urls = mutableSetOf()
+ mutableListOf().apply {
+ this.addAll(discoveryClient.services)
+ this.add(mafProjectProperties.projectArtifactId)
+ }.forEach { serviceName: String ->
+ if (!CollUtil.contains(swaggerConfigurationProperties.ignoredServiceIds, serviceName)) {
+ log.warn("Found discovery client. Service name: $serviceName")
+ groups.add(GroupedOpenApi.builder().pathsToMatch("/$serviceName/**").group(serviceName).build())
+ val swaggerUrl = SwaggerUrl()
+ swaggerUrl.url = serviceName + SWAGGER_API_URI
+ swaggerUrl.name = serviceName
+ swaggerUiConfigProperties.urls.add(swaggerUrl)
+ }
+ }
+ return groups
+ }
+}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/RedirectConfiguration.java b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/RedirectConfiguration.java
deleted file mode 100644
index 844d927c..00000000
--- a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/RedirectConfiguration.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.jmsoftware.maf.apigateway.configuration;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.reactive.function.server.RouterFunction;
-import org.springframework.web.reactive.function.server.ServerResponse;
-
-import javax.annotation.PostConstruct;
-import java.net.URI;
-
-import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
-import static org.springframework.web.reactive.function.server.RouterFunctions.route;
-
-/**
- * RedirectConfiguration
- *
- * Redirect Configuration.
- *
- * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
- * @date 2/15/20 11:54 PM
- **/
-@Slf4j
-@Configuration
-public class RedirectConfiguration {
- @PostConstruct
- private void postConstruct() {
- log.info("URL redirect service initialized.");
- }
-
- @Bean
- public RouterFunction home() {
- return route(GET("/"), request -> {
- log.info("Redirect to Home page.");
- return ServerResponse.temporaryRedirect(URI.create("/static/home.html")).build();
- });
- }
-
- @Bean
- public RouterFunction doc() {
- return route(GET("/doc"), request -> {
- log.info("Redirect to Bootstrap Swagger API documentation.");
- return ServerResponse.temporaryRedirect(URI.create("/doc.html")).build();
- });
- }
-
- @Bean
- public RouterFunction favicon() {
- return route(GET("/favicon.ico"), request -> {
- log.info("Redirect to favicon.");
- return ServerResponse.temporaryRedirect(URI.create("/static/asset/favicon.ico")).build();
- });
- }
-}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/RedirectConfiguration.kt b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/RedirectConfiguration.kt
new file mode 100644
index 00000000..6735b318
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/RedirectConfiguration.kt
@@ -0,0 +1,54 @@
+package com.jmsoftware.maf.apigateway.configuration
+
+import com.jmsoftware.maf.common.util.logger
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.web.reactive.function.server.RequestPredicates
+import org.springframework.web.reactive.function.server.RouterFunction
+import org.springframework.web.reactive.function.server.RouterFunctions
+import org.springframework.web.reactive.function.server.ServerResponse
+import java.net.URI
+import javax.annotation.PostConstruct
+
+/**
+ * # RedirectConfiguration
+ *
+ * Redirect Configuration.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 10:31 PM
+ */
+@Configuration
+class RedirectConfiguration {
+ companion object {
+ private val log = logger()
+ }
+
+ @PostConstruct
+ private fun postConstruct() {
+ log.info("URL redirect service initialized.")
+ }
+
+ @Bean
+ fun home(): RouterFunction {
+ return RouterFunctions.route(RequestPredicates.GET("/")) {
+ log.info("Redirect to Home page.")
+ ServerResponse.temporaryRedirect(URI.create("/static/home.html")).build()
+ }
+ }
+
+ @Bean
+ fun doc(): RouterFunction {
+ return RouterFunctions.route(RequestPredicates.GET("/doc")) {
+ log.info("Redirect to Bootstrap Swagger API documentation.")
+ ServerResponse.temporaryRedirect(URI.create("/doc.html")).build()
+ }
+ }
+
+ @Bean
+ fun favicon(): RouterFunction {
+ return RouterFunctions.route(RequestPredicates.GET("/favicon.ico")) {
+ log.info("Redirect to favicon.")
+ ServerResponse.temporaryRedirect(URI.create("/static/asset/favicon.ico")).build()
+ }
+ }
+}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/WebFluxSecurityConfiguration.java b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/WebFluxSecurityConfiguration.java
deleted file mode 100644
index 2c029700..00000000
--- a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/WebFluxSecurityConfiguration.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.jmsoftware.maf.apigateway.configuration;
-
-import cn.hutool.core.util.BooleanUtil;
-import com.google.common.collect.Lists;
-import com.jmsoftware.maf.apigateway.remote.AuthCenterRemoteApi;
-import com.jmsoftware.maf.apigateway.security.impl.*;
-import com.jmsoftware.maf.reactivespringcloudstarter.property.MafConfigurationProperties;
-import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.authentication.ReactiveAuthenticationManager;
-import org.springframework.security.authorization.ReactiveAuthorizationManager;
-import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
-import org.springframework.security.config.web.server.ServerHttpSecurity;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.web.server.SecurityWebFilterChain;
-import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
-import org.springframework.security.web.server.authorization.AuthorizationContext;
-import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
-import org.springframework.security.web.server.context.ServerSecurityContextRepository;
-
-/**
- * Description: WebFluxSecurityConfiguration, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/18/2020 3:23 PM
- * @see
- * Spring Secirity Reference - Reactive Applications
- * @see
- * Securing Spring WebFlux Reactive APIs with JWT Auth
- * @see
- * SpringCloud Gateway 整合 Spring Security Webflux 的关键点(痛点解析),及示例项目
- **/
-@Slf4j
-@Configuration
-@EnableWebFluxSecurity
-@RequiredArgsConstructor
-public class WebFluxSecurityConfiguration {
- private final MafConfigurationProperties mafConfigurationProperties;
- private final AuthCenterRemoteApi authCenterRemoteApi;
-
- @Bean
- SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http,
- ServerAuthenticationEntryPoint serverAuthenticationEntryPoint,
- ServerAccessDeniedHandler serverAccessDeniedHandler,
- ServerSecurityContextRepository serverSecurityContextRepository,
- ReactiveAuthenticationManager reactiveAuthenticationManager,
- ReactiveAuthorizationManager reactiveAuthorizationManager) {
- if (BooleanUtil.isFalse(this.mafConfigurationProperties.getWebSecurityEnabled())) {
- log.warn("Web security was disabled.");
- return http
- .cors().disable()
- .csrf().disable()
- .build();
- }
- log.warn("Spring Security will ignore following URLs: {}",
- Lists.newArrayList(this.mafConfigurationProperties.flattenIgnoredUrls()));
- return http
- .cors().disable()
- .csrf().disable()
- .formLogin().disable()
- .httpBasic().disable()
- .exceptionHandling()
- .authenticationEntryPoint(serverAuthenticationEntryPoint)
- .accessDeniedHandler(serverAccessDeniedHandler)
- .and()
- // Authentication
- .securityContextRepository(serverSecurityContextRepository)
- .authenticationManager(reactiveAuthenticationManager)
- .authorizeExchange()
- .pathMatchers(this.mafConfigurationProperties.flattenIgnoredUrls()).permitAll()
- .pathMatchers(HttpMethod.OPTIONS).permitAll()
- // Authorization
- .anyExchange().access(reactiveAuthorizationManager)
- .and()
- .build();
- }
-
- @Bean
- public ServerAuthenticationEntryPoint serverAuthenticationEntryPoint(ResponseUtil responseUtil) {
- return new ServerAuthenticationEntryPointImpl(responseUtil);
- }
-
- @Bean
- public ServerAccessDeniedHandler serverAccessDeniedHandler(ResponseUtil responseUtil) {
- return new GatewayServerAccessDeniedHandlerImpl(responseUtil);
- }
-
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
-
- @Bean
- public ServerSecurityContextRepository serverSecurityContextRepository(ReactiveAuthenticationManager reactiveAuthenticationManager) {
- return new JwtReactiveServerSecurityContextRepositoryImpl(this.mafConfigurationProperties, reactiveAuthenticationManager,
- this.authCenterRemoteApi);
- }
-
- @Bean
- public ReactiveAuthenticationManager reactiveAuthenticationManager() {
- return new JwtReactiveAuthenticationManagerImpl(this.authCenterRemoteApi);
- }
-
- @Bean
- public ReactiveAuthorizationManager reactiveAuthorizationManager() {
- return new RbacReactiveAuthorizationManagerImpl(this.authCenterRemoteApi);
- }
-}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/WebFluxSecurityConfiguration.kt b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/WebFluxSecurityConfiguration.kt
new file mode 100644
index 00000000..f1f9c7bb
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/configuration/WebFluxSecurityConfiguration.kt
@@ -0,0 +1,118 @@
+package com.jmsoftware.maf.apigateway.configuration
+
+import cn.hutool.core.util.BooleanUtil
+import com.jmsoftware.maf.apigateway.remote.AuthCenterWebClientService
+import com.jmsoftware.maf.apigateway.security.impl.*
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.reactivespringcloudstarter.property.MafConfigurationProperties
+import com.jmsoftware.maf.reactivespringcloudstarter.util.ResponseUtil
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.http.HttpMethod
+import org.springframework.security.authentication.ReactiveAuthenticationManager
+import org.springframework.security.authorization.ReactiveAuthorizationManager
+import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
+import org.springframework.security.config.web.server.ServerHttpSecurity
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
+import org.springframework.security.crypto.password.PasswordEncoder
+import org.springframework.security.web.server.SecurityWebFilterChain
+import org.springframework.security.web.server.ServerAuthenticationEntryPoint
+import org.springframework.security.web.server.authorization.AuthorizationContext
+import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler
+import org.springframework.security.web.server.context.ServerSecurityContextRepository
+
+/**
+ * # WebFluxSecurityConfiguration
+ *
+ * Description: WebFluxSecurityConfiguration, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/17/22 7:52 AM
+ * @see Kotlin Configuration
+ * @see
+ * Spring Secirity Reference - Reactive Applications
+ * @see
+ * Securing Spring WebFlux Reactive APIs with JWT Auth
+ * @see
+ * SpringCloud Gateway 整合 Spring Security Webflux 的关键点(痛点解析),及示例项目
+ */
+@Configuration
+@EnableWebFluxSecurity
+class WebFluxSecurityConfiguration(
+ private val mafConfigurationProperties: MafConfigurationProperties,
+ private val authCenterWebClientService: AuthCenterWebClientService
+) {
+ companion object {
+ private val log = logger()
+ }
+
+ @Bean
+ fun springWebFilterChain(
+ http: ServerHttpSecurity,
+ serverAuthenticationEntryPoint: ServerAuthenticationEntryPoint,
+ serverAccessDeniedHandler: ServerAccessDeniedHandler,
+ serverSecurityContextRepository: ServerSecurityContextRepository,
+ reactiveAuthenticationManager: ReactiveAuthenticationManager,
+ reactiveAuthorizationManager: ReactiveAuthorizationManager
+ ): SecurityWebFilterChain {
+ if (BooleanUtil.isFalse(mafConfigurationProperties.webSecurityEnabled)) {
+ log.warn("Web security was disabled.")
+ return http
+ .cors().disable()
+ .csrf().disable()
+ .build()
+ }
+ val ignoredUrls = mafConfigurationProperties.flattenIgnoredUrls().toTypedArray()
+ log.warn("Spring Security will ignore following URLs: $ignoredUrls")
+ return http
+ .cors().disable()
+ .csrf().disable()
+ .formLogin().disable()
+ .httpBasic().disable()
+ .exceptionHandling()
+ .authenticationEntryPoint(serverAuthenticationEntryPoint)
+ .accessDeniedHandler(serverAccessDeniedHandler)
+ .and() // Authentication
+ .securityContextRepository(serverSecurityContextRepository)
+ .authenticationManager(reactiveAuthenticationManager)
+ .authorizeExchange()
+ .pathMatchers(*ignoredUrls).permitAll()
+ .pathMatchers(HttpMethod.OPTIONS).permitAll() // Authorization
+ .anyExchange().access(reactiveAuthorizationManager)
+ .and()
+ .build()
+ }
+
+ @Bean
+ fun serverAuthenticationEntryPoint(responseUtil: ResponseUtil): ServerAuthenticationEntryPoint {
+ return ServerAuthenticationEntryPointImpl(responseUtil)
+ }
+
+ @Bean
+ fun serverAccessDeniedHandler(responseUtil: ResponseUtil): ServerAccessDeniedHandler {
+ return GatewayServerAccessDeniedHandlerImpl(responseUtil)
+ }
+
+ @Bean
+ fun passwordEncoder(): PasswordEncoder {
+ return BCryptPasswordEncoder()
+ }
+
+ @Bean
+ fun serverSecurityContextRepository(reactiveAuthenticationManager: ReactiveAuthenticationManager): ServerSecurityContextRepository {
+ return JwtReactiveServerSecurityContextRepositoryImpl(
+ mafConfigurationProperties,
+ reactiveAuthenticationManager,
+ authCenterWebClientService
+ )
+ }
+
+ @Bean
+ fun reactiveAuthenticationManager(): ReactiveAuthenticationManager {
+ return JwtReactiveAuthenticationManagerImpl(authCenterWebClientService)
+ }
+
+ @Bean
+ fun reactiveAuthorizationManager(): ReactiveAuthorizationManager {
+ return RbacReactiveAuthorizationManagerImpl(authCenterWebClientService)
+ }
+}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/handler/GlobalExceptionHandler.java b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/handler/GlobalExceptionHandler.java
deleted file mode 100644
index c366c6d6..00000000
--- a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/handler/GlobalExceptionHandler.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.jmsoftware.maf.apigateway.handler;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import com.jmsoftware.maf.reactivespringcloudstarter.util.RequestUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
-import org.springframework.core.annotation.Order;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.server.reactive.ServerHttpResponse;
-import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.client.WebClientResponseException;
-import org.springframework.web.server.ResponseStatusException;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-import java.nio.charset.StandardCharsets;
-
-/**
- * GlobalExceptionHandler
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 12/23/20 7:45 AM
- **/
-@Slf4j
-@Order(-1)
-@Component
-@RequiredArgsConstructor
-public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
- private final ObjectMapper objectMapper;
-
- @Override
- @SuppressWarnings("NullableProblems")
- public Mono handle(ServerWebExchange exchange, Throwable ex) {
- val request = exchange.getRequest();
- log.error("Exception occurred when [{}] requested access. Exception message: {}. Request URL: [{}] {}",
- RequestUtil.getRequesterIpAndPort(request), ex.getMessage(), request.getMethod(), request.getURI());
- val response = exchange.getResponse();
- if (response.isCommitted()) {
- return Mono.error(ex);
- }
- // Set HTTP header, major browsers like Chrome now comply with the specification and interpret correctly
- // UTF-8 special characters without requiring a charset=UTF-8 parameter.
- response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
- return response.writeWith(Mono.fromSupplier(() -> {
- val bufferFactory = response.bufferFactory();
- val responseBody = setResponseBody(response, ex);
- try {
- return bufferFactory.wrap(objectMapper.writeValueAsBytes(responseBody));
- } catch (JsonProcessingException e) {
- log.warn("Exception occurred when writing response", e);
- return bufferFactory.wrap(e.getMessage().getBytes(StandardCharsets.UTF_8));
- }
- }));
- }
-
- /**
- * Sets response body.
- *
- * @param response the response
- * @param ex the ex
- * @return the response body
- */
- private ResponseBodyBean> setResponseBody(ServerHttpResponse response, Throwable ex) {
- if (ex instanceof ResponseStatusException) {
- response.setStatusCode(((ResponseStatusException) ex).getStatus());
- return ResponseBodyBean.ofStatus(((ResponseStatusException) ex).getStatus());
- } else if (ex instanceof SecurityException) {
- HttpStatus status = HttpStatus.valueOf(((SecurityException) ex).getCode());
- response.setStatusCode(status);
- return ResponseBodyBean.ofStatus(status, ex.getMessage());
- } else if (ex instanceof WebClientResponseException) {
- val exception = (WebClientResponseException) ex;
- response.setStatusCode(exception.getStatusCode());
- try {
- return objectMapper.readValue(exception.getResponseBodyAsString(), ResponseBodyBean.class);
- } catch (JsonProcessingException e) {
- log.warn("Exception occurred when writing response. Exception message: {}", e.getMessage());
- return ResponseBodyBean.ofStatus(exception.getStatusCode(),
- exception.getResponseBodyAsString(StandardCharsets.UTF_8));
- }
- }
- response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
- return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
- String.format("Exception message: %s", ex.getMessage()));
- }
-}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/handler/GlobalExceptionHandler.kt b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/handler/GlobalExceptionHandler.kt
new file mode 100644
index 00000000..d3741528
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/handler/GlobalExceptionHandler.kt
@@ -0,0 +1,88 @@
+package com.jmsoftware.maf.apigateway.handler
+
+import com.fasterxml.jackson.core.JsonProcessingException
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.reactivespringcloudstarter.util.getRequesterIpAndPort
+import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler
+import org.springframework.core.annotation.Order
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.http.server.reactive.ServerHttpResponse
+import org.springframework.stereotype.Component
+import org.springframework.web.reactive.function.client.WebClientResponseException
+import org.springframework.web.server.ResponseStatusException
+import org.springframework.web.server.ServerWebExchange
+import reactor.core.publisher.Mono
+import java.nio.charset.StandardCharsets
+
+/**
+ * # GlobalExceptionHandler
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, 4/16/22 11:49 AM
+ **/
+@Order(-1)
+@Component
+class GlobalExceptionHandler(
+ private val objectMapper: ObjectMapper
+) : ErrorWebExceptionHandler {
+ companion object {
+ private val log = logger()
+ }
+
+ override fun handle(exchange: ServerWebExchange, ex: Throwable): Mono {
+ val request = exchange.request
+ log.error("Exception occurred when [${getRequesterIpAndPort(request)}] requested access. Exception message: ${ex.message}. Request URL: [${request.method}] ${request.uri}")
+ val response = exchange.response
+ if (response.isCommitted) {
+ return Mono.error(ex)
+ }
+ // Set HTTP header, major browsers like Chrome now comply with the specification and interpret correctly
+ // UTF-8 special characters without requiring a charset=UTF-8 parameter.
+ response.headers.contentType = MediaType.APPLICATION_JSON
+ return response.writeWith(Mono.fromSupplier {
+ val bufferFactory = response.bufferFactory()
+ val responseBody: ResponseBodyBean<*> = setResponseBody(response, ex)
+ try {
+ return@fromSupplier bufferFactory.wrap(objectMapper.writeValueAsBytes(responseBody))
+ } catch (e: JsonProcessingException) {
+ log.warn("Exception occurred when writing response", e)
+ return@fromSupplier bufferFactory.wrap(e.message!!.toByteArray(StandardCharsets.UTF_8))
+ }
+ })
+ }
+
+ private fun setResponseBody(response: ServerHttpResponse, ex: Throwable): ResponseBodyBean<*> {
+ when (ex) {
+ is ResponseStatusException -> {
+ response.statusCode = ex.status
+ return ResponseBodyBean.ofStatus(ex.status)
+ }
+ is SecurityException -> {
+ val status = HttpStatus.valueOf(ex.code)
+ response.statusCode = status
+ return ResponseBodyBean.ofStatus(status, ex.message)
+ }
+ is WebClientResponseException -> {
+ response.statusCode = ex.statusCode
+ return try {
+ objectMapper.readValue(ex.responseBodyAsString, ResponseBodyBean::class.java)
+ } catch (e: JsonProcessingException) {
+ log.warn("Exception occurred when writing response. Exception message: ${e.message}")
+ ResponseBodyBean.ofStatus(ex.statusCode, ex.getResponseBodyAsString(StandardCharsets.UTF_8))
+ }
+ }
+ else -> {
+ response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR
+ return ResponseBodyBean.ofStatus(
+ HttpStatus.INTERNAL_SERVER_ERROR,
+ "Exception message: ${ex.message}"
+ )
+ }
+ }
+ }
+}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/RedisRateLimiterConfigurationProperties.java b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/RedisRateLimiterConfigurationProperties.java
deleted file mode 100644
index 899a9b67..00000000
--- a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/RedisRateLimiterConfigurationProperties.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.jmsoftware.maf.apigateway.property;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.validation.annotation.Validated;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * RedisRateLimiterConfigurationProperties
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 3/1/2021 9:59 AM
- */
-@Data
-@Validated
-@RefreshScope
-@Configuration
-@ConfigurationProperties(prefix = RedisRateLimiterConfigurationProperties.PREFIX)
-public class RedisRateLimiterConfigurationProperties {
- /**
- * The constant PREFIX.
- */
- public static final String PREFIX = "maf.configuration.redis-rate-limiter";
- /**
- * The Replenish rate.
- */
- @NotBlank
- private String replenishRate;
- /**
- * The Burst capacity.
- */
- @NotBlank
- private String burstCapacity;
- /**
- * The Requested tokens.
- */
- @NotBlank
- private String requestedTokens;
-}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/RedisRateLimiterConfigurationProperties.kt b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/RedisRateLimiterConfigurationProperties.kt
new file mode 100644
index 00000000..6897a0b0
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/RedisRateLimiterConfigurationProperties.kt
@@ -0,0 +1,40 @@
+package com.jmsoftware.maf.apigateway.property
+
+import org.springframework.boot.context.properties.ConfigurationProperties
+import org.springframework.cloud.context.config.annotation.RefreshScope
+import org.springframework.context.annotation.Configuration
+import org.springframework.validation.annotation.Validated
+import javax.validation.constraints.NotBlank
+
+/**
+ * # RedisRateLimiterConfigurationProperties
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 10:34 PM
+ */
+@Validated
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = RedisRateLimiterConfigurationProperties.PREFIX)
+class RedisRateLimiterConfigurationProperties {
+ companion object {
+ /**
+ * The constant PREFIX.
+ */
+ const val PREFIX = "maf.configuration.redis-rate-limiter"
+ }
+
+ /**
+ * The Replenish rate.
+ */
+ lateinit var replenishRate: @NotBlank String
+
+ /**
+ * The Burst capacity.
+ */
+ lateinit var burstCapacity: @NotBlank String
+
+ /**
+ * The Requested tokens.
+ */
+ lateinit var requestedTokens: @NotBlank String
+}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/SwaggerConfigurationProperties.java b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/SwaggerConfigurationProperties.java
deleted file mode 100644
index dda03fe0..00000000
--- a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/SwaggerConfigurationProperties.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.jmsoftware.maf.apigateway.property;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.validation.annotation.Validated;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotEmpty;
-import java.util.Set;
-
-/**
- * SwaggerConfigurationProperties
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 2/7/2021 3:28 PM
- **/
-@Data
-@Validated
-@RefreshScope
-@Configuration
-@ConfigurationProperties(prefix = SwaggerConfigurationProperties.PREFIX)
-public class SwaggerConfigurationProperties {
- public static final String PREFIX = "maf.configuration.swagger";
- /**
- * Ignored service id set
- */
- @NotEmpty
- private Set<@NotBlank String> ignoredServiceIds;
-}
diff --git a/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/SwaggerConfigurationProperties.kt b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/SwaggerConfigurationProperties.kt
new file mode 100644
index 00000000..73a5f3a9
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/main/java/com/jmsoftware/maf/apigateway/property/SwaggerConfigurationProperties.kt
@@ -0,0 +1,27 @@
+package com.jmsoftware.maf.apigateway.property
+
+import org.springframework.boot.context.properties.ConfigurationProperties
+import org.springframework.cloud.context.config.annotation.RefreshScope
+import org.springframework.context.annotation.Configuration
+import org.springframework.validation.annotation.Validated
+import javax.validation.constraints.NotEmpty
+
+/**
+ * SwaggerConfigurationProperties
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 2/7/2021 3:28 PM
+ */
+@Validated
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = SwaggerConfigurationProperties.PREFIX)
+class SwaggerConfigurationProperties {
+ companion object {
+ const val PREFIX = "maf.configuration.swagger"
+ }
+
+ /**
+ * Ignored service id set
+ */
+ lateinit var ignoredServiceIds: @NotEmpty Set
+}
diff --git a/api-gateway/api-gateway-web/src/test/java/com/jmsoftware/maf/apigateway/package-info.java b/api-gateway/api-gateway-web/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
deleted file mode 100644
index 1f6f99b5..00000000
--- a/api-gateway/api-gateway-web/src/test/java/com/jmsoftware/maf/apigateway/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.apigateway;
diff --git a/api-gateway/api-gateway-web/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt b/api-gateway/api-gateway-web/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
new file mode 100644
index 00000000..238d8d7a
--- /dev/null
+++ b/api-gateway/api-gateway-web/src/test/java/com/jmsoftware/maf/apigateway/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.apigateway
diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml
index 89851117..de1daff0 100644
--- a/api-gateway/pom.xml
+++ b/api-gateway/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
muscle-and-fitness-server
- 0.0.8.1
+ 0.0.9
pom
@@ -82,17 +82,6 @@
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
-
-
-
io.projectreactor
reactor-test
diff --git a/auth-center/auth-center-biz/pom.xml b/auth-center/auth-center-biz/pom.xml
index b07a966c..e9b53ca2 100644
--- a/auth-center/auth-center-biz/pom.xml
+++ b/auth-center/auth-center-biz/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
auth-center
- 0.0.8.1
+ 0.0.9
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.java
deleted file mode 100644
index 73567962..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission.configuration;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.validation.annotation.Validated;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotEmpty;
-import java.util.Set;
-
-/**
- * Description: PermissionConfiguration, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 2/8/2021 5:18 PM
- **/
-@Data
-@Validated
-@RefreshScope
-@Configuration
-@ConfigurationProperties(prefix = PermissionConfiguration.PREFIX)
-public class PermissionConfiguration {
- public static final String PREFIX = "maf.configuration.permission";
- @NotEmpty
- private Set<@NotBlank String> ignoredServiceIds;
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/package-info.kt b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/package-info.kt
new file mode 100644
index 00000000..9bd0fd89
--- /dev/null
+++ b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.permission
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.java
deleted file mode 100644
index 53abc5c9..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse;
-import com.jmsoftware.maf.authcenter.permission.persistence.Permission;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
-import com.jmsoftware.maf.common.exception.BizException;
-import org.springframework.validation.annotation.Validated;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotEmpty;
-import java.util.List;
-
-/**
- * PermissionService
- *
- * Service of Permission.(Permission)
- *
- * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
- * @date 5 /11/20 8:34 AM
- */
-@Validated
-public interface PermissionService extends IService {
- /**
- * Gets permission list by role id list.
- *
- * @param payload the payload
- * @return the permission list by role id list
- */
- GetPermissionListByRoleIdListResponse getPermissionListByRoleIdList(@Valid GetPermissionListByRoleIdListPayload payload);
-
- /**
- * Gets permission list by role id list.
- *
- * @param roleIdList the role id list
- * @param permissionTypeList the permission type list
- * @return the permission list by role id list
- */
- List getPermissionListByRoleIdList(@NotEmpty List roleIdList,
- @NotEmpty List permissionTypeList);
-
- /**
- * Gets services info.
- *
- * @return the services info
- * @throws BizException the business exception
- */
- GetServicesInfoResponse getServicesInfo() throws BizException;
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.kt b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.kt
new file mode 100644
index 00000000..60a37997
--- /dev/null
+++ b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionService.kt
@@ -0,0 +1,33 @@
+package com.jmsoftware.maf.authcenter.permission.service
+
+import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse
+import org.springframework.validation.annotation.Validated
+import javax.validation.Valid
+import javax.validation.constraints.NotNull
+
+/**
+ * Description: PermissionServiceImpl, change description here.
+ *
+ * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com, date: 2/18/2022 11:22 PM
+ **/
+@Validated
+interface PermissionService {
+ /**
+ * Gets permission list by role id list.
+ *
+ * @param payload the payload
+ * @return the permission list by role id list
+ */
+ fun getPermissionListByRoleIdList(
+ payload: @Valid @NotNull GetPermissionListByRoleIdListPayload
+ ): GetPermissionListByRoleIdListResponse
+
+ /**
+ * Gets services info.
+ *
+ * @return the services info
+ */
+ fun getServicesInfo(): GetServicesInfoResponse
+}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.java
deleted file mode 100644
index 391976d6..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission.service.impl;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.collection.CollUtil;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.jmsoftware.maf.authcenter.permission.configuration.PermissionConfiguration;
-import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse;
-import com.jmsoftware.maf.authcenter.permission.persistence.Permission;
-import com.jmsoftware.maf.authcenter.permission.mapper.PermissionMapper;
-import com.jmsoftware.maf.authcenter.permission.service.PermissionService;
-import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
-import com.jmsoftware.maf.common.domain.springbootstarter.HttpApiResourcesResponse;
-import com.jmsoftware.maf.common.exception.BizException;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.cloud.client.discovery.DiscoveryClient;
-import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestTemplate;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotEmpty;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * PermissionServiceImpl
- *
- * Service implementation of Permission.(Permission)
- *
- * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
- * @date 5/11/20 8:34 AM
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class PermissionServiceImpl
- extends ServiceImpl
- implements PermissionService {
- private final RoleService roleService;
- private final DiscoveryClient discoveryClient;
- private final RestTemplate restTemplate;
- private final PermissionConfiguration permissionConfiguration;
-
- @Override
- public GetPermissionListByRoleIdListResponse getPermissionListByRoleIdList(@Valid GetPermissionListByRoleIdListPayload payload) {
- val adminRole = this.roleService.checkAdmin(payload.getRoleIdList());
- val response = new GetPermissionListByRoleIdListResponse();
- if (adminRole) {
- log.warn("Admin role checked. The role can access any resources");
- val permission = new GetPermissionListByRoleIdListResponse.Permission();
- permission.setUrl("/**");
- permission.setType(PermissionType.BUTTON.getType());
- permission.setPermissionExpression("admin-permission");
- permission.setMethod("*");
- response.getPermissionList().add(permission);
- return response;
- }
- val permissionList = this.getPermissionListByRoleIdList(payload.getRoleIdList(),
- payload.getPermissionTypeList());
- permissionList.forEach(permissionPersistence -> {
- val permission = new GetPermissionListByRoleIdListResponse.Permission();
- BeanUtil.copyProperties(permissionPersistence, permission);
- response.getPermissionList().add(permission);
- });
- return response;
- }
-
- @Override
- public List getPermissionListByRoleIdList(@NotEmpty List roleIdList,
- @NotEmpty List permissionTypeList) {
- return this.getBaseMapper().selectPermissionListByRoleIdList(roleIdList, permissionTypeList);
- }
-
- @Override
- public GetServicesInfoResponse getServicesInfo() throws BizException {
- val serviceIdList = this.discoveryClient.getServices();
- log.info("Getting service info from Service ID list: {}", serviceIdList);
- val response = new GetServicesInfoResponse();
- val mapper = new ObjectMapper();
- log.info("Ignored service ID: {}", this.permissionConfiguration.getIgnoredServiceIds());
- for (String serviceId : serviceIdList) {
- if (CollUtil.contains(this.permissionConfiguration.getIgnoredServiceIds(), serviceId)) {
- log.warn("Ignored service ID: {}", serviceId);
- continue;
- }
- ResponseBodyBean> responseBodyBean = Optional.ofNullable(this.restTemplate.getForObject(
- String.format("http://%s/http-api-resources", serviceId), ResponseBodyBean.class))
- .orElseThrow(() -> new BizException("Internal service mustn't respond null"));
- val data = Optional.of(responseBodyBean.getData())
- .orElseThrow(() -> new BizException("HttpApiResourcesResponse mustn't be null"));
- val httpApiResourcesResponse = mapper.convertValue(data, HttpApiResourcesResponse.class);
- val serviceInfo = new GetServicesInfoResponse.ServiceInfo();
- serviceInfo.setServiceId(serviceId);
- serviceInfo.setHttpApiResources(httpApiResourcesResponse);
- response.getList().add(serviceInfo);
- }
- if (CollUtil.isEmpty(response.getList())) {
- log.warn("Got am empty ServiceInfo list");
- }
- return response;
- }
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.kt b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.kt
new file mode 100644
index 00000000..f6c2007f
--- /dev/null
+++ b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImpl.kt
@@ -0,0 +1,110 @@
+@file:Suppress("HttpUrlsUsage")
+
+package com.jmsoftware.maf.authcenter.permission.service.impl
+
+import cn.hutool.core.collection.CollUtil
+import cn.hutool.core.text.CharSequenceUtil.format
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.google.common.collect.Lists
+import com.jmsoftware.maf.authcenter.permission.configuration.PermissionConfiguration
+import com.jmsoftware.maf.authcenter.permission.converter.PermissionMapStructMapper
+import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse
+import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse.ServiceInfo
+import com.jmsoftware.maf.authcenter.permission.service.PermissionDomainService
+import com.jmsoftware.maf.authcenter.permission.service.PermissionService
+import com.jmsoftware.maf.authcenter.role.service.RoleDomainService
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse
+import com.jmsoftware.maf.common.domain.authcenter.permission.Permission
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType
+import com.jmsoftware.maf.common.domain.springbootstarter.HttpApiResourcesResponse
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.function.lazyDebug
+import org.springframework.cloud.client.discovery.DiscoveryClient
+import org.springframework.stereotype.Service
+import org.springframework.web.client.RestTemplate
+import java.util.*
+import javax.validation.Valid
+import javax.validation.constraints.NotNull
+
+/**
+ * # PermissionServiceImpl
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com, date: 2/18/2022 11:37 PM
+ */
+@Service
+class PermissionServiceImpl(
+ private val permissionDomainService: PermissionDomainService,
+ private val roleDomainService: RoleDomainService,
+ private val discoveryClient: DiscoveryClient,
+ private val restTemplate: RestTemplate,
+ private val permissionConfiguration: PermissionConfiguration,
+ private val objectMapper: ObjectMapper,
+) : PermissionService {
+ companion object {
+ private val log = logger()
+ }
+
+ override fun getPermissionListByRoleIdList(
+ payload: @Valid @NotNull GetPermissionListByRoleIdListPayload
+ ): GetPermissionListByRoleIdListResponse {
+ val adminRole = roleDomainService.checkAdmin(payload.roleIdList)
+ val response = GetPermissionListByRoleIdListResponse()
+ response.permissionList = Lists.newArrayList()
+ if (adminRole) {
+ log.warn("Admin role checked. The role can access any resources")
+ val permission = Permission()
+ permission.url = "/**"
+ permission.type = PermissionType.BUTTON.type
+ permission.permissionExpression = "admin-permission"
+ permission.method = "*"
+ response.permissionList.add(permission)
+ return response
+ }
+ return response.apply {
+ this.permissionList.addAll(
+ permissionDomainService.getPermissionListByRoleIdList(
+ payload.roleIdList, payload.permissionTypeList
+ ).stream()
+ .map { permission -> PermissionMapStructMapper.INSTANCE.of(permission) }
+ .toList()
+ )
+ }
+ }
+
+ override fun getServicesInfo(): GetServicesInfoResponse {
+ val serviceIdList = discoveryClient.services
+ log.info("Getting service info from Service ID list: {}", serviceIdList)
+ val response = GetServicesInfoResponse()
+ log.info("Ignored service ID: {}", permissionConfiguration.ignoredServiceIds)
+ response.list = serviceIdList.stream()
+ .filter { serviceId: String ->
+ !CollUtil.contains(
+ permissionConfiguration.ignoredServiceIds,
+ serviceId
+ )
+ }
+ .parallel()
+ .map { serviceId: String ->
+ val responseBodyBean = restTemplate.getForObject(
+ format("http://{}/http-api-resources", serviceId), ResponseBodyBean::class.java,
+ )!!
+ val httpApiResourcesResponse = objectMapper.convertValue(
+ Objects.requireNonNull(responseBodyBean).data,
+ HttpApiResourcesResponse::class.java
+ )
+ val serviceInfo = ServiceInfo()
+ serviceInfo.serviceId = serviceId
+ serviceInfo.httpApiResources = httpApiResourcesResponse
+ lazyDebug(log) { "Added serviceInfo: $serviceInfo" }
+ serviceInfo
+ }.toList()
+ if (CollUtil.isEmpty(response.list)) {
+ log.warn("Got am empty ServiceInfo list")
+ }
+ return response
+ }
+}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/package-info.kt b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/package-info.kt
new file mode 100644
index 00000000..7095635a
--- /dev/null
+++ b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/permission/service/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.permission.service
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.java
deleted file mode 100644
index abf521f5..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter.role;
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.kt b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.kt
new file mode 100644
index 00000000..a937619c
--- /dev/null
+++ b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.role
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleService.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleService.java
deleted file mode 100644
index 0c798e78..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleService.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.jmsoftware.maf.authcenter.role.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.jmsoftware.maf.authcenter.role.RoleExcelBean;
-import com.jmsoftware.maf.authcenter.role.persistence.Role;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
-import lombok.NonNull;
-import org.springframework.validation.annotation.Validated;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.util.List;
-
-/**
- * RoleService
- *
- * Service of Role.(Role)
- *
- * @author Johnny Miller (锺俊)
- * @date 2020 -05-10 22:39:49
- */
-@Validated
-public interface RoleService extends IService {
- String ROLE_TEMPLATE_EXCEL = "role-stat.xlsx";
-
- /**
- * Gets role list by user id.
- *
- * @param userId the user id
- * @return the role list by user id
- */
- GetRoleListByUserIdResponse getRoleList(@NotNull Long userId);
-
- /**
- * Gets role list by user id.
- *
- * @param userId the user id
- * @return the role list by user id
- */
- List getRoleListByUserId(@NonNull Long userId);
-
- /**
- * Check admin boolean.
- *
- * @param roleIdList the role id list
- * @return the boolean
- */
- boolean checkAdmin(@NotEmpty List<@NotNull Long> roleIdList);
-
- /**
- * Gets list for exporting.
- *
- * @return the list for exporting
- */
- List getListForExporting();
-
- /**
- * Validate before add to bean list boolean.
- *
- * @param beanList the bean list
- * @param bean the bean
- * @param index the index
- * @throws IllegalArgumentException the illegal argument exception
- */
- void validateBeforeAddToBeanList(List beanList, RoleExcelBean bean, int index) throws IllegalArgumentException;
-
- /**
- * Save.
- *
- * @param beanList the bean list
- */
- void save(@NotEmpty List<@Valid RoleExcelBean> beanList);
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleServiceImpl.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleServiceImpl.java
deleted file mode 100644
index a9892e5d..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleServiceImpl.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package com.jmsoftware.maf.authcenter.role.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.BooleanUtil;
-import cn.hutool.core.util.RandomUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.validation.ValidationUtil;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.jmsoftware.maf.authcenter.role.RoleExcelBean;
-import com.jmsoftware.maf.authcenter.role.constant.RoleRedisKey;
-import com.jmsoftware.maf.authcenter.role.persistence.Role;
-import com.jmsoftware.maf.authcenter.role.mapper.RoleMapper;
-import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
-import com.jmsoftware.maf.springcloudstarter.property.MafConfigurationProperties;
-import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties;
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-/**
- * RoleServiceImpl
- *
- * Service implementation of Role.(Role)
- *
- * @author Johnny Miller (锺俊)
- * @date 2020-05-10 22:39:50
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class RoleServiceImpl
- extends ServiceImpl
- implements RoleService {
- private final MafProjectProperties mafProjectProperties;
- private final MafConfigurationProperties mafConfigurationProperties;
- private final RedisTemplate redisTemplate;
- private final ObjectMapper objectMapper;
-
- @Override
- @SneakyThrows({JsonProcessingException.class})
- public GetRoleListByUserIdResponse getRoleList(@NotNull Long userId) {
- val key = String.format(String.format("%s%s", this.mafProjectProperties.getProjectParentArtifactId(),
- RoleRedisKey.GET_ROLE_LIST_BY_USER_ID.getKeyInfixFormat()), userId);
- val hasKey = this.redisTemplate.hasKey(key);
- if (BooleanUtil.isTrue(hasKey)) {
- return this.objectMapper.readValue(this.redisTemplate.opsForValue().get(key),
- GetRoleListByUserIdResponse.class);
- }
- val response = new GetRoleListByUserIdResponse();
- response.setRoleList(this.getRoleListByUserId(userId));
- this.redisTemplate.opsForValue().set(key, this.objectMapper.writeValueAsString(response),
- RandomUtil.randomLong(1, 7),
- TimeUnit.DAYS);
- return response;
- }
-
- @Override
- public List getRoleListByUserId(@NonNull Long userId) {
- return this.getBaseMapper().selectRoleListByUserId(userId);
- }
-
- @Override
- public boolean checkAdmin(@NotEmpty List<@NotNull Long> roleIdList) {
- val wrapper = Wrappers.lambdaQuery(Role.class);
- wrapper.select(Role::getName)
- .in(Role::getId, roleIdList);
- val roleList = this.list(wrapper);
- val roleNameSet = roleList
- .stream()
- .map(Role::getName)
- .filter(roleName -> StrUtil.equals(this.mafConfigurationProperties.getSuperUserRole(), roleName))
- .collect(Collectors.toSet());
- // If roleNameSet is not empty (contains "admin")
- return CollUtil.isNotEmpty(roleNameSet);
- }
-
- @Override
- public List getListForExporting() {
- val rolePage = new Page(1, 500);
- this.page(rolePage);
- return rolePage
- .getRecords()
- .stream()
- .map(RoleExcelBean::transformBy)
- .collect(Collectors.toList());
- }
-
- @Override
- public void validateBeforeAddToBeanList(List beanList, RoleExcelBean bean, int index) throws IllegalArgumentException {
- val beanValidationResult = ValidationUtil.warpValidate(bean);
- if (!beanValidationResult.isSuccess()) {
- log.warn("Validation failed! beanList: {}, bean: {}, index: {}", beanList, bean, index);
- val firstErrorMessage = CollUtil.getFirst(beanValidationResult.getErrorMessages());
- throw new IllegalArgumentException(
- String.format("%s %s", firstErrorMessage.getPropertyName(), firstErrorMessage.getMessage()));
- }
- }
-
- @Override
- @Transactional(rollbackFor = Throwable.class)
- public void save(@NotEmpty List<@Valid RoleExcelBean> beanList) {
- val roleList = beanList.stream().map(RoleExcelBean::transformTo).collect(Collectors.toList());
- val saved = this.saveBatch(roleList);
- if (!saved) {
- log.error("Cannot save batch role list. {}", roleList);
- }
- }
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/package-info.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/package-info.java
deleted file mode 100644
index 7b8988ba..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter.security;
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.java
deleted file mode 100644
index 7c00d499..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.jmsoftware.maf.authcenter.security.service.impl;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.text.CharSequenceUtil;
-import cn.hutool.core.util.ObjectUtil;
-import com.jmsoftware.maf.authcenter.security.service.JwtService;
-import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse;
-import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import com.jmsoftware.maf.springcloudstarter.property.JwtConfigurationProperties;
-import io.jsonwebtoken.*;
-import io.jsonwebtoken.security.Keys;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.PostConstruct;
-import javax.crypto.SecretKey;
-import javax.servlet.http.HttpServletRequest;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-/**
- * JwtServiceImpl
- * Change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
- * @date 2019-03-03 13:40
- **/
-@Slf4j
-@Service
-@RequiredArgsConstructor
-@SuppressWarnings("unused")
-public class JwtServiceImpl implements JwtService {
- private final JwtConfigurationProperties jwtConfigurationProperties;
- private final RedisTemplate redisTemplate;
- private SecretKey secretKey;
- private JwtParser jwtParser;
-
- @PostConstruct
- private void init() {
- log.info("Start to init class members of {}.", this.getClass().getSimpleName());
- this.secretKey = Keys.hmacShaKeyFor(this.jwtConfigurationProperties.getSigningKey().getBytes(StandardCharsets.UTF_8));
- log.warn("Secret key for JWT was generated. Algorithm: {}", this.secretKey.getAlgorithm());
- this.jwtParser = Jwts.parserBuilder().setSigningKey(this.secretKey).build();
- }
-
- @Override
- public String createJwt(Authentication authentication, Boolean rememberMe) {
- val userPrincipal = (UserPrincipal) authentication.getPrincipal();
- return this.createJwt(rememberMe, userPrincipal.getId(), userPrincipal.getUsername(), userPrincipal.getRoles(),
- userPrincipal.getAuthorities());
- }
-
- @Override
- @SuppressWarnings("scwjava-time_ReplacenewDatewithjava.time")
- public String createJwt(Boolean rememberMe, Long id, String subject, List roles,
- Collection extends GrantedAuthority> authorities) {
- val now = new Date();
- val builder = Jwts.builder()
- .setId(id.toString())
- .setSubject(subject)
- .setIssuedAt(now)
- .signWith(this.secretKey)
- .claim("roles", roles);
- // Don't generate authority information in JWT.
- // .claim("authorities", authorities)
- // Set expire duration of JWT.
- val ttl = Boolean.TRUE.equals(rememberMe) ?
- this.jwtConfigurationProperties.getTtlForRememberMe() : this.jwtConfigurationProperties.getTtl();
- if (ttl > 0) {
- builder.setExpiration(DateUtil.offsetMillisecond(now, ttl.intValue()));
- }
- val jwt = builder.compact();
- // Store new JWT in Redis
- String redisKeyOfJwt = String.format("%s%s", this.jwtConfigurationProperties.getJwtRedisKeyPrefix(), subject);
- this.redisTemplate.opsForValue().set(redisKeyOfJwt, jwt, ttl, TimeUnit.MILLISECONDS);
- log.info("Storing JWT in Redis. Key: {}, Value: {}", redisKeyOfJwt, jwt);
- return jwt;
- }
-
- @Override
- public Claims parseJwt(String jwt) throws SecurityException {
- Claims claims;
- try {
- claims = Optional.ofNullable(this.jwtParser.parseClaimsJws(jwt).getBody())
- .orElseThrow(() -> new SecurityException(HttpStatus.INTERNAL_SERVER_ERROR,
- "The JWT Claims Set is null", null));
- } catch (ExpiredJwtException e) {
- log.error("JWT is expired. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (JWT itself)");
- } catch (UnsupportedJwtException e) {
- log.error("JWT is unsupported. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is unsupported");
- } catch (MalformedJwtException e) {
- log.error("JWT is invalid. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is invalid");
- } catch (IllegalArgumentException e) {
- log.error("The parameter of JWT is invalid. Message: {} JWT: {}", e.getMessage(), jwt);
- throw new SecurityException(HttpStatus.UNAUTHORIZED, "The parameter of JWT is invalid");
- }
- val username = claims.getSubject();
- val redisKeyOfJwt = this.jwtConfigurationProperties.getJwtRedisKeyPrefix() + username;
- // Check if JWT exists
- val expire = this.redisTemplate.opsForValue().getOperations().getExpire(redisKeyOfJwt, TimeUnit.MILLISECONDS);
- if (ObjectUtil.isNull(expire) || expire <= 0) {
- throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Redis expiration)");
- }
- // Check if the current JWT is equal to the one in Redis.
- // If it's noe equal, that indicates current user has signed out or logged in before.
- // Both situations reveal the JWT has expired.
- val jwtInRedis = (String) this.redisTemplate.opsForValue().get(redisKeyOfJwt);
- if (!CharSequenceUtil.equals(jwt, jwtInRedis)) {
- throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Not equaled)");
- }
- return claims;
- }
-
- @Override
- public void invalidateJwt(HttpServletRequest request) throws SecurityException {
- val jwt = this.getJwtFromRequest(request);
- val username = this.getUsernameFromJwt(jwt);
- // Delete JWT from redis
- String redisKeyOfJwt = String.format("%s%s", this.jwtConfigurationProperties.getJwtRedisKeyPrefix(), username);
- val deletedKeyNumber = this.redisTemplate.opsForValue().getOperations().delete(redisKeyOfJwt);
- log.error("Invalidate JWT. Redis key of JWT = {}, deleted = {}", redisKeyOfJwt, deletedKeyNumber);
- }
-
- @Override
- public String getUsernameFromJwt(String jwt) throws SecurityException {
- val claims = this.parseJwt(jwt);
- return claims.getSubject();
- }
-
- @Override
- public String getUsernameFromRequest(HttpServletRequest request) throws SecurityException {
- val jwt = this.getJwtFromRequest(request);
- return this.getUsernameFromJwt(jwt);
- }
-
- @Override
- public String getJwtFromRequest(HttpServletRequest request) {
- val bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
- if (CharSequenceUtil.isNotBlank(bearerToken)
- && bearerToken.startsWith(JwtConfigurationProperties.TOKEN_PREFIX)) {
- return bearerToken.substring(JwtConfigurationProperties.TOKEN_PREFIX.length());
- }
- return null;
- }
-
- @Override
- @SneakyThrows
- public ParseJwtResponse parse(HttpServletRequest request) {
- val jwt = this.getJwtFromRequest(request);
- val claims = this.parseJwt(jwt);
- val parseJwtResponse = new ParseJwtResponse();
- parseJwtResponse.setId(Long.parseLong(claims.getId()));
- parseJwtResponse.setUsername(claims.getSubject());
- return parseJwtResponse;
- }
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.java
deleted file mode 100644
index 069059ce..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter.user;
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.kt b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.kt
new file mode 100644
index 00000000..b707e02d
--- /dev/null
+++ b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.user
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserRoleService.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserRoleService.java
deleted file mode 100644
index 2f56a80c..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserRoleService.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.jmsoftware.maf.authcenter.user.persistence.User;
-import com.jmsoftware.maf.authcenter.user.persistence.UserRole;
-import lombok.NonNull;
-import org.springframework.validation.annotation.Validated;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * UserRoleService.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/29/2021 12:09 PM
- */
-@Validated
-public interface UserRoleService extends IService {
- /**
- * Assign role by role name.
- *
- * @param user the user
- * @param roleName the role name
- */
- void assignRoleByRoleName(@NonNull User user, @NotBlank String roleName);
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserService.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserService.java
deleted file mode 100644
index 6dbab97b..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserService.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.jmsoftware.maf.authcenter.user.payload.GetUserPageListPayload;
-import com.jmsoftware.maf.authcenter.user.payload.GetUserStatusPayload;
-import com.jmsoftware.maf.authcenter.user.persistence.User;
-import com.jmsoftware.maf.common.bean.PageResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.user.*;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import org.springframework.validation.annotation.Validated;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.validation.Valid;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-
-/**
- * UserService
- *
- * Service of UserPersistence.(UserPersistence)
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 5/10/20 12:31 PM
- */
-@Validated
-public interface UserService extends IService {
- /**
- * Gets user by login token.
- *
- * @param loginToken the login token
- * @return the user by login token
- */
- GetUserByLoginTokenResponse getUserByLoginToken(@NotBlank String loginToken);
-
- /**
- * Save user for registering save user for registering response.
- *
- * @param payload the payload
- * @return the save user for registering response
- */
- SignupResponse saveUserForSignup(@Valid SignupPayload payload);
-
- /**
- * Login login response.
- *
- * @param payload the payload
- * @return the login response
- * @throws SecurityException the security exception
- */
- LoginResponse login(@Valid LoginPayload payload) throws SecurityException;
-
- /**
- * Logout boolean.
- *
- * @param request the request
- * @return the boolean
- * @throws SecurityException the security exception
- */
- boolean logout(HttpServletRequest request) throws SecurityException;
-
- /**
- * Gets user status.
- *
- * @param payload the payload
- * @return the user status
- */
- String getUserStatus(@Valid @NotNull GetUserStatusPayload payload);
-
- /**
- * Gets user page list.
- *
- * @param payload the payload
- * @return the user page list
- */
- PageResponseBodyBean getUserPageList(@Valid @NotNull GetUserPageListPayload payload);
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleServiceImpl.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleServiceImpl.java
deleted file mode 100644
index 99a7ad13..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleServiceImpl.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.service.impl;
-
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.jmsoftware.maf.authcenter.role.persistence.Role;
-import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import com.jmsoftware.maf.authcenter.user.mapper.UserRoleMapper;
-import com.jmsoftware.maf.authcenter.user.persistence.User;
-import com.jmsoftware.maf.authcenter.user.persistence.UserRole;
-import com.jmsoftware.maf.authcenter.user.service.UserRoleService;
-import com.jmsoftware.maf.common.exception.BizException;
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.stereotype.Service;
-
-import javax.validation.constraints.NotBlank;
-import java.util.Optional;
-
-/**
- * UserRoleServiceImpl.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/29/2021 12:09 PM
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class UserRoleServiceImpl
- extends ServiceImpl
- implements UserRoleService {
- private final RoleService roleService;
-
- @Override
- @SneakyThrows({BizException.class})
- public void assignRoleByRoleName(@NonNull User user, @NotBlank String roleName) {
- val queryWrapper = Wrappers.lambdaQuery(Role.class);
- queryWrapper.select(Role::getId)
- .eq(Role::getName, roleName);
- val role = Optional.ofNullable(this.roleService.getOne(queryWrapper))
- .orElseThrow(() -> new BizException("Cannot find the role: " + roleName));
- val userRole = new UserRole();
- userRole.setUserId(user.getId());
- userRole.setRoleId(role.getId());
- val saved = this.save(userRole);
- if (!saved) {
- throw new BizException(String.format("Cannot assign role (%s) to user (%s)", roleName, user.getUsername()));
- }
- }
-}
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserServiceImpl.java b/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserServiceImpl.java
deleted file mode 100644
index 21ce6205..00000000
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserServiceImpl.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.service.impl;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.text.CharSequenceUtil;
-import cn.hutool.core.util.BooleanUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.RandomUtil;
-import cn.hutool.json.JSONUtil;
-import com.baomidou.mybatisplus.core.metadata.OrderItem;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.jmsoftware.maf.authcenter.security.service.JwtService;
-import com.jmsoftware.maf.authcenter.user.constant.UserRedisKey;
-import com.jmsoftware.maf.authcenter.user.mapper.UserMapper;
-import com.jmsoftware.maf.authcenter.user.payload.GetUserPageListPayload;
-import com.jmsoftware.maf.authcenter.user.payload.GetUserStatusPayload;
-import com.jmsoftware.maf.authcenter.user.persistence.User;
-import com.jmsoftware.maf.authcenter.user.service.UserRoleService;
-import com.jmsoftware.maf.authcenter.user.service.UserService;
-import com.jmsoftware.maf.common.bean.PageResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.user.*;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import com.jmsoftware.maf.springcloudstarter.property.MafConfigurationProperties;
-import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties;
-import com.jmsoftware.maf.springcloudstarter.util.UserUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.cache.annotation.CacheConfig;
-import org.springframework.context.MessageSource;
-import org.springframework.context.i18n.LocaleContextHolder;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.validation.Valid;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import java.util.concurrent.TimeUnit;
-
-/**
- * UserServiceImpl
- *
- * Service implementation of UserPersistence.(UserPersistence)
- *
- * @author Johnny Miller (锺俊)
- * @date 2020-05-10 12:08:28
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-@CacheConfig(cacheNames = "user-service-cache")
-public class UserServiceImpl
- extends ServiceImpl
- implements UserService {
- private final BCryptPasswordEncoder bCryptPasswordEncoder;
- private final JwtService jwtService;
- private final MessageSource messageSource;
- private final MafProjectProperties mafProjectProperties;
- private final RedisTemplate redisTemplate;
- private final UserRoleService userRoleService;
- private final MafConfigurationProperties mafConfigurationProperties;
-
- @Override
- public GetUserByLoginTokenResponse getUserByLoginToken(@NotBlank String loginToken) {
- val key = String.format(String.format("%s%s", this.mafProjectProperties.getProjectParentArtifactId(),
- UserRedisKey.GET_USER_BY_LOGIN_TOKEN.getKeyInfixFormat()), loginToken);
- val hasKey = this.redisTemplate.hasKey(key);
- if (BooleanUtil.isTrue(hasKey)) {
- return JSONUtil.toBean(this.redisTemplate.opsForValue().get(key), GetUserByLoginTokenResponse.class);
- }
- val wrapper = Wrappers.lambdaQuery(User.class);
- wrapper.and(queryWrapper -> queryWrapper.eq(User::getUsername, loginToken)
- .or()
- .eq(User::getEmail, loginToken)
- .or()
- .eq(User::getCellphone, loginToken));
- val userPersistence = this.getBaseMapper().selectOne(wrapper);
- if (ObjectUtil.isNull(userPersistence)) {
- return null;
- }
- val response = new GetUserByLoginTokenResponse();
- BeanUtil.copyProperties(userPersistence, response);
- this.redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(response), RandomUtil.randomLong(1, 7),
- TimeUnit.DAYS);
- return response;
- }
-
- @Override
- @Transactional(rollbackFor = Throwable.class)
- public SignupResponse saveUserForSignup(@Valid SignupPayload payload) {
- val user = new User();
- user.setUsername(payload.getUsername());
- user.setEmail(payload.getEmail());
- user.setPassword(this.bCryptPasswordEncoder.encode(payload.getPassword()));
- user.setStatus(UserStatus.ENABLED.getValue());
- this.save(user);
- log.warn("Saved user for signup, going to assign guest role to user. {}", user);
- this.userRoleService.assignRoleByRoleName(user, this.mafConfigurationProperties.getGuestUserRole());
- val response = new SignupResponse();
- response.setUserId(user.getId());
- return response;
- }
-
- @Override
- public LoginResponse login(@Valid LoginPayload payload) throws SecurityException {
- val user = this.getUserByLoginToken(payload.getLoginToken());
- if (ObjectUtil.isNull(user)) {
- throw new SecurityException(HttpStatus.UNAUTHORIZED);
- }
- log.info("User login: {}", user);
- val matched = this.bCryptPasswordEncoder.matches(payload.getPassword(), user.getPassword());
- if (!matched) {
- throw new SecurityException(HttpStatus.UNAUTHORIZED);
- }
- val jwt = this.jwtService.createJwt(payload.getRememberMe(), user.getId(), user.getUsername(), null, null);
- val response = new LoginResponse();
- response.setGreeting(this.messageSource.getMessage("greeting", null, LocaleContextHolder.getLocale()));
- response.setJwt(jwt);
- return response;
- }
-
- @Override
- public boolean logout(HttpServletRequest request) throws SecurityException {
- this.jwtService.invalidateJwt(request);
- return true;
- }
-
- @Override
- public String getUserStatus(@Valid @NotNull GetUserStatusPayload payload) {
- log.info("Current username: {}", UserUtil.getCurrentUsername());
- return UserStatus.ofValue(payload.getStatus()).getDescription();
- }
-
- @Override
- public PageResponseBodyBean getUserPageList(@Valid @NotNull GetUserPageListPayload payload) {
- log.info("{}", payload);
- val page = new Page(payload.getCurrentPage(), payload.getPageSize());
- val queryWrapper = Wrappers.lambdaQuery(User.class);
- if (CharSequenceUtil.isNotBlank(payload.getUsername())) {
- queryWrapper.like(User::getUsername, payload.getUsername());
- }
- page.setOrders(ListUtil.of(OrderItem.desc(payload.getOrderBy())));
- this.page(page, queryWrapper);
- return PageResponseBodyBean.ofSuccess(page.getRecords(), page.getTotal());
- }
-}
diff --git a/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/package-info.java b/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
deleted file mode 100644
index e702ef59..00000000
--- a/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter;
diff --git a/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt b/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
new file mode 100644
index 00000000..b7191a36
--- /dev/null
+++ b/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter
diff --git a/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImplTest.kt b/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImplTest.kt
new file mode 100644
index 00000000..734cc581
--- /dev/null
+++ b/auth-center/auth-center-biz/src/test/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionServiceImplTest.kt
@@ -0,0 +1,137 @@
+package com.jmsoftware.maf.authcenter.permission.service.impl
+
+import cn.hutool.core.util.StrUtil
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.google.common.collect.Lists
+import com.jmsoftware.maf.authcenter.permission.configuration.PermissionConfiguration
+import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse.ServiceInfo
+import com.jmsoftware.maf.authcenter.permission.service.PermissionDomainService
+import com.jmsoftware.maf.authcenter.role.service.RoleDomainService
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.springbootstarter.HttpApiResourcesResponse
+import com.jmsoftware.maf.common.util.logger
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.ArgumentMatchers.*
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.junit.jupiter.MockitoExtension
+import org.springframework.cloud.client.discovery.DiscoveryClient
+import org.springframework.web.bind.annotation.RequestMethod
+import org.springframework.web.client.RestTemplate
+
+/**
+ * # PermissionServiceImplTest
+ *
+ * Description: PermissionServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com, date: 4/3/22 10:19 PM
+ * @see Using Mockito with JUnit 5
+ * @see YouTube - Using Mockito with JUnit 5
+ */
+@Suppress("unused")
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class PermissionServiceImplTest {
+ companion object {
+ private val log = logger()
+ }
+
+ @InjectMocks
+ lateinit var permissionService: PermissionServiceImpl
+
+ @Mock
+ lateinit var permissionDomainService: PermissionDomainService
+
+ @Mock
+ lateinit var roleDomainService: RoleDomainService
+
+ @Mock
+ lateinit var discoveryClient: DiscoveryClient
+
+ @Mock
+ lateinit var restTemplate: RestTemplate
+
+ @Mock
+ lateinit var permissionConfiguration: PermissionConfiguration
+
+ @Mock
+ lateinit var objectMapper: ObjectMapper
+
+ @BeforeEach
+ fun setUp() {
+ log.info("{} setUp", this.javaClass.simpleName)
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("{} tearDown", this.javaClass.simpleName)
+ }
+
+ @Test
+ fun getPermissionListByRoleIdList() {
+ `when`(roleDomainService.checkAdmin(anyList())).thenReturn(false)
+ `when`(permissionDomainService.getPermissionListByRoleIdList(anyList(), anyList()))
+ .thenReturn(Lists.newArrayList())
+ val payload = GetPermissionListByRoleIdListPayload()
+ payload.roleIdList = Lists.newArrayList()
+ payload.permissionTypeList = Lists.newArrayList()
+ val response = permissionService.getPermissionListByRoleIdList(payload)
+ log.info("Permission list response: {}", response)
+ verify(roleDomainService).checkAdmin(anyList())
+ verify(permissionDomainService).getPermissionListByRoleIdList(anyList(), anyList())
+ assertEquals(0, response.permissionList.size)
+ }
+
+ @Test
+ fun getServicesInfo() {
+ `when`(discoveryClient.services)
+ .thenReturn(listOf("auth-center", "oss-center", "maf-mis", "api-gateway", "spring-boot-admin"))
+ `when`(permissionConfiguration.ignoredServiceIds)
+ .thenReturn(setOf("api-gateway", "spring-boot-admin"))
+ val httpApiResourcesResponse = HttpApiResourcesResponse()
+ val element = HttpApiResourcesResponse.HttpApiResource()
+ element.method = RequestMethod.GET
+ element.urlPattern = "/api/v1/**"
+ httpApiResourcesResponse.list.add(element)
+ `when`(objectMapper.convertValue(any(), any>()))
+ .thenReturn(httpApiResourcesResponse)
+ `when`(restTemplate.getForObject(anyString(), any>()))
+ .thenReturn(ResponseBodyBean.ofSuccess(httpApiResourcesResponse))
+ val servicesInfo = permissionService.getServicesInfo()
+ log.info("Services info: {}", servicesInfo)
+ verify(discoveryClient).services
+ assertNotEquals(0, servicesInfo.list.size)
+ assertTrue(
+ servicesInfo.list
+ .stream()
+ .anyMatch { service: ServiceInfo ->
+ StrUtil.equalsAnyIgnoreCase(service.serviceId, "auth-center")
+ }
+ )
+ }
+}
diff --git a/auth-center/auth-center-bootstrap/pom.xml b/auth-center/auth-center-bootstrap/pom.xml
index 00c8801d..0469e2f6 100644
--- a/auth-center/auth-center-bootstrap/pom.xml
+++ b/auth-center/auth-center-bootstrap/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
auth-center
- 0.0.8.1
+ 0.0.9
@@ -30,44 +30,6 @@
-
- org.apache.maven.plugins
- maven-pmd-plugin
- ${maven-pmd-plugin.version}
-
- ${project.build.sourceEncoding}
- ${java.version}
- true
-
- rulesets/java/ali-comment.xml
- rulesets/java/ali-concurrent.xml
- rulesets/java/ali-constant.xml
- rulesets/java/ali-exception.xml
- rulesets/java/ali-flowcontrol.xml
- rulesets/java/ali-naming.xml
- rulesets/java/ali-oop.xml
- rulesets/java/ali-orm.xml
- rulesets/java/ali-other.xml
- rulesets/java/ali-set.xml
-
-
-
-
- verify
-
- check
-
-
-
-
-
- com.alibaba.p3c
- p3c-pmd
- ${p3c-pmd.version}
-
-
-
-
com.google.cloud.tools
@@ -100,12 +62,16 @@
-
- adoptopenjdk/openjdk11:${adoptopenjdk11.tag}
+
+ eclipse-temurin:${temurin.tag}
docker.io/ijohnnymiller/${project.baseArtifactId}.${project.parent.artifactId}
+
${git.commit.id.abbrev}-${project.version}
@@ -132,32 +98,6 @@
-
-
-
- io.github.git-commit-id
- git-commit-id-maven-plugin
- 5.0.0
-
-
- get-the-git-info
-
- revision
-
- initialize
-
-
-
- true
- ${project.build.outputDirectory}/git.properties
-
-
- ^git.build.(time|version)$
- ^git.commit.id.(abbrev|full)$
-
- full
-
-
diff --git a/auth-center/auth-center-bootstrap/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.java b/auth-center/auth-center-bootstrap/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.java
deleted file mode 100644
index 365fbf03..00000000
--- a/auth-center/auth-center-bootstrap/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.jmsoftware.maf.authcenter;
-
-import com.jmsoftware.maf.springcloudstarter.helper.SpringBootStartupHelper;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.util.StopWatch;
-
-/**
- * AuthCenterApplication
- *
- * Change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 3/12/20 9:57 AM
- **/
-@Slf4j
-@EnableFeignClients
-@EnableDiscoveryClient
-@SpringBootApplication
-@SuppressWarnings("scwjava_Createprivateconstructorforutilityclassallfieldsmethodsarestatic")
-public class AuthCenterApplication {
- public static void main(String[] args) {
- val stopWatch = new StopWatch();
- stopWatch.start();
- val configurableApplicationContext = SpringApplication.run(AuthCenterApplication.class, args);
- val springBootStartupHelper = configurableApplicationContext.getBean(SpringBootStartupHelper.class);
- springBootStartupHelper.stop(stopWatch);
- }
-}
diff --git a/auth-center/auth-center-bootstrap/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.kt b/auth-center/auth-center-bootstrap/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.kt
new file mode 100644
index 00000000..b691506a
--- /dev/null
+++ b/auth-center/auth-center-bootstrap/src/main/java/com/jmsoftware/maf/authcenter/AuthCenterApplication.kt
@@ -0,0 +1,28 @@
+package com.jmsoftware.maf.authcenter
+
+import com.jmsoftware.maf.springcloudstarter.helper.SpringBootStartupHelper
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.runApplication
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient
+import org.springframework.cloud.openfeign.EnableFeignClients
+import org.springframework.util.StopWatch
+
+/**
+ * # AuthCenterApplication
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 11:44 AM
+ */
+@EnableFeignClients
+@EnableDiscoveryClient
+@SpringBootApplication
+class AuthCenterApplication
+
+fun main(args: Array) {
+ val stopWatch = StopWatch()
+ stopWatch.start()
+ runApplication(*args)
+ .getBean(SpringBootStartupHelper::class.java)
+ .stop(stopWatch)
+}
diff --git a/auth-center/auth-center-bootstrap/src/main/resources/application.yml b/auth-center/auth-center-bootstrap/src/main/resources/application.yml
index 0c15a5eb..8730fe33 100644
--- a/auth-center/auth-center-bootstrap/src/main/resources/application.yml
+++ b/auth-center/auth-center-bootstrap/src/main/resources/application.yml
@@ -21,7 +21,7 @@ spring:
config:
# `default-context` should not be modified, keeps "application" for common configuration.
# Properties in the config/application folder are applicable to all applications using consul for configuration.
- profile-separator: "::"
+ profile-separator: "@"
format: YAML
data-key: "data"
watch:
@@ -29,6 +29,7 @@ spring:
delay: 1000
prefixes:
- config
+ - shardingsphere
discovery:
register: true
instance-id: ${spring.application.name}-${spring.cloud.client.hostname}-${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
@@ -39,19 +40,15 @@ spring:
health-check-critical-timeout: 15s
servlet:
multipart:
- # `location` specifies the directory where uploaded files will be stored. When not specified,
- # a temporary directory will be used. ATTENTION: it may differ due to OS.
location: @project.parent.artifactId@/${spring.application.name}/temprary-file
- # `max-file-size` specifies the maximum size permitted for uploaded files. The default is 1MB. We set it as 64 MB.
max-file-size: 64MB
- # `max-request-size` specifies the maximum size allowed for multipart/form-data requests. The default is 10MB.
max-request-size: 70MB
- # `file-size-threshold` specifies the size threshold after which files will be written to disk.
- # The default is 0. We set it as 0 too.
file-size-threshold: 0
logging:
config: classpath:logback-configuration/logback-${spring.profiles.active}.xml
+ level:
+ org.springframework.data.elasticsearch.client.WIRE: DEBUG
maf:
project-properties:
@@ -59,7 +56,7 @@ maf:
context-path: ${server.servlet.context-path}
group-id: @project.groupId@
project-parent-artifact-id: @project.parent.artifactId@
- project-artifact-id: @project.artifactId@
+ project-artifact-id: @project.parent.artifactId@
version: @project.version@
description: @project.description@
jdk-version: @java.version@
diff --git a/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/AuthCenterApplicationTests.java b/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/AuthCenterApplicationTests.java
deleted file mode 100644
index 7fa17004..00000000
--- a/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/AuthCenterApplicationTests.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.jmsoftware.maf.authcenter;
-
-import cn.hutool.core.util.StrUtil;
-import com.jmsoftware.maf.authcenter.security.service.JwtService;
-import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-
-import java.util.ArrayList;
-
-/**
- * Description: AuthCenterApplicationTests.
- *
- * @author 钟俊 (zhongjun), email: zhongjun@toguide.cn, date: 12/21/2020 3:08 PM
- */
-@Slf4j
-@SpringBootTest
-class AuthCenterApplicationTests {
- @Autowired
- private JwtService jwtService;
-
- @Test
- @SneakyThrows
- void mockLogin() {
- GetUserByLoginTokenResponse user = new GetUserByLoginTokenResponse();
- user.setId(1L);
- user.setUsername("ijohnnymiller");
- val authenticationToken = new UsernamePasswordAuthenticationToken(
- UserPrincipal.create(user, new ArrayList<>(), new ArrayList<>()), 12345678);
- String jwt = jwtService.createJwt(authenticationToken, false);
- log.info("Generated JWT: {}", jwt);
- Assertions.assertTrue(StrUtil.isNotBlank(jwt));
- }
-}
diff --git a/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/mybatis/MyBatisPlusTests.java b/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/mybatis/MyBatisPlusTests.java
deleted file mode 100644
index dab7b16b..00000000
--- a/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/mybatis/MyBatisPlusTests.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.jmsoftware.maf.authcenter.mybatis;
-
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.jmsoftware.maf.authcenter.role.mapper.RoleMapper;
-import com.jmsoftware.maf.authcenter.role.persistence.Role;
-import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import com.jmsoftware.maf.common.domain.DeletedField;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.junit.jupiter.api.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-import java.util.Optional;
-
-/**
- * Description: MyBatisPlusTests, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 1/13/2021 4:41 PM
- **/
-@Slf4j
-@SpringBootTest
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class MyBatisPlusTests {
- private static final int AFFECTED = 0;
- @Autowired
- private RoleService roleService;
- @Autowired
- private RoleMapper roleMapper;
-
- @Test
- @Order(1)
- void insertAutoFillTest() {
- val role = new Role();
- role.setName("role-for-mybatis-plus-tests");
- role.setDescription("Role for MyBatis Plus tests. Testing functions");
- int inserted;
- try {
- inserted = roleService.getBaseMapper().insert(role);
- } catch (Exception e) {
- log.error("Error occurred when inserting role", e);
- return;
- }
- log.info("insertAutoFillTest saved: {}", inserted);
- Assertions.assertEquals(AFFECTED, inserted);
- }
-
- @Test
- @Order(2)
- void logicDeleteTest() {
- val lambdaQuery = Wrappers.lambdaQuery(Role.class);
- lambdaQuery.eq(Role::getName, "role-for-mybatis-plus-tests");
- var optionalRolePersistence = Optional.ofNullable(roleService.getBaseMapper().selectOne(lambdaQuery));
- if (optionalRolePersistence.isEmpty()) {
- optionalRolePersistence = Optional.ofNullable(roleMapper.selectByName("role-for-mybatis-plus-tests"));
- }
- Assertions.assertTrue(optionalRolePersistence.isPresent());
- val rolePersistence = optionalRolePersistence.get();
- if (DeletedField.DELETED.getValue().equals(rolePersistence.getDeleted())) {
- log.warn("Role deleted. {}", rolePersistence);
- return;
- }
- val deleted = roleService.getBaseMapper().delete(lambdaQuery);
- log.info("Logic delete result: {}", deleted);
- Assertions.assertEquals(AFFECTED, deleted);
- lambdaQuery.eq(Role::getDeleted, DeletedField.DELETED.getValue());
- val rolePersistence2 = roleMapper.selectByName(rolePersistence.getName());
- log.info("Deleted role: {}", rolePersistence2);
- Assertions.assertEquals(rolePersistence2.getDeleted(), DeletedField.DELETED.getValue());
- final var deletedRolePersistence = roleService.getOne(lambdaQuery);
- Assertions.assertNull(deletedRolePersistence);
- }
-}
diff --git a/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt b/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
new file mode 100644
index 00000000..b7191a36
--- /dev/null
+++ b/auth-center/auth-center-bootstrap/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter
diff --git a/auth-center/auth-center-domain/pom.xml b/auth-center/auth-center-domain/pom.xml
index 71d5601b..62f51c2f 100644
--- a/auth-center/auth-center-domain/pom.xml
+++ b/auth-center/auth-center-domain/pom.xml
@@ -11,7 +11,7 @@
com.jmsoftware.maf
auth-center
- 0.0.8.1
+ 0.0.9
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/package-info.java b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/package-info.java
deleted file mode 100644
index e702ef59..00000000
--- a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter;
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/package-info.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/package-info.kt
new file mode 100644
index 00000000..b7191a36
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/package-info.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/package-info.kt
new file mode 100644
index 00000000..9bd0fd89
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.permission
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionDomainService.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionDomainService.kt
new file mode 100644
index 00000000..d5856c20
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/service/PermissionDomainService.kt
@@ -0,0 +1,29 @@
+package com.jmsoftware.maf.authcenter.permission.service
+
+import com.baomidou.mybatisplus.extension.service.IService
+import com.jmsoftware.maf.authcenter.permission.persistence.Permission
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType
+import org.springframework.validation.annotation.Validated
+import javax.validation.constraints.NotEmpty
+
+/**
+ * # PermissionDomainService
+ *
+ * Domain Service of Permission. (Permission)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 11:50 AM
+ */
+@Validated
+interface PermissionDomainService : IService {
+ /**
+ * Gets permission list by role id list.
+ *
+ * @param roleIdList the role id list
+ * @param permissionTypeList the permission type list
+ * @return the permission list by role id list
+ */
+ fun getPermissionListByRoleIdList(
+ roleIdList: @NotEmpty List,
+ permissionTypeList: @NotEmpty List
+ ): List
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionDomainServiceImpl.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionDomainServiceImpl.kt
new file mode 100644
index 00000000..af7d8245
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionDomainServiceImpl.kt
@@ -0,0 +1,27 @@
+package com.jmsoftware.maf.authcenter.permission.service.impl
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
+import com.jmsoftware.maf.authcenter.permission.mapper.PermissionMapper
+import com.jmsoftware.maf.authcenter.permission.persistence.Permission
+import com.jmsoftware.maf.authcenter.permission.service.PermissionDomainService
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType
+import org.springframework.stereotype.Service
+import javax.validation.constraints.NotEmpty
+
+/**
+ * # PermissionDomainServiceImpl
+ *
+ * Domain Service implementation of Permission. (Permission)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 11:53 AM
+ */
+@Service
+class PermissionDomainServiceImpl
+ : ServiceImpl(), PermissionDomainService {
+ override fun getPermissionListByRoleIdList(
+ roleIdList: @NotEmpty List,
+ permissionTypeList: @NotEmpty List
+ ): List {
+ return getBaseMapper().selectPermissionListByRoleIdList(roleIdList, permissionTypeList)
+ }
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignService.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignService.kt
new file mode 100644
index 00000000..82db98ce
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignService.kt
@@ -0,0 +1,24 @@
+package com.jmsoftware.maf.authcenter.remote
+
+import com.jmsoftware.maf.common.domain.osscenter.write.ObjectResponse
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.multipart.MultipartFile
+import javax.validation.constraints.NotNull
+
+/**
+ * # OssCenterFeignService
+ *
+ * Description: OssCenterFeignService, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 11:57 AM
+ */
+@Validated
+interface OssCenterFeignService {
+ /**
+ * Upload single resource object response.
+ *
+ * @param multipartFile the multipart file
+ * @return the object response
+ */
+ fun uploadSingleResource(multipartFile: @NotNull MultipartFile): ObjectResponse
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/remote/impl/OssCenterFeignServiceImpl.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/remote/impl/OssCenterFeignServiceImpl.kt
new file mode 100644
index 00000000..a46d1b65
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/remote/impl/OssCenterFeignServiceImpl.kt
@@ -0,0 +1,37 @@
+package com.jmsoftware.maf.authcenter.remote.impl
+
+import com.jmsoftware.maf.authcenter.remote.OssCenterFeignClient
+import com.jmsoftware.maf.authcenter.remote.OssCenterFeignService
+import com.jmsoftware.maf.common.domain.osscenter.write.ObjectResponse
+import com.jmsoftware.maf.common.exception.InternalServerException
+import com.jmsoftware.maf.common.util.logger
+import org.springframework.stereotype.Service
+import org.springframework.web.multipart.MultipartFile
+import java.util.*
+import javax.validation.constraints.NotNull
+
+/**
+ * # OssCenterFeignServiceImpl
+ *
+ * Description: OssCenterFeignServiceImpl, change description here.
+ *
+ * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com, date: 2/5/2022 7:47 PM
+ */
+@Service
+class OssCenterFeignServiceImpl(
+ private val ossCenterFeignClient: OssCenterFeignClient
+) : OssCenterFeignService {
+ companion object {
+ private val log = logger()
+ }
+
+ override fun uploadSingleResource(multipartFile: @NotNull MultipartFile): ObjectResponse {
+ log.info("Uploading single resource to oss center. multipartFile: {}", multipartFile)
+ return Optional.ofNullable(ossCenterFeignClient.uploadSingleResource(multipartFile))
+ .map { response -> response.data!! }
+ .orElseThrow {
+ log.error("Failed to upload single resource to oss center. multipartFile: ${multipartFile.name}")
+ InternalServerException("Failed to upload single resource to oss center")
+ }
+ }
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.kt
new file mode 100644
index 00000000..a937619c
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.role
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleDomainService.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleDomainService.kt
new file mode 100644
index 00000000..74b963bb
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/service/RoleDomainService.kt
@@ -0,0 +1,73 @@
+package com.jmsoftware.maf.authcenter.role.service
+
+import com.baomidou.mybatisplus.extension.service.IService
+import com.jmsoftware.maf.authcenter.role.RoleExcelBean
+import com.jmsoftware.maf.authcenter.role.persistence.Role
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse
+import org.springframework.validation.annotation.Validated
+import javax.validation.constraints.NotEmpty
+import javax.validation.constraints.NotNull
+
+/**
+ * # RoleDomainService
+ *
+ * Domain Service of Role. (Role)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 5:23 PM
+ */
+@Validated
+interface RoleDomainService : IService {
+ companion object {
+ const val ROLE_TEMPLATE_EXCEL = "role-stat.xlsx"
+ }
+
+ /**
+ * Gets role list by user id.
+ *
+ * @param userId the user id
+ * @return the role list by user id
+ */
+ fun getRoleList(userId: @NotNull Long): GetRoleListByUserIdResponse
+
+ /**
+ * Gets role list by user id.
+ *
+ * @param userId the user id
+ * @return the role list by user id
+ */
+ fun getRoleListByUserId(userId: Long): List
+
+ /**
+ * Check admin boolean.
+ *
+ * @param roleIdList the role id list
+ * @return the boolean
+ * @see Kotlin Wrapper for MyBatis Plus
+ */
+ fun checkAdmin(roleIdList: @NotEmpty List): Boolean
+
+ /**
+ * Gets list for exporting.
+ *
+ * @return the list for exporting
+ */
+ fun getListForExporting(): List
+
+ /**
+ * Validate before add to bean list boolean.
+ *
+ * @param beanList the bean list
+ * @param bean the bean
+ * @param index the index
+ * @throws IllegalArgumentException the illegal argument exception
+ */
+ fun validateBeforeAddToBeanList(beanList: List, bean: RoleExcelBean, index: Int)
+
+ /**
+ * Save.
+ *
+ * @param beanList the bean list
+ */
+ fun save(beanList: @NotEmpty List)
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleDomainServiceImpl.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleDomainServiceImpl.kt
new file mode 100644
index 00000000..8df5d3c8
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleDomainServiceImpl.kt
@@ -0,0 +1,110 @@
+package com.jmsoftware.maf.authcenter.role.service.impl
+
+import cn.hutool.core.collection.CollUtil
+import cn.hutool.core.text.CharSequenceUtil
+import cn.hutool.core.util.RandomUtil
+import cn.hutool.core.util.StrUtil
+import cn.hutool.extra.validation.ValidationUtil
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.jmsoftware.maf.authcenter.role.RoleExcelBean
+import com.jmsoftware.maf.authcenter.role.constant.RoleRedisKey.GET_ROLE_LIST_BY_USER_ID
+import com.jmsoftware.maf.authcenter.role.mapper.RoleMapper
+import com.jmsoftware.maf.authcenter.role.persistence.Role
+import com.jmsoftware.maf.authcenter.role.service.RoleDomainService
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse
+import com.jmsoftware.maf.common.exception.InternalServerException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.function.lazyDebug
+import com.jmsoftware.maf.springcloudstarter.function.requireTrue
+import com.jmsoftware.maf.springcloudstarter.property.MafConfigurationProperties
+import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties
+import org.springframework.data.redis.core.RedisTemplate
+import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import java.util.concurrent.TimeUnit
+import javax.validation.constraints.NotEmpty
+import javax.validation.constraints.NotNull
+
+/**
+ * # RoleDomainServiceImpl
+ *
+ * Domain Service implementation of Role. (Role)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 5:25 PM
+ */
+@Service
+class RoleDomainServiceImpl(
+ private val mafProjectProperties: MafProjectProperties,
+ private val mafConfigurationProperties: MafConfigurationProperties,
+ private val redisTemplate: RedisTemplate,
+ private val objectMapper: ObjectMapper
+) : ServiceImpl(), RoleDomainService {
+ companion object {
+ private val logger = logger()
+ }
+
+ override fun getRoleList(userId: @NotNull Long): GetRoleListByUserIdResponse {
+ val key = "${mafProjectProperties.projectParentArtifactId}${GET_ROLE_LIST_BY_USER_ID.keyInfixFormat}$userId"
+ val hadKey = redisTemplate.hasKey(key)
+ if (hadKey) {
+ return objectMapper.readValue(redisTemplate.opsForValue()[key], GetRoleListByUserIdResponse::class.java)
+ }
+ val response = GetRoleListByUserIdResponse()
+ response.roleList = getRoleListByUserId(userId)
+ redisTemplate.opsForValue()[key, objectMapper.writeValueAsString(response), RandomUtil.randomLong(1, 7)] =
+ TimeUnit.DAYS
+ return response
+ }
+
+ override fun getRoleListByUserId(userId: Long): List {
+ return getBaseMapper().selectRoleListByUserId(userId)
+ }
+
+ override fun checkAdmin(roleIdList: @NotEmpty List): Boolean {
+ // If roleNameSet is not empty (contains "admin")
+ return this.ktQuery()
+ .select(Role::name)
+ .`in`(Role::id, roleIdList)
+ .list()
+ .stream()
+ .map { item -> item.name }
+ .anyMatch { roleName: String ->
+ StrUtil.equals(mafConfigurationProperties.superUserRole, roleName)
+ }
+ }
+
+ override fun getListForExporting(): List {
+ return this.page(Page(1, 500))
+ .records
+ .stream()
+ .map { role: Role -> RoleExcelBean.transformBy(role) }
+ .toList()
+ }
+
+ override fun validateBeforeAddToBeanList(beanList: List, bean: RoleExcelBean, index: Int) {
+ val beanValidationResult = ValidationUtil.warpValidate(bean)
+ if (!beanValidationResult.isSuccess) {
+ logger.warn("Validation failed! beanList: $beanList, bean: $bean, index: $index")
+ val firstErrorMessage = CollUtil.getFirst(beanValidationResult.errorMessages)
+ throw IllegalArgumentException(
+ CharSequenceUtil.format("{} {}", firstErrorMessage.propertyName, firstErrorMessage.message)
+ )
+ }
+ }
+
+ @Transactional(rollbackFor = [Throwable::class])
+ override fun save(beanList: @NotEmpty List) {
+ val roleList = beanList
+ .stream()
+ .map { roleExcelBean: RoleExcelBean -> RoleExcelBean.transformTo(roleExcelBean) }
+ .toList()
+ lazyDebug(logger) { "Saving roleList: $roleList" }
+ requireTrue(this.saveBatch(roleList)) { saved: Boolean ->
+ logger.info("Saved role list: $saved")
+ }.orElseThrow { InternalServerException("Failed to save roles! Transaction rollback") }
+ }
+}
+
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/package-info.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/package-info.kt
new file mode 100644
index 00000000..70ab7551
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.security
diff --git a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.java b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.kt
similarity index 53%
rename from auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.java
rename to auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.kt
index ed8dd38d..02a9d42c 100644
--- a/auth-center/auth-center-biz/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.java
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/service/JwtService.kt
@@ -1,25 +1,24 @@
-package com.jmsoftware.maf.authcenter.security.service;
+package com.jmsoftware.maf.authcenter.security.service
-import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import io.jsonwebtoken.Claims;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.validation.annotation.Validated;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.Collection;
-import java.util.List;
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse
+import com.jmsoftware.maf.common.exception.SecurityException
+import io.jsonwebtoken.Claims
+import org.springframework.security.core.Authentication
+import org.springframework.security.core.GrantedAuthority
+import org.springframework.validation.annotation.Validated
+import javax.servlet.http.HttpServletRequest
+import javax.validation.constraints.NotBlank
+import javax.validation.constraints.NotNull
/**
- * JwtService
- *
+ * # JwtService
+ *
* Change description here.
*
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/29/2020 10:44 AM
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 8:47 PM
*/
@Validated
-public interface JwtService {
+interface JwtService {
/**
* Create JWT string.
*
@@ -27,7 +26,7 @@ public interface JwtService {
* @param rememberMe the remember me
* @return the string
*/
- String createJwt(Authentication authentication, Boolean rememberMe);
+ fun createJwt(@NotNull authentication: Authentication, @NotNull rememberMe: Boolean): String
/**
* Create JWT string.
@@ -39,8 +38,13 @@ public interface JwtService {
* @param authorities the authorities
* @return the JWT string
*/
- String createJwt(Boolean rememberMe, Long id, String subject, List roles, Collection
- extends GrantedAuthority> authorities);
+ fun createJwt(
+ @NotNull rememberMe: Boolean,
+ @NotNull id: Long,
+ @NotBlank subject: String,
+ roles: List,
+ authorities: Collection
+ ): String
/**
* Parse JWT.
@@ -49,7 +53,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
* @return the claims
* @throws SecurityException the security exception
*/
- Claims parseJwt(String jwt) throws SecurityException;
+ fun parseJwt(@NotBlank jwt: String): Claims
/**
* Invalidate jwt.
@@ -57,7 +61,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
* @param request the request
* @throws SecurityException the security exception
*/
- void invalidateJwt(HttpServletRequest request) throws SecurityException;
+ fun invalidateJwt(@NotNull request: HttpServletRequest)
/**
* Gets username from jwt.
@@ -66,7 +70,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
* @return the username from jwt
* @throws SecurityException the security exception
*/
- String getUsernameFromJwt(String jwt) throws SecurityException;
+ fun getUsernameFromJwt(@NotBlank jwt: String): String
/**
* Gets username from request.
@@ -75,7 +79,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
* @return the username from request
* @throws SecurityException the security exception
*/
- String getUsernameFromRequest(HttpServletRequest request) throws SecurityException;
+ fun getUsernameFromRequest(@NotNull request: HttpServletRequest): String
/**
* Gets jwt from request.
@@ -83,7 +87,7 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
* @param request the request
* @return the jwt from request
*/
- String getJwtFromRequest(HttpServletRequest request);
+ fun getJwtFromRequest(@NotNull request: HttpServletRequest): String
/**
* Parse parse jwt response.
@@ -91,5 +95,5 @@ String createJwt(Boolean rememberMe, Long id, String subject, List roles
* @param request the request
* @return the parse jwt response
*/
- ParseJwtResponse parse(HttpServletRequest request);
+ fun parse(@NotNull request: HttpServletRequest): ParseJwtResponse
}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.kt
new file mode 100644
index 00000000..acbd2ac8
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImpl.kt
@@ -0,0 +1,170 @@
+package com.jmsoftware.maf.authcenter.security.service.impl
+
+import cn.hutool.core.date.DateUtil
+import cn.hutool.core.text.CharSequenceUtil
+import cn.hutool.core.util.ObjectUtil
+import com.jmsoftware.maf.authcenter.security.service.JwtService
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse
+import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.property.JwtConfigurationProperties
+import io.jsonwebtoken.*
+import io.jsonwebtoken.security.Keys
+import org.springframework.data.redis.core.RedisTemplate
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
+import org.springframework.security.core.Authentication
+import org.springframework.security.core.GrantedAuthority
+import org.springframework.stereotype.Service
+import java.nio.charset.StandardCharsets
+import java.util.*
+import java.util.concurrent.TimeUnit
+import javax.annotation.PostConstruct
+import javax.crypto.SecretKey
+import javax.servlet.http.HttpServletRequest
+import javax.validation.constraints.NotBlank
+import javax.validation.constraints.NotNull
+
+/**
+ * # JwtServiceImpl
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 9:27 PM
+ */
+@Service
+class JwtServiceImpl(
+ private val jwtConfigurationProperties: JwtConfigurationProperties,
+ private val redisTemplate: RedisTemplate
+) : JwtService {
+ companion object {
+ private val log = logger()
+ }
+
+ private lateinit var secretKey: SecretKey
+ private lateinit var jwtParser: JwtParser
+
+ @PostConstruct
+ fun init() {
+ log.info("Start to init class members of ${this.javaClass.simpleName}")
+ secretKey = Keys.hmacShaKeyFor(
+ jwtConfigurationProperties.signingKey.toByteArray(StandardCharsets.UTF_8)
+ )
+ jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build()
+ log.warn("Secret key for JWT parser was generated. Algorithm: ${secretKey.algorithm}")
+ }
+
+ override fun createJwt(@NotNull authentication: Authentication, @NotNull rememberMe: Boolean): String {
+ val userPrincipal = authentication.principal as UserPrincipal
+ return this.createJwt(
+ rememberMe,
+ userPrincipal.id!!,
+ userPrincipal.usernameProperty!!,
+ userPrincipal.roles!!,
+ userPrincipal.authoritiesProperty!!
+ )
+ }
+
+ override fun createJwt(
+ @NotNull rememberMe: Boolean,
+ @NotNull id: Long,
+ @NotNull subject: String,
+ roles: List,
+ authorities: Collection
+ ): String {
+ val now = Date()
+ val builder = Jwts.builder()
+ .setId(id.toString())
+ .setSubject(subject)
+ .setIssuedAt(now)
+ .signWith(secretKey)
+ .claim("roles", roles)
+ // Don't generate authority information in JWT.
+ // .claim("authorities", authorities)
+ // Set expire duration of JWT.
+ val ttl = if (rememberMe) jwtConfigurationProperties.ttlForRememberMe else jwtConfigurationProperties.ttl
+ if (ttl > 0) {
+ builder.setExpiration(DateUtil.offsetMillisecond(now, ttl.toInt()))
+ }
+ val jwt = builder.compact()
+ // Store new JWT in Redis
+ val redisKeyOfJwt = "${jwtConfigurationProperties.jwtRedisKeyPrefix}$subject"
+ redisTemplate.opsForValue()[redisKeyOfJwt, jwt, ttl] = TimeUnit.MILLISECONDS
+ log.info("Storing JWT in Redis. Key: $redisKeyOfJwt, Value: $jwt")
+ return jwt
+ }
+
+ override fun parseJwt(@NotBlank jwt: String): Claims {
+ val claims: Claims = try {
+ Optional.ofNullable(jwtParser.parseClaimsJws(jwt).body)
+ .orElseThrow {
+ SecurityException(HttpStatus.INTERNAL_SERVER_ERROR, "The JWT Claims Set is null")
+ }
+ } catch (e: ExpiredJwtException) {
+ log.error("JWT is expired. Message: ${e.message}, JWT: $jwt")
+ throw SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (JWT itself)")
+ } catch (e: UnsupportedJwtException) {
+ log.error("JWT is unsupported. Message: ${e.message}, JWT: $jwt")
+ throw SecurityException(HttpStatus.UNAUTHORIZED, "JWT is unsupported")
+ } catch (e: MalformedJwtException) {
+ log.error("JWT is invalid. Message: ${e.message}, JWT: $jwt")
+ throw SecurityException(HttpStatus.UNAUTHORIZED, "JWT is invalid")
+ } catch (e: IllegalArgumentException) {
+ log.error("The parameter of JWT is invalid. Message: ${e.message}, JWT: $jwt")
+ throw SecurityException(HttpStatus.UNAUTHORIZED, "The parameter of JWT is invalid")
+ }
+ val username = claims.subject
+ val redisKeyOfJwt = jwtConfigurationProperties.jwtRedisKeyPrefix + username
+ // Check if JWT exists
+ val expire = redisTemplate.opsForValue().operations.getExpire(redisKeyOfJwt, TimeUnit.MILLISECONDS)
+ if (ObjectUtil.isNull(expire) || expire!! <= 0) {
+ throw SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Redis expiration)")
+ }
+ // Check if the current JWT is equal to the one in Redis.
+ // If it's noe equal, that indicates current user has signed out or logged in before.
+ // Both situations reveal the JWT has expired.
+ val jwtInRedis = redisTemplate.opsForValue()[redisKeyOfJwt] as String?
+ if (!CharSequenceUtil.equals(jwt, jwtInRedis)) {
+ throw SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Not equaled)")
+ }
+ return claims
+ }
+
+ override fun invalidateJwt(@NotNull request: HttpServletRequest) {
+ val jwt = getJwtFromRequest(request)
+ val username = getUsernameFromJwt(jwt)
+ // Delete JWT from redis
+ val redisKeyOfJwt = "${jwtConfigurationProperties.jwtRedisKeyPrefix}$username"
+ val deletedKeyNumber = redisTemplate.opsForValue().operations.delete(redisKeyOfJwt)
+ log.error("Invalidate JWT. Redis key of JWT = $redisKeyOfJwt, deleted = $deletedKeyNumber")
+ }
+
+ override fun getUsernameFromJwt(@NotBlank jwt: String): String {
+ val claims = parseJwt(jwt)
+ return claims.subject
+ }
+
+ override fun getUsernameFromRequest(@NotNull request: HttpServletRequest): String {
+ val jwt = getJwtFromRequest(request)
+ return getUsernameFromJwt(jwt)
+ }
+
+ override fun getJwtFromRequest(@NotNull request: HttpServletRequest): String {
+ val bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION)
+ return if (CharSequenceUtil.isNotBlank(bearerToken)
+ && bearerToken.startsWith(JwtConfigurationProperties.TOKEN_PREFIX)
+ ) {
+ bearerToken.substring(JwtConfigurationProperties.TOKEN_PREFIX.length)
+ } else null.toString()
+ }
+
+ override fun parse(@NotNull request: HttpServletRequest): ParseJwtResponse {
+ val jwt = getJwtFromRequest(request)
+ val claims = parseJwt(jwt)
+ val parseJwtResponse = ParseJwtResponse()
+ parseJwtResponse.id = claims.id.toLong()
+ parseJwtResponse.username = claims.subject
+ return parseJwtResponse
+ }
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.kt
new file mode 100644
index 00000000..b707e02d
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter.user
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserDomainService.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserDomainService.kt
new file mode 100644
index 00000000..20f58abe
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserDomainService.kt
@@ -0,0 +1,74 @@
+package com.jmsoftware.maf.authcenter.user.service
+
+import com.baomidou.mybatisplus.extension.service.IService
+import com.jmsoftware.maf.authcenter.user.payload.GetUserPageListPayload
+import com.jmsoftware.maf.authcenter.user.payload.GetUserStatusPayload
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.common.bean.PageResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.user.*
+import com.jmsoftware.maf.common.exception.SecurityException
+import org.springframework.validation.annotation.Validated
+import javax.servlet.http.HttpServletRequest
+import javax.validation.Valid
+import javax.validation.constraints.NotBlank
+import javax.validation.constraints.NotNull
+
+/**
+ * # UserDomainService
+ *
+ * Service of UserPersistence. (UserPersistence)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 7:41 AM
+ */
+@Validated
+interface UserDomainService : IService {
+ /**
+ * Gets user by login token.
+ *
+ * @param loginToken the login token
+ * @return the user by login token
+ */
+ fun getUserByLoginToken(loginToken: @NotBlank String): GetUserByLoginTokenResponse?
+
+ /**
+ * Save user for registering save user for registering response.
+ *
+ * @param payload the payload
+ * @return the save user for registering response
+ */
+ fun saveUserForSignup(payload: @Valid SignupPayload): SignupResponse
+
+ /**
+ * Login login response.
+ *
+ * @param payload the payload
+ * @return the login response
+ * @throws SecurityException the security exception
+ */
+ fun login(payload: @Valid LoginPayload): LoginResponse
+
+ /**
+ * Logout boolean.
+ *
+ * @param request the request
+ * @return the boolean
+ * @throws SecurityException the security exception
+ */
+ fun logout(request: HttpServletRequest): Boolean
+
+ /**
+ * Gets user status.
+ *
+ * @param payload the payload
+ * @return the user status
+ */
+ fun getUserStatus(payload: @Valid @NotNull GetUserStatusPayload): String
+
+ /**
+ * Gets user page list.
+ *
+ * @param payload the payload
+ * @return the user page list
+ */
+ fun getUserPageList(payload: @Valid @NotNull GetUserPageListPayload): PageResponseBodyBean
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserRoleDomainService.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserRoleDomainService.kt
new file mode 100644
index 00000000..67b113da
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/UserRoleDomainService.kt
@@ -0,0 +1,23 @@
+package com.jmsoftware.maf.authcenter.user.service
+
+import com.baomidou.mybatisplus.extension.service.IService
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.authcenter.user.persistence.UserRole
+import org.springframework.validation.annotation.Validated
+import javax.validation.constraints.NotBlank
+
+/**
+ * # UserRoleDomainService
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 10:09 AM
+ */
+@Validated
+interface UserRoleDomainService : IService {
+ /**
+ * Assign role by role name.
+ *
+ * @param user the user
+ * @param roleName the role name
+ */
+ fun assignRoleByRoleName(user: User, roleName: @NotBlank String)
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserDomainServiceImpl.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserDomainServiceImpl.kt
new file mode 100644
index 00000000..1b8cc8a4
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserDomainServiceImpl.kt
@@ -0,0 +1,140 @@
+package com.jmsoftware.maf.authcenter.user.service.impl
+
+import cn.hutool.core.collection.ListUtil
+import cn.hutool.core.text.CharSequenceUtil
+import cn.hutool.core.util.ObjectUtil
+import cn.hutool.core.util.RandomUtil
+import cn.hutool.json.JSONUtil
+import com.baomidou.mybatisplus.core.metadata.OrderItem
+import com.baomidou.mybatisplus.core.toolkit.Wrappers
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
+import com.jmsoftware.maf.authcenter.security.service.JwtService
+import com.jmsoftware.maf.authcenter.user.constant.UserRedisKey
+import com.jmsoftware.maf.authcenter.user.converter.UserMapStructMapper
+import com.jmsoftware.maf.authcenter.user.mapper.UserMapper
+import com.jmsoftware.maf.authcenter.user.payload.GetUserPageListPayload
+import com.jmsoftware.maf.authcenter.user.payload.GetUserStatusPayload
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.authcenter.user.service.UserDomainService
+import com.jmsoftware.maf.authcenter.user.service.UserRoleDomainService
+import com.jmsoftware.maf.common.bean.PageResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.user.*
+import com.jmsoftware.maf.common.enumeration.ValueDescriptionBaseEnum
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.property.MafConfigurationProperties
+import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties
+import com.jmsoftware.maf.springcloudstarter.util.currentUsername
+import org.springframework.cache.annotation.CacheConfig
+import org.springframework.context.MessageSource
+import org.springframework.context.i18n.LocaleContextHolder
+import org.springframework.data.redis.core.RedisTemplate
+import org.springframework.http.HttpStatus
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
+import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import java.util.concurrent.TimeUnit
+import javax.servlet.http.HttpServletRequest
+import javax.validation.Valid
+import javax.validation.constraints.NotBlank
+import javax.validation.constraints.NotNull
+
+/**
+ * # UserDomainServiceImpl
+ *
+ * Service implementation of UserPersistence.(UserPersistence)
+ *
+ * @author Johnny Miller (锺俊), date 2020-05-10 12:08:28
+ */
+@Service
+@CacheConfig(cacheNames = ["user-service-cache"])
+class UserDomainServiceImpl(
+ private val bCryptPasswordEncoder: BCryptPasswordEncoder,
+ private val jwtService: JwtService,
+ private val messageSource: MessageSource,
+ private val mafProjectProperties: MafProjectProperties,
+ private val redisTemplate: RedisTemplate,
+ private val userRoleDomainService: UserRoleDomainService,
+ private val mafConfigurationProperties: MafConfigurationProperties,
+) : ServiceImpl(), UserDomainService {
+ companion object {
+ private val logger = logger()
+ }
+
+ override fun getUserByLoginToken(loginToken: @NotBlank String): GetUserByLoginTokenResponse? {
+ val key =
+ "${mafProjectProperties.projectParentArtifactId}${UserRedisKey.GET_USER_BY_LOGIN_TOKEN.keyInfixFormat}$loginToken"
+ val hasKey = redisTemplate.hasKey(key)
+ if (hasKey) {
+ return JSONUtil.toBean(redisTemplate.opsForValue()[key], GetUserByLoginTokenResponse::class.java)
+ }
+ val user = this.ktQuery().eq(User::username, loginToken).one()
+ if (ObjectUtil.isNull(user)) {
+ return null
+ }
+ val response = UserMapStructMapper.INSTANCE.of(user)
+ redisTemplate.opsForValue()[key, JSONUtil.toJsonStr(response), RandomUtil.randomLong(1, 7)] = TimeUnit.DAYS
+ return response
+ }
+
+ @Transactional(rollbackFor = [Throwable::class])
+ override fun saveUserForSignup(payload: @Valid SignupPayload): SignupResponse {
+ val user = User()
+ user.username = payload.username
+ user.email = payload.email
+ user.password = bCryptPasswordEncoder.encode(payload.password)
+ user.status = UserStatus.ENABLED.value
+ save(user)
+ logger.warn("Saved user for signup, going to assign guest role to user. $user")
+ userRoleDomainService.assignRoleByRoleName(user, mafConfigurationProperties.guestUserRole)
+ val response = SignupResponse()
+ response.userId = user.id
+ return response
+ }
+
+ override fun login(payload: @Valid LoginPayload): LoginResponse {
+ val user = getUserByLoginToken(payload.loginToken) ?: throw SecurityException(HttpStatus.UNAUTHORIZED)
+ logger.info("User login: $user")
+ val matched = bCryptPasswordEncoder.matches(payload.password, user.password)
+ if (!matched) {
+ throw SecurityException(HttpStatus.UNAUTHORIZED)
+ }
+ val jwt = jwtService.createJwt(payload.rememberMe, user.id!!, user.username!!, listOf(), listOf())
+ val response = LoginResponse()
+ response.greeting = messageSource.getMessage(
+ "greeting",
+ null,
+ LocaleContextHolder.getLocale()
+ )
+ response.jwt = jwt
+ return response
+ }
+
+ override fun logout(request: HttpServletRequest): Boolean {
+ jwtService.invalidateJwt(request)
+ return true
+ }
+
+ override fun getUserStatus(payload: @Valid @NotNull GetUserStatusPayload): String {
+ logger.info("Current username: {}", currentUsername())
+ return ValueDescriptionBaseEnum.getDescriptionByValue(UserStatus::class.java, payload.status)
+ }
+
+ override fun getUserPageList(payload: @Valid @NotNull GetUserPageListPayload): PageResponseBodyBean {
+ logger.info("{}", payload)
+ val page = Page(
+ payload.currentPage.toLong(), payload.pageSize.toLong()
+ )
+ val queryWrapper = Wrappers.lambdaQuery(
+ User::class.java
+ )
+ if (CharSequenceUtil.isNotBlank(payload.username)) {
+ queryWrapper.like(SFunction { obj: User -> obj.username }, payload.username)
+ }
+ page.orders = ListUtil.of(OrderItem.desc(payload.orderBy))
+ this.page(page, queryWrapper)
+ return PageResponseBodyBean.ofSuccess(page.records, page.total)
+ }
+}
diff --git a/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleDomainServiceImpl.kt b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleDomainServiceImpl.kt
new file mode 100644
index 00000000..23417f63
--- /dev/null
+++ b/auth-center/auth-center-domain/src/main/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleDomainServiceImpl.kt
@@ -0,0 +1,40 @@
+package com.jmsoftware.maf.authcenter.user.service.impl
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
+import com.jmsoftware.maf.authcenter.role.persistence.Role
+import com.jmsoftware.maf.authcenter.role.service.RoleDomainService
+import com.jmsoftware.maf.authcenter.user.mapper.UserRoleMapper
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.authcenter.user.persistence.UserRole
+import com.jmsoftware.maf.authcenter.user.service.UserRoleDomainService
+import com.jmsoftware.maf.common.exception.InternalServerException
+import com.jmsoftware.maf.springcloudstarter.function.requireTrue
+import org.springframework.stereotype.Service
+import java.util.*
+
+/**
+ * # UserRoleDomainServiceImplKt
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, 4/12/22 10:28 AM
+ **/
+@Service
+class UserRoleDomainServiceImpl(
+ private val roleDomainService: RoleDomainService
+) : ServiceImpl(), UserRoleDomainService {
+ override fun assignRoleByRoleName(user: User, roleName: String) {
+ val role = Optional.ofNullable(
+ roleDomainService.ktQuery()
+ .select(Role::id)
+ .eq(Role::name, roleName)
+ .one()
+ ).orElseThrow { InternalServerException("Cannot find the role: $roleName") }
+ val userRole = UserRole()
+ userRole.userId = user.id
+ userRole.roleId = role.id
+ requireTrue(save(userRole), null).orElseThrow {
+ InternalServerException("Cannot assign role ($roleName) to user (${user.username})")
+ }
+ }
+}
diff --git a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/package-info.java b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
deleted file mode 100644
index e702ef59..00000000
--- a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter;
diff --git a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionDomainServiceImplTest.kt b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionDomainServiceImplTest.kt
new file mode 100644
index 00000000..d0f3b21b
--- /dev/null
+++ b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/permission/service/impl/PermissionDomainServiceImplTest.kt
@@ -0,0 +1,79 @@
+package com.jmsoftware.maf.authcenter.permission.service.impl
+
+import com.jmsoftware.maf.authcenter.permission.mapper.PermissionMapper
+import com.jmsoftware.maf.authcenter.permission.persistence.Permission
+import com.jmsoftware.maf.common.util.logger
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertNotNull
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.mockito.Mockito.*
+import org.mockito.junit.jupiter.MockitoExtension
+
+/**
+ * # PermissionDomainServiceImplTest
+ *
+ * Description: PermissionDomainServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ *
+ * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com, date: 4/4/2022 8:40 AM
+ * @see Using Mockito with JUnit 5
+ * @see YouTube - Using Mockito with JUnit 5
+ */
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class PermissionDomainServiceImplTest {
+ companion object {
+ private val log = logger()
+ }
+
+ @InjectMocks
+ private lateinit var permissionDomainService: PermissionDomainServiceImpl
+
+ @Mock
+ private lateinit var permissionMapper: PermissionMapper
+
+ @BeforeEach
+ fun setUp() {
+ log.info("${this.javaClass.simpleName} setUp")
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("${this.javaClass.simpleName} tearDown")
+ }
+
+ @Test
+ fun getPermissionListByRoleIdList() {
+ val permission = Permission()
+ permission.id = 1
+ `when`(permissionMapper.selectPermissionListByRoleIdList(anyList(), anyList()))
+ .thenReturn(listOf(permission))
+ val permissionList = permissionDomainService.getPermissionListByRoleIdList(listOf(), listOf())
+ log.info("permissionList: $permissionList")
+ verify(permissionMapper)
+ .selectPermissionListByRoleIdList(anyList(), anyList())
+ assertNotNull(permissionList)
+ }
+}
diff --git a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/remote/impl/OssCenterFeignServiceImplTest.kt b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/remote/impl/OssCenterFeignServiceImplTest.kt
new file mode 100644
index 00000000..287e02af
--- /dev/null
+++ b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/remote/impl/OssCenterFeignServiceImplTest.kt
@@ -0,0 +1,82 @@
+package com.jmsoftware.maf.authcenter.remote.impl
+
+import com.jmsoftware.maf.authcenter.remote.OssCenterFeignClient
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.osscenter.write.ObjectResponse
+import com.jmsoftware.maf.common.util.logger
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertNotNull
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.junit.jupiter.MockitoExtension
+import org.springframework.mock.web.MockMultipartFile
+
+/**
+ * # OssCenterFeignServiceImplTest
+ *
+ * Description: OssCenterFeignServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 12:38 PM
+ * @see Using Mockito with JUnit 5
+ * @see YouTube - Using Mockito with JUnit 5
+ */
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class OssCenterFeignServiceImplTest {
+ companion object {
+ private val log = logger()
+ }
+
+ @InjectMocks
+ private lateinit var ossCenterFeignService: OssCenterFeignServiceImpl
+
+ @Mock
+ private lateinit var ossCenterFeignClient: OssCenterFeignClient
+
+ @BeforeEach
+ fun setUp() {
+ log.info("{} setUp", this.javaClass.simpleName)
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("{} tearDown", this.javaClass.simpleName)
+ }
+
+ @Test
+ fun uploadSingleResource() {
+ val multipartFile = MockMultipartFile(
+ "name-for-unit-test.txt",
+ "original-filename.txt",
+ null,
+ null
+ )
+ `when`(ossCenterFeignClient.uploadSingleResource(multipartFile))
+ .thenReturn(ResponseBodyBean.ofSuccess(ObjectResponse()))
+ val objectResponse = ossCenterFeignService.uploadSingleResource(multipartFile)
+ assertNotNull(objectResponse)
+ log.info("Pass: PermissionServiceImplTest#uploadSingleResource. $objectResponse")
+ }
+}
diff --git a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleDomainServiceImplTest.kt b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleDomainServiceImplTest.kt
new file mode 100644
index 00000000..baa506a4
--- /dev/null
+++ b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/role/service/impl/RoleDomainServiceImplTest.kt
@@ -0,0 +1,155 @@
+package com.jmsoftware.maf.authcenter.role.service.impl
+
+import cn.hutool.core.collection.CollUtil
+import com.baomidou.mybatisplus.core.MybatisConfiguration
+import com.baomidou.mybatisplus.core.metadata.TableInfoHelper
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.jmsoftware.maf.authcenter.role.RoleExcelBean
+import com.jmsoftware.maf.authcenter.role.mapper.RoleMapper
+import com.jmsoftware.maf.authcenter.role.persistence.Role
+import com.jmsoftware.maf.common.exception.InternalServerException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.property.MafConfigurationProperties
+import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties
+import org.apache.ibatis.builder.MapperBuilderAssistant
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.mockito.Mockito.*
+import org.mockito.Spy
+import org.mockito.junit.jupiter.MockitoExtension
+import org.springframework.data.redis.core.RedisTemplate
+import org.springframework.data.redis.core.ValueOperations
+
+/**
+ * # RoleDomainServiceImplTest
+ *
+ * Description: RoleDomainServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com, date: 4/4/2022 8:40 AM
+ * @see Using Mockito with JUnit 5
+ * @see YouTube - Using Mockito with JUnit 5
+ * WrapperTest.kt - MyBatis Plus
+ */
+@Suppress("unused")
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class RoleDomainServiceImplTest {
+ companion object {
+ private val log = logger()
+ }
+
+ @Spy
+ @InjectMocks
+ private lateinit var roleDomainService: RoleDomainServiceImpl
+
+ @Mock
+ private lateinit var roleMapper: RoleMapper
+
+ @Mock
+ private lateinit var mafProjectProperties: MafProjectProperties
+
+ @Mock
+ private lateinit var mafConfigurationProperties: MafConfigurationProperties
+
+ @Mock
+ private lateinit var redisTemplate: RedisTemplate
+
+ @Mock
+ private lateinit var valueOperations: ValueOperations
+
+ @Mock
+ private lateinit var objectMapper: ObjectMapper
+
+ /**
+ * Set up
+ *
+ * @see WrapperTest.kt - MyBatis Plus
+ */
+ @BeforeEach
+ fun setUp() {
+ log.info("{} setUp", this.javaClass.simpleName)
+ TableInfoHelper.initTableInfo(MapperBuilderAssistant(MybatisConfiguration(), ""), Role::class.java)
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("{} tearDown", this.javaClass.simpleName)
+ }
+
+ @Test
+ fun getRoleList() {
+ doReturn(roleMapper).`when`(roleDomainService).baseMapper
+ `when`(redisTemplate.hasKey(anyString())).thenReturn(false)
+ `when`(redisTemplate.opsForValue()).thenReturn(valueOperations)
+ val response = roleDomainService.getRoleList(1L)
+ log.info("roleListResponse: $response")
+ assertNotNull(response)
+ assertTrue(CollUtil.isEmpty(response.roleList))
+ }
+
+ @Test
+ fun roleListByUserId() {
+ doReturn(roleMapper).`when`(roleDomainService).baseMapper
+ val roleList = roleDomainService.getRoleListByUserId(1L)
+ log.info("roleList: $roleList")
+ assertNotNull(roleList)
+ assertTrue(CollUtil.isEmpty(roleList))
+ }
+
+ @Test
+ fun checkAdmin() {
+ doReturn(roleMapper).`when`(roleDomainService).baseMapper
+ val admin = roleDomainService.checkAdmin(listOf(1L))
+ log.info("admin: $admin")
+ assertFalse(admin)
+ }
+
+ @Test
+ fun listForExporting() {
+ doReturn(roleMapper).`when`(roleDomainService).baseMapper
+ val thrownException = assertThrows(NullPointerException::class.java) { roleDomainService.getListForExporting() }
+ log.warn("thrownException for listForExporting(): $thrownException")
+ }
+
+ @Test
+ fun validateBeforeAddToBeanList() {
+ val roleExcelBean = RoleExcelBean()
+ val thrownException = assertThrows(IllegalArgumentException::class.java) {
+ roleDomainService.validateBeforeAddToBeanList(
+ listOf(roleExcelBean),
+ roleExcelBean,
+ 0
+ )
+ }
+ log.info("Exception thrown: ${thrownException.message}")
+ }
+
+ @Test
+ fun save() {
+ val thrownException = assertThrows(InternalServerException::class.java) { roleDomainService.save(listOf()) }
+ log.warn("thrownException for save(): $thrownException")
+ }
+}
diff --git a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImplTest.kt b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImplTest.kt
new file mode 100644
index 00000000..f132e058
--- /dev/null
+++ b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/security/service/impl/JwtServiceImplTest.kt
@@ -0,0 +1,148 @@
+package com.jmsoftware.maf.authcenter.security.service.impl
+
+import cn.hutool.core.util.StrUtil
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.property.JwtConfigurationProperties
+import io.jsonwebtoken.Claims
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.mockito.Mockito.*
+import org.mockito.Spy
+import org.mockito.junit.jupiter.MockitoExtension
+import org.springframework.data.redis.core.RedisTemplate
+import org.springframework.data.redis.core.ValueOperations
+import java.util.concurrent.atomic.AtomicReference
+import javax.servlet.http.HttpServletRequest
+
+
+/**
+ * # JwtServiceImplTest
+ *
+ * Description: JwtServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 9:29 PM
+ * @see Using Mockito with JUnit 5
+ * @see YouTube - Using Mockito with JUnit 5
+ */
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class JwtServiceImplTest {
+ companion object {
+ private val log = logger()
+ private const val USER_ID = 1L
+ private const val USERNAME = "ijohnnymiller"
+ private const val JWT = "eyJhbGciOiJIUzM4NCJ9" +
+ ".eyJqdGkiOiIxIiwic3ViIjoiaWpvaG5ueW1pbGxlciIsImlhdCI6MTY0OTA0NTgzMiwicm9sZXMiOltdfQ" +
+ ".lMQDOTnNsZTaopDBf7O_4zlhPJTZmGB3v6MpjmWnPuMEb2Aj-bXciDh4m2pAYtEp"
+ }
+
+ @Spy
+ @InjectMocks
+ private lateinit var jwtService: JwtServiceImpl
+
+ @Mock
+ private lateinit var jwtConfigurationProperties: JwtConfigurationProperties
+
+ @Mock
+ private lateinit var redisTemplate: RedisTemplate
+
+ @Mock
+ private lateinit var valueOperations: ValueOperations
+
+ @Mock
+ private lateinit var httpServletRequest: HttpServletRequest
+
+ @BeforeEach
+ fun setUp() {
+ log.info("${this.javaClass.simpleName} setUp")
+ `when`(jwtConfigurationProperties.signingKey)
+ .thenReturn("signing-key-for-unit-test-only-do-not-use-in-production")
+ jwtService.init()
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("{} tearDown", this.javaClass.simpleName)
+ }
+
+ @Test
+ fun createJwt() {
+ `when`(redisTemplate.opsForValue()).thenReturn(valueOperations)
+ doNothing().`when`(valueOperations)[anyString(), anyString(), anyLong()] = any()
+ val jwt = jwtService.createJwt(true, USER_ID, USERNAME, listOf(), listOf())
+ assertNotEquals(0, jwt.length)
+ }
+
+ @Test
+ fun parseJwt() {
+ `when`(redisTemplate.opsForValue()).thenReturn(valueOperations)
+ `when`(valueOperations.operations).thenReturn(redisTemplate)
+ val claimsAtomicReference = AtomicReference()
+ assertThrows(SecurityException::class.java) { claimsAtomicReference.set(jwtService.parseJwt(JWT)) }
+ log.info("Parse JWT. claimsAtomicReference: ${claimsAtomicReference.hashCode()}")
+ assertNotNull(claimsAtomicReference)
+ assertNull(claimsAtomicReference.get())
+ }
+
+ @Test
+ fun invalidateJwt() {
+ `when`(redisTemplate.opsForValue()).thenReturn(valueOperations)
+ `when`(valueOperations.operations).thenReturn(redisTemplate)
+ doReturn(JWT).`when`(jwtService).getJwtFromRequest(httpServletRequest)
+ assertThrows(SecurityException::class.java) { jwtService.invalidateJwt(httpServletRequest) }
+ }
+
+ @Test
+ fun usernameFromJwt() {
+ `when`(redisTemplate.opsForValue()).thenReturn(valueOperations)
+ `when`(valueOperations.operations).thenReturn(redisTemplate)
+ assertThrows(SecurityException::class.java) { jwtService.getUsernameFromJwt(JWT) }
+ }
+
+ @Test
+ fun getUsernameFromRequest() {
+ `when`(redisTemplate.opsForValue()).thenReturn(valueOperations)
+ `when`(valueOperations.operations).thenReturn(redisTemplate)
+ doReturn(JWT).`when`(jwtService).getJwtFromRequest(httpServletRequest)
+ val thrownException =
+ assertThrows(SecurityException::class.java) { jwtService.getUsernameFromRequest(httpServletRequest) }
+ log.warn("Thrown exception: ${thrownException.message}")
+ }
+
+ @Test
+ fun jwtFromRequest() {
+ val jwt = jwtService.getJwtFromRequest(httpServletRequest)
+ log.info("JWT: $jwt")
+ assertTrue(StrUtil.isNotBlank(jwt))
+ }
+
+ @Test
+ fun parse() {
+ val thrownException = assertThrows(SecurityException::class.java) { jwtService.parse(httpServletRequest) }
+ log.warn("Thrown exception: ${thrownException.message}")
+ }
+}
diff --git a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/user/service/impl/UserDomainServiceImplTest.kt b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/user/service/impl/UserDomainServiceImplTest.kt
new file mode 100644
index 00000000..0a820fae
--- /dev/null
+++ b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/user/service/impl/UserDomainServiceImplTest.kt
@@ -0,0 +1,167 @@
+package com.jmsoftware.maf.authcenter.user.service.impl
+
+import cn.hutool.core.collection.CollUtil
+import com.baomidou.mybatisplus.core.MybatisConfiguration
+import com.baomidou.mybatisplus.core.metadata.TableInfoHelper
+import com.jmsoftware.maf.authcenter.security.service.JwtService
+import com.jmsoftware.maf.authcenter.user.mapper.UserMapper
+import com.jmsoftware.maf.authcenter.user.payload.GetUserPageListPayload
+import com.jmsoftware.maf.authcenter.user.payload.GetUserStatusPayload
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.authcenter.user.service.UserRoleDomainService
+import com.jmsoftware.maf.common.domain.authcenter.user.LoginPayload
+import com.jmsoftware.maf.common.domain.authcenter.user.SignupPayload
+import com.jmsoftware.maf.common.exception.SecurityException
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.property.MafConfigurationProperties
+import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties
+import org.apache.ibatis.builder.MapperBuilderAssistant
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.mockito.Mockito.*
+import org.mockito.Spy
+import org.mockito.junit.jupiter.MockitoExtension
+import org.springframework.context.MessageSource
+import org.springframework.data.redis.core.RedisTemplate
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
+import javax.servlet.http.HttpServletRequest
+
+/**
+ * # UserDomainServiceImplTest
+ *
+ * Description: UserDomainServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 7:46 AM
+ * @see Using Mockito with JUnit 5
+ * @see YouTube - Using Mockito with JUnit 5
+ */
+@Suppress("unused")
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class UserDomainServiceImplTest {
+ companion object {
+ private const val USERNAME = "ijohnnymiller"
+ private val log = logger()
+ }
+
+ @Spy
+ @InjectMocks
+ lateinit var userDomainService: UserDomainServiceImpl
+
+ @Mock
+ lateinit var userMapper: UserMapper
+
+ @Mock
+ lateinit var bCryptPasswordEncoder: BCryptPasswordEncoder
+
+ @Mock
+ lateinit var jwtService: JwtService
+
+ @Mock
+ lateinit var messageSource: MessageSource
+
+ @Mock
+ lateinit var mafProjectProperties: MafProjectProperties
+
+ @Mock
+ lateinit var redisTemplate: RedisTemplate
+
+ @Mock
+ lateinit var userRoleDomainService: UserRoleDomainService
+
+ @Mock
+ lateinit var mafConfigurationProperties: MafConfigurationProperties
+
+ @Mock
+ lateinit var httpServletRequest: HttpServletRequest
+
+ @BeforeEach
+ fun setUp() {
+ log.info("{} setUp", this.javaClass.simpleName)
+ TableInfoHelper.initTableInfo(MapperBuilderAssistant(MybatisConfiguration(), ""), User::class.java)
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("{} tearDown", this.javaClass.simpleName)
+ }
+
+ @Test
+ fun getUserByLoginToken() {
+ doReturn(userMapper).`when`(userDomainService).baseMapper
+ val user = userDomainService.getUserByLoginToken(USERNAME)
+ log.info("User: {}", user)
+ assertNull(user)
+ }
+
+ @Test
+ fun saveUserForSignup() {
+ doReturn(userMapper).`when`(userDomainService).baseMapper
+ `when`(bCryptPasswordEncoder.encode(anyString())).thenReturn("encrypted-password-for-unit-test")
+ `when`(mafConfigurationProperties.guestUserRole).thenReturn("guest")
+ val payload = SignupPayload()
+ payload.username = USERNAME
+ payload.email = "johnnysviva@outlook.com"
+ payload.password = "password-for-unit-test"
+ val signupResponse = userDomainService.saveUserForSignup(payload)
+ log.info("Signup response: {}", signupResponse)
+ assertNotNull(signupResponse)
+ }
+
+ @Test
+ fun login() {
+ doReturn(userMapper).`when`(userDomainService).baseMapper
+ val payload = LoginPayload()
+ payload.loginToken = USERNAME
+ val thrownException = assertThrows(SecurityException::class.java) { userDomainService.login(payload) }
+ log.warn("Thrown exception: ${thrownException.message}")
+ }
+
+ @Test
+ fun logout() {
+ val logout = userDomainService.logout(httpServletRequest)
+ assertTrue(logout)
+ }
+
+ @Test
+ fun getUserStatus() {
+ val payload = GetUserStatusPayload()
+ payload.status = 1.toByte()
+ payload.status2 = 0.toByte()
+ val thrownException =
+ assertThrows(IllegalStateException::class.java) { userDomainService.getUserStatus(payload) }
+ log.warn("Thrown exception: ${thrownException.message}")
+ }
+
+ @Test
+ fun getUserPageList() {
+ doReturn(userMapper).`when`(userDomainService).baseMapper
+ val response = userDomainService.getUserPageList(GetUserPageListPayload())
+ log.info("User page list: {}", response)
+ assertNotNull(response)
+ assertTrue(CollUtil.isEmpty(response.list))
+ }
+}
diff --git a/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleDomainServiceImplTest.kt b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleDomainServiceImplTest.kt
new file mode 100644
index 00000000..928c67bb
--- /dev/null
+++ b/auth-center/auth-center-domain/src/test/java/com/jmsoftware/maf/authcenter/user/service/impl/UserRoleDomainServiceImplTest.kt
@@ -0,0 +1,96 @@
+package com.jmsoftware.maf.authcenter.user.service.impl
+
+import com.baomidou.mybatisplus.core.MybatisConfiguration
+import com.baomidou.mybatisplus.core.metadata.TableInfoHelper
+import com.baomidou.mybatisplus.extension.kotlin.KtQueryChainWrapper
+import com.jmsoftware.maf.authcenter.role.mapper.RoleMapper
+import com.jmsoftware.maf.authcenter.role.persistence.Role
+import com.jmsoftware.maf.authcenter.role.service.RoleDomainService
+import com.jmsoftware.maf.authcenter.user.mapper.UserRoleMapper
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.authcenter.user.persistence.UserRole
+import com.jmsoftware.maf.common.exception.InternalServerException
+import com.jmsoftware.maf.common.util.logger
+import org.apache.ibatis.builder.MapperBuilderAssistant
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertThrows
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Spy
+import org.mockito.junit.jupiter.MockitoExtension
+
+/**
+ * # UserRoleDomainServiceImplTest
+ *
+ * Description: UserRoleDomainServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 10:23 AM
+ * @see Using Mockito with JUnit 5
+ * @see YouTube - Using Mockito with JUnit 5
+ */
+@Suppress("unused")
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class UserRoleDomainServiceImplTest {
+ companion object {
+ private val log = logger()
+ }
+
+ @Spy
+ @InjectMocks
+ private lateinit var userRoleDomainService: UserRoleDomainServiceImpl
+
+ @Mock
+ private lateinit var userRoleMapper: UserRoleMapper
+
+ @Mock
+ private lateinit var roleMapper: RoleMapper
+
+ @Mock
+ private lateinit var roleDomainService: RoleDomainService
+
+ @BeforeEach
+ fun setUp() {
+ log.info("{} setUp", this.javaClass.simpleName)
+ TableInfoHelper.initTableInfo(MapperBuilderAssistant(MybatisConfiguration(), ""), UserRole::class.java)
+ TableInfoHelper.initTableInfo(MapperBuilderAssistant(MybatisConfiguration(), ""), Role::class.java)
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("{} tearDown", this.javaClass.simpleName)
+ }
+
+ @Test
+ fun assignRoleByRoleName() {
+ `when`(roleDomainService.ktQuery()).thenReturn(KtQueryChainWrapper(roleMapper, Role::class.java))
+ val user = User()
+ user.username = "johnny"
+ val thrownException = assertThrows(InternalServerException::class.java) {
+ userRoleDomainService.assignRoleByRoleName(user, "ROLE_ADMIN_FOR_UNIT_TEST")
+ }
+ log.warn("Exception: ${thrownException.message}")
+ }
+}
diff --git a/auth-center/auth-center-infra/pom.xml b/auth-center/auth-center-infra/pom.xml
index 307eadc2..14255f21 100644
--- a/auth-center/auth-center-infra/pom.xml
+++ b/auth-center/auth-center-infra/pom.xml
@@ -11,6 +11,6 @@
com.jmsoftware.maf
auth-center
- 0.0.8.1
+ 0.0.9
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.kt
new file mode 100644
index 00000000..28c29711
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/configuration/PermissionConfiguration.kt
@@ -0,0 +1,24 @@
+package com.jmsoftware.maf.authcenter.permission.configuration
+
+import org.springframework.boot.context.properties.ConfigurationProperties
+import org.springframework.cloud.context.config.annotation.RefreshScope
+import org.springframework.context.annotation.Configuration
+import org.springframework.validation.annotation.Validated
+import javax.validation.constraints.NotEmpty
+
+/**
+ * Description: PermissionConfiguration, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 5:35 PM
+ */
+@Validated
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = PermissionConfiguration.PREFIX)
+class PermissionConfiguration(
+ @NotEmpty var ignoredServiceIds: Set
+) {
+ companion object {
+ const val PREFIX = "maf.configuration.permission"
+ }
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/converter/PermissionMapStructMapper.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/converter/PermissionMapStructMapper.kt
new file mode 100644
index 00000000..a1da8c6c
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/converter/PermissionMapStructMapper.kt
@@ -0,0 +1,25 @@
+package com.jmsoftware.maf.authcenter.permission.converter
+
+import com.jmsoftware.maf.authcenter.permission.persistence.Permission
+import org.mapstruct.Mapper
+import org.mapstruct.factory.Mappers.getMapper
+
+/**
+ * Description: PermissionMapStructMapper, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 6:04 PM
+ */
+@Mapper
+interface PermissionMapStructMapper {
+ companion object {
+ val INSTANCE: PermissionMapStructMapper = getMapper(PermissionMapStructMapper::class.java)
+ }
+
+ /**
+ * Permission -> GetPermissionListByRoleIdListResponse.Permission
+ *
+ * @param permission the permission
+ * @return the get permission list by role id list response . permission
+ */
+ fun of(permission: Permission): com.jmsoftware.maf.common.domain.authcenter.permission.Permission
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.java
deleted file mode 100644
index c4d72251..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.jmsoftware.maf.authcenter.permission.persistence.Permission;
-import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * PermissionMapper
- *
- * Mapper of Permission.(Permission)
- *
- * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
- * @date 5 /11/20 8:34 AM
- */
-@Mapper
-public interface PermissionMapper extends BaseMapper {
- /**
- * Select permission list by role id list list.
- *
- * @param roleIdList the role id list
- * @param permissionTypeList the permission type list
- * @return the list
- */
- List selectPermissionListByRoleIdList(
- @Param("roleIdList") List roleIdList,
- @Param("permissionTypeList") List permissionTypeList
- );
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.kt
new file mode 100644
index 00000000..4709433b
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/mapper/PermissionMapper.kt
@@ -0,0 +1,29 @@
+package com.jmsoftware.maf.authcenter.permission.mapper
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper
+import com.jmsoftware.maf.authcenter.permission.persistence.Permission
+import com.jmsoftware.maf.common.domain.authcenter.permission.PermissionType
+import org.apache.ibatis.annotations.Mapper
+import org.apache.ibatis.annotations.Param
+
+/**
+ * # PermissionMapper
+ *
+ * Mapper of Permission. (Permission)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 6:06 PM
+ */
+@Mapper
+interface PermissionMapper : BaseMapper {
+ /**
+ * Select permission list by role id list.
+ *
+ * @param roleIdList the role id list
+ * @param permissionTypeList the permission type list
+ * @return the list
+ */
+ fun selectPermissionListByRoleIdList(
+ @Param("roleIdList") roleIdList: List,
+ @Param("permissionTypeList") permissionTypeList: List
+ ): List
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/persistence/Permission.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/persistence/Permission.java
deleted file mode 100644
index 7323ac92..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/persistence/Permission.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission.persistence;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-import static com.baomidou.mybatisplus.annotation.FieldFill.INSERT;
-import static com.baomidou.mybatisplus.annotation.FieldFill.UPDATE;
-
-/**
- * Permission
- *
- * Permission Persistence object class
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 3:22 PM
- */
-@Data
-@TableName(value = Permission.TABLE_NAME)
-public class Permission {
- public static final String TABLE_NAME = "permission";
- public static final String COL_ID = "id";
- public static final String COL_URL = "url";
- public static final String COL_DESCRIPTION = "description";
- public static final String COL_TYPE = "type";
- public static final String COL_PERMISSION_EXPRESSION = "permission_expression";
- public static final String COL_METHOD = "method";
- public static final String COL_SORT = "sort";
- public static final String COL_PARENT_ID = "parent_id";
- public static final String COL_CREATED_BY = "created_by";
- public static final String COL_CREATED_TIME = "created_time";
- public static final String COL_MODIFIED_BY = "modified_by";
- public static final String COL_MODIFIED_TIME = "modified_time";
- public static final String COL_DELETED = "deleted";
- /**
- * Primary key
- */
- @TableId(value = COL_ID, type = IdType.AUTO)
- private Long id;
- /**
- * URL. If type of record is page (1), URL stands for route; if type of record is button (2), URL stands for API
- */
- @TableField(value = COL_URL)
- private String url;
- /**
- * Permission description
- */
- @TableField(value = COL_DESCRIPTION)
- private String description;
- /**
- * Permission type. 1 - page; 2 - button
- */
- @TableField(value = COL_TYPE)
- private Byte type;
- /**
- * Permission expression
- */
- @TableField(value = COL_PERMISSION_EXPRESSION)
- private String permissionExpression;
- /**
- * HTTP method of API
- */
- @TableField(value = COL_METHOD)
- private Object method;
- /**
- * Sort number
- */
- @TableField(value = COL_SORT)
- private Integer sort;
- /**
- * Primary key of parent
- */
- @TableField(value = COL_PARENT_ID)
- private Long parentId;
- /**
- * Created by
- */
- @TableField(value = COL_CREATED_BY, fill = INSERT)
- private Long createdBy;
- /**
- * Created time
- */
- @TableField(value = COL_CREATED_TIME, fill = INSERT)
- private LocalDateTime createdTime;
- /**
- * Modified by
- */
- @TableField(value = COL_MODIFIED_BY, fill = UPDATE)
- private Long modifiedBy;
- /**
- * Modified time
- */
- @TableField(value = COL_MODIFIED_TIME, fill = UPDATE)
- private LocalDateTime modifiedTime;
- /**
- * Deleted flag
- */
- @TableField(value = COL_DELETED, fill = INSERT)
- private Byte deleted;
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/persistence/Permission.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/persistence/Permission.kt
new file mode 100644
index 00000000..4ba287cc
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/persistence/Permission.kt
@@ -0,0 +1,68 @@
+package com.jmsoftware.maf.authcenter.permission.persistence
+
+import com.baomidou.mybatisplus.annotation.TableField
+import com.baomidou.mybatisplus.annotation.TableName
+import com.jmsoftware.maf.springcloudstarter.database.BasePersistenceEntity
+
+/**
+ * # Permission
+ *
+ * Permission Persistence object class
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 4:19 PM
+ */
+@TableName(value = Permission.TABLE_NAME)
+class Permission : BasePersistenceEntity() {
+ companion object {
+ const val TABLE_NAME = "permission"
+ const val COL_URL = "url"
+ const val COL_DESCRIPTION = "description"
+ const val COL_TYPE = "type"
+ const val COL_PERMISSION_EXPRESSION = "permission_expression"
+ const val COL_METHOD = "method"
+ const val COL_SORT = "`sort`"
+ const val COL_PARENT_ID = "parent_id"
+ }
+
+ /**
+ * URL. If type of record is page (1), URL stands for route; if type of record is button (2), URL stands for API
+ */
+ @TableField(value = COL_URL)
+ lateinit var url: String
+
+ /**
+ * Permission description
+ */
+ @TableField(value = COL_DESCRIPTION)
+ lateinit var description: String
+
+ /**
+ * Permission type. 1 - page; 2 - button
+ */
+ @TableField(value = COL_TYPE)
+ var type: Byte = 0
+
+ /**
+ * Permission expression
+ */
+ @TableField(value = COL_PERMISSION_EXPRESSION)
+ lateinit var permissionExpression: String
+
+ /**
+ * HTTP method of API
+ */
+ @TableField(value = COL_METHOD)
+ lateinit var method: String
+
+ /**
+ * Sort number
+ */
+ @TableField(value = COL_SORT)
+ var sort: Int = 0
+
+ /**
+ * Primary key of parent
+ */
+ @TableField(value = COL_PARENT_ID)
+ var parentId: Long? = null
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/response/GetServicesInfoResponse.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/response/GetServicesInfoResponse.java
deleted file mode 100644
index 6bebf385..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/response/GetServicesInfoResponse.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission.response;
-
-import com.google.common.collect.Lists;
-import com.jmsoftware.maf.common.domain.springbootstarter.HttpApiResourcesResponse;
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * Description: GetServicesInfoResponse, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/28/2020 9:30 AM
- **/
-@Data
-public class GetServicesInfoResponse {
- private List list = Lists.newLinkedList();
-
- @Data
- public static class ServiceInfo{
- private String serviceId;
- private HttpApiResourcesResponse httpApiResources;
- }
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/response/GetServicesInfoResponse.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/response/GetServicesInfoResponse.kt
new file mode 100644
index 00000000..0df452db
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/permission/response/GetServicesInfoResponse.kt
@@ -0,0 +1,17 @@
+package com.jmsoftware.maf.authcenter.permission.response
+
+import com.jmsoftware.maf.common.domain.springbootstarter.HttpApiResourcesResponse
+
+/**
+ * Description: GetServicesInfoResponse, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/11/22 6:08 PM
+ */
+class GetServicesInfoResponse {
+ lateinit var list: List
+
+ class ServiceInfo {
+ lateinit var serviceId: String
+ lateinit var httpApiResources: HttpApiResourcesResponse
+ }
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignClient.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignClient.kt
new file mode 100644
index 00000000..64e694dd
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignClient.kt
@@ -0,0 +1,53 @@
+package com.jmsoftware.maf.authcenter.remote
+
+import com.jmsoftware.maf.authcenter.remote.OssCenterFeignClient.OssCenterFeignClientFallback
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.osscenter.write.ObjectResponse
+import com.jmsoftware.maf.common.util.logger
+import org.springframework.cloud.openfeign.FeignClient
+import org.springframework.context.annotation.Primary
+import org.springframework.http.MediaType
+import org.springframework.stereotype.Component
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.RequestPart
+import org.springframework.web.multipart.MultipartFile
+import javax.validation.constraints.NotNull
+
+/**
+ * # OssCenterFeignClient
+ *
+ * Description: OssCenterFeignClient, change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 9/15/2021 11:10 AM
+ * @see Spring Cloud OpenFeign
+ */
+@Primary
+@Validated
+@FeignClient(value = OssCenterFeignClient.SERVICE_NAME, fallback = OssCenterFeignClientFallback::class)
+interface OssCenterFeignClient {
+ companion object {
+ const val SERVICE_NAME = "oss-center"
+ }
+
+ /**
+ * Upload single resource response body bean.
+ *
+ * @param multipartFile the multipart file
+ * @return the response body bean
+ */
+ @PostMapping(value = ["/upload/single"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
+ fun uploadSingleResource(@RequestPart("file") multipartFile: @NotNull MultipartFile): ResponseBodyBean
+
+ @Component
+ class OssCenterFeignClientFallback : OssCenterFeignClient {
+ companion object {
+ private val log = logger()
+ }
+
+ override fun uploadSingleResource(multipartFile: @NotNull MultipartFile): ResponseBodyBean {
+ log.error("Fallback -> OssCenterFeignClient#uploadSingleResource()")
+ return ResponseBodyBean.ofFailureMessage("Fell back uploading single resource")
+ }
+ }
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterRemoteApi.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterRemoteApi.java
deleted file mode 100644
index a7460390..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/remote/OssCenterRemoteApi.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.jmsoftware.maf.authcenter.remote;
-
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.osscenter.write.ObjectResponse;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestPart;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.validation.constraints.NotNull;
-
-/**
- * Description: OssCenterRemoteApi, change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 9/15/2021 11:10 AM
- * @see Spring Cloud OpenFeign
- **/
-@Validated
-@FeignClient(value = OssCenterRemoteApi.SERVICE_NAME, fallback = OssCenterRemoteApi.OssCenterRemoteApiFallback.class)
-public interface OssCenterRemoteApi {
- String SERVICE_NAME = "oss-center";
-
- /**
- * Upload single resource response body bean.
- *
- * @param multipartFile the multipart file
- * @return the response body bean
- */
- @PostMapping(value = "/upload/single", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- ResponseBodyBean uploadSingleResource(@NotNull @RequestPart("file") MultipartFile multipartFile);
-
- @Slf4j
- @Component
- class OssCenterRemoteApiFallback implements OssCenterRemoteApi {
- @Override
- public ResponseBodyBean uploadSingleResource(@NotNull MultipartFile multipartFile) {
- log.error("Fallback -> OssCenterRemoteApi#uploadSingleResource()");
- return null;
- }
- }
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/RoleExcelBean.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/RoleExcelBean.java
deleted file mode 100644
index 526101e9..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/RoleExcelBean.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.jmsoftware.maf.authcenter.role;
-
-import com.jmsoftware.maf.authcenter.role.persistence.Role;
-import com.jmsoftware.maf.springcloudstarter.poi.ExcelColumn;
-import lombok.Data;
-import lombok.val;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * Description: RoleExcelBean, change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 8/22/2021 10:52 AM
- **/
-@Data
-public class RoleExcelBean {
- /**
- * Role name
- */
- @NotBlank
- @ExcelColumn(name = "Name")
- private String name;
- /**
- * Role description
- */
- @NotBlank
- @ExcelColumn(name = "Description")
- private String description;
-
- /**
- * Transform by role.
- *
- * @param role the role
- * @return the role excel import
- */
- public static RoleExcelBean transformBy(Role role) {
- val roleExcelImport = new RoleExcelBean();
- roleExcelImport.setName(role.getName());
- roleExcelImport.setDescription(role.getDescription());
- return roleExcelImport;
- }
-
- /**
- * Transform by role.
- *
- * @param roleExcelBean the role excel import
- * @return the role excel import
- */
- public static Role transformTo(RoleExcelBean roleExcelBean) {
- val role = new Role();
- role.setName(roleExcelBean.getName());
- role.setDescription(roleExcelBean.getDescription());
- return role;
- }
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/RoleExcelBean.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/RoleExcelBean.kt
new file mode 100644
index 00000000..cec524a0
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/RoleExcelBean.kt
@@ -0,0 +1,56 @@
+package com.jmsoftware.maf.authcenter.role
+
+import com.jmsoftware.maf.authcenter.role.persistence.Role
+import com.jmsoftware.maf.springcloudstarter.poi.ExcelColumn
+import javax.validation.constraints.NotBlank
+
+/**
+ * # RoleExcelBean
+ *
+ * Description: RoleExcelBean, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:40 PM
+ */
+class RoleExcelBean {
+ /**
+ * Role name
+ */
+ @NotBlank
+ @ExcelColumn(name = "Name")
+ private lateinit var name: String
+
+ /**
+ * Role description
+ */
+ @NotBlank
+ @ExcelColumn(name = "Description")
+ private lateinit var description: String
+
+ companion object {
+ /**
+ * Transform by role.
+ *
+ * @param role the role
+ * @return the role excel import
+ */
+ fun transformBy(role: Role): RoleExcelBean {
+ val roleExcelImport = RoleExcelBean()
+ roleExcelImport.name = role.name
+ roleExcelImport.description = role.description
+ return roleExcelImport
+ }
+
+ /**
+ * Transform by role.
+ *
+ * @param roleExcelBean the role excel import
+ * @return the role excel import
+ */
+ fun transformTo(roleExcelBean: RoleExcelBean): Role {
+ val role = Role()
+ role.name = roleExcelBean.name
+ role.description = roleExcelBean.description
+ return role
+ }
+ }
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/constant/RoleRedisKey.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/constant/RoleRedisKey.java
deleted file mode 100644
index baff6d64..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/constant/RoleRedisKey.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.jmsoftware.maf.authcenter.role.constant;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-/**
- * RoleRedisKey
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com, 6/28/21 9:45 PM
- **/
-@Getter
-@RequiredArgsConstructor
-public enum RoleRedisKey {
- /**
- * Get user by login token key pattern, expired in random [1, 7) days
- */
- GET_ROLE_LIST_BY_USER_ID(":role:get_role_list_by_user_id:%s");
-
- private final String keyInfixFormat;
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/constant/RoleRedisKey.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/constant/RoleRedisKey.kt
new file mode 100644
index 00000000..6c2ec625
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/constant/RoleRedisKey.kt
@@ -0,0 +1,17 @@
+package com.jmsoftware.maf.authcenter.role.constant
+
+/**
+ * # RoleRedisKey
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:37 PM
+ */
+enum class RoleRedisKey(
+ val keyInfixFormat: String
+) {
+ /**
+ * Get user by login token key pattern, expired in random [1, 7) days
+ */
+ GET_ROLE_LIST_BY_USER_ID(":role:get_role_list_by_user_id:");
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.java
deleted file mode 100644
index 928d531e..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.jmsoftware.maf.authcenter.role.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.jmsoftware.maf.authcenter.role.persistence.Role;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.List;
-
-/**
- *
RoleMapper
- *
- * Mapper of Role.(Role)
- *
- * @author Johnny Miller (锺俊)
- * @date 2020 -05-10 22:39:48
- */
-@Mapper
-public interface RoleMapper extends BaseMapper {
- /**
- * Select role list by user id list.
- *
- * @param userId the user id
- * @return the list
- */
- List selectRoleListByUserId(Long userId);
-
- /**
- * Select by id role persistence.
- *
- * @param roleName the role name
- * @return the role persistence
- */
- Role selectByName(String roleName);
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.kt
new file mode 100644
index 00000000..d6f2e558
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/mapper/RoleMapper.kt
@@ -0,0 +1,32 @@
+package com.jmsoftware.maf.authcenter.role.mapper
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper
+import com.jmsoftware.maf.authcenter.role.persistence.Role
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdSingleResponse
+import org.apache.ibatis.annotations.Mapper
+
+/**
+ * # RoleMapper
+ *
+ * MyBatis Mapper of Role. (Role)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:39 PM
+ */
+@Mapper
+interface RoleMapper : BaseMapper {
+ /**
+ * Select role list by user id list.
+ *
+ * @param userId the user id
+ * @return the list
+ */
+ fun selectRoleListByUserId(userId: Long): List
+
+ /**
+ * Select by id role persistence.
+ *
+ * @param roleName the role name
+ * @return the role persistence
+ */
+ fun selectByName(roleName: String): Role
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/persistence/Role.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/persistence/Role.java
deleted file mode 100644
index 2503ae3f..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/persistence/Role.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.jmsoftware.maf.authcenter.role.persistence;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-import static com.baomidou.mybatisplus.annotation.FieldFill.INSERT;
-import static com.baomidou.mybatisplus.annotation.FieldFill.UPDATE;
-
-/**
- * Role
- *
- * Role Persistence object class
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 3:22 PM
- */
-@Data
-@TableName(value = Role.TABLE_NAME)
-public class Role {
- public static final String TABLE_NAME = "role";
- public static final String COL_ID = "id";
- public static final String COL_NAME = "name";
- public static final String COL_DESCRIPTION = "description";
- public static final String COL_CREATED_BY = "created_by";
- public static final String COL_CREATED_TIME = "created_time";
- public static final String COL_MODIFIED_BY = "modified_by";
- public static final String COL_MODIFIED_TIME = "modified_time";
- public static final String COL_DELETED = "deleted";
- /**
- * Primary key
- */
- @TableId(value = COL_ID, type = IdType.AUTO)
- private Long id;
- /**
- * Role name
- */
- @TableField(value = COL_NAME)
- private String name;
- /**
- * Role description
- */
- @TableField(value = COL_DESCRIPTION)
- private String description;
- /**
- * Created by
- */
- @TableField(value = COL_CREATED_BY, fill = INSERT)
- private Long createdBy;
- /**
- * Created time
- */
- @TableField(value = COL_CREATED_TIME, fill = INSERT)
- private LocalDateTime createdTime;
- /**
- * Modified by
- */
- @TableField(value = COL_MODIFIED_BY, fill = UPDATE)
- private Long modifiedBy;
- /**
- * Modified time
- */
- @TableField(value = COL_MODIFIED_TIME, fill = UPDATE)
- private LocalDateTime modifiedTime;
- /**
- * Deleted flag.
- */
- @TableField(value = COL_DELETED, fill = INSERT)
- private Byte deleted;
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/persistence/Role.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/persistence/Role.kt
new file mode 100644
index 00000000..9095885a
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/role/persistence/Role.kt
@@ -0,0 +1,34 @@
+package com.jmsoftware.maf.authcenter.role.persistence
+
+import com.baomidou.mybatisplus.annotation.TableField
+import com.baomidou.mybatisplus.annotation.TableName
+import com.jmsoftware.maf.springcloudstarter.database.BasePersistenceEntity
+
+/**
+ * # Role
+ *
+ * Role Persistence object class
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/10/22 7:15 PM
+ * @see MySQL Keywords and Reserved Words
+ */
+@TableName(value = Role.TABLE_NAME)
+class Role : BasePersistenceEntity() {
+ companion object {
+ const val TABLE_NAME = "role"
+ const val COL_NAME = "`name`"
+ const val COL_DESCRIPTION = "`description`"
+ }
+
+ /**
+ * Role name
+ */
+ @TableField(value = COL_NAME)
+ lateinit var name: String
+
+ /**
+ * Role description
+ */
+ @TableField(value = COL_DESCRIPTION)
+ lateinit var description: String
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/constant/UserRedisKey.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/constant/UserRedisKey.java
deleted file mode 100644
index 5c906b55..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/constant/UserRedisKey.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.constant;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-/**
- * Description: UserRedisKey, change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/28/2021 3:18 PM
- **/
-@Getter
-@RequiredArgsConstructor
-public enum UserRedisKey {
- /**
- * Get user by login token key pattern, expired in random [1, 7) days
- */
- GET_USER_BY_LOGIN_TOKEN(":user:get_user_by_login_token:%s");
-
- private final String keyInfixFormat;
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/constant/UserRedisKey.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/constant/UserRedisKey.kt
new file mode 100644
index 00000000..3da7a3e1
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/constant/UserRedisKey.kt
@@ -0,0 +1,17 @@
+package com.jmsoftware.maf.authcenter.user.constant
+
+/**
+ * # UserRedisKey
+ *
+ * Description: UserRedisKey, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:43 PM
+ */
+enum class UserRedisKey(
+ val keyInfixFormat: String
+) {
+ /**
+ * Get user by login token key pattern, expired in random [1, 7) days
+ */
+ GET_USER_BY_LOGIN_TOKEN(":user:get_user_by_login_token:%s");
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/converter/UserMapStructMapper.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/converter/UserMapStructMapper.kt
new file mode 100644
index 00000000..0b5aeaa3
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/converter/UserMapStructMapper.kt
@@ -0,0 +1,27 @@
+package com.jmsoftware.maf.authcenter.user.converter
+
+import com.jmsoftware.maf.authcenter.user.converter.UserMapStructMapper
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse
+import org.mapstruct.Mapper
+import org.mapstruct.factory.Mappers
+
+/**
+ * Description: UserMapStructMapper, change description here.
+ *
+ * @author Johnny Miller (鍾俊), e-mail: johnnysviva@outlook.com, date: 2/5/2022 7:15 PM
+ */
+@Mapper
+interface UserMapStructMapper {
+ companion object {
+ val INSTANCE: UserMapStructMapper = Mappers.getMapper(UserMapStructMapper::class.java)
+ }
+
+ /**
+ * User -> response.
+ *
+ * @param user the user
+ * @return the get user by login token response
+ */
+ fun of(user: User): GetUserByLoginTokenResponse
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.java
deleted file mode 100644
index 0a832051..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.jmsoftware.maf.authcenter.user.persistence.User;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- *
UserMapper
- *
- * Mapper of UserPersistence.(UserPersistence)
- *
- * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
- * @date 5 /10/20 12:17 PM
- */
-@Mapper
-public interface UserMapper extends BaseMapper {
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.kt
new file mode 100644
index 00000000..da6fdfce
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserMapper.kt
@@ -0,0 +1,15 @@
+package com.jmsoftware.maf.authcenter.user.mapper
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import org.apache.ibatis.annotations.Mapper
+
+/**
+ * # UserMapper
+ *
+ * Mapper of UserPersistence.(UserPersistence)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:45 PM
+ */
+@Mapper
+interface UserMapper : BaseMapper
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.java
deleted file mode 100644
index c2253e90..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.jmsoftware.maf.authcenter.user.persistence.UserRole;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * UserRoleMapper
- *
- * Mapper of user_role.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 7/4/2021 1:24 PM
- */
-@Mapper
-public interface UserRoleMapper extends BaseMapper {
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.kt
new file mode 100644
index 00000000..b0e182f6
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/mapper/UserRoleMapper.kt
@@ -0,0 +1,15 @@
+package com.jmsoftware.maf.authcenter.user.mapper
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper
+import com.jmsoftware.maf.authcenter.user.persistence.UserRole
+import org.apache.ibatis.annotations.Mapper
+
+/**
+ * # UserRoleMapper
+ *
+ * Mapper of user_role.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:45 PM
+ */
+@Mapper
+interface UserRoleMapper : BaseMapper
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserPageListPayload.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserPageListPayload.java
deleted file mode 100644
index f4ace9fc..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserPageListPayload.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.payload;
-
-import com.jmsoftware.maf.common.bean.PaginationBase;
-import com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeConstraints;
-import com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeGroup;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.time.LocalDateTime;
-
-import static com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeType.END_TIME;
-import static com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeType.START_TIME;
-
-/**
- * Description: GetUserPageList, change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 4:32 PM
- **/
-@Data
-@DateTimeRangeConstraints
-@EqualsAndHashCode(callSuper = true)
-public class GetUserPageListPayload extends PaginationBase {
- private String username;
- @DateTimeRangeGroup(type = START_TIME)
- private LocalDateTime startTime;
- @DateTimeRangeGroup(type = END_TIME)
- private LocalDateTime endTime;
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserPageListPayload.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserPageListPayload.kt
new file mode 100644
index 00000000..9b5abe64
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserPageListPayload.kt
@@ -0,0 +1,23 @@
+package com.jmsoftware.maf.authcenter.user.payload
+
+import com.jmsoftware.maf.common.bean.PaginationBase
+import com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeGroup
+import com.jmsoftware.maf.springcloudstarter.validation.annotation.DateTimeRangeType
+import java.time.LocalDateTime
+
+/**
+ * # GetUserPageListPayload
+ *
+ * Description: GetUserPageList, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:46 PM
+ */
+class GetUserPageListPayload : PaginationBase() {
+ var username: String? = null
+
+ @DateTimeRangeGroup(type = DateTimeRangeType.START_TIME)
+ val startTime: LocalDateTime? = null
+
+ @DateTimeRangeGroup(type = DateTimeRangeType.END_TIME)
+ val endTime: LocalDateTime? = null
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserStatusPayload.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserStatusPayload.java
deleted file mode 100644
index 178259cd..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserStatusPayload.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.payload;
-
-import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus;
-import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus2;
-import com.jmsoftware.maf.springcloudstarter.validation.annotation.ValidEnumValue;
-import lombok.Data;
-
-/**
- * GetUserStatusPayload
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 6/6/21 4:31 PM
- **/
-@Data
-public class GetUserStatusPayload {
- @ValidEnumValue(targetEnum = UserStatus.class)
- private Byte status;
- @ValidEnumValue(targetEnum = UserStatus2.class)
- private Byte status2;
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserStatusPayload.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserStatusPayload.kt
new file mode 100644
index 00000000..eea82f1a
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/payload/GetUserStatusPayload.kt
@@ -0,0 +1,20 @@
+package com.jmsoftware.maf.authcenter.user.payload
+
+import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus
+import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus2
+import com.jmsoftware.maf.springcloudstarter.validation.annotation.ValidEnumValue
+
+/**
+ * # GetUserStatusPayload
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:50 PM
+ */
+class GetUserStatusPayload {
+ @ValidEnumValue(targetEnum = UserStatus::class)
+ var status: Byte? = null
+
+ @ValidEnumValue(targetEnum = UserStatus2::class)
+ var status2: Byte? = null
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/User.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/User.java
deleted file mode 100644
index bd00675a..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/User.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.persistence;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-
-import static com.baomidou.mybatisplus.annotation.FieldFill.INSERT;
-import static com.baomidou.mybatisplus.annotation.FieldFill.UPDATE;
-
-/**
- *
User
- *
- * User Persistence object class
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 3:22 PM
- */
-@Data
-@SuppressWarnings("jol")
-@TableName(value = User.TABLE_NAME)
-public class User {
- public static final String TABLE_NAME = "user";
- public static final String COL_ID = "id";
- public static final String COL_USERNAME = "username";
- public static final String COL_EMAIL = "email";
- public static final String COL_CELLPHONE = "cellphone";
- public static final String COL_PASSWORD = "password";
- public static final String COL_FULL_NAME = "full_name";
- public static final String COL_BIRTHDAY = "birthday";
- public static final String COL_GENDER = "gender";
- public static final String COL_AVATAR = "avatar";
- public static final String COL_STATUS = "status";
- public static final String COL_CREATED_BY = "created_by";
- public static final String COL_CREATED_TIME = "created_time";
- public static final String COL_MODIFIED_BY = "modified_by";
- public static final String COL_MODIFIED_TIME = "modified_time";
- public static final String COL_DELETED = "deleted";
- /**
- * Primary key of user
- */
- @TableId(value = COL_ID, type = IdType.AUTO)
- private Long id;
- /**
- * Username
- */
- @TableField(value = COL_USERNAME)
- private String username;
- /**
- * Email
- */
- @TableField(value = COL_EMAIL)
- private String email;
- /**
- * Cellphone number
- */
- @TableField(value = COL_CELLPHONE)
- private String cellphone;
- /**
- * Password
- */
- @TableField(value = COL_PASSWORD)
- private String password;
- /**
- * Full name
- */
- @TableField(value = COL_FULL_NAME)
- private String fullName;
- /**
- * Birthday
- */
- @TableField(value = COL_BIRTHDAY)
- private LocalDate birthday;
- /**
- * 26 gender options
- */
- @TableField(value = COL_GENDER)
- private Object gender;
- /**
- * User avatar full path on SFTP server
- */
- @TableField(value = COL_AVATAR)
- private String avatar;
- /**
- * Status. 1 - enabled, 2 - disabled
- */
- @TableField(value = COL_STATUS)
- private Byte status;
- /**
- * Created by
- */
- @TableField(value = COL_CREATED_BY, fill = INSERT)
- private Long createdBy;
- /**
- * Created time
- */
- @TableField(value = COL_CREATED_TIME, fill = INSERT)
- private LocalDateTime createdTime;
- /**
- * Modified by
- */
- @TableField(value = COL_MODIFIED_BY, fill = UPDATE)
- private Long modifiedBy;
- /**
- * Modified time
- */
- @TableField(value = COL_MODIFIED_TIME, fill = UPDATE)
- private LocalDateTime modifiedTime;
- /**
- * Delete flag.
- */
- @TableField(value = COL_DELETED, fill = INSERT)
- private Byte deleted;
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/User.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/User.kt
new file mode 100644
index 00000000..4158028b
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/User.kt
@@ -0,0 +1,83 @@
+package com.jmsoftware.maf.authcenter.user.persistence
+
+import com.baomidou.mybatisplus.annotation.TableField
+import com.baomidou.mybatisplus.annotation.TableName
+import com.jmsoftware.maf.springcloudstarter.database.BasePersistenceEntity
+import java.time.LocalDate
+
+/**
+ * # User
+ *
+ * User Persistence object class
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 7:31 AM
+ */
+@TableName(value = User.TABLE_NAME)
+class User : BasePersistenceEntity() {
+ companion object {
+ const val TABLE_NAME = "user"
+ const val COL_USERNAME = "username"
+ const val COL_EMAIL = "email"
+ const val COL_CELLPHONE = "cellphone"
+ const val COL_PASSWORD = "password"
+ const val COL_FULL_NAME = "full_name"
+ const val COL_BIRTHDAY = "birthday"
+ const val COL_GENDER = "gender"
+ const val COL_AVATAR = "avatar"
+ const val COL_STATUS = "status"
+ }
+
+ /**
+ * Username
+ */
+ @TableField(value = COL_USERNAME)
+ lateinit var username: String
+
+ /**
+ * Email
+ */
+ @TableField(value = COL_EMAIL)
+ lateinit var email: String
+
+ /**
+ * Cellphone number
+ */
+ @TableField(value = COL_CELLPHONE)
+ lateinit var cellphone: String
+
+ /**
+ * Password
+ */
+ @TableField(value = COL_PASSWORD)
+ lateinit var password: String
+
+ /**
+ * Full name
+ */
+ @TableField(value = COL_FULL_NAME)
+ lateinit var fullName: String
+
+ /**
+ * Birthday
+ */
+ @TableField(value = COL_BIRTHDAY)
+ lateinit var birthday: LocalDate
+
+ /**
+ * 26 gender options
+ */
+ @TableField(value = COL_GENDER)
+ lateinit var gender: String
+
+ /**
+ * User avatar full path on SFTP server
+ */
+ @TableField(value = COL_AVATAR)
+ lateinit var avatar: String
+
+ /**
+ * Status. 1 - enabled, 2 - disabled
+ */
+ @TableField(value = COL_STATUS)
+ var status: Byte = 0
+}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/UserRole.java b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/UserRole.java
deleted file mode 100644
index 8fe9bf03..00000000
--- a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/UserRole.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.jmsoftware.maf.authcenter.user.persistence;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-
-/**
- * User-role Relation. Roles that users have.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/29/2021 12:09 PM
- */
-@Data
-@TableName(value = UserRole.TABLE_NAME)
-public class UserRole {
- /**
- * The primary key
- */
- @TableId(value = COL_ID, type = IdType.AUTO)
- private Long id;
-
- /**
- * The primary key of user
- */
- @TableField(value = COL_USER_ID)
- private Long userId;
-
- /**
- * The primary key of role
- */
- @TableField(value = COL_ROLE_ID)
- private Long roleId;
-
- public static final String TABLE_NAME = "user_role";
-
- public static final String COL_ID = "id";
-
- public static final String COL_USER_ID = "user_id";
-
- public static final String COL_ROLE_ID = "role_id";
-}
diff --git a/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/UserRole.kt b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/UserRole.kt
new file mode 100644
index 00000000..c29e6097
--- /dev/null
+++ b/auth-center/auth-center-infra/src/main/java/com/jmsoftware/maf/authcenter/user/persistence/UserRole.kt
@@ -0,0 +1,41 @@
+package com.jmsoftware.maf.authcenter.user.persistence
+
+import com.baomidou.mybatisplus.annotation.IdType
+import com.baomidou.mybatisplus.annotation.TableField
+import com.baomidou.mybatisplus.annotation.TableId
+import com.baomidou.mybatisplus.annotation.TableName
+
+/**
+ * # UserRole
+ *
+ * User-role Relation. Roles that users have.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:51 PM
+ */
+@TableName(value = UserRole.TABLE_NAME)
+class UserRole {
+ companion object {
+ const val TABLE_NAME = "user_role"
+ const val COL_ID = "id"
+ const val COL_USER_ID = "user_id"
+ const val COL_ROLE_ID = "role_id"
+ }
+
+ /**
+ * The primary key
+ */
+ @TableId(value = COL_ID, type = IdType.AUTO)
+ var id: Long? = null
+
+ /**
+ * The primary key of user
+ */
+ @TableField(value = COL_USER_ID)
+ var userId: Long? = null
+
+ /**
+ * The primary key of role
+ */
+ @TableField(value = COL_ROLE_ID)
+ var roleId: Long? = null
+}
diff --git a/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/package-info.java b/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
deleted file mode 100644
index e702ef59..00000000
--- a/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter;
diff --git a/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt b/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
new file mode 100644
index 00000000..b7191a36
--- /dev/null
+++ b/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter
diff --git a/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignClientTest.kt b/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignClientTest.kt
new file mode 100644
index 00000000..eb587e4d
--- /dev/null
+++ b/auth-center/auth-center-infra/src/test/java/com/jmsoftware/maf/authcenter/remote/OssCenterFeignClientTest.kt
@@ -0,0 +1,75 @@
+package com.jmsoftware.maf.authcenter.remote
+
+import com.jmsoftware.maf.common.util.logger
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertNull
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import org.mockito.Mock
+import org.mockito.junit.jupiter.MockitoExtension
+import org.springframework.mock.web.MockMultipartFile
+
+/**
+ * # OssCenterFeignClientTest
+ *
+ * Description: PermissionDomainServiceImplTest, change description here.
+ *
+ * ## Mockito JUnit 5 Extension
+ *
+ * There is also a Mockito extension for JUnit 5 that will make the initialization even simpler.
+ *
+ * **Pros:**
+ *
+ * * No need to call `MockitoAnnotations.openMocks()`
+ * * Validates framework usage and detects incorrect stubbing
+ * * Easy to create mocks
+ * * Very readable
+ *
+ * **Cons:**
+ *
+ * * Need an extra dependency on `org.mockito:mockito-junit-jupiter`, which has been included by Spring.
+ * So we don't have to worry about this.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 10:43 AM
+ * @see Using Mockito With JUnit 5
+ * @see YouTube - Using Mockito With JUnit 5
+ */
+@ExtendWith(MockitoExtension::class)
+@Execution(ExecutionMode.CONCURRENT)
+internal class OssCenterFeignClientTest {
+ companion object {
+ private val log = logger()
+ }
+
+ @Mock
+ private lateinit var ossCenterFeignClient: OssCenterFeignClient
+
+ @Mock
+ private lateinit var ossCenterFeignClientFallback: OssCenterFeignClient.OssCenterFeignClientFallback
+
+ @BeforeEach
+ fun setUp() {
+ log.info("${this.javaClass.simpleName} setUp")
+ }
+
+ @AfterEach
+ fun tearDown() {
+ log.info("${this.javaClass.simpleName} tearDown")
+ }
+
+ @Test
+ fun uploadSingleResource() {
+ val multipartFile = MockMultipartFile(
+ "name-for-unit-test.txt",
+ "original-filename.txt",
+ null,
+ null
+ )
+ val response = ossCenterFeignClient.uploadSingleResource(multipartFile)
+ log.info("Response: $response")
+ assertNull(response)
+ }
+}
diff --git a/auth-center/auth-center-message/pom.xml b/auth-center/auth-center-message/pom.xml
index 768045fd..c1ee5e5a 100644
--- a/auth-center/auth-center-message/pom.xml
+++ b/auth-center/auth-center-message/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
auth-center
- 0.0.8.1
+ 0.0.9
diff --git a/auth-center/auth-center-message/src/main/java/com/jmsoftware/maf/authcenter/DelayedMessageSender.java b/auth-center/auth-center-message/src/main/java/com/jmsoftware/maf/authcenter/DelayedMessageSender.java
deleted file mode 100644
index 96b08fcb..00000000
--- a/auth-center/auth-center-message/src/main/java/com/jmsoftware/maf/authcenter/DelayedMessageSender.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.jmsoftware.maf.authcenter;
-
-import com.google.common.collect.Maps;
-import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.amqp.rabbit.core.RabbitTemplate;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.time.LocalDateTime;
-import java.util.concurrent.TimeUnit;
-
-import static cn.hutool.core.text.CharSequenceUtil.format;
-import static com.jmsoftware.maf.springcloudstarter.rabbitmq.DelayedMessageConfiguration.*;
-
-/**
- * DelayedMessageSender
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com, 10/2/21 1:27 PM
- **/
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class DelayedMessageSender {
- private final RabbitTemplate rabbitTemplate;
- private final MafProjectProperties mafProjectProperties;
-
- @Scheduled(fixedDelay = 2L, timeUnit = TimeUnit.MINUTES)
- public void sendMessage() {
- val message = format("{} - {}", this.mafProjectProperties.getProjectArtifactId(), LocalDateTime.now());
- val messageMap = Maps.newHashMap();
- messageMap.put("message", message);
- this.rabbitTemplate.convertAndSend(
- DELAYED_MESSAGE_EXCHANGE_NAME,
- DELAYED_MESSAGE_ROUTING_KEY,
- messageMap,
- messagePostProcessor -> {
- // Make it be consumed after 30 seconds
- messagePostProcessor.getMessageProperties().setDelay(30 * 1000);
- return messagePostProcessor;
- }
- );
- log.info("Sent a delayed message into queue: {}, messageMap: {}", DELAYED_MESSAGE_QUEUE_NAME, messageMap);
- }
-}
diff --git a/auth-center/auth-center-message/src/main/java/com/jmsoftware/maf/authcenter/DelayedMessageSender.kt b/auth-center/auth-center-message/src/main/java/com/jmsoftware/maf/authcenter/DelayedMessageSender.kt
new file mode 100644
index 00000000..874d71ad
--- /dev/null
+++ b/auth-center/auth-center-message/src/main/java/com/jmsoftware/maf/authcenter/DelayedMessageSender.kt
@@ -0,0 +1,44 @@
+package com.jmsoftware.maf.authcenter
+
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.property.MafProjectProperties
+import com.jmsoftware.maf.springcloudstarter.rabbitmq.DelayedMessageConfiguration
+import org.springframework.amqp.core.Message
+import org.springframework.amqp.rabbit.core.RabbitTemplate
+import org.springframework.scheduling.annotation.Scheduled
+import org.springframework.stereotype.Component
+import java.time.LocalDateTime
+import java.util.concurrent.TimeUnit
+
+/**
+ * # DelayedMessageSender
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 12:55 PM
+ */
+@Component
+class DelayedMessageSender(
+ private val rabbitTemplate: RabbitTemplate,
+ private val mafProjectProperties: MafProjectProperties
+) {
+ companion object {
+ private val log = logger()
+ }
+
+ @Scheduled(fixedDelay = 2L, timeUnit = TimeUnit.MINUTES)
+ fun sendMessage() {
+ val message = "${mafProjectProperties.projectArtifactId} - ${LocalDateTime.now()}"
+ val messageMap = mapOf("message" to message)
+ rabbitTemplate.convertAndSend(
+ DelayedMessageConfiguration.DELAYED_MESSAGE_EXCHANGE_NAME,
+ DelayedMessageConfiguration.DELAYED_MESSAGE_ROUTING_KEY,
+ messageMap
+ ) { messagePostProcessor: Message ->
+ // Make it be consumed after 30 seconds
+ messagePostProcessor.messageProperties.delay = 30 * 1000
+ messagePostProcessor
+ }
+ log.info("Sent a delayed message into queue: ${DelayedMessageConfiguration.DELAYED_MESSAGE_QUEUE_NAME}, messageMap: $messageMap")
+ }
+}
diff --git a/auth-center/auth-center-message/src/test/java/com/jmsoftware/maf/authcenter/package-info.java b/auth-center/auth-center-message/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
deleted file mode 100644
index e702ef59..00000000
--- a/auth-center/auth-center-message/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.jmsoftware.maf.authcenter;
diff --git a/auth-center/auth-center-message/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt b/auth-center/auth-center-message/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
new file mode 100644
index 00000000..b7191a36
--- /dev/null
+++ b/auth-center/auth-center-message/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter
diff --git a/auth-center/auth-center-web/pom.xml b/auth-center/auth-center-web/pom.xml
index 0946fbba..e0508c4d 100644
--- a/auth-center/auth-center-web/pom.xml
+++ b/auth-center/auth-center-web/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
auth-center
- 0.0.8.1
+ 0.0.9
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/configuration/OssConfiguration.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/configuration/OssConfiguration.java
deleted file mode 100644
index a6a89fcf..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/configuration/OssConfiguration.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.jmsoftware.maf.authcenter.configuration;
-
-import com.jmsoftware.maf.authcenter.remote.OssCenterRemoteApi;
-import com.jmsoftware.maf.springcloudstarter.poi.OssUploader;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.mock.web.MockMultipartFile;
-
-/**
- * Description: OssConfiguration, change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 9/15/2021 11:51 AM
- **/
-@Slf4j
-@Configuration
-@RequiredArgsConstructor
-public class OssConfiguration {
- private final OssCenterRemoteApi ossCenterRemoteApi;
-
- @Bean
- public OssUploader ossUploader() {
- return (name, inputStream) -> {
- val multipartFile = new MockMultipartFile(name, name, null, inputStream);
- val response = this.ossCenterRemoteApi.uploadSingleResource(multipartFile);
- log.info("Called {} to upload multipartFile. {}", OssCenterRemoteApi.SERVICE_NAME, response);
- return String.format("%s/%s", response.getData().getBucket(), response.getData().getObject());
- };
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/configuration/OssConfiguration.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/configuration/OssConfiguration.kt
new file mode 100644
index 00000000..e3cda259
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/configuration/OssConfiguration.kt
@@ -0,0 +1,37 @@
+package com.jmsoftware.maf.authcenter.configuration
+
+import com.jmsoftware.maf.authcenter.remote.OssCenterFeignService
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.poi.OssUploader
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.mock.web.MockMultipartFile
+import java.io.InputStream
+
+/**
+ * # OssConfiguration
+ *
+ * Description: OssConfiguration, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 5:51 PM
+ */
+@Configuration
+class OssConfiguration(
+ private val ossCenterFeignService: OssCenterFeignService
+) {
+ companion object {
+ private val log = logger()
+ }
+
+ @Bean
+ fun ossUploader(): OssUploader {
+ return OssUploader { name: String, inputStream: InputStream ->
+ val multipartFile = MockMultipartFile(name, name, null, inputStream)
+ val objectResponse = ossCenterFeignService.uploadSingleResource(multipartFile)
+ log.info("Uploaded multipartFile. objectResponse: $objectResponse")
+ "${objectResponse.bucket}/${objectResponse.`object`}".apply {
+ log.info("Uploaded multipartFile. Path: $this")
+ }
+ }
+ }
+}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionController.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionController.java
deleted file mode 100644
index 70eedb38..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionController.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission;
-
-import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse;
-import com.jmsoftware.maf.authcenter.permission.service.PermissionService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.exception.BizException;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * PermissionController
- *
- * Controller implementation of Permission.(Permission)
- *
- * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
- * @date 5/11/20 8:34 AM
- */
-@Slf4j
-@RestController
-@RequiredArgsConstructor
-public class PermissionController {
- private final PermissionService permissionService;
-
- /**
- * Services info response body bean.
- *
- * @return the response body bean
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/25/2020 5:44 PM
- * @see
- * RestTemplate Excample
- */
- @GetMapping("/permissions/services-info")
- public ResponseBodyBean getServicesInfo() throws BizException {
- return ResponseBodyBean.ofSuccess(this.permissionService.getServicesInfo());
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionController.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionController.kt
new file mode 100644
index 00000000..6bed2333
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionController.kt
@@ -0,0 +1,24 @@
+package com.jmsoftware.maf.authcenter.permission
+
+import com.jmsoftware.maf.authcenter.permission.response.GetServicesInfoResponse
+import com.jmsoftware.maf.authcenter.permission.service.PermissionService
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.RestController
+
+/**
+ * # PermissionController
+ *
+ * Controller implementation of Permission.(Permission)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 2:53 PM
+ */
+@RestController
+class PermissionController(
+ private val permissionService: PermissionService
+) {
+ @GetMapping("/permissions/services-info")
+ fun getServicesInfo(): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(permissionService.getServicesInfo())
+}
+
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionRemoteApiController.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionRemoteApiController.java
deleted file mode 100644
index 9ce0c316..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionRemoteApiController.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.jmsoftware.maf.authcenter.permission;
-
-import com.jmsoftware.maf.authcenter.permission.service.PermissionService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload;
-import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.validation.Valid;
-
-/**
- * PermissionRemoteApiController
- *
- * Change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
- * @date 5/11/20 8:24 AM
- **/
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/permission-remote-api")
-public class PermissionRemoteApiController {
- private final PermissionService permissionService;
-
- @GetMapping("/permissions")
- public ResponseBodyBean getPermissionListByRoleIdList(@Valid GetPermissionListByRoleIdListPayload payload) {
- return ResponseBodyBean.ofSuccess(this.permissionService.getPermissionListByRoleIdList(payload));
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionRemoteApiController.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionRemoteApiController.kt
new file mode 100644
index 00000000..29ec7289
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/permission/PermissionRemoteApiController.kt
@@ -0,0 +1,30 @@
+package com.jmsoftware.maf.authcenter.permission
+
+import com.jmsoftware.maf.authcenter.permission.service.PermissionService
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListPayload
+import com.jmsoftware.maf.common.domain.authcenter.permission.GetPermissionListByRoleIdListResponse
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+import javax.validation.Valid
+
+/**
+ * PermissionRemoteApiController
+ *
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
+ * @date 5/11/20 8:24 AM
+ */
+@RestController
+@RequestMapping("/permission-remote-api")
+class PermissionRemoteApiController(
+ private val permissionService: PermissionService
+) {
+ @GetMapping("/permissions")
+ fun getPermissionListByRoleIdList(payload: @Valid GetPermissionListByRoleIdListPayload)
+ : ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(permissionService.getPermissionListByRoleIdList(payload))
+}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleController.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleController.java
deleted file mode 100644
index f49c75cb..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleController.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.jmsoftware.maf.authcenter.role;
-
-import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import com.jmsoftware.maf.springcloudstarter.poi.AbstractExcelDataController;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.time.Instant;
-import java.util.List;
-
-/**
- * Description: RoleController, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/17/2020 4:44 PM
- **/
-@Slf4j
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/roles")
-public class RoleController extends AbstractExcelDataController {
- private final RoleService roleService;
-
- @Override
- public void onExceptionOccurred() {
- log.error("Exception occurred when uploading excel for role.");
- this.fileName.set("role-stat" + Instant.now() + ".xlsx");
- }
-
- @Override
- protected void beforeDatabaseOperation(List beanList) {
- log.info("BeforeDatabaseOperation: {}", beanList);
- }
-
- @Override
- protected void executeDatabaseOperation(List beanList) {
- log.info("ExecuteDatabaseOperation: {}", beanList);
- this.roleService.save(beanList);
- }
-
- @Override
- protected String getTemplateFileName() {
- return RoleService.ROLE_TEMPLATE_EXCEL;
- }
-
- @Override
- protected List getListForExporting() {
- return this.roleService.getListForExporting();
- }
-
- @Override
- protected void validateBeforeAddToBeanList(List beanList, RoleExcelBean bean, int index) throws IllegalArgumentException {
- this.roleService.validateBeforeAddToBeanList(beanList, bean, index);
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleController.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleController.kt
new file mode 100644
index 00000000..287b4087
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleController.kt
@@ -0,0 +1,53 @@
+package com.jmsoftware.maf.authcenter.role
+
+import com.jmsoftware.maf.authcenter.role.service.RoleDomainService
+import com.jmsoftware.maf.common.util.logger
+import com.jmsoftware.maf.springcloudstarter.poi.AbstractExcelDataController
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+import java.time.Instant
+
+/**
+ * Description: RoleController, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 8:08 PM
+ */
+@RestController
+@RequestMapping("/roles")
+class RoleController(
+ private val roleDomainService: RoleDomainService
+) : AbstractExcelDataController() {
+ companion object {
+ private val log = logger()
+ }
+
+ override fun onExceptionOccurred() {
+ log.error("Exception occurred when uploading excel for role.")
+ fileName.set("role-stat-${Instant.now()}.xlsx")
+ }
+
+ override fun executeDatabaseOperation(beanList: List) {
+ log.info("ExecuteDatabaseOperation: {}", beanList)
+ roleDomainService.save(beanList)
+ }
+
+ override fun validateBeforeAddToBeanList(
+ beanList: List,
+ bean: RoleExcelBean,
+ index: Int
+ ) {
+ roleDomainService.validateBeforeAddToBeanList(beanList, bean, index)
+ }
+
+ override fun beforeDatabaseOperation(beanList: List) {
+ log.info("BeforeDatabaseOperation: {}", beanList)
+ }
+
+ override fun getTemplateFileName(): String {
+ return RoleDomainService.ROLE_TEMPLATE_EXCEL
+ }
+
+ override fun getListForExporting(): List {
+ return roleDomainService.getListForExporting()
+ }
+}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleRemoteApiController.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleRemoteApiController.java
deleted file mode 100644
index bb09815e..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleRemoteApiController.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.jmsoftware.maf.authcenter.role;
-
-import com.jmsoftware.maf.authcenter.role.service.RoleService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * RoleRemoteApiController
- *
- * Change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
- * @date 5/10/20 10:43 PM
- **/
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/role-remote-api")
-public class RoleRemoteApiController {
- private final RoleService roleService;
-
- @GetMapping("/roles/{userId}")
- public ResponseBodyBean getRoleList(@PathVariable Long userId) {
- return ResponseBodyBean.ofSuccess(this.roleService.getRoleList(userId));
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleRemoteApiController.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleRemoteApiController.kt
new file mode 100644
index 00000000..7e7871dd
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/role/RoleRemoteApiController.kt
@@ -0,0 +1,26 @@
+package com.jmsoftware.maf.authcenter.role
+
+import com.jmsoftware.maf.authcenter.role.service.RoleDomainService
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.role.GetRoleListByUserIdResponse
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PathVariable
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+
+/**
+ * # RoleRemoteApiController
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 3:08 PM
+ */
+@RestController
+@RequestMapping("/role-remote-api")
+class RoleRemoteApiController(
+ private val roleDomainService: RoleDomainService
+) {
+ @GetMapping("/roles/{userId}")
+ fun getRoleList(@PathVariable userId: Long): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(roleDomainService.getRoleList(userId))
+}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/security/JwtRemoteApiController.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/security/JwtRemoteApiController.java
deleted file mode 100644
index 37c6049a..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/security/JwtRemoteApiController.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.jmsoftware.maf.authcenter.security;
-
-import com.jmsoftware.maf.authcenter.security.service.JwtService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * Description: JwtRemoteApiController, change description here.
- *
- * @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/29/2020 11:04 AM
- **/
-@Validated
-@Slf4j
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/jwt-remote-api")
-public class JwtRemoteApiController {
- private final JwtService jwtService;
-
- /**
- * Parse response body bean.
- *
- * @return the response body bean
- */
- @GetMapping("/parse")
- public ResponseBodyBean parse(HttpServletRequest request) {
- return ResponseBodyBean.ofSuccess(this.jwtService.parse(request));
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/security/JwtRemoteApiController.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/security/JwtRemoteApiController.kt
new file mode 100644
index 00000000..6397d62c
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/security/JwtRemoteApiController.kt
@@ -0,0 +1,31 @@
+package com.jmsoftware.maf.authcenter.security
+
+import com.jmsoftware.maf.authcenter.security.service.JwtService
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+import javax.servlet.http.HttpServletRequest
+
+/**
+ * # JwtRemoteApiController
+ *
+ * Description: JwtRemoteApiController, change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 3:09 PM
+ */
+@RestController
+@RequestMapping("/jwt-remote-api")
+class JwtRemoteApiController(
+ private val jwtService: JwtService
+) {
+ /**
+ * Parse response body bean.
+ *
+ * @return the response body bean
+ */
+ @GetMapping("/parse")
+ fun parse(request: HttpServletRequest): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(jwtService.parse(request))
+}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserController.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserController.java
deleted file mode 100644
index 91b4544c..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserController.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.jmsoftware.maf.authcenter.user;
-
-import com.jmsoftware.maf.authcenter.user.service.UserService;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.user.LoginPayload;
-import com.jmsoftware.maf.common.domain.authcenter.user.LoginResponse;
-import com.jmsoftware.maf.common.domain.authcenter.user.SignupPayload;
-import com.jmsoftware.maf.common.domain.authcenter.user.SignupResponse;
-import com.jmsoftware.maf.common.exception.SecurityException;
-import lombok.RequiredArgsConstructor;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.validation.Valid;
-
-/**
- * UserController
- *
- * Controller implementation of UserPersistence.(UserPersistence)
- *
- * @author Johnny Miller (锺俊)
- * @date 2020-05-10 12:08:28
- */
-@Validated
-@RestController
-@RequiredArgsConstructor
-public class UserController {
- private final UserService userService;
-
- @PostMapping("/users/signup")
- public ResponseBodyBean signup(@Valid @RequestBody SignupPayload payload) {
- return ResponseBodyBean.ofSuccess(this.userService.saveUserForSignup(payload));
- }
-
- @PostMapping("/users/login")
- public ResponseBodyBean login(@Valid @RequestBody LoginPayload payload) throws SecurityException {
- return ResponseBodyBean.ofSuccess(this.userService.login(payload));
- }
-
- @PostMapping("/users/logout")
- public ResponseBodyBean logout(HttpServletRequest request) throws SecurityException {
- return ResponseBodyBean.ofSuccess(this.userService.logout(request));
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserController.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserController.kt
new file mode 100644
index 00000000..d7fde96c
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserController.kt
@@ -0,0 +1,39 @@
+package com.jmsoftware.maf.authcenter.user
+
+import com.jmsoftware.maf.authcenter.user.service.UserDomainService
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.user.LoginPayload
+import com.jmsoftware.maf.common.domain.authcenter.user.LoginResponse
+import com.jmsoftware.maf.common.domain.authcenter.user.SignupPayload
+import com.jmsoftware.maf.common.domain.authcenter.user.SignupResponse
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RestController
+import javax.servlet.http.HttpServletRequest
+import javax.validation.Valid
+
+/**
+ * # UserController
+ *
+ * Controller implementation of UserPersistence.(UserPersistence)
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 3:10 PM
+ */
+@Validated
+@RestController
+class UserController(
+ private val userDomainService: UserDomainService
+) {
+ @PostMapping("/users/signup")
+ fun signup(@Valid @RequestBody payload: SignupPayload): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(userDomainService.saveUserForSignup(payload))
+
+ @PostMapping("/users/login")
+ fun login(@Valid @RequestBody payload: LoginPayload): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(userDomainService.login(payload))
+
+ @PostMapping("/users/logout")
+ fun logout(request: HttpServletRequest): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(userDomainService.logout(request))
+}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserRemoteApiController.java b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserRemoteApiController.java
deleted file mode 100644
index 541659a4..00000000
--- a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserRemoteApiController.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.jmsoftware.maf.authcenter.user;
-
-import com.jmsoftware.maf.authcenter.user.payload.GetUserPageListPayload;
-import com.jmsoftware.maf.authcenter.user.payload.GetUserStatusPayload;
-import com.jmsoftware.maf.authcenter.user.persistence.User;
-import com.jmsoftware.maf.authcenter.user.service.UserService;
-import com.jmsoftware.maf.common.bean.PageResponseBodyBean;
-import com.jmsoftware.maf.common.bean.ResponseBodyBean;
-import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse;
-import lombok.RequiredArgsConstructor;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.validation.Valid;
-
-/**
- * UserRemoteApiController
- *
- * Change description here.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
- * @date 5/10/20 12:36 PM
- **/
-@Validated
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/user-remote-api")
-public class UserRemoteApiController {
- private final UserService userService;
-
- @GetMapping("/users/{loginToken}")
- public ResponseBodyBean getUserByLoginToken(@PathVariable String loginToken) {
- return ResponseBodyBean.ofSuccess(this.userService.getUserByLoginToken(loginToken));
- }
-
- @GetMapping("/users")
- public PageResponseBodyBean getUserPageList(@Valid GetUserPageListPayload payload) {
- return this.userService.getUserPageList(payload);
- }
-
- @GetMapping("/users/status")
- public ResponseBodyBean getUserStatus(@Valid GetUserStatusPayload payload) {
- return ResponseBodyBean.ofSuccess(this.userService.getUserStatus(payload), "Correct enum value");
- }
-}
diff --git a/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserRemoteApiController.kt b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserRemoteApiController.kt
new file mode 100644
index 00000000..65dbd1d1
--- /dev/null
+++ b/auth-center/auth-center-web/src/main/java/com/jmsoftware/maf/authcenter/user/UserRemoteApiController.kt
@@ -0,0 +1,41 @@
+package com.jmsoftware.maf.authcenter.user
+
+import com.jmsoftware.maf.authcenter.user.payload.GetUserPageListPayload
+import com.jmsoftware.maf.authcenter.user.payload.GetUserStatusPayload
+import com.jmsoftware.maf.authcenter.user.persistence.User
+import com.jmsoftware.maf.authcenter.user.service.UserDomainService
+import com.jmsoftware.maf.common.bean.PageResponseBodyBean
+import com.jmsoftware.maf.common.bean.ResponseBodyBean
+import com.jmsoftware.maf.common.domain.authcenter.user.GetUserByLoginTokenResponse
+import org.springframework.validation.annotation.Validated
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PathVariable
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+import javax.validation.Valid
+
+/**
+ * # UserRemoteApiController
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/12/22 3:21 PM
+ */
+@Validated
+@RestController
+@RequestMapping("/user-remote-api")
+class UserRemoteApiController(
+ private val userDomainService: UserDomainService
+) {
+ @GetMapping("/users/{loginToken}")
+ fun getUserByLoginToken(@PathVariable loginToken: String): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(userDomainService.getUserByLoginToken(loginToken))
+
+ @GetMapping("/users")
+ fun getUserPageList(@Valid payload: GetUserPageListPayload): PageResponseBodyBean =
+ userDomainService.getUserPageList(payload)
+
+ @GetMapping("/users/status")
+ fun getUserStatus(@Valid payload: GetUserStatusPayload): ResponseBodyBean =
+ ResponseBodyBean.ofSuccess(userDomainService.getUserStatus(payload), "Correct enum value")
+}
diff --git a/auth-center/auth-center-web/src/test/java/com/jmsoftware/maf/authcenter/package-info.java b/auth-center/auth-center-web/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
deleted file mode 100644
index 4bc2a3b9..00000000
--- a/auth-center/auth-center-web/src/test/java/com/jmsoftware/maf/authcenter/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright By ZATI
- * Copyright By 3a3c88295d37870dfd3b25056092d1a9209824b256c341f2cdc296437f671617
- * All rights reserved.
- *
- * If you are not the intended user, you are hereby notified that any use, disclosure, copying, printing, forwarding or
- * dissemination of this property is strictly prohibited. If you have got this file in error, delete it from your
- * system.
- */
-package com.jmsoftware.maf.authcenter;
diff --git a/auth-center/auth-center-web/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt b/auth-center/auth-center-web/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
new file mode 100644
index 00000000..b7191a36
--- /dev/null
+++ b/auth-center/auth-center-web/src/test/java/com/jmsoftware/maf/authcenter/package-info.kt
@@ -0,0 +1 @@
+package com.jmsoftware.maf.authcenter
diff --git a/auth-center/pom.xml b/auth-center/pom.xml
index ed325f84..fac2d3cc 100644
--- a/auth-center/pom.xml
+++ b/auth-center/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
muscle-and-fitness-server
- 0.0.8.1
+ 0.0.9
pom
@@ -75,6 +75,10 @@
org.springframework.boot
spring-boot-starter-data-redis
+
+ org.springframework.boot
+ spring-boot-starter-data-elasticsearch
+
org.springframework.boot
spring-boot-starter-amqp
@@ -96,52 +100,37 @@
org.springframework.boot
spring-boot-starter-reactor-netty
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
-
-
-
org.springframework
spring-test
-
-
- com.baomidou
- mybatis-plus-boot-starter
- ${mybatis-plus-boot-starter.version}
+ org.mockito
+ mockito-inline
+ test
+
+
- com.baomidou
- dynamic-datasource-spring-boot-starter
- ${dynamic-datasource-spring-boot-starter.version}
+ org.springframework.integration
+ spring-integration-redis
+
+
mysql
mysql-connector-java
runtime
- com.alibaba
- druid-spring-boot-starter
- ${druid-spring-boot-starter.version}
-
-
- com.sun
- tools
-
-
- com.sun
- jconsole
-
-
+ com.baomidou
+ mybatis-plus-boot-starter
+ ${mybatis-plus-boot-starter.version}
+
+
+ org.apache.shardingsphere
+ shardingsphere-jdbc-core-spring-boot-starter
+ ${shardingsphere.version}
diff --git a/auto-run-mac.sh b/auto-run-mac.sh
index bb15fe8d..6f9aca40 100755
--- a/auto-run-mac.sh
+++ b/auto-run-mac.sh
@@ -174,7 +174,7 @@ function executePreBuildPhase() {
function executeBuildPhase() {
logInfo "[BUILD] Maven is staring to build"
if [ "$skipBuild" = false ]; then
- mvn clean package --show-version -Dmaven.javadoc.skip=true -DskipTests=true -P $mavenActiveProfile
+ mvn clean package --show-version -Dmaven.javadoc.skip=true -P $mavenActiveProfile
buildCommandResult=$?
# After the command that might error, instead of || exit 1...
if [ "$buildCommandResult" -ne 0 ]; then
diff --git a/common/pom.xml b/common/pom.xml
index 866a379f..83aa837f 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -10,7 +10,7 @@
com.jmsoftware.maf
muscle-and-fitness-server
- 0.0.8.1
+ 0.0.9
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/EnumerationBase.java b/common/src/main/java/com/jmsoftware/maf/common/bean/EnumerationBase.java
deleted file mode 100644
index 4d56b063..00000000
--- a/common/src/main/java/com/jmsoftware/maf/common/bean/EnumerationBase.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.jmsoftware.maf.common.bean;
-
-/**
- * EnumerationBase
- *
- * Change description here.
- *
- * @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
- * @date 6/6/21 5:38 PM
- **/
-public interface EnumerationBase {
- /**
- * Gets value.
- *
- * @return the value
- */
- T getValue();
-}
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/ExcelImportResult.java b/common/src/main/java/com/jmsoftware/maf/common/bean/ExcelImportResult.java
deleted file mode 100644
index 17cd9bc6..00000000
--- a/common/src/main/java/com/jmsoftware/maf/common/bean/ExcelImportResult.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.jmsoftware.maf.common.bean;
-
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * ExcelImportResult
- *
- * Change description here.
- *
- * @author 钟俊 (jun.zhong), email: jun.zhong@ucarinc.com
- * @date 4/29/20 8:50 PM
- **/
-@Data
-public class ExcelImportResult {
- private List messageList;
- private String excelFilePath;
-}
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/ExcelImportResult.kt b/common/src/main/java/com/jmsoftware/maf/common/bean/ExcelImportResult.kt
new file mode 100644
index 00000000..37496a5a
--- /dev/null
+++ b/common/src/main/java/com/jmsoftware/maf/common/bean/ExcelImportResult.kt
@@ -0,0 +1,13 @@
+package com.jmsoftware.maf.common.bean
+
+/**
+ * # ExcelImportResult
+ *
+ * Change description here.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 11:01 AM
+ */
+class ExcelImportResult {
+ var messageList: List? = null
+ var excelFilePath: String? = null
+}
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/PageResponseBodyBean.java b/common/src/main/java/com/jmsoftware/maf/common/bean/PageResponseBodyBean.java
deleted file mode 100644
index c26aadd5..00000000
--- a/common/src/main/java/com/jmsoftware/maf/common/bean/PageResponseBodyBean.java
+++ /dev/null
@@ -1,326 +0,0 @@
-package com.jmsoftware.maf.common.bean;
-
-import cn.hutool.json.JSON;
-import cn.hutool.json.JSONConfig;
-import cn.hutool.json.JSONUtil;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.jmsoftware.maf.common.constant.UniversalDateTime;
-import com.jmsoftware.maf.common.exception.BaseException;
-import com.jmsoftware.maf.common.exception.BizException;
-import lombok.*;
-import org.springframework.http.HttpStatus;
-import org.springframework.lang.Nullable;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * PageResponseBodyBean
- *
- * Page Response body bean.
- *
- * @param the response body data type
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 4:24 PM
- */
-@Data
-@SuppressWarnings("unused")
-public class PageResponseBodyBean implements Serializable {
- /**
- * The constant serialVersionUID.
- */
- private static final long serialVersionUID = 4645461634548783641L;
-
- /**
- * The Timestamp. Must be annotated by '@JsonFormat', otherwise will cause following error, cuz api-gateway does not
- * know how to convert LocalDateTime.
- *
- * Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2021-06-27
- * 23:08:46'
- */
- @Setter(AccessLevel.NONE)
- @JsonFormat(pattern = UniversalDateTime.DATE_TIME_FORMAT)
- final LocalDateTime timestamp = LocalDateTime.now();
- /**
- * Default status is 200 OK.
- */
- private Integer status = HttpStatus.OK.value();
- /**
- * The Message. Default: 200 OK.
- */
- private String message = HttpStatus.OK.getReasonPhrase();
- /**
- * The List.
- */
- private List list = Collections.emptyList();
- /**
- * The Total.
- */
- private long total;
-
- /**
- * Respond to client with IUniversalStatus (status may be OK or other).
- * ATTENTION:
- * This method CANNOT be used by controller or service or other class, only provided for Exception controller
- * .
- *
- * @param the type parameter
- * @param status IUniversalStatus
- * @return response body for ExceptionControllerAdvice javax.servlet.http.HttpServletResponse, Exception)
- */
- public static PageResponseBodyBean ofStatus(@NonNull final HttpStatus status) {
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setStatus(status.value());
- responseBodyBean.setMessage(status.getReasonPhrase());
- return responseBodyBean;
- }
-
- /**
- * Of status response body bean.
- *
- * @param the type parameter
- * @param status the status
- * @param message the message
- * @return the response body bean
- */
- public static PageResponseBodyBean ofStatus(@NonNull final HttpStatus status,
- @NonNull final String message) {
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setStatus(status.value());
- responseBodyBean.setMessage(message);
- return responseBodyBean;
- }
-
- /**
- * Respond to client with IUniversalStatus and data.
- * ATTENTION:
- * This method CANNOT be used by controller or service or other class, only provided for Exception controller
- * .
- *
- * @param the response body data type
- * @param status IUniversalStatus
- * @param data data to be responded to client
- * @param total the total
- * @return response body for ExceptionControllerAdvice
- */
- public static PageResponseBodyBean ofStatus(@NonNull final HttpStatus status,
- final List data,
- final long total) {
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setStatus(status.value());
- responseBodyBean.setMessage(status.getReasonPhrase());
- responseBodyBean.setList(data);
- responseBodyBean.setTotal(total);
- return responseBodyBean;
- }
-
- /**
- * Highly customizable response. Status might be any HttpStatus' code value.
- * ATTENTION:
- * This method CANNOT be used by controller or service or other class, only provided for Exception controller
- * .
- *
- * @param the response body data type
- * @param status status code
- * @param message message to be responded
- * @param data data to be responded
- * @param total the total
- * @return response body for ExceptionControllerAdvice
- */
- public static PageResponseBodyBean ofStatus(@NonNull final Integer status,
- @NonNull final String message,
- final List data,
- final long total) {
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setStatus(status);
- responseBodyBean.setMessage(message);
- responseBodyBean.setList(data);
- responseBodyBean.setTotal(total);
- return responseBodyBean;
- }
-
- /**
- * Highly customizable response. Status might be any HttpStatus' code value.
- * ATTENTION:
- * This method CANNOT be used in ExceptionControllerAdvice.
- *
- * @param the response body data type
- * @param status status code
- * @param message message to be responded
- * @param data data to be responded
- * @param total the total
- * @return response body
- * @throws BaseException the base exception
- */
- public static PageResponseBodyBean setResponse(@NonNull final Integer status,
- @NonNull final String message,
- final List data,
- final long total)
- throws BaseException {
- if (!HttpStatus.valueOf(status).is2xxSuccessful()) {
- throw new BaseException(status, message, data);
- }
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setStatus(status);
- responseBodyBean.setMessage(message);
- responseBodyBean.setList(data);
- responseBodyBean.setTotal(total);
- return responseBodyBean;
- }
-
- /**
- * Respond null data, and status is OK.
- *
- * @param the response body data type
- * @return response body
- */
- public static PageResponseBodyBean ofSuccess() {
- return new PageResponseBodyBean<>();
- }
-
- /**
- * Respond data and status is OK.
- *
- * @param the response body data type
- * @param data data to be responded to client.
- * @param total the total
- * @return response body
- */
- public static PageResponseBodyBean ofSuccess(final List data,
- final long total) {
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setList(data);
- responseBodyBean.setTotal(total);
- return responseBodyBean;
- }
-
- /**
- * Respond a message and status is OK.
- *
- * @param the response body data type
- * @param message message to be responded
- * @return response body
- */
- public static PageResponseBodyBean ofSuccess(@NonNull final String message) {
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setMessage(message);
- return responseBodyBean;
- }
-
- /**
- * Respond data, message and status is OK.
- *
- * @param the response body data type
- * @param data data to be responded
- * @param message message to be responded
- * @param total the total
- * @return response body
- */
- public static PageResponseBodyBean ofSuccess(final List data,
- @NonNull final String message,
- final long total) {
- PageResponseBodyBean responseBodyBean = new PageResponseBodyBean<>();
- responseBodyBean.setMessage(message);
- responseBodyBean.setList(data);
- responseBodyBean.setTotal(total);
- return responseBodyBean;
- }
-
- /**
- * Respond a message and status is FAILURE(464).
- *
- * @param the response body data type
- * @param message message to be responded.
- * @return response body
- * @throws BizException the business exception
- */
- public static PageResponseBodyBean ofFailure(@NonNull final String message) throws BizException {
- throw new BizException(message);
- }
-
- /**
- * Respond a message and status is FAILURE(464).
- *
- * @param the response body data type
- * @param data data to be responded
- * @return response body
- * @throws BizException the business exception
- */
- public static PageResponseBodyBean ofFailure(final List data) throws BizException {
- throw new BizException(data);
- }
-
- /**
- * Respond data and message, and status if FAILURE(464).
- *
- * @param the response body data type
- * @param data data to be responded
- * @param message message to be responded
- * @return response body
- * @throws BizException the business exception
- */
- public static PageResponseBodyBean ofFailure(final List data,
- @NonNull final String message) throws BizException {
- throw new BizException(data, message);
- }
-
- /**
- * Respond an ERROR(500).
- *
- * @param the response body data type
- * @return response body
- * @throws BaseException the base exception
- */
- public static PageResponseBodyBean ofError() throws BaseException {
- return setResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(),
- null, 0);
- }
-
- /**
- * Respond a custom error.
- *
- * @param the response body data type
- * @param status Error status, not OK(200)
- * @return response body
- * @throws BaseException the base exception
- */
- public static PageResponseBodyBean ofError(@NonNull final HttpStatus status)
- throws BaseException {
- return setResponse(status.value(), status.getReasonPhrase(), null, 0);
- }
-
- /**
- * Response an exception.
- *
- * @param the response body data type
- * @param Subclass of {@link BaseException}
- * @param throwable exception
- * @return the response body bean
- * @throws BaseException the base exception
- */
- public static PageResponseBodyBean ofException(@NonNull final B throwable)
- throws BaseException {
- throw throwable;
- }
-
- /**
- * Of json.
- *
- * @param the type parameter
- * @param message the message
- * @param data the data
- * @param total the total
- * @param status the status
- * @return the json
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/22/2020 10:16 AM
- */
- public static JSON of(@NonNull String message,
- @Nullable List data,
- long total, @NonNull Integer status) {
- val responseBodyBean = PageResponseBodyBean.ofStatus(status, message, data, total);
- val config = new JSONConfig();
- config.setIgnoreNullValue(false).setDateFormat("yyyy-MM-dd HH:mm:ss");
- return JSONUtil.parse(responseBodyBean, config);
- }
-}
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/PageResponseBodyBean.kt b/common/src/main/java/com/jmsoftware/maf/common/bean/PageResponseBodyBean.kt
new file mode 100644
index 00000000..e611cffd
--- /dev/null
+++ b/common/src/main/java/com/jmsoftware/maf/common/bean/PageResponseBodyBean.kt
@@ -0,0 +1,350 @@
+package com.jmsoftware.maf.common.bean
+
+import cn.hutool.json.JSON
+import cn.hutool.json.JSONConfig
+import cn.hutool.json.JSONUtil
+import com.fasterxml.jackson.annotation.JsonFormat
+import com.jmsoftware.maf.common.constant.UniversalDateTime
+import com.jmsoftware.maf.common.exception.BaseException
+import com.jmsoftware.maf.common.exception.InternalServerException
+import org.springframework.http.HttpStatus
+import org.springframework.lang.Nullable
+import java.io.Serial
+import java.io.Serializable
+import java.time.LocalDateTime
+
+/**
+ * # PageResponseBodyBean
+ *
+ * Page Response body bean.
+ *
+ * @param the response body data type
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 11:02 AM
+ */
+class PageResponseBodyBean private constructor() : TrackableBean(), Serializable {
+ /**
+ * The Timestamp. Must be annotated by '@JsonFormat', otherwise will cause following error, cuz api-gateway does not
+ * know how to convert LocalDateTime.
+ *
+ * Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2021-06-27 23:08:46'
+ */
+ @JsonFormat(pattern = UniversalDateTime.DATE_TIME_FORMAT)
+ val timestamp: LocalDateTime = LocalDateTime.now()
+
+ /**
+ * Default status is 200 OK.
+ */
+ var status = HttpStatus.OK.value()
+
+ /**
+ * The Message. Default: 200 OK.
+ */
+ var message = HttpStatus.OK.reasonPhrase
+
+ /**
+ * The List.
+ */
+ var list = emptyList()
+
+ /**
+ * The Total.
+ */
+ var total: Long = 0
+
+ companion object {
+ /**
+ * The constant serialVersionUID.
+ */
+ @Serial
+ var serialVersionUID = 4645461634548783641L
+
+ /**
+ * Respond to client with IUniversalStatus (status may be OK or other).
+ *
+ * **ATTENTION:**
+ *
+ * This method CANNOT be used by controller or service or other class, only provided for Exception controller.
+ *
+ * @param the type parameter
+ * @param status IUniversalStatus
+ * @return response body for ExceptionControllerAdvice javax.servlet.http.HttpServletResponse, Exception)
+ */
+ fun ofStatus(status: HttpStatus): PageResponseBodyBean {
+ val responseBodyBean = PageResponseBodyBean()
+ responseBodyBean.status = status.value()
+ responseBodyBean.message = status.reasonPhrase
+ return responseBodyBean
+ }
+
+ /**
+ * Of status response body bean.
+ *
+ * @param the type parameter
+ * @param status the status
+ * @param message the message
+ * @return the response body bean
+ */
+ fun ofStatus(
+ status: HttpStatus,
+ message: String
+ ): PageResponseBodyBean {
+ val responseBodyBean = PageResponseBodyBean()
+ responseBodyBean.status = status.value()
+ responseBodyBean.message = message
+ return responseBodyBean
+ }
+
+ /**
+ * Respond to client with IUniversalStatus and data.
+ *
+ * **ATTENTION:**
+ *
+ * This method CANNOT be used by controller or service or other class, only provided for Exception controller
+ * .
+ *
+ * @param the response body data type
+ * @param status IUniversalStatus
+ * @param data data to be responded to client
+ * @param total the total
+ * @return response body for ExceptionControllerAdvice
+ */
+ fun ofStatus(
+ status: HttpStatus,
+ data: List?,
+ total: Long
+ ): PageResponseBodyBean {
+ val responseBodyBean = PageResponseBodyBean()
+ responseBodyBean.status = status.value()
+ responseBodyBean.message = status.reasonPhrase
+ data?.let { responseBodyBean.list = it }
+ responseBodyBean.total = total
+ return responseBodyBean
+ }
+
+ /**
+ * Highly customizable response. Status might be any HttpStatus' code value.
+ *
+ * **ATTENTION:**
+ *
+ * This method CANNOT be used by controller or service or other class, only provided for Exception controller.
+ *
+ * @param the response body data type
+ * @param status status code
+ * @param message message to be responded
+ * @param data data to be responded
+ * @param total the total
+ * @return response body for ExceptionControllerAdvice
+ */
+ fun ofStatus(
+ status: Int,
+ message: String,
+ data: List?,
+ total: Long
+ ): PageResponseBodyBean {
+ val responseBodyBean = PageResponseBodyBean()
+ responseBodyBean.status = status
+ responseBodyBean.message = message
+ data?.let { responseBodyBean.list = it }
+ responseBodyBean.total = total
+ return responseBodyBean
+ }
+
+ /**
+ * Highly customizable response. Status might be any HttpStatus' code value.
+ *
+ * **ATTENTION:**
+ *
+ * This method CANNOT be used in ExceptionControllerAdvice.
+ *
+ * @param the response body data type
+ * @param status status code
+ * @param message message to be responded
+ * @param data data to be responded
+ * @param total the total
+ * @return response body
+ * @throws BaseException the base exception
+ */
+ @Throws(BaseException::class)
+ fun setResponse(
+ status: Int,
+ message: String,
+ data: List?,
+ total: Long
+ ): PageResponseBodyBean {
+ if (!HttpStatus.valueOf(status).is2xxSuccessful) {
+ throw BaseException(status, message, data)
+ }
+ val responseBodyBean = PageResponseBodyBean()
+ responseBodyBean.status = status
+ responseBodyBean.message = message
+ data?.let { responseBodyBean.list = it }
+ responseBodyBean.total = total
+ return responseBodyBean
+ }
+
+ /**
+ * Respond null data, and status is OK.
+ *
+ * @param the response body data type
+ * @return response body
+ */
+ fun ofSuccess(): PageResponseBodyBean {
+ return PageResponseBodyBean()
+ }
+
+ /**
+ * Respond data and status is OK.
+ *
+ * @param the response body data type
+ * @param data data to be responded to client.
+ * @param total the total
+ * @return response body
+ */
+ fun ofSuccess(
+ data: List?,
+ total: Long
+ ): PageResponseBodyBean {
+ val responseBodyBean = PageResponseBodyBean()
+ data?.let { responseBodyBean.list = it }
+ responseBodyBean.total = total
+ return responseBodyBean
+ }
+
+ /**
+ * Respond a message and status is OK.
+ *
+ * @param the response body data type
+ * @param message message to be responded
+ * @return response body
+ */
+ fun ofSuccess(message: String): PageResponseBodyBean {
+ val responseBodyBean = PageResponseBodyBean()
+ responseBodyBean.message = message
+ return responseBodyBean
+ }
+
+ /**
+ * Respond data, message and status is OK.
+ *
+ * @param the response body data type
+ * @param data data to be responded
+ * @param message message to be responded
+ * @param total the total
+ * @return response body
+ */
+ fun ofSuccess(
+ data: List?,
+ message: String,
+ total: Long
+ ): PageResponseBodyBean {
+ val responseBodyBean = PageResponseBodyBean()
+ responseBodyBean.message = message
+ data?.let { responseBodyBean.list = it }
+ responseBodyBean.total = total
+ return responseBodyBean
+ }
+
+ /**
+ * Respond a message and status is FAILURE(464).
+ *
+ * @param the response body data type
+ * @param message message to be responded.
+ * @return response body
+ * @throws InternalServerException the business exception
+ */
+ fun ofFailure(message: String): PageResponseBodyBean {
+ throw InternalServerException(message)
+ }
+
+ /**
+ * Respond a message and status is FAILURE(464).
+ *
+ * @param the response body data type
+ * @param data data to be responded
+ * @return response body
+ * @throws InternalServerException the business exception
+ */
+ fun ofFailure(data: List?): PageResponseBodyBean {
+ throw InternalServerException(data)
+ }
+
+ /**
+ * Respond data and message, and status if FAILURE(464).
+ *
+ * @param the response body data type
+ * @param data data to be responded
+ * @param message message to be responded
+ * @return response body
+ * @throws InternalServerException the business exception
+ */
+ fun ofFailure(
+ data: List?,
+ message: String
+ ): PageResponseBodyBean {
+ throw InternalServerException(data, message)
+ }
+
+ /**
+ * Respond an ERROR(500).
+ *
+ * @param the response body data type
+ * @return response body
+ * @throws BaseException the base exception
+ */
+ fun ofError(): PageResponseBodyBean {
+ return setResponse(
+ HttpStatus.INTERNAL_SERVER_ERROR.value(),
+ HttpStatus.INTERNAL_SERVER_ERROR.reasonPhrase,
+ null,
+ 0
+ )
+ }
+
+ /**
+ * Respond a custom error.
+ *
+ * @param the response body data type
+ * @param status Error status, not OK(200)
+ * @return response body
+ * @throws BaseException the base exception
+ */
+ fun ofError(status: HttpStatus): PageResponseBodyBean {
+ return setResponse(status.value(), status.reasonPhrase, null, 0)
+ }
+
+ /**
+ * Response an exception.
+ *
+ * @param the response body data type
+ * @param Subclass of [BaseException]
+ * @param throwable exception
+ * @return the response body bean
+ * @throws BaseException the base exception
+ */
+ fun ofException(throwable: B): PageResponseBodyBean {
+ throw throwable
+ }
+
+ /**
+ * Of json.
+ *
+ * @param the type parameter
+ * @param message the message
+ * @param data the data
+ * @param total the total
+ * @param status the status
+ * @return the json
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/22/2020 10:16 AM
+ */
+ fun of(
+ message: String,
+ @Nullable data: List?,
+ total: Long, status: Int
+ ): JSON {
+ val responseBodyBean = ofStatus(status, message, data, total)
+ val config = JSONConfig()
+ config.setIgnoreNullValue(false).dateFormat = "yyyy-MM-dd HH:mm:ss"
+ return JSONUtil.parse(responseBodyBean, config)
+ }
+ }
+}
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/PaginationBase.java b/common/src/main/java/com/jmsoftware/maf/common/bean/PaginationBase.java
deleted file mode 100644
index 30ff793d..00000000
--- a/common/src/main/java/com/jmsoftware/maf/common/bean/PaginationBase.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.jmsoftware.maf.common.bean;
-
-import cn.hutool.core.text.CharSequenceUtil;
-import cn.hutool.core.util.NumberUtil;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import lombok.Data;
-import org.hibernate.validator.constraints.Range;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-
-/**
- * PaginationBase
- *
- * Pagination Base.
- *
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
- * @date 2/17/20 11:18 PM
- **/
-@Data
-@SuppressWarnings("unused")
-public class PaginationBase {
- /**
- * The current page. Default: 1
- */
- @JsonIgnore
- @NotNull(message = "The current page is required!")
- @Min(value = 1L, message = "The current page is not less then 1!")
- private Integer currentPage = 1;
- /**
- * The page size. Default: 10
- */
- @JsonIgnore
- @NotNull(message = "The page size is required!")
- @Range(min = 10L, max = 100L, message = "The rage of page size: 10 <= page size <= 100!")
- private Integer pageSize = 10;
- /**
- * The order-by. (for table's field)
- */
- @JsonIgnore
- private String orderBy;
- /**
- * The order rule. Default: DESC
- */
- @JsonIgnore
- @Pattern(regexp = "^(ASC|DESC)$")
- private String orderRule = "DESC";
- /**
- * The order-by statement needs to be joined.
- */
- @JsonIgnore
- private String orderByStatement;
-
- @JsonIgnore
- public String getOrderByStatement() {
- if (!CharSequenceUtil.isBlank(this.orderBy)) {
- return String.format("%s `%s` %s", "ORDER BY", this.orderBy, this.orderRule);
- }
- return this.orderByStatement;
- }
-
- /**
- * Has next page boolean.
- *
- * @param pageResponseBodyBean the page response body bean
- * @return the boolean
- * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 4:37 PM
- */
- public boolean hasNextPage(@NotNull PageResponseBodyBean> pageResponseBodyBean) {
- if (NumberUtil.compare(pageResponseBodyBean.getTotal(), (long) this.currentPage * this.pageSize) > 0) {
- this.currentPage += 1;
- return true;
- }
- return false;
- }
-}
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/PaginationBase.kt b/common/src/main/java/com/jmsoftware/maf/common/bean/PaginationBase.kt
new file mode 100644
index 00000000..98388bc2
--- /dev/null
+++ b/common/src/main/java/com/jmsoftware/maf/common/bean/PaginationBase.kt
@@ -0,0 +1,79 @@
+package com.jmsoftware.maf.common.bean
+
+import cn.hutool.core.util.NumberUtil
+import com.fasterxml.jackson.annotation.JsonIgnore
+import org.hibernate.validator.constraints.Range
+import javax.validation.constraints.Min
+import javax.validation.constraints.NotNull
+import javax.validation.constraints.Pattern
+
+/**
+ * PaginationBase
+ *
+ * Pagination Base.
+ *
+ * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com, date: 4/16/22 11:13 AM
+ */
+open class PaginationBase {
+ /**
+ * The current page. Default: 1
+ */
+ @JsonIgnore
+ @NotNull(message = "The current page is required!")
+ @Min(value = 1L, message = "The current page is not less then 1!")
+ var currentPage: Int = 1
+
+ /**
+ * The page size. Default: 10
+ */
+ @JsonIgnore
+ @NotNull(message = "The page size is required!")
+ @Range(min = 10L, max = 100L, message = "The rage of page size: 10 <= page size <= 100!")
+ var pageSize: Int = 10
+
+ /**
+ * The order-by. (for table's field)
+ */
+ @JsonIgnore
+ var orderBy: String? = null
+
+ /**
+ * The order rule. Default: DESC
+ */
+ @JsonIgnore
+ @Pattern(regexp = "^(ASC|DESC)$")
+ var orderRule: String = "DESC"
+
+ /**
+ * The order-by statement needs to be joined.
+ */
+ @JsonIgnore
+ var orderByStatement: String? = null
+
+ /**
+ * The order-by statement needs to be joined.
+ */
+ @JsonIgnore
+ fun orderByStatement(): String {
+ orderByStatement?.isBlank()
+ if (orderBy?.isNotBlank() == true) {
+ return "ORDER BY `$orderBy` $orderRule"
+ }
+ return orderByStatement!!
+ }
+
+ /**
+ * Has next page boolean.
+ *
+ * @param pageResponseBodyBean the page response body bean
+ * @return the boolean
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 4:37 PM
+ */
+ fun hasNextPage(pageResponseBodyBean: @NotNull PageResponseBodyBean<*>?): Boolean {
+ if (NumberUtil.compare(pageResponseBodyBean!!.total, currentPage.toLong() * pageSize) > 0) {
+ currentPage += 1
+ return true
+ }
+ return false
+ }
+}
diff --git a/common/src/main/java/com/jmsoftware/maf/common/bean/ResponseBodyBean.java b/common/src/main/java/com/jmsoftware/maf/common/bean/ResponseBodyBean.java
deleted file mode 100644
index 4130bf49..00000000
--- a/common/src/main/java/com/jmsoftware/maf/common/bean/ResponseBodyBean.java
+++ /dev/null
@@ -1,290 +0,0 @@
-package com.jmsoftware.maf.common.bean;
-
-import cn.hutool.json.JSON;
-import cn.hutool.json.JSONConfig;
-import cn.hutool.json.JSONUtil;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.jmsoftware.maf.common.constant.UniversalDateTime;
-import com.jmsoftware.maf.common.exception.BaseException;
-import com.jmsoftware.maf.common.exception.BizException;
-import lombok.*;
-import org.springframework.http.HttpStatus;
-import org.springframework.lang.Nullable;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- *
ResponseBodyBean
- *
- * Response body bean.
- *
- * @param the response body data type
- * @author Johnny Miller (锺俊), e-mail: johnnysviva@outlook.com
- * @date 2/27/20 9:24 AM
- */
-@Data
-@SuppressWarnings("unused")
-public class ResponseBodyBean implements Serializable {
- private static final long serialVersionUID = 4645469240048361965L;
-
- /**
- * The Timestamp. Must be annotated by '@JsonFormat', otherwise will cause following error, cuz api-gateway does not
- * know how to convert LocalDateTime.
- *
- * Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2021-06-27
- * 23:08:46'
- */
- @Setter(AccessLevel.NONE)
- @JsonFormat(pattern = UniversalDateTime.DATE_TIME_FORMAT)
- private final LocalDateTime timestamp = LocalDateTime.now();
- /**
- * Default status is 200 OK.
- */
- private int status = HttpStatus.OK.value();
- /**
- * The Message. Default: 200 OK.
- */
- private String message = HttpStatus.OK.getReasonPhrase();
- /**
- * The Data.
- */
- private T data;
-
- private ResponseBodyBean() {
- }
-
- /**
- *
Respond to client with IUniversalStatus (status may be OK or other).
- * ATTENTION:
- * This method CANNOT be used by controller or service or other class, only provided for Exception controller
- * .
- *
- * @param the type parameter
- * @param status IUniversalStatus
- * @return response body for ExceptionControllerAdvice javax.servlet.http.HttpServletResponse, Exception)
- */
- public static ResponseBodyBean ofStatus(@NonNull final HttpStatus status) {
- ResponseBodyBean responseBodyBean = new ResponseBodyBean<>();
- responseBodyBean.setStatus(status.value());
- responseBodyBean.setMessage(status.getReasonPhrase());
- return responseBodyBean;
- }
-
- /**
- * Of status response body bean.
- *
- * @param the type parameter
- * @param status the status
- * @param message the message
- * @return the response body bean
- */
- public static ResponseBodyBean ofStatus(@NonNull final HttpStatus status, @NonNull final String message) {
- ResponseBodyBean responseBodyBean = new ResponseBodyBean<>();
- responseBodyBean.setStatus(status.value());
- responseBodyBean.setMessage(message);
- return responseBodyBean;
- }
-
- /**
- * Respond to client with IUniversalStatus and data.
- * ATTENTION:
- * This method CANNOT be used by controller or service or other class, only provided for Exception controller
- * .
- *
- * @param the response body data type
- * @param status IUniversalStatus
- * @param data data to be responded to client
- * @return response body for ExceptionControllerAdvice
- */
- public static ResponseBodyBean ofStatus(@NonNull final HttpStatus status, @Nullable final T data) {
- ResponseBodyBean responseBodyBean = new ResponseBodyBean<>();
- responseBodyBean.setStatus(status.value());
- responseBodyBean.setMessage(status.getReasonPhrase());
- responseBodyBean.setData(data);
- return responseBodyBean;
- }
-
- /**
- * Highly customizable response. Status might be any HttpStatus' code value.
- * ATTENTION:
- * This method CANNOT be used by controller or service or other class, only provided for Exception controller
- * .
- *
- * @param the response body data type
- * @param status status code
- * @param message message to be responded
- * @param data data to be responded
- * @return response body for ExceptionControllerAdvice
- */
- public static ResponseBodyBean ofStatus(final int status, @NonNull final String message,
- @Nullable final T data) {
- ResponseBodyBean responseBodyBean = new ResponseBodyBean<>();
- responseBodyBean.setStatus(status);
- responseBodyBean.setMessage(message);
- responseBodyBean.setData(data);
- return responseBodyBean;
- }
-
- /**
- * Highly customizable response. Status might be any HttpStatus' code value.
- * ATTENTION:
- * This method CANNOT be used in ExceptionControllerAdvice.
- *
- * @param the response body data type
- * @param status status code
- * @param message message to be responded
- * @param data data to be responded
- * @return response body
- */
- public static ResponseBodyBean setResponse(final int status, @NonNull final String message,
- @Nullable final T data)
- throws BaseException {
- if (!HttpStatus.valueOf(status).is2xxSuccessful()) {
- throw new BaseException(status, message, data);
- }
- ResponseBodyBean responseBodyBean = new ResponseBodyBean<>();
- responseBodyBean.setStatus(status);
- responseBodyBean.setMessage(message);
- responseBodyBean.setData(data);
- return responseBodyBean;
- }
-
- /**
- * Respond null data, and status is OK.
- *
- * @param the response body data type
- * @return response body
- */
- public static ResponseBodyBean