文章目录
- Java server pages(jsp)
- jsp简介
- jsp语法
- jsp头部的page指令
- jsp中常用的脚本
- 声明脚本(**很少使用**)
- 表达式脚本
- 代码脚本
- jsp中的三种注解
- html注释
- java注释
- jsp注释
- jsp对象
- 九个内置对象
- 四个域对象
- 输出对象
- jsp中常用标签
- jsp静态包含
- jsp动态包含
- jsp标签-转发
- jsp练习题
- 练习一:在jsp页面中输出九九乘法表
- 练习二:jsp输出一个表格,里面有10个学生信息
Java server pages(jsp)
jsp简介
什么是jsp,它有什么作用?
答:jsp全程是java server pages,java的服务器页面,主要作用是替代Servlet程序会穿html页面的数据。这是因为Servlet程序回传html页面数据是一件非常繁琐的事情,开发成本和维护成本都太高。
疑问:为什么要用servlet回传html页面?而不是选择跳转某个html页面?
一个原因是html是静态页面,并不是回传数据
如何访问jsp?
答:jsp页面和html页面一样,都是存放在web目录下,访问也和访问html页面一样
访问地址是http://ip:port/工程路径/a.html以及http://ip:port/工程路径/a.jsp
jsp页面都本质是什么?
答:jsp页面本质上是一个servlet程序,
当第一次访问jsp页面的时候,Tomcat服务器会帮我们把jsp页面翻译称为一个java源文件,并且对它进行编译成为.class字节码文件,可以在idea中的tomcat执行窗口查看org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:
对应路径找到该web工程下jsp被tomcat封装的jsp文件。
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/9.0.41
* Generated at: 2021-02-14 02:43:30 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.*;
public final class a_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
// ....
}
进一步HttpJspBase是继承了HttpServlet对象,如下
由此可知,jsp翻译出来的java类,间接地继承了 HttpServlet类,也就是说,一个jspBase类实际上就是一个Servlet对象。
小结:通过翻译的java源码我们可知:jsp就是Servlet程序。也可以发现,jsp被封装称为java类后,底层也是通过输出流把html页面回传给客户端。
jsp语法
jsp头部的page指令
jsp的page指令可以修改jsp页面中一些重要的属性或者行为
<%@ page contentType="text/html;charset=UTF-8"
language="java"
pageEncoding="UTF-8"
import="java.util.*" autoFlush="true"
errorPage="/error500.jsp"
buffer="8kb"
isErrorPage="true" %>
-
language
属性:表示jsp翻译后是什么语言文件,暂时只支持java -
contentType
属性:表示jsp返回的数据类型是什么,也是源码中response.setContentType()
参数值 -
pageEncoding
属性:表示当前jsp页面本身的字符集(一般不作修改). -
import
属性:和java源代码一样,用于导包,导类。
以下两个属性是给out输出流使用
-
autoFlush
属性:设置当out输出流缓冲区满了之后,是否自动刷新缓冲,默认是true(一般不作修改) -
buffer
属性:设置out缓冲区的大小,默认是8kb(经测试最优,一般不作修改)。
errorPage
属性:设施当jsp页面运行时出错,自动跳转去的错误页面路径
<!-- errorPage 表示错误后自动跳转去的路径,这个路径一般是以斜杠大头,表示请求地址为http:ip:port/工程路径/-->
isErrorPage
属性:设置当前页面是否是错误信息页面,默认是false,如果是true可以获取一场信息session
属性:设置访问当前jsp页面,是否会创建HttpSession对象,默认true(一般用默认不修改)extends
属性:设置jsp翻译出来的java类默认继承谁
jsp中常用的脚本
声明脚本(很少使用)
声明脚本的格式如下:
<%! 声明java代码 %>
作用:可以给jsp翻译出来的java类定义属性和方法,甚至是静态代码块,内部类等。
<%--练习:
--%>
<%--1、声明类属性--%>
<%!
private Integer id;
private String name;
private static Map<String, Object> map;//这个时候上面就会自动导包
%>
<%--2、声明static静态代码块--%>
<%!
static {
map = new HashMap<String, Object>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
}
%>
<%--3、声明类方法--%>
<%!
public int abc() {
return 12;
}
%>
<%--4、声明内部类--%>
<%!
public static class A {
private Integer id = 12;
private String abc = "abc";
}
%>
表达式脚本
表达式脚本的声明格式如下:
<%=表达式%>
表达式脚本的作用是:在jsp页面上输出数据
<%--练习:
1.输出整型
2.输出浮点型
3.输出字符串
4.输出对象 --%>
<%=12 %> <br>
<%=12.12 %> <br>
<%="我是字符串" %> <br>
<%=map%> <br>
<%=request.getParameter("username")%>
效果如下图所示:
上述内容在源码中其实就是调用了write方法
表达式脚本的特点:
- 所有的表达式脚本都会被翻译到
_jspService()
方法中
- 表达式脚本都会被翻译成为
out.print()
输出到页面上 - 由于表达式脚本翻译的内容都在
_jspService()
方法中,所以_jspService()
中的对象都可以直接使用,如request
和response
。 - 表达式脚本中的表达式不能以分号结束。
代码脚本
代码脚本的格式如下
<%
java语句
%>
代码脚本的作用:在jsp页面中,编写我们自己需要的功能(写的是java语句)
代码脚本的特点是:
- 代码脚本翻译之后都在
_jspService()
方法中 - 代码脚本由于翻译到
_jspService()
方法中,所以该方法内的所有对象都可以使用 - 代码脚本可以由多个代码脚本块组合完成一个完整的java语句
<%--1.代码脚本----if 语句--%>
<%
int i = 13;
if (i == 12) {
%>
<h1>国哥好帅</h1> <!-- 这里是输出在页面上 -->
<%
} else {
System.out.println("我更帅") // 这里是输出在java控制台
}
%>
翻译得到的java源码如下:
int i = 13;
if (i == 12) {
out.write("\n");
out.write("<h1>国哥好帅</h1>\n");
} else {
out.write("\n");
out.write("<h1>国哥又骗人了!</h1>\n");
}
- 代码脚本还可以和表达式脚本一起组合使用,在jsp页面上输出数据
<%--2.代码脚本----for 循环语句--%>
<table border="1" cellspacing="0">
<%
for (int j = 0; j < 10; j++) {
%>
<tr>
<td>第 <%=j + 1%>行</td>
</tr>
<%
}
%>
</table>
效果图
jsp中的三种注解
html注释
<!-- 这是html -->
html注释会被翻译到java源代码中,在_jspService方法
里,以out.writer
输出到客户端
java注释
// 单行java主是
/* 多行java注释 */
java注释会被翻译到java源代码中
jsp注释
<%-- 这是jsp注释 --%>
jsp注释可以注掉jsp页面中所有代码,是jsp中真正的注释
jsp对象
九个内置对象
jsp中单内置对象:是指Tomcat在翻译jsp页面成为Servlet源代码后,内部提供的九大对象,叫做内置对象。见如下截图
四个域对象
在上述的九个内置对象中,有四个域对象分别是
-
pageContex
:PageContextImpl
类——在当前jsp页面范围内有效 -
request
:HttpServletRequest
类——一起请求内有效 -
session
:HttpSession
类——一个会话(打开浏览器访问浏览,直到关闭浏览器)范围内有效 -
application
:ServletContext
类——整个web工程范围内都有效(只要web工程不停止,数据都在)
域对象是可以像Map一样存取数据的对象。四个域对象功能一样,不同的是他们对数据的存取范围。
<%
// 往四个域中都分别保存了数据
pageContext.setAttribute("key", "pageContext"); // 当前页面有效,换一个jsp页面就没有
request.setAttribute("key", "request"); // 当次请求有效,如果是请求重定向则有效,如果重新请求泽没有
session.setAttribute("key", "session"); //只要此次浏览器没关闭,就有效,
application.setAttribute("key", "application"); //重新部署项目后无效。
%>
pageContext域是否有值:<%=pageContext.getAttribute("key")%> <br>
request域是否有值:<%=request.getAttribute("key")%> <br>
session域是否有值:<%=session.getAttribute("key")%> <br>
application域是否有值:<%=application.getAttribute("key")%> <br>
说明:虽然四个域对象都可以存取数据,在使用他们上是有优先顺序的——从小到大的顺序
pageContex. ---->>>>. request ----->>>> session ---->>>> application
输出对象
jsp中有两种输出的方法,一种是out输出,以及response.getWriter输出
- response中表示响应,我们常用于设置返回给客户端的内容(输出)
- out也是给客户端的输出
上述两个输出之间存在着转移关系,具体转移顺序见下图:
由于jsp翻译之后,底层源代码都是使用out来进行输出,所以一般情况下,我们在jsp页面中统一使用out来进行输出,避免打乱页面输出内容的顺序。
-
out.write()
:输出字符串没有问题,但如果是其他数据类型,因为会用到字符数组类型作为缓冲,就会出现将其他数据强制转换为字符串数据类型,造成原始数据发生更改,从而使得在页面中的显示有问题,在java中对应的源码如下(以输出整型为例);
public void write(int c) throws IOException {
if (this.writer != null) {
this.writer.write(c);
} else {
this.ensureOpen();
if (this.nextChar >= this.bufferSize) {
this.reAllocBuff(1);
}
this.cb[this.nextChar++] = (char)c; // 将int型转换成为了字符数组
}
}
-
out.println()
输出任意数据都没有问题(都换转换成字符还后调用write输出)以后就用这种
jsp中常用标签
演示该部分的代码如下图所示
jsp静态包含
静态包含出现的需求背景:对于一些重复出现在许多页面中的内容模块(例如许多大网站下方的加入我们…),我们不希望在修改时对每一个包含了该模块的页面进行修改,而是考虑将其单独写在一个页面中,如果有哪个页面需要,直接将其静态包含过去即可。
语法为:
<%@ include file="/include/footer.jsp"%>--%>
下方是main.jsp中的主要代码
<body>
头部信息 <br>
主体内容 <br>
<%--
<%@ include file=""%> 就是静态包含
file 属性指定你要包含的jsp页面的路径
地址中第一个斜杠 / 表示为http://ip:port/工程路径/ 映射到代码的web目录
<%@ include file="/include/footer.jsp"%>--%>
</body>
下方为foot.jsp中的代码
<body>
友情连接 <br>
脚页信息 <br>
</body>
</html>
效果如下图所示:
关于静态包含的一些说明:
- 静态包含不会翻译被包含的jsp页面(文件中只有main的代码)
- 静态包含其实是把被包含的jsp页面的代码拷贝到包含的位置执行输出。
jsp动态包含
和静态包含相比,动态包含的调用语法如下
<jsp:include page="/include/foot.jsp">
<jsp:param name="username" value="bbj"/> <!-- 可选参数 -->
<jsp:param name="password" value="root"/> <!-- 可选参数 -->
</jsp:include>
动态包含的特点:
- 动态包含会把jsp页面也翻译成为java代码
- 动态包含底层代码使用如下代码去调用被包含的jsp页面去执行输出:
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/include/foot.jsp", out, false);
此时,当main.jsp把参数传递过去后,后者的request
,response
以及out
都是前者对应的对象,因此两者共享相关的信息,于是后者就可以将内容写进前者的out缓冲区中,具体底层原理示意图翦下图。
- 动态包含还可以传递参数,此时上述调用方法如下
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/include/foot.jsp" + "?" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("username", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("bbj", request.getCharacterEncoding()) + "&" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("password", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("root", request.getCharacterEncoding()), out, false);
动态包含的底层原理
⭐️ 在实际开发中,我们更多的是使用静态包含
jsp标签-转发
<%--
<jsp:forward page=""></jsp:forward> 是请求转发标签,它的功能就是请求转发
page 属性设置请求转发的路径
--%>
<jsp:forward page="/scope2.jsp"></jsp:forward>
jsp练习题
练习一:在jsp页面中输出九九乘法表
<html>
<head>
<title>Title</title>
</head>
<body>
<table>
<%-- 练习一:在jsp页面中输出九九乘法口诀表 --%>
<h1 align="center">九九乘法口诀表</h1>
<table align="center">
<% for (int i = 1; i <= 9; i++) { %>
<tr>
<% for (int j = 1; j <= i ; j++) { %>
<td><%=j + "x" + i + "=" + (i*j)%></td>
<% } %>
</tr>
<% } %>
</table>
</body>
</body>
</html>
效果图:
练习二:jsp输出一个表格,里面有10个学生信息
<%@ page import="java.util.List" %>
<%@ page import="pojo.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
table{
border: 1px blue solid;
width: 600px;
border-collapse: collapse;
}
td,th{
border: 1px blue solid;
}
</style>
</head>
<body>
<%--练习二:jsp输出一个表格,里面有10个学生信息。--%>
<%
List<Student> studentList = new ArrayList<Student>();
for (int i = 0; i <; i++) {
int t =i+1;
studentList.add(new Student(t,"name"+t,18+t,"phone"+t));
}
%>
<table>
<tr>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>电话</td>
<td>操作</td>
</tr>
<% for (Student student: studentList) { %>
<tr>
<td><%=student.getId()%></td>
<td><%=student.getName()%></td>
<td><%=student.getAge()%></td>
<td><%=student.getPhone()%></td>
<td>删除、修改</td>
</tr>
<% } %>
</table>
</body>
</html>
效果图
在实际的需求中,servlet与jsp页面的协同合作如下图所示:
由于servlet不适合发送数据,于是servlet会把查询得到的数据请求转发给jsp页面,然后jsp页面再将其呈现在用户面前
上述过程用代码实现如下
public class SearchStudentServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求的参数
// 发sql语句查询学生的信息
// 使用for循环生成查询到的数据做模拟
List<Student> studentList = new ArrayList<Student>();
for (int i = 0; i < 10; i++) {
int t = i + 1;
studentList.add(new Student(t,"name"+t, 18+t,"phone"+t));
}
// 保存查询到的结果(学生信息)到request域中
// 请求转发到showStudent.jsp页面
request.setAttribute("stuList", studentList);
request.getRequestDispatcher("/test/showStudent.jsp").forward(request, response);
}
}
对应的jsp页面中也作如下修改(获取来自于request域中的对应的数据)第4行
<body>
<%--练习二:jsp输出一个表格,里面有10个学生信息。--%>
<%
List<Student> studentList = (List<Student>) request.getAttribute("stuList");
%>
<table>
<tr>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>电话</td>
<td>操作</td>
</tr>
<% for (Student student: studentList) { %>
<tr>
<td><%=student.getId()%></td>
<td><%=student.getName()%></td>
<td><%=student.getAge()%></td>
<td><%=student.getPhone()%></td>
<td>删除、修改</td>
</tr>
<% } %>
</table>
</body>
然后请求访问SearchStudentServlet
,即可得到表格结果**(不能直接访问对应的jsp)**