Several ways Spring MVC handles json type requests and returns Json format

Several ways Spring MVC handles json type requests and returns Json format

One, @RequestBody annotation

It can help us parse the json data sent by the client (mobile device, browser, etc.) and encapsulate it into the entity class.
Commonly used http request MIME types are application/json, text/html, text/xml, image/jpeg, etc., which are Content-Type types corresponding to fixed formats.
In the syntax of the form element in the web page, EncType indicates the format of the submitted data. Use the Enctype attribute to specify the encoding type used by the browser when sending the data back to the server.
E.g:

  • application/x-www-form-urlencoded: The form data is encoded as name/value pairs. This is the default (standard) encoding format. When the method of the form is get, the browser uses the encoding method of x-www-form-urlencoded to convert the form data into a string (name1=value1&name2=value2...), and then append this string to the back of the url and divide it with? , Load this new url.
  • multipart/form-data: The form data is encoded as a message. Each control on the page corresponds to a part of the message. This is generally used when uploading files. When the action is post, the browser encapsulates the form data in the http body and sends it to the server. If there is no type=file control, use the default application/x-www-form-urlencoded. But if there is type=file, multipart/form-data will be used. The browser will divide the entire form in units of controls, and add Content-Disposition (form-data or file), Content-Type (default text/plain), name (control name) and other information to each part, and Add the separator (boundary).
  • text/plain: The form data is encoded in the form of plain text, which does not contain any controls or format characters, which are not included in the type of form.
    The point is here~~~
    @ReqeustBody: It is
    often used to process content whose content-type is not the default application/x-www-form-urlcoded encoding, such as application/json or application/xml, etc., which are often used to process application /json type.
    Note: @requestBody receives the json string from the front-end, not the JSON object. In the http protocol, only the string can be transmitted. The object can only exist in the front-end or back-end language, so the front-end Json object must use javascript Provide the JSON.stringify() method to convert to json string.
    In addition, when using JQuery's ajax, the default content-type type is application/x-www-form-urlcoded.
    A JQuery ajax code example
// Jquery Ajax请求
$.ajax({
    
    
    url : "doindex.action",
    type : "POST",
    contentType : "application/json;charset=UTF-8",
    data :JSON.stringify(json),
    dataType : "json",
    success : function(data) {
    
    
    }
});

Note that the contentType in ajax: "application/json;charset=UTF-8", charset=UTF-8 must be written in it, otherwise the backend is prone to Chinese garbled characters, and the default character set of tomcat is not utf-8
. The @RequestBody annotation is used in the signature of the end method to read the json string passed in the previous paragraph, see an example

@RequestMapping("/doindex.action")
    public @ResponseBody Customer getPages(@RequestBody(required=true) Map<String,Object> map , HttpServletRequest request)throws Exception{
    
    
        Customer cust=new Customer();
        cust.setLcname("马雷");
        cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
        //mv.addObject(cust);
        //Map<String,Object> map=new HashMap();
        //map.put("cust",cust);
        ObjectMapper om=new ObjectMapper();
        om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        //ModelAndView mv=new ModelAndView(new MappingJackson2JsonView(om),cust);
        return cust;
    }

Regardless of the meaning of the specific code in the method body, the json string parameter information from the front end is automatically filled into the Map<String,Object> map type marked by @RequestBody(required=true). How is this done?
Spring has built a lot of HttpMessageConverter for us, for example, MappingJackson2HttpMessageConverter, StringHttpMessageConverter, etc. Mainly to cooperate with @RequestBody and @ResponsetBody.
The HttpMessageConverter interface is a newly added interface in Spring 3.0, which is responsible for 1, converting the request information into an object (type T), and 2, outputting the object (type T) as response information.
Take a look at the interface code

public interface HttpMessageConverter<T> {
    
    
    //指定转换器 可以读取的对象类型,即转换器是否可将请求信息转换为clazz类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)
    boolean canRead(Class<?> var1, MediaType var2);
    //指定转换器 是否可将 clazz类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。–LIst getSupportMediaTypes():该转换器支持的媒体类型
    boolean canWrite(Class<?> var1, MediaType var2);
	
    List<MediaType> getSupportedMediaTypes();
	//将请求信息流转换为 T 类型的对象
    T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;
     //将T类型的对象写到响应流中,同时指定相应的媒体类型为contentType
    void write(T var1, MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}

From the above interface code, it can be seen that the converter can convert the request information, or the response information can be automatically converted, so based on the previous ajax request example, the back-end code receiving method can be

  //以下三种方法头都可以接收前段ajax传入的非application/x-www-form-urlcoded类型信息
 //将传入的json参数自动封装到map里,参数名成是key,参数值时value
 public @ResponseBody Customer getPages(@RequestBody(required=true) Map<String,Object> map , HttpServletRequest request)
 //将传入的json字符串直接复制给username字段
 public @ResponseBody Customer getPages(@RequestBody(required=true) String username, HttpServletRequest request)
 //将传入的json字符串中每个字段的值赋给user对象实例对应名称的属性
 public @ResponseBody Customer getPages(@RequestBody(required=true) User user , HttpServletRequest request)

Note: The above is to use the SpringMVC default converter. If you specify other converters in the springmvc configuration file, there is no guarantee that the above automatic encapsulation can be realized, depending on the specified converter function.

Two, @ResponseBody annotation

It is used to convert the object returned by the Controller method into data in the specified format through the HttpMessageConverter interface, such as json, xml, etc., and respond to the client through the Response.
Note: It is not necessary to only pass the string, if there is a corresponding java class, SpringMVC will automatically help convert it into a data format that meets the requirements (json/xml).
Here are several methods that can be returned to the corresponding type of json in the previous section after actual measurement:

1. Prerequisite configuration for the following methods

In web.xml, configure an interception of *.action in DispatcherServlet request interception, which is used to process the json return. If it is not added, the configured view resolver will be called by default to resolve it. If the resolution fails, an error 406 will be reported. So after adding a new mapping type, json returns are processed specially.

<servlet-mapping>
  <servlet-name>miniappservice</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 解决*.html后缀请求,无法返回json -->
<servlet-mapping>
  <servlet-name>miniappservice</servlet-name>
  <url-pattern>*.action</url-pattern>
 </servlet-mapping>

When request interception is added

<servlet-mapping>
  <servlet-name>miniappservice</servlet-name>
  <url-pattern>*.action</url-pattern>
 </servlet-mapping>

All previous requests that need to return json must be suffixed with action. Of course, action can be changed to any name such as do

2. Several @ResponseBody that return json format

Since processing the json format in springmvc requires the support of some jar packages, first add the following dependencies to the pom list:

    <!--com.fasterxml.jackson.databind.ObjectMapper servlet配置需要-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.10.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.10.1</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.10.1</version>
    </dependency>
  • Use the MappingJackson2JsonView view to return the json
    springmvc configuration file ( **-servlet.xml) to configure the JSP view parser;
    configure in the springmvc configuration file ( **-servlet.xml) <mvc:annotation-driven/>;
    method use @ResponseBodyannotation;
    configure the MappingJackson2JsonView view in the returned ModelAndView, and return the entity instance of json , Collection or map type directly copied to ModelAndView, here to pay attention to the following, if the entity instance, collection or map type to be returned is added to ModelAndView and the name is specified, the returned json name is the specified name, if no name is specified, the returned json The name is the lowercase name of the entity instance, collection, or map type name. See an example
  @RequestMapping("/test1.action")
    @ResponseBody
    public ModelAndView getDo1(@RequestBody(required=true) String username , HttpServletRequest request){
    
    
        Customer cust=new Customer();
        cust.setLcname("测试");
        cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
        ModelAndView mv=new ModelAndView(new MappingJackson2JsonView());
        mv.addObject(cust);
        return mv;
    }

The parameter requested by the front end is a json string {"username":"测试","password":"123456fg"}, and the injected value obtained by the @RequestBody string type parameter username in the method is the json string passed from the front end.
The response output returned to the previous stage after the getDo1 method is executed is:

{
    
    "customer":{
    
    "sysId":null,"createtime":1577084421101,,"lcname":"马雷"}}

It can be seen that the json output to the front end outputs the lowercase class name of the cust instance as the key of the json string, and the date createtime is output according to the timestamp type. If you want to format the time output, you need to use the com.fasterxml.jackson.databind.ObjectMapperclass At this time, modify the above code as follows:

@RequestMapping("/test2.action")
    @ResponseBody
    public ModelAndView getDo2(@RequestBody(required=true) String username , HttpServletRequest request){
    
    
        Customer cust=new Customer();
        cust.setLcname("马雷");
        cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
        //引入格式化
        ObjectMapper om=new ObjectMapper();
        om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        ModelAndView mv=new ModelAndView(new MappingJackson2JsonView(om));
        mv.addObject(cust);
        return mv;
    }

The request parameters remain unchanged, and the corresponding results are as follows:

{
    
    "customer":{
    
    "sysId":null,"2019-12-23 15:10:41","lcname":"马雷"}}
  • Directly return the object type and output the json format
    springmvc configuration file ( **-servlet.xml) to configure the view parser of JSP;
    configure in the springmvc configuration file ( **-servlet.xml) <mvc:annotation-driven/>;
    method use @ResponseBodyannotation;
    method above:
 @RequestMapping("/test3.action")
    public @ResponseBody Map<String,Object> getDo3(@RequestBody(required=true) String username , HttpServletRequest request){
    
    
        Customer cust=new Customer();
        cust.setLcname("测试");
        cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
        Map<String,Object> map=new HashMap<>();
        map.put("customer",cust);
        return map;
    }

@ResponseBody can be marked on the method or on the method signature;
the parameters requested by the front-end are still json strings {"username":"测试","password":"123456fg"}. In the following introduction, each request parameter of the front-end is this string, so I will not repeat them separately.
The corresponding output result to the front end is:

{
    
    "customer":{
    
    "sysId":null,"createtime":1577085315542,"lcname":"测试"}}

It can be seen that createtime is still the output timestamp, and there is no good way to convert it into a date and time format.
Note: The difference between the above two methods
1. To format the date, only the first one can be used;
2. If the output json needs {"key":"value","key":"value"} format, you can use the first Two types or the first type and the second type use map encapsulation;

  • MappingJackson2HttpMessageConverter implements json output.
    First **-servlet.xmlconfigure the following code in the springmvc configuration file ( )
   <!-- mvc:annotation-driven:使用mvc注解,解决406同时解决时间问题 -->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                        <property name="dateFormat">
                            <bean class="java.text.SimpleDateFormat">
                                <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />
                            </bean>
                        </property>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

The above code replaces mvc:annotation-driven; the
second step is to use @ResponseBody annotation in or on the method, see the code

@RequestMapping("/test4.action")
    public @ResponseBody Customer getDo4(String username,String password, HttpServletRequest request){
    
    
        Customer cust=new Customer();
        cust.setLcname("测试");
        cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
        return cust;
    }

The front end uses the application/x-www-form-urlcoded format, and the url is test4.action?username=测试&password=123456fg; the
response output is

{
    
    
    "sysId": null,
    "createtime": "2019-12-23 16:08:17",
    "lcname": "测试"
}

The front-end can also use the application/json;charset=UTF-8 format, and the back-end method is as follows:

@RequestMapping("/test4.action")
    public @ResponseBody List<Customer> getDo4(@RequestBody(required=true) Map<String,Object> map1 , HttpServletRequest request){
    
    
        Customer cust=new Customer();
        cust.setLcname("测试");
        cust.setCreatetime(new Timestamp(System.currentTimeMillis()));
        List<Customer> map=new ArrayList<>();
        map.add(cust);
        return map;
    }

I want to emphasize here that when using @RequestBody signature, you can encapsulate the map to receive the json string from the front-end, or use the entity class to receive the json string from the front-end. You cannot directly use the string string to receive the front-end. If the json is used, it will report a 400 error. In addition, if the entity class is used to receive the json string of the front-end string, the attribute of the entity class is less than the attribute of the passed string, the 400 error will also be reported.
The advantage of using this method to output json, you can format the date;

In addition, I introduce a tool, posman is used to simulate requests for debugging, and it is particularly good. Give two reference addresses:
download address,
instructions for use,
win7 patch

Guess you like

Origin blog.csdn.net/u011930054/article/details/103663772