web 学习笔记10-Servlet介绍

1、Servlet是什么:

Servlet(Server Applet),是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
    编写一个Java类,实现servlet接口。
    把开发好的Java类部署到web服务器中。

2、手动创建一个简单的Servlet示例:

新建个web工程
File-New-Web Project-Test,直接下一步,Finish
新建一个com.test.servlet包
在这个包下建个Servlet,右击-New-Servlet,名称ServletDemo1,继承javax.servlet.http.HttpServlet
Finish

3、Servlet调用过程分析:

代码演示调用顺序:注意这里是继承GenericServlet,这个是HttpServlet的父类(可以查看J2EE5.chm帮助)
    public class ServletDemo1 extends GenericServlet {
        public ServletDemo1() {
            System.out.println("构造函数");
        }
        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println("初始化");
        }
        @Override
        public void service(ServletRequest arg0, ServletResponse arg1)
                throws ServletException, IOException {
            System.out.println("处理请求");
        }
        @Override
        public void destroy() {
            System.out.println("我被销毁了");
        }
    }
输入网址:http://localhost:8080/Demo/servlet/ServletDemo1
运行的结果:
    构造函数
    初始化了
    处理请求
注意:destroy是在服务器程序停止运行的时候调用,tomcat6.0可以进入后台停止服务.
    默认情况下,servlet对象在第一次请求的时候调用构造函数创建, 创建之后自动调用带参的init方法,
    然后调用service方法.destroy方法在停止服务器或者停止应用的时候调用。
    整个过程中,init方法和destroy方法只会调用一次,而service方法会反复调用。

4、web.xml文件的配置:

你创建了一个Servlet看看web.xml里面都配置了下什么
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>ServletDemo1</servlet-name>//这个是java的类名,通过这个和servlet标签匹配上
        <servlet-class>com.test.servlet.ServletDemo1</servlet-class>//这个是java类的地址,真正运行的程序
    </servlet>

    <servlet-mapping>
        <servlet-name>ServletDemo1</servlet-name>//这个是java的类名,通过这个和servlet标签匹配上
        <url-pattern>/servlet/ServletDemo1</url-pattern>//这个是url的地址,
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

5、servlet的执行调用过程:

servlet执行调用过程.png

6、servlet的URL配置:

就是配置:<url-pattern>/servlet/ServletDemo1</url-pattern>
    http://localhost:8080/Demo/servlet/ServletDemo1 这个就是你浏览器访问的地址

写法有两种:
    1. 以/开头: /代表的是工程路径(/工程名称)  必须要加/
    2. 以*开头: 必须要加后缀名(后缀名任意) 后缀名不能用*
    3. 如果只是配置一个/,那么此Servlet就是一个默认的servlet,它用来处理所有找不到匹配的url的请求
       注意: /*.后缀名此种情况允许

配置优先级:  精确匹配  > 以/开头的匹配 > 以*开头的匹配

7、serlvet创建的时机:

可以通过配置web.xml文件来改变创建servlet的时机
<servlet>
    <servlet-name>ServletDemo1</servlet-name>
    <servlet-class>com.test.servlet.ServletDemo1</servlet-class>
    <!-- 启动时加载   数字代表了启动的顺序-->
    <load-on-startup>2</load-on-startup>
</servlet>

8、编写servlet的三种方法:

可以直接在myeclipse中新建,继承类
a.采用实现servlet接口(不推荐)
b.采用继承GenericServlet类( 不推荐)
c.采用继承HttpServlet(推荐)
封装度越高,那么自由度就会越低。

9、修改Servlet模板:

我们在用myeclipse创建Servlet的时候,会有很多我们不需要的东西。
a.找到你的myeclipse的安装路径中的 com.genuitec.eclipse.wizards_11.5.0.me201310291746.jar这个文件
b.把这个文件复制到桌面,使用rar打开,在templates的文件夹中有个Servlet.java
c.拖到桌面来,修改里面的模板。
e.然后在拖回去,把原来的那个jar文件替换掉。
f.重启myeclipse就可以了。

10、线程的安全问题:

Servlet的设计是一个单实例多线程。
线程安全要求将变量创建成一个局部变量,而不要创建成实例变量。
如果定义为全局变量,那么每个访问者都改变这个变量,值就乱掉了。
例如:(我们不要这样去定义)
public class ServletDemo7 extends HttpServlet{
    int a = 0 ;
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        a++ ;
        System.out.println(Thread.currentThread().getName() + ":" + a);
        try {
            Thread.sleep(5000) ;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":" + a);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

11、获取ServletConfig对象的两种方式:

servletConfig的作用:就是拿取servlet的相关配置.也就是拿去web.xml里面的配置信息。
1.通过带参的init方法获取。
    因为如果你写没有带参的init方法,ServletConfig config这个就不会初始化。就获取不到了。

2. 采用servlet实例拿取(不要写带参的init方法)
    因为看底层的代码,this.getServletConfig()其实返回的就是一个父类的config,
    没有调父类的带参init,所以父类的config就没有实例化,返回的就是一个null值
    如果一定要写带参的init方法,就必须手动调用super(config),手动初始化下。

例如:
public class ServletConfig1 extends HttpServlet {
    ServletConfig config ;
    @Override
    public void init(ServletConfig config) throws ServletException {//第一次调用的时候就把config传过来了,所以不写super也可以拿到config
        super.init(config) ;//这个是如果用第二种方法,一定要写这句,用第一种可以不用写
        this.config = config ;//第一种方法
    }
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ServletConfig sc = this.getServletConfig() ;//第二种方法
        //System.out.println(config == sc);
        System.out.println(sc);
        System.out.println(config == sc);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
注意:init方法只是在第一次访问的时候调用。系统默认调用的是带参的init方法。

12、ServletConfig对象的应用-拿取配置信息:

web.xml的参数配置如下:(一个servlet的参数)
<servlet>
    <servlet-name>ServletConfig1</servlet-name>
    <servlet-class>com.test.servletconfig.ServletConfig1</servlet-class>
    <init-param>
        <param-name>name</param-name>
        <param-value>张三</param-value>
    </init-param>
    <init-param>
        <param-name>age</param-name>
        <param-value>20</param-value>
    </init-param>
</servlet>

例如:
public class ServletConfig1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //拿到servletConfi对象
        ServletConfig sc = this.getServletConfig() ;//这里没有init方法,系统自动调用带参的init,所以不会是null

        //拿取配置的单个信息
        String name0 = sc.getInitParameter("name") ;
        System.out.println(name0);

        //拿取配置的多个信息
        Enumeration<String> enu = sc.getInitParameterNames() ;
        while(enu.hasMoreElements()){
            String name = enu.nextElement() ;
            System.out.println(name + ":" + sc.getInitParameter(name));
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
运行的结果:
    张三
    name:张三
    age:20

13、ServletContext介绍:

每个web应用都有一个唯一的servletContext对象
在每个应用加载的时候,服务器就会创建servletContext对象
生命周期很长
ServletContext对象是一个域对象

14、获取servletContext对象的三种方式:

1. 采用servletConfig对象获取
2. 采用servlet实例对象获取
3. 采用request对象获取
例如:
public class ServletContext1 extends HttpServlet {
    ServletContext sc ; 
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config) ;
        sc = config.getServletContext() ;//第一种方式
    }
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ServletContext sc1 = this.getServletContext() ;//第二种方式
        System.out.println(sc);
        System.out.println(sc1 == sc);

        ServletContext sc2 = request.getSession().getServletContext() ;//第三种方式
        System.out.println(sc2 == sc);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
运行的结果:
org.apache.catalina.core.ApplicationContextFacade@3e403c23
true
true
可以看到这三种方式拿到的context都是一样的。

15、ServletContext的一些应用:

a.获取全局对象中存储的数据
    例如:
    在ServletContext2.java中存数据
        public class ServletContext2 extends HttpServlet {
            public void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {

                ServletContext sc = this.getServletContext() ;//获取全局对象
                sc.setAttribute("name", "张三") ;//存储数据
            }
            public void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                doGet(request, response);
            }
        }
    在ServletContext3对象中取数据
        public class ServletContext3 extends HttpServlet {
            public void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {

                ServletContext sc = this.getServletContext() ;//拿取全局对象
                String name = (String)sc.getAttribute("name") ;//从sc中拿取数据
                System.out.println(name);
            }
            public void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                doGet(request, response);
            }
        }
    我们访问ServletContext3这个Servlet:http://localhost:8080/Demo/servlet/ServletContext3
    运行的结果:张三

b.获取全局配置参数:(这个和ServletConfig的功能差不多)
    前提你已经在web.xml中配置了参数
    例如:
        public class ServletContext4 extends HttpServlet {
            public void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {

                ServletContext sc = this.getServletContext() ;//拿到全局对象

                String name0 = sc.getInitParameter("name") ;//获取单个配置参数(获取姓名)
                System.out.println(name0);

                Enumeration<String> enu = sc.getInitParameterNames() ;//拿取多个配置参数的值
                while(enu.hasMoreElements()){
                    String name = enu.nextElement() ;
                    System.out.println(name + ":" + sc.getInitParameter(name));
                }
            }
            public void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                doGet(request, response);
            }
        }

c.请求转发:
    例如:
    在ServletContext5.java中获取request
        public class ServletContext5 extends HttpServlet {
            public void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                ServletContext sc = this.getServletContext() ;//拿到全局对象
                request.setAttribute("name", "张三") ;
                //拿到请求转发器,指定你需要转发的地址
                RequestDispatcher rd = sc.getRequestDispatcher("/servlet/ServletContext6") ;
                rd.forward(request, response) ;//转发过去
            }
            public void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                doGet(request, response);
            }
        }
    在ServletContext6.java中处理请求
        public class ServletContext6 extends HttpServlet {
            public void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                String name = (String)request.getAttribute("name") ;
                System.out.println("在这里处理转发过来的数据: " + name);
            }
            public void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                doGet(request, response);
            }
        }
    我们访问:http://localhost:8080/Demo/servlet/ServletContext5
    运行的结果:
        在这里处理转发过来的数据: 张三

d.获取资源文件:

16、获取资源文件:

获取资源文件有三种方式: 
    1.采用 ServletContext对象获取 
    2.采用ResourceBundle类来获取 
    3.采用类加载器获取(推荐使用)

3个资源文件的路径为:
    p1.properties:在src目录下
    p2.properties:在包名下
    p3.properties:在工程目录下,D:\tomcat\apache-tomcat-7.0.77\webapps\Demo\p3.properties

例如:
    1.采用 ServletContext对象获取(只是路径不同而已):
        // 获取p1资源文件的内容
        public void test11() {
            ServletContext sc = this.getServletContext();// 拿到全局对象
            // 获取p1.properties文件的路径
            String path = sc.getRealPath("/WEB-INF/classes/p1.properties");
            System.out.println(path);

            Properties pro = new Properties();// 创建一个Properties对象
            try {
                pro.load(new FileReader(path));// 加载文件
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(pro.get("k"));// 读取k的值
        }

        // 获取p2资源文件的内容
        public void test12() {
            ServletContext sc = this.getServletContext();// 拿到全局对象
            // 获取p1.properties文件的路径
            String path = sc.getRealPath("/WEB-INF/classes/com/test/context/p2.properties");
            System.out.println(path);
            Properties pro = new Properties();// 创建一个Properties对象
            try {
                pro.load(new FileReader(path));// 加载文件
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(pro.get("k"));// 读取k的值
        }

        // 获取p3资源文件的内容
        public void test13() {
            ServletContext sc = this.getServletContext();// 拿到全局对象
            // 获取p1.properties文件的路径
            String path = sc.getRealPath("/p3.properties");
            System.out.println(path);
            Properties pro = new Properties();// 创建一个Properties对象
            try {
                pro.load(new FileReader(path));// 加载文件
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(pro.get("k"));// 读取k的值
        }

    2.采用ResourceBundle类来获取:
        // 采用resourceBunble拿取资源文件:获取p1资源文件的内容 默认路径是src,对用到web环境就是classes目录
        public void test21() {
            // 拿取ResourceBundle对象(专门用来获取properties文件的信息)
            ResourceBundle rb = ResourceBundle.getBundle("p1");
            System.out.println(rb.getString("k"));
        }

        // 采用resourceBunble拿取资源文件:获取p2资源文件的内容
        public void test22() {
            // 拿取ResourceBundle对象(专门用来获取properties文件的信息)
            ResourceBundle rb = ResourceBundle.getBundle("com.test.context.p2");
            System.out.println(rb.getString("k"));
        }

    3.采用类加载器获取:

        // 采用类加载器拿取资源文件:获取p1资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
        public void test31() {
            // 获取类加载器的方式
            /*
            * 1. 通过类名 ServletContext7.class.getClassLoader() 
            * 2. 通过对象this.getClass().getClassLoader()
            * 3. Class.forName("ServletContext7").getClassLoader()
            */
            InputStream in = this.getClass().getClassLoader().getResourceAsStream("p1.properties");
            Properties pro = new Properties();// 创建Properties对象
            try {
                pro.load(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(pro.getProperty("k"));// 拿取文件的数据
        }

        // 采用类加载器拿取资源文件:获取p2资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
        public void test32() {
            InputStream in = this.getClass().getClassLoader().getResourceAsStream("com/test/four/p2.properties");
            Properties pro = new Properties();// 创建Properties对象
            try {
                pro.load(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(pro.getProperty("k"));// 拿取文件的数据
        }

        // 采用类加载器拿取资源文件:获取p3资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
        public void test33() {
            InputStream in = this.getClass().getClassLoader().getResourceAsStream("../../p3.properties");
            Properties pro = new Properties();// 创建Properties对象
            try {
                pro.load(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(pro.getProperty("k"));// 拿取文件的数据
        }

        // 采用类加载器拿取资源文件:获取p3资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
        public void test34() {
            URL url  = this.getClass().getClassLoader().getResource("p1.properties") ;
            String path = url.getPath() ;
            Properties pro = new Properties();// 创建Properties对象
            try {
                pro.load(new FileReader(path));
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(pro.getProperty("k"));// 拿取文件的数据
        }

三种方式优缺点:
    a): 采用servletContext对象获得.  
        优点: 任意文件,任意路径都可获得
        缺点: 必须在web环境下
    b): 采用resourceBundle获得
        优点: 非web环境下
        缺点: 只能获取properties文件
    c): 采用类加载器获得
        优点: 任意路径,任意文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值