Java - 如何进行 JSON 日期验证?
Java - How to make JSON date validation?
我有这段代码:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
protected Date statusDate;
但不知何故它接受日期格式,如 -
"statusDate": "2017-13-27"
或
"statusDate": "201823-12-12"
是否可以在请求中验证格式(非手动)?
好吧,您需要编写一个自定义日期 serialisation/de-serialisation class,如果您在拦截数据时收到的日期格式不是您预期的格式,则抛出一个自定义异常。
This 答案将为您指明正确的操作方向。
您也可以在您的代码中使用验证器来验证有效负载并让 Jackson 保持简单状态。
是的,你可以。让我告诉你细节。
首先,请创建一个基本控制器来过滤所有请求,如下所示:
package com.letv.address.controller;
import com.letv.address.utils.ConstantCode;
import com.letv.address.utils.ResponseWrapper;
import com.letv.xice.core.controller.GlobalController;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import java.util.ArrayList;
import java.util.List;
/**
* Created by shichaoyang on 2017/1/10.
*/
public class BaseController extends GlobalController {
public ResponseWrapper requestCheckAndPost(BindingResult result) {
if (result.hasErrors()) {
List<Object> errorList = new ArrayList<>();
StringBuilder sBuilder = new StringBuilder();
for (ObjectError error : result.getAllErrors()) {
String fieldName = ((FieldError) error).getField();
String fieldMessage = error.getDefaultMessage();
sBuilder.append(fieldName)
.append(" ")
.append(getMessage(fieldMessage))
.append(";");
errorList.add(fieldName);
}
return new ResponseWrapper(
ConstantCode.FAILING_WITH_ERROR_PARAM_CODE
, errorList.toArray()
, ""
, sBuilder.toString()
);
}
return null;
}
}
从上面的代码来看,BindingResult 将检查@JsonFormat 或其他组件header,如@NotBlank、@Pattern 等。如果他们符合规则,他们将被 BindingResult 捕获,我们可以得到错误。下面是我用过的DTO object,给你看看,这样你就可以得到更多的细节:
package com.letv.address.controller.dto;
import com.letv.address.utils.ConstantCode;
import org.hibernate.validator.constraints.NotBlank;
/**
* Created by shichaoyang on 2016/12/23.
*/
public class ChildrenAreaSelectRequest{
@NotBlank(message = ConstantCode.REQUEST_VALIDATE_NOT_EMPTY)
private String areaIds;
public String getAreaIds() {
return areaIds;
}
public void setAreaIds(String areaIds) {
this.areaIds = areaIds;
}
}
然后在我们的业务逻辑控制器中,我们需要扩展基础控制器并编写如下代码:
package com.letv.address.controller;
import com.letv.address.controller.dto.ChildrenAreaSelectRequest;
import com.letv.address.controller.dto.ParentAreaSelectReqeust;
import com.letv.address.domain.Area;
import com.letv.address.service.ChildAreaService;
import com.letv.address.utils.ConstantCode;
import com.letv.address.utils.ResponseWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
/**
* Created by shichaoyang on 2016/12/12.
*/
@RestController("areaController")
public class AreaController extends BaseController {
@Autowired
protected ChildAreaService childAreaService;
/**
* get area info by parent id
*
* @param areaReqeust
* @param result
*/
@ResponseBody
@RequestMapping(value = ConstantCode.CHILD_AREA_PATH, method = {RequestMethod.POST})
public ResponseWrapper childArea(@RequestBody @Valid ParentAreaSelectReqeust areaReqeust, BindingResult result) {
ResponseWrapper validationWrapper = requestCheckAndPost(result);
if (validationWrapper != null) {
return validationWrapper;
}
List<Area> areaList = childAreaService.selectByParentId(areaReqeust.getParentId());
if (areaList == null || areaList.size() == 0) {
return new ResponseWrapper(ConstantCode.SUCCESS_WITH_EMPTY_DATA_CODE, new ArrayList<>());
} else {
return new ResponseWrapper(ConstantCode.SUCCESS_WITH_FILL_DATA_CODE, areaList);
}
}
}
通过使用上述方法,您可以轻松验证请求中的字段。这是实现这一目标的绝妙方式。
希望对您有所帮助。
编辑:
图片替换为真实代码,方便大家测试。
@JsonFormat 用于设置返回 statusDate 作为响应时的输出格式。
最好创建一个接受字符串 statusDate 的 DTO 对象,然后在控制器中将其转换为日期格式。
要验证字符串格式的日期,您可以使用@Pattern
public class StatusDateDto {
@NotNull(message="Status date is a required field")
@Pattern(regexp = "^\d{4}-\d{2}-\d{2}", message="Invalid status date")
private String statusDate;
//Getter and setter
}
public ResponseEntity<?> postStatusDate(@Valid @RequestBody StatusDateDto dateDto, BindingResult result) {
if (result.hasFieldErrors()) {
String errors = result.getFieldErrors().stream()
.map(p -> p.getDefaultMessage()).collect(Collectors.joining("\n"));
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
// Convert the String to Date after validation
return ResponseEntity.ok().build();
}
我有这段代码:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
protected Date statusDate;
但不知何故它接受日期格式,如 -
"statusDate": "2017-13-27"
或
"statusDate": "201823-12-12"
是否可以在请求中验证格式(非手动)?
好吧,您需要编写一个自定义日期 serialisation/de-serialisation class,如果您在拦截数据时收到的日期格式不是您预期的格式,则抛出一个自定义异常。
This 答案将为您指明正确的操作方向。
您也可以在您的代码中使用验证器来验证有效负载并让 Jackson 保持简单状态。
是的,你可以。让我告诉你细节。
首先,请创建一个基本控制器来过滤所有请求,如下所示:
package com.letv.address.controller;
import com.letv.address.utils.ConstantCode;
import com.letv.address.utils.ResponseWrapper;
import com.letv.xice.core.controller.GlobalController;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import java.util.ArrayList;
import java.util.List;
/**
* Created by shichaoyang on 2017/1/10.
*/
public class BaseController extends GlobalController {
public ResponseWrapper requestCheckAndPost(BindingResult result) {
if (result.hasErrors()) {
List<Object> errorList = new ArrayList<>();
StringBuilder sBuilder = new StringBuilder();
for (ObjectError error : result.getAllErrors()) {
String fieldName = ((FieldError) error).getField();
String fieldMessage = error.getDefaultMessage();
sBuilder.append(fieldName)
.append(" ")
.append(getMessage(fieldMessage))
.append(";");
errorList.add(fieldName);
}
return new ResponseWrapper(
ConstantCode.FAILING_WITH_ERROR_PARAM_CODE
, errorList.toArray()
, ""
, sBuilder.toString()
);
}
return null;
}
}
从上面的代码来看,BindingResult 将检查@JsonFormat 或其他组件header,如@NotBlank、@Pattern 等。如果他们符合规则,他们将被 BindingResult 捕获,我们可以得到错误。下面是我用过的DTO object,给你看看,这样你就可以得到更多的细节:
package com.letv.address.controller.dto;
import com.letv.address.utils.ConstantCode;
import org.hibernate.validator.constraints.NotBlank;
/**
* Created by shichaoyang on 2016/12/23.
*/
public class ChildrenAreaSelectRequest{
@NotBlank(message = ConstantCode.REQUEST_VALIDATE_NOT_EMPTY)
private String areaIds;
public String getAreaIds() {
return areaIds;
}
public void setAreaIds(String areaIds) {
this.areaIds = areaIds;
}
}
然后在我们的业务逻辑控制器中,我们需要扩展基础控制器并编写如下代码:
package com.letv.address.controller;
import com.letv.address.controller.dto.ChildrenAreaSelectRequest;
import com.letv.address.controller.dto.ParentAreaSelectReqeust;
import com.letv.address.domain.Area;
import com.letv.address.service.ChildAreaService;
import com.letv.address.utils.ConstantCode;
import com.letv.address.utils.ResponseWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
/**
* Created by shichaoyang on 2016/12/12.
*/
@RestController("areaController")
public class AreaController extends BaseController {
@Autowired
protected ChildAreaService childAreaService;
/**
* get area info by parent id
*
* @param areaReqeust
* @param result
*/
@ResponseBody
@RequestMapping(value = ConstantCode.CHILD_AREA_PATH, method = {RequestMethod.POST})
public ResponseWrapper childArea(@RequestBody @Valid ParentAreaSelectReqeust areaReqeust, BindingResult result) {
ResponseWrapper validationWrapper = requestCheckAndPost(result);
if (validationWrapper != null) {
return validationWrapper;
}
List<Area> areaList = childAreaService.selectByParentId(areaReqeust.getParentId());
if (areaList == null || areaList.size() == 0) {
return new ResponseWrapper(ConstantCode.SUCCESS_WITH_EMPTY_DATA_CODE, new ArrayList<>());
} else {
return new ResponseWrapper(ConstantCode.SUCCESS_WITH_FILL_DATA_CODE, areaList);
}
}
}
通过使用上述方法,您可以轻松验证请求中的字段。这是实现这一目标的绝妙方式。
希望对您有所帮助。
编辑:
图片替换为真实代码,方便大家测试。
@JsonFormat 用于设置返回 statusDate 作为响应时的输出格式。
最好创建一个接受字符串 statusDate 的 DTO 对象,然后在控制器中将其转换为日期格式。
要验证字符串格式的日期,您可以使用@Pattern
public class StatusDateDto {
@NotNull(message="Status date is a required field")
@Pattern(regexp = "^\d{4}-\d{2}-\d{2}", message="Invalid status date")
private String statusDate;
//Getter and setter
}
public ResponseEntity<?> postStatusDate(@Valid @RequestBody StatusDateDto dateDto, BindingResult result) {
if (result.hasFieldErrors()) {
String errors = result.getFieldErrors().stream()
.map(p -> p.getDefaultMessage()).collect(Collectors.joining("\n"));
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
// Convert the String to Date after validation
return ResponseEntity.ok().build();
}