Javaweb的三大组件之-Servlet

Javaweb的三大组件之-Servlet

概述

Servlet是JavaWeb三大组件之一,它是我们学习JavaWeb最为基本的组件,也就是说一定要100%的掌握它

其它两种:Filter(拦截器)、Listener(观察者模式),后续讲解

Servlet,即Server Let的意思,用来处理用户请求,当客户端发出请求后,由Tomcat去找到可以处理这一请求的Servlet来处理

也就是说,用户的请求是由Servlet来处理的!例如用户发出登录请求,那么就应该由处理登录的Servlet来处理;用户发出登录请求,那么就应该有登录Servlet来处理

Servlet实现

servlet 是运行在 Web 服务器中小型 Java 程序。servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。也就是说,Servlet是由我们自己来完成的!但Servlet一定要实现javax.servlet.Servlet接口,并且还要在web.xml文件中部署!不然Tomcat是找不到我们写的Servlet的

Servlet接口

javax.servlet.Servlet接口中方法如下:

  • void init(ServletConfig servletConfig):当Tomcat创建Servlet实例后,马上调用init()方法。这个方法只在创建后调用一次!用来做Servlet初始化工作!一个Servlet实例只被创建一次,所以init()方法也只被调用一次!(本方法编写对Servlet的初始化代码)
  • void service(ServletRequest request, ServletResponse response):Servlet实例在每次处理请求时都调用service()方法
  • void destroy():当Tomcat要销毁Servlet实例时,会先调用destroy()方法,再销毁它。所谓销毁Servlet,其实就是在Servlet缓存池中把Servlet移除!一般只有Tomcat关闭时,才会销毁Servlet实例
  • ServletConfig getServletConfig():这个方法返回ServletConfig对象,但我们不能自己去创建ServletConfig对象,所以一般我们会在init()方法中把init()方法的参数保存起来,然后再在本方法中返回它ServletConfig对象对应web.xml中当前Servlet实例的配置信息
  • String getServletInfo():这个方法只是返回一个字符串,用来说明当前Servlet。基本没用!

实现:

  • 第一步:src下建立class、实现Servlet的接口,实现接口中的方法
import javax.servlet.*;
import java.io.IOException;

public class testServlet 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 {
       
        //以字节流的形式写入页面
        servletResponse.getOutputStream().write(" i am login..".getBytes());

    }

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

    @Override
    public void destroy() {

    }
}

  • 第二步:配置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_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>testServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
    
</web-app>

第三步,启动Tomcat,浏览器输入http://localhost:8081/login

成功访问到servlet

JavaWeb请求响应原理如下:

当Tomcat接收到请求http://localhost:8081/login后,Tomcat会找到项目中的web.xml文件,然后通过login这个请求路径,查找处理这个请求的Servlet类型,这刚好与<url-pattern>/login</url-pattern>匹配,说明存在一个可以通过这个请求的Servlet,然后再通过<url-pattern>/login </url-pattern>查找到<servlet-name>login</servlet-name>,然后再通过<servlet-name>login </servle-name>查找到<servlet-class>testServlet</servlet-class>。这时Tomcat已经得到了一个Servlet类名字(一个字符串而已)

omcat通过Servlet类名字去查找内存中是否存在Servlet对象,如果存在,那么就不用再去创建,直接获取这个Servlet实例,调用它的service()方法完成请求

如果这个Servlet不存在,那么Tomcat会通过反射来创建Servlet实例,并把Servlet实例存放到Servlet池中,再去调用Servlet的service方法处理请求

Servlet生命周期

Servlet对象的实例默认情况下是在浏览器第一次调用servlet时候被创建的(可以修改其创建时机后续讲解)

Servlet的实例不由我们创建,Servlet的方法不由我们来调用,这一切都是由Tomcat来完成,这就是说由Tomcat来管理Servlet,而我们只需要去编写Servlet实现类并将其部署到web.xml文件中去

提醒:只有这三个方法(init()、service()、destroy())是生命周期中的方法。也就是说,生命周期方法会被Tomcat在不同的时间点来调用!而其它方法就不会被调用了!!!如果你在自己写的Servlet中添加了其他方法,那么Tomcat也是不会去调用它们的!但你可以让生命周期方法去调用你自己写的方法就OK了

HttpServlet

因为现在我们的请求都是基于HTTP协议的,所以我们应该专门为HTTP请求写一个Servlet做为通用父类

对于专注于HTTP的Servlet,我们需要处理以下几个问题:

service()方法的参数ServletRequest和ServletResponse,因为所有的请求都是HTTP请求,所以传递给service()就去的参数其实是HttpServletRequest和HttpServletResponse对象如果子类希望使用的是HttpServletRequest,而不是ServletRequest,那么它需要自己去做强转

Servlet:一个标准

GenericServlet:是Servlet接口子类

HttpServlet与协议相关的Servlet

实现HttpServlet,只需要重写doGet和doPost就行

根据请求方式的不同,调用doGet方法或doPost方法

代码示例:

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

public class TestHttpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getOutputStream().write(" doGet方法被调用".getBytes());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getOutputStream().write(" doPost方法被调用".getBytes());
    }
}

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_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>HttpServlet</servlet-name>
        <servlet-class>TestHttpServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HttpServlet</servlet-name>
        <url-pattern>/httpservlet</url-pattern>
    </servlet-mapping>

</web-app>

效果:

Tomcat启动时调用Servlet

有些Servlet需要在Tomcat启动时就被创建,而不是第一次访问时被创建,那么可以在web.xml文件中配置< servlet >元素,添加子元素< load-on-startup>元素,里面的数值必须大于0

	<servlet>
		<servlet-name>One</servlet-name>
		<servlet-class>com.rl.servlet.OneServlet</servlet-class>
		<load-on-startup>0</load-on-startup>
	</servlet>
	<servlet>
		<servlet-name>Two</servlet-name>
		<servlet-class> com.rl.servlet.TwoServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
  • 所有添加了< load-on-startup>子元素的Servlet,都会在Tomcat启动时被创建!当然,只是被创建,但没有处理请求

  • < load-on-startup>元素的值是一个序号,Tomcat会使用这个序号给多个Servlet排序!然后在Tomcat启动时会按这个顺序来创建Servlet实例对象

ServletConfig

ServletConfig对象对应web.xml文件中的< servlet>元素,例如,你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法获取

例如

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println(config.getServletName());
    }

你不能自己去创建ServletConfig对象,Servlet的init()方法的参数就是ServletConfig类型的。Tomcat在调用init()方法时,会传递ServletConfig对象。你可以在init()方法中使用它

添加初始化参数:

<servlet>
  <servlet-name>One</servlet-name>
  <servlet-class>
  	OneServlet
  </servlet-class>
  
  <init-param>
   	<param-name>paramName1</param-name>
    <param-value>paramValue1</param-value>
  </init-param>

  <init-param>
  	  <param-name>paramName2</param-name>
  	  <param-value>paramValue2</param-value>
  </init-param>
 </servlet>

配置中加了两个初始化参数,第一个参数的名称为paramName1,第一个参数的值为paramValue1;第二个参数的名称为paramName2,第二个参数值为paramValue2

获取实例

        System.out.println(config.getInitParameter("paramName1"));

Servlet路径映射

这是关于Url-Pattern的配置

    <servlet-mapping>
        <servlet-name>HttpServlet</servlet-name>
        <url-pattern>/httpservlet</url-pattern>
    </servlet-mapping>
  • 完全路径匹配 以/开头 例如 /aaa /aaa/bbb

  • 目录匹配(通配符匹配) 以/开头 例如 /aaa/* /*

例如,我们把路径映射设置如下

    <servlet-mapping>
        <servlet-name>HttpServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

启动tomcat,访问http://localhost:8081/

或者访问http://localhost:8081/a/b(a/b不存在)

都可以被调用

  • 扩展名匹配 不能以/开头 例如 *.do *.action …

优先级: 完全路径匹配 > 目录匹配 > 扩展名匹配

经典错误: /*.do

ServletContext(容器)

WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用

由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象

一般应用:

获取WEB应用的全局初始化参数,通过ServletContext域对象实现数据共享

来源:

调用:

拿到域对象之后可以做的事情:

核心方法:

getRealPath获得路径问题

获取根目录:

是从当前servlet 在tomcat 中的存放文件夹开始计算起的(一般称根目录)

    @Override
    public void init(ServletConfig config) throws ServletException {
        ServletContext context = config.getServletContext();
        //"/"代表根目录
        String path = context.getRealPath("/");
        System.out.println(path);
    }
  • /代表根目录
  • 此方法不会判断文件是否真实存在,故路径要写对(文件所在的位置按照根目录(/)后的目录层级写入)

读取文件信息:

    @Override
    public void init(ServletConfig config) throws ServletException {
        ServletContext context = config.getServletContext();
        //"/"代表根目录
        System.out.println(context.getRealPath("/"));
        /*先从本地根目录文件夹下找到test.properties文件,确定好根目录后的路径,再确定参数*/
        InputStream in  = context.getResourceAsStream("/WEB-INF/classes/test.properties") ;
        Properties pro  = new Properties() ;
        try {
            pro.load(in);
            System.out.println(pro.get("key"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

单例的Servlet

因为Servlet实例是由Tomcat来创建的,但Tomcat只会创建一个Servlet实例,所以Servlet就是单例的!这与我们自己写的单例模式不太一样。因为这种单例是通过容器来管理而实现的!

一个实例需要在同一个时间点上处理多个请求!

同步就是安全,但效率太低!

Servlet是线程不安全的!

所以注意:

单例的servlet的属性的公共的,在不加锁的情况下,线程不安全,故

  • 不写属性;

  • 不写可以存储数据的属性!

发布了161 篇原创文章 · 获赞 93 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/JunSIrhl/article/details/103952029
今日推荐