7、Servlet(重点*****)
7.1、servlet简介
Servlet是一个专门用来接收客户端发送过来的请求的小web程序。并且它还可以把数据回传给客户端
要编写一个Servlet小程序,这个程序的类必须要实现Servlet接口。
servlet 是运行在 Web 服务器中的小型 Java 程序。servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。
要实现此接口,可以编写一个扩展 javax.servlet.GenericServlet
的一般 servlet,或者编写一个扩展 javax.servlet.http.HttpServlet
的 HTTP servlet。
此接口定义了初始化 servlet 的方法、为请求提供服务的方法和从服务器移除 servlet 的方法。这些方法称为生命周期方法,它们是按以下顺序调用的:
- 构造 servlet,然后使用
init
方法将其初始化。 - 处理来自客户端的对
service
方法的所有调用。 - 从服务中取出 servlet,然后使用
destroy
方法销毁它,最后进行垃圾回收并终止它。
Servlet:
1、接受浏览器发送过来的消息。
2、给浏览器返回消息。浏览器认识html。可以动态去输出html
7.2、servlet快速入门
7.2.1、手动编写servlet实现
写servlet做两件事
1、实现servlet接口。 由sun公司定义的一个接口。(定义一个规范)
2、把类部署到web服务器中(tomcat)。
sun公司定义一个servlet的规范。定义了servlet应该有哪些方法,以及方法需要的参数。
1、实现servlet接口(javax.servlet.Servlet)
2、重写service方法(service方法每次请求都会调用一次)
当浏览器输入地址,访问servlet的时候,servlet会执行servcie方法。
3、在WebContent/WEB-INF/web.xml中配置servlet的访问路径 。浏览器访问servlet的路径
web.xml(新建web工程的时候,eclipse自动创建出来的)的位置:
在web.xml的根标签web-app下,直接书写如下内容。
4、把项目部署到tomcat中,去启动tomcat。在地址栏中输入信息,访问servlet
控制台打印:
7.2.2、解析url到servlet访问细节(***理解)
浏览器地址栏中输入:http://localhost:8080/day06/helloServlet
访问过程分析:
7.2.3、模拟Get请求和Post请求的分发
1)修改代码如下:
/**
* 而因为service是具体业务处理方法。所以不同的servlet业务不同。所以把service方法给我们留下了
*/
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
// 将servletRequest对象强转成为 HttpServletRequest对象
HttpServletRequest httpRequest = (HttpServletRequest) req;
// 获取请求的方式
String method = httpRequest.getMethod();
// get请求获取到"GET" ,post请求获取到"POST"字符串
System.out.println("请求的方式:" + method);
// 根据请求的方式 执行不同的方法去做不同的处理
if ("GET".equals(method)) {
doGet();
} else if ("POST".equals(method)) {
doPost();
}
}
public void doPost() {
System.out.println("这是POST请求的处理方法");
}
public void doGet() {
System.out.println("这是GET请求的处理方法");
}
2)准备html页面表单内容如下(分别测试get请求和post请求):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="http://127.0.0.1:8080/web06/helloServlet2" method="get">
用户名:<input name="username" type="text" /><br/>
密码:<input name="password" type="password" /> <br/>
<input type="submit" />
</form>
</body>
</html>
测试get请求的打印如下:
测试post请求的打印如下:
7.2.4、继承HttpServlet类实现我们自己的Servlet程序
1) 继承httpServlet实现的Servlet类的代码如下:
package com.atguigu.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 继承HttpServlet
* @author wzg
*
*/
public class HelloServlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("这是继承HttpServlet实现的Servlet类,doGet方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("这是继承HttpServlet实现的Servlet类,doPost方法");
}
}
2) 在web.xml文件中的配置
<servlet>
<!-- 给servlet起别名 -->
<servlet-name>HelloServlet3</servlet-name>
<!-- 告诉tomcat这个别名对应的是哪个具体的实现类 -->
<servlet-class>com.atguigu.servlet.HelloServlet3</servlet-class>
</servlet>
<servlet-mapping>
<!-- 告诉tomcat当前配置的访问路径对应哪一个Servlet -->
<servlet-name>HelloServlet3</servlet-name>
<!-- 配置servlet的访问路径
http://ip:端口号/工程名/资源路径
http://127.0.0.1:8080/web06/helloServlet3
-->
<url-pattern>/helloServlet3</url-pattern>
</servlet-mapping>
3)准备html页面表单内容如下(分别测试get请求和post请求):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="http://127.0.0.1:8080/web06/helloServlet3" method="get">
用户名:<input name="username" type="text" /><br/>
密码:<input name="password" type="password" /> <br/>
<input type="submit" />
</form>
</body>
</html>
测试get请求的打印如下:
测试post请求的打印如下:
7.2.5、Servlet生命周期
servlet的生命周期。
什么时候创建一个servlet?
什么时候去销毁一个servlet?
Servlet的生命周期
1.先调用 Servlet的构造方法
2.调用 init 方法 初始化Servlet
3.调用 Servlet中的service方法 处理请求操作
4.调用 destory方法 执行Servlet销毁的操作
init方法:当服务器创建一个serlvet的时候,会去调用init方法。
当我们第一次去访问一个servlet的时候,会去创建这个servlet对象。并且只会创建一次。
当我们继承HttpServlet类实现Servlet程序,重写 init(Servletconfig config) 方法的时候,一定要在里面写上。super.init(config);
否则后面调用getServletContext() 方法就会报空指针异常
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config); // 一定要写上,因为在父类的方法中。这里保存了ServletConfig的引用
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
getServletContext(); // 如果没有super.init(config)调用。这里就会报空指针异常
}
7.3、Eclipse创建Servlet程序(重点*****)
1)通过Eclipse自动新建一个Servlet程序
2)修改Servlet的访问url地址
3)勾选需要生成的Servlet方法
- 修改doGet方法和doPost方法后的代码内容如下:
在web.xml文件中自动生成的配置信息如下:
5)准备html页面表单内容如下(分别测试get请求和post请求):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="http://127.0.0.1:8080/web06/helloServlet4" method="get">
用户名:<input name="username" type="text" /><br/>
密码:<input name="password" type="password" /> <br/>
<input type="submit" />
</form>
</body>
</html>
测试get请求的打印如下:
测试post请求的打印如下:
7.4、Servlet类的继承体系:
8、ServletConfig类(注意:一个Servlet对应一个config对象,各Servlet之间的config对象不共享)
ServletConfig类,见名知义。它是Servlet类的配置文件类。封装了Servlet的配置文件的信息。
它常用的功能有三个。
- 获取Servlet在web.xml文件中配置的Servlet名称(也就是servlet-name的值<servlet-name>ConfigServlet</servlet-name>)。
- 获取Servlet初始化信息。(web.xml文件中<Servlet>标签中 <init-param>的初始化信息 )
- 获取ServletContext域对象
1) Servlet中的示例代码:
/**
* init是初始化方法。
* 一个Servlet对应一个ServletConfig对象
*/
public void init(ServletConfig _config) throws ServletException {
super.init(config);
// 获取config对象
ServletConfig config = _config;
System.out.println(config);
// 它常用的功能有三个。
// 1.获取Servlet在web.xml文件中配置的Servlet名称(也就是servlet-name的值<servlet-name>ConfigServlet</servlet-name>)。
String servlet_name = config.getServletName();
System.out.println("servlet-name ==>> " + servlet_name);
// 2.获取Servlet初始化信息。(web.xml文件中<Servlet>标签中 <init-param>的初始化信息 )
String param_value = config.getInitParameter("username");
System.out.println("username 的值:" + param_value);
// 3.获取ServletContext域对象
// ServletContext它是一个域对象,并且一个Web工程对应一个ServletContext
ServletContext context = config.getServletContext();
System.out.println(context);
}
2) web.xml文件中的配置信息:
<servlet>
<servlet-name>ConfigServlet</servlet-name>
<servlet-class>com.atguigu.servlet.ConfigServlet</servlet-class>
<!-- 给servlet添加初始化参数 -->
<init-param>
<!-- param-name 是初始化参数的名 -->
<param-name>username</param-name>
<!-- param-value 是初始化参数的值 -->
<param-value>root</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ConfigServlet</servlet-name>
<url-pattern>/configServlet</url-pattern>
</servlet-mapping>
- 在浏览器中输入访问地址http://127.0.0.1:8080/day07/configServlet 访问测试:
4) 控制台打印信息
9、servletContext说明(ServletContext对应一个Web工程,重*****点)
什么是ServletContext?
第一:ServletContext是一个接口。
第二:ServletContext是一个域对象!
第三:每个Web工程,都对应一个ServletContext对象!
ServletContext有什么作用?
第一:ServletContext可以获取web.xml文件中的配置上下文参数
第二:ServletContext可以获取web工程在服务器的工程名
第三:ServletContext可以获取web工程中文件夹或文件在服务器硬盘上的绝对路径
第四:ServletContext可以设置、获取web工程的全局属性
9.1、ServletContext获取在Web.xml中配置的全局参数
1) Servlet中的示例代码:
package com.atguigu.servlet;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ContextServlet
*/
public class ContextServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 获取ServletConfig对象
ServletConfig config = getServletConfig();
// 获取Servlet的上下文对象
ServletContext context = config.getServletContext();
// 获取web.xml文件中配置的参数的值
// 正确。ServletContext只能获取context-param配置的参数
String passwordValue = context.getInitParameter("password");
System.out.println("获取context-param参数:" + passwordValue);
// ServletContext无法获取Servlet中配置的init-param参数
String usernameValue = context.getInitParameter("username");
System.out.println("获取servlet配置的init-param参数:" + usernameValue);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
}
}
2) web.xml中的配置信息
<!-- 配置由ServletContext获取的参数 -->
<context-param>
<!-- 配置参数的名 -->
<param-name>password</param-name>
<!-- 配置参数的值 -->
<param-value>root</param-value>
</context-param>
<servlet>
<!-- 配置Servlet中的别名 -->
<servlet-name>ContextServlet</servlet-name>
<!-- 配置Servlet的全类名 -->
<servlet-class>com.atguigu.servlet.ContextServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 配置Servlet的别名 -->
<servlet-name>ContextServlet</servlet-name>
<!-- 配置Servlet的访问路径 -->
<url-pattern>/contextServlet</url-pattern>
</servlet-mapping>
3) 控制台的打印信息:
9.2、ServletContext对象获取布署后的工程名(常*用)
projectPath 得到的结果: /day07
9.3、ServletContext获取工程目录或文件在服务器硬盘上的绝对路径(重**点)
1)工程文件的目录图
2)获取工程中目录和文件的硬盘绝对路径代码:
// 获取ServletConfig对象
ServletConfig config = getServletConfig();
// 获取Servlet的上下文对象
ServletContext context = config.getServletContext();
//获取/表示的路径表示从http://127.0.0.1:8080/工程名/ 所表示的硬盘绝对路径
// /也就是WebContent下的内容
String path = context.getRealPath("/");
System.out.println("/的硬盘路径:" + path);
//获取/imgs表示的路径
// /imgs也就是表示WebContent目录下的imgs目录,发布后的硬盘绝对路径。
String imgspath = context.getRealPath("/imgs");
System.out.println("/imgs的硬盘路径:" + imgspath);
//获取/imgs表示的路径
// /imgs也就是表示WebContent目录下的imgs目录里wrong.png文件,发布后的硬盘绝对路径。
String wrongpath = context.getRealPath("/imgs/wrong.png");
System.out.println("/imgs/wrong.png的硬盘路径:" + wrongpath);
- 控制台打印:
9.4、ServletContext设置全局共享属性(重****点)
我们可以创建两个Servlet程序。分别是:ContextAttrServlet1和ContextAttrServlet2.
a) 在ContextAttrServlet1 中直接通过ServletContext获取一个没有设置的属性值。
b) 然后在ContextAttrServlet2 中,通过ServletContext设置一个全局的属性值。
c) 然后通过不同的访问顺序测试ServletContext对象管理的全局共享属性。
1) ContextAttrServlet1的代码
ContextAttrServlet1的配置信息,访问路径:http://127.0.0.1:8080/day07/contextAttrServlet1
<servlet>
<servlet-name>ContextAttrServlet1</servlet-name>
<servlet-class>com.atguigu.servlet.ContextAttrServlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ContextAttrServlet1</servlet-name>
<url-pattern>/contextAttrServlet1</url-pattern>
</servlet-mapping>
2) ContextAttrServlet2的代码
ContextAttrServlet2的配置信息,访问路径:http://127.0.0.1:8080/day07/contextAttrServlet2
<servlet>
<servlet-name>ContextAttrServlet2</servlet-name>
<servlet-class>com.atguigu.servlet.ContextAttrServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ContextAttrServlet2</servlet-name>
<url-pattern>/contextAttrServlet2</url-pattern>
</servlet-mapping>
- 访问测试过程:
- 先访问http://127.0.0.1:8080/day07/contextAttrServlet1 查看全局的username属性,因为还没设置,所以获取是null
- 然后访问http://127.0.0.1:8080/day07/contextAttrServlet2 设置全局的username属性值。
- 最后再访问http://127.0.0.1:8080/day07/contextAttrServlet1 由于 contextAttrServlet2中已经设置了属性值,这时候再访问可以获取到值。
4) 控制台打印信息:
10 HTTP协议介绍
10.1、HTTP协议
1.HTTP(hypertext transport protocol),即超文本传输协议。这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。
2.客户端与服务端通信时传输的内容我们称之为报文。
3.HTTP就是一个通信规则,这个规则规定了客户端发送给服务器的报文格式,
也规定了服务器发送给客户端的报文格式。实际我们要学习的就是这两种报文。
客户端发送给服务器的称为”请求报文“,服务器发送给客户端的称为”响应报文“。
大白话说,什么是协议。是双方相互约定好的规则;
比如:租房协议:租房协议就是租客和房东之间相互约定好的租房规则
10.2、请求的协议格式
请求的HTTP协议格式
请求首行;
请求头信息;
空行;
请求体;
GET请求协议格式
POST请求协议格式
10.3、常见请求头的说明
GET /Hello/index.jsp HTTP/1.1:GET请求,请求服务器路径为Hello/index.jsp,协议为1.1;
Host:localhost:请求的主机名为localhost;
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0…:与浏览器和OS相关的信息。有些网站会显示用户的系统版本和浏览器版本信息,这都是通过获取User-Agent头信息而来的;
Accept: */*:告诉服务器,当前客户端可以接收的文档类型, */*,就表示什么都可以接收;
Accept-Language: zh-CN:当前客户端支持的语言,可以在浏览器的工具à选项中找到语言相关信息;
Accept-Encoding: gzip, deflate:支持的压缩格式。数据在网络上传递时,服务器会把数据压缩后再发送;
Connection: keep-alive:客户端支持的链接方式,保持一段时间链接。
10.4、get请求和post请求都分别是哪些操作?
GET请求 :
1)、在浏览器地址栏中输入地址直接按回车
2)、点击超链接 <a>
3)、GET请求表单提交 <form mehtod=”get”>
4)、script src=””,引入外部文件
5)、img src=”路径”,引入图片
6)、引入外部css。。。
POST请求:
1)只有表单提交的时候method=post,提交表单就是发post请求 <form method=”POST” />
10.5、响应的协议格式
响应的HTTP协议格式
响应首行
响应头信息
空行
响应体
10.6、常见的响应码
响应码对浏览器来说很重要,它告诉浏览器响应的结果;
200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;
404:请求的资源没有找到,说明客户端错误的请求了不存在的资源;
500:请求资源找到了,但服务器内部出现了错误;
302:重定向,当响应码为302时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头Location,它指定了新请求的URL地址;
回顾:
在HTTP请求的格式中分为三部分
第一部分:请求行
第二部分:请求头
空行
第三部分:请求体
请求行又分为三部分
第一部分是 请求的方式
第二部分是 请求的资源路径
第三部分是 请求的协议和版本号
-----------------------------------------------
在POST请求中,HTTP协议有三部分
在GET请求中,HTTP协议有两部分
-----------------------------------------------
响应的HTTP协议格式
分为三部分
第一部分是 响应行
第二部分是 响应头
空行
第三部分是 响应体
响应行又分为三部分
第一部分 HTTP协议和版本号
第二部分 响应码 200 请求成功
第三部分 响应描述 OK OK表示请求响应成功
10.7、MIME类型
MINE是HTTP协议中数据类型。
MIME的英文全称是"Multipurpose Internet Mail Extensions" 多功能Internet 邮件扩充服务。MIME类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。
常见的MIME类型:
文件 | MIME类型 |
超文本标记语言文本 | .html,.html text/html |
普通文本 | .txt text/plain |
RTF文本 | .rtf application/rtf |
GIF图形 | .gif image/gif |
JPEG图形 | .jpeg,.jpg image/jpeg |
au声音文件 | .au audio/basic |
MIDI音乐文件 | mid,.midi audio/midi,audio/x-midi |
RealAudio音乐文件 | .ra, .ram audio/x-pn-realaudio |
MPEG文件 | .mpg,.mpeg video/mpeg |
AVI文件 | .avi video/x-msvideo |
GZIP文件 | .gz application/x-gzip |
TAR文件 | .tar application/x-tar |
11、HttpServletRequest类介绍(重****点)
HttpServletRequest类封装了从客户端传递过来的信息。每次请求,Tomcat都会把客户端请求的信息封装在一个HttpServletRequest对象实例传递到service请求的方法中让我们使用。
11.1、Request对象常用方法(重****点)
getRequestURI() 获取请求的资源路径
getRequestURL() 获取请求的统一资源定位符
getRemoteHost() 获取请求的客户端ip地址
getHeader() 获取请求头信息
getParameter() 获取请求参数值
getParameterValues() 获取请求的多个值(常用于复选框和下拉列表多选)。
getRequestDispatcher() 获取请求的转发对象。转发请求(转发的请求和原请求共享request对象和response对象)
getMethod() 获取请求的方式GET 或 POST
setAttribute(key, value); 设置Request请求范围的属性值。
getAttribute(key); 获取Request请求范围的属性值。
(下面四个方法不是今天的学习重点,后面专门提到。今天先知道)
getCookies() 获取Cook对象
getSession() 获取或创建Session对象
a) Request对象的常用方法测试代码:
1.获取请求的资源路径
2.获取请求的统一资源定位符
3.获取请求的客户端ip地址
4.获取请求头信息
5.获取请求的方式GET 或 POST
package com.atguigu.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Request对象的常用方法
*/
public class Request1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// Request的常用方法
// 获取请求的资源路径
System.out.println("getRequestURI==>>" + request.getRequestURI());
// 获取请求路径的统一资源定位符
System.out.println("getRequestURL==>>" + request.getRequestURL());
// 获取客户端的ip地址
System.out.println("getRemoteHost==>>" + request.getRemoteHost());
// 获取请求头的信息。
System.out.println("getHeader('User-Agent')==>>" + request.getHeader("User-Agent"));
// 获取请求方式GET或 POST
System.out.println("getRemoteHost==>>" + request.getMethod());
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
b) 在web.xml文件中的配置信息
<servlet>
<servlet-name>Request1</servlet-name>
<servlet-class>com.atguigu.servlet.Request1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Request1</servlet-name>
<url-pattern>/request1</url-pattern>
</servlet-mapping>
c) 直接访问http://127.0.0.1:8080/day07/request1测试
解释:
1) 获取请求行
request.getRequestURI(); 获取请求的资源路径 /day07/requst1 表示访问的是day07工程下的/request1的servlet动态资源
request.getRequestURL();获取请求的统一资源定位符。
http://192.168.11.30:8080/day07/request1
192.168.11.30 是我的ip地址
8080 服务器端口号
day07是工程名
request1 是资源的路径
// Request的常用方法
// 获取请求的资源路径
System.out.println( "getRequestURI==>>" + request.getRequestURI() );
// 获取请求路径的统一资源定位符
System.out.println( "getRequestURL==>>" + request.getRequestURL() );
2) 获取访问的客户端的ip地址:
// 获取客户端的ip地址
System.out.println("getRemoteHost==>>" + request.getRemoteHost());
得到客户端的请求ip地址 例如:192.168.11.10 , 192.168.10.32等等
3) 获取请求头信息
//获取请求头的信息。
System.out.println("getHeader('User-Agent')==>>" + request.getHeader("User-Agent"));
打印内容(不同的浏览器,得到的信息不一样):
getHeader('User-Agent')==>>Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
11.2、获取请求参数的值 (重*****点,必须掌握)
1) 请求的页面 register.html 内容
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>用户注册</h1>
<!--
在web工程中,路径我们可以写成相对路径 ,也可以写成绝对路径。
如果当前浏览器地址栏地址是:http://127.0.0.1:8080/day07/register.html
相对路径:
. 表示当前目录(http://127.0.0.1:8080/day07)
.. 表示上一级目录(http://127.0.0.1:8080/day07)
./params 表示访问(http://127.0.0.1:8080/day07/params)
params 是 ./params的简写(./可以省略)
绝对路径:
http://127.0.0.1:8080/day07/register.html绝对路径
http://127.0.0.1:8080/day07/params 绝对路径
在web中绝对路径,还可以用/表示。
/表示为根的绝对路径
这个根分为两种根
1)一个是tomcat的根(http://127.0.0.1:8080/)
2)一个是工程的根(http://127.0.0.1:8080/day07)
它们分别表示两个不同的路径
在页面中输入/表示 访问http://127.0.0.1:8080
在javaweb工程代码中/表示http://127.0.0.1:8080/工程名/
这两个不同的根要怎么理解呢。
比方说:
我是地球上,中国的海南人。
1.那么,如果你在中国。别人问你,你的根在哪,你会回答,我的根在海南,我是海南人。
2.如果你在其他国家。别人问你,你的根在哪,你会回答,我的根在中国。我是中国人。
3.甚至一千年以后,我们科学发达了。你可以到不同的星球上生物交流。
当你在其他星球上的时候,其他星球的生物问你,你的根在哪。你会回答,我的根在地球。我是地球人。
所以根指的是哪,是根据环境而定。
当我们在页面中输入/的时候,Tomcat设置它的环境是在Tomcat的访问路径。
而相对于Tomcat而言。并没有告诉它是哪一个工程。所以它默认的访问地址就是Tomcat的根。也就是
http://127.0.0.1:8080/
当我们在web工程的java代码中。调用如下代码 ServletContext.getRealPath("/");
它得到的路径是http://127.0.0.1:8080/工程名。 因为它已经在工程这个环境中了。
-->
<form action="http://127.0.0.1:8080/day07/params" method="get">
用户名:<input name="username" type="text" /><br/>
密 码:<input name="password" type="password" /><br/>
兴趣爱好:
<input name="hobby" type="checkbox" value="c" />C
<input name="hobby" type="checkbox" value="cpp" />C++
<input name="hobby" type="checkbox" value="java" />java
<input name="hobby" type="checkbox" value="php" />php
<br/>
<input type="submit" />
</form>
</body>
</html>
2) 接收请求参数的代码:
package com.atguigu.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 获取请求的参数值
*
* @author wzg
*
*/
public class Params extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//获取客户端传递过来的用户名参数值
String username = request.getParameter("username");
System.out.println("用户名:" + username);
// 获取密码
String password = request.getParameter("password");
System.out.println("密码:" + password);
// 获取兴趣爱好,这个方法只能获取到一个兴趣爱好。
// String hobby = request.getParameter("hobby");
// System.out.println("getParameter得到的兴趣爱好:" + hobby);
// 如果获取的参数有多个值的情况下。我们都使用getParameterValues方法来获取
// 因为它可以获取到多个值。而getParameter只能获取到一个值。
String[] hobbys = request.getParameterValues("hobby");
if (hobbys != null) {
for (String hb : hobbys) {
System.out.println("getParameterValues兴趣爱好:" + hb);
}
}
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
3) web.xml文件中的配置信息
<servlet>
<display-name>Params</display-name>
<servlet-name>Params</servlet-name>
<servlet-class>com.atguigu.servlet.Params</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Params</servlet-name>
<url-pattern>/params</url-pattern>
</servlet-mapping>
4) 控制台打印:
11.3、GET请求中文参数值乱码问题解决(重****点)。
1) 使用如下页面表单内容:
<form action="http://127.0.0.1:8080/day07/params" method="get">
用户名:<input name="username" type="text" /><br/>
密 码:<input name="password" type="password" /><br/>
<input type="submit" />
</form>
2) 获取表单内容代码:
3) 控制台打印乱码内容:
解决乱码的核心代码:
解决乱码的核心思路,就是把得到的乱码按照原来乱码的步骤逆序操作。
1、先以iso-8895-1进行编码
2、然后再以utf-8进行解码
1) 使用 String类的方法进行编解码
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
System.out.println("乱码解决后用户名:" + username);
解决乱码的代码如下:
package com.atguigu.servlet;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Params2
*/
public class Params2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//获取客户端传递过来的用户名参数值
String username = request.getParameter("username");
System.out.println("用户名:" + username);
// 先iso-8859-1编码码,再utf-8解码
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
System.out.println("乱码解决后用户名:" + username);
// 获取密码
String password = request.getParameter("password");
System.out.println("密码:" + password);
}
}
11.4、POST请求中文参数值乱码问题解决(重*****点)
post请求方式乱码的原因是:Tomcat服务器对参数的默认编码是ISO-8859-1
POST请求乱码解决,只需要在获取请求参数之前调用 request.setCharacterEncoding("UTF-8"); 方法设置字符集 即可。
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 1.post请求方式的数据是以二进制流的形式发送到服务器。
// 2.那么就说明它缺少一个字符集。所以我们要设置请求体的字符集即可。
// setCharacterEncoding必须要获取请求参数之前调用才有效
request.setCharacterEncoding("UTF-8");
//获取客户端传递过来的用户名参数值
String username = request.getParameter("username");
System.out.println("用户名:" + username);
}
11.5、做为域对象设置请求Request范围的属性值
把下面的这三行代码放到任意一个Servlet中,去请求访问。
// 在Request中设置 属性值。
request.setAttribute("abc", "abcValue");
// 获取 Request域中的属性值
String abcAttr = (String) request.getAttribute("abc");
System.out.println(abcAttr); // 控制台打印 abcValue
如果大家读源码你会发现。其实在Request对象中,有一个Map对象用来存放 属性值。
所以属性的操作就跟操作一个map对象是一样一样的。
11.6、请求转发(重*****点)
1)问题:什么是请求的转发?
图解什么是请求转发
2)请求转发的具体实现代码:
3)直接在浏览器地址栏中输入 http://127.0.0.1:8080/day07/servlet1?username=abc 访问第1个Servlet1 程序
4)控制台打印如下内容:
11.7、Base标签
base 标签它会把所有的相对路径,设定在base指定的路径的基础之上做操作。
12、HttpServletResponse类介绍(重****点)
Response对象封装了服务器到客户端返回的信息。
12.1、获取输出流
getOutoutStream() 拿到的是二进制流。主要用于返回二进制数据。比如说下载,图片验证码等。
getWriter() 拿到字符流。大部分的返回都用writer。
这两个输出流,我们不能同时获取两个,只能使用一个做为返回。
只要同时获取两个输出流就会报错,不管你是先获取二进制输出,还是先获取字符串输出流。代码如下:
/**
* 同时通过response对象获取两个输出流对象,就会报错。
* 不管你是先获取二进制的字节流,还是字符流
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 获取二进制输出流
response.getOutputStream();
// 获取字符串输出流
response.getWriter();
}
当代码执行,就会报错:
12.2、如何往客户端回传数据
1) 往客户端输出。分两个步骤:
第一步:先获取输出流(二进制返回用获取字节流,字符出获取字符流)
第二步:调用输出流对象,写出数据第客户端
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 通过response响应对象获取到字符输出流
Writer writer = response.getWriter();
// 往 客户 端 输出数据。
writer.write("this is response content!");
}
2) 访问你的Servlet。通过Response对象输出数据到客户端
12.3、输出中文到客户端的乱码解决方法
1) 如果拿到writer字符输出流。直接输出中文内容返回到客户端。会得到乱码。比如:
程序如下,客户端收到会有乱码情况:
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 通过response响应对象获取到字符输出流
Writer writer = response.getWriter();
// 往 客户 端 输出数据。
// writer.write("this is response content!");
// 输出中文数据到客户端
writer.write("这是中文的输出");
}
通过浏览器访问后显示的结果:
遇到这种情况是什么原因呢?主要是因为服务器输出的字符串的编码和客户端显示字符串的编码不一致。导致乱码问题。
所以我们只需要设置服务器和客户端的编码相同就可以解决这个问题。
2) 乱码的解决。
设置服务器的字符串编码
//设置服务器输出的编码为UTF-8
response.setCharacterEncoding("UTF-8");
// 通过响应头,告诉客户端使用什么字符集
response.setHeader("Content-Type", "text/html; charset=UTF-8");
设置客户端的字符串显示编码。
//告诉浏览器输出的内容是html,并且以utf-8的编码来查看这个内容。
response.setContentType("text/html;charset=utf-8");
这两行语句要在获取输出流之前执行。才会生效。
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//设置服务器输出的编码为UTF-8
response.setCharacterEncoding("UTF-8");
//告诉浏览器输出的内容是html,并且以utf-8的编码来查看这个内容。
response.setContentType("text/html; charset=utf-8");
// 通过response响应对象获取到字符输出流
Writer writer = response.getWriter();
// 往 客户 端 输出数据。
// writer.write("this is response content!");
// 输出中文数据到客户端
writer.write("这是中文的输出");
}
再次通过浏览器访问。得到的是正确的中文。
12.4、设置响应状态码,和设置响应头
下面的代码演示了
1) 设置响应状态码和设置响应头的代码:
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
/**
* 当响应状态码为302的时候,表示要重定向。
* 浏览器会检测Location的值,去重新发起请求。
*/
// 设置响应状态码 302 表示重定向
response.setStatus(302);
// 设置响应头 Location中的信息
// 浏览器会把Location中的值重新发起一次请求。
// response.setHeader("Location", "http://127.0.0.1:8080/day07/response2");
// 浏览器会重新 发起请求http://www.baidu.com
response.setHeader("Location", "http://www.baidu.com");
}
2)在浏览器中访问响应状态的代码。得到的响应内容如下:
并且浏览器收到响应后会马上自动发生起第二次的请求。第二次请求的地址是Location对应的值。
请求重定向。是两次请求,浏览器地址栏会发生改变。
第一次请求返回的响应码为302.并且有响应头Location的内容。
第二次请求的地址就是Location对应的值。
重定向,第二次请求不仅可以是站内的资源,也可以是站外的资源。
12.5、请求重定向 sendRedirect的方式
除了通过设置响应状态码和响应头可以实现重定向之外。我们还可以通过HttpServletResponse对象的sendRedirect方法实现重定向。
实现的代码如下:
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
/**
* 当响应状态码为302的时候,表示要重定向。
* 浏览器会检测Location的值,去重新发起请求。
*/
// 设置响应状态码 302 表示重定向
// response.setStatus(302);
// 设置响应头 Location中的信息
// 浏览器会把Location中的值重新发起一次请求。
// response.setHeader("Location", "http://127.0.0.1:8080/day07/response2");
// 浏览器会重新 发起请求http://www.baidu.com
// response.setHeader("Location", "http://www.baidu.com");
// 通过sendRedirect方法直接重定向到你需要的网址。
response.sendRedirect("http://www.baidu.com");
}
浏览器访问后,会有两次请求。
第一次是http://127.0.0.1:8080/day07/response3 访问上面的java代码。
第二次是访问Location中的地址。
请求转发和重定向的对比
| 转发 | 重定向 |
浏览器地址栏 | 不会变化 | 会变化 |
几次请求 | 同一个请求 | 两次请求 |
API | Request对象 | Response对象 |
WEB-INF | 可以访问 | 不能访问 |
共享request请求域数据 | 可以共享 | 不可以共享 |
目标资源 | 必须是当前Web应用中的资源 | 不局限于当前Web应用 |
最后 附上 常见的请求与响应头的说明 以供参考:
HTTP Request Header 请求头
Header | 解释 | 示例 |
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html |
Accept-Charset | 浏览器可以接受的字符编码集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 请求的特定的服务器行为 | Expect: 100-continue |
From | 发出请求的用户的Email | From: user@email.com |
Host | 指定请求的服务器的域名和端口号 | Host: www.zcmhi.com |
If-Match | 只有请求内容与实体相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只请求实体的一部分,指定范围 | Range: bytes=500-999 |
Referer | 先前网页的地址,当前请求网页紧随其后,即来路 | Referer: http://www.zcmhi.com/archives/71.html |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
HTTP Responses Header 响应头
Header | 解释 | 示例 |
Accept-Ranges | 表明服务器是否支持指定范围请求及哪种类型的分段请求 | Accept-Ranges: bytes |
Age | 从原始服务器到代理缓存形成的估算时间(以秒计,非负) | Age: 12 |
Allow | 对某网络资源的有效的请求行为,不允许则返回405 | Allow: GET, HEAD |
Cache-Control | 告诉所有的缓存机制是否可以缓存及哪种类型 | Cache-Control: no-cache |
Content-Encoding | web服务器支持的返回内容压缩编码类型。 | Content-Encoding: gzip |
Content-Language | 响应体的语言 | Content-Language: en,zh |
Content-Length | 响应体的长度 | Content-Length: 348 |
Content-Location | 请求资源可替代的备用的另一地址 | Content-Location: /index.htm |
Content-MD5 | 返回资源的MD5校验值 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
Content-Range | 在整个返回体中本部分的字节位置 | Content-Range: bytes 21010-47021/47022 |
Content-Type | 返回内容的MIME类型 | Content-Type: text/html; charset=utf-8 |
Date | 原始服务器消息发出的时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
ETag | 请求变量的实体标签的当前值 | ETag: “737060cd8c284d8af7ad3082f209582d” |
Expires | 响应过期的日期和时间 | Expires: Thu, 01 Dec 2010 16:00:00 GMT |
Last-Modified | 请求资源的最后修改时间 | Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT |
Location | 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 | Location: http://www.zcmhi.com/archives/94.html |
Pragma | 包括实现特定的指令,它可应用到响应链上的任何接收方 | Pragma: no-cache |
Proxy-Authenticate | 它指出认证方案和可应用到代理的该URL上的参数 | Proxy-Authenticate: Basic |
refresh | 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) |
Refresh: 5; url= http://www.zcmhi.com/archives/94.html |
Retry-After | 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 | Retry-After: 120 |
Server | web服务器软件名称 | Server: Apache/1.3.27 (Unix) (Red-Hat/Linux) |
Set-Cookie | 设置Http Cookie | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
Trailer | 指出头域在分块传输编码的尾部存在 | Trailer: Max-Forwards |
Transfer-Encoding | 文件传输编码 | Transfer-Encoding:chunked |
Vary | 告诉下游代理是使用缓存响应还是从原始服务器请求 | Vary: * |
Via | 告知代理客户端响应是通过哪里发送的 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 警告实体可能存在的问题 | Warning: 199 Miscellaneous warning |
WWW-Authenticate | 表明客户端请求实体应该使用的授权方案 | WWW-Authenticate: Basic |