Spring REST API 为 pojo 注册日期转换器
Spring REST API register date converter for pojo
Spring rest 默认从路径变量和 url 参数提供构建 pojo 功能。
就我而言,我有 pojo:
public class MyCriteria {
private String from;
private String till;
private Long communityNumber;
private String communityName;
}
在我的控制器中使用。 Url 是 http://localhost:8080/community/{communityNumber}/app
。
的请求结果
curl "http://localhost:8080/community/1/app?from=2018-11-14&till=2019-05-13&communityName=myCOm"
是:
{
'from':'2018-11-14';
'till':'2019-05-12';
'communityNumber':'1';
'communityName':'myCOm'
}
看起来效果不错。按目的使用所需类型的 pojo 数据要好得多。所以我想要 LocalDate
类型的 from
和 till
字段。使用 spring 我希望这个解决方案几乎 开箱即用 。但是由于生命周期的原因,任何 spring 或 jackson 日期转换器都无法解决我的问题。
Spring 在注入日期之前验证 pojo 字段的类型,我得到类型不匹配异常。我认为一般原因是 spring 使用了特殊的构建器,它试图按名称查找所需的参数,它忽略了要在 pojo 内部为字段应用的注释。
问题是:
对于spring构建pojo是否有任何优雅的解决方案,默认情况下某些字段将从String
格式转换为LocalDate
格式?
P.S.
强制条件是:
- 请求方式为
GET
;
- 所需的 pojo 是:
public class MyCriteria {
private LocalDate from;
private LocalDate till;
private Long communityNumber;
private String communityName;
}
- 让我们跳过自定义 AOP 实现或注入转换逻辑的
getter
s 的想法;
- 既没有主体(请求主体为空)也没有json(所有必需的数据都是路径变量或路径参数)。
P.S.2.
- 可用于实验的控制器示例为:
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import org.vl.example.rest.dtofromoaramsandpath.web.dto.MyCriteria;
import java.time.LocalDate;
@RestController
@RequestMapping("verify/criteria/mapping")
@Slf4j
public class MyController {
@GetMapping("community/{communityNumber}/dto")
public MyCriteria loadDataByDto(MyCriteria criteria) {
log.info("received criteria: {}", criteria);
return criteria;
}
@GetMapping("community/{communityNumber}/default/params")
public String loadDataByDefaultParameters(@PathVariable("communityNumber") String communityNumber,
@RequestParam(value = "from", required = false) String from,
@RequestParam(value = "till", required = false) String till,
@RequestParam(value = "communityName", required = false) String communityName) {
log.info("received data without converting:\n\tcommunityNumber => {}\n\tfrom => {}\n\ttill => {}\n\tcommunityName => {}",
communityNumber, from, till, communityName);
return new StringBuilder("{")
.append("\n\tfrom:").append(from).append(";")
.append("\n\tfrom:").append(from).append(";")
.append("\n\ttill:").append(till).append(";")
.append("\n\tcommunityName:").append(communityName)
.append("\n}\n").toString();
}
@GetMapping("community/{communityNumber}/converted/params")
public String loadUsingConvertedParameters(@PathVariable("communityNumber") String communityNumber,
@RequestParam(value = "from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
@RequestParam("till") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate till,
@RequestParam(value = "communityName", required = false) String communityName) {
log.info("received data with LocalDate converting:\n\tcommunityNumber => {}\n\tfrom => {}\n\ttill => {}\n\tcommunityName => {}",
communityNumber, from, till, communityName);
return new StringBuilder("{")
.append("\n\tfrom:").append(from).append(";")
.append("\n\tfrom:").append(from).append(";")
.append("\n\ttill:").append(till).append(";")
.append("\n\tcommunityName:").append(communityName)
.append("\n}\n").toString();
}
}
- 还有 link on github project,其中包含具有必需
controller
和 criteria
的模块,以使您的理解和实验更有用。
这可能对您有所帮助。我有类似的情况,我使用这种方法将数据转换为特定需求。
public class MyCriteria {
public MyCriteria(LocalDate from, LocalDate till, Long communityNumber, String communityName){
// assignement of variables
}
private LocalDate from;
private LocalDate till;
private Long communityNumber;
private String communityName;
}
所以每当您从 JSON 创建对象时,它都会根据要求创建它。
当我实现这个的时候,我使用了 "Jackson" 的 ObjectMapper class 来做这件事。希望你也一样。
在 pojo class 中使用 java.sql.Date .like private Date from。我希望它适用于 JSON 转换。当您从 UI 接收日期 JSON 字段时,请始终使用 Java.sql.Date 进行 Jackson 日期转换。
为此,您需要添加 jsr310 依赖项。
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.10")
我希望这对你有用。
问题的答案是使用 init binder 在指定条件内注册类型映射。需要 PropertyEditorSupport
实现特定目的。
短代码示例为:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ISO_LOCAL_DATE));
}
});
}
完整的代码示例可以从 github:
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.vl.example.rest.dtofromoaramsandpath.web.dto.MyCriteriaLd;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@RestController
@RequestMapping("verify/criteria/mapping")
@Slf4j
public class MyControllerLd {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ISO_LOCAL_DATE));
}
});
}
@GetMapping("community/{communityNumber}/dtold")
public MyCriteriaLd loadDataByDto(MyCriteriaLd criteria) {
log.info("received criteria: {}", criteria);
return criteria;
}
}
所以这个案例的模型可以是下一个:
import lombok.Data;
import java.time.LocalDate;
@Data
public class MyCriteriaLd {
private LocalDate from;
private LocalDate till;
private Long communityNumber;
private String communityName;
}
Spring rest 默认从路径变量和 url 参数提供构建 pojo 功能。
就我而言,我有 pojo:
public class MyCriteria {
private String from;
private String till;
private Long communityNumber;
private String communityName;
}
在我的控制器中使用。 Url 是 http://localhost:8080/community/{communityNumber}/app
。
curl "http://localhost:8080/community/1/app?from=2018-11-14&till=2019-05-13&communityName=myCOm"
是:
{
'from':'2018-11-14';
'till':'2019-05-12';
'communityNumber':'1';
'communityName':'myCOm'
}
看起来效果不错。按目的使用所需类型的 pojo 数据要好得多。所以我想要 LocalDate
类型的 from
和 till
字段。使用 spring 我希望这个解决方案几乎 开箱即用 。但是由于生命周期的原因,任何 spring 或 jackson 日期转换器都无法解决我的问题。
Spring 在注入日期之前验证 pojo 字段的类型,我得到类型不匹配异常。我认为一般原因是 spring 使用了特殊的构建器,它试图按名称查找所需的参数,它忽略了要在 pojo 内部为字段应用的注释。
问题是:
对于spring构建pojo是否有任何优雅的解决方案,默认情况下某些字段将从String
格式转换为LocalDate
格式?
P.S.
强制条件是:
- 请求方式为
GET
; - 所需的 pojo 是:
public class MyCriteria {
private LocalDate from;
private LocalDate till;
private Long communityNumber;
private String communityName;
}
- 让我们跳过自定义 AOP 实现或注入转换逻辑的
getter
s 的想法; - 既没有主体(请求主体为空)也没有json(所有必需的数据都是路径变量或路径参数)。
P.S.2.
- 可用于实验的控制器示例为:
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import org.vl.example.rest.dtofromoaramsandpath.web.dto.MyCriteria;
import java.time.LocalDate;
@RestController
@RequestMapping("verify/criteria/mapping")
@Slf4j
public class MyController {
@GetMapping("community/{communityNumber}/dto")
public MyCriteria loadDataByDto(MyCriteria criteria) {
log.info("received criteria: {}", criteria);
return criteria;
}
@GetMapping("community/{communityNumber}/default/params")
public String loadDataByDefaultParameters(@PathVariable("communityNumber") String communityNumber,
@RequestParam(value = "from", required = false) String from,
@RequestParam(value = "till", required = false) String till,
@RequestParam(value = "communityName", required = false) String communityName) {
log.info("received data without converting:\n\tcommunityNumber => {}\n\tfrom => {}\n\ttill => {}\n\tcommunityName => {}",
communityNumber, from, till, communityName);
return new StringBuilder("{")
.append("\n\tfrom:").append(from).append(";")
.append("\n\tfrom:").append(from).append(";")
.append("\n\ttill:").append(till).append(";")
.append("\n\tcommunityName:").append(communityName)
.append("\n}\n").toString();
}
@GetMapping("community/{communityNumber}/converted/params")
public String loadUsingConvertedParameters(@PathVariable("communityNumber") String communityNumber,
@RequestParam(value = "from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
@RequestParam("till") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate till,
@RequestParam(value = "communityName", required = false) String communityName) {
log.info("received data with LocalDate converting:\n\tcommunityNumber => {}\n\tfrom => {}\n\ttill => {}\n\tcommunityName => {}",
communityNumber, from, till, communityName);
return new StringBuilder("{")
.append("\n\tfrom:").append(from).append(";")
.append("\n\tfrom:").append(from).append(";")
.append("\n\ttill:").append(till).append(";")
.append("\n\tcommunityName:").append(communityName)
.append("\n}\n").toString();
}
}
- 还有 link on github project,其中包含具有必需
controller
和criteria
的模块,以使您的理解和实验更有用。
这可能对您有所帮助。我有类似的情况,我使用这种方法将数据转换为特定需求。
public class MyCriteria {
public MyCriteria(LocalDate from, LocalDate till, Long communityNumber, String communityName){
// assignement of variables
}
private LocalDate from;
private LocalDate till;
private Long communityNumber;
private String communityName;
}
所以每当您从 JSON 创建对象时,它都会根据要求创建它。
当我实现这个的时候,我使用了 "Jackson" 的 ObjectMapper class 来做这件事。希望你也一样。
在 pojo class 中使用 java.sql.Date .like private Date from。我希望它适用于 JSON 转换。当您从 UI 接收日期 JSON 字段时,请始终使用 Java.sql.Date 进行 Jackson 日期转换。
为此,您需要添加 jsr310 依赖项。
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.10")
我希望这对你有用。
问题的答案是使用 init binder 在指定条件内注册类型映射。需要 PropertyEditorSupport
实现特定目的。
短代码示例为:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ISO_LOCAL_DATE));
}
});
}
完整的代码示例可以从 github:
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.vl.example.rest.dtofromoaramsandpath.web.dto.MyCriteriaLd;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@RestController
@RequestMapping("verify/criteria/mapping")
@Slf4j
public class MyControllerLd {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ISO_LOCAL_DATE));
}
});
}
@GetMapping("community/{communityNumber}/dtold")
public MyCriteriaLd loadDataByDto(MyCriteriaLd criteria) {
log.info("received criteria: {}", criteria);
return criteria;
}
}
所以这个案例的模型可以是下一个:
import lombok.Data;
import java.time.LocalDate;
@Data
public class MyCriteriaLd {
private LocalDate from;
private LocalDate till;
private Long communityNumber;
private String communityName;
}