JSP的由来
为什么有JSP规范
Servlet技术产生后,在使用时最麻烦的是使用大量的out.print语句输出页面,这样的形式字系统变更、维护、预览效果时都不能方便快捷的完成任务,于是推出了JSP这种技术,用来将Servlet中负责显示的语句抽取出来。
什么是JSP
Sun公司指定的一中服务器端动态页面技术的组件规范。JSP是以一个.jsp为后缀的文件,在改文件中,主要是HTML和少量的Java代码。JSP文件会被容器转换成一个Servlet类,然后执行;其实JSP就是一个特殊的Servlet
JSP编写规范
如何编写JSP
(1)写一个.jsp为后缀的文件
(2)在该文件中,可以包含如下内容:HTML、注释、Java代码、指令、隐含对象
JSP中的HTML代码
· 像编写HTML一样编写即可
· 作用:控制页面在浏览器中显示的效果
· 转译成Servlet时的规则:成为Servlet中service()方法的out.write语句
JSP页面中的注释
(1)<!-- 注释内容 -->
HTML注释,注释中的内容如果包含Java代码,这些Java代码会被执行;
(2)<%-- 注释内容 --%>
JSP特有的注释,如果注释的内容中出现Java代码,会被忽略;
JSP页面中的Java代码
(1)JSP小脚本
· 语法规则:<% ... ... %>
· 合法内容:能够写在方法里面的java代码片段都可以作为小脚本
· 转译成Servlet时的规则:原封不动称为Servlet类service()方法里面的一段代码
<!-- 写Java代码 -->
<%
//获取当前系统时间
Date date = new Date();
//修改时间格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sdf.format(date);
%>
(2)JSP声明
· 语法规则:<%! ...... %>
· 合法内容:成员属性或成员方法的声明
· 转译成Servlet时的规则:成为JSP页面转译成的Servlet类中成员属性或成员方法
<!-- 2.3JSP声明:定义的函数。 -->
<%!
public int pf(int n){
return n*n;
}
%>
(3)JSP表达式
· 语法规则:<%= ...... %>
· 合法内容:变量、变量加运算符组合的表达式、有返回值的方法
· 转译成Servlet时的规则:在Service()方法中用out.print语句输出该变量、表达式、方法的值
<!-- 用jsp表达式输出变量 -->
<p><%= time %></p>
JSP页面中的指令
(1)page指令:用于导包,设置页面属性
<%@page pageEncoding="utf-8" contentType="text/html" import="java.util.*,java.text.*" %>
(2)include指令
· 作用:在JSP页面转换为Servlet的时候,能够将其他文件包含进来。可以包含JSP文件,也可以是静态的HTML文件。
· 通过该语句能方便的在每一个JSP页面中包含导航栏、版权声明、logo等。
· 语法:
<%@include file= "url" %>
· 例如:
<%@include file= "header.html" %>
<%@include file= "footer.html" %>
JSP运行原理
JSP如何运行
JAP如何转化为Java
如何将静态页面转换为动态页面
(1)拷贝静态页面代码至JSP页面
(2)添加page指令:pageEncording和contentType
(3)修改页面内容与目标页面一致
(4)将需要动态生成的内容删除,替换为Java代码
JSP九大隐含(内置)对象
什么是隐含对象
- 容器自动创建,在JSP文件中可以直接使用的对象
- 作用:JSP预先创建的这些对象可以简化对HTTP请求,相应信息的访问
如图:
转发(对比重定向)
什么是转发
· 一个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续完成
· 如:一个Servlet获取数据之后(比如通过调用dao),将这些数据转发给一个JSP,由这个JSP来展现这些数据(比如,以表格的当时来展现)
如何实现转发
(1)绑定数据到request对象
//name:绑定名;obj:绑定值
request.setAttribute(String name,Object obj);
//读取绑定值
Object request.getAttibute(String name);
//如果绑定名对应的值不存在,返回null
(2)获取转发器
//uri:转发的目的地,即将未完成的处理继续下去的另一个组件,比如一个JSP文件
RequestDispatcher rd = request.getRequestDispatcher(Strng uri);
(3)转发
rd.forward(request,response);
注:通常第二步和第三步会合并
request.getRequestDispatcher(uri).forward(request,response);
转发原理
转发特点
(1)转发之后,地址栏地址不会发生变化。原因是转发的过程是发生在服务器内部的,浏览器并不知道。
(2)转发的目的地必须是同一个应用内部的某个地址
(3)转发索涉及的各个Web组件会共享同一个request对象和response对象
注意:在forward之后的其他语句还会执行吗?
答:一定会执行,但是不会包异常。
转发与重定向的区别
(1)重定向是浏览器发送请求并收到响应以后再次向一个新地址发请求,转发是服务器收到请求之后为了完成响应转到一个新地址;
(2)重定向中有两次请求对象,不共享数据,转发只产生一次请求对象且组件之间共享数据;相当于重定向在两个Servlet之间工作,而转发只是在一个Servlet内部工作;
(3)重定向后地址栏改变;转发后地址栏不会改变;
(4)重定向的新地址可以是任意地址,转发到的新地址必须是用一个应用内的某地址
EL表达式
为什么需要EL表达式和JSP标签
· JSP中嵌套了大量Java代码增加了页面内容的复杂度,是的页面不够简洁,不方便代码的维护;
· 为此Sun公司推出了JSP标签(类似于html标签)来代替Java代码;
· Apache组织开发的一套标签库被Sun公司整合后,称为标准标签库(JSP Standard Tag Library 即JSTL),配合EL表达式,以达到减轻JSP文件的复杂度、方便维护JSP文件的目的;
什么是EL表达式
· EL表达式是一套简单的计算规则,用于给JSP标签的属性赋值,也可以直接用来输出;配合框架的使用,即方便又简洁;
· 表达式也可以脱离标签单独使用
EL表达式的作用
(1)访问Bean属性
方式一:${对象名.属性名}
· 如:${user.name}
· 执行过程:容器会依次从pageContext,request,session,application中查找名称为“user”的对象。找到后,调用“getName”方法,然后输出。
· 其等价代码如下:
<%
User user = (User)request.getAttribute("user");
out.print(user.getName());
%>
注意:上述代码存在一下问题
- 如果request中没有user对象,汇报500错误;
- 没有为name属性赋过值,页面会打出“null”字样;
- 取值时绑定名写错,会报出空指针异常;
但是,以${user.name}方式访问
- 如果没有为name赋值,页面会输出空白,不会出现“null”;
- 如果取值时绑定名写错,页面输出空白,不会报空指针异常;
方式二:${对象名["属性名"]}
· 方括号中的属性名可以使用单引号和双引号;
· 此种方式允许[ ]中出现绑定名,还可以允许[ ]出现从0开始的下标,用于访问数组中的某个元素的值;
· 如:${user["name"]}
或:
<%request.setAtrribute("propName","age");%>
${user[propName]}
注:相当于表达式中写了一个变量
指定对象查找范围
· 在编写EL表达式时,可以指定查找对应绑定名对象的范围;
· 如,在session中查找绑定名为user的对象时,可编写如下:
${sessionScope.user.name}
注:还可以是:pageScope,requestScope,applicationScope这三个作用域;
· 一旦指定了查找范围,那么在该范围内没有找到指定的绑定对象时,不会再去其他的区域中查找;
(2)输出简单的运算结果
· EL表达式可以做一些简单的计算,可将结果直接输出或给JSP标签属性值
- 算数运算:“+”、“-”、“*”、“/”、“%”;
注意:“+”只能求和不能连接字符串;
如:${1+1};
- 逻辑运算:“&&”、“||”、“!”
如:${1>0 && 2<3};
- 关系运算:“>”、“>=”、“<”、“<=”、“==”、“!=”
如:${1 > 2};
- empty:用来判断一个字符串是否为空,或者一个集合是否为空,以下四种情况结果为true:空字符串、空集合、值为null、找不到对应的值;
如:${empty str};
(3)使用EL表达式获取请求参数
· ${param.username} 等价于 request.getParameter("username");
· ${paramValues.city} 等价于 request.getParameterValues("city");
EL对象的来源:就是转发时绑定到request上的对象;
JSTL
什么是JSTL
· JSTL(JSP Standard Tag Library) JSP标准标签库;
· JSP标签是Sun公司定义的一套标准,由Apache组织基于这套标准开发的一套标签库后又转给Sun公司,被称为JSTL,成为了JavaEE5.0的核心;
JSTL运行流程
如何使用JSTL
· step1,将JSTL标签对应的jar文件拷贝到WEB-INF/lib目录下
· step2,使用taglib指令导入要使用的JSP标签;
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="/my-tag" prefix="k" %>
uri:JSP标签的命名空间;
prefix:命名空间的前缀;
核心标签
(1)if 标签
· 语法:
<c:if test="" var="" scope=""></c:if>
· 代码:
<!-- 1. if -->
<p>
<!-- 表示用c标签里面的if标签;test写上条件,满足条件输出内容 -->
<c:if test="${stu.sex=='M' }">男</c:if>
<c:if test="${stu.sex=='F' }">女</c:if>
</p>
· 当test属性值为true时,执行标签体的内容。test属性可以使用EL表达式复制;
· var属性:指定一个绑定名称;
· scope属性:指定绑定的范围:(page、request、session、application);
注:var和scope要配合使用;
(2)choose 标签
· 语法:
<c:choose>
<c:when test=""></c:when>
...
<c:otherwise><c:otherwise>
</c:choose>
· 代码:
<!-- 2. choose -->
<P>
<c:choose>
<c:when test="${stu.sex=='M' }">男</c:when>
<c:otherwise>女</c:otherwise>
</c:choose>
</P>
· when表示一个分支处理,当test属性为true时会执行该分支,可以出现1次或者多次;
· otherwise表示例外,可以出现0次或者1次;
(3)forEach 标签
· 用来遍历集合或者数组
· 语法:
<c:forEach var="" item="">... ... </c:forEach>
· 代码:
<!-- 3. forEach -->
<p>
<!-- 每次循环,JSTL会创建一个对象专门用来记录循环下标循环次数等值。若想获取这个对象则使用varStatus声明该对象的名称。 -->
<c:forEach var="i" items="${stu.interests }" varStatus="s">
<!-- 输出循环的每次输出,直接用EL输出 -->
${i }:${s.index }<br>
循环次数:${s.count }<br>
</c:forEach>
</p>
自定义标签
· step1,编写Java类,继承SimpleTagSupport类;
· step2,在doTag方法中添加处理逻辑;
public class SysdateTag extends SimpleTagSupport {
//利用set传参
private String format;
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
@Override
public void doTag() throws JspException, IOException {
//创建系统时间
Date date = new Date();
//格式化改时间
SimpleDateFormat sdf = new SimpleDateFormat(format);
String now = sdf.format(date);
//输出时间
//该方法声明返回类型是JspContext,
//而实现时返回的时机类型为PageContext
//PageContext extends JspContext
PageContext ctx = (PageContext)getJspContext();
JspWriter out = ctx.getOut();
out.print(now);
//此处不能关闭流,因为其他标签也要使用该流,
//tomcat最终会自动关闭它。
}
· step3,配置标签说明文件
<?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">
<description>我的标签库</description>
<display-name>My Jstl</display-name>
<tlib-version>3.2</tlib-version>
<short-name>k</short-name>
<uri>/my-tag</uri>
<tag>
<description>输出系统时间</description>
<name>sysdate</name>
<tag-class>web.SysdateTag</tag-class>
<body-content>empty</body-content>
<attribute>
<description>格式</description>
<name>format</name>
<!-- 是否必须输入 -->
<required>true</required>
<!-- 是否允许使用EL输入 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
· JSP输出:
<p>
<k:sysdate format="HH:mm:ss"/>
</p>
标签运行原理
· 容器依据JSP标签的命名空间找到标签的描述文件(.tld文件),然后依据标签名字找到标签类,接下来将该标签类实例化;
· 容器会依据标签的属性给标签实例的属性赋值,然后调用标签实例的doTag方法;