你的位置:首页 > Java教程

[Java教程]SpringMVC——对Ajax的处理(包含 JSON 类型)


一、首先要搞明白的一些事情。

1.从客户端来看,需要搞明白:

(1)要发送什么样格式的 JSON 数据才能被服务器端的 SpringMVC 很便捷的处理,怎么才能让我们写更少的代码,如何做好 JSON 数据和实体之间的对应。

(2)如何组织这些发送的数据。

2.从服务器端来看,需要搞明白:

(1)SpringMVC 如何返回 JSON 数据。

(2)SpringMVC 如何处理请求的复杂数据。

3.$.ajax 的几个参数:

(1)contentType:

contentType: 'application/json;charset=utf-8',作为请求头,用来告诉服务器消息的主体是序列化后的 JSON 字符串。除了低版本的 ie 浏览器外,各大浏览器都原生支持 JSON.stringify() 对对象进行序列化。

(2)dataType:预期服务器返回的数据类型。

4.SpringMVC 是如何处理 JSON 数据的

5.总体的思想:

(1)SpringMVC 能完成的,尽量借助于 SpringMVC,而不是我们手动的去解析。

(2)SpringMVC 解析不了的,尽量借助于第三方的 Jar 包来解析。

(3)SpringMVC 和 第三方 Jar 包解决不了的时候,我们再自己去解析。

 

二、想要搞明白第一个问题,前提是先要搞明白第一个问题:SpringMVC 是如何处理 JSON 数据的。

1.使用 HttpMessageConverter<T> 来处理  JSON 数据的。

Spring 的 HttpMessageConverter<T> 负责将请求信息转换为一个对象,将对象输出为响应信息。

2.API

(1)boolean canRead(Class<?> clazz, MediaType mediaType);

转换器是否可将请求信息转换为 clazz 类型的对象,同时支持指定的 MIME 类型,如: text/html,application/json 等。

(2)boolean canWrite(Class<?> clazz, MediaType mediaType);

转换器是否可以将 clazz 类型的对象写到响应中,响应支持的类型在 mediaType 中定义。

(3)List<MediaType> getSupportedMediaTypes();

改转换器支持的 MediaType 类型。

(4)T read(Class<? extends T> clazz, HttpInputMessage inputMessage);

将请求信息流转换为 clazz 类型的对象。

(5)void write(T t, MediaType contentType, HttpOutputMessage outputMessage)。

将 T 类型的对象写到响应输出流中,同时指定 MediaType。

3.实现类

3.从上图可以看出,Spring 默认支持使用 Jackson来处理 JSON 问题。添加 Jackson Jar 包后,来看 RequestMappingHadlerAdapter 装配的 HttpMessageConverter:

导入的 Jackson Jar 包:

4.具体的处理方法:

(1)使用 @RequestBody 和 HttpEntity<T> 对请求进行处理。

(2)使用 @ResponseBody 和 ResponseEntity<T> 对响应进行处理。

(3)@RequestBody 对处理方法的入参进行标注。

(4)@ResponseBody 对处理方法的签名进行标注。

(5)HttpEntity<T> 和 ResponseEntity<T> 作为处理方法的入参使用。

具体的使用方法会在下面例子中进行说明。

5.@RequestBody 和 @ResponseBody 是可以同时使用的。

 

三、上面简单介绍了 SpringMVC 是怎么处理 JSON 数据的,现在来看第二个问题:发送什么样格式的 JSON 数据才能被服务器端的 SpringMVC 很便捷的处理,这里主要指的是请求的 JSON 字符串和实体的映射。

以一个简单的实体为例:Person

/** * @author solverpeng * @create 2016-08-12-10:50 */public class Person {  private String name;  private Integer age;  public Person() {  }  public Person(String name, Integer age) {    this.name = name;    this.age = age;  }  @NotBlank(message = "人名不能为空")  public String getName() {    return name;  }  public void setName(String name) {    this.name = name;  }  public int getAge() {    return age;  }  public void setAge(int age) {    this.age = age;  }  @Override  public String toString() {    return "Person{" +        "name='" + name + '\'' +        ", age=" + age +        '}';  }}

Person.java

(1)对于简单的一个Person 对象来说,我们甚至都不需要借助于 JSON 就可以完成请求的数据与实体之间的映射。

请求:

$("#testJson").click(function () {  $.ajax({    url: "testJson",    type: "post",    data: {      name : "abc",      age : "23"    },    success: function (result) {      console.log(result);    }  });});

handler 方法:

@RequestMapping("/testJson")public Person testJson(Person person) {  System.out.println("person:" + person);  return person;}

(2)对于Person数组来说,需要发送什么样的格式才能被 SpringMVC 直接处理?

请求:

$("#testJson6").click(function () {  $.ajax({    url: "testJson6",    type: "post",    data:'[{ "name": "Brett", "age":"12" }, { "name": "Jason", "age":"23" }, { "name": "Elliotte", "age":"33" }]',    contentType: "application/json; charset=utf-8",    success: function (result) {      console.log(result);    }  });});

handler 方法:

@RequestMapping("/testJson6")public String testJson6(@RequestBody List<Person> persons) {  System.out.println("persons:" + persons);  return "success";}

注意:

(1)需要指定 "contentType",同时需要注意的是:发送的请求数据不在 Form data 中,而是在 Request Payload 中。关于 [Request Payload] ,在后面说明。

(2)必须要指定 @RequestBody ,否则无法解析。

 

四、第三个问题:如何组织这些数据以及SpringMVC 如何处理这些数据,做好映射。

(1)说明:

上面说的两个例子,仅仅是最简单的一种形式。现在对其进行扩展,在四里,所说的 SpringMVC 如何处理这些数据,不仅仅指的是SpringMVC,也包括SpringMVC处理不了,使用第三方来处理,或者第三方处理不了,我自己来处理。

同时这里的数据也不仅仅指的 JSON 类型的数据。

(2)对于非表单的 Ajax 提交,这里只提供比较简单的一种方式。还是以上面的 Person 为例。

e1:

数据的组织与请求的发送:

var personList = [];personList.push({name: "李四",age: "23"});personList.push({name: "张三",age: "12"});$("#testJson5").click(function () {  $.ajax({    type: "POST",    url: "testJson5",    data: JSON.stringify(personList),//将对象序列化成JSON字符串    contentType: 'application/json;charset=utf-8', //设置请求头信息    success: function (data) {    },    error: function (res) {    }  });});

handler 方法:

@RequestMapping("/testJson5")public String testJson5(@RequestBody List<Person> persons) {  System.out.println(persons);  return "success";}

(3)基于表单的 Ajax 提交。

提供一个序列化方法:

$.fn.serializeObject = function(){  var o = {};  var a = this.serializeArray();  $.each(a, function() {    if (o[this.name] !== undefined) {      if (!o[this.name].push) {        o[this.name] = [o[this.name]];      }      o[this.name].push(this.value || '');    } else {      o[this.name] = this.value || '';    }  });  return o;};

还有一种序列化方式:

★单表单情况:

表单:

<form action="" method="post">  First Name:<input type="text" name="firstName" maxlength="12" size="12"/> <br/>  Last Name:<input type="text" name="lastName" maxlength="36" size="12"/> <br/>  Gender:<br/>  Male:<input type="radio" name="gender" value="1"/><br/>  Female:<input type="radio" name="gender" value="0"/><br/>  Favorite Food:<br/>  Steak:<input type="checkbox" name="foods" value="Steak"/><br/>  Pizza:<input type="checkbox" name="foods" value="Pizza"/><br/>  Chicken:<input type="checkbox" name="foods" value="Chicken"/><br/>  <textarea wrap="physical" cols="20" name="quote" rows="5">Enter your favorite quote!</textarea><br/>  Select a Level of Education:<br/>  <select name="education">    <option value="Jr.High">Jr.High</option>    <option value="HighSchool">HighSchool</option>    <option value="College">College</option>  </select><br/>  Select your favorite time of day:<br/>  <select size="3" name="tOfD">    <option value="Morning">Morning</option>    <option value="Day">Day</option>    <option value="Night">Night</option>  </select>  <p><input type="submit"/></p></form>

对应的实体:

/** * @author solverpeng * @create 2016-08-16-11:14 */public class Student {  private String firstName;  private String lastName;  private Integer gender;  private List<String> foods;  private String quote;  private String education;  private String tOfD;  public String getFirstName() {    return firstName;  }  public void setFirstName(String firstName) {    this.firstName = firstName;  }  public String getLastName() {    return lastName;  }  public void setLastName(String lastName) {    this.lastName = lastName;  }  public Integer getGender() {    return gender;  }  public void setGender(Integer gender) {    this.gender = gender;  }  public List<String> getFoods() {    return foods;  }  public void setFoods(List<String> foods) {    this.foods = foods;  }  public String getQuote() {    return quote;  }  public void setQuote(String quote) {    this.quote = quote;  }  public String getEducation() {    return education;  }  public void setEducation(String education) {    this.education = education;  }  public String gettOfD() {    return tOfD;  }  public void settOfD(String tOfD) {    this.tOfD = tOfD;  }  @Override  public String toString() {    return "Student{" +        "firstName='" + firstName + '\'' +        ", lastName='" + lastName + '\'' +        ", gender=" + gender +        ", foods=" + foods +        ", quote='" + quote + '\'' +        ", education='" + education + '\'' +        ", tOfD='" + tOfD + '\'' +        '}';  }}

Student.java

e1:使用 serializeObject()

序列化后的值:

JSON.stringify($('form').serializeObject()):

{"firstName":"jack","lastName":"lily","gender":"1","foods":["Pizza","Chicken"],"quote":"hello hello","education":"Jr.High","tOfD":"Day"}

请求:

$(function() {  $('form').submit(function() {    $.ajax({      url : "testStudent",      data : JSON.stringify($('form').serializeObject()),      contentType : "application/json;charset=utf-8",      type : "post",      success : function (result) {        console.log(result);      }    });    return false;  });});

e11:SpringMVC自身进行处理

handler 方法:

@RequestMapping("/testStudent")public String testStudent(@RequestBody Student student) {  System.out.println(student);  return "success";}

e12:引入第三方 Jar 包进行处理。

准备:

导入 sl4j jar 包,同时添加 JsonUtil 工具类。

public final class JsonUtil {  private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class);  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();  /**   * 将 POJO 转换为 JSON   */  public static <T> String toJson(T obj) {    String json;    try {      json = OBJECT_MAPPER.writeValueAsString(obj);    } catch(JsonProcessingException e) {      LOGGER.error("convert POJO to JSON failure", e);      throw new RuntimeException(e);    }    return json;  }  /**   * 将 JSON 转换为 POJO   */  public static <T> T fromJson(String json, Class<T> type) {    T pojo;    try {      pojo = OBJECT_MAPPER.readValue(json, type);    } catch(IOException e) {      LOGGER.error("convert JSON to POJO failure", e);      throw new RuntimeException(e);    }    return pojo;  }}

JsonUtil.java

后端处理:

@RequestMapping("/testStudent")public String testStudent(@RequestBody String inputBody) {  Student student = JsonUtil.fromJson(inputBody, Student.class);  System.out.println(student);  return "success";}

都可以正常打印 Student 对象。

e2:使用 serialize()

序列化后的值:

$('form').serialize():

firstName=jack&lastName=lily&gender=1&foods=Pizza&foods=Chicken&quote=hello+hello&education=Jr.High&tOfD=Day

请求:

$(function() {  $('form').submit(function() {    $.ajax({      url : "testStudent",      data : $('form').serialize(),      type : "post",      success : function (result) {        console.log(result);      }    });    return false;  });});

handler 方法:

@RequestMapping("/testStudent")public String testStudent(Student student) {  System.out.println(student);  return "success";}

可以正常打印 Student 对象。

e1 和 e2 对比说明:

e1提交的 JSON 数据,e2 提交的不是 JSON 格式的数据。e1 的请求参数存放在 [Request Payload] 中,而 e2 的请求参数存放在 Form Data 中。

★单表单复杂数据

表单还是上面的 Student 表单,但是在表单外增加了:

<span id="amount">33</span>

需求是:通过 Ajax 发送表单数据的同时,同时发送 "amount" 。

经过测试,我就直接说结论了,有兴趣的童鞋可以自行探索,有新的发现欢迎和我交流。

结论:

不能对这样的数据,指定 "contentType:application/json",否则后端SpringMVC或者第三方的Jar 包 不能进行自动的解析,增加了解析的复杂度,所以将 json 串传入后台,在后台进行解析。

e1:serializeObject()

请求:

$(function() {  $('form').submit(function() {    $.ajax({      url : "testStudent",      data : {        amount : $("#amount").text(),        student : JSON.stringify($('form').serializeObject())      },      type : "post",      success : function (result) {        console.log(result);      }    });    return false;  });});

后端处理:使用第三方工具类进行解析

@RequestMapping("/testStudent")public String testStudent(@RequestParam("student") String studentStr, String amount) {  Student student = JsonUtil.fromJson(studentStr, Student.class);  System.out.println("student:" + student);  System.out.println("amount:" + amount);  return "success";}

可以正常打印。

e2:serialize()

请求:

$(function() {  $('form').submit(function() {    $.ajax({      url : "testStudent",      data : {        amount : $("#amount").text(),        student : $('form').serialize()      },      type : "post",      success : function (result) {        console.log(result);      }    });    return false;  });});

Handler 方法:

e1:尝试让 SpringMVC 来解析:

@RequestMapping("/testStudent")public String testStudent(@RequestParam("student") Student student, String amount) {  System.out.println("student:" + student);  System.out.println("amount:" + amount);  return "success";}

结果:请求无法到达 handler 方法

e2:

@RequestMapping("/testStudent")public String testStudent(Student student, String amount) {  System.out.println("student:" + student);  System.out.println("amount:" + amount);  return "success";}

结果:请求可以正常到达目标 Handler 方法,但是无法映射 Student 对象。

方案:自己解析,编写自定义的类型转换器:

public class String2StudentConverter implements Converter<String, Student>{  @Override  public Student convert(String source) {    return InjectUtil.convert2Obj(source, Student.class);  }}

这里我编写了一个通用的类型转换器:

用来转换形如: 

firstName=jack&lastName=lily&gender=1&foods=Steak&foods=Pizza&quote=Enter+your+favorite+quote!&education=Jr.High&tOfD=Day 到 Student 对象。

/** * @author solverpeng * @create 2016-08-22-17:37 */public final class InjectUtil<T> {  private static final Logger LOGGER = LoggerFactory.getLogger(InjectUtil.class);  public static <T> T converter2Obj(String source, Class<T> tClass) {    T t = null;    try {      t = tClass.newInstance();      Map<String, Object> params = new HashMap<String, Object>();      if(source != null && source.length() > 0) {        String[] fields = source.split("&");        for(String field : fields) {          String[] fieldKeyValue = field.split("\\=");          String fieldKey = fieldKeyValue[0];          String fieldValue = fieldKeyValue[1];          if (params.containsKey(fieldKey)) {            Object keyValueRetrieved = params.get(fieldKey);            if (keyValueRetrieved instanceof String) {              ArrayList<String> values = new ArrayList<>();              values.add(keyValueRetrieved.toString());              values.add(fieldValue);              params.put(fieldKey, values);            } else {              ((ArrayList<String>) keyValueRetrieved).add(fieldValue);            }          } else {            params.put(fieldKey, fieldValue);          }        }      }      BeanUtils.populate(t, params);    } catch(InstantiationException | IllegalAccessException | InvocationTargetException e) {      e.printStackTrace();      LOGGER.error("String convert to Bean failure!", e);    }    return t;  }}

不要忘记在 SpringMVC 中添加自定义的转换器。

e3:也可以在 handler 方法中来调用上面我编写的通用的类型转换器来完成解析。

@RequestMapping("/testStudent")public String testStudent(@RequestParam("student") String studentStr, String amount) {  System.out.println("studentStr:" + studentStr);  System.out.println("amount:" + amount);  return "success";}

说明:对于复杂数据来说,我们借助不了 SpringMVC,只能借助于第三方,或是自己来编写解析器来解析。

★多表单一次提交

表单数据:

<form action="" method="post" id="form2">  First Name:<input type="text" name="firstName" maxlength="12" size="12"/> <br/>  Last Name:<input type="text" name="lastName" maxlength="36" size="12"/> <br/>  Gender:<br/>  Male:<input type="radio" name="gender" value="1"/><br/>  Female:<input type="radio" name="gender" value="0"/><br/>  &lt;%&ndash;Favorite Food:<br/>  Steak:<input type="checkbox" name="foods" value="Steak"/><br/>  Pizza:<input type="checkbox" name="foods" value="Pizza"/><br/>  Chicken:<input type="checkbox" name="foods" value="Chicken"/><br/>&ndash;%&gt;  <textarea wrap="physical" cols="20" name="quote" rows="5">Enter your favorite quote!</textarea><br/>  Select a Level of Education:<br/>  <select name="education">    <option value="Jr.High">Jr.High</option>    <option value="HighSchool">HighSchool</option>    <option value="College">College</option>  </select><br/>  Select your favorite time of day:<br/>  <select size="3" name="tOfD">    <option value="Morning">Morning</option>    <option value="Day">Day</option>    <option value="Night">Night</option>  </select>  <p><input type="submit"/></p></form><form action="" method="post" id="form1">  First Name:<input type="text" name="firstName" maxlength="12" size="12"/> <br/>  Last Name:<input type="text" name="lastName" maxlength="36" size="12"/> <br/>  Gender:<br/>  Male:<input type="radio" name="gender" value="1"/><br/>  Female:<input type="radio" name="gender" value="0"/><br/>  &lt;%&ndash; Favorite Food:<br/>  Steak:<input type="checkbox" name="foods" value="Steak"/><br/>  Pizza:<input type="checkbox" name="foods" value="Pizza"/><br/>  Chicken:<input type="checkbox" name="foods" value="Chicken"/><br/>&ndash;%&gt;  <textarea wrap="physical" cols="20" name="quote" rows="5">Enter your favorite quote!</textarea><br/>  Select a Level of Education:<br/>  <select name="education">    <option value="Jr.High">Jr.High</option>    <option value="HighSchool">HighSchool</option>    <option value="College">College</option>  </select><br/>  Select your favorite time of day:<br/>  <select size="3" name="tOfD">    <option value="Morning">Morning</option>    <option value="Day">Day</option>    <option value="Night">Night</option>  </select></form>

View Code

e1:

同时需要定义一个 Students 类:

public class Students {  private List<Student> students;  public List<Student> getStudents() {    return students;  }  public void setStudents(List<Student> students) {    this.students = students;  }}

请求:

$('form').submit(function() {  $.ajax({    url : "testStudent",    data : JSON.stringify({      "students": [        $('#form1').serializeObject()        ,        $('#form2').serializeObject()      ]    }),    contentType:"application/json;charset=utf-8",    type : "post",    success : function (result) {      console.log(result);    }  });  return false;});

handler 方法:

@RequestMapping("/testStudent")public String testStudent(@RequestBody Students students) {  for(Student student : students.getStudents()) {    System.out.println("student:" + student);  }  return "success";}

可以正常打印。 

e2:不额外增加类,即不定义 Students

请求:

$('form').submit(function() {  $.ajax({    url : "testStudent",    data : JSON.stringify([      $('#form1').serializeObject(),      $('#form2').serializeObject()    ]),    contentType:"application/json;charset=utf-8",    type : "post",    success : function (result) {      console.log(result);    }  });  return false;});

handler 方法:

e21:通过数组来接收

@RequestMapping("/testStudent")public String testStudent(@RequestBody Student[] students) {  for(Student student : students) {    System.out.println("student: " + student);  }  return "success";}

e22:通过 List 来接收

@RequestMapping("/testStudent")public String testStudent(@RequestBody List<Student> students) {  for(Student student : students) {    System.out.println("student: " + student);  }  return "success";}

★一个表单多个对象

表单对象如:

e1:

<form action="" method="post" id="form">  First Name:<input type="text" name="firstName" maxlength="12" size="12"/> <br/>  Last Name:<input type="text" name="lastName" maxlength="36" size="12"/> <br/>  Gender:<br/>  Male:<input type="radio" name="gender" value="1"/><br/>  Female:<input type="radio" name="gender" value="0"/><br/>  &lt;%&ndash;Favorite Food:<br/>  Steak:<input type="checkbox" name="foods" value="Steak"/><br/>  Pizza:<input type="checkbox" name="foods" value="Pizza"/><br/>  Chicken:<input type="checkbox" name="foods" value="Chicken"/><br/>&ndash;%&gt;  <textarea wrap="physical" cols="20" name="quote" rows="5">Enter your favorite quote!</textarea><br/>  Select a Level of Education:<br/>  <select name="education">    <option value="Jr.High">Jr.High</option>    <option value="HighSchool">HighSchool</option>    <option value="College">College</option>  </select><br/>  Select your favorite time of day:<br/>  <select size="3" name="tOfD">    <option value="Morning">Morning</option>    <option value="Day">Day</option>    <option value="Night">Night</option>  </select>  First Name:<input type="text" name="firstName" maxlength="12" size="12"/> <br/>  Last Name:<input type="text" name="lastName" maxlength="36" size="12"/> <br/>  Gender:<br/>  Male:<input type="radio" name="gender" value="1"/><br/>  Female:<input type="radio" name="gender" value="0"/><br/>  &lt;%&ndash; Favorite Food:<br/>  Steak:<input type="checkbox" name="foods" value="Steak"/><br/>  Pizza:<input type="checkbox" name="foods" value="Pizza"/><br/>  Chicken:<input type="checkbox" name="foods" value="Chicken"/><br/>&ndash;%&gt;  <textarea wrap="physical" cols="20" name="quote" rows="5">Enter your favorite quote!</textarea><br/>  Select a Level of Education:<br/>  <select name="education">    <option value="Jr.High">Jr.High</option>    <option value="HighSchool">HighSchool</option>    <option value="College">College</option>  </select><br/>  Select your favorite time of day:<br/>  <select size="3" name="tOfD">    <option value="Morning">Morning</option>    <option value="Day">Day</option>    <option value="Night">Night</option>  </select>  <p><input type="submit"/></p></form>

View Code

e2:

<form action="" method="post">  First Name:<input type="text" name="firstName[0]" maxlength="12" size="12"/> <br/>  Last Name:<input type="text" name="lastName[0]" maxlength="36" size="12"/> <br/>  Gender:<br/>  Male:<input type="radio" name="gender[0]" value="1"/><br/>  Female:<input type="radio" name="gender[0]" value="0"/><br/>  Favorite Food:<br/>  Steak:<input type="checkbox" name="foods[0]" value="Steak"/><br/>  Pizza:<input type="checkbox" name="foods[0]" value="Pizza"/><br/>  Chicken:<input type="checkbox" name="foods[0]" value="Chicken"/><br/>  <textarea wrap="physical" cols="20" name="quote[0]" rows="5">Enter your favorite quote!</textarea><br/>  Select a Level of Education:<br/>  <select name="education[0]">    <option value="Jr.High">Jr.High</option>    <option value="HighSchool">HighSchool</option>    <option value="College">College</option>  </select><br/>  Select your favorite time of day:<br/>  <select size="3" name="tOfD[0]">    <option value="Morning">Morning</option>    <option value="Day">Day</option>    <option value="Night">Night</option>  </select>  First Name:<input type="text" name="firstName[1]" maxlength="12" size="12"/> <br/>  Last Name:<input type="text" name="lastName[1]" maxlength="36" size="12"/> <br/>  Gender:<br/>  Male:<input type="radio" name="gender[1]" value="1"/><br/>  Female:<input type="radio" name="gender[1]" value="0"/><br/>  Favorite Food:<br/>  Steak:<input type="checkbox" name="foods[1]" value="Steak"/><br/>  Pizza:<input type="checkbox" name="foods[1]" value="Pizza"/><br/>  Chicken:<input type="checkbox" name="foods[1]" value="Chicken"/><br/>  <textarea wrap="physical" cols="20" name="quote[1]" rows="5">Enter your favorite quote!</textarea><br/>  Select a Level of Education:<br/>  <select name="education[1]">    <option value="Jr.High">Jr.High</option>    <option value="HighSchool">HighSchool</option>    <option value="College">College</option>  </select><br/>  Select your favorite time of day:<br/>  <select size="3" name="tOfD[1]">    <option value="Morning">Morning</option>    <option value="Day">Day</option>    <option value="Night">Night</option>  </select>  <p><input type="submit"/></p></form>

View Code

来看经过处理后的数据:

e1:

(1)JSON.stringify($('form').serializeObject()):

{"firstName":["jack","tom"],"lastName":["aa","lily"],"foods":["Steak","Pizza","Steak"],"quote":["Enter your favorite quote!","Enter your favorite quote!"],"education":["Jr.High","Jr.High"],"tOfD":["Day","Day"],"gender":"1"}

(2)$('form').serialize():

 firstName=jack&lastName=aa&foods=Steak&foods=Pizza&quote=Enter+your+favorite+quote!&education=Jr.High&tOfD=Day&firstName=tom&lastName=lily&gender=1&foods=Steak&quote=Enter+your+favorite+quote!&education=Jr.High&tOfD=Day

说明:

第一种是无法处理的,没办法分清数组中的值是属于哪个对象的。

第二种方式可以处理,但是需要编写自定义的类型转换器,这里不进行说明。有兴趣的童鞋,请自行探索。

e2:

(1)JSON.stringify($('form').serializeObject()):

{"firstName[0]":"aa","lastName[0]":"bb","gender[0]":"1","foods[0]":"Pizza","quote[0]":"Enter your favorite quote!","education[0]":"Jr.High","tOfD[0]":"Day",

"firstName[1]":"ds","lastName[1]":"cc","gender[1]":"1","foods[1]":["Steak","Pizza"],"quote[1]":"Enter your favorite quote!","education[1]":"Jr.High","tOfD[1]":"Day"}

(2)$('form').serialize():

firstName%5B0%5D=aa&lastName%5B0%5D=bb&gender%5B0%5D=1&foods%5B0%5D=Pizza&quote%5B0%5D=Enter+your+favorite+quote!&education%5B0%5D=Jr.High&tOfD%5B0%5D=Day&

firstName%5B1%5D=ds&lastName%5B1%5D=cc&gender%5B1%5D=1&foods%5B1%5D=Steak&foods%5B1%5D=Pizza&quote%5B1%5D=Enter+your+favorite+quote!&education%5B1%5D=Jr.High&tOfD%5B1%5D=Day

说明:

第一种看着有规律可循,貌似可以进行解析,但是不是一个标准的 JSON 格式的数据。

第二种甚至都出现了乱码,没有想到解析的办法。

来看看第一种,同样这里提供一种思路,因为实现起来比较费劲。

思路:使用正则

like this :

Gson gson = new Gson();String jsonInString = "{\"student[0].firstName\": \"asdf\",\"student[0].lastName\": \"sfd\",\"student[0].gender\": \"1\",\"student[0].foods\":[\"Steak\",\"Pizza\"],\"student[0].quote\": \"Enter your favorite quote!\",\"student[0].education\": \"Jr.High\",\"student[0].tOfD\": \"Day\",\"student[1].firstName\": \"sf\",\"student[1].lastName\": \"sdf\",\"student[1].gender\": \"1\",\"student[1].foods\": [\"Pizza\",\"Chicken\"],\"student[1].quote\": \"Enter your favorite quote!\",\"student[1].education\": \"Jr.High\",\"student[1].tOfD\": \"Night\"}";String jsonWithoutArrayIndices = jsonInString.replaceAll("\\[\\d\\]", "").replaceAll("student.","");String jsonAsCollection = "[" + jsonWithoutArrayIndices + "]";String jsonAsValidCollection = jsonAsCollection.replaceAll(",\"student.firstName\"","},{\"student.firstName\"");System.out.println(jsonAsValidCollection);Student[] students = gson.fromJson(jsonAsValidCollection, Student[].class);System.out.println("-----------------------------------------------");System.out.println(students[0]);System.out.println("-----------------------------------------------");

说明:

在真实的生产环境下我也没有遇到过这样的情况,所以这里就不往深挖了,等什么时候遇到这样的情况,我再来进行补充这篇文章。

总结:

上面这部分,介绍了项目中遇到的绝大部分 SpringMVC 处理 Ajax 的问题,也提供了多种方案进行选择,对于不常见的问题,也给出了思路。是这篇文章最重要的部分。

 

五、服务器端的 SpringMVC 如何返回 JSON 类型的字符串。

请求:

$("#testJson8").click(function () {  $.ajax({    url: "testReturnJsonValue",    type: "post",    success: function (result) {      console.log(result);    }  });});

1.返回单个对象

handler 方法:

@ResponseBody@RequestMapping("/testReturnJsonValue")public Person testReturnJsonValue() {  Person person = new Person();  person.setName("lily");  person.setAge(23);  return person;}

在浏览器控制台正常打印了 Person 对象。

注意:这里没有指定 dataType。

2.返回多个对象

handler 方法:

@ResponseBody@RequestMapping("/testReturnJsonValue")public List<Person> testReturnJsonValue() {  List<Person> personList = new ArrayList<>();  Person person = new Person();  person.setName("lily");  person.setAge(23);  Person person2 = new Person();  person2.setName("lucy");  person2.setAge(33);  personList.add(person);  personList.add(person2);  return personList;}

在浏览器控制条正常打印了 Person 数组。 

3.返回 Map

@ResponseBody@RequestMapping("/testReturnJsonValue")public Map<String, Person> testReturnJsonValue() {  Map<String, Person> map = new HashMap<>();  Person person = new Person();  person.setName("lily");  person.setAge(23);  Person person2 = new Person();  person2.setName("lucy");  person2.setAge(33);  map.put("1", person);  map.put("2", person2);  return map;}

浏览器控制台输出:

 

4.在实际生产环境下的 Ajax 返回值。

封装一个返回值类型:

/** * @author solverpeng * @create 2016-08-30-17:58 */public class AjaxResult implements Serializable {  public static final String RESULT_CODE_0000 = "0000";  public static final String RESULT_CODE_0001 = "0001";  private String code;  private String message;  private Object data;  public AjaxResult() {  }  public String getCode() {    return this.code;  }  public void setCode(String code) {    this.code = code;  }  public String getMessage() {    return this.message;  }  public void setMessage(String message) {    this.message = message;  }  public Object getData() {    return this.data;  }  public void setData(Object data) {    this.data = data;  }}

 

实际使用:

@ResponseBody@RequestMapping("/testReturnJsonValue")public AjaxResult testReturnJsonValue() {  AjaxResult ajaxResult = new AjaxResult();  try {    Map<String, Person> map = new HashMap<>();    Person person = new Person();    person.setName("lily");    person.setAge(23);    Person person2 = new Person();    person2.setName("lucy");    person2.setAge(33);    map.put("1", person);    map.put("2", person2);    ajaxResult.setData(map);    ajaxResult.setMessage("success!");    ajaxResult.setCode(AjaxResult.RESULT_CODE_0000);  } catch(Exception e) {    e.printStackTrace();    ajaxResult.setMessage("fail!");    ajaxResult.setCode(AjaxResult.RESULT_CODE_0001);  }  return ajaxResult;}

 

控制台打印:

六、Request Payload

(1)出现的条件:

contentType: 'application/json;charset=utf-8'

type:post

(2)具体请参看

http://xiaobaoqiu.github.io/blog/2014/09/04/form-data-vs-request-payload/

(3)建议尽量不要手动的去处理此种情况,能选用别的方式避免就尽量避免。

七、总结

本篇文章主要介绍了SpringMVC 对 Ajax 的支持,对与 Ajax 数据如何组织,重点介绍了对表单的支持。在测试的过程中也遇到过很多问题,所幸的是,也都一一克服了。还有想说的是,不可能将所有的情况都覆盖,只是将最最常用的情况进行了分析。

也进行了另外一种序列化方式的测试,serializeArray() ,但是对我不太友好,也就没有深入的研究。有兴趣的朋友,可以自行深入研究一下。最后想说的是,写文章不易,希望大家转载的时候表明出处。也欢迎大家一起和我讨论学习。