جاوا و تکنولوژی های آن

java programming language

در این وبلاگ به بررسی نکات موجود در جاوا و تکنولوژی های آن می پردازیم

طبقه بندی موضوعی


در فریم ورک اسپرینگ از دو طریق میتوان RESTful-Service ایجاد کرد :


- از طریق MVC با ModelAndView

- از طریق تبدیل پیام های HTTP


روش ModelAndView قدیمی تر و داکیومنت پخته تری دارد اما تنظیمات سنگین تری را نیاز دارد از Spring 3.0 با در نظر گرفتن معایب موجود در روش قدیمی نیاز بود که روشی سریعتر و سبکتری ارائه میشد که در نهایت منجر به طراحی توسط Annotation ها و HttpMessageConverter شد



تنظیمات Java :

@Configuration
@EnableWebMvc
public class WebConfig{
   //
}


استفاده از EnableWebMvc@ جدید موقع کار با REST بسیار سودمند است چون براحتی کتابخانه های JAXB و Jackson را برای تبدیل کننده های JSON و XML شناسایی میکند و کار ما راحت تر است ولی هنگامی که بخواهیم تنظیمات خاص و پیچیده تری را داشته باشیم نیاز داریم که از WebMvcConfigurationSupport ارث بری کنیم 



استفاده از Spring Boot :


اگر از SpringBootApplication@ و کتابخانه spring-webmvc استفاده کنیم، EnableWebMvc@ بطور اتوماتیک اضافه خواهد شد و اگر بخواهیم تنظیماتی را داشته باشیم از طریق پیاده سازی اینترفیس WebMvcConfigurer همراه با Configuration@ در یک کلاس امکان پذیر است.

همچنین با استفاده از WebMvcRegistrationsAdapter میتوانیم RequestMappingHandlerMapping, RequestMappingHandlerAdapter و یا ExceptionHandlerExceptionAdapter دلخواه خودمان را پیاده سازی کنیم 



اضافه کردن کتابخانه های مورد نیاز برای marshaling و unmarshaling به JSON و XML در REST :


بدون Spring Boot :

<dependencies>
   <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
   </dependency>
   <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.3.1</version>
      <scope>runtime</scope>
   </dependency>
</dependencies>


با Spring Boot :

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>

Spring Boot با توجه به نیازمندی پروژه کتابخانه های مورد نیاز را بصورت اتوماتیک اضافه خواهد کرد

بصورت پیش فرض Spring Boot از کتابخانه Jackson برای مبدل ها استفاده میکند و چنانچه بخواهیم از فرمت XML استفاده کنیم باید کتابخانه jackson-dataformat-xml را اضافه کنیم و یا اگر از XmlRootElement@ استفاده کنیم کتابخانه JAXB موجود در JDK استفاده خواهد شد 


تست کردن Spring Context :


از ورژن Spring 3.1 امکان تست کردن Context ها بوجود آمد. ما کلاس های Configuration را با ContextConfiguration@ مشخص میکنیم که با استفاده از کلاس AnnotationConfigContextLoader کلیه bean های تعریف شده داخل کلاس های Configuration@ را لود میکند 

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( 
  classes = {WebConfig.class, PersistenceConfig.class},
  loader = AnnotationConfigContextLoader.class)
public class SpringContextIntegrationTest {
 
   @Test
   public void contextLoads(){
      // When
   }
}

* دقت کنید که چون SevletContext را نداریم امکان تست WebConfig وجود ندارد 



استفاده از Spring Boot برای تست :


Spring Boot چندین Annotation برای راه اندازی AppicationContext ارائه میدهد که میتوانیم تست را بصورت بصری انجام دهیم. همچنین ما میتوانیم قسمتی از تنظیمات خاص را لود کنیم و یا کل Context را اجرا کنیم. برای نمونه با استفاده از SpringBootTest@ ما میتوانیم کل Context را بالا بیاوریم برای تست بدون اینکه سرور اجرا شود و در کنار این annotation میتوانیم از AutoConfigureMockMvc@ استفاده کنیم که یک نمونه از MockMvc را تزریق میکند و بعد میتوانیم درخواست های Http ارسال کنیم 

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class FooControllerAppIntegrationTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    public void whenTestApp_thenEmptyResponse() throws Exception {
        this.mockMvc.perform(get("/foos")
            .andExpect(status().isOk())
            .andExpect(...);
    }
 
}


اگر نیاز به تستی داشتیم که نیاز نبود کل context اجرا شود و فقط MVC Controller ها تست شوند از WebMvcTest@ استفاده میکنیم :


@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerWebLayerIntegrationTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @MockBean
    private IFooService service;
 
    @Test()
    public void whenTestMvcController_thenRetrieveExpectedResult() throws Exception {
        // ...
 
        this.mockMvc.perform(get("/foos")
            .andExpect(...);
    }
}




ساخت Controller برای REST : 


در وب میتوانیم از RestController@ برای ایجاد Controller استفاده کنیم :

@RestController
@RequestMapping("/foos")
class FooController {
 
    @Autowired
    private IFooService service;
 
    @GetMapping
    public List<Foo> findAll() {
        return service.findAll();
    }
 
    @GetMapping(value = "/{id}")
    public Foo findById(@PathVariable("id") Long id) {
        return RestPreconditions.checkFound(service.findById(id));
    }
 
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Long create(@RequestBody Foo resource) {
        Preconditions.checkNotNull(resource);
        return service.create(resource);
    }
 
    @PutMapping(value = "/{id}")
    @ResponseStatus(HttpStatus.OK)
    public void update(@PathVariable( "id" ) Long id, @RequestBody Foo resource) {
        Preconditions.checkNotNull(resource);
        RestPreconditions.checkNotNull(service.getById(resource.getId()));
        service.update(resource);
    }
 
    @DeleteMapping(value = "/{id}")
    @ResponseStatus(HttpStatus.OK)
    public void delete(@PathVariable("id") Long id) {
        service.deleteById(id);
    }
 
}



public class RestPreconditions {
    public static <T> T checkFound(T resource) {
        if (resource == null) {
            throw new MyResourceNotFoundException();
        }
        return resource;
    }
}


کلاس RestController@ نیازی ندارد که از نوع public باشد چون کلاس RestController@ در حلقه آخر زنجیره قرار دارد. مسولیت این کلاس گرفتن درخواست های Http از Spring front Controller ( که در اینجا ServletDispatcher است ) و واگذاری آنها به سمت لایه service است و هیچ مورد قابل استفاده ای وجود ندارد که دیگر لایه ها از کلاس RestController@ استفاده کنند در نتیجه نیازی به public بودن نخواهد داشت



برای برقراری تناظر بین Controller ها و درخواست ها مثل روش معمول وب، متد هایی را در داخل کلاس Controller تعریف میکنیم و با استفاده از RequestBody@ مقادیر را استخراج و با استفاده از ResponseBody@ ابجکت خروجی به Response مورد نظر تبدیل میکنیم


RestController@ در حقیقت ترکیبی از Controller@ و ResponseBody@ را برای ما فراهم و اطمینان حاصل میکند که تبدیل data model  انجام شود (marshaling / unmarshaling)

برای انتخاب مبدل مورد نظر به فیلد accept از هدر توجه میکند 




ساخت Http Status Code موقع ارسال پاسخ در REST :


در REST یکی از بخش های مهم سرویس ارسال کد وضعیت متناسب است که گاهی میتواند تبدیل به مسئله بزرگی در سرویس دهی شود که شرایط های مختلف را بررسی خواهیم کرد :


- درخواست هایی که هیچ متد متناظر برای آن وجود ندارد :


برای این حالت نیاز نیست ما تنظیمات خاصی را انجام دهیم و توسط Spring MVC انجام خواهد شد 

اگر Spring MVC درخواستی را دریافت کند که هیچ متد متناظری برای آن ست نشده باشد آنرا 405 (METHOD NOT ALLOWED) در نظر میگیرد در این زمان بهتر است همراه با کد 405 در فیلد Allow هدر، عملیات مجاز ارسال شود تا کلاینت بتواند درخواست درست را ارسال کند


- درخواست هایی که متد کنترلر متناظر آن موجود باشد :


بصورت 200 ارسال خواهد شد 


- حالت ایجاد خطا در هنگام انجام عملیات :


@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
   //
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
   //
}


  این خطا ها مربوط به REST Api و از نوع  Runtime Exception هستند باید توجه داشت که باید فقط در لایه REST از آنها استفاده شود و لایه های دیگر برنامه از مدیریت خطا لایه REST بصورت مستقیم استفاده نکنند


برای مدیریت خطا انتخاب دیگری که داریم استفاده از ExceptionHandler@ است و اینطوری میتوانیم Status Code مورد نیاز را خودمان ارسال کنیم نقطه ضعفی که این روش دارد این است که در هر یک از کلاس های کنترلر REST باید تعریف شود 





نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی