JSP
Java Sever Page,本质就是 Servlet,初有 Servlet 时,Servlet既要处理业务逻辑又要负责输出html,由于在其中输出html太过繁琐,于是推出了JSP技术专注于显示。
- Introduction
- 指令
- page 指令
- include 指令
- taglib 指令
- 内置对象
- 内置标签
- <jsp:forward标签>
- <jsp:include>标签
- JSP中使用JavaBean
- ExpressionLanguage
- 使用EL内置对象获得数据
- EL的内置对象:
- EL表达式内置对象的操作:
- 使用EL表达式可以获取JAVABEAN属性、集合项的值
- 使用EL可以进行逻辑运算
- EL函数库
- 自定义EL函数库
- 系统自带的EL函数.
- 使用EL内置对象获得数据
Introduction
运行原理图

- JSP由 HTML, JSP脚本和标签构成
- HTML代码使用 out.write()输出
- JSP脚本使用<% %> 程序代码标签包围Java代码,即JSP脚本,其中不可以定义方法。在该脚本中写的java代码最终会生成到jsp对应Servlet类中的service方法中。
- 声明标签:
<%! int i = 0; %> - 表达式:
<%= %>同out.print(); - JSP注释
- 服务器端注释:
<%-- --%>被注释掉的内容不会参与编译,转化阶段消失,只能被开发人员看到 - html注释:
<!-- -->被注释掉的内容不显示但是不会消失
- 服务器端注释:
指令
指令元素用于指示JSP执行某些步骤或者指示JSP表现特定行为,语法格式
<%@ directive [ attribute =“value” ] * %>
page 指令
用于定义JSP文件的全局属性,属性包含在
<%@ page和%>之间
属性:
- language: 声明使用脚本的种类,如
language="java" - import:用来导包或类的列表,唯一一个可以出现多次的标记属性
contentType="text/html;charset=UTF-8":响应浏览器时,告诉浏览器JSP页面响应的MIME类型以及用什么码表解码- pageEncoding="UTF-8”:指定服务器读取jsp时采用的编码格式,其优先权高于contentType, 以上两个属性,指定一个,另一个会自动指定
- session:是否需要使用session对象,设置为false,则session内置对象会消失。默认为true,一般不用修改
- errorPage:处理异常事件是调用的JSP页面(不常用)
- isErrorPage:设置此页是否可为其他页errorPage的目标,值取“true”或"false”(不常用)
- buffer="8kb”:指定对客户端输出缓冲区的大小(不常用)
- autoFlush: 当buffer溢出时,如果该属性设置为true,会将缓存自动输出到浏览器,设置为false,将会报错。(不常用)
- extends:指定继承类,需要加入Java class的全名,默认继承org.apache.jasper.runtime.HttpJspBase,通过该属性可以改变,但必须是HTTPServlet的子类。(不用)
<!-- 错误页面可以在web.xml中使用如下统一配置 -->
<error-page>
<error-code>500</error-code>
<location>/zhiling/Demo2.jsp</location>
</error-page>
include 指令
静态包含,在JSP页面中静态包含一个文件,同时由JSP解析包含的文件内容

语法格式:<%@ include file=“filename” %>
- file不能为一变量,如:
<% String url="index.html" ; %>
<%@ include file = "<%= url %>" %>
- file所指定的文件后不可以再接任何参数,如:
<%@ include file = "jw.jsp?nm=browser" %>
demo1.jsp
<body>
常见写法:<br>
<%@ include file="Demo2.jsp" %>
<%=i %>
</body>
demo2.jsp
haha
xixi
heihei
hehe
gaga
hiahia
<%
int i = 10;
%>
taglib 指令
引入标签指令,允许用户使用标签库自定义新的标签,例如常用的标签库:JSTL
语法格式:<% taglib uri="taglibURI" prefix="tabPrefix"%>
- uri - 标签文件的URI地址
- prefix - 标签组的命名空间前缀
taglib指令中的uri属性用于根据标签的前缀对自定义的标签进行唯一的命名,其值可以是相对路径,绝对路径或标签库描述文件。
内置对象
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
PageContext pageContext = null;
HttpSession session = null;
Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
if (exception != null) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
//……
}
| 类型 | 变量名称 |
|---|---|
| HttpServletRequest | request |
| HttpServletResponse | response |
| HttpSession | session |
| Throwable | exception |
| ServletContext | application |
| ServletConfig | config |
| Object | page |
| JspWriter | out |
| PageContext | pageContext |
-
request对象是javax.servlet.http.HttpServletRequest类的实例,它代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据(头信息、系统信息、请求方式以及请求参数等)
-
response对象是javax.servlet.HttpServletResponse类的实例。它代表了客户端的响应,它提供了一系列方法来获取HTTP头信息,cookies,HTTP方法,表单数据等
-
session对象是javax.servlet.http.HttpSession类的实例,主要用来跟踪在各个客户端请求间的会话
-
application是javax.servlet.ServletContext类的实例。ServletContext是全局对象,可用于存放共享数据
-
out对象主要向输出流写入内容,jsp中使用JspWriter在向外输出内容
response.getWriter 和 JspWriter 有什么区别?- response.getWriter的输出会出现在JspWriter输出的前面
- JspWriter缓存会附加到response.getWriter缓存后,最终输出response.getWriter缓存
注意:JSP中不要直接使用response.getWriter
-
PageContext对象主要作用是获取任何范围的参数
- page域:范围只在当前页面当中(4个域中最小一个域)
存值:
pageContext.setAttribute("", "");
取值:pageContext.getAttribute("");
删除一个值:pageContext.removeAttribute("");- pageContext操作其他3个域:
存值:
pageContext.setAttribute("name", "tom",PageContext.REQUEST_SCOPE );
取值:pageContext.getAttribute("name", PageContext.REQUEST_SCOPE);
删除一个值:pageContext.removeAttribute("name", PageContext.REQUEST_SCOPE);
查找各域中的属性:pageContext.findAttribute();
遍历所有键:pageContext.getAttributeNamesInScope(PageContext.REQUEST_SCOPE);- 获得其他8个内置对象:
jsp主要负责显示,所以应该尽量减少jsp中Java代码,当逻辑代码转移到Java类中时,需用用到jsp的内置对象,此时就只需要传递一个PageContext对象就可以获得其他对象
pageContext.getRequest();
pageContext.getResponse();
pageContext.getSession();
pageContext.getServletContext();
pageContext.getServletConfig();
pageContext.getOut();
pageContext.getException();
pageContext.getPage(); -
page对象代表JSP本身,是页面实例的引用,指向了当前JSP程序本身的对象(this)
-
config对象是javax.sevlet.ServletConfig类的实例,主要用于取得服务器的配置信息。servletConfig对象仅对servlet自身有效,一个servlet的ServletConfig对象不能被另一个servlet访问。
-
exception对象包装了从先前页面中抛出的异常信息,主要用于产生对出错条件的适当响应。
内置标签
内置标签,不需要引入,用于在jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码造成jsp页面难以维护
<jsp:forward标签>
<jsp:forward page="/jspTag/Demo2.jsp">
<jsp:param name="name" value="tom" ></jsp:param>
</jsp:forward>
<!-- <jsp:forward>之后的代码不执行 -->
接受用户输入并将请求分派给另一页面,相当于如下java代码:
request.getRequestDispatcher("").forward(request, response);
<jsp:include>标签
动态包含

<jsp:include page="/jspTag/Demo2.jsp"></jsp:include>
请求时文件包含,相当于如下java代码:
request.getRequestDispatcher("").include(request, response);
动态包含与静态包含的区别:

JSP中使用JavaBean
JSP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分别为:
<jsp:useBean>标签
用于在指定的域范围内查找指定名称的JavaBean对象。如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
语法:
<jsp:useBean id="beanName" class="po.User" scope="page|request|session|application"/>
- id属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称
- class属性用于指定JavaBean的完整类名(即必须带有包名)
- scope属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application等四个值中的一个,其默认值是page
<jsp:useBean id="u" scope="page" class="cn.beans.User" >
</jsp:useBean>
相当于如下java代码:
User user = new User();
pageContext.setAttribute("u", user);
<jsp:setProperty>标签
用于设置和访问JavaBean对象的属性。
语法:
<jsp:setProperty name="beanName"
{
property="propertyName" value="{string | <%= expression %>}" |
property="propertyName" [ param="parameterName" ] |
property= "*"
}/>
- name属性用于指定JavaBean对象的名称。
- property属性用于指定JavaBean实例对象的属性名。
- value属性用于指定JavaBean对象的某个属性的值,value的值可以是字符串,也可以是表达式。为字符串时,该值会自动转化为JavaBean属性相应的类型,如果value的值是一个表达式,那么该表达式的计算结果必须与所要设置的JavaBean属性的类型一致。
- param属性用于将JavaBean实例对象的某个属性值设置为一个请求参数值,该属性值同样会自动转换成要设置的JavaBean属性的类型。
<jsp:setProperty property="name" name="u" param="name" />
相当于如下java代码:
((User)pageContext.getAttribute("u")).setName(request.getParameter("name"));
<jsp:getProperty>标签
用于读取JavaBean对象的属性,也就是调用JavaBean对象的getter方法,然后将读取的属性值转换成字符串后插入进输出的响应正文中。
语法
<jsp:getProperty name="beanInstanceName" property="PropertyName" />
- name属性用于指定JavaBean实例对象的名称,其值应与jsp:useBean标签的id属性值相同
- property属性用于指定JavaBean实例对象的属性名
- 如果一个JavaBean实例对象的某个属性的值为null,那么,使用jsp:getProperty标签输出该属性的结果将是一个内容为“null”的字符串
<jsp:getProperty property="name" name="u"/>
相当于如下java代码
out.print(((User)pageContext.getAttribute("u")).getName());
Demo: demo1.jsp
<body>
<form action="/Review/jsp/Demo4.jsp" method="post">
用户名:<input type="text" name="name"/><br>
密码:<input type="password" name="password"/><br>
<input type="submit"/><br>
</form>
</body>
demo2.jsp
<body>
<jsp:useBean id="u" scope="page" class="po.User"></jsp:useBean>
<jsp:setProperty property="name" name="u" param="name"/>
<jsp:getProperty property="name" name="u"/>
</body>
以上代码相当于:
<%
po.User user = new po.User();
pageContext.setAttribute("u", user);
((po.User) pageContext.getAttribute("u")).setName(request.getParameter("name"));
out.print(((po.User) pageContext.getAttribute("u")).getName());
%>
ExpressionLanguage
EL封装内省的操作,可以通过EL替代页面上的代码操作JAVA BEAN
使用EL内置对象获得数据
EL的内置对象:
requestScope 、sessionScope、applicationScope、pageScope 通过以上4个内置对象可以对4大域进行访问 以下内置对象用处不大: param、paramValues(返回string[]) - 这两个对象封装了表单参数: header、headerValues - 这两个对象封装了HTTP请求头 initParam - 封装了web.xml中配置,初始化参数 pageContext - 封装了9大内置对象中的 cookie - 封装了cookie信息
注意事项:
- 测试headerValues时,如果头里面有“-”,例Accept-Encoding,则要headerValues[“Accept-Encoding”]
- 测试cookie时,例${cookie.key}取的是cookie对象,如访问cookie的名称和值,须${cookie.key.name}或${cookie.key.value}
EL表达式内置对象的操作:
格式: ${}
<%
request.setAttribute("name", "requestTom");
session.setAttribute("name", "sessionTom");
application.setAttribute("name", "applicationTom");
pageContext.setAttribute("name", "pageTom");
%>
${requestScope.name} - <% request.getAttribute("name"); %>
${sessionScope.name} - <% session.getAttribute("name"); %>
${applicationScope.name} - <% application.getAttribute("name"); %>
${pageScope.name} - <% pageContext.getAttribute("name");%>
EL表达式如果获得的值是null,那么什么都不打印
从最小的域开始,找key为name的属性值
${name} - <%pageContext.findAttribute("name");
下面试试剩下不常用的7个内置对象
param 获得单个值,paramValues 获得多个值,这两个对象封装了表单参数
${param.name } - <% request.getParameter("name"); %>
${paramValues.habit } - <% request.getParameterValues("habit"); %>
header, headerValues 这两个对象封装了HTTP请求头
${header.Accept } - <%request.getHeader("Accept"); %>
${headerValues.Accept } - <%request.getHeaders("Accept"); %>
initParam 封装了web.xml中配置
${initParam.name } - <% application.getInitParameter("name"); %>
pageContex 封装了9大内置对象中的 pageContext
${pageContext.request.contextPath } - <% ((HttpServletRequest)pageContext.getRequest()).getContextPath(); %>
cookie封装了cookie信息
<%
Cookie c = new Cookie("name","jerry");
c.setMaxAge(60*60);
response.addCookie(c); %>
${cookie.name.value } -->
<%
for(Cookie cookie : request.getCookies()){
if(cookie.getName().equals("name")){
cookie.getName();
}
}
%>
使用EL表达式可以获取JAVABEAN属性、集合项的值
使用EL访问User对象:
<%
User u = new User();
u.setName("tom");
request.setAttribute("user", u);
%>
${requestScope.user.name} - <%((User)request.getAttribute("user")).getName(); %>
${requestScope.user['name']} - <%((User)request.getAttribute("user")).getName(); %>
使用EL访问数组:
<%
String[] array = new String[]{"tom","jerry","jack","rose"};
request.setAttribute("array", array);
%>
${requestScope.array[2]}
使用EL访问List:
<%
List<String> list = new ArrayList<String>();
list.add("jack");
list.add("rose");
request.setAttribute("list", list);
%>
${requestScope.list[1]}
使用EL访问Map:
<%
Map<String,String> map = new HashMap<String,String>();
map.put("birthday", "now");
map.put("haha.heihei", "hiahia");
request.setAttribute("map", map);
%>
${requestScope.map.birthday}
${requestScope.map['birthday']}
${requestScope.map['haha.heihei']}
使用EL可以进行逻辑运算
<%
request.setAttribute("num1", 10);
request.setAttribute("num2", 20);
%>
<!-- EL表达式支持如下运算符: -->
${num1 > num2} -> ${num1 gt num2}
${num1 < num2} -> ${num1 lt num2}
${num1 <= num2} -> ${num1 le num2}
${num1 >= num2} -> ${num1 ge num2}
${num1 == num2} -> ${num1 eq num2}
${num1 != num2} -> ${num1 ne num2}
${true && true}
${true || true}
${!true}
${(num1 > num2)?"num1厉害":"num2厉害" }
EL函数库
简化页面中静态方法的调用,使用EL函数代替JAVA代码
自定义EL函数库
先定义工具类,在类中定义静态方法并填写配置文件xxx.tld放到WEB-INF下除了classes和lib目录之外的任意子目录中 Tool.tool
package tool;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Tool {
public static String getTime() {
return new SimpleDateFormat("hh:mm:ss").format(new Date());
}
public static void main(String[] args) {
System.out.println(Tool.getTime());
}
}
myFn.tld
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 版本号没啥用 -->
<tlib-version>1.0</tlib-version>
<!-- 推荐使用的前缀 -->
<short-name>myFn</short-name>
<!-- 给该标签库起一个"包名",在页面中引入时使用 -->
<!--TLD文件中的<uri>元素用指定该TLD文件的URI,在JSP文件中需要通过这个URI来引入该标签库描述文件-->
<uri>http://www.iamwyj.com/myFn</uri>
<!-- 注册一个EL函数 -->
<function>
<!-- 声明函数名称 -->
<name>getTime</name>
<!-- 注册静态方法所在的完整类名 -->
<function-class>tool.Tool</function-class>
<!-- 绑定类中的静态方法 -->
<function-signature>java.lang.String getTime()</function-signature>
</function>
</taglib>
之后在需要使用的页面中引入
<%@ taglib prefix="myFn" uri="http://www.itcast.cn/myFn" %>
后再使用${myFn:getTime()}
Demo.jsp
<%@ page language="java" pageEncoding="UTF-8" import="tool.Tool" %>
<%@ taglib prefix="myFn" uri="www.iamwyj.com" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'Demo1.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<!-- 方式一 -->
<%=Tool.getTime() %><br>
<!-- 方式二 -->
${myFn:getTime()}<br>
</body>
</html>
访问后浏览器分别以上诉两种方式显示当前时间
系统自带的EL函数.
<!-- 判断是否包含 -->
${fn:contains("hiahia", "hi")}
<!-- 判断是否以某字符串结尾(有BUG) -->
${fn:endsWith("abha", "ha")}
<!-- 自动将html关键字符转义 -->
${fn:escapeXml("<font color='red'>haha</font>")}