Skip to content

Commit

Permalink
feat($Validation): support enum value validation
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnymillergh committed Jun 6, 2021
1 parent 5086351 commit 0951f97
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jmsoftware.maf.authcenter.user.controller;

import com.jmsoftware.maf.authcenter.user.entity.GetUserStatusPayload;
import com.jmsoftware.maf.authcenter.user.service.UserService;
import com.jmsoftware.maf.common.bean.ResponseBodyBean;
import com.jmsoftware.maf.common.domain.authcenter.user.LoginPayload;
Expand All @@ -11,6 +12,7 @@
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -50,4 +52,9 @@ public ResponseBodyBean<LoginResponse> login(@Valid @RequestBody LoginPayload pa
public ResponseBodyBean<Boolean> logout(HttpServletRequest request) throws SecurityException {
return ResponseBodyBean.ofSuccess(userService.logout(request));
}

@GetMapping("/users/status")
public ResponseBodyBean<String> getUserStatus(@Valid GetUserStatusPayload payload) {
return ResponseBodyBean.ofSuccess(userService.getUserStatus(payload), "Correct enum value");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.jmsoftware.maf.authcenter.user.entity;

import com.jmsoftware.maf.common.domain.authcenter.user.UserStatus;
import com.jmsoftware.maf.springcloudstarter.annotation.ValidEnumValue;
import lombok.Data;

/**
* <h1>GetUserStatusPayload</h1>
* <p>
* 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;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.jmsoftware.maf.authcenter.user.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.jmsoftware.maf.authcenter.user.entity.GetUserStatusPayload;
import com.jmsoftware.maf.authcenter.user.entity.UserPersistence;
import com.jmsoftware.maf.common.domain.authcenter.user.*;
import com.jmsoftware.maf.common.exception.SecurityException;
Expand All @@ -9,6 +10,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
* <h1>UserService</h1>
Expand Down Expand Up @@ -53,4 +55,12 @@ public interface UserService extends IService<UserPersistence> {
* @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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jmsoftware.maf.authcenter.security.service.JwtService;
import com.jmsoftware.maf.authcenter.user.entity.GetUserStatusPayload;
import com.jmsoftware.maf.authcenter.user.entity.UserPersistence;
import com.jmsoftware.maf.authcenter.user.mapper.UserMapper;
import com.jmsoftware.maf.authcenter.user.service.UserService;
Expand All @@ -15,7 +16,6 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
Expand All @@ -25,6 +25,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
* <h1>UserServiceImpl</h1>
Expand All @@ -44,7 +45,6 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, UserPersistence> im
private final MessageSource messageSource;

@Override
@Cacheable
public GetUserByLoginTokenResponse getUserByLoginToken(@NotBlank String loginToken) {
LambdaQueryWrapper<UserPersistence> wrapper = Wrappers.lambdaQuery();
wrapper.and(queryWrapper -> queryWrapper.eq(UserPersistence::getUsername, loginToken)
Expand All @@ -67,7 +67,7 @@ public SignupResponse saveUserForSignup(@Valid SignupPayload payload) {
userPersistence.setUsername(payload.getUsername());
userPersistence.setEmail(payload.getEmail());
userPersistence.setPassword(bCryptPasswordEncoder.encode(payload.getPassword()));
userPersistence.setStatus(UserStatus.ENABLED.getStatus());
userPersistence.setStatus(UserStatus.ENABLED.getValue());
this.save(userPersistence);
log.warn("Saved user for signup. {}", userPersistence);
val response = new SignupResponse();
Expand Down Expand Up @@ -98,4 +98,9 @@ public boolean logout(HttpServletRequest request) throws SecurityException {
jwtService.invalidateJwt(request);
return true;
}

@Override
public String getUserStatus(@Valid @NotNull GetUserStatusPayload payload) {
return UserStatus.ofValue(payload.getStatus()).getDescription();
}
}
6 changes: 3 additions & 3 deletions auto-run-mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ set -e
readonly mavenActiveProfile="development-local"
readonly javaParameter="-Xms256m -Xmx256m -Dfile.encoding=UTF-8 -Dspring.cloud.consul.host=localhost -Dspring.profiles.active=$mavenActiveProfile"
readonly runServices=(
spring-boot-admin
# api-portal
auth-center
api-gateway
)
readonly skipGitPull=false
readonly skipGitPull=true
readonly skipBuild=false
# Available options for `startMode`: "keep-previous", "overlap"
readonly startMode="overlap"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,6 @@ public boolean isCredentialsNonExpired() {

@Override
public boolean isEnabled() {
return Objects.equals(this.status, UserStatus.ENABLED.getStatus());
return Objects.equals(this.status, UserStatus.ENABLED.getValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ public enum UserStatus {
*/
DISABLED((byte) 0, "Disabled user");

private final Byte status;
private final Byte value;
private final String description;

UserStatus(Byte status, String description) {
this.status = status;
UserStatus(Byte value, String description) {
this.value = value;
this.description = description;
}

/**
* Get user status enum by status value
* Get user value enum by value value
*
* @param status status value
* @return user status enum
* @param value value value
* @return user value enum
*/
public static UserStatus getByStatus(Byte status) {
public static UserStatus ofValue(Byte value) {
UserStatus result = UserStatus.DISABLED;
UserStatus[] userStatuses = UserStatus.values();
for (UserStatus userStatus : userStatuses) {
if (userStatus.status.equals(status)) {
if (userStatus.value.equals(value)) {
result = userStatus;
}
}
Expand Down
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@
<spring-boot-admin-starter-client.version>2.4.0</spring-boot-admin-starter-client.version>
<druid-spring-boot-starter.version>1.2.5</druid-spring-boot-starter.version>
<mybatis-plus-boot-starter.version>3.4.2</mybatis-plus-boot-starter.version>
<hutool-all.version>5.6.1</hutool-all.version>
<hutool-all.version>5.6.4</hutool-all.version>
<guava.version>30.0-jre</guava.version>
<knife4j.version>3.0.2</knife4j.version>
<jjwt.version>0.11.2</jjwt.version>
<java-faker.version>1.0.2</java-faker.version>
<easyexcel.version>2.2.6</easyexcel.version>
<poi.version>5.0.0</poi.version>
<logstash-logback-encoder.version>6.6</logstash-logback-encoder.version>
<minio.version>8.2.1</minio.version>
</properties>

<!-- The modules (sometimes called subprojects) to build as a part of this project. -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.jmsoftware.maf.springcloudstarter.annotation;

import com.jmsoftware.maf.springcloudstarter.validation.EnumValueValidator;

import javax.validation.Constraint;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* <h1>ValidEnumValue</h1>
* <p>
* Change description here.
*
* @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
* @date 5/29/21 12:31 PM
**/
@Documented
@Retention(RUNTIME)
@Target({FIELD, PARAMETER})
@Constraint(validatedBy = EnumValueValidator.class)
public @interface ValidEnumValue {
String message() default "Invalid enumeration value";

Class<?> targetEnum() default Class.class;

boolean ignoreNull() default false;

Class[] groups() default {};

Class[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.jmsoftware.maf.springcloudstarter.validation;

import cn.hutool.core.util.ObjectUtil;
import com.jmsoftware.maf.springcloudstarter.annotation.ValidEnumValue;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
* <h1>EnumValueValidator</h1>
* <p>
* Change description here.
*
* @author Johnny Miller (鍾俊), email: johnnysviva@outlook.com
* @date 5/29/21 12:34 PM
**/
@Slf4j
public class EnumValueValidator implements ConstraintValidator<ValidEnumValue, Number> {
private final static String METHOD_NAME = "getValue";
private ValidEnumValue validEnumValue;

/**
* {@inheritDoc}
*/
@Override
public void initialize(ValidEnumValue constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
validEnumValue = constraintAnnotation;
}

/**
* {@inheritDoc}
*/
@Override
public boolean isValid(Number value, ConstraintValidatorContext context) {
val enumClass = validEnumValue.targetEnum();
val ignoreNull = validEnumValue.ignoreNull();
if (!enumClass.isEnum()) {
log.warn("The given target enum class is not enum! {}", enumClass.getName());
return false;
}
if (ignoreNull && ObjectUtil.isNull(value)) {
return true;
}
val enumConstantArray = enumClass.getEnumConstants();
Method method;
try {
method = enumClass.getMethod(METHOD_NAME);
} catch (NoSuchMethodException | SecurityException e) {
log.warn("Did not find the method {} in the class {}", METHOD_NAME, enumClass.getName());
return false;
}
var validResult = false;
try {
for (var obj : enumConstantArray) {
Object valueDeclaredInEnum = method.invoke(obj);
if (!(valueDeclaredInEnum instanceof Number)) {
log.error("The value declared in enum is not an instance of Number!");
throw new IllegalArgumentException("The value declared in enum is not an instance of Number!");
}
if (Objects.deepEquals(value, valueDeclaredInEnum)) {
validResult = true;
break;
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
log.error("Exception occurred when invoking method! Exception message: {}", e.getMessage());
return false;
}
return validResult;
}
}

0 comments on commit 0951f97

Please sign in to comment.