How to pass multiple different object using @ RequestBody

  • 2021-12-04 09:57:13
  • OfStack

Directory @ RequestBody Pass Multiple Different Objects Solution 1 Solution 2 Use Multiple @ RequestBody Receive Parameters Reason Solution: Two classes, just copy

@ RequestBody passes multiple different objects

If you use spring mvc to communicate with the client, and use json data format completely, you need to add RequestBody annotation, and the function parameter is custom class


@Controller
public class TestController{
  @RequestMapping("\test")
  @ResponseBody
  public RetureResult test(@RequestBody User user){
    return new ReturnResult();
  }  
}

In this case, the received data in json format can be converted to the specified data object user. For example, {name: "test"}, name is the attribute field of User class. With ResponseBody annotations, you can return data in json format.

Sometimes when we receive data in json format, we may need to convert it into multiple objects.

The following approach is wrong. The reason is that content-body of request is read in the form of stream, and after reading once, it cannot be read again.


@Controller
public class TestController{
  @RequestMapping("\test")
  @ResponseBody
  public RetureResult test(@RequestBody User user,@RequestBody Address address){
    return new ReturnResult();
  }  
}

Solution 1

Add 1 wrapper class, write the required class, and add get and set methods


@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;
    }
}

At this time, the transmitted json data format changes to {user: {name: "test"}, address: {location: "Xinhua Road"}}.

Because only one wrapper class is added in TestController, it will not affect other classes and the defined model class, so it is very convenient to receive multiple object parameters.

Solution 2

Define the receive parameter as Map < String, Object > And then use the map to object tool to convert it to the desired object.

At this point, it doesn't matter if there are fewer attributes in the custom Param class than in the json data.

Among them, JSONUtils is a custom tool class, which can be wrapped and implemented by common toolkits such as fastjson.


@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);
    }
}

Use multiple @ RequestBody receive parameters

Cause

Under normal circumstances, because body of request can only be read once, and @ RequestBody can only be parsed once, stream has been turned off when parsing the second @ RequestBody, so it cannot be read again.

Not much to say, loading:

Solution: Two classes, just copy directly


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

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() { 
    }
}

Use: Self-test.


Related articles: