知行合一
Github
顺翔的技术驿站
顺翔的技术驿站
  • README
  • ABOUTME
  • Computer Science
    • 数据结构与算法
      • 位运算以及位图
      • 随机数
      • 递归
      • 经典排序算法
      • 经典查找算法
      • 数组和动态数组
      • 链表
      • 栈和队列
      • 树
      • 哈希表
    • 计算机网络
      • 物理层
      • 数据链路层
      • 网络层
        • TCP
      • 运输层
      • 应用层
      • HTTP
        • HTTPS的原理
        • DNS详解
        • file协议
        • 邮件协议
    • 设计模式
      • 单例模式
      • 建造者模式
      • 原型模式
      • 工厂模式
      • 享元模式
      • 代理模式
      • 装饰者模式
      • 桥接模式
      • 适配器模式
      • 外观模式
      • 组合模式
      • 事件驱动
      • 有限状态机
      • 备忘录模式
      • 模板方法模式
      • 策略模式
      • 迭代器模式
      • 命令模式
      • 解释器模式
    • 加密与解密
      • 数字证书原理
      • cfssl
  • Programming Language
    • 编程语言学习要素
    • Java
      • 集合
        • List
          • ArrayList
          • Vector
          • Stack
          • LinkedList
        • Iterator
        • Set
          • HashSet
          • TreeSet
        • Map
          • HashMap
          • HashTable
          • TreeMap
          • LinkedHashMap
      • 常用API
        • 日期时间处理
        • System
        • Random
        • Arrays
        • Scanner
        • 格式化输出
      • java特性
        • java5特性
        • java8特性
        • java9特性
        • java10特性
        • java11特性
      • 并发编程
        • 线程基础
        • 线程同步:synchronized及其原理
        • 线程同步: volatile
        • 锁机制
        • 锁的分类与对应的Java实现
        • JUC:同步辅助类
        • JUC: AtomicXXX
        • 线程池
        • ThreadLocal详解
      • 测试
        • 使用JMH进行基准测试
      • JVM
        • 强引用、软引用、弱引用、虚引用
        • jvm内存模型
        • jvm优化
        • GC算法与回收器
        • 静态绑定与动态绑定
      • ORM
        • Mybatis
          • IBatis常用操作
      • Web编程
        • Servlet详解(一)
        • Servlet详解(二):request和response对象
        • Servlet详解(三):会话技术与Cookie
        • JSP详解(一):页面构成、EL表达式
        • JSP详解(二):九大内置对象
        • JavaWeb的编码问题
        • Thymeleaf
      • Velocity
      • Java日志框架总结
      • Spring
        • SpringIOC
        • SpringMVC
        • SpringBoot源码
      • 其他
        • Apache Commons Lang使用总结
        • 使用FtpClient进行ftp操作
        • Java PDF操作总结
        • Java使用zip4j进行文件压缩
        • Java解析Excel总结
    • JVM Language
      • Groovy
      • Scala
    • Kotlin
      • 变量和常量
      • 数据类型
        • 基本数据类型
        • 容器类型
        • 函数类型
        • null和null安全
      • 流程控制
      • 包
      • 面向对象
    • Golang
      • 关键字与标识符
      • 变量和常量
      • 数据类型
      • 函数
      • 常用API
        • 时间日期处理
        • 字符串操作
        • 正则表达式
      • 控制语句
      • 包package
      • 面向对象
      • 错误处理
      • 命令行编程
        • Cobra
      • 文件操作
      • 测试
      • 并发编程
        • sync包详解
      • 数据格式与编码
        • 使用encoding包操作xml
        • 使用encoding包操作json
        • 使用magiconair操作properties
        • 使用go-ini操作ini
      • 反射
      • Build Tools
        • Go Module
        • Go Vendor
      • 日志框架
        • zap日志框架
      • Web编程
        • Gin
    • JavaScript
      • 数据类型
      • ECMAScript
        • ECMAScript6
      • NodeJS
    • TypeScript
      • 变量和常量
      • 数据类型
      • 函数
      • 面向对象
      • 泛型
      • Build Tools
        • tsc编译
        • 与webpack整合
    • Python
      • BuildTools
        • requirements.txt
        • Ananconda
    • Swift
      • 变量和常量
    • Script Language
      • Regex
      • BAT
      • Shell
    • Markup Language
      • Markdown
      • Yaml
  • Build Tools
    • CMake
    • Maven
      • 搭建Nexus私服
      • maven使用场景
    • Gradle
  • Version Control
    • Git
      • Git工作流
      • Git分支管理
      • Git Stash
      • Git Commit Message规范
      • .gitttributes文件
    • SVN
  • Distributed
    • 分布式基础理论
      • 互联网架构演变
      • 架构设计思想AKF拆分原则
      • CAP理论
      • BASE理论
    • 一致性
      • 一致性模型
      • 共识算法
        • Paxos
        • Raft
        • ZAB
      • 复制
        • 主从复制
        • Quorum机制
        • Nacos Distro协议
      • 缓存一致性
        • 双写一致性
        • 多级缓存一致性
    • 事务一致性
      • Seata
      • 本地消息表实现方案
      • 关于dpad的事务问题的分析
    • IO
    • RPC协议
    • 序列化
    • Session共享
    • 分布式协调
      • Zookeeper
        • zk集群4节点搭建
    • 服务治理
      • Dubbo分布式治理
    • 分布式ID
      • 分布式ID生成策略总结
    • 分布式锁
    • 应用服务器
      • Tomcat
    • Web服务器
      • Nginx
        • Nginx的基本配置
        • ab接口压力测试工具
        • nginx模块
        • 随机访问页面
        • 替换响应内容
        • 请求限制
        • 访问控制
        • 状态监测
        • nginx应用场景
        • 代理服务
        • 负载均衡
        • 缓存
        • 静态资源服务器和动静分离
        • 附录
      • Kong
    • 缓存中间件
      • Caffeine
      • memcached
      • Redis
        • Centos下安装Redis
        • RatHat下安装Redis
    • 数据库中间件
      • ShardingSphere
      • MyCat2
    • 消息中间件
      • Kafka
      • RocketMQ
  • Microservices
    • 服务发现
      • Nacos注册中心
      • Consul
    • 配置中心
      • Apollo
    • 消息总线
    • 客户端负载均衡
    • 熔断器
    • 服务网关
    • 链路追踪
      • Skywalking
  • Domain-Specific
    • Auth
      • 有关权限设计的思考
      • 认证方式
      • JWT
    • 任务调度
      • QuartzScheduler
      • Elastic-Job
      • XXL-Job
      • PowerJob
    • 工作流
      • BPM
      • Activiti
      • Flowable
    • 规则引擎
      • Drools
  • Architect
    • DDD领域驱动设计
      • 三层架构设计
      • 四层架构设计
    • Cola
    • 代码设计与代码重构
      • 重构改变既有代码设计
      • 枚举规范化
      • 接口幂等
      • 限流
      • 历史与版本
      • 逻辑删除和唯一索引
      • 业务对象设计
    • 单元测试
      • SpringBoot单元测试实践
    • 项目管理
    • APM
      • SkyWalking
      • Arthas
    • 性能优化
      • 接口性能优化
    • 系统设计
      • 流程中台
      • 短信中台
      • 权限中台
        • 智电运维平台组织架构改造二期
  • Database
    • Oracle
      • Docker下安装oracle11g
    • IBM DB2
    • Mysql
      • 安装Mysql
      • 用户与权限管理
      • MySQL的逻辑架构
      • 存储引擎
      • 索引详解
      • MySql的列类型
      • MySql中表和列的设计
      • MySql的SQL详解
      • 锁机制
      • 事务
      • Mysql函数总结
      • MySql存储过程详解
      • MySql触发器详解
      • Mysql视图详解
      • Mysql中Sql语句的执行顺序
      • 配置MySql主从和读写分离
      • MySql的备份策略
      • MySql分库分表解决方案
      • MySql优化总结
      • MySQL实战调优
        • schema与数据类型优化
    • Mongo
  • File System
    • README
    • HDFS
    • FastDFS
    • MinIO
  • Linux
    • 常用的Linux命令
    • vim
    • Linux磁盘管理
    • Linux系统编程
    • RedHat
      • rpm包管理器具体用法
    • Ubuntu
      • Ubuntu下录制屏幕并做成gif图片
      • Ubuntu20.05LiveServe版安装
  • DevOps
    • VM
      • 新建一个新的Linux虚拟机需要配置的东西
      • VMware桥接模式配置centos
      • VMwareFusion配置Nat静态IP
    • Ansible
    • Container
      • Docker
        • Dockerfile详解
        • DockerCompose详解
      • Containerd
    • Kubernetes
      • 安装k8s
        • 使用Minikube安装k8s
        • centos7.x下使用kubeadm安装k8s1.21
        • ubuntu20下使用kubeadm安装k8s1.21
        • centos7.x下使用二进制方式安装k8s1.20
        • 使用DockerDesktop安装K8s(适用M1芯片)
      • 切换容器引擎
      • 使用k8s部署项目的流程
      • 集群维护-备份升级排错
    • Gitlab
      • GitlabCI/CD
    • CI/CD
      • ArgoCD
  • Big-Data
    • Hadoop
    • MapReduce
    • HDFS
  • Front-End
    • Android
      • Log的使用、自定义Log工具类
      • Android倒计时功能实现
      • 解决ViewDrawableLeft左侧图片大小不可控的问题
      • AndroidSQLite基本用法
      • View的生命周期
      • 工具类
      • WebView详解
      • ViewTreeObserver类监听ViewTree
      • 在onCreate中获取控件的宽高等信息的几种方法
      • View的foreground属性
        • MaterialDesign
          • BottomNavigationBar
          • CardView
          • Elevation高度、shadows阴影、clipping裁剪、tint着色
          • TouchFeedbackRipple波纹动画
      • Volley完全解析——使用、源码
      • Android围住神经猫的实现
      • LookLook剖析,架构概述——MVP、Retrofit+RxJava
      • Android性能优化之渲染
    • Browser
      • 浏览器的工作原理
    • HTML
      • DOCTYPE标签、XHTML与HTML的区别
    • CSS
      • CSS的继承性、层叠性、权重
      • CSS浮动float详解(一):标准文档流
      • CSS浮动float详解(二):使用float
      • CSS浮动float详解(三):清除浮动方案
    • Tools Lib
      • JavaScript 文件下载解决方案-download.js
      • js-url 用于url的js开源库
      • jsuri 用于操作url的js开源库
      • window offset
    • React
      • 模块化和组件
      • 组件的三大核心属性
      • 事件处理
      • 表单数据收集
      • 生命周期
      • DOM的diff算法
      • 工程化
        • 脚手架create-react-app
        • 工程结构和模块化
      • 路由
  • Design
    • 产品设计
      • 交互设计
由 GitBook 提供支持
在本页
  • 什么是Servlet
  • 创建Servlet
  • Servlet线程安全问题:
  • 修改Servlet创建时机
  • Servlet访问路径配置
  • ServletContext

这有帮助吗?

在GitHub上编辑
  1. Programming Language
  2. Java
  3. Web编程

Servlet详解(一)

上一页Web编程下一页Servlet详解(二):request和response对象

最后更新于2年前

这有帮助吗?

什么是Servlet

Servlet(Server Applet),全称Java Servlet。一个Java Servlet就是一个小型Java应用程序,它可以继承HttpServlet实现,运行在Web服务器中。Servlet 会接收并响应来自浏览器的请求,通常是基于Http协议的请求。

如下图:

创建Servlet

实现Servlet或者继承Servlet的实现类:

方法一:实现Servlet接口

1> 实现接口Servlet并实现以下几个 生命周期 方法:

  • init(ServletConfig config):当Servlet被创建时,将会使用此方法对自己初始化

  • service(ServletRequest req,ServletResponse res):当浏览器对服务器发出请求后,servlet会使用该方法处理请求

  • destory():当Servlet处理完请求后,在销毁前会调用此方法,然后GC会将它回收掉

生命周期:

当client访问Servlet时,创建并初始化Servlet, 在服务器中只有一个Servlet实例,当服务器被关闭时,Servlet才会被销毁。

package com.feathers.servletdemo;
import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class HelloServlet implements Servlet {

    private ServletConfig config;

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init(): servlet 初始化");
        this.config = config;
    }

    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        System.out.println("service():servlet 收到请求了,开始取出请求的数据(request)并作出处理,\n 并将处理后的结果放置到响应对象(response)中");
        // 响应对象向客户端写东西
        response.getWriter().write("Hello Client, I'm Servlet");
    }

    @Override
    public void destroy() {
        System.out.println("destory(): servlet被销毁");
    }

    @Override // 获取配置信息,键值对的方式
    public ServletConfig getServletConfig() {
        return config;
    }

    @Override  // 返回servlet信息,比如servlet的author version copyright等
    public String getServletInfo() {
        return null;
        // return "Feather著作 Feathers 版权所有";
    }
}

2> 在 web.xml 中注册Servlet,告诉服务器有这么一个Servlet

<!-- 注册servlet到服务器 -->
  <servlet>
    <servlet-name>HelloServlet</servlet-name><!-- 注册名称 -->
    <servlet-class>com.feathers.servletdemo.HelloServlet</servlet-class><!-- java字节码路径 -->
  </servlet>
  <!-- 给注册过的Servlet配置路径 -->
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name><!-- 给哪一个Servlet配置路径 -->
    <url-pattern>/HelloServlet</url-pattern><!-- 要配置的路径,servle访问路径  / 代表项目路径 -->
  </servlet-mapping>

什么?太麻烦了?还好我们有注解 @WebServlet

使用java注解注册Servlet

@WebServlet("/FirstServlet") // 后面是Servlet的访问路径

@WebServlet(
    name="Hello",   // Servlet名称
    urlPatterns={"/hello.view"}, // 访问路径
    loadOnStartup=1 // 加载级别
)
public class HelloServlet extends HttpServlet {

启动服务器,访问此Servlet:

在tomcat中的项目结构:

我们可以看到,Java编译的class文件全部被eclipse放置到WEB-INF—> classes目录下了。

输出:

生命周期时序图:

服务器是如何查找Servlet的?

我们看到,通过 <url-pattern> 访问servlet,最后访问到他的class文件。

首先根据 <url-pattern> 找到它的name,然后根据name找到 <servlet> <name> 相同的servlet标签,根据name找到 <servlet-class> class路径,使用找到的class生成servlet实例到服务器内存中。

ServletConfig接口:

servlet容器使用servlet配置对象,该对象在初始化期间将信息传递给ServletConfig。

  • String getInitParamter(String name):根据初始化参数名称获取初始化参数的值,如果没有此参数,返回null

  • Enumeration getInitParamterNames():获取所有初始化参数名称,以枚举方式返回,如果没有参数,返回一个空的枚举

在 web.xml 中初始化参数:

  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.feathers.servletdemo.HelloServlet</servlet-class>
    <!-- 配置两个初始化参数 -->
    <init-param>
        <param-name>name</param-name><!-- key -->
        <param-value>Feathers</param-value><!-- value -->
    </init-param>
    <init-param>
        <param-name>age</param-name>
        <param-value>100</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/HelloServlet</url-pattern>
  </servlet-mapping>

在Servlet service()中对初始化参数进行处理:

package com.feathers.servletdemo;
import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class HelloServlet implements Servlet {

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

    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        // 响应对象向客户端写东西
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("Hello Client, I'm Servlet");
        // 获取初始化参数 作出处理
        Enumeration<String> enums = getServletConfig().getInitParameterNames();
        while (enums.hasMoreElements()){
            String key = enums.nextElement();
            String value = getServletConfig().getInitParameter(key);
            response.getWriter().write(key+":"+value + "<br/>");
        }
    }

    @Override
    public void destroy() {
    }

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

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

}

请求结果如下:

  • getServletName():获取Servlet的名称 <servlet-name>

  • getServletContext():获取ServletContext上下文对象

点击form表单提交,跳转servlet

<!-- 注意action, 这个是Servlet的访问路径,但是不能加/ 不能加/ 不能加/  -->
<form action="FirstServlet" method="get">
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username" value=""/></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password" value=""/></td>
            </tr>
            <tr>
                <td><input type="checkbox" name="remember" value=“yes”/>记住用户名</td>
            </tr>
            <tr>
                <td><input type="submit" value="提交"/></td>
            </tr>
        </table>
    </form>

方法二、继承GenericServlet

所谓的GenericServlet只是一个Servlet的实现类,因为用户每次使用Servlet接口自定义一个Servlet都会进行许多不必要的操作,所以就封装了一个GenericServlet以方便程序员使用,

使用方法:在方法service()中进行请求的处理,具体请查看源码。

下面是它的源码:

    package javax.servlet;

    import java.io.IOException;
    import java.util.Enumeration;

    //GenericServlet实现了Servlet、ServletConfig、Serializable三个接口
    public abstract class GenericServlet
        implements Servlet, ServletConfig, java.io.Serializable
    {
        private transient ServletConfig config;

        //无参的构造方法
        public GenericServlet() { }

        /*
        实现接口Servlet接口生命周期初始化init(ServletConfig Config)方法,将ServletConfig对象保存到成员变量中,以扩展他的生命周期,让service方法也能访问
        **/

        public void init(ServletConfig config) throws ServletException {
          this.config = config;
          this.init(); // 用户的初始化方法
        }

        public void init() throws ServletException {
        }

        public void destroy() { }

        //返回ServletConfig对象
        public ServletConfig getServletConfig(){
           return config;
        }

        //该方法实现接口<Servlet>中的ServletInfo,默认返回空字符串
        public String getServletInfo() {
           return "";
        }

       // service方法没有去实现,而是丢给使用者去实现
        public abstract void service(ServletRequest req, ServletResponse res)
     throws ServletException, IOException;

      // 为了方便用户调用,简化操作,实现了ServletConfig接口,这样就不用使用getServletConfig().getServletContext()获取对象了
      // 只需使用getServletContext即可
      // 即实现ServletConfig的目的
        public ServletContext getServletContext() {
           return getServletConfig().getServletContext();
        }

        public String getInitParameter(String name) {
         return getServletConfig().getInitParameter(name);
        }

        public Enumeration getInitParameterNames() {
           return getServletConfig().getInitParameterNames();

        public String getServletName() {
            return config.getServletName();
        }

        public void log(String msg) {
           getServletContext().log(getServletName() + ": "+ msg);
        }

        public void log(String message, Throwable t) {
           getServletContext().log(getServletName() + ": " + message, t);
        }
    }

方法三、继承HttpServlet

HttpServlet继承自GenericServlet,是针对Http协议的Servlet,是进一步的封装,

使用只需要继承HttpServlet,重写doGet或doPost方法即可,doGet用来处理get请求,而doPost方法用来进行post请求处理。

源码如下:

    package javax.servlet.http;
    .....

    public abstract class HttpServlet extends GenericServlet
        implements java.io.Serializable
    {

        private static final String METHOD_GET = "GET";
        private static final String METHOD_POST = "POST";
        ......
        public HttpServlet() { }

        public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException
        {
        // 1. 强转ServletRequest与ServletResponse
            HttpServletRequest        request;
            HttpServletResponse        response;

            try {
                request = (HttpServletRequest) req;
                response = (HttpServletResponse) res;
            } catch (ClassCastException e) {
                throw new ServletException("non-HTTP request or response");
            }
            //调用重载的service()方法
            service(request, response);
        }

        //重载的service方法
        protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            // 根据操作的不同,作出不同的处理
            // 处理方法有 doGet,doPost,doHead,doDelete...
            // 这些都是http协议中的方法,get请求,post修改,delete删除,put上传等。

            // 获取请求方式
            String method = req.getMethod();

            if (method.equals(METHOD_GET)) {  // get请求
                long lastModified = getLastModified(req);
                if (lastModified == -1) {
                    doGet(req, resp);
                } else {
                    long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    if (ifModifiedSince < (lastModified / 1000 * 1000)){
                        maybeSetLastModified(resp, lastModified);
                        doGet(req, resp);
                    } else {
                        resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                    }
                }

            } else if (method.equals(METHOD_HEAD)) {
                long lastModified = getLastModified(req);
                maybeSetLastModified(resp, lastModified);
                doHead(req, resp);

            } else if (method.equals(METHOD_POST)) {   // post请求
                doPost(req, resp);

            } else if (method.equals(METHOD_PUT)) {  // put 增加操作
                doPut(req, resp);

            } else if (method.equals(METHOD_DELETE)) {   // 删除操作
                doDelete(req, resp);

            } else if (method.equals(METHOD_OPTIONS)) {
                doOptions(req,resp);

            } else if (method.equals(METHOD_TRACE)) {
                doTrace(req,resp);

            } else {
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[1];
                errArgs[0] = method;
                errMsg = MessageFormat.format(errMsg, errArgs);

                resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
            }
        }

        ......

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_get_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
            } else {
                resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
            }
        }

        protected void doHead(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            .......
        }
        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_post_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
            } else {
                resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
            }
        }
        protected void doPut(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException  {
            //todo
        }

        protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
           //todo
        }

        protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException   {
          //todo
        }

        protected void doDelete(HttpServletRequest req,
                                HttpServletResponse resp)
            throws ServletException, IOException   {
            //todo
        }

    }

Servlet线程安全问题:

Servlet存在这线程安全的问题,

假设在Servlet中放置一个成员变量name,用来接受用户的表单信息。当多个用户访问Servlet时,会对name进行多次赋值,那么用户得到的结果就很有可能出错,因为多个用户共用一块内存。

解决办法也很简单,让每个用户都有一块内存保存自己的name值,只需要将name值保存在方法中,建立一个局部变量即可。因为java方法在被调用时,每次被调用,都会开辟一个新的方法区。

修改Servlet创建时机

通常情况下,servlet在被用户第一次调用时创建,如果servlet要进行非常耗时的创建操作,用户就会等待很久,影响用户体验,所以,我们可以将servlet设置在服务器启动之后,解决这类问题:

在 web.xml 中,添加加载时间标签:

<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.feathers.servletdemo.HelloServlet</servlet-class>
    <!-- 让servlet随项目的启动而启动 value: 0-5  数字越小,启动优先级越高       如果多个servlet优先级相同,则按照配置顺序启动-->
    <load-on-startup>3</load-on-startup>
  </servlet>

Servlet访问路径配置

相对路径:

/ 代表 项目路径

/AServlet => http://localhost:8080/ServletDemo/Aservlet

/File/* => /File/ => http://localhost:8080/ServletDemo/File/sfsdfdsfsdfe 匹配任意

匹配范围越大,优先级越低:

两个配置 /File/AServlet 与 /File/*

访问: http://localhost:8080/ServletDemo/File/AServlet

则会访问AServlet,而不会访问第二个路径,因为第一个优先级高。

后缀名匹配:

*.do: http://localhost:8080/ServletDemo/sfdsfds.do

该方式不常用,Filter过滤器常用

注意:不能同时使用 后缀名 匹配和 相对路径。例如: /File/*.do

ServletContext

项目级别的对象,一个Web项目,有且只有一个ServletContext对象,在项目启动时创建,到项目关闭时销毁,可以理解为这个类集合了项目所有的功能方法,代表了项目,所以这个类非常强大。

我们使用 ServletConfig.getServletContext() 获得这个对象。

功能如下:

获取项目参数

配置项目初始化参数:

<webapp>
  <context-param>
    <param-name>name</param-name>
    <param-value>tom</param-value>
  </context-param>
</webapp>

获取项目初始化参数:

getServletContext().getInitParamter(String name)

getServletContext().getInitParamterNames()

ServletContext 域

域是服务器两个组件之间的通讯,比如两个Servlet之间通讯。

Application域

在ServletContext中,有一个 Map<String,Object> 集合,用来保存信息,这个Map集合就是ServletContext的域。

AServlet获取ServletContext对象,向域中添加信息,BServlet也可以获取Servlet,然后从ServletContext域中获取AServlet填入的信息。

这样,每个Servlet之间就可以共享信息了。

同样存在线程不安全的问题。

/*AServlet*/
// 1. 获取ServletContext
ServletContex scontext = getServletContext();
// 2. 向域中存放键值对
scontext.setAttribute(key,object);

/*BServlet*/
// 3. 在另一个Servlet中从域中取出键值对
getServletContext().getAttribute(key);
// 4. 删除key
getServletContext().removeAttribute(key);
// 5. 获取所有建
getServletContext().getAttributeNames();//返回枚举

ServletContext获取项目内的资源

获取WebRoot/WebContent下的 user.xml 文件:

InputStream is = getServletContext().getResourceAsStream("/user.xml"); // 获得资源流
String path = getServletContext().getRealPath("/user.xml");// 获取资源绝对路径(tomcat webapp下 项目的部署路径)

// 获取WEB-INFO下的`user.xml`文件
getServletContext().getResourceAsStream("/WEB-INFO/user.xml");

获取class资源:

// 方法1:使用上面的方法
getServletContext().getResourceAsStream("/WEB-INFO/classes/com/feathers/servlet/AServlet.class"); // 麻烦

// 方法2:
// “/” 代表src目录,或者是classes目录,详见getResourceAsStream方法
InputStrean is2 = AServlet.class.getResourceAsStream("/user.xml");