每篇一句

吾皇一日不退役,尔等都是臣子


对Spring感兴趣可扫码加入wx群:`Java高工、架构师3群`(文末有二维码)


前言

前几篇文章在讲Spring的数据绑定的时候,多次提到过数据校验。可能有人认为数据校验模块并不是那么的重要,因为硬编码都可以做。若是这么想的话,那就大错特错了~

前面讲解DataBinder的时候一个小细节,它所在的包是:org.springframework.validation,并且在分析源码的时候能看到DataBinder它不仅能够完成数据绑定,也提供了对数据校验的支持且还保存了校验结果。

我以数据绑定DataBinder为引子引出了数据校验这一块,是想表明它的重要性。连Java都把它抽象成了JSR标准进行提出,so我认为这块是必修课,有必要了解本章的内容。

为什么要有数据校验?

数据校验 是非常常见的工作,在日常的开发中贯穿于代码的各个层次,从上层的View层到底层的数据层。

在此处有必要再强调一句:前面说了数据绑定并不属于Spring MVC的专利,同样的数据校验也不是只会发生在web层,它可以在任意一层,从后面的示例中你会有更深的理解

在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的(比如生日必须是过去时,年龄必须>0等等~)。

我们知道通常情况下程序肯定是分层的,不同的层一般由不同的人来开发。若你是一个有经验的程序员, 我相信你肯定见过在不同的层了都出现了相同的校验代码,这就是某种意义上的垃圾代码。

public String queryValueByKey(String parmTemplateCode, String conditionName, String conditionKey, String resultName) {
checkNotNull(parmTemplateCode, "parmTemplateCode not null");
checkNotNull(conditionName, "conditionName not null");
checkNotNull(conditionKey, "conditionKey not null");
checkNotNull(resultName, "resultName not null");
...
}

从这个简单的方法入参校验至少能发现如下问题:

  1. 需要写大量的代码来进行参数验证。(这种代码多了就算垃圾代码)
  2. 需要通过注释来知道每个入参的约束是什么(否则别人咋看得懂)
  3. 每个程序员做参数验证的方式不一样,参数验证不通过抛出的异常也不一样(后期几乎没法维护)

如上会导致代码冗余和一些管理的问题(代码量越大,管理起来维护起来就越困难),比如说语义的一致性等。为了避免这样的情况发生,最好是将验证逻辑与相应的域模型(领域模型的概念)进行绑定,这就是本文提供的一个新思路(其实是JavaEE提供的思路)

为了解决这个问题,Bean ValidationJavaBean 验证定义了相应的元数据模型和 API。默认的元数据是 各种Java Annotations,当然也支持xml方式并且你也可以扩展~

可以说Bean ValidationJavaBean的一个拓展,它可以布局于任意一层代码,不局限于Web应用还是端应用。

Java Bean Validation

JSR是Java Specification Requests的缩写,意思是Java 规范提案。关于数据校验这块,最新的是JSR380,也就是我们常说的Bean Validation 2.0

Bean Validation 2.0 是JSR第380号标准。该标准连接如下:https://www.jcp.org/en/egc/view?id=380

Bean Validation的主页:http://beanvalidation.org

Bean Validation的参考实现:https://github.com/hibernate/hibernate-validator

Bean Validation是一个通过配置注解来验证参数的框架,它包含两部分Bean Validation API(规范)和Hibernate Validator(实现)。

Bean Validation是Java定义的一套基于注解/xml的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已经经历了三个版本(我截图如下:)



现在绝大多数coder使用者其实都还在使用Bean Validation 1.1,毕竟一般来说它已经够用了~

本文会介绍Bean Validation 2.0提供的一些实用的新东西,毕竟Java8现在已成为主流,完全可以使用了~

简单Demo示例

要想使用它,首先就得导包嘛~根据经验,和JCache类似Java只提供了规范,并没有提供实现,所以我们可以先找到它的API包然后导入:

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<!-- <version>1.1.0.Final</version> -->
<version>2.0.1.Final</version>
</dependency>

关于版本之间的差异其实不是本文说明的重点,毕竟2.0做到了很好的向下兼容,使用起来是无缝的。

但是本处还是给个1.1版本和2.0.1的截图,感官上简单对比一下区别:



兼容性表格

Bean Validation Hibernate Validation JDK Spring Boot
1.1 5.4 + 6+ 1.5.x
2.0 6.0 + 8+ 2.0.x

关于Bean Validation 2.0的关注点(新特性)

因为2.0推出的时间确实不算长,so此处我把一些重要的关注点列举如下:

  1. 对Java的最低版本要求是Java 8
  2. 支持容器的校验,通过TYPE_USE类型的注解实现对容器内容的约束:List<@Email String>
  3. 支持日期/时间的校验,@Past@Future
  4. 拓展元数据(新增注解):@Email,@NotEmpty,@NotBlank,@Positive, @PositiveOrZero,@Negative,@NegativeOrZero,@PastOrPresent和@FutureOrPresent

    1. 像@Email、@NotEmpty、@NotBlank之前是Hibernate额外提供的,2.0标准后hibernate自动退位让贤并且标注为过期了
  5. Bean Validation 2.0的唯一实现为Hibernate Validator。(其实还有Apache BVal,但是你懂的,forget it)
  6. 对于Hibernate Validator,它自己也扩展了一些注解支持。

    1. 6.0以上版本新增(对应标准2.0版本):@UniqueElements、@ISBN、@CodePointLength

    2. 6.0以下版本可以使用的: @URL、@ScriptAssert、@SafeHtml、@Range、@ParameterScriptAssert、@Mod11Check、@Mod10Check、@LuhnCheck、@Length、@EAN、@Currency、@CreditCardNumber、@ConstraintComposition、

    3. Hibernate Validator默认会校验完所有的属性,然后返回所有的验证失败信息。开启fail fast mode后,只要有一个验证失败,则返回验证失败信息。

so,对于Java Bean Validation的实现落地产品就没啥好选的,导入Hibernate Validator(最新版本)吧:

<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>

小细节:



可以看到,导入了hibernate-validator就必要再自己导入Java Bean ValidationAPI了,因此建议不用再手动导入API,交给内部来管理依赖。

定义一个待校验的普通JavaBean:

@Getter
@Setter
@ToString
public class Person { // 错误消息message是可以自定义的
@NotNull(message = "名字不能为null")
public String name;
@Positive
public Integer age; @NotNull
@NotEmpty
private List<@Email String> emails;
@Future
private Date start; }

书写测试用例:

    public static void main(String[] args) {
Person person = new Person();
//person.setName("fsx");
person.setAge(-1);
// email校验:虽然是List都可以校验哦
person.setEmails(Arrays.asList("fsx@gmail.com", "baidu@baidu.com", "aaa.com"));
//person.setStart(new Date()); //start 需要是一个将来的时间: Sun Jul 21 10:45:03 CST 2019
//person.setStart(new Date(System.currentTimeMillis() + 10000)); //校验通过 // 对person进行校验然后拿到结果(显然使用时默认的校验器) 会保留下校验失败的消息
Set<ConstraintViolation<Person>> result = Validation.buildDefaultValidatorFactory().getValidator().validate(person);
// 对结果进行遍历输出
result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())
.forEach(System.out::println);
}

运行,报错啦:

Caused by: java.lang.ClassNotFoundException: javax.el.ELManager
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
...

可以看到运行必须依赖于javax.el这个包。(其实我是比较费解的,为何校验框架非得依赖它呢?有小伙伴可以帮忙解释一下吗?)

那行,导入依赖javax.el以及它的实现:

<!-- 注意这里导入的是Apr, 2013发布的el3.x的版本,但是glassfish并没有对此版本进行支持了  当然tomcat肯定是支持的 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.1-b06</version>
</dependency>
<!-- servlet容器大都对el有实现(支持jsp的都对此有实现),比如tomcat/glassfish等 -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>

需要注意的是,网上大都建议导入org.glassfish.web包。但是EL3.0后它并没有再提供支持了,因此我个人是不建议使用它,而是使用下面tomcat的实现的~

关于EL的实现此处啰嗦一句:JavaEE并没有提供el的实现,需要容器自行提供,比如上面你想要导入最为流行的tomcat,你可以导入如下jar即可:

<!-- 嵌入式的tomcat -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.22</version>
</dependency>
<!-- 传统的tomcat(需要注意的是:传统的tomcat这种jar是不需要你手动导入的,tomcat自带的) -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper-el</artifactId>
<version>9.0.22</version>
<scope>provided</scope>
</dependency>

此处还需要说明一点的是:嵌入式tomcat(比如SpringBoot环境)若要使用时需要显示导入的。但是传统tomcat中你若要使用是不用自己导入的(tomcat自带此jar)。

但是,但是,但是自从tomcat8.5后不再自带jsper-el的包了,需要手动导入。(tomcat7还是有的~

最佳实践:

一般来说,javax.el-api以及validation-api都是没有必要单独导入的,第三方包都会自带。所以绝大数情况下,我们只需要这么导入即可正常work,形如下面这样非常赶紧整洁:

<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.22</version>
</dependency>
此处可能有伙伴会问:为何自己在使用的时候从来都没有导入过EL相关Jar包,也能正常数据校验呢?

答:那是因为绝大多数情况下你使用@Valid是使用在Spring MVC上,它是不依赖于EL方式的,下篇文章会详细说明关于数据校验在Spring上的使用。而本文主要还是讲解API的方式~



经过一番导包后,再次运行打印如下(方式一、方式二结果一致):

name名字不能为null: null //  此处错误消息是自己的自定义内容
age必须是正数: -1
emails[2].<list element>不是一个合法的电子邮件地址: aaa.com

这样通过API调用的方式就完成了对这个JavaBean的属性校验~

核心API分析

Validation

官方给它的定义为:This class is the entry point for Bean Validation.它作为校验的入口,有三种方式来启动它:

  1. 最简单方式:使用默认的ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 虽然是默认的单也会有如下2种情况:

    1. 若使用了xml配置了一个provider,那就会使用这个provider来提供Factory

    2. 若没有xml或者xml力没有配置provider,那就是用默认的ValidationProviderResolver实现类来处理
  2. 方式二:选择自定义的ValidationProviderResolver来跟XML配置逻辑选出一个ValidationProvider来。大致代码如下:
Configuration configuration = Validation.byDefaultProvider()
.providerResolver(new MyResolverStrategy()) // 自定义一个ValidationProviderResolver的实现类
.configure();
ValidatorFactory factory = configuration.buildValidatorFactory();
  1. 第三种方式就更加自由了:你可以直接提供一个类型安全ValidationProvider实现。比如HibernateValidator就是一个ValidationProvider的实现:
HibernateValidatorConfiguration configuration = Validation.byProvider(HibernateValidator.class)
// .providerResolver( ... ) // 因为制定了Provider,这个参数就可选了
.configure()
.failFast(false);
ValidatorFactory validatorFactory = configuration.buildValidatorFactory();

这三种初始化方式,在源码处就是对应提供的三个public static方法:

public class Validation {

	// 方式一
public static ValidatorFactory buildDefaultValidatorFactory() {
return byDefaultProvider().configure().buildValidatorFactory();
}
// 方式二
public static GenericBootstrap byDefaultProvider() {
return new GenericBootstrapImpl();
}
// 方式三
public static <T extends Configuration<T>, U extends ValidationProvider<T>> ProviderSpecificBootstrap<T> byProvider(Class<U> providerType) {
return new ProviderSpecificBootstrapImpl<>( providerType );
}
...
}

对于若你想使用xml文件独立配置校验规则,可以使用Configuration.addMapping(new FileInputStream(validationFile));,现在很少这么使用,略~

使用注意事项:ValidatorFactory被创建后应该缓存起来再提供使用,因为它是县城安全的。

因为现在都会使用Hibernate-Validation来处理校验,因此此处只关心方式三~

HibernateValidatorConfiguration

此接口表示配置,继承自标注接口javax.validation.Configuration。很明显,它是HibernateValidator的专属配置类



先看顶级接口:javax.validation.Configuration,为构建ValidatorFactory的配置类。默认情况下,它会读取配置文件META-INF/validation.xml,Configuration提供的API方法是覆盖xml配置文件项的。若没有找到validation.xml,就会使用默认的ValidationProviderResolver也就是:DefaultValidationProviderResolver

public interface Configuration<T extends Configuration<T>> {
// 该方法调用后就不会再去找META-INF/validation.xml了
T ignoreXmlConfiguration();
// 消息内插器 它是个狠角色,关于它的使用场景,后续会有详解(包括Spring都实现了它来做事)
// 它的作用是:插入给定的约束冲突消息
T messageInterpolator(MessageInterpolator interpolator);
// 确定bean验证提供程序是否可以访问属性的协定。对每个正在验证或级联的属性调用此约定。(Spring木有实现它)
// 对每个正在验证或级联的属性都会调用此约定
// Traversable: 可移动的
T traversableResolver(TraversableResolver resolver);
// 创建ConstraintValidator的工厂
// ConstraintValidator:定义逻辑以验证给定对象类型T的给定约束A。(A是个注解类型)
T constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory);
// ParameterNameProvider:提供Constructor/Method的方法名们
T parameterNameProvider(ParameterNameProvider parameterNameProvider);
// java.time.Clock 用作判定@Future和@Past(默认取值当前时间)
// 若你希望他是个逻辑实现,提供一个它即可
// @since 2.0
T clockProvider(ClockProvider clockProvider);
// 值提取器。这是add哦~ 负责从Optional、List等这种容器里提取值~
// @since 2.0
T addValueExtractor(ValueExtractor<?> extractor);
// 加载xml文件
T addMapping(InputStream stream);
// 添加特定的属性给Provider用的。此属性等效于XML配置属性。
// 此方法通常是框架自己分析xml文件得到属性值然后放进去,调用者一般不使用(当然也可以用)
T addProperty(String name, String value); // 下面都是get方法喽
MessageInterpolator getDefaultMessageInterpolator();
TraversableResolver getDefaultTraversableResolver();
ConstraintValidatorFactory getDefaultConstraintValidatorFactory();
ParameterNameProvider getDefaultParameterNameProvider();
ClockProvider getDefaultClockProvider();
BootstrapConfiguration getBootstrapConfiguration(); // 整个配置也可返回出去 // 上面都是工作,这个方法才是最终需要调用的:得到一个ValidatorFactory
ValidatorFactory buildValidatorFactory();
}

该接口提供了一些标准的配置项。在实际应用中都是使用Hibernate Validation,所以再看看这个具体的子接口:

public interface HibernateValidatorConfiguration extends Configuration<HibernateValidatorConfiguration> {

	// 这批属性,证明直接可以通过System属性值来控制,大大地方便~
// 这个机制快速失败机制:true检查完一个有错误就返回,false全部检查完把错误消息一起返回 默认false
String FAIL_FAST = "hibernate.validator.fail_fast";
String ALLOW_PARAMETER_CONSTRAINT_OVERRIDE = "hibernate.validator.allow_parameter_constraint_override";
String ALLOW_MULTIPLE_CASCADED_VALIDATION_ON_RESULT = "hibernate.validator.allow_multiple_cascaded_validation_on_result";
String ALLOW_PARALLEL_METHODS_DEFINE_PARAMETER_CONSTRAINTS = "hibernate.validator.allow_parallel_method_parameter_constraint";
// @since 5.2
@Deprecated
String CONSTRAINT_MAPPING_CONTRIBUTOR = "hibernate.validator.constraint_mapping_contributor";
// @since 5.3
String CONSTRAINT_MAPPING_CONTRIBUTORS = "hibernate.validator.constraint_mapping_contributors";
// @since 6.0.3
String ENABLE_TRAVERSABLE_RESOLVER_RESULT_CACHE = "hibernate.validator.enable_traversable_resolver_result_cache";
// @since 6.0.3 ScriptEvaluatorFactory:执行脚本
@Incubating
String SCRIPT_EVALUATOR_FACTORY_CLASSNAME = "hibernate.validator.script_evaluator_factory";
// @since 6.0.5 comparing date/time in temporal constraints. In milliseconds.
@Incubating
String TEMPORAL_VALIDATION_TOLERANCE = "hibernate.validator.temporal_validation_tolerance"; // ResourceBundleMessageInterpolator用于 load resource bundles
ResourceBundleLocator getDefaultResourceBundleLocator();
// 创建一个ConstraintMapping:通过编程API配置的约束映射
// 设置映射后,必须通过addMapping(constraintmapping)将其添加到此配置中。
ConstraintMapping createConstraintMapping();
// 拿到所有的值提取器 @since 6.0
@Incubating
Set<ValueExtractor<?>> getDefaultValueExtractors(); // 往下就开始配置了~~~~~~~~~~
HibernateValidatorConfiguration addMapping(ConstraintMapping mapping);
HibernateValidatorConfiguration failFast(boolean failFast);
// used for loading user-provided resources:
HibernateValidatorConfiguration externalClassLoader(ClassLoader externalClassLoader);
// true:表示允许覆盖约束的方法。false表示不予许(抛出异常) 默认值是false
HibernateValidatorConfiguration allowOverridingMethodAlterParameterConstraint(boolean allow);
// 定义是否允许对返回值标记多个约束以进行级联验证。 默认是false
HibernateValidatorConfiguration allowMultipleCascadedValidationOnReturnValues(boolean allow);
// 定义约束的**并行方法**是否应引发ConstraintDefinitionException
HibernateValidatorConfiguration allowParallelMethodsDefineParameterConstraints(boolean allow);
// 是否允许缓存TraversableResolver 默认值是true
HibernateValidatorConfiguration enableTraversableResolverResultCache(boolean enabled);
// 设置一个脚本执行器
@Incubating
HibernateValidatorConfiguration scriptEvaluatorFactory(ScriptEvaluatorFactory scriptEvaluatorFactory);
// 允许在时间约束中比较日期/时间时设置可接受的误差范围
// 比如@Past @PastOrPresent @Future @FutureOrPresent
@Incubating
HibernateValidatorConfiguration temporalValidationTolerance(Duration temporalValidationTolerance);
// 允许设置将传递给约束验证器的有效负载。如果多次调用该方法,则只传播最后传递的有效负载。
@Incubating
HibernateValidatorConfiguration constraintValidatorPayload(Object constraintValidatorPayload);
}

关于此接口的唯一实现类:ConfigurationImpl,这里就不用再做分析了,因为对于Validation这块,咱们面向接口编程是完全没有问题的~

准备好了Configuration后,下一步显然就是configuration.buildValidatorFactory()来得到一个ValidatorFactory喽,关于ValidatorFactory这块的内容,请听下文分解~

总结

该文讲解是关于Bean Validation数据校验,在现在Spring的高度封装下,越来越少的人能够主动去发现Java实现/标准了~

实际上Spring的强大并不是自己创造了多少轮子,而是它主要是带来了更为简单的抽象,从而减少样板代码、促进解耦、提高可单测性。因此对于有些常用的功能还是建议稍微了解多一点,做到心中有数,运用起来也才会更加的游刃有余

知识交流

若文章格式混乱,可点击原文链接-原文链接-原文链接-原文链接-原文链接

The last:如果觉得本文对你有帮助,不妨点个赞呗。当然分享到你的朋友圈让更多小伙伴看到也是被作者本人许可的~

若对技术内容感兴趣可以加入wx群交流:Java高工、架构师3群

若群二维码失效,请加wx号:fsx641385712(或者扫描下方wx二维码)。并且备注:"java入群" 字样,会手动邀请入群


深入了解数据校验:Bean Validation 2.0(JSR380)的更多相关文章

  1. Java数据校验(Bean Validation / JSR303)

    文档: http://beanvalidation.org/1.1/spec/ API : http://docs.jboss.org/hibernate/beanvalidation/spec/1. ...

  2. 深入了解数据校验:Java Bean Validation 2.0(JSR380)

    每篇一句 吾皇一日不退役,尔等都是臣子 相关阅读 [小家Java]深入了解数据校验(Bean Validation):基础类打点(ValidationProvider.ConstraintDescri ...

  3. springboot使用hibernate validator校验,Bean Validation校验

    第一个地址:springboot使用hibernate validator校验,Bean Validation校验

  4. Bean Validation完结篇:你必须关注的边边角角(约束级联、自定义约束、自定义校验器、国际化失败消息...)

    每篇一句 没有任何技术方案会是一种银弹,任何东西都是有利弊的 相关阅读 [小家Java]深入了解数据校验:Java Bean Validation 2.0(JSR303.JSR349.JSR380)H ...

  5. Spring官网阅读(十七)Spring中的数据校验

    文章目录 Java中的数据校验 Bean Validation(JSR 380) 使用示例 Spring对Bean Validation的支持 Spring中的Validator 接口定义 UML类图 ...

  6. 1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知

    乔丹是我听过的篮球之神,科比是我亲眼见过的篮球之神.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免 ...

  7. 2. Bean Validation声明式校验方法的参数、返回值

    你必须非常努力,才能干起来毫不费力.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众 ...

  8. Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC 配置校验器

    Spring4新特性——泛型限定式依赖注入 Spring4新特性——核心容器的其他改进 Spring4新特性——Web开发的增强 Spring4新特性——集成Bean Validation 1.1(J ...

  9. SpringMVC——类型转换和格式化、数据校验、客户端显示错误消息

    在介绍类型转换和格式化之前,我首先来介绍 <mvc:annotation-driven />. 需要导入的 schema: xmlns:mvc="http://www.sprin ...

随机推荐

  1. 把握每次机会,麒麟芯片5年成就高端(SoC包括AP、基带、ISP等,华为确实牛)

    从2016年11月华为Mate 9 /Mate 9 Pro发布,到2017年2月荣耀V9和华为P10 /P10 Plus 相继发布,这几款都是华为和荣耀的高端旗舰机型,且搭载的都是华为最新旗舰芯片-- ...

  2. virtualbox ubuntu16.04 自动挂载共享文件夹

    为了操作方便,需要ubuntu 在开机运行时自动挂载共享文件夹,ubuntu的版本是16.04,宿主机是win10,步骤如下: 1. 在virtualbox “设备”-“共享文件夹”中设置共享文件夹如 ...

  3. 社会不是承认有学历的人, 而是承认努力过得人, 而且是真正努力过不是穷忙的人(没有学历就要多付出一倍的努力)good

    送你一句 这就是你水平差的理由? 楼主你工资低是因为你技术不行, 不想努力然后怪罪学历, 为什么学历高的混得好, 因为学历高的人努力过, 你没学历技术还不行, 凭什么证明你努力过, 社会不是承认有学历 ...

  4. 以太坊(ethereum)开发DApp应用的入门区块链技术教程

    概述 对初学者,首先要了解以太坊开发相关的基本概念.   学习以太坊开发的一般前序知识要求,最好对以下技术已经有一些基本了解: 一种面向对象的开发语言,例如:Python,Ruby,Java... 前 ...

  5. Qt系统对话框中文化及应用程序实现重启及使用QSS样式表文件及使用程序启动界面

    一.应用程序中文化 1).Qt安装目录下有一个目录translations/,在此目录下有qt_zh_CN.ts和 qt_zh_CN.qm把它们拷贝到你的工程目录下. 2).在main函数加入下列代码 ...

  6. 【Linux】Linux下设备网卡以及硬件管理等

    这是Linux下网络硬件管理的基础知识,虽然平时用到的可能比软件的少一点,但是作为基础命令,还是需要记住,以免用时又得查询. 本文参考官方文档:https://wiki.ubuntu.com.cn/% ...

  7. mac下 编译php的 openssl

    编译openssl.so tar zxvf php-7.2.8.tar.gz# 进入PHP的openssl扩展模块目录cd php-7.2.8/ext/openssl/brew install ope ...

  8. 分析RESTful API安全性及如何采取保护措施

    本文中讨论了API安全性和采用安全措施的重要性,如身份验证,API密钥,访问控制和输入验证. API设计的第一步是撰写接口文档 根据TechTarget(海外IT专业媒体)的定义,RESTful AP ...

  9. Appium+python自动化(十一)- 元素定位秘籍助你打通任督二脉 - 下卷(超详解)

    简介 宏哥看你骨骼惊奇,印堂发亮,必是练武之奇才! 按照上一篇的节目预告,这一篇还是继续由宏哥给小伙伴们分享元素定位,是不是按照上一篇的秘籍修炼,是不是感觉到头顶盖好像被掀开,内气从头上冒出去,顿时觉 ...

  10. Linux 中文设置

    命令  locale,查看Linux默认系统语言 [root@VM_0_15_centos /]# locale LANG=en_US.utf8 LC_CTYPE="en_US.utf8&q ...