Spring MVC對象轉換說明


在Spring MVC之前我們需要在Servlet里處理HttpServletRequest參數對象,但這個對象里的屬性都是通用類型的對象(如字符串),處理起來很繁瑣並且容易出錯,而Spring MVC允許我們直接把參數和返回值定義為對象,比如:

先定義一個對象:

@Data
public class User {

    private String id;
    private String name;

}

然后定義一個Spring MVC方法:

@RequestMapping(value = "/create-user", method = RequestMethod.POST)
public void createUser(@RequestBody User user) {
    LOGGER.debug("參數:user = {}", user);
}

其中,參數為User類型的對象,@RequestBody注解通知Spring MVC把http請求的body轉換為User對象,並作為參數調用我們寫的createUser方法。

除把參數定義為對象外,返回值也能為對象:

@RequestMapping(value = "/find-user", method = RequestMethod.GET)
@ResponseBody
public User findUser() {
    return new User("01", "yw");
}

返回值對象需要加@ResponseBody注解,該注解通知Spring MVC把返回值對象轉換為字符串,並作為http響應消息中的body部分。

除@RequestBody、@ResponseBody注解外,Spring MVC還提供了其它注解,具體請參見相關文檔說明。

Spring MVC是如何進行http消息與對象之間的轉換呢?答案是HttpMessageConverter轉換器接口。

 

HttpMessageConverter

Spring MVC就像是一個中間人,一邊為http消息(即HttpServletRequest和HttpServletResponse),另一邊是@RequestMapping方法,Spring MVC的使命就是自動把http消息轉換為對象,以及反過來把對象轉換為字符串返回。這一切都依賴於HttpMessageConverter轉換接口。Spring MVC內置了其很多實現,每個實現對應於一種格式的數據轉換,我們可按需配置加載轉換器。如果未配置則Spring MVC進行默認加載,至於默認加載了哪些轉換器請參見WebMvcConfigurationSupport#addDefaultHttpMessageConverters方法,另請參見[Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest)。

特別要提醒的是,如果你配置了則Spring MVC將只加載你配置的,如果你未配置則默認加載。因此,不要誤以為你的配置是對默認值的補充。

我們基本上不需要自己去配置轉換器,使用默認配置就足夠了。但如果你有必要則可這樣配置:

@Configuration
@EnableWebMvc
public class WeMvcConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(...);
    }
}

不論你是否配置了,我們最好都檢查一下運行時到底加載了哪些轉換器:

@EventListener
public void on(ContextRefreshedEvent event) {
    RequestMappingHandlerAdapter requestMappingHandlerAdapter =     applicationContext.getBean(RequestMappingHandlerAdapter.class);
    List<?> messageConverters =     requestMappingHandlerAdapter.getMessageConverters();
    StringBuilder sb = new StringBuilder();
    sb.append("Spring共加載了").append(messageConverters.size()).append("個消息轉換器對象:").append(messageConverters.toString());
    LOGGER.info(sb.toString());
}

上面的事件監聽器方法將在Spring啟動完畢后打印輸出所有加載的轉換器。你可做兩個試驗,一是自己不配置,二是自己配置,然后分別啟動系統看看到底加載了哪些轉換器。

 

JSON

如果系統加載了json轉換器你就可以發送json消息了:

curl -X POST -H 'Content-Type: application/json' -d '{"id":"01","name":"yw"}' http://localhost:8080/create-user

如果調用不成功則很可能是系統並未加載json轉換器。Spring MVC的默認配置只當存在jackson-databind時才加載json轉換器。

你可先檢查是否存在jackson-databind依賴項:

mvn dependency:tree | find "jackson-databind"

若不存在則定義之:

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

這樣Spring MVC將自動加載json轉換器。

除發送json消息外,你也可以接收json消息:

curl http://localhost:8080/find-user
{"id":"01","name":"yw"}

 

XML

同json一樣,Spring MVC也是利用轉換器來實現發送和接收xml消息。不同的是,Spring MVC只支持jackson-databind一種json轉換器,但支持jaxb和jackson-databind-xml兩種xml轉換器,你可選擇其一使用。

要讓Spring MVC自動配置jackson-databind-xml就需存在該依賴項。你可先檢查是否存在該依賴項:

mvn dependency:tree | find "jackson-databind-xml"

若不存在則定義之:

<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

接着你就可以傳xml消息了:

curl -X POST -H 'Content-Type: application/xml' -d '<root><id>01</id><name>yw</name></root>' http://localhost:8080/create-user

 

強制數據格式

如上,你的create-user方法既可接收xml消息,也可接收json消息,但有時你希望限制數據格式,此時可加consumes參數:

@RequestMapping(value = "/xml-create-user", consumes = {MediaType.APPLICATION_XML_VALUE}, method = RequestMethod.POST)
public void xmlCreateUser(@RequestBody User user) {
    LOGGER.debug("參數:user = {}", user);
}

上例表示只接收xml格式的消息。因此若你再發json消息則將失敗。

同樣,你也可以限制返回值為xml:

@RequestMapping(value = "/xml-find-user", method = RequestMethod.GET, produces = {MediaType.APPLICATION_XML_VALUE})
@ResponseBody
public User xmlFindUser() {
    return new User("02", "yw");
}

接着我們就可以接收xml消息了:

curl http://localhost:8080/xml-find-user
<User xmlns=""><id>02</id><name>yw</name></xml>

 

Jackson XML

上面說到,Spring MVC支持jackson-databind-xml作為xml轉換器,並實際測試得到返回的xml:

<User xmlns=""><id>01</id><name>yw</name></xml>

其中有 xmlns="" 。該xmlns並無什么副作用,但如果你很在意一定要去掉它則可增加依賴項:

<dependency>
  <groupId>com.fasterxml.woodstox</groupId>
  <artifactId>woodstox-core</artifactId>
  <version>5.0.2</version>
</dependency>

其原因請參見[FasterXML討論](https://github.com/FasterXML/jackson-dataformat-xml/issues/32)。

 

面向對象

上面我們花了很多篇幅介紹了json和xml,但Spring MVC給我們帶來的好處卻在於讓我們忽視它們的存在,讓我們只關注對象,無需去考慮對象是從json來的還是從xml來的,這些底層的事就交給Spring MVC去處理吧。同時,直接把我們自己的對象作為參數和返回值也使得單元測試更容易寫。

 

練習

1、如果你的系統同時有json和xml轉換器,請解釋為何用RestTemplate代碼和curl工具調用同一個Spring MVC方法時時,一個返回的是xml,另一個返回的是json?

@Test
public void test() {
    RestTemplate restTemplate = new RestTemplate();
    String s = restTemplate.getForObject("http://localhost:8080/find-user", String.class);
    System.out.println(s);
    // <User xmlns=""><id>01</id><name>yw</name></xml>
}

 

curl http://localhost:8080/find-user
{"id":"01","name":"yw"}

 

2、本說明文檔介紹了用Jackson-Xml作為Xml轉換器,同時說到你也可以用jaxb進行Xml轉換。請改為使用jaxb方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM