栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

深度好文之Servlet技术详解(九)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

深度好文之Servlet技术详解(九)

目录

一.自启动Servlet

1.自启动Servlet特点

 2.通过自启动Servlet实现配置信息的读取

二.Servlet线程安全问题

三.Servlet的url-pattern配置

1.URL的匹配规则

(1)精确匹配

(2)扩展名匹配

(3)路径匹配

(4)任意匹配

(5)匹配所有

2.优先顺序

3.考考你

四.Servlet的多URL映射方式

1.方式一

2.方式二


一.自启动Servlet

1.自启动Servlet特点 自动启动 Servlet 表示在 Tomcat 启动时就会实例化这个 Servlet ,他的实例化过程 不依赖于请求 ,而是 依赖容器的启动 。 可以通过在 web.xml中的 标签中通过1 配置自启动Servlet 。
AutoStartServlet.java:
package com.first.servlet;

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 AutoStartServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter pw=resp.getWriter();
        pw.println("AutoServlet......");
        pw.flush();
        pw.close();
    }

    @Override
    public void init() throws ServletException {
        //看servlet什么时候初始化,请求时还是启动时
        System.out.println("AutoStartServlet Init......");
    }
}
web.xml配置:
    
        AutoStartServlet
        com.first.servlet.AutoStartServlet


        1
    
    
        AutoStartServlet
        /autoStart.do
    

输出:

启动Tomcat时控制台就输出了

AutoStartServlet Init......

请求访问servlet:

 2.通过自启动Servlet实现配置信息的读取 需求:修改文件下载案例,通过自启动 Servlet 读取配置信息。

实际应用原因:

之前写的文件下载案例是文件路径是硬编码,而实际工程现场,部署的不是源代码,而是编译好的字节码文件,字节码文件已经不能再根据实际工程环境再去改变文件路径了,但web.xml相当于一个文本文件可以随意修改,所以本节讲解将配置信息放在web.xml文件中,启动Tomcat时,自动读取配置信息。

AutoStartServlet.java配置好且FileDownServlet.java修改之后,直接运行FileDownServlet.java即可,因为由1.可知AutoStartServlet.java在服务器启动之时就自动启动了,此时web.xml的路径配置信息(在AutoStartServlet.java的servlet配置中)就配置好了。

输出:

此时访问FileDownServlet.java,发现文件可下载

二.Servlet线程安全问题 在 Servlet 中使用的是多线程方式来执行 service() 方法处理请求,所以我们在使用 Servlet 时需要考虑到线程安全问题,在多线程中对于 对象中的成员变量是最不安全的,所以不要在 Servlet 中通过成员变 量的方式来存放数据,如果一定要使用成员变量存储数据,在对数 据进行操作时需要使用线程同步的方式来解决线程安全问题,避免 出现数据张冠李戴现象。

比如执行了一个servlet,一个客户端请求之后,在一个线程中执行了一个 service()方法,又有一个客户端请求之后,又新建了一个线程,这个线程又调用了一个service()方法,但是这两个线程共享这个servlet的成员变量。所以尽量不要使用成员变量,能用局部变量最好用局部变量,非得用成员变量的话最好只读不写。

ThreadSafeServlet.java:

package com.first.servlet;

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 ThreadSafeServlet extends HttpServlet {
    //设置成员变量(多线程下不安全,即多个线程都可访问)
    private PrintWriter pw;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户提交数据
        String value=req.getParameter("name");

        pw=resp.getWriter();
        try {
            //沉睡5s
            Thread.sleep(5000);
            pw.println(value);
            pw.flush();
            pw.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

配置web.xml: 

    
        ThreadSafeServlet
        com.first.servlet.ThreadSafeServlet
    
    
        ThreadSafeServlet
        /safe.do
    

输出:

访问http://localhost:8888/ajaxDemo/safe.do?name=kd

Chrome:

Firefox:

先用Chrome访问ThreadSafeServlet.java,此时尽快再用Firefox浏览器访问此servlet,尽快的访问的原因是程序就出沉睡5s。此时发现Chrome没有输出,而在Firefox有输出,这是因为pw是成员变量(类变量),两个客户端进程皆可访问它,所以Firefox的浏览器线程就又创建了pw变量,即把Chrome创建的那个覆盖了,所以Chrome没有输出,而访问Firefox5s后Firefox输出了获得了name参数的值。

如果想要改进上面的情况,可作如下修改:

ThreadSafeServlet.java:

package com.first.servlet;

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 ThreadSafeServlet extends HttpServlet {
    //设置成员变量(多线程下不安全,即多个线程都可访问)
    private PrintWriter pw;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户提交数据
        String value=req.getParameter("name");
        
        synchronized (this){
            pw=resp.getWriter();
            try {
                //沉睡5s
                Thread.sleep(5000);
                pw.println(value);
                pw.flush();
                pw.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

再做上面相同的访问,结果如下,两个浏览器会依次输出name的值!

三.Servlet的url-pattern配置

1.URL的匹配规则

下面的示例都假设以Servlet为项目名

(1)精确匹配 精确匹配是指中配置的值必须与 url 完全精确匹配。

    demoServlet
    /demo.do
http://localhost:8888/Servlet/demo.do 匹配 http://localhost:8888/Servlet/suibian/demo.do 不匹配 可见我们之前配置的url-pattern都是精确匹配

(2)扩展名匹配 在允许使用统配符作为匹配规则, “*” 表示匹配任意字符。在扩展名匹配中只要扩展名相同都会被匹配和路径无关。注意,在使用扩展 名匹配时在中不能使用 “/” ,否则容器启动就会抛出异常。
 
    demoServlet 
    
    *.do 
http://localhost:8888/demo/abc.do 匹配 http://localhost:8888/demo/suibian/haha.do 匹配(虽然又多加了层路径,但是以.do结尾就行) http://localhost:8888/demo/abc 不匹配

(3)路径匹配 根据请求路径进行匹配,在请求中只要包含该路径都匹配。 “*” 表示任意路径以及子路径。

    demoServlet
    
    /suibian/* 
http://localhost:8888/demo/suibian/haha.do 匹配 http://localhost:8888/demo/suibian/hehe/haha.do 匹配 http://localhost:8888/demo/hehe/heihei.do 不匹配

 

(4)任意匹配 匹配 “/” 。匹配所有但不包含 JSP 页面(即不会拦截jsp页面,但是其他的页面都会被拦截并转到此servlet)。
/
http://localhost:8888/demo/suibian.do 匹配 http://localhost:8888/demo/addUser.html 匹配 http://localhost:8888/demo/css/view.css 匹配 http://localhost:8888/demo/addUser.jsp 不匹配 http://localhost:8888/demo/user/addUser.jsp 不匹配

(5)匹配所有
/*
http://localhost:8888/demo/suibian.do 匹配 http://localhost:8888/demo/addUser.html 匹配 http://localhost:8888/demo/suibian/suibian.do 匹配

2.优先顺序 当一个 url 与多个 Servlet 的匹配规则可以匹配时,则按照 “ 精确路径> 最长路径 > 扩展名 ” 这样的优先级匹配到对应的 Servlet 。

3.考考你 Servlet1 映射到 /abc/* Servlet2 映射到 /* Servlet3 映射到 /abc Servlet4 映射到 *.do (扩展名匹配,优先级最低) 当请求 URL 为 “/abc/a.html” , “/abc/* ” 和 “/* ” 都匹配, Servlet 引擎将调用 Servlet1 。 当请求 URL 为 “/abc” 时, “/abc/* ” 和 “/abc” 都匹配, Servlet 引擎将调用 Servlet3 。 当请求 URL 为 “/abc/a.do” 时, “/abc/* ” 和 “ *.do” 都匹配, Servlet 引擎将调用 Servlet1 。 当请求 URL 为 “/a.do” 时, “/* ” 和 “*.do” 都匹配, Servlet 引擎将调用Servlet2 。 当请求 URL 为 “/xxx/yyy/a.do” 时, “/* ” 和 “*.do” 都匹配, Servlet 引擎将调用 Servlet2 。

四.Servlet的多URL映射方式 在 web.xml 文件中支持将多个 URL 映射到一个 Servlet 中,但是相同的 URL 不能同时映射到两个 Servlet 中。

1.方式一

    demoServlet
    /suibian/*
    *.do

2.方式二

    demoServlet
    /suibian/*
 
    demoServlet
    *.do

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/856492.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号