Spring专题

迁移Spring MVC RESTful到Spring4

  

Spring4主要在Web服务方面有下面两个方面提升:

1. 控制器使用@ResponseBody和 @RestController

2.异步调用。

项目迁移前后的源码:

下图是Spring 3.2的数据模型图:

Spring3.2 配置

<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>

服务代码实现:

  @Service
public class SeriesServiceImpl implements SeriesService {

@Autowired
private MongoOperations mongoOps;

@Override
public Series[] getAllSeries() {
List<Series> seriesList = mongoOps.findAll(Series.class);
return seriesList.toArray(new Series[0]);
}

@Override
public Series getSeries(long id) {
return mongoOps.findById(id, Series.class);
}

@Override
public void insertSeries(Series series) {
mongoOps.insert(series);
}

@Override
public void deleteSeries(long id) {
Query query = new Query();
Criteria criteria = new Criteria("_id").is(id);
query.addCriteria(criteria);

mongoOps.remove(query, Series.class);
}
}

控制器实现:


01 @Controller
02 @RequestMapping(value="/series")
03 public class SeriesController {
04      
05     private SeriesService seriesService;
06      
07     @Autowired
08     public SeriesController(SeriesService seriesService) {
09         this.seriesService = seriesService;
10     }
11      
12     @RequestMapping(method=RequestMethod.GET)
13     @ResponseBody
14     public Series[] getAllSeries() {
15         return seriesService.getAllSeries();
16     }
17      
18     @RequestMapping(value="/{seriesId}", method=RequestMethod.GET)
19     public ResponseEntity<Series> getSeries(@PathVariable("seriesId") long id) {
20         Series series = seriesService.getSeries(id);
21          
22         if (series == null) {
23             return new ResponseEntity<Series>(HttpStatus.NOT_FOUND);
24         }
25          
26         return new ResponseEntity<Series>(series, HttpStatus.OK);
27     }
28      
29     @RequestMapping(method=RequestMethod.POST)
30     @ResponseStatus(HttpStatus.CREATED)
31     public void insertSeries(@RequestBody Series series, HttpServletRequest request, HttpServletResponse response) {
32         seriesService.insertSeries(series);
33         response.setHeader("Location", request.getRequestURL().append("/").append(series.getId()).toString());
34     }
35      
36     @RequestMapping(value="/{seriesId}", method=RequestMethod.DELETE)
37     @ResponseStatus(HttpStatus.NO_CONTENT)
38     public void deleteSeries(@PathVariable("seriesId") long id) {
39         seriesService.deleteSeries(id);
40     }
41 }

迁移到Spring 4

 

1. 改变Maven的依赖:

<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改为serv;et 3.1

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

2.改变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

3.jackson升级

原来是1.4版本:

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

现在是2.3:

<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());

如果REST有JSON or XML格式,原来@ResponseBody是标注在方法上,从4.0以后可以标注在类上:

@Controller
@ResponseBody
public class SeriesController {

另外使用使用@RestController更加简化 ,只需一个 @RestController即可:

@RestController
public class SeriesController {

Spring 4.0 包含了通过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());
}