קלסר נתונים מותאם אישית באביב MVC

1. סקירה כללית

מאמר זה יראה כיצד אנו יכולים להשתמש במנגנון קשירת הנתונים של Spring על מנת להפוך את הקוד שלנו לברור וקריא יותר על ידי החלת פרימיטיבים אוטומטיים להמרות אובייקטים.

כברירת מחדל, אביב יודע להמיר רק סוגים פשוטים. במילים אחרות, ברגע שאנחנו מגישים נתונים לבקר Int, חוּט אוֹ בוליאני סוג הנתונים, הוא יחויב לסוגי Java המתאימים באופן אוטומטי.

אבל בפרויקטים בעולם האמיתי, זה לא יספיק ייתכן שנצטרך לאגד סוגים מורכבים יותר של אובייקטים.

2. קשירת אובייקטים בודדים לבקשת פרמטרים

נתחיל פשוט ונקשר תחילה סוג פשוט; נצטרך לספק יישום מותאם אישית של ה- מֵמִיר ממשק איפה ס הוא הסוג שממנו אנו ממירים, ו ט הוא הסוג אליו אנו ממירים:

המחלקה הציבורית @Component StringToLocalDateTimeConverter מיישם ממיר {@Override LocalDateTime convert (מקור מחרוזת) {החזר LocalDateTime.parse (מקור, DateTimeFormatter.ISO_LOCAL_DATE_TIME); }}

כעת אנו יכולים להשתמש בתחביר הבא בבקר שלנו:

@GetMapping ("/ findbydate / {date}") public GenericEntity findByDate (@PathVariable ("date") תאריך LocalDateTime) {חזרה ...; }

2.1. שימוש באנומות כפרמטרים של בקשה

לאחר מכן, נראה כיצד להשתמש ב- eמספר כ RequestParameter.

הנה, יש לנו פשוט enumמצבים:

מצבי האומה הציבוריים {ALPHA, BETA; }

אנו בונים a חוּט ל ממיר enum כדלהלן:

מחלקה ציבורית StringToEnumConverter מיישם ממיר {@Override Modes public convert (String from) {return Modes.valueOf (from); }}

לאחר מכן, עלינו לרשום את שלנו מֵמִיר:

@Configuration בכיתה ציבורית WebConfig מיישם את WebMvcConfigurer {@Override public void addFormatters (FormatterRegistry registry) {registry.addConverter (StringToEnumConverter חדש ()); }}

עכשיו אנחנו יכולים להשתמש שלנו Enum כ RequestParameter:

@GetMapping תגובה ציבורית ציבורית getStringToMode (@RequestParam ("מצב") מצב מצבים) {// ...}

או כ PathVariable:

@GetMapping ("/ entity / findbymode / {mode}") public GenericEntity findByEnum (מצב מצבים) @PathVariable ("mode")) {// ...}

3. כריכת היררכיית אובייקטים

לפעמים אנחנו צריכים להמיר את כל העץ של היררכיית האובייקטים וזה הגיוני שיש לנו קישור יותר מרכזי ולא קבוצה של ממירים בודדים.

בדוגמה זו יש לנו מופשט ישות כיתת הבסיס שלנו:

מעמד מופשט ציבורי AbstractEntity {id id; מופשט ציבורי (מזהה ארוך) {this.id = id; }}

ושיעורי המשנה פו ו בָּר:

הכיתה הציבורית Foo מרחיבה את AbstractEntity {שם מחרוזת פרטי; // בונים סטנדרטיים, גטרים, סטרים}
בר בכיתה ציבורית מרחיב את AbstractEntity {ערך פרטי פרטי; // בונים סטנדרטיים, גטרים, סטרים}

במקרה הזה, אנחנו יכולים ליישם ConverterFactory כאשר S יהיה הסוג שממנו אנו ממירים ו- R יהיה סוג הבסיס הגדרת טווח השיעורים שאנו יכולים להמיר ל:

מחלקה ציבורית StringToAbstractEntityConverterFactory מיישמת את ConverterFactory {@Override ממיר ציבורי getConverter (Class targetClass) {להחזיר StringToAbstractEntityConverter חדש (targetClass); } מחלקה סטטית פרטית StringToAbstractEntityConverter מיישמת ממיר {class class target class; ציבור StringToAbstractEntityConverter (Class targetClass) {this.targetClass = targetClass; } @Override T המרה ציבורית (מקור מחרוזת) {long id = Long.parseLong (source); אם (this.targetClass == Foo.class) {return (T) Foo (id) חדש; } אחר אם (this.targetClass == Bar.class) {להחזיר (T) סרגל חדש (id); } אחר {להחזיר null; }}}}

כפי שאנו רואים, השיטה היחידה שחייבת ליישם היא getConverter () שמחזיר ממיר לסוג הדרוש. לאחר מכן הועבר תהליך ההמרה לממיר זה.

לאחר מכן, עלינו לרשום את שלנו ConverterFactory:

@Configuration בכיתה ציבורית WebConfig מיישם את WebMvcConfigurer {@Override public void addFormatters (Registry FormatterRegistry) {registry.addConverterFactory (StringToAbstractEntityConverterFactory חדש); }}

לבסוף, אנו יכולים להשתמש בו כמו שאנחנו רוצים בבקר שלנו:

@RestController @RequestMapping ("/ מחרוזת למופשט") מחלקה ציבורית AbstractEntityController {@GetMapping ("/ foo / {foo}") ResponseEntity public getStringToFoo (@PathVariable Foo foo) {return ResponseEntity.ok (foo); } @ GetMapping ("/ bar / {bar}") ResponseEntity ציבורי getStringToBar (@ Bar בר סרגל) {return ResponseEntity.ok (bar); }}

4. אובייקטים של תחום מחייב

ישנם מקרים בהם אנו רוצים לאגד נתונים לאובייקטים, אך הם מגיעים באופן לא ישיר (למשל מ- מוֹשָׁב, כּוֹתֶרֶת אוֹ עוגייה משתנים) או אפילו מאוחסנים במקור נתונים. במקרים אלה, עלינו להשתמש בפתרון אחר.

4.1. פותר ארגומנטים בהתאמה אישית

קודם כל נגדיר הערה לפרמטרים כאלה:

@ Retention (RetentionPolicy.RUNTIME) @ Target (ElementType.PARAMETER) גרסת ממשק @ ממשק ציבורית {}

לאחר מכן, נבצע יישום מותאם אישית HandlerMethodArgument פותר:

class class HeaderVersionArgumentResolver מיישם HandlerMethodArgumentResolver {@Override בוליאני תומך בפרמטר (MethodParameter methodParameter) {return methodParameter.getParameterAnnotation (Version.class)! = null; } @Override אובייקט ציבורי resolutionArgument (MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) זורק חריג {HttpServletRequest בקשה = (HttpSgetWequRative); return request.getHeader ("גרסה"); }}

הדבר האחרון הוא להודיע ​​לאביב לאן לחפש אותם:

@Configuration בכיתה ציבורית WebConfig מיישם את WebMvcConfigurer {// ... @Override public void addArgumentResolvers (List argumentResolvers) {argumentResolvers.add (new HeaderVersionArgumentResolver ()); }}

זהו זה. כעת אנו יכולים להשתמש בו בבקר:

@GetMapping ("/ entity / {id}") ResponseEntity ציבורי findByVersion (@PathVariable מזהה ארוך, גרסת מחרוזת @Version) {return ...; }

כמו שאנו יכולים לראות, HandlerMethodArgumentResolverשל resolArgument () שיטה מחזירה לְהִתְנַגֵד. במילים אחרות, נוכל להחזיר כל חפץ, לא רק חוּט.

5. מסקנה

כתוצאה מכך, נפטרנו מהמרות שגרתיות רבות ונתנו לאביב לעשות את רוב הדברים עבורנו. בסוף, בואו נסכם:

  • עבור סוג פשוט בודד להתנגד להמרות עלינו להשתמש מֵמִיר יישום
  • כדי לתמצת את לוגיקת ההמרה למגוון אובייקטים, נוכל לנסות ConverterFactory יישום
  • עבור כל נתונים שמגיעים בעקיפין או נדרש ליישם לוגיקה נוספת כדי לאחזר את הנתונים המשויכים עדיף להשתמש בהם HandlerMethodArgumentResolver

כרגיל, את כל הדוגמאות ניתן למצוא תמיד במאגר GitHub שלנו.


$config[zx-auto] not found$config[zx-overlay] not found