JSP相关
参考: 菜鸟教程JSP
目录
JSP生命周期
https://www.runoob.com/jsp/jsp-life-cycle.html
JSP生命周期与Servlet生命周期类似, 只不过JSP首先需要将JSP文件转成Servlet并编译
-
编译阶段
IDEA中可以通过以下目录找到编译后的JSP文件
C:\Users\用户名\AppData\Local\JetBrains\IntelliJIdea2020.2\tomcat\部署在服务器中的项目名\work\Catalina\localhost\部署在服务器中的项目名\org\apache\jsp
-
test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>测试</title> </head> <body> <p>请求JSP文件时, JSP文件会被转化成相应的Servlet实例, 编译生成Java代码</p> </body> </html>
-
test_jsp.java
package org.apache.jsp; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent, org.apache.jasper.runtime.JspSourceImports { private static final javax.servlet.jsp.JspFactory _jspxFactory = javax.servlet.jsp.JspFactory.getDefaultFactory(); private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants; private static final java.util.Set<java.lang.String> _jspx_imports_packages; private static final java.util.Set<java.lang.String> _jspx_imports_classes; static { _jspx_imports_packages = new java.util.HashSet<>(); _jspx_imports_packages.add("javax.servlet"); _jspx_imports_packages.add("javax.servlet.http"); _jspx_imports_packages.add("javax.servlet.jsp"); _jspx_imports_classes = null; } private volatile javax.el.ExpressionFactory _el_expressionfactory; private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager; public java.util.Map<java.lang.String,java.lang.Long> getDependants() { return _jspx_dependants; } public java.util.Set<java.lang.String> getPackageImports() { return _jspx_imports_packages; } public java.util.Set<java.lang.String> getClassImports() { return _jspx_imports_classes; } public javax.el.ExpressionFactory _jsp_getExpressionFactory() { if (_el_expressionfactory == null) { synchronized (this) { if (_el_expressionfactory == null) { _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory(); } } } return _el_expressionfactory; } public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() { if (_jsp_instancemanager == null) { synchronized (this) { if (_jsp_instancemanager == null) { _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig()); } } } return _jsp_instancemanager; } public void _jspInit() { } public void _jspDestroy() { } public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException { if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) { final java.lang.String _jspx_method = request.getMethod(); if ("OPTIONS".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); return; } if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS"); return; } } 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; try { 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; out.write("\r\n"); out.write("\r\n"); out.write("<html>\r\n"); out.write("<head>\r\n"); out.write(" <title>测试</title>\r\n"); out.write("</head>\r\n"); out.write("<body>\r\n"); out.write(" <p>请求JSP文件时, JSP文件会被转化成相应的Servlet实例, 编译生成Java代码</p>\r\n"); out.write("</body>\r\n"); out.write("</html>\r\n"); } catch (java.lang.Throwable t) { if (!(t instanceof javax.servlet.jsp.SkipPageException)){ out = _jspx_out; if (out != null && out.getBufferSize() != 0) try { if (response.isCommitted()) { out.flush(); } else { out.clearBuffer(); } } catch (java.io.IOException e) {} if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); else throw new ServletException(t); } } finally { _jspxFactory.releasePageContext(_jspx_page_context); } } }
-
-
初始化-执行-销毁阶段
JSP基本语法
1)脚本程序 <% %>
包含在<% %>
中的jsp代码,在编译生成相应Servlet
后, 会包含在_jspService()
方法中
所以凡是可以写在_jspService()
方法中的java代码, 都可以包含在<% %>
中
如:
<%
for (int i = 1; i <= 3; i++) {
%>
<p class="text-success">哈哈哈</p>
<%
}
%>
public void _jspService(final HttpServletRequest request,final HttpServletResponse response)
{
for (int i = 1; i <= 3; i++) {
out.write("\n");
out.write(" <p class=\"text-success\">哈哈哈</p>\n");
out.write(" ");
}
}
2)声明<%! %>
包含在<%! %>
中的jsp代码,在编译生成相应Servlet
后, 会包含在相应Servlet类
中(类中, 方法外)
所以凡是可以写在Servlet类
中的java代码, 都可以包含在<%! %>
中
<%!
public int x = 100;
public void sayHi(){
System.out.println("Hi");
}
%>
public final class jsp脚本元素_jsp {
public int x = 100;
public void sayHi() {
System.out.println("Hi");
}
public void _jspInit() {
}
public void _jspService() {
}
public void _jspDestroy() {
}
}
3)表达式<%= %>
可以JSP页面在任何地方插入表达式, 因为表达式会先被转成string,再插入
<p>
<br>程序范围属性:<%=application.getAttribute("number")%>
<br>会话范围属性:<%=session.getAttribute("number")%>
<br>请求范围属性:<%=request.getAttribute("number")%>
<br>页面范围属性:<%=pageContext.getAttribute("number")%>
</p>
4)指令<%@ %>
用来设置与整个JSP页面相关的属性
<%@ directive(指令) attribute="value" %>
5)注释 <%-- --%>
<%-- JSP注释,注释内容不会被发送至浏览器甚至不会被编译 --%>
JSP指令
https://www.runoob.com/jsp/jsp-directives.html
1) Page指令
发送给Web容器, 定义JSP页面的全局属性, 一个JSP页面可以包含多个Page指令
<%@ page attribute="value" %>
-
buffer / autoFlush
<%@page buffer="8kb" autoFlush="true" %>
JSP页面的缓冲区大小默认为
8kb
, 例如在浏览页面时, 图片一般先写入缓冲区, 等缓冲区满后,再flush显示在页面上 -
isTreadSafe
默认值为
true
,如果设置成false
,则JSP页面转化后的Servlet会实现singleThreadModel
接口public final class jsp指令_jsp implements javax.servlet.SingleThreadModel {
-
session
默认值为
true
session = pageContext.getSession();
如果设置成
false
,则无法在JSP页面中使用session
对象 -
contentType / pageEncoding
指定当前JSP页面的MIME类型和字符编码
<%@page contentType="text/html" pageEncoding="UTF-8" %>
编译后:
response.setContentType("text/html;charset=UTF-8");
-
errorPage / isErrorPage 配置错误页面
通过
errorPage
配置当前页面发生异常是需要跳转的错误处理页面<%@page errorPage="errorPage.jsp" %> // A.jsp
通过
isErrorPage
指定当前页面可以作为错误配置页面<%@page isErrorPage="true"%> // errorPage.jsp
-
import 导入所需的Java类
<%@ page import="java.lang.String"%>
2) Include指令
可以在A页面包含B页面的内容, 例如在多个页面添加同一个导航栏, 可用此指令, 方便维护
<%@include file="menu.html" %>
3) Taglib指令
用于引入一个自定义标签集合
<%@ taglib uri="标签库的地址" prefix="标签的前缀" %>
如引入JSTL的核心标签
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
这样就可以使用JSTL的核心标签了
<c:forEach begin="1" end="3">
<p>测试</p>
</c:forEach>
JSP的四种属性范围
https://blog.csdn.net/evankaka/article/details/46877371
四种属性范围都支持:
public void setAttribute(String name,Object value)
public Object getAttribute(String name)
public void removeAttribute(String name)
作用范围有小到大依次是:
-
page
使用
pageContext
对象设置属性只在当前的
JSP
页面内有效, 跳转后无效 -
request
使用
request
对象设置属性在当前
JSP
页面有效, 若转发该request
对象, 则在下一个页面也有效 -
session
使用
session
对象设置属性在一次会话范围内,无论何种跳转都可以使用,但是新开浏览器无法使用
-
application
使用
application
对象设置属性属性保存在服务器上,所有页面,所有用户都可以使用.
如果两个项目运行在同一个服务器上, 他们都能获取到相应的属性
JSP动作
https://www.runoob.com/jsp/jsp-actions.html
JSP动作基本上都是一些预定义的函数. 用来替代JSP页面中的Java代码.
-
< jsp:forword >
<jsp:forward page="second.jsp"></jsp:forward>
其实就相当于
request.getRequestDispatcher("second.jsp").forward(request,responce);
-
< jsp: include>
<jsp:include page="second.jsp"></jsp:include>
其实就相当于
request.getRequestDispatcher("second.jsp").include(request,responce);
JSP隐式对象
https://www.runoob.com/jsp/jsp-implicit-objects.html
https://blog.csdn.net/evankaka/article/details/46877371
1) pageContext
作用域 page
pageContext对象可以获取当前JSP页面的任何对象,如request, session, application(ServletContext), response, out, ErrorData等
可以获取当前页面四种作用域(page(默认), request, session, application)的属性
public abstract Object getAttribute(String name, int scope);
也可以设置四种作用域的属性
public abstract void setAttribute(String name, Object value, int scope);
PageContext.PAGE_SCOPE(默认) | 1 | page范围 |
---|---|---|
PageContext.REQUEST_SCOPE | 2 | request范围 |
PageContext.SESSION_SCOPE | 3 | session范围 |
PageContext.APPLICATION_SCOPE | 4 | application范围 |
2) request
作用域request
, 与Servlet中的用法相同
3) session
作用域session
,与Servlet中的用法相同
4) application
application是ServletContext的实例
application = pageContext.getServletContext(); // JSP转化后的代码
作用域application
, 可以将信息保存在服务器中, 直至服务器关闭
5) Exception
Exception
代表发生异常的JSP页面中的异常对象.
但Exception
必须在处理异常的页面中使用,
即A.jsp
发生异常, 必须在B.jsp
(处理异常的页面)使用Exception
, Exception
封装了A.jsp
的相关异常信息.
<%@page isErrorPage="true" %> // B.jsp
<%
out.println("<br>异常类型:" + exception.getClass());
out.println("<br>异常消息:" + exception.getMessage());
out.println("<br>异常对象:" + exception);
%>
如果想获得更多错误信息, 可以从pageContext
中获取ErrorData
对象,再获取相关错误信息
<%
ErrorData ed = pageContext.getErrorData();
out.println("<br>请求的URI:" + ed.getRequestURI());
out.println("<br>状态代码:" + ed.getStatusCode());
out.println("<br>异常对象:" + ed.getThrowable());
%>
-
如网页访问量统计
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>网页访问量统计</title> </head> <body> <% if(application.getAttribute("count") == null) { application.setAttribute("count",0); } application.setAttribute("count", (int)application.getAttribute("count") + 1); %> <p> 当前网页的访问量: <%=(int)application.getAttribute("count")%> </p> </body> </html>
EL表达式
1) 访问变量
EL表达式无法直接访问Java代码段中定义的变量,
<% int number = 200 %>
${number1} <%-- 无法访问到 number --%>
必须将该变量添加至四个属性范围中的任意一个才能访问
<% pageContext.setAttribute("number", number); %>
${number1} <%-- 200 --%>
2) 运算符
运算符与Java
基本一致
${1+1} // 2
注意EL表示式中/
的计算结果是浮点数
${4/2} // 2.0
另外empty
可以测试是否为空值
${empty object} // true false
3) 自动处理空值
EL表达式会自动处理空值, 不会出现
NULL POINTER
异常
${number} <!-- 对于为空值变量或属性,EL不会在页面中显示 -->
${number + 1} <!-- 对于算术运算中的空值, EL会作为0处理 1 -->
${number && true} <!-- 对于逻辑运算中的空值, EL会作为false处理 -->
4) 使用函数
-
-
使用Java自定义静态方法
-
首先编写相关的java静态方法
package com.xxx.util; public class StringUtil { public static String getMobile(String mobile){ return mobile.substring(0,3)+"****"+mobile.substring(7,11); } }
package com.xxx.util; import java.util.Random; public class NumberUtil { public static int sum(int a, int b) { return a + b; } }
-
创建编写TLD文件
TLD(即Tag Library Descriptor 标记库描述符)用于描述如何使用标记和函数
<?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>1.0</tlib-version> <!--自定义当前标签库的版本--> <short-name>uf</short-name> <!--当前标签库的简称--> <uri>http://shy.com/util_functions</uri> <!--标签库的唯一表示, 用于在jsp页面中引用该标签库--> <function> <name>sum</name> <function-class>com.qdu.util.NumberUtil</function-class> <!-- 方法的签名: 返回值类型 方法名(参数1类型,参数2类型,...) --> <function-signature>int sum(int,int)</function-signature> </function> <function> <name>getMobile</name> <function-class>com.qdu.util.StringUtil</function-class> <!-- 对于需要导入的包,需要写包的全限定名 --> <function-signature>java.lang.String getMobile(java.lang.String)</function-signature> </function> </taglib>
-
在JSP页面引入自定义的标签库
<%@taglib prefix="utilfc" uri="http://shy.com/util_functions" %> <!-- prefix可以自定义 -->
-
使用EL表达式调用静态方法
${utilfc:sum(3,4)} ${utilfc:getMobile("18888888888")}
-
4)EL 隐含对象
https://www.runoob.com/jsp/jsp-expression-language.html
1) Scope对象
用来获取各个作用域范围内的Attribute
<p>
<br>程序范围属性:${applicationScope.number}
<br>会话范围属性:${sessionScope.number}
<br>请求范围属性:${requestScope.number}
<br>页面范围属性:${pageScope.number}
</p>
2) pageContxt对象
即当前页面的pageContext
隐式对象, 可以获取/设置各作用域的属性, 获取当前页面的对象
3) param对象
获取初始化参数, 如表单中的参数 或是 URL中包含的数据
4) paramValues 对象
获取一个请求参数的一组值, 如获取多选框的值
<form action="first.jsp">
爱好:
<!--多个同一个组的复选框名称可以相同,可以不同,但是一般建议相同-->
<!--如果相同,则参数作为一个字符串数组提交给服务器-->
<input id="h1" checked type="checkbox" name="hobbies" value="LOL">
<label for="h1">英雄联盟</label>
<input id="h2" checked type="checkbox" name="hobbies" value="贪玩蓝月">
<label for="h2">贪玩蓝月</label>
<input id="h3" checked type="checkbox" name="hobbies" value="王者荣耀">
<label for="h3">王者荣耀</label>
<input id="h4" checked type="checkbox" name="hobbies" value="绝地求生">
<label for="h4">绝地求生</label>
<input id="h5" checked type="checkbox" name="hobbies" value="学习">
<label for="h5">学习</label>
<button class="btn btn-success">提交请求参数给first.jsp</button>
<form>
-
非遍历方式获取
<br>爱好: ${paramValues.hobbies[0]} ${paramValues.hobbies[1]} ${paramValues.hobbies[2]} <%--EL表达式会自动处理空值--%> ${paramValues.hobbies[3]} <%--EL表达式会自动处理空值--%> ${paramValues.hobbies[4]}
-
遍历方式获取
<br>爱好: <c:forEach items="${paramValues.hobbies}" var="value"> ${value} </c:forEach>
JSTL:jsp标准标签库
1) 安装JSTL库
在项目中导入相应JAR包
jstl.jar
和standard.jar
可以在Apache官网下载获得
接下来,在每个您想使用JSTL标签的JSP页面上使用 taglib
指令引入相应标签
-
如使用核心标签
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
2) 核心标签
-
引用核心标签
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
-
<c:set> 定义变量
<c:set var="number1" value="${1+2}" scope="page"></c:set>
<c:set var="array" value="${[1,2,3]}"></c:set> <!-- 定义数组 -->
-
<c:remove> 移除变量
<c:remove var="number1"></c:remove>
-
<c:set var="salary" value="6000" /> <c:if test="${salary >= 5000}" var="result" scope="page"> <c:out value="${salary}"></c:out> </c:if> <c:out value="判断结果:${result}"></c:out>
-
<c:choose> 类似于if…else / swith…case
<!-- 优秀 --> <c:set var="score" value="86" /> <c:choose> <c:when test="${score >= 85}">优秀</c:when> <c:when test="${score >= 60}">及格</c:when> <c:otherwise>不及格</c:otherwise> </c:choose>
-
<c:foreach> 遍历
<br>爱好:
<c:forEach items="${paramValues.hobbies}" var="value">
${value}
</c:forEach>
3) 格式化标签
用来格式化并输出文本、日期、时间、数字, 以及国际化等等
简单介绍一下,具体参考API
-
可以用来格式化数字, 货币, 百分比
<br>格式化数字:<fmt:formatNumber value="123456789.987654321" type="number"/> <br>格式化百分比:<fmt:formatNumber value="22.5" type="currency"/> <br>格式化金额:<fmt:formatNumber value="0.55" type="percent"/>
-
可以格式化日期/时间
<!--Date类需要用 @page import指令导包--> <%@ page import="java.util.Date" %> <c:set var="now" value="<%=new Date()%>" /> <br> 未格式化:${now} <br> 格式化日期:<fmt:formatDate value="${now}" type="date"></fmt:formatDate> <br> 格式化时间:<fmt:formatDate value="${now}" type="time"></fmt:formatDate> <br> 格式化日期和时间:<fmt:formatDate value="${now}" type="both"></fmt:formatDate>
-
将给定的区域存储在locale配置变量中, 从而实现国际化
从而根据不同的语言环境,显示不同的格式
<fmt:setLocale value="zh_CN"/> 日期: <fmt:formatDate value="<%=new Date()%>" type="both"/> 金额: <fmt:formatNumber value="123456789.987654321" type="currency"/>
-
根据设置的locale,载入相应的资源束
<fmt:setLocale value="en_US" /> <fmt:setBundle basename="com.shy.bundles.resource" var="mybundle"/>
-
根据所载入的资源束, 找到对应的映射, 替换显示在页面中
<form class="form-inline"> <fmt:message key="labelUname" bundle="${mybundle}"/> <br> <input type="text" name="uname" class="form-control"><br><br> <fmt:message key="labelUpwd" bundle="${mybundle}"/> <br> <input type="text" name="pwd" class="form-control"><br><br> <button class="btn btn-sm btn-primary" > <fmt:message key="labelLogin" bundle="${mybundle}"/> </button> <a href="#"><fmt:message key="labelReg" bundle="${mybundle}"/></a> </form>
4) SQL 标签
利用SQL标签可以在不编写Java代码而操作相关数据库, 不过还是推荐使用JDBC
的方式操作数据库
这里简要了解一下SQL标签
-
<sql:setDataSource driver="com.mysql.cj.jdbc.Driver" url="....." user="root" password="....." var="ds" scope="session" />
<sql:query dataSource="${ds}" var="rs" scope="page"> <!-- rs保存了查询的结果集--> select * from student where sbatch=? <sql:param value="班级"></sql:param> <!-- 将?设为"班级" --> </sql:query>
<!-- 结果集(ResultSet)包含很多信息,不仅仅包含行(row)数据,还包含数据的额外信息 需要使用${结果集.rows}获取所有的行数据进行遍历 --> <c:forEach items="${rs.rows}" var="row"> <tr> <td>${row.sid}</td> <td>${row.spassword}</td> <td>${row.sname}</td> <td>${row.sgender}</td> <td>${row.sbatch}</td> </tr> </c:forEach>
JSP 国际化
-
Locale
JSP容器能够根据request的locale属性来提供正确地页面版本
request.getLocale()
-
Content-Language
通过设置Http报头的
Content-Language
,来使页面能够显示其他语言<%@ page import="java.io.*,java.util.Locale" %> <%@ page import="javax.servlet.*,javax.servlet.http.* "%> <% // 设置页面内容要显示的语言 response.setHeader("Content-Language", "es"); String title = "En Espa?ol"; %> <html lang="es"> <!-- lang属性为告知浏览器该页面的语言, 从而浏览器可以提供翻译功能 --> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <head> <title><%out.print(title); %></title> </head> <body> <p>¡Vamos Barça!</p> </body> </html>