当前位置: 首页 > news >正文

南阳市城乡和住房建设局网站店铺推广渠道

南阳市城乡和住房建设局网站,店铺推广渠道,苏州网站建设专家,龙岩网站设计价格分组校验 场景描述 在实际开发中经常会遇到这种情况#xff1a;添加用户时#xff0c;id是由后端生成的#xff0c;不需要校验id是否为空#xff0c;但是修改用户时就需要校验id是否为空。如果在接收参数的User实体类的id属性上添加NotNull#xff0c;显然无法实现。这时…分组校验 场景描述 在实际开发中经常会遇到这种情况添加用户时id是由后端生成的不需要校验id是否为空但是修改用户时就需要校验id是否为空。如果在接收参数的User实体类的id属性上添加NotNull显然无法实现。这时候就可以定义分组在需要校验id的时候校验不需要的时候不校验。 定义分组 校验的分组通过接口的形式定义。 代码准备 /*** author lihz* date 2023/2/18*/ RestController RequestMapping(/group/validation/) public class GroupValidationController {PostMapping(/insert)public String testInsert(RequestBody Validated({UserValidGroup.Insert.class}) UserInfo userInfo) {System.out.println(userInfo);return OK;}PostMapping(/update)public String testUpdate(RequestBody Validated({UserValidGroup.Update.class}) UserInfo userInfo) {System.out.println(userInfo);return OK;}PostMapping(/delete)public String testDelete(RequestBody Validated({UserValidGroup.Delete.class}) UserInfo userInfo) {System.out.println(userInfo);return OK;} }Data class UserInfo {Min(value 1, message ID不能小于1, groups {UserValidGroup.Delete.class, UserValidGroup.Update.class})private int id;NotBlank(message 用户名不能为空, groups {UserValidGroup.Update.class, UserValidGroup.Insert.class})private String username;NotBlank(message 密码不能为空, groups {UserValidGroup.Update.class, UserValidGroup.Insert.class})Length(min 8, max 20, message 密码长度在8-20之间, groups {UserValidGroup.Update.class, UserValidGroup.Insert.class})private String password; }class UserValidGroup {public interface Insert {}public interface Update {}public interface Delete {}GroupSequence({Insert.class, Update.class, Delete.class})public interface All {} }数据准备 insert测试 {id: null,username: demon,password: 123456 }输出 {code: 1,msg: Validation failed for argument [0] in public java.lang.String com.jurassic.cloud.project.controller.GroupValidationController.testInsert(com.jurassic.cloud.project.controller.UserInfo): [Field error in object userInfo on field password: rejected value [12345]; codes [Length.userInfo.password,Length.password,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.password,password]; arguments []; default message [password],20,8]; default message [密码长度在8-20之间]] ,data: null }注意没有校验 id 属性。 update测试 {id: null,username: demon,password: 123456 }输出 {code: 1,msg: Validation failed for argument [0] in public java.lang.String com.jurassic.cloud.project.controller.GroupValidationController.testUpdate(com.jurassic.cloud.project.controller.UserInfo) with 2 errors: [Field error in object userInfo on field id: rejected value [0]; codes [Min.userInfo.id,Min.id,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.id,id]; arguments []; default message [id],1]; default message [ID不能小于1]] [Field error in object userInfo on field password: rejected value [123456]; codes [Length.userInfo.password,Length.password,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.password,password]; arguments []; default message [password],20,8]; default message [密码长度在8-20之间]] ,data: null }注意校验了 id 属性。 delete测试 {id: null,username: demon,password: 123456 }输出 {code: 1,msg: Validation failed for argument [0] in public java.lang.String com.jurassic.cloud.project.controller.GroupValidationController.testDelete(com.jurassic.cloud.project.controller.UserInfo): [Field error in object userInfo on field id: rejected value [0]; codes [Min.userInfo.id,Min.id,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.id,id]; arguments []; default message [id],1]; default message [ID不能小于1]] ,data: null }注意仅验证 id 属性。 总结 如果未指定分组则是Default组不属于Default组的属性不会验证。 指定了分组则仅验证指定的分组涉及的约束。 分组的高级特性 见其他JSR 380文档。 i18n 在进行约束声明时会指定message属性用于设置约束校验失败之后的提示如果需要支持多语言则不能得到期望的结果。 不指定message属性 如果不指定message则会采用框架的默认值会提供主流的语言 框架解析message默认值的相关逻辑在 org.hibernate.validator.internal.engine.ValidationContext 中 private String interpolate(String messageTemplate,Object validatedValue,ConstraintDescriptor? descriptor,MapString, Object messageParameters,MapString, Object expressionVariables) {MessageInterpolatorContext context new MessageInterpolatorContext(descriptor,validatedValue,getRootBeanClass(),messageParameters,expressionVariables);try {//使用 MessageInterpolator 解析return validatorScopedContext.getMessageInterpolator().interpolate(messageTemplate,context); }catch (ValidationException ve) {throw ve;}catch (Exception e) {throw LOG.getExceptionOccurredDuringMessageInterpolationException( e );}}在约束定义时会设置message的默认值是个消息插值。例如NotNull{javax.validation.constraints.NotNull.message}定义了消息参数在Resource Bundle ValidationMessages中作为Key获取 获取属性值。 Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) Retention(RUNTIME) Repeatable(List.class) Documented Constraint(validatedBy { }) public interface NotNull {String message() default {javax.validation.constraints.NotNull.message};Class?[] groups() default { };Class? extends Payload[] payload() default { };Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })Retention(RUNTIME)Documentedinterface List {NotNull[] value();} }ValidationMessages.properties javax.validation.constraints.NotBlank.message must not be blank javax.validation.constraints.NotEmpty.message must not be empty javax.validation.constraints.NotNull.message must not be null javax.validation.constraints.Null.message must be nullAbstractMessageInterpolator 消息解析主要是通过MessageInterpolator的实现类默认都继承AbstractMessageInterpolator。 此类默认会根据JVM的Locale来获取对应的i18n消息源码中的 defaultLocale Locale.getDefault() 不能根据request传递来的Locale来显示对应的消息。 缺陷 只能显示JVM的locale对应的消息。 自定义MessageInterpolator 自定义一个 MessageInterpolator 实现并改写其第一个interpolate方法可以根据request传递的locale进行动态显示。 Configuration public class I18nConstrainValidator {Beanpublic Validator validator() {return Validation.byDefaultProvider().configure().messageInterpolator(new ParameterMessageInterpolator() {Overridepublic String interpolate(String message, Context context) {return interpolate(message, context, Locale.getDefault());}Overridepublic String interpolate(String message, Context context, Locale locale) {// 获取当前请求所指定的语言对应的LocaleLocale requestLocale I18nUtil.getLocaleFromCurrentRequest();if (null requestLocale) {requestLocale locale;}return super.interpolate(message, context, requestLocale);}}).buildValidatorFactory().getValidator();}}缺陷 当request指定了一种框架中不存在的语种时无法得到准确的对应语种的消息而是得到JVM Locale对应的消息。 语种不存在时会获取Locale.getDefault()对应的Locale ResourceBundleMessageInterpolator Slf4j Configuration public class ConstrainValidatorConfig {Value(${spring.messages.basename})private String[] baseNames;Beanpublic Validator validator() {return Validation.byDefaultProvider().configure().messageInterpolator(new RequesLocaleAwareMessageInterpolator(// 提供AggregateResourceBundleLocator使得除了用框架提供的Validation ConstrainViolation// Message外还可以用自己指定的或覆盖框架提供的。new AggregateResourceBundleLocator(Arrays.asList(baseNames)))).buildValidatorFactory().getValidator();}/*** 自定义ResourceBundleMessageInterpolator的若干方法使得可根据request指定的语言返回对应语种的Validation* ConstrainViolation Message*/public static class RequesLocaleAwareMessageInterpolator extends ResourceBundleMessageInterpolator {public RequesLocaleAwareMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {super(userResourceBundleLocator);}Overridepublic String interpolate(String message, Context context) {return interpolate(message, context, Locale.getDefault());}Overridepublic String interpolate(String message, Context context, Locale locale) {// 获取当前请求所指定的语言对应的LocaleLocale requestLocale LocaleContextHolder.getLocale();log.debug(locale for javax.validation.Validator resolved: {}, requestLocale);if (null requestLocale) {requestLocale locale;}return super.interpolate(message, context, requestLocale);}}} 若注解的message未指定——即用的是框架默认值如 {javax.validation.constraints.Size.message} 则对于框架未提供的i18n语种如 zh_CHS在你自己项目的i18n文件里补充相应值即可如在messages_zh_CHS.properties文件里增加 javax.validation.constraints.Size.message 长度不能超过{max} 若注解的message不用默认值而是自己指定message如 message“{custom.constraints.Size.message.name}” 则在你自己项目的i18n文件里补充相应值即可如 custom.constraints.Size.message.name 姓名的长度不能超过{max} 。此时注解的message仍支持EL表达式。实际使用中推荐用此方案因为这种方案不仅支持EL表达式、i18n消息、还支持返回可直接弹窗显示给用户的i18n字段名。 设置的properties文件可以不叫 ValidationMessages可以是任何文件名。 设置语言的方式 1、设置header Accept-Language基于 AcceptHeaderLocaleResolver 实现 2、设置session / cookie基于 CookieLocaleResolver SessionLocaleResolver 实现。自定义参数的名称需要用到LocaleChangeInterceptor(需要启用默认参数名为locale)用于监控哪个属性(可自定义)切换语言。 public static final String LOCALE_SESSION_ATTRIBUTE_NAME SessionLocaleResolver.class.getName() .LOCALE; public static final String LOCALE_REQUEST_ATTRIBUTE_NAME CookieLocaleResolver.class.getName() .LOCALE;CookieLocaleResolver会把locale放到cookie中cookieNameorg.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE 3、固定locale。FixedLocaleResolver。 spring.mvc.localezh_CN //或者 spring:web:locale: zh_CNlocale-resolver: fixed spring.web.locale-resolver 优先级比 spring.mvc.locale-resolver 高一些。 spring.web.locale、spring.mvc.locale 这两个配置属性假如存在就会成为AcceptHeaderLocaleResolver 的默认的Locale 区域对象。 并在请求响应的请求头中没有Accept-Language这个属性时成为AcceptHeaderLocaleResolver返回的Locale 区域对象。 Spring实现原理 Spring会在启动时通过AOP对使用Validated或Valid的类或其子类的对象生成一个代理对象。在代理对象中调用目标hanlder方法前后会分别进行参数、返回值的JSR校验。 MethodValidationPostProcessor 切面创建的相关逻辑在MethodValidationPostProcessor。 //org.springframework.validation.beanvalidation public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean {private Class? extends Annotation validatedAnnotationType Validated.class;Nullableprivate Validator validator;public void setValidatedAnnotationType(Class? extends Annotation validatedAnnotationType) {Assert.notNull(validatedAnnotationType, validatedAnnotationType must not be null);this.validatedAnnotationType validatedAnnotationType;}public void setValidator(Validator validator) {// Unwrap to the native Validator with forExecutables supportif (validator instanceof LocalValidatorFactoryBean) {this.validator ((LocalValidatorFactoryBean) validator).getValidator();}else if (validator instanceof SpringValidatorAdapter) {this.validator validator.unwrap(Validator.class);}else {this.validator validator;}}public void setValidatorFactory(ValidatorFactory validatorFactory) {this.validator validatorFactory.getValidator();}//此方法在bean自身初始化时会创建一个DefaultPointcutAdvisor用于向符合条件的对象添加进行方法验证的AOP adviseOverridepublic void afterPropertiesSet() {Pointcut pointcut new AnnotationMatchingPointcut(this.validatedAnnotationType, true);this.advisor new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));}//如果有 protected Advice createMethodValidationAdvice(Nullable Validator validator) {return (validator ! null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());}}MethodValidationPostProcessor实现了接口BeanPostProcessor定义的方法postProcessAfterInitialization从父类AbstractAdvisingBeanPostProcessor继承该方法会检查每个bean的创建(在该bean初始化之后)如果检测到该bean符合条件会向其增加上述AOP advise。 MethodValidationPostProcessor是被ValidationAutoConfiguration自动配置到IoC容器的。 ValidationAutoConfiguration package org.springframework.boot.autoconfigure.validation;ConfigurationConditionalOnClass(ExecutableValidator.class)ConditionalOnResource(resources classpath:META-INF/services/javax.validation.spi.ValidationProvider)Import(PrimaryDefaultValidatorPostProcessor.class)public class ValidationAutoConfiguration {Bean Role(BeanDefinition.ROLE_INFRASTRUCTURE)ConditionalOnMissingBean(Validator.class)public static LocalValidatorFactoryBean defaultValidator() {LocalValidatorFactoryBean factoryBean new LocalValidatorFactoryBean();MessageInterpolatorFactory interpolatorFactory new MessageInterpolatorFactory();factoryBean.setMessageInterpolator(interpolatorFactory.getObject());return factoryBean;}// 向容器注册一个 bean MethodValidationPostProcessor BeanConditionalOnMissingBeanpublic static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment, Lazy Validator validator) {MethodValidationPostProcessor processor new MethodValidationPostProcessor();boolean proxyTargetClass environment.getProperty(spring.aop.proxy-target-class, Boolean.class, true);processor.setProxyTargetClass(proxyTargetClass);processor.setValidator(validator);return processor;}} MethodValidationInterceptor 切面中进行参数验证、返回值验证的相关逻辑在MethodValidationInterceptor。 Override SuppressWarnings(unchecked) public Object invoke(MethodInvocation invocation) throws Throwable {// Avoid Validator invocation on FactoryBean.getObjectType/isSingletonif (isFactoryBeanMetadataMethod(invocation.getMethod())) {return invocation.proceed();}//获取对哪些组进行校验Class?[] groups determineValidationGroups(invocation);// Standard Bean Validation 1.1 APIExecutableValidator execVal this.validator.forExecutables();Method methodToValidate invocation.getMethod();SetConstraintViolationObject result;try {result execVal.validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), groups);}catch (IllegalArgumentException ex) {// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011// Lets try to find the bridged method on the implementation class...methodToValidate BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));result execVal.validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), groups);}if (!result.isEmpty()) {throw new ConstraintViolationException(result);}Object returnValue invocation.proceed();result execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);if (!result.isEmpty()) {throw new ConstraintViolationException(result);}return returnValue; } 附录 Spring MVC localeResolver Configuration public class WebMvcConfig implements WebMvcConfigurer {Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(localeChangeInterceptor());}/*** Cookie方式** return*/Beanpublic LocaleResolver localeResolver() {return new CookieLocaleResolver();}/*** 切换语言按钮URL?languagezh_CN切换后将语言信息存入cookie** return*/Beanpublic LocaleChangeInterceptor localeChangeInterceptor() {LocaleChangeInterceptor lci new LocaleChangeInterceptor();//不设置默认为locale。lci.setParamName(language);return lci;} }
http://www.hkea.cn/news/14393363/

相关文章:

  • 网站安全建设自建商城
  • 微山网站建设哪家好北京公司摇号需要哪些资格条件
  • 广西东晋建设有限公司网站新郑做网站推广
  • 网站平台开发报价表怎么做建设一个电商网站的步骤
  • 信丰做网站wordpress推荐文章
  • 潍坊网站建设怎样郑州中森网站建设
  • 延吉市住房城乡建设局官方网站芜湖市建设工程质量监督站官方网站
  • 网上花店 网站源代码WordPress 3.5火车头发布接口
  • 产品经理网站开发需求程序员为什么不敢创业做网站
  • 嘉兴网站设计999 999在阿里巴巴上做网站要多少钱
  • 郑州网络营销网站湖北省建设主管部门网站
  • 手机模板网站模板免费下载苏州工业园区教育网
  • 网站空间数据百度收录申请
  • 嘉定网站设计制作价格四川短视频seo优化网站
  • 好发信息网-网站建设魔兽世界 建设公会网站
  • 哪个网站虚拟主机好怎样将自己做的网站发布到外网上
  • 群晖网站建设处理错误500网站建设网站备案所需资料
  • 劳务 东莞网站建设网络营销的主要特点有哪些
  • 网站建设梦幻创意手机开发人员选项在哪
  • 主播网站开发设计师关注的十大网站
  • 上海城隍庙景点介绍自助建站网站seo公司
  • 建筑网官方网站dw编辑器
  • 公司网站建设怎么做账wordpress主题升级失败
  • 格尔木市公司网站建设wordpress怎么删除评论源码
  • 类似wordpress的博客系统龙岩seo包年系统排行榜
  • 免费软件网站有哪些郑口住房和城乡建设局网站
  • 威海网站建设公司学建设网站去哪里学
  • 临海做网站的公司旅游搭建网站
  • 建设网站需要两种服务支持昆山制造网站的地方
  • 攀枝花建设规划网站网站后台树形菜单样式