Saya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:
>> SEMAK KURSUS1. Gambaran keseluruhan
Artikel ini menunjukkan cara menyiapkan REST pada musim bunga - kod respons Pengawal dan HTTP, konfigurasi pengumpulan muatan dan perundingan kandungan.
2. Memahami REST pada musim bunga
Kerangka Spring menyokong dua cara untuk mewujudkan perkhidmatan RESTful:
- menggunakan MVC dengan ModelAndView
- menggunakan penukar mesej HTTP
The ModelAndView pendekatan adalah lebih tua dan lebih baik didokumenkan, tetapi juga lebih berjela-jela dan konfigurasi berat. Ia cuba memasukkan paradigma REST ke model lama, yang bukan tanpa masalah. Pasukan Spring memahami perkara ini dan memberikan sokongan REST kelas pertama bermula dengan Spring 3.0.
Pendekatan baru, berdasarkan HttpMessageConverter dan anotasi, jauh lebih ringan dan mudah dilaksanakan. Konfigurasi adalah minimum, dan ia menyediakan default yang wajar untuk apa yang anda harapkan dari perkhidmatan RESTful.
3. Konfigurasi Java
@Configuration @EnableWebMvc public class WebConfig{ // }
Anotasi @EnableWebMvc baru melakukan beberapa perkara berguna - khususnya, dalam kes REST, ia mengesan kewujudan Jackson dan JAXB 2 di classpath dan secara automatik membuat dan mendaftarkan penukar JSON dan XML lalai. Fungsi anotasi setara dengan versi XML:
Ini adalah jalan pintas, dan walaupun mungkin berguna dalam banyak keadaan, itu tidak sempurna. Apabila konfigurasi yang lebih kompleks diperlukan, hapus anotasi dan panjangkan terus WebMvcConfigurationSupport .
3.1. Menggunakan Spring Boot
Sekiranya kita menggunakan anotasi @SpringBootApplication dan pustaka webmvc spring ada di classpath, maka anotasi @EnableWebMvc ditambahkan secara automatik dengan konfigurasi automatik lalai.
Kami masih boleh menambahkan fungsi MVC ke konfigurasi ini dengan menerapkan antara muka WebMvcConfigurer pada kelas anotasi @Configuration . Kita juga dapat menggunakan instance WebMvcRegistrationsAdapter untuk menyediakan implementasi RequestMappingHandlerMapping , RequestMappingHandlerAdapter , atau ExceptionHandlerExceptionResolver kita sendiri .
Akhirnya, jika kita ingin membuang ciri MVC Spring Boot dan menyatakan konfigurasi tersuai, kita boleh melakukannya dengan menggunakan anotasi @EnableWebMvc .
4. Menguji Konteks Musim Semi
Bermula dengan Spring 3.1, kami mendapat sokongan ujian kelas pertama untuk kelas @Configuration :
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = {WebConfig.class, PersistenceConfig.class}, loader = AnnotationConfigContextLoader.class) public class SpringContextIntegrationTest { @Test public void contextLoads(){ // When } }
Kami menentukan kelas konfigurasi Java dengan anotasi @ContextConfiguration . AnnotationConfigContextLoader baru memuatkan definisi kacang dari kelas @Configuration .
Perhatikan bahawa kelas konfigurasi WebConfig tidak termasuk dalam ujian kerana perlu dijalankan dalam konteks Servlet, yang tidak disediakan.
4.1. Menggunakan Spring Boot
Spring Boot menyediakan beberapa anotasi untuk menyiapkan Spring ApplicationContext untuk ujian kami dengan cara yang lebih intuitif.
Kita hanya dapat memuatkan potongan konfigurasi aplikasi tertentu, atau kita dapat mensimulasikan keseluruhan proses permulaan konteks.
Sebagai contoh, kita boleh menggunakan anotasi @SpringBootTest jika kita mahu keseluruhan konteks dibuat tanpa memulakan pelayan.
Dengan itu, kita kemudian dapat menambahkan @AutoConfigureMockMvc untuk menyuntikkan instance MockMvc dan mengirim permintaan 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(...); } }
Untuk mengelakkan membuat keseluruhan konteks dan hanya menguji Pengawal MVC kami, kami boleh menggunakan @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(...); } }
Kami boleh mendapatkan maklumat terperinci mengenai perkara ini pada artikel 'Testing in Spring Boot' kami.
5. Pengawal
The @RestController adalah artifak yang utama dalam Tier Web keseluruhan API RESTful. Untuk tujuan siaran ini, pengawal memodelkan sumber REST ringkas - Foo :
@RestController @RequestMapping("/foos") class FooController { @Autowired private IFooService service; @GetMapping public List 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); } }
Anda mungkin menyedari bahawa saya menggunakan utiliti RestPreconditions gaya Jambu yang mudah :
public class RestPreconditions { public static T checkFound(T resource) { if (resource == null) { throw new MyResourceNotFoundException(); } return resource; } }
Pelaksanaan Controller tidak bersifat umum - ini kerana tidak perlu.
Biasanya, pengawal adalah yang terakhir dalam rantai kebergantungan. Ia menerima permintaan HTTP dari pengawal depan Spring ( DispatcherServlet ) dan hanya mendelegasikannya ke lapisan perkhidmatan. Sekiranya tidak ada kes penggunaan di mana pengawal harus disuntik atau dimanipulasi melalui rujukan langsung, maka saya lebih suka tidak menyatakannya sebagai umum.
Pemetaan permintaan adalah mudah. Seperti mana-mana pengawal, sebenar nilai pemetaan, dan juga sebagai kaedah HTTP, menentukan kaedah sasaran untuk permintaan itu. @ RequestBody akan mengikat parameter kaedah ke badan permintaan HTTP, sedangkan @ResponseBody melakukan hal yang sama untuk jenis respons dan pengembalian.
The @RestController ialah trengkas memasukkan kedua-dua @ResponseBody dan @Controller penjelasan dalam kelas kami .
Mereka juga memastikan bahawa sumber daya akan dikumpulkan dan dihapus dengan menggunakan penukar HTTP yang betul. Perundingan kandungan akan dilakukan untuk memilih mana dari penukar aktif yang akan digunakan, berdasarkan kebanyakan pada header Terima , walaupun tajuk HTTP lain dapat digunakan untuk menentukan perwakilan juga.
6. Memetakan Kod Respons HTTP
Kod status tindak balas HTTP adalah salah satu bahagian paling penting dalam perkhidmatan REST, dan subjek dengan cepat dapat menjadi sangat rumit. Mendapatkan hak ini boleh menjadi yang membuat atau menghentikan perkhidmatan.
6.1. Permintaan yang belum dipetakan
Sekiranya Spring MVC menerima permintaan yang tidak mempunyai pemetaan, ia menganggap permintaan tersebut tidak dibenarkan dan mengembalikan KAEDAH 405 yang TIDAK DIBENARKAN kembali kepada pelanggan.
Ini juga merupakan amalan yang baik untuk memasukkan header Allow HTTP ketika mengembalikan 405 kepada klien, untuk menentukan operasi mana yang dibenarkan. Ini adalah tingkah laku standard Spring MVC dan tidak memerlukan konfigurasi tambahan.
6.2. Permintaan yang Dipetakan Sah
Untuk sebarang permintaan yang mempunyai pemetaan, Spring MVC menganggap permintaan itu sah dan bertindak balas dengan 200 OK jika tidak ada kod status lain yang dinyatakan sebaliknya.
Oleh kerana itu, pengawal menyatakan @ResponseStatus yang berbeza untuk tindakan membuat , mengemas kini dan menghapus tetapi tidak untuk mendapatkan , yang semestinya akan mengembalikan 200 OK lalai.
6.3. Ralat Pelanggan
In the case of a client error, custom exceptions are defined and mapped to the appropriate error codes.
Simply throwing these exceptions from any of the layers of the web tier will ensure Spring maps the corresponding status code on the HTTP response:
@ResponseStatus(HttpStatus.BAD_REQUEST) public class BadRequestException extends RuntimeException { // } @ResponseStatus(HttpStatus.NOT_FOUND) public class ResourceNotFoundException extends RuntimeException { // }
These exceptions are part of the REST API and, as such, should only be used in the appropriate layers corresponding to REST; if for instance, a DAO/DAL layer exists, it should not use the exceptions directly.
Note also that these are not checked exceptions but runtime exceptions – in line with Spring practices and idioms.
6.4. Using @ExceptionHandler
Another option to map custom exceptions on specific status codes is to use the @ExceptionHandler annotation in the controller. The problem with that approach is that the annotation only applies to the controller in which it's defined. This means that we need to declares in each controller individually.
Of course, there are more ways to handle errors in both Spring and Spring Boot that offer more flexibility.
7. Additional Maven Dependencies
In addition to the spring-webmvc dependency required for the standard web application, we'll need to set up content marshalling and unmarshalling for the REST API:
com.fasterxml.jackson.core jackson-databind 2.9.8 javax.xml.bind jaxb-api 2.3.1 runtime
These are the libraries used to convert the representation of the REST resource to either JSON or XML.
7.1. Using Spring Boot
If we want to retrieve JSON-formatted resources, Spring Boot provides support for different libraries, namely Jackson, Gson and JSON-B.
Auto-configuration is carried out by just including any of the mapping libraries in the classpath.
Usually, if we're developing a web application, we'll just add the spring-boot-starter-web dependency and rely on it to include all the necessary artifacts to our project:
org.springframework.boot spring-boot-starter-web 2.1.2.RELEASE
Spring Boot uses Jackson by default.
If we want to serialize our resources in an XML format, we'll have to add the Jackson XML extension (jackson-dataformat-xml) to our dependencies, or fallback to the JAXB implementation (provided by default in the JDK) by using the @XmlRootElement annotation on our resource.
8. Conclusion
Tutorial ini menggambarkan cara menerapkan dan mengkonfigurasi REST Service menggunakan konfigurasi berasaskan Spring dan Java.
Dalam artikel siri seterusnya, saya akan memfokuskan pada Kebolehcapaian API, perundingan kandungan lanjutan dan bekerja dengan perwakilan tambahan Sumber.
Semua kod artikel ini terdapat di Github. Ini adalah projek berasaskan Maven, jadi mudah diimport dan dijalankan sebagaimana adanya.
REST bawah