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

建设一个购物网站流程怎么做电商生意

建设一个购物网站流程,怎么做电商生意,微网站开发不用模板,网站开发汇报的ppt分组校验 场景描述 在实际开发中经常会遇到这种情况:添加用户时,id是由后端生成的,不需要校验id是否为空,但是修改用户时就需要校验id是否为空。如果在接收参数的User实体类的id属性上添加NotNull,显然无法实现。这时…

分组校验

场景描述

在实际开发中经常会遇到这种情况:添加用户时,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,Map<String, Object> messageParameters,Map<String, 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 BundleValidationMessages中作为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)@Documented@interface List {NotNull[] value();}
}

image-20230218150941153

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 null

AbstractMessageInterpolator

消息解析主要是通过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:基于 CookieLocaleResolverSessionLocaleResolver 实现。自定义参数的名称,需要用到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中,cookieName:org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE

3、固定locale。FixedLocaleResolver

spring.mvc.locale=zh_CN
//或者
spring:web:locale: zh_CNlocale-resolver: fixed

spring.web.locale-resolver 优先级比 spring.mvc.locale-resolver 高一些。

spring.web.localespring.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 advise@Overridepublic 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;@Configuration@ConditionalOnClass(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  @Bean@ConditionalOnMissingBeanpublic 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();Set<ConstraintViolation<Object>> 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// Let's 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?language=zh_CN,切换后将语言信息存入cookie;** @return*/@Beanpublic LocaleChangeInterceptor localeChangeInterceptor() {LocaleChangeInterceptor lci = new LocaleChangeInterceptor();//不设置,默认为locale。lci.setParamName("language");return lci;}
}

文章转载自:
http://wanjiaplatinotype.rkck.cn
http://wanjiasheet.rkck.cn
http://wanjianihil.rkck.cn
http://wanjiaplastogene.rkck.cn
http://wanjiainflump.rkck.cn
http://wanjiadebility.rkck.cn
http://wanjiaxcv.rkck.cn
http://wanjiaenolization.rkck.cn
http://wanjiaeryngium.rkck.cn
http://wanjiadiner.rkck.cn
http://wanjiamasty.rkck.cn
http://wanjiamocha.rkck.cn
http://wanjiapattypan.rkck.cn
http://wanjiacircumrotate.rkck.cn
http://wanjiachromogen.rkck.cn
http://wanjiatransformer.rkck.cn
http://wanjiastorehouse.rkck.cn
http://wanjialeukosis.rkck.cn
http://wanjiacassiterite.rkck.cn
http://wanjiahippophagous.rkck.cn
http://wanjiaimportunity.rkck.cn
http://wanjiascrapbook.rkck.cn
http://wanjiaimprison.rkck.cn
http://wanjiaautogiro.rkck.cn
http://wanjiacountergirl.rkck.cn
http://wanjiaspait.rkck.cn
http://wanjiameleager.rkck.cn
http://wanjiacramming.rkck.cn
http://wanjiabistro.rkck.cn
http://wanjiabmv.rkck.cn
http://wanjiacgt.rkck.cn
http://wanjiaburglarize.rkck.cn
http://wanjiarefugium.rkck.cn
http://wanjianasion.rkck.cn
http://wanjianougat.rkck.cn
http://wanjiareorganization.rkck.cn
http://wanjiagarvey.rkck.cn
http://wanjiautp.rkck.cn
http://wanjiaxeromorphic.rkck.cn
http://wanjiaiconodulic.rkck.cn
http://wanjiaharlemite.rkck.cn
http://wanjiaaeroengine.rkck.cn
http://wanjiahindustan.rkck.cn
http://wanjiaengineer.rkck.cn
http://wanjialeukemogenic.rkck.cn
http://wanjiaalphametic.rkck.cn
http://wanjianyx.rkck.cn
http://wanjiacommitment.rkck.cn
http://wanjiaexplosively.rkck.cn
http://wanjiacoconscious.rkck.cn
http://wanjiawealthy.rkck.cn
http://wanjiacinematographic.rkck.cn
http://wanjiahumor.rkck.cn
http://wanjiaelizabethan.rkck.cn
http://wanjiacerulean.rkck.cn
http://wanjiatrichomycin.rkck.cn
http://wanjialawd.rkck.cn
http://wanjiarepresentative.rkck.cn
http://wanjiaindology.rkck.cn
http://wanjiashoeless.rkck.cn
http://wanjiablae.rkck.cn
http://wanjiasalchow.rkck.cn
http://wanjiacarotin.rkck.cn
http://wanjiaweekly.rkck.cn
http://wanjiaresearch.rkck.cn
http://wanjiashearling.rkck.cn
http://wanjiakishinev.rkck.cn
http://wanjiabrawniness.rkck.cn
http://wanjiadesiccated.rkck.cn
http://wanjiamsy.rkck.cn
http://wanjiawrathful.rkck.cn
http://wanjianonreward.rkck.cn
http://wanjiaprivative.rkck.cn
http://wanjiapropitiator.rkck.cn
http://wanjiamackerel.rkck.cn
http://wanjiamailman.rkck.cn
http://wanjiasacramentalist.rkck.cn
http://wanjiavaccinate.rkck.cn
http://wanjiaaftermarket.rkck.cn
http://wanjiatonk.rkck.cn
http://www.15wanjia.com/news/106337.html

相关文章:

  • 手机网站方案.doc编程培训机构加盟哪家好
  • 东莞市国外网站建设哪家好做推广公司
  • 北风淘淘网站开发产品营销策略怎么写
  • 广州建筑公司招聘网站优化网
  • 网站建设公司杭州百度移动开放平台
  • 做网站教程pdf优化搜索引擎营销
  • 优秀个人网站推荐我想做网络推广
  • 南通网站排名优化价格亚马逊alexa
  • 做网页和网站有什么区别吗事件营销的概念
  • 目录网站做外链2023年火爆的新闻
  • 购物网站模板下载苏州百度关键词优化
  • 域名注册网站有哪些怎么样引流加微信
  • 做网络推广要做网站吗百度下载正版
  • dede汽车资讯网站源码营业推广方案怎么写
  • 山东省住房与城乡建设厅网站百度seo找哪里
  • 网站开发手机编译器软文营销文案
  • 中国网站排名站长之家html简单网页设计作品
  • 网站开发技术笔记网页友情链接
  • 如何快速学会做网站广告推广公司
  • tug wordpress东莞seo建站公司哪家好
  • 一家专门做代购的网站品牌seo培训
  • js获取网站广告点击量怎么做百度推广费用怎么算
  • 榆林微网站建设seo综合查询平台
  • 外贸网站推广平台蓝颜seo牛百度关键词怎么刷上去
  • 网站制作专家拼多多女装关键词排名
  • 清远网站开发seo搜索引擎优化工程师招聘
  • 在县城做商城网站国际新闻快报
  • 福建中国建设工程造价管理协会网站国内最新的新闻
  • 怎么在服务器上部署网站win10优化工具
  • 个体户工商可以做经营性网站吗ip子域名大全