问题
I have this piece of code:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
protected Date statusDate;
But for somehow it accepts date formats like -
"statusDate": "2017-13-27"
or
"statusDate": "201823-12-12"
Is it possible to validate the format within the request (not manually)?
回答1:
Well, you need to write a custom date serialisation/de-serialisation class and throw a custom exception if the date format you receive while intercepting the data is not what you'd expected.
This answer will point you in the right direction of how to do so.
Also you can have the validator in your code to validate the payload and leave Jackson to it's simple state.
回答2:
@JsonFormat is used to set the output format when you're returning the statusDate as response.
It is better you create a DTO object that will accept String statusDate and then convert it to Date format in your controller.
To validate the date in String format, you can use @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();
}
回答3:
Yes, you can. Let me show u the details.
First, pls create a base controller to filter all the requests like below:
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;
}
}
From above code, the BindingResult will check the @JsonFormat or other components header, like @NotBlank, @Pattern and so on. If they hit the rule, they will be caught by the BindingResult and we can get the error. Below is the DTO object I used, just show it to u so that you can get more details:
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;
}
}
Then in our business logic controller, we need to extend the base controller and write the codes like below:
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);
}
}
}
By using above method, you can validate the field easily within the request. It's a beautiful way to achive this.
Hope that helps.
EDIT:
Replace the images with real codes so that anyone needs to test it.
来源:https://stackoverflow.com/questions/47967641/java-how-to-make-json-date-validation