JSP知识点总结
程序员文章站
2022-08-09 21:52:24
JSP(Java Server Page)
JSP是服务器端运行的页面,JSP本就是一个文档,他不仅可以包含静态的HTML代码,也可以包含动态的JAVA代码,服务器容...
JSP(Java Server Page)
JSP是服务器端运行的页面,JSP本就是一个文档,他不仅可以包含静态的HTML代码,也可以包含动态的JAVA代码,服务器容器可以将JSP转换成Servlet发布,并接受请求。
Jsp文件只需放在应用文件下就可以了。
JSP例子:
<html>
<head><title>time</title></head>
<body>
<h1><%=new java.util.Date()%></h1>
</body>
</html>
JSP运行过程
1,JSP文件先要翻译成Java文件(Servlet),在tomcat中翻译后的java文件在tomcat下的work\Catalina\localhost中相应名字的应用目录里。
2,编译Java文件
3,运行.class文件
Tomcat的全局配置文件
在Tomcat下的conf目录中的web.xml是服务器全局的配置文件,其中要想关闭列表显示叫要把
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
Tomcat的管理员设置
在tomcat下的conf目录中的tomcat-use.xml文件中可以配置tomcat的用户角色
<tomcat-users>
<role rolename="manager" description=""/>
<role rolename="admin"/><!--设定角色的名字,admin是管理员,manager是项目管理-->
<user username="manager" password="123" roles="manager"/><!--设定用户名密码,和角色-->
<user username="admin" password="123" roles="admin"/>
</tomcat-users>
JSP的特点
1,JSP不需要编译
2,JSP不需要进行配置
3,JSP本质上就是一个Servlet
4,JSP是以静态页面为主的。
JSP的语法格式
<%=...%>表达式,写表达式时不要加上分号,表达式,翻译成Java代码也就是直接使用流输出,也就不能加分号了。
<%! int a=0; %>声明,使用声明的变量,所创建的变量是在service方法体外,也就是翻译成实例变量,声明也可以声明内部类或者是方法的声明。
<% if(a==0){ a=3;}%>代码片断,代码段会原样翻译。在代码段中声明的变量,就会被翻译的service的方法体中,也就是被翻译成局部变量。
前三种JSP的语法也叫做JSP代码,以上的表示方法,都有与之相对应的xml表达形式,因为可读性较差,所以较少使用。
<%@ ... %>JSP指令
<%@page import="...,..."%>引入包
<%include file="...."%>直接引入内容,这些内容会直接嵌入到页面中。
JSP的注释
<%--........--%>
JSP指令和JSP动作(标准的JSP标签)
JSP指令的语法
<%@... ....%>
<%@include file="...."%> 包含指令,包含指令会将要包含的文件代码原样输出到本页面(在翻译时把包含文件的内容引入并合并),不进行翻译,file属性制定要包含的文件的名字(注意要包含的文件的路径),这个指令可以实现页面的复用。
注意:<%@include file=" "%>要包含的JSP文件中不能定义重名的变量,如果不使用包含指令,那么JSP中的最小转换单元就是JSP文件,使用了包含指令就会将多个jsp的结果合并到一起。
<%@page ..%>页面指令
<%@page import="..."%> 引入包 例:<%@page import="java.util.*,ent.*"%>(可出现多次)
<%@page pageEncoding="GBK"%>设定页面显示的字符集
<%@page contentType="text/html;charset=GBK"%>设置输出流的编码方式和文件格式。
注意:输出的字符集编码方式要和页面显示的字符集相同,一般定义输出流的编码方式,注意以上两个页面指令在JSP中最好只出现一次。注意在请求中传送的参数的值是中文的话需要调用请求request的
setCharacterEncoding("..")方法设置相应的编码方式,只适用于post请求,也可以通过Servlet的Filter来进行中文编码方式的处理。
<%@page language="java"%>指定JSP的脚本语言,现在只能写java
<%@page extends=".."> 指定翻译后代码类型的父类,最好不要使用这个指令
<%@page session="true|false"%>指定是否自动创建Session,最好不自己指定,使用默认值
<%@page buffer=".." autoflush="true|false"%>设置输出的缓存和是否自动刷新缓存,一般情况下都使用默认值,缓存的默认值为8KB。
<%@page isThreadSafe="true|false"%>是否线程安全,默认为true,也就是线程安全,只使用默认值。
<%@page info=".."%>设置页面信息,一般不用
<%@page errorPage=""%>指定异常处理页面
<%@page isErrorPage="true|false"%>设定本页面就是异常后跳转的页面
<%@page isELIgnored="true|false"%>设定本页面是否忽略JSP2.0种EL表达式
<%@taglib ..%> 标签库指令,用于引入自定义标签库
JSP动作
<jsp:... ...>
<jsp:include page="..." flush=true|false> include动作是在翻译和编译后运行时进行响应的合并,也就是对应了Servlet中RequestDispatcher类的include(ServletRequest request, ServletResponse response)方法。
include动作可以传递参数
<jsp:include page="test.jsp">
<jsp:param name="user" value=" ">
</jsp:include>
在使用参数时,可以用request内置对象来获取参数的值。
<jsp:forward page="xxx/xxx.jsp">forward动作对应的是Servlet中RequestDispatcher类的forward(ServletRequest request, ServletResponse response)方法,也就是把请求进行转发。
也可以写成
<jsp:forward>
<jsp:attribute name="page">xxx/xxx.jsp</jsp:attribute>
</jsp:forward>
这种写法等价于上面的写法。
在使用Servlet的response的重定向sendRedirect(String location)方法在使用时要包含应用的路径,注意,重定向会放弃这个请求,并向服务器发送一个新的请求,但是响应对象还是一个。重定向是用来避免重复提交的。
注意:对页面的刷新操作就会再一次运行程序,也就仿佛进行了再一次的提交一样,这也就是重复提交的问题,所以需要使用重定向来解决这个问题。
<jsp:plugin type="bean|applet" code="...">
...
</jsp:plugin>
jsp:plugin动作可以使页面上运行applet,或者是使用java代码。
<jsp:useBean id="对象名" class="类全名"|type="类全名"(使用多态时使用)beanName="类全名" scope="page|request|session|application">
jsp:useBean动作,可以通过这个动作来使用java代码,id就是变量名,clss和type的区别在于,使用type是不会创建对象,而只是会先查找如果有该对象就会使用,如果没有就会抛出异常,class在没有该对象存在时,则会创建新对象。scope是用来保存实例的空间范围,page、request、session、application,由小到大,默认为page。
<jsp:setProperty name="对象名" property="属性名" value="属性值"/>
直接指定Bean属性的值,必须类型一致。
<jsp:setProperty name="对象名" property="属性名" param="from表单中的响应的参数名"/>
用表单中指定的参数来为Bean属性赋值,系统会自动作类型转换。
<jsp:setProperty name="对象名" property="属性名"/>
用表单中和Bean属性同名的标单项来给Bean属性赋值,这样写只会为指定的属性赋值
<jsp:setProperty name="对象名" property="*"/>
这种方式会自动用表单中的同名参数来为Bean的所有属性赋值
<jsp:setProperty name="对象名" property="属性名" value="<%= ...%>"/>
使用表达式来为Bean的属性进行赋值
<jsp:getProperty name="对象名" property="属性名">
取得指定的属性,这个动作不常用,一般用表达式代替
我们可以通过设置属性名的方法名也就是setXxxx()来控制属性的赋值,用form表单的参数为Bean的属性赋值时,系统会自动的调用与之同名属性的setXxxx()方法,尤其是日期类型,可以通过使用这一方法来处理。
例:
import java.sql.*;
public class Person{
private Srting name;
private Date birthday;
public void setName(String name){
this.name=name;
}
public void setBirthdayAsString(String birthday){
this.setBirthday(valueOf(birthday));
}
public void setBirthday(Date birthdays){
this.birthday=birthday;
}
}
add.jsp
<jsp:useBean id="person" type="Person" scope="request">
<jsp:setProper name="person" property="*"/>
</jsp:useBean>
toadd.jsp
<form action="xxx" methmod="post">
<input type="text" name="name">
<input type="text" name="birhtdayAsString">
<input type="submit" value="add.jsp">
</form>
JavaBean和EJB的区别
JavaBean是可视的或者是不可视的,不用部署,EJB是不可视的,需要部署到服务器中。
JavaBean部署在应用程序中,EJB是部署在容器中,可以是有状态或者是无状态的,声明式事务。
JavaBean的属性和方法是普通的,EJB是需要遵守规范,是需要通过标准的描述符来定义的。
JavaBean是基于事件驱动的,EJB中只有消息驱动Bean是基于事件的
注意:jsp:useBean动作,用表单为Bean的属性赋值时,也就是jsp:setProperty动作直接收请求中表单的信息为使用的Bean的属性进行赋值,也就是说jsp:useBean和jsp:setProperty不能够出现在为这个Bean的属性赋值的form表单的页面上。
JSP的异常处理
<%@page errorPage="xxx.jsp"%> 指定本页面出现异常后要转到的页面
<%@page iserrorPage="true"%> 见本页面指定为异常处理页面,也就是其他出异常的页面可以指定本页面为要转到的异常处理页面。
处理异常
运行时异常
1) 一个程序运行时重获的错误;
2) 能被一固有的异常对象引用所使用;
3) 可以利用异常引用创建或产生一个JSP页面显示异常信息给用户。
创建一个异常跟踪方案
1) 在每一个JSP页面,包含要创建的异常页面名称;
<%@page import="numberguess.NumberGuessBean" errorPage="error.jsp"%>
2) 创建一个异常页面;
<%@page isErrorPage="true"%>
JSP页面中的异常处理
1) <%=exception.toString()%> 打印异常名称;
2) <%exception.printStackTrace();%> 打印当前错误流中所有错误的列表;
3) <%=exception.getMessage()%> 打印错误的详细描述信息
JSP中异常页面的部署描述
<error-page>
<error-code>404</error-code>
<location>notFound.html</location>
</error-page>
<error-page>
<exception-type>java.lang.NumberFormatException</exception-page>
<location>error.jsp</location>
</error-page>
JSP隐含内置对象
JSP中隐含内置对象
名称 类型 注释和范围
request javax.servlet.http.HttpServletRequest request
response javax.servlet.http.HttpServletResponse response
page javax.lang.Object page
Exception java.lang.Throwable page
pageContext javax.servlet.jsp.PageContext page
session javax.servlet.http.HttpSession session
application javax.servlet.ServletContext ServletContext
out javax.servlet.jsp.JspWriter OutputStream
config javax.servlet.ServletConfig ServletConfig
内置对象request(HttpServletRequest)
1)封装了来自客户端的请求:
2)方法:
Parameter related methods:
+getParameterNames():Enumberation 返回form中对象名称的枚举;
+getParameter(String name):String返回指定名称的对象值;
+getParameterValues(String name) :String[ ] 返回指定名称的对象值数组;
+getParameterMap():Map
Attribute related methods:
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
URL related methods:
+getContextPath():String
+getServletPath():String
+getPathInfo():String
State related methods:
+getCookies():Cooie[ ] 取得Cookie数组;
+getSession():HttpSession
+getSession(Boolean create) :HttpSession
内置对象response(HttpServletResponse)
+getWriter():PrintWriter
+addCookie(Cookie c) :void
+encodeURL(String URL) :String
+sendRedirect(String URL) :void
+sendError(int errorCode) :void
内置对象session(HttpSession)
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
Other motheds:
+seMaxInactiveInterval(int seconds) :void
Invalidate():void
内置对象pageContext(PageContext)
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
+findAttribute(String name) :Object
Other motheds:
+getRequest():HttpServletRequest
+getSession():HttpSession
+getServletContext():ServletContext
+getOut():JspWriter
内置对象application(ServletContext)
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
Other methods:
+getRequstDispather(String URL):RequestDispather
+getInitParameter(String name) :String
内置对象out
1)JSPWriter的一个实例, 用于发送响应给客户端
2)方法:
print(String)/println(String) 用于向页面输出
print(int)/println(int)
flush() 刷新out对象的缓存
内置对象exception
1) 用于异常对象的异常实例;
2) 异常页面在page指令中存在属性isErrorPage="true";
3) 方法:
getMessage()/printStackTrace()/toString()
内置对象session
1) HttpSession的一个实例, 用于来维护session的状态
2) 方法:
getAttribute(String name)/setAttribute(String name)
取得设置的属性的对应资源/设置属性的对应资源
removeAttribute(String name) 删除属性和队应资源
getAttributeNames()
返回值是一个迭代器,可以获得session中设置的属性的名字也就是在set时使用的与资源对应的那个名字
内置对象application
1) ServletContext一个实例,用来维护application的状态
2) 方法:
getAttribute()/setAttribute() 和session以及request中的那一对设置属性及其对应资源的方法
getInitParameter() 获得初始化参数
getServletInfo() 获得Servlet的信息
3) application的作用域比session大得多,一个session和一个client联系, 而application保持了用于所有客户端的状态。
注意:如果要保存的数据量比较大时,就要使用生命周期比较短的request对象,page对象只在本页面中有效,也就是会再翻译后的service方法体内的一个局部变量,service运行结束后就会销毁,不像request可以转发。session和application的生命周期都比较长而且作用域比较大。
JSP自定义标签(tag)
什么是自定义标签?
1,用户自定义的Java语言元素, 实质是运行一个或者两个接口的JavaBean;
2,可以非常紧密地和JSP的表示逻辑联系在一起,又具有和普通JavaBean相同的业务逻辑处理能力;
3,当一个JSP页面转变为servlet时,其间的用户自定义标签转化为操作一个称为标签hander的对象;
4,可操作默认对象,处理表单数据,访问数据库以及其它企业服务;
自定义标签库的特点
1,通过调用页面传递参数实现定制;
2,访问所有对JSP页面可能的对象;
3,修改调用页面生成的响应;
4,自定义标签间可相互通信;
5,在同一个JSP页面中通过标签嵌套,可实现复杂交互。
如何使用自定义标签库
1,声明标签库
2,使标签库执行对Web应用程序可用
声明标签库
1,使用taglib指令声明标签库
2,语法:<%@taglib uri="URI" prefix="pre" %>
注意:a. uri属性可以是绝对的,也可以是相对URL,该URL指向标记库描述符(TLD)文件;
b. uri属性也可以是一个并不存在的URL,该URL为web.xml文件中将标记库描述符(TLD)文件的绝对
URL到本地系统的一个映射;
3,范例:<%@taglib uri="/WEB-INF/template.tld" prefix="test" %>
<%@taglib uri="https://java.sun.com/jstl/core" prefix="core" %>
使标签库执行可用
方式一:在WEB-INF/classes目录下部署标记处理程序类;
方式二:将标记处理程序类打包成jar文件并置于WEB-INF/lib目录。
几种典型的标签
1,不带属性和主体的简单标签:<mytaglibs:SomeTag/>;
2,不带主体但有属性的标签:<mytaglibs:SomeTag user="TonyDeng"/>;
3,带有主体和属性的标签:
<mytaglibs:SomeTag user="TonyDeng">
...// 标签体
</mytaglibs:SomeTag>;
注意:a. 属性列于start tag中,它是在标记库描述符(TLD)文件中指定,服务于标记库的自定义行为;
b. 标签体位于start tag和end tag间,可以是任何合法的JSP内容或者标签;
定义标签
1,开发实现tag的类(tag handler);
2,编辑标记库描述符(TLD)文件;
3,在web.xml中为标记库描述符(TLD)文件的绝对URL建立一个映射(该步骤可选);
标记库描述符(TLD)文件
1,一个描述标记库的XML文件;
2,内容开始是整个库的描述,然后是tag的描述;
3,标记库描述符(TLD)文件用于Web Container确认tag以及JSP页面发展工具;
实现tag的类(标签处理器)(tag handler)
1,是一些在引用了标签的JSP页面执行期间被Web Container调用以求自定义标签值的对象;
2,必须实现Tag, SimpleTag和BodyTag之一;
3,可以继承TagSupport和BodyTagSupport之一。
标签库的接口和类的继承关系接口的继承关系:
☉interface javax.servlet.jsp.tagext.JspTag
☉interface javax.servlet.jsp.tagext.SimpleTag
☉interface javax.servlet.jsp.tagext.Tag
☉interface javax.servlet.jsp.tagext.IterationTag
☉interface javax.servlet.jsp.tagext.BodyTag
类的继承关系:
☉class javax.servlet.jsp.tagext.TagSupport
(implements javax.servlet.jsp.tagext.IterationTag, java.io.Serializable)
☉class javax.servlet.jsp.tagext.BodyTagSupport
(implements javax.servlet.jsp.tagext.BodyTag)
☉class javax.servlet.jsp.tagext.SimpleTagSupport
(implements javax.servlet.jsp.tagext.SimpleTag)
(Interface)
JspTag
|
|ˉˉˉˉˉˉˉˉ|
(Interface) (Interface)JSP2.0
Tag SimpleTag ←--SimpleTagSupport
|
|
(Interface)
IterationTag←--TagSupport
支持迭代的标签 |
| |
| |
(Interface) |
BodyTag ←---BodyTagSupport
可以处理标签体
自定义标签的开发步骤
1,写标签处理器,也就是一个符合自定义标签规范的类xxx.java
2,写标签库定义文件,也就是定义标签的格式规范,也要符合自定义标签的规范xxx.tld
3,建上述两步中的相应文件进行部署。web.xml
tld文件中的配置
<tag>
<name>loop</name>
<tag-class>com.tag.LoopTag</tag-class>
<body-content>jsp</body-content>
<!--设定自定义标签体内的内容,可以置为empty,也就是只能写空标签-->
<attribute>
<name>counter</name><!--配置自定义标签的属性名-->
<required>true</required><!--配置属性是否必须出现-->
<rtexprvalue>true</rtexprvalue><!--允许使用表达式作为属性的值-->
<type>int<type><!--配置属性的类型-->
</attribute>
</tag>
简单的标签处理程序类
1,必须实现Tag接口的doStartTag()和doEndTag()方法;
2,因为不存在Body,doStartTag()方法必须返回SKIP_BODY;
3,如其余页面要执行,doEndTag()方法返回EVAL_PAGE, 否则返回SKIP_PAGE;
4,对于每一个标签属性,你必须在标签处理程序类里定义一个特性以及get和set方法以一致于JavaBeans 体系惯例
带Body的自定义标签
1,必须实现Tag接口的doStartTag()和doEndTag()方法;
2,可以实现IterationTag接口的doAfterBody()方法;
3,可以实现BodyTag接口的doInitBody和setBodyContent方法;
4,doStartTag方法可以返回SKIP_BODY、EVAL_BODY_INCLUDE、或者EVAL_BODY_BUFFERED(当你想使用 BodyContent);
5,doEndTag方法可以返回SKIP_PAGE或EVAL_PAGE;
6,doAfterBody方法可以返回EVAL_BODY_AGAIN, SKIP_BODY;
定义脚本变量的标签(迭代标签)
1,定义脚本标签的二个步骤:
. 在标记库描述符(TLD)文件中列明脚本变量;
. 定义标签扩展信息类(TEI)并且在TLD文件中包括这个类元素(tei-class);
2,变量必须在标签处理程序类中使用pageContext.setAttribute()方法设置;
3,标签扩展信息类(TEI)必须继承TagExtraInfo以及覆盖getVariableInfo()方法;
4,变量的范围可以是AT_BEGIN, NESTED, AT_END(标签扩展信息类(TEI)的VariableInfo中定义)之一;
脚本变量的有效性
变量 | 有效性
---------------------------------------
NESTED | 标签中的参数在starttag到endtag之间是有效的
AT_BEGIN | 标签中的参数在标签的开始到JSP页面结束是有效的
AT_END | 标签中的参数在标签的结束到JSP页面结束是有效的
Tag接口的方法
interface javax.servlet.jsp.tagext.Tag
------------------------------------------------------
+EVAL_BODY_INCLUDE:int
+EVAL_PAGE:int//继续执行页面
+SKIP_BODY:int//跳出标签体
+SKIP_PAGE:int//跳出页面,也就是整个JSP不会再运行
------------------------------------------------------
+release():void
+getParent():javax.servlet.jsp.tagext.Tag
+setParent(javax.servlet.jsp.tagext.Tag):void
+doEndTag():int
+doStartTag():int
+setPageContext(javax.servlet.jsp.PageContext):void
Tag的生命周期
1,setPageContext(javax.servlet.jsp.PageContext):void
2,setParent(javax.servlet.jsp.tagext.Tag):void
3,setAttribute:void
4,doStartTag():int
5,doEndTag():int
6,release():void
BodyTag和Tag接口的关系
interface javax.servlet.jsp.tagext.BodyTag-->interface javax.servlet.jsp.tagext.Tag
------------------------------------------
+EVAL_BODY_AGAIN:int//继续执行标签体
-----------------------------------------
+doInitBody():void
+setBodyContent(javax.servlet.jsp.tagext.BodyContext):void
+doAfterBody():int
BodyTag的处理过程
1,setPageContext(javax.servlet.jsp.PageContext):void
2,setParent(javax.servlet.jsp.tagext.Tag):void //设置此标签的父标签,也就是上一层标签
3,setParent()
4,doStartTag():int
5,setBodyContent(javax.servlet.jsp.tagext.BodyContent):void//设置方法体
6,doInitBody():void//
7,doAfterBody():int
/* 这个方法会被不断的调用直到不再满足条件,通过这个方法来控制返回,从而控制循环是否中断
SKIP_BODY是跳出标签体的,EVAL_BODY_INCLUDE是继续执行标签体,通过返回这两个值来控制循环是否*/
8,doEndTag():int
9,release():void
SimpleTag接口的方法
javax.servlet.jsp.tagext.SimpleTag
------------------------------------------
+doTag():void
+getParent():JspTag
+setJspBody(JspFragment jspBody):void
+setJspContext(JspContext pc):void
+setParent(JspTag parent):void
SimpleTage接口的生命周期(JSP2.0的自定义标签接口)
1,new:
每次遇到标签,容器构造一个SimpleTag的实例,这个构造方法没有参数。和红典的标签一样, SimpleTag不能缓冲,故不能重用,每次都需要构造新的实例。
2,setJspContext()、setParent(): 只有这个标签在另一个标签之,才调用setParent()方法;
3,设置属性:调用每个属性的setter方法;
4,setJspBody();
5,doTag(): 所有标签的逻辑、迭代和Body计算,都在这个方法中;
6,return
例:
package com.tag;
public class HelloTag implements Tag
{
private PageContext pageContext;
private Tag parent;
public HelloTag(){
super();
}
/**
*设置标签的页面的上下文
*/
public void setPageContext(final PageContext pageContext) {
this.pageContext=pageContext;
}
/**
*设置上一级标签 www.2cto.com
*/
public void setParent(final Tag parent) {
this.parent=parent;
}
/**
*开始标签时的操作
*/
public int doStartTag() throws JspTagException{
return SKIP_BODY; //返回SKIP_BODY,表示不计算标签体
}
/**
*结束标签时的操作
*/
public int doEndTag() throws JspTagException{
try{
pageContext.getOut().write("Hello World!你好,世界!");
}
catch(java.io.IOException e){
throw new JspTagException("IO Error: " + e.getMessage());
}
return EVAL_PAGE;
}
/**
*release用于释放标签程序占用的资源,比如使用了数据库,那么应该关闭这个连接。
*/
public void release() {}
public Tag getParent(){
return parent;
}
}
xxx.tld
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="https://java.sun.com/xml/ns/j2ee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
version="2.0">
<tag>
<description>Extends TagSupport</description>
<name>hello</name>
<tag-class>com.tag.HelloWorldTag</tag-class>
<body-content>jsp</body-content>
</tag>
</taglib>
web.xml
<web-app>
<taglib-uri>/xxx</taglib-uri>
<taglib-location>/WEB-INF/tlds/xxx.tld</taglib-location>
</web-app>
xxx.jsp
<%@ taglib uri="/xxx" prefix="mytag" %>
<%@ page contentType="text/html; charset=gb2312" %>
<html><head><title>first cumstomed tag</title></head><body>
<p>以下的内容从Taglib中显示:</p>
<p><i><mytag:hello_int/></i>
<br>
<p><mytag:hello_int></mytag:hello_int>
</body></html>
JSP2.0中的表达式语言(EL表达式)
EL语法
EL的语法很简单,他最大的特点就是使用上很方便
例:
${sessionScope.user.sex}
所有EL都是以${ 为起始、以} 为结尾的。
上述EL范例的意思是:从Session取得用户的性别。如果使用之前JSP代码的写法如下:
<%
User user = (User)session.getAttribute("user");
String sex = user.getSex( );
%>
两者相比较之下,可以发现EL的语法比传统JSP代码更为方便、简洁。
EL提供. 和[ ] 两种运算符来存取数据,[ ]可以访问集合或者是数组的元素、Bean的属性。下列两者所代表的意思是一样的,但是需要保证要取得对象的那个的属性有相应的setXxx()和getXxx()方法才行。
例:
${sessionScope.user.sex}
等于
${sessionScope.user["sex"]}
. 和[ ] 也可以同时混合使用,如下:
${sessionScope.shoppingCart[0].price}
返回结果为shoppingCart中第一项物品的价格。
在EL中,字符串既可以使用"abc",可以使用'abc'。
EL运算符
EL的算术运算符和Java中的运算符的大致相同,优先级也相同。
注意:'+' 运算符不会连接字符串了,他只用于加法运算。
EL关系运算符有以下六个运算符
关系运算符 说 明 范 例 结果
= = 或eq | 等于 |${ 5 = = 5 } 或${ 5 eq 5 } | true
!= 或ne | 不等于 |${ 5 != 5 } 或${ 5 ne 5 } | false
< 或lt | 小于 |${ 3 < 5 }或${ 3 lt 5 } | true
> 或gt | 大于 |${ 3 > 5 }或${ 3 gt 5 } | false
<= 或le | 小于等于|${ 3 <= 5 }或${ 3 le 5 } | true
>= 或ge | 大于等于|${ 3 >= 5 }或${ 3 ge 5 } | false
empty运算符
Empty运算符主要用来判断值是否为null或空的,例如:
${ empty param.name }
接下来说明Empty运算符的规则:
{empty} A
如果A为null时,返回true
如果A不存在时,返回true
如果A为空字符串时,返回true
如果A为空数组时,返回true
如果A为空的Map时,返回true
如果A为空的Collection时,返回true
否则,返回false
注意:
在使用EL关系运算符时,不能够写成:
${param.password1} = = ${param.password2}
或者
${ ${param.password1 } = = ${ param.password2 } }
而应写成
${ param.password1 = = param.password2 }
使用EL从表单中取得数据
与输入有关的隐含对象有两个:param和paramValues,它们是EL中比较特别的隐含对象。一般而言,我们在取得用户的请求参数时,可以利用下列方法:
request.getParameter(String name)
request.getParameterValues(String name)
在EL中则可以使用param和paramValues两者来取得数据。
${param.name}
${paramValues.name}可以取得所有同名参数的值
${paramValues.hobbies[0]}可以通过指定下标来访问特定的参数的值
这里param的功能和request.getParameter(String name)相同,而paramValues和request.getParameterValues(String name)相同。如果用户填了一个form,form名称有为username的文本框,则我们就可以使用${param.username}来取得用户填入文本框的值。
EL函数
EL中使用函数要写一个要使用到方法的类,然后在配置xxx.tld文件,然后在JSP中使用时和JSP的自定义标签相似。
xxx.tld中的配置
<function>
<name>reverse</name><!--函数名-->
<function-class>jsp2.examples.el.Functions</function-class><!--函数所在的类-->
<function-signature>java.lang.String reverse( java.lang.String )</function-signature>
<!--函数原型,也就是函数的返回值类型,函数名,参数表,注意一定要写类型的全名-->
</function>
使用EL函数的写法
${sn:upper('abc')}
注意:在定义EL函数时,都必须为公开静态(public static)
EL的隐含对象
EL也可以使用内置对象中设置的属性,需要使用特定的EL内置对象
属性范围 | 在EL中的对象
Page | pageScope
Request | requestScope
Session | sessionScope
Application | applicationScope
EL中使用内置对象的属性
${requestScope.user}
等价于
<%request.getAttribute("user")%>
如果不写出特定的范围 ,那就会在不同的范围间进行搜索了
例:{user}(user是在request范围request.setAttribute("user",user))
也就等于
${requestScope.user}
<%request.getAttribute("user")%>
EL的隐含对象
对象 类 型 说 明
PageContext | javax.servlet.ServletContext |表示此JSP的PageContext
-----------------------------------------------------------------------------------
PageScope | java.util.Map |取得Page范围的属性名称所对应的值
-------------------------------------------------------------------------------------
RequestScope | java.util.Map |取得Request范围的属性名称所对应的值
-------------------------------------------------------------------------------------
sessionScope | java.util.Map |取得Session范围的属性名称所对应的值
-------------------------------------------------------------------------------------
applicationScope | java.util.Map |取得Application范围的属称所对应的值
-------------------------------------------------------------------------------------
param | java.util.Map |如同ServletRequest.getParameter(String | |name)返回String类型的值
----------------------------------------------------------------------------------------
paramValues | java.util.Map |如同ServletRequest.getParameterValues | |(String name)。返回String []类型的值
-----------------------------------------------------------------------------------------
header | java.util.Map |如同ServletRequest.getHeader(String name) | |返回String类型的值
------------------------------------------------------------------------------------------
headerValues | java.util.Map |如同ServletRequest.getHeaders(String name) | |。返回String []类型的值
------------------------------------------------------------------------------------------
cookie | java.util.Map |如同HttpServletRequest.getCookies( )
------------------------------------------------------------------------------------------
initParam | java.util.Map |如同ServletContext.getInitParameter(String | |name)。返回String类型的值
-------------------------------------------------------------------------------------------
cookie对象
所谓的cookie是一个小小的文本文件,它是以key、value的方式将Session Tracking的内容记录在这个文本文件内,这个文本文件通常存在于浏览器的暂存区内。JSTL并没有提供设定cookie的动作,因为这个动作通常都是后端开发者必须去做的事情,而不是交给前端的开发者。如果我们在cookie中设定一个名称为userCountry的值,那么可以使用${cookie.userCountry}来取得它。
header和headerValues(请求报头对象)
header储存用户浏览器和服务端用来沟通的数据,当用户要求服务端的网页时,会送出一个记载要求信息的标头文件,例如:用户浏览器的版本、用户计算机所设定的区域等其他相关数据。如果要取得用户浏览器的版本,即${header["User-Agent"]}。另外在很少机会下,有可能同一标头名称拥有不同的值,此时必须改为使用headerValues来取得这些值。
注意:因为User-Agent中包含“-”这个特殊字符,所以必须使用“[]”,而不能写成${header.User-Agent}。
initParam
就像其他属性一样,我们可以自行设定web应用的环境参数(Context),当我们想取得这些参数时,可以使用initParam隐含对象去取得它,例如:当我们在web.xml中设定如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="https://java.sun.com/xml/ns/j2ee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<context-param>
<param-name>userid</param-name>
<param-value>mike</param-value>
</context-param>
</web-app>
那么我们就可以直接使用${initParam.userid}来取得名称为userid,其值为mike的参数。下面是之前的做法:String userid = (String)application.getInitParameter("userid");
pageContext对象
我们可以使用${pageContext}来取得其他有关用户要求或页面的详细信息。下面列出了几个比较常用的部分。
Expression 说 明
${pageContext.request} |取得请求对象
${pageContext.session} |取得session对象
${pageContext.request.queryString} |取得请求的参数字符串
${pageContext.request.requestURL} |取得请求的URL,但不包括请求之参数字符串
${pageContext.request.contextPath} |服务的web application的名称
${pageContext.request.method} |取得HTTP的方法(GET、POST)
${pageContext.request.protocol} |取得使用的协议(HTTP/1.1、HTTP/1.0)
${pageContext.request.remoteUser} |取得用户名称
${pageContext.request.remoteAddr } |取得用户的IP地址
${pageContext.session.new} |判断session是否为新的,所谓新的session,表示刚由 server产生而client尚未使用
${pageContext.session.id} |取得session的ID
${pageContext.servletContext.serverInfo}|取得主机端的服务信息
JSTL(JSP标准标签库)
JSTL由核心标签,<c:... > ,xml解析标签<x:...>,国际化标签<fmt:....>,数据库访问标签<sql:...>,函数标签<fn:...>
核心标签
Core
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
属性设置
<c:set> 设置属性
<c:remove> 移除设置的属性
过程控制
<c:if test="..."> 条件标签 只有在test属性的值为true是才会执行标签体
例:
<c:if test="${!(empty user.age)}">
<h1>hello</h1>
</c:if>
<c:choose>choose和when是组合在一起使用的,有点类似于swith case的语法 。
<c:when test="...">when也是条件判断标签,test属性的值为true是才会执行标签体。
例:
<c:choose>
<c:when test="${param.age<18}">
<h1>you is a child<h1>
</c:when>
<c:when test="${param.age>18 and param.age<50 }">
<h1>you is a young person</h1>
</c:when>
<c:when test="${param.age>50}">
<h1>you is a old person</h1>
</c:when>
</c:choose>
<c:forEach>迭代标签
例:
<c:forEach var="book" item="${store.books}" varStatus="status">
<h1>${book.parice}</h1>
</c:forEach>
<c:forEach begin="1" end="5" step="1">
<h1>hello</h1>
</c:forEach>
<c:forTokens>字符串迭代标签
<c:import>引入标签
<c:import url="引入内容的url" var="别名">
${别名}
<c:url>url标签
<c:url value="...">
<c:param name="..." value="..."/>
</c:url>
<c:url value="...">
使用url标签可以实现URL回写
<c:redirect uri="xxx/xxx/xxx.xx"/>
国际化标签
<fmt:lauguage>
<fmt:bundel>资源指定标签
<fmt:message>消息标签
例:
<fmt:setLocale value="zh"/>
<fmt:bundel basename="message.MessageResources">
<fmt:message>name</fmt:message>
</fmt:bundel>
xxxx.properties
name=\0060\0700\
摘自HarderXin的专栏
JSP是服务器端运行的页面,JSP本就是一个文档,他不仅可以包含静态的HTML代码,也可以包含动态的JAVA代码,服务器容器可以将JSP转换成Servlet发布,并接受请求。
Jsp文件只需放在应用文件下就可以了。
JSP例子:
<html>
<head><title>time</title></head>
<body>
<h1><%=new java.util.Date()%></h1>
</body>
</html>
JSP运行过程
1,JSP文件先要翻译成Java文件(Servlet),在tomcat中翻译后的java文件在tomcat下的work\Catalina\localhost中相应名字的应用目录里。
2,编译Java文件
3,运行.class文件
Tomcat的全局配置文件
在Tomcat下的conf目录中的web.xml是服务器全局的配置文件,其中要想关闭列表显示叫要把
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
Tomcat的管理员设置
在tomcat下的conf目录中的tomcat-use.xml文件中可以配置tomcat的用户角色
<tomcat-users>
<role rolename="manager" description=""/>
<role rolename="admin"/><!--设定角色的名字,admin是管理员,manager是项目管理-->
<user username="manager" password="123" roles="manager"/><!--设定用户名密码,和角色-->
<user username="admin" password="123" roles="admin"/>
</tomcat-users>
JSP的特点
1,JSP不需要编译
2,JSP不需要进行配置
3,JSP本质上就是一个Servlet
4,JSP是以静态页面为主的。
JSP的语法格式
<%=...%>表达式,写表达式时不要加上分号,表达式,翻译成Java代码也就是直接使用流输出,也就不能加分号了。
<%! int a=0; %>声明,使用声明的变量,所创建的变量是在service方法体外,也就是翻译成实例变量,声明也可以声明内部类或者是方法的声明。
<% if(a==0){ a=3;}%>代码片断,代码段会原样翻译。在代码段中声明的变量,就会被翻译的service的方法体中,也就是被翻译成局部变量。
前三种JSP的语法也叫做JSP代码,以上的表示方法,都有与之相对应的xml表达形式,因为可读性较差,所以较少使用。
<%@ ... %>JSP指令
<%@page import="...,..."%>引入包
<%include file="...."%>直接引入内容,这些内容会直接嵌入到页面中。
JSP的注释
<%--........--%>
JSP指令和JSP动作(标准的JSP标签)
JSP指令的语法
<%@... ....%>
<%@include file="...."%> 包含指令,包含指令会将要包含的文件代码原样输出到本页面(在翻译时把包含文件的内容引入并合并),不进行翻译,file属性制定要包含的文件的名字(注意要包含的文件的路径),这个指令可以实现页面的复用。
注意:<%@include file=" "%>要包含的JSP文件中不能定义重名的变量,如果不使用包含指令,那么JSP中的最小转换单元就是JSP文件,使用了包含指令就会将多个jsp的结果合并到一起。
<%@page ..%>页面指令
<%@page import="..."%> 引入包 例:<%@page import="java.util.*,ent.*"%>(可出现多次)
<%@page pageEncoding="GBK"%>设定页面显示的字符集
<%@page contentType="text/html;charset=GBK"%>设置输出流的编码方式和文件格式。
注意:输出的字符集编码方式要和页面显示的字符集相同,一般定义输出流的编码方式,注意以上两个页面指令在JSP中最好只出现一次。注意在请求中传送的参数的值是中文的话需要调用请求request的
setCharacterEncoding("..")方法设置相应的编码方式,只适用于post请求,也可以通过Servlet的Filter来进行中文编码方式的处理。
<%@page language="java"%>指定JSP的脚本语言,现在只能写java
<%@page extends=".."> 指定翻译后代码类型的父类,最好不要使用这个指令
<%@page session="true|false"%>指定是否自动创建Session,最好不自己指定,使用默认值
<%@page buffer=".." autoflush="true|false"%>设置输出的缓存和是否自动刷新缓存,一般情况下都使用默认值,缓存的默认值为8KB。
<%@page isThreadSafe="true|false"%>是否线程安全,默认为true,也就是线程安全,只使用默认值。
<%@page info=".."%>设置页面信息,一般不用
<%@page errorPage=""%>指定异常处理页面
<%@page isErrorPage="true|false"%>设定本页面就是异常后跳转的页面
<%@page isELIgnored="true|false"%>设定本页面是否忽略JSP2.0种EL表达式
<%@taglib ..%> 标签库指令,用于引入自定义标签库
JSP动作
<jsp:... ...>
<jsp:include page="..." flush=true|false> include动作是在翻译和编译后运行时进行响应的合并,也就是对应了Servlet中RequestDispatcher类的include(ServletRequest request, ServletResponse response)方法。
include动作可以传递参数
<jsp:include page="test.jsp">
<jsp:param name="user" value=" ">
</jsp:include>
在使用参数时,可以用request内置对象来获取参数的值。
<jsp:forward page="xxx/xxx.jsp">forward动作对应的是Servlet中RequestDispatcher类的forward(ServletRequest request, ServletResponse response)方法,也就是把请求进行转发。
也可以写成
<jsp:forward>
<jsp:attribute name="page">xxx/xxx.jsp</jsp:attribute>
</jsp:forward>
这种写法等价于上面的写法。
在使用Servlet的response的重定向sendRedirect(String location)方法在使用时要包含应用的路径,注意,重定向会放弃这个请求,并向服务器发送一个新的请求,但是响应对象还是一个。重定向是用来避免重复提交的。
注意:对页面的刷新操作就会再一次运行程序,也就仿佛进行了再一次的提交一样,这也就是重复提交的问题,所以需要使用重定向来解决这个问题。
<jsp:plugin type="bean|applet" code="...">
...
</jsp:plugin>
jsp:plugin动作可以使页面上运行applet,或者是使用java代码。
<jsp:useBean id="对象名" class="类全名"|type="类全名"(使用多态时使用)beanName="类全名" scope="page|request|session|application">
jsp:useBean动作,可以通过这个动作来使用java代码,id就是变量名,clss和type的区别在于,使用type是不会创建对象,而只是会先查找如果有该对象就会使用,如果没有就会抛出异常,class在没有该对象存在时,则会创建新对象。scope是用来保存实例的空间范围,page、request、session、application,由小到大,默认为page。
<jsp:setProperty name="对象名" property="属性名" value="属性值"/>
直接指定Bean属性的值,必须类型一致。
<jsp:setProperty name="对象名" property="属性名" param="from表单中的响应的参数名"/>
用表单中指定的参数来为Bean属性赋值,系统会自动作类型转换。
<jsp:setProperty name="对象名" property="属性名"/>
用表单中和Bean属性同名的标单项来给Bean属性赋值,这样写只会为指定的属性赋值
<jsp:setProperty name="对象名" property="*"/>
这种方式会自动用表单中的同名参数来为Bean的所有属性赋值
<jsp:setProperty name="对象名" property="属性名" value="<%= ...%>"/>
使用表达式来为Bean的属性进行赋值
<jsp:getProperty name="对象名" property="属性名">
取得指定的属性,这个动作不常用,一般用表达式代替
我们可以通过设置属性名的方法名也就是setXxxx()来控制属性的赋值,用form表单的参数为Bean的属性赋值时,系统会自动的调用与之同名属性的setXxxx()方法,尤其是日期类型,可以通过使用这一方法来处理。
例:
import java.sql.*;
public class Person{
private Srting name;
private Date birthday;
public void setName(String name){
this.name=name;
}
public void setBirthdayAsString(String birthday){
this.setBirthday(valueOf(birthday));
}
public void setBirthday(Date birthdays){
this.birthday=birthday;
}
}
add.jsp
<jsp:useBean id="person" type="Person" scope="request">
<jsp:setProper name="person" property="*"/>
</jsp:useBean>
toadd.jsp
<form action="xxx" methmod="post">
<input type="text" name="name">
<input type="text" name="birhtdayAsString">
<input type="submit" value="add.jsp">
</form>
JavaBean和EJB的区别
JavaBean是可视的或者是不可视的,不用部署,EJB是不可视的,需要部署到服务器中。
JavaBean部署在应用程序中,EJB是部署在容器中,可以是有状态或者是无状态的,声明式事务。
JavaBean的属性和方法是普通的,EJB是需要遵守规范,是需要通过标准的描述符来定义的。
JavaBean是基于事件驱动的,EJB中只有消息驱动Bean是基于事件的
注意:jsp:useBean动作,用表单为Bean的属性赋值时,也就是jsp:setProperty动作直接收请求中表单的信息为使用的Bean的属性进行赋值,也就是说jsp:useBean和jsp:setProperty不能够出现在为这个Bean的属性赋值的form表单的页面上。
JSP的异常处理
<%@page errorPage="xxx.jsp"%> 指定本页面出现异常后要转到的页面
<%@page iserrorPage="true"%> 见本页面指定为异常处理页面,也就是其他出异常的页面可以指定本页面为要转到的异常处理页面。
处理异常
运行时异常
1) 一个程序运行时重获的错误;
2) 能被一固有的异常对象引用所使用;
3) 可以利用异常引用创建或产生一个JSP页面显示异常信息给用户。
创建一个异常跟踪方案
1) 在每一个JSP页面,包含要创建的异常页面名称;
<%@page import="numberguess.NumberGuessBean" errorPage="error.jsp"%>
2) 创建一个异常页面;
<%@page isErrorPage="true"%>
JSP页面中的异常处理
1) <%=exception.toString()%> 打印异常名称;
2) <%exception.printStackTrace();%> 打印当前错误流中所有错误的列表;
3) <%=exception.getMessage()%> 打印错误的详细描述信息
JSP中异常页面的部署描述
<error-page>
<error-code>404</error-code>
<location>notFound.html</location>
</error-page>
<error-page>
<exception-type>java.lang.NumberFormatException</exception-page>
<location>error.jsp</location>
</error-page>
JSP隐含内置对象
JSP中隐含内置对象
名称 类型 注释和范围
request javax.servlet.http.HttpServletRequest request
response javax.servlet.http.HttpServletResponse response
page javax.lang.Object page
Exception java.lang.Throwable page
pageContext javax.servlet.jsp.PageContext page
session javax.servlet.http.HttpSession session
application javax.servlet.ServletContext ServletContext
out javax.servlet.jsp.JspWriter OutputStream
config javax.servlet.ServletConfig ServletConfig
内置对象request(HttpServletRequest)
1)封装了来自客户端的请求:
2)方法:
Parameter related methods:
+getParameterNames():Enumberation 返回form中对象名称的枚举;
+getParameter(String name):String返回指定名称的对象值;
+getParameterValues(String name) :String[ ] 返回指定名称的对象值数组;
+getParameterMap():Map
Attribute related methods:
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
URL related methods:
+getContextPath():String
+getServletPath():String
+getPathInfo():String
State related methods:
+getCookies():Cooie[ ] 取得Cookie数组;
+getSession():HttpSession
+getSession(Boolean create) :HttpSession
内置对象response(HttpServletResponse)
+getWriter():PrintWriter
+addCookie(Cookie c) :void
+encodeURL(String URL) :String
+sendRedirect(String URL) :void
+sendError(int errorCode) :void
内置对象session(HttpSession)
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
Other motheds:
+seMaxInactiveInterval(int seconds) :void
Invalidate():void
内置对象pageContext(PageContext)
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
+findAttribute(String name) :Object
Other motheds:
+getRequest():HttpServletRequest
+getSession():HttpSession
+getServletContext():ServletContext
+getOut():JspWriter
内置对象application(ServletContext)
+setAttribute(String name,Object value) :void 设置属性
+getAttribute(String name) :Oject 返回属性值;
+removeAttribute(String name) :void
+getAttributeNames():Enumberation 返回属性名称
Other methods:
+getRequstDispather(String URL):RequestDispather
+getInitParameter(String name) :String
内置对象out
1)JSPWriter的一个实例, 用于发送响应给客户端
2)方法:
print(String)/println(String) 用于向页面输出
print(int)/println(int)
flush() 刷新out对象的缓存
内置对象exception
1) 用于异常对象的异常实例;
2) 异常页面在page指令中存在属性isErrorPage="true";
3) 方法:
getMessage()/printStackTrace()/toString()
内置对象session
1) HttpSession的一个实例, 用于来维护session的状态
2) 方法:
getAttribute(String name)/setAttribute(String name)
取得设置的属性的对应资源/设置属性的对应资源
removeAttribute(String name) 删除属性和队应资源
getAttributeNames()
返回值是一个迭代器,可以获得session中设置的属性的名字也就是在set时使用的与资源对应的那个名字
内置对象application
1) ServletContext一个实例,用来维护application的状态
2) 方法:
getAttribute()/setAttribute() 和session以及request中的那一对设置属性及其对应资源的方法
getInitParameter() 获得初始化参数
getServletInfo() 获得Servlet的信息
3) application的作用域比session大得多,一个session和一个client联系, 而application保持了用于所有客户端的状态。
注意:如果要保存的数据量比较大时,就要使用生命周期比较短的request对象,page对象只在本页面中有效,也就是会再翻译后的service方法体内的一个局部变量,service运行结束后就会销毁,不像request可以转发。session和application的生命周期都比较长而且作用域比较大。
JSP自定义标签(tag)
什么是自定义标签?
1,用户自定义的Java语言元素, 实质是运行一个或者两个接口的JavaBean;
2,可以非常紧密地和JSP的表示逻辑联系在一起,又具有和普通JavaBean相同的业务逻辑处理能力;
3,当一个JSP页面转变为servlet时,其间的用户自定义标签转化为操作一个称为标签hander的对象;
4,可操作默认对象,处理表单数据,访问数据库以及其它企业服务;
自定义标签库的特点
1,通过调用页面传递参数实现定制;
2,访问所有对JSP页面可能的对象;
3,修改调用页面生成的响应;
4,自定义标签间可相互通信;
5,在同一个JSP页面中通过标签嵌套,可实现复杂交互。
如何使用自定义标签库
1,声明标签库
2,使标签库执行对Web应用程序可用
声明标签库
1,使用taglib指令声明标签库
2,语法:<%@taglib uri="URI" prefix="pre" %>
注意:a. uri属性可以是绝对的,也可以是相对URL,该URL指向标记库描述符(TLD)文件;
b. uri属性也可以是一个并不存在的URL,该URL为web.xml文件中将标记库描述符(TLD)文件的绝对
URL到本地系统的一个映射;
3,范例:<%@taglib uri="/WEB-INF/template.tld" prefix="test" %>
<%@taglib uri="https://java.sun.com/jstl/core" prefix="core" %>
使标签库执行可用
方式一:在WEB-INF/classes目录下部署标记处理程序类;
方式二:将标记处理程序类打包成jar文件并置于WEB-INF/lib目录。
几种典型的标签
1,不带属性和主体的简单标签:<mytaglibs:SomeTag/>;
2,不带主体但有属性的标签:<mytaglibs:SomeTag user="TonyDeng"/>;
3,带有主体和属性的标签:
<mytaglibs:SomeTag user="TonyDeng">
...// 标签体
</mytaglibs:SomeTag>;
注意:a. 属性列于start tag中,它是在标记库描述符(TLD)文件中指定,服务于标记库的自定义行为;
b. 标签体位于start tag和end tag间,可以是任何合法的JSP内容或者标签;
定义标签
1,开发实现tag的类(tag handler);
2,编辑标记库描述符(TLD)文件;
3,在web.xml中为标记库描述符(TLD)文件的绝对URL建立一个映射(该步骤可选);
标记库描述符(TLD)文件
1,一个描述标记库的XML文件;
2,内容开始是整个库的描述,然后是tag的描述;
3,标记库描述符(TLD)文件用于Web Container确认tag以及JSP页面发展工具;
实现tag的类(标签处理器)(tag handler)
1,是一些在引用了标签的JSP页面执行期间被Web Container调用以求自定义标签值的对象;
2,必须实现Tag, SimpleTag和BodyTag之一;
3,可以继承TagSupport和BodyTagSupport之一。
标签库的接口和类的继承关系接口的继承关系:
☉interface javax.servlet.jsp.tagext.JspTag
☉interface javax.servlet.jsp.tagext.SimpleTag
☉interface javax.servlet.jsp.tagext.Tag
☉interface javax.servlet.jsp.tagext.IterationTag
☉interface javax.servlet.jsp.tagext.BodyTag
类的继承关系:
☉class javax.servlet.jsp.tagext.TagSupport
(implements javax.servlet.jsp.tagext.IterationTag, java.io.Serializable)
☉class javax.servlet.jsp.tagext.BodyTagSupport
(implements javax.servlet.jsp.tagext.BodyTag)
☉class javax.servlet.jsp.tagext.SimpleTagSupport
(implements javax.servlet.jsp.tagext.SimpleTag)
(Interface)
JspTag
|
|ˉˉˉˉˉˉˉˉ|
(Interface) (Interface)JSP2.0
Tag SimpleTag ←--SimpleTagSupport
|
|
(Interface)
IterationTag←--TagSupport
支持迭代的标签 |
| |
| |
(Interface) |
BodyTag ←---BodyTagSupport
可以处理标签体
自定义标签的开发步骤
1,写标签处理器,也就是一个符合自定义标签规范的类xxx.java
2,写标签库定义文件,也就是定义标签的格式规范,也要符合自定义标签的规范xxx.tld
3,建上述两步中的相应文件进行部署。web.xml
tld文件中的配置
<tag>
<name>loop</name>
<tag-class>com.tag.LoopTag</tag-class>
<body-content>jsp</body-content>
<!--设定自定义标签体内的内容,可以置为empty,也就是只能写空标签-->
<attribute>
<name>counter</name><!--配置自定义标签的属性名-->
<required>true</required><!--配置属性是否必须出现-->
<rtexprvalue>true</rtexprvalue><!--允许使用表达式作为属性的值-->
<type>int<type><!--配置属性的类型-->
</attribute>
</tag>
简单的标签处理程序类
1,必须实现Tag接口的doStartTag()和doEndTag()方法;
2,因为不存在Body,doStartTag()方法必须返回SKIP_BODY;
3,如其余页面要执行,doEndTag()方法返回EVAL_PAGE, 否则返回SKIP_PAGE;
4,对于每一个标签属性,你必须在标签处理程序类里定义一个特性以及get和set方法以一致于JavaBeans 体系惯例
带Body的自定义标签
1,必须实现Tag接口的doStartTag()和doEndTag()方法;
2,可以实现IterationTag接口的doAfterBody()方法;
3,可以实现BodyTag接口的doInitBody和setBodyContent方法;
4,doStartTag方法可以返回SKIP_BODY、EVAL_BODY_INCLUDE、或者EVAL_BODY_BUFFERED(当你想使用 BodyContent);
5,doEndTag方法可以返回SKIP_PAGE或EVAL_PAGE;
6,doAfterBody方法可以返回EVAL_BODY_AGAIN, SKIP_BODY;
定义脚本变量的标签(迭代标签)
1,定义脚本标签的二个步骤:
. 在标记库描述符(TLD)文件中列明脚本变量;
. 定义标签扩展信息类(TEI)并且在TLD文件中包括这个类元素(tei-class);
2,变量必须在标签处理程序类中使用pageContext.setAttribute()方法设置;
3,标签扩展信息类(TEI)必须继承TagExtraInfo以及覆盖getVariableInfo()方法;
4,变量的范围可以是AT_BEGIN, NESTED, AT_END(标签扩展信息类(TEI)的VariableInfo中定义)之一;
脚本变量的有效性
变量 | 有效性
---------------------------------------
NESTED | 标签中的参数在starttag到endtag之间是有效的
AT_BEGIN | 标签中的参数在标签的开始到JSP页面结束是有效的
AT_END | 标签中的参数在标签的结束到JSP页面结束是有效的
Tag接口的方法
interface javax.servlet.jsp.tagext.Tag
------------------------------------------------------
+EVAL_BODY_INCLUDE:int
+EVAL_PAGE:int//继续执行页面
+SKIP_BODY:int//跳出标签体
+SKIP_PAGE:int//跳出页面,也就是整个JSP不会再运行
------------------------------------------------------
+release():void
+getParent():javax.servlet.jsp.tagext.Tag
+setParent(javax.servlet.jsp.tagext.Tag):void
+doEndTag():int
+doStartTag():int
+setPageContext(javax.servlet.jsp.PageContext):void
Tag的生命周期
1,setPageContext(javax.servlet.jsp.PageContext):void
2,setParent(javax.servlet.jsp.tagext.Tag):void
3,setAttribute:void
4,doStartTag():int
5,doEndTag():int
6,release():void
BodyTag和Tag接口的关系
interface javax.servlet.jsp.tagext.BodyTag-->interface javax.servlet.jsp.tagext.Tag
------------------------------------------
+EVAL_BODY_AGAIN:int//继续执行标签体
-----------------------------------------
+doInitBody():void
+setBodyContent(javax.servlet.jsp.tagext.BodyContext):void
+doAfterBody():int
BodyTag的处理过程
1,setPageContext(javax.servlet.jsp.PageContext):void
2,setParent(javax.servlet.jsp.tagext.Tag):void //设置此标签的父标签,也就是上一层标签
3,setParent()
4,doStartTag():int
5,setBodyContent(javax.servlet.jsp.tagext.BodyContent):void//设置方法体
6,doInitBody():void//
7,doAfterBody():int
/* 这个方法会被不断的调用直到不再满足条件,通过这个方法来控制返回,从而控制循环是否中断
SKIP_BODY是跳出标签体的,EVAL_BODY_INCLUDE是继续执行标签体,通过返回这两个值来控制循环是否*/
8,doEndTag():int
9,release():void
SimpleTag接口的方法
javax.servlet.jsp.tagext.SimpleTag
------------------------------------------
+doTag():void
+getParent():JspTag
+setJspBody(JspFragment jspBody):void
+setJspContext(JspContext pc):void
+setParent(JspTag parent):void
SimpleTage接口的生命周期(JSP2.0的自定义标签接口)
1,new:
每次遇到标签,容器构造一个SimpleTag的实例,这个构造方法没有参数。和红典的标签一样, SimpleTag不能缓冲,故不能重用,每次都需要构造新的实例。
2,setJspContext()、setParent(): 只有这个标签在另一个标签之,才调用setParent()方法;
3,设置属性:调用每个属性的setter方法;
4,setJspBody();
5,doTag(): 所有标签的逻辑、迭代和Body计算,都在这个方法中;
6,return
例:
package com.tag;
public class HelloTag implements Tag
{
private PageContext pageContext;
private Tag parent;
public HelloTag(){
super();
}
/**
*设置标签的页面的上下文
*/
public void setPageContext(final PageContext pageContext) {
this.pageContext=pageContext;
}
/**
*设置上一级标签 www.2cto.com
*/
public void setParent(final Tag parent) {
this.parent=parent;
}
/**
*开始标签时的操作
*/
public int doStartTag() throws JspTagException{
return SKIP_BODY; //返回SKIP_BODY,表示不计算标签体
}
/**
*结束标签时的操作
*/
public int doEndTag() throws JspTagException{
try{
pageContext.getOut().write("Hello World!你好,世界!");
}
catch(java.io.IOException e){
throw new JspTagException("IO Error: " + e.getMessage());
}
return EVAL_PAGE;
}
/**
*release用于释放标签程序占用的资源,比如使用了数据库,那么应该关闭这个连接。
*/
public void release() {}
public Tag getParent(){
return parent;
}
}
xxx.tld
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="https://java.sun.com/xml/ns/j2ee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
version="2.0">
<tag>
<description>Extends TagSupport</description>
<name>hello</name>
<tag-class>com.tag.HelloWorldTag</tag-class>
<body-content>jsp</body-content>
</tag>
</taglib>
web.xml
<web-app>
<taglib-uri>/xxx</taglib-uri>
<taglib-location>/WEB-INF/tlds/xxx.tld</taglib-location>
</web-app>
xxx.jsp
<%@ taglib uri="/xxx" prefix="mytag" %>
<%@ page contentType="text/html; charset=gb2312" %>
<html><head><title>first cumstomed tag</title></head><body>
<p>以下的内容从Taglib中显示:</p>
<p><i><mytag:hello_int/></i>
<br>
<p><mytag:hello_int></mytag:hello_int>
</body></html>
JSP2.0中的表达式语言(EL表达式)
EL语法
EL的语法很简单,他最大的特点就是使用上很方便
例:
${sessionScope.user.sex}
所有EL都是以${ 为起始、以} 为结尾的。
上述EL范例的意思是:从Session取得用户的性别。如果使用之前JSP代码的写法如下:
<%
User user = (User)session.getAttribute("user");
String sex = user.getSex( );
%>
两者相比较之下,可以发现EL的语法比传统JSP代码更为方便、简洁。
EL提供. 和[ ] 两种运算符来存取数据,[ ]可以访问集合或者是数组的元素、Bean的属性。下列两者所代表的意思是一样的,但是需要保证要取得对象的那个的属性有相应的setXxx()和getXxx()方法才行。
例:
${sessionScope.user.sex}
等于
${sessionScope.user["sex"]}
. 和[ ] 也可以同时混合使用,如下:
${sessionScope.shoppingCart[0].price}
返回结果为shoppingCart中第一项物品的价格。
在EL中,字符串既可以使用"abc",可以使用'abc'。
EL运算符
EL的算术运算符和Java中的运算符的大致相同,优先级也相同。
注意:'+' 运算符不会连接字符串了,他只用于加法运算。
EL关系运算符有以下六个运算符
关系运算符 说 明 范 例 结果
= = 或eq | 等于 |${ 5 = = 5 } 或${ 5 eq 5 } | true
!= 或ne | 不等于 |${ 5 != 5 } 或${ 5 ne 5 } | false
< 或lt | 小于 |${ 3 < 5 }或${ 3 lt 5 } | true
> 或gt | 大于 |${ 3 > 5 }或${ 3 gt 5 } | false
<= 或le | 小于等于|${ 3 <= 5 }或${ 3 le 5 } | true
>= 或ge | 大于等于|${ 3 >= 5 }或${ 3 ge 5 } | false
empty运算符
Empty运算符主要用来判断值是否为null或空的,例如:
${ empty param.name }
接下来说明Empty运算符的规则:
{empty} A
如果A为null时,返回true
如果A不存在时,返回true
如果A为空字符串时,返回true
如果A为空数组时,返回true
如果A为空的Map时,返回true
如果A为空的Collection时,返回true
否则,返回false
注意:
在使用EL关系运算符时,不能够写成:
${param.password1} = = ${param.password2}
或者
${ ${param.password1 } = = ${ param.password2 } }
而应写成
${ param.password1 = = param.password2 }
使用EL从表单中取得数据
与输入有关的隐含对象有两个:param和paramValues,它们是EL中比较特别的隐含对象。一般而言,我们在取得用户的请求参数时,可以利用下列方法:
request.getParameter(String name)
request.getParameterValues(String name)
在EL中则可以使用param和paramValues两者来取得数据。
${param.name}
${paramValues.name}可以取得所有同名参数的值
${paramValues.hobbies[0]}可以通过指定下标来访问特定的参数的值
这里param的功能和request.getParameter(String name)相同,而paramValues和request.getParameterValues(String name)相同。如果用户填了一个form,form名称有为username的文本框,则我们就可以使用${param.username}来取得用户填入文本框的值。
EL函数
EL中使用函数要写一个要使用到方法的类,然后在配置xxx.tld文件,然后在JSP中使用时和JSP的自定义标签相似。
xxx.tld中的配置
<function>
<name>reverse</name><!--函数名-->
<function-class>jsp2.examples.el.Functions</function-class><!--函数所在的类-->
<function-signature>java.lang.String reverse( java.lang.String )</function-signature>
<!--函数原型,也就是函数的返回值类型,函数名,参数表,注意一定要写类型的全名-->
</function>
使用EL函数的写法
${sn:upper('abc')}
注意:在定义EL函数时,都必须为公开静态(public static)
EL的隐含对象
EL也可以使用内置对象中设置的属性,需要使用特定的EL内置对象
属性范围 | 在EL中的对象
Page | pageScope
Request | requestScope
Session | sessionScope
Application | applicationScope
EL中使用内置对象的属性
${requestScope.user}
等价于
<%request.getAttribute("user")%>
如果不写出特定的范围 ,那就会在不同的范围间进行搜索了
例:{user}(user是在request范围request.setAttribute("user",user))
也就等于
${requestScope.user}
<%request.getAttribute("user")%>
EL的隐含对象
对象 类 型 说 明
PageContext | javax.servlet.ServletContext |表示此JSP的PageContext
-----------------------------------------------------------------------------------
PageScope | java.util.Map |取得Page范围的属性名称所对应的值
-------------------------------------------------------------------------------------
RequestScope | java.util.Map |取得Request范围的属性名称所对应的值
-------------------------------------------------------------------------------------
sessionScope | java.util.Map |取得Session范围的属性名称所对应的值
-------------------------------------------------------------------------------------
applicationScope | java.util.Map |取得Application范围的属称所对应的值
-------------------------------------------------------------------------------------
param | java.util.Map |如同ServletRequest.getParameter(String | |name)返回String类型的值
----------------------------------------------------------------------------------------
paramValues | java.util.Map |如同ServletRequest.getParameterValues | |(String name)。返回String []类型的值
-----------------------------------------------------------------------------------------
header | java.util.Map |如同ServletRequest.getHeader(String name) | |返回String类型的值
------------------------------------------------------------------------------------------
headerValues | java.util.Map |如同ServletRequest.getHeaders(String name) | |。返回String []类型的值
------------------------------------------------------------------------------------------
cookie | java.util.Map |如同HttpServletRequest.getCookies( )
------------------------------------------------------------------------------------------
initParam | java.util.Map |如同ServletContext.getInitParameter(String | |name)。返回String类型的值
-------------------------------------------------------------------------------------------
cookie对象
所谓的cookie是一个小小的文本文件,它是以key、value的方式将Session Tracking的内容记录在这个文本文件内,这个文本文件通常存在于浏览器的暂存区内。JSTL并没有提供设定cookie的动作,因为这个动作通常都是后端开发者必须去做的事情,而不是交给前端的开发者。如果我们在cookie中设定一个名称为userCountry的值,那么可以使用${cookie.userCountry}来取得它。
header和headerValues(请求报头对象)
header储存用户浏览器和服务端用来沟通的数据,当用户要求服务端的网页时,会送出一个记载要求信息的标头文件,例如:用户浏览器的版本、用户计算机所设定的区域等其他相关数据。如果要取得用户浏览器的版本,即${header["User-Agent"]}。另外在很少机会下,有可能同一标头名称拥有不同的值,此时必须改为使用headerValues来取得这些值。
注意:因为User-Agent中包含“-”这个特殊字符,所以必须使用“[]”,而不能写成${header.User-Agent}。
initParam
就像其他属性一样,我们可以自行设定web应用的环境参数(Context),当我们想取得这些参数时,可以使用initParam隐含对象去取得它,例如:当我们在web.xml中设定如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="https://java.sun.com/xml/ns/j2ee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<context-param>
<param-name>userid</param-name>
<param-value>mike</param-value>
</context-param>
</web-app>
那么我们就可以直接使用${initParam.userid}来取得名称为userid,其值为mike的参数。下面是之前的做法:String userid = (String)application.getInitParameter("userid");
pageContext对象
我们可以使用${pageContext}来取得其他有关用户要求或页面的详细信息。下面列出了几个比较常用的部分。
Expression 说 明
${pageContext.request} |取得请求对象
${pageContext.session} |取得session对象
${pageContext.request.queryString} |取得请求的参数字符串
${pageContext.request.requestURL} |取得请求的URL,但不包括请求之参数字符串
${pageContext.request.contextPath} |服务的web application的名称
${pageContext.request.method} |取得HTTP的方法(GET、POST)
${pageContext.request.protocol} |取得使用的协议(HTTP/1.1、HTTP/1.0)
${pageContext.request.remoteUser} |取得用户名称
${pageContext.request.remoteAddr } |取得用户的IP地址
${pageContext.session.new} |判断session是否为新的,所谓新的session,表示刚由 server产生而client尚未使用
${pageContext.session.id} |取得session的ID
${pageContext.servletContext.serverInfo}|取得主机端的服务信息
JSTL(JSP标准标签库)
JSTL由核心标签,<c:... > ,xml解析标签<x:...>,国际化标签<fmt:....>,数据库访问标签<sql:...>,函数标签<fn:...>
核心标签
Core
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
属性设置
<c:set> 设置属性
<c:remove> 移除设置的属性
过程控制
<c:if test="..."> 条件标签 只有在test属性的值为true是才会执行标签体
例:
<c:if test="${!(empty user.age)}">
<h1>hello</h1>
</c:if>
<c:choose>choose和when是组合在一起使用的,有点类似于swith case的语法 。
<c:when test="...">when也是条件判断标签,test属性的值为true是才会执行标签体。
例:
<c:choose>
<c:when test="${param.age<18}">
<h1>you is a child<h1>
</c:when>
<c:when test="${param.age>18 and param.age<50 }">
<h1>you is a young person</h1>
</c:when>
<c:when test="${param.age>50}">
<h1>you is a old person</h1>
</c:when>
</c:choose>
<c:forEach>迭代标签
例:
<c:forEach var="book" item="${store.books}" varStatus="status">
<h1>${book.parice}</h1>
</c:forEach>
<c:forEach begin="1" end="5" step="1">
<h1>hello</h1>
</c:forEach>
<c:forTokens>字符串迭代标签
<c:import>引入标签
<c:import url="引入内容的url" var="别名">
${别名}
<c:url>url标签
<c:url value="...">
<c:param name="..." value="..."/>
</c:url>
<c:url value="...">
使用url标签可以实现URL回写
<c:redirect uri="xxx/xxx/xxx.xx"/>
国际化标签
<fmt:lauguage>
<fmt:bundel>资源指定标签
<fmt:message>消息标签
例:
<fmt:setLocale value="zh"/>
<fmt:bundel basename="message.MessageResources">
<fmt:message>name</fmt:message>
</fmt:bundel>
xxxx.properties
name=\0060\0700\
摘自HarderXin的专栏
上一篇: 最简单的瑜伽动作,比爬楼梯还简单,1分钟就能通经络,排毒素!
下一篇: HDFS命令行工具