Spring Boot 实现各种参数校验

2023-10-27

目录

1、简单使用

1、引入依赖

2、requestBody参数校验

3、requestParam/PathVariable参数校验

4、统一异常处理

2、进阶使用

1、分组校验

2、嵌套校验

3、集合校验

4、自定义校验

5、编程式校验

6、快速失败 (Fail Fast)

7、@Valid和@Validated区别

3、实现原理

1、requestBody参数校验实现原理

2、方法级别的参数校验实现原理


1、简单使用

Java API规范 (JSR303) 定义了Bean校验的标准validation-api,但没有提供实现。hibernate validation是对这个规范的实现,并增加了校验注解如@Email@Length等。Spring Validation是对hibernate validation的二次封装,用于支持spring mvc参数自动校验。接下来,我们以spring-boot项目为例,介绍Spring Validation的使用。

1、引入依赖

如果spring-boot版本小于2.3.xspring-boot-starter-web会自动传入hibernate-validator依赖。如果spring-boot版本大于2.3.x,则需要手动引入依赖:

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

对于web服务来说,为防止非法参数对业务造成影响,在Controller层一定要做参数校验的!大部分情况下,请求参数分为如下两种形式:

  1. POSTPUT请求,使用requestBody传递参数;

  2. GET请求,使用requestParam/PathVariable传递参数。

下面我们简单介绍下requestBodyrequestParam/PathVariable的参数校验实战!

2、requestBody参数校验

POSTPUT请求一般会使用requestBody传递参数,这种情况下,后端使用** DTO 对象**进行接收。只要给 DTO 对象加上@Validated注解就能实现自动参数校验。比如,有一个保存User的接口,要求userName长度是2-10accountpassword字段长度是6-20。如果校验失败,会抛出MethodArgumentNotValidException异常,Spring默认会将其转为400(Bad Request)请求。

DTO 表示数据传输对象(Data Transfer Object),用于服务器和客户端之间交互传输使用的。在 spring-web 项目中可以表示用于接收请求参数的Bean对象。

  • DTO字段上声明约束注解

@Data
public class UserDTO {

    private Long userId;

    @NotNull
    @Length(min = 2, max = 10)
    private String userName;

    @NotNull
    @Length(min = 6, max = 20)
    private String account;

    @NotNull
    @Length(min = 6, max = 20)
    private String password;
}

  • 在方法参数上声明校验注解

@PostMapping("/save")
public Result saveUser(@RequestBody @Validated UserDTO userDTO) {

    return Result.ok();
}

这种情况下,使用@Valid@Validated都可以

3、requestParam/PathVariable参数校验

GET请求一般会使用requestParam/PathVariable传参。如果参数比较多 (比如超过 6 个),还是推荐使用DTO对象接收。否则,推荐将一个个参数平铺到方法入参中。在这种情况下,必须在Controller类上标注@Validated注解,并在入参上声明约束注解 (如@Min等)。如果校验失败,会抛出ConstraintViolationException异常。代码示例如下:

@RequestMapping("/api/user")
@RestController
@Validated
public class UserController {

    @GetMapping("{userId}")
    public Result detail(@PathVariable("userId") @Min(10000000000000000L) Long userId) {

        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(userId);
        userDTO.setAccount("11111111111111111");
        userDTO.setUserName("xixi");
        userDTO.setAccount("11111111111111111");
        return Result.ok(userDTO);
    }

    @GetMapping("getByAccount")
    public Result getByAccount(@Length(min = 6, max = 20) @NotNull String  account) {

        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(10000000000000003L);
        userDTO.setAccount(account);
        userDTO.setUserName("xixi");
        userDTO.setAccount("11111111111111111");
        return Result.ok(userDTO);
    }
}

4、统一异常处理

前面说过,如果校验失败,会抛出MethodArgumentNotValidException或者ConstraintViolationException异常。在实际项目开发中,通常会用统一异常处理来返回一个更友好的提示。比如我们系统要求无论发送什么异常,http的状态码必须返回200,由业务码去区分系统的异常情况。

@RestControllerAdvice
public class CommonExceptionHandler {

    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        StringBuilder sb = new StringBuilder("校验失败:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
        }
        String msg = sb.toString();
       return Result.fail(BusinessCode.参数校验失败, msg);
    }

    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Result handleConstraintViolationException(ConstraintViolationException ex) {
        return Result.fail(BusinessCode.参数校验失败, ex.getMessage());
    }
}

2、进阶使用

1、分组校验

在实际项目中,可能多个方法需要使用同一个DTO类来接收参数,而不同方法的校验规则很可能是不一样的。这个时候,简单地在DTO类的字段上加约束注解无法解决这个问题。因此,spring-validation支持了分组校验的功能,专门用来解决这类问题。还是上面的例子,比如保存User的时候,UserId是可空的,但是更新User的时候,UserId的值必须>=10000000000000000L;其它字段的校验规则在两种情况下一样。这个时候使用分组校验的代码示例如下:

  • 约束注解上声明适用的分组信息groups

@Data
public class UserDTO {

    @Min(value = 10000000000000000L, groups = Update.class)
    private Long userId;

    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 2, max = 10, groups = {Save.class, Update.class})
    private String userName;

    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})
    private String account;

    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})
    private String password;

    public interface Save {
    }

    public interface Update {
    }
}

  • @Validated注解上指定校验分组

@PostMapping("/save")
public Result saveUser(@RequestBody @Validated(UserDTO.Save.class) UserDTO userDTO) {

    return Result.ok();
}

@PostMapping("/update")
public Result updateUser(@RequestBody @Validated(UserDTO.Update.class) UserDTO userDTO) {

    return Result.ok();
}

2、嵌套校验

前面的示例中,DTO类里面的字段都是基本数据类型String类型。但是实际场景中,有可能某个字段也是一个对象,这种情况先,可以使用嵌套校验。比如,上面保存User信息的时候同时还带有Job信息。需要注意的是,此时DTO类的对应字段必须标记@Valid注解

@Data
public class UserDTO {

    @Min(value = 10000000000000000L, groups = Update.class)
    private Long userId;

    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 2, max = 10, groups = {Save.class, Update.class})
    private String userName;

    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})
    private String account;

    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})
    private String password;

    @NotNull(groups = {Save.class, Update.class})
    @Valid
    private Job job;

    @Data
    public static class Job {

        @Min(value = 1, groups = Update.class)
        private Long jobId;

        @NotNull(groups = {Save.class, Update.class})
        @Length(min = 2, max = 10, groups = {Save.class, Update.class})
        private String jobName;

        @NotNull(groups = {Save.class, Update.class})
        @Length(min = 2, max = 10, groups = {Save.class, Update.class})
        private String position;
    }

    public interface Save {
    }

    public interface Update {
    }
}

嵌套校验可以结合分组校验一起使用。还有就是嵌套集合校验会对集合里面的每一项都进行校验,例如List<Job>字段会对这个list里面的每一个Job对象都进行校验。

3、集合校验

如果请求体直接传递了json数组给后台,并希望对数组中的每一项都进行参数校验。此时,如果我们直接使用java.util.Collection下的list或者set来接收数据,参数校验并不会生效!我们可以使用自定义list集合来接收参数:

  • 包装List类型,并声明@Valid注解

public class ValidationList<E> implements List<E> {

    @Delegate
    @Valid
    public List<E> list = new ArrayList<>();

    @Override
    public String toString() {
        return list.toString();
    }
}

@Delegate注解受lombok版本限制,1.18.6以上版本可支持。如果校验不通过,会抛出NotReadablePropertyException,同样可以使用统一异常进行处理。

比如,我们需要一次性保存多个User对象,Controller层的方法可以这么写:

@PostMapping("/saveList")
public Result saveList(@RequestBody @Validated(UserDTO.Save.class) ValidationList<UserDTO> userList) {

    return Result.ok();
}

4、自定义校验

业务需求总是比框架提供的这些简单校验要复杂的多,我们可以自定义校验来满足我们的需求。自定义spring validation非常简单,假设我们自定义加密id(由数字或者a-f的字母组成,32-256长度)校验,主要分为两步:

  • 自定义约束注解

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EncryptIdValidator.class})
public @interface EncryptId {

    String message() default "加密id格式错误";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

  • 实现ConstraintValidator接口编写约束校验器

public class EncryptIdValidator implements ConstraintValidator<EncryptId, String> {

    private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {

        if (value != null) {
            Matcher matcher = PATTERN.matcher(value);
            return matcher.find();
        }
        return true;
    }
}

这样我们就可以使用@EncryptId进行参数校验了!

5、编程式校验

上面的示例都是基于注解来实现自动校验的,在某些情况下,我们可能希望以编程方式调用验证。这个时候可以注入javax.validation.Validator对象,然后再调用其api

@Autowired
private javax.validation.Validator globalValidator;

@PostMapping("/saveWithCodingValidate")
public Result saveWithCodingValidate(@RequestBody UserDTO userDTO) {
    Set<ConstraintViolation<UserDTO>> validate = globalValidator.validate(userDTO, UserDTO.Save.class);

    if (validate.isEmpty()) {

    } else {
        for (ConstraintViolation<UserDTO> userDTOConstraintViolation : validate) {

            System.out.println(userDTOConstraintViolation);
        }
    }
    return Result.ok();
}

6、快速失败 (Fail Fast)

Spring Validation默认会校验完所有字段,然后才抛出异常。可以通过一些简单的配置,开启Fali Fast模式,一旦校验失败就立即返回。

@Bean
public Validator validator() {
    ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
            .configure()

            .failFast(true)
            .buildValidatorFactory();
    return validatorFactory.getValidator();
}

7、@Valid@Validated区别

区别 @Valid @Validated
提供者 JSR-303 规范 Spring
是否支持分组 不支持 支持
标注位置 METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE TYPE, METHOD, PARAMETER
嵌套校验 支持 不支持

3、实现原理

1、requestBody参数校验实现原理

spring-mvc中,RequestResponseBodyMethodProcessor是用于解析@RequestBody标注的参数以及处理@ResponseBody标注方法的返回值的。显然,执行参数校验的逻辑肯定就在解析参数的方法resolveArgument()中:

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

        parameter = parameter.nestedIfOptional();

        Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
        String name = Conventions.getVariableNameForParameter(parameter);

        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {

                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
            if (mavContainer != null) {
                mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
            }
        }
        return adaptArgumentIfNecessary(arg, parameter);
    }
}

可以看到,resolveArgument()调用了validateIfApplicable()进行参数校验。

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {

    Annotation[] annotations = parameter.getParameterAnnotations();
    for (Annotation ann : annotations) {

        Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);

        if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
            Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
            Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});

            binder.validate(validationHints);
            break;
        }
    }
}

看到这里,大家应该能明白为什么这种场景下@Validated@Valid两个注解可以混用。我们接下来继续看WebDataBinder.validate()实现。

@Override
public void validate(Object target, Errors errors, Object... validationHints) {
    if (this.targetValidator != null) {
        processConstraintViolations(

            this.targetValidator.validate(target, asValidationGroups(validationHints)), errors);
    }
}

最终发现底层最终还是调用了Hibernate Validator进行真正的校验处理。

2、方法级别的参数校验实现原理

上面提到的将参数一个个平铺到方法参数中,然后在每个参数前面声明约束注解的校验方式,就是方法级别的参数校验。实际上,这种方式可用于任何Spring Bean的方法上,比如Controller/Service等。其底层实现原理就是AOP,具体来说是通过MethodValidationPostProcessor动态注册AOP切面,然后使用MethodValidationInterceptor对切点方法织入增强

public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean {
    @Override
    public 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());
    }
}

接着看一下MethodValidationInterceptor

public class MethodValidationInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
            return invocation.proceed();
        }

        Class<?>[] groups = determineValidationGroups(invocation);
        ExecutableValidator 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) {
            ...
        }

        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;
    }
}

实际上,不管是requestBody参数校验还是方法级别的校验,最终都是调用Hibernate Validator执行校验,Spring Validation只是做了一层封装

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot 实现各种参数校验 的相关文章

  • 指纹奇异点检测

    我正在尝试确定指纹的核心点和增量点 我正在使用庞加莱指数方法 但我无法成功检测到这一点 而且我不明白为什么 First I divide the image in 15x15 blocks then I calculate the x an
  • 重构——套接字中的良好实践——简单的服务器-客户端 Swing 应用程序

    我使用单例和观察者模式编写了一个带有 Swing 接口的简单服务器 客户端程序 每个客户端都连接到服务器并可以发送消息 服务器将其收到的消息转发给其余的客户端 客户端使用 GUI 允许它们随时连接和断开与服务器的连接 该程序运行得很好 因为
  • 如何使用 Java 创建多个模式连接?

    我必须使用两个数据库 DB2 Oracle 我在 DB2 数据库中有一个名为NAVID 我想使用 Java 为 Oracle 中的所有表创建相同的架构 public class automateExport static String va
  • 启动时修改@RequestMappings

    是否可以更改 RequestMapping启动时的值 基本上我想要的是创建一个注释 Api Api Version V1 这意味着请求映射应该修改为 api dogs to api v1 dogs 我想在类级别 适用于所有 和方法级别 重新
  • 使用 JAXB 编组 LocalDate

    我正在构建一系列链接类 我希望能够将其实例编组到 XML 以便我可以将它们保存到文件中并稍后再次读取它们 目前我使用以下代码作为测试用例 import javax xml bind annotation import javax xml b
  • 带有面板的 Java Swing JToolbar:外观和感觉

    我有一个JToolbar其中包含多个JPanels 需要 因为我希望每个都有特定的边界 不幸的是 外观管理器无法识别JPanels属于工具栏和JButtons因此 渲染器与普通按钮一样 即没有工具栏上的特殊鼠标悬停效果 更换JPanels
  • 如何在命令提示符中检查 JAVA_OPTS 值?

    我们的应用程序部署 JBoss 服务器然后抛出错误 PermGen space 然后在 jboss bat 和配置文件中设置 permgen 变量中的 java OPTS JAVA OPTs 中是否有值 assige 如何检查 如何在命令提
  • 更改 RowLayout SWT Java 中元素的顺序

    有没有办法更改在行布局中创建的元素的顺序 我想将其显示在元素中 首先显示 例如 如果我创建 element1 则 element2 element3 element4 我想看到的布局为 元素4 元素3 元素2 元素1 这意味着最后创建的元素
  • XSLT:我们可以使用abs值吗?

    我想知道在 XSLT 中我们是否可以使用 math abs 我在某处看到过这个 但它不起作用 我有类似的东西
  • C++ 中的 Java ArrayList [重复]

    这个问题在这里已经有答案了 在Java中我可以做 List
  • 在 netBeans 中运行程序时,字体看起来非常奇怪

    我在我的新 MacBook M1 上设置了 netBeans 和 SceneBuilder 除了运行程序时的字体外 一切正常 它看起来像这样 我不知道为什么 按钮应显示 Click me 标签应显示 Hello 我收到的错误消息是 M rz
  • 在方法内声明类 - Final 关键字 [重复]

    这个问题在这里已经有答案了 给定方法中的以下内部类 IsSomething public class InnerMethod private int x public class Something private int y public
  • Java 8根据Map属性过滤Map对象列表以删除一些重复项

    Have a List
  • 无法在 BlackBerry Playbook 上设置音量

    我在更改黑莓游戏书的音量时遇到问题 首先 我将 Android 应用程序重新打包到 Palybook 应用程序 我需要使用搜索栏更改黑莓剧本的音量 并在搜索监听器中设置音频管理器音量 这是代码 audioManager AudioManag
  • JPA - 非主键字段上的 @OneToOne 关系不起作用

    我有一个 Spring Data JPA 后端 使用 Hibernate 作为 ORM 实现 这是模型 Person MailConfig id PK uid PK FK Person uid uid Entity
  • java数据结构模拟数据树

    我需要帮助定义使用什么方法 我有一个 SOAP 响应 给我一个 xml 文件 我需要在屏幕上显示 3 个相关列表 当您在第一个列表中选择一个项目时 相应的选择将出现在第二个列表中 依此类推 我只对从 xml 流中提取数据后如何有效地组织数据
  • 条件查询:按计数排序

    我正在尝试执行一个标准查询 该查询返回 stackoverflow 中回答最多的问题 例如常见问题解答 一个问题包含多个答案 我正在尝试使用标准查询返回按每个问题的答案数排序的回答最多的问题 任何人都知道我应该在 hibernate cri
  • C/C++ 通过 Android NDK 在 JNI 中看不到 Java 方法

    我正在尝试从使用 NDK 构建的 C 类文件调用 Java 方法 它不断抛出常见的 未找到非静态方法 错误并导致整个 Android 应用程序崩溃 下面的代码片段 有些东西可能不需要 但我按原样保留它们 因为焦点 问题在于refreshJN
  • 在多线程环境中,Collections.sort 方法有时会抛出 ConcurrentModificationException。列表没有进行结构性修改

    package CollectionsTS import java util ArrayList import java util Collections import java util HashSet import java util
  • RecyclerView 不调用 onCreateViewHolder 或 onBindView

    没有收到任何错误 所有数据似乎都有效 由于某种原因 没有调用与视图相关的方法 我已确定以下事项 getItemCount 是唯一被调用的适配器方法 并且返回一个正整数值 我知道这将是你们将要查看的区域 构造函数正在被调用 成员变量有效 Pa

随机推荐

  • Java实验报告(四)

    文章目录 题目一 题目二 题目三 题目四 题目五 题目六 题目七 题目一 一 程序一 源程序 public class Leaf int i 0 Leaf increment i return this void print System
  • 除了敲代码,程序员还能有什么副业?晓健韩品批发

    积极发展副业中 做韩妆一般贸易进口 跟集装箱通关的 仓库在山东烟台莱山区 做的比较大 价格方面有优势 有需要 可以私聊哈 正品是本分 xiaojian675050734 H19950211H
  • composer 中国镜像

    我的个人博客 逐步前行STEP 使用以下代码将packagist源更换为中国镜像 composer config g repo packagist composer https packagist phpcomposer com 或者 co
  • 【满分】【华为OD机试真题2023 JAVA&JS】不爱施肥的小布

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 不爱施肥的小布 知识点二分查找 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 某农场主管理了一大片果园 fields i 表示不同果林的面积 单位 m 2 现在
  • targetElement.closest

    在组件挂载时 给 document 添加点击事件监听 onMounted gt document addEventListener click closeIdentity 点击事件处理函数 用于改变 isExpanded 的值为 false
  • Lock wait timeout exceeded; try restarting transaction

    2016 08 05 09 21 52 com zhishi common controller BaseController ERROR Error updating database Cause com mysql jdbc excep
  • 教师怎样将成绩单独发送给学生和家长?

    在工作学习中 我们经常会遇到怎样将成绩单独发送给学生和家长这样的问题 因此 面对怎样将成绩单独发送给学生和家长我们应该有努力探索的精神 诚挚的心灵 是学生情感的钥匙 高尚的师德 是学生心灵的明镜 对于这个问题也是一样的 读书忌死读 死读钻牛
  • redhat7.6安装weblogic12c

    目录 一 环境准备 二 使用root创建用户和组 三 创建部署目录 四 上传安装包 五 创建 oraInst loc 文件 六 创建wls rsp 响应文件 七 进行安装 八 使用 wlst sh 离线模式创建一个域 九 启动服务 十 浏览
  • 电脑wps可以语音录入吗_怎样用word进行语音录入文字

    怎样用 word 进行语音录入文字 有时候我们不方便手敲键盘输入时 可以利用 word 的语音录入功能进行输入 以下是学习啦小编为您带来的关于用 Word 进行语音录入文字 希望对您有所帮助 用 Word 进行语音录入文字 语音输入功能添加
  • 最适合程序猿的笔记软件

    因为这几天小编要去听课 所以心血来潮找了几个适合程序猿的笔记软件 经过几天在csdn上的扒饭之后 我结合自己的某些要求 为大家整理出了这几个软件 有需要直接去后面找 一 必须支持markdown markdown的重要性不需要在这里多说了吧
  • TypeScript 联合类型(union type)

    TS是JS的超集 在JS的基础上添加了一套类型系统 这样的TS可以被静态分析带来的好处显而易见 let val string val 声明一个string类型的变量val let val string val val 1 Type numb
  • hive异常MetaException-Metastore contains multiple versions

    在执行hive运行脚本时 出现了MetaException Metastore contains multiple versions异常错误 Exception in thread main java lang RuntimeExcepti
  • Java 手动分页

    功能需求背景 今天负责短信后台定时任务时 需要定时向用户发送短信信息 但数据库记录的待发送记录数量比较大 无法一次查询出结果 需要手动分页 手动分页核心功能代码 Date now DateUtils getBeforeMouth new D
  • Arduino基本知识

    analogWrite 将一个模拟数值写进Arduino引脚 这个操作可以用来控制LED的亮度 或者控制电机的转速 Arduino每一次对引脚执行analogWrite 指令 都会给该引脚一个固定频率的PWM信号 digitalRead 读
  • 基于FPGA的图像采集之二 GEN_FRAME(成帧)模块

    距离上次的博客已经有段时间了 这写些日子一直在调SDRAM的模块以及文档的书写 SDRAM的子模块比较多 包括init 初始化模块 refresh 刷新模块 write 写模块 read 读模块 使用起来相比之前的USB控制模块 今天的GE
  • JAVA中队列,数据结构队列入队操作

    java中构造函数和构造方法的区别 Java中什么是构造函数 构造函数和普通函数的区别如下 1 写法上的不同 施工方法 Public modifier class 定义类的关键字 Test 类名 没有参数 测试 类名 接受一个参数 测试 类
  • 使用Visual Studio写一个简单的Windows窗体应用登录界面

    需要的知识 C 的基本语法 以及Visual Studio的基本操作方法 编辑软件 Sql Server 2017 Visual Studio 2017 前提 Sql Server 中有一个名为 MY LAPTOP 的服务器 一个名为 Te
  • 初学(9)——Hadoop错误:ssh: Could not resolve hostname master: Name or service not known

    进行ssh访问时出现错误 ssh Could not resolve hostname master Name or service not known 解决方法 修改hosts文件 将名称和IP建立联系 1 打开 etc目录下hosts文
  • 深入理解Go——context(2)

    文章目录 结构体 emptyCtx cancleCtx timerCtx valueCtx 结构体 emptyCtx 源码中定义了 Context 接口后 并且给出了一个实现 type emptyCtx int func emptyCtx
  • Spring Boot 实现各种参数校验

    目录 1 简单使用 1 引入依赖 2 requestBody参数校验 3 requestParam PathVariable参数校验 4 统一异常处理 2 进阶使用 1 分组校验 2 嵌套校验 3 集合校验 4 自定义校验 5 编程式校验