JSP高级
一. JSP页面的组成
1.JSP 页面的元素
Servlet做动态页面响应这种方式有几个问题: 1)有大量的字符串拼接操作,操作复杂。 2)前端工程师修改页面代码困难 为了解决以上问题sun公司给出了:Java Server Page——简称JSP技术 JSP是为了同时满足动态生成网页和简化页面书写的需求诞生的。
2.JSP注释
在JSP文件的编写过程中,共有三种注释方法 HTML的注释,将输出到客户端 JSP注释,不翻译到Java文件中,JSP注释只有在JSP文件中可见 <%— JSP注释 —%> 在Java脚本中注释,将翻译到Java文件中,依然是注释语句 <% //单行注释 %> <% /多行注释 / %>
3.JSP指令
3.1 指令概念
JSP可以通过指令元素而影响容器翻译生成Java类的整体结构。 指令的语法为: <%@ directive attr1=”value1” attr2=”value2” %> 其中,directive为指令名,attr指该指令对应的属性名,一个指令可能有多个属性。 JSP中常用的指令有三个:page、include、taglib,本章主要学习其中的两个:page指令、include指令。taglib指令将在JSTL标签章节学习。
3.2 page指令
page指令是最复杂的一个指令,共有13个属性。page指令作用于整个JSP页面,可以将指令放在JSP页面任何一个位置。
1). page指令属性:import
import属性用来引入JSP文件需要使用的类。 如下代码所示: <%@ page import=”java.util. , java.io.“ %> <%@ page import=”com.test.vo.*” %> 上述代码可以在JSP文件中使用,引入需要使用的类。可以使用逗号同时引入多个包,也可以在一个JSP文件中多次使用import。值得注意的是,import是page指令中唯一一个可以在一个JSP文件中多次出现的属性,其他属性在一个JSP文件中只能出现一次。
2). page指令属性:pageEncoding
pageEncoding属性用来设置JSP文件的页面编码格式。 如下代码所示: <%@ page pageEncoding=”utf-8”%> 上述代码设置当前JSP的页面编码格式是utf-8。
3). page指令属性:session
session属性用来设置JSP页面是否生成session对象。该属性默认值为true,可以设置成false。 如下代码所示: <%@ page session=”false”%> session属性值设置为false后,该JSP翻译生成的类中将没有内置对象session,该JSP不参与会话。
4). page指令属性:errorPage
errorPage属性设置JSP页面的错误页面。当JSP中发生异常或错误却没有被处理时,容器将请求转发到错误页面。 如下代码所示: <%@ page errorPage=”error.jsp”%> 显然,当页面将发生异常,而且并没有对异常进行处理,那么将跳转到错误页面,例如定制的error.jsp
5). page指令属性: isErrorPage
isErrorPage属性默认值是false,可以设置为true。在JSP的错误页面中,将isErrorPage设置为true,则该页面翻译生成的Java类中,将生成exception内置对象。 若在error.jsp中加入代码: <%@ page isErrorPage=”true”%> 上述代码将error.jsp页面设置为错误页面,所以,在error.jsp翻译生成的Java类中的_jspService方法中将生成exception内置对象。 注意:即使一个页面没有设置isErrorPage=“true”,也可以作为错误页面使用,区别在是否有内置对象exception内置对象产生。
3.3 include指令
include指令是JSP中另外一个常用指令,用来静态包含其他页面。所谓静态包含,指的是在翻译期间,把包含的页面也翻译到当前页面的Java文件中,所谓Java源文件就实现“二合一”。 若在main.jsp中编写如下代码: <%@ include file=”copyright.jsp”%> 过程:翻译main.jsp时,会把copyright.jsp文件翻译插入到相应位置。
4.JSP标准动作
4.1 标准动作概念
JSP规范中定义了一系列的标准动作。Web容器按照规范进行了实现,可以解析并执行标准动作。 标准动作使用标准的XML语法:
4.2 标准动作 :forward
forward动作:在JSP页面中进行请求转发。 如下代码所示:
4.3 标准动作 :include
include动作:在JSP页面中,进行动态包含。 如下代码所示:
2.静态包含 <%@ include file=”top.jsp” %>
动态包含
3.include指令的属性是file,实现静态包含,发生在翻译阶段,将包含的jsp文件翻译进去 include标准动作的属性是page,实现动态包含,发生在请求阶段,将包含的jsp文件直接翻译成java文件
4.4 标准动作 :param
param动作往往作为子动作使用,为forward和include动作传递参数。 如下代码所示:
二.EL表达式&EL的内置对象
EL全称:Expression Language 语法:${ 表达式} 作用:代替jsp中脚本表达式的功能,简化对java代码的操作。
1. EL使用 - 获取作用域的值
获得四个容器(pagerequestsessionservletContext :域对象)的数据
1.1 ScopeServlet中
@WebServlet(name = “ScopeServlet” , urlPatterns = “/scope”) public class ScopeServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//请求域传值
request.setAttribute("name", "李四");
//获得会话
HttpSession session = request.getSession();
session.setAttribute("name", "张三");
//获得上下文
ServletContext sc = request.getServletContext();
sc.setAttribute("name" , "王二");
//跳转页面
request.getRequestDispatcher("scope.jsp").forward(request, response);
}
}
1.2 scope.jsp中
<% pageContext.setAttribute(“name”, “赵六”); %>
当前页作用域:${pageScope.name} <br>
请求作用域:${requestScope.name} <br>
会话作用域:${sessionScope.name} <br>
上下文作用域:${applicationScope.name} <br>
<br>
${name}
${aaa}
1.3 效果
注意:获取属性时,若使用表达式的话,指定的key不存在,表达式会得到null;而使用EL表达式取出的时候指定的key不存在,页面上什么都没有。
2. EL使用 - 解析复杂数据
复杂数据:数组,集合(List Map),自定义对象(Person User Animal) 案例:EL使用 - 解析复杂数据 <%@ page contentType=”text/html;charset=UTF-8” language=”java” import=”java.util. , com.igeek.javaee.entity.User” %>
<%— EL获取复杂数据 —%> <% //测试数组 int[] arr = {666,1888,2333,1024,999}; pageContext.setAttribute(“arr”, arr); %> 可以通过下标获取数据:${arr[0]}<% //测试集合 List list = new ArrayList(); list.add(“白米饭”); list.add(“咸菜”); list.add(“紫菜汤”); pageContext.setAttribute(“list”, list); Map map = new HashMap(); map.put(“sj1”, “诺基亚”); map.put(“sj2”, “黑莓”); map.put(“sj3”, “摩托罗拉”); map.put(“sj4”, “大哥大”); map.put(“aa.bb.cc”, “波导手机中的战斗机”); pageContext.setAttribute(“map”, map); %> 可以通过下标获取数据:${list[0]}
通过map的key获取数据: ${map.sj1} ${map[“aa.bb.cc”]}
<%— EL获取自定义对象 —%> <% User u = new User(); u.setName(“李四”); u.setAge(18); pageContext.setAttribute(“u”, u); %> 通过相同的属性名称获取数据: ${u} ${u.name} ${u.age} <%— 所有可以使用点的地方,都可以使用[ ]获取数据 —%> ${u[“age”]}
3. EL使用 - 执行运算
3.1 支持算术运算符
- / %
3.2 支持逻辑运算符
3.3 支持比较运算符
代码: <%— 演示El执行运算 —%> <% int x = 3; int y = 4; //String y = “4g”; pageContext.setAttribute(“x”, x); pageContext.setAttribute(“y”, y); %>
<%— 使用EL表达式获取数据,最终都是讲数据转换成字符串,根据字符串,格式化数字,在进行计算 —%> ${x+y } ${x-y } ${x*y } ${x/y } ${x%y }
<% boolean flag = true; boolean info = false; pageContext.setAttribute(“flag”, flag); pageContext.setAttribute(“info”, info); %>
${flag && info}
${!info}
${flag || info}
${x < y } ${x <= y} ${x > y } ${x >= y } ${x == y } ${x != y } 效果:
注意:当算术运算的时候,如果字符串内容不能解析成数据,则报数字格式化异常。数字格式化错误:EL取出来的数据无法转换成数字
3.4 empty运算符:检查对象是否为null或“空”
对于自定义对象,检查是否为null
对于集合检查,是否为空(集合存在,但是没有数据)
代码:
<%
User user = new User();
user.setName(“张三”);
pageContext.setAttribute(“user”, user);
%>
${empty user} 效果: false
3.5 ${ user!=null ? user.name : “”} 三元运算
代码:
<%
User user = new User();
user.setName(“张三”);
pageContext.setAttribute(“user”, user);
%>
${user!=null ? user.name : “” } 效果: 张三
4. EL的11个内置对象使用
EL表达式它也有自己的内置(直接使用)对象可以直接在EL表达式中使用
4.1 从不同的容器中取值
pageScope
requestScope
sessionScope
applicationScope
代码: <% pageContext.setAttribute(“name”,”a”); //只在当前页面
request.setAttribute("name","b"); //一次请求中,可以请求转发
session.setAttribute("name","c"); //会话超时之前都存在,只要浏览器不关闭
application.setAttribute("name","d"); //服务器重启或关闭前都存在,只要服务器不关闭
%>
EL表达式取name:
${pageScope.name }
${requestScope.name }
${sessionScope.name }
${applicationScope.name }
4.2 获取用户提交的请求参数param/paramValues
获取单个值:
param
获取某个key对应的多个value值(例如获取页面中checkbox):
paramValues
代码: ${param.username} ${paramValues.hobby[0]}
测试: http://localhost:8888/javaee/testInnerObj.jsp?username=lisi&hobby=football&hobby=basketball
4.3 获取请求头中的信息 header/headerValues
获取请求头中的单个值:
header
代码:
${header}
结果:
某个请求头中的多个value值:
headerValues
代码:
${headerValues.cookie[0]}
结果:
4.4 cookie内置对象
代码:
<%— ${cookie}获取了cookie数组,获取所有的cookie数据。 —%>
${cookie}
<%— 若要获取数组中的指定cookie,使用点名称的方式获取 —%>
${cookie.JSESSIONID.name }
${cookie.JSESSIONID.value}
${cookie.nameCookie.name}
${cookie.nameCookie.value}
效果:
4.5 pageContext内置对象
它和JSP内置对象pageContext功能一致,可以使用pageContext,获取request对象,调用request对象的方法。 代码: ${pageContext.request.contextPath}
4.6 initParam内置对象
通过initParam获取的项目的全局配置参数 配置:
三.JSTL的核心标签库使用
Sun公司,推出了一套java标签的标准,根据这个标准,自己制作了一套标签,给所有的Java程序员使用,这个标签就是JSTL。 JSTL的介绍:
1. 准备工作
1.1 导入相关jstl的jar包
1.2 使用核心标签库,引入标签库到jsp页面中
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core“ %> prefix 表示的是标签的小名 ; uri 表示的是引入那个标签库
1.3 常见库
core:jstl的核心标签库,使用最多(必须掌握) fmt:格式化的标签(对页面显示数据,格式化,现在都交给前端去做) functions:jstl中提供对字符串操作的函数库(建议,在数据显示在页面之前,在后台程序中,先格式化好字符串,然后直接显示,不再页面做处理,如果有前端,交给前端处理(javascript 解析json格式数据)) sql:jstl提供的在jsp页面上书写sql,操作数据库,目前已经不再(不允许)使用(jsp开发模式二(MVC),这个开发模式不允许,在页面操作数据库) xml:jstl操作xml文件的。目前已经不再使用(页面传递数据,页面解析数据,json格式字符串。)
2. c:if 标签
作用: 相当于java代码中if语句 。 使用c:if 标签,在JSP页面上可以完成if判断。 注意: 在JSTL核心标签库中没有c:else , 只有if( ){ }结构,没有 if( ){ }else{ }结构 写法:
var属性:用来保存test属性的结果(使用var属性给他取个名字),这个结果可以保存到指定的容器中。(如果没有指定容器,默认存入page容器中)
scope属性:指定保存数据的容器。 案例: <%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core“ %>
<%— scope=”session” 设置var中的数据flag保存在会话容器中,值为test的值—%>
pageScope:${pageScope.flag }
requestScope:${requestScope.flag }
sessionScope:${sessionScope.flag }
applicationScope:${applicationScope.flag }
效果:
3. c:choose / c:when / c:otherwise 标签
c:choose c:when c:otherwise 相当于:if( ){ }else if( ){ } else if( ){ } …… else{ }。 c:choose标签它必须与c:when和c:otherwise 标签一起使用,它表示哪些c:when和c:otherwise 是在一组的。 使用c:choose,c:when和c:otherwise 三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。 c:when ,c:otherwise 属于同一级别标签,同时是c:choose的子标签。 代码: <%— 演示choose when otherwise 标签 —%> <%
int num = 4;
pageContext.setAttribute("num", num);
int flag = 1;
pageContext.setAttribute("flag", flag);
%>
<c:when test="${num==1 }">星期一</c:when>
<c:when test="${num==2 }">星期二</c:when>
<c:when test="${num==3 }">星期三</c:when>
<c:when test="${num==4 }">星期四</c:when>
<c:when test="${num==5 }">星期五</c:when>
<c:when test="${num==6 }">星期六</c:when>
<c:when test="${num==7 }">星期日</c:when>
<c:when test="${flag==1 }">白天</c:when>
<c:when test="${flag==2 }">黑夜</c:when>
<c:otherwise>参数不合法</c:otherwise>
效果:星期四
异常:使用when otherwise标签的时候,一定要写在choose标签内,不然报错 异常:一组choose中有多个otherwise,就出现异常。 异常:choose标签中不要写java代码
4. c:set和c:out标签
4.1 c:set
作用:它可以给某个容器中保存数据,或者去修改某个对象的属性值。相当于代替了pageContext.setAttribute。 API截图: var:声明了一个变量空间,用来存储数据(value属性的值)的
value:要保存的数据
scope:指定保存在那个容器中
target:指定要修改的对象
property:指定要修改的属性
代码: <%— 演示set标签 —%>
<%— 演示修改数据 —%> <% pageContext.setAttribute(“user”, new User()); %>
<%— target=”${user}” 指定要修改的对象 property=”name” 指定要修改的属性 —%>
${user}
效果:
异常原因: 修改对象属性的时候不能修改它所在的容器。var 属性和scope属性必须一起使用。
异常原因:target属性和property属性是要一起使用的,如果修改的数据不是对象的属性,那么就会报错
4.2 c:out
作用:它可以把数据输出到页面上,相当于JSP的内置对象out API截图: 代码: <%— 演示out标签 —%> <% pageContext.setAttribute(“str”, null); %>
<%— default设置没有数据的时候,默认输出 —%>
<%— escapeXml=”true” 让浏览器不解析其中的html—%>
5. c:forEach标签
c:forEach 循环的标签。 实现 java中for循环的功能。 API截图: varStatus:保存了当前循环过程中的信息
1 public java.lang.Integer getBegin() 返回为标签设置的begin属性的值,如果没有设置begin属性则返回null
2 public int getCount() 返回当前已循环迭代的次数
3 public java.lang.Object getCurrent() 返回当前迭代到的元素对象
4 public java.lang.Integer getEnd() 返回为标签设置的end属性的值,如果没有设置end属性则返回null
5 public int getIndex() 返回当前迭代的索引号
6 public java.lang.Integer getStep() 返回为标签设置的step属性的值,如果没有设置step属性则返回null
7 public boolean isFirst() 返回当前是否是第一次迭代操作
8 public boolean isLast() 返回当前是否是最后一次迭代操作
5.1 foreach不循环对象(集合、数组)的情况下,单单控制循环的次数。
代码:
<%— 演示foreach标签 —%>
<%—
c:forEach控制迭代 begin起始值 end终止值 step步长,控制循环
var用来设置当前迭代到的元素,保存在page容器中的数据的名称
varStatus保存了循环过程中状态信息
—%>
<%— 用来设置当前迭代到的元素,保存在page容器中的数据的名称 —%>
5.2 foreach循环对象的情况下(数组,集合:list和map)
代码: <%— 演示foreach,循环对象 —%> <% int[] arr = {666,23333,886,9527,82}; pageContext.setAttribute(“arr”, arr); %>
<%— var=”num” :保存的是数组中的元素 —%>
<% List list = new ArrayList(); list.add(“跑男”); list.add(“欢乐喜剧人”); list.add(“极限挑战”); list.add(“笑傲江湖”); list.add(“爸爸去哪儿”);
pageContext.setAttribute(“list”, list); %>
<% Map map = new TreeMap(); map.put(“addr1”, “东京”); map.put(“addr2”, “马尔代夫”); map.put(“addr3”, “巴黎”); map.put(“addr4”, “东南亚”);
pageContext.setAttribute(“map”, map); %>