javaweb之Servlet基础详解(一文看懂,干货多多)

44 篇文章 0 订阅
28 篇文章 0 订阅

Servlet基础

一、Servlet概述

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

即是:

  • Servlet是一个Java程序
  • 是运行在服务器上
  • 处理客户端请求并作出响应

1.回顾JSP如何编写服务器动态网页

在这里插入图片描述


就像其他普通的网页一样,您的浏览器发送一个HTTP请求给服务器。
Web服务器识别出这是一个对JSP网页的请求,并且将该请求传递给JSP引擎。通过使用URL或者.jsp文件来完成。
JSP引擎从磁盘中载入JSP文件,然后将它们转化为servlet。这种转化只是简单地将所有模板文本改用println()语句,并且将所有的JSP元素转化成Java代码。
JSP引擎将servlet编译成可执行类,并且将原始请求传递给servlet引擎。
Web服务器的某组件将会调用servlet引擎,然后载入并执行servlet类。在执行过程中,servlet产生HTML格式的输出并将其内嵌于HTTP response中上交给Web服务器。
Web服务器以静态HTML网页的形式将HTTP response返回到您的浏览器中。
最终,Web浏览器处理HTTP response中动态产生的HTML网页,就好像在处理静态网页一样。


二、Servlet与JSP的关系

1.疑问

发起疑问:先有JSP还是先有Servlet?(当然是先有Servlet了-手动滑稽)

在这里插入图片描述


回忆JSP 执行过程,然后说明JSP被翻译成.JAVA,这个.JAVA到底是什么样子呢?
打开环境,新建一个JSP,运行后,再观看此.java文件上,如Test.jsp在运行时首先解析成一个Java类Test_jsp.java,
而这个Test_jsp.java继承于org.apache.jasper.runtime.HttpJspBase类,
而HttpJspBase又是继承自HttpServlet的类,
由此可以得出一个结论,就是JSP在运行时会被Web容器翻译为一个Servlet


三、Servlet的声明周期

1.Servlet声明周期

在这里插入图片描述


2.生命周期的各个阶段

在这里插入图片描述


请求处理:当有请求到达容器时,容器会调用servlet对象的service方法。HttpServlet的service方法,它会根据用户的请求方式来调用doGet()或doPost().
但是,这两个do方法默认情况下会抛出异常,所以需要子类去重写(override)


3.Servlet构造方法

  • 构造方法只有首次调用Servlet时,会被执行,后续请求不在执行
  • 例如:
public HelloServlet() {
        //1.只有首次会执行
        System.out.println("创建HelloServlet对象");
    }

4.init()方法

  • init方法被设计成只调用一次
  • 它在第一次创建Servelt时,被调用,在后续每次用户请求时,不再调用。因此,它是用于一次性初始化。
@Override
    public void init(ServletConfig config) throws ServletException {
        //2.只有首次会执行
        System.out.println("开始初始化");
        super.init(config);
    }

5.service方法

  • service()方法是执行实际任务的主要方法
  • Servlet容器(即Web服务器)调用service()方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
@Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //3.每次刷新都执行
        System.out.println("service方法执行");
        super.service(req, resp);
    }

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。
service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。


6.doGet()方法

  • get请求来自于一个URL的正常请求,或者来自于一个未指定Method的HTML表单,它由doGet()方法处理。
@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //4.由service方法决定是调用doGet方法还是doPost等方法
        System.out.println("doGet方法执行");
    }

7.doPost()方法

  • post请求来自于一个特别指定了Method为POST的HTML表单,它由doPost()方法处理。
@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }

8.destroy()方法

  • destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
  • 在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:
@Override
    public void destroy() {
        //销毁时,执行
        System.out.println("destroy方法执行");
        super.destroy();
    }

9.GET和POST的区别

GET和POST的区别

GETPOST
从服务器上获取数据向服务器传送数据
把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一 一对应,在URL中可以看到通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程
传送的数据量较小,不能大于2KB传送的数据量较大,一般被默认不受限制(但跟服务器有关)
安全性非常低,但执行效率高安全性较高,但执行效率低

建议:

get方式的安全性较Post方式要差些,包含机密信息的话,建议用post数据提交方式。
在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式。


四、Servlet的配置、实例


实例1:简单的xml配置,带上下文参数和初始化参数

Servlet代码:

package cn.ebuy.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {
    public HelloServlet() {
        //1.只有首次会执行
        System.out.println("创建HelloServlet对象");
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        //2.只有首次会执行
        System.out.println("开始初始化");
        //获取上下文参数
        System.out.println(config.getServletContext().getInitParameter("deltools"));
        //获取初始化参数
        System.out.println(config.getInitParameter("dbtype"));
        System.out.println(config.getInitParameter("className"));
        super.init(config);
    }
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //3.每次刷新都执行
        System.out.println("service方法执行");
        super.service(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //4.由service方法决定是调用doGet方法还是doPost方法
        System.out.println("doGet方法执行");
        PrintWriter out=resp.getWriter();
        out.println("HelloServlet");
        //打印上下文参数
        out.println(this.getServletContext().getInitParameter("deltools"));
        //打印初始化参数
        out.println(this.getInitParameter("dbtype"));
    }

    @Override
    public void destroy() {
        //销毁时,执行
        System.out.println("destroy方法执行");
        super.destroy();
    }



    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}


web.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <context-param>
        <param-name>deltools</param-name>
        <param-value>idea</param-value>
    </context-param>
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>cn.ebuy.servlet.HelloServlet</servlet-class>

        <!--配置初始化参数-->
        <init-param>
            <param-name>dbtype</param-name>
            <param-value>mysql</param-value>
        </init-param>
        <init-param>
            <param-name>className</param-name>
            <param-value>HelloServlet</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/helloServlet</url-pattern>
    </servlet-mapping>




</web-app>

怎么启动时,就自动实例并初始化Servlet,而不是第一次访问时再创建呢?

在xml文件中<servlet>标签内加上 <load-on-startup>0</load-on-startup>(注意位置,不能在<init-param>前面)

在servlet的配置当中,1的含义是:
标记容器是否在启动的时候就加载这个servlet。
当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;
当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。
正数的值越小,启动该servlet的优先级越高。

如果我们在web.xml中设置了多个servlet的时候,可以使用load-on-startup来指定servlet的加载顺序,服务器会根据load-on-startup的大小依次对servlet进行初始化。不过即使我们将load-on-startup设置重复也不会出现异常,服务器会自己决定初始化顺序。
版权声明:本文为CSDN博主「xuke6677」的原创文章
原文链接


实例2:使用WebServlet注解配置Servlet

首先有可能你不能使用WebServlet这个注解,接下来有解决方法:

在这里插入图片描述


类代码:

package cn.ebuy.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
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.io.PrintWriter;

/**
 * 测试注解配置Servlet
 */
//配置注解属性
@WebServlet(name = "roleServlet",urlPatterns = {"/roleServlet","/role"},loadOnStartup = 1,initParams = {@WebInitParam(name = "deltool",value = "idea"),
@WebInitParam(name = "dbtype",value = "mysql")
} )

public class RoleServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out= resp.getWriter();

        //获取初始化属性deltool
        out.println(this.getInitParameter("deltool"));
    }

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


实例3:测试Servlet是线程不安全

测试1 单例:

package cn.ebuy.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;
import java.io.PrintWriter;

@WebServlet("/testServlet1")
public class TestServlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out= resp.getWriter();
        out.println(this);
    }

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

页面显示:

在这里插入图片描述


测试2:

类代码:

package cn.ebuy.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;
import java.io.PrintWriter;

@WebServlet("/testServlet1")
public class TestServlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out= resp.getWriter();

        String op= req.getParameter("op");
        if (op.equals("read")){
            out.println(i);
        }else if (op.equals("add")){

            this.add();
        }
    }

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

    int i;
    public void add(){
        this.i++;
    }



}

效果:

在这里插入图片描述


之后

在这里插入图片描述


由此得出结论:Servlet慎用全局变量


至此便结束了


  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小吕努力变强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值