[JSP]JSTL简介、核心标签库

1. 为什么提出JSTL以及JSTL的配置:

    1) 即使在JSP中可以直接编写HTML、JavaScript代码,同时也有标准标签库和EL表达式的支持,但仍想在JSP中彻底放弃Scriptlet还是不可能的,因为最重要的流程控制语句和一些基本的编程元素还没有对应的JSP标签!!

    2) JSTL就是为了让JSP彻底告别Scriptlet,JSTL全称是JSP Standard Tag Library,即JSP标准标签库;

    3) JSTL中提供了有关流程控制等重要的编程元素所对应的标签,如<if>标签进行逻辑判断、<forEach>标签进行循环操作等;

    4) JSTL之于JSP类似于boost库之于C++,boost库并非C++标准规范下的库,而是C++开发平台所定制的一个类库(用于实现跨平台),而JSTL也并非JSP标准规范下的标签库,而是J2EE平台规范下所定制的标签库,因此当Tomcat等Web容器的下载并不包含这个标签库,这个标签库需要另外下载才行;

    5) 众所周知,任何JSP代码、JSP标签最终都是会被转译成Servlet代码的,因此JSTL标准库中的标签必须要有对应的.class文件支持(每种标签必须有Java代码的实现),因此JSTL标签库以jar包的形式发布,里面不仅有各种标签的.class实现,也有相应的.tld的标签声明文件,这两种类型的文件一并打包进了jar包中;

!!这里需要到Apache组织的FTP服务器上下载JSTL实现库:

!!这里顺便介绍一下Apache的FTP服务器:

        a. 其地址是:http://www.apache.org/dist/

        b. 进入后可以看到Apache的所有产品,从云计算、大数据到服务器应用等应有尽有,其中每种大产品都有一个目录,每个目录中都有该产品系列中的各种产品的发布版、源码、文档、beta版等,这些资源都完全免费开放,随意下载;

        c. 我们需要的产品JSTL标签库的实现对应的路径是:jakarta/taglibs/standard/

        d. 该目录下有两个子目录,一个是binary,另一个是source,分别对应JSTL库的实现和源码,在binary中下载最新版本的.zip,对于source也是;

        e. 下载后解压JSTL实现库的.zip包,将lib目录中的两个jar包解压出来就可以用了(分别是jstl.jar(JSTL标准接口与类,但没有实现,还包括.tld的标签声明)和standard.jar(JSTL的实现);

        f. 将source目录下standard/src解压出去并打包成一个jar包,该jar包就可以在Eclipse中和前面两个.jar包Attach在一块儿,可以在IDE中非常方便地查看源码,而不需要在线查看帮助文档了!!

!!可以在FTP的jakarta目录中看到我们的Tomcat、Struts等产品,它们都属于Jakarta工程;

    6) 只需要将上面的jar包放到WEB-INF目录中就可以正常使用了,但是在使用Eclipse开发的时候没必要也将jar包直接放到工程的WEB-INF目录中,设想每个代码工程都这样做的话岂不是很麻烦(特别是手上的工程数量特别多的时候,那么每个工程都要包含这些类库,岂不是非常占用空间),因此还是采取部署的方式,将要用到的类库都连接到工程外部的文件系统中,各个工程都可以共享文件系统中同一个库文件:

         i. 右键左侧项目图标,选中Properties菜单项;

         ii. 选中对话框左侧的Deployment Assembly选项卡进行类库的部署;

         iii. 单击Add按钮,然后选择Archives from File System后选择下载过的jar文件,将其添加到当前工程的依赖库集合中;

         iv. 添加完成后可以看到项目左侧的Java Resource/Libraries结点中看到加入的两个jar包;

         v. 但是点击里面的.class文件却不能查看其源码,这在IDE中编程时不方便查看方法说明,因此需要Attach一下前面下载的源码包,然后就全部配置完毕了;


2. JSTL中具体包含哪些标签库:

    1) 大致可以分为5大标签库,分别对应不同的功能,分别是核心标签库、I18N标签库、SQL标签库、XML标签库和函数标签库;

    2) 核心标签库:提供条件判断、流程控制、属性访问、URL处理以及错误处理等基础功能;

    3) I18N标签库:提供国际化功能;

    4) SQL标签库:提供和数据库操作相关的功能;

    5) XML标签库:提供XML解析、流程控制、转换等功能;

    6) 函数标签库:提供了一些常用的EL函数标签(就相当于C++的函数库),特别是一些常用的字符串处理函数;


3. 使用标签库中的标签:

    1) 和上一章讲过的EL函数的使用完全一样;

    2) 必须先使用taglib指示元素声明要使用的标签库;

    3) 属性prefix就是给标签库取一个命名空间,在之后的JSP代码中使用标签库中的标签必须要加命名空间的前缀;

    4) 属性uri指定标签库的资源定位;

    5) 例如,要使用JSTL的核心标签库则可以这样声明:<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

!!一般都给核心标签库的前缀取名为"c",即core的缩写;

!!还有就是URI的前缀一般都是http://java.sun.com/jsp/jstl,后缀就是要使用的具体的JSTL的库的名称了,像sql之类的;

    6) 最后在使用JSTL标签的时候注意一定要加上前缀(即命名空间),例如:<c:if>等;


4. 核心标签库简介:

    1) 主要的功能包括6大类;

    2) 逻辑判断/流程处理:包含if、forEach等和普通编程语言类似的程序控制结构;

    3) 错误处理:此类标签可以捕获异常并进行处理;

    4) 网页导入/请求调配/网页重定向:虽然JSP标准标签已提供相关的功能,但是JSTL核心标签库提供的相关功能更强大,书写也更简洁;

    5) 属性处理:比<jsp:set/getProperty>的功能更多更丰富,形式也更简洁;

    6) 输出处理:提供诸如把输出流中的<、>等HTML字符替换为纯文本字符的功能;

    7) URL处理:也比JSP标准标签来的更加方便;

!!!接下来要介绍的全部都是核心标签库的标签;


5. 逻辑判断/流程处理标签:

    1) <c:if>:

         i. 即实现if语句的功能,可根据某个逻辑判断是否显示Body的内容;

!!!接下来可以看到,所有标签语言都是像脚本语言靠拢的,可以发现后面JSTL的标签的属性都模仿Unix的Bash Shell命令!!

         ii. if的test属性可以放置EL表达式,如果结果为true就输出该标签所包裹内容,否则就不输出;

         iii. 例如:

<c:if test="${param.name == 'Peter'}">
	<h1>${param.name} is loging!<h1>
</c:if>
!!这里需要注明一下JSP代码中" "和' '的用法,在这个例子中,这两个符号都用到了,因此可能会搞混!!

        a. 首先是“代码字符串”:顾名思义就是JSP、HTML中的代码字符所组成的字符串了,在这个例子中就是诸如<c:if test、<h1>等字符串,这些字符串都是真正的代码,都是代码的关键字(就像C语言的for、=、;等字符);

        b. 而在JSP、HTML中还有一种最重要的字符串那就是纯文本字符串了,像<h1></h1>中间的字符串,就是一种纯文本,将会输出到浏览器页面上,还有像<title></title>之间的字符串也是一种纯文本,将会作为标题栏中的文本输出,文本里是什么就输出什么,诸如"abc'ab'abc"就会照样输出,双引号、引号一个不落;

!!还有就是最重要的一点:像JSP标准标签、EL表达式等的返回值也是纯文本,可以将他们的运算结果当成一种纯文本字符串的变量来对待!!这就跟Shell的$VAR的变量引用的原理一模一样,所以标签语言都是像脚本语言靠拢的,因为脚本语言是世界上最简洁、最简单的编程语言;

        c. 最后一种就是参数字符串了,它是标签的属性的值,要求必须用双引号括起来,而且双引号中间的内容必须也是纯文本(即b.中定义的字符串,当然可以包含EL表达式,因为其返回值也是纯文本);

!!那么问题来了,既然都是纯文本,那又何必一定要用双引号括起来呢?原因很简单,首先标签语言中所有的数据都是字符串(和脚本一样),其次是,如果参数值里面带空格,如果不用双引号引用,那么空格后面的词就会被当成下一个属性了!!

!!双引号之于标签属性的作用就是将一串字符串包成一个整体!!

         d. 既然双引号是专门用来包裹标签属性的,那么单引号的作用呢?很简单,就在上面的例子中,如果属性中含有EL表达式,而EL表达式中也包含纯文本字符串(EL表达式中不用引号引起来的字符串会被当做对象看待,因此EL中的纯文本必须用引号引起来,双引号和单引号都行)该怎么办?如果用继续用双引号的话(如果上面的例子为"${param.name == "Peter"}",那么$前面的"就会和P前面的"匹配在一起,将"${param.name =="作为属性赋给test了,那么后面剩余的字符串算什么东西呢?这样Web容器必定会报错,报错类型是转译错误!!因此要用单引号括起来,以示区别!!

!!因此,test属性的值也必定是true或者false的字符串("true"和"false"),而肯定不是什么boolean类型的数据,因为标签语言的数据类型只有一种,那就是字符串!!!

    2) JSTL并没有提供else标签,而是用choose-when-otherwise标签来代替else以及switch!!!

         i. 其实也完全可以替代if标签,只不过if用的太频繁了,所有程序员都难以一个语言没有if,所以还是保留if了;

         ii. when和otherwise是choose的子标签,每个when给出一个test测试,when成立就执行when,when都不成立就执行最后的otherwise,因此otherwise没有测试条件,choose呢也没有属性,choose-when-otherwise的可以和C语言的switch-case-default相对应;

         iii. 举例:

<c:choose>
	<c:when test="${user.name != null}">
		<h1>logging!</h1>
	</c:when>
	<c:when test="${12 == 12}">
		<h1>Yes!</h1>
	</c:when>
	<c:otherwise>
		<h1>Otherwise!!</h1>
	</c:otherwise>
</c:choose>

!!和C语言的switch-case-default一样,when可以有多个,但otherwise只有一个,且必须放在最后,而otherwise可以没有但when必须至少要有一个,只不过和switch-case-default不一样的地方就是如果某个when中枪了,则只执行该when中的语句,后面的when和otherwise全部不执行,如果有多个when,则按照从上到下的顺序检查是否中枪;

    3) <forEach>:

         i. 顾名思义是for循环,而且只提供for一种循环,没有while、do-while等,一切从简;

         ii. JSTL的forEach可以对Java的数组、Collection(容器)、Interator、Enumeration、Map和字符串进行迭代;

         iii. 语法格式:<c:forEach var="变量名" items="EL表达式">XXX</c:forEach>

         iv. 其中EL表达式返回的是一种上述可迭代的类型的数据,之后JSTL会再每次循环中将var指定的变量名和items中的数据依次绑定在一起,接着就可以在XXX中使用该变量名进行操作;

!!!所有JSTL标签中的var都是指变量名的意思,都会将该变量名和某个值(可以是Java对象,也可以是普通的字符串)绑定在一起,然后利用EL表达式来操作该变量名;

!!这种变量名都属于EL表达式,必须用${}的形式来使用它!!!

         v. 例如:

<jsp:useBean id="messageService" class="com.lirx.MessageService" />
...
	<c:forEach var="message" items="${messageService.messages}">
		${message.name} : ${message.text}
	</c:forEach>
...
!!这里假设有一个JavaBean,其getter为getMessages(),返回的是一个Message数组,而Message类型也是一个自定义类型,有两个getter,一个是getName返回信息的名称,另一个是getText,返回信息的内容;

!!在这里items可以是上面说的Java的数组、Collection、Iterator、Enumeration、Map和字符串;

!!在每次循环中都会吧items中的一个值和var挂钩(按照迭代器的顺序);

         vi. 如果迭代的是数组、容器和Iterator那么就按照上面的做法循环即可,如果是Map的话,那么和var挂钩的对象会是Map.Entry,该对象有getKey和getValue两个getter,因此可以这样迭代:

<c:forEach var="item" items="${someMap}">
	Key: ${item.key}<br>
	Value: ${item.value}<br>
</c:forEach>
         vii. 如果迭代的是字符串,那就必须指定一个分隔符,标签会议指定的分隔符来切割给出的字符串,将切割后的各个部分迭代给var,分隔符的属性是dlims,例如:

<c:forEach var="token" delims=":" items="aa:bb:cc:dd">
	${token} <br>
</c:forEach>
!得到的结果就是aa、bb、cc和dd,不包括分隔符本身的;

!如果不指定分隔符,则默认使用逗号","进行分割!


6. 错误处理标签:

    1) 通常在JSP页面中出现错误(比如EL表达式错误、正常的JSP语法错误、转译、编译、运行时错误等等),如果不进行任何处理的话就会发送至错误页面,即使你使用了errorPage属性,也是转发值错误页面,但是如果你想向用户隐藏错误信息而只在当前页面中打印一句“页面错误!”并且不转发页面那该怎么做呢?

    2) 在Scriptlet中编写try-catch代码当然没有问题,但是JSTL提供了<c:catch>标签可以避免编写Scriptlet;

    3) 该标签有一个属性,就是var,和该变量名挂钩的默认是一个Java的Exception对象,捕获的异常就会放到该对象中,在<c:catch>模块之后可以加以利用;

    4) 使用时只要将可能会发生异常的代码包裹在<c:catch>标签中即可(JSTL没有try标签,直接用catch标签当做try标签使用),过了catch标签之后可以在利用if标签判断一下有没有catch到异常,如果catch到了则可以进行进一步的操作,例如:

<c:catch var="error">
	${param.a} + ${param.b} = ${param.a + param.b}
</c:catch>
<c:if test="${error != null}">
	${error.message} : ${error}
</c:if>
!!这里catch中var的作用于可以延伸至if;

!!如果请求参数中给出的a或b不是数字而是字母的话则会发生异常!

!!此时由于异常直接在当前页面中捕获并处理,因此不会转发页面,而知直接显示错误的内容${error};

    5) 由于catch的error都默认是Throwable的对象,该对象中定义了getMessage方法,因此可以访问其属性${error.message},该方法返回的是出错的位置,而该类型对象本身也定义过toString方法,返回的是错误的原因,因此可以直接使用EL获取该字符串${error}

    6) 注意!!!不要将<c:catch>的捕获异常和JSP隐式对象exception捕获异常混淆!!exception有效的前提是当前页面必须是isErrorPage="true",而catch标签则不需要这个前提,因为它是局部捕获的、直接在当前页面中捕获的;


7. 网页导入/重定向:

    1) 首先介绍核心标签的动态导入,使用的标签是<c:import>:

         i. 它是标准标签<jsp:include>的加强版,转译时都是转译成Dispatcher.include方法,只不过<c:import>比<jsp:include>还多了一个编码的功能;

         ii. 该标签最重要的参数就是url了,用来指示要导入的网页的URL地址,但该标签和<jsp:include>一样,不支持直接在导入网页的URL中添加额外参数,而是使用<param>标签指定额外参数,例如:

<c:import url="xxx.jsp">
	<c:param name="a", value="1" />
	<c:param name="b", value="2" />
</c:import>
         iii. 其次,<c:import>标签的另外一个功能就是还可以导入外部JSP页面,也就是说要导入的页面不在当前应用程序中!!此时就要考虑编码问题了,如果要导入的网页和当前网页的编码不一致会出现乱码,因此需要用<c:import>标签的charEncoding来指定导入后应该使用的编码,这样可以使两者的编码保持一致,例如:

<c:import url="xxx.jsp" charEncoding="UTF-8" />

    2) 接着就是重定向标签<c:redirect>:

         i. 该标签取代Servlet里Response的sendRedirect方法;

         ii. 属性仍然是url,即重定向的url,如果有额外的参数还是用<c:param>来指示,例如:

<c:redirect url="xxx.jsp">
	<c:param name="a", value="1" />
	<c:param name="b", value="2" />
</c:redirect>


8. 属性处理:

    1) 设置属性:使用<c:set>标签

         i. 是<jsp:setProperty>标准标签的加强版,标准标签只能设置JavaBean属性,但是<c:set>可以设置更多类型数据的范围属性,而且还可以设置Map类型范围属性的键和值;

         ii. 该标签的3大属性是:var、value、scope

         iii. var就是用一个变量名和value所指示的数据进行关联,value所表示的变量名在之后可以进行引用,并且var也是范围属性在范围内的名称,scope指出了设置的范围;

         iv. value可以是普通的字符串,也可以用EL表达式返回一个Java中的数据类型;

         v. 例如:<c:set var="name" value="Peter" scope="session" />,如果value是这样的${user},则代表设置一个User数据类型的值了;

!!上例就相当于:session.setAttribute("name", "Peter");

         vi. 当然,如果设置的值非常长,比如是一个长的字符串,则可以用Body的方式编写:

<c:set var="sentence" scope="session">
	Good Morning!!!!
</c:set>
!那么两个标签中间的字符串就是value的值,而且不需要加双引号,直接就是一个纯字符串文本了;

!!如果不设置scope,则默认按照page、request、session、application的顺序找,如果找到了就重设该值,如果不存在则在page中新增该值;

    2) 删除属性:使用<c:remove>,用var确定范围属性的名称,用scope确定范围,例如<c:remove var="name" scope="application" />

!!同样,如果不注明范围,则默认按上面的顺序查找并删除第一个找到的;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值