前言
要求设计:新建学生类并放在entity包下,在servlet中新建学生对象信息,并将学生信息放在共享数据中,在JSP文件中将其取出,最后在网页中以警示框的形式输出出来。
学生类代码:
package Entity;
public class Student {
String name;
int age;
public Student() {}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
JSP文件
<%--
Created by IntelliJ IDEA.
User: 繁花fancy
Date: 2021/11/15
Time: 14:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>test</title>
<script>
var stuObj = ${requestScope.student};//EL表达式
window.alert("学生姓名" + stuObj.name + "学生年龄" + stuObj.age);
</script>
</head>
<body>
</body>
</html>
一、错误做法
我们直接在Servlet中把student对象作为共享数据放进请求作用域对象中,然后在JSP文件中取出并执行相关代码,我们发现没有弹出显示学生成绩的警示框。
MyServlet类
package Controller;
import Entity.Student;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "MyServlet", value = "/MyServlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Student stu = new Student("Mike", 18);
request.setAttribute("student", stu);
request.getRequestDispatcher("/test.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
结果如图,下方报了语法错误
我们查看网页源代码发现
stuObj的值为一串内存地址,我们无法根据这串内存地址在JSP文件中来得到Student对象的属性值。
所以我们应该在Servlet中将stu转换成JSON格式数据,再将其请求转发到 test.jsp 文件中
二、正确做法
将stu转换为 json 格式数据再进行发送:
MyServlet类
package Controller;
import Entity.Student;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "MyServlet", value = "/MyServlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Student stu = new Student("Mike", 18);
String stu = "{'name': 'Mike', 'age' : 18}";
request.setAttribute("student", stu);
request.getRequestDispatcher("/test.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
这样是可以正常输出出来的,但是在Servlet类中,我们并没有新建Student对象然后转化成JSON格式,而是直接写了一个JSON格式的字符串来冒充Student实例对象。这样做是不规范的,与我们的本意有所矛盾,应该通过一些算法将stu对象转换成JSON。要实例对象转化为JSON格式字符串的算法比较长和复杂,我们可以将其封装成一个工具类来供我们使用。工具类如下。
三、标准做法
新建Utility包,在包下新建ReflectUtil工具类,用于将对象转化成JSON字符串类型。
ReflectUtil.java
package Utility;
import java.lang.reflect.Field;
public class ReflectUtil {
//作用: 将任意类型对象内容转换为JSON格式字符串返回
public static String jsonObject(Object obj) {
Class classFile = null; //字节码文件
Field fieldArray[] = null; //参数列表
StringBuffer str = new StringBuffer("{");//要频繁进行字符串拼接,用StringBuffer类型,且json字符串以{开头
//1. 获取当前对象隶属的class文件
classFile = obj.getClass();
//2.获取class对象所有属性
fieldArray = classFile.getDeclaredFields();
//3.获取当前对象所有属性值
try {
for (int i = 0; i < fieldArray.length; i++) {
Field field = fieldArray[i];
field.setAccessible(true);//确保私有属性可以在class文件外使用
String fieldName = field.getName();//获取属性名称
Object value = field.get(obj);
//4.将获得的属性和其值拼接为JSON类型
str.append("'");
str.append(fieldName);
str.append("':'");
str.append(value);
str.append("'");
if (i < fieldArray.length - 1) {
str.append(",");
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
str.append("}");
}
return str.toString();
}
}
以上代码运用了反射机制,这也是我们起名为ReflectUtil的原因
package Controller;
import Entity.Student;
import Utility.ReflectUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "MyServlet", value = "/MyServlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Student stu = new Student("Mike", 18);
//String stu = "{'name': 'Mike', 'age' : 18}";
Student stu = new Student("Alan", 19);
String str = ReflectUtil.jsonObject(stu);
request.setAttribute("student", str);
request.getRequestDispatcher("/test.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
四、使用JSON工具包
目前常见的JSON工具包有以下几种:
-
Gson : Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用。Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。类里面只要有get和set方法,Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。
-
FastJson : Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。无依赖,不需要例外额外的jar,能够直接跑在JDK上。FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。
-
Jackson : 相比json-lib框架,Jackson所依赖的jar包较少,简单易用并且性能也要相对高些。而且Jackson社区相对比较活跃,更新速度也比较快。Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式。
-
Json-lib : json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,包括commons-beanutils.jar,commons-collections-3.2.jar,commons-lang-2.6.jar,commons-logging-1.1.1.jar,ezmorph-1.0.6.jar,对于复杂类型的转换,json-lib对于json转换成bean还有缺陷,比如一个类里面会出现另一个类的list或者map集合,json-lib从json到bean的转换就会出现问题。json-lib在功能和性能上面都不能满足现在互联网化的需求。
在接下来的项目中我们主要使用的是Jackson
其使用方法为:
首先在WEB-INF的lib目录下导入三个jackson jar包
1. 创建Jackson的核心对象ObjectMapper
ObjectMapper om = new ObjectMapper();
2. 将自定义对象转换为JSON字符串
writeValueAsString(obj);
3. 或将json数据填充到字符流中
writeValue(parameter1, parameter2);
parameter1 :
(1) File: 将obj对象转换为json格式字符串并保存到指定文件
(2) Writer: 将obj对象转换为json字符串并填充到字符输出流中(response对象的getWriter()方法来获取该类)
(3) OutputStream : 将obj对象转换为json字符串,并将json数据填充到字节输出流中