Spring REST API регистр даты преобразователь для pojo - PullRequest
1 голос
/ 24 октября 2019

Spring rest по умолчанию обеспечивает сборку функций pojo из переменных пути и параметров url.

В моем случае у меня есть 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 данные с необходимыми типами по назначению. Поэтому я хотел бы иметь поля from и till типа LocalDate. Используя пружину, я хотел бы получить это решение почти из коробки . Но никакие преобразователи даты Spring или Jackson не могут решить мою проблему из-за жизненного цикла.

Spring проверяет типы полей pojo перед введением дат, и я получаю исключение несоответствия типов. Я думаю, что основной причиной является использование специального компоновщика весной, который пытается найти необходимые параметры по имени, и он игнорирует аннотации, которые будут применены внутри pojo для полей.

Вопрос:

Есть ликакие-нибудь элегантные решения для создания pojo к весне, где некоторые поля будут преобразованы из String в LocalDate формат по умолчанию?

PS

Обязательные условия:

  • Метод запроса GET;
  • Требуется Pojo:
public class MyCriteria {
  private LocalDate from;
  private LocalDate till;
  private Long communityNumber;
  private String communityName;
}
  • позволяет пропустить идеи с пользовательскими реализациями AOP или с getter s, где вводится конвертироватьлогика;
  • нет ни тела (тело запроса пусто), ни json (все необходимые данные являются переменными пути или параметрами пути).

PS2.

  • Пример контроллера, который можно использовать для экспериментов:
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();
    }
}
  • также ссылка на проект github , которая содержит модуль с необходимыми controller и criteriaсделать ваше понимание и экспериментыболее полезно.

Ответы [ 4 ]

1 голос
/ 26 октября 2019

Ответ на вопрос заключается в использовании инициатора связывания для регистрации сопоставления типов внутри указанных критериев. Для указанной цели требуется реализация 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;
}
1 голос
/ 24 октября 2019

Используйте java.sql.Date внутри класса pojo .like private Date from. Я надеюсь, что это будет работать для преобразования JSON. Когда вы получаете поле даты JSON из пользовательского интерфейса, всегда используйте Java.sql.Date для преобразования даты Джексона.

1 голос
/ 25 октября 2019

Для этого вам нужно добавить jsr310 зависимость.

compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.10")

Надеюсь, это хорошо сработает для вас.

1 голос
/ 24 октября 2019

Это может помочь вам. У меня похожая ситуация, и я использовал этот подход для преобразования данных в конкретные требования.

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

SO, когда вы создаете объект из JSON, он будет создаваться в соответствии с требованием.

Когда я реализовал это, я использовал класс «Джексон» ObjectMapper, чтобы сделать это. Надеюсь, вы используете то же самое.

...