Servlet

Servlet (第一部分 p1-p6)

1. HTTP协议

HTTP 协议(Hypertext Transfer Protocol, 超文本传输协议)

是一个客户端请求和响应的标准协议,这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。用户输入地址和端口号之后就可以从服务器上取得所需要的网页信息。

客户端发送给服务器的格式叫"请求协议";服务器发送给客户端的格式叫"响应协议"。

1.1 浏览器中的书写格式

服务器端资源需要通过浏览器进行,此时由浏览器将我们给出的请求解析为满足 HTTP 协议的格式并发出。

请求格式需要按照浏览器规定的格式来书写,在浏览器中书写格式如下:

//规则     内容 http协议需要按照规则给数据,后期也会按照规则解析
http://   127.0.0.1:8080 / myweb/sevlet01 ?name=zs

1.2 HTTP协议的特点

  • 支持客户/服务器模式
  • 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的 有 GET、POST。每种方法规定了客户与服务器联系的类型不同。由于 HTTP 协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  • 灵活:HTTP 允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
  • 无连接: 无连接是表示每次连接只处理一个请求。基于请求-响应模型.(一次请求对应一次响应) 服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  • **无状态:HTTP 协议是无状态协议。**无状态是指协议对于事务处理没有记忆能力。
    • 缺点: 缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送 的数据量增大。多次请求不能共享数据.java使用会话技术(cookie / session)来解决该问题
    • 优点: 另一方面,在服务器不需要先前信息时它的应答就较快。速度快
  • 基于TCP协议:面向连接,安全

1.3 HTTP之URL

HTTP(超文本传输协议)是一个基于请求与响应模式的、应用层的协议,常基于 TCP 的连接方式. 所以是面向连接,安全的.

HTTP URL (URL 是一种特殊类型的 URI,包含了用于查找某个资源的足够的信息)的格式 如下:

//通过http协议定位网络资源
  http://host[:port]/[abc_path]
      //表示主机域名或者IP,port指端口号,缺省端口80
//abs_path 指定请求资源的 URI; 如果 URL 中没有给出,当它作为请求 URI 时,必须以“/”的形式给出
http://IP(主机名/域名):端口/访问的资源路径
//

1.4 HTTP 请求数据格式

HTTP 请求数据结构由三部分组成,分别是:请求行、请求头、请求正文。

  1. 请求行 :请求数据的第一行。其中GET表示请求方式,/表示请求资源的路径,HTTP/1.1表示请求协议版本
  2. 请求头: 第二行开始,格式为键值对
  3. 请求体: POST请求的最后一行,存放请求参数

常见的HTTP请求头:

  • Host:表示请求的主机名
  • User-Agent:浏览器版本
  • Accept: 表示浏览器能接受的资源类型,如text/html
  • Accept-Language: 表示浏览器偏好的语言
  • Accept-Encoding: 表示浏览器可以支持的压缩类型

GET与POST请求的区别:

  1. GET的请求参数在请求行中,没有请求体。POST的请求参数在请求体中
  2. GET的请求参数大小有限制,POST没有

1.5 HTTP 响应

在接收和解释请求消息后,服务器返回一个 HTTP 响应消息。HTTP 响应也是由三个部分组成,分别是:状态行、消息报头、响应正文

  1. 响应行: 响应数据的第一行,其中HTTP/1.1表示协议的版本,200表示状态码,OK表示状态码的描述
  2. 响应头: 第二行开始,格式为键值对
  3. 响应体: 最后一部分,存放响应数据
1.6 消息头
  • Content-Type:表示该响应内容的类型,例如text/html
  • Content-Length:表示该响应内容的长度(字节数)
  • Content-Encoding:表示该响应的压缩算法
  • Cache-Control:指示客户端应如何缓存

状态码分类 说明
1xx 响应中——临时状态码,表示请求已接受,告诉客户端应该继续请求或者如果它完成了就 忽略它
2xx 成功——表示请求已被成功接收,处理已完成
3xx 重定向——重定向到其他地方:它让客户端再发起一个请求以完成整个处理
4xx 客户端错误——处理发生错误,责任在客户端。
5xx 服务器端错误——处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等

常见的响应码:

  • 200 表示请求成功
  • 302 表示请求重定向
  • 404 表示服务器收到请求,但是请求的数据不存在(请求地址错误)
  • 500 表示服务器收到请求,但是服务器内部错误(代码错误)

MIME类型说明:

MIME是HTTP协议中的数据类型,格式是:大类型/小类型,并与某一种文件的扩展名相对应:

img

上图引用来源:https://blog.csdn.net/Curry_Java/article/details/123664915

2 Web服务器

web服务器是一个应用程序(软件),对HTTP协议的操作进行封装,使得程序员不必直接对协议进行操作,让Web开发更加便捷。主要功能是“提供网上信息浏览服务”

3 . Servlet的实现

Servlet 是 Server 与 Applet 的缩写,是服务端小程序的意思。

使用 Java 语言编写的服务器端程序(开发动态网站的技术),可以像生成动态的 WEB 页,Servlet 主要运行在服务器端,并由服务器调用执行, 是一种按照Servlet 标准来开发的类。

是 SUN 公司提供的一门用于开发动态Web 资源的技术。

Servlet 本质上也是 Java 类,但要遵循 Servlet 规范进行编写,没有 main()方法,它的创建、使用、销毁都由 Servlet 容器进行管理(如 Tomcat)。

Servlet的类继承体系结构

引用来源:https://blog.csdn.net/Curry_Java/article/details/123664915

img

拓展,实现servlet的三种方式,

一, 见如下文章举例: 继承HttpServlet类

二. 继承GenericServlet类

@WebServlet("/ser02")
public class Servlet02 extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("继承GenericServlet类...");
    }
}

三. 实现Servlet接口

@WebServlet("/ser03")
public class Servlet03 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("实现Servlet接口...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
    }
}

本文采用JDK11版本 和 IDEA20.2版本 和tomcat8.5举例

3.1 创建Web项目

  1. 选择 “File” —> “New” —> “Project”
    在这里插入图片描述

在这里插入图片描述

  1. 设置项目的相关信息,选择 “Next”
    在这里插入图片描述
    在这里插入图片描述

  2. 设置项目名称及工作空间

以上步骤走完,具体的web项目目录结构如下图:

3.2 Servlet的实现

第一步:配置tomcat服务器,具体步骤如下:
在这里插入图片描述

第二步,相关属性设置如下图:
在这里插入图片描述
在这里插入图片描述

上图注意,

  1. 由于8080可能存在端口冲突,因此博主给他修改成为了8079,大家可以自行按规范设置
  2. 另外为了简化资源路径,博主将URL的地址在Deployment的路径修改成 /demo0206

创建一个普通的 Java 类

在这里插入图片描述

在这里插入图片描述

总结以上java类步骤:

  1. 新建java类
  2. 实现Servlet规范: 实现 Servlet 规范,即继承 HttpServlet 类,并到如响应的包,该类中已经完成了通信的规则,我们只需要进行业务的实现即可
  3. 重写 service 方法: 满足 Servlet 规范只是让我们的类能够满足接收请求的要求,接收到请求后需要对请求进行分析,以及进行业务逻辑处理,计算出结果,则需要添加代码,在规范中有一个叫做 service的方法,专门用来做请求处理的操作,业务代码则可以写在该方法中。
  4. 设置注解 : 向服务器说明,特定请求对应特定资源。开发servlet项目,使用@WebServlet将一个继承于javax.servlet.http.HttpServlet 的类定义为Servlet组件。在Servlet3.0中 , 可以使用@WebServlet注解将一个继承javax.servlet.http.HttpServlet的类标注为可以处理用户请求的Servlet。
  5. 发布项目并启动服务 需要外界能够访问, 还需要将项目发布到服务器上并运行服务器。
  6. 访问并查看结果 用户即可通过浏览器访问该项目中的资源。注意 url 的 格式正确,一般tomcat 的端口为 8080。本文特殊设置为8079.
/*
* 第一步,继承HttpServlet类            实现Servlet的规范
* 第二步,重写service方法               用来处理请求
* 第三步,方法体语句编写
* 第四步,注解@WebServlet("/demo0206")  设置注解,指定访问的路径
* */
@WebServlet("/demo0206")
public class HelloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");//防止中文乱码
        resp.setHeader("content-type","text/html;charset=UTF-8");//因为默认是ISO-8859-1编码格式,需要设置修改为UTF-8
        System.out.println("你好,servlet");
        resp.getWriter().write("你好,Hello,servlet..."); // 通过流输出数据到浏览器
    }
}

到这里,我们的第一个Servlet 就实现了!

3.3 Servlet的生命周期

Servlet没有 main()方法,不能独立运行,它的运行完全由 Servlet
引擎来控制和调度。 所谓生命周期,指的是 servlet 容器何时创建
servlet 实例、何时调用其方法进行请求的处理、 何时并销毁其实
例的整个过程。

实例和初始化时机
当请求到达容器时,容器查找该 servlet 对象是否存在,如果不
存在,则会创建实例并进行初始化。

init方法,在Servlet实例创建之后执行(该Servlet已经有实例创建),仅仅一次

  • 初始化方法,在Servlet被创建时执行,只执行一次

就绪/调用/服务阶段
有请求到达容器,容器调用 servlet 对象的 service()方法,处理
请求的方法在整个生命周期中可以被多次调用; HttpServlet 的
service()方法,会依据请求方式来调用 doGet()或者 doPost()方
法。但是, 这两个 do 方法默认情况下,会抛出异常,需要子
类去 override。

service 方法,每次有请求到达某个 Servlet 方法时执行,用来处
理请求(证明该Servlet 进行服务了),每次调用

  • 提供服务方法,每次Servlet被访问,都会调用该方法

销毁时机
当容器关闭(或者释放内存)时(应用程序停止时),会将程序中的 Servlet 实例
进行销毁。该实例随后被java的垃圾收集器回收

上述的生命周期可以通过 Servlet 中的生命周期方法来观察。在
Servlet 中有三个生命周 期方法,不由用户手动调用,而是在特
定的时机有容器自动调用,观察这三个生命周期方法 即可观察
到 Servlet 的生命周期。

destroy 方法,Servlet 实例销毁时执行(证明该 Servlet 的实例被
销毁了)仅仅一次

Servlet 的生命周期,简单的概括这就分为四步:servlet 类加载–>
实例化–>服务–>销毁。

  1. Web Client 向 Servlet 容器(Tomcat)发出 Http 请求

  2. Servlet 容器接收 Web Client 的请求

  3. Servlet 容器创建一个 HttpServletRequest 对象,将 Web
    Client 请求的信息封装到这个对象 中

  4. Servlet 容器创建一个 HttpServletResponse 对象

  5. Servlet 容器调HttpServlet 对象service 方法,把 Request 与
    Response 作为参数,传给 HttpServlet

  6. HttpServlet 调用 HttpServletRequest 对象的有关方法,获取
    Http 请求信息

  7. HttpServlet 调用 HttpServletResponse 对象的有关方法,生成
    响应数据

  8. Servlet 容器把 HttpServlet 的响应结果传给 Web Client

4. HttpServletRequest对象

HttpServletRequest 对象:主要作用是用来接收客户端发送过来的
请求信息

HttpServletRequest 是 ServletRequest 的子接口,

直接在Service 方法中由容器传入过来,而我们需要做的就是取出对象中
的数据,进行分析、处理。

4.1 接收请求

常用方法
获取请求参数
// 获取指定名称的参数,返回字符串
String uname = request.getParameter("uname");
System.out.print(uname);
// 获取指定名称参数的所有参数值,返回数组
String[] hobbys =
request.getParameterValues("hobby");
System.out.println("获取指定名称参数的所有参数值:"
+ Arrays.toString(hobbys));

请求乱码问题

request 属于接收客户端的参数,在解析过程中默认使用的编码方式为 ISO-
8859-1(此编码不支持中文),所以解析时一定会出现乱码。

方式一:

/*
* 第一步,继承HttpServlet类
* 第二步,重写service方法
* 第三步,方法体语句编写
* 第四步,注解@WebServlet("/demo0206")
* */
@WebServlet("/demo0206")
public class HelloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");//防止中文乱码
        resp.setHeader("content-type","text/html;charset=UTF-8");//因为默认是ISO-8859-1编码格式,需要设置修改为UTF-8
        System.out.println("你好,servlet");
        resp.getWriter().write("你好,Hello,servlet...");
    }
}

这种方式只针对 POST 有效(必须在接收所有的数据之前设定)

**
 * 乱码原因:
 *      由于在解析过程中默认使用的编码方式为 ISO-8859-1(此编码不支持中文),所以解析时一定会出现乱码。
 *
 * 请求乱码问题
 *                  Tomcat8及以上版本                                Tomcat7及以下版本
 *  GET请求         不会乱码,不需要处理                              new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
 *
 *  POST请求        会乱码,通过设置服务器解析编码的格式               会乱码,通过设置服务器解析编码的格式
 *                  request.setCharacterEncoding("UTF-8");          request.setCharacterEncoding("UTF-8");
 *
 *  乱码情况:
 *      POST请求:无论什么版本的服务器,post请求中文都会乱码。(request.setCharacterEncoding("UTF-8");*
 *  注:
 *      1. request.setCharacterEncoding("UTF-8") 只针对POST请求乱码有效
 *      2. new String(request.getParameter("uname").getBytes("ISO-8859-1"),"UTF-8") 针对任何请求方式。
 *        但是如果数据本身不乱吗,还依然使用new String()方法转换,则会乱码
 */
@WebServlet("/s02")
public class Servlet02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置请求的编码格式
        request.setCharacterEncoding("UTF-8");

        // 获取客户端传递的参数
        String uname = request.getParameter("uname");
        String upwd = request.getParameter("upwd");
        System.out.println("姓名:" + uname);
        System.out.println("密码:" + upwd);

        // 解决Tomcat7及以下版本的GET请求乱码
        String name = new String(request.getParameter("uname").getBytes("ISO-8859-1"),"UTF-8");
        System.out.println("name:" + name);
    }
}

请求转发

请求转发(forward),是一种服务器的行为(服务器内部的资源跳转方式).地址栏中的 URL 地址不会改变,从始至终只有一个请求发出

request.getRequestDispatcher(url).forward(request
,response);

特点:

  • 浏览器 地址不会改变,
  • 从始至终只有一个请求发出
  • 只能转发到当前服务器的内部资源,可转发到WEB-INF目录下
  • 可以共享Request域中的数据
  • 不可以访问工程以外的资源
/**
 * 请求转发跳转
 *    request.getRequestDispatcher(url).forward(request,response);
 *   可以让请求从服务端跳转到客户端(或跳转到指定Servlet)
 *
 *   特点:
 *      1. 服务端行为
 *      2. 地址栏不发生改变
 *      3. 从始至终只有一个请求
 *      4. request数据可以共享
 */
@WebServlet("/s03")
public class Servlet03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 接收客户端请求的参数
        String uname = request.getParameter("uname");
        System.out.println("Servlet03 uname :" + uname);

        // 请求转发跳转到Servlet04
        // request.getRequestDispatcher("s04").forward(request,response);
        // 请求转发跳转到jsp页面
        // request.getRequestDispatcher("login.jsp").forward(request,response);
        // 请求转发跳转到html页面
        request.getRequestDispatcher("login.html").forward(request,response);
    }
}

request作用域

通过该对象可以在一个请求中传递数据,作用范围:在一次请求中
有效,即服务器跳转有效。

request 域对象中的数据在一次请求中有效,则经过请求转发,
request 域中的数据依然存在,则在请求转发的过程中可以通过
request 来传输/共享数据。

/**
 *  request作用域
 *      通过该对象可以在一个请求中传递数据,作用范围:在一次请求中有效,即服务器跳转有效。(请求转发跳转时有效)
 *      // 设置域对象内容
 *      request.setAttribute(String name, Object value);
 *      // 获取域对象内容
 *      request.getAttribute(String name);
 *      // 删除域对象内容
 *      request.removeAttribute(String name);
 */
@WebServlet("/s05")
public class Servlet05 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Servlet05...");

        // 设置域对象内容
       request.setAttribute("name","admin");
       request.setAttribute("age",18);
       List<String> list = new ArrayList<>();
       list.add("aaa");
       list.add("bbb");
       request.setAttribute("list",list);

       // 请求转发跳转到Servlet06
       // request.getRequestDispatcher("s06").forward(request,response);
       // 请求转发跳转到jsp 并通过域对象传递数据
       request.getRequestDispatcher("index.jsp").forward(request,response);
    }
}
WebServlet("/s06")
public class Servlet06 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Servlet06...");
        // 获取域对象内容
        String name = (String) request.getAttribute("name");
        System.out.println("name:" + name);
        Integer age  = (Integer) request.getAttribute("age");
        System.out.println("age:" + age);
        List<String> list = (List<String>) request.getAttribute("list");
        System.out.println(list.get(0));
    }
}

5. HttpServletResponse对象

request 和 response 对象代表请求和响应:获取客户端数据,需
要通过 request 对象;向客户端输出数据,需要通过 response 对
象。

HttpServletResponse 的主要功能用于服务器对客户端的请求进行
响应,将 Web 服务器处理后的结果返回给客户端

service()方法中
形参接收的是 HttpServletResponse 接口的实例化对象,这个对象
中封装了向客户端发送数据、发送响应头,发送响应状态码的方
法。

5.1 响应数据

getWriter() 获取字符流(只能响应回字符)

getOutputStream() 获取字节流(能响应一切数据)

注意:两者不能同时使用。如果同时使用会报错:java.lang.IllegalStateException: getWriter() has already been called for this response

5.2 响应乱码问题

1 . getWriter()的字符乱码

一句话:保证发送端和接收端的编码一致

// 设置服务端的编码
response.setCharacterEncoding("UTF-8");
// 设置客户端的响应类型及编码
response.setHeader("content-
type","text/html;charset=UTF-8");
// 得到字符输出流
PrintWriter writer = response.getWriter();
writer.write("<h2>你好</h2>");
//同时指定服务器和客户端
response.setContentType("text/html;charset=UTF-8");

2 . getOutputStream()字节乱码

指定客户端和服务器使用的编码方式一致。

response.setHeader("content-type","text/html;charset=UTF-8");
// 设置客户端的编码及响应类型
ServletOutputStream out =
response.getOutputStream();
response.setHeader("content-
type","text/html;charset=UTF-8");
out.write("<h2>你好</h2>".getBytes("UTF-8"));
// 设置客户端与服务端的编码
response.setContentType("text/html;charset=UTF-8");

5.3 重定向

重定向是一种服务器指导,客户端的行为。

请求重定向的特定:

  • 浏览器地址会直接发生变化
  • 两次请求
  • 不共享Request域中的数据
  • 不能访问WEB-INF下的资源
  • 可以访问工程外的资源
@WebServlet("/s04")
public class Servlet04 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Servlet04...");

        // 接收参数
        String uname = request.getParameter("uname");
        System.out.println("Servlet04 " + uname);

        // 重定向跳转到s05
        response.sendRedirect("s05");
    }
}
/**
 * 重定向与请求转发的区别
 *    1. 请求转发的地址栏不会发生改变,重定向的地址栏会发生改变
 *    2. 请求转发只有一次请求,重定向有两次请求
 *    3. 请求转发时request对象可共享,重定向时request对象不共享
 *    4. 请求转发是服务端行为,重定向是客户端行为
 *    5. 请求转发时的地址只能是当前站点下(当前项目)的资源,重定向时地址可以是任何地址
 *
 */
   写在结尾:  
   超详细保姆级别笔记!
   这是servlet第一部分,剩余的cookie,session还有过滤器等内容下回更新.
   走过路过的小伙伴别忘了小手一点,点赞加关注啊,多谢
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值