Vlastný zväzok údajov na jar MVC

1. Prehľad

Tento článok ukáže, ako môžeme použiť mechanizmus Spring Data Binding, aby bol náš kód jasnejší a čitateľnejší použitím automatických primitívov na konverzie objektov.

Spring predvolene vie, ako prevádzať iba jednoduché typy. Inými slovami, akonáhle poskytneme údaje správcovi Int, String alebo Boolovský typu údajov, bude automaticky naviazaný na príslušné typy Java.

Ale v projektoch z reálneho sveta to nebude stačiť možno budeme musieť viazať zložitejšie typy objektov.

2. Viazanie jednotlivých objektov na vyžiadanie parametrov

Začnime jednoduchým a najskôr spojme jednoduchý typ; budeme musieť zabezpečiť vlastnú implementáciu Prevádzač rozhranie kde S je typ, z ktorého konvertujeme, a T je typ, na ktorý prevádzame:

@Component public class StringToLocalDateTimeConverter implementuje Converter {@Override public LocalDateTime convert (String source) {return LocalDateTime.parse (source, DateTimeFormatter.ISO_LOCAL_DATE_TIME); }}

Teraz môžeme v našom ovládači použiť nasledujúcu syntax:

@GetMapping ("/ findbydate / {date}") public GenericEntity findByDate (@PathVariable ("date") LocalDateTime date) {návrat ...; }

2.1. Používanie výčtov ako parametrov požiadavky

Ďalej uvidíme ako používať ečíslo ako RequestParameter.

Tu máme jednoduchý enumRežimy:

režimy verejného výčtu {ALPHA, BETA; }

Postavíme String do enum Converter nasledovne:

public class StringToEnumConverter implementuje Converter {@Override public Modes convert (String from) {return Modes.valueOf (from); }}

Potom musíme zaregistrovať naše Prevádzač:

@Configuration public class WebConfig implementuje WebMvcConfigurer {@Override public void addFormatters (register FormatterRegistry) {registry.addConverter (nový StringToEnumConverter ()); }}

Teraz môžeme použiť našu Enum ako RequestParameter:

@GetMapping public ResponseEntity getStringToMode (@RequestParam ("režim") režim režimov) {// ...}

Alebo ako PathVariable:

@GetMapping ("/ entity / findbymode / {mode}") public GenericEntity findByEnum (@PathVariable ("mode") Režimy režimu) {// ...}

3. Viazanie hierarchie objektov

Niekedy potrebujeme previesť celý strom hierarchie objektov a má zmysel mať skôr centralizovanú väzbu ako množinu jednotlivých prevádzačov.

V tomto príklade máme AbstractEntity naša základná trieda:

verejná abstraktná trieda AbstractEntity {long id; public AbstractEntity (dlhé id) {this.id = id; }}

A podtriedy Foo a Bar:

public class Foo extends AbstractEntity {private String name; // štandardné konštruktory, getre, setre}
public class Bar extends AbstractEntity {private int value; // štandardné konštruktory, getre, setre}

V tomto prípade, môžeme realizovať ConverterFactory kde S bude typ, z ktorého prevádzame, a R bude základný typ definovanie rozsahu tried, do ktorých môžeme prevádzať:

public class StringToAbstractEntityConverterFactory implementuje ConverterFactory {@Override public Converter getConverter (Class targetClass) {return new StringToAbstractEntityConverter (targetClass); } súkromná statická trieda StringToAbstractEntityConverter implementuje Converter {private Class targetClass; public StringToAbstractEntityConverter (Class targetClass) {this.targetClass = targetClass; } @Override public T convert (zdroj reťazca) {long id = Long.parseLong (zdroj); if (this.targetClass == Foo.class) {return (T) new Foo (id); } else if (this.targetClass == Bar.class) {return (T) new Bar (id); } else {return null; }}}}

Ako vidíme, jediná metóda, ktorú je potrebné implementovať, je getConverter () ktorý vráti prevodník pre potrebný typ. Proces premeny je potom delegovaný na tento prevádzač.

Potom musíme zaregistrovať naše ConverterFactory:

@Configuration verejná trieda WebConfig implementuje WebMvcConfigurer {@Override public void addFormatters (register FormatterRegistry) {registry.addConverterFactory (nový StringToAbstractEntityConverterFactory ()); }}

Nakoniec to môžeme použiť ako sa nám páči v našom ovládači:

@RestController @RequestMapping ("/ string-to-abstract") verejná trieda AbstractEntityController {@GetMapping ("/ foo / {foo}") public ResponseEntity getStringToFoo (@PathVariable Foo foo) {return ResponseEntity.ok (foo); } @GetMapping ("/ bar / {bar}") public ResponseEntity getStringToBar (@PathVariable Bar bar) {return ResponseEntity.ok (bar); }}

4. Viazanie doménových objektov

Existujú prípady, keď chceme viazať údaje na objekty, ale prichádza to buď nepriamo (napríklad z Session, Hlavička alebo Cookie premenné) alebo dokonca uložené v zdroji údajov. V týchto prípadoch musíme použiť iné riešenie.

4.1. Custom Argument Resolver

Najskôr definujeme anotáciu pre tieto parametre:

@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.PARAMETER) public @interface Version {}

Potom implementujeme zvyk HandlerMethodArgumentResolver:

verejná trieda HeaderVersionArgumentResolver implementuje HandlerMethodArgumentResolver {@Override verejný boolean podporujeParameter (MethodParameter methodParameter) {návrat methodParameter.getParameterAnnotation (Version.class)! = null; } @Override public Object resolveArgument (MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) vyvolá výnimku {HttpServletRequest request = (HttpServletRequest) návrat request.getHeader ("Verzia"); }}

Posledná vec je dať Springu vedieť, kde ich hľadať:

@Configuration verejná trieda WebConfig implementuje WebMvcConfigurer {// ... @Override public void addArgumentResolvers (List argumentResolvers) {argumentResolvers.add (new HeaderVersionArgumentResolver ()); }}

To je všetko. Teraz ho môžeme použiť v ovládači:

@GetMapping ("/ entity / {id}") public ResponseEntity findByVersion (@PathVariable Long id, @Version String version) {návrat ...; }

Ako vidíme, HandlerMethodArgumentResolver‘S resolveArgument () metóda vracia Objekt. Inými slovami, mohli by sme vrátiť akýkoľvek objekt, nielen String.

5. Záver

Vo výsledku sme sa zbavili mnohých rutinných konverzií a nechali sme Spring, nech urobí väčšinu vecí za nás. Na záver poďme na záver:

  • Mali by sme použiť individuálny jednoduchý typ namietania konverzií Prevádzač implementácia
  • Môžeme skúsiť zapuzdrenie logiky prevodu pre rad objektov ConverterFactory implementácia
  • Akékoľvek údaje prichádzajú nepriamo alebo je potrebné na získanie súvisiacich údajov použiť ďalšiu logiku, je lepšie ich použiť HandlerMethodArgumentResolver

Ako obvykle, všetky príklady nájdete vždy v našom úložisku GitHub.