JSP原理
JSP本质上跟Servlet是一样的,可以看作是Servlet的扩展。
JSP页面包括HTML标签和JSP标签。相比Servlet,JSP更容易维护,因为我们可以分离设计和开发。JSP提供了额外的特性,比如Expression Language,、Custom Tags等等
JSP经过 JSP translator 会变为Servlet(java文件)。JSP translator是web服务器的一部分。这个java文件会被编译器编译为class文件。之后会按照Servlet流程,像初始化、提交响应、销毁等等
启动tomcat,进入JSP页面,然后我在主机C:\Users\Bi\AppData\Local\JetBrains\IntelliJIdea2021.2\tomcat\05551e6e-aedf-4778-b8d6-655f016681e2\work\Catalina\localhost\ROOT\org\apache\jsp,找到了被编译好的java和class文件,这是idea创建的tomcat工作空间。
打开这个java文件,我们会发现这个类继承了HttpJspBase,而HttpJspBase又继承了HttpServlet
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports
此外,我们还可以发现初始化、销毁以及Service操作,以及请求和响应
一些内置对象与赋值
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
以及对于我们在jsp中写的HTML代码,会被逐行输出
因此对于jsp,会被转为一个Servlet java文件,文件中的类继承HttpJspBase,创建了很多对象和方法。此外对于jsp中的HTML代码,会被以out.write的形式输出到前端上,而对于java代码,则会原封不动的输出,因此java代码甚至可以直接使用现成的创建好的对象,比如application等
JSP基础语法和指令
依赖
<!--Servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!--jsp依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<!--standard标签库-->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!--jstl表达式依赖-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
jstl包有时候即使导入进来,存在于本地仓库中,但在项目发布时仍然报错,有可能是Tomcat问题,发布时没有把jar包带上。因此可以把此jar包拷贝到Tomcat的lib目录下即可
JSP语句
jsp注释
html注释会被输出到前端去,而jsp注释不会
<%--我是jsp注释--%>
<!--我是HTML注释-->
jsp表达式
在java代码中,是out.print( new java.util.Date());
<%= %>
<%--JSP表达式:用来将程序的输出,输出到客户端上
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
通常我们一般使用 EL 表达式进行输出
${new java.util.Date()}
用EL表达式的好处在于,当输出的对象不存在时,前端不会显示。而jsp表达式输出时,前端会显示null
jsp脚本片段
<% %>
<%--JSP脚本片段--%>
<%
int sum = 0;
for (int i = 0; i < 100; i++) {
sum+=i;
}
out.println("<h1>sum=" + sum + "</h1>");
%>
jsp声明
jsp声明会被编译到生成的java类中,而像jsp脚本片段和jsp表达式这些都被生成到_jspService方法中
<%! %>
<%--JSP声明--%>
<%!
static{
System.out.println("Loading Servlet!");
}
private int globalVar = 0;
public void kuang(){
System.out.println("方法kuang");
}
%>
jsp指令
<%@ %>
<%@ page import="java.util.Date" %> <%--导入java包--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%--指定contentType--%>
<%@ page errorPage="error/500.jsp" %> <%--发生错误后,转向error下的500.jsp页面--%>
<%--直接将三个页面代码合在一起--%>
<%@include file="common/header.jsp"%>
<h1>我是主体</h1>
<%@include file="common/footer.jsp"%>
补充:错误页面也可以在web.xml中设置
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
jsp标签
使用jsp标签可以简化一些操作,常用的是include(包含页面)、forward(转发)、param(设置参数,转发时会把这些参数带上,保存在Request中)
<jsp:XXX />
<jsp:include page="common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="common/footer.jsp"/>
<jsp:forward page="jsptag2.jsp">
<jsp:param name="name" value="yuan"/>
<jsp:param name="age" value="12"/>
</jsp:forward>
JSP的9大内置对象
PageContext、Request、Response、Session、Application(Servlet Context)、config(Servlet Config)、out、page、exception
对于 pageContext、request、 session、 application,会有各自的作用域
下面以存储属性为例展示
pageContext 保存的数据只在一个页面中有效
request 保存的数据在一次请求中有效,请求转发时也会携带这个数据
session 保存的数据在一次会话中有效,从打开浏览器到关闭浏览器
application 保存的数据在服务器中有效,直到服务器关闭,或删除此Servlet对象
pageContext.findAttribute()类似于双亲委派机制,会一直往上查找符合的属性,直到Application
PageContextDemo01.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--内置对象--%>
<%
pageContext.setAttribute("name1","page"); //保存的数据只在一个页面中有效
request.setAttribute("name2","request"); //保存的数据在一次请求中有效,请求转发时也会携带这个数据
session.setAttribute("name3","session"); //保存的数据在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","application"); //保存的数据在服务器中有效,直到服务器关闭,或删除此Servlet对象
%>
<%
String name1 = (String)pageContext.findAttribute("name1");
String name2 = (String)pageContext.findAttribute("name2");
String name3 = (String)pageContext.findAttribute("name3");
String name4 = (String)pageContext.findAttribute("name4");
String name5 = (String)pageContext.findAttribute("name5");
pageContext.forward("/PageDemo02.jsp");
%>
<%--EL表达式 ${} --%>
<h1>取出的值为:</h1>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1>${name4}</h1>
<h1>${name5}</h1> <%--不会显示null--%>
<h1><%=name5%></h1> <%--会显示null--%>
</body>
</html>
之后,我们在PageDemo02.jsp中尝试去取这些属性,结果发现只能取到session和applicaion。说明不同的页面下,不能取到PageContext和Request对象中存的值,这也体现了作用域的概念
当然,我们也可以去设置存进去属性的作用域,会自动判断是存进当前页面,还是session等等
pageContext.setAttribute("name","yuan",1);
在jsp页面中,也可以实现请求转发。转发会携带请求,如果此时获取属性,可以获得Request对象中设置的属性,但Page中的依然不会获得
pageContext.forward("/PageContextDemo01.jsp");
EL表达式 ${}
获取数据
${name1}
执行运算
${score>90}
获取Web开发中常用对象
JSTL标签
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能,可以让我们的使用更加方便。功能上跟java代码是一样的
JSP标准标签库可以分为五类:核心标签、格式化标签、SQL 标签、XML 标签、JSTL 函数
其中,核心标签是最常用的 JSTL标签。引用核心标签库的语法如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
比如,for each,用el表达式获取列表传给items,用var用来定义变量
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
ArrayList<String> list = new ArrayList<>();
list.add("yuan");
list.add("qi");
list.add("bin");
request.setAttribute("test", list);
%>
<c:forEach var="people" items="${test}" begin="1" end="3" step="1">
<c:out value="${people}"/>
</c:forEach>
设置变量,choose选择
<c:set var="score" value="88"/>
<c:choose>
<c:when test="${score>90}">
<c:out value="优秀"/>
</c:when>
<c:when test="${score>80}">
<c:out value="一般"/>
</c:when>
</c:choose>