Commit 7e972199 authored by trumansdo's avatar trumansdo
Browse files

添加hibernate-validator逻辑,并对service层进行验证

parent e24b97ee
...@@ -5,9 +5,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; ...@@ -5,9 +5,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication @SpringBootApplication
@EnableCaching @EnableCaching
@EnableAspectJAutoProxy
public class ConsoleApplication extends SpringBootServletInitializer { public class ConsoleApplication extends SpringBootServletInitializer {
@Override @Override
......
package com.ibeetl.admin.console.web;
import javax.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
public class PageParams {
@NotNull Integer page = 1;
@NotNull Integer limit = 10;
}
package com.ibeetl.admin.console.web; package com.ibeetl.admin.console.web;
import com.ibeetl.admin.console.util.VOUtil; import com.ibeetl.admin.console.util.VOUtil;
import com.ibeetl.admin.core.entity.CoreRoute;
import com.ibeetl.admin.core.entity.CoreUser; import com.ibeetl.admin.core.entity.CoreUser;
import com.ibeetl.admin.core.service.CoreUserService; import com.ibeetl.admin.core.service.CoreUserService;
import com.ibeetl.admin.core.web.JsonResult; import com.ibeetl.admin.core.web.JsonResult;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.validation.constraints.NotNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@Validated
@RestController @RestController
public class UserElController { public class UserElController {
...@@ -22,7 +24,7 @@ public class UserElController { ...@@ -22,7 +24,7 @@ public class UserElController {
} }
@GetMapping("/users") @GetMapping("/users")
public JsonResult<List<CoreUser>> users(Integer page, Integer limit) { public JsonResult<List<CoreUser>> users(@NotNull Integer page, @NotNull Integer limit) {
List<CoreUser> allUsers = coreUserService.getAllUsers(page, limit); List<CoreUser> allUsers = coreUserService.getAllUsers(page, limit);
return JsonResult.success(allUsers); return JsonResult.success(allUsers);
} }
......
...@@ -20,9 +20,9 @@ spring.datasource.baseDataSource.driver-class-name=com.mysql.cj.jdbc.Driver ...@@ -20,9 +20,9 @@ spring.datasource.baseDataSource.driver-class-name=com.mysql.cj.jdbc.Driver
#html\u89C6\u56FE\u4EA4\u7ED9beetl\u6E32\u67D3 #html\u89C6\u56FE\u4EA4\u7ED9beetl\u6E32\u67D3
beetl.suffix=html beetl.suffix=html
beetlsql.ds.baseDataSource.basePackage=com beetlsql.ds.baseDataSource.basePackage=com.ibeetl.admin
beetlsql.ds.baseDataSource.daoSuffix=Dao
beetlsql.ds.baseDataSource.dbStyle=org.beetl.sql.core.db.MySqlStyle beetlsql.ds.baseDataSource.dbStyle=org.beetl.sql.core.db.MySqlStyle
#beetlsql.basePackage=com.ibeetl,com.xxx.yourpackage
#\u6709\u4E00\u4E2A\u6570\u636E\u6E90\u547D\u540D\u4E3AbaseDataSource,\u4F60\u53EF\u4EE5\u6DFB\u52A0\u591A\u6570\u636E\u6E90 #\u6709\u4E00\u4E2A\u6570\u636E\u6E90\u547D\u540D\u4E3AbaseDataSource,\u4F60\u53EF\u4EE5\u6DFB\u52A0\u591A\u6570\u636E\u6E90
beetlsql.mutiple.datasource=baseDataSource beetlsql.mutiple.datasource=baseDataSource
......
package com.ibeetl.admin.core.conf; package com.ibeetl.admin.core.conf;
import static cn.hutool.system.SystemUtil.LINE_SEPRATOR;
import static java.lang.String.format;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.dialect.Props;
import cn.hutool.system.SystemUtil;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.ibeetl.admin.core.util.FormFieldException; import com.ibeetl.admin.core.util.FormFieldException;
import com.ibeetl.admin.core.util.PlatformException; import com.ibeetl.admin.core.util.PlatformException;
...@@ -44,11 +50,11 @@ public class CustomErrorController extends AbstractErrorController { ...@@ -44,11 +50,11 @@ public class CustomErrorController extends AbstractErrorController {
@RequestMapping(ERROR_PATH) @RequestMapping(ERROR_PATH)
public ModelAndView getErrorPath(HttpServletRequest request, HttpServletResponse response) { public ModelAndView getErrorPath(HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, false)); Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, false));
Throwable cause = getCause(request); Throwable cause = getCause(request);
int status = (Integer) model.get("status"); int status = (Integer) model.get("status");
// 错误信息 // 错误信息
String message = (String) model.get("message"); // String message = (String) model.get("message");
// 友好提示 // 友好提示
String errorMessage = getErrorMessage(cause); String errorMessage = getErrorMessage(cause);
String requestPath = (String) model.get("path"); String requestPath = (String) model.get("path");
...@@ -56,8 +62,7 @@ public class CustomErrorController extends AbstractErrorController { ...@@ -56,8 +62,7 @@ public class CustomErrorController extends AbstractErrorController {
List<FieldError> filedErrors = this.getFieldError(model, cause); List<FieldError> filedErrors = this.getFieldError(model, cause);
// 后台打印日志信息方方便查错 // 后台打印日志信息方方便查错
logger.error("{} : {} {} {}", status, message, filedErrors, cause); prettyLog(model, cause, filedErrors);
logger.error("requestPath : {}", requestPath);
response.setStatus(status); response.setStatus(status);
if (!isJsonRequest(request)) { if (!isJsonRequest(request)) {
...@@ -78,11 +83,28 @@ public class CustomErrorController extends AbstractErrorController { ...@@ -78,11 +83,28 @@ public class CustomErrorController extends AbstractErrorController {
} else { } else {
writeJson(response, JsonResult.fail(this.wrapFieldErrors(filedErrors))); writeJson(response, JsonResult.fail(this.wrapFieldErrors(filedErrors)));
} }
return null; return null;
} }
} }
protected void prettyLog(Map model, Throwable cause, List<FieldError> filedErrors) {
Object path = model.get("path");
Object status = model.get("status");
Object message = model.get("message");
StringBuilder log = new StringBuilder();
log.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("┏━━━━ response status: <{}> ━━━━", status))
.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("┣━━━━ error message: <{}> ━━━━", message))
.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("┣━━━━ error fileds: <{}> ━━━━", filedErrors))
.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("┗━━━━ error cause: <{}> ━━━━", cause))
.append(SystemUtil.get(LINE_SEPRATOR))
.append(StrUtil.format("┗━━━━ request path <{}> error log.━━━━", path));
logger.error(log.toString());
}
protected List<FieldError> getFieldError(Map<String, Object> model, Throwable cause) { protected List<FieldError> getFieldError(Map<String, Object> model, Throwable cause) {
List<FieldError> filedErrors = (List<FieldError>) model.get("errors"); List<FieldError> filedErrors = (List<FieldError>) model.get("errors");
if (filedErrors != null) { if (filedErrors != null) {
...@@ -133,6 +155,7 @@ public class CustomErrorController extends AbstractErrorController { ...@@ -133,6 +155,7 @@ public class CustomErrorController extends AbstractErrorController {
} }
protected String getErrorMessage(Throwable ex) { protected String getErrorMessage(Throwable ex) {
if (ex instanceof PlatformException) { if (ex instanceof PlatformException) {
return ex.getMessage(); return ex.getMessage();
} else { } else {
...@@ -152,7 +175,6 @@ public class CustomErrorController extends AbstractErrorController { ...@@ -152,7 +175,6 @@ public class CustomErrorController extends AbstractErrorController {
@Override @Override
public String getErrorPath() { public String getErrorPath() {
// TODO Auto-generated method stub return ERROR_PATH;
return null;
} }
} }
...@@ -100,6 +100,9 @@ class CustomJsonResultSerializer extends JsonSerializer<JsonResult> { ...@@ -100,6 +100,9 @@ class CustomJsonResultSerializer extends JsonSerializer<JsonResult> {
CustomJsonResultSerializer() {} CustomJsonResultSerializer() {}
/**
* 处理 JsonResult 返回结果。自动分离分页信息,不需要手动在controller中分离
*/
@Override @Override
public void serialize(JsonResult value, JsonGenerator gen, SerializerProvider serializers) public void serialize(JsonResult value, JsonGenerator gen, SerializerProvider serializers)
throws IOException { throws IOException {
......
package com.ibeetl.admin.core.conf;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
public class SpringConfiguration {
/**
* 配置验证器
*
* @return validator
*/
@Bean
public Validator validator() {
ValidatorFactory validatorFactory =
Validation.byProvider(HibernateValidator.class)
.configure()
// 快速失败模式
.failFast(true)
// .addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
/**
* 设置SpringMVC Controller方法参数验证器。 必须在controller类上使用 {@link
* org.springframework.validation.annotation.Validated} 注解
*/
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor(
@Autowired Validator validator) {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
postProcessor.setValidator(validator);
return postProcessor;
}
}
package com.ibeetl.admin.core.conf; package com.ibeetl.admin.core.conf;
import static com.ibeetl.admin.core.util.HttpRequestLocal.ACCESS_CURRENT_USER;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
...@@ -13,9 +10,6 @@ import cn.hutool.json.JSONArray; ...@@ -13,9 +10,6 @@ import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.ibeetl.admin.core.annotation.RequestBodyPlus; import com.ibeetl.admin.core.annotation.RequestBodyPlus;
import com.ibeetl.admin.core.entity.CoreOrg;
import com.ibeetl.admin.core.entity.CoreUser;
import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.service.CoreUserService; import com.ibeetl.admin.core.service.CoreUserService;
import com.ibeetl.admin.core.util.HttpRequestLocal; import com.ibeetl.admin.core.util.HttpRequestLocal;
import com.ibeetl.admin.core.util.JoseJwtUtil; import com.ibeetl.admin.core.util.JoseJwtUtil;
...@@ -26,7 +20,6 @@ import java.util.List; ...@@ -26,7 +20,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.beetl.core.GroupTemplate; import org.beetl.core.GroupTemplate;
import org.beetl.ext.spring.BeetlGroupUtilConfiguration; import org.beetl.ext.spring.BeetlGroupUtilConfiguration;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
...@@ -41,6 +34,7 @@ import org.springframework.http.MediaType; ...@@ -41,6 +34,7 @@ import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.NativeWebRequest;
...@@ -55,7 +49,7 @@ import org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConv ...@@ -55,7 +49,7 @@ import org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConv
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
@Configuration @Configuration
public class MVCConf implements WebMvcConfigurer, InitializingBean { public class SpringWebMvcConfigurer implements WebMvcConfigurer, InitializingBean {
public static final String DEFAULT_APP_NAME = "开发平台"; public static final String DEFAULT_APP_NAME = "开发平台";
...@@ -75,19 +69,32 @@ public class MVCConf implements WebMvcConfigurer, InitializingBean { ...@@ -75,19 +69,32 @@ public class MVCConf implements WebMvcConfigurer, InitializingBean {
@Autowired private RequestMappingHandlerAdapter adapter; @Autowired private RequestMappingHandlerAdapter adapter;
/**
* 添加拦截器
*
* @param registry 拦截器的注册器
*/
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
registry registry.addInterceptor(new SessionInterceptor(userService)).addPathPatterns("/**");
.addInterceptor(new SessionInterceptor(userService))
.addPathPatterns("/**");
// super.addInterceptors(registry); // super.addInterceptors(registry);
} }
/**
* 增加跨域映射
*
* @param registry 跨域映射注册器
*/
@Override @Override
public void addCorsMappings(CorsRegistry registry) { public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**"); registry.addMapping("/**");
} }
/**
* SpringMVC的请求响应消息的转换格式器
*
* @param registry
*/
@Override @Override
public void addFormatters(FormatterRegistry registry) { public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss")); registry.addFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
...@@ -123,10 +130,10 @@ class SessionInterceptor implements HandlerInterceptor { ...@@ -123,10 +130,10 @@ class SessionInterceptor implements HandlerInterceptor {
@Override @Override
public boolean preHandle( public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) { HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpRequestLocal.set(request); HttpRequestLocal.set(request);
if (StrUtil.containsAny(request.getRequestURI(), "/login", "/error", "/logout")) { if (StrUtil.containsAny(request.getRequestURI(), "/login", "/error", "/logout")) {
return true; return true;
} }
String token = HttpRequestLocal.getAuthorization(); String token = HttpRequestLocal.getAuthorization();
Map<String, Object> payload = JoseJwtUtil.parsePayload(token); Map<String, Object> payload = JoseJwtUtil.parsePayload(token);
......
package com.ibeetl.admin.core.conf.aop;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ibeetl.admin.core.util.ValidateUtils;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
@Aspect
@Component
public class ServiceValidationAop {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("@target(org.springframework.stereotype.Service)")
public void service() {}
@Pointcut("@annotation(org.springframework.validation.annotation.Validated)")
public void validated() {}
@Pointcut("@annotation(javax.validation.Valid)")
public void valid() {}
@Around("service() && (valid() || validated())")
public Object doValidation(ProceedingJoinPoint point) throws Throwable {
Object returnValue;
/*被代理对象、目标对象*/
Object target = point.getTarget();
/*代理对象*/
/*Object pointThis = point.getThis();*/
/*获取代理方法签名*/
Signature signature = point.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
/*通过方法签名获取到的method是代理对象中的,不具有目标method的方法信息*/
Method targetMethod = methodSignature.getMethod();
/*只能通过反射获取原目标方法的方法信息*/
Method realMethod =
target.getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes());
Object[] args = point.getArgs();
/*获取验证组*/
Class[] groups;
groups =
Optional.ofNullable(realMethod.getAnnotation(Validated.class))
.map(Validated::value)
.orElse(new Class[0]);
/*使用hibernate-validator验证*/
Set<ConstraintViolation<Object>> constraintViolations =
ValidateUtils.validateMethod(target, realMethod, args, groups);
if (CollUtil.isEmpty(constraintViolations)) {
returnValue = point.proceed(args);
} else {
/*向上抛出验证失败的异常,交由统一异常管理处理*/
throw new ConstraintViolationException(
StrUtil.format("Service [{}] method parameter unvalidate", signature.getName()),
constraintViolations);
}
return returnValue;
}
}
package com.ibeetl.admin.core.dao;
import org.beetl.sql.core.mapper.BaseMapper;
/**
* 只是作为专门获取数据源的SQLmanager的接口,避免多数据源中,每次使用名称指定注入SQLmanager。
* 泛型不可少
* */
public interface SQLManagerBaseDao extends BaseMapper<Object> {}
package com.ibeetl.admin.core.service; package com.ibeetl.admin.core.service;
import com.ibeetl.admin.core.dao.SQLManagerBaseDao;
import java.util.List; import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.beetl.sql.core.SQLManager; import org.beetl.sql.core.SQLManager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -27,7 +30,7 @@ public class CoreUserService { ...@@ -27,7 +30,7 @@ public class CoreUserService {
@Autowired PasswordEncryptService passwordEncryptService; @Autowired PasswordEncryptService passwordEncryptService;
@Autowired SQLManager sqlManager; @Autowired SQLManagerBaseDao sqlManagerBaseDao;
public UserLoginInfo login(String userName, String password) { public UserLoginInfo login(String userName, String password) {
CoreUser query = new CoreUser(); CoreUser query = new CoreUser();
...@@ -72,8 +75,9 @@ public class CoreUserService { ...@@ -72,8 +75,9 @@ public class CoreUserService {
return userDao.getUserByRole(role); return userDao.getUserByRole(role);
} }
public List<CoreUser> getAllUsers(Integer page, Integer limit) { @Valid
return sqlManager.lambdaQuery(CoreUser.class).page(page, limit).getList(); public List<CoreUser> getAllUsers(@NotNull Integer page, @NotNull Integer limit) {
return sqlManagerBaseDao.getSQLManager().lambdaQuery(CoreUser.class).page(page, limit).getList();
} }
public CoreUser getUserByCode(String userName) { public CoreUser getUserByCode(String userName) {
......
package com.ibeetl.admin.core.util; package com.ibeetl.admin.core.util;
import javax.servlet.http.HttpSession; import com.ibeetl.admin.core.conf.SpringWebMvcConfigurer;
/** /**
* 用户Controller对应的功能 {@link com.ibeetl.admin.core.conf.MVCConf} * 用户Controller对应的功能 {@link SpringWebMvcConfigurer}
* *
* @author lijiazhi * @author lijiazhi
*/ */
......
...@@ -9,9 +9,7 @@ import java.net.InetAddress; ...@@ -9,9 +9,7 @@ import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -19,10 +17,10 @@ import javax.servlet.http.HttpSession; ...@@ -19,10 +17,10 @@ import javax.servlet.http.HttpSession;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ibeetl.admin.core.conf.MVCConf; import com.ibeetl.admin.core.conf.SpringWebMvcConfigurer;
/** /**
* 保留用户会话,以方便在业务代码任何地方调用 {@link MVCConf} * 保留用户会话,以方便在业务代码任何地方调用 {@link SpringWebMvcConfigurer}
* *
* @author lijiazhi * @author lijiazhi
*/ */
......
package com.ibeetl.admin.core.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.executable.ExecutableValidator;
import org.hibernate.validator.HibernateValidator;
public class ValidateUtils {
private static final Validator VALIDATOR =
Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(true)
.buildValidatorFactory()
.getValidator();
/**
* 验证bean
*
* @param <T> 被验证bean的类型
* @param bean 被验证的bean
* @param groups 验证组
* @return
*/
public static <T> Set<ConstraintViolation<T>> validateBean(T bean, Class<?>... groups) {
Assert.notNull(groups, "groups can't null. Instead of empty groups" );
Set<ConstraintViolation<T>> constraintViolations = VALIDATOR.validate(bean, groups);
return constraintViolations;
}
/**
* 验证方法入参
*
* @param <T> 所属对象的类型
* @param object 方法所属对象
* @param method 方法
* @param parameterValues 方法入参值
* @param groups 校验组
* @return
*/
public static <T> Set<ConstraintViolation<T>> validateMethod(
T object, Method method, Object[] parameterValues, Class<?>... groups) {
Assert.notNull(groups, "groups can't null. Instead of empty groups" );
ExecutableValidator executableValidator = VALIDATOR.forExecutables();
Set<ConstraintViolation<T>> constraintViolations =
executableValidator.validateParameters(object, method, parameterValues, groups);
return constraintViolations;
}
public static <T> List wrapConstraintViolations(
Set<ConstraintViolation<T>> constraintViolations) {
List errorMsgs = CollUtil.newArrayList();
constraintViolations.stream()
.forEach(
violation -> {
errorMsgs.add(violation.getMessage());
});
return errorMsgs;
}
}
...@@ -11,8 +11,19 @@ import java.util.Map; ...@@ -11,8 +11,19 @@ import java.util.Map;
*/ */
public class JsonResult<T> { public class JsonResult<T> {
/**
* 建议标准http响应码
* */
private String code; private String code;
/**
* 自定义信息
* */
private String message; private String message;
/**
* 携带数据
* */
private T data; private T data;
public String getCode() { public String getCode() {
......
/*
* @Author: 一日看尽长安花
* @since: 2019-09-04 20:55:14
* @LastEditTime: 2019-10-29 23:17:53
* @LastEditors: 一日看尽长安花
* @Description:
*/
module.exports = { module.exports = {
root: true, root: true,
env: { env: {
browser: true, browser: true,
node: true, node: true,
es6: true, es6: true
}, },
parserOptions: { parserOptions: {
parser: 'babel-eslint', parser: 'babel-eslint'
}, },
overrides: [ overrides: [
{ {
files: ['**/__tests__/*.{j,t}s?(x)'], files: ['**/__tests__/*.{j,t}s?(x)'],
env: { env: {
jest: true, jest: true
}, }
}, }
], ],
extends: [ extends: [
'plugin:vue/recommended', 'plugin:vue/recommended',
'plugin:prettier/recommended', 'plugin:prettier/recommended',
'@vue/prettier', '@vue/prettier'
], ],
plugins: ['vue'], plugins: ['vue'],
...@@ -42,21 +49,22 @@ module.exports = { ...@@ -42,21 +49,22 @@ module.exports = {
trailingComma: 'none', trailingComma: 'none',
bracketSpacing: true, bracketSpacing: true,
jsxBracketSameLine: false, jsxBracketSameLine: false,
arrowParens: 'avoid', arrowParens: 'avoid'
}, }
], ],
'no-console': 'off', 'no-console': 'off',
'no-debugger': 'off', 'no-debugger': 'off',
'no-unused-vars': 'off', 'no-unused-vars': 'off',
'vue/no-unused-vars': 'off', 'vue/no-unused-vars': 'off',
'no-useless-escape': 'off', 'no-useless-escape': 'off',
'vue/require-component-is': 'off',
quotes: [ quotes: [
2, 2,
'single', 'single',
{ {
avoidEscape: true, avoidEscape: true,
allowTemplateLiterals: true, allowTemplateLiterals: true
}, }
], ],
'jsx-quotes': [2, 'prefer-single'], 'jsx-quotes': [2, 'prefer-single'],
// 缩进为2个空格 // 缩进为2个空格
...@@ -66,8 +74,8 @@ module.exports = { ...@@ -66,8 +74,8 @@ module.exports = {
{ {
attribute: 1, attribute: 1,
alignAttributesVertically: true, alignAttributesVertically: true,
ignores: [], ignores: []
}, }
], ],
'vue/max-attributes-per-line': [ 'vue/max-attributes-per-line': [
2, 2,
...@@ -75,9 +83,9 @@ module.exports = { ...@@ -75,9 +83,9 @@ module.exports = {
singleline: 10, singleline: 10,
multiline: { multiline: {
max: 1, max: 1,
allowFirstLine: false, allowFirstLine: false
}, }
}, }
], ],
'vue/html-self-closing': 'off', 'vue/html-self-closing': 'off',
'vue/name-property-casing': ['error', 'PascalCase'], 'vue/name-property-casing': ['error', 'PascalCase'],
...@@ -99,6 +107,6 @@ module.exports = { ...@@ -99,6 +107,6 @@ module.exports = {
'no-multiple-empty-lines': 'off', 'no-multiple-empty-lines': 'off',
// 关闭模板字符串检测 // 关闭模板字符串检测
'no-template-curly-in-string': 'off', 'no-template-curly-in-string': 'off',
'no-console': 'off', 'no-console': 'off'
}, }
} };
<!--
* @Author: 一日看尽长安花
* @since: 2019-09-04 20:55:14
* @LastEditTime: 2019-10-30 19:53:28
* @LastEditors: 一日看尽长安花
* @Description:
-->
<template> <template>
<!-- eslint-disable vue/require-component-is --> <!-- eslint-disable vue/require-component-is -->
<component :is="linkProps(to)"> <!-- 该is特性不要使用官网的v-bind:is -->
<component v-bind="linkProps(to)">
<slot /> <slot />
</component> </component>
</template> </template>
...@@ -12,8 +20,8 @@ export default { ...@@ -12,8 +20,8 @@ export default {
props: { props: {
to: { to: {
type: String, type: String,
required: true, required: true
}, }
}, },
methods: { methods: {
linkProps(url) { linkProps(url) {
...@@ -22,14 +30,14 @@ export default { ...@@ -22,14 +30,14 @@ export default {
is: 'a', is: 'a',
href: url, href: url,
target: '_blank', target: '_blank',
rel: 'noopener', rel: 'noopener'
}; };
} }
return { return {
is: 'router-link', is: 'router-link',
to: url, to: url
}; };
}, }
}, }
}; };
</script> </script>
<!--
* @Author: 一日看尽长安花
* @since: 2019-09-04 20:55:14
* @LastEditTime: 2019-10-29 22:02:14
* @LastEditors: 一日看尽长安花
* @Description:
-->
<template> <template>
<div v-if="!item.hidden" class="menu-wrapper"> <div v-if="!item.hidden" class="menu-wrapper">
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> <template
v-if="
hasOneShowingChild(item.children, item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
!item.alwaysShow
"
>
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> <el-menu-item
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> :index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
>
<item
:icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)"
:title="onlyOneChild.meta.title"
/>
</el-menu-item> </el-menu-item>
</app-link> </app-link>
</template> </template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> <el-submenu
v-else
ref="subMenu"
:index="resolvePath(item.path)"
popper-append-to-body
>
<template slot="title"> <template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> <item
v-if="item.meta"
:icon="item.meta && item.meta.icon"
:title="item.meta.title"
/>
</template> </template>
<sidebar-item <sidebar-item
v-for="child in item.children" v-for="child in item.children"
...@@ -25,11 +53,11 @@ ...@@ -25,11 +53,11 @@
</template> </template>
<script> <script>
import path from 'path' import path from 'path';
import { isExternal } from '@/utils/validate' import { isExternal } from '@/utils/validate';
import Item from './Item' import Item from './Item';
import AppLink from './Link' import AppLink from './Link';
import FixiOSBug from './FixiOSBug' import FixiOSBug from './FixiOSBug';
export default { export default {
name: 'SidebarItem', name: 'SidebarItem',
...@@ -53,43 +81,43 @@ export default { ...@@ -53,43 +81,43 @@ export default {
data() { data() {
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
// TODO: refactor with render function // TODO: refactor with render function
this.onlyOneChild = null this.onlyOneChild = null;
return {} return {};
}, },
methods: { methods: {
hasOneShowingChild(children = [], parent) { hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => { const showingChildren = children.filter(item => {
if (item.hidden) { if (item.hidden) {
return false return false;
} else { } else {
// Temp set(will be used if only has one showing child) // Temp set(will be used if only has one showing child)
this.onlyOneChild = item this.onlyOneChild = item;
return true return true;
} }
}) });
// When there is only one child router, the child router is displayed by default // When there is only one child router, the child router is displayed by default
if (showingChildren.length === 1) { if (showingChildren.length === 1) {
return true return true;
} }
// Show parent if there are no child router to display // Show parent if there are no child router to display
if (showingChildren.length === 0) { if (showingChildren.length === 0) {
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true } this.onlyOneChild = { ...parent, path: '', noShowingChildren: true };
return true return true;
} }
return false return false;
}, },
resolvePath(routePath) { resolvePath(routePath) {
if (isExternal(routePath)) { if (isExternal(routePath)) {
return routePath return routePath;
} }
if (isExternal(this.basePath)) { if (isExternal(this.basePath)) {
return this.basePath return this.basePath;
} }
return path.resolve(this.basePath, routePath) return path.resolve(this.basePath, routePath);
} }
} }
} };
</script> </script>
<!--
* @Author: 一日看尽长安花
* @since: 2019-09-04 20:55:14
* @LastEditTime: 2019-10-29 21:41:31
* @LastEditors: 一日看尽长安花
* @Description:
-->
<template> <template>
<div :class="{'has-logo':showLogo}"> <div :class="{ 'has-logo': showLogo }">
<logo v-if="showLogo" :collapse="isCollapse" /> <logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper"> <el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu <el-menu
...@@ -12,43 +19,45 @@ ...@@ -12,43 +19,45 @@
:collapse-transition="false" :collapse-transition="false"
mode="vertical" mode="vertical"
> >
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" /> <sidebar-item
v-for="route in permission_routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu> </el-menu>
</el-scrollbar> </el-scrollbar>
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex';
import Logo from './Logo' import Logo from './Logo';
import SidebarItem from './SidebarItem' import SidebarItem from './SidebarItem';
import variables from '@/styles/variables.scss' import variables from '@/styles/variables.scss';
export default { export default {
components: { SidebarItem, Logo }, components: { SidebarItem, Logo },
computed: { computed: {
...mapGetters([ ...mapGetters(['permission_routes', 'sidebar']),
'permission_routes',
'sidebar'
]),
activeMenu() { activeMenu() {
const route = this.$route const route = this.$route;
const { meta, path } = route const { meta, path } = route;
// if set path, the sidebar will highlight the path you set // if set path, the sidebar will highlight the path you set
if (meta.activeMenu) { if (meta.activeMenu) {
return meta.activeMenu return meta.activeMenu;
} }
return path return path;
}, },
showLogo() { showLogo() {
return this.$store.state.settings.sidebarLogo return this.$store.state.settings.sidebarLogo;
}, },
variables() { variables() {
return variables return variables;
}, },
isCollapse() { isCollapse() {
return !this.sidebar.opened return !this.sidebar.opened;
} }
} }
} };
</script> </script>
/* /*
* @Author: 一日看尽长安花 * @Author: 一日看尽长安花
* @since: 2019-09-04 20:55:14 * @since: 2019-09-04 20:55:14
* @LastEditTime: 2019-10-27 00:28:33 * @LastEditTime: 2019-10-29 21:52:51
* @LastEditors: 一日看尽长安花 * @LastEditors: 一日看尽长安花
* @Description: * @Description:
*/ */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment