文章目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210503000718796.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21tbW1tQ0pQ,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021050300073860.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21tbW1tQ0pQ,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210503000748892.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21tbW1tQ0pQ,size_16,color_FFFFFF,t_70)
一、 web
1、web概述
Web(World Wide Web)即全球广域网,也称为万维网。它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分布式图形信息系统。是建立在Internet上的一种网络服务,为浏览者在Internet上查找和浏览信息提供了图形化的、易于访问的直观界面,其中的文档及超级链接将Internet上的信息节点组织成一个互为关联的网状结构。
简而言之web就是我们平时上网浏览的网页,玩的网页游戏,上网下载资源。对于程序员而言就是前端知识、web服务器知识和数据库知识的结合
WEB1.0 开始于1994年.网页是用来阅读,传递信息。 【公司主导】
WEB1.0的任务,其主要特征是大量使用静态的 HTML 网页来发布信息,并开始使用浏览器来获取信息,这个时候主要是单向的信息传递。是将以前没有放在网上的人类知识,通过商业的力量,放到网上去;从内容产生者角度看,WEB1.0是商业公司为主体把内容往网上搬。并没有解决人与人之间沟通、互动和参与的需求,所以Web2.0应运而生。中国黄页
WEB2.0 网页用来交互的。【用户主导】 推出;平台
例如: 微博、淘宝,社区、交友网站、视频网站等等 。这类网站开发常用的技术:java,php,.net(微软技术体系 asp.net c#.net vb.net) 、ruby、python ...
Web2.0 则更注重用户的交互作用,用户既是网站内容的浏览者,也是网站内容的制造者。
2、JavaWeb
概念:用Java技术来解决相关web互联网领域的技术总和【用java技术开发web服务应用(软件)】(Web前端+Web后台)。
比如:京东网站,就是用Java开发的。我们可以通过浏览器访问。
1)软件架构模式
生活中,我们从网络中获取资源的方式通常有两种
B/S架构:又称Browser/Server架构,即浏览器和服务器架构模式。它是通过浏览器 和后台服务器 进行交互的,如淘宝,京东,12306,百度等等。
- 优点:
- 用户只需要安装一个浏览器即可访问不同的服务器,不需要安装很多客户端,节约硬盘资源;
- 系统更新和升级比较方便;
- 跨平台优势;
- 缺点:
- 动画效果受浏览器限制;
- 网站的压力集中在服务器端。
C/S架构:又称Client/Server架构,及客户端和服务器架构模式。它是通过客户端 和服务器 进行交互的,如QQ,迅雷,360,百度网盘等等。
- 优点:
- 客户端效果炫,用户体验好;
- 客户端能够进行部分计算功能,减轻服务器的压力;
- 缺点:
- 需要安装客户端,占用硬盘空间;
- 系统升级麻烦,需要安装很多升级包;
注:B/S模型可以理解为一种特殊C/S模型。
B/S优势:
B/S是基于网页语言的、与操作系统无关,所以跨平台也是它的优势,而且以后随着网页语言以及浏览器的进步,
B/S表现能力上的处理以及运行的速度上会越来越快,它的缺点将会越来越少。
比如,现在的HTML5,在图形的渲染方面以及音频、文件的处理上已经非常强大了。
所以,B/S架构将是未来的软件架构趋势 。
共同点:
1、基于请求-响应交互模型
浏览器(客户端)向服务器 发送一个请求
web服务器向浏览器(客户端)回送 一个响应
一次请求、一次响应
2、必须先有请求 再有响应
3、请求和响应成对出现
2)web资源
通过浏览器从网络中访问的资源我们称之为WEB资源
1. 静态资源: 指web页面中供人们浏览的数据始终是不变的。无论何时,在任何人的电脑上访问,页面都是一样的。就是我们前面学习的前端内容。比如:HTML、CSS、JS、图片、音频、视频等。
2. 动态资源: 指web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同。
比如:你在不同时间搜索微博的热门话题内容是不一样的,每天的天气情况也是变化的。每次访问购物网站登陆的时候,会显示我们自己的用户名等。这些数据由程序生成,JSP/Servlet、ASP等技术都可以完成。
总结:
静态资源的数据都是写死在页面上的固定不变。
动态资源,浏览器访问的结果是变化的(动态web资源就是你的数据都是程序读取数据库生成的数据)。
注意:
学习javase的时,运行要有main方法,因为他是程序的开始。而junit框架使用@Test注解提供入口可以让程序开始运行,仅仅只是为了测试而诞生的。
这里我们会使用浏览器访问我们书写的后台服务器,而`浏览器页面中的每个按钮都可以看作为一个入口`,只要点击每个按钮那么后台服务器就会接收前端页面的请求,后台服务器就会开始执行,并且将数据响应给浏览器。
3)URL请求路径
URL (Uniform Resource Locator)
统一资源定位符是对互联网上资源位置的一种表示,互联网上的每个文件都有一个唯一的URL。
协议://ip或者域名:端口号/资源位置
协议,http、https、ftp等
域名,域名或IP地址,能够帮我们定位到互联网上的某一台服务器
端口号,端口号是一个应用程序在一台服务器上的编号。http协议的默认端口号:80
资源位置,用于描述WEB资源在服务器上的位置参数=值,浏览器和服务器交互传递的数据。
二、tomcat服务器
官网地址:https://tomcat.apache.org
选择tomcat8.5版本,比较稳定。
tar.gz 文件 是linux和mac操作系统下的压缩版本
zip文件是window操作系统下压缩版本(我们选择zip文件)
1、服务器介绍
服务器硬件
可以把服务器理解成一台电脑主机,只不过这台电脑需要提供可靠的服务,
因此在处理能力,稳定性,安全性方面要求更高。
服务器只是一台设备,必须安装服务器软件才能提供服务。
在网络环境下,根据服务器提供的服务类型不同,
分为文件服务器,数据库服务器,应用程序服务器,WEB服务器等
服务器软件
本质上是一个应用程序(由代码编写而成),运行在服务器设备上。
能够接收请求并根据请求给客户端响应数据,发布资源(静态和动态)。
1)常见的web服务器软件
1、Tomcat:Apache组织提供一个免费开源的小型的服务器软件。
支持Servlet和JSP规范,性能高。开源,免费,性能高。
2、WebLogic:Bea公司的一个收费的大型的服务器软件,后被Oracle收购。支持EE的所有的规范
3、WebSphere:IBM公司的一个收费的大型的服务器软件,支持EE的所有的规范。
4、JBoss:是一个基于J2EE的开放源代码的应用服务器。
JBoss核心服务不包括支持servlet/JSP的WEB容器,一般与Tomcat绑定使用。占用内存。
2)JavaEE规范
Java中所有的服务器厂商都要实现一组Oracle公司规定的接口,这些接口是称为JavaEE规范。不同厂商的JavaWeb服务器都实现了这些接口,在JavaEE中一共有13种规范。实现的规范越多,功能越强。
1、JavaSE 标准版的Java,开发一些客户端的程序,桌面应用程序。JavaTM Platform Standard Edition
2、JavaEE 企业版的Java,开发运行在服务器上程序,必须以JavaSE为基础。Enterprise Edition
3、JavaME 用于嵌入式开发,手机移动端开发。不再使用。被安卓取代。
2、tomcat服务器【启动/关闭】
tomcat服务器是一个免费的开源的web应用服务器。**是Apache软件基金会的Jakarta项目中的一个核心项目,由Apache,Sun和其他一些公司及个人共同开发而成。**由于有了Sun的参与和支持,最新的Servlet和JSP规范总是能在Tomcat中得到体现。
因为tomcat技术先进,性能稳定,且免费。是目前比较流行的Web应用服务器。
将下载的zip文件解压后就是安装了,可以看到其中的目录结构
bin:脚本目录
启动脚本(启动服务器):startup.bat
停止脚本(停止服务器):shutdown.bat
conf:配置文件目录 (config /configuration)
核心配置文件:server.xml
用户权限配置文件:tomcat-users.xml
所有web项目默认配置文件:web.xml
lib:依赖库,tomcat和web项目中需要使用的jar包
logs:日志文件.
localhost_access_log.txt tomcat记录用户访问信息,..表示时间。
例如:localhost_access_log.2017-04-28.txt
temp:临时文件目录,文件夹内内容可以任意删除。
webapps:默认情况下发布WEB项目所存放的目录。
work:tomcat处理JSP的工作目录。
启动
双击tomcat解压目录/bin/startup.bat 文件即可启动tomcat
tomcat的默认端口为8080,所以在浏览器的地址栏输入:
http://ip:8080
即可访问tomcat服务器。
关闭
关闭startup.bat启动窗口;
双击tomcat的/bin/shutdown.bat文件;
Ctrl+C;
3、tomcat启动失败常见原因
##### (1) JAVA_HOME 配置
如果没有配置JAVA_HOME环境变量,在双击“startup.bat”文件运行tomcat时,将**一闪立即关闭**。
解决方式:需要正确配置JAVA_HOME环境变量,指向JDK的bin目录的上一级目录;
##### (2)端口号冲突
一台拥有ip地址的主机上可以提供多个服务(启动多个软件),
每一个服务都有一个唯一的端口号。所以端口号不能重复。
`【端口号冲突报错信息】
严重: Failed to initialize end point associated with ProtocolHandler ["http-bio-8080"]
java.net.BindException: Address already in use: JVM_Bind <null>:8080
...
Caused by: java.net.BindException: Address already in use: JVM_Bind
...
控制台将出现大量异常信息,描述的是8080端口被占用。
`【解决方案】
1. 修改tomcat端口
通过修改tomcat目录下conf/server.xml配置文件修改端口号。将8080修改成其他端口号。
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
2.终止占用端口号的程序
打开dos窗口,在dos窗口中输入如下命令:
netstat –nao
4、tomcat发布JavaWeb项目
>JavaWeb项目与java项目的区别:
>
>* java项目:后台代码;例如之前的javase.
>* JavaWeb项目:前端代码+后台代码;
1)企业中项目部署方式
直接发布
将web项目复制到tomcat的webapps目录下:
说明:我们在tomcat中发布的web项目都会存在于webapps文件夹下,如果这里使用手动发布项目,我们可以先在webapps文件夹下创建一个文件夹demo【文件名自拟】作为项目名,
然后在demo文件夹下新创键一个index.html页面作为该项目的主页,输入内容,
启动tomcat服务器即可。
url【http://ip:端口号/项目名/资源路径】
访问web目录下的index.html的url为:
http://localhost:8080/demo/index.html
**注意:**当我们在浏览器地址栏中不输入heima项目下的index.html也可以访问主页面中的内容,
http://localhost:8080/demo
这样也是可以的
原因:当我们启动tomcat服务器的时候,在tomcat服务下的conf文件夹下有个配置文件叫做web.xml.
这个文件中有如下代码:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--
这些代码称为欢迎页面,当我们在访问项目的时候如果不输入页面的时候,
那么就会默认访问项目下默认的欢迎页面,从上往下依次访问。
访问顺序:index.html、index.htm、index.jsp。
所以当我们在浏览器地址栏中不输入页面的时候就会访问欢迎页面。
-->
虚拟路径发布
优点:项目不需要发布在webapps下,因为webapps项目越多,导致tomcat启动越慢。
在conf/server.xml文件的host元素中配置Context(上下文)标签 | |
---|---|
path属性 | 虚拟访问目录的名称 |
docBase属性 | Web应用所在目录 |
案例:发布项目到e:\MyWeb\下,index.html文件
找到server.xml文件中148行,host元素,写下面的代码:
启动tomcat服务器,然后在浏览器上测试:http://localhost:8080/aaa/index.html
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
.........
.........
.........
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
-----------------------------------------------------------------------
<!--上下文路径,path表示访问地址,docBase表示要访问页面所属文件夹-->
<Context path="/aaa" docBase="e:\MyWeb"/>
-----------------------------------------------------------------------
</Host>
独立的xml配置发布
IDEA中默认是这种访问方式发布web项目
第一步:在tomcat/conf目录下新建一个Catalina目录(如果已经存在无需创建)
第二步:在Catalina目录下创建localhost目录
第三步:在localhost中创建xml配置文件,名称为:second(注:这个名称是浏览器访问路径,随便定义)
第四步:添加xml文件的内容为:
<?xml version="1.0" encoding="UTF-8" ?>
<Context docBase="E:/MyWeb" reloadable="true"/>
<!--
说明: reloadable="true"表示可以重复加载。
-->
第五步:在e:/MyWeb/下创建index.html
第六步:访问测试http://localhost:8080/second/index.html
2)IDEA配置tomcat直接发布项目
我们要想在idea中将项目发布到tomcat中,首先我们要先创建web项目。
1、File—New—Project/Module
2、选择Java Enterprise版本,选择jdk8,然后配置tomcat。
因为jdk11对于一些软件时不兼容的,例如tomcat,学到后面会报各种异常,企业主流也是jdk8
3、在创建项目的时候在下面勾选Web Application
4、然后next即可创建完成
5、在EditConfigurations中配置Tomcat Server,选择tomcat的安装路径。
注意:这里关联的tomcat home指的是tomcat的解压目录(bin目录的上一级目录)
WEB项目结构如下
WEB-INF目录下文件
**web.xml:**当前web项目的核心配置文件,可以管理整个web项目,创建完web项目自动生成。
Servlet2.5必须有。Servlet3.0注解开发可以省略。
**lib:**当前web项目所需要的第三方的jar包存放的位置。需要手动创建一个文件夹lib。
classes文件: .java源文件编译后生成的class文件存放的位置。不用手动创建,
运行程序会自动生成该文件夹并且将.java源文件对应的.class文件自动放到该文件夹下。
在创建好的web项目下新创键index.html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>在idea中创建的第一个javaweb项目</h1>
</body>
</html>
在idea中启动tomcat服务器
可以正常启动或者Debug模式启动。启动成功之后,会自动弹出index.html页面
当然我们也可以在页面浏览器地址栏中按照如下访问:http://localhost:8080/index.html
**注意:**当我们已经将tomcat启动了,当再次点击绿色三角即启动tomcat按钮的时候会出现如下所示的框:
Update resources:修改静态资源页面时,选择这个可以将修改后的静态资源页面部署到tomcat服务器上。
Update classes and resources:这里其实功能和第一个一样。
Redeploy: 表示.java源文件改变时重新部署代码,重新部署。
Restart server:表示.java源文件改变时重新部署代码,重新部署。关闭服务器和开启服务器。效率比较低。
页面资源热更新
对于静态页面每次修改之后都要重新部署,
所以我们可以在idea中配置页面资源热更新,这样每次修改静态页面之后就不会在重新部署了
三、Servlet服务器端小程序
1、Servlet介绍
Servlet 是 Server applet 简称
表示服务程序.是运行在服务端的Java小程序【属于服务器端的一个接口】。
sun公司提供一套规范,用来处理客户端请求、响应给浏览器的动态web资源。
其实servlet的实质就是java代码,通过java的API动态的向客户端输出内容,并且从客户端接收数据。
Servlet 的作用
接收请求 :接收客户端发送的请求数据
业务逻辑的处理
响应结果 :将处理结果响应给客户端(浏览器)
servlet服务
- 客户端(浏览器)发送的数据会被提交到服务器;
- 服务器必须具备:1.接收请求数据;2.处理请求数据(业务逻辑的处理);3.给浏览器生成响应信息的能力;
- tomcat服务器遵从了JavaEE规范,Sun公司制定的动态资源规范Servlet实现这个功能;(运行在服务器端,能够接收用户请求,处理请求数据和给浏览器生成响应信息)
- 在java的世界里制定规范往往是接口来实现的,所以Servlet是一个接口,里边只是定义了一些方法;
- 如果,我们对这个接口进行具体的实现,就能够完成对用户数据的接收,处理和生成响应信息;
2、Servlet简单开发
将html页面发布到tomcat服务器中,然后用户通过浏览器访问html页面,
那么用户也可以通过浏览器访问java的类,要想让用户能够访问到我们书写的java类,
可以按照如下做法:
1、java类希望让用户通过浏览器访问,需要将被访问的类实现规范(接口),这个规范(接口)称为Servlet。
这里不需要导入jar包,因为tomcat软件已经集成。
2、创建一个java类实现Servlet接口
3、由于Servlet属于接口,肯定有抽象方法,所以要求自定义实现类实现接口中的所有抽象方法主要是Servlet接口中的service方法,service方法主要是用来处理来自客户端的服务的
4、操作完成之后,客户端要想访问该类,必须使用Tomcat服务器帮助我们发布项目,需要通知tomcat,已经创建好了一个类,可以供外部访问
代码演示
编写实现Servlet实现类
public class HelloWorldServlet implements Servlet{
/*
处理客户端的服务
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service......");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {}
@Override
public ServletConfig getServletConfig() {return null;}
@Override
public String getServletInfo() { return null;}
@Override
public void destroy() {}
}
web.xml中书写如下内容:
<servlet>
<servlet-name>helloWorldServlet</servlet-name>
<servlet-class>com.itheima.sh.quickstart_01.HelloWorldServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloWorldServlet</servlet-name>
<!-- 【注意】 url-pattern 映射路径前面必须添加"/" -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
对上述标签的解释如下所示:
<servlet>// 将自定义类注册给tomcat,其实就是通知tomcat,有一个类可以被外部访问
<servlet-name></servlet-name> //类的一个别名,随便写,但是必须保证在当前web.xml文件中唯一
<servlet-class></servlet-class> //全限定类名 ,tomcat获得类可以帮助我们实例化对象,调用类中的方法。tomcat底层使用反射创建对象
//对象.方法
<servlet-mapping> //映射路径,给访问的类加路径
<servlet-name></servlet-name> //上面配置的别名,必须匹配已经存在的名称
<url-pattern></url-pattern> //被访问的路径,浏览器最后输入的访问路径,
例如:http://localhost:8080/hello
发布项目,启动项目,使用浏览器访问这个类;
注意:
使用idea创建的web项目,可以通过配置,访问路径中不需要添加项目名,具体配置如下:
Edit Configurations -> Deployment -> Application context [ 可写 / ]
配置好后:在浏览器中输入,访问路径为:http://ip:8080/hello
分析项目运行流程
之前的java项目中,我们运行一段程序都是使用main方法来运行的。
Servlet中没有main方法,那它是怎么运行的呢?
1.当我们点击run运行的时候,tomcat之所以会启动,是因为程序入口(main方法)在tomcat中
2.tomcat开始运行,会加载web项目里面的配置文件web.xml(xml解析,读取数据)
主要是根据url-pattern 找到对应的servlet-class
3.然后tomcat进入等待状态(永不停止,除非手动关闭)
4.当用户在浏览器中输入地址:http://localhost:8080/hello 就会定位到tomcat的访问的项目下面的某个servlet中
5**.tomcat会根据 /hello 的servlet的虚拟路径** 找到HelloServlet的全限定名
6**.tomcat底层通过反射创建HelloServlet的对象**,并调用HelloServlet的service方法:
Class clazz = Class.forName("全限定名"); Servlet servlet = clazz.newInstance();//实际上HelloServlet对象,向上转型 servlet.service();
3、Servlet编程优化方案
在上述的HelloWorldServlet中,实现Servlet接口后能够接收浏览器发送的请求。
由于Servlet是一个接口,我们实现接口后必须重写接口中所有的抽象方法。
但是,我们在接口请求和响应数据的时候只需要一个service方法就足够了。
所以,我们需要有选择地实现父接口中的方法。那么我们怎样做才能实现使用哪个方法就重写哪个方法呢?
可以在定义一个类GenericServlet来实现Servlet接口,这个类重写接口中的所有的抽象方法,然后让我们自定义类继承GenericServlet类,这样就可以只重写需要的方法了
1)方案一:继承GenericServlet抽象类
GenericServlet类是一个抽象类,它实现了多个接口,其中有一个是Servlet,
所以它重写了Servlet接口中的所有方法。我们只需要继承GenericServlet类,重写其中的service方法即可。
继承GenericServlet的优点
1、实现了Servlet接口,我们继承GenericServlet之后相当于间接实现了Servlet接口;
2、给我们提供了很多通用方法,这些方法已经帮我们实现了很多功能,继承GenericServlet之后可以直接调用这些方法**,GenericServlet相对于Servlet,进行了功能的扩展和衍生**;
3、GenericServlet是一个抽象类,里边只有一个抽象方法service(),我们继承GenericServlet之后只需要重写service()方法处理具体的业务逻辑即可,减少了直接实现Servlet接口带来的代码冗余;
代码演示 :使用GenericServlet优化Servlet接口编程
实现步骤 :
1、创建一个普通的java类继承GenericServlet;
2、在web.xml中配置这个GenericServlet的子类;
3、重写service方法,在service方法中完成接收从浏览器请求数据的功能;
编写一个普通的java类,ServletDemo1,继承GenericServlet;
package com.heima.servlet;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* @author suoge
*/
public class ServletDemo1 extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
}
}
在web.xml配置ServletDemo1
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>com.heima.servlet.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
重写service方法,并在service方法中书写以下代码,完成接收从浏览器请求数据的功能;
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("GenericServlet...");
}
启动tomcat并访问
127.0.0.1:8080/demo01
2)方案二:HttpServlet优化方案
在实际的生活中,客户端(浏览器)给我们发送的请求往往是HTTP协议下的请求,
所以我们只需要处理HTTP的请求和响应即可。也就是说我们需要的只是一个与HTTP协议相关的Servlet。
Sun公司为我们提供了HttpServlet,对GenericServlet再次进行扩展和功能加强。
实际开发中:我们编写Servlet就可以采用 继承HttpServlet来完成servlet的开发,
这样的Servlet我们可以获取更多的业务功能。
HttpServlet是GenericServlet的一个子类。
这个类是专门帮我们处理与HTTP协议相关的请求与响应的一个Servlet类,
在我们的日常生活中最常用的HTTP请求只有get请求和post请求。
所以我们在继承了HttpServlet之后只需要重写里边的doGet()方法和doPost()方法即可满足我们的需求。
继承HttpServlet优点
- HttpServlet继承了GenericServlet,功能比GenericServlet更强大;
- GenericServlet中处理不同的请求都使用service()方法,HttpServlet根据不同的请求方式提供了不同的方法进行处理。等于是细化了service()方法;
- HttpServlet类中的方法参数为HttpServletRequest对象和HttpServletResponse对象。使用这两个对象的好处在于:
- HttpServletRequest接口继承了ServletRequest接口,HttpServletResponse接口继承了ServletResponse接口。功能更强大;
- HttpServletRequest接口和HttpServletResponse接口为我们提供了很多处理HTTP协议相关的API,HTTP协议正是我们日常生活中使用得比较多的一种协议;
代码演示 :使用HttpServlet优化Servlet接口编程
编写FormServlet继承HttpServlet抽象类
/**
* @author suoge
*/
public class FormServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("处理get请求提交的数据.................");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("处理post请求提交的数据..................");
}
}
在web.xml配置FormServlet
启动tomcat并访问127.0.0.1:8080/demo01
4、源码分析
请求是怎么到达doGet()和doPost()的
在我们继承HttpServlet之后,重写了doGet()和doPost()方法。
浏览器发送的get请求会被doGet()接收并处理,浏览器发送的post请求会被doPost()请求接收并处理。
服务器端是怎么辨别我的请求是get还是post请求的呢?
下面,我们看一下HttpServlet的源码中的service方法:
- 实际处理请求的还是HttpServlet的service()方法;
- service方法中,接收请求之后获取了请求方式,
1.用户访问服务端都是http协议,使用HttpServlet专门来处理http协议的请求与响应,我们希望使用HttpServlet类的方法中的HttpServletRequest和HttpServletResponse,我们需要子接口,而之前给的是父接口ServletRequest和ServletResponse,所以需要强制类型转换。
2.之前无论是get还是post请求都是在service方法中处理,我们希望使用原子性思想,即如果是get请求就执行get方法,如果是post请求就执行post方法。对请求方式进行细分:
通过HttpServletRequest接口中的getMethod()方法来获取请求方式:
get请求,该方法获取GET字符串
post请求,该方法获取POST字符串
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取数据的请求方式
String method = req.getMethod();
//根据请求方式的不同,调用不同的方法
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
//调用doGet()方法
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
//调用doPost()方法
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
HttpServletRequest接口中的方法getMethod()可以获取用户的请求方式:
get请求:该方法获取字符串“GET”
post请求:该方法获取字符串“POST”
自定义HttpServlet的代码
public abstract class HttpServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//强制类型转换
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
this.service(request,response);
}
private void service(HttpServletRequest request, HttpServletResponse response) {
//获取请求方式
String method = request.getMethod();//GET POST
if("GET".equals(method))
{
//get
doGet(request,response);
}else if("POST".equals(method))
{
//post
doPost(request,response);
}else
{
//其他请求
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
}
}
HttpServlet类的子类
public class FormServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
//post请求执行的方法
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
//get请求执行的方法
System.out.println("get.....");
}
}
优化小结
Servlet编程的作用:接收浏览器的请求,处理请求数据,给浏览器响应数据;
- Servlet接口:
- Sun公司规定如果想要在服务端接收和响应客户端的数据,必须实现Servlet接口;
- 由于Servlet是一个接口,实现Servlet接口后必须重写其中所有的抽象方法;
- GenericServlet:
- GenericServlet:是一个抽象类,它实现了Servlet接口,与协议无关;
- 继承GenericServlet,只需要重写service方法即可接收和响应数据;
- HttpServlet:
- HttpServlet:是一个抽象类,它继承了GenericServlet,为HTTP请求定制的;
- 继承HttpServlet,重写doGet和doPost方法,能够更加方便地处理不同请求的数据;
两种报错状态码
响应状态码405
请求方法没有重写…
/*
注意: 如果我们不重写doGet/doPost方法, 那么父类的doGet/doPost方法会执行(继承)
给浏览器响应一个错误: 状态码405 (http1.1)
*/
响应状态码500
java代码写错了…
5、Servlet生命周期
- Servlet对象的创建:
- 创建者:tomcat;创建时机:在Servlet第一次被访问的时候;
- 特点:
- 只会创建一次(单例);
- 对象创建完成之后,会调用init()方法;
- Servlet运行:
- service()方法接收用户的请求,和处理响应;
- 特点:
- 每次对这个Servlet的访问都会由service()方法来处理;
- service()方法的两个参数:request和response对象专门用来处理请求和响应;
- Servlet销毁:
- Servlet对象在服务器正常关闭的时候销毁;
- 特点:
- 销毁的时候会调用destory()方法;
**1、tomcat创建servlet的对象,使用反射技术调用的是自定义servlet中的无参构造方法,所以自定义servlet中必须含有无参构造方法**
**2、初始化的目的是为了让Servlet对象在处理客户端请求前完成一些初始化的工作,如建立数据库的连接,获取配置信息等。对于每一个Servlet实例,init()方法只被调用一次。**(这里我们先了解)
**3、当关闭tomcat服务器的时候,tomcat就会使用servlet的对象调用servlet的destroy()方法,以便让该实例可以释放它所使用的资源,保存数据到持久存储设备中,该实例随后会被Java的垃圾收集器所回收。如果再次需要这个Servlet处理请求,Servlet容器会创建一个新的Servlet实例。**
【测试代码】
public interface Servlet {
/*
* Servlet对象创建后,使用对象立刻调用init()方法,只调用一次
*/
public void init(ServletConfig config) throws ServletException;
/*
* Servlet对象创建后,每次的请求都由service方法处理
*/
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
/*
* Servlet对象销毁前会调用destory方法。主要是用于释放一些资源。
*/
public void destroy();
}
【实现类】
package com.heima.user.web;
import javax.servlet.*;
import java.io.IOException;
public class LifeCycleTestServlet implements Servlet {
public LifeCycleTestServlet() {
System.out.println("创建对象执行构造方法");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init.....");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service.....");
}
@Override
public void destroy() {
System.out.println("destroy.....");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
}
执行的结果如下:
6、<load-on-startup>
Servlet对象优先级
问题
:普通的Servlet对象在我们第一次访问的时候创建, 开发中,如果我们需要在服务器启动的时候,初始化Servlet对象应该如何编写呢?
需求
:服务器tomcat启动,立刻加载配置文件,获取配置文件信息,为项目后续代码提供数据支持。
解决
:此时的业务场景,我们需要在web.xml文件中
给指定的Servlet添加一个标签<load-on-startup>
默认搜索 -1
实现步骤
:在web.xml
中在**标签内部中配置**:
2 — 传入正整数,整数越小,被创建的优先级就越高。12345
举例:上述我们在演示servlet的生命周期的时候,创建了LifeCycleServlet,如下:
public class LifeCycleTestServlet implements Servlet {
public LifeCycleTestServlet() {
System.out.println("创建对象执行构造方法");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init.....");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service.....");
}
@Override
public void destroy() {
System.out.println("destroy.....");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
}
如果我们想在tomcat服务器一启动的时候就初始化servlet对象,我们可以在web.xml文件中按照如下配置:
<servlet>
<servlet-name>lifeCycleServlet</servlet-name>
<servlet-class>com.itheima.sh.lifecycle_04.LifeCycleServlet</servlet-class>
<!--优先级是2-->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>lifeCycleServlet</servlet-name>
<url-pattern>/life</url-pattern>
</servlet-mapping>
注意:
对于2
- 传入正整数,整数越小,被创建的优先级就越高。12345
- 优先级越高,服务器启动的时候就越先被初始化。
7、 Servlet映射路径配置规范
在web.xml核心配置文件的标签:中的映射路径配置存在以下几种方式:
1. 完全匹配 /user/hello 资源路径为/user/hello时可以访问
2. 目录匹配 /user/* 资源路径中含有/user目录均可访问
3. 后缀名匹配 *.do 资源路径中以.do结尾的均可访问
4. 缺省路径 / 访问的路径找不到,就会去找缺省路径
tomcat获得匹配路径时,优先级顺序:1 >2 > 3 > 4
注意:开发中一般使用完全匹配,即一个Servlet对应一个映射路径。
1)完全路径匹配
完全路径匹配就是在映射路径这里<url-pattern></url-pattern>
配置什么就在浏览器地址栏访问什么。
代码演示如下所示:
创建一个PathOneServlet继承GenericServlet,代码如下:
public class PathOneServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("PathOneServlet......");
}
}
web.xml配置文件中的代码:
<servlet>
<servlet-name>pathOneServlet</servlet-name>
<servlet-class>com.itheima.sh.pathservlet_05.PathOneServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathOneServlet</servlet-name>
<!--全路径访问-->
<url-pattern>/user/path</url-pattern>
</servlet-mapping>
注意:/user/path 这里书写的内容不固定,也就是说不一定是user或者path。随便定义。
浏览器地址栏访问:127.0.0.1:8080/user/path
2)目录匹配
目录匹配 :/user/*
1、当前路径以及子路径都可以访问到servlet。也就是说只要资源路径中含有/user目录均可访问servlet。
2、上述路径不一定是user,内容随便书写。
创建一个PathTwoServlet继承HttpServlet
public class PathTwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("PathTwoServlet。。。");
}
}
web.xml配置文件中的代码:
<servlet>
<servlet-name>pathTwoServlet</servlet-name>
<servlet-class>com.itheima.sh.pathservlet_05.PathTwoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathTwoServlet</servlet-name>
<!--目录匹配访问-->
<url-pattern>/user/*</url-pattern>
</servlet-mapping>
浏览器地址栏访问:只要在浏览器地址栏中输入的地址前面是http://localhost:8080/user,后面的内容随便写。
或者http://localhost:8080/user/kajaja/alakal
idea的控制台输出结果:
PathTwoServlet。。。
PathTwoServlet。。。
3)后缀名匹配
后缀名匹配:*.do
只要资源路径中以.do结尾的均可访问servlet
.
创建一个PathThreeServlet继承GenericServlet,代码如下所示:
public class PathThreeServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("PathThreeServlet....");
}
}
web.xml配置文件中的代码:
<servlet>
<servlet-name>pathThreeServlet</servlet-name>
<servlet-class>com.itheima.sh.pathservlet_05.PathThreeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathThreeServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
注意:上述路径*.do。不一定是do,其他的内容也可以。
浏览器访问:
http://localhost:8080/jahahah/alakk.do
4)缺省路径
缺省路径 : / . 如果在浏览器输入访问servlet的路径在web.xml中不存在那么就会去找缺省路径。
创建PathFourServlet类继承GenericServlet:
public class PathFourServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("PathFourServlet....");
}
}
web.xml配置文件中的代码:
<servlet>
<servlet-name>pathFourServlet</servlet-name>
<servlet-class>com.itheima.sh.pathservlet_05.PathFourServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathFourServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
浏览器访问:http://localhost:8080/jahahah/alakkkajaajaj
访问的路径不存在,则找缺省路径。
8、请求路径相对/绝对路径
现阶段我们访问资源的方式越来越多,请求路径在编写时难免出现混淆
- 浏览器的地址栏 (输入服务器某个资源地址,敲回车会发送请求)
- a标签的href属性 (超链接被点击的时候会发送请求)
- form表单的action属性 (form中的submit按钮被点击的时候,发送请求)
- js的loation.href属性 (只要设置, 触发相应的)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>path</title>
</head>
<body>
<h3>测试访问路径:http://localhost:8080/day08_servlet_xml/static/path.html</h3>
<h4>绝对路径</h4>
<!--
在开发时,强烈建议使用绝对路径
完整:协议://域名:端口/映射路径名/资源名
推荐:/映射路径名/资源名 (省略了三要素,前提: 当前页面和所访问的资源必须在同一服务器上)
注意绝对路径最前面需要加/
-->
<a href="http://localhost:8080/day08_servlet_xml/quickServlet">带http协议的绝对路径:quickServlet</a> <br>
<a href="/day08_servlet_xml/quickServlet">不带http协议的绝对路径:quickServlet</a>
<h4>相对路径路径</h4>
<!--
相对路径语法:
./ 当前目录 注:./可以省略不写
../ 上级目录
-->
<a href="../quickServlet">相对路径:quickServlet</a>
</body>
</html>
对于相对路径不是看项目,而是看浏览器地址栏访问的资源路径。
举例:
假设我们在浏览器地址栏访问的页面路径:
http://localhost:8080/index.html
而在index.html页面想使用相对路径访问servlet:
http://localhost:8080/hello
那么对于上述两个路径而言只有最后一级目录不一样,所以在index.html中直接使用 ./hello 表示在当前路径下查找hello的servlet,当然了这里./可以省略不写 直接书写 <a href="hello">相对路径:helloServlet</a>
总结:开发中建议书写绝对路径,如果层级比较多,相对路径书写太麻烦并且容易产生错误。
9、Servlet3.0注解开发
在我们上面创建的Servlet中,Servlet的配置信息都是在web.xml中完成的。
如果我们创建的Servlet非常多,就会导致web.xml中的配置非常臃肿,不便于管理。
Servlet3.0为我们提供了注解支持,创建Servlet的时候。
在这个Servlet类上面添加注解就可以完成Servlet的配置。
这样对于创建的servlet类就不用在web.xml配置文件中配置了。
1)Servlet3.0新特性及优点
该版本新增了若干注解,用于简化 Servlet、过滤器(Filter)和监听器(Listener)的声明,
这使得 web.xml 部署描述文件从该版本开始不再是必选的了。就是可以不再需要web.xml文件了。
web.xml中配置过多servlet不便于管理,容易出错;
注解开发使得开发更敏捷,效率更高;
注解开发是公司未来开发的一种趋势;
2)使用IDEA创建Servlet3.0版本的web项目
新版的IDEA(2017版本)创建的Servlet默认是3.0版本的,
所以我们只需要新建一个Servlet,然后用注解配置即可。具体步骤如下:
1、新建一个Servlet;
在包上面点击鼠标右键New–>Servlet,给这个Servlet取个名,然后点击OK
2、配置Servlet
创建完成后,Servlet类上面会默认添加一个注解
@WebServlet(name="Servlet3Demo")
。这个
@WebServlet
注解就是用来配置当前这个Servlet的。这个注解中常用的有两个属性:
- name属性: 相当于web.xml的 ;
- urlPatterns属性: 编写访问servlet的路径 类似于
所以,我们需要手动在
@WebServlet
注解中添加urlPatterns
属性,来设置映射路径。
package com.heima.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author suoge
* 1. name属性: 相当于web.xml的 <servlet-name>;
* 2. urlPatterns属性: 编写访问servlet的路径 类似于 <url-pattern>
*/
@WebServlet(name = "Servlet3Demo",urlPatterns = "/servlet3")
public class Servlet3Demo extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
第三步:启动tomcat并访问
访问路径:
http://localhost:8080/servlet3
;运行结果:
其实到这里我们已经完成了servlet3.0的注解开发。
但是对于我们使用注解开发,我们只需要在浏览器输入@WebServlet注解中的属性urlPatterns 的属性值即可,我们不需要name属性,所以我们可以在idea中更改下servlet生成注解的模板代码。
3)优化
优化一
基于IDEA的模板,快速创建Servlet。
【模板配置代码】在idea中按照如下操作即可完成修改servlet的注解模板代码:
打开设置Settings—>搜索框输入tempplate---->找到 File and code Templates---->到右边点击other---->到下面选择Web----->然后选择Servlet Annotated Calss.java---->到原来的模板中只需要修改两个地方,
一个是在doPost方法体中加入:doGet(request,response); 来调用doGet方法。
另外一个是将
WebServlet(name = "${Entity_Name} ")
变为WebServlet("/${Entity_Name}")
注意:不要将下面的所有的代码都复制你的idea中,只是修改两个地方即可。
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")![在这里插入图片描述](https://img-blog.csdnimg.cn/20210503001615752.bmp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21tbW1tQ0pQ,size_16,color_FFFFFF,t_70)
@javax.servlet.annotation.WebServlet("/${Entity_Name}")
public class ${Class_Name} extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {
doGet(request,response);
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {
}
}
WebServlet注解中的属性含义
优化二
在doPost方法中调用doGet方法。这样我们的代码都在goGet()方法里写就可以了。
说明:好处是无论前端浏览器是get还是post请求,我们都可以在doGet方法中完成代码的书写。否则在开发的时候有可能会导致是get请求却在doPost方法中完成的代码,或者是post请求却在doGet方法中完成的代码,导致我们无法看到代码完成的效果。
10、Servlet开发常用版
@WebServlet("/lastDemo")
public class LastDemoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
总结
`tomcat
【1】tomcat:web服务器-运行web资源(静态资源+动态资源)
【2】默认端口:8080
【3】项目部署: 把项目交给tomcat运行
企业应用:
1、直接部署: 直接把web项目复制到webapps目录
2、虚拟路径: conf/server.xml==》 Host中<Context path="/aaa" docBase="E:\MyWeb" />
3、独立xml文件: conf/Catalina/localhost/ ==》 aa.xml ==>
<Context docBase="E:\MyWeb" reloadabl="true" />
开发阶段:
把tomcat配置到idea中,直接通过idea启动
`servlet
【1】Servlet:Sun公司制定的动态资源规范
运行在web服务器中的,java程序。 接收用户请求,处理请求,响应数据;
【2】Servlet入门开发:xml配置
1、新建类,实现Servlet接口;
2、重写所有抽象方法。在service方法中处理请求
3、配置Servlet:
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.heima....HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
【3】Servlet生命周期:
创建时机:第一次访问时,被创建;------单例的
【4】Servlet优化过程:
实现接口(Servlet)
继承抽象类(GenericServlet)
继承抽象类(HttpServlet)
【5】url-pattern配置规则:
1、全路径匹配 /web/a
2、目录名 /user/* /*
3、后缀名 *.xxx
4、缺省路径 /
【6】注解:
@WebServlet(name="",value={"/demo1","/demo2"})
@WebServlet("/queryAllServlet")
`Servlet3.0注解开发小结:
第一步:创建一个普通类继承HttpServlet,重写doGet和doPost方法;
第二步:在类上面添加注解 @WebServlet;
第三步:配置注解@WebServlet的值(映射路径);
@WebServlet注解配置简介:
【1】简单配置:@WebServlet("/annDemoServlet") 注解的默认值为value值,就等价于web.xml中<url-pattern>/annDemoServlet</url-pattern>;
【2】其他配置:@WebServlet(name = "AnnDemoServlet",urlPatterns = "/annDemoServlet") 其中的
name属性值等价于web.xml中<servlet-name>AnnDemoServlet</servlet-name>的值
urlPatterns的属性值等价于web.xml中<url-pattern>/annDemoServlet</url-pattern>的值
注意事项:web.xml配置方式和注解只能使用一种,基本统一使用注解开发。
四、HTTP协议
1、http概述
1)http概念
HTTP协议分为请求协议和响应协议,通信就是一次请求,一次响应。
**请求协议:**浏览器将数据以请求格式发送到服务器。
**响应协议:**服务器将数据以响应格式返回给浏览器。
什么是协议
:网络通信中,数据以固定的格式传输数据.
HTTP协议
:**超文本传输协议(HTTP,HyperText Transfer Protocol)**是互联网上应用最为广泛的一种网络协议。例如:
我们平常上网都应该完成过登录的过程,那么,浏览器是如何将用户名和密码传送给服务器的?浏览器发送数据是随意发送的吗?
其实浏览器和服务器通信是按照一定格式进行交互的。这就是协议!
我们浏览器和服务器是按照HTTP协议进行数据交互的。
简而言之:浏览器和服务器数据交换固定的格式。
2)发展背景
WWW文件(客户机/服务器网络)都必须遵守这个标准。
设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。
1960年美国人TedNelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。
Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC(一系列以编号排定的文件),其中著名的RFC 2616定义了HTTP 1.1
协议版本:
- HTTP/1.0,发送请求,创建一次连接,获得一个web资源,连接断开。
- HTTP/1.1,发送请求**,创建一次连接,获得多个web资源,连接断开。**
3)HTTP协议的特点
基于请求/响应模型的协议。请求和响应必须成对,先有请求后有响应。
HTTP协议的结构包括两部分
1、请求报文:浏览器给服务器发送的请求数据的格式。
请求报文主要包括:请求行 ,请求头 ,请求体 。
2、响应报文:服务器给客户端(浏览器)响应的数据格式。
响应报文主要包括:响应行 ,响应头 ,响应体 ;
HTTP的请求方式有8种,但是我们在实际应用中常用的也就是get和post。
请求方式 请求说明 OPTIONS 返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送’*'的请求来测试服务器的功能性。 HEAD 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息 GET 向特定的资源发出请求(a href="servlet"标签/js location.href=“servlet”,在浏览器输入网址) POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建或已有资源的修改 PUT 向指定资源位置上传其最新内容 DELETE 请求服务器删除Request-URI所标识的资源 TRACE 回显服务器收到的请求,主要用于测试或诊断 CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
4)get和post区别
1、GET请求:
1)请求行直接传递请求参数,将请求参数追加在URL后面,不安全。例如:form.html?username=jack&username=1234
补充:get请求可以作为商品的分享。
2)URL长度限制(不同浏览器限制大小不一致),GET请求方式的数据大小,不可以传输数据量较大或者非文本数据。例如图片或者视频。
3)请求体里面没有内容。
2、POST请求:
1)请求参数以请求体形式发送给服务器,数据传输安全。2)请求数据可以为非文本数据,可以传输数据量较大的数据。
3)只有表单设置为method=”post”才是post请求,其他的都是get请求。
常见GET请求:地址栏直接访问、、
等
5)HTTP请求报文【浏览器抓包】
(1)请求报文组成
【请求行】
请求行位于请求报文的第一行:url 请求方式 协议/版本
可能由于浏览器的原因我们看不到请求协议和版本。
【请求头】
位于请求行的下面,以键值对 的形式给服务器传递信息,有些请求头信息是非必须的。
【请求体】
get请求请求体为空;post请求的请求体传递请求参数 。
(2)案例演示
1、idea中创建html文件
<h2>GET请求</h2>
<form action="/getServlet" method="get">
用户名:<input type="text" name="username" value="zhangsan" /><br>
密码:<input type="text" name="pwd" value="123" /><br>
<input type="submit" value="提交"/>
</form>
<h2>POST请求</h2>
<form action="/postServlet" method="post">
用户名:<input type="text" name="username" value="zhangsan"/><br>
密码:<input type="text" name="pwd" value="123"/><br>
<input type="submit" value="提交"/>
</form>
2、idea中创建Servlet
GetServlet代码
@WebServlet("/getServlet")
public class GetServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//给浏览器响应数据
response.getWriter().print("response getServlet");
}
}
PostServlet代码
@WebServlet("/postServlet")
public class PostServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//给浏览器响应数据
response.getWriter().print("response postServlet");
}
}
**3、启动Tomcat服务器 **
浏览器访问request01.html页面分别操作,观察NetWork中的请求白文段
点击GET请求提交按钮,然后按下快捷键F12 :【GET请求抓取包的内容】
请求参数追加在URL后面,不安全
【请求行】
Request URL: http://localhost:8080/getServletusername=lisi&password=1234
Request Method: GET
【请求头】
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
......
......
Host: localhost:8080
Referer: http://localhost:8080/demo01.html
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
【请求体】
点击POST请求提交按钮,然后按下快捷键F12:【POST请求抓取包的内容】
请求参数以请求体形式发送给服务器,数据传输安全
【请求行】
Request URL: http://localhost:8080/postServlet
Request Method: POST
【请求头】
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
......
......
Host: localhost:8080
Origin: http://localhost:8080
Referer: http://localhost:8080/demo01.html
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
【请求体】
username: lisi
password: 1234
6)HTTP响应报文【浏览器抓包】
由于浏览器的原因,有的会把请求行和响应行信息放在一起;get和post请求的响应没有明显区别
抓取的响应报文如下图所示:
(1)响应报文组成
【响应行】
响应行格式:协议/版本 状态码
如:HTTP/1.1 200 ;
常见状态码:
状态码 | 状态码描述 | 说明 |
---|---|---|
200 | OK | **请求已成功,**请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。 |
302 | Move temporarily | 重定向,请求的资源临时从不同的 地址响应请求。 |
304 | Not Modified | **从浏览器缓存中读取数据,不从服务器重新获取数据。**例如,用户第一次从浏览器访问服务器端图片资源,以后在访问该图片资源的时候就不会再从服务器上加载而直接到浏览器缓存中加载,这样效率更高。 |
404 | Not Found | 请求资源不存在。通常是用户路径编写错误,也可能是服务器资源已删除。 |
403 | Forbidden | 服务器已经理解请求,但是拒绝执行它 |
405 | Method Not Allowed | 请求行中指定的请求方法不能被用于请求相应的资源 |
500 | Internal Server Error | 服务器内部错误。通常程序抛异常 |
【响应头】
响应头也是用的键值对key:value,服务器基于响应头通知浏览器的行为。
响应头Key | 响应头value |
---|---|
location | 指定响应的路径,需要与状态码302配合使用,完成重定向 |
content-Type | 响应正文的类型(MIME类型,属于服务器里面的一种类型,例如文件在window系统有自己的类型,.txt .doc .jpg。文件在服务器中也有自己的类型),同时还可以解决乱码问题。例如:text/html;charset=UTF-8 |
content-disposition | 通过浏览器以附件形式解析正文,例如:attachment;filename=xx.zip |
refresh | 页面刷新,例如:3;url=www.itcast.cn //三秒刷新页面到www.itcast.cn |
MimeType:标识数据类型
最早的HTTP协议中,并没有附加的数据类型信息,所有传送的数据都被客户程序解释为超文本标记语言HTML 文档,而为了支持多媒体数据类型,HTTP协议中就使用了附加在文档之前的MIME数据类型信息来标识数据类型。
MIME意为多功能Internet邮件扩展,它设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩。
每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。
常见的MIME类型(通用型)
windows tomcat
--------------------------------------------
超文本标记语言文本 .html text/html
xml文档 .xml text/xml
XHTML文档 .xhtml application/xhtml+xml
普通文本 .txt text/plain
PDF文档 .pdf application/pdf
Microsoft Word文件 .word application/msword
PNG图像 .png image/png
GIF图形 .gif image/gif
JPEG图形 .jpeg,.jpg image/jpeg
......
----------------------------------------------
【响应体】
响应体,就是服务器发送给浏览器的数据。
当前浏览器向服务器请求的资源是html文件,那么服务器给浏览器响应的数据是一个html页面。
当请求是servlet,那么浏览器的响应体接收到的是servlet响应的数据
五、HttpServletRequest&HttpServletResponse接口对象
HttpServletRequest接口
HttpServletRequest实现ServletRequest父接口
ServletRequest 兼容大部分协议,HttpServletRequest 只兼容HTTP协议
HttpServletRequest 对象代表客户端请求,tomcat创建HttpServletRequest 对象,
并将该对象作为参数传递给servlet的service方法。
HTTP请求中的所有信息都封装HttpServletRequest接口的对象中,通过这个对象的方法,
可以获得客户端信息。
作用:
- 获取请求行信息:请求方式,url,ip地址和HTTP版本。
- 获取请求头信息:浏览器类型,ip地址等。
- 获取请求参数或者请求体中的数据:url后面拼接的参数或者请求体中提交的参数;
HttpServletResponse接口
HttpServletResponse实现ServletResponse父接口
ServletResponse兼容大部分协议,HttpServletResponse 只兼容HTTP协议
HttpServletResponse对象代表服务器响应,tomcat创建HttpServletResponse对象,
并将该对象作为参数传递给servlet的service方法。
作用:设置响应行、头、体
响应行:协议版本号 状态码
200(一切正常) 404(找不到资源路径) 500(服务器报异常)
302(和location一起使用,实现重定向) 304(从浏览器缓存中读取数据)
响应头:
location 指定响应的路径
content-type:告诉浏览器文件格式,告诉浏览器不要解析html文件,解决中文乱码问题
refresh 定时刷新
content-disposition 以附件形式展示图片等资源
响应体:
服务器处理的结果响应到浏览器中
1、Request对象常用API
1)获取【请求行】信息的方法
方法StringBuffer getRequestURL() 的返回值是StringBuffer ,它也表示字符串缓冲区,
StringBuffer 是多线程安全的,效率低。
StringBuilder 多线程不安全的,效率高。
方法 | 说明 |
---|---|
String getMethod() | 获取请求方式的类型 字母是大写的 |
StringBuffer getRequestURL() | 获取客户端发出请求完整URL |
String getRemoteAddr() | 获取IP地址 |
String getProtocol() | 获取当前协议的名称和版本 |
如果浏览器地址栏中的地址为:http://localhost:8080/rowServlet ,
获取的ip地址为:0:0:0:0:0:0:0:1。
0:0:0:0:0:0:0:1是ipv6的表现形式,对应ipv4来说相当于127.0.0.1,也就是本机。
导致上述的原因是客户端和服务器在同一台电脑上。
如果不想出现ipv6版本的ip地址格式,在访问网址的时候可以书写127.0.0.1。
或者在访问servlet的时候,输入具体的ip地址,
假设我的电脑ip地址是:192.168.29.10
访问servlet的时候这样输入:http://192.168.29.10:8080/rowServlet
那么这里获取的ip地址:remoteAddr = 192.168.29.10
2)获取【请求头】信息的方法
浏览器的请求头信息是由很多:
关键字:值
即key:value 形式的数据组成的。
请求头key | 请求头value |
---|---|
referer | 浏览器通知服务器,当前请求来自何处,如果是直接访问,则不会有这个头。 |
If-modified-Since | 浏览器通知服务器,本地缓存的最后变更时间。与另一个响应头组合控制浏览器页面的缓存。 |
cookie | 与会话有关技术,用于存放浏览器缓存的cookie信息。 |
user‐agent | 浏览器通知服务器,客户端浏览器与操作系统相关信息 |
connection | 保持连接状态。Keep-Alive 连接中,close 已关闭 |
host | 请求的服务器主机名 |
content-length | 请求体的长度 |
content-type | 如果是POST请求,会有这个头,默认值为application/x-www-form-urlencoded,表示请求体内容使用url编码 |
accept | 浏览器可支持的MIME类型。文件类型的一种描述方式。 |
mime格式 | 浏览器请求数据的类型,例如: text/html ,html文件 text/css,css文件 text/javascript,js文件 image/*,所有图片文件 |
accept-encoding | 浏览器通知服务器,浏览器支持的数据压缩格式。如:GZIP压缩 |
accept-language | 浏览器通知服务器,浏览器支持的语言。各国语言(国际化i18n) |
… | … |
HttpServletRequest对象提供了两个方法获取请求的头信息
1、String getHeader(String name) 根据请求头的key关键字获取请求头信息
2、Enumeration getHeaderNames() 返回此请求包含的所有头信息的key,属于对枚举类型进行遍历
/*
枚举属于一种特殊的数据类型,类似于集合,对他遍历也是类似于集合遍历方式。
Enumeration类似于Iterator的迭代器。
区别:
Enumeration 迭代1.2之前集合和枚举类型的。
Iterator 迭代1.2之后的集合。
*/
代码演示
@WebServlet("/headerServlet")
public class HeaderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
--------------------------------------------------
//获取请求头信息
//获取所有请求key信息
Enumeration<String> headerNames = request.getHeaderNames();
//取出每个key
while (headerNames.hasMoreElements()){
System.out.println(headerNames.nextElement());
}
//获取user-agent 对应value值
String header = request.getHeader("user-agent");
System.out.println("header = " + header);
--------------------------------------------------
}
}
3)获取【请求体】参数【重要】
get请求:get请求提交的数据是拼接在url后面的
post请求:post请求的数据是在请求体中发送到后台的
通过上面抓包对比,发现数据传递的格式都是:
name=value
;
方法名 | 描述 |
---|---|
String getParameter(String name) | 获得指定参数名对应的值。如果没有返回null,如果值有多个获得第一个。 例如:username=lisi。注意:参数name是form表单中的name属性值。 |
String[] getParameterValues(name) | **获取请求数据的key相同的多个数据,一般获取的是复选框。**例如爱好选项。 |
Map<String,String[]> request.getParameterMap(); | 获得表单中所有的数据,key表示input标签name的属性值:,value是一个数组,表示input输入框的值 |
案例演示
1、编写用户表单user.html,
提供表单字段:username、password、hobby、education,以post方式提交。
<form action="/requestServlet" method="post">
用户名:<input type="text" name="username"/><br/>
密码: <input type="text" name="password"/><br/>
爱好: <input type="checkbox" name="hobby" value="basketball"/> 篮球
<input type="checkbox" name="hobby" value="football"/> 足球
<input type="checkbox" name="hobby" value="film"/> 电影 <br/>
学历:<select name="education">
<option value="gz">高中</option>
<option value="dz">大专</option>
<option value="bk">本科</option>
</select><br>
<input type="submit" value="post提交"/>
</form>
2、编写Servlet接受用户表单发送的数据
@WebServlet("/requestServlet")
public class RequestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//请求参数/请求体API
//获取用户名
String username = request.getParameter("username");
System.out.println("username = " + username);
//请求爱好
String[] hobbies = request.getParameterValues("hobby");
String s = Arrays.toString(hobbies);
System.out.println("s = " + s);
//获取学历
String education = request.getParameter("education");
System.out.println("education = " + education);
//获取表单所有信息
/*
Map集合的key:表单的name属性值。
Map集合的value:以String类型的数组形式存储表单提交的每一项的值。
*/
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> strings1 = parameterMap.keySet();
System.out.println("strings1 = " + strings1);
//获取用户输入所有值
Collection<String[]> values = parameterMap.values();
for (String[] strings : values) {
System.out.println(strings.length);
System.out.println("strings = " + Arrays.toString(strings));
}
}
}
4)BeanUtils工具包获取请求参数【重要】
概念
BeanUtils 是 Apache commons组件的成员之一,主要用于简化JavaBean封装数据的操作。
它可以给JavaBean封装一个字符串数据,也可以将一个表单提交的所有数据封装到JavaBean中。
条件
BeanUtils 表单项的name属性值 和 javaBean实体类的属性名一致
案例场景:只有4个属性,封装比较简单, 如果有40个,还那么些很冗余
原理:
解决: BeanUtils (apache出品工具包),简化封装javaBean数据的代码 1.在WEB-INF 目录下 新建 lib目录 导入jar包: commons-beanutils.jar commons-logging.jar 2. 编写代码 BeanUtils.populate(bean,map) BeanUtils.populate(bean,map)方法底层原理: 反射(内省) BeanUtils.populate(user,map); 1. 遍历这个map key value eg: username 李四 2. 方法反射 Class clazz = user.getClass(); // User.class 对象 Method 指定的方法 = clazz.getMethod(方法名,方法参数列表对应Class对象); method.invoke(调用此方法的对象,实参); 例如: // setUsername 根据map中遍历出来的key 推导来的 //获取User类里的setUsername方法对象 Method method = clazz.getMethod("setUsername",String.class); //李四 就是 map中遍历出来的key对应的value method.invoke(user,"李四") // 相当于 user.setUserName("李四") 总结: javaBean 的 setXxx 的 Xxx 跟Map的key一致 !!! 1. map中的key跟表单项的name属性值 一致 2. setXXX 习惯于 本类的 属性名一致 最终结论: 表单的name 跟 javaBean的属性名要一致
什么是POJO ?
POJO(Plain Old Java Object)这种叫法是Martin Fowler、Rebecca Parsons和Josh MacKenzie在2000年的一次演讲的时候提出来的。
按照Martin Fowler的解释是“Plain Old Java Object”,从字面上翻译为“纯洁老式的Java对象”,但大家都使用“简单java对象”来称呼它。POJO的内在含义是指:那些没有继承任何类、也没有实现任何接口,更没有被其它框架侵入的java对象。
先给一个定义吧:
POJO是一个简单的、普通Java对象,它包含业务逻辑处理或持久化逻辑等,但不是JavaBean、EntityBean等,不具有任何特殊角色,不继承或不实现任何其它Java框架的类或接口。 可以包含类似与JavaBean属性和对属性访问的setter和getter方法的。
POJO(Plain Old Java Object)这个名字用来强调它是一个普通java对象,而不是一个特殊的对象。
2005年11月时,“POJO”主要用来指代那些没用遵从特定的Java对象模型,约定或框架如EJB的Java对象。
什么是JavaBean?
JavaBean实际上是指一种特殊的Java类,它通常用来实现一些比较常用的简单功能,并可以很容易的被重用或者是插入其他应用程序中去。所有遵循“一定编程原则”的Java类都可以被称作JavaBean。
JavaBean是一个遵循特定写法的Java类,是一种Java语言编写的可重用组件,它的方法命名,构造及行为必须符合特定的约定:
1、这个类必须具有一个公共的(public)无参构造函数;
2、所有属性私有化(private);
3、私有化的属性必须通过public类型的方法(getter和setter)暴露给其他程序,并且方法的命名也必须遵循一定的命名规范。
4、这个类应是可序列化的。(比如可以实现Serializable 接口,用于实现bean的持久性)
什么是Bean?
Bean并不需要继承特别的基类(BaseClass)或实现特定的接口(Interface)。Bean的编写规范使Bean的容器(Container)能够分析一个Java类文件,并将其方法(Methods)翻译成属性(Properties),即把Java类作为一个Bean类使用。Bean的编写规范包括Bean类的构造方法、定义属性和访问方法编写规则。
代码演示
user.html
<form action="/day09-request/ParamServlet" method="get">
用户 <input type="text" name="username" > <br>
密码 <input type="text" name="password" > <br>
性别
<input type="radio" name="gender" value="male"> 男
<input type="radio" name="gender" value="female"> 女 <br>
爱好
<input type="checkbox" name="hobby" value="smoke"> 舞蹈
<input type="checkbox" name="hobby" value="drink"> 跑步
<input type="checkbox" name="hobby" value="perm"> 看电影 <br>
<input type="submit">
</form>
实现HttpServlet抽象类处理请求
@WebServlet("/ParamServlet")
public class ParamServlet2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
// 一个name对应一个value
String username = request.getParameter("username");
String password = request.getParameter("password");
String gender = request.getParameter("gender");
String[] hobbies = request.getParameterValues("hobby");
//封装到数据到对象中(JavaBean)
// 第一种方法:一般API方法
User user1 = new User(); //空的对象
user.setUsername(username);
user.setPassword(password);
user.setGender(gender);
user.setHobby(hobbies);
System.out.println(user);
// 第二种方法:BeanUtils工具
User user2 = new User(); //空的对象
Map<String, String[]> map = request.getParameterMap();//获取所有请求参数
try {
BeanUtils.populate(user,map);
System.out.println(user);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
javaBean
/*
* JavaBean: java标准类 (三个必须规范)
* 1. public 空参构造
* 2. private 属性
* 2. public get set 方法
* */
public class User {
private String username;
private String password;
private String gender;
private String[] hobby;
// 一个类若不显式声明任何构造, 默认一个public空参构造(隐式声明)
省略toString
省略set/get方法
}
5)request作用域【重要】
request生命周期
创建:浏览器给服务器发送请求后,tomcat创建request对象封装请求数据;
销毁:服务器给浏览器响应信息结束后销毁;
特点:浏览器每次给服务器发送请求,服务器都会为这次请求创建一个新的request对象。
一次请求和响应的完整流程
1、浏览器向servlet发送请求
2、tomcat收到请求后,创建Request和Response两个对象,并将请求数据封装到request对象中,然后传递给Servlet
3、Servlet接收到请求后,调用doget或者dopost方法。处理浏览器的请求信息,然后通过Response返回tomcat服务器信息
4、tomcat接收到返回的信息,返回给浏览器。
5、浏览器接收到返回消息后,tomcat销毁Request和Response两个对象,同时销毁这两个对象所获得的信息。
(1)request域对象(重要)
web阶段需要对象来存储数据,获取数据和移除数据,就可以使用域对象来实现。
request域对象是一个容器,可以在一次请求中的多个servlet之间进行数据共享
一个存储数据的区域对象,是把request当成一个容器来存储数据,
request域存储数据主要是用于在两个servlet之间传递数据。
request作为域对象,常用的方法如下
// 1、往request域中设置值Object
void setAttribute(String name, Object o)
// 2、从request域中根据name取值,这里的name和setAttribute()方法中的第一个参数name一致
void getAttribute(String name)
// 3、从request域中移除值,这里的name和setAttribute()方法中的第一个参数name一致
void removeAttribute(String name)
【注意】
三个方法都是操作request中域对象中的数据,与请求参数无关。
getParameter()方法和getAttribute()方法的区别
getParameter()方法获取的是浏览器提交的数据(是表单提交的数据)
getAttribute()方法获取的是request域中的数据(即获取的都是通过request.setAttribute()设置的值)
案例演示
- 创建一个ScopeServlet类继承HttpServlet类;
- 往request域中设置值;
- 从request域中取值;
- 将request域中的值移除;
@WebServlet("/scopeServlet")
public class ScopeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 使用request域对象,进行存储值,删除值,获取值操作
Student student = new Student("李四","1234");
// 向request存储值
request.setAttribute("stu",student);
request.setAttribute("msg","张三");
// 可以获取值
String msg = (String) request.getAttribute("msg");
System.out.println("msg = " + msg);
// 移除request中值
request.removeAttribute("msg");
Object msg1 = request.getAttribute("msg");
if (null== msg1){
System.out.println("没有获取到值");
}
// 从request域中获取值
Student student1 = (Student) request.getAttribute("stu");
System.out.println("student1 = " + student1);
}
}
实体类
public class Student {
private String name;
private String password;
public Student(String name, String password) {
this.name = name;
this.password = password;
}
............
............
............
}
(2) 请求转发(重要)
request是域对象的一种,
主要是负责向request域对象中存储数据,然后以key作为键将数据取出。
这种使用存储和获取数据的方式在开发中最为常见的就是请求转发。
请求转发概念
当前servlet可以从其他servlet到某个html静态资源,还可以访问其他servlet。
之前使用到的请求都是从页面发出,然后请求到Servlet。
在Servlet中,请求也可以从一个Servlet发起,然后请求到另一个Servlet或静态页面。
这项技术叫做请求转发。
请求转发方法
方法 | 说明 |
---|---|
RequestDispatcher getRequestDispatcher(String path) | 获取请求转发器(该方法需要使用request对象调用)。参数:path指定指向资源的路径名的 String 。如果该路径名是相对的,那么它必须是相对于当前 servlet 的。 |
void forward(ServletRequest request, ServletResponse response) | 将请求转发到另一个资源(Servlet)上。参数:request表示客户端对 servlet 发出的请求的 ServletRequest 对象 response 表示 servlet 向客户端返回的响应的 ServletResponse 对象。 |
案例演示
案例一:从一个Servlet转发到一个静态页面;
注意:从OneServlet转发到dispatcher.html页面之后,浏览器地址栏并没有发生变化。
dispatcher.html
<h1>转发到html静态资源</h1>
接收Servlet转发到dispatcher.html
@WebServlet("/oneServlet")
public class OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("oneServlet...");
//转发到静态资源
request.getRequestDispatcher("/dispatcher.html").forward(request,response);
}
}
案例二:从一个Servlet转发到另一个Servlet;
注意:从TwoServlet转发到ThrServlet之后,浏览器地址栏并没有发生变化。
@WebServlet("/twoServlet")
public class TwoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 使用转发技术 去ThrServelt
// System.out.println("twoServlet...");
// 引入request域对象,向request存储值
request.setAttribute("flag","help me");
request.getRequestDispatcher("/thrServlet").forward(request,response);
}
}
@WebServlet("/thrServlet")
public class ThrServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//System.out.println("thrServlet...");
//获取request域对象中值
String flag = (String) request.getAttribute("flag");
System.out.println("flag = " + flag);
}
}
总结
转发是服务器内部的跳转行为;
从一个Servlet转发到另一个资源(静态或动态),能够实现跳转,
但是浏览器地址栏地址没有发生改变。因为对浏览器来说本质上就只有一次请求;
请求转发的时候,共享request域中的数据;
无论转发多少次,都是只有一次请求,同时会有一次响应;
6)POST请求中文乱码问题
(1)乱码产生原因
原因:Tomcat8只对于get请求处理了乱码问题。post请求并没有处理乱码。
所以我们要手动进行处理。在进行手动处理乱码之前,我们要知道乱码是如何产生的。
(2)解决POST乱码
默认情况下,tomcat服务器使用的的编码方式:iso-8859-1。
而html页面是utf-8,我们可以采用先编码在解码的方式来处理。
先将从页面获取的数据编码为iso-8859-1,然后在使用UTF-8进行解码。
方案一
URLEncoder属于java.net包下的类,专门用来对HTML表单进行编码的。该类中的静态方法:
URLDecoder属于java.net包下的类,专门用来对HTML表单进行解码的。该类中的静态方法:
// 使用特定的编码方案将字符串转换为指定的编码格式。
// 参数:s 要编码的字符串 enc 使用的编码表
static String encode(String s, String enc)
// 使用特定的编码方案解码指定字符串。
// 参数:s 要编码的字符串 enc 使用的编码表
static String decode(String s, String enc)
代码演示
//获取用户名和密码
String username = request.getParameter("username");
//方式一:
//编码
String encodeUsername = URLEncoder.encode(username, "iso-8859-1");
//解码
username = URLDecoder.decode(encodeUsername, "utf-8");
//方式二:
//编码
byte[] bytes = username.getBytes("iso-8859-1");
//解码
username = new String(bytes, "utf-8");
//方式二变为一行代码
username = new String(username.getBytes("iso-8859-1"), "utf-8");
String password = request.getParameter("password");
System.out.println("username = " + username);
System.out.println("password = " + password);
注意:
上述代码是可以解决post请求,可是如果换成get请求又会出现乱码。
因为Tomcat8已经对于get请求处理了乱码问题。换句话说get请求方式我们拿到的已经是正确的数据了,如果在使用iso-8859-1编码,然后使用utf-8解码,又会导致乱码。
所以我们可以使用另一种方式来解决post乱码。
方案二
使用request对象中的方法:setCharacterEncoding(String chasetName)
代码演示
//解决post中文乱码问题
request.setCharacterEncoding("utf-8");
//获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username = " + username);
System.out.println("password = " + password);
注意:
request.setCharacterEncoding(“utf-8”); 处理乱码一定放在获取数据的代码之前,
一般我们都放在方法第一句话。先设置编码,再获取数据。
request.setCharacterEncoding(“utf-8”);表示设置请求编码集,只对请求体中的数据有效。
而post具有请求体存放参数,get有请求体,但没有数据,所以只对post有效,get无效。
2、Response对象常用API
1)设置【响应行】信息方法
响应行:协议/版本 状态码 如:HTTP/1.1 200 。这里边的信息,我们通常只会用到状态码
// 向浏览器发送状态码
// 200响应成功 404资源路径错误或资源被删除 500服务器内部错误 302重定向
setStatus(int code)
2)设置【响应头】信息方法
key参考 四中的 第六小结 请求体
// 设置响应头信息
setHeader(String name,String value)
【常见响应头(key)】 key -> value
refresh 页面刷新,例如:3;url=http://www.itcast.cn //三秒刷新页面到http://www.itcast.cn
content-type 设置响应**数据的类型(MIME类型)**和**编码格式** 例如:text/html;charset=UTF-8
location 指定响应的路径,需要与状态码302配合使用,完成重定向。
content-disposition 通过浏览器以附件形式解析正文,例如:attachment;filename=xx.zip。
refresh跳转功能
// 实现refresh关键字跳转功能
// 方法具有2个参数 关键字 跳转地址
response.setHeader("refresh","3;url=http://www.baidu.com");
----------------------------------------------------------------
// 告诉浏览器不要解析html格式数据
response.setHeader("content-type","text/plain");
// 每次写这些方法,代码太多,而且API还经常使用
response.setContentType("text/plain");
response.getWriter().print("<html><body><h1>itcast</h1></body></html>");
// 告诉浏览器不要解析html格式数据
response.setContentType("text/html;charset=UTF-8");
text/plain的意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理。
处理响应乱码
服务器如果需要响应给浏览中文数据,tomcat使用
getWriter()
输出字符时,对于中文需要进行编码处理,而tomcat8 默认编码是
ISO-8859-1
,该码表是不支持中文编码的。所以响应给浏览器,出现乱码。
两种方法:
response.setHeader("content-type","text/html;charset=utf-8"); // 设置响应头
response.setContentType("text/html;charset=utf-8"); // 简写方式
//通过设置响应头
//1.设置响应的数据格式;
//2.设置响应数据的编码格式;
//response.setHeader("content-type","text/html;charset=utf-8");
//简化API
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("你好!浏览器!");
注意:
开发中通常使用
response.setContentType("text/html;charset=utf-8");
来处理响应乱码;处理响应乱码必须书写在响应数据之前才起作用;
重定向(重要)
重定向可以去一个servlet,也可以去一个html静态资源.
// 方式一:通过设置响应状态码和响应头实现重定向
response.setStatus(302);
response.setHeader("location", "/otherServlet");
// 方式二:重定向的简写方式
response.sendRedirect("/otherServlet");
转发和重定向的区别
转发和现在的重定向都可以完成跳转,都可以跳转到一个servlet,也可以跳转到一个html静态资源,
功能相同。那么他们之间有什么区别呢?
区别点 | 转发 | 重定向 |
---|---|---|
实现原理 | 服务器内部 | 浏览器执行 |
请求次数 | 一次 | 两次 |
浏览器地址栏地址 | 不变化 | 变为第二次请求的地址 |
能否共享request域 | 能够共享 | 不能共享 |
作用 | 共享request域对象 | 完成跳转 |
转发和重定向怎么选择
1、如果需要共享request域,必须使用转发;
2、如果需要将浏览器地址栏地址变为第二次请求的地址,必须使用重定向;
3)设置【响应体】信息方法
// 用于向浏览器输出二进制数据。【字节流--文件下载】
ServletOutputStream getOutputStream()
// 用于向浏览器输出字符数据。【字符流--给浏览器响应数据】
java.io.PrintWriter getWriter()
代码演示
// 方式一:response.getWriter().print(): 可以向浏览器打印任意任类型的数据
char[] arr = {'a','b'};
List<String> list = new ArrayList<>();
list.add("liuyan");
list.add("zhuyin");
list.add("guanxiaotong");
response.getWriter().println("hello");
response.getWriter().println('a');
response.getWriter().println(65);
response.getWriter().println(true);
response.getWriter().println(arr);
response.getWriter().println(list);
// 底层接收的数值都变成了字符串,只能打印 字符类型的数组
3、ServletContext域对象
tomcat服务器启动的时候,会为每个web项目创建一个唯一的ServletContext对象,
该对象代表当前整个Web应用项目。该对象不仅封装了当前web应用的所有信息,
而且实现了多个servlet的数据共享.在ServletContext中可以存放共享数据,
ServletContext对象是真正的一个全局对象,凡是web容器中的Servlet都可以访问。
在每个项目中可以有多个Servlet程序,每个Servlet程序都是独立的。
下面案例的配置信息,就必须使用描述这个项目的ServletContext对象获取。
方法名 | 描述 |
---|---|
setAttribute(String name,Object object) | 向ServletContext中存数据 |
getAttribute(String name) | 从ServletContext中取数据 |
removeAttribute(name) | 从ServletContext中移除数据 |
String getRealPath(String path) | 返回资源文件在服务器文件系统上的真实路径(文件的绝对路径) |
getMimeType(fileName) | 获取服务器中文件类型 |
ServletContext对象,tomcat为每一个web项目单独创建的一个上下文(知上知下贯穿全文)对象。
1.可以在多个servlet之间共享数据
存放:setAttribute()
获得:getAttribute()
删除:removeAttribute()
2.可以获得当前WEB项目中的指定资源(文件)
String path = getRealPath( String string);
//获取ServletContext类的对象
ServletContext servletContext = getServletContext();
//获取服务器中每个文件的路径。
// 例如,在当前项目下的web文件夹下放一个1.jpg的图片,获取其真实路径(绝对路径)。
String realPath = servletContext.getRealPath("/1.jpg");
/*
输出结果:
realPath = F:\ideawork\javaweb\out\artifacts\web_war_exploded\1.jpg
说明:我们的项目在发布的时候会被打成一个war包,这个war包下的class文件会被放在tomcat下被运行。
所以这里获取的真实路径是这个war包下的1.jpg所在的路径。
*/
/*
获取当前项目下的1.jpg在服务器中的文件类型。
getMimeType("1.jpg");这里书写获取文件类型的文件名和后缀名即可
*/
String mimeType = servletContext.getMimeType("1.jpg");
System.out.println("mimeType = " + mimeType); //mimeType = image/jpeg