第一节 Servlet概述
1.1 什么是Servlet
Servlet 是Java Server Applet的简称,称为小服务器程序,用Java编写的服务器端程序,主要功能交互式地浏览和修改数据,生成动态Web内容。
Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
Servlet编程需要使用到javax.servlet 和 javax.servlet.http两个包下面的类和接口,在所有的类和接口中,javax.servlet.Servlet 接口最为重要。所有的servlet程序都必须实现该接口或者继承实现了该接口的类。javax.servlet.ServletConfig;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.http.HttpSession;
javax.servlet.http.Cookie;
1.2 Servlet入门
-
在src创建package
-
选中刚刚创建的包,右键–>New–>Servlet
-
第一个Servlet代码如下:
/**
*第一个Servlet程序
*/
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;/** * @see 构造函数 */ public HelloServlet() { super(); // TODO Auto-generated constructor stub } /** * @see 处理Get请求 */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 响应内容到浏览器 response.getWriter().print("Hello Word");; } /** * @see 处理Post请求 */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
-
发布右键–>Run As–>Run On Server
-
浏览器输入网址访问:http://localhost:8080/项目名称/HelloServlet
1.3 常见错误解决方法
(1)HTTP Status 404 资源找不到
解决方法:查看Tomcat的webapps目录下找到当前项目在WEB-INF下的classes内能否找到刚刚的class文件
如果有,重新启动Tomcat
如果没有,在Eclipse中选择Project-->clean让Eclipse清空缓存并重新构建项目,再次运行
idea中,把out目录的内容删除,然后重新运行。
(2)serlvet地址配置重复
(3)serlvet地址配置错误,比如没有写/ Invalid <url-pattern>
1.4 HTTP协议
1.4.1 什么是HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。
HTTP协议的主要特点如下:
1.支持客户端/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
1.4.2 Http协议的通信
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
1、 建立TCP连接
在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能进行更高层协议的连接。因此,首先要建立TCP连接,一般TCP连接的端口号是80
2、 浏览器向Web服务器发送请求命令
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令
例如:GET /sample/hello.html HTTP/1.1
3、 浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4、 Web服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答,
HTTP/1.1 200 OK
应答的第一部分是协议的版本号和应答状态码
5、 Web服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6、 Web服务器向浏览器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
7、 Web服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽
1.4.3 请求和响应数据格式
HTTP请求报文
当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息(请求报文),HTTP请求信息由4部分组成:
1 请求行 请求方法/地址 URI协议/版本
2 请求头(Request Header)
3 空行
4 请求正文
下面是一个HTTP请求的例子:
POST /hello HTTP/1.1
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language:zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4
Connection:Keep-Alive
Host:localhost:8080
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept-Encoding:gzip, deflate, br
username=zhangsan&age=20&add=beijing
1、请求方法 URI 协议/版本
请求的第一行是“方法URL议/版本”:GET/hello HTTP/1.1
以上代码中“GET”代表请求方法,“/hello”表示URI,“HTTP/1.1代表协议和协议的版本。
根据HTTP标准,HTTP请求可以使用多种请求方法。例如:HTTP1.1支持7种请求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。在Internet应用中,最常用的方法是GET和POST。
URL完整地指定了要访问的网络资源,通常只要给出相对于服务器的根目录的相对目录即可,因此总是以“/”开头,最后,协议版本声明了通信过程中使用HTTP的版本。
2、请求头(Request Header)
请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language:zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4
Connection:Keep-Alive
Host:localhost
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept-Encoding:gzip, deflate, br
3 空行
4、请求正文
请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的查询字符串信息:
name=zhangsan
HTTP响应报文
HTTP应答与HTTP请求相似,HTTP响应也由4个部分构成,分别是:
1、状态行
2、响应头(Response Header)
3、空行
4、响应正文
HTTP/1.1 200 OK //状态行
Server: nginx
Date: Tue, 31 May 2016 02:09:24 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With,access_token,access-token,content-type,multipart/form-data,application/x-www-form-urlencoded
Access-Control-Allow-Methods: GET,POST,OPTIONS
Content-Length: 49
<!DOCTYPE html> //正文
<html>
<head>
<title>网页标题</title>
<meta charset="utf-8">
</head>
<body>
网页内容
</body>
</html>
(1)状态行
由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。
状态代码:
状态代码由3位数字组成,表示请求是否被理解或被满足。
状态描述:
状态描述给出了关于状态代码的简短的文字描述。
状态代码的第一个数字定义了响应的类别,后面两位没有具体的分类。
第一个数字有五种可能的取值:
- 1xx: 指示信息—表示请求已接收,继续处理。
- 2xx: 成功—表示请求已经被成功接收、理解、接受。
- 3xx: 重定向—要完成请求必须进行更进一步的操作。
- 4xx: 客户端错误—请求有语法错误或请求无法实现。
- 5xx: 服务器端错误—服务器未能实现合法的请求。
状态代码 状态描述 说明
200 OK 客户端请求成功
301 永久重定向
302 临时重定向
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
401 Unauthonzed 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
404 Not Found 请求的资源不存在,例如,输入了错误的URL。
500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常
(2)响应头
响应头可能包括:
Location:
Location响应报头域用于重定向接受者到一个新的位置。例如:客户端所请求的页面已不存在原先的位置,为了让客户端重定向到这个页面新的位置,服务 器端可以发回Location响应报头后使用重定向语句,让客户端去访问新的域名所对应的服务器上的资源。当我们在JSP中使用重定向语句的时候,服务器 端向客户端发回的响应报头中,就会有Location响应报头域。
Server:
Server响应报头域包含了服务器用来处理请求的软件信息。它和User-Agent请求报头域是相对应的,前者发送服务器端软件的信息,后者发送客户 端软件(浏览器)和操作系统的信息。下面是Server响应报头域的一个例子:Server: Apache-Coyote/1.1
WWW-Authenticate:
WWW-Authenticate响应报头域必须被包含在401(未授权的)响应消息中,这个报头域和前面讲到的Authorization请求报头域是 相关的,当客户端收到401响应消息,就要决定是否请求服务器对其进行验证。如果要求服务器对其进行验证,就可以发送一个包含了 Authorization报头域的请求,下面是WWW-Authenticate响应报头域的一个例子:WWW-Authenticate: Basic realm="Basic Auth Test!"
从这个响应报头域,可以知道服务器端对我们所请求的资源采用的是基本验证机制。
Content-Encoding:
Content-Encoding实体报头域被使用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容编码,因而要获得Content- Type报头域中所引用的媒体类型,必须采用相应的解码机制。Content-Encoding主要用语记录文档的压缩方法,下面是它的一个例子: Content-Encoding: gzip。如果一个实体正文采用了编码方式存储,在使用之前就必须进行解码。
Content-Language:
Content-Language实体报头域描述了资源所用的自然语言。Content-Language允许用户遵照自身的首选语言来识别和区分实体。 如果这个实体内容仅仅打算提供给丹麦的阅读者,那么可以按照如下的方式设置这个实体报头域:Content-Language: da。
如果没有指定Content-Language报头域,那么实体内容将提供给所以语言的阅读者。
Content-Length:
Content-Length实体报头域用于指明正文的长度,以字节方式存储的十进制数字来表示,也就是一个数字字符占一个字节,用其对应的ASCII码存储传输。
要注意的是:这个长度仅仅是表示实体正文的长度,没有包括实体报头的长度。
Content-Type :
Content-Type实体报头域用语指明发送给接收者的实体正文的媒体类型。例如:
Content-Type: text/html;charset=utf-8
Content-Type: text/html;charset=GBK
Last-Modified :
Last-Modified实体报头域用于指示资源最后的修改日期及时间。
Expires :
Expires实体报头域给出响应过期的日期和时间。通常,代理服务器或浏览器会缓存一些页面。当用户再次访问这些页面时,直接从缓存中加载并显示给用 户,这样缩短了响应的时间,减少服务器的负载。为了让代理服务器或浏览器在一段时间后更新页面,我们可以使用Expires实体报头域指定页面过期的时 间。当用户又一次访问页面时,如果Expires报头域给出的日期和时间比Date普通报头域给出的日期和时间要早(或相同),那么代理服务器或浏览器就 不会再使用缓存的页面而是从服务器上请求更新的页面。不过要注意,即使页面过期了,也并不意味着服务器上的原始资源在此时间之前或之后发生了改变。
Expires实体报头域使用的日期和时间必须是RFC 1123中的日期格式,例如:
Expires: Thu, 15 Sep 2005 16:00:00 GMT
HTTP1.1的客户端和缓存必须将其他非法的日期格式(也包括0)看作已过期。例如,为了让浏览器不要缓存页面,我们也可以利用Expires实体报头 域,设置它的值为0,如下(JSP):response.setDateHeader("Expires",0);
第二节 Servlet使用
2.1 Servlet核心接口和类
Servlet接口
在ServletAPI中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。
该接口包括以下五个方法:
init(ServletConfig config)
ServletConfig getServletConfig()
service(ServletRequest req,ServletResponse res)
String getServletInfo()
destroy( )
处理方式:
(1)第一次访问Servlet时,服务器会创建Servlet对象,并调用init方法,再调用service方法
(2)第二次再访问时,Servlet对象已经存在,不再创建,执行service方法
(3)当服务器停止,会释放Servlet,调用destroy方法。
案例:使用Servlet接口
package com.qf.web.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
/**
* @author wgy 2018/11/19 11:53
* @version 1.0
* 使用Servlete接口
*/
@WebServlet(name = "MyServler4",value = "/myservlet4")
public class MyServlet4 implements Servlet {
//初始化servlet
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("初始化servlet-----------init------"+this.hashCode());
}
//获取Servlet配置
@Override
public ServletConfig getServletConfig() {
System.out.println("获取Servlet配置------------getServletConfig----"+this.hashCode());
return null;
}
//服务
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("服务方法---------------service--------"+this.hashCode());
}
//获取servlet基本信息
@Override
public String getServletInfo() {
System.out.println("获取servlet基本信息----------------getServletInfo");
return null;
}
//销毁
@Override
public void destroy() {
System.out.println("------销毁----------destroy---------"+this.hashCode());
}
}
GenericServlet抽象类
GenericServlet 使编写 servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单实现,要编写一般的 servlet,只需重写抽象 service 方法即可。
HttpServlet类
是继承GenericServlet的基础上进一步的扩展。
提供将要被子类化以创建适用于 Web 站点的 HTTP servlet 的抽象类。HttpServlet 的子类至少必须重写一个方法,该方法通常是以下这些方法之一:
doGet,如果 servlet 支持 HTTP GET 请求
doPost,用于 HTTP POST 请求
doPut,用于 HTTP PUT 请求
doDelete,用于 HTTP DELETE 请求
init 和 destroy,用于管理 servlet 的生命周期内保存的资源
getServletInfo,servlet 使用它提供有关其自身的信息
2.2 Servlet的两种创建方式
Servlet的第一种创建方式:继承HttpServlet
/**
* Servlet implementation class HelloServlet
* 演示Servlet的第一种创建方式,继承HttpServlet.也是开发中推荐的
*
*/
@WebServlet("/hs1")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("我是Servlet创建的第一种方式");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
Servlet创建的第二种方式:实现接口Servlet
/**
* Servlet创建的第二种方式:实现接口Servlet
* */
@WebServlet("/hs2")
public class HelloServlet2 implements Servlet{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("OK");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("我是第二种创建方式");
}
}
2.3 Servlet的两种配置方式
第一种注解式配置 Servlet3.0及以后 :
/**
* Servlet implementation class HelloServlet
* 演示Servlet注解式配置
*/
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("OK");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
使用注解方式:
注解类 WebServlet
name:serlvet名字 (可选)
value: 配置url路径
urlPatterns:配置url路径 ,和value作用一样,不能同时使用
loadOnStartup:配置Servlet的创建的时机, 如果是0或者正数 启动程序时创建,如果是负数,则访问时创建。
数子越小优先级越高。
initParams:配置Servlet的初始化参数
第二种web.xml配置 Servlet所有版本都支持:
/**
* Servlet implementation class HelloServlet
* 演示Servlet的web.xml配置
*/
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("OK");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>Web_Day11</display-name>
<!--Servlet的第二种配置 -->
<!--Servlet配置 -->
<servlet>
<!--名称 -->
<servlet-name>hello2</servlet-name>
<!--Servlet的全称类名 -->
<servlet-class>com.qf.web.servlet.HelloServlet</servlet-class>
<!--启动的优先级,数字越小越先起作用 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--映射配置 -->
<servlet-mapping>
<!--名称 -->
<servlet-name>hello2</servlet-name>
<!--资源的匹配规则:精确匹配 -->
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
</web-app>
容器在进行url-pattern配置的时候是遵循一定的匹配原则的
url-pattern定义匹配规则,取值说明:
精确匹配 /具体的名称 只有url路径是具体的名称的时候才会触发Servlet
后缀匹配 *.xxx 只要是以xxx结尾的就匹配触发Servlet
通配符匹配 /* 匹配所有请求,包含服务器的所有资源
通配符匹配 / 匹配所有请求,包含服务器的所有资源,不包括.jsp
load-on-startup
1元素标记容器是否应该在web应用程序启动的时候就加载这个servlet。
2它的值必须是一个整数,表示servlet被加载的先后顺序。
3如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载。
4如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。
<init-param>
<param-name>name</param-name>
<param-value>张三</param-value>
</init-param>
1 init-param元素用来定义Servlet启动的参数,可以定义多个
2 param-name表示参数名称
3 param-value表示参数值
2.4 Servlet生命周期
2.4.1 什么是生命周期
生命周期也就是生命历程,就像人都是从怀胎–>出生–>婴儿–>儿童–>少年–>成年–>中年–>老年–>死亡
2.4.2 生命周期的四个阶段
阶段一、实例化(调用构造方法)
实例化阶段是Servlet生命周期中的第一步,由Servlet容器调用Servlet的构造器创建一个具体的Servlet对象的过程。而这个创建的时机可以是在容器收到针对这个组件的请求之后,即用了才创建;也可以在容器启动之后立刻创建实例,而不管此时Servlet是否使用的上。使用如下代码可以设置Servlet是否在服务器启动时就执行创建
<load-on-startup>1</load-on-startup>
阶段二、初始化(init方法)
Servlet在被加载实例化之后,必须要初始化它。在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。ServletConfig对象由Servlet引擎负责创建,从中可以读取到事先在web.xml文件中通过<init-param>节点配置的多个name-value名值对。ServletConfig对象还可以让Servlet接受一个ServletContext对象。
一般情况下,init方法不需要编写,因GenericServlet已经提供了init方法的实现,并且提供了getServletConfig方法来获得ServletConfig对象。
注:init方法只被执行一次
阶段三、就绪/服务
Servlet被初始化以后就处于能够响应请求的就绪状态。每个对Servlet的请求由一个ServletRequest对象代表,Servlet给客户端的响应由一个ServletResponse对象代表。当客户端有一个请求时,容器就会将请求与响应对象转给Servlet,以参数的形式传给service方法。service方法由javax.servlet.Servlet定义,由具体的Servlet实现
HttpServlet将service方法拆分了。doGet和doPost
阶段四、销毁
Servlet容器在销毁Servlet对象时会调用destroy方法来释放资源。通常情况下Servlet容器停止或者重新启动都会引起销毁Servlet对象的动作,但除此之外,Servlet容器也有自身管理Servlet对象的准则,整个生命周期并不需要人为进行干预
Servlet代码如下:
/**
* Servlet implementation class LifeServlet
* 演示Servlet的生命周期:
* 1、实例化
* 2、init:初始化
* 3、service:服务
* 4、destory:销毁
*/
@WebServlet("/LifeServlet")
public class LifeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LifeServlet() {
super();
System.out.println("1、完成了实例化");
// TODO Auto-generated constructor stub
}
@Override
public void init() throws ServletException {
// TODO Auto-generated method stub
super.init();
System.out.println("2、完成了初始化");
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("3、就绪中");
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
super.destroy();
System.out.println("4、销毁了");
}
}
2.5 获取请求参数
html页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎页面</title>
</head>
<body>
<h1>欢迎你</h1>
<div>
<form action="HelloServlet" method="post">
<label>姓名:</label><input name="name"><br/>
<label>年龄:</label><input name="age"><br/>
<input type="submit" value="提交">
</form>
</div>
</body>
</html>
Servlet代码:
/**
* Servlet implementation class HelloServlet
* 演示Servlet的获取请求参数
*
*/
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取表单提交的姓名
String name=request.getParameter("name");
//获取年龄
String age=request.getParameter("age");
//服务端输出打印
System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2.6 请求方式
默认的请求方式是GET请求
2.6.1 GET请求
GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
GET提交的数据大小有限制(因为浏览器对URL的长度有限制)
GET方式提交数据,会带来安全问题
效率高
对应的Servlet的方法是doGet
2.6.2 POST请求
POST方法是把提交的数据放在HTTP包的Body中
POST方法提交的数据没有限制
POST提交的数据相对安全
效率相对没有GET高
对应的Servlet的方法是doPost
2.7 如何处理中文参数
2.7.1 为什么表单中会产生中文乱码
产生乱码,就是因为服务器和客户端沟通的编码不一致造成的,因此解决的办法是:在客户端和服务器之间设置一个统一的编码,之后就按照此编码进行数据的传输和接收
2.7.2 GET中文乱码
在Tomcat7及以下
客户端以UTF-8的编码传输数据到服务器端,而服务器端的request对象使用的是ISO8859-1这个字符编码来接收数据,服务器和客户端沟通的编码不一致因此才会产生中文乱码的。解决办法:在接收到数据后,先获取request对象以ISO8859-1字符编码接收到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题。
Tomcat8的版本中GET基本就不会乱码了,因为服务器对url的编码格式可以进行自动转换
/**
* Servlet implementation class HelloServlet
* 演示Servlet的GET请求,中文乱码的问题
*
*/
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置请求参数的编码格式--对GET无效
request.setCharacterEncoding("UTF-8");
//获取表单提交的信息
String name=request.getParameter("msg");
//服务端输出打印
System.out.println(request.getRemoteAddr()+"发来信息:"+msg);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2.7.3 POST乱码
由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器也需要设置以UTF-8字符编码进行接收,要想完成此操作,服务器可以直接使用从ServletRequest接口继承而来的"setCharacterEncoding(charset)"方法进行统一的编码设置。
解决POST中文乱码代码如下:
/**
* Servlet implementation class HelloServlet
* 演示Servlet的GET请求,中文乱码的问题
*
*/
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置请求参数的编码格式--对GET无效
request.setCharacterEncoding("UTF-8");
//获取表单提交的信息
String name=request.getParameter("msg");
//服务端输出打印
System.out.println(request.getRemoteAddr()+"发来信息:"+msg);
}
}
2.8 Servlet输出中文内容
2.8.1 页面返回乱码原因
浏览器识别不到返回的中文是什么编码格式,就会默认使用GB2312,如果返回的是UTF-8格式的那么在浏览器上就会显示乱码的问题
2.8.2 如何解决内容中的乱码
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");//输出一个完整的网页
2.9 Servlet线程安全问题
2.9.1 线程安全问题
因为每次请求都会创建一个线程,如果多人同时请求,那么就会存在多个线程操作同一个Servlet对象,那么如果在对应的方法中操作了成员变量,就有可能产生线程安全的问题。
2.9.2 如何保证线程安全
1、synchronized
将存在线程安全问题的代码放到同步代码块中
2、实现SingleThreadModel接口
servlet实现SingleThreadModel接口后,每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端请求的效率太低,所以已经淘汰。
3、尽可能只使用局部变量
2.10 综合案例
实现注册信息的提交
页面:register.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<h1>用户注册</h1>
<form action="/myxiaomi/registerservlet" method="post">
<table>
<tr>
<td>用户名:</td>
<td>
<input type="text" name="username">
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="password" name="pwd">
</td>
</tr>
<tr>
<td>确认密码:</td>
<td>
<input type="password" name="repwd">
</td>
</tr>
<tr>
<td>邮箱:</td>
<td>
<input type="email" name="email">
</td>
</tr>
<tr>
<td>性别</td>
<td>
<input type="radio" name="gender" value="男" checked="checked">男
<input type="radio" name="gender" value="女">女
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
<input type="reset" value="重置">
</td>
</tr>
</table>
</form>
</body>
</html>
Servlet:
RegisterServlet.java(获取参数 给数据库里的表赋值)
package com.qf.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.codec.binary.StringUtils;
import com.qf.utils.ActiveCodeUtils;
@WebServlet("/registerservlet")
public class RegisterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public RegisterServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//注册
//1编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//2获取数据
String username=request.getParameter("username");
String pwd=request.getParameter("pwd");
String repwd=request.getParameter("repwd");
String email=request.getParameter("email");
String gender=request.getParameter("gender");
//3验证数据
PrintWriter out = response.getWriter();
if(username==null||username.trim().equals("")) {
out.write("用户不能为空");
return;
}
if(pwd==null||pwd.trim().equals("")) {
out.write("密码不能为空");
return;
}
if(!pwd.equals(repwd)) {
out.write("两次密码不一样");
return;
}
//4保存数据库 后边封装起来
Connection connection=null;
PreparedStatement pstat=null;
try {
//4.1注册驱动
Class.forName("com.mysql.jdbc.Driver");
//4.2获取连接
connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/db_shopping", "root", "root");
//4.3创建命令
pstat=connection.prepareStatement("insert into tb_user(username,password,email,gender,flag,role,code) values(?,?,?,?,?,?,?)");
//4.4设置参数
pstat.setString(1, username);
pstat.setString(2, pwd);
pstat.setString(3, email);
pstat.setString(4, gender);
pstat.setInt(5, 0);
pstat.setInt(6, 1);
pstat.setString(7, ActiveCodeUtils.createActiveCode());
//5执行
int result=pstat.executeUpdate();
if(result>0) {
out.write("注册成功");
}else {
out.write("注册失败");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
out.write("注册失败");
}finally {
if(connection!=null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(pstat!=null) {
try {
pstat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
工具类
package com.qf.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
/**
* 激活码工具类
* @author wgy
*
*/
public class ActiveCodeUtils {
public static String createActiveCode() {
Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmssSSS");
String s1=sdf.format(date);
String s2=Integer.toHexString(new Random().nextInt(900)+100);
return s1+s2;
}
}
总结
1 什么是Servlet:小服务器程序,用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。
2 创建Servlet
2.1 继承HttpServlet
2.2 实现Servlet接口
3 配置Servlet
3.1注解 WebServlet
3.2web.xml文件配置
urlpatterns
/xxxx
*.xx
/*
/
load-on-startup 默认-1 0或整数
intparam
4 servlet生命周期
4.1实例化
4.2初始化 init方法
4.3服务 service方法
4.4 销毁 destroy
4 接受请求参数
request.setCharacterEncoding(“utf-8”);
requset.getParameter(“username”);
5 响应数据
response.setContentType(“text/html;charset=utf-8”);
PrintWriter out=response.getWriter();
out.println(“xxxxx”);
6综合案例