Jsp:用java语言+html语言 开发动态资源的技术
Jsp继承自servlet
Servlet技术: 开发动态资源。是一个java类,擅长写java代码。
jsp技术: 开发动态资源。用于通过java代码输出html代码。
Jsp的特点:
1)jsp的运行必须交给tomcat服务器。
tomcat的work目录: tomcat服务器存放jsp运行时的临时文件
2)jsp页面既可以写html代码,也可以写java代码。(html页面不能写java代码 ,而jsp页面可以写java代码)
可以把jsp页面当做html页面在tomcat中访问
目录
Jsp的执行过程:
- (翻译)访问hello.jsp页面,tomcat扫描到jsp文件,在%tomcat%/work把jsp文件翻译成java源文件 (hello.jsp -> _hello_jsp.java)
- (编译)tomcat服务器把java源文件编译成class字节码文件 (_hello_jsp.java -> _hello_jsp.class)
- (实例化)tomcat服务器构造_hello_jsp类对象
- (调用service)tomcat服务器调用_hello_jsp类里面方法,返回内容显示到浏览器。
注意:
第一次访问jsp:->1.->2.->3.->4.
第n次访问jsp:->4.
jsp文件被修改了或jsp的临时文件被删除了,要重新走(1)翻译和(2)编译的过程
jsp翻译成的java文件:
public final class _hello_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent {
HttpJspBase类:
public abstract class org.apache.jasper.runtime.HttpJspBase extends javax.servlet.http.HttpServlet implements javax.servlet.jsp.HttpJspPage {
所以Jsp就是一个servlet程序
servlet的技术可以用在jsp程序中,jsp的技术并不是全部适用于servlet程序!
Servlet的生命周期:
- 构造方法(第1次访问)
- init方法(第1次访问)
- service方法
- destroy方法
Jsp的生命周期:1.翻译->2.编译->3456.同Servlet
- 翻译: jsp->java文件
- 编译: java文件->class文件(servlet程序)
- 构造方法(第1次访问)
- init方法(第1次访问):_jspInit()
- service方法:_jspService()
- destroy方法:_jspDestroy()
Jsp语法
jsp页面中会被翻译成servlet程序:html语句会被翻译成 out.write("html语句"); jsp语句会被翻译成对应的java语句
Jsp表达式
语法:<%= 变量或表达式 %>
作用:向浏览器输出变量的值或表达式计算的结果
原理:表达式被翻译成 out.print(变量); 通过该方法向浏览器写出内容。表达式后面不需要带分号来结束
Jsp的脚本
语法:<% java代码 %>
作用:执行java代码
原理:把脚本中java代码原封不动拷贝到_jspService方法中执行。不能声明方法,因为代码在_jspService方法中
Jsp的声明
语法:<%! 声明变量或方法 %>
作用:声明jsp的变量或方法
原理:变量翻译成成员变量,方法翻译成成员方法。不能声明servlet程序已经存在的方法,如:_jspInit()···
Jsp的注释
语法: <%!-- jsp注释 --%>
注意:html的注释依然会被翻译和执行。而jsp的注释不能被翻译和执行。
Jsp的三大指令
include指令:
作用:在当前页面用于包含其他页面
语法:<%@ include file="路径/包含的页面.jsp" %>
原理:把被包含的页面(分页.jsp)的内容翻译到包含页面(主页.jsp)中,合并成翻译成一 个java源文件,再编译运行!这种包含叫静态包含(源码包含,先合并在翻译)
如果使用静态包含,被包含页面中不需要出现全局的html标签了(如html、head、 body),只要body里的内容就行
page指令:
作用: 告诉tomcat服务器如何翻译jsp文件
<%@ page
language="java" 告诉服务器使用什么动态语言来翻译jsp文件,目前jsp只支持java
import="包名1 , 包名2" 导入java包,多个包之间用逗号分割
jsp执行过程中编码转换:jsp文件-①-> 保存到硬盘-②-> 翻译java源文件-③-> 编译class字节码-④-> 发送到浏览器-⑤-> 浏览器解码
pageEncoding="utf-8" 告诉服务器使用什么编码翻译jsp文件 ②③
contentType="text/html; charset=utf-8" 服务器发送浏览器的数据类型和内容编码。 ④ 省略不写值会参考pageEncoding
注意:在eclipse工具中,①也会参考pageEncoding,所以只需要设置pageEncoding即可解决中文乱码问题
异常错误相关:
errorPage="目录/名称.jsp" 指定当前jsp页面的错误处理的跳转页面 比web.xml中的全局配置优先
isErrorPage="true" 指定当前页面是否为错误处理页面 false则没有exception内置对象
<!-- 在web.xml中 配置全局错误处理页面 -->
<error-page>
<error-code>500</error-code>
<location>/路径/500错误跳转页面.jsp/html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/路径/404错误跳转页面.jsp/html</location>
</error-page>
buffer="8kb" jsp页面的缓存区大小
session="true" 是否开启session功能 false则没有session内置对象
isELIgnored="false" 是否忽略EL表达式
%>
taglib指令:
作用:在jsp页面导入标签库
<%@taglib uri="tld文件的<uri>" prefix="标签库简称<short-name>"%> tld文件:声明标签
*Jsp的内置对象*
在jsp开发中,会频繁使用到一些对象。所以Sun公司设计Jsp时,在jsp页面加载完毕之后就会自动帮开发者创建好这些对象,而开发者只需要直接使用这些对象调用方法即可,这些创建好的对象就叫内置对象。
9大内置对象:
内置对象名 | 类型 |
* request | HttpServletRequest |
response | HttpServletResponse |
config | ServletConfig |
* application | ServletContext |
* session | HttpSession |
exception | Throwable |
page | Object(this) |
out | JspWriter |
* pageContext | PageContext |
Out对象:
out对象类型,JspWriter类的实例,相当于带缓存的PrintWriter
PrintWriter: response发送实体内容
wrier(内容):直接向浏览器写出内容。
JspWriter:
writer(内容):向jsp缓冲区写出内容。 缓冲区默认大小8kb
当满足以下条件之一,缓冲区内容写出到PrintWriter:
- 缓冲区满了
- 刷新缓存区 out.flash();
- 关闭缓存区 buffer="0kb"
- 执行完毕jsp页面
pageContext对象:
pageContext对象的类型是PageContext,叫jsp的上下文对象
1)可以获取其他八个内置对象
例:jap翻译成的java文件
public class _hello_jsp {
public void _jspService(request,response){
//Service中创建所有的内置对象
HttpSession session =···;
ServletConfig config = ···;
······
//把其他8个内置对象封装到PageContext对象中
PageContext pageContext = 封装其他8个对象;
//调用自定义方法,传入pageContext对象
自定义方法(pageContext);
}
public void 自定义方法(PageContext pageContext){
//从PageContext对象中获取其他的内置对象,就可以在自定义方法中使用Service中的内置对象
JspWriter out = pageContext.getOut();
HttpServletRequest rquest = pageContext.getRequest();
······
}
}
在自定义标签的时候,PageContext对象会频繁使用到!
2)本身是一个域对象
因为pageContext可以获取其他对象,所以可以往其他的域对象中存取数据
保存数据
- 默认情况下,保存到page域。 pageContext.setAttribute("name");
- 可以向四个域对象保存数据。 pageContext.setAttribute("name",域范围常量)
获取数据
- 默认情况下,从page域获取。 pageContext.getAttribute("name")
- 可以从四个域中获取数据。 pageContext.getAttribute("name",域范围常量)
- 自动在四个域中搜索数据。 pageContext.findAttribute("name"); 搜索顺序:page域 > request域 > session域 > context域(application域)
域范围常量:
PageContext.PAGE_SCOPE
PageContext.REQUEST_SCOPE
PageContext.SESSION_SCOPE
PageContext.APPLICATION_SCOPE
注意:从哪个域保存的数据就必须从哪个域取出
域对象详解:
四个域对象:
pageContext page域
request request域
session session域
application context域
域对象作用:保存数据 和 获取数据 ,用于数据共享
域对象方法:
setAttribute("name",Object) 保存数据
getAttribute("name") 获取数据
removeAttribute("name") 清除数据
域对象作用范围:
page域:只能在当前jsp页面中使用
request域:只能在同一个请求链中使用(转发)
session域:只能在同一个会话(session对象)中使用。私有的
context域:只能在同一个web应用中使用。全局的
开发jsp的原则: 尽量在jsp页面中少写甚至不写java代码。(用EL表达式替换掉 jsp表达式,用jsp标签替换掉 jsp脚本)
EL表达式
EL表达式作用: 向浏览器输出域对象中的变量值或表达式计算的结果
EL语法:${ 变量或表达式 }
1)输出基本数据类型变量
1.1 从四个域自动获取:${变量}
等价于:pageContext.findAttribute("变量");
1.2 指定域获取:${域范围.变量} 域范围:pageScoep / requestScope / sessionScope / applicationScope
等价于:pageContext.getAttribute("变量",域范围常量)
2)输出javabean对象的属性
先将对象放入域对象,然后使用 ${对象.xx属性} 点相当于调用getXX()方法。 注意:XX并不是属性名,而是getXX()方法中get后的字母
等价于: <%=((对象类型)pageContext.findAttribute("对象")).getXX()%>
3)输出集合对象(List 和 Map)
先将集合放入域对象,然后使用 ${list集合[参数].xx属性} / ${map集合['键'].xx属性} 中括号相当于调用get(参数)方法
等价于:((集合类型)pageContext.findAttribute("集合")).get(参数/键)
4)EL表达式计算
算术表达式,比较运算,逻辑运算,判空
${name==null || name==""} / ${empty name }
Jsp标签
Jsp标签作用:在jsp页面执行java代码
Jsp标签分类
- 内置标签(动作标签): 不需要在jsp页面导入标签
- JSTL标签: 需要在jsp页面中导入标签
- 自定义标签 : 开发者自行定义,需要在jsp页面导入标签
- 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
内置标签
转发标签: <jsp:forward/>
参数标签: <jsp:pararm/>
<jsp:forward page="/路径"> <jsp:param value="jacky" name="name"/> <jsp:param value="123456" name="password"/> </jsp:forward>
等价于:request.getRequestDispatcher("/路径?name=jacky&password=123456").forward(request,response);
包含标签: <jsp:include/>
<jsp:include page="/包含的页面.jsp"> <jsp:param value="lucy" name="name"/> </jsp:include>
原理: 包含与被包含的页面先各自翻译成java源文件,然后再运行时合并在一起。动态包含(可以传递参数,先翻译再合并)
- 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
JSTL标签
(java standard tag libarary / java标准标签库)
核心标签库(c标签库)
国际化标签(fmt标签库)
EL函数库(fn函数库)
xml标签库(x标签库)
sql标签库(sql标签库)
JSTL标签使用步骤:
- 项目中导入jstl支持的jar包 (标签背后隐藏使用的java代码)
- jsp页面中使用taglib指令导入标签库 :<%@taglib uri="tld文件的<uri>"prefix="标签库简称<short-name>"%>
- 在jsp中使用标签
核心标签库的主要标签: 注意:有些参数中不能用el表达式
保存数据:c:set 保存数据到域中,默认保存到page域
<c:set var="name" value="jacky" scope="page"></c:set>
获取数据:c:out 控制value值输出。value值为null时使用default。escapeXml(默认true):对value值进行转义,当作文本内容输出
<c:out value="${name}" default="默认值" escapeXml="false"></c:out>
单条件判断:c:if
<c:if test="判断">true输出,false不输出</c:if>
多条件判断:choose标签+when标签+otherwirse标签
<c:choose>
<c:when test="判断1">if true 输出</c:when>
<c:when test="判断2">else if true 输出</c:when>
判断3、4、5······
<c:otherwise>else 输出</c:otherwise>
</c:choose>
循环数据:c:forEach,c:forTokens
-------------------forEach标签:遍历数据 ------------------
<c:forEach begin="开始元素(默认0)" end="结束元素(默认遍历所有元素)" step="步数(默认1)" items="${要遍历的数据(集合)}"var="元素名称"varStatus="count属性(从1开始)">
普通遍历方法:(序号:${count属性.count} - 值:${元素名称} )<br/>map集合遍历方法:(map键:${元素名称.key} - map值1:${元素名称.value.属性1 } - map值2:${元素名称.value.属性2 })<br/>
</c:forEach>--------------forToken标签: 循环特殊字符串 ---------------
<%
String str = "java-php-c++-.net";
pageContext.setAttribute("str",str);
%>
<c:forTokens items="${str}" delims="-" var="s">
将字符串切割后循环输出:${s }<br/>
</c:forTokens>
重定向:c:redirect
<c:redirect url="http://www.baidu.com"></c:redirect>
- 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
自定义标签
自定义标签开发步骤:
1)编写一个普通的java类,实现SimpleTag接口 / 继承SimpleTagSupport类,覆盖doTag方法。叫标签处理器类
SimpleTagSupport中的代码:
//传入pageContext对象
private JspContext context;
public void setJspContext(JspContext pc) {
this.context = pc;
}
//提供getJspContext()方法获取pageContext
doTag方法内容:
//得到pageContext对象
PageContext pageContext = (PageContext)this.getJspContext();
//编写实现标签功能的java代码······
2)在web项目的WEB-INF目录下建立对应的.tld文件,这个tld叫标签库的声明文件。(参考核心标签库的tld文件)
<!-- 标签库声明 -->
<!-- 标签库的版本 -->
<tlib-version>1.1</tlib-version>
<!-- 标签库简称 -->
<short-name> 标签库简称 </short-name>
<!-- *tld文件的唯一标记* -->
<uri> tld文件的uri </uri>
<!-- 一个标签的声明 -->
<tag>
<!-- 标签名称 -->
<name>标签名</name>
<!-- *标签处理器类的全名* -->
<tag-class>包名.类名</tag-class>
<!-- 输出标签体内容格式 -->
<body-content>JSP/scriptless/empty/tagdependent</body-content>
<!-- 标签一个属性的声明 -->
<attribute>
<!-- 属性名称 -->
<name>属性名</name>
<!-- 是否必填 -->
<required>true</required>
<!-- 是否支持EL表达式 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
输出标签体内容格式:
JSP: 只能在传统标签中使用的。可以写和执行jsp的java代码。
scriptless: 标签体不可以写jsp的java代码
empty: 必须是空标签。
tagdependent :标签体内容可以写jsp的java代码,但不会执行
3)在jsp页面的头部导入自定义标签库
<%@taglib uri=" tld文件的uri " prefix=" 标签简称<short-name> "%>
4)在jsp中使用自定义标签
<标签库简称:标签名> </标签库简称:标签名>
自定义标签的执行过程:
例:http://localhost:8080/webroot/myTag.jsp 如何访问到自定义标签?
前提: tomcat服务器启动时,加载到每个web应用,加载每个web应用的WEB-INF目录下的所有文件!!!例如。web.xml、tld文件
-
- 访问mytag.jsp资源
- tomcat服务器把jsp文件翻译成java源文件->编译class->构造类对象->调用_jspService()方法
- 检查jsp文件的taglib指令,是否存在<uri>为指定名称的tld文件。如果没有,则报错
- 读到指定的.tld文件
- 读到<标签库简称:标签名> 到.tld文件中查询<tag>标签中是否存在<name>为标签名的标签
- 找到对应的<tag>标签,则读到<tag-class>内容
- 得到标签处理器类的全名:包名.类名
构造myTag对象,然后调用myTag里面的方法
自定义标签处理器类的生命周期:
SimpleTag接口: 调用顺序
void setJspContext(JspContext pc) --设置pageContext对象,传入pageContext,通过getJspCotext()方法得到pageContext对象。(一定会调用)
void setParent(JspTag parent) --设置父标签对象,传入父标签对象,通过getParent()方法得到父标签对象。如果没有父标签,则不调用此方法。
void setXXX(值) --设置属性值。
void setJspBody(JspFragment jspBody) --设置标签体内容。标签体内容封装到JspFragment对象 中,然后传入JspFragment对象。通过getJspBody()方法得到标签体内容。如果没有标签体内容,则不调用此方法
void doTag() --执行标签时调用的方法。(一定会调用)
自定义标签的作用:
- 控制标签体内容是否输出 invoke方法
//1.1 得到标签体内容 JspFragment jspBody = this.getJspBody(); //1.2 执行invoke方法输出(不执行则不输出): 把标签体内容输出到指定的Writer对象中,writer为null就是默认往浏览器输出 jspBody.invoke(null); /*等价于: JspWriter out = this.getJspContext().getOut(); jspBody.invoke(out); */
- 控制标签外余下内容是否输出 标签后余下内容默认自动输出,抛出skipPageExcepion异常则不输出
- 控制标签体内容重复输出 执行多次jspBody.invoke()方法
- 改变标签体内容
//4.1 创建StringWriter临时容器 StringWriter sw = new StringWriter(); //4.2 把标签体拷贝到临时容器 jspBody.invoke(sw); //4.3 从临时容器中得到标签体内容 String content = sw.toString(); //4.4 改变内容 content = content.toLowerCase(); //4.5 把改变的内容输出到浏览器。 不能使用jspBody.invoke(null)方式输出,因为jsbBody没有改变过 this.getJspContext().getOut().write(content);
- 标签的属性 在tld文件中描术标签的属性,标签处理器中添加每个属性对应的setter方法。就能在其中使用标签的属性值
//1.声明属性的成员变量 private Integer num; //2.关键点: 必须提供公开的setter方法,用于给属性赋值 public void setNum(Integer num) { this.num = num; }
==================================================================================