使用servlet+JDBC,我们基本可以做出大部分web项目了。可是有时候因为页面数据内容复杂又很多,不可能将所有数据都写在该方法里,因此就需要有另外一个方法将HTML语句直接输出。这时就引入了JSP技术。前一天我们说到tomcat服务器只能去找servlet文件执行,那它又怎么去执行jsp呢,其实是tomcat提供了一个JspServlet类,这是JSP的引擎,它将jsp文件转换成servlet文件,然后tomcat才去调用执行,所以我们也可以说本质上讲JSP也是servlet。
一、JSP的语法
1、page指令
Jsp在转换成servlet的时候,需要遵循一些规范,这就是每个jsp文件的第一行显示的内容。我们称之为page指令: <%@ page 属性名=“属性值” 属性名=“属性值” ....... %>,其属性有以下一些。
a、language:声明转换的语言,通常这个值"java";
b、import:声明转换后的java文件所依赖的java包,不同的包用,隔开;
c、pageEncoding:设置当前jsp文件所要保存的格式,一般“pageEncoding="UTF-8"”;
d、contentType:浏览器响应格式编码,一般“contentType="text/html; charset=UTF-8"”,这个和servlet中的setContentType里面是一样的;
e、extends:转换后的java文件要继承的java文件;
f、session:转换后的servlet是否开启session支持;
g、errorPage:设置jsp运行错误后跳转的页面。
这里面很多时候eclipse创建jsp文件的时候直接就写好了。
2、JSP中的Java代码
在学习servlet的时候,我们写的代码都是java,如果我们要输出HTML语言,就需要getWriter方法。那么因为jsp是写HTML+css的servlet,那么如果我们想写Java语言呢,要怎么处理呢?
a、<% java代码块 %>,这就是在jsp文件中写java的格式,我们称为局部代码块。相应的也就有全局代码块,这里就不细说了。
b、上面是在逻辑层面的判断等等,还有需求:java里面的变量或者数据需要通过HTML展示,而且这个变量或者数据是变化的。这个时候就需要脚本段语句:<%=变量名或者方法%>。
3、文件路径,在jsp中也会有表达文件路径的需求,一般情况下有两种方式:
a、绝对路径表示:/项目名/项目文件路径
b、另外一种方式是在头部配置语句中,和head里面加入两行java语句,将绝对路径名拼接出来,这样就可以省去项目名,直接用项目文件路径表示。
4、自此,我们把jsp的基本语法就算是学完了,但是我们会发现三个问题:(1)代码冗余,如果jsp里面有很多重复代码,我们有没有类似java提取出来方法这种形式减少冗余代码呢?(2)在servlet中,request和response对象都是由tomcat服务器自动创建,那么jsp有没有提供类似的常用对象呢?不需要项目自己去创建。(3) 至少目前我们还是没能把java和HTML代码分开,还是硬编码,在servlet里面主要关注java代码,但是HTML也是混在一起写,而jsp能支持HTML了,又需要引入java代码,有没有一种办法将他们分开,各司其职呢,servlet只管java里面的逻辑以及后台数据传输,jsp主要是页面显示。
二、静态引入和动态引入
最常见的jsp页面中的代码冗余就是网页的头和尾,比如网页中最常见的友情链接或者网站备案号邓信息,每个页面都有,这是我们就会将这些公共信息提取,重新编写一个jsp文件。一般情况下,公共信息组成的jsp文件中没有java代码块的话一般我们使用静态引入,它在转换成servlet的时候不会单独生成java文件;如果公共信息组成的jsp文件有java代码,建议使用动态引入,这样是在做servlet转换的时候生成两个java文件。但是这个使用方式并不是绝对的,两个都可以使用的情况很常见。
1、静态引入指令:Include指令,格式为<%@include file="引入的jsp文件名" %>。
2、动态引入指令:Include指令,格式为
如下建立一个新的jsp文件描述网站的备案版权等信息,动态引入和静态引入可以达到相同效果:
三、JSP的内置对象:jsp的内置对象我们可以理解为,jsp在转换成servlet的时候,tomcat服务器自动创建了的对象,不需要我们再去创建就可以直接使用。
request:封存当前请求数据对象,由tomcat创建; response:响应对象,类似servlet可以设置响应数据,可以转发或者重定向; pageContext:页面上下文对象,封存了jsp的运行信息;session:用来存储用户不同请求的相同数据;application:相当于servletContext对象;out:响应对象,jsp独有,有缓冲,效率高于response;page:代表当前jsp页面的对象,相对于java文件中的this;exception:异常对象;config:相对于servletConfig对象,用来获取web.xml里面的配置数据。其中有四个内置对象非常重要,且我们要知道他们里面数据的作用范围,也就是作用域:
1、pageContext:当前页面,解决了当前页面的数据共享问题,获取其他内置对象;
2、request:一次请求的servlet的数据共享,通过请求转发将数据流转给下一个servlet;
3、session:一次会话,一个用户的不同请求的数据共享,将数据从一次请求流转到另一次请求;
4、application:项目内不同用户的数据共享问题,将一个用户的数据流转到其他用户。
四、EL表达式与JSTL
我们发现jsp中混入java代码主要的两种形式分别问局部代码块和脚本段语句,因此出现了两种技术分别取处理他们:EL表达式和JSTL,从而能够将servlet和jsp的功能分开,各司其职(其实不能全部解决,只是最常用的部分得到了解决)。
1、EL表达式:简化获取作用域对象中的数据的写法,原来用的是<%=变量名或方法%>,这个碰到比较复杂的对象数据的时候,需要导入java依赖,需要类型转换等等操作,而EL表达式都不需要,其格式为:${表达式}。注意EL表达式不能获取普通对象的数据,只能获取作用域对象的数据,通俗来讲就是jsp内置对象pageContext、request、session、application中的数据。那么我们可以分别看看这四个对象中的数据用EL表达式怎么表达的?
a、request对象中的数据:表达式为param.键名 (返回键名对应的value值) 或者paramValues.键名 (这个返回的是一个value值的数组);其他三个对象比照相同的方式。
b、上面是从浏览器中传来的数据,还有一种是java后台存入这些对象中的数据,比如通过setAttribute()方法存入的数据,则通过${键名}直接返回值即可。这里面需要注意的是,如果存入的数据是字符串,则返回的就是字符串;如果存入的是对象,没有重写toString方法就返回对象地址;如果对象的属性还是一个对象,可以用这种方式${键名.属性名.属性名.属性名};如果存入数据是一个list集合,则表达式是${键名[角标].属性名};如果是map集合,则表达式为${键名.map集合里面的键名}。
2、JSTL:
JSTL就是解决局部代码块问题的,当然也是部分解决。因为JSTL并不是jsp自带的技术,所以需要导入依赖包:jstl-1.2.jar;解决方法是是通过jstl提供的标签来代替java代码,因此jstl里面一共有5个标签库:核心标签库,格式化标签库,SQL标签库,函数标签库,XML标签库。
接下来就是要在jsp头部进行配置,配置格式:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>;其中taglib就是jsp的一个指令,用来配置外部引入文件的,URI是jstl文件提供的地址,prefix是指以什么作为开头来标明这些标签,什么意思呢,就是里面的标签和java里面类似,为了区分它是jstl,所以要选定一个标签,那么就认为定义了c作为其标签的前缀,算是约定俗成。
a、设定数据和输出、删除标签:c:set和c:out 、c:remove,其中c:set标签的属性有var表示键名,value表示值,scope表示作用域对象,c:out标签的属性有value表示值,default表示默认值;上面一段代码我们使用标签书写做一个对比。
b、逻辑标签,c:if标签,其属性test的值相当于java的判断语句中的布尔表达式,还有c:choose c:when标签联合使用,相对于多分支选择语句。
上述三段代码的结果对比如下:
c、循环标签:这是最重要的一个标签,我们在项目开发中基本一定会遇到。
上面的是常量循环,但是项目中最常用的是动态循环,我们先看一个list集合的动态循环:
其表达的意思就是我们先创建了一个包含“小美、小丽、小花”三个字符串的list集合,然后要把这个集合放入request作用域,这一步一定不要忘了,因为EL和JSTL都是只能作用于作用域。然后我们就用c:forEach标签将list的值都拿出来,使用了items属性,它表达的意思是这个list集合存储在request对象中的键名,var表达的意思就是每循环一次,都会把list集合的值存入var里面,因此要想取出list的值,使用EL表达式取出var里面的值就可以了。
Map集合是在web项目开发中经常遇到的,以键值对的形式将存储了后台传来数据的对象存在Map集合中,然后再Jsp文件中以键名的形式访问这些数据,然后通过逻辑标签和循环标签进行控制操作,并且通过HTML+CSS将数据美化,就变成我们通常想要的页面了。
如果你希望页面有更好的动作,数据传输方式有更大的变化,那就需要学习JQuery和Ajax技术了。
这里我们还可以思考一个问题,既然JDBC有一套框架方便我们更好的操作数据库,那么servlet是不是应该也有一套这样的框架呢?