Servlet
什么是Servlet
Servlet是JavaEE的规范之一,它是一个运行在服务器上的java小程序,它通常通过HTTP协议接收和响应来自Web客户端的请求。
实现一个Servlet程序
Servlet的生命周期
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet {
public HelloServlet() {
System.out.println("1 构造器方法");
}
// service方法是专门用来处理请求和响应的
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3 service方法:Hello Servlet 被访问了");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2 init初始化方法");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("4 destroy 销毁方法");
}
}
Get和Post
获取请求方式
如何根据不同的请求方式来进行不同的处理呢?
- 在webaqq目录下新建一个HTML页面a.html来进行演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/servlet_01_war/hello" method="get">
<input type="submit">
</form>
</body>
</html>
- 在HelloServlet类的service方法里里根据请求方式来进行不同的处理
// service方法是专门用来处理请求和响应的
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3 service方法:Hello Servlet 被访问了");
// servletRequest就是请求的方式,需要借助HttpServletRequest接口中的getMethod()方法来获取
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
// 获取到请求的方式
String method = httpServletRequest.getMethod();
if ("Get".equals(method)){
System.out.println("Get请求");
}else if ("Post".equals(method)){
System.out.println("Post");
}
}
通过HttpServlet接口来实现Servlet程序
在现实开发中通常都是使用继承HttpServlet类的方式来实现Servlet程序的,其具体步骤是:
- 编写一个类去继承HttpServlet类
- 根据业务重写doGet和doPost方法
- 到web.xml中去配置,把java类部署到web服务器中
- 创建一个HelloHttpServlet类,继承HttpServlet类,并重写doGet和doPost方法
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloHttpServlet extends HttpServlet {
// doGet()方法在get请求时调用
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloHttpServlet 的 doGet 方法");
}
// doPost()方法在post请求时调用
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloHttpServlet 的 doPost 方法");
}
}
- 在web.xml中进行部署
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- <servlet>:把Servlet程序配置给Tomcat服务器-->
<servlet>
<servlet-name>HelloHttpServlet</servlet-name>
<servlet-class>HelloHttpServlet</servlet-class>
</servlet>
<!-- <servlet-mapping>:给Servlet程序配置访问地址-->
<servlet-mapping>
<servlet-name>HelloHttpServlet</servlet-name>
<url-pattern>/hellohttp</url-pattern>
</servlet-mapping>
</web-app>
Servlet的继承体系
ServletConfig类
此外我们也可以在别的方法中使用ServletConfig,比如在继承了HttpServlet的HelloHttpServlet类的doGet、doPost等方法中:
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloHttpServlet extends HttpServlet {
// doGet()方法在get请求时调用
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloHttpServlet 的 doGet 方法");
ServletConfig servletConfig = getServletConfig();
System.out.println("Servlet程序的别名servlet-name:" + servletConfig.getServletName());
}
// doPost()方法在post请求时调用
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloHttpServlet 的 doPost 方法");
ServletConfig servletConfig = getServletConfig();
System.out.println("初始化参数username:" + servletConfig.getInitParameter("username"));
System.out.println("初始化参数url:" + servletConfig.getInitParameter("url"));
}
}
在web.xml中配置:
<servlet>
<servlet-name>HelloHttpServlet</servlet-name>
<servlet-class>HelloHttpServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<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-name>HelloHttpServlet</servlet-name>
<url-pattern>/hellohttp</url-pattern>
</servlet-mapping>
ServletContext类
ServletContext是一个接口,它表示Servlet上下文对象,每个web工程,只有一个ServletContext对象实例。并且它是在web工程部署启动的时候创建,停止的时候销毁。
域对象
ServletContext对象是一个域对象。它是一种可以像Map一样存取数据的对象。这里的域指的是存取数据的操作范围,也就是整个web工程。
ServletContext 类的四个作用
- 获取web.xml中配置的上下文参数context-param
- 获取当前的工程路径,格式:/ 工程路径
- 获取工程部署后在服务器硬盘上的绝对路径
- 像Map一样存取数据
演示
- 获取上下文参数context-param
创建一个新的类ContextServlet,继承HttpServlet类,重写doGet方法:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class ContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取web.xml中配置的上下文参数context-param
ServletContext servletContext = getServletConfig().getServletContext();
String username = servletContext.getInitParameter("username");
String password = servletContext.getInitParameter("password");
System.out.println("context-param参数其username是:" + username);
System.out.println("context-param参数其password是:" + password);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
在web.xml中配置:
<context-param>
<!-- <context-param>:它是上下文参数,属于整个web工程-->
<param-name>username</param-name>
<param-value>context</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>12345678</param-value>
</context-param>
运行,查看结果:
- 获取当前的工程路径
- 获取工程部署后在服务器硬盘上的绝对路径
修改doGet类:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取web.xml中配置的上下文参数context-param
ServletContext servletContext = getServletConfig().getServletContext();
String username = servletContext.getInitParameter("username");
String password = servletContext.getInitParameter("password");
System.out.println("context-param参数其username是:" + username);
System.out.println("context-param参数其password是:" + password);
// 2. 获取当前的工程路径,格式:/ 工程路径
System.out.println("当前工程路径为:" + servletContext.getContextPath());
// 3. 获取工程部署后在服务器硬盘上的绝对路径
// ”/“斜杠表示服务器解析地址为:http://ip:port/工程名/
System.out.println("工程部署的路径为:" + servletContext.getRealPath("/"));
}
运行,查看结果:
- 像Map一样存取数据
修改doGet类:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("set之前:");
System.out.println("ContextServlet 中获取key1的值是:" + servletContext.getAttribute("key1"));
servletContext.setAttribute("key1", "value1");
System.out.println("set之后:");
System.out.println("ContextServlet 中获取key1的值是:" + servletContext.getAttribute("key1"));
}
运行,查看结果:
HttpServletRequest类
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中。 然后传递到service方法(doGet和doPost)中给我们使用。我们可以通过 HttpServletRequest对象,来获取所有请求的信息。
部分演示
创建一个新的类RequestAPIServlet,继承HttpServlet类,重写doGet方法:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class RequestAPIServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// getRequestURI() 获取请求的资源路径
System.out.println("获取请求的资源路径:" + request.getRequestURI());
// getRequestURL() 获取请求的统一资源定位符(绝对路径)
System.out.println("获取请求的绝对路径:" + request.getRequestURL());
// getRemoteHost() 获取客户端的ip地址
System.out.println("获取客户端的ip地址:" + request.getRemoteHost());
// getHeader() 获取请求头
System.out.println("获取请求头:" + request.getHeader("User-agent"));
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
在web.xml中配置:
<servlet>
<servlet-name>RequestAPIServlet</servlet-name>
<servlet-class>RequestAPIServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RequestAPIServlet</servlet-name>
<url-pattern>/request</url-pattern>
</servlet-mapping>
运行,查看结果:
获取请求的参数值演示
创建一个form.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/servlet_01_war/parameterservlet" method="get">
用户名:<input type="text" name="username"></br>
密码:<input type="text" 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>
创建一个新的类ParameterServlet,继承HttpServlet类,重写doGet方法:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 兴趣爱好有多项,使用数组接收
String[] hobbys = request.getParameterValues("hobby");
System.out.println("用户名:" + username);
System.out.println("密码:" + password);
System.out.println("兴趣爱好:" + Arrays.toString(hobbys));
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobbys = request.getParameterValues("hobby");
System.out.println("用户名:" + username);
System.out.println("密码:" + password);
System.out.println("兴趣爱好:" + Arrays.toString(hobbys));
}
}
在web.xml中配置:
<servlet>
<servlet-name>ParameterServlet</servlet-name>
<servlet-class>ParameterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ParameterServlet</servlet-name>
<url-pattern>/parameterservlet</url-pattern>
</servlet-mapping>
运行,访问form.html,输入并提交:
请求转发演示
新建一个Servlet1和一个Servlet2,都继承继承HttpServlet类,重写doGet方法:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 查看请求参数
String username = request.getParameter("tablename");
System.out.println("学生(Servlet1)查看一下表格" + username);
// 学生1在表格上写下姓名
request.setAttribute("name1", "tom");
System.out.println("学生(Servlet1)填写:" + request.getAttribute("name1"));
//把表格给下一个学生 ————> 请求转发
// 找到下一个学生Servlet2
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
// 传表格给下一个学生
requestDispatcher.forward(request,response);
}
}
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 查看请求参数
String username = request.getParameter("tablename");
System.out.println("学生(Servlet2)查看一下表格" + username);
//查看Servlet1学生是否已经填好
Object name1 = request.getAttribute("name1");
System.out.println("学生(Servlet1)已经填写了:" + name1);
//Servlet2学生填表
request.setAttribute("name2", "jerry");
System.out.println("学生(Servlet2)填写:" + request.getAttribute("name2"));
}
}
在web.xml中配置:
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/servlet1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Servlet2</servlet-name>
<servlet-class>Servlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet2</servlet-name>
<url-pattern>/servlet2</url-pattern>
</servlet-mapping>
运行,传入tablename参数:
HttpServletResponse类
- HttpServletResponse类的作用
HttpServletResponse类和HttpServletRequest类一样。每次有请求进来,Tomcat服务器都会创建一个 Response对象传递给Servlet程序去使用。HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,我们如果需要设置返回给客户端的信息,可以通过 HttpServletResponse对象来进行设置。
- 两个输出流(两个流同时只能使用一个)
- 字节流getOutputStream():常用于下载(传递二进制数据)
- 字符流getWriter():常用于回传字符串(常用)
- 演示
修改Servlet2类的doGet方法:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 查看请求参数
String username = request.getParameter("tablename");
System.out.println("学生(Servlet2)查看一下表格" + username);
//查看Servlet1学生是否已经填好
Object name1 = request.getAttribute("name1");
System.out.println("学生(Servlet1)已经填写了:" + name1);
//Servlet2学生填表
request.setAttribute("name2", "jerry");
System.out.println("学生(Servlet2)填写:" + request.getAttribute("name2"));
// 演示往客户端回传字符流数据
PrintWriter writer = response.getWriter();
writer.write("学生(Servlet2)把表格还给老师了");
}
}
请求重定向
- 演示
新建一个Response1和一个Response2,都继承继承HttpServlet类,重写doGet方法:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我来过这:Response1");
// 设置响应状态码302,表示重定向
response.setStatus(302);
// 设置相应头,指明新地址在哪
response.setHeader("Location", "http://localhost:8080/servlet_01_war/response2");
}
}
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class Response2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 同时设置服务器和客户端字符集
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("欢迎光临:Response2");
}
}
在web.xml中配置:
<servlet>
<servlet-name>Response1</servlet-name>
<servlet-class>Response1</servlet-class>
</servlet>
<servlet>
<servlet-name>Response2</servlet-name>
<servlet-class>Response2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Response1</servlet-name>
<url-pattern>/response1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Response2</servlet-name>
<url-pattern>/response2</url-pattern>
</servlet-mapping>
运行,访问/response1:
另外一种方式,直接使用sendRedirect方法(推荐):
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我来过这:Response1");
response.sendRedirect("http://localhost:8080/servlet_01_war/response2");
}
}
文章notion链接
https://www.notion.so/Servlet-6cb37a12749b4ed8a9873beb5459817f