JSP
jsp相当于java+html。jsp的最大特点在于,写jsp就像在写html。相比html而言,html只能为用户提供静态数据,而jsp技术允许在页面中嵌套java代码,为用户提供动态数据。相比servlet而言,servlet很难对数据进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易对数据进行排版。
不管是JSP还是Servlet,虽然都可以用于开发动态web资源。但由于这2门技术各自的特点,在长期的软件实践中,人们逐渐把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
原因在于,程序的数据通常要美化后再输出,让jsp既用java代码产生动态数据,又做美化会导致页面难以维护;让servlet既产生数据,又在里面嵌套html代码美化数据,同样也会导致程序可读性差,难以维护。 因此最好的办法就是根据这两门技术的特点,让它们各自负责各的,servlet只负责响应请求产生数据,并把数据通过转发技术带给jsp,数据的显示jsp来做。
执行过程
jsp本质上就是servlet。第一次访问jsp文件时,会在tomcat的work目录下生成对应的java文件,然后编译为字节码文件,执行jsp时,其实就是执行对应的class文件,再次访问还jsp时,直接从work下找到对应的class文件并执行。
JSP语法
JSP脚本
<!-- jsp脚本,脚本中声明的变量放在_jspService方法中
可在路径 tomcat\apache-tomcat-8.0.46\work\Catalina\localhost 下找到源文件并查看
-->
<%
//
int num = 10;
String name = "zhangsan";
System.out.println(name);
Date date = new Date();
//对日期字符串进行解析和格式化输出
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = sdf.format(date);
System.out.println(dateStr);
%>
<!-- 必须保证Java语句的完整性 -->
<%
for(int i = 1; i <= 6; i++){
response.getWriter().write("<h" + i + ">标题" + i + "<h" + i +"/>");
}
%>
<%
for(int i = 1; i <=6; i++){
%>
<h<%=i %>>标题<%=i %></h<%=i %>>
<%
}
%>
<%-- jsp的注释,java代码不会对注释进行处理 --%>
JSP表达式
<!-- jsp表达式 -->
<!-- 相当于out.print(name ); -->
<%=name %>
<%=name.length() %>
<!-- 当前时间 -->
<%= new java.util.Date() %>
JSP声明
<!-- jsp声明 -->
<%!
//相当于成员变量
private int aaa = 10;
//定义一个方法
public int add(int a, int b){
return a + b;
}
//不建议使用
int sum = add(10, 12);
%>
<%
//调用方法
System.out.println(add(12, 10));
System.out.println(sum);
%>
三大指令
JSP指令的基本语法格式:<%@ 指令 属性名=”值” %>
include
include指令用于引入其他JSP页面,使用include指令引入其他JSP页面,JSP引擎将把这两个JSP翻译成一个servlet。include指令引入通常也称之为静态引入。
被引入的文件必须遵循JSP语法。被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。
<!-- include.jsp -->
<!-- include指令,相当于将多个文件合成一个文件,转换为一个java文件
file 用于指定被引入文件的相对路径,必须使用相对路径
-->
<%@ include file="header.jsp" %>
page
用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。
配置
<!--
contentType 服务器返回给浏览器内容的编码格式,相当于response.setContentType(...)
pageEndoing JSP文件的编码格式
import 导入的包
session 默认true,表示是否自动创建session对象
errorPage 指定出错时跳转到的界面,只在本jsp中起作用
isErrorPage 指定页面是一个错误处理页面
-->
<%@ page import="java.util.Date" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
session="false"
errorPage="error.jsp"
isErrorPage="true"
%>
<!-- 如果使用exception,必须设置isErrotPage="true",否则无法识别exception -->
<%=exception.toString() %>
全局配置
<!-- 配置全局的错误处理界面 -->
<!-- 在web.xml中配置 -->
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/error.jsp</location>
</error-page>
taglib
用于在JSP页面中导入标签库
内置对象
JSP引擎在调用JSP对应的xxx_jspService时,会传递或创建9个与web开发相关的对象供xxx_jspService使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。
九大内置对象
- request HttpServletRequest
- response HttpServletResponse
- application ServletContext
- session HttpSession
- out JspWriter
- pafeContext PageContext
- exception Throwable
- config ServletConfig
- page Object(this) 较少使用
out
out 隐式对象用于向客户端发送文本数据。
out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
<%@ buffer="8kb" %>
<%
//有缓存 jspWriter使用了缓存,缓存满了、或者flush、或者流关闭,都会将缓存中的内容输出
//JspWriter相当于一种带缓存功能的PrintWriter
//buffer="8kb" 设置缓存out的缓存,默认8kb
out.write("hello");
//刷新缓存
out.flush();
//先执行
response.getWriter().write("hahaha");
%>
pageContext
pageContext对象是JSP技术中最重要的一个对象,它代表当前JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如包含和跳转其它资源、检索其它域对象中的属性等。
<%
//可以获取其他内置对象
pageContext.getRequest();
pageContext.getResponse();
pageContext.getServletContext();
pageContext.getSession();
pageContext.getServeltConfig();
pageContext.getException();
pageContext.getOut();
pageContext.getPage();
%>
<%
//pageContext 域对象
//存储数据
pageContext.setAttribute("msg", "page_msg");
//第三份参数,指定向那个域中设置数据
//四个域对象:request, session, application, pageContext
pageContext.setAttribute("msg", "page_msg", PageContext.PAGE_SCOPE);
pageContext.setAttribute("msg", "page_msg", PageContext.REQUEST_SCOPE);
pageContext.setAttribute("msg", "page_msg", PageContext.SESSION_SCOPE);
pageContext.setAttribute("msg", "page_msg", PageContext.APPLICATION_SCOPE);
%>
<%
//获取
System.out.println(pageContext.getAttribute("msg"));
System.out.println(request.getAttribute("msg"));
System.out.println(session.getAttribute("msg"));
System.out.println(application.getAttribute("msg"));
//从域中查找属性
//pageContext->request->session->application
pageContext.findAttribute("msg");
%>
应用
<!-- userinfo.jsp -->
<%
//从域中获取数据
List<User> list = (List<User>)request.getAttribute("list");
%>
<table>
<tr>
<td>id</td>
<td>name</td>
</tr>
<% for(User user : list){ %>
<tr>
<td><%=u.getId() %></td>
<td><%=u.getName() %></td>
</tr>
<% } %>
</table>
//UserInfoServlet.java
List<User> list = new ArrayList<>();
for(int i = 0; i < 10; i++){
list.add(new User(10 + i, "Tom" + i));
}
request.setAttribute("list", list);
//转发,共享request域中的数据
request.getRequestDispatcher("/userinfo.jsp").forward(request, response);
EL表达式
获取数据
EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的域中检索java对象、获取数据。使用EL表达式获取数据语法:${标识符}
从指定域中获取数据
<!-- xxx.jsp -->
<%
//域中写入数据
request.setAttribute("name", "zhangsan");
//从域中取数据
request.getAttribute("name");
//
pageContext.setAttribute("name", "lisi");
%>
<!-- 获取域中的数据,并且显示到页面上
大括号中的值表示域中的key值,不带双引号
相当于pageContext.findAttribute("name")
没有放到域中,无法读取数据
-->
${name }
<!-- 从指定域中获取数据
pageScope
requestScope
sessionScope
applicationScope
都是EL中的内置对象
pageContext-request-session-applocation
-->
${requestScope.name }
${pageScope.name }
<!-- tomcat8下,可以设置;tomcat7不可以设置 -->
${name="heiheihei" }
${name }
${requestScope.name="123" }
${requestScope.name }
//跳到jsp
request.setAttribute("name", "haha");
request.getRequestDispatcher("/EL.jsp").forward(request, response);
<!-- 无法直接获取一个Java变量的值 -->
<%
int i = 0;
%>
${i }
获取对象属性
<!-- 对象 -->
<%
Student stu = new Student();
stu.setId(10);
stu.setName("lisi");
request.setAttribute("student", stu);
%>
<!-- 读取对象中的属性值 -->
<!-- 内部通过调用get方法获得值 -->
${student }<!-- 输出对象的内容 -->
${student.id }
${student.name }
获取集合中的值
<!-- 集合 -->
<%
List<String> list = new ArrayList<String>();
list.add("zhangsan");
list.add("lisi");
request.setAttribute("list", list);
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "aaa");
map.put("age", 20);
request.setAttribute("map", map);
%>
<!-- 根据下标得到集合中数据 -->
${list[0] }
<!-- map中,根据key值获取value -->
${map["name"] }
${map.name }
表达式运算
<!-- 数学运算 -->
${10 + 3 }
<!-- 关系运算符
false,true,false,true,true
-->
${10 < 3 }
${10 > 3 }
${10 == 3 }
${10 != 3 }
${10 gt 3 }
<!-- 逻辑运算符
false,false,true,true,false,false
-->
${true && false }
${true and false }<!-- 逻辑与 -->
${true || false }
${true or false }<!-- 逻辑或 -->
${!true }
${not true }
<!-- 判断字符串是否是空 -->
<%
String str = "hello";
request.setAttribute("str", str);
%>
<!-- false,false,true -->
${str == null || str == "" }
${empty str }
${not empty str }
<!-- 三目运算符 -->
${empty str ? 1 : 111 }
内置对象
EL 表达式定义了一些内置(隐式)对象,利用这些隐式对象,开发人员可以获得对web中常用对象的引用,从而获得这些对象中的数据。
隐含对象名称 | 描述 |
---|---|
pageContext | 对应于JSP页面中的pageContext对象(注意:取的是pageContext对象) |
pageScope | 代表page域中用于保存属性的Map对象 |
requestScope | 代表request域中用于保存属性的Map对象 |
sessionScope | 代表session域中用于保存属性的Map对象 |
applicationScope | 代表application域中用于保存属性的Map对象 |
param | 表示一个保存了所有请求参数的Map对象 |
paramValues | 表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回的是一个string[] |
header | 表示一个保存了所有http请求头字段的Map对象 |
headerValues | 同上,返回string[]数组。注意:如果头里面有“-” ,例Accept-Encoding,则要headerValues[“Accept-Encoding”] |
cookie | 表示一个保存了所有cookie的Map对象 |
initParam | 表示一个保存了所有web应用初始化参数的Map对象 |
<!-- 获取请求参数 -->
${param["id"] }
${param.id }
<!-- 返回数组结构
针对有key值相同的多个参数,比如checkbox
-->
${paramValues["hobby"][0] }
<!-- 获取请求头中的数据 -->
${header["Host"] }
<!-- 获取cookie对象 -->
${cookie["JSESSIONID"] }
<!-- 得到cookie的名称和值
内部调用getName、getvalue方法
-->
${cookie["JSESSIONID"].name }
${cookie["JSESSIONID"].value }
${cookie.JSESSIONID.value }
<!-- -->
<%
pageContext.getRequest();
%>
<!-- 获得应用路径 -->
${pageContext.request.contextPath }
<!-- 可以获取其他对象,但是不能直接调用get方法 -->
${pageContext.out }
<form action="${pageContext.request.contextPath }/xxx.jsp"></form>
JSP标签
内置动作标签
<!-- 创建对象,对象会放到域中
class 包名+类名
-->
<jsp:useBean id="stu" class="com.ff.servlet.Student" ></jsp:useBean>
<!-- 设置对象的属性值
name 表示对象的名称
property 属性名
value 对应的值
-->
<jsp:setProperty property="name" name="stu" value="lisi" />
<!-- 获取属性值 -->
<jsp:getProperty property="name" name="stu" ></jsp:getProperty>
${stu.name }
<!-- 转发
WE8-INF 下的资源不能直接访问
通常情况下,需要通过转发的方式访问
项目中,访问WE8-INF文件夹下的资源
-->
<jsp:forward page="WE8-INF/xxx.jsp" ></jsp:forward>
JSTL标签
主要包括
- 核心标签(c:)
- JSTL函数(fn:)
- 格式化标签(fmt:)
- 数据库标签
- XML标签
使用
<!-- 导包 导入jstl-1.2.jar文件 -->
<!-- 通过taglib引入jstl的核心标签库,核心标签库的前缀c -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
核心标签库
set/out
<!-- 理解 -->
<!-- 设置值,向域中添加数据
var 相当于变量名
value 对应的值
scope 指定存放的域
-->
<c:set var="name" value="zhangsan" ></c:set>
<!-- 设置null值 -->
<c:set var="name" value="${null }" ></c:set>
<c:set var="age" value="10" scope="request" ></c:set>
${name }
${requestScope.age }
<!-- -->
<%
Student stu = new Student();
request.setAttribute("student", stu);
%>
<!-- target需要设置属性的对象
property需要设置的属性
-->
<c:set target="${student }" property="name" value="lisi" ></c:set>
${student.name }
<!-- 通过表达式设置 -->
<c:set target="<%=stu %>" property="name" value="laowang" ></c:set>
<%=student.getName() %>
<!-- value 要输出的值
default 值不存在时,对应的缺省值
escapeXml 是否让html标签起作用,false起作用,true不起作用
-->
<c:out value="${age1 }" default="<h1>20</h1>" escapeXml="false" ></c:out>
条件判断
<!-- test 中给出判断条件,由EL表达式给出
单条件判断
-->
<c:if test="${10 > 5}" >yes</c:if>
<!-- 相当于往域中写入值 -->
<c:set var="sex" value="男" ></c:set>
<c:if test="${sex == '男' }" >
<input type="radio" chacked="checked" />男
<input type="radio" />女
</c:if>
<!-- -->
<input type="radio" <c:if test="${sex == '男' }">checked="checked"</c:if> />男
<input type="radio" <c:if test="${sex == '女' }">checked="checked"</c:if> />女
<c:set var="score" value="80"></c:set>
<!-- 多条件判断,相当于if(){...}else if(){...}...else{...} -->
<c:choose>
<c:when test="${score >= 0 && score < 60 }">
不及格
</c:when>
<c:when test="${score >= 60 && score < 80 }">
良好
</c:when>
<c:when test="${score >= 80 && score <= 100 }">
优秀
</c:when>
<c:otherwise>值不对</c:otherwise><!-- 其他条件 -->
</c:choose>
循环
<!-- -->
<%
List<String> list = new ArrayList<String>();
for(int i = 0; i < 10; i++){
list.add("Tom" + i);
}
request.setAttribute("list", list);
%>
<!-- 循环遍历
items 表示循环遍历的对象
var 表示每次遍历的元素在pageContext域中的name值
begin/end 指定遍历开始和结束的索引
step 步长 每遍历一个元素后,移动几个元素继续遍历 例似于自增(i++)
varStatus 遍历的元素的状态,状态存在域中,比如,vs表示域中状态对象的name值
setAttribute("vs", ...)
count 数据的序号 从1开始
index 数据在集合中的索引 从0开始
first 判断是否是遍历的第一个元素
last 判断是否是遍历的最后一个元素
-->
<c:forEach items="${list }" var="s" varStatus="vs" begin="2" end="8" step="" >
${s }
${vs.count }<!-- 数据的序号 从1开始 -->
${vs.index }<!-- 数据在集合中的索引 从0开始 -->
${vs.first }<!-- 判断是否是遍历的第一个元素 -->
${vs.last }<!-- 判断是否是遍历的最后一个元素 -->
</c:forEach>
属性名 | 是否支持EL | 属性类型 | 属性描述 |
---|---|---|---|
var | false | String | 指定将当前迭代到的元素保存到page这个Web域中的属性名称 |
items | true | 任何支持的类型 | 将要迭代的集合对象 |
varStatus | false | String | 指定将代表当前迭代状态信息的对象保存到page这个Web域中的属性名称 |
begin | true | int | 如果指定items属性,就从集合中的第begin个元素开始进行迭代,begin的索引值从0开始编号;如果没有指定items属性,就从begin指定的值开始迭代,直到end值时结束迭代 |
end | true | int | 参看begin属性的描述 |
step | true | int | 指定迭代的步长,即迭代因子的迭代增量 |
其他
<!-- 遍历一些特殊写法的字符串
delims 相当于拆分用的分隔符
了解
-->
<c:forTokens items="java-c-php" delims="-" var="v" >
${v }
</c:forTokens>
<!-- 重定向 -->
<c:redirect url="http://www.baidu.com" ></c:redirect>
<!-- 设置url路径 -->
<c:url value="/xxx.jsp" var="url" >
<!-- 设置参数 /xxx.jsp?id=10&name=lisi -->
<c:param name="id" value="10" ></c:param>
<c:param name="name" value="lisi" ></c:param>
</c:url>
<!-- 获取定义的url路径 -->
<a href="${url }" >jstl</a>
格式化标签
<!-- 引入格式化标签库 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!-- 数字的格式化标签
value 要处理的数据
type 数字的类型
number 数字
currency 货币
percent 百分比
pattern 指定格式
currencySymbol 货币符号
minFractionDigits 小数点后面最少多少位
-->
<fmt:formatNumber value="12345.123" type="number" pattern="###,###.##" ></fmt:formatNumbe>
<fmt:formatNumber value="1000" type="currency" currencySymbol="¥" ></fmt:formatNumber>
<fmt:formatNumber value="0.211421" type="percent" minFractionDigits="2" ></fmt:formatNumber>
<!-- 日期的格式化
type
time 时间
date 年月日
both 两者都显示
dateStyle 日期风格
timeStyle 时间的风格
pattern 格式化的样式
-->
<%
Date date = new Date();
request.setAttribute("date", date);
%>
<fmt:formatDate value="${date }" type="date" />
<fmt:formatDate value="${date }" type="time" />
<fmt:formatDate value="${date }" type="both" dateStyle="long" timeStyle="short" />
<fmt:formatDate value="${date }" type="both" pattern="yyyy/MM/dd HH:mm:ss.SSS" />