تحية ، خابروفسك. إذن وصلت ترجمة الجزء الثاني من مقالة تم إعدادها خصيصًا لطلاب الدورة "مطور إطار الربيع" في الوقت المناسب. الجزء الأول يمكن قراءته هنا .
يعد Spring أحد أكثر برامج تطوير Java شهرة. هذه أداة قوية ولكن صعبة التعلم. مفاهيمها الأساسية سهلة الفهم والتعلم إلى حد ما ، ولكن الأمر يتطلب بعض الوقت والجهد لتصبح مطور ربيع ذي خبرة.
في هذه المقالة ، سننظر في بعض الأخطاء الأكثر شيوعًا التي تحدث عند العمل في Spring وما يتصل بها ، على وجه الخصوص ، من تطوير تطبيقات الويب واستخدام منصة Spring Boot. كما هو موضح في موقع Spring Boot ، فإن Spring Boot يتبع مقاربة موحدة لإنشاء تطبيقات جاهزة للاستخدام ، وستتبع هذه المقالة هذا النهج. سوف يقدم عددًا من التوصيات التي يمكن استخدامها بفعالية في تطوير تطبيقات الويب القياسية القائمة على Spring Boot.
في حال لم تكن معتادًا على منصة Spring Boot ، ولكنك ترغب في تجربة الأمثلة الواردة في هذه المقالة ، فقد أنشأت مستودع GitHub بمواد إضافية لهذه المقالة . إذا كنت مرتبكًا بعض الشيء في قراءة هذه المقالة ، فإنني أنصحك بإنشاء نسخة من هذا المستودع وتجربة الرمز على جهاز الكمبيوتر الخاص بك.
خطأ شائع رقم 6: عدم استخدام التحقق من صحة البيانات المستندة إلى التعليق التوضيحي
دعنا نتخيل أن خدمة TopTalent لدينا من الأمثلة السابقة تحتاج إلى نقطة نهاية لإضافة بيانات TopTalent جديدة. أيضًا ، لنفترض أنه لسبب مهم حقًا ، يجب أن يكون طول كل اسم تضيفه 10 أحرف بالضبط. يمكن تنفيذ ذلك ، على سبيل المثال ، على النحو التالي:
@RequestMapping("/put") public void addTopTalent(@RequestBody TopTalentData topTalentData) { boolean nameNonExistentOrHasInvalidLength = Optional.ofNullable(topTalentData) .map(TopTalentData::getName) .map(name -> name.length() == 10) .orElse(true); if (nameNonExistentOrInvalidLength) {
ومع ذلك ، فإن الكود أعلاه ليس منظمًا بشكل سيء فحسب ، ولكنه ليس حلًا "نظيفًا" حقًا. نحن
TopTalentData
عدة أنواع من التحقق من صحة البيانات (أي ، نحن نتحقق من أن كائن
TopTalentData
ليس خاليًا ، وأن قيمة الحقل TopTalentData.name ليست خالية ، وأن طول حقل
TopTalentData.name
هو 10 أحرف) ، ورمي استثناء أيضًا إذا كانت البيانات غير صحيحة.
كل هذا يمكن القيام به بشكل أكثر دقة باستخدام
أداة التحقق من السبات في فصل الربيع. لنقم أولاً بإعادة كتابة طريقة
addTopTalent
، مع إضافة دعم للتحقق من صحة البيانات:
@RequestMapping("/put") public void addTopTalent(@Valid @NotNull @RequestBody TopTalentData topTalentData) { topTalentService.addTopTalent(topTalentData); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleInvalidTopTalentDataException(MethodArgumentNotValidException methodArgumentNotValidException) {
بالإضافة إلى ذلك ، نحتاج إلى الإشارة إلى التحقق من صحة الخاصية الذي نريد تنفيذه في فئة
TopTalentData
:
public class TopTalentData { @Length(min = 10, max = 10) @NotNull private String name; }
سوف يقوم Spring الآن باعتراض الطلب والتحقق منه قبل الاتصال بالطريقة ، لذلك لن تكون هناك حاجة إلى إجراء فحص يدوي إضافي.
يمكن أيضًا تحقيق الهدف المنشود عن طريق إنشاء التعليقات التوضيحية الخاصة بك. في ظل الظروف الحقيقية ، يكون من المنطقي عادة استخدام التعليقات التوضيحية الخاصة بك فقط عندما تتجاوز احتياجاتك إمكانات
مجموعة Hibernate المدمجة ، ولكن على سبيل المثال ، دعنا نتخيل أن التعليقات التوضيحية
@Length
غير موجودة. يمكنك إنشاء أداة التحقق من صحة البيانات التي تتحقق من طول السلسلة عن طريق إنشاء فئتين إضافيتين: واحدة للتحقق من الصحة وواحدة لخصائص التعليق التوضيحي:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = { MyAnnotationValidator.class }) public @interface MyAnnotation { String message() default "String length does not match expected"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; int value(); } @Component public class MyAnnotationValidator implements ConstraintValidator<MyAnnotation, String> { private int expectedLength; @Override public void initialize(MyAnnotation myAnnotation) { this.expectedLength = myAnnotation.value(); } @Override public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { return s == null || s.length() == this.expectedLength; } }
يرجى ملاحظة أنه في هذه الحالات ، يتطلب التطبيق الصحيح لمبدأ الفصل بين المسؤولية وضع علامة على الخاصية على أنها صالحة إذا كانت قيمتها فارغة
(s == null
في طريقة
isValid
) ، ثم استخدم التعليق التوضيحي
@NotNull
إذا كان هذا مطلوبًا بالإضافة إلى هذه الخاصية:
public class TopTalentData { @MyAnnotation(value = 10) @NotNull private String name; }
خطأ شائع رقم 7: استخدام التكوينات القديمة المستندة إلى XML
كان استخدام XML أمرًا ضروريًا عند العمل مع الإصدارات السابقة من Spring ، ولكن الآن يمكن تنفيذ معظم مهام التكوين باستخدام تعليمات Java البرمجية والتعليقات التوضيحية. تعمل تكوينات XML الآن على شكل كود قالب إضافي واختياري.
في هذه المقالة (وأيضًا في مواد مستودع تخزين GitHub المصاحبة) ، تستخدم التعليقات التوضيحية لتكوين Spring ، ويعرف Spring مكونات JavaBean التي يجب ربطها ، نظرًا لأن الحزمة الجذرية موضحة باستخدام التعليق التوضيحي المركبSpringBootApplication - مثل هذا:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
يخبر هذا التعليق التوضيحي المركب (راجع
وثائق Spring لمزيد من المعلومات حول هذا) النظام الأساسي لـ Spring الذي يحزم المسح الضوئي لاستخراج مكونات JavaBean. في حالتنا الخاصة ، هذا يعني أن الحزم الفرعية co.kukurin التالية سيتم استخدامها للربط:
- المكون (TopTalentConverter ، MyAnnotationValidator)
- RestController (TopTalentController)
- المستودع (TopTalentRepository)
- فئات الخدمة (TopTalentService)
إذا كان لدينا فئات إضافية تحتوي على تعليق توضيحي على
@Configuration
، فسيتم أيضًا التحقق من تهيئة Java.
خطأ شائع رقم 8: عدم استخدام ملفات تعريف التكوين
عند تطوير أنظمة الخادم ، هناك مشكلة شائعة تتمثل في التبديل بين التكوينات المختلفة (كقاعدة عامة ، هذه تكوينات لبيئات التشغيل والتطوير). بدلاً من تغيير المعلمات المختلفة يدويًا عند كل انتقال بين أوضاع الاختبار والتشغيل ، يكون استخدام ملفات تعريف التكوين أكثر فعالية.
تخيل الحالة عندما تكون في بيئة التطوير المحلية تستخدم قاعدة البيانات في ذاكرة الوصول العشوائي ، وفي بيئة التشغيل الفعلي للتطبيق الخاص بك تستخدم قاعدة بيانات MySQL. هذا يعني بشكل أساسي أنك ستستخدم عناوين URL مختلفة ، ويفترض أن تكون بيانات اعتماد مختلفة للوصول إلى كل قاعدة من قواعد البيانات هذه. دعونا نرى كيف يمكن تنفيذ ذلك باستخدام ملفي التكوين:
تطبيق الملف. YAML # set default profile to 'dev' spring.profiles.active: dev # production database details spring.datasource.url: 'jdbc:mysql://localhost:3306/toptal' spring.datasource.username: root spring.datasource.password:
ملف التطبيق - DEV.YAML spring.datasource.url: 'jdbc:h2:mem:' spring.datasource.platform: h2
يجب افتراض أنه عند التعامل مع التعليمات البرمجية ، لن ترغب في تنفيذ بعض الإجراءات العشوائية باستخدام قاعدة بيانات مخصصة لبيئة التشغيل ، لذلك فمن المنطقي تحديد ملف التعريف لبيئة التطوير (DEV) كملف التعريف الافتراضي. بعد ذلك ، يمكنك تجاوز ملف تعريف التكوين يدويًا على الخادم عن طريق تحديد
-Dspring.profiles.active=prod
لـ JVM. بالإضافة إلى ذلك ، يمكن تحديد ملف تعريف التكوين الافتراضي في متغير بيئة نظام التشغيل.
عدد الأخطاء الشائعة 9. الفشل في استخدام آلية حقن التبعية
الاستخدام السليم لآلية حقن التبعية في Spring يعني أن Spring يمكنه ربط جميع الكائنات عن طريق مسح جميع فئات التكوين الضرورية. هذا مفيد لتخفيف الترابط ويسهل الاختبار إلى حد كبير. بدلاً من ربط الفئات بإحكام ، شيء من هذا القبيل:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController() { this.topTalentService = new TopTalentService(); } }
... نسمح لمنصة Spring بالربط:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController(TopTalentService topTalentService) { this.topTalentService = topTalentService; } }
تشرح محاضرة Mishko Hevery على قناة Google Tech Talks بالتفصيل سبب استخدام حقنة التبعية ، ولكن هنا سنرى كيف يتم استخدام هذه الآلية في الممارسة العملية. في تقسيم المسؤولية ("خطأ مشترك رقم 3") ، أنشأنا فصول الخدمة والتحكم. افترض أننا نريد اختبار وحدة تحكم ، على افتراض أن فئة
TopTalentService
تعمل بشكل صحيح. يمكننا إدراج كائن محاكاة بدلاً من تنفيذ الخدمة الحالية من خلال إنشاء فئة تكوين منفصلة:
@Configuration public class SampleUnitTestConfig { @Bean public TopTalentService topTalentService() { TopTalentService topTalentService = Mockito.mock(TopTalentService.class); Mockito.when(topTalentService.getTopTalent()).thenReturn( Stream.of("Mary", "Joel").map(TopTalentData::new).collect(Collectors.toList())); return topTalentService; } }
بعد ذلك ، يمكننا تطبيق كائن المحاكاة عن طريق
SampleUnitTestConfig
النظام الأساسي Spring بأننا بحاجة إلى استخدام
SampleUnitTestConfig
كمصدر التكوين:
@ContextConfiguration(classes = { SampleUnitTestConfig.class })
بعد ذلك ، سيتيح لنا ذلك استخدام التكوين السياقي لتضمين مكون JavaBean المخصص في اختبار وحدة.
خطأ شائع رقم 10. عدم وجود اختبار أو اختبار غير صحيح
على الرغم من حقيقة أن فكرة اختبار الوحدة ليست جديدة بأي حال من الأحوال ، يبدو أن العديد من المطورين إما "ينسون" الأمر (خاصةً إذا
لم يكن إلزاميًا ) أو ينفقونه متأخراً. من الواضح أن هذا خطأ ، لأن الاختبارات لا تسمح لك فقط بالتحقق من التشغيل الصحيح للرمز ، ولكن أيضًا بمثابة وثائق توضح كيف يجب أن يتصرف التطبيق في مواقف مختلفة.
عند اختبار خدمات الويب ، نادراً ما تقوم بإجراء اختبارات وحدة "نظيفة" بشكل استثنائي ، لأن اتصال HTTP تحتاج عادة إلى استخدام Spring
DispatcherServlet
servlet ومعرفة ما يحدث عندما تتلقى طلب
HttpServletRequest
حقيقي (أي أنه يتحول إلى اختبار
تكامل يستخدم التحقق من الصحة ، التسلسل ، وما إلى ذلك). الحل الأنيق والمثبت هو استخدام
REST Assured ، مكتبة Java لاختبار خدمات REST بشكل مريح ، مع MockMVC. النظر في جزء التعليمات البرمجية التالي مع التبعية حقن:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { Application.class, SampleUnitTestConfig.class }) public class RestAssuredTestDemonstration { @Autowired private TopTalentController topTalentController; @Test public void shouldGetMaryAndJoel() throws Exception {
SampleUnitTestConfig
يربط التطبيق البديل للفئة
TopTalentService
بـ
TopTalentController
، وجميع الفئات الأخرى مرتبطة باستخدام التكوين القياسي الذي تم الحصول عليه عن طريق مسح الحزم بناءً على حزمة فئة التطبيق.
RestAssuredMockMvc
ببساطة لإعداد بيئة خفيفة الوزن وإرسال طلب
GET
إلى
/toptal/get
.
استخدام الربيع مهنيا
Spring عبارة عن منصة قوية يسهل البدء بها ، لكن الأمر يتطلب بعض الوقت والجهد لإتقانها بشكل كامل. إذا كنت تأخذ الوقت الكافي للتعرف على هذا النظام الأساسي ، فسوف يؤدي في النهاية إلى زيادة كفاءة عملك ، مما يساعدك في إنشاء رمز أكثر نظافة وزيادة مؤهلاتك كمطور.
أوصي بأن تنتبه إلى
Spring In Action - هذا كتاب جيد موجه نحو التطبيق يناقش العديد من الموضوعات المهمة المتعلقة بمنصة Spring.
هذه هي نهاية ترجمة هذه المقالة.
اقرأ الجزء الأول .