Servlet运行原理
- Servlet API详解
- HttpServlet类
- HttpServletRequest类
- HttpServletResponse类
Servlet API详解
Servlet API中包含了很多的内容,但我们主要用到的是以下三个类,HttpServlet,HttpServletRequest,HttpServletResponse
HttpServlet类
在写Servlet代码的时候,第一步是创建一个类,继承HttpServlet,并重写其中的方法
【核心方法】
【补充】:
- 我们实际开发的时候主要重写 doXXX 方法, 很少会重写 init / destory / service
- destory这个方法不一定能执行到,如果Tomcat是通过8005管理端口来进行关闭,会执行destory,如果直接杀死Tomcat进程,则不会调用,且大部分情况是直接杀死Tomcat进程
- Servlet的生命周期,上述方法的调用时机,就是Servlet的生命周期(描述了一个Servlet实例从生到死的过程) 最先执行init方法,且只执行一次,然后执行service方法(可能执行多次),最后执行destory方法
- HttpServlet的实例只在程序启动时创建一次,而不是每次收到HTTP请求都重新创建实例
【处理GET请求】
- 在浏览器地址栏中填写url,默认就是通过GET方法发送请求
- 处理GET请求的Servlet代码
- 响应结果
【处理POST请求】
通过ajax的方式构造一个POST请求,因此我们需要创建一个HTML,在HTML中创建出对应的webapp代码,HTML文件必须要放在webapp目录下
访问test.html,同时发送POST请求
处理POST请求的代码
响应结果,在success中是将返回的结果打印到控制台上的
【注意】
- 直接通过浏览器输入url得到的响应的内容就是直接被浏览器渲染到界面上的,但ajax不是,拿到的响应数据,是由回调的方法来处理的,可以显示到界面上,也可以不显示
- ajax中url参数的写法,上面是相对路径的写法,test.html处在/servlet1/test.html中,要访问的路径是/servlet1/hello,因此url可直接写成hello,但绝对不能写成/hello,加了/就表示当前路径是绝对路径
- 绝对路径的写法 : /servlet1/hello
- 在WebServlet这个注解中的路径,一定要加/,如果不加/,Tomcat就会认为是无效的路径,从而不能正确启动/加载
除了使用ajax构造请求,还可以使用第三方工具Postman构造请求,这种方式使用起来更方便简单
HttpServletRequest类
Http请求中包含了很多信息,例如请求方法,url,版本号,各种header,body,因此HttpServletRequest类中就提供了一组方法,让我们能够获取到Http请求中的这些信息
【核心方法】
上述的方法都是"读方法",而不是"写方法",因为对于服务器来说,请求对象是服务器收到的内容,不应该修改
【使用示例1】:打印请求的信息
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 java.io.IOException;
import java.util.Enumeration;
@WebServlet("/showRequest")
public class ShowRequest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
StringBuilder respBody = new StringBuilder();
respBody.append(req.getProtocol());
respBody.append("<br>");
respBody.append(req.getMethod());
respBody.append("<br>");
respBody.append(req.getRequestURI());
respBody.append("<br>");
respBody.append(req.getContextPath());
respBody.append("<br>");
respBody.append(req.getQueryString());
respBody.append("<br>");
respBody.append("<h3>headers:</h3>");
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
respBody.append(headerName + " ");
respBody.append(req.getHeader(headerName));
respBody.append("<br>");
}
resp.getWriter().write(respBody.toString());
}
}
【使用示例2】:获取GET请求中的参数
GET请求中的参数一般是通过query string传递给服务器的
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 java.io.IOException;
@WebServlet("/studentInfo")
public class StudentInfoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//假设客户端发来的请求格式形如/studentInfo?studentId=100&classId=8
//可以通过getParameter方法拿到这两个id的值
String queryString=req.getQueryString(); //拿到整个querystring
String classId=req.getParameter("classId");
String studentId=req.getParameter("studentId");
resp.getWriter().write("classId:"+classId+" "+"studentId:"+studentId);
//resp.getWriter().write(queryString);
}
}
getParameter 的效果是拿到 query string中的键值对,根据key获取value
当没有 query string的时候, getParameter 获取的值为 null
【使用示例3】:获取POST请求中的参数
POST请求一般是通过body传递给服务器,body中的格式有很多种,如果采用form表单的形式,仍然可以通过getParameter获取参数的值
- 通过Postman构造一个POST请求,并通过form表单的形式传参数
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf8");
//获取body中的参数
//约定body使用application/x-www-form-urlencoded的形式传参,也就是form表单的形式
//形如classId=100&studentId=99,这个格式和query string相同,只是数据在body中
String classId=req.getParameter("classId");
String studentId=req.getParameter("studentId");
resp.getWriter().write("classId:"+classId+" "+"studentId:"+studentId);
}
- 在body中通过json的形式传参
在服务器端不能通过getParameter的方式直接获取json形式的参数了,因为json格式解析起来,并不是特别容易,json支持一些更复杂的数据结构,也可以进行嵌套,例如某个key的value又是一个json
因此,可以使用处理json的第三方库,我们下面使用的是Jackson,在使用之前需要在项目中引入Jackson
【关于Jackson的使用】
- 我们主要使用的是Jackson提供的一个类ObjectMapper
- ObjectMapper中提供两个了两个主要的方法
- readValue,将json字符串转换成Java对象,该方法的第一个参数是String或InputStream,第二个参数是转换的结果对应的类对象(因此需要先有一个类)
- writeValue方法,将Java对象转成json字符串
- 通过Postman构造POST请求,并通过json格式传递参数
- 后端使用Jackson处理json格式的字符串
HttpServletResponse类
【核心方法】
响应对象是服务器要返回给浏览器的内容, 这里的重要信息都是程序猿设置的. 因此上面的方法都是 “写” 方法.
【代码示例1】:设置状态码
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 java.io.IOException;
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置状态码
resp.setStatus(200);
}
}
在响应中设置状态码200,得到的抓包结果
在响应中设置状态码404,得到的浏览器页面和抓包结果
【代码示例2】:自动刷新,在响应的header中设置Refresh属性,每刷新一次都会给服务器发送一个新的请求
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 java.io.IOException;
@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Refresh","1"); //value表示每隔几秒刷新一次
resp.getWriter().write(System.currentTimeMillis()+"");//返回当前的时间戳
}
}
页面显示效果和抓包结果
【代码示例3】:重定向,服务器返回一个重定向报文,让浏览器自动跳转到新的页面
具体做法:
- 设置状态码3xx(典型是302)
- 在响应的header中设置Location,表示要跳转的页面
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 java.io.IOException;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(302);
resp.setHeader("Location","https://www.sogou.com");
//resp.sendRedirect("https://www.sogou.com");和上面两行代码的写法等价
}
}
页面效果和抓包结果
敲下回车之后,跳转到搜狗主页