Spring就是一個大大的插線板,上面插着各種各樣的Bean。
SpringBoot大大簡化了Spring的配置,將原來放在XML中的配置大量的在代碼中使用注解實現。這么做有利有弊,總體上利大於弊。
使用注解的方式在Spring中注冊Bean,有四種方式:
- Component
- Service
- Controller,RestController
- Repository
上面這四個注解真是SpringBoot的核心。因為要想使用
@Value
屬性注入@Resource
,@Autowired
自動注入
就必須讓Spring能夠看見使用這些注解的類,也就是說必須在Spring中注冊Bean,Spring才會統一幫你管理。
上面“Component”等注解都是用來注解類,注解接口要使用@Bean
注解。當讓Spring注入接口時,如果接口有多個實例類,需要用@Resource("myUserDaoImpl")
這種方式注明實例類的名稱;如果接口只有一個實例類,Spring會自動檢測合適的類型進行注入。
沒有Spring的時候,各個Bean形成的依賴關系是一個錯綜復雜的圖狀結構。有了Spring,各個Bean之間松耦合,各個Bean只跟Spring容器有聯系,這就形成了總線型的依賴,大大簡化了類與類之間的依賴關系。
下面進入正題,我編寫了一個Controller,返回User類型的數據,Spring會把User轉化成JSON字符串,現在我想對這個字符串進行一些處理再返回。要求不能更改Controller部分的代碼,因為我要對全部的返回的JSON都進行這種處理,如果改Controller的話需要更改好多地方。
@RestController
class MyController {
@RequestMapping("user")
User getUser() {
return new User("weidiao", 25);
}
}
雖然這個函數返回的User類型,實際上Spring會把這個對象轉換成JSON。跟@ResponseBody
、@RequestBody
兩個注解密切相關的一個接口是:HttpMessageConverter。
消息轉換器的目標是:HTTP輸入請求格式向Java對象的轉換;Java對象向HTTP輸出請求的轉換。有的消息轉換器只支持多個數據類型,有的只支持多個輸出格式,還有的兩者兼備。
HttpMessageConverter 接口提供了5個方法:
- canRead :判斷該轉換器是否能將請求內容轉換成Java對象
- canWrite :判斷該轉換器是否可以將Java對象轉換成返回內容
- getSupportedMediaTypes :獲得該轉換器支持的MediaType類型
- read :讀取請求內容並轉換成Java對象
- write :將Java對象轉換后寫入返回內容
其中 read 和 write 方法的參數分別有有 HttpInputMessage 和 HttpOutputMessage 對象,這兩個對象分別代表着一次Http通訊中的請求和響應部分,可以通過 getBody 方法獲得對應的輸入流和輸出流。
Spring已經默認包含了常用的消息轉換器:
名稱 | 作用 | 讀支持MediaType | 寫支持MediaType |
---|---|---|---|
ByteArrayHttpMessageConverter | 數據與字節數組的相互轉換 | / | application/octet-stream |
StringHttpMessageConverter | 數據與String類型的相互轉換 | text/* | text/plain |
FormHttpMessageConverter | 表單與MultiValueMap<string, string=””> 的相互轉換 |
application/x-www-form-urlencoded | application/x-www-form-urlencoded |
SourceHttpMessageConverter | 數據與javax.xml.transform.Source的相互轉換 | text/xml和application/xml | text/xml和application/xml |
MarshallingHttpMessageConverter | 使用Spring的Marshaller/Unmarshaller轉換XML數據 | text/xml和application/xml | text/xml和application/xml |
MappingJackson2HttpMessageConverter | 使用Jackson的ObjectMapper轉換Json數據 | application/json | application/json |
MappingJackson2XmlHttpMessageConverter | 使用Jackson的XmlMapper轉換XML數據 | application/xml application/xml | |
BufferedImageHttpMessageConverter | 數據與java.awt.image.BufferedImage的相互轉換 Java I/O API支持的所有類型 | Java I/O API支持的所有類型 |
請看實現
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
@Component
public class MyHttpMessageConverter implements HttpMessageConverter<Object> {
@Override
public boolean canRead(Class<?> aClass, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Class<?> aClass, MediaType mediaType) {
return true;
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8);
}
@Override
public Object read(Class<?> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(Object o, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
PrintWriter cout = new PrintWriter(httpOutputMessage.getBody());
JSONObject ans = new JSONObject();
ans.put("object", o);
ans.put("successful", o != null);
cout.write(JSON.toJSONString(ans, true));
cout.close();
}
}
使用@Component
注解這個類就能夠讓Spring知道:這里有一個消息轉換器。這樣Spring就會使用它。