@RequestBody傳遞多個不同對象
如果使用spring mvc同客戶端通信,完全使用json數據格式,需要增加RequestBody注解,函數參數為自定義類
1
2
3
4
5
6
7
8
|
@Controller public class TestController{ @RequestMapping ( "\test" ) @ResponseBody public RetureResult test( @RequestBody User user){ return new ReturnResult(); } } |
這樣的話,可以將接收到的json格式的數據轉換為指定的數據對象user。比如{name:"test"},name為User類的屬性域。通過ResponseBody注解,可以返回json格式的數據。
有時接收json格式數據時,我們可能需要將其轉換為多個對象。
以下方式是錯誤的。原因是request的content-body是以流的形式進行讀取的,讀取完一次后,便無法再次讀取了。
1
2
3
4
5
6
7
8
|
@Controller public class TestController{ @RequestMapping ( "\test" ) @ResponseBody public RetureResult test( @RequestBody User user, @RequestBody Address address){ return new ReturnResult(); } } |
解決方案1
增加一個包裝類,將所需要類寫入,增加get,set方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@Controller public class TestController{ @RequestMapping ( "\test" ) @ResponseBody public RetureResult test( @RequestBody Param param){ User user=param.getUser(); Address address=param.getAddress(); return new ReturnResult(); } } class Param{ private User user; private Address address; public User getUser() { return user; } public void setUser(User user) { this .user = user; } public Address getAddress() { return address; } public void setAddress(Address address) { this .address = address; } } |
此時傳輸的json數據格式變為{user:{name:"test"},address:{location:"新華路"}}。
由于只是在TestController中增加一個包裝類,不會影響其他的類以及已經定義好的model類,因此可以非常方便的達到接收多個對象參數的目的。
解決方案2
將接收參數定義為Map<String, Object>,然后使用map轉object工具,轉換成需要的對象。
此時,即使自定義的Param類中的屬性即使比json數據中的屬性少了,也沒關系。
其中JSONUtils為自定義的工具類,可使用常見的fastjson等工具包包裝實現。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@Controller public class TestController{ @RequestMapping ( "\test" ) @ResponseBody public Object test( @RequestBody Map<String, Object> models){ User user=JsonXMLUtils.map2object((Map<String, Object>)models.get( "user" ),User. class ); Address address=JsonXMLUtils.map2object((Map<String, Object>)models.get( "address" ),Address. class ); return models; } } import com.alibaba.fastjson.JSON; public class JsonXMLUtils { public static String obj2json(Object obj) throws Exception { return JSON.toJSONString(obj); } public static <T> T json2obj(String jsonStr, Class<T> clazz) throws Exception { return JSON.parseObject(jsonStr, clazz); } public static <T> Map<String, Object> json2map(String jsonStr) throws Exception { return JSON.parseObject(jsonStr, Map. class ); } public static <T> T map2obj(Map<?, ?> map, Class<T> clazz) throws Exception { return JSON.parseObject(JSON.toJSONString(map), clazz); } } |
使用多個@RequestBody接收參數
原因
常規情況下,因為request的body只能讀取一次,@RequestBody也只能解析一次,這就導致解析第二個的@RequestBody的時候stream已經關閉了,無法再次讀取。
話不多說,上貨:
解決辦法:兩個類,直接copy即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; public class BodyReaderRequestWrapper extends HttpServletRequestWrapper { private final String body; /** * * @param request */ public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException{ super (request); StringBuilder sb = new StringBuilder(); InputStream ins = request.getInputStream(); BufferedReader isr = null ; try { if (ins != null ){ isr = new BufferedReader( new InputStreamReader(ins)); char [] charBuffer = new char [ 128 ]; int readCount = 0 ; while ((readCount = isr.read(charBuffer)) != - 1 ){ sb.append(charBuffer, 0 ,readCount); } } else { sb.append( "" ); } } catch (IOException e){ throw e; } finally { if (isr != null ) { isr.close(); } } sb.toString(); body = sb.toString(); } @Override public BufferedReader getReader() throws IOException { return new BufferedReader( new InputStreamReader( this .getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes()); ServletInputStream servletIns = new ServletInputStream() { @Override public boolean isFinished() { return false ; } @Override public boolean isReady() { return false ; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException { return byteArrayIns.read(); } }; return servletIns; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component @WebFilter (filterName = "crownFilter" , urlPatterns = "/*" ) public class BodyReaderRequestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)res; BodyReaderRequestWrapper requestWrapper = new BodyReaderRequestWrapper(request); if (requestWrapper == null ){ filterChain.doFilter(request,response); } else { filterChain.doFilter(requestWrapper,response); } } @Override public void destroy() { } } |
使用:自行測試。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/sunayn/article/details/106214391