哈哈说再见是不可能的,有点标题党了。
只是 JSP 是十几年前的老技术了,已经慢慢被时代抛弃了。如果你已经工作了,此篇文章完全可以略过。如果你是学生,要应付考试或者作业,可以跟着学一学。
1. JSP 规范
我们要学习JSP
,首先要了解一下JSP规范。JSP 规范其实来自于 JAVAEE 规范。
- JSP 规范制定了如何用 JSP 文件代替响应对象将处理结果写入到响应体的开发流程。
- JSP 规范制定了 Http 服务器应该如何管理 JSP 文件。
- JSP 文件在执行时,自动将文件中的内容写入到响应体
2. 为啥要用 JSP?
我们前面在学 servlet 的时候知道,servlet 处理完用户的请求之后,需要将处理结果写入到响应体中,然后浏览器渲染响应体中的内容。例如:
@WebServlet("/one")
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("我会发着呆,");
writer.println("然后忘记你,");
writer.println("接着紧紧闭上眼。");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
启动项目,浏览器输入网址访问:
http://localhost:8080/myProject/one
但是!servlet 的响应对象只适合将少量数据
写入到响应体。如果数据量太大,依然使用响应对象的话,就会增加响应对象的开发难度,代码看起来就会很繁琐。例如:
@WebServlet("/one")
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<User> userList = Stream.of(new User("孙尚香", 27, "女"), new User("刘备", 31, "男"),
new User("吕布", 29, "男"), new User("貂蝉", 22, "女"))
.collect(Collectors.toList());
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<table border='3'>");
writer.print("<tr>");
writer.print("<td>姓名</td>");
writer.print("<td>年龄</td>");
writer.print("<td>性别</td>");
writer.print("</tr>");
userList.forEach(user -> {
writer.print("<tr>");
writer.print("<td>"+user.getName()+"</td>");
writer.print("<td>"+user.getAge()+"</td>");
writer.print("<td>"+user.getSex()+"</td>");
writer.print("</tr>");
});
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
所以在 Servlet 里面使用响应对象输出一大堆数据也太麻烦了,为了减轻响应对象的负担,JSP 闪亮登场!
3. JSP 的使用
3.1 新建 jsp 文件
我们在 web/webapp 目录下新建以.jsp
为后缀的文件,然后在里面随便写一些 html 标签,启动项目访问该 jsp 文件:
启动项目之后我们可以直接访问该 jsp 文件,并且 jsp 文件中的内容也被浏览器渲染了。
说明 jsp 文件可以代替 Servlet 中的响应对象将一些数据写入到响应体中,然后交给浏览器渲染。
我们仔细观察 jsp 文件,发现 jsp 文件有两个特点。
-
- 头部包含“contentType”,其实就是 servlet 中响应对象设置的文件类型。
-
- language="java":说明可以在 jsp 中写 java 命令。
3.2 JSP 文件中写 JAVA 命令
java 语句的命令格式:
<% java 代码 %>
输出 java 值的命令格式:
<%=java的变量名%>
<%=java的表达式%>
例如:修改 index.jp
<%@ page import="com.xxl.model.User" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<% int a = 10;%>
<p>a的值: <%= a%></p>
<p>姓名: <%= a>100?"张无忌":"赵敏"%></p>
<%
User user1 = new User("张三", 27, "女");
User user2 = new User("李四", 31, "男");
User user3 = new User("王五", 29, "男");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
%>
<table border="2">
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<%
for(User user:userList){
%>
<tr>
<td><%= user.getName()%></td>
<td><%= user.getAge()%></td>
<td><%= user.getSex()%></td>
</tr>
<%
}
%>
<hr>
</table>
</body>
</html>
启动项目,访问 index.jsp:
从上面的例子中我们发现:
-
- 所有的 <% %> 标签都是一体的
-
- 当使用 java 中的某些引用类型时,jsp 文件头部会导入这些对象的包。
3.3 JSP 九大内置对象
我们知道 jsp 中可以写一些 java 代码,但是有时候我们需要在 jsp 中实现一些 servlet 拥有的功能,例如获取请求参数、跳转页面等。那怎么实现呢?
JSP 提供九大内置对象帮我们实现这些功能。在 java 中,我们要想使用一个对象中的方法必须要先实例化一个对象,但是在 jsp 中不需要定义这些对象,可以直接使用。
内置对象 | 描述 |
---|---|
request | 获取用户请求信息 |
response | 返回给浏览器的响应信息 |
application | 全局作用域对象 |
session | 在服务端存储用户信息 |
out | 页面输出 |
config | 获取服务器配置信息 |
page | 表示 jsp 对象本身 |
pageContext | 获取上下文对象 |
exception | 获取异常信息对象 |
3.3.1 request 对象
1.获取请求参数
request.getParameter("参数名");
例如:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<%
String name = request.getParameter("name");
%>
<p>name: <%= name%> </p>
</body>
</html>
启动项目,浏览器输入:
http://localhost:8080/myProject/index.jsp?name=雷布斯
执行结果:
2.共享数据
前面讲 servlet 的请求转发时,讲过使用 HttpServletRequest 对象设置/获取数据,这个效果和它一样。语法格式:
// 设置数据
request.setAttribute("key","value");
// 获取数据
request.getAttribute("key");
3.获取 Cookie 信息
创建 Cookie,保存共享数据
// 1.创建一个 cookie 对象,保存共享数据
Cookie cookie = new Cookie("key","value");
// 2. 将 cookie 信息写入到响应头,交给浏览器
response.addCookie(cookie);
获取 Cookie 中的数据
// 1. 调用请求对象从请求头得到浏览器返回的 Cookie 信息
Cookie cookies[] = request.getCookies();
// 2. 遍历数据获取 cookie 的 key 与 value
for(Cookie cookie:cookies) {
// 3. 获取 key 的值
String key = cookie.getName();
// 4. 获取 value 的值
String value = cookie.getValue();
}
例如:
index1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<%
// 1.创建一个 cookie 对象,保存共享数
Cookie cookie = new Cookie("info","花田里到底犯了什么错?");
// 2. 将 cookie 信息写入到响应头,交给浏览器
response.addCookie(cookie);
%>
</body>
</html>
index2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<%
// 1. 调用请求对象从请求头得到浏览器返回的 Cookie 信息
Cookie cookies[] = request.getCookies();
// 2. 遍历数据获取 cookie 的 key 与 value
for (Cookie cookie : cookies) {
// 3. 获取 key 的值
String key = cookie.getName();
%>
<p>key: <%= key%></p>
<%
// 4. 获取 value 的值
String value = cookie.getValue();
%>
<p>value: <%= value%></p>
<%
}
%>
</body>
</html>
先访问index1.jsp
,再访问index2.jsp
:
4.获取请求行参数信息
// 1. 获取请求行中【url】信息
String url = request.getRequestURL().toString();
// 2. 获取请求行中【method】信息
String method = request.getMethod();
// 3. 获取请求行中【URI】信息,URI: "/网站名/资源文件名"
String uri = request.getRequestURI();
3.3.2 response 对象
1.页面重定向
response.sendRedirect("网址");
例如:index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<%
response.sendRedirect("http://www.baidu.com");
%>
</body>
</html>
启动项目,访问 index.jsp:
2.设置页面刷新
// 设置页面每隔 20 秒刷新
response.setHeader("refresh","20");
3.3.3 application 对象
application 是一个全局作用域对象,同一个网站中 Servlet 和 JSP,都可以通过 application 对象实现数据共享。
// 设置值
application.setAttribute("key","value");
// 获取值
Object object = application.getAttribute("key");
3.3.4 session 对象
JSP 文件在运行时,可以使用 session 对象将数据放入服务器的缓存中。
// 设置值
session.setAttribute("key", 20211219);
// 获取值
Object object = session.getAttribute("key");
3.3.5 out 对象
out 对象可以向向客户端输出信息。
// 不换行
out.print("内容");
// 换行,但是需要用<pre> 标签包起来
out.println("内容");
例如:index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<pre>
<%
out.println("蝴蝶眨几次眼睛,才学会飞行");
out.println("夜空洒满了星星,但几颗会落地");
%>
</pre>
</body>
</html>
3.3.6 config 对象
config 对象主要用于获得服务器的配置信息。config 对象的常用方法如下:
方法 | 说明 |
---|---|
getServletContext() | 返回所执行的Servlet的上下文 |
getServletName() | 返回所执行的Servlet的名字 |
getInitParameter(String name) | 获取服务器所有初始化参数名称 |
getInitParameterNames() | 获取服务器中name参数的初始值 |
不过这个对象用的不多。
3.3.7 page 对象
page 对象有点类似 java 中面向对象中的 this 关键字,他指向了当前jsp 页面本身。
page 对象的常用方法:
方法 | 说明 |
---|---|
getClass() | 获取当前的object类 |
hashCode | 返回page对象的hashCode值 |
toString | 打印当前项目的信息 |
equals | 用于比较对象是否与当前对象相同 |
例如: |
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<% Object object =new Object();%>
<p>getClass(): <%=page.getClass()%></p>
<p>hashCode(): <%=page.hashCode()%></p>
<p>toString(): <%=page.toString()%></p>
<p>与Object对象比较: <%=page.equals(object)%></p>
<p>与this对象比较: <%=page.equals(this)%></p>
</body>
</html>
执行结果:
3.3.8 pageContext 对象
pageContext 对象叫做上下文对象,通过它可以获取JSP页面的 request、response、out等对象。它是这几个内置对象中武功最强的。
pageContext 对象的常用方法:
方法名 | 说明 |
---|---|
forward | 页面重定向 |
getAttribute | 获取参数的属性值 |
findAttribute | 按范围搜索指定名字的属性 |
removeAttribute | 删除某范围中指定名字的属性 |
setAttribute | 设定某范围中指定名字的属性值 |
getException | 获取当前异常对象 |
getRequest | 获取当前请求对象 |
getResponse | 获取当前响应对象 |
getServletConfig | 获取当前页面的ServletConfig对象 |
getServletContext | 获取ServletContext对象 |
getSession | 获取Session对象 |
不过呢 pageContext 对象在实际开发中很少用,因为其他内置对象可以直接使用。再用它去获取其他对象有点"脱裤子放屁“了。 |
3.3.9 exception 对象
exception 对象表示在执行 jsp 文件时抛出的异常,不常用。
3.4 servlet 与 jsp 交互
我们前面说了 JSP 文件可以代替 servlet 中的响应对象,将数据写入到响应体中,那 servlet 和 JSP 文件是怎样打交道的?
-
- servlet 负责处理用户的请求,然后得到处理结果。
-
- servlet 将处理结果添加到作用域对象(例如request作用域)。
-
- servlet 通过请求转发的方式调用 jsp 。
-
- jsp 从请求作用域中获取数据,将数据放到响应体中,然后交给浏览器渲染。
例如:
UserServlet:
@WebServlet("/user")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user1 = new User("唐三", 25, "男");
User user2 = new User("小舞", 22, "女");
User user3 = new User("宁荣荣", 20, "女");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
// 将数据添加到请求作用域对象
request.setAttribute("userList", userList);
// 通过请求转发,向 Tomcat 申请调用 user.jsp
// 同时将 request 与 response 对象通过 tomcat 交给 user.jsp
request.getRequestDispatcher("/user.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
user.jsp:
<%@ page import="com.xxl.model.User" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>user.jsp</title>
</head>
<body>
<%
// 从请求作用域对象得到 UserServlet 添加的数据
List<User> userList = (List)request.getAttribute("userList");
%>
<!--将处理结果写入到响应体-->
<table border="3">
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<%
for(User user:userList){
%>
<tr>
<td><%=user.getName()%></td>
<td><%=user.getAge()%></td>
<td><%=user.getSex()%></td>
</tr>
<%
}
%>
</table>
</body>
</html>
启动项目,访问 UserServlet:
3.5 JSP 文件的运行原理
-
- Tomcat 根据 JSP 规范,将被访问的 JSP 文件编辑为一个java文件。这个 Java 文件是 Servlet 接口实现类。
-
- Tomcat 根据 JSP 规范,调用 JVM 将这个 java 文件编译为
.class
文件。
- Tomcat 根据 JSP 规范,调用 JVM 将这个 java 文件编译为
-
- Tomcat 负责创建这个 class 文件的实例对象。这个实例对象是一个 Servelt 接口实例对象。
-
- Tomcat 通过 Servlet 实例对象调用 jsp_service 方法,将 JSP 文件内容写入到响应体。
从上面的流程我们知道:其实 jsp 就是一个 Servlet。其他 Servlet 通过请求转发向 Tomcat 请求调用 jsp 文件,Tomcat 将这个 jsp 文件变成一个特殊的 Servlet 实例,然后调用它的特殊的方法将数据写入到响应体中。
3.6 JSP 文件和 HTML 文件的区别
-
- HTML 文件属于静态资源文件,需要在浏览器中编译并执行。
-
- JSP 文件属于动态资源文件,需要被服务器编译并执行。
3.7 关于 JSP 的几个问题
1. 为什么要用 JSP?
回答:
因为 servlet 的响应对象适合向响应体写入数据量小的数据,而 JSP 可以向响应体写入数据量大的数据。
2. JSP 和 servlet 的区别
回答:
JSP 经编译后就变成了 Servlet,是 Servlet 的扩展,本质上还是 Servlet。
JSP 是在 Html 代码中嵌入 Java 代码,适合页面的显示。
Servlet 适合动态输出 Web 数据和业务逻辑的处理。
3. JSP 和 Servlet 如何交互
回答:
servlet 处理完用户的请求之后将处理结果添加到 request 作用域对象。然后通过请求转发的方式调用 JSP 文件。
因为在请求转发的过程中,JSP 文件和 Servlet 获取的是同一个请求对象,所以 JSP 可以从 request 请求作用域中获取数据,然后将数据放到响应体中,交给浏览器渲染。