日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

将Spring MVC RESTful Web服务迁移到Spring 4

發布時間:2023/12/3 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 将Spring MVC RESTful Web服务迁移到Spring 4 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1引言

Spring 4為MVC應用程序帶來了一些改進 。 在這篇文章中,我將重點介紹寧靜的Web服務,并通過采用Spring 3.2實現的項目并將其升級到Spring 4來嘗試這些改進。以下幾點總結了本文的內容:

  • 從Spring 3.2遷移到Spring 4.0
  • 變化中的@ResponseBody和包容的@RestController
  • 同步和異步調用

以下項目的源代碼可以在github上找到:

  • 原始項目(Spring3.2)
  • 遷移到Spring 4

2 Spring 3.2 RESTful示例

起始項目使用Spring 3.2( pom.xml )實現。 它包含一個Spring MVC應用程序,該應用程序訪問數據庫以檢索有關電視連續劇的數據。 讓我們看一下其REST API,以使其更加清晰:

彈簧配置

<import resource="db-context.xml"/><!-- Detects annotations like @Component, @Service, @Controller, @Repository, @Configuration --> <context:component-scan base-package="xpadro.spring.web.controller,xpadro.spring.web.service"/><!-- Detects MVC annotations like @RequestMapping --> <mvc:annotation-driven/>

db-context.xml

<!-- Registers a mongo instance --> <bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean"><property name="host" value="localhost" /> </bean><bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"><constructor-arg name="mongo" ref="mongo" /><constructor-arg name="databaseName" value="rest-db" /> </bean>

服務實施

此類負責從mongoDB數據庫中檢索數據:

@Service public class SeriesServiceImpl implements SeriesService {@Autowiredprivate MongoOperations mongoOps;@Overridepublic Series[] getAllSeries() {List<Series> seriesList = mongoOps.findAll(Series.class);return seriesList.toArray(new Series[0]);}@Overridepublic Series getSeries(long id) {return mongoOps.findById(id, Series.class);}@Overridepublic void insertSeries(Series series) {mongoOps.insert(series);}@Overridepublic void deleteSeries(long id) {Query query = new Query();Criteria criteria = new Criteria("_id").is(id);query.addCriteria(criteria);mongoOps.remove(query, Series.class);} }

控制器實施

該控制器將處理請求并與服務進行交互,以檢索系列數據:

@Controller @RequestMapping(value="/series") public class SeriesController {private SeriesService seriesService;@Autowiredpublic SeriesController(SeriesService seriesService) {this.seriesService = seriesService;}@RequestMapping(method=RequestMethod.GET)@ResponseBodypublic Series[] getAllSeries() {return seriesService.getAllSeries();}@RequestMapping(value="/{seriesId}", method=RequestMethod.GET)public ResponseEntity<Series> getSeries(@PathVariable("seriesId") long id) {Series series = seriesService.getSeries(id);if (series == null) {return new ResponseEntity<Series>(HttpStatus.NOT_FOUND);}return new ResponseEntity<Series>(series, HttpStatus.OK);}@RequestMapping(method=RequestMethod.POST)@ResponseStatus(HttpStatus.CREATED)public void insertSeries(@RequestBody Series series, HttpServletRequest request, HttpServletResponse response) {seriesService.insertSeries(series);response.setHeader("Location", request.getRequestURL().append("/").append(series.getId()).toString());}@RequestMapping(value="/{seriesId}", method=RequestMethod.DELETE)@ResponseStatus(HttpStatus.NO_CONTENT)public void deleteSeries(@PathVariable("seriesId") long id) {seriesService.deleteSeries(id);} }

整合測試

這些集成測試將在模擬Spring MVC環境中測試我們的控制器。 這樣,我們將能夠測試處理程序方法的映射。 為此, MockMvc類變得非常有用。 如果您想學習如何編寫Spring MVC控制器的測試,我強烈推薦Petri Kainulainen編寫的Spring MVC Test Tutorial系列。

@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(locations={"classpath:xpadro/spring/web/test/configuration/test-root-context.xml","classpath:xpadro/spring/web/configuration/app-context.xml"}) public class SeriesIntegrationTest {private static final String BASE_URI = "/series";private MockMvc mockMvc;@Autowiredprivate WebApplicationContext webApplicationContext;@Autowiredprivate SeriesService seriesService;@Beforepublic void setUp() {reset(seriesService);mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();when(seriesService.getAllSeries()).thenReturn(new Series[]{new Series(1, "The walking dead", "USA", "Thriller"), new Series(2, "Homeland", "USA", "Drama")});when(seriesService.getSeries(1L)).thenReturn(new Series(1, "Fringe", "USA", "Thriller"));}@Testpublic void getAllSeries() throws Exception {mockMvc.perform(get(BASE_URI).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(content().contentType("application/json;charset=UTF-8")).andExpect(jsonPath("$", hasSize(2))).andExpect(jsonPath("$[0].id", is(1))).andExpect(jsonPath("$[0].name", is("The walking dead"))).andExpect(jsonPath("$[0].country", is("USA"))).andExpect(jsonPath("$[0].genre", is("Thriller"))).andExpect(jsonPath("$[1].id", is(2))).andExpect(jsonPath("$[1].name", is("Homeland"))).andExpect(jsonPath("$[1].country", is("USA"))).andExpect(jsonPath("$[1].genre", is("Drama")));verify(seriesService, times(1)).getAllSeries();verifyZeroInteractions(seriesService);}@Testpublic void getJsonSeries() throws Exception {mockMvc.perform(get(BASE_URI + "/{seriesId}", 1L).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(content().contentType("application/json;charset=UTF-8")).andExpect(jsonPath("$.id", is(1))).andExpect(jsonPath("$.name", is("Fringe"))).andExpect(jsonPath("$.country", is("USA"))).andExpect(jsonPath("$.genre", is("Thriller")));verify(seriesService, times(1)).getSeries(1L);verifyZeroInteractions(seriesService);}@Testpublic void getXmlSeries() throws Exception {mockMvc.perform(get(BASE_URI + "/{seriesId}", 1L).accept(MediaType.APPLICATION_XML)).andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_XML)).andExpect(xpath("/series/id").string("1")).andExpect(xpath("/series/name").string("Fringe")).andExpect(xpath("/series/country").string("USA")).andExpect(xpath("/series/genre").string("Thriller"));verify(seriesService, times(1)).getSeries(1L);verifyZeroInteractions(seriesService);} }

我正在展示一些已實施的測試。 檢查SeriesIntegrationTesting以獲得完整的實現。

功能測試

該應用程序使用RestTemplate類包含一些功能測試。 您需要部署Web應用程序才能對此進行測試。

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:xpadro/spring/web/configuration/root-context.xml","classpath:xpadro/spring/web/configuration/app-context.xml"}) public class SeriesFunctionalTesting {private static final String BASE_URI = "http://localhost:8080/spring-rest-api-v32/spring/series";private RestTemplate restTemplate = new RestTemplate();@Autowiredprivate MongoOperations mongoOps;@Beforepublic void setup() {List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();converters.add(new StringHttpMessageConverter());converters.add(new Jaxb2RootElementHttpMessageConverter());converters.add(new MappingJacksonHttpMessageConverter());restTemplate.setMessageConverters(converters);initializeDatabase();}private void initializeDatabase() {try {mongoOps.dropCollection("series");mongoOps.insert(new Series(1, "The walking dead", "USA", "Thriller"));mongoOps.insert(new Series(2, "Homeland", "USA", "Drama"));} catch (DataAccessResourceFailureException e) {fail("MongoDB instance is not running");}}@Testpublic void getAllSeries() {Series[] series = restTemplate.getForObject(BASE_URI, Series[].class);assertNotNull(series);assertEquals(2, series.length);assertEquals(1L, series[0].getId());assertEquals("The walking dead", series[0].getName());assertEquals("USA", series[0].getCountry());assertEquals("Thriller", series[0].getGenre());assertEquals(2L, series[1].getId());assertEquals("Homeland", series[1].getName());assertEquals("USA", series[1].getCountry());assertEquals("Drama", series[1].getGenre());}@Testpublic void getJsonSeries() {List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();converters.add(new MappingJacksonHttpMessageConverter());restTemplate.setMessageConverters(converters);String uri = BASE_URI + "/{seriesId}";ResponseEntity<Series> seriesEntity = restTemplate.getForEntity(uri, Series.class, 1l);assertNotNull(seriesEntity.getBody());assertEquals(1l, seriesEntity.getBody().getId());assertEquals("The walking dead", seriesEntity.getBody().getName());assertEquals("USA", seriesEntity.getBody().getCountry());assertEquals("Thriller", seriesEntity.getBody().getGenre());assertEquals(MediaType.parseMediaType("application/json;charset=UTF-8"), seriesEntity.getHeaders().getContentType());}@Testpublic void getXmlSeries() {String uri = BASE_URI + "/{seriesId}";ResponseEntity<Series> seriesEntity = restTemplate.getForEntity(uri, Series.class, 1L);assertNotNull(seriesEntity.getBody());assertEquals(1l, seriesEntity.getBody().getId());assertEquals("The walking dead", seriesEntity.getBody().getName());assertEquals("USA", seriesEntity.getBody().getCountry());assertEquals("Thriller", seriesEntity.getBody().getGenre());assertEquals(MediaType.APPLICATION_XML, seriesEntity.getHeaders().getContentType());} }

就是這樣,Web應用程序已經過測試并正在運行。 現在是時候遷移到Spring 4了。

3遷移到Spring 4

檢查此頁面以閱讀有關從早期版本的Spring框架進行遷移的信息

3.1更改Maven依賴項

本節說明應修改哪些依賴項。 您可以在此處查看完整的pom.xml。

第一步是將Spring依賴版本從3.2.3.RELEASE更改為4.0.0.RELEASE:

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.0.0.RELEASE</version> </dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.0.0.RELEASE</version> </dependency>

下一步是更新到Servlet 3.0規范。 這一步很重要,因為某些Spring功能基于Servlet 3.0,因此將不可用。 事實上,試圖執行SeriesIntegrationTesting將導致一個ClassNotFoundException由于這個原因,這也解釋了這里 。

<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version> </dependency>

3.2更新Spring名稱空間

不要忘記更改spring配置文件的名稱空間:

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

請查看第2節中鏈接的信息頁面,因為有關mvc名稱空間的某些更改。

3.3棄用杰克遜庫

如果再次檢查SeriesFunctionalTesting(設置方法),您會發現杰克遜轉換器已被棄用。 如果您嘗試運行測試,由于Jackson庫中的方法更改,它將拋出NoSuchMethodError:

java.lang.NoSuchMethodError: org.codehaus.jackson.map.ObjectMapper.getTypeFactory()Lorg/codehaus/jackson/map/type/TypeFactory

在Spring4中,已不再支持Jackson 1.x,而支持Jackson v2。 讓我們更改舊的依賴項:

<dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.4.2</version> </dependency>

對于這些:

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.3.0</version> </dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.3.0</version> </dependency>

最后,如果要顯式注冊消息轉換器,則需要為新版本更改不推薦使用的類:

//converters.add(new MappingJacksonHttpMessageConverter()); converters.add(new MappingJackson2HttpMessageConverter());

3.4遷移完成

遷移完成。 現在,您可以運行該應用程序并執行其測試。 下一節將回顧我在本文開頭提到的一些改進。

4 Spring 4 Web改進

4.1 @ResponseBody和@RestController

如果您的REST API以JSON或XML格式提供內容,則某些API方法(用@RequestMapping注釋)的返回類型將用@ResponseBody注釋。 使用此注釋,返回類型將包含在響應主體中。 在Spring4中,我們可以通過兩種方式簡化此過程:

用@ResponseBody注釋控制器

現在可以在類型級別添加此注釋。 這樣,注釋就被繼承了,我們不必強迫將注釋放在每個方法中。

@Controller @ResponseBody public class SeriesController {

用@RestController注釋控制器

@RestController public class SeriesController {

此注釋甚至進一步簡化了控制器。 如果我們檢查此注釋,我們將看到它本身已使用@Controller和@ResponseBody進行了注釋:

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController {

包括此注釋將不會影響使用@ResponseEntity注釋的方法。 處理程序適配器查找返回值處理程序的列表,以確定誰有能力處理響應。 的
在ResponseBody類型之前會先詢問負責處理ResponseEntity返回類型的處理程序 ,因此,如果方法中存在ResponseEntity批注,則將使用該處理程序。

4.2異步調用

使用實用程序類RestTemplate調用RESTful服務將阻塞線程,直到它收到響應為止。 Spring 4包含AsyncRestTemplate以便執行異步調用。 現在,您可以撥打電話,繼續進行其他計算,并在以后檢索響應。

@Test public void getAllSeriesAsync() throws InterruptedException, ExecutionException {logger.info("Calling async /series");Future<ResponseEntity<Series[]>> futureEntity = asyncRestTemplate.getForEntity(BASE_URI, Series[].class);logger.info("Doing other async stuff...");logger.info("Blocking to receive response...");ResponseEntity<Series[]> entity = futureEntity.get();logger.info("Response received");Series[] series = entity.getBody();assertNotNull(series);assertEquals(2, series.length);assertEquals(1L, series[0].getId());assertEquals("The walking dead", series[0].getName());assertEquals("USA", series[0].getCountry());assertEquals("Thriller", series[0].getGenre());assertEquals(2L, series[1].getId());assertEquals("Homeland", series[1].getName());assertEquals("USA", series[1].getCountry());assertEquals("Drama", series[1].getGenre()); }

帶回調的異步調用

盡管前面的示例進行了異步調用,但如果尚未發送響應,則嘗試使用futureEntity.get()檢索響應時,線程將阻塞。

AsyncRestTemplate返回ListenableFuture ,它擴展了Future并允許我們注冊一個回調。 以下示例進行異步調用,并繼續執行其自己的任務。 當服務返回響應時,它將由回調處理:

@Test public void getAllSeriesAsyncCallable() throws InterruptedException, ExecutionException {logger.info("Calling async callable /series");ListenableFuture<ResponseEntity<Series[]>> futureEntity = asyncRestTemplate.getForEntity(BASE_URI, Series[].class);futureEntity.addCallback(new ListenableFutureCallback<ResponseEntity<Series[]>>() {@Overridepublic void onSuccess(ResponseEntity<Series[]> entity) {logger.info("Response received (async callable)");Series[] series = entity.getBody();validateList(series);}@Overridepublic void onFailure(Throwable t) {fail();}});logger.info("Doing other async callable stuff ...");Thread.sleep(6000); //waits for the service to send the response }

5結論

我們使用了Spring 3.2.x Web應用程序,并將其遷移到Spring 4.0.0的新版本中。 我們還回顧了可以應用于Spring 4 Web應用程序的一些改進。

我正在Google Plus和Twitter上發布我的新帖子。 如果您要更新新內容,請關注我。

參考:在XavierPadró的Blog博客上,從我們的JCG合作伙伴 Xavier Padro將Spring MVC RESTful Web服務遷移到Spring 4 。

翻譯自: https://www.javacodegeeks.com/2014/02/migrating-spring-mvc-restful-web-services-to-spring-4.html

總結

以上是生活随笔為你收集整理的将Spring MVC RESTful Web服务迁移到Spring 4的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。