首页 > 其他分享 >@RequestBody接收Json参数 用自定义注解对Vo对象中Date类型日期格式校验

@RequestBody接收Json参数 用自定义注解对Vo对象中Date类型日期格式校验

时间:2023-11-07 23:34:00浏览次数:34  
标签:return String 自定义 request Vo RequestBody json 注解 import

@RequestBody接收Json参数 | 用自定义注解对Vo对象中Date类型日期格式校验

问题描述

昨天测试的同事测试接口的时候,测试出来一个Date类型校验问题。

要求输入的日期格式是:yyyy-MM-dd HH:mm:ss,Vo中使用的注解如下:

@DateTimeFormat(pattern=”yyyy-MM-dd HH:mm:ss”)

测试同事输入下面两种参数都是保存成功,当输入为“202105”参数时,保存的数据变为“1970-01-01 08:03:22”,由此发现这个问题。

常用的三种日期格式化的注解解释如下:

//入参格式化注解

@DateTimeFormat(pattern=”yyyy-MM-dd HH:mm:ss”)

//出餐格式化注解

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

@JSONField(format = "yyyy-MM-dd HH:mm:ss") //建议这种

由于@RequestBody注解先将json字符串转换成对应的Vo对象,Vo对象中的字段上添加的注解再生效,@DateTimeFormat只是做格式化,无法做格式校验。

解决方案

用自定义注解进行json字符串中的日期格式做校验。

解决思路:

1.从request对象中获取原始json字符串入参。由于自定义注解接口ConstraintValidator的实现获取到的参数值是@RequestBody注解将json字符串参数解析成Vo对象后的Date对象,不是原始json字符串值,所以需要从request中获取json原始参数值;

2.获取到json入参原始值使用正则表达式对日期进行格式进行校验。

温馨提示:

1.由于自定义注解中是无法直接获取到request对象,所以需要按照各自框架获取request对象的方式进行获取。

2.获取到的原始json字符串入参可能包含空格、回车、换行符、制表符这些特殊字符,所以需要进行特殊字符处理。

3.获取Vo对象中添加注解的属性名。

详细见:getFieldName(ConstraintValidatorContext context)即:【((ConstraintValidatorContextImpl) context).basePath.currentLeafNode.name】

代码实现

SearchTaskVo.java

/**

  • 任务结束时间

import javax.validation.Constraint;

import javax.validation.Payload;

import java.lang.annotation.*;

/**

  • 说明:日期格式校验

  • @Author Wanghx
  • @Date 2021/5/11 10:16
  • @Version 1.0

**/

@Target({ElementType.FIELD, ElementType.PARAMETER})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Constraint(validatedBy = {DateFormatValidator.class})

public @interface DateFormatValidation {

//验证失败错误提示信息,使用注解时没有设置错误信息则默认使用信息

String message() default "格式错误";

//验证格式的规则,使用注解时没有设置验证格式规则则默认使用下面的格式

String format() default "yyyy-MM-dd";

//分组验证

Class[] groups() default {};

Class[] payload() default {};

}

DateFormatValidator.java

import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;

import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintViolationCreationContext;

import org.hibernate.validator.internal.engine.path.NodeImpl;

import org.hibernate.validator.internal.engine.path.PathImpl;

import javax.servlet.http.HttpServletRequest;

import javax.validation.ConstraintValidator;

import javax.validation.ConstraintValidatorContext;

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.*;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/**

  • 说明:日期格式校验

  • @Author Wanghx
  • @Date 2021/4/30 10:17
  • @Version 1.0

**/

public class DateFormatValidator extends BaseRestService implements ConstraintValidator {

private DateFormatValidation dateFormatValidation;

@Override

public void initialize(DateFormatValidation constraintAnnotation) {

this.dateFormatValidation = constraintAnnotation;

}

@Override

public boolean isValid(Date value, ConstraintValidatorContext context) {

//如果 value 为空则不进行格式验证,为空验证可以使用 @NotBlank @NotNull @NotEmpty 等注解来进行控制,职责分离

if (value == null) {

return true;

}

//获取规定的格式

String format = dateFormatValidation.format();

//验证日期的格式是否正确 try { //获取原始json参数值 String originalValue = getOriginalValueByFieldName(getFieldName(context)); //用长度进行比较 if (ValidateUtil.isNotEmpty(originalValue) && originalValue.length() != format.length()) { return false; } //校验字符串日期格式 if (!verifyFormatDateStr(originalValue, format)) { return false; } //用日期格式化验证 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); simpleDateFormat.format(value); } catch (Exception e) { return false; } return true;

}

/**

  • 校验字符串日期格式

  • @param dateStr
  • @param format
  • @return

/**

  • 获取日期格式的正则表达式,根据具体业务需要可新增

  • @return

*/

private Map getAllDateFormat() {

String yyyy = "((1|2)[0-9]{3})";

String MM = "(0[1-9]|1[012])";

String dd = "(0[1-9]|[12][0-9]|3[01])";

String HH = "((0|1)[0-9]|2[0-3])";

String mm = "([0-5][0-9])";

String ss = "([0-5][0-9])";

Map();

resultMap.put(DatePattern.PATTEN_DATETIME, yyyy + "-" + MM + "-" + dd + " " + HH + ":" + mm + ":" + ss);

resultMap.put(DatePattern.PATTEN_DATETIME_SERIAL, yyyy + MM + dd + HH + mm + ss);

resultMap.put(DatePattern.PATTEN_DATE, yyyy + "-" + MM + "-" + dd);

resultMap.put(DatePattern.PATTEN_DATE_yyyyMMdd, yyyy + MM + dd);

return resultMap;

}

/**

  • 获取添加注解的字段名称

  • @param context
  • @return

*/

private String getFieldName(ConstraintValidatorContext context) {

String fieldName = "";

if (context != null) {

List constraintViolationCreationContexts = ((ConstraintValidatorContextImpl) context).getConstraintViolationCreationContexts();

if (ValidateUtil.isNotEmpty(constraintViolationCreationContexts)) {

ConstraintViolationCreationContext constraintViolationCreationContext = constraintViolationCreationContexts.get(0);

PathImpl path = constraintViolationCreationContext.getPath();

if (path != null) {

NodeImpl node = path.makeLeafNodeIterable();

if (node != null) {

fieldName = node.getName();

}

}

}

}

return fieldName;

}

/**

  • 根据字段名称获取json原始值

  • @param fieldName
  • @return/ private String getOriginalValueByFieldName(String fieldName) throws Exception { String resultStr = "";//结果值 if (!StringUtil.isBlank(fieldName)) { //获取request对象,【注:根据各自项目获取request对象即可】 HttpServletRequest request = getRequest(); //获取json参数原始值,并封装到Map集合中 Map(); if (request != null) { //未清洗的json原始值 String reqPostStr = getRequestPostStr(request); //清洗json原始值 if (!StringUtil.isBlank(reqPostStr)) { reqPostStr = reqPostStr.substring(reqPostStr.indexOf("{"), reqPostStr.indexOf("}")); //去除字符串中的空格、回车、换行符、制表符这些特殊字符 Pattern p = Pattern.compile("\s
  • 获取 post 请求的 byte[] 数组

  • @param request
  • @return
  • @throws IOException/ private static byte[] getRequestPostBytes(HttpServletRequest request) throws IOException { int contentLength = request.getContentLength(); if (contentLength < 0) { return null; } byte buffer[] = new byte[contentLength]; for (int i = 0; i < contentLength; ) { int readlen = request.getInputStream().read(buffer, i, contentLength - i); if (readlen == -1) { break; } i += readlen; } return buffer; } /

/**

* 获取 post 请求内容

*

* @param request

* @return

* @throws IOException

*/

private static String getRequestPostStr(HttpServletRequest request)

throws IOException {

byte buffer[] = getRequestPostBytes(request);

String charEncoding = request.getCharacterEncoding();

if (charEncoding == null) {

charEncoding = "UTF-8";

}

return new String(buffer, charEncoding);

}

}

标签:return,String,自定义,request,Vo,RequestBody,json,注解,import
From: https://blog.51cto.com/u_16271212/8240513

相关文章

  • 让自定义的容器,也能基于范围循环
      C++11起,引入了基于范围的for循环这一特性,有什么好处呢?它有时可以大大地简化遍历容器的操作,比如说STL的vector。std::vectorv{1,2,3};std::vector<int>::iteratorit=begin(v);for(;it!=end(v);++it)std::cout<<*it<<'\n';  这是使用了迭代器的写法,......
  • 混合云中 DevOps 的最佳实践
    近年来,出现了各种工具、技术和框架,其目标是增强灵活性、性能和可扩展性。传统的整体方法已被微服务和纳米服务等更加模块化的方法所取代。此外,云计算的兴起导致本地软件被云环境所取代,云环境提供了以前无法提供的广泛优势和功能。能够通过适应云设置来优化速度和效率是一项至关重要......
  • 通过计算巢轻松部署ROS自定义资源
    概述阿里云资源编排服务ROS(ResourceOrchestrationService)可以帮助您简化云计算资源的管理。遵循ROS定义的模板规范,您可以定义所需云计算资源的集合及资源间的依赖关系。ROS可以自动完成所有资源的创建和配置,实现自动化部署和运维。ROS不仅能够编排阿里云资源,还支持自定义资源......
  • byte[]、list<byte>数组类型的几个自定义扩展方法
    byte[]、list<byte>数组类型的几个自定义扩展方法。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;namespaceiPublic.类型扩展方法{///<summary>///类型的扩展方法,用起来方便的///修改记录:///20230415,海......
  • bitsdojo_window自定义导航以及关闭按钮
    1、Windows里面的配置在应用程序文件夹中,转到windows\runner\main.cpp,并在文件开头添加以下两行:#include<bitsdojo_window_windows/bitsdojo_window_plugin.h>autobdw=bitsdojo_window_configure(BDW_CUSTOM_FRAME|BDW_HIDE_ON_STARTUP);2、macOS里面的配置1、在应用程......
  • 界面组件Telerik UI for WinForms中文教程 - 如何自定义应用程序文件窗口?
    TelerikUIforWinForms包含了一个高度可定制的组件,它取代了.NET中默认的OpenFileDialog。在下一个更新版本中,会发布一个向对话框浏览器提那家自定义位置的请求功能,本文演示了这个和另一个自定义功能,它可以帮助用户在浏览文件夹时快速选择最后修改的文件,自定义将根据最近的日期/......
  • Linux Vim批量注释和自定义注释
    使用Vim编辑Shell脚本,在进行调试时,需要进行多行的注释,每次都要先切换到输入模式,在行首输入注释符"#"再退回命令模式,非常麻烦。连续行的注释其实可以用替换命令来完成。换句话说,在指定范围行加"#"注释,可以使用":起始行,终止行s/^/#/g",例如::1,10s/^/#/g表示在第1~10行行首加"#......
  • 无涯教程-批处理 - VOL函数
    此批处理命令显示卷标。VOL-语法VOLVOL-示例@echooffVOL输出将显示当前音量标签。如,VolumeindriveCisWindows8_OSVolumeSerialNumberisE41C-6F43参考链接https://www.learnfk.com/batch-script/batch-script-vol.html......
  • 通过mybatis-plus的自定义拦截器实现控制 mybatis-plus的全局逻辑删除字段的控制 (修改
    需求:过滤部分请求不实现mybatis-plus的逻辑删除看到网上关于mybatis-plus的自定义拦截器的文章有的少想了想自己写了一篇欢迎参考指正通过springboot的拦截器在请求进来时标记需要实现的需求的逻辑importlombok.Data;@DatapublicclassSyncBo{privateBoolean......
  • java中的重排序和volatile关键字
    一、内存模型基础1、内存模型描述的是程序中各变量(线程共享变量)的访问规则,以及在实际计算机系统中将变量存储到内存和从内存读取出变量这样的低层细节。2、Jvm系统中存在一个主内存(MainMemory或JavaHeapMemory),Java中所有变量都储存在主存中,对于所有线程都是共享的。3、每......