Java:Servlet
本文内容:
- servlet的介绍
- servlet的基础使用介绍
- HttpServlet
- ServletConfig
- ServletContext
- Cookie
- Session
- 数据域对象
servlet的介绍:
- Servlet是sun公司提供的一门用于开发动态web资源的技术。
- servlet程序运行在服务器上。能用来处理浏览器的数据请求。
- servlet可以获取客户端发送的数据,也可以返回数据给客户端,servlet和其他服务配合的话就可以返回一个动态的数据给客户端。
Sun公司在其API中提供了一个servlet接口,来让开发者开发web资源,通常步骤是:
1、编写一个Java类,实现servlet接口。
2、把开发好的Java类部署到web服务器中。
下面介绍如何写一个普通的Servlet的实现类。
servlet的基础使用介绍:
1.创建一个动态web工程【Servlet是JavaEE的内容,所以需要引用JavaEE的库,不能使用一般的库,所以需要创建动态web工程】:
2.新建一个类,实现Servlet接口:
Servlet接口有几个函数需要实现,destroy(),init(),service(),getServletConfig(),getServletInfo()【后面两个可以忽视,一般不用】
- init()方法:当Servlet初始化时调用。通常不需要重写,除非你想用提前进行某些例如资源预备操作。
- service():每一个http请求都会调用service()来处理,这里写如何处理请求。
- destroy():当servlet销毁的时候,调用此方法,即服务器停止的时候。通常不需要重写。
service函数是http请求处理的核心,它有两个分别为ServletRequest和ServletResponse类型的参数,这两个参数由服务器负责封装,request封装了http请求数据,response封装了http请求返回的数据。
(下面讲的HttpServlet本质上还有service,它里面默认会根据http请求的类型来调用不同的方法,比如get类型的就调用doGet),【由于一般不直接实现Servlet,所以这些详细功能的使用留到HttpServlet来讲,这里仅仅做一个例子来讲述请求处理过程】
3.配置Servlet路径匹配,在webContent/WEB-INF/web.xml 【在新版本中,逐渐采用“注解”替代了web.xml的功能。有兴趣的可以自查,我暂时没空去整理。】
配置格式例子如下:
处理过程:
- 比如客户端访问,
- 服务器先读取web.xml来查找servlet-mapping中是否有url-pattern对应,
- 如果对应,根据servlet-mapping中的servlet-name查找到对应的servlet-name,然后将请求处理交给servlet-class中对应的类
- 如果不对应,调用tomcat的默认servlet来查找是否有对应的静态资源,
- 如果都没有,返回404,提示找不到对应资源。
4.运行程序:运行需要tomcat。这里不讲怎么配置tomcat,自己去找吧。
Servlet生命周期:
- servlet的创建与初始化:当有需要指定servlet处理的请求过来时,创建该servlet的实例,执行init()函数。 一个servlet只会初始化一次, init方法只会执行一次 默认情况下是 : 初次访问该servlet,才会创建实例。 【如果想提前创建servlet的实例,需要对servlet进行配置,会在下面的补充中讲解】
- 处理请求:Servlet 调用 service() 函数来处理客户端的请求。
- Servlet的销毁:结束服务器时,Servlet 调用 destroy() 函数,servlet对象被销毁。
如何配置web.xml中的servlet映射(路径匹配):
1.全路径匹配,以 / 开始,格式:/匹配目标字符串
例如:/a,/index,/admin
可以有多个/,例如:/a /aa/bb
/a 匹配到 | localhost:8080/项目名称/a |
/admin 匹配到 | localhost:8080/项目名称/admin |
/user/address匹配到 | localhost:8080/项目名称/user/address |
2.模糊路径匹配,以 / 开始 , 以/ * 结束(这里注意,所以/a/*/b不是模糊匹配),格式:/确定的匹配目标字符串/*
*是一个通配符,代表匹配什么都可以!
/a/* 可以匹配到 | localhost:8080/项目名称/a/1001或localhost:8080/项目名称/a/aaa |
/user/super/*可以匹配到 | localhost:8080/项目名称/user/super/001 |
3.扩展名匹配,没有/ ,以 * 开始,格式:*.扩展名
*.扩展名就是前面的路径是什么,但只要.扩展名结尾的都可以匹配成功
*.jpg 可以匹配到 | localhost:8080/项目名称/a/1.jpg或localhost:8080/项目名称/b/2.jpg |
默认匹配:tomcat默认有个匹配,<url-pattern>/</url-pattern>,它是用来匹配静态资源的。
匹配优先级:精确匹配>路径匹配>扩展名匹配>缺省匹配
注意:
- 路径匹配和扩展名匹配无法同时设置!如<url-pattern>/user/*.aaa</url-pattern>是非法的
- Servlet 2.5开始,一个servlet可以使用多个url-pattern规则,这样可以定义多个url的请求都交给同一个servlet处理。
补充:
- 一些servlet的初始化可能需要不少时间,所以可能需要采用预加载。可以在web.xml的指定servlet中配置属性load-on-startup。当配置这个属性后,服务器启动就会提前初始化这个servlet,它的属性值越小,提前创建的优先级越高。tomcat有两个默认的servlet使用了0和1的优先级,所以我们一般都是从2开始。
HttpServlet
- 由于servlet一般是用来处理http请求的,为了简化开发流程,所以sun提供了一个实现类HttpServlet,它只需要我们重写doGet,doPost函数即可。
- HttpServlet是Servlet的一个实现类service,它里面默认根据http请求的类型来调用不同的方法,比如get类型的就调用doGet。所以有些程序员自己实现了一个子接口来重写service,然后里面的请求类型是自己定义的,这是一种简化servlet数量的好方法。
实现流程:
1.继承HttpServlet类.
2.重写函数,get请求类型的会调用doGet,如果要处理get请求就需要重写doGet;post请求类型的会调用doPost,如果要处理post请求就需要重写doPost;默认情况下,doPost会默认调用doGet。【怎么重写下面讲】
3.配置Servlet路径匹配.
4.运行程序.
与Servlet接口中的service函数类似,doGet和doPost函数也有两个参数,它们的类型为HttpServletRequest和HttpServletResponse,下面介绍一下它们。它们本质上和ServletRequest对象和ServletResponse对象是类似的,只是进行了封装。
HttpServletRequest对象:
- HttpServletRequest对象封装了客户端给服务端发送过来的请求数据,包括请求头,请求行,请求体等内容。
- 所以我们一般使用HttpServletRequest对象来获取客户端发来的请求数据。
HttpServletResponse对象
- HttpServletResponse对象封装了服务端对客户端的返回数据通道。可以返回响应行,响应头,响应体等数据。
- 所以我们可以使用HttpServletResponse对象来给客户端返回我们指定的数据。
重写技巧:
-
获取请求信息:
http请求行信息:
获取请求的方式:request.getMethod() 【可以判断是否来自get方式还是post等方式 】
请求资源 :request.getRequetURI() 或 request.getRequetURL()
请求http协议版本 :request.getProtocol()
http请求头信息:
根据请求头获取请求值 :request.getHeader("名称")
获取所有的请求头名称 :request.getHeaderNames()
- 获取提交过来的数据:
实体内容:
获取实体内容数据 :request.getInputStream() 【使用情况一般是文件上传之类的情况,普通的表单内容可以使用下面的getParameter】
表单内容:
- 根据参数名获取参数值(只能获取一个值的参数):request.getParameter("参数名")【这种方式get和post都可以使用】
- 根据参数名获取参数值(可以获取有多个值的参数):request.getParameterValues("参数名") 【对于可以有多个值的参数,需要使用这个(比如一些复选框的值)】
- 获取所有参数的名称列表 :request.getParameterNames()
- 获取由参数名和参数值组成的map集合:Map<String, String[]> map = request.getParameterMap();【由于有些参数可能有多个值,所以第二个为String[]】
表单内容中的中文编码问题:
- get方式提交的表单跟在url后面,浏览器会对提交的数据进行编码,所以可能需要进行解码,可以采用name = new String(name.getBytes("iso-8859-1"),"utf-8"); 【浏览器与服务器之间的数据编码格式默认是iso-8859-1】 【在tomcat一些版本中已经不需要这一步了。tomcat8已经默认将数据编码成utf-8再进行封装,添加这一步反而变成乱码】
- post方式提交的表单数据在请求体中,使用response.setCharacterEncoding("utf-8")来告诉使用什么类型的编码方式来解码请求体内容。【一定要写在getParameter之前】
- 【由于对于不同的方式需要采用不同的方式来编码,每个servlet都进行处理会代码赘余度很高,一般会采用过滤器来处理。过滤器可以根据不同的请求方式来调用不同的处理方式】
- 返回数据给客户端:
以字节格式返回:
- 获取字节输出通道:response.getOutStream()
- 字节输出流对象调用write("返回的内容")函数返回内容到客户端所见的页面中。【注意返回的内容要转成字节类型】
以字符串格式返回:
- 获取字符流输出通道:response.getWriter()
- 字符输出流对象调用write("返回的内容")函数返回内容到客户端所见的页面中。
设置响应码:response.setStatus()【有些时候可能还需要使用响应码,所以说一下。】
设置响应头:response.setHeader(name,value)
有时候因为客户端和服务端编码不一致会造成乱码,所以需要告诉客户端返回的数据的编码格式(处理中文问题):
- response.setHeader("Content-Type","text/html;charset=UTF-8")或response.setContentType("text/html;charset=UTF-8");
-
转发和重定向:
转发:转发是服务端将客户请求转发给其他servlet。地址栏不会变,过程仅仅发生在服务端。
request.getRequestDispatcher("路径").forward(request, response);【转发会带上之前的请求信息(就是把一个完整的request转发了),转发的目的地只能限于本工程;由于限于本工程,使用相对路径时,可以直接略去工程。】
重定向:重定向是服务端返回一个网页给客户,客户的浏览器将自动跳转到指定网页。地址栏会变。
response.sendRedirect("路径");【转向不限于服务端,所以这个路径可以很随意,连百度都可以;如果使用相对路径,那么必须保留工程】;
ServletConfig
-
当一个servlet它需要一些自定义初始化参数时,可以定义在web.xml中。【这就类似一些开源的线程池可以在它的配置文件中自定义最大线程数量。】
-
而ServletConfig可以用来获取Servlet的初始化配置参数。
配置参数的方法:
在web.xml中,在<servlet>中,格式如下:
获取配置参数:
ServletContext
- ServletContext 对象是整个工程共有的对象,一个工程可以有多个servlet,但它们使用的ServletContext 对象都是同一个。
作用:
-
获取全局配置参数,类似于ServletConfig中的仅仅一个Servlet范围的参数,ServletContext的初始化参数是全局有效的。
-
获取web工程中的资源,web应用程序部署到服务器上后,资源的相对位置是变化了的,所以不能使用在web工程中的路径,一般都需要使用ServletContext对象来获取路径
-
存取数据,servlet间共享数据域对象,如果想在多个servlet*享数据,可以使用ServletContext对象来存取数据。
使用方法:
获取全局配置参数:
- 首先,配置全局配置参数,在web.xml中:
- 获取ServletContext对象:ServletContext context = getServletContext();
- 获取参数:
获取web工程中的资源:
- 假设WebContent下面有个文件夹config,里面有个文件base.properties
- 获取方式1,先获取路径,再获取流:
- 获取方式2,直接获取流:
用ServletContext对象存取数据,使得servlet间能共享数据【存能存多个,取也能取多个;但注意存的时候同名参数的值会覆盖】:
- 存:
- 取:
生命周期与作用范围:
- ServletContext对象是全局生效的,服务器启动的时候,会为托管的每一个web应用程序创建一个ServletContext对象,一个web程序中多个servlet共用同一个 ServletContext对象。
- 当从服务器移除托管的web程序,或者是关闭服务器的时候,ServletContext对象就会被销毁。
Cookie
- cookies能用来存储一些服务端的数据到本地,这些数据能够帮助服务端来识别客户以及记录客户信息。比如你浏览商品的记录可能就存在cookie里,这使得你再次访问网站的时候,服务端能根据cookie来给你指向性地推荐商品。
- 服务端通过返回响应头来存储cookie,当浏览器发现响应头有cookie时就会把cookie存储起来。
- 当用户再次访问对应网站时,浏览器会携带cookie来发起请求,服务端会接受到cookie来进行特殊处理(例如针对性广告,保持用户登录记录等等操作)。
使用方法:
- 创建cookie:cookie可以有多个
Cookie cookie=new Cookie("name","value")
response.addCookie(cookie) 【把cookie发给客户端存起来】
- 获取cookie,没有直接获取某个cookie的函数,只能迭代查找。
获取所有cookie:Cookie[] cookies = request.getCookies();
获取cockie的名字:String cookieName = cookie.getName();
获取cockie的值:String cookieValue = c.getValue();
- 设置cookie的存活时间(过期会被清除):
cookie.setMaxAge(seconds);【单位是秒,默认值是-1代表关闭浏览器就失效】
- 给cookie赋予新值:
cookie.setValue(newValue);
- 删除cookie:
cookie.setMaxAge(0);
Session:
- session原意是会话的意思,每一次打开浏览器访问目标网站就是一次会话。关闭浏览器就是断开会话了。
- 它一般用来与cookies配合使用,cookie不可以存储对象并且存储数据大小太小,而session可以存储对象,而且session存储在服务器上。
- cookie和session的配合:每一个session都有一个id,把session的ID作为cookie存储到本地,下一次就能自动获取sessiond的ID对应的session。
使用:
创建session:request.getSession()
获取session: request.getSession(false) 【默认会做一次判断,根据请求过来的JSESSIONID判断是否已经有对应的session,如果已经有,那么会获取对应的那个,如果没有,那么这个函数是创建的意思。而false代表获取,获取不到就返回null】
在session中存储数据:session.setAttribute(name, value)
获取数据:session.getAttribute(name)
移除数据:
删除指定:session.removeAttribute(name)
删除所有:session.invalidate()
设置session的有效时间:setMaxInactiveInterval(seconds)【默认30分钟】
cookie与session的配合:现在新增的session会默认存储到cookie,但在浏览器关闭之后就会清除,所以关键是给cookie设置生存时间:
这样session中存储的数据下一次就可以继续取了。
数据域对象:
从上面可以学到session能用来存储数据和读取数据。除此之外还有一些能够用来存储数据的”数据域“对象。下面对几个经常用来存储数据的”数据域“对象来讲解。
HttpServletRequest
- 上面没有介绍到request对象也能存储数据,实际上它也是能用来存储数据的。
- 存储数据:request.setAttribute(name, value)
- 取出数据:request.getAttribute(name)
- 作用范围:当次请求范围的,如果转发给别的Servlet,那么另一个Servlet也能获取request中的数据。
HttpSession
- 存储数据:session.setAttribute(name, value)
- 取出数据:session.getAttribute(name)
- 作用范围:多个Servlet范围的。生存时间是可以自己设置的。
ServletContext
- 存储数据:context.setAttribute(name, value)
- 取出数据:context.getAttribute(name)
- 移除数据:context.remoAttribute(name)
- 作用范围与时间:全局范围的,所有的servlet都可以获取到。保存的数据除非主动删除,否则会持续到ServletContext对象销毁
在实际应用中,经常要考虑作用范围来使用不同的数据域对象.比如一些”一次性的,经常需要更新“的数据,一般使用HttpServletRequest来存储,因为它寿命较短,耗费长期资源少。