type
status
date
slug
summary
tags
category
icon
password
JSP
简介
JSP全称是JavaServer Pages,它和servlet技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。
JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比html而言,html只能为用户提供静态数据,而jsp技术允许在页面中嵌套java代码,为用户提供动态数据;相比servlet而言,servlet很难对数据进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易对数据进行排版。
不管是JSP还是Servlet,虽然都可以用于开发动态web资源,但由于这2门技术各自的特点,在长期的软件实践中,人们逐渐把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
其原因为,程序的数据通常要美化后再输出,让jsp既用java代码产生动态数据,又做美化会导致页面难以维护;让servlet既产生数据,又在里面嵌套html代码美化数据,同样也会导致程序可读性差,难以维护;因此最好的办法就是根据这两门技术的特点,让它们各自负责各的,servlet只负责响应请求产生数据,并把数据通过转发技术带给jsp,数据的显示jsp来做。
语法
- jsp模版元素
- jsp表达式
- jsp脚本片段
- jsp注释
- jsp指令
- jsp标签
- jsp内置对象
- 如何查找jsp页面中的错误
Jsp模板元素
jsp页面中的HTML内容称之为jsp模版元素;jsp模版元素定义了网页的基本骨架,即定义了页面的结构和外观。
Jsp脚本表达式
jsp脚本表达式(expression)用于将程序数据输出到客户端。
语法:
举例
jsp引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…)将数据输给客户端。
jsp脚本表达式中的变量或表达式后面不能有分号;。
Jsp脚本片段
jsp脚本片断(scriptlet)用于在jsp页面中编写多行Java代码。
语法:
注意:jsp脚本片断中只能出现java代码,不能出现其它模板元素,jsp引擎在翻译jsp页面中,会将jsp脚本片断中的Java代码将被原封不动地放到Servlet的_jspService方法中。
jsp脚本片断中的Java代码必须严格遵循Java语法,例如,每执行语句后面必须用分号;结束。
在一个jsp页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他jsp元素。
举例:
多个脚本片断中的代码可以相互访问,犹如将所有的代码放在一对<%%>之中的情况。如:out.println(x);,单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句,例如:
Jsp声明
jsp页面中编写的所有代码,默认会翻译到servlet的service方法中, 而Jsp声明中的java代码被翻译到_jspService方法的外面。
语法:
所以,jsp声明可用于定义jsp页面转换成的Servlet程序的静态代码块、成员变量和方法。
多个静态代码块、变量和函数可以定义在一个jsp声明中,也可以分别单独定义在多个jsp声明中。
jsp隐式对象的作用范围仅限于Servlet的_jspService方法,所以在jsp声明中不能使用这些隐式对象。
Jsp 注释
jsp注释的格式:
jsp引擎在将jsp页面翻译成Servlet程序时,忽略jsp页面中被注释的内容。
Jsp 指令
jsp指令(directive)是为jsp引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理jsp页面中的其余部分。
在jsp2.0规范中共定义了三个指令:
- page指令
- include指令
- taglib指令
jsp指令的基本语法格式:
page指令
page指令用于定义jsp页面的各种属性,无论page指令出现在jsp页面中的什么地方,它作用的都是整个jsp页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个jsp页面的起始位置。
jsp 2.0规范中定义的page指令的完整语法:
通过page指令设置页面的编码
举例:
这个指令的作用就相当于response.setContentType("text/html;charset=gb2312");。
但是这个指令和
的区别是:
- pageEncoding是jsp文件本身的编码
- contentType的charset是指服务器发送给客户端时的内容编码
jsp要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8,第三阶段就是由Tomcat出来的网页,用的是contentType。
第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的utf-8格式java源码(即.java),如果pageEncoding设定错了,或没有设定,出来的就是中文乱码。
第二阶段是由javac的Java源码至java byteCode的编译,不论jsp编写时候用的是什么编码方案,经过这个阶段的结果全部是utf-8的encoding的Java源码。
javac用utf-8的encoding读取java源码,编译成utf-8 encoding的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。
第三阶段是Tomcat(或其的application container)载入和执行阶段二的来的Java二进制码,输出的结果,也就是在客户端见到的,这时隐藏在阶段一和阶段二的参数contentType就发挥了功效
contentType的设定:
pageEncoding和contentType的预设都是ISO8859-1,而随便设定了其中一个, 另一个就跟着一样了(Tomcat4.1.27是如此);但这不是绝对的,这要看各自JSPC的处理方式,而pageEncoding不等于contentType,更有利亚洲区的文字CJKV系jsp网页的开发和展示,(例pageEncoding=GB2312不等于contentType=utf-8)。
jsp文件不像.java,.java在被编译器读入的时候默认采用的是操作系统所设定的locale所对应的编码,比如中国大陆就是GBK,台湾就是BIG5或者MS950;而一般不管是在记事本还是在ue中写代码,如果没有经过特别转码的话,写出来的都是本地编码格式的内容。所以编译器采用的方法刚好可以让虚拟机得到正确的资料。
但是jsp文件不是这样,它没有这个默认转码过程,但是指定了pageEncoding就可以实现正确转码了。
当同时使用这两个命令时:
这时候就会发现,文件的编码是utf-8,而页面浏览的编码是gb2312,所以说上面的一条指令是专门设置页面浏览的编码的,下面的指令是专门设置文件的保存编码的。
通过page指令导入Java包
jsp引擎自动导入下面的包:
可以在一条page指令的import属性中引入多个类或包,其中的每个包或类之间使用逗号分隔:
上面的语句也可以改写为使用多条page指令的import属性来分别引入各个包或类:
buffer属性
使用这个属性是指定out对象的缓存大小,如果我们想关闭缓冲区的话,只需要设置值为none就可以了。
isThreadSafe 属性
这个属性见名知意,是设置是否线程安全的。
- isThreadSafe=false模式表示它是以Singleton模式运行;该模式implements了接口SingleThreadMode,该模式同一时刻只有一个实例,不会出现信息同步与否的概念;若多个用户同时访问一个这种模式的页面,那么先访问者完全执行完该页面后,后访问者才开始执行
- isThreadSafe=true模式表示它以多线程方式运行;该模式的信息同步,需访问同步方法(用synchronized标记的)来实现
session属性
是指不能在本页使用session,也就是在本页面禁用了session,也就是在将jsp翻译成servlet的时候不会传递session对象了
errorPage属性
这个属性是设置服务器端出错之后的错误页面的。
通过这个属性值,设置一个错误页面,当服务器发生错误的时候都会跳转到这个页面中。
转到错误页面使用的是转发技术,所以在书写url地址的时候,那个开始的斜杠代表是当前应用,因为这个地址是给服务器用的。
在web.xml文件中给应用配置一个全局的错误页面
在web.xml文件中可以配置抛出的异常类型所对应的错误页面,也可以配置状态码对应的错误页面,且这里配置的结果的优先级没有errorPage属性配置错误页面的优先级高。
isErrorPages属性
是否开启错误页面,就是控制上面的errorPage属性的作用开关的。
isELIgnored 属性
是否在该页面中忽视EL表达式的功能,这个一般都不去做设置,因为在页面中肯定会使用到EL表达式的。
注意:如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。
例如:
也可以写作:
include指令
include指令是实现页面包含的,使用include指令来实现页面包含是静态包含。
taglib指令
这个指令作用是引入标签(收JSTL的内容)。
Jsp内置的9个隐式对象
每个jsp页面在第一次被访问时,web容器都会把请求交给jsp引擎(即一个Java程序)去处理,jsp引擎先将jsp翻译成一个_jspServlet(实质上也是一个servlet),然后按照servlet的调用方式进行调用。
由于jsp第一次访问时会翻译成servlet,所以第一次访问通常会比较慢,但第二次访问,jsp引擎如果发现jsp没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响。
jsp引擎在调用jsp对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用,jsp技术的设计者为便于开发人员在编写jsp页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在jsp页面中通过这些变量就可以快速获得这9大对象的引用。
这9个对象分别是:
对象 | 类型 |
request | HttpServletRequest |
response | HttpServletResponse |
session | HttpSession |
application | servletContext |
config | servletConfig |
out | JspWriter |
exception | Throwable |
page | this |
pageContext | PageContext |
exception是个异常对象,只有当jsp页面中抛出异常的时候,才会有这个对象的产生,否则是不会传递这个对象的。
page对象就是当前对象,即jsp翻译后的servlet对象。
out对象
用于向客户端发送文本数据。
out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
jsp页面中的out隐式对象的类型为jspWriter,jspWriter相当于一种带缓存功能的PrintWriter,设置jsp页面的page指令的buffer属性可以调整它的缓存大小,甚至可以关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
- 设置page指令的buffer属性关闭了out对象的缓存功能
- out对象的缓冲区已满
- 整个jsp页面结束
实例:
访问jsp页面可以看到,是先向浏览器中输出bbb,然后在输出aaa,原因是out对象是jspWriter,是带有缓冲的。
看下图解释:
所以给浏览器输出数据的时候一定要注意,最好不要同时使用这两个对象,一般只是用out对象进行输出数据。
pageContext对象
pageContext对象是jsp技术中最重要的一个对象,它代表jsp页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,这个域对象的生命周期最短,作用域最小,它的作用域就是当前的jsp页面,当然它可以用来保存数据;并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。
- getException方法返回exception隐式对象
- getPage方法返回page隐式对象
- getRequest方法返回request隐式对象
- getResponse方法返回response隐式对象
- getServletConfig方法返回config隐式对象
- getServletContext方法返回application隐式对象
- getSession方法返回session隐式对象
- getOut方法返回out隐式对象
pageContext封装其它8大内置对象的意义
只需要传递一个pageContext对象,就可以操作其他多个对象。
pageContext对象中的操作域中数据的方法
pageContext对象中还封装了访问其它域的方法(和上面的方法不同之处就是多了一个参数,这个参数是可以直接指定相应的域)。
代表各个域的常量:
findAttribute方法是在所有的域中查找数据,查找顺序是:pageContext->request->session->ServletContext,如果查找不到相应的数据的话,就返回一个空字符串。
PageContext类中定义了一个forward方法和两个include方法来分别简化和替代RequestDispatcher.forward方法和include方法。
传递给这些方法的资源路径都只能是相对路径,如果路径以/开头,表示相对于当前web应用程序的根目录,否则,表示相对于当前jsp所映射到的访问路径。
JSP标签库
虽然希望jsp页面仅用作数据显示模块,不要嵌套任何java代码引入任何业务逻辑,但在实际开发中不引入一点业务逻辑是不可能的,引入业务逻辑会导致页面出现难看的Java代码怎么办?
Sun公司允许用户开发自定义标签封装页面的Java代码,以便jsp页面不出现一行java代码,当然Sun公司在jsp页面中也内置了一些标签(这些标签叫做jsp标签),开发人员使用这些标签可以完成页面的一些常用业务逻辑。
jsp标签也称之为Jsp Action(jsp动作)元素,它用于在jsp页面中提供业务逻辑功能。
- <jsp:include>标签
- <jsp:forward>标签
- <jsp:param>标签
- <jsp:useBean>标签
- <jsp:setProperty>标签
- <jsp:getProperty>标签
<jsp:include>标签
<jsp:include>标签用于把另外一个资源的输出内容插入进当前jsp页面的输出内容之中,这种在jsp页面执行时的引入方式称之为动态引入。
语法:
page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
flush属性指定在插入其他资源的输出内容时,是否先将当前jsp页面的已输出的内容刷新到客户端。
<jsp:include>标签是动态引入(和使用代码进行include一样),<jsp:include>标签涉及到的2个jsp页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。
include指令是静态引入(编译时引入),涉及到的2个jsp页面会被翻译成一个servlet,其内容是在源文件级别进行合并。
不管是<jsp:include>标签,还是include指令,它们都会把两个jsp页面内容合并输出,所以这两个页面不要出现重复的html全局架构标签,否则输出给客户端的内容将会是一个格式混乱的html文档。
例子:
使用<jsp:include>标签来实现包含页面:
在tomcat的work目录中可以发现会将head.jsp和foot.jsp单独翻译成servlet,这个就是动态包含。
使用include指令实现页面包含:
这时候可以发现work目录中并不会还单独翻译head.jsp页面了,同时我们看看jsp页面翻译的servlet代码:
可以看到在代码中使用静态代码块实现静态页面包含的。
<jsp:forward>标签
<jsp:forward>标签用于把请求转发给另外一个资源。
语法:
page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。
<jsp:param>或<jsp:params>标签
当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给其它资源时,可以使用<jsp:param>标签向这个资源传递参数。
- 语法1
- 语法2
name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签引中可以使用多个<jsp:param>标签来传递多个参数。
<jsp:useBean>、<jsp:setProperty>和<jsp:getProperty>标签
这三个标签是一起用来操作bean对象的,<jsp:useBean>是用来初始化bean对象的,<jsp:setProperty>标签是用来设置bean对象中的属性值,<jsp:getProperty>标签是用来获取bean对象中的属性值的
例子:
同时定义了一个bean对象:com.weijia.domain.Person,其中有一个name属性(一定要有get/set方法才叫属性)。
对于标签<jsp:useBean>,它可以指定在哪个域中创建这个bean对象,它的规则是首先在这个域中查找有没有这个对象,没有就创建,有就直接拿来使用。
对于<jsp:setProperty>标签,可以直接使用value属性设置属性的值,这里面他内部是有一个类型转换的,可以将字符串值转化成8中基本类型的值,其他对象类型的转化是会报错的,比如现在Person类中有一个属性birthday是Date型的,那么这里就不能直接写成这样:
这样系统会报类型转化错误,当然可以直接使用脚本表达式给这个属性值传递一个Date类型的对象,这样就不会错了:
当然也可以使用请求参数来设置属性值:
访问http://localhost:8080/JspDemo/bean.jsp?name=jiangwei就可以进行属性赋值。
同时这里的name属性中的填的是<jsp:useBean>标签中的id值,所以说,在使用get/setProperty标签的时候一定是在useBean标签之后。
EL
简介
EL提供了在jsp脚本编制元素范围外使用运行时表达式的功能。脚本编制元素是指页面中能够用于在jsp文件中嵌入Java代码的元素。它们通常用于对象操作以及执行那些影响所生成内容的计算。JSP 2.0将EL表达式添加为一种脚本编制元素。
基本语法
${ EL Expression},EL表达式是配合JSTL使用的。需要引入JSTL标签库。
示例:
EL 表达式 | 说明 |
${ “Helloworld” } | 输出字符串常量 |
${ str } | 输出字符串变量str的值 |
${ 3 + 2 } | 输出3+2的结果 |
{user["name"] } | 输出user对象的name属性 |
${ sessionScope["user"].name } | 输出session域中user对象的name属性 |
${user.name} | 访问对象user的getName()方法以得到name成员的值 |
${list[1]} | 访问list对象的第二项 |
${map["key"]} | 访问map指定键的值 |
“.”与”[ ]”的相同点和差别
- 相同:都可以访问对象有属性
- 差别:当属性的名字包含有空格,点号等复杂符号时。使用”.”来访问对象有属性将会出现异常
EL 变量
EL存取变量数据的方法很简单,例如${username}的意思是取出某一范围中名称为username的变量,因为并没有指定哪一个范围的username,所以它的默认值会先从Page范围找,假如找不到,再依序到Request、Session、Application范围;假如途中找到username,就直接回传,不再继续找下去,但是假如全部的范围都没有找到时,就回传NULL,当然EL表达式还会做出优化,页面上显示空白,而不是打印输出NULL。
属性范围(JSTL名称) | EL中的名称 |
Page | PageScope |
Request | RequestScope |
Session | SessionScope |
Application | ApplicationScope |
也可以指定要取出哪一个范围的变量:
范例 | 说明 |
${pageScope.username} | 取出Page范围的username变量 |
${requestScope.username} | 取出Request范围的username变量 |
${sessionScope.username} | 取出Session范围的username变量 |
${applicationScope.username} | 取出Application范围的username变量 |
其中,pageScope、requestScope、sessionScope和applicationScope都是EL的隐含对象。
自动转变类型
EL除了提供方便存取变量的语法之外,它另外一个方便的功能就是:自动转变类型。
例如${param.count + 20},假若窗体传来count的值为10时,那么上面的结果为30,之前没接触过jsp可能会认为上面的例子是理所当然的,但是在jsp 1.2之中不能这样做;原因是从窗体所传来的值,它们的类型一律是String,所以当你接收之后,必须再将它转为其他类型,如:int、float等等,然后才能执行一些数学运算,下面是之前的做法:
所以,注意不要和Java的语法(当字符串和数字用+链接时会把数字转换为字符串)搞混淆。
EL 隐含对象
jsp有9个隐含对象,而EL也有自己的隐含对象,EL隐含对象总共有11个。
隐含对象 | 类型 | 说明 |
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类型的值 |
不过有一点要注意的是如果你要用EL输出一个常量的话,字符串要加双引号,不然的话EL会默认把你认为的常量当做一个变量来处理,这时如果这个变量在4个声明范围不存在的话会输出空,如果存在则输出该变量的值。
属性(Attribute)与范围(Scope)
与范围有关的EL隐含对象包含以下四个:pageScope、requestScope、sessionScope和applicationScope。
它们基本上就和jsp的pageContext、request、session和application一样。
必须注意的是,这四个隐含对象只能用来取得范围属性值,即jsp中的getAttribute(String name),却不能取得其他相关信息,例如:
jsp中的request对象除可以存取属性之外,还可以取得用户的请求参数或表头信息等等。
但是在EL中,它就只能单纯用来取得对应范围的属性值,
例如:
要在session中储存一个属性,它的名称为username,在jsp中使用session.getAttribute("username")来取得username的值,但是在EL中,则是使用${sessionScope.username}来取得其值的。
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站台的环境参数(Context),当想取得这些参数
那么就可以直接使用${initParam.userid}来取得名称为userid,其值为mike的参数。
下面是之前的做法:
param和paramValues
在取得用户参数时通常使用一下方法:
在EL中则可以使用param和paramValues两者来取得数据。
这里param的功能和request.getParameter(String name)相同,而paramValues和request.getParameterValues(String name)相同。
如果用户填了一个表格,表格名称为username,则就可以使用${param.username}来取得用户填入的值。
pageContext
可以使用${pageContext}来取得其他有关用户要求或页面的详细信息。
下表列出了几个比较常用的部分:
Expression | 说明 |
${pageContext.request.queryString} | 取得请求的参数字符串 |
${pageContext.request.requestURL} | 取得请求的URL,但不包括请求之参数字符串,即servlet的HTTP地址 |
${pageContext.request.contextPath} | 服务的webapplication的名称 |
${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} | 取得主机端的服务信息 |
这个对象可有效地改善代码的硬编码问题,如页面中有一A标签链接访问一个servlet,如果写死了该servlet的HTTP地址,那么如果当该servlet的servlet-mapping改变的时候必须要修改源代码,这样维护性会大打折扣。
EL算术运算
表达式语言支持的算术运算符和逻辑运算符非常多,所有在Java语言里支持的算术运算符,表达式语言都可以使用;甚至Java语言不支持的一些算术运算符和逻辑运算符,表达式语言也支持。
上面页面中示范了表达式语言所支持的加、减、乘、除、求余等算术运算符的功能,表达式语言还支持div、mod等运算符。
而且表达式语言把所有数值都当成浮点数处理,所以3/0的实质是3.0/0.0,得到结果应该是Infinity。
如果需要在支持表达式语言的页面中正常输出$符号,则在$符号前加转义字符\,否则系统以为$是表达式语言的特殊标记。
EL关系运算符
关系运算符 | 说明 | 范例 | 结果 |
==或eq | 等于 | {5==5}或{5eq5} | true |
!=或ne | 不等于 | {5!=5}或{5ne5} | false |
<或lt | 小于 | {3<5}或{3lt5} | true |
>或gt | 大于 | ${3>5}或{3gt5} | false |
<=或le | 小于等于 | {3<=5}或{3le5} | true |
>=或ge | 大于等于 | {3>=5}或{3ge5} | false |
表达式语言不仅可在数字与数字之间比较,还可在字符与字符之间比较,字符串的比较是根据其对应UNICODE值来比较大小的。
注意:在使用EL关系运算符时,不能够写成:${param.password1} == ${param.password2}或者${${param.password1} == ${param.password2}}而应写成${ param.password1 == param.password2 }。
EL逻辑运算符
逻辑运算符 | 范例 | 结果 |
&&或and | 交集${A && B}或${A and B} | true/false |
|或or | ㅤ | ㅤ |
!或not | 非${! A}或${not A} | true/false |
Empty 运算符
Empty运算符主要用来判断值是否为空(NULL,空字符串,空集合)。
条件运算符
${ A ? B : C}。
JSTL
简介
JSTL是Java中的一个定制标记库集。
jsp标准标签库(JSTL)是一个jsp标签集合,它封装了jsp应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。
jstl 标签库
JSTL一共包含四大标签库:
- core:核心标签库,学习的重点;
- fmt:格式化标签库,只需要学习两个标签即可
- sql:数据库标签库,不需要学习了,它过时了
- xml:xml标签库,不需要学习了,它过时了
除了jsp动作标签外,使用其他第三方的标签库都需要导包。
在使用标签的jsp页面中使用taglib指令导入标签库;下面是导入jstl的core标签库:
- prefix="c":指定标签库的前缀,这个前缀可以随便给值,但大家都会在使用core标签库时指定前缀为c
- uri="http://java.sun.com/jstl/core":指定标签库的uri,它不一定是真实存在的网址,但它可以让jsp找到标签库的描述文件
core标签库
out和set标签
标签 | 说明 |
<c:out value=”aaa”/> | 输出aaa字符串常量 |
<c:out value=”{aaa}” default=”xxx”/> | 当{aaa}不存在时,输出xxx字符串 |
<%request.setAttribute("a","<script></scrip>")%><c:out value="${a }" default="xxx" escapeXml="false" /> | 当escapeXml为false,不会转换<、>,这可能会受到JavaScript攻击 |
<c:set var=”a” value=”hello”/> | 在pageContext中添加name为a,value为hello的数 |
<c:set var=”a” value=”hello” scope=”session”/> | 在session中添加name为a,value为hello的数据 |
remove标签
标签 | 说明 |
<c: remove var="a"/> <c: out value="${a}" default="none"/> | 删除所有域中name为a的数据 |
<c:remove var="a" scope=”page”/> | 删除pageContext中name为a的数据 |
url标签
该标签会在需要重写URL时添加。
表格 | 说明 |
<c:url value="/"/> | 输出上下文路径:/项目名/ |
<c:url value="/" var="a" scope="request"/> | 把本该输出的结果赋给变量a。范围为request |
<c:url value="/AServlet"/> | 输出:/项目名/AServlet |
<c:url value="/AServlet"><c:param name="username" value="abc"/><c:param name="password" value="123"/> | 输出:/项目名/AServlet?username=abc&password=123 |
如果参数中包含中文,那么会自动使用URL编码!
if标签
if标签的test属性必须是一个boolean类型的值,如果test的值为true,那么执行if标签的内容,否则不执行。
choose标签
choose标签对应Java中的if/else结构。when标签的test为true时,会执行这个when的内容。当所有when标签的test都为false时,才会执行otherwise标签的内容。
forEach标签
forEach就是循环标签,forEach标签有多种两种使用方式:
- 使用循环变量,指定开始和结束值,类似for(int i = 1; i <= 10; i++) {}
- 循环遍历集合,类似for(Object o : 集合)
- 遍历集合或数组
- 遍历List
- 遍历Map
forEach标签还有一个属性varStatus,这个属性用来指定接收循环状态的变量名,例如:
这时就可以使用vs这个变量来获取循环的状态了。
- count:int类型,当前已遍历元素的个数
- index:int类型,当前元素的下标
- first:boolean类型,是否为第一个元素
- last:boolean类型,是否为最后一个元素
- current:Object类型,表示当前项目
fmt标签库
fmt标签库是用来格式化输出的,通常需要格式化的有时间和数字。
- 格式化时间
- 格式化数字
自定义标签
步骤
在jsp页面中使用标签就等于调用某个对象的某个方法,例如<c:if test=””>,自定义标签其实就是自定义类一样!
- 定义标签处理类:必须是Tag或SimpleTag的实现类
- 编写标签库描述符文件(TLD),SimpleTag接口是jsp2.0中新给出的接口,用来简化自定义标签,所以现在基本上都是使用SimpleTag;Tag是老的,传统的自定义标签时使用的接口,现在不建议使用它了
SimpleTag接口
SimpleTag接口内容如下:
- void doTag():标签执行方法;
- JspTag getParent():获取父标签;
- void setParent(JspTag parent):设置父标签
- void setJspContext(JspContext context):设置PageContext
- void setJspBody(JspFragment jspBody):设置标签体对象
标签对应的类称为“标签处理类”!
标签的生命周期
- 当容器(Tomcat)第一次执行到某个标签时,会创建标签处理类的实例
- 然后调用setJspContext(JspContext)方法,把当前jsp页面的pageContext对象传递给这个方法
- 如果当前标签有父标签,那么使用父标签的标签处理类对象调用setParent(JspTag)方法
- 如果标签有标签体,那么把标签体转换成JspFragment对象,然后调用setJspBody()方法
- 每次执行标签时,都调用doTag()方法,它是标签处理方法
标签库描述文件(TLD)
标签库描述文件是用来描述当前标签库中的标签的!
标签库描述文件的扩展名为tld,可以把它放到WEB-INF下,这样就不会被客户端直接访问到了。
使用标签
在页面中使用标签分为两步:
- 使用taglib导入标签库
- 使用标签
自定义标签进阶
继承SimpleTagSupport
继承SimpleTagSuppport要比实现SimpleTag接口方便太多了,只需要重写doTag()方法,其他方法都已经被SimpleTagSuppport完成了。
有标签体的标签
标签体内容的可选值:
<body-content>元素的可选值有:
- empty:无标签体
- jsp:传统标签支持它,SimpleTag已经不再支持使用<body-content>jsp</body-content>。标签体内容可以是任何东西:EL、JSTL、<%=%>、<%%>,以及html
- scriptless:标签体内容不能是java脚本,但可以是EL、JSTL等;在SimpleTag中,如果需要有标签体,那么就使用该选项;
- tagdependent:标签体内容不做运算,由标签处理类自行处理,无论标签体内容是EL、JSP、JSTL,都不会做运算。这个选项几乎没有人会使用!
自定义有标签体的标签需要:
- 获取标签体对象:JspFragment jspBody = getJspBody()
- 把标签体内容输出到页面:jspBody.invoke(null)
- tld中指定标签内容类型:scriptless
不执行标签下面的页面内容
如果希望在执行了自定义标签后,不再执行jsp页面下面的东西,那么就需要在doTag()方法中使用SkipPageException。
带有属性的标签
一般标签都会带有属性,例如
其中test就是一个boolean类型的属性。
完成带有属性的标签需要:
- 在处理类中给出JavaBean属性(提供get/set方法)
- 在TLD中部属相关属性
AJAX
简介
是一种用于创建更好更快以及交互性更强的Web应用程序的技术,是基于JavaScript、XML、HTML、CSS新用法。
- JavaScript:更新局部的网页
- XML:一般用于请求数据和响应数据的封装
- XMLHttpRequest对象:发送请求到服务器并获得返回结果
- CSS:美化页面样式
- 异步:发送请求后不等返回结果,由回调函数处理结果
步骤
- 创建XmlHttpRequest对象
- 注册状态监控回调函数
- 建立与服务器的异步连接
- 发出异步请求
如下是一个搜索框提示的JavaScript函数写法。
对应调用的是一个SearchBookAJAXServlet,这里可以自己进行数据的封装,也可以直接调用json,json的使用很简单,String str = JSONArray.fromObject(list).toString();即可。
创建XMLHttpRequest对象时,不同浏览器提供不同的支持。
XMLHttpRequest
属性
- readyState:类型short,只读
- responseText:类型String,只读
- responseXML:类型Document,只读
- status:类型short,只读
方法
- open()
- send()
- setRequestHeader()
- 事件处理器onreadystatechange
将状态触发器绑定到一个函数
- var xmlHttp;
- createXMLHttpRequest()
- xmlHttp.onreadystatechange = processor;,这里的processor是回调函数的方法名
- function processor (){… …}
使用open方法建立连接
open(method,url, asynch)
- 其中method表示HTTP调用方法,一般使用"GET","POST"
- url表示调用的服务器的地址
- asynch表示是否采用异步方式,true表示异步,一般这个参数不写
范例代码:
- xmlHttp.open("POST", "url");
- xmlHttp.open("GET", "url?name=xxx&pwd=xxx");
向服务器端发送数据
- GET方式提交,数据在URL上xmlHttp.send(null);
- POST方式提交
- xmlHttp.setRequestHeader("CONTENT-TYPE","application/x-www-form-urlencoded");
- xmlHttp.send("name=xxx&pwd=xxx");
在回调函数中对数据进行处理:
常用的服务器返回数据格式
- HTML片段
- JSON格式的数据
- XML格式的数据
验证码机制
验证码是由后端随机生成的(后端始终认为前端有可能会被伪造)
- 后端调用相关的绘图第三方类库或是(平台PHP、.NET、Java)系统核心类库进行图片的绘制
- 绘制的那些随机的数字、字母都是后端预先定义好的
- 将绘制的图片url地址通过网络返回给客户端,然后客户端使用img标签去引用这个验证码的地址
- 后端在绘制完毕验证码之后,随机选择生成的字母不能丢弃,而是需要保存到Session中
- 当客户端输入验证码完毕后,表单提交到服务器,后端服务器拿到客户端提交的验证码,与服务器端Session中的验证码进行比较
MD5
- 作者:青山🌊
- 链接:http://cxuan.me/article/java-ee-jsp
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。