Servlet
概述
1. 什么是Servlet?
- Servlet是一个接口,是JavaEE的规范之一
- Servlet是JavaWeb的三大组件之一,三大组件分别为:Servlet程序、Filter过滤器、Listener监听器
- Servlet是运行在服务器上的一个Java程序,它可以接受客户端发送的请求,并响应数据给客户端
2. 如何实现Servlet程序?
-
编写一个类实现Servlet接口
-
实现service方法,处理请求并响应数据
-
在web.xml中配置servlet程序的访问地址,并可以配置初始化参数,初始化参数可以通过servletConfig对象获取
注:ServletConfig类是Servlet程序的配置信息类,有三个作用:获取Servlet程序的别名servlet-name的值;获取初始化参数init-param;获取ServletContext对象
Servlet程序示例:
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//1. 可以获取servlet程序的别名servlet-name值
System.out.println(servletConfig.getServletName());
//2. 获取初始化参数init-param
System.out.println(servletConfig.getInitParameter("username"));
System.out.println(servletConfig.getInitParameter("url"));
//3. 获取ServletContext对象
System.out.println(servletConfig.getServletContext());
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("HelloServlet被访问了");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
web.xml中的配置:
<!--servlet标签给Tomcat配置servlet程序-->
<servlet>
<!--servlet-name标签:给servlet程序起一个别名(一般是类名)-->
<servlet-name>HelloServlet</servlet-name>
<!--servlet-class标签:servlet程序的全类名-->
<servlet-class>com.th1024.servlet.HelloServlet</servlet-class>
<!--init-param:初始化参数-->
<init-param>
<!--param-name:参数名-->
<param-name>username</param-name>
<!--param-value:参数值-->
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</init-param>
</servlet>
<!--servlet-mapping标签:给servlet程序配置访问地址-->
<servlet-mapping>
<!--servlet-name标签:当前配置的标签给名为标签内容的servlet程序使用-->
<servlet-name>HelloServlet</servlet-name>
<!--url-pattern标签:配置访问地址
/ 斜杠在服务器解析时,表示地址为:http://ip:port/工程路径/
/hello 表示地址为http://ip:port/工程路径/hello-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
常见错误:
- url-pattern中配置的路径没有以斜杠打头
- servlet-name配置的值不存在
- servlet-class的全类名配置错误
3. url到Servlet程序的访问
客户端发送请求,比如http://localhost:8080/06_servlet/hello至服务器,服务器解析之后调用servlet程序完成特定功能,具体流程如图
4. Servlet的生命周期
- 工程启动,调用servlet程序
- 执行servlet构造器方法
- 执行init初始化方法
- 初始化完成
- 每次访问调用service方法
- 工程停止,在停止之前调用destroy方法,销毁servlet程序
5. 通过继承HttpServlet来实现Servlet程序
一般在实际开发中,都是使用继承HttpServlet类的方式实现servlet程序
- 编写一个类继承HttpServlet
- 根据业务需求重写doGet和doPost方法,实现GET请求和POST请求的分发处理
- 在web.xml中配置servlet程序的访问地址
servlet程序:
public class HelloServlet2 extends HttpServlet {
@Override
public void init() throws ServletException {
super.init();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloServlet2的doGet方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloServlet2的doPost方法");
}
}
web.xml中的配置:
<servlet>
<servlet-name>HelloServlet2</servlet-name>
<servlet-class>com.th1024.servlet.HelloServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet2</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
6. servlet类的继承关系
Servlet接口,定义了Servlet程序的访问规范
GenericServlet类做了Servlet接口的很多空实现,维护了SevletConfig类的一些使用
HttpServlet类实现了service()方法,并对请求进行了分发处理
自定义的Servlet程序只需要继承HttpServlet,根据业务需要重写doGet或者doPost方法
ServletContext类
1. 什么是ServletContext类?
- ServletContext是一个接口,它表示Servlet上下文对象
- 一个web工程,只有一个ServletContext对象实例
- ServletContext对象是一个域对象
- ServletContext在web工程部署启动的时候创建,在web工程停止的时候销毁
什么是域对象?
域对象是指可以像map一样存取数据的对象,这里的域指的是存取数据的操作范围,即整个web工程
2. ServletContext类的四个作用
- 获取web.xml中配置的上下文参数context-param
- 获取当前的工程路径
- 获取工程部署在服务器硬盘上的绝对路径
- 存取数据
ServletContext演示:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取ServletContext对象
ServletContext context = getServletConfig().getServletContext();
//1. 获取web.xml配置的上下文参数context-param
String username = context.getInitParameter("username");
String password = context.getInitParameter("password");
System.out.println(username + ":" + password);
//2. 获取当前的工程路径,格式:/工程路径
System.out.println(context.getContextPath());
//3. 获取工程部署后在服务器硬盘上的绝对路径
/*
/ 斜杠被服务器解析为:http://ip:port/工程名/ 映射到idea代码的web目录
*/
System.out.println(context.getRealPath("/"));
}
web.xml中的配置:
<!--context-param是上下文参数(它属于整个web工程)-->
<context-param>
<param-name>username</param-name>
<param-value>context</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>
存取数据:
ContextServlet1
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取ServletContext对象
ServletContext context = getServletContext();
System.out.println("保存之前key1的值:" + context.getAttribute("key1"));
context.setAttribute("key1","value1");
System.out.println("保存之后域数据key1的值:" + context.getAttribute("key1"));
}
ContextServlet2
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
System.out.println("Context2获取域数据key1:" + context.getAttribute("key1"));
}
HTTP协议
1. 什么是HTTP协议
超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应;HTTP协议中的数据又称报文
2. 请求的HTTP协议格式
请求分为GET请求和POST请求两种
-
GET请求
请求行
(1)请求的方式 GET
(2)请求的资源路径【+?+请求参数】
(3)请求的协议的版本号 HTTP/1.1
请求头
key:value 不同的键值对,表示不同的含义
-
POST请求
请求行
(1)请求的方式 POST
(2)请求的资源路径【+?+请求参数】
(3)请求的协议的版本号 HTTP/1.1
请求头
key:value 不同的键值对,表示不同的含义
空行
请求体 发送给服务器的数据
常用请求头说明
Accept:客户端可以接收的数据类型
Accept-Languge:客户端可以接收的语言类型
User-Agent:客户端浏览器的信息
Host:请求时的服务器ip和端口号
常见的GET请求:
- form标签,method=get
- a标签
- link标签引入css
- script标签引入js文件
- img标签引入图片
- iframe标签引入html页面
- 在浏览器地址栏中输入地址后敲回车
常见的POST请求:
- form标签,method=post
3. 响应的HTTP协议格式
响应行
(1)响应的协议和版本号
(2)响应状态码
(3)响应状态描述符
响应头
key:value 不同的响应头,有不同的含义
空行
响应体 回传给客户端的数据
常见的响应码:
200 请求成功
302 请求重定向
404 服务器收到请求,请求的资源不存在(请求地址错误)
500 服务器收到请求,内部发生错误(代码错误)
HttpServletRequest类
1. 什么是HttpServletRequest?
HttpServletRequest类继承自ServletRequest,客户端发出的请求被封装成为一个HttpServletRequest对象,其中包含了客户端请求信息包括请求的地址,请求的参数,提交的数据,上传的文件客户端ip甚至客户端操作系统
2. HttpServletRequest类的作用
当请求发送到服务器之后,服务器就会将请求的HTTP协议信息解析好封装到HttpServletRequest对象中,然后传递到service()方法(doGet和doPost)中供我们使用;在程序中可以通过HttpServletRequest对象获取所有请求的信息
3. HttpServletRequest类的常用方法
- getRequestURI() 获取请求的资源路径
- getRequestURL() 获取请求的统一资源定位符(绝对路径)
- getRemoteHost() 获取客户端的ip地址
- getHeader() 获取请求头
- getParameter() 获取请求的参数
- getParameterValues() 获取请求的参数(多个值的时候使用)
- getMethod() 获取请求的方式GET或POST
- setAttribute(key,value) 设置域数据
- getAttribute(key) 获取域数据
- getRequestDispatcher() 获取请求转发对象
4. 获取请求参数
表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/07_servlet/parameterServlet" method="get">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
兴趣爱好:<input type="checkbox" name="hobby" value="Java">Java
<input type="checkbox" name="hobby" value="C">C
<input type="checkbox" name="hobby" value="C++">C++<br/>
<input type="submit">
</form>
</body>
</html>
Java代码:
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("-----------doget-----------");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.asList(hobbies));
}
}
POST请求的中文乱码问题解决:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("-----------dopost-----------");
//设置请求体的字符集为UTF-8,解决post请求中文乱码问题
req.setCharacterEncoding("UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.asList(hobbies));
}
5. 请求转发
服务器收到请求后,从一个资源跳转到另一个资源的操作叫请求转发
示例:发送请求到Servlet1,转发到Servlet2
Servlet1:
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求的参数
String username = req.getParameter("username");
System.out.println("Servlet1:" + username);
//添加域数据
req.setAttribute("key","value");
//请求转发至Servlet2
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
requestDispatcher.forward(req,resp);
}
}
Servlet2:
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求参数
String username = req.getParameter("username");
System.out.println("Servlet2:" + username);
//查看域数据
Object key = req.getAttribute("key");
System.out.println(key);
//处理业务
System.out.println("Servlet2处理业务");
}
}
请求转发的特点:
- 浏览器地址栏不发生变化
- 整个过程只有一次请求
- 共享Request域中的数据
- 可以转发到WEB-INF目录下的资源
- 不可以访问工程以外的资源
6. 相对路径和绝对路径
在JavaWeb中,路径分为绝对路径和相对路径
绝对路径:http://ip:port/工程路径/资源路径
相对路径:
. 表示当前目录
.. 表示上一级目录
资源名 表示当前目录/资源名
实际开发中,路径都使用绝对路径,而不简单地使用相对路径(base标签+相对路径)
在web中,/ 斜杠 是一种绝对路径
/ 斜杠 如果被浏览器解析,得到的地址是:http://ip:port/
<a href="/">斜杠</a>
/ 斜杠 如果被服务器解析,得到的地址是:http://ip:port/工程路径
1. <url-pattern>/servlet1</url-pattern>
2. servletContext.getRealPath("/");
3. request.getRequestDispatcher("/");
特殊情况:response.sendRedirect("/"); 将斜杠发送给浏览器解析,得到的地址是:http://ip:port/
HttpServletResponse类
1. 什么是HttpServletResponse
HttpServletResponse继承了ServletResponse接口,并提供了与Http协议有关的方法,这些方法的主要功能是设置HTTP状态码和管理Cookie
2. HttpServletResponse的作用
每当服务器接收到请求之后,服务器都会创建一个HttpServletResponse对象传递给Servlet程序使用,包含了所有响应的信息,可以通过该对象设置需要返回给客户端的信息
3. 如何往客户端回传数据
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码问题
resp.setContentType("text/html;charset=UTF-8");
//往客户端回传数据
PrintWriter writer = resp.getWriter();
writer.write("response content");
writer.write("中文内容");//中文存在乱码
}
}
注:两个输出流
字节流 getOutPutStream(); 常用于下载(传递二进制数据)
字符流 getWriter(); 常用于回传字符串(常用)
两者不能同时使用
3. 请求重定向
服务器将发送过来的请求定位到新的资源地址
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("response1");
// // 设置响应状态码302 ,表示重定向,(已搬迁)
// resp.setStatus(302);
// // 设置响应头,说明新的地址在哪里
// resp.setHeader("Location", "http://localhost:8080/07_servlet/response2");
//推荐使用
resp.sendRedirect("http://localhost:8080/07_servlet/response2");
}
}
请求重定向的特点:
- 浏览器地址栏会发生变化
- 整个过程有两次请求
- 不共享Request域中的数据
- 不能重定向至WEB-INF下的资源
- 可以访问工程以外的资源