Servlet基础知识学习

Servlet

Servlet的介绍

  • Servlet是运行在java服务器端的程序,用于接收和响应来自客户端基于HTTP协议的请求

  • 如果想要实现Servlet的功能,可以通过java.servlet.Servlet接口或者继承它的实现类

  • 核心方法:service(),任何客户端请求都会经过该方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ivky8108-1642497460852)(/Users/heroma/Library/Application Support/typora-user-images/image-20220116223918388.png)]

Servlet执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q5MJySZr-1642497460853)(/Users/heroma/Library/Application Support/typora-user-images/image-20220116220633851.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b0NU73ke-1642497460854)(/Users/heroma/Library/Application Support/typora-user-images/image-20220116221238241.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-69jdbkb9-1642497460854)(/Users/heroma/Library/Application Support/typora-user-images/image-20220116221312205.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eVlpb5a0-1642497460855)(/Users/heroma/Library/Application Support/typora-user-images/image-20220116224819646.png)]

Servlet关系视图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0nWfZFBH-1642497460856)(/Users/heroma/Library/Application Support/typora-user-images/image-20220116225039234.png)]

Servlet实现方式

  1. 第一种
    • 实现Servlet接口,实现所有的抽闲方法。该方法支持最大程度的自定义
  2. 第二种
    • 继承GenericServlet抽象类,必须重写service方法,其他方法可以选择重写。该方式让我们开发Servlet变得简单
  3. 第三种
    • 继承HttpServlet抽象类,需要重写doGet和doPost方法。该方法表示请求和相应都需要和HTTP协议相关

Servlet生命周期

  • 对象的生命周期,就是对象从出生到死亡的过程。即:出生->活着->死亡。即对象创建到销毁的过程
  • 出生:请求第一次到达Servlet时,对象就创建出来,并且初始化成功。只出生一次,将对象存放到内存中
  • 活着:服务器提供服务的整个过程中,该对象一直存在,每次都是在执行service方法
  • 死亡:当服务器停止时,或者服务器宕机时,对象死亡

Servletlet线程安全问题

  • 由于Servlet采用的是单例模式,也就是整个应用中只有一个实例对象。所以我们需要分析这个唯一的实例对象中的类成员是否线程安全
  • 模拟用户登录功能来查看Servlet线程是否安全
  • 模拟用户登录时,假设一个浏览器代表一个线程,那么多个浏览器代表多个线程。我们期望每个浏览器看到的应该是自己的用户名,但结果却是数据混乱。因此,Servlet是线程不安全的
  • 解决:定义类成员要谨慎。如果是共用的,并且只在初始化时赋值的话,那么是没有问题的。如果不是共享的,或者每次使用都有可能对其赋值,就需要考虑线程安全问题,可以将doGet或者doPost方法内使用同步功能即可

Servlet映射方式

  1. 具体名称的方式。访问的资源路径必须和映射配置完全相同

  2. /开头+通配符的方式。只要符合项目结构即可,不用考虑结尾是什么

  3. 通配符+固定格式结尾的方式。只要符合固定结尾格式即可,不用考虑前面的路径

    //指定名称
       <!--    servlet声明-->
        <servlet>
            <servlet-name>Demo04</servlet-name>
            <servlet-class>hero.mps.web_demo02.servlet.Demo04</servlet-class>
        </servlet>
    <!--    servlet映射-->
        <servlet-mapping>
            <servlet-name>Demo04</servlet-name>
            <url-pattern>/Demo04</url-pattern>
        </servlet-mapping>
        //开头+通配符的方式。只要符合项目结构即可,不用考虑结尾是什么
       <!--    servlet声明-->
        <servlet>
            <servlet-name>Demo04</servlet-name>
            <servlet-class>hero.mps.web_demo02.servlet.Demo04</servlet-class>
        </servlet>
    <!--    servlet映射-->
        <servlet-mapping>
            <servlet-name>Demo04</servlet-name>
            <url-pattern>/servlet/*</url-pattern>
        </servlet-mapping>
        
         //通配符+固定格式结尾的方式。只要符合固定结尾格式即可,不用考虑前面的路径
       <!--    servlet声明-->
        <servlet>
            <servlet-name>Demo04</servlet-name>
            <servlet-class>hero.mps.web_demo02.servlet.Demo04</servlet-class>
        </servlet>
    <!--    servlet映射-->
        <servlet-mapping>
            <servlet-name>Demo04</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
        
    

    优先级,越具体优先级越高 第一种-> 第二种 -> 第三种

Servlet多路径映射

  • 可以给Servlet配置多个访问路径映射,从而根据不同的请求路径实现不同的功能

  • 场景分析:

    如果访问路径是/vip 商品价格打九折

    如果访问路径是/vvip 商品价格打五折

    如果访问路径是其他 商品价格不打折

    package hero.mps.web_demo02.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Servlet多路径
     */
    public class Demo06 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //定义一个金额
            int money = 100;
            //获取访问路径
            String uri = req.getRequestURI();
            String path = uri.substring(uri.lastIndexOf("/"));
            //进行判断
            if ("/vip".equals(path)){
                System.out.println("商品原价:" + money + ".优惠后价格:" + money*0.9);
            }else if ("/vvip".equals(path)){
                System.out.println("商品原价:" + money + ".优惠后价格:" + money*0.5);
            }else {
                System.out.println("商品原价:" + money + ".优惠后价格:" + money);
            }
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    
    /*servlet配置*/
        <servlet>
            <servlet-name>Demo06</servlet-name>
            <servlet-class>hero.mps.web_demo02.servlet.Demo06</servlet-class>
        </servlet>
        <!--    servlet映射-->
        <servlet-mapping>
            <servlet-name>Demo06</servlet-name>
            <url-pattern>/hero/*</url-pattern>
        </servlet-mapping>
    

Servlet创建时机

  1. 第一次访问是创建
    • 优势:减少服务器内存的浪费。提高服务器启动效率
    • 弊端:如果有一些要在应用加载时做得初始化操作,无法完成
  2. 服务器加载时创建
    • 优势:提前创建好对象,提高了首次运行的效率。可以完成一些应用加载时需要的初始化操作
    • 弊端:对服务器内存占用较多,影响了服务器启动的效率
  • 修改Servlet创建时机。在标签中,添加标签
//正整数代表服务器加载时创建,值越小,优先级越高。负整数或者不写代表第一次访问时创建 
<load-on-startup>1</load-on-startup>

默认Servlet

  • 默认servlet是由服务器提供的一个Servlet。它配置在Tomcat的conf目录的web.xml中
  • 它的映射路径是/,我们在发送请求时,首先会在我们项目中的web.xml中查找映射噢诶之,找到则执行。当找不到时,就去找默认的servlet,由默认的servlet处理。多以,一切都是servlet

ServletConfig介绍

  • ServletConfig是Servlet的配置参数对象,在Servlet的规范中,允许为每一个Servlet都提供一些初始化的配置。所以,每一个Servlet都有一个自己的ServletConfig
  • 作用:在Servlet初始化时,把一些配置信息传递个诶Servlet
  • 声明周期:和Servlet相同

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8U5AGrTy-1642497460857)(/Users/heroma/Library/Application Support/typora-user-images/image-20220118142805385.png)]

ServletConfig配置方式

  • 在标签中,通过标签来配置。有两个子标签
  • :代表初始化参数的key
  • :代表初始化参数的value
<servlet>
    <servlet-name>Demo06</servlet-name>
    <servlet-class>hero.mps.web_demo02.servlet.Demo06</servlet-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</servlet>
 <!--    servlet映射-->
    <servlet-mapping>
        <servlet-name>Demo06</servlet-name>
        <url-pattern>/hero/*</url-pattern>
    </servlet-mapping>

ServletConfig常用方法

返回值 方法名 说明
String getInitParameter(String name) 根据参数名获取参数值
Enumeration getInitParameterNames() 获取所有参数名称的枚举
String getServletName() 获取Servlet名称
ServletContext getServletContext() 获取ServletContext对象
package hero.mps.web_demo02.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
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.util.Enumeration;

/**
 * Servlet多路径
 */
public class Demo06 extends HttpServlet {
    // 1.声明servletconfig
    private ServletConfig servletConfig;
    // 2.通过init方法来对servletConfig赋值

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.servletConfig = config;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String encoding = servletConfig.getInitParameter("encoding");
        System.out.println(encoding);
        Enumeration<String> names = servletConfig.getInitParameterNames();
        while (names.hasMoreElements()){
            String el = names.nextElement();
            String value = servletConfig.getInitParameter(el);
            System.out.println(el+":" + value);
        }
        String servletName = servletConfig.getServletName();
        System.out.println(servletName);

        ServletContext servletContext = servletConfig.getServletContext();
        System.out.println(servletContext);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!--    servlet声明-->
<servlet>
    <servlet-name>Demo06</servlet-name>
    <servlet-class>hero.mps.web_demo02.servlet.Demo06</servlet-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</servlet>
<!--    servlet映射-->
<servlet-mapping>
    <servlet-name>Demo06</servlet-name>
    <url-pattern>/hero/*</url-pattern>
</servlet-mapping>

ServletContext介绍

  • ServletContext是应用上下文对象(应用域对象)。每一个应用中只有一个ServletContext对象
  • 作用:可以配置和获得相应的全局初始化参数,可以实现Servlet之间的数据共享
  • 生命周期:应用一加载则创建,应用停止则销毁
  • 域对象指的是对象有作用域。即作用范围。域对象可以实现数据的共享。不同作用范围的域对象,共享数据的能力也不一样
  • 在Servlet规范中,一共有四个域对象。ServletContext就是其中一个。他是web应用中最大的作用域,也叫application域。它可以实现整个应用之间的数据共享

ServletContext配置方式

  • 在标签中。通过标签来配置。有两个子标签
  • :代表全局初始化参数的key
  • :代表全局初始化参数的value
<context-param>
    <param-name>globalEncoding</param-name>
    <param-value>UTF-8</param-value>
</context-param>

ServletContext常用方法

返回值 方法名 说明
String getInitParameter(String name) 根据名称获取全局配置的参数
String getContextPath() 获取当前应用的访问虚拟目录
String getRealPath(String path) 根据虚拟目录获取部署的磁盘绝对路径
public class ServletContextDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取ServletContext对象
        ServletContext context = getServletContext();

        //获取全局配置的globalEncoding
        String value = context.getInitParameter("globalEncoding");
        System.out.println(value);

        //获取应用的访问虚拟目录
        String contextPath = context.getContextPath();
        System.out.println(contextPath);

        //根据虚拟目录获取应用部署的磁盘绝对路径
        //获取b.txt文件的绝对路径 获取webapp目录下的b.txt
        String b = context.getRealPath("/b.txt");
        System.out.println(b);

        //获取c.txt文件的绝对路径 WEB-INF下的c.txt
        String c = context.getRealPath("/WEB-INF/c.txt");
        System.out.println(c);

        //获取a.txt文件的绝对路径 对应src下文件a.txt
        String a = context.getRealPath("/WEB-INF/classes/a.txt");
        System.out.println(a);


        //向域对象中存储数据
        context.setAttribute("username","zhangsan");

        //移除域对象中username的数据
        //context.removeAttribute("username");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
返回值 方法名 说明
void setAttribute(String name, Object value) 向应用对象中存储数据
Object getAttribute() 通过名称获取应用作用域对象中的数据
void removeAttribute(String name) 通过对象名称移除应用域对象中的数据

注解开发Servlet

自动注解开发的实现步骤

  1. 创建一个web项目
  2. 定义一个类,继承HttpServlet
  3. 重写doGet和doPost方法
  4. 在类上使用@WebServlet注解配置servlet
  5. 部署并启动项目
  6. 通过浏览器进行测试
package com.example.web_demo04;

import java.io.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;

@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
    private String message;

    public void init() {
        message = "Hello World!";
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println(message);
    }

    public void destroy() {
    }
}

自动注解开发详解

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package javax.servlet.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
		//指定servlet名称。等同于web.xml文件下<servlet>标签下的<servlet-name>
    String name() default "";
	//用于映射Servlet,等效于<url-pattern>
    String[] value() default {};
    String[] urlPatterns() default {};
//Servlet的加载机制,等效于<load-on-startup>
    int loadOnStartup() default -1;
//Servlet初始化参数,等效于<init-param>
    WebInitParam[] initParams() default {};
//Servlet是否支持异步
    boolean asyncSupported() default false;
//Servlet小图标
    String smallIcon() default "";
//Servlet大图标
    String largeIcon() default "";
//Servlet的描述信息
    String description() default "";
//Servlet显示名称
    String displayName() default "";
}
上一篇:Linux基础学习(一)基本命令及快捷键


下一篇:linux学习笔记6