Servlet 简介
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
1. servlet的路径配置
注解配置:
- 精确匹配,一般作用于站点独特的几个路径,首页、登录、注册等等
@WebServlet("/hello")
2.路径匹配,一般用于产品页,新闻页面,百科页面一般用于大量相类似的页面
@WebServlet("/product/*")
3.扩展名匹配
@WebServlet("*.json")
4.匹配多个路径:
@WebServlet(urlPatterns= {"/morepath","*.do","/more/*"})
1.2 Servlet的web.xml 配置
web.xml 文件的配置是为了保护servlet。其实服务器应该调用哪个 servlet 进行请求的处理, 在浏览器的请求地址中写的很清楚。
Web.xml 配置的作用:保护Servlet。
配置方式一:精确匹配
<!-- 配置方式一 -->
<servlet>
<servlet-name>my3</servlet-name>
<servlet- class>com.bjsxt.servlet.MyServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>my3</servlet-name>
<url-pattern>/my3</url-pattern>
</servlet-mapping>
配置方式二:路径匹配
<servlet>
<servlet-name>my3</servlet-name>
<servlet- class>com.bjsxt.servlet.MyServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>my3</servlet-name>
<url-pattern>/news/*</url-pattern>
</servlet-mapping>
配置方式三:扩展名匹配
<servlet>
<servlet-name>my3</servlet-name>
<servlet- class>com.bjsxt.servlet.MyServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>my3</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
1.3 加载时机
服务器启动的时候会将 webapps 中部署好的项目统一进行加载,并完成对每个项目的 web.xml 文件的加载。
注意:
一个 Servlet 可有拥有多个 url-pattern 配置,但是一个url-pattern 配置只能对应一个Servlet。路径和扩展名匹配无法同时设置,比如下面的三个<url-pattern>都是非法的,如果设置,启动tomcat服务器会报错。
<url-pattern>/kata/*.jsp</url-pattern>
<url-pattern>/*.jsp</url-pattern>
<url-pattern>he*.jsp</url-pattern>
另外注意:<url-pattern>/aa/*/bb</url-pattern>
这个是精确匹配,url必须是 /aa/*/bb,这里的*不是通配的含义。
1.4 优先顺序
当一个url与多个servlet的匹配规则可以匹配时,则按照 “ 精确路径 > 最长路径>扩展名”这样的优先级匹配到对应的servlet。举例如下:
2. servlet的生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
现在让我们详细讨论生命周期的方法。
2.1 init() 方法
- init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。
- Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。
- 当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。
init 方法的定义如下:
public void init() throws ServletException {
// 初始化代码...
}
2.2 service() 方法
- service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
- 每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
下面是该方法的特征:
public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException{
}
service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。
doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。
2.2.1 doGet() 方法
GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}
2.2.2 doPost() 方法
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}
2.3 destroy() 方法
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:
public void destroy() {
// 终止化代码...
}
2.4 架构图
下图显示了一个典型的 Servlet 生命周期方案。
- 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
- Servlet 容器在调用 service() 方法之前加载 Servlet。
- 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
3. servlet的请求处理
我们编写的Servlet 代码是没有对浏览器的请求进行处理的。现在我们开始学习如何使用Servlet 进行对浏览器的请求进行处理。
3.1 Request 对象:
问题:
浏览器发起请求到服务器,会遵循HTTP 协议将请求数据发送给服务器。那么服务器接受到请求的数据该怎么存储呢?不但要存,而且要保证完成性。
解决:
使用对象进行存储,服务器每接受一个请求,就创建一个对象专门的存储此次请求的请求数据。
request 对象解释:
服务器接收到浏览器的请求后,会创建一个 Request 对象,对象中存储了此次请求相关的请求数据。服务器在调用 Servlet 时会将创建的Request 对象作为实参传递给 Servlet 的方法。
使用:
- 获取请求头数据
- 获取请求行数据获取用户数据
3.1.1 读取 HTTP 头的方法
下面的方法可用在 Servlet 程序中读取 HTTP 头。这些方法通过 HttpServletRequest 对象可用。
方法 & 描述:
- Cookie[] getCookies()
- 返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。
- Object getAttribute(String name)
- 以对象形式返回已命名属性的值,如果没有给定名称的属性存在,则返回 null。
- String getCharacterEncoding()
- 返回请求主体中使用的字符编码的名称。
- String getContextPath()
- 返回指示请求上下文的请求 URI 部分。
- String getHeader(String name)
- 以字符串形式返回指定的请求头的值。
- String getMethod()
- 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
- String getParameter(String name)
- 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
- String getPathInfo()
- 当请求发出时,返回与客户端发送的 URL 相关的任何额外的路径信息。
- String getProtocol()
- 返回请求协议的名称和版本。
- String getQueryString()
- 返回包含在路径后的请求 URL 中的查询字符串。
- String getRemoteAddr()
- 返回发送请求的客户端的互联网协议(IP)地址。
- String getRequestURI()
- 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。
- String getServletPath()
- 返回调用 JSP 的请求的 URL 的一部分。
- String[] getParameterValues(String name)
- 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。
- int getIntHeader(String name)
- 返回指定的请求头的值为一个 int 值。
- int getServerPort()
- 返回接收到这个请求的端口号。
- int getParameterMap()
- 将参数封装成 Map 类型。
案例解析:
前端判断userAgent,显示PC还是移动端页面的流程
User --> 发送请求http://www.baidu.com ---> 返回PC端页面(JS开始执行判断浏览器是什么浏览器(直接通过js自动适配移动端页面)) ----> location.href = http://m.baidu.com --> 发送请求到百度移动端页面
后端判断userAgent,显示PC还是移动端页面的流程
User --> 发送请求http://www.baidu.com -->servlet分析判断浏览器是什么浏览器 ---》返回移动端页面或者是PC页面
前端需要两步,而后端只需要一步。
3.2 Response 对象
问题:
在使用 Request 对象获取了请求数据并进行处理后,处理的结果如何显示到浏览器中呢?
解决:使用 Response 对象
服务器在调用指定的 Servlet 进行请求处理的时候,会给 Servlet 的方法传递两个实参 request 和 response。其中 request 中封存了请求相关的请求数据,而 response 则是用来进行响应的一个对象。
使用:
- 设置响应头
- 设置响应编码格式
设置 HTTP 响应报头的方法
下面的方法可用于在 Servlet 程序中设置 HTTP 响应报头。这些方法通过 HttpServletResponse 对象可用。
方法 & 描述
- void addCookie(Cookie cookie)
- 把指定的 cookie 添加到响应。
- void addHeader(String name, String value)
- 添加一个带有给定的名称和值的响应报头。
- void sendRedirect(String location)
- 使用指定的重定向位置 URL 发送临时重定向响应到客户端。
- void setCharacterEncoding(String charset)
- 设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。
- void setContentType(String type)
- 如果响应还未被提交,设置被发送到客户端的响应的内容类型。
- void setHeader(String name, String value)
- 设置一个带有给定的名称和值的响应报头。
- void setIntHeader(String name, int value)
- 设置一个带有给定的名称和整数值的响应报头。
- void setStatus(int sc)
- 为该响应设置状态码。
设置响应实体
请求乱码问题解决:
使用 String 进行重新编码:
uname=new String(uname.getBytes("iso8859-1"),"utf-8");
Get 方式请求:
在 service 方法中使用: req.setCharacterEncoding(“utf-8”);
在 tomcat 服务器目录下的 conf 文件下找到 server.xml 文件,打开进行如下配置:
Post 方式请求:
在 service 方法中使用: req.setCharacterEncoding(“utf-8”);
流程总结:
Servlet 的使用流程:
设置请求编码格式设置响应编码格式获取请求信息
处理请求信息响应处理结果
数据流转流程:
浏览器------>服务器 >数据库
浏览器<------服务器<数据库
4. servlet表单数据
很多情况下,需要传递一些信息,从浏览器到 Web 服务器,最终到后台程序。浏览器使用两种方法可将这些信息传递到 Web 服务器,分别为 GET 方法和 POST 方法。
4.1 GET方法
GET 方法向页面请求发送已编码的用户信息。页面和已编码的信息中间用字符分隔,如下所示:http://www.test.comhellokey1=value1&key2=value2
GET 方法是默认的从浏览器向 Web 服务器传递信息的方法,它会产生一个很长的字符串,出现在浏览器的地址栏中。
如果您要向服务器传递的是密码或其他的敏感信息,请不要使用 GET 方法。
GET 方法有大小限制:请求字符串中最多只能有 1024 个字符。
4.2 POST 方法
另一个向后台程序传递信息的比较可靠的方法是 POST 方法。POST 方法打包信息的方式与 GET 方法基本相同,但是 POST 方法不是把信息作为 URL 中字符后的文本字符串进行发送,而是把这些信息作为一个单独的消息。消息以标准输出的形式传到后台程序,您可以解析和使用这些标准输出。
Servlet 使用 doPost() 方法处理这种类型的请求。
4.3 Servlet 读取表单数据
Servlet 处理表单数据,这些数据会根据不同的情况使用不同的方法自动解析:
- getParameter():您可以调用 request.getParameter() 方法来获取表单参数的值。
- getParameterValues():如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。
- getParameterNames():如果您想要得到当前请求中的所有参数的完整列表,则调用该方法。
读取所有的表单参数
以下是通用的实例,使用 HttpServletRequest 的 getParameterNames() 方法读取所有可用的表单参数。该方法返回一个枚举,其中包含未指定顺序的参数名。
一旦我们有一个枚举,我们可以以标准方式循环枚举,使用 hasMoreElements() 方法来确定何时停止,使用 nextElement() 方法来获取每个参数的名称。
4.4 AJAX:允许跨域请求
//允许所有IP地址和端口请求
response.setHeader("Access-Control-Allow-Origin", "*");
//允许所有的文档类型请求
response.setHeader("Access-Control-Content-Type", "*");
5. cookie学习
问题:
HTTP 协议是没有记忆功能的,一次请求结束后,相关数据会被销毁。如果第二次的请求需要使用相同的请求数据怎么办呢? 难道是让用户再次请求书写吗?
解决:使用Cookie 技术解释:
Cookie 技术其实是浏览器端的数据存储技术,解决了不同请求需要使用相同的请求数据的问题。我们把请求需要共享的请求数据,存储在浏览器端,避免用户进行重复的书写请求数据。但是哪些数据需要使用Cookie 技术存储起来是一个主观问题,需要在后台进行响应的时候来告诉浏览器,有些数据其他请求还会使用,需要存储起来。
特点:
- 浏览器端的数据存储技术
- 适合少量数据键值对
第1次请求加响应
- 请求:客户端 ---》 服务器
- 响应:服务器 ---》响应内容包含(set-cookie:userType-》VIP)
第2次请求
- 请求:客户端(浏览器判断是否有有效期内的cookie)将cookie发送给到 ---》 服务器
- 响应:服务器获取cookie,判断是否是vip用户 ---》相应内容给到客户端(并且可以添加新cookie或者修改原来的cookie)
5.1 Cookie 数据存储
临时存储:不设置cookie 信息的存储时间,周期为一次会话, 存储在浏览器内存中
定时存储:设置存储时间,周期为时间设置,存储在用户电脑中。
Servlet Cookie 处理
Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息。Java Servlet 显然支持 HTTP Cookie。
识别返回用户包括三个步骤:
- 服务器脚本向浏览器发送一组 Cookie。例如:姓名、年龄或识别号码等。
- 浏览器将这些信息存储在本地计算机上,以备将来使用。
- 当下一次浏览器向 Web 服务器发送任何请求时,浏览器会把这些 Cookie 信息发送到服务器,服务器将使用这些信息来识别用户。
Servlet Cookie 处理需要对中文进行编码与解码,方法如下:
String str = java.net.URLEncoder.encode("中文","UTF-8"); //编码
String str = java.net.URLDecoder.decode("编码后的字符串","UTF-8");// 解码
Javascript
encodeURI() //路径编码函数
decodeURI() //路径解码函数
5.2 Cookie 剖析
Cookie 通常设置在 HTTP 头信息中(虽然 JavaScript 也可以直接在浏览器上设置一个 Cookie)。设置 Cookie 的 Servlet 会发送如下的头信息:
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT;
path=/; domain=m.baidu.com
Connection: close
Content-Type: text/html
Set-Cookie 头包含了一个名称值对、一个 GMT 日期、一个路径和一个域。名称和值会被 URL 编码。expires 字段是一个指令,告诉浏览器在给定的时间和日期之后"忘记"该 Cookie。
果浏览器被配置为存储 Cookie,它将会保留此信息直到到期日期。如果用户的浏览器指向任何匹配该 Cookie 的路径和域的页面,它会重新发送 Cookie 到服务器。浏览器的头信息可能如下所示:
GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz
Servlet 就能够通过请求方法 request.getCookies() 访问 Cookie,该方法将返回一个 Cookie 对象的数组。
Servlet Cookie 方法
以下是在 Servlet 中操作 Cookie 时可使用的有用的方法列表。
方法 & 描述
- public void setMaxAge(int expiry)
- 该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。
- public int getMaxAge()
- 该方法返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示,没有设定值。
- public String getName()
- 该方法返回 cookie 的名称。名称在创建后不能改变。
- public void setValue(String newValue)
- 该方法设置与 cookie 关联的值。
- public String getValue()
- 该方法获取与 cookie 关联的值。
- public void setSecure(boolean flag)
- 该方法设置布尔值,表示 cookie 是否应该只在加密的(即 SSL)连接上发送。
- public void setComment(String purpose)
- 设置cookie的注释。该注释在浏览器向用户呈现 cookie 时非常有用。
- public String getComment()
- 获取 cookie 的注释,如果 cookie 没有注释则返回 null。
5.4 通过 Servlet 设置 Cookie
通过 Servlet 设置 Cookie 包括三个步骤:
(1) 创建一个 Cookie 对象:您可以调用带有 cookie 名称和 cookie 值的 Cookie 构造函数,cookie 名称和 cookie 值都是字符串。
Cookie cookie = new Cookie("key","value");
- 请记住,无论是名字还是值,都不应该包含空格或以下任何字符:
- [ ] ( ) = , " / ? @ : ;
(2) 设置最大生存周期:您可以使用 setMaxAge 方法来指定 cookie 能够保持有效的时间(以秒为单位)。下面将设置一个最长有效期为 24 小时的 cookie。
cookie.setMaxAge(60*60*24);
(3) 发送 Cookie 到 HTTP 响应头:您可以使用 response.addCookie 来添加 HTTP 响应头中的 Cookie,如下所示:
response.addCookie(cookie);
5.5 通过 Servlet 读取 Cookie
要读取 Cookie,您需要通过调用 HttpServletRequest 的 getCookies( ) 方法创建一个 javax.servlet.http.Cookie 对象的数组。然后循环遍历数组,并使用 getName() 和 getValue() 方法来访问每个 cookie 和关联的值
5.6 通过 Servlet 删除 Cookie
删除 Cookie 是非常简单的。如果您想删除一个 cookie,那么您只需要按照以下三个步骤进行:
- 读取一个现有的 cookie,并把它存储在 Cookie 对象中。
- 使用 setMaxAge() 方法设置 cookie 的年龄为零,来删除现有的 cookie。
- 把这个 cookie 添加到响应头。