Servlet+HTTP+Request+Response+SevletContext+Cookie+Session大杂烩学习笔记


服务器软件:可以接收用户的请求,处理请求,做出响应。
在web服务器软件中,可以部署web项目,让浏览器可以访问这些项目,中小型免费开源的JavaEE服务器,首选tomcat。
这里就不讲tomcat的安装,可以直接在官网下载安装。
一般将Tomcat集成到IDEA中,并且创建JavaEE的项目,部署项目。采用热部署可以有更好的使用体验。

Servlet

Servlet,可以拆分成server applet,概念上就是运行在服务器端的小程序。
实际上,Servlet是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。
在这里插入图片描述
想要使用接口,用户就是要自定义实现类了。

自定义类的实现原理:
1.当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
3. 如果有,则在找到对应的<servlet-class>全类名
4. tomcat会将字节码文件加载进内存,并且创建其对象
5. 调用其方法
在这里插入图片描述
Servlet3.0以上就支持注解配置了,不需要在web.xml里面写一系列的代码了。只需要在自定义实现类上加上注解@WebServlet(“资源路径”)
在这里插入图片描述
那调用Servlet接口,然后复写里面的抽象方法,我们也总是只复写Service这一个方法,不方便。
这里就引出了一个HttpServlet类,它是Servlet类的实现类。
那我们现在就可以通过继承这个HttpServlet类来使用Servlet的方法了。
而且HttpServlet还有一个好处就是在服务器接收到请求的时候,提供了判断请求方式的方法,常用的就是doPost()和doGet()。我们就不用自己去判断是哪一种请求方式。在这里插入图片描述

HTTP

Hyper Text Transfer Protocol 超文本传输协议

这种传输协议定义了客户端和服务器端通信时,发送数据的格式

特点
1.基于TCP/IP的高级协议
2. 默认端口号:80
3. 基于请求/响应模型的:一次请求对应一次响应
4. 无状态的:每次请求之间相互独立,不能交互数据

请求消息的数据格式
HTTP协议中的请求方式,常用的有GET和POST,先简单讲一下他们的区别:

GET
1.请求参数在请求行中,在url后。
2. 请求的url长度有限制的
3. 不太安全

POST
1.请求参数在请求体中
2. 请求的url长度没有限制的
3. 相对安全

请求信息的数据格式
请求消息:客户端发送给服务器端的数据

1.请求行:请求方式 请求url 请求协议/版本

2.请求头:客户端浏览器告诉服务器一些信息

3.请求空行:就是用于分割POST请求的请求头,和请求体的。

4.请求体(正文):封装POST请求消息的请求参数的

响应信息的数据格式
响应消息:服务器端发送给客户端的数据

1.响应行:协议/版本 响应状态码 状态码描述

响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。都是3位数字,分类如下:

1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码

2xx:成功。代表:200

3xx:重定向。代表:302(重定向),304(访问缓存)

4xx:客户端错误。 例如: 404(请求路径没有对应的资源) 405:请求方式没有对应的doXxx方法

5xx:服务器端错误。代表:500(服务器内部出现异常)

2.响应头

格式:头名称: 值

常见的响应头有以下两种
Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
++++++++++分割线+++++++++++++
Content-disposition:服务器告诉客户端以什么格式打开响应体数据
常用的值:
in-line:默认值,在当前页面内打开
attachment;filename=xxx:以附件形式打开响应体。文件下载

3.响应空行

4.响应体:传输的数据

Request

request对象和response对象的原理
1.request和response对象是由服务器创建的。我们来使用它们
2.request对象是来获取请求消息,response对象是来设置响应消息
在这里插入图片描述

request功能
1.获取请求消息数据
1.1 获取请求行数据

package demo;

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;

@WebServlet("/req_demo1")
public class Request_demo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求行数据: GET /Servlet_DEMO/req_demo1?username=123456 HTTP/1.1

        //获取请求方式:GET
        String method = request.getMethod();
        System.out.println(method);
        //获取虚拟目录:/Servlet_DEMO
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //获取资源文件(Servlet)路径:/req_demo1
        String servletPath = request.getServletPath();
        System.out.println(servletPath);
        //获取get方式的请求参数:username=123456
        String queryString = request.getQueryString();
        System.out.println(queryString);
        //获取请求URI: /Servlet_DEMO/req_demo1
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        //获取请求URL:http://localhost/Servlet_DEMO:war exploded/req_demo1
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURL);
        //获取协议及版本:HTTP/1.1
        String protocol = request.getProtocol();
        System.out.println(protocol);
        //获取客户机的IP地址:
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);
    }
}

1.2 获取请求头数据

String getHeader(String name):通过请求头的名称获取请求头的值
Enumeration<String> getHeaderNames():获取所有的请求头名称

demo

package demo;

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;
import java.util.Enumeration;

@WebServlet("/request_demo2")
public class Request_demo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取所有请求头名称
        Enumeration<String> headerNames = request.getHeaderNames();
        while(headerNames.hasMoreElements()){
            String s = headerNames.nextElement();
            String header = request.getHeader(s);
            System.out.println(s+"----"+header);
        }
    }
}

package demo;

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;
import java.util.Enumeration;

@WebServlet("/request_demo3")
public class Request_demo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求头名称:user-agent
        String header = request.getHeader("user-agent");
        if(header.contains("Chrome")){
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write("我是谷歌O ");
        }
    }
}

1.3 获取请求体数据
只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数

1.获取流对象
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
2.再从流对象中拿数据

demo

package demo;

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.BufferedReader;
import java.io.IOException;

//获取请求体数据
@WebServlet("/request_demo4")
public class Request_demo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        BufferedReader reader = request.getReader();
        String line=null;
        while((line=reader.readLine())!=null){
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(line);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

2.其他功能
2.1 获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数

demo

package demo;

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;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

/*
获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数
			1. String getParameter(String name):根据参数名称获取参数值    username=zs&password=123
			2. String[] getParameterValues(String name):根据参数名称获取参数值的数组  hobby=xx&hobby=game
			3. Enumeration<String> getParameterNames():获取所有请求的参数名称
			4. Map<String,String[]> getParameterMap():获取所有参数的map集合
 */
@WebServlet("/request_demo5")
public class Request_demo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post中文乱码解决,设置字符编码为utf-8
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        String[] parameterValues = request.getParameterValues("hobby");
//        for (String parameterValue : parameterValues) {
//            System.out.println(parameterValue);
//        }
        Enumeration<String> parameterNames = request.getParameterNames();
//        while(parameterNames.hasMoreElements()){
//            String s = parameterNames.nextElement();
//            String parameter = request.getParameter(s);
//            System.out.println(s+"=="+parameter);
//        }
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> strings = parameterMap.keySet();
        for (String string : strings) {
            String[] strings1 = parameterMap.get(string);
            System.out.println(string);
            for (String s : strings1) {
                System.out.println(s);
            }
            System.out.println("---------");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

2.2 请求转发:一种在服务器内部的资源跳转方式

步骤
1.通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
2.使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)

特点:
1.浏览器地址栏路径不发生变化
2.只能转发到当前服务器内部资源中。
3.转发是一次请求

2.3 共享数据

首先得说明一下域对象,之前我们说请求转发是一次请求,就是一次请求可以波及到多个Servlet,这个影响的范围就是request域。
在这里插入图片描述

域对象:一个有作用范围的对象,可以在范围内共享数据

request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

方法
1.void setAttribute(String name,Object obj):存储数据
2.Object getAttitude(String name):通过键获取值
3.void removeAttribute(String name):通过键移除键值对

Response

功能:设置响应消息

1.设置响应行
格式为:HTTP/1.1 200 ok
可以设置状态码:setStatus(int sc)

2.设置响应头
setHeader(String name, String value)

3.设置响应体
步骤:
1.获取输出流,有两种
字符输出流:PrintWriter getWriter()
字节输出流:ServletOutputStream getOutputStream()

2.使用输出流,将数据输出到客户端浏览器

重定向
一种资源跳转的方式
在这里插入图片描述

package demo;

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;
@WebServlet("/response_demo1")
public class Response_demo1 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo1被访问到了");
//        //设置响应状态码为302,也就是重定向
//        resp.setStatus(302);
//        //设置重定向的页面
//        resp.setHeader("location","/Servlet_Demo/response_demo2");
        //重定向的简便写法
        resp.sendRedirect("/Servlet_Demo/response_demo2");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }
}

response如果回复中文,会产生乱码
在这里插入图片描述

package demo;

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;

@WebServlet("/response_demo2")
public class Response_demo2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter.write("demo2又被访问到了");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }
}

forward 和 redirect 区别
重定向的特点:redirect

  1. 地址栏发生变化
  2. 重定向可以访问其他站点(服务器)的资源
  3. 重定向是两次请求。不能使用request对象来共享数据

转发的特点:forward

  1. 转发地址栏路径不变
  2. 转发只能访问当前服务器下的资源
  3. 转发是一次请求,可以使用request对象来共享数据

SevletContext

代表整个web应用,可以和程序的容器(服务器)来通信

可以通过两种方法获取对象
1.通过request对象获取
request.getServletContext();

2.(推荐)通过HttpServlet获取
this.getServletContext();

SevletContext功能如下

1.获取MIME类型
MIME类型:在互联网通信过程中定义的一种文件数据类型
格式: 大类型/小类型
例如:text/html 或 image/jpeg
String getMimeType(String file)
在获取MIME类型后,我们就可以用来设置响应头类型

2.域对象:共享数据
这个跟request域的概念差不多,方法一样
但是ServletContext的范围更大,是所有用户所有请求的数据。request域的共享数据只在于一次请求的范围

1.setAttribute(String name,Object value)
2.getAttribute(String name)
3.removeAttribute(String name)

3.获取文件的真实(服务器)路径

方法:String getRealPath(String path)  
String b = context.getRealPath("/b.txt");//web目录下资源访问
System.out.println(b);

String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
System.out.println(c);

String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
System.out.println(a);

会话技术

会话:一次会话中包含多次请求和响应。
一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止

功能:在一次会话的范围内的多次请求间,共享数据

方式:
1.客户端会话技术:Cookie
2.服务器端会话技术:Session

Cookie

概念:客户端会话技术,将数据保存到客户端

使用步骤:
1.创建Cookie对象,绑定数据
new Cookie(String name, String value)
2.发送Cookie对象
response.addCookie(Cookie cookie)
3.获取Cookie,拿到数据
Cookie[] request.getCookies()

实现原理:基于响应头set-cookie和请求头cookie实现

服务器新建cookie对象,响应头发给客户端。
客户端收到cookie对象后,保存在客户端,之后的请求头会夹带cookie信息,所以服务器可以在请求头里拿cookie数据

在这里插入图片描述
cookie的细节
1.一次可不可以发送多个cookie?
可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。

2.cookie在浏览器中保存多长时间?
默认情况下,当浏览器关闭后,Cookie数据被销毁
我们可以使用持久化存储:

setMaxAge(int seconds)

seconds为存活秒值
正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
负数:默认值
零:删除cookie信息

3.cookie能不能存中文?
注意)在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析

URL编码:
String value=URLEncoder.encode(value,"utf-8");
URL解码:
String value=URLDecoder.decode(value,"utf-8");

4.cookie共享问题?
4.1 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
默认情况下cookie不能共享
setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
如果要共享,则可以将path设置为"/"

4.2 不同的tomcat服务器间cookie共享问题?
setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享

Cookie的特点和作用
特点
1.cookie存储数据在客户端浏览器
2.浏览器对於单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)

作用
1.cookie一般用于存储少量的不太敏感的数据
2.在不登录的情况下,完成服务器对客户端的身份识别

Session

服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession

使用步骤:
1.获取HttpSession对象:

HttpSession session = request.getSession();

2.使用HttpSession对象:

Object getAttribute(String name)  
void setAttribute(String name, Object value)
void removeAttribute(String name) 

原理:Session的实现是依赖于Cookie的。
客户端请求头会请求在服务器获取session值,如果没获取到,那就创建一个新的session对象。如果获取到了,那么服务器会自动响应给客户端一个sessionID。
接下来客户端的请求头就会夹带这个sessionID去服务器内获取session值。
在这里插入图片描述
细节

1.当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
默认情况下。不是。
如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。

Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);

2.客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作

session的钝化:
在服务器正常关闭之前,将session对象系列化到硬盘上
session的活化:(IDEA无法完成此功能,所以在IDEA中服务器一旦关闭在重启就是新的session了)
在服务器启动后,将session文件转化为内存中的session对象即可。

3.session什么时候被销毁?
1.服务器关闭
2.session对象调用invalidate() 。
3.session默认失效时间 30分钟
选择性配置修改

30

session的特点

1.session用于存储一次会话的多次请求的数据,存在服务器端
2.session可以存储任意类型,任意大小的数据

session与Cookie的区别:
1.session存储数据在服务器端,Cookie在客户端
2.session没有数据大小限制,Cookie有
3.session数据安全,Cookie相对于不安全

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章