servlet&&HTTP协议&&Request对象学习
1.servlet 的体系结构和介绍
Servlet
||
GenericServlet:将除service方法外的其余方法默认空实现,只将service方法作为抽象(在正式开发的时候,我们不会使用这种方法),在使用的时候,直接直接定义一个类继承genericservlet类即可
||
HttpServlet:对http协议的一种封装,简化操作
处理了一个判断请求的功能,在以前使用的servlet中当一个访问来后,创建完service方法,无论是get方法请求还是 post方式请求,都需要进行判断才能使用,因为这两种方式是不同的,所以我们需要判断,而HttpServlet就在内部对这个进行
编写,直接有doget,dopost方法,来响应不同方式的请求。而我们一般只写一个
在doget中调dopost,或者在dopost中调doget;
2.servlet的相关配置
- 1.使用注释,资源路径可以有多个,也就是说使用不同的资源路径,创建同一个servlet,访问同一个servlet
- 2.在WebServlet注释的定义中,可以看出,urlPattern是使用数组进行定义的所以,使用大括号对资源路径进行赋值
@WebServlet({"/demo4","/de4","/d4"})//* 使用这三个资源路径都可以访问到servlet资源路径. - 3.路径定义规则:的优先级很低,使用之后,会优先匹配别的资源路径
1./xxx : / :所有的资源路径都可以访问到当前的servlet
2./xxx/xxx (目录结构) :/xxx/* :也可以使用通配符
:/user/demo :多级目录
3.*.do(自定义后缀名) :demo.do
2.Http协议(Hyper Text Transfer Protocol)
- 概念:超文本传输协议
传输协议:定义了客户端与服务器端通信的时候,请求消息和响应消息的格式
-
http协议的特点
1,基于tcp/ip协议的高级协议,也就是说面向连接的,安全的,协议,进行通信的时候需要进行三次握手。
2,默认端口号是:80。
3,基于请求/响应模型:一次请求对应一次响应,不会出现一次请求多次响应的情况,也不可能是对个请求一个响应。
4,无状态的:每次请求之间相互独立,不能交互数据
抓包,百度网页的每一个资源都是一次请求 - 历史版本
1.0:每一次请求响应都是建立新的连接
1.1:复用链接,将所有资源获都传输成功后再断开连接,但是每一个资源都是
基于请求/响应的模式
- http请求/响应消息数据格式(在使用浏览器,开发者工具抓包的时候,浏览器太高级会导致我们去学习的时候很不便利,所以我们使用垃圾一点的浏览器,查看原始头)
1.请求行:(请求方式 请求url 请求协议和版本,在浏览器中会用其他的方式显示,但是内容还是这个内容)
如:GET /login.html?name=xzw http/1.1
请求方式
http协议有7种请求方式,而我们常见的方式有两种,get,post方式
GET方式:
1,请求参数在请求行中,在url后 ,如:name=xzw
2,请求的url长度有限制
3,不太安全(在url中可以之间看见参数)
POST方式:
1,请求参数在请求体中
2,请求的url长度没有限制
3,相对安全(在url中看不见参数)
2,请求头(键值对的形式存在,请求头名称,请求头值)(就是客户端浏览器发送给服务器的一些信息)
如:
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: Idea-9bab5137=3dd752db-249a-4508-851c-04dd5f28bc9e
Upgrade-Insecure-Requests: 1
If-Modified-Since: Sun, 26 Jan 2020 08:12:31 GMT
If-None-Match: W/"620-1580026351282"
Cache-Control: max-age=0
其中几个常用的请求头:
1.User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息,这个信息可以在服务器中获取,然后根据这个信息解决服务器的兼容问题
2.accept:可以接受什么样的文本
3.referer:告诉服务器,我当前的请求从哪里来?
referer:http://localhost:8080/java_idea_request/input.html
作用:1.防盗链2.统计功能(判断叠加)
说明:就是可以通过这个请求头,去判断当前请求是从哪个连接过来的,可以防止盗链,和统计工作
3.请求空行:就是用来分隔请求头和请求体的
4.请求体:封装Post请求消息的请求参数
Tomcat服务器在请求和响应是真正的过程
1.Tomcat服务器会根据请求的url资源路径,创建对应的servlet对象。
2.Tomcat服务器会创建request和response对象,request对象中会封装请求消息数据。
3.Tomcat服务器将request对象和response对象传递给service方法,并且调用service方法。
4.我们可以通过request对象获取请求消息数据,再通过response对象设置响应信息数据
5.服务器在给浏览器做出响应之前,从response对象中那程序员设置的响应数据信息(也就是说,在浏览器还没有接受到响应的时候,是服务器先获取到response中的数据,在将数据响应给浏览器)
(!就是说我以前认为的request对象就是请求,response对象就是响应是不对的,他们只是对请求和响应的封装)
- request&&response对象的原理:
1.request和response对象是服务器创建的,我们只是使用它
2.request对象是用来获取请求信息的,而response对象是用来设置响应消息的
1.request对象
1.request继承体系结构

ServletRequest(接口)
|| 继承
HttpServletRequest(接口)
|| 实现
RequestFacade(tomcat对象):我们实际使用的对象就是RequestFacade对象
- RequestFacade对象在文档中没有,可以在tomcat的源码中找到,也就是说这是tomcat对HttpServlet接口进行的实现
2.request对象的功能
- 1.获取请求行信息
1,请求行信息包括:请求方式 请求url 请求协议和版本
2,方法:
@WebServlet("/request_demo2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求头方法
String method = req.getMethod();
System.out.println("方法:"+method);
//2.获取虚拟目录V
String contextPath = req.getContextPath();
System.out.println("虚拟路径:"+contextPath);
//3.获取资源路径
String servletPath = req.getServletPath();
System.out.println("资源路径:"+servletPath);
//4.获取get请求的请求参数
String queryString = req.getQueryString();
System.out.println("请求参数"+queryString);
//5.获取请求参数url
String requestURI = req.getRequestURI();
StringBuffer requestURL = req.getRequestURL();
System.out.println("url:"+requestURL);
System.out.println("uri:"+requestURI);
//6.获取协议和版本
String protocol = req.getProtocol();
System.out.println("协议和版本:"+protocol);
//7.获取客户机的ip地址
String remoteAddr = req.getRemoteAddr();
System.out.println("客户机的ip地址"+remoteAddr);
}
(!):URL和URI的区别:URI的范围更大
URL:统一资源定位符--http://localhost:8080/java_idea_request/request_demo2
中华人民共和国
URI :统一资源标识符--/java_idea_request/request_demo2
共和国
- 2.获取请求头信息
- 3.获取请求体信息
- 2.获取请求头信息
1,请求头信息 键值对的存在
2,方法:两个方法比较重要
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取所有的请求头信息 Enumeration看做迭代器使用
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()){
String name = headerNames.nextElement();
//2.通过请求头名称获取请求头的值
String header = request.getHeader(name);
System.out.println(name+":"+header);
}
}
- 案例:浏览器兼容和盗链问题还有统计数据的功能
1,浏览器兼容的问题
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//案例一:浏览器兼容问题,就是要获取User-agent的值,判断他的包含那一种浏览器的名字
String user_agent = request.getHeader("User-agent");
if (user_agent!=null){
if (user_agent.contains("Chrome")){
System.out.println("谷歌浏览器");
}
else if (user_agent.contains("Firefox")){
System.out.println("火狐浏览器");
}
}else {
System.out.println("user_agent为空");
}
}
2,统计数据功能
public class RequestDemo5 extends HttpServlet {
private static int a=0;
private static int b=0;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//实现对百度和网易两个网站的进入的访问量统计
//1.获取Referer信息,然后判断获取的Referer中的信息,判断是否在其中包含所需要的数据,进行叠加
String referer = request.getHeader("Referer");
if (referer!=null){
if (referer.contains("baidu")){
this.a++;
}else if(referer.contains("wangyi")){
this.b++;
}
System.out.println("百度访问:"+this.a+"次");
System.out.println("网易访问:"+this.b+"次");
}
}
3,防盗链
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取Referer的值
String referer = request.getHeader("referer");
System.out.println(referer);
//2.判断链接是否来自首页
if (referer!=null){
if (referer.contains("java_idea_request")){
//正常播放
System.out.println("正常播放");
}else {
//请在优酷首页播放
System.out.println("请在优酷首页进入");
}
}
}
- 3.获取请求体信息
请求体只有在Post请求方式,才会有请求体,在请求体中封装了post请求的请求参数
获取步骤:
1,获取流对象,字符流或者是字节流
2,从流对象中获取数据
方法:
public class RequsetDemo7 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取字符流对象:getReader();
BufferedReader reader = request.getReader();//获取字符流,获取字符
//2.获取字节流对象getInputStream();
// ServletInputStream inputStream = request.getInputStream();//获取字节流,操作所有类型的文件
String str = null;
//2.获取流对象中的数据
while((str=reader.readLine())!=null){
System.out.println(str);
}
}
- 3.request 对象的其余功能
1,获取请求参数,通用方法(以前的方法获取的是一个字符串的形式,每一个键值对之间用&连接,而且在使用的时候还要分成get方式和post方式)
方法
//1. 通用方式获取请求参数
String username = request.getParameter("name");
String password = request.getParameter("password");
System.out.println("username:"+username);
System.out.println("password:"+password);
//2.根据参数名获取参数数组
String[] hobbies = request.getParameterValues("hobby");
System.out.println("兴趣是");
for (String hobby : hobbies) {
System.out.println(hobby);
}
//3.获取所有参数名
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
String parameter_value = request.getParameter(name);
System.out.println(name+":"+parameter_value);
}
//4.获取所有参数的集合
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> strings = parameterMap.keySet();
for (String string : strings) {
String[] values = parameterMap.get(string);
System.out.println(string);
for (String value : values) {
System.out.println(" "+value);
}
}
在使用的过程中,会出现中文乱码的问题:

- get方式:tomcat8已经将get方式的乱码问题解决了
- post方式:会乱码,主要原因是底层使用流的方式获取数据
解决方法:设置流的编码,在获取参数之前设置request的编码
request.setCharacterEncoding("utf-8");
我么在使用的时候,无论是使用get方式还是post的方式都需要设置编码
效果:
中文编码正常
- 4.请求转发
概念:一种在服务器内部资源跳转方式
Aservlet
||两个内部资源之间的跳转方式
Bservlet
1.步骤:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo9的doGet方法调用成功");
//1.获取转发器对象,并使用它进行转发,请求路径是在虚拟路径下的
request.getRequestDispatcher("/requestDemo10").forward(request,response);
}


2,特点(面试题经常与重定向之间进行比较)
1.浏览器的地址栏没有发生变化
2.只能请求转发到当前服务器的内部资源中
3.转发是一次请求(调用了请求路径的service方法)
- 5.共享数据:request域,只能在请求转发中实现,也就是说只能在服务器内部资源中使用
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中,共享数据
方法(因为在请求转发中,使用的都是当前请求的request对象,进行的请求转发,所以一般用于请求转发的多个资源中,共享数据)
//demo9
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo9的doGet方法调用成功");
//1.存储数据
request.setAttribute("name","xzw");
//3.通过键值移除域中的数据
request.removeAttribute("name");
//1.获取转发器对象,并使用它进行转发,请求路径是在虚拟路径下的
request.getRequestDispatcher("/requestDemo10").forward(request,response);
}
//demo10
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("进入demo10......");
//2.获取request域中的内容
Object name = request.getAttribute("name");
if (name!=null){
System.out.println(name.toString());
}else {
System.out.println("对象为空,可能已经移除");
}
}

移除键值对后

- 6.获取servletcontext:
//获取servletContext对象
ServletContext servletContext = request.getServletContext();
System.out.println("servletContext:"+servletContext);
//结果:
servletContext:org.apache.catalina.core.ApplicationContextFacade@5a1fec1b

