Egyedi adatkötő a tavaszi MVC-ben

1. Áttekintés

Ez a cikk bemutatja, hogyan használhatjuk a Spring adatmegkötő mechanizmusát annak érdekében, hogy kódunkat világosabbá és olvashatóbbá tegyük az automatikus primitívek alkalmazásával az objektumok átalakításakor.

Alapértelmezés szerint a Spring csak az egyszerű típusok konvertálását tudja. Más szavakkal, ha az adatokat benyújtjuk az adatkezelőhöz Int, Húr vagy Logikai típusú adatok, akkor automatikusan a megfelelő Java típusokhoz lesznek kötve.

De a valós projektekben ez nem lesz elég, mint lehet, hogy összetettebb típusú objektumokat kell kötnünk.

2. Az egyes objektumok kötése a paraméterek kérésére

Kezdjük egyszerűnek, és először kössünk egy egyszerű típust; nekünk kell biztosítanunk a Átalakító interfész hol S az a típus, amelyből átváltunk, és T az a típus, amelyre átváltunk:

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

Most a következő szintaxist használhatjuk vezérlőnkben:

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

2.1. Enums használata kérési paraméterként

Ezután meglátjuk hogyan kell használni az eszám mint a RequestParameter.

Itt van egy egyszerű enumMódok:

nyilvános enum módok {ALPHA, BETA; }

Építünk egy Húr nak nek enum Converter alábbiak szerint:

public class StringToEnumConverter implementálja a Converter {@Override public Modes convert (String from) {return Modes.valueOf (from); }}

Ezután regisztrálnunk kell Átalakító:

@Configuration public class A WebConfig végrehajtja a WebMvcConfigurer {@Override public void addFormatters (FormatterRegistry registry) {register.addConverter (új StringToEnumConverter ()); }}

Most már használhatjuk a mi Enum mint a RequestParameter:

@GetMapping public ResponseEntity getStringToMode (@RequestParam ("mode" Modes mode) {// ...}

Vagy mint a PathVariable:

@GetMapping ("/ entity / findbymode / {mode}") public GenericEntity findByEnum (@PathVariable ("mode") Modes mode) {// ...}

3. Az objektumok hierarchiájának megkötése

Néha át kell alakítanunk az objektumhierarchia teljes fáját, és van értelme, ha inkább egy központosított kötést használunk, mint egyes átalakítókat.

Ebben a példában van AbstractEntity alaposztályunk:

public abstract class AbstractEntity {long id; public AbstractEntity (hosszú id) {this.id = id; }}

És az alosztályok Foo és Rúd:

a Foo nyilvános osztály kiterjeszti az AbstractEntity {private String name; // szabványos kivitelezők, szerelők, beállítók}
public class Bar kiterjeszti az AbstractEntity {private int value; // szabványos kivitelezők, szerelők, beállítók}

Ebben az esetben, megvalósíthatjuk ConverterFactory ahol S lesz az a típus, amelyből átalakítunk, és R lesz az alaptípus meghatározva az osztályok körét, amelyekre átválthatunk:

public class StringToAbstractEntityConverterFactory megvalósítja a ConverterFactory {@Override public Converter getConverter (Class targetClass) {return new StringToAbstractEntityConverter (targetClass); } privát statikus osztály StringToAbstractEntityConverter megvalósítja a Converter {private Class targetClass; public StringToAbstractEntityConverter (Osztály targetClass) {this.targetClass = targetClass; } @Orride public T convert (String source) {long id = Long.parseLong (source); if (this.targetClass == Foo.class) {return (T) új Foo (id); } else if (this.targetClass == Sáv.osztály) {return (T) új sáv (id); } else {return null; }}}}

Mint láthatjuk, az egyetlen módszert kell végrehajtani getConverter () amely visszaadja a szükséges típusú konvertert. Ezután az átalakítási folyamat erre a konverterre van átruházva.

Ezután regisztrálnunk kell ConverterFactory:

@Configuration public class A WebConfig implementálja a WebMvcConfigurer {@Orride public void addFormatters (FormatterRegistry registry) {register.addConverterFactory (new StringToAbstractEntityConverterFactory ()); }}

Végül tetszés szerint használhatjuk a vezérlőnkben:

@RestController @RequestMapping ("/ string-to-abstract") public class 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. Domain objektumok megkötése

Vannak esetek, amikor az adatokat objektumokhoz akarjuk kötni, de ezek vagy nem közvetlen módon érkeznek (például Ülés, Fejléc vagy Aprósütemény változók), vagy akár adatforrásban tárolják. Ezekben az esetekben más megoldást kell használnunk.

4.1. Custom Argument Resolver

Először meghatározzuk az ilyen paraméterek kommentárját:

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

Ezután megvalósítunk egy szokást HandlerMethodArgumentResolver:

public class HeaderVersionArgumentResolver implementálja a HandlerMethodArgumentResolver {@Orride public boolean supportParameter (MethodParameter methodParameter) {return methodParameter.getParameterAnnotation (Version.class)! = null; } @Override public Object ResolArgument (MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) kivételt dob ​​{HttpServletRequestName = (HttpServ return request.getHeader ("Verzió"); }}

Az utolsó dolog, hogy tudatja tavasszal, hol keresse őket:

@Configuration public class A WebConfig végrehajtja a WebMvcConfigurer {// ... @Orride public void addArgumentResolvers (List argumentResolvers) {argumentResolvers.add (new HeaderVersionArgumentResolver ()); }}

Ez az. Most egy vezérlőben használhatjuk:

@GetMapping ("/ entitás / {id}") nyilvános ResponseEntity findByVersion (@PathVariable Long id, @Version String verzió) {return ...; }

Ahogy látjuk, HandlerMethodArgumentResolver’S resolArgument () metódus egy Tárgy. Más szavakkal, bármilyen tárgyat visszaadhatunk, nemcsak Húr.

5. Következtetés

Ennek eredményeként megszabadultunk a sok rutinszerű megtéréstől, és hagytuk, hogy Spring a legtöbb dolgot elvégezze helyettünk. Végül vonjuk le a következtetést:

  • Egy egyedi típusú objektum konverziókhoz használnunk kell Átalakító végrehajtás
  • Megpróbálhatjuk az objektumok egy csoportjának átalakítási logikájának beágyazását ConverterFactory végrehajtás
  • Bármely adat közvetett módon származik, vagy további logikát kell alkalmaznia a társított adatok beolvasásához, amelyet jobb használni HandlerMethodArgumentResolver

Szokás szerint az összes példa mindig megtalálható a GitHub adattárunkban.