Java Web、Tomcat、Servlet、JSP

1.web概述

1.1.WEB概念

1.1.1.Web概念
WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源。
1.2.web资源分类
1.2.1.静态web资源(如html 页面):
指web页面中供人们浏览的数据始终是不变。如Html、CSS、javaScript
1.2.2.动态web资源:
2.指web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同。如JSP/Servlet、ASP、PHP
3.在Java中,动态web资源开发技术统称为Javaweb,我们课程的重点也是教大家如何使用Java技术开发动态的web资源,即动态web页面。
2.Web服务器
2.1.Servlet容器、web容器、web服务器
2.1.1.Servlet容器:
java中的动态资源开发技术为Servlet/JSP,sun公司定义了Servlet/JSP的技术规范,遵循这样规范就可以写出对应的Servlet、JSP程序,但是Servlet、JSP本身不能直接运行,需要运行他们的环境,于是有不同的厂商分别按照Servlet/JSP规范的要求开发了对应的运行环境,这样的能够运行Servlet/JSP的环境就叫做Servlet容器。
2.1.2.web容器:
web资源按照一定的规则整合起来组成能够被web访问的应用程序就叫做web应用,web应用运行也需要一定的环境。能够运行web应用的环境叫做web容器。
web容器的概念通常要大于Servlet容器,Servlet容器通常都是web容器,但是web容器不一定是Servlet容器,因为运行ASP、PHP的服务器是web容器,但是不能运行Servlet所以不能叫Servlet容器。
2.1.3.web服务器
web容器/Servlet容器具体来说就是web服务器,学习web开发,需要先安装一台web服务器,然后再在web服务器中开发相应的web资源,供用户使用浏览器访问。
注意:这里所说的服务器不是指服务器硬件资源,而是指服务器软件。
2.2.常见的web服务器
2.2.1.WebLogic
WebLogic是BEA公司的产品,是目前应用最广泛的Web服务器,支持J2EE规范。
如图-1所示:

2.2.2.图-1
2.2.3.WebSphere
WebSphere是IBM公司的产品,支持J2EE规范,使用的也不少。
如图-2所示:

2.2.4.图-2
2.2.5.Tomcat
在小型的应用系统或者有特殊需要的系统中,可以使用一个免费的Web服务器:Tomcat,该服务器支持全部JSP以及Servlet规范
虽然是免费开源的服务器,并且不能完全支持J2EE规范,但是它免费、轻量等特性让他仍然十分受到欢迎。我们学习阶段就是使用tomcat作为服务器。
如图-3所示:

2.3.图-3
2.4.tomcat的下载安装配置
2.4.1.下载tomcat
tomcat是Apache开源组织开发并无偿发布的免费开源的servlet容器,任何人都可以在他的官网上免费获取该服务器的拷贝及源代码,下载地址为:http://tomcat.apache.org/
如下图位置提供了各个版本的tomcat下载,如图-4所示:

图-4
下载时请注意,不同版本的区别:
.zip为压缩版,解压后即可使用,注意区分操作系统是32位还是64位。
.exe为安装版,安装后使用,注意区分操作系统是32位还是64位。
安装版和解压版基本相同,只不过解压版解压后需要配置环境变量,安装版不需要。
.tar.gz为linux版本.
如图-5所示:

图-5
我们这里选择解压版下载。
2.4.2.安装tomcat
将解压版.zip包拷贝到要安装的目录下,解压。
注意,在tomcat的安装目录中不允许有空格和中文字符! 其实不止tomcat,绝大部分开发相关的软件都对中文和空格支持有问题,所以以后在安装任何软件时都要养成一个习惯:路径中绝对不要有中文和空格!
打开[tomcat]/bin目录,发现其中包含大量.bat程序,找到startup.bat,双击启动发现cmd窗口一闪而过。这是因为启动报错后cmd窗口关闭了自己,所以我们只看到一闪而过的窗口。
在windows的命令中启动cmd窗口,进入[tomcat]/bin目录,执行startup.bat,发现报错,如图-6所示:

图-6
简单阅读后发现提示,没有配置JAVA_HOME环境变量,因为tomcat本身也是java写的程序,运行需要jdk的支持,所以需要通过JAVA_HOME环境变量通知tomcat启动时用的jdk在哪。
要注意的是,不同版本的tomcat要求的jdk的版本是不相同的。
tomcat6 需要 jdk5.0以上版本。
tomcat7 需要 jdk6.0以上版本。
tomcat8 需要jdk7.0以上版本。
所以只需要配置环境变量JAVA_HOME指向tomcat安装的根目录即可,如图-7所示:

图-7
再次启动tomcat,发现可以正常工作。
看到类似界面说明tomcat正常的启动起来了。如图-8所示:

图-8
打开浏览器,访问 http://localhost:8080可以看到如下画面,如图-9所示:

2.4.3.图-9
2.4.4.安装常见问题
(1)端口占用问题:
可以在cmd窗口中使用netstat -ano命令查询出哪个程序占用了端口,结束这个程序后再启动tomcat即可
(2)Catalina_home环境变量:
用来指定启动的tomcat的位置,如果没有配置过这个环境变量,则在哪个tomcat中启动,则该tomcat被启动,如果这个环境变量被配置过,无论在哪个tomcat中启动,最终启动的都是该环境变量指定的tomcat
2.4.5.关闭服务器
在[tomcat]/bin 目录下 双击shutdown.bat即可关闭服务器。
直接关闭tomcat窗口也可快速关闭服务器,但是这种做法服务器没有执行正常的关闭流程,有时会造成下次启动报错,遇到这种情况只要再执行一次shutdonw.bat即可解决问题。
2.5.tomcat的目录结构
bin — 存放tomcat启动和关闭用的bat文件
conf — 存放tomcat配置文件的目录
lib — 存放tomcat运行时依赖的jar包
logs — 存放tomcat运行时产生的日志文件的
temp — tomcat自己用来存放运行过程中产生的临时文件的目录,不需要我们管理,tomcat自动管理
webapps — 这是和开发人员关系最大的目录,是用来存放web应用的目录,我们开发的web资源最终要保存在这个目录下,外界就可以访问了
work — tomcat的工作目录,tomcat在运行时产生的工作文件存放在这个目录
conf/server.xml–tomcat的核心配置文件
练习:修改tomcat/conf/server.xml Connector 中的 prot 将tomcat监听的端口号从8080 转为 80
操作:找到tomcat安装目录D:\ProgramFiles\tomcat7\conf,打开server.xml文件,修改端口port为“80”。

2.6.tomcat中的基本概念
2.6.1.虚拟主机
tomcat中可以配置管理多个网站,外界在访问这些网站时,并不知道这些网站是运行在同一个tomcat中的,感觉起来就像他们各自运行在各自的虚拟出来的主机中一样,所以将一个网站交给tomcat去管理的过程称为为tomcat配置一台虚拟主机。
2.6.2.web应用
一个虚拟主机包含着许多web资源,但这些web资源不能直接交给虚拟主机管理,需要按照功能将web资源按照一定的目录结构组织成web应用再交给虚拟主机去管理
2.6.3.虚拟路径映射
将web应用交给虚拟主机管理,为web应用真实路径配置一个对外访问的虚拟的路径的过程叫做web应用的虚拟路径映射。
以上概念如图-10所示:

图-10
2.7.web应用目录结构
2.7.1.web应用目录结构
web资源需要按照一定方式组织成web应用才能交给虚拟主机去管理。web应用的目录结构如下:
mail — web应用所在的目录
|
|–html css js jsp
|
|–WEB-INF
|–classes
|
|–lib
|
|–web.xml
(1)静态web资源和jsp可以放置在web应用的根目录下,在web应用根目录下的资源,浏览器可以直接访问
(2)WEB-INF目录可以没有,但是一旦有了,必须符合结构,放置在这个目录中的资源会被保护起来,浏览器是没有办法直接访问的
(3)WEB-INF/classes存放动态web资源的 class文件的
(4)WEB-INF/lib 存放class们依赖的jar包的
(5)WEB-INF/web.xml整个web应用的核心配置文件,这个web应的所有配置都要在这里进行 (配置web应用的主页 配置Servlet映射 配置监听器 配置过滤器…)
练习:新建game应用,包含index.html 和 news.html,并在web.xml中将index.html配置为主页。
2.8.web应用配置虚拟路径映射的三种方式
2.8.1.方式1
在server.xml中的标签中配置标签,其中的path属性指定虚拟路径(浏览器访问的路径),docBase指向真实的web应用目录。
注意,这种方式配置的web应用需要重启服务器后才会生效。但享受最高优先级。
如果将path配置为空,则当前web应用称为虚拟主机的缺省web应用。

如图-11所示:

图-11
2.8.2.方式2
在[tomcat]/conf/[engin]/[host]目录下新建一个xml文件,其中文件名为成当前web应用虚拟路径,在xml文件的内部,用标签配置docBase指定真实路径,注意这种配置方式不需要指定path虚拟路径,因为文件名就是path.
这种方式不需要重启服务器即可起作用。
如果将xml文件名改为ROOT.xml则当前web应用成为当前虚拟主机的缺省web应用。
如图-12所示:

图-12
2.8.3.方式3
直接将web应用放置到虚拟主机管理的目录中(D:\ProgramFiles\tomcat7\webapps)。虚拟主机自动管理该目录,文件夹的名字成为web应用的虚拟路径。
这种方式不需要重启服务器即可起作用。
如果将文件夹的名字改为ROOT,则当前web应用成为缺省web应用。
localhost虚拟主机管理的是webapps目录,所以将应用放置到webapps目录下通过localhost主机就可以直接访问了。
如图-13所示:

图-13
2.9.配置虚拟主机
2.9.1.配置虚拟主机
想要配置一台虚拟主机,只需要在[tomcat]/server.xml的标签下配置标签即可:

其中“虚拟主机管理的目录”是为当前虚拟主机配置一个虚拟主机管理的目录,可以将web应用放置到该目录下,虚拟主机就会自动管理该web应用了。
如图-14所示:

图-14
此时通过浏览器访问http://www.baidu.com发现无法访问。
这是因为还没有配置dns服务器。
2.9.2.DNS服务器
网络中是通过ip来区分不同的主机的,浏览器如何知道www.baidu.com对应的主机的ip呢?这里就是dns服务器在起作用了。
互联网上有一些专门将域名翻译为对应主机ip的服务器叫做dns服务器(域名解析服务器)专门进行域名到ip的翻译工作。
如果我们想要让www.baidu.com能够访问当前虚拟主机,还需要到dns服务器中进行配置,将www.baidu.com和本机ip地址进行绑定才可以。
但是dns是不能随意修改的!那我们如何进行测试呢?
2.9.3.Hosts文件
好在c:/windwos/system32/drivers/etc/hosts文件可以模拟dns的功能,浏览器在访问dns之前会首先检查该文件,如果这个文件中配置过域名ip映射,则会直接使用而不再去找dns服务器了。所以我们可以在hosts文件中进行如下配置,如图-15所示:

图-15
再通过浏览器访问,发现成功访问了我们配置的虚拟主机中的web应用。
2.9.4.综合练习
配置www.163.com虚拟主机,以三种方式配置web应用,并选择一种配置为缺省web应用,并且配置web应用的主页,最终实现,直接访问www.163.com时能够显示主页的内容。
2.10.其他相关
2.10.1.打war包
web应用是一个文件夹,可以将文件夹形式的web应用打成一个war包,减少体积同时更方便操作。
在cmd窗口中进入应用目录,使用jar -cvf news.war * 即可将当前目录下的内容打成 news.war包
将war包直接丢到虚拟主机管理目录下,发现会自动解压成web应用。十分方便。
2.10.2.通用web.xml 通用context.xml
在[tomcat]/conf目录下有一个web.xml和context.xml文件,整个服务器内所有的web.xml可以认为继承自该web.xml。整个服务器中的可以认为继承自该context.xml中配置的,所以如果有一些通用配置不希望每次都具体配置一次,可以在这里配置。
4.Myeclipse环境下整合JDK、TOMCAT
3.3.1.Myeclipse概述
3.1.1.Myeclipse概述
Myeclipse是基于Eclipse的一个javaweb集成开发环境。在Eclipse基础上增加了很多和javaweb开发相关的插件,可以大大提高开发效率。
3.2.Myeclipse配置
3.2.1.为Myeclipse配置JDK
Myeclipse可以帮我们管理JDK。我们可以将自己的jdk交给Myeclipse管理,供开发使用。
步骤一:在菜单中选择window->preferences
如图-15所示:

图-15
步骤二:在弹出的选项卡中选择java->installed jres选项卡。
我们发现Myeclipse已经自带了一个JDK,但是强烈建议不要使用这个默认的JDK,这是一个不完整的JDK,经常会导致一些莫名奇妙的问题。我们导入自己安装的jdk使用。
如图-16所示:

图-16
步骤三:点击Add…->StandardVM弹出如下界面, 点击Directory…选择要导入的jdk所在的文件夹,确定导入。
如图-17所示:

图-17
步骤四:最终成功导入了jdk,然后勾选新导入的jdk,确定即可将新导入的jdk设置为Myeclipse默认jdk。
如图-18所示:

图-18
3.2.2.在Myeclipse中整合tomcat
Myeclipse同样可以帮我们管理tomcat。
步骤一:选择window->preferences->myeclipse->server->Tomcat->tomcat x.x点击Browse…选择要导入的tomcat。并将状态设置为Enable,启用该tomcat。
如图-19所示:

图-19
步骤二:打开JDK选项,指定tomcat要使用的JDK。
如图-20所示:

图-20
步骤三:打开launch选项,设置tomcat工作模式。
其中debug mode为调试模式,该模式下tomcat会响应断点调试,便于调试程序。
Run mode为运行模式,该模式下忽略所有断点。
所以开发阶段使用debug mode,开发完成到真正上线环节时,tomcat要运行在run mode模式。
如图-21所示:

图-21
完成以上步骤后,我们就将tomcat交给了Myeclipse去管理。
Myeclipse提供了使用tomcat的快捷键。如图-22所示:

图-22
左边为部署按钮,可以将Myeclipse开发的web应用拷贝到tomcat/weapps目录下,即直接交给localhost虚拟主机管理。
右边为服务器管理按钮,从其中可以找到刚才配置的tomcat服务器,实现对服务器的开启、关闭操作
3.2.3.Myeclipse中开发web应用
在File->New->WebProject创建一个新的web工程。如图-23所示:

图-23
其中Project Name指定当前工程名称。
Source folder指定工程中源代码目录。
Web Root Folder工程中会维护一个web应用目录结构,此选项指定目录名称。
Context root Url web工程开发完成后可以通过Myeclipse发布到tomcat中webapps目录中,此选项指定发布到tomcat时web应用的名称。
J2EE specification level 要使用的javaee版本。
如图-24所示:

图-24
配置好确定后一个web应用工程就创建出来了。
Src目录放置源码,此处写的.java会被自动编译,编译出来的class会被放置到WebRoot/classes目录下。
如图-25所示:

图-25
WebRoot目录维护了一个web应用结构,Web应用开发完成后可通过发布工具发布到tomcat,所谓的发布其实就是将WebRoot下的所有东西拷贝了一份到tomcat/webapps/[web应用名称] 目录下,这样相当于将该web应用配置到了localhost虚拟主机中。
通过localhost虚拟主机就可以访问该web应用了。
如图-26所示:

5.图-26
6.EasyMall开发环境搭建
6.1.搭建EasyMall开发环境
6.1.1.搭建EasyMall开发环境
首先我们来创建一个web工程,开始开发EasyMall。如图-27所示:

图-27
之前在学习Servlet的过程中都是使用Myeclipse自带的发布功能进行发布的。这种发布方式只能将应用发布到localhost虚拟主机中,这样一来我们只能通过http://localhost/EasyMall的方式来访问了。如图-28所示

图-28
这不是我们想要的方式,所以我们不能使用这种发布的方式。
我们希望英才商城是一个独立的站点,这就要为tomcat配置一台虚拟主机并将当前web应用并配置为这台虚拟主机的缺省web应用。
首先我们来配置虚拟主机。
找到tomcat/conf/server.xml,在Engin标签中进行配置,增加一台虚拟主机。这台虚拟主机,我们不需要该虚拟主机管理任何目录所以只配置一个name属性即可,docBase不进行配置。如图-29所示:

图-29
接着我们还需要到DNS服务器中进行ip地址和虚拟主机的映射。但是DNS是不可能随意更改的。我们利用本机Hosts文件模拟DNS服务器功能。
找到Hosts文件,在其中进行配置
虚拟主机配置完成,将当前web应用配置给这台虚拟主机,成为这台虚拟主机的缺省web应用。
为一台虚拟主机配置web应用共有三种方法。我们选择第二种方式。
在tomcat/conf/[Engin]/[Host]/下创建一个xml文件,将文件名配置为ROOT,则当前web应用称为缺省该虚拟主机的缺省web应用。打开该xml文件在其中配置标签,其中docBase指向Myeclipse工程中的WebRoot目录,这样,虚拟主机就直接管理了该目录,我们开发完成后直接就可以访问。如图-30所示:

图-30
启动服务器,经测试,可以直接通过http://www.easymall.com访问当前web应用了。
7.HTTP概述
7.1.http概述
7.1.1.什么是http协议
网络通信中存在不同的主机、网络、设备,需要遵循一套统一的通信协议才可以有效的进行通信。
HTTP协议就是一套基于tcp/ip协议的应用层协议
它规定了客户端(通常是浏览器)和服务器之间的通信方式。
7.1.2.基本原则
HTTP协议基于请求响应模型
一次请求对应一次响应
请求只能是客户端发出服务器端只能被动的等待请求,做出响应。
7.1.3.工具
如何观察http协议呢?这里推荐一个ie浏览器的插件,HTTPWatch,可以通过他十分方便的观察http协议的工作过程。如图-31所示:

图-31
8.HTTP协议详解
HTTP协议分为HTTP请求和HTTP响应
8.1.HTTP请求
8.1.1.HTTP请求结构
一个典型的HTTP请求分为 一个请求行 若干请求头 一个空行 实体内容
8.1.2.一个请求行
GET /books/java.html HTTP/1.1
请求方式:一共有7种请求方式(:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE),但是真正使用的只有两种 GET POST,其他五种很少使用。
POST和GET之间的区别:请求参数的提交方式不同,GET请求请求参数位于URL后面,所能传输的请求参数最大不超过1KB,安全性比较低.POST提交请求参数位于请求的实体内容中,没有大小限制,也比较安全
只有当一个表单method明确被指定为POST时,才是POST提交,其他情况下都是GET提交.
请求的资源:/books/java.html
所遵循的协议:HTTP/1.1
8.1.3.若干请求头
http协议中请求头非常多,下面列出常见的请求头及其功能:
Accept: text/html,image/*
– 通知服务器当前浏览器可以接受那些格式的数据
Accept-Charset: ISO-8859-1
– 浏览器可以接受的字符集编码
Accept-Encoding: gzip,compress
– 浏览器可以接受的压缩格式
Accept-Language: en-us,zh-cn
– 浏览器接受的语言环境,和国际化相关的头
Host: www.tedu.cn:80
– 需要访问的虚拟主机的名称
If-Modified-Since: Fri, 17 Feb 2017 18:23:51 GMT
– 这是和缓存机制相关的头
Referer: http://www.tedu.cn/index.jsp
– 这是和防盗链相关的头,对当前资源的访问来自哪个页面的超链接
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) – 客户端的基本信息
Cookie
– 和cookie相关的头
Connection: close/Keep-Alive
– 是否继续保持连接
Date: Fri, 17 Feb 2017 18:23:51 GMT
– 当前发送请求的时间
8.1.4.一个空行
空行的作用为分割请求头和实体内容。
8.1.5.实体内容
实体内容中为需要传递给服务器的内容数据。
8.2.HTTP响应:
8.2.1.HTTP响应结构
一个典型的HTTP响应分为 一个状态行 若干响应头 一个空行 实体内容。
8.2.2.一个状态行
HTTP/1.1 200 OK
所遵循的协议号:HTTP目前分为1.0和1.1两个版本,其中1.0每次请求都要新建连接,响应结束后断开连接,连接不会复用效率较低。1.1版本在一次请求结束后会保持连接一段时间,下次再次请求时可以复用连接,提高了效率。
状态码:是3位的十进制数,通过不同的状态码表示服务器对请求的不同处理结果。响应状态码分为5类。

状态码
100~199 表示接收的请求正在处理
200~299 表示成功接收请求并已完成整个处理过程,常用200
300~399 需要进行附加操作以完成请求。例如: 请求的资源已经移动一个新地址,常用302、307和304
400~499 客户端的请求有错误,常用404
500~599 服务器端出现错误,常用 500
100 表示客户必须继续发出请求
200 表示成功处理完成请求
204(无内容) - 资源有空表示
301(Moved Permanently) - 资源的URI已被更新
302 表示请求重定向
303(See Other) - 其他(如,负载均衡)
304 表示通知浏览器使用缓存中的资源
307 表示表示申明请求的资源临时性删除
400 (bad request)- 指代坏请求(如,参数错误)
404 找不到资源
406 (not acceptable)- 服务端不支持所需表示
415 表示请求资源不支持请求项目格式;
416 表示请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段;
417 表示服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求
500 表示服务器产生内部错误.
503 (Service Unavailable)- 服务端当前无法处理请求

原因叙述:一个字符串描述原因。
8.2.3.若干响应头
http协议中响应头头非常多,下面列出常见的响应头及其功能:
Location: http://www.tedu.cn/index.jsp
– 配合302使用实现请求重定向
Server:apache tomcat
– 服务器的基本信息
Content-Encoding: gzip
– 服务器发送的数据使用的压缩格式
Content-Length: 80
– 服务器发送的数据的大小
Content-Language: zh-cn
–服务器发送的数据使用的语言环境 国际化相关的头
Content-Type: text/html; charset=GB2312
– 服务器发送的数据是什么格式的,如果是字符格式的数据,则还可以通知服务器发送的数据使用的是什么编码,浏览器会根据这个头指定的编码决定使用哪个编码来打开收到的数据
Last-Modified: Fri, 17 Feb 2017 18:24:11 GMT
– 和缓存相关的头
Refresh: 1;url=http://www.tedu.cn
– 定时刷新相关的头,通知浏览器,过几秒后自动刷新访问哪个地址
Content-Disposition: attachment;filename=aaa.zip
– 通知浏览器以附件的形式打开发送过去的数据,是和文件下载相关的头
Set-Cookie:SS=Q0=5Lb_nQ; path=/search
– 和Cookie相关的头
Expires: -1
– 通知浏览器是否缓存
Cache-Control: no-cache
– 通知浏览器是否缓存
Pragma: no-cache
– 通知浏览器是否缓存
–之所以一个功能有三个头,是因为历史原因.所以为了网页的兼容性考虑,通常这三个头要一起使用
Connection: close/Keep-Alive
– 是否保持连接
Date: Fri, 17 Feb 2017 18:24:11 GMT
8.2.4.-- 响应时的时间
8.2.5.一个空行
空行的作用为分割响应头和实体内容。
8.2.6.实体内容
实体内容中为服务器发送回的内容数据。
//class org.apache.catalina.core.ApplicationHttpRequest
System.out.println(req.getClass());
1.Servlet概述
1.1.Servlet概述
1.1.1.Servlet是什么
Servlet是sun公司提供的一门用于开发动态web资源的技术。
按照这套规范写出来的Servlet可以放置到web应用中在Servlet容器中运行。
1.1.2.开发Servlet步骤
想要开发一个Servlet只需要两个步骤:
(1)写一个类实现javax.servlet接口。
(2)在web.xml中为servlet配置对外访问路径。
2.开发第一个Servlet
2.1.写一个类实现Servlet接口
2.1.1.Servlet接口api
接下来我们就手动编写一个Servlet感受一下Servlet开发的过程。
我们用记事本,写一个类实现Servlet接口,我们打开api发现如果直接实现Servlet接口需要实现如下方法,如图-1所示:

图-1
简单介绍下其中重要方法:
init(ServletConfig config)
初始化方法,会在Servlet被创建出来后立即执行,做一些初始化的工作
destroy()
销毁方法,会在Servlet被销毁之前执行,做一些善后工作
service(ServletRequest req, ServletResponse res)
服务方法,每当有请求访问Servlet时,此方法执行,处理请求的代码要写到这个方法里。
2.1.2.GenericServlet抽象类
我们发现这个接口中方法太多了,其实我们可以直接继承Servlet接口的一个默认实现了GenericServlet类,如图-2所示:

图-2
通过观察api,我们发现GenericServlet是个抽象类,实现了Servlet接口中的大部分方法,唯独service方法没有做实现,我们继承GenericServlet需要实现这个Service方法在其中写处理请求的代码。如图-3所示:

图-3
在记事本中编写如下代码,注意写的过程中需要导入包。如图-4所示:

图-4
我们输出当前时间到客户端,service方法有两个参数,ServletRequest代表HTTP请求,ServletResponse代表HTTP响应,我们想要获取客户端发送过来的信息时可以找ServletRequest,现在需要向客户端发送数据就可以使用ServletResponse对象。
通过查询ServletResponse对象的api,发现其中有获取写出数据的流的方法,通过这个方法获取流就可以将数据发送给浏览器。代码如图-5所示:

图-5
编写好java文件后,需要进行编译,如图-6所示:

图-6
在编译的过程中发现少了开发包,这是因为我们现在开发的是javaee项目,需要将javaee相关的开发包加入classpath环境变量,这个包在tomcat的支持包中存有,将其加入classpath环境变量即可。如图-7所示:

图-7
再次编译。
报出了警告,是因为Date的toLocaleString方法已经过时,但是我们不关心,到此编译已经完成。编译成功后将包拷入web应用的WEB-INF/classes目录下,如图-8所示:

2.2.图-8
2.3.配置Servlet的对外访问路径
2.3.1.在web.xml配置servlet
我们还需要在web.xml中为这个Servlet配置一个对外访问路径。
打开web.xml文件,在根标签下进行如下配置,如图-9所示:

图-9
其中,servlet-class中为配置的Servlet类的全路径名。
servlet-name是为该servlet配置的名称,此名称没有特殊要求,为了便于识别此处取名和类名相同。
url-pattern是为该名称的servlet配置对外访问路径,浏览器可以通过该路径访问此servlet。
启动服务器,通过浏览器访问,如图-10所示:

图-10
发现成功输出了当前时间,多次刷新页面发现每次显示的都是最新的时间,不同的人在不同的时间看到的结果不同,说明这确实是一个动态web资源。
3.Servlet的调用过程和生命周期
3.1.servlet的调用过程
3.1.1.Servlet调用过程图
当我们在访问这个Servlet时,是如何看到时间输出的呢?整个过程是如何工作的呢?我们画图解释,如图-11所示:

图-11
(1)在浏览器输入地址,浏览器先去查找hosts文件,将主机名翻译为ip地址,如果找不到就再去查询dns服务器将主机名翻译成ip地址。
(2)浏览器根据ip地址和端口号访问服务器,组织http请求信息发送给服务器。
(3)服务器收到请求后首先根据Host请求头判断当前访问的是哪台虚拟主机。
(4)服务器根据http请求头中的请求URI判断当前访问的是哪个web应用。
(5)服务器根据http请求头中的请求URI判断当前访问的是web应用中的哪个web资源。
(6)检查web应用的web.xml文件,如果根据路径找到具体的servlet处理类的全路径名交给该servlet处理,如果找不到就交给缺省servlet处理。
(7)这个过程中浏览器只知道自己发出来http请求,不久就收到了http响应,浏览器不知道也不关心服务器内部是如何处理的。浏览器和服务器之间的关系是非常单纯的,只有HTTP协议。
(8)解析请求、封装RequestResponse对象、创建Servlet、调用Service方法都是服务器自动进行的,开发人员只需要写好Servlet配置进容器中即可,无需操心具体的底层实现。—这就是容器啊!多重要!多形象!
3.2.servlet的生命周期
3.2.1.servlet生命周期详解
(1)Servlet第一次被访问到时创建对象,创建出来后立即执行init方法执行初始化的操作。
(2)从此以后该对象一直驻留在内存中为后续的对这个Servlet的请求进行服务。
(3)直到服务器关闭或web应用移除出容器时,随着web应用的销毁Servlet对象销毁掉,在销毁之前调用destory方法执行善后工作。
(4)在存活期间,每次对Servlet 的调用都会导致Service方法的执行。
4.Myeclipse环境下整合JDK、TOMCAT
3.3.Myeclipse概述
3.3.1.Myeclipse概述
Myeclipse是基于Eclipse的一个javaweb集成开发环境。在Eclipse基础上增加了很多和javaweb开发相关的插件,可以大大提高开发效率。
3.4.Myeclipse配置
3.4.1.为Myeclipse配置JDK
Myeclipse可以帮我们管理JDK。我们可以将自己的jdk交给Myeclipse管理,供开发使用。
步骤一:在菜单中选择window->preferences
如图-15所示:

图-15
步骤二:在弹出的选项卡中选择java->installed jres选项卡。
我们发现Myeclipse已经自带了一个JDK,但是强烈建议不要使用这个默认的JDK,这是一个不完整的JDK,经常会导致一些莫名奇妙的问题。我们导入自己安装的jdk使用。
如图-16所示:

图-16
步骤三:点击Add…->StandardVM弹出如下界面, 点击Directory…选择要导入的jdk所在的文件夹,确定导入。
如图-17所示:

图-17
步骤四:最终成功导入了jdk,然后勾选新导入的jdk,确定即可将新导入的jdk设置为Myeclipse默认jdk。
如图-18所示:

图-18
3.4.2.在Myeclipse中整合tomcat
Myeclipse同样可以帮我们管理tomcat。
步骤一:选择window->preferences->myeclipse->server->Tomcat->tomcat x.x点击Browse…选择要导入的tomcat。并将状态设置为Enable,启用该tomcat。
如图-19所示:

图-19
步骤二:打开JDK选项,指定tomcat要使用的JDK。
如图-20所示:

图-20
步骤三:打开launch选项,设置tomcat工作模式。
其中debug mode为调试模式,该模式下tomcat会响应断点调试,便于调试程序。
Run mode为运行模式,该模式下忽略所有断点。
所以开发阶段使用debug mode,开发完成到真正上线环节时,tomcat要运行在run mode模式。
如图-21所示:

图-21
完成以上步骤后,我们就将tomcat交给了Myeclipse去管理。
Myeclipse提供了使用tomcat的快捷键。如图-22所示:

图-22
左边为部署按钮,可以将Myeclipse开发的web应用拷贝到tomcat/weapps目录下,即直接交给localhost虚拟主机管理。
右边为服务器管理按钮,从其中可以找到刚才配置的tomcat服务器,实现对服务器的开启、关闭操作
3.4.3.Myeclipse中开发web应用
在File->New->WebProject创建一个新的web工程。如图-23所示:

图-23
其中Project Name指定当前工程名称。
Source folder指定工程中源代码目录。
Web Root Folder工程中会维护一个web应用目录结构,此选项指定目录名称。
Context root Url web工程开发完成后可以通过Myeclipse发布到tomcat中webapps目录中,此选项指定发布到tomcat时web应用的名称。
J2EE specification level 要使用的javaee版本。
如图-24所示:

图-24
配置好确定后一个web应用工程就创建出来了。
Src目录放置源码,此处写的.java会被自动编译,编译出来的class会被放置到WebRoot/classes目录下。
如图-25所示:

图-25
WebRoot目录维护了一个web应用结构,Web应用开发完成后可通过发布工具发布到tomcat,所谓的发布其实就是将WebRoot下的所有东西拷贝了一份到tomcat/webapps/[web应用名称] 目录下,这样相当于将该web应用配置到了localhost虚拟主机中。
通过localhost虚拟主机就可以访问该web应用了。
如图-26所示:

5.图-26
6.在myeclipse中开发Servlet
6.1.为什么需要myeclipse
6.1.1.为什么需要myeclipse
上面的例子中我们用记事本实现了一个Servlet,这样做的目的是为了让大家更好的理解Servlet的本质,但是如果在真实开发中也用记事本开发,可以想见效率一定是非常低的。接下来我们来了解一下如何在Myeclipse环境中开发Servlet
6.2.在Myeclipse中开发Servlet
6.2.1.第一步:创建servlet
在工程src目录上右键弹出菜单,选择new->Servlet,如图-12所示:

图-12
6.2.2.第二步:配置servlet类信息
在弹出的对话框中输入Servlet的包名、类名,默认继承HttpServlet,覆盖其中doGet和doPost方法。如图-13所示:

图-13
6.2.3.第三步:配置serlvet虚拟路径
进入下一界面,选择是否自动配置servlet到web.xml中,一旦勾选,则自动会用输入的信息在web.xml中为该Servlet配置对外访问路径,如图-14所示:

6.2.4.图-14
6.2.5.第四步:编写servlet处理逻辑
点击确定,创建出Servlet,发现该类继承了HttpServlet(此类是Servlet接口的实现类,我们的类继承他,自然也是个Servlet),并且覆写了其中的doGet和doPost方法。
当客户端用get方式访问该Servlet时会导致doGet方法执行
当客户端用post方式访问该Servlet时会导致doPost方法执行
我们只需要写代码处理对应的处理逻辑即可。
很多时候我们的处理代码对于get方式的请求和post方式的请求的处理是相同的,此时可以在doPost中调用doGet();然后将处理代码写在doGet中。这样无论是get还是post请求都可以进行处理了。
编写代码,如图-15所示:

图-15
6.2.6.第五步:将web应用发布到tomcat中
如图-16所示:

图-16
启动tomcat,如图-17所示:

图-17
6.2.7.第六步:通过浏览器访问
由于web应用是发布到了webapps中即localhost虚拟主机中,所以按照如下方式访问,注意此处的/Demox不是工程名,而是发布时的指定的web应用名,如图-18所示:

图-18
通过浏览器访问,如图-19所示:

图-19
7.Servlet的继承结构
7.1.Serlvet继承结构
7.1.1.概述
我们在手写Servlet时继承的是GenericServlet,而用Myeclipse生成的Servlet是继承了HttpServlet,那么他们之间的关系到底是什么样的呢?下面我们讨论下Servlet的继承结构:
7.1.2.Servlet接口
定义了一个servlet应该具有的方法,所有的Servlet都应该直接或间接实现此接口
7.1.3.GenericServlet抽象类
GenericServlet抽象类是对Servlet接口的默认实现,对Serlvet接口中的大部分方法都做了默认实现,只有service方法是一个抽象方法需要继承者自己实现。实现者只需要实现Service方法在其中写处理请求的代码即可。
7.1.4.HttpServlet类
继承自GenericServlet类,在GenericServlet类的基础上对HTTP协议进行了优化,并且实现了其中的service抽象方法,在其中判断了请求的请求方式,并根据请求方式的不同分别调用不同的doXXX()方法。
通常我们在开发Servlet时,直接继承HttpServlet覆盖对应的doGet()doPost()方法即可,一般不推荐直接覆盖service()方法。

8.Servlet对外访问路径配置细节
8.1.Servlet配置细节
8.1.1.基本配置
Servlet需要在web.xml中配置对外访问的路径。如图-20所示:

图-20
其中:
标签配置Servlet。
标签配置该Servlet的对外访问路径。
一个可以对应多个。
8.1.2.星号匹配符的使用
可以用通配符配置,但是要注意,必须是 .后缀 或者 /开头的以/结尾的路径。
由于匹配符的引入有可能一个虚拟路径会对应多个,此时的匹配优先原则为:哪个最像找哪个,
.后缀 优先级最低。
思考:
8.1.3.对于如下的一些映射关系:
Servlet1 映射到 /abc/

Servlet2 映射到 /

Servlet3 映射到 /abc
Servlet4 映射到 .do
问题:
当请求URL为“/abc/a.html”,“/abc/
”和“/”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc/
”和“/abc”都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/”和“.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/”和“.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,“/”和“.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
8.1.4.缺省Servlet
路径中有一个特殊的配置“/”,如果一个servlet的对外访问路径被设置为/,则该servlet就是一个缺省servlet,其他servlet不处理的请求都由它来处理。
在conf/web.xml(通用web.xml,参考tomcat章节)中配置了缺省servlet,对静态资源的访问和错误页面的输出就是由这个缺省servlet来处理的。
如果我们自己写一个缺省servlet把爸爸web.xml中的缺省servlet覆盖的话,会导致静态web资源无法访问。所以不推荐自己配置缺省Servlet。
9.创建EasyMall注册Servlet
9.1.注册Servlet实现
9.1.1.开发注册Servlet
在前面的学习过程中我们已近开发好了EasyMall的注册页,现在我们学完了Servlet,可以试着开发后台代码了。
首先我们将之前开发好的注册页面导入工程中,放置在web应用根目录下。
创建注册用的RegistServlet,并配置对外访问路径。如图-21所示:

图-21
修改注册页面中注册表单的提交地址指向RegistServlet。如图-22所示:

图-22
通过测试发现表单可以正确提交到Servlet中。如图-23所示:

图-23
9.1.2.引申出的问题
所谓的注册其实就是获取提交过来的请求参数中的注册信息,进行处理后保存在服务器数据库中。
遇到的第一个问题就是,如何获取客户端提交的请求参数。
我们注意看doGet和doPost方法,他们有两个参数,其中HttpServletRequest代表请求,HttpServletResponse代表Http响应。
既然我们需要的是请求参数,根据面向对象的思想,我们可以想见HttpServletRequest必然提供了对应的方法。
10.Request对象
10.1.Request的继承结构
10.1.1.Request的继承结构
我们查看api,如图-24所示:

图-24
虽然我们一直简称为Request,但实际上代表请求的接口为ServletRequest,其中定义了http请求相关的方法。
ServletRequest有一个子类HttpServletRequest,在ServletRequest的基础上增加了很多和http协议相关的方法。
既然Request代表HTTP,那么Http请求相关的请求行请求头实体内容等信息都可以通过这个对象获得。
10.2.Request获取客户机信息
10.2.1.通过request对象获取客户机相关的信息
URL:Uniform Resource Locator统一资源定位符——通过URI可以在互联网上访问到该资源,就像资源的地址一样。
URI:Uniform Resource Identification统一资源标识符——资源的唯一表示,通过URI可以准确识别一个资源,就像资源的身份证号一样。
getRequestURL方法 – 返回客户端发出请求完整URL
getRequestURI方法 – 返回请求行中的资源名部分
getQueryString方法 – 返回请求行中的参数部分
getRemoteAddr方法 – 返回发出请求的客户机的IP地址
getMethod方法 – 返回客户机的请求方式
getContextPath方法 – 获得当前web应用的虚拟目录名称
10.3.Request获取请求头信息
10.3.1.通过request对象获取请求头相关的信息
getHeader(name)方法 — String
getHeaders(String name)方法 — Enumeration
getHeaderNames方法 — Enumeration
getIntHeader(name)方法 — int
getDateHeader(name)方法 — long(日期对应毫秒)
10.4.Request获取请求参数和乱码解决
10.4.1.获取请求参数。
getParameter(String name) – String 通过name获得值
getParameterValues(String name) – String[] 通过name获得多值 如: 爱好
getParameterNames() – Enumeration 获得所有请求参数的name
getParameterMap() – Map<String,String[ ]> key :name value: 多值
我们试着通过这些方法去获取请求参数。如图-25所示:

图-25
经过测试,发现如果请求参数中是英文字符,是可以正常获取的。
但如果请求参数是中文,获取到的却是乱码。,入图-26所示:

图-26
10.4.2.请求参数乱码的原因和解决方法
这些乱码是如何产生的呢?又该如何解决呢?
我们来画图分析一下乱码产生的原理。

图-27
我们知道计算机中并不能真的存储字符,计算机的底层所有的数据都是由01这样的二进制组成的。
将字符映射成对应二进制的表叫做码表。
而大部分情况下乱码都是由于编码-解码过程中码表不一致产生的。
我们来分析一下请求乱码产生的原因。
首先浏览器是用什么码表来将字符转编码成二进制进行发送的呢?浏览器用什么码表来打开表单页面就用什么编码来发送数据。当前我们的注册页面指定了用utf-8来打开。
如图-28所示:

图-28
这就决定了浏览器是用utf-8打开的页面,浏览器在提交表单时是用utf-8编码的。
而tomcat默认情况下会使用iso8859-1来进行解码。
我们知道全世界的码表都兼容iso8859-1,所以英文处理是没有问题的。
但是iso8859-1中并没有中文,iso8859-1对于无法处理的字节都使用?替代,所以我们看到打印的是很多的“?”。
那么该如何解决这类乱码呢?
既然这个问题是服务器处理的过程中产生的,那么只要通知服务器不要使用iso8859-1而是使用正确的utf-8解析数据就可以了。
ServletRequest中提供了setCharacterEncoding方法,可以通知服务器在处理请求时使用哪个指定编码。如图-29所示:

图-29
但是要注意这行代码必须在获取任何请求参数之前执行,如果之前获取过任何请求参数,则此方法失效。
我们设置这行代码,再进行测试,发现乱码已经解决。如图-30所示:

图-30
之前我们的表单是POST提交,我们再将请求方式改为GET,再次测试,发现乱码又出现了。如图-31所示:

图-31
很奇怪,明明已经设置过编码,为什么对POST可以,但GET不行呢?
原来setCharacterEncoding是通知服务器以什么编码处理请求实体内容中的数据,在POST提交时,数据在请求的实体内容中,这行方法可以起作用,而GET提交时,由于请求参数是赋在地址栏后的,这行代码管不到,所以仍然有乱码。
那么应该如何来处理这种乱码呢?回到问题的本质,由于客户端发送时使用的是utf-8编码而服务器用iso8859-1解码造成了乱码,虽然字符已经乱掉了,但底层的字节仍然是正确的,我们只要将乱码字符getBytes(“iso8859-1”)转换为字节,就是正确的字节,再将这些字节new String(bytes,“utf-8”)按照正确的码表编码,就可以转换回正确的字符了。从而解决了乱码。如图-32所示:

图-32
这种方式乱码的解决是从原理上手动编解码解决的乱码,对GET和POST方式的提交都有效。
将本机映射到某个网址,实现在地址栏输入该网址就能进入相应界面。
C:\Windows\System32\drivers\etc 配置hosts文件。
内容127.0.0.1 www.EasyMall.com
注意:中间的空是按tab键实现。

11.ServletConfig
11.1.ServletConfig概述
11.1.1.ServletConfig是什么
ServletConfig代表当前Servlet在web.xml中的配置信息。
11.2.获取ServletConfig
11.2.1.获取ServletConfig
在Servlet接口中init方法参数就是ServletConfig,在Servlet创建出来时,init方法立即被容器调用,由容器传入ServletConfig对象。
在GenericServlet中,实现了这个方法,将ServletConfig设置成了类的成员变量,并提供了getServletConfig方法,获取该对象。
我们的Servlet都间接继承自GenericServlet,所以可以在自己的Servlet中直接调用getServletConfig方法获取这个对象。
11.3.ServletConfig获取初始化参数
11.3.1.配置初始化参数
在web.xml中的标签中可以配置零个或多个标签,用来为当前Servlet配置一些自定义的参数–称为Serlvet的初始化参数。如图-34所示:

图-34
11.3.2.通过ServletConfig获取初始化参数
在ServletConfig身上提供了如下方法获取该Servlet上配置的初始化参数。如图-35所示:

图-35
通过实验发现可以获取Servlet中配置的初始化参数。
如图-36所示:

图-36
12.ServletContext对象
12.1.ServletContext对象概述
ServletContext对象代表当前web应用。当服务器启动时,服务器在启动时会依次加载web应用,每一个web应用加载完成后都会创建一个ServletContext对象唯一代表该web应用,这个对象一直存活,直到web应用移除出容器或服务器关闭时,随着应用销毁,ServletContext对象跟着销毁。

12.2.获取ServletContext对象
在ServletConfig对象身上提供了getServletContext()方法可以用来获取ServletContext对象。
而在GenericServlet中提供了便捷的getServletContext(),我们编写的servlet继承自GenericServlet,所以可以直接调用此方法,便捷的获取ServletContext。
12.3.ServletContext对象读取web应用初始化参数
我们可以在web.xml中利用标签为整个web应用配置初始化信息

encode
utf-8

可以利用ServletContext对象的如下方法获取初始化信息:
ServletContext.getInitParameter();
ServletContext.getInitParameterNames();
之前我们在学习Servlet时,知道Servlet的web.xml配置中可以配置初始化参数,但是这种初始化参数只能在该Servlet内部获取。而为整个web应用配置的初始化参数,通过ServletContext可在整个web应用中使用。
一般来说,整个站点的编码应该是一致的,所以我们可以修改之前的代码,将配给servlet的编码集改为整个站点配置,通过ServletContext获取。

12.3.1.ServletContext对象作为域对象使用
域:一个对象具有了可以被看见的范围,利用这个对象身上的Map,在这个范围内共享数据,这样的对象叫做域对象
javaweb开发中一共有4大域对象
ServletContext域:
作用范围:
整个web应用
生命周期:
当服务器启动web应用加载后立即创建代表这个web应用的ServletContext对象,一直驻留在内存中,唯一的代表这个web应用,直到服务器关闭或web应用被移除出容器时,随着web应用的销毁,ServletContext对象销毁
操作域的方法:
setAttribute(String name,Object obj);//向域中设置数据
Object getAttribute(String name);//从域中获取数据
removeAttribute(String name);//从域中移除数据
12.4.ServletContext对象读取web资源
12.4.1.路径难题
在web环境中读取资源时,如果写的是相对路径,则在tomcat/bin目录下寻找资源。如果写的是绝对路径,则在tomcat所在目录的根目录下寻找资源。如果写的是盘符开始的绝对路径可以正确找到资源,但是一旦改变了发布环境路径很可能是错的。我们发现无论怎么写路径都有问题。
12.4.2.ServletContext读取资源
面对路径难题,ServletContext为我们提供管理解决方法。
servletContext.getRealPath(“xxxx”);–这个方法会在传入的路径前拼接当前web应用的硬盘路径,从而拼接出资源的硬盘路径,从而可以找到资源。
这种方式没有将web应用的硬盘路径写死,所以即使换了一个发布环境,路径也是正确的
12.4.3.类加载器读取资源
如果当前程序中没有ServletContext可以用,此时可以拜托类加载器帮我们加载资源:
类加载器可以加载.class文件,同样也可以加载其他类型的资源文件
在ClassLoader上提供了getResource(“相对于类加载目录的路径”)可以加载资源,但是要求这个路径给一个相对于类加载器加载类的目录的路径(WEB-INF/classes)

13.实现资源跳转
13.1.三种资源跳转方式
Request对象请求转发
Response对象请求重定向
Response对象定时刷新
13.2.三种资源跳转方式的比较
13.2.1.不同特点
转发是服务器内部资源跳转,重定向是通过302+Location实现浏览器跳转访问。
转发一次请求一次响应,重定向两次请求两次响应
转发地址栏不发生变化,重定向地址栏会发生变化
转发之前和转发之后request是一个,重定向之前和之后不是一个request
13.2.2.应用场景
转发和重定向都能实现资源的跳转,那什么时候用重定向什么时候用转发呢?
如果希望资源跳转的过程中使用request域传输数据,必须用转发
如果希望资源跳转时想要改变地址栏的地址,此时必须用重定向
如果某些应用场景下,既不需要用request域传输据也不需要改变地址栏,此时两种都可以,但是推荐使用请求转发,可以减少对服务器的访问次数,从而减轻服务器的压力
如果在资源跳转之前想要向客户端输出些信息用定时刷新。
14.Request对象
14.1.Request的继承结构
14.1.1.Request的继承结构
我们查看api,如图-24所示:

图-24
虽然我们一直简称为Request,但实际上代表请求的接口为ServletRequest,其中定义了http请求相关的方法。
ServletRequest有一个子类HttpServletRequest,在ServletRequest的基础上增加了很多和http协议相关的方法。
既然Request代表HTTP,那么Http请求相关的请求行请求头实体内容等信息都可以通过这个对象获得。
14.2.Request获取客户机信息
14.2.1.通过request对象获取客户机相关的信息
getRequestURL方法 – 返回客户端发出请求完整URL
getRequestURI方法 – 返回请求行中的资源名部分
getQueryString方法 – 返回请求行中的参数部分
getRemoteAddr方法 – 返回发出请求的客户机的IP地址
getMethod方法 – 返回客户机的请求方式
getContextPath方法 – 获得当前web应用的虚拟目录名称
14.3.Request获取请求头信息
14.3.1.通过request对象获取请求头相关的信息
getHeader(name)方法 — String
getHeaders(String name)方法 — Enumeration
getHeaderNames方法 — Enumeration
getIntHeader(name)方法 — int
getDateHeader(name)方法 — long(日期对应毫秒)
14.4.Request获取请求参数和乱码解决
14.4.1.获取请求参数。
getParameter(String name) – String 通过name获得值
getParameterValues(String name) – String[] 通过name获得多值 如: 爱好
getParameterNames() – Enumeration 获得所有请求参数的name
getParameterMap() – Map<String,String[ ]> key :name value: 多值
我们试着通过这些方法去获取请求参数。如图-25所示:

图-25
经过测试,发现如果请求参数中是英文字符,是可以正常获取的。
但如果请求参数是中文,获取到的却是乱码。,入图-26所示:

图-26
14.4.2.请求参数乱码的原因和解决方法
这些乱码是如何产生的呢?又该如何解决呢?
我们来画图分析一下乱码产生的原理。

图-27
我们知道计算机中并不能真的存储字符,计算机的底层所有的数据都是由01这样的二进制组成的。
将字符映射成对应二进制的表叫做码表。
而大部分情况下乱码都是由于编码-解码过程中码表不一致产生的。
我们来分析一下请求乱码产生的原因。
首先浏览器是用什么码表来将字符转编码成二进制进行发送的呢?浏览器用什么码表来打开表单页面就用什么编码来发送数据。当前我们的注册页面指定了用utf-8来打开。
如图-28所示:

图-28
这就决定了浏览器是用utf-8打开的页面,浏览器在提交表单时是用utf-8编码的。
而tomcat默认情况下会使用iso8859-1来进行解码。
我们知道全世界的码表都兼容iso8859-1,所以英文处理是没有问题的。
但是iso8859-1中并没有中文,iso8859-1对于无法处理的字节都使用?替代,所以我们看到打印的是很多的“?”。
那么该如何解决这类乱码呢?
既然这个问题是服务器处理的过程中产生的,那么只要通知服务器不要使用iso8859-1而是使用正确的utf-8解析数据就可以了。
ServletRequest中提供了setCharacterEncoding方法,可以通知服务器在处理请求时使用哪个指定编码。如图-29所示:

图-29
但是要注意这行代码必须在获取任何请求参数之前执行,如果之前获取过任何请求参数,则此方法失效。
我们设置这行代码,再进行测试,发现乱码已经解决。如图-30所示:

图-30
之前我们的表单是POST提交,我们再将请求方式改为GET,再次测试,发现乱码又出现了。如图-31所示:

图-31
很奇怪,明明已经设置过编码,为什么对POST可以,但GET不行呢?
原来setCharacterEncoding是通知服务器以什么编码处理请求实体内容中的数据,在POST提交时,数据在请求的实体内容中,这行方法可以起作用,而GET提交时,由于请求参数是赋在地址栏后的,这行代码管不到,所以仍然有乱码。
那么应该如何来处理这种乱码呢?回到问题的本质,由于客户端发送时使用的是utf-8编码而服务器用iso8859-1解码造成了乱码,虽然字符已经乱掉了,但底层的字节仍然是正确的,我们只要将乱码字符getBytes(“iso8859-1”)转换为字节,就是正确的字节,再将这些字节new String(bytes,“utf-8”)按照正确的码表编码,就可以转换回正确的字符了。从而解决了乱码。如图-32所示:

图-32
这种方式乱码的解决是从原理上手动编解码解决的乱码,对GET和POST方式的提交都有效。

15.Response
15.1.Response概述
15.1.1.Response概述
Servlet中应该如何向用户输出数据呢?在doGet和doPost方法的参数中,HttpServletRequest代表的是http请求,而HttServletResponse代表的是http响应。想要获取请求中的信息时使用HttpServletRequest对象,而有数据需要发送给客户端时,就要用到HttpServletResponse对象了。
15.2.Response继承结构
15.2.1.Response继承结构
虽然我们经常简称为response,实际上是ServletResponse接口,其中定义了很多和响应对象相关的方法,HttpServletResponse是ServletResponse接口的子接口,在ServletResponse的基础上增加了很多和http协议相关的方法。如图-40所示:

图-40
15.3.Response常用方法
15.3.1.设置状态码
setStatus(int sc)
setStatus(int sc, String sm)
15.3.2.设置响应头
setIntHeader(String name, int value)
setHeader(String name, String value)
setDateHeader(String name, long date)
15.3.3.获取输出流
PrintWriter getWriter()
ServletOutputStream getOutputStream();
15.4.Response输出信息到客户端
15.4.1.输出信息到客户端api
查询api,在Response向外输出数据的方法有如下两个:
PrintWriter getWriter()
ServletOutputStream getOutputStream();
其中getWriter获取的是字符流,可以输出字符数据到客户端。
getOutputStream获取的是字节流,可以输出字节数据到客户端。
我们现在要将字符数据发送给客户端,可以调用getWriter方法向其中输出数据
经测试可以正确的输出。如图-41所示:

图-41
接着我们测试中文。发现输出时产生了乱码。如图-42所示:

图-42
15.4.2.响应乱码处理
这个乱码是如何产生的呢?乱码的产生大多是由于编码和解码时的码表不同产生的。
那么服务器是以什么码表来发送数据呢?我们发现乱码是以“?”的形式出现的。根据我们的经验,这种问题多半是由ISO8859-1编码导致的。
确实是的,如果不指定,服务器默认将用iso8859-1进行编码发送数据。浏览器用什么码表打开呢?一般来说如果不指定,浏览器默认会用所在的操作系统的平台码,我们当前的中文系统中,默认就是使用GB2312作为解码码表的。
首先iso8859-1中没有中文,对于无法表示的字符,iso8859-1会用“?”来替代,所以真正发送给浏览器的数据其实是“?”,世界上所有的码表都默认兼容iso8859-1,所以gb2312认识,显示为了“?”。如图-43所示:

图-43
在解决这个问题时,可以通过设置response.setCharacterEncoding(“gbk”)来指定服务器发送数据时使用的码表。同时要注意,此行代码必须出现在任何输出数据的代码之前,如果在这行代码之前已经有任何数据写入给了response,则此行代码无效。
设置过后再重新测试。发现仍然是乱码,但不再是“??”而是变成了“涓浗”。如图-44所示:

图-44
这种类型的乱码是怎么发生的呢?我们接着分析。服务器用utf-8发送数据给浏览器,而浏览器用平台码(当前为gbk)gbk打开自然产生了乱码。如图-45所示:

图-45
这种乱码的产生是由于浏览器没有使用正确的编码打开造成的,那么我们该如何控制浏览器用指定码表打开数据呢?
在http协议中有一个响应头叫做Content-Type可以用来通知浏览器当前服务器发送的数据的格式,如果是字符格式的数据还可以指定解析时使用的码表。所以我们可以通过如下方法通知浏览器用指定码表打开发送的数据,代码如下,经测试没有乱码。
我们通过response.setHeader(“Content-Type”, “text/html;charset=utf-8”);通知服务器发送数据时的码表。
通过response.setCharacterEncoding(“utf-8”);通知浏览器解析时使用的码表。
两码相同就不会有乱码了。
如图-46所示:

图-46
另外response提供了setContentType()快捷方法,在它的底层,会同时做上面两件事,所以可以一行代码解决response产生的乱码问题。如图-47所示:

图-47
15.4.3.Response输出数据时的细节
(1)getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。
(2)Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。
(3)Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎tomcat将调用close方法关闭该输出流对象。
请求转发和请求包含的区别:
二者的共同点:
1.这两种都是一个请求跨多个Servlet(可以共享request的域属性)
2.多个Servlet在一个请求中共享一个Request对象。
二者的区别:
1.请求转发可以这样理解:如果AServlet转发到BServlet,那么这个请求就交给BServlet来处理了,AServlet就不插手了。
2.请求包含:AServlet包含BServlet,那么这两个Servlet共同处理请求。
二者的联系:
请求转发和请求包含都需要一个相同的对象RequestDispatcher
请求转发和重定向的区别:
1.请求转发是一个请求,重定向是两个请求
2.请求转发只能是一种请求方式,要么是Get要么是Post,但是重定向的第二个请求一定是Get。
3.请求转发的地址栏并不会发生变化,但是重定向的会变化,因为它是两个请求。
4.请求转发只能在本应用下的资源,但是重定向却可以跨应用,比如重定向到百度的主页。
1.JSP技术01
1.1.JSP概述
1.1.1.JSP概述
Servlet是j2ee提供的动态资源开发技术,是以java的程序的形式进行开发,在java中书写HTML标签是一件十分头疼的事情,所以人们开发出了JSP,看起来像是HTML一样,但可以在其中写java代码,本质上是动态web资源,Jsp会在第一次访问时被容器翻译为Servlet。
1.2.JSP基本语法
1.2.1.模版元素
直接书写在JSP中的HTML内容,看起来就像写HTML一样的方便,但是最终会在被翻译成Servlet的过程中 out.write()直接输出
1.2.2.脚本表达式
<%= 表达式%> 接受的是一段java表达式,在JSP翻译到Servlet的过程中,将会计算表达式的值,利用out.write()输出出去
1.2.3.脚本片段
<% %>直接可以在脚本片段中书写java源代码,其中的源代码将会直接拷贝到翻译过来的servlet中的响应位置上。
1.2.4.JSP声明
<%! %>在其中可以写java代码,其中的源代码会被拷贝到servlet中的service方法之外,可以利用它来为servlet增加成员方法、成员变量、静态代码块
1.2.5.JSP注释
<%-- --%>被jsp注释包围起来的内容将不会被服务器翻译到servlet之中,要注意区分html注释和java注释的区别
jsp注释不会被翻译到servlet中,会在翻译时遗弃
java注释不会被编译到class文件中,会在编译时遗弃
html注释将会当作模版元素,直接输出到浏览器中,浏览器将不会显示html注释中的内容
1.3.JSP指令
1.3.1.page指令
用来通知翻译引擎,如何翻译当前的JSP
[ language=“java” ] 当前JSP使用的开发语言
[ extends=“package.class” ] 当前jsp翻译成servlet后要继承的类,注意此值必须是一个servlet的子类,一般情况下不要改
[ import="{package.class | package.}, …" ] 导入需要使用到的包 java.lang.;javax.servlet.;javax.servlet.jsp.;javax.servlet.http.*;
[ session=“true | false” ] 用来指定当前页面是否使用session,如果设置为true,则翻译过来的servlet中将会有对session对象的引用,于是可以直接在jsp中使用session隐式对象。但是这将导致一旦访问jsp就会调用request.getSession()方法,可能导致不必要的空间浪费。如果确定jsp中不需要session可以设为false
[ buffer=“none | 8kb | sizekb” ] out隐式对象所使用的缓冲区的大小
[ autoFlush=“true | false” ] out隐式对象是否自动刷新缓冲区,默认为true,不需要更改
[ isThreadSafe=“true | false” ] 翻译过来的servlet是否实现SingleThreadModel
[ errorPage=“relative_url” ] 如果页面出错,将要跳转到的页面,除了在jsp中使用此属性指定错误页面外也可以在web.xml中配置整个web应用的错误页面,如果两个都设置则jsp中的此属性起作用
[ isErrorPage=“true | false” ] 如果设置此属性为true,翻译过来的servlet中将含有Exception隐式对象,其中封装的就是上一个页面中抛出的异常对象
[ contentType=“mimeType [ ;charset=characterSet ]” | “text/html ; charset=ISO-8859-1” ] 和jsp乱码相关的指令,用来指定jsp输出时,设置的Content-Type响应头用来指定浏览器打开的编码
[ pageEncoding=“characterSet | ISO-8859-1” ] 服务器翻译jsp时使用的编码集.如果向防止jsp乱码,应该保证文件的保存编码和jsp翻译成servlet用的编码以及输出到浏览器后浏览器打开的编码一致.此属性一旦设置好,翻译引擎会间接帮我们设置content-type属性.
[ isELIgnored=“true | false” ] 当前页面是否使用el表达式,设置为false时表示启用el,j2ee4.0开始默认支持,j2ee4.0一下做开发时,如果要使用el表达式,需将此属性设置为fals

1.3.2.include指令
<%@ incluede file=“”%> 静态引入其他页面的内容
*静态引入:
在源文件级别进行合并,多个jsp生成一个servlet,最终由这一个servlet生成响应。推荐使用。
*动态引入:
在运行时将多个输出进行合并,多个jsp分别生成多个servlet,最终由这多个servlet生成响应,组成一个输出流,提供响应。执行效率没有静态引入高。

1.3.3.taglib指令
<%@ taglib uri=“” prefix=“”%>用来引入标签库。
uri指定被引入.tld文件的名称空间
prefix 对该名称空间的一个缩写
1.4.四大作用域
PageContext:生命周期:访问JSP开始时创建pageContext对象,访问结束时销毁。作用范围:当前JSP(页面)中 主要功能:在当前JSP中共享数据
ServletContext: 代表整个Web应用的对象。生命周期:当服务器(tomcat不关就一直有效)加载时创建ServletContext对象,当web应用被服务器移出是销毁。主要功能:在整个web应用范围内实现数据的共享。
ServletRequest:生命周期:一次请求开始时创建request对象,一次请求结束时销毁request对象。
HttpSession:代表一次会话的对象。生命周期:(浏览器有效,换个浏览器就去不到了)在第一次调用request.getSession()方法时创建session对象。销毁:①超时销毁(默认30分钟)②自杀(调用invalidate方法)③意外身亡 作用范围:整个会话范围内 主要功能:实现整个会话范围内实现数据的共享

取值范围从小到大,pageContext < request < session < application
1.5.九大隐式对象
1.5.1.九大隐式对象概述
在jsp翻译成Serlvet时,jsp翻译引擎在翻译过来的Serlvet中,预先定义了一些变量,可以不需要在JSP中预先定义就可以直接使用,共有9个,统称为jsp的九大隐式对象。分别是:
page
config
application
response
request
session
out
exception
pageContext
其中其他的七个我们都学习过了,只需要再学习一下out和pageContext即可。
1.5.2.out对象
可以将他理解成response.getWriter()获得的PrintWriter.
它自带一个缓冲区,其大小收page指令中的buffer的设定限制。当缓冲区满或缓冲区被关闭或当前jsp页面结束,则此缓冲区中的内容将被刷新到response.getWriter()的缓冲区中。
1.5.3.PageContext对象
(1)作为入口对象获取其它八大隐式对象。
getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象
(2)作为入口对象获取其他域中的数据
pageContext操作所有域中属性的方法
getAttribute(String name,int scope)
setAttribute(String name, Object value,int scope)
removeAttribute(String name,int scope)
其中pageContext中代表域的常量:
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
findAttribute方法:
在四大域中搜寻属性,搜寻的顺序是page域、request域、session域、application域,从小域到大域开始搜索,如果搜索到就直接获取该值,如果所有域中都找不到,返回一个null
(3)作为域对象使用
作用的范围:整个jsp页面,是四大作用域中最小的一个。
生命周期:当对jsp的请求开始时生成,当响应结束时销毁。
作用:在jsp页面范围内共享数据

(4)跳转到其他资源
其身上提供了forward和
2.JSP标签技术概述
2.1.Jsp标签技术概述
2.1.1.JSP标签技术概述
在之前我们编写的程序中,JSP页面中大量的写入了java代码,我们发现在jsp页面中嵌入大量java代码会造成页面的可读性、可维护性下降。
如图-1所示:

图-1
那么该如何解决这种问题呢?sun公司考虑到这种问题,为我们提供了JSP标签技术,通过标签替换掉jsp页面中的java代码,从而提高jsp页面的可读性、可维护性。
JSP中的标签技术我们介绍如下四种:
JSP标签
EL表达式
JSTL标签
自定义标签
3.JSP标签
3.1.JSP标签详解
3.1.1.JSP标签详解
由sun公司提供,属于jsp规范中的内容,不需要引入第三方标签库,我们介绍其中的三个。
jsp:inclue用来替代request.getRequestDispatcher().include()
jsp:forward用来替代request.getRequestDispatcher().forward()
jsp:param配合前两个标签使用,可以在包含或转发时,带一些参数过去
4.el表达式
4.1.EL概述
4.1.1.EL概述
EL 全名为Expression Language,用来替代<%= %>脚本表达式。
在j2ee4.0以前默认是不支持el,如果需要需要指定page指令[isELIgnored=“true | false” ]为false,J2EE4.0后默认支持el
EL具有获取数据、执行运算、获取常用开发对象、调用java方法这四方面的功能
4.2.获取数据
4.2.1.获取常量
EL支持数据、字符串、布尔类型的常量
${23}
${“asdf”}
${true}
4.2.2.获取变量:在四大作用域中搜寻属性
${propName}在四个域中搜寻proName属性,输出该值到输出流中
搜寻域的顺序为由小到大。
如果四大域中都搜寻不到,则什么都不输出。
4.2.3.获取变量:获取指定域中的属性
${pageScope/requestScope/sessionScope/applicationScope.proName}
获取指定域中的属性
4.2.4.获取变量:获取数组中的数据
${attr[0]}获取域中的数组的指定元素
4.2.5.获取变量:获取集合中的数据
${list[0]}获取list中的指定位置元素
4.2.6.获取变量:获取map中的数据
${map.keyName}获取map中指定键的值
4.2.7.获取变量:获取javabean属性
${bean.propName}获取javaBean的属性,可以认为是调用了javaBean的getXXX方法,
最重要的一个应用场景:
在写路径的时候最好不要把web应用名称写死,java中应该用request.getContextPath去获取,jsp中就用el获取:
p a g e C o n t e x t . r e q u e s t . c o n t e x t P t h 4.2.8. 获取数据细节( 1 )和 [ ] 区别:使用点的地方都可以用中括号,如果属性名是数字或包含特殊符号( . − )就必须使用中括号。例子: {pageContext.request.contextPth} 4.2.8.获取数据细节 (1)和[]区别:使用点的地方都可以用中括号,如果属性名是数字或包含特殊符号(.-)就必须使用中括号。例子: pageContext.request.contextPth4.2.8.获取数据细节(1)和[]区别:使用点的地方都可以用中括号,如果属性名是数字或包含特殊符号(.)就必须使用中括号。例子:{map[“first.name”]}
(2)EL只能获取不能设置
(3)EL只能获取不能遍历
4.3.进行简单运算
4.3.1.算数运算
${3+2}
${“3”+2}
${“3”+2}
${1+”a”}
所有参与元算的元素都会被转成数字,如果不能转就报错,空元素参与运算当作没参与。
4.3.2.关系运算:
如图-2所示:

图-2
${3 > 2}
${3 gt 2}
4.3.3.逻辑运算:
如图-3所示:

图-3
${3>2 && 4>5}
4.3.4.Empty运算符
empty/not empty判断对象是否为null,判断集合是否为空,数组长度是否为0,判断字符串是否为空串,判断域中是否没有任何属性。
4.3.5.三元表达式
${name == null ? “张三” : name;}
4.4.获取web开发常用对象
4.4.1.EL的内置对象
El中预先定义了11个内置对象,不需要提前存入域中个,可以直接在el使用。
如图-4、图-5所示:

图-4

图-5
4.4.2.pageContext
代表pageContext对象,通过他可以获取其他八大隐式对象

p a g e C o n t e x t . r e q u e s t . c o n t e x t P a t h 获取所请求页面所在路径 4.4.3. 四大作用域中域属性组成的 m a p p a g e S c o p e :代表 p a g e 域,可以用来获取 p a g e 域中的属性 r e q e u s t S c o p e :代表 r e q e u s t 域,可以用来获取 r e q e u s t 域中的属性 s e s s i o n S c o p e :代表 s e s s i o n 域,可以用来获取 s e s s i o n 域中的属性 a p p l i c a t i o n S c o p e :代表 a p p l i c a t i o n 域,可以用来获取 a p p l i c a t i o n 域中的属性 4.4.4. 请求参数组成的 m a p p a r a m 代表请求参数组成的 m a p 集合 {pageContext.request.contextPath }获取所请求页面所在路径 4.4.3.四大作用域中域属性组成的map pageScope:代表page域,可以用来获取page域中的属性 reqeustScope:代表reqeust域,可以用来获取reqeust域中的属性 sessionScope:代表session域,可以用来获取session域中的属性 applicationScope:代表application域,可以用来获取application域中的属性 4.4.4.请求参数组成的map param 代表请求参数组成的map集合 pageContext.request.contextPath获取所请求页面所在路径4.4.3.四大作用域中域属性组成的mappageScope:代表page域,可以用来获取page域中的属性reqeustScope:代表reqeust域,可以用来获取reqeust域中的属性sessionScope:代表session域,可以用来获取session域中的属性applicationScope:代表application域,可以用来获取application域中的属性4.4.4.请求参数组成的mapparam代表请求参数组成的map集合{param.userName}
paramValues 代表请求参宿组成的map集合,但是此集合的value是String[],用来获取一名多值的param
4.4.5.请求头组成的map
header 获取请求头组成的map
headerValues 获取请求头组成的map但是value是一个String[],用来获取一名多值的head
4.4.6.所有cookie信息组成的map
cookie :获取cookie组成的map对象,键为cookie的名,值为Cookie对象。
${cookie.cookieName.cookieValue}
4.4.7.web应用初始化参数组成的map
initParam 以map封装的web.xml中配置的整个web应用的初始化参数
4.5.调用java方法
4.5.1.调用java方法
略。
5.JSTL标签库
5.1.JSTL标签库概述
5.1.1.JSTL标签库概述
JSTL全称为JavaServer Pages Standard Tag Library
由JCP(Java Community Process)指定标准
是提供给 Java Web 开发人员一个标准通用的标签函数库
可以和 EL 配合来取代传统直接在页面上嵌入 Java 程序(Scripting)的做法,以提高程序可读性、维护性和方便性
在javaee4.0需要导入JSTL相关的jar包,在javaee5.0开始,默认已经包含了此jar包。
还要需要用<%@taglib%>指令引入标签库
5.2.JSTL标签库子库
5.2.1.JSTL标签库子库
核心标签库 (core) — c
国际化标签 fmt
数据库标签 sql --Servlet
XML标签 xml
JSTL函数(EL函数) el
5.3.JSTL核心标签库
5.3.1.<c:out>
如图-6所示:

图-6
输出固定值
<c:out value=“Hello c out~”/>
输出变量
<c:out value=“KaTeX parse error: Expected 'EOF', got '#' at position 75: …alue="<a href='#̲'>link</a>" esc…{city}” default=“北京”/>
5.3.2.<c:set>
如图-7所示:

图-7
标签用于把某一个对象存在指定的域范围内,或者设置Web域中的java.util.Map类型的属性对象或JavaBean类型的属性对象的 属性。
在指定域中增加、修改属性
<c:set var=“name” value=“value”
[scope=“{page|request|session|application}]”/>
设置一个保存在四个范围的java对象的属性值,cset不能设置对象进域,但是可以更改域中对象的属性
<c:set targe=“${person}” property=“name” value=“lisi”/>
5.3.3.<c:remove>
标签用于删除各种Web域中的属性
<c:remove var=“varName”
[scope=“{page|request|session|application}”] />
5.3.4.<c:catch>
标签用于捕获嵌套在标签体中的内容抛出的异常,其语法格式如下:
<c:catch var=“e”>
<%
String s = null;
s.charAt(1);
%>
</c:catch>
5.3.5.<c:if>
如图-8所示:

图-8
此标签可以构造简单的“if-then”结构的条件表达式 。
5.3.6.<c:choose>
标签用于指定多个条件选择的组合边界,它必须与<c:when>和<c:otherwise>标签一起使用。使用<c:choose>,<c:when>和<c:otherwise>三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。
<c:choose>
<c:when test=“ w e e k d a y = = 1 " > 星期一 < / c : w h e n > < c : w h e n t e s t = " {weekday==1}"> 星期一 </c:when> <c:when test=" weekday==1">星期一</c:when><c:whentest="{weekday2}“>
星期二
</c:when>
<c:when test=”${weekday
3}”>
星期三
</c:when>
<c:otherwise>
输入无效
</c:otherwise>
</c:choose>
5.3.7.<c:forEach>
标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。
如图-9所示:

图-9
varStatus属性,如图-10所示:

图-10
实验:遍历10到100的偶数,如果数字所在的位置是3的倍数,显示成红色
5.3.8.<c:forTokens>
用来浏览字符串中所有的成员,其成员是由定义符号所分隔的
5.3.9.<c:param>
在JSP页面进行URL的相关操作时,经常要在URL地址后面附加一些参数。<c:param>标签可以嵌套在<c:import>、<c:url>或<c:redirect>标签内,为这些标签所使用的URL地址附加参数。
5.3.10.<c:import>
标签,实现include操作,如图-11所示:

图-11
5.3.11.<c:url>
如图-12所示:

图-12
标签用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。URL重写就是将会话标识号以参数形式附加在URL地址后面
5.3.12.<c:redirect>
此标签用于实现请求重定向。如图-13所示:

图-13
6.自定义标签技术
6.1.自定义标签概述
6.1.1.自定义标签概述
虽然有第三方组织提供了很多标签,但是这些都是一些通用标签,开发中常常需要根据业务需求使用jsp页面,这个时候通用的标签就不够用了,我们需要自己去开发标签库。
6.2.开发自定义标签
6.2.1.开发步骤
想要开发自定义标签需要两个步骤:
写一个类实现SimpleTag接口
在tld文件中描述该标签,在jsp页面中通过<%@taglib %>引入该标签库使用标签
6.3.写一个类实现SimpleTag接口
6.3.1.写一个类实现SimpleTag接口
SimpleTag接口的继承结构如图-14所示:

图-14
我们写一个类实现SimpleTag接口,发现其中包含如下方法:
public void doTag() throws JspException, IOException {

}

public void setParent(JspTag parent) {

}

public JspTag getParent() {
	return null;
}

public void setJspContext(JspContext pc) {

}

public void setJspBody(JspFragment jspBody) {

}
6.3.2.SimpleTag接口方法详解
当jsp页面执行到自定义标签时,首先创建出自定义标签处理类对象,创建出来后会立即调用setJspContext方法将当前页面的PageContext传入。如果当前标签具有标签体,则将标签的标签体封装到JspFragment对象中调用setJspBody方法,如果没有标签体此方法不执行。如果当前自定义标签有父标签,则调用setParent方法将父标签传入。最后调用doTag方法执行自定义标签的处理逻辑。
所以我们在开发自定义标签时,将核心代码写入doTag方法即可。
更多的时候我们不会直接实现SimpleTag接口而是继承SimpleTagSupport。
SimpleTagSupport实现了SimpleTag接口,对立面的方法都做了实现,实现了setJspContext方法,将JspContext保存成了类的成员,并提供了getJspContext()方法获取该对象。实现了setJspBody(JspFragment)方法,将JspFragment保存成了类的成员,并提供了getJspBody()方法获取该对象。实现了doTag方法,做了空实现,我们作为实现类,只需要覆盖这个方法,在其中编写标签处理代码。

6.4.实现自定义标签的基本功能
6.4.1.控制是否执行标签体
控制标签体不执行:什么都不做标签体默认就不执行
控制标签体执行:获取封装了标签体的JSPFragment对象,执行invoke方法,输出到out输出流中即可
JspFragment fragment = this.getJspBody();
fragment.invoke(this.getJspContext().getOut());
fragment.invoke(null);
6.4.2.控制是否执行标签之后的内容
控制标签之后的内容执行:什么都不做,就执行
控制标签之后的内容不执行:抛出一个特殊的异常SkipPageException就可以阻止标签之后的内容执行
throw new SkipPageException();
6.4.3.控制标签体重复执行
JspFragment fragment = this.getJspBody();
for(int i = 0;i<5 ;i++){
fragment.invoke(null);
}
6.4.4.修改标签体输出
StringWriter writer = new StringWriter();
JspFragment fragment = this.getJspBody();
fragment.invoke(writer);
String str = writer.toString();
str = str.toUpperCase();
this.getJspContext().getOut().write(str);
6.5.在tld文件中描述该标签
6.5.1.tld文件详解
tld是专门用来描述自定义标签的文件,可以在其中描述自定义标签。
tld文件必须放置在WEB-INF目录除classes和lib目录外的其他目录下。
其格式如下,如图-15所示:

图-15
其中是该自定义标签的名字
是该自定义标签处理类的全路径名
是标签体类型,可取的值为Empty表示不能含有标签体。scriptless表示可以包含标签体但是不能包含java源代码。JSP表示可以包含任意内容的标签体。
6.6.在jsp页面中引入自定义标签使用
6.6.1.在jsp页面中引入自定义标签
在jsp页面中使用<%@taglib %>引入自定义标签。
<%@ taglib uri=“http://www.easymall.com/myTag” prefix=“myTag” %>
6.7.开发带有属性的自定义标签
6.7.1.开发带有属性的自定义标签
想要开发带有属性的标签,需要做如下两件事:
在自定义标签处理类中定义javabean属性并提供setXxx()方法,如图-16所示:

图-16
在tld文件中描述该属性,如图-17所示:

图-17
其中,描述属性的标签如图-18所示:

图-18
6.8.打包自定义标签为jar包
6.8.1.打包自定义标签为jar包
略。
2.JSP技术01
2.1.JSP概述
2.1.1.JSP概述
Servlet是j2ee提供的动态资源开发技术,是以java的程序的形式进行开发,在java中书写HTML标签是一件十分头疼的事情,所以人们开发出了JSP,看起来像是HTML一样,但可以在其中写java代码,本质上是动态web资源,Jsp会在第一次访问时被容器翻译为Servlet。
2.2.JSP基本语法
2.2.1.模版元素
直接书写在JSP中的HTML内容,看起来就像写HTML一样的方便,但是最终会在被翻译成Servlet的过程中 out.write()直接输出
2.2.2.脚本表达式
<%= 表达式%> 接受的是一段java表达式,在JSP翻译到Servlet的过程中,将会计算表达式的值,利用out.write()输出出去
2.2.3.脚本片段
<% %>直接可以在脚本片段中书写java源代码,其中的源代码将会直接拷贝到翻译过来的servlet中的响应位置上。
2.2.4.JSP声明
<%! %>在其中可以写java代码,其中的源代码会被拷贝到servlet中的service方法之外,可以利用它来为servlet增加成员方法、成员变量、静态代码块
2.2.5.JSP注释
<%-- --%>被jsp注释包围起来的内容将不会被服务器翻译到servlet之中,要注意区分html注释和java注释的区别
jsp注释不会被翻译到servlet中,会在翻译时遗弃
java注释不会被编译到class文件中,会在编译时遗弃
html注释将会当作模版元素,直接输出到浏览器中,浏览器将不会显示html注释中的内容
3.JSP技术02
3.1.JSP指令
3.1.1.page指令
用来通知翻译引擎,如何翻译当前的JSP
[ language=“java” ] 当前JSP使用的开发语言
[ extends=“package.class” ] 当前jsp翻译成servlet后要继承的类,注意此值必须是一个servlet的子类,一般情况下不要改
[ import="{package.class | package.}, …" ] 导入需要使用到的包 java.lang.;javax.servlet.;javax.servlet.jsp.;javax.servlet.http.*;
[ session=“true | false” ] 用来指定当前页面是否使用session,如果设置为true,则翻译过来的servlet中将会有对session对象的引用,于是可以直接在jsp中使用session隐式对象。但是这将导致一旦访问jsp就会调用request.getSession()方法,可能导致不必要的空间浪费。如果确定jsp中不需要session可以设为false
[ buffer=“none | 8kb | sizekb” ] out隐式对象所使用的缓冲区的大小
[ autoFlush=“true | false” ] out隐式对象是否自动刷新缓冲区,默认为true,不需要更改
[ isThreadSafe=“true | false” ] 翻译过来的servlet是否实现SingleThreadModel
[ errorPage=“relative_url” ] 如果页面出错,将要跳转到的页面,除了在jsp中使用此属性指定错误页面外也可以在web.xml中配置整个web应用的错误页面,如果两个都设置则jsp中的此属性起作用
[ isErrorPage=“true | false” ] 如果设置此属性为true,翻译过来的servlet中将含有Exception隐式对象,其中封装的就是上一个页面中抛出的异常对象
[ contentType=“mimeType [ ;charset=characterSet ]” | “text/html ; charset=ISO-8859-1” ] 和jsp乱码相关的指令,用来指定jsp输出时,设置的Content-Type响应头用来指定浏览器打开的编码
[ pageEncoding=“characterSet | ISO-8859-1” ] 服务器翻译jsp时使用的编码集.如果向防止jsp乱码,应该保证文件的保存编码和jsp翻译成servlet用的编码以及输出到浏览器后浏览器打开的编码一致.此属性一旦设置好,翻译引擎会间接帮我们设置content-type属性.
[ isELIgnored=“true | false” ] 当前页面是否使用el表达式,设置为false时表示启用el,j2ee4.0开始默认支持,j2ee4.0一下做开发时,如果要使用el表达式,需将此属性设置为fals

3.1.2.include指令
<%@ incluede file=“”%> 静态引入其他页面的内容
*静态引入:
在源文件级别进行合并,多个jsp生成一个servlet,最终由这一个servlet生成响应。推荐使用。
*动态引入:
在运行时将多个输出进行合并,多个jsp分别生成多个servlet,最终由这多个servlet生成响应,组成一个输出流,提供响应。执行效率没有静态引入高。

3.1.3.taglib指令
<%@ taglib uri=“” prefix=“”%>用来引入标签库。
uri指定被引入.tld文件的名称空间
prefix 对该名称空间的一个缩写
3.2.九大隐式对象
3.2.1.九大隐式对象概述
在jsp翻译成Serlvet时,jsp翻译引擎在翻译过来的Serlvet中,预先定义了一些变量,可以不需要在JSP中预先定义就可以直接使用,共有9个,统称为jsp的九大隐式对象。分别是:
page
config
application
response
request
session
out
exception
pageContext
其中其他的七个我们都学习过了,只需要再学习一下out和pageContext即可。
3.2.2.out对象
可以将他理解成response.getWriter()获得的PrintWriter.
它自带一个缓冲区,其大小收page指令中的buffer的设定限制。当缓冲区满或缓冲区被关闭或当前jsp页面结束,则此缓冲区中的内容将被刷新到response.getWriter()的缓冲区中。
3.2.3.PageContext对象
(1)作为入口对象获取其它八大隐式对象。
getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象
(2)作为入口对象获取其他域中的数据
pageContext操作所有域中属性的方法
getAttribute(String name,int scope)
setAttribute(String name, Object value,int scope)
removeAttribute(String name,int scope)
其中pageContext中代表域的常量:
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
findAttribute方法:
在四大域中搜寻属性,搜寻的顺序是page域、request域、session域、application域,从小域到大域开始搜索,如果搜索到就直接获取该值,如果所有域中都找不到,返回一个null
(3)作为域对象使用
作用的范围:真个jsp页面,是四大作用域中最小的一个。
生命周期:当对jsp的请求开始时生成,当响应结束时销毁。
作用:在jsp页面范围内共享数据

(4)跳转到其他资源
其身上提供了forward和include方法,简化重定向和转发的操作

区别:
1.要在页面上输出2+3=5,则对应的程序代码应为 2+3= 2 + 3 2. 要在页面上输出 2 + 3 = {2+3} 2.要在页面上输出2+3= 2+32.要在页面上输出2+3={2+3},则对应的程序代码应为 2+3=${2+3}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值