北京行——Servlet入门

Servlet 3天
1、Servlet程序编写 ----- 生命周期
2、ServletAPI Request Response
3、Cookie 和 Session

Servlet 用来 动态web资源 开发
静态web资源 : 固定数据文件
动态web资源 : 通过程序动态生成数据文件

Servlet技术基于Request-Response编程模型 ---- HTTP协议也是基于请求响应 模型
* Servlet技术 用来 开发基于HTTP web 应用程序

接触 JavaEE API ------ 程序 接口 和 已经实现接口 类的 使用
JavaEE ---- Java Platform, Enterprise Edition 缩写

Servlet快速入门
1、创建web project
2、编写 class 继承 HttpServlet

代码附上:

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setCharacterEncoding("GBK");
        PrintWriter printWriter = resp.getWriter();
        printWriter.print("这是我的第一个Servlet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

    }
}

 


3、在web.xml 配置 Servlet程序 虚拟访问路径
* 用户在浏览器上通过这个路径 访问编写Servlet程序,先上代码

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <!--这个地方的类的路径一定要搞清清楚楚,不用后缀名  -->
        <servlet-class>cn.binbin.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/Myfirst</url-pattern>
    </servlet-mapping>

 


4、覆盖doGet或者doPost方法 进行输出

* Servlet 动态生成 网页文件

执行过程
1、用户在客户端发起url请求 : http://localhost/day05/hello ----- web.xml /hello 映射 HelloServlet程序
2、用户提交请求时,get方式提交 执行 HelloServlet的 doGet方法 post方式提交 执行 HelloServlet的doPost 方法

这个的执行过程要理解啊,。。。。。。

 

Servlet程序在编写和运行时,需要javaee 类库 (API支持)
* 在学习javase List 需要 import java.util.List 需要 jre/lib/rt.jar
* MyEclipse 自动导入 javaee5 liberary 存在 javaee.jar 提供 Servlet 需要类 API支持 (开发环境使Servlet程序正常编译)
* Serlvet程序运行tomcat环境中 没有javaee.jar , 在 tomcat/lib/servlet-api.jar 提供Servlet程序运行需要 类API 支持 (运行环境需要的)

手动编写Servlet运行
1、在webapps 新建 day05test目录 --- 虚拟应用
2、在day05test 新建 WEB-INF/classes
3、将编写Servlet的java源码文件 放入 classes ,在 WEB-INF 配置web.xml
4、编译Servlet的 java程序
javac -classpath E:\apache-tomcat-6.0.14\lib\servlet-api.jar HelloServlet.java // 通过 -classpath 指定 Servlet需要jar 包
生成Servlet package结构
javac -d . -classpath E:\apache-tomcat-6.0.14\lib\servlet-api.jar HelloServlet.java

总结:做这个实例的目的是为了理解servlet运行时是需要一定类库的支持的

Servlet运行原理分析

每一次请求,都需要经过TOMCAT服务器解析,根据请求路径获得访问资源,由tomcat调用目标资源执行
编写Servlet程序没有 main函数 ---- tomcat调用Servlet程序执行

通过myeclipse向导 创建Servlet ---- 创建Servlet程序,生成web.xml 配置
* 生成Servlet信息非常复杂,想生成Servlet 内容整洁一些,精简一些 ------ 修改Servlet模板
1、myeclipse工具 ---- 安装目录 common / plugins
com.genuitec.eclipse.wizards_8.5.0.me201003052220.jar

2、解压缩 templates/Servlet.java --- 这个就是Servlet模板

通过API Servlet继承关系
Servlet接口 ---- 实现类 : GenericServlet ------ 子类 HttpServlet ------ 编写Servlet 继承HttpServlet
* 编写Servlet 间接 实现 Servlet 接口 (简化开发)
Servlet接口 提出,为了解决基于请求-响应模型数据处理 (并没有涉及与HTTP协议相关 API)
GenericServlet 实现接口 通用Servlet 也没有提供与 HTTP协议相关 API
HttpServlet 引入与 协议相关 API

总结:这个地方就在次提到了面向接口的编程方法

 

Servlet生命周期
init(ServletConfig config) 初始化
service(ServletRequest req, ServletResponse res) 提供服务方法
destroy() 销毁

1、tomcat服务器启动时,没有创建Servlet对象
2、第一次访问时,tomcat构造Servlet对象,调用 init,执行service
3、从第二次以后访问 tomcat 不会从新创建Servlet对象,也不会调用init ---- 每一次访问都会调用service

《这个地方时没一次发生访问就是在服务器内部产生单独的线程去执行servlet》
4、当服务器重启或正常关闭时 调用destroy (正常关闭 shutdown.bat)

疑问:搞懂生命周期有什么用呢?

Servlet对象是tomcat创建的,每次请求调用Servlet中service方法,tomcat服务器会在每次调用Servlet的service方法时,为该方法创建Request对象和Response对象
* 在 JavaEE API 中没有Request和Response实现类 ----- 实现类由Servlet服务器提供的,tomcat提供实现类 weblogic 提供实现类《是服务器实现的类》

service方法 和 HttpServlet doGet/doPost 关系区别? ----- 必须阅读HttpServlet源代码
在HttpServlet代码实现中,根据请求方式不同 调用相应doXXX方法 get方式请求 --- doGet post方式 --- doPost

配置Servlet随tomcat服务器启动时 进行初始化 --- <load-on-startup >
*<load-on-startup > 参数可以是一个数字 0-9 代表服务器加载优先级 0 最高
例如:在tomcat启动时,想通过Servlet加载一些框架配置文件 配置随服务器启动 (struts1 )

结论:service中判断是什么方式,然后在调用doget或者是dopost
1、编写Servlet 继承HttpServlet
2、编写Servlet 不需要覆盖service方法,只需要覆盖doGet和doPost 方法

Servlet初始化时覆盖init() ,无需覆盖init(config) ??
* init(Config) 调用 init()

当doGet和doPost代码逻辑相同时,可以相互调用,简化编程


一个Servlet可以配置多个url-pattern
URL 配置格式 三种:
1、完全路径匹配 (以/开始 ) 例如:/hello /init
* 当前工程没有被正确发布,访问该工程所有静态资源、动态资源 发生404 ----- 工程启动时出错了
* 查看错误时 分析错误
1) 单一错误 : 从上到下 查看第一行你自己写代码 (有的错误与代码无关,查看错误信息)
2)复合错误 Caused by ---- 查看最后一个Caused by
* Invalid <url-pattern> init2 in servlet mapping

2、目录匹配 (以/开始) 例如:/* /abc/*
/ 代表网站根目录

3、扩展名 (不能以/开始) 例如:*.do *.action
典型错误 /*.do

优先级:完全匹配>目录匹配 > 扩展名匹配

 

也就是说当遇到这几个都能解决的时候优先考虑用优先级高的
路径问题:编写九九乘法表
1、需要用户在客户端输入一个数字
2、Servlet接收客户输入数字 打印对应乘法表

上代码:

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");// 加这一句的目的是为了让返回的页面使用html进行解析
        int num = Integer.parseInt(request.getParameter("num"));
        for (int i = 1; i <= num; i++) {
            for (int j = 1; j <= i; j++) {
                response.getWriter().write(i + "*" + j + "=" + i * j + "   ");
            }
            response.getWriter().write("<br>");// 这个地方遇到浏览器不识别的问题,稍微一想,原来是没有指定浏览器的解析方式
        }
    }

 

 

在chengfabiao.html 通过 action 访问 ChengfabiaoServlet 路径可以用绝对路径和相对路径

相对路径:相对当前网页地址 路径 例如 chengfabiao ./chengfabiao ../chengfabiao
例如: http://localhost/day05/chengfabiao.html 提交 action="chengfabiao"
* 将url最后地址换成相对路径
结果: http://localhost/day05/chengfabiao ----- 服务器端 /chengfabiao

例如: http://localhost/day05/aaa/chengfabiao.html 提交 action="chengfabiao"
结果: http://localhost/day05/aaa/chengfabiao ----- 服务器 /chengfabiao
* /aaa/chengfabiao 与服务器 /chengfabiao 不匹配 出现404

http://localhost/day05/aaa/chengfabiao.html 提供 action="../chengfabiao"
结果:http://localhost/day05/aaa/../chengfabiao ---- > ..和/aaa抵消 http://localhost/day05/chengfabiao 可以匹配服务器 /chengfabiao

结论:如果用相对路径提交请求,考虑当前路径, 当前访问服务器资源路径不同 ---- 相对路径写法不同

绝对路径 解决相对路径,会根据当前地址改变问题。 例如: /day05/chengfabiao 、http://localhost/day05/chengfabiao
绝对路径 以/开始 /访问服务器根目录 

个人总结: 绝对路径是以/ 开始的,也就是表示的是根目录的开始,若是相对路径,则不需要以/开始
例如: 客户端访问服务器,不管当前路径是什么 --- / 服务器根目录 http://localhost
/day05 --- 找到虚拟目录day05工程 /day05/chengfabiao --- 找到 day05工程下配置 虚拟路径/chengfabiao

结论: 客户端路径 /工程虚拟目录/servlet虚拟路径 例如:/day05/chengfabiao
服务器端 配置web.xml 不需要写工程虚拟目录 只要直接写/servlet虚拟路径 例如:/chengfabiao

个人总结:无论是在xml文件配置,还是别的有关于路径问题时,只要是以/开始的就是以根目录(也就是服务器的目录,需要加上工程的名字)开始的,也就是绝对路径,包括配置servlet

 客户端关于路径问题的编程结论

*.html *.jsp内部使用绝对路径

*.css内部使用相对路径的只有北京图片

*.js中使用绝对路径

<form action="/day6/chengfabiao" method="post">//这个地方改成了post的目的是为了能够以密文的形式来提交
    <input type ="text" name = "num"  >
    <input type ="submit" value="提交"> 
</form>
</body>
</html>

客户端比服务器多写一个工程名。这个是最后的结论,和上边说的有点偏差,就是客户端和服务器是不同的,因为相对的根目录是不同的

-----------------------------------------------------------------------------------------------------------------------------------------------
掌握Servlet程序编写
通过路径 访问Servlet 程序
* Servlet 生命周期

init
service
destroy

学习init方法 ---- init(ServletConfig) ---- 通过ServletConfig 获得Servlet初始化参数
1、创建一个Servlet
2、在web.xml 中 <servlet> 标签内 通过 <init-param> 标签 为Servlet配置初始化参数
<init-param>
<param-name>itcast</param-name>
<param-value>传智播客</param-value>
</init-param>

3、在Servlet程序中通过ServletConfig对象 获得itcast对应数据
getInitParameter ------ 通过name获得value
getInitParameterNames ----- 获得所有name

* 思考 :如何在doGet 或 doPost 方法中 获得 Servlet初始化参数
将ServletConfig对象保存实例成员变量
GenericServlet 已经将ServletConfig 保存成员变量 ----- 在子类中通过 getServletConfig方法 获得 初始化参数

结论:子类Servlet不需要覆盖 init(ServletConfig) 覆盖后会引起错误 , 只需要通过GenericServlet中 getServletConfig() 获得ServletConfig对象

应用:在init-param 指定配置文件位置和名称,配置Servlet随服务器启动创建 load-on-startup

上代码:

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // System.out.println(getServletConfig().getInitParameter("company"));
        // getServletConfig().getInitParameter("company");
    }//写了这个就不能覆盖init()方法了,否则出错!!
    <load-on-startup>2</load-on-startup>//这个是配置在服务器启动时创建此servlet的代码

 

 

* ServletConfig 配置初始化数据,只能在配置Servlet获得,其它Servlet无法获得 ----- 每个Servlet程序都对应一个ServletConfig对象

ServletContext 是Servlet上下文对象
每一个工程 对会创建 单独ServletContext对象,这个对象代表当前web工程
操作ServletContext 必须通过ServletConfig 获得对象

两者的区别:上图喽:

 

应用:
1、 获得整个web应用初始化参数

代码附上:

public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ServletContext context = getServletContext();// 在这个方法里,已经封装好了servletconfig调用的代码
        System.out.println(context.getInitParameter("websit"));
    }

 


2、 实现全局数据共享

3、 实现服务器端转发功能
4、 读取web工程资源文件

1、获取WEB应用的初始化参数 和 ServletConfig 对象不同
* ServletConfig对象 配置参数,只对配置Servlet有效如果配置参数,所有Servlet都可以访问 通过ServletContext
<context-param>

2、通过ServletContext 在多个Servlet间 共享数据
在ServletContext中 保存站点访问次数 ,每当一个用户访问站点,将访问次数+1
在CountServlet 初始化过程中,向ServletContext 保存访问次数 ---- 0 --------------> ServletContext setAttribute

每次访问次数 +1 --- 数据存放ServletContext中 ---- 所有Servlet都可以获得该数据

* 在ServletContext中保存数据,所有Servlet都可以访问

 

 

3、通过ServletContext 完成服务器程序转发
什么是转发? 转发和重定向区别 ?
getRequestDispatcher(java.lang.String path) ---- 完成转发

使用转发还是重定向? ---- 转发性能好于重定向,请求次数好

统计字母次数
request.getParameter("content") 获得form 提交内容 content 就是 textarea name属性

代码附上:

wordcount.html

<body>
<form action="/day6/WordCount" method="post">
    <textarea rows="10" cols="30" name="words"></textarea>
    <input type="submit" value="提交" >
</form>
</body>
</html>

Servlet: WordCount.java

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {// 通过这个例子说明转发后浏览器地址没有变
        String words = request.getParameter("words");
        int[] timers = new int[26];
        words = words.toUpperCase();
        System.out.println(words);
        for (int i = 0; i < words.length(); i++) {
            char c = words.charAt(i);
            if ('A' <= c && c <= 'Z') {// 这个字母统计这一块还是相当高级的,应该理解在下一次的应用中要灵活应用
                timers[c - 'A']++;
                System.out.println(c);
            }
        }
        ServletContext context = getServletContext();
        context.setAttribute("timers", timers);
        RequestDispatcher dispatcher = context.getRequestDispatcher("/result");
        dispatcher.forward(request, response);//这两行代码有点陌生
    }// 还有一个比较重要的就是我是用的post提交方式,所以在转发的时候这两个servlet中都应该在dopost中调用doget方法

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

}

Servlet: WordResult.java

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("我执行了。============");
        int[] timers = (int[]) getServletContext().getAttribute("timers");
        response.setContentType("text/html;charset=utf-8");
        for (int i = 0; i < timers.length; i++) {
            char c = (char) ('A' + i);
            response.getWriter().write("字母" + c + "出现的次数为" + timers[i]);
            response.getWriter().write("<br>");
        }
    }

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

}

浏览器的地址并没有改变,这是内部转发

4、利用ServletContext对象读取资源文件

使用java application 读取文件,读取当前工程下所有文件 ----- 使用相对路径读取文件
使用Servlet读取文件 只能读取WebRoot下所有文件 ---- 必须使用绝对磁盘路径读取文件,对于web应用程序

通过站点根目录绝对路径 获得磁盘绝对路径 ------ getServletContext().getRealPath(“/WEB-INF/info.txt”)

* 因为 WEB-INF/classes 非常特殊 (存放.class文件目录),被类加载器加载,通过Class类对象读取 该目录下文件
String filename3 = c.getResource("/a1.txt").getFile(); ----- / 代表 /WEB-INF/classes

结论:在web工程中,必须将 文件路径转换绝对磁盘路径 c:\xxx e:\xxx\xxx ----- getServletContext().getRealPath("/xxx"); /代表WebRoot
如果读取文件 恰好位于 WEB-INF/classes ----- 通过 类名.class.getResource("/文件名").getFile(); 获得绝对磁盘路径 / 代表 /WEB-INF/classes

这个是个重点,也是在这次学习中感觉到吃力的地方

代码附上:

java小应用程序 用的是相对路径

public class FileRead {

    public static void main(String[] args) throws Exception {
        String fileName1 = "src/a.txt";// 这个地方没有加/,是因为没有使用相对路径
        String fileName2 = "day6.txt";
        String fileName3 = "WebRoot/b.txt";
        readfile(fileName3);

    }

    private static void readfile(String fileName) throws FileNotFoundException,
            IOException {
        BufferedReader in = new BufferedReader(new FileReader(fileName));
        String line = null;
        while ((line = in.readLine()) != null) {
            System.out.println(line);
        }
    }

}

工程发布的时候只是发布Web-Root文件,不能读取所有的文件,不过它把src目录的文件发布在了web-inf的classes下,只能读这两个地方

javaweb程序读取文件:

 

缺省Servlet 功能:处理其他Servlet都不处理请求
tomcat/conf/web.xml org.apache.catalina.servlets.DefaultServlet 作为缺省Servlet

总结:
1、编写Servlet HelloServlet
2、修改Servlet模板
3、Servlet生命周期 理论重点掌握
4、Servlet url三种写法 完全、目录、扩展名
5、路径问题:绝对路径 ----- 案例 九九乘法表
将web.xml 配置路径复制到网页 在路径前 /工程名
6、ServletConfig 和ServletContext 读取初始化参数区别 ?
7、ServletContext数据共享案例 ----- 统计访问次数
8、ServletContext转发案例 --- 统计字母出现次数
9、读取web工程中资源文件 ---- 绝对路径
在web工程中,必须将 文件路径转换绝对磁盘路径 c:\xxx e:\xxx\xxx ----- getServletContext().getRealPath("/xxx"); /代表WebRoot
如果读取文件 恰好位于 WEB-INF/classes ----- 通过 类名.class.getResource("/文件名").getFile(); 获得绝对磁盘路径 / 代表 /WEB-INF/classes

对于路径这一块现在还是有点不是太明白,还是需要在进一步的学习。
10、缺省Servlet 了解功能将静态资源数据内容读取写给客户端

如果某个servlet的映射路径仅仅为一个正斜杠(/),那么当前的servlet为当前web应用的默认servlet

缺省的servlet是用来处理,其他servlet的没有映射的请求

当访问Tomcat服务器中的某个静态HTML和图片是,实际上是访问的缺省servlet

 

 

 

 

 

 

 

 

posted @ 2013-04-17 18:15  蓝冰悠见  阅读(232)  评论(0编辑  收藏  举报