WEB-9-Servlet

Servlet

1. servlet概述

1.1.servlet是什么

Servletsun公司提供的一门用于开发动态web资源的技术。

按照这套规范写出来的Servlet可以放置到web应用中在Servlet容器中运行。

1.2.开发Servlet步骤

1)写一个类, 实现Servlet接口, 并实现其中的方法

2)在web.xml中为servlet配置对外访问路径。

 

1.3.案例: 手写一个servlet

详细步骤参见: /FristServlet/手写一个servlet.txt

 

2.使用myeclipse开发servlet

使用myeclipse开发Servlet程序时, 可以新建一个Servlet, 默认继承HttpServlet, Servlet内部会覆盖doGetdoPost方法, 分别来处理GETPOST请求。

 

2.1.新建项目

新建一个Web Project,给一个项目名称,其他保持默认即可,然后finish,弹出的对话框选择yes即可。

 

 

2.2.新建一个servlet

新建一个servlet,如果new中找不到servlet,注意视图是否切换到MyEclipse中,给一个包名和类名,下面对勾只留doGet()doPost(),其他去掉,下一步

 

这里将最后两行删掉,是一些xml中的提示,其他地方一般保持默认即可,也可以修改对外访问路径,其中nameURL会自动配置到xml中。最后finash

 

 

servlet中的注释以及方法中的默认实现全部删掉。

 

为什么要继承HttpServlet?

因为这是一个继承了GenericServlet的类,已经提供doGet()doPost()方法,可以方便我们开发web项目。

GenericServlet是一个基础的实现,如果要用此类,需要自己写doGet()doPost()方法,并且需要在service方法中对请求进行判断,会比较麻烦。

 

HttpServlet底层又是如何实现的?

可以打开HttpServlet源码,发现HttpServlet也是继承自GenericServlet,同时,HttpServlet会写各种方法,比如doGet()doPost(),然后在service方法中进行判断,不同的请求调用不同的方法。

 

注意:复制一个servletweb.xml中是不会自动生成配置信息的,所以一般不要复制,而是要新建!

2.3.tomcat配置到myeclipse

详细步骤见:/resource/MyEclipse中配置自己安装的tomcat

 

如果不配置,则每次都要手动将程序发布到tomcat中。

2.3.web应用发布到自己的tomcat

这里注意项目名称是否是自己要发布的项目,然后finish,最后ok

 

 

也可以修改发布的项目名称,参见/resource/myeclipse中修改web应用发布到Tomcat中的应用的名称.pdf

 

MyEclipse中启动tomcat

 

启动后,可以通过浏览器访问servlet,比如:

http://localhost/day09/servlet/SecondServlet

 

可以查看serverstomcat如果是debug模式,则可以修改方法中的代码而无需重启服务器,但是若要新建一个servlet,则需要重启服务器。

 

3. Servlet的继承结构

Servlet接口 – 提供了一个Servlet应该具有的最基本的功能

|

|-- GenericServlet, 实现了Servlet接口, 并实现了其中大部分的方法, 但是service方法没有实现, 这个方法需要开发人员自己去实现

|

|-- HttpServlet, 继承了GenericServlet, 并实现了service方法, service方法中是根据不同的请求方式, 调用不同的doXxx方法, 我们在开发中, 只需要写一个类, 继承HttpServlet, 并覆盖 doGet()和 doPost()方法分别来处理Get请求和POST请求即可!!

4.修改servlet模版

方式一:

将\resource\修改Servlet模板\com.genuitec.eclipse.wizards_9.0.0.me201108091322.jar文件拷贝到:

[Myeclipse安装目录]\Common\plugins目录下,会提示是否替换文件,确定替换即可,如果未出现提示,则看是否进对目录,或者是其他版本的MyEclipse

 

方式二:

(1)[Myeclipse安装目录]\Common\plugins目录下找到文件:com.genuitec.eclipse.wizards.xxx.jar,在此文件中的Templates目录下可以看到Servlet.java源代码。

(2)打开源代码,将doGet()doPost()两个方法的注释和方法中的内容删掉,在doPost()中调用doGet()方法即可。

(3)修改之后保存

(4)重新启动Myeclipse即可以使用新的模板代码了

 

5.Servlet调用过程

 

 

5.1.调用过程

参照<<servlet调用图解>>

 

5.2.Servlet生命周期

Servlet实例在第一次被访问时创建, 创建之后服务器会立即调用init方法进行初始化的操作, 从此以后该实例会一直驻留在服务器的内存中, 为后续的请求服务, 只要有请求访问servlet, 服务器就会调用service方法来处理这个请求, 直到服务器关闭或者是web应用被移出容器时为止, 随着web应用的销毁, servlet实例也会跟着销毁, 在销毁之前, 服务器就调用destroy方法进行善后的处理.

 

6.servlet虚拟路径的配置

web.xml中的servlet对外访问的虚拟路径的配置, 可以直接写一个路径, 或者通过 * 号匹配符写一个路径.

 

方式一:直接写一个路径: /servlet/SecondServlet

方式二:通过*号匹配符写一个路径:

(1) / 开头, /* 结尾, : /servlet/* /a/*  /*

(2) *.后缀 的形式, : *.html *.servlet  *.do *.action

使用*号匹配符写路径, 路径的配置变得更加灵活, 但是也可能会造成, 一个url会被多个servlet Mapping所匹配

 

Urlhttp://localhost/day09/servlet/SecondServlet.do

 

Servlet1Test1: /servlet/*

Servlet2Test2: *.do

 

匹配规则:

*.后缀的优先级永远最低!!

哪一个更接近哪一个起作用!!

 

示例:

Servlet1 映射到 /abc/*

Servlet2 映射到 /*

Servlet3 映射到 /abc

Servlet4 映射到 *.do

 

当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应

Servlet引擎将调用Servlet1

当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应

Servlet引擎将调用Servlet3

当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet1

当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应

Servlet引擎将调用Servlet2

 

7.Request

代表http请求的对象

7.1.继承结构 (!!重要)

ServletRequest – 提供一个request对象最基本的功能

|

|-- HttpServletRequest – 继承了ServletRequest接口, 并在其基础上添加了很多和Http协议相关的方法

 

7.2.request的功能 (!!!重要)

7.2.1.获取客户端相关的信息

getRequestURL方法 -- 返回客户端发出请求完整URL

: http://localhost/day09/servlet/SecondServlet

getRequestURI方法 -- 返回请求行中的资源名部分

: /day09/servlet/SecondServlet

getQueryString方法 -- 返回请求行中的参数部分

: username=zhangfei&password=123

getRemoteAddr方法 -- 返回发出请求的客户机的IP地址

: 127.0.0.1  //可能会出现0:0:0:0:0:0:0:1形式,是ipv6的表现形式。

getMethod -- 得到客户机请求方式

: GETPOST

!!getContextPath -- 获得当前web应用虚拟目录名称

: /day09

注意:在写路径时不要将web应用的虚拟路径的名称写死, 应该在需要写web应用的名称的地方通过getContextPath方法动态获取

7.2.2.获取请求头信息

getHeader(name)方法 --- String

getHeaders(String name)方法 --- Enumeration<String>

可以通过遍历枚举遍历每一个信息

例如:while (values.hasMoreElements()) {

String value = (String) values.nextElement();

System.out.println(value);

}

getHeaderNames方法 --- Enumeration<String>

getIntHeader(name)方法  --- int

getDateHeader(name)方法 --- long(日期对应毫秒)

7.2.3.获取请求参数(!!!重要)

getParameter(String name) --- String 通过name获得值

getParameterValues(String name)  --- String[ ] 通过name获得多值 checkbox

getParameterMap()  --- Map<String,String[ ]> key :name value: 多值

getParameterNames()  --- Enumeration<String> 获得所有name

 

例如:创建servletRequestDemo2,并webRoot下,将css那天的regist文件夹放进去,并修改form中的属性:

<!-- <form action="http://localhost/day09/servlet/RequestDemo2"> -->

<!-- 也可以简写为如下格式 -->

<form action="/day09/servlet/RequestDemo2">

 

RequestDemo2中代码如下:

//getParameter(String name)

String username = request.getParameter("username");

System.out.println("username:"+username);

//getParameterValues(String name)

//可以自定义一个网址拼接参数,如:

 //http://localhost/day09/servlet/RequestDemo2?like=lanqiu&like=zuqiu&like=ppq

String[] likes = request.getParameterValues("like");

System.out.println("likes:"+Arrays.toString(likes));

//getParameterMap()获取所有请求参数组成的map集合

//可以自己指定map的类型

Map<String,String[]> map = request.getParameterMap();

for (Map.Entry<String,String[]> entry:map.entrySet()) {

String key = entry.getKey();

String[] values = entry.getValue();

System.out.println(key+" : "+Arrays.toString(values));

}

 

 

 

请求参数中的乱码问题

 

乱码分析: 编码时和解码时使用的码表不一致造成的!!

编码: 是在浏览器进行的, 浏览器发送数据使用的是什么编码?  

浏览器在打开当前页面时使用的是什么码表,也会使用相同的码表来发送数据.

打开页面使用utf-8, 所以发送数据也是用utf-8码表

 

解码: 是在服务器端进行的, 服务器端接收数据使用的又是什么编码?

如果不指定, 服务器会使用默认的码表来接收浏览器发送过来的数据, 默认的码表是iso8859-1.

解决方案:

乱码造成的原因是编码不一致, 所以应该让两端的编码保持一致!, 应该通知服务器使用utf-8来接受客户端发送过来的数据!!

 

request.setCharacterEncoding(utf-8);//用来通知服务器使用什么编码来接受请求实体内容中的数据, 如果使用的是POST提交, POST提交的请求参数就是在请求实体内容中!, 所有这个方法可以解决POST提交的乱码问题!!!

 

GET提交的请求参数由于不在请求实体内容中,而是在请求行中的请求资源路径后面拼接着, 所以这行代码对GET提交的参数乱码不起作用!!!

 

GET提交的参数乱码问题该如何解决???

GET提交的乱码问题可以通过手动编解码来解决!!

//>>username为乱码, 通过乱码反向编码得回二进制数组

byte[] bytes = username.getBytes("iso8859-1");

//>>通过二进制数组查询正确的码表, 得出正确的数据

username = new String(bytes, "utf-8");

 

7.2.4.实现请求转发(!!!重要)

请求重定向: 302状态码+location响应头

请求转发: 和请求重定向都可以实现资源的跳转, 但是区别是请求转发是服务器内部的并且是同一个WEB应用内部的资源跳转

请求转发的特点:

一次请求对应一次响应

地址栏地址不会发生变化

请求转发只能在同一个WEB应用内部资源之间进行跳转! 不能是不同的WEB应用或者不同的主机!

实现代码:

  创建servletRequestDemo3RequestDemo4,RequestDemo3转发到RequestDemo4

  在RequestDemo3中:

/*

 * 在web阶段写路径时,除了请求转发和请求包含在写

 * 路径是不用包含web应用的虚拟路径,其他地方都需要

 * 加上web应用的虚拟路径。

 * 完整路径:http://localhost/day09/servlet/RequestDemo4

 */

request.getRequestDispatcher("/servlet/RequestDemo4").forward(request, response);

 

  在RequestDemo4中响应:

       response.getWriter().write("1$");

 

 

request开发细节:

在转发之前, 如果response缓冲区被写入了数据但是还没有打给浏览器, 在转发时response缓冲区(数据)将会被清空!

例如:在RequestDemo3中添加代码:

response.getWriter().write("no money!");

发现浏览器中并未得到"no money!"这段字符串的响应。

 

在转发之前, 如果response缓冲区被写入了数据并且已经打给了浏览器, 转发将会失败!!

例如:在RequestDemo3中添加代码:

response.getWriter().write("no money!");

response.flushBuffer();

发现浏览器可以显示"no money!",因为强制刷新了,但是转发就会报错,因为已经响应过了,一次请求对应一次响应。

 

在同一个Servlet中转发不能进行多次!!(A既转发B, 又转发给C)

但是可以进行多重转发(比如A转发给B, B再转发给C)

 

7.2.5.作为域对象来使用(!!!重要)

域对象:如果一个对象具有一个可以被看见的范围, 利用该对象上的map可以在整个范围内实现资源的共享!

域对象提供的方法(可以操作map中的数据):

setAttribute(String name, Object value);  用来存储一个对象,也可以称之为存储一个域属性

getAttribute(String name);   用来获取request中的数据

removeAttribute(String name);   用来移除request中的域属性

getAttributeNames();   获取所有域属性的名称

 

生命周期:

一次请求开始时创建request对象, 一次请求结束时销毁request对象

作用范围:

整个请求链

主要功能:

在整个范围内共享数据

带数据到目的地

 

例如:在RequestDemo3中可以设置一些属性,比如是从数据库查询出来的数据,转发到RequestDemo4后,在RequestDemo4中从request域中获取数据,并打印到页面中。

7.2.6.实现请求包含

请求包含是服务器内部资源合并的现象


如果浏览器访问Servlet A, 但是A不能独立的处理这次请求, 需要另外一个Servlet B帮忙, 于是在A中可以将B包含进来, 包含的代码如下:

request.getRequestDispatcher(B的路径”).include(request, response);

 

B包含进来后, 将会由AB共同来处理这次请求, 处理的结果也会合并在一起, 一起打给浏览器!

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值