@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
查看更多关于使用@RequestBody传递多个不同对象方式的详细内容...