一、什么是servlet?

处理请求和发送响应的过程是由一种叫做Servlet的程序来完成的,并且Servlet是为了解决实现动态页面而衍生的东西。理解这个的前提是了解一些http协议的东西,并且知道B/S模式(浏览器/服务器)。

二、tomcat和servlet的关系

Tomcat 是Web应用服务器,是一个Servlet/JSP容器. 
Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户. 
而Servlet是一种运行在支持Java语言的服务器上的组件. 
Servlet最常见的用途是扩展Java Web服务器功能,提供非常安全的,可移植的,易于使用的CGI替代品. 
从http协议中的请求和响应可以得知,浏览器发出的请求是一个请求文本,而浏览器接收到的也应该是一个响应文本。 
但是并不知道是如何转变的,只知道浏览器发送过来的请求也就是request,我们响应回去的就用response。 
①:Tomcat将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象, 
所有的HTTP头数据读可以通过request对象调用对应的方法查询到。 
②:Tomcat同时会要响应的信息封装为HttpServletResponse类型的response对象, 
通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给tomcat,tomcat就会将其变成响应文本的格式发送给浏览器 
Java Servlet API 是Servlet容器(tomcat)和servlet之间的接口,它定义了serlvet的各种方法, 
还定义了Servlet容器传送给Servlet的对象类,其中最重要的就是ServletRequest和ServletResponse。 
所以说我们在编写servlet时,需要实现Servlet接口,按照其规范进行操作。

三、编写Servlet代码

1、创建一个MyServlet继承HttpServlet,重写doGet和doPost方法,根据请求的方式是get还是post,然后用不同的处理方式来处理请求。 
2、在web.xml中配置MyServlet,为什么需要配置? 
让浏览器发出的请求知道到达哪个servlet,也就是让tomcat将封装好的request找到对应的servlet让其使用。

  <servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>controller.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>/servlet</url-pattern>
</servlet-mapping>

按照步骤,首先浏览器通过http://localhost:8080//servlet来找到web.xml中的url-pattern,这就是第一步,匹配到了url-pattern后,就会找到第二步servlet的名字servlet,知道了名字,就可以通过servlet-name找到第三步,到了第三步,也就能够知道servlet的位置class了。然后到其中找到对应的处理方式进行处理。

四 、 创建servlet的原理

1 、 servlet的生命周期是什么?

服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf)。 
该servlet对象去处理所有客户端请求,在service(ServletRequest req,ServletResponse res)方法中执行。 
最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。

2、servlet的生命周期中,可以看出,执行的是service方法,为什么我们就只需要写doGet和doPost方法呢?为什么创建的servlet是继承自httpServlet,而不是直接实现Servlet接口?

(1).httpServlet的继承结构

httpServlet继承GenericServlet,GenericServlet实现了Servlet接口和ServletConfig接口。 
GenericServlet(通用Servlet)的作用是什么? 
GenericServlet实现Servlet接口的方法,简化编写servlet的步骤。

(2).ServletConfig和ServletContext

getServletConfig()方法来获取ServletConfig对象,ServletConfig对象可以获取到Servlet的一些信息,例如ServletName、ServletContext、InitParameter、InitParameterNames。 
通过查看ServletConfig这个接口就可以知道,ServletConfig接口中ServletContext对象是servlet上下文对象,功能有很多,获得了ServletContext对象,就能获取大部分我们需要的信息,比如获取servlet的路径和servlet方法。

(3).Servlet接口中的内容和作用

Servlet生命周期的三个关键方法,init、service、destroy。 
获取ServletConfig,而通过ServletConfig又可以获取到ServletContext。 
而GenericServlet实现了Servlet接口后,也就说明我们可以直接继承GenericServlet,就可以使用上面我们所介绍Servlet接口中的那几个方法了,能拿到ServletConfig,也可以通过ServletConfig拿到ServletContext,不过那样太麻烦,不能直接获取ServletContext,所以GenericServlet除了实现Servlet接口外,还实现了ServletConfig接口,那样,就可以直接获取ServletContext了。因为httpServlet继承了GenericServlet,所以我们可以直接使用httpServlet。

(4).GenericServlet类的内容详解

Servlet和ServletConfig接口所实现的方法,有9个,这很正常, 
但是我们可以发现,init方法有两个,一个是带有参数ServletConfig的,一个有无参的方法.

    public class ServletDemo extends GenericServlet {
@Override
public void init() throws ServletException {
// TODO Auto-generated method stub
super.init();
}
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
super.init(config);
}
}

首先看init(ServletConfig config)方法,因为init(ServletConfig config)中带有ServletConfig对象,为了方便能够在其他地方也能直接使用ServletConfig对象,而不仅仅局限在init(ServletConfig config)方法中,所以创建一个私有的成员变量config,在init(ServletConfig config)方法中就将其赋值给config,然后通过getServletConfig()方法就能够获取ServletConfig对象了,可以通过全局变量保存ServletConfig对象。 
在GenericServlet类中增加一个init()方法,如果以后需要在init方法中需要初始化别的数据,只需要重写init()这个方法,而不需要去覆盖init(ServletConfig config)这个方法。

再来看service(ServletRequest req, ServletResponse res) 方法

    public class ServletDemo extends GenericServlet {
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
}
}

在GenericServlet类中并没有实现该内容,因为在它下面还有一层,还有一个子类继承GenericServlet,并实现该方法,service方法中的参数还是ServletRequest,ServletResponse,并没有跟http相关对象挂钩。

(5).HttpServlet类详解

这个类主要的功能是实现service方法的各种细节和设计。并且通过类名可以知道,该类就跟http挂钩了。

public class ServletDemo extends HttpServlet {
@Override
protected void service(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
super.service(arg0, arg1);
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
super.service(arg0, arg1);
}
}

五.四个重点的对象。ServletConfig、ServletContext,request、response

1.ServletConfig对象

getServletConfig(); //获取ServletConfig对象
getServletName(); //获取servlet的名称,也就是我们在web.xml中配置的servlet-name
getServletContext(); //获取ServletContext对象
getInitParameter(String); //获取在servlet中初始化参数的值。这里注意与全局初始化参数的区分。这个获取的只是在该servlet下的初始化参数
getInitParameterNames(); //获取在Servlet中所有初始化参数的名字,也就是key值,可以通过key值,来找到各个初始化参数的value值。注意返回的是枚举类型

注意:在上面我们所分析的源码过程中,我们就知道,其实可以不用先获得ServletConfig,然后在获取其各种参数, 
可以直接使用其方法,比如上面我们用的ServletConfig().getServletName();可以直接写成getServletName(); 
而不用在先获取ServletConfig();了,原因就是在GenericServlet中,已经帮我们获取了这些数据,我们只需要直接拿就行。

2.ServletContext对象

getServletContext();
getServletConfig().getServletContext();
//这两种获取方式的区别就跟上面的解释一样,第一种是直接拿,
//在GenericServlet中已经帮我们用getServletConfig().getServletContext()拿到了ServletContext。
//我们只需要直接获取就行了,第二种就相当于我们自己在获取一遍,两种是一样的。

功能:tomcat为每个web项目都创建一个ServletContext实例,tomcat在启动时创建,服务器关闭时销毁,在一个web项目中共享数据,管理web项目资源,为整个web配置公共信息。通俗点讲,就是一个web项目,就存在一个ServletContext实例,每个Servlet都可以访问到它。 
1、web项目中共享数据,

setAttribute(String name, Object obj);// 在web项目范围内存放内容,以便让在web项目中所有的servlet读能访问到
getAttribute(String name);// 通过指定名称获得内容
removeAttribute(String name);// 通过指定名称移除内容  

2、整个web项目的初始化参数,这个就是全局初始化参数,每个Servlet中都能获取到该初始化值

getInitPatameter(String name);  //通过指定名称获取初始化值
getInitParameterNames();  //获得枚举类型

3、获取web项目资源

getServletContext().getRealPath("/WEB-INF/web.xml");//获取web项目下指定资源的路径
InputStream getResourceAsStream(java.lang.String path);//获取web项目下指定资源的内容,返回的是字节输入流
getResourcePaths(java.lang.String path);//指定路径下的所有内容。

3.request对象

request就是将请求文本封装而成的对象,所以通过request能获得请求文本中的所有内容,请求头、请求体、请求行 。

String getHeader(java.lang.String name);// 获得指定头内容String
long getDateHeader(java.lang.String name);// 获得指定头内容Date
int getIntHeader(java.lang.String name);// 获得指定头内容int
Enumeration getHeaders(java.lang.String name);// 获得指定名称所有内容

请求体的获取 – 请求参数的获取分两种,一种get请求,一种post请求 
get请求参数:http://localhost:8080/MyServlet?username=123&password=123 
post请求参数:<form method="post"><input type="text" name="username">

String request.getParameter(String);// 获得指定名称,一个请求参数值。
String[] request.getParameterValues(String);// 获得指定名称,所有请求参数值。例如:checkbox、select等
Map<String , String[]> request.getParameterMap();// 获得所有的请求参数  

请求转发

request.getRequestDispatcher(String path).forward(request,response);  
//path:转发后跳转的页面,这里不管用不用"/"开头,都是以web项目根开始,因为这是请求转发
//请求转发只局限与在同一个web项目下使用,所以这里一直都是从web项目根下开始的

特点:浏览器中url不会改变,也就是浏览器不知道服务器做了什么,是服务器帮我们跳转页面的,并且在转发后的页面,能够继续使用原先的request,因为是原先的request,所以request域中的属性都可以继续获取到。

4.response对象

response.setHeader(java.lang.String name, java.lang.String value) ;//设置指定的响应头,常用。
response.setHeader("Refresh",3);//设置每隔3秒就自动刷新一次,

重定向(页面跳转) 
方式一:手动方案

response.setStatus(302);  //状态码302就代表重定向
response.setHeader("location","http://www.baidu.com");

方式二:使用封装好的,通过response.sendRedirect("http://www.baidu.com"); 
特点:服务器告诉浏览器要跳转的页面,是浏览器主动去跳转的页面,浏览器的地址栏中url会变,是浏览器重新发起一个请求到另外一个页面,所以request是重新发起的,跟请求转发不一样,原先request域中的属性不能获取。 
重定向没有任何局限,可以重定向web项目内的任何路径,也可以访问别的web项目中的路径,并且这里就用”/”区分开来。 
如果使用了”/”开头,就说明我要重新开始定位了,不访问刚才的web项目,自己写项目名,可以访问服务器上的其他项目。 
如果没有使用”/”开始,那么就知道是访问原来那个web项目下的servlet,就可以省略项目名了。

六. 实例代码

  -->实现javax.servlet.Servlet接口  -->
-->继承javax.servlet.GenericServlet类 (适配器模式) -->
-->继承javax.servlet.http.HttpServlet类 (模板方法设计) -->
-->继承HttpServlet
最常用的就是继承HttpServlet,我们使用起来很方便
public class servletdemo extends HttpServlet{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("");
out.print("");
//创建cookie,
Cookie cookie = new Cookie("name", "Value");
//设置cookie的有效时间,单位是秒
cookie.setMaxAge(1);
/*负数:cookie的数据存在浏览器缓存中
* 0:删除。路径要保持一致,否则可能删错人。
* 正数:缓存(持久化到磁盘上)的时间*/
//设置cookie的path
cookie.setPath(request.getContextPath());
/*客户端在访问服务器另外资源时,根据访问的路径来决定是否带着Cookie到服务器
*当前访问的路径如果是以cookie的path开头的路径,浏览器就带。否则不带。
cookie.setMaxAge(0);相当于删除cookie*/
//把cookie信息写回到客户端
response.addCookie(cookie); //Cookie遍历
Cookie[] cookies = request.getCookies();//获取客户端的所有Cookie对象
for (int i = 0;cookies!=null && i < cookies.length; i++) {
System.out.println(cookies[i].getName());
System.out.println(cookies[i].getValue());
System.out.println(cookies[i].getPath());
System.out.println(cookies[i].getMaxAge());
}
//session
request.getSession().setAttribute("","");
//得到session对象
HttpSession session = request.getSession();
//session操作
session.getAttribute("");
session.setAttribute("", "");
session.getId();
//请求转发
request.getRequestDispatcher("").forward(request, response);
/*转发是服务器行为,重定向是客户端行为
1.转发在服务器端完成的;重定向是在客户端完成的
2.转发的速度快;重定向速度慢
3.转发的是同一次请求;重定向是两次不同请求
4.转发不会执行转发后的代码;重定向会执行重定向之后的代码
5.转发地址栏没有变化;重定向地址栏有变化
6.转发必须是在同一台服务器下完成;重定向可以在不同的服务器下完成 */
//请求重定向
response.setStatus(302);
response.sendRedirect("");
//告知客户端不缓存
response.setHeader("pragma", "no-cache");
response.setHeader("cache-control", "no-cache");
response.setDateHeader("expires", 0); System.out.println(request.getMethod());//获得请求方式
System.out.println(request.getRequestURL());//返回客户端发出请求时的完整URL
System.out.println(request.getContextPath());//当前应用的虚拟目录
System.out.println(request.getRequestURI());//返回请求行中的资源名部分
System.out.println(request.getQueryString());//返回请求行中的参数部分
System.out.println(request.getHeaderNames());//得到所有头信息name
//Properties
//获取资源路径
//此处填写的路径一定要注意是WEB服务器部署后的路径
String path=this.getServletContext().getRealPath("/test.properties");
//创建Properties
Properties pro =new Properties();
pro.load(new FileInputStream(path));//读入文件test.properties //通过调用GenericServlet的getServletContext方法得到ServletContext对象
ServletContext setServletContext=this.getServletContext();
//向ServletContext添加一个键值对
setServletContext.setAttribute("name", "value"); /*获取非表单数据,先set后get,可以remove
void setAttribute(String name, Object value);
Object getAttribute(String name);
Void removeAttribute(String name);
*/
//服务器和客户端浏览器编码要统一,否则会乱码
// resp.setCharacterEncoding("UTF-8");//设置服务器编码
// resp.setHeader("content-type", "text/html;charset=UTF-8");//通过响应消息头设置客户端浏览器编码
// resp.setContentType("text/html;charset=UTF-8");//此行代码封装了上面两行代码
// PrintWriter out=resp.getWriter();//得到一个字符输出流
// out.write("Response文本信息");//向客户端响应文本内容 //获取编码 //第一种方式
// String encoding=config.getInitParameter("encoding");
// System.out.println("第一种方式"+encoding);
// //第二种方式
// System.out.println("第二种方式"+this.getServletConfig().getInitParameter("encoding"));
//第三种方式
// System.out.println("第三种方式"+super.getInitParameter("encoding")); } }
public class DownloadFileDemo extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//通过路径得到输出流
String path =this.getServletContext().getRealPath("/WEB-INF/classes/cn/servlet/Servlet.jpg");
FileInputStream file=new FileInputStream(path);
//创建输出流
ServletOutputStream sos=resp.getOutputStream();
//得到文件名
String filename=path.substring(path.lastIndexOf("\\")+1);//分割字符串,取最后一个'"\\'"符号后面的1个字符
//设置文件名的编码
filename=URLEncoder.encode(filename,"UTF-8");//将编码改为UTF-8
//告知客户端下载文件
resp.setHeader("content-disposition", "attachment;filename="+filename);
resp.setHeader("content-type","image/jpg");
//输出
int len=1;
byte[] b=new byte[1024];
while((len=file.read(b))!=-1) {
sos.write(b,0,len);
}
sos.close();
file.close();
}
}
public class ServletDemo implements Servlet{
//Servlet生命周期的方法
//在servlet第一次被访问时调用
//实例化
public ServletDemo(){
System.out.println("ServLetDemo执行了,在servlet实例化时调用");
}
//Servlet生命周期的方法
//在servlet第一次被访问时调用
//初始化
public void init(ServletConfig arg0) throws ServletException {
System.out.println("init执行了,在servlet第一次被访问时调用"); }
//Servlet生命周期的方法
//每次访问时都会被调用
//服务
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
//System.out.println("hello servlet");
System.out.println("service执行了,每次访问时都会被调用");
}
//Servlet生命周期的方法
//销毁
public void destroy() {
System.out.println("destroy执行了,销毁");
}
public ServletConfig getServletConfig() {
System.out.println("getServletConfig"); return null;
}
public String getServletInfo() {
System.out.println("getServletInfo"); return null;
}
}

tomcat和servlet的关系的更多相关文章

  1. tomcat/jsp/servlet版本关系

    Servlet Spec JSP Spec EL Spec WebSocket Spec JASPIC Spec Apache Tomcat version Actual release revisi ...

  2. 【tomcat】servlet原理及其生命周期

    1.什么是servlet? Servlet(Servlet Applet),全称Java Servlet,是用Java编写的服务器端程序.而这些Servlet都要实现Servlet这个接口.其主要功能 ...

  3. WEB服务器,TOMCAT和servlet之间的关系

    WEB服务器,TOMCAT和servlet之间的关系 什么是WEB服务器Web服务器是指能够为发出请求的浏览器提供文档的程序.服务器是 一种被动程序,只有浏览器发出请求的时候才会响应.应用层使用 的是 ...

  4. web服务器、tomcat、servlet是什么?它们之间的关系又是什么?

    今天偶然看到常见web服务器的介绍有Apache HTTP server.Nginx.Microsoft IIS.GWS,心中不禁产生了疑问,这些都是什么呢?一直认为tomcat就是web服务器,以下 ...

  5. JSP学习 —— 开篇:JSP,servlet容器,Tomcat,servlet容器之间的关系

    JSP(JAVA SERVER PAGE)的缩写,其本身就是servlet的简化,是一种动态网页标准,其特点是在HTML代码中嵌入JAVA代码,JSP标签或用户标签来生成网页.至于它为什么会出现,主要 ...

  6. 浅谈Tomcat和Servlet

    本文浅谈下对Tomcat和Servlet总体的理解,初学时有用过一段时间,但当时疲于应对如何xml配置和使用,对他们的理解就像是一个黑匣子.现在回顾一下帮助自己加深网络的理解.开始还是先推荐我看的文章 ...

  7. jdk和Tomcat版本之间的关系,jdk尽量要比tomcat低才行

    注:本文来源于:6860 <jdk和Tomcat版本之间的关系,jdk尽量要比tomcat低才行> 用的tomcat是低版本的,但是用的jdk却是高版本的,用Servlet做的项目运行都没 ...

  8. Tomcat和Servlet简析

    目录 Servlet Tomcat 参考 Servlet Servlet通常指我们继承了Servlet接口的类,我们开发Servlet时一般就是继承HttpServlet重写它的doGet.doPos ...

  9. Tomcat深入浅出——Servlet(二)

    一.Servlet简介 Servlet类最终开发步骤: 第一步:编写一个Servlet类,直接继承HttpServlet 第二步:重写doGet方法或者doPost方法,重写哪个我说的算! 第三步:将 ...

随机推荐

  1. customization arm ubuntu rootfs

    requirment: want to get arm ubuntu rootfs method: base on debootstrap tool, customization full funct ...

  2. 获取jsp选中复选框的id传到后台controller,进行逻辑删除等操作

    逻辑删除设备:(数据表中还有这条记录,不显示出来) 思路: 数据表加个字段display,值为Y/N,只显示display为Y的,删除时,把display的值改为N,就不会显示出来 jsp页面如下图, ...

  3. IO文件相关操作

    IO编程 IO 即Input/Output  input stream 就是数据从外面(磁盘.网络)流进内存,output stream 就是数据从内存流到外面去. 通常cpu 和 内存的速度远远高于 ...

  4. Swift Tips笔记

    “??”操作符可以判断输入并在当左侧的值是非 nil 的 Optional 值时返回其 value,当左侧是 nil 时返回右侧的值. 例: var level: Int? var startLeve ...

  5. rim

    “也许我们需要一些药物了”卡拉米走回他的研究室 不去看他最好的朋友的尸体. 过了今晚,他的血肉会被工虫分解. 播种机会犁过他的骨殖,种下土豆与甜菜. 索斯蹲下,不禁思考 生与死在这里太过平常 这是他们 ...

  6. 移动前端开发之viewport的深入理解 --- 待续

    在移动设备上进行网页的重构或开发, 只有明白了viewport的概念 才能 响应 各种  不同分辨率 的移动设备 一.viewport的概念 通俗的讲,移动设备上的viewport就是设备的屏幕上能用 ...

  7. 仿sql注入 sql

    <?phpclass sqlsafe { //(and|or)\\b 表示以and和or结尾的单词如:aand,band,都可以匹配//如果匹配and或or则使用 \\b(and|or)\\b来 ...

  8. Femtocell家庭基站通信截获、伪造任意短信漏洞

    阿里移动安全团队与中国泰尔实验室无线技术部的通信专家们一起,联合对国内运营商某型Femtocell基站进行了安全分析,发现多枚重大漏洞,可导致用户的短信.通话.数据流量被窃听.恶意攻击者可以在免费申领 ...

  9. 【转载】Java Web的web.xml文件作用及基本配置

    其实web.xml就是asp.net的web.config一个道理. 说明: 一个web中完全可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的. web.xml文件是用来 ...

  10. tensorflow中 tf.add_to_collection、 tf.get_collection 和 tf.add_n函数

    tf.add_to_collection(name, value)  用来把一个value放入名称是'name'的集合,组成一个列表; tf.get_collection(key, scope=Non ...