Javaweb三大组件之Servlet

Javaweb开发中有很重要的三个组件分别是:Servlet,Filter,Listener。这些组件在Javaweb的开发中起着不同且至关重要的作用,而我们常用的web框架基本都是基于这些基础组件进行封装之后的用法,所以对于这些原生的方式进行Javaweb开发也要需要了解的,这样对框架的认识也能更加深入,理解为什么要那么做。

1.Serlvet的广义概念

Servlet是运行在服务器容器中的一个小程序,所有的用户请求最终都会汇入这里,然后根据请求,通过url交给不同的Servlet对象去处理,也就是业务逻辑的核心部分。

2.Servlet的作用

Servlet在Javaweb担当核心的作用,最核心的业务逻辑是在Servlet对象中进行处理,然后返回给用户的,也是我们最需要关注的组件。

3.Servlet的狭义概念

但是其实Servlet在Java中就是一个有5个抽象方法的接口而已,通过实现这个接口构建不同的Servlet类,处理不同的业务请求。

这就是那个神奇的Servlet最本来的样子。

这几个函数去看api就知道了,下面主要演示一个Servlet的简单例子,看看怎么使用Servlet来进行web的开发。

 

4. Servlet的基本使用

首先是使用最基本的Servlet接口来实现访问一个url,然后返回success,顺便说一下Servlet的一些xml设置和生命周期

1. 首先需要实现Serlvet接口来创建一个Serlvet类,这样才能创建对象(接口不能实例化,应该都知道吧)

public class ServletDemo implements Servlet{

    //对象销毁时调用
    @Override
    public void destroy( ){
        System.out.println("Servlet has been destroyed");
    }

    //这个方法一般不用管
    @Override
    public ServletConfig getServletConfig(){
        return null;
    }

    //这个方法一般不用管
    @Override
    public String getServletInfo(){
        return null;
    }

    //做Servlet的一些初始化操作,在Serlvet实例创建的同时调用
    @Override
    public void init(ServletConfig servletConfig)throws ServletException{
        //测试ServletConfig对象是否接收到xml里面配置的参数
        String username = servletConfig.getInitParameter("username");
        System.out.println("username: "+ username);

        System.out.println("Servlet has been created");
    }

    //这个是Servlet里面最重要的函数,通过这个函数来处理对应的请求的业务
    // 这里可以去学习ServletRequest和ServletResponse这两个类,整个web的前后端交互都是基于Request和Response的
    @Override
    public void service(ServletRequest request, ServletResponse response)
            throws ServletException, IOException{
        response.getWriter().write("success");
    }
}

这样用一个类ServletDemo来实现了我们最原始的Serlvet接口,这样这个SerlvetDemo就具备处理请求的能力了,但是处理是谁的请求,又是如何映射到这个类的实例上的呢?

接下来配置Servlet另一个很重要的部分,就是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">

    <!-- 声明一个Servlet,并且与一个实体类之间构成映射-->
    <servlet>
        <!-- 这是Servlet的name可以自己随便取-->
        <servlet-name>servletDemo</servlet-name>

        <!-- 这是这个名字对应的那个class -->
        <servlet-class>com.lyh.servlet.ServletDemo</servlet-class>

        <!-- 这是为Servlet的init函数中的参数ServletConfig对象里面添加值,通过这样配置就可以在ServletCongfig对象中取到了 -->
        <init-param>
            <param-name>username</param-name>
            <param-value>lyh</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>112233</param-value>
        </init-param>

        <!-- 这条配置设置Servlet随着服务器启动就创建实例,值必须为大于零的整数,如果有多个,就根据值的从小到大排序进行创建实例 -->
        <!-- 如果没有的话,Servlet就在他对应的url第一次被访问的时候创建 -->
        <load-on-startup>1</load-on-startup>

    </servlet>

    <!-- 这是Servlet和一个url的映射,即对url的访问会被转向name等于这个的Servlet来处理 -->
    <servlet-mapping>
        <!-- 一个已经声明了的Servlet的name -->
        <servlet-name>servletDemo</servlet-name>

        <!-- 想要转向此Servlet处理的url -->
        <!-- URL格式支持三种格式的URL形式
            完全路径匹配:例如/login
            目录匹配:例如/user/* , /user/*
            扩展名匹配:例如*.do,这种情况是不能加/的,比如/*.do就是错误的
            当上述三种匹配都通过话,匹配的优先级是完全路S径>目录匹配>扩展名匹配
        -->
        <url-pattern>/ServletDemo</url-pattern>
    </servlet-mapping>

</web-app>

这里的xml就配置了我们访问"项目路径/ServletDemo”的时候,会将请求转到ServletDemo这个name的Servlet实例去处理,然后就去找name为ServletDemo的实例,然后发现找到了,对应的类是com.lyh.Servlet.ServletDemo这个用户创建的类。那么就会去创建一个这个类的对象(一般方便起见,都称为Servlet实例),调用init方法。

此时这个Servlet的生命周期就开始了,通过自己的Service方法来处理从各个ip发来的Http请求,只要是对这个url的请求,都会转给他来处理,知道服务器关闭的时候,这个Servlet实例就被销毁了,然后destroy方法被调用,Servlet实例生命周期结束。

这样一个基础的web响应就完成了,通过Servlet,Java里比较原生的方式实现了。

但是我们发现Servlet这个接口直接实现使用有很多不方便的地方,而且我们一般只是和Http协议进行交互,Java设计者自然也想到了这一点,所以在javax.servlet库中已经有为Http协议专门设计的一个类,HttpServlet。

5.HttpServlet的基本使用

HttpServlet类继承自GenericServlet类,GenericServlet类实现了Servlet接口,ServletConfig接口和Serializable接口。这里的源码也比较简单,建议去读读源码。既然有ServletConfig了,那就能用ServletContext这个全局的东西。

 

下面用HttpServlet来做一个简单的web应用,就可以看到这个这个类比Servlet接口好用多了。

HttpServlet里有很多方法,我们需要重写的一般是doGet(),doPost(),init()等等这些方法,因为在HttpServlet中,通过Service方法实际上调用的都是doGet()和doPost()这样的方法,来对Http协议中具体的方法进行业务处理。

先写一个HttpServletDemo类,继承自HttpServlet类,重写了doGet()和init()方法(重写那个方法是有讲究的,还是建议去读源码,就是看最后调用到那个方法然后父类将这个方法空了下来,那么我们就需要去重写的是这个方法)

public class HttpServletDemo extends HttpServlet{

    @Override
    public void init() throws ServletException {
        System.out.println("HttpServlet has been Created");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        //测试ServletConfig对象是否接收到xml里面配置的参数
        ServletContext sc = getServletContext();
        System.out.println(sc);

        //测试向ServletContext中添加数据,进行读取和更新
        if(sc.getAttribute("count") == null){
            sc.setAttribute("count", 1);
        }else{
            int count = (int) sc.getAttribute("count");
            sc.setAttribute("count", count+1);
        }
        Integer count = (Integer) sc.getAttribute("count");
        resp.getWriter().write(count.toString());
    }

    @Override
    public void destroy() {
        super.destroy();
        System.out.println("HttpServlet has been destroyed");
    }
}

这里可以看到和前面的方式不同的,一个是我们重写的是doGet()方法不再是service方法,这是由于基类为我们细分了请求类型;另外是使用了ServletContext这个对象,至于具体的说明,看下面的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">

    <!-- 这里配置的是添加到ServletContext对象中的数据,和前面ServletConfig不同的是,在一个web项目中
       所有的Servlet共享一份ServletContext对象,但是ServletConfig却是每一个Servlet实例都有独立的
       同样,这里配置的参数可以再ServletContext对象中取到和修改-->
    <context-param>
        <param-name>test</param-name>
        <param-value>hello</param-value>
    </context-param>

    <!-- 声明一个Servlet,并且与一个实体类之间构成映射-->
    <servlet>
        <!-- 这是Servlet的name可以自己随便取-->
        <servlet-name>servletDemo</servlet-name>

        <!-- 这是这个名字对应的那个class -->
        <servlet-class>com.lyh.servlet.ServletDemo</servlet-class>

        <!-- 这是为Servlet的init函数中的参数ServletConfig对象里面添加值,通过这样配置就可以在ServletCongfig对象中取到了 -->
        <init-param>
            <param-name>username</param-name>
            <param-value>lyh</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>112233</param-value>
        </init-param>

        <!-- 这条配置设置Servlet随着服务器启动就创建实例,值必须为大于零的整数,如果有多个,就根据值的从小到大排序进行创建实例 -->
        <!-- 如果没有的话,Servlet就在他对应的url第一次被访问的时候创建 -->
        <load-on-startup>1</load-on-startup>

    </servlet>

    <!-- 这是Servlet和一个url的映射,即对url的访问会被转向name等于这个的Servlet来处理 -->
    <servlet-mapping>
        <!-- 一个已经声明了的Servlet的name -->
        <servlet-name>servletDemo</servlet-name>

        <!-- 想要转向此Servlet处理的url -->
        <!-- URL格式支持三种格式的URL形式
            完全路径匹配:例如/login
            目录匹配:例如/user/* , /user/*
            扩展名匹配:例如*.do,这种情况是不能加/的,比如/*.do就是错误的
            当上述三种匹配都通过话,匹配的优先级是完全路S径>目录匹配>扩展名匹配
        -->
        <url-pattern>/ServletDemo</url-pattern>
    </servlet-mapping>

    <!-- 这里是配置的第二个Servlet,是一个HttpServlet -->
    <servlet>
        <servlet-name>HttpServletDemo</servlet-name>
        <servlet-class>com.lyh.servlet.HttpServletDemo</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HttpServletDemo</servlet-name>
        <url-pattern>/HttpServletDemo</url-pattern>
    </servlet-mapping>

</web-app>

这个就是HttpServlet的基本使用,实际web开发中不同的知识doGet()方法要处理的业务逻辑更加复杂罢了,为了方便业务处理等,大牛们封装了Servlet而形成了框架。

最后根据Serlvet的生命周期我们知道Servlet实例是单例的,而且没有同步处理,所以是线程不安全的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值