本文被 系统学习JavaWeb 收录点击订阅专栏
JSP(java server pages), 即Java的服务器界面。其主要作用是 代替 Servlet 程序回传 html 页面数据。
因为 Servlet 程序回传 html 页面数据很繁琐,维护成本比较高。
如果通过Servlet程序回传html数据,演示代码如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 兴趣使然黄小黄
* @version 1.0
* 演示传统Servlet回传html数据的繁琐
*/
public class PrintHtml extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过响应的输出流回传html页面数据
resp.setContentType("text/html;charset=UTF-8");
PrintWriter writer = resp.getWriter();
writer.write("\r\n");
writer.write("\r\n");
writer.write("\r\n");
writer.write(" \r\n");
writer.write(" Title \r\n");
writer.write("\r\n");
writer.write("\r\n");
writer.write("这是html页面数据\r\n");
writer.write("\r\n");
writer.write("\r\n");
writer.write("\r\n");
}
}
而实际开发时,html的代码多达千行万行,可见,传统Servlet程序回传html的方式相当繁琐!
而JSP的主要作用就是代替Servlet程序回传html页面的数据:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
这是html页面数据
body>
html>
如何访问JSP页面?
a.jsp访问地址:http://ip:port/工程路径/a.jsp
jsp页面的本质是一个Servlet程序。
当第一次访问jsp页面时,Tomcat服务器会帮我们把jsp页面翻译成为一个java源文件,并将它翻译成为.class字节码文件。
源代码中,jsp页面所翻译出来的类继承了HttpJSPBase类,该类直接继承了HttpServlet类。即,jsp翻译出来的java类,间接继承了HttpServlet类,是一个Servlet程序。
jsp的page指令可以修改jsp页面中的一些重要属性或行为。
属性 | 说明 |
---|---|
language属性 | 表示jsp翻译后是什么语言文件,目前只支持java |
contentType属性 | 表示jsp返回的数据类型。也是源码中response.setContentType()的参数值 |
pageEncoding属性 | 表示当前jsp页面文件本身的字符集 |
import属性 | 用于导包,导类 |
autoFlush属性 | 设置当out输出流缓冲区满了之后,是否自动刷新缓冲区,默认值是true |
buffer属性 | 设置out缓冲区的大小,默认8kb |
errorPage属性 | 设置当jsp页面运行出错时,自动跳转的错误页面路径 |
isErrorPage属性 | 设置当前jsp页面是否有错误信息,默认是false,如果是true可以获取异常信息 |
session属性 | 设置访问当前jsp页面,是否会创建HttpSession对象,默认是true |
extends属性 | 设置jsp翻译出来的java类默认继承的父类 |
声明脚本的语法格式:
<%! 声明java代码 %>
可以给jsp翻译出来的java类定义属性和方法,甚至是静态代码块,内部类等。
演示代码如下:
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %><%--
Created by IntelliJ IDEA.
User: 26510
Date: 2022/10/17
Time: 8:52
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<%--1.声明类属性--%>
<%!
private String id;
private String name;
private int age;
private static Map<String, Object> map;
%>
<%--2.声明static静态代码块--%>
<%!
static {
map = new HashMap<String, Object>();
map.put("key1", "value1");
map.put("key2", "value2");
}
%>
<%--3.声明类方法--%>
<%!
public int sum(int a, int b){
return a+b;
}
%>
<%--4.生成内部类--%>
<%!
public static class A{
private String telephone;
}
%>
</body>
</html>
表达式脚本的语法格式:
<%= 表达式 %>
可以在jsp页面上输出数据。
演示代码如下:
<%--1.输出整型--%>
<%=12 %><br>
<%--2.输出浮点型--%>
<%=12.12 %><br>
<%--3.输出字符串--%>
<%="我是黄小黄" %><br>
<%--4.输出对象--%>
<%=map %><br>
表达式脚本的特点:
代码脚本的语法格式:
<% java语句 %>
可以在jsp页面中,编写自己需要的功能。
演示代码如下:
<%--1.代码脚本:if语句--%>
<%
int i = 10;
if (i == 10){
System.out.println("i = 10");
}else {
System.out.println("i != 10");
}
%>
<%--2.代码脚本:for语句--%>
<%
for (int j = 0; j < 10; j++) {
System.out.println(j);
}
%>
<%--3.翻译后java文件中_jspService方法内的代码都可以写--%>
<%
String username = request.getParameter("username");
System.out.println("username = " + username);
%>
代码脚本的特点:
<%
for (int j = 0; j < 10; j++) {
%>
<%=j %>
<%
}
%>
在jsp中分为三种注释:
该注释会被翻译在java源代码中,在_jspService方法中,以out.write输出到客户端。
//单行注释
/*多行注释*/
java注释会被翻译到java源代码中。
<%--这是jsp注释--%>
jsp注释可以注释掉jsp中所有代码。
test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>乘法表</title>
</head>
<body>
<table>
<%for (int i = 1; i <= 9; i++) {%>
<tr>
<%for (int j = 1; j <= i; j++) {%>
<td><%=j + "x" + i + "=" + (j*i)%></td>
<%}%>
</tr>
<%}%>
</table>
</body>
</html>
jsp的内置对象,是指,Tomcat服务器在翻译jsp页面成为Servlet源代码后,内部提供的九大对象。
对象 | 说明 |
---|---|
request | 请求对象 |
response | 响应对象 |
pageContext | jsp的上下文对象 |
session | 会话对象 |
application | ServletContext对象 |
config | ServletConfig对象 |
out | jsp的输出流对象 |
page | 指向当前的jsp对象 |
exception | 异常对象 |
其中exception异常对象需要在page指令的参数isErrorPage="true"时才存在。
域对象是可以像Map一样存取数据的对象,四个域对象的功能一样,区别是对数据的存取范围。
下表列举了四个域对象和作用范围
对象 | 作用范围 |
---|---|
pageContext(PageContextImpl类) | 当前jsp页面范围 |
request(HttpServletRequest类) | 一次请求内 |
session(HttpSession类) | 一个会话范围内(打开浏览器访问服务器,直到关闭浏览器) |
application(ServletContext类) | 整个web工程范围内有效(只要web工程不停止,数据都在) |
在进行代码演示前,需要导入Tomcat中lib目录下的jsp与Servlet的jar包!
演示代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>scope.jsp页面</h1>
<%
//在四个域中都分别保存了数据
pageContext.setAttribute("key", "pageContext");
request.setAttribute("key", "request");
session.setAttribute("key", "session");
application.setAttribute("key", "application");
%>
pageContext域是否有值:<%=pageContext.getAttribute("key")%>
request域是否有值:<%=pageContext.getAttribute("key")%>
session域是否有值:<%=pageContext.getAttribute("key")%>
application域是否有值:<%=pageContext.getAttribute("key")%>
</body>
</html>
可以尝试多创建一个jsp页面,关闭浏览器,再次部署web项目打开服务器的方式一步步扩大范围,最终结果与表中所述一致!
四个域对象虽然都可以存取数据,但是 具有自己的优先顺序,优先级从小到大如下:
response表示响应,用于设置返回给客户端的内容(输出);
out 也是给用户输出使用的。
演示案例:
虽然out语句在response之前,但是结果确是response在前,out在后。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
out.write("out输出1
");
out.write("out输出2
");
response.getWriter().write("response输出1
");
response.getWriter().write("response输出2
");
%>
</body>
</html>
过程图解如下:
当jsp页面中的所有代码执行完成后会做如下的操作:
由于jsp翻译的servlet程序中源码都是out进行输出的,为了避免打乱页面的内容顺序,所以在jsp中一般统一使用out输出。
关于out.write()与out.print()
方法 | 说明 |
---|---|
out.write() | 输出字符串 |
out.print() | 输出任意数据类型(转换成字符串后调用了write输出 |
静态包含一般用于加载进页面显示后就再也不变的东西, 比如页眉、背景、标题等等。静态包含不会检查所含文件的变化,把文件包含进来后,被包含文件的修改变化是不会影响已被包含进来的内容的。
静态包含发生在编译阶段。比如:a.jsp中使用了语句 <%@ include file=“b.jsp”%>,把b.jsp包含了进来,那么在编译a.jsp文件时, 会直接把b.jsp文件的内容全部内嵌到a.jsp文件中包含b的语句的位置。 然后运行a,显示a页面。也就是说,静态include是先把被包含文件的内容全部复制内嵌到包含文件中,再进行编译运行的。也 正是因为要把b包含进a,所以b中的变量等不能与a重复,否则会报错。
演示案例:将footer.jsp内嵌在main.jsp中
footer.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
脚页信息<br>
body>
html>
main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
头部信息<br>
主体内容<br>
<%@include file="/include/footer.jsp"%>
body>
html>
静态包含小结:
动态包含用于加载经常变化的、要求显示最新版本内容的东西。 比如提交时间戳:用户打开博客编辑页面时,有一个时间加载进来了。用户编写完博客,点击提交时,就应该使用/显示提交瞬间的时间而不是打开编辑页面时的那个时间。所以这里要用的就是最新时间。由上面我们知道,静态include是先包含进来,再编译,运行并传回浏览器显示的,所以不能满足我们要求某些部分使用最新内容的要求。那么,我们就要用到动态include。
动态include与静态include的最大不同在于:包含文件与被包含文件都是先编译执行,再包含。二者的编译阶段是相互独立的,只有在包含文件的include语句处把被包含文件的执行结果包含进来。 换言之,包含文件先编译,执行。执行到了include语句的时候才触发被包含文件的编译、执行,并实时把结果包含进来。从而达到获取最新的被包含内容的目的。同样使用a.jsp包含b.jsp的例子:加入a.jsp中动态include了b.jsp。现在,a先编译成servlet类文件,然后运行,当运行到包含b的语句处,引起b的编译,运行,并把b的运行servlet运行结果包含进a。最后a顺利运行完毕,把a的servlet类运行结果输出到浏览器显示。
案例代码:
footer.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
脚页信息<br>
body>
html>
main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
头部信息<br>
主体内容<br>
<jsp:include page="/include/footer.jsp">jsp:include>
body>
html>
运行结果页面与上个案例一致(但是底层原理和对象有区别)
原理示意图:
动态包含小结:
JspRuntimeLibrary.include(request, response, "/include/footer.jsp", out, false);
之前学过的请求转发:
request.getRequestDispatcher("/include/footer.jsp").forward(request, response);
另一种形式
<jsp:forward page="/include/footer.jsp"></jsp:forward>
本文部分内容参考:尚硅谷JavaWeb课程。好了,本文内容到这里就告一段落了,欢迎大家订阅专栏,加入JavaWeb学习!点击订阅
如果你有任何问题,欢迎私信,感谢您的支持!