SpringMVC——对Ajax的处理(包含 JSON 类型)

本地部署大模型框架 LMStudio和Ollama+WebUI对比 之前我们的辣妈系列文章介绍了很多如何使用Ollama框架+OpenWebUI做很多大模型框架下相关的事情。之后我们也尝试了LMStudio这样一体化的工具。本文介绍下LMStudio 和 Ollama+Web UI 各有优劣,具体选择取决于你的需求。 阅读详情

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 +
                '}';
    }
}
复制代码

(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 + '\'' +
                '}';
    }
}
复制代码

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

}
复制代码

后端处理:

@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>
复制代码

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>
复制代码

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>
复制代码

来看经过处理后的数据:

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"e%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"e%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() ,但是对我不太友好,也就没有深入的研究。有兴趣的朋友,可以自行深入研究一下。最后想说的是,写文章不易,希望大家转载的时候表明出处。也欢迎大家一起和我讨论学习。

【异常】安装hermes-agent时提示GnuTLS recv error (-110): The TLS connection was non-properly terminated. Git克隆仓库时出现TLS连接异常报错的解决方案摘要: 当执行git clone命令时遇到"GnuTLS recv error (-110)"报错,通常由网络不稳定、缓冲区不足或证书验证问题导致。主要解决方案包括:1)增大Git HTTP缓冲区(git config --global http.postBuffer 524288000);2)使用GitHub镜像站加速克隆;3)临时禁用SSL验证进行测试;4)检查并调整代理配置;5)改用SSH协议克隆。建议优先尝试增大缓冲区和镜像站方案, 阅读详情

相关推荐

Windows 10 下 DockerToolbox 安装全攻略:从下载到配置阿里云镜像加速

本文详细介绍了在Windows 10系统上安装和配置DockerToolbox的完整流程。从下载安装包、执行初步安装,到关键步骤——修改虚拟机存储路径以及配置阿里云镜像加速器,旨在帮助开发者,尤其是初次接触Docker的新手,快速搭建高效的本地容器开发环境,并解决国内镜像下载缓慢的痛点。

moon9的博客 475

第七章 springmvc Ajax、Json

本章目标 SpringMVC生成json格式的数据 @RequestBody注解 了解HttpMessageConverter接口 Spring MVC和Ajax 在现在的项目中Ajax可以说是必须使用的技术,SpringMVC框架作为目前最受欢迎的框架,和Ajax的集成非常的友好,可以说是非常傻瓜式的。 当客户端使用ajax向服务器发送请求,服务器返回对应格式的数据,一般常见的数据格式...

Jaosn.Yang的博客 313

FOC观测器之龙伯格观测器

状态观测器: 理论依据:根据控制理论,如果一个系统能够完全通过其检测到的输出值来重构其系统状态,则认为该系统是可观测的。其作用于无传感器转子的位置和速度的检测反馈,再作用到PARK逆变换和转矩磁链控制上。 Luenberger观察器原理图: Luenberger观测器的离散化: (其观测器的闭环参数为经验验证值) 引入估测电流( iα,iβ )的反馈值并离散化(T 为采样时间),可得...

ShawnChan的博客 2万+

JavaWeb 开发入门:理解 MVC、Ajax 和 JSON

MVC 开发模式、Ajax 技术和 JSON 数据格式是 JavaWeb 开发的三大核心概念。掌握这三个概念,可以帮助你构建功能更完善、性能更优、用户体验更好的 JavaWeb 应用程序。希望这篇文章能帮助你入门 JavaWeb 开发,并激发你进一步探索的兴趣!

qq_63289396的博客 837

GD32F103实战:用ADC+DMA实现高精度多通道电压采集与OLED实时显示(附完整工程)

本文详细介绍了如何利用GD32F103的ADC+DMA技术实现高精度多通道电压采集,并通过OLED实时显示数据。文章包含硬件架构设计、ADC配置技巧、DMA传输优化及显示系统实现方案,提供完整工程代码和调试指南,适用于工业传感器和环境监测设备开发。

weixin_42567497的博客 399

海康机器人ID5000 系列智能读码器(三)

又過了兩個月,漸漸的對這個攝像頭的功能更加熟悉了,而實際上,我要做的功能也越來越複雜,從一開始的讀碼,到後來的通過讀二維碼控制設備,再到未讀到二維碼控制設備等,下面就對具體的細項做一個總結。了解完這些就能對ID5000這個設備,乃至很多海康的設備都能做一個二次開發。

qq_54359036的博客 3070

springMvc 接收 ajax传递Map,list,对象的方式

一. Map 传递和接收 前端ajax写法: 错误写法 var submitMap=function () { var params={}; params['aa']="aa"; params['bb']="bb"; $.ajax({ url:"/acceptMap", data:{params:params}, ...

shan_zhi_jun的博客 1753

三菱FX5U系列PLC与汇川IT6000系列触摸屏进行MODBUS TCP通信的具体方法

三菱FX5U系列PLC与汇川IT6000系列触摸屏进行MODBUS TCP通信的具体方法

Robot_PLC_HMI_Automation 6513

SpringMVC通过Ajax处理Json数据

SpringMVC通过Ajax处理Json数据的实现 文章目录一、前言:二、使用步骤1.引入jar2.Person类3.前端页面4.Controller5.测试 一、前言: Ajax: 在不重新加载整个页面的前提下,对网页的部分进行刷新,例如点赞,发送短信验证码功能等等,都可以通过ajax进行实现,Ajax实现了网页的异步刷新 想要实现的效果,点击按钮,前端显示后台发送过来的学生信息,本次我们使用jquery形式的Ajax来完成 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任

wenwenaier的博客 485

【零基础学习CAPL】——CAN报文的发送(CRC——ChecSum值)

本章主要介绍带有CRC值的报文发送一般报文可使用CANoe的IG模块直接发送,但带有CRC值的报文就只能编写脚本进行发送,以下详细讲解在配合Panel面板情况下,如何进行带有循环冗余码的报文进行报文的发送。

LOVE135149的博客 1910

Qt界面美化-飞扬青云自绘控件插件的使用-避免采坑

1、先上一个集成到QtCreater中的效果图: 2、飞扬青云自绘控件插件下载地址:https://gitcode.net/mirrors/feiyangqingyun/qucsdk?utm_source=csdn_github_accelerator 3、集成插件到QtCreater中的方法: (1)、查看自己使用的QtCreater的版本信息,我的:Qt 5.15.2 MSVC2019 64位 (2)插件下载下来后工程预览: 我选择msvc版本的SDK,打开找到匹配的SDK:...

小米的修行之路 2789

c ajax处理类,SpringMVC——对Ajax的处理(包含 JSON 类型)

SpringMVC——对Ajax的处理(包含 JSON 类型)SpringMVC——对Ajax的处理(包含JSON 类型)一、首先要搞明白的一些事情。1.从客户端来看,需要搞明白:(1)要发送什么样格式的JSON 数据才能被服务器端的SpringMVC 很便捷的处理,怎么才能让我们写更少的代码,如何做好JSON 数据和实体之间的对应。(2)如何组织这些发送的数据。2.从服务器端来看,需要搞明白:(...

weixin_42637593的博客 305

Open3D 基于法线的双边滤波

基于法线的双边滤波是一种用于点云平滑的技术,它结合了点与其邻域点之间的几何距离和法线方向的相似性,从而在去除噪声的同时保留几何特征。这种滤波方法广泛应用于点云处理领域,尤其是在需要保留表面细节和边缘的场景中。

纵马踏花向自由 2499

SpringMVC 处理 Ajax 请求

SpringMVC 是 Spring 框架的一个模块,它实现了模型-视图-控制器(MVC)设计模式,用于构建 Web 应用程序。SpringMVC 分离了应用程序的不同部分,使得开发更加高效、可维护。Ajax(Asynchronous JavaScript and XML)即异步 JavaScript 和 XML,它允许在不刷新整个页面的情况下,与服务器进行数据交互。通过 Ajax,可以提高用户体验,减少页面加载时间,实现更加流畅的交互效果。通过使用和。

dawn191228的博客 1567

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

SpringMVC通过ajax处理json数据

TAjax请求SpringMVC,并且JSON格式的数据@ResponseBody Ajax请求SpringMVC,并且JSON格式的数据 步骤: a. jar(注意版本,如果版本不兼容会报错) jackson-annotations-2.8.9.jar jackson-core-2.8.9.jar jackson-databind-2.8.9.jar b. 前端: 首先用一个按钮来触发该事件 &...

Hello World 472

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SpringMVC-Ajax和JSON

Ajax和JSON 什么是JSON? SON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。 采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。 在 JS 语言中,一切都是对象。因此,任何JS...

weixin_44823472的博客 862

SpringMVC处理Ajax请求及处理和响应json格式的数据

首先在maven工程里创建新的module(其他方式均可),然后在pom文件中导入依赖,在其中包括我们上文所写到的jackson的依赖,然后配置web里的web.xml编码过滤器、处理请求方式过滤器以及SpringMVC的前端控制器。c>在处理请求的控制器方法的形参位置,直接设置json格式的请求参数要转换的Java类型的形参,使用@RequestBody注解标识即可。method:"", //请求方式(以name=value&name=value的方式发送的请求参数,a>导入Jackson的依赖。

qq_47637405的博客 1812

SpringMVC的Ajax请求与处理返回json数据

这里我用了三种形式返回 1、String 2、返回对象 3、 返回数组 一、以String方式返回 先看一下JavaScript代码 <%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTM...

Rm_and_Rf的博客 2552

springmvc+Ajax+JSON

原文地址:https://www.cnblogs.com/big-xuzhou/p/5368282.html springmvc+Ajax+JSON(@RequestBody 使用问题) 在jsp页面利用Ajax传输json,发现进不了控制器,去掉控制器方法里面的@RequestBody注释,就没有问题。 控制器方法如下: @RequestMapping(value="/login", metho...

Mr.h的博客 830

SpringMVC —— 响应json数据发送ajax请求、json格式数据

目录结构: 引入jquery文件,版本尽量在2.0以上。可以在官网下载,有需求的可以在下面留言。 <%-- Created by IntelliJ IDEA. User: LFY Date: 2020/2/6 Time: 21:56 To change this template use File | Settings | File Templates. --%>...

qq_44706044的博客 2689

SpringMVC 数据校验、SpringMVC通过Ajax处理Json

1. 错误消息: public String testDateTimeFormat(Student student, BindingResult result ,Map&lt;String,Object&gt; map) { 需要验证的数据是 Student中的 birthday , SPringMVC要求 如果校验失败  则将错误信息 自动放入 该对象之后紧挨着的    Binding...

Shirley的博客 559

springmvc 对ajax 支持,SpringMVC—对Ajax的处理(含 JSON 类型)(3)

五、服务器端的 SpringMVC 如何返回 JSON 类型的字符串。请求:$("#testJson8").click(function () {$.ajax({url: "testReturnJsonValue",type: "post",success: function (result) {console.log(result);}});});1.返回单个对象handler 方法:@Resp...

weixin_39526706的博客 341

spring处理ajax请求,如何实现Springmvc处理ajax请求并返回json数据

如何实现Springmvc处理ajax请求并返回json数据发布时间:2020-07-02 09:23:14来源:亿速云阅读:78作者:清晨小编给大家分享一下如何实现Springmvc处理ajax请求并返回json数据,希望大家阅读完这篇文章后大所收获,下面让我们一起去探讨方法吧!①在springmvc方法上添加@ResponseBody注解,springmvc会将数据转换成json并返回;@Re...

weixin_39616339的博客 898

SpringMVC第五讲:SpringMVC实现AJAX及JSON格式转换

AJAX异步提交是页面与程序交互的重要手段之一,在SpringMVC中,也支持页面向Controller控制器发送异步请求。当页面发送AJAX请求时,如果请求的数据格式为JSON格式时,需要在形参上加入@RequestBody注解,@RequestBody注解可以帮助我们实现对数据的绑定。//传输格式必须是JSON,如果仅以数据传递,则无法封装数据,普通数据根据参数名SpringMVC会自动封装,JSON格式需要配置@RequestBody。//传输格式为JSON格式时,需要配置请求内容格式及编码格式。

跟着老高学Java 954
上一篇: FastJson、Jackson、Gson进行Java对象转换Json的细节处理
下一篇: 使用jstack 查看线程
netdevgirl
博客等级 码龄18年 27粉丝 17原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值