Servlet第一天

 

1.Servlet简介
  • servlet是sun公司提供的一门用于开发动态web资源的技术
  • servlet技术基于Resquest-Response编程模型
  • sun公司在其API中提供了一个Servlet接口,编写一个servlet需要两步骤 
  1. 编写一个Java类实现Servlet接口
  2. 把Java类部署到web服务器中

学习目标:手动编写一个Servlet

Servlet支持Java包 tomcat\lib\servlet-api.jar

2.注册Servlet

在Web.xml文件中,一个<servlet>元素用于注册一个Servlet,<servlet>元素中包含有两个主要的子元素:<servlet-name>和<servlet-class>它们分别用于设置Servlet的注册名称和指定Servlet的完整类名,如下所示:

<servlet>
    <servlet-name>ServletDemo1</servlet-name>
    <servlet-class>com.malinkang.web.ServletDemo1</servlet-class>
  </servlet>
3.映射Servlet
<servlet-mapping>
    <servlet-name>ServletDemo1</servlet-name>
    <url-pattern>/ServletDemo1</url-pattern>
  </servlet-mapping>

url-pattern三种匹配方式:
1.完整路径配置(不含通配符*,以/开始)

2.目录匹配(含通配符*,必须以/开始,以/*结尾)

3.扩展名匹配(含有通配符*、必须不以/开始,以*.xxx结尾):例如*.do

匹配优先级:完整路径匹配>目录匹配>扩展名

 

缺省Servlet:如果某个Servlet映射路径仅仅为一个正斜杠,那么这个Servlet就是当前web应用的缺省Servlet。

作用:凡是在web.xml文件中找不到匹配的资源,它们的访问请求都将交给缺省Servlet。

所有服务器端 静态web资源 都是由缺省Servlet 返回给客户端

默认缺省Servlet 在tomcat/conf/web.xml 

<servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
</servlet-mapping>


将上面的listings值改为true访问某个资源目录,则以列表显示。

 

 

4.Sevlet生命周期

  1.浏览器访问Servlet的过程

1.浏览器根据用户的请求生成http请求消息,并将其发给web容器

2.Web容器检查内存中是否存在负责处理当前请求Servlet程序的实例对象,如果不存在,则加载和创建该Servlet对象。

3.web服务器创建针对本次访问的请求对象和响应对象。请求对象包含了http的请求消息,从它里面可以获取http请求消息的内容:响应对象用于封装将要回送给浏览器的http响应信息,响应对象中的初始化内容为空,但是以后可以调用各种方法来生成http响应消息的各个部分。

4.web服务器调用Servlet的service方法,并将请求对象和响应对象传递给该方法。

5.Servlet对象的service方法从请求对象中读取该请求消息,并向响应对象中写入响应头和响应体消息。

6.service方法执行完毕

7.web服务器从响应对象中读取响应消息。

2.Servlet生命周期

第一次访问创建Servlet对象,调用init方法和service方法

第二次访问只调用service方法,没有创建Servlet对象也没有调用init方法。在Servlet整个生命周期中Servlet对象只创建一次,init方法也只调用一次。

当服务器正常关闭时,调用destory方法

3.Servlet自动加载

默认情况下Servlet在第一次访问时,创建对象和执行init。如果希望服务器启动时创建Servlet对象、执行init,则要配置web.xml添加<load-on-startup>

  <servlet>
    <servlet-name>InitServlet</servlet-name>
    <servlet-class>cn.itcast.servlet.InitServlet</servlet-class>
    <!-- 配置Servlet 随服务器启动时 进行创建初始化 -->
    <!-- 中间值可以 0-9 代表加载优先级 0 最高 -->
    <load-on-startup>0</load-on-startup>
  </servlet>

 

5.ServletConfig

 ServletConfig:在Servlet初始化阶段,向Servlet传递数据。

  当Servlet配置了初始化参数后,当web容器创建了Servlet的实例对象会自动将这些初始化参数封装到ServletConfig对象,调用init(ServletConfig config)方法将ServletConfig对象传递给Servlet。Servlet.getServletConfig()方法必须返回init(ServletConfig config)方法传递进来的这个ServletConfig对象的引用。

应用:1.在web.xml进行初始化参数的配置

    <init-param>
    <param-name>company</param-name>
    <param-value>google</param-value>
    </init-param>
    <init-param>
    <param-name>city</param-name>
    <param-value>北京</param-value>
    </init-param>

 

public class ServletTest2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //根据初始化参数名字获取初始化值
        String value = this.getServletConfig().getInitParameter("company");
        response.getOutputStream().write(value.getBytes());
        //获取所有初始化名字
        Enumeration<String> e = this.getServletConfig().getInitParameterNames();
        while (e.hasMoreElements()) {
            response.getOutputStream().write(e.nextElement().getBytes());
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

 

1.ServletContext

 Web容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。

ServletConfig对象中维护了ServletContext对象的引用,开发人员在创建servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。由于一个web应用中的所有Servlet共享同一个ServletContext对象,所以多个Servlet通过ServletContext对象实现数据共享。ServletContext对象通常被称为context域对象

 ServletContext应用

1.提供全局初始化参数

    <!-- 全局初始化参数 -->
    <context-param>
    <param-name>name</param-name>
    <param-value>zhangsan</param-value>
    </context-param>

 

public class ServletTest extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // ServletContext context=this.getServletConfig().getServletContext();可以简化为下面代码
        ServletContext context = this.getServletContext();
        String value = context.getInitParameter("name");
        response.getOutputStream().write(value.getBytes());
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    }

}

ServletContext与ServletConfig区别:
ServletConfig每个Servlet对象对应一个,用来在Servlet的init方法进行初始化,传递Servlet私有初始化信息。

ServletContext 每个web应用对应一个,提供全局初始化参数,所有Servlet都可以访问。

2.案例二:通过文件扩展名 获得文件MIME类型

MIME类型:MIME协议中规定文件书写格式

tomcat/conf/web.xml 配置了文件扩展名和MIME类型对应关系

ServletContext对象 提供 API : String getMimeType(String file)  根据文件名获得MIME类型

 

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String file = "QQ.exe";
        String mime = this.getServletContext().getMimeType(file);
        System.out.println(mime);//application/octet-stream
    }

3.案例三:获取日志信息
public void log(String msg):将特定信息写入servlet日志文件(通常是一个事件日志)。servlet日志文件的名称和类型是特定于servlet容器的。

public void log(String message,Throwable throwable):将给定异常的解释性信息和堆栈跟踪写入servlet日志文件。

注:MyEclipse情动tomcat,无法写入日志文件

public class ServletTest extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ServletContext context = getServletContext();
        context.log("记录普通信息");
        try {
            int a = 5 / 0;
        } catch (Exception e) {
            context.log("记录异常信息", e);
        }
    }

案例四 : 统计Servlet的访问次数

作为数据域,保存整个web应用数据

void setAttribute(String name, Object object)  将一个数据保存ServletContext中

Object getAttribute(String name) 从ServletContext对象中取出数据

ServletContext因为全局唯一的,所以在多个Servlet之间可以共享数据

public class ServletTest extends HttpServlet {

    @Override
    // 初始化访问次数为0
    public void init() throws ServletException {
        getServletContext().setAttribute("visittimes", 0);
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;utf-8");
        Integer times = (Integer) getServletContext()
                .getAttribute("visittimes");
        // 加一并返回
        getServletContext().setAttribute("visittimes", times + 1);
        response.getOutputStream().write(
                ("你是第" + (times + 1) + "个访问者").getBytes("utf-8"));
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    }

}


案例五:统计字母出现次数

知识点:对请求分发。

常见面试题:比较转发和重定向

重定向:产生两次请求和两次响应。对于客户端来说,知道产生了重定向(URL地址会转变为B的地址);

转发:服务器内部技术,由服务器多个资源共同处理同一个请求和响应。转发的过程对于客户端是不可见的。

操作步骤:

RequestDispatcher getRequestDispatcher(String path):获得转发器,完成转发。

再使用Dispatcher的void forward(ServletRequest request,ServletRequest response):完成请求和响应转发操作。

1.写一个html页面输入字母

<form action="/day05/count" method="post" >
<textarea rows="5" cols="30" name="content"></textarea>
<input type="submit" value="提交"/>
</form>

2.创建一个Servlet 虚拟目录为count 用于统计字母个数

public class Demo extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获得请求的内容
        String content = request.getParameter("content");
        // 索引代表字母
        int[] arr = new int[26];
        for (int i = 0; i < content.length(); i++) {
            char ch = content.charAt(i);
            if (Character.isLetter(ch)) {
                // 转换为小写
                ch = Character.toLowerCase(ch);
                arr[ch - 'a']++;
            }
        }
        getServletContext().setAttribute("arr", arr);
        RequestDispatcher dispatcher = getServletContext()
                .getRequestDispatcher("/Demo2");
        dispatcher.forward(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

3.创建一个Servlet,用于输出结果

public class Demo2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获得统计结果
        int arr[] = (int[]) getServletContext().getAttribute("arr");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        for (int i = 0; i < arr.length; i++) {
            char ch = (char) ('a' + i);
            out.print(ch + "出现的次数是" + arr[i] + "</br>");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}


案例六:读取文件

回顾Java读取文件

public class FileReaderTest {
    public static void main(String[] args) {
        // 读取项目目录文件
        String path_1 = "1.txt";
        reader(path_1);
        // 读取src下的文件
        String path_2 = "src/2.txt";
        reader(path_2);
        // 读取WebRoot下的文件
        String path_3 = "WebRoot/5.txt";
        reader(path_3);
        // 读取WEB-INF目录下的文件
        String path_4 = "WebRoot/WEB-INF/4.txt";
        reader(path_4);
        // 读取包下的文件
        String path_5 = "src/cn/itcast/test/3.txt";
        reader(path_5);
    }

    public static void reader(String path) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(path));
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}


在Web中读取文件要使用绝对路径:

public class Demo3 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 读取项目目录文件 因为项目下的文件没有发布

        // 读取src下的文件
        String path_2 = "/WEB-INF/classes/2.txt";
        String real_path_2 = getServletContext().getRealPath(path_2);
        // 使用类加载器读取src下的文件
        reader(real_path_2);
        String path = Demo3.class.getResource("/2.txt").getFile();
        reader(path);
        // 读取WebRoot下的文件
        String path_3 = "/5.txt";
        String real_path_3 = getServletContext().getRealPath(path_3);
        reader(real_path_3);
        // 读取WEB-INF目录下的文件
        String path_4 = "/WEB-INF/4.txt";
        String real_path_4 = getServletContext().getRealPath(path_4);
        reader(real_path_4);
        // 读取包下的文件
        String path_5 = "/WEB-INF/classes/cn/itcast/test/3.txt";
        String real_path_5 = getServletContext().getRealPath(path_5);
        reader(real_path_5);
    }

    public static void reader(String path) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(path));
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

 

posted @ 2012-09-27 21:20  Carve_Time  阅读(272)  评论(0编辑  收藏  举报