• 【计算机网络】Servlet API重点知识汇总


    目录

    1.HttpServlet:

    2.HttpServletRequest:

    3.HttpServletRequest代码实例:

    3.1.打印请求的内容:

    3.2.获取请求中的重要参数

    (query string中的值):

    3.3.获取请求中的重要参数

    (body中的值):

    4.HttpServletResponse:

    5.HttpServletResponse代码示例:

    5.1.设置不同的状态码

    5.2.设置响应的header,实现页面的自动刷新

    5.3.构造一个重定向响应

    6.代码案例:


    1. Servlet 是Tomcat给后端程序员提供的开发服务器程序的API合集,借助这个更方便搭建网站的后端。
    2. Servlet提供的类和方法有很多主要使用的就是三个(HttpServlet、HttpServletRequestHttpServletResponse

    1.HttpServlet:

    1. HttpServlet,编写servlet代码的时候第一步就是先创建类继承自HttpServlet,并重写某些方法:
      核心方法说明
      init首次创建出HttpServlet实例会调用一次
      destroy在HttpServlet实例不使用时调用一次
      service收到HTTP请求的时候调用头一次
      doGet收到GET请求的时候service调用doGet
      doPost收到POST请求的时候service来调用
      doPut / doDelete收到这些请求的时候service来调用
    2. init 方法:创建出HttpServlet实例会调用一次,init方法的作用就是用来初始化。注意:HttpServlet的实例只是在程序启动的时候创建一次而不是每次收到HTTP请求都重新创建实例。
    3. destroy方法:不一定真的能调用到!如果Tomcat关闭了,则不再调用HttpServlet了
      Tomcat的关闭:
      1.杀进程, 类似于拔电源
      比如点击idea中的红色方框、cmd直接点×、任务管理器结束任务......
      
      2.通过8005端口给Tomcat发送一个关闭操作, 类似于走正常的程序关闭电脑
      这个时候Tomcat就会正常关机就可以调用到destroy方法
    4. service方法:Tomcat收到请求实际上是先调用service,在service里面再去根据方法调用不同的doXxx。
    5. 【面试题】谈一谈Servlet的生命周期。
      初始阶段实例化的时候,调用一次 init
      结束销毁之前,调用一次 destroy
      每次收到请求,调用 service

    2.HttpServletRequest:

    1. 当Tomcat通过Socket api读取HTTP请求(字符串),并且按照HTTP协议的格式把字符串解析成HttpServletRequest对象
    2. URL是唯一资源定位符;URI是唯一资源标识符。
    3. 常用方法:
      方法说明
      String getProtocol()返回请求协议的名称和版本号
      String getMethod()返回请求的HTTP方法
      String getPrequestURI()返回URL中的一部分
      String getContextPath()返回ContextPath
      String getQueryString()返回查询字符串
      Enumeration getParameterNames()
      String getParameter(String name)返回请求参数的值,参数不存在返回null
      String[ ] getParameterValues(String name)返回请求参数的所有值
      Enumeration getHeaderNames()返回包含请求中所有header的key的枚举
      String getCharacterEncoding()返回请求中使用的字符编码
      String getContentType()返回请求中使用的文本类型和字符编码
      int getContentLength()返回请求主体的长度,字节为单位
      String getHeader(String name)返回指定请求头的值
      InputStream getInputStream()用来读取query string和body的内容
    4. 请求的对象是服务器收到的内容,不应该修改;因此上面都是读的方法不是写的方法。

    3.HttpServletRequest代码实例:

    3.1.打印请求的内容:

     代码如下:

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. import java.util.Enumeration;
    8. @WebServlet("/showRequest")
    9. public class showRequest extends HttpServlet {
    10. @Override
    11. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    12. //resp是响应的对象,setContentType给响应的ContentType设置了值html
    13. //声明响应body是html结构的数据
    14. resp.setContentType("text/html");
    15. StringBuilder stringBuilder = new StringBuilder();
    16. //getProtocol返回请求协议的版本
    17. stringBuilder.append(req.getProtocol());
    18. //要将\n 替换成
      否则html无法识别
    19. // stringBuilder.append("\n");
    20. stringBuilder.append("
      "
      );
    21. //getMethod返回请求中http方法的名称
    22. stringBuilder.append(req.getMethod());
    23. stringBuilder.append("
      "
      );
    24. //getRequestURI返回请求的uri
    25. stringBuilder.append(req.getRequestURI());
    26. stringBuilder.append("
      "
      );
    27. //getRequeatURL返回请求的url
    28. stringBuilder.append(req.getRequestURL());
    29. stringBuilder.append("
      "
      );
    30. //返回Context Path
    31. stringBuilder.append(req.getContextPath());
    32. stringBuilder.append("
      "
      );
    33. //返回查询字符串
    34. stringBuilder.append(req.getQueryString());
    35. stringBuilder.append("
      "
      );
    36. //拼接header中的内容
    37. //getHeaderNames返回一个包含请求中所有的键值对key的值
    38. Enumeration headerNames = req.getHeaderNames();
    39. while(headerNames.hasMoreElements()){
    40. String name = headerNames.nextElement();
    41. //getHeader以字符串的形式返回key对应的value值
    42. String value = req.getHeader(name);
    43. stringBuilder.append(name+ ": " + value);
    44. stringBuilder.append("
      "
      );
    45. }
    46. resp.getWriter().write(stringBuilder.toString());
    47. }
    48. }

    3.2.获取请求中的重要参数

    (query string中的值):

    1.  对于获取query string来说,核心的方法就是getParameter
    2. 如果在浏览器页面上已经手动对特殊符号包括汉字encode编码了,那么servlet getParameter方法会自动的针对encode的结果进行decode解码操作,不需要手动处理。注意一点:浏览器地址栏里用户输入的查询字符串中包含汉字,也不一定会出错(有的浏览器自动编码)。
    3. getParameter方法使用时,如果键值对不存在,得到的就是 null;如果键值对的值不存在,得到的就是 “ ”,例如查询字符串为?studentId=1&studentName=  )。
    4. 如果不写Content-Type,浏览器就不知道用什么方式什么格式来解析。

    代码如下: 

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/getParameter")
    8. public class getParameterServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //获取query string中的键值对
    12. //取值的时候,如果键值对不存在返回的是 null
    13. //如果键存在,值不存在那么返回 “ ”
    14. String studentId = req.getParameter("studentId");
    15. String studentName = req.getParameter("studentName");
    16. System.out.println(studentId);
    17. System.out.println(studentName);
    18. //如果不加这行代码,浏览器就会显示出 ???,这里是 = ,不能是 -
    19. resp.setContentType("text/html; charset=utf8");
    20. resp.getWriter().write(studentId + " , " + studentName);
    21. }
    22. }

    3.3.获取请求中的重要参数

    (body中的值):

    分为俩种情况!

    1. (1)如果请求的body是x-www-form-urlencode格式,form表单、这里也使用getParameter来获取。
    2. 用 html 和 postman 分别来操作!
    3. 使用html来发送form请求,需要先在webapp目录下创建一个html。
    4. 服务器的代码:
    5. 上述的前端和后端代码运行后会出现问题
    6. 请求req这里设置的utf8是告诉servlet(tomcat)如何解析响应resp这里设置的utf8是告诉浏览器如何解析
    7. 请求req和响应resp的字符编码。
      请求这里使用这个方法:
      req.setCharacterEncoding("utf8");
      
      响应建议使用第一种,
      因为不止要设置字符集还要设置格式
      resp.setContentType("text/html; charset = utf8");
      //resp.setCharacterEncoding("utf8");
    8. 加字符编码的总体原则:不要让程序猜!最好的做法就是显示声明该声明的东西。
    9. 通过postman来构造一个POST请求,postman也是一个http客户端,和浏览器是对等的。请求req也要设置字符集,否则还是会有乱码。

    后端代码如下:

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/getParameter")
    8. public class getParameterServlet extends HttpServlet {
    9. @Override
    10. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //如果不加上这段代码,req就会随机解析,因此页面上显示的就是乱码
    12. req.setCharacterEncoding("utf8");
    13. String studentId = req.getParameter("studentId");
    14. String studentName = req.getParameter("studentName");
    15. System.out.println(studentId);
    16. System.out.println(studentName);
    17. resp.setContentType("text/html; charset = utf8");
    18. resp.getWriter().write(studentId + ", " + studentName);
    19. }
    20. }

    1. (2)如果请求的body是json格式,需要先读取body中的内容,进一步的再来读取流对象(getInputStream),下一步解析json格式,但是servlet中没有内置json解析,因此我们需要到借助第三方库jackson
    2. Jackson的使用需要我们知道一个类和俩个方法。一个ObjectMapper,方法是readValuewriteValueAsString
    3. readValue的作用是先读取输入流获取要解析的字符串,再把字符串按照json格式解析得到一组键值对(map),再根据类对象创建一个实例,再遍历类对象中的属性的名字,拿着名字去上面的map中查询,查到的value赋值到对应的对象的属性中,最后返回这个构造完成的对象。
    4. readValue要求键值对中键的名字和类的属性名要一一对应。
    5. 如果类属性多,请求的key少,不会报错,少的那个属性就是null。如果类属性少,请求的key多这里key的多指的是个数多,不是种类,结果就是最后那个。如果类属性少,请求的key多这里key多的是种类,那就会报错。
    6. 还可以使用writeValueAsString方法来返回响应。
    7. 对三种返回响应的代码抓包:

     后端代码如下:

    1. import com.fasterxml.jackson.databind.ObjectMapper;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.annotation.WebServlet;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. class Student{
    9. //1.这个student类的属性必须是public或者带有 public 的getter 和 setter
    10. // 否则jackson无法访问这个对象的属性
    11. //2.这个类必须要有无参版本的构造方法
    12. public int studentId;
    13. public String studentName;
    14. public String studentSex;
    15. }
    16. @WebServlet("/json")
    17. public class JsonServlet extends HttpServlet {
    18. @Override
    19. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    20. //此处假设请求中的body是json格式的
    21. //{studentId:66,studentName:"王大锤"}
    22. //jackson 一个类ObjectMapper 和俩个方法
    23. //一个方法是readValue,把json格式的数据转换成 java 对象
    24. //另外一个方法是writeValueAsString,把java对象转换成json格式的字符串
    25. ObjectMapper objectMapper = new ObjectMapper();
    26. //readValue的第一个参数可以是字符串,也可以是输入流
    27. //第二个参数是类的对象
    28. Student s = objectMapper.readValue(req.getInputStream(),Student.class);
    29. System.out.println(s.studentId);
    30. System.out.println(s.studentName);
    31. System.out.println(s.studentSex);
    32. // resp.setContentType("text/html; charset = utf8");
    33. // resp.getWriter().write(s.studentId + ", " + s.studentName +", " + s.studentSex);
    34. // //响应的数据是html格式的
    35. // resp.setContentType("text/html; charset = utf8");
    36. // resp.getWriter().write(objectMapper.writeValueAsString(s));
    37. //响应的数据是json格式的
    38. resp.setContentType("application/json; charset = utf8");
    39. resp.getWriter().write(objectMapper.writeValueAsString(s));
    40. }
    41. }

    4.HttpServletResponse:

    1. HttpServletRequest的方法大部分都是前缀为get;HttpServletResponse的方法大部分都是前缀为set。
    2. 在doGet/doPost等方法中,这里面的HttpServletResponse对象都是空的。因此这些方法都是set系列也就好理解了。
    3. 常用方法:
      方法说明
      void setStatus()设置状态码
      void setHeader(String name,String value)设置一个header字段,如果已经存在,会覆盖
      void addHeader(String name,String value)设置一个header字段,如果存在,会再创建一个
      void setContentType()设置发送给客户端的响应的内容类型+字符编码
      void setCharacterEncoding()设置发送给客户端的响应的字符编码
      void sendRedirect(String location)重定向
      PrintWriter getWriter()用于往body中写入文本格式数据
      OutputStream getOutputStream()用于往body中写入二进制数据
    4. 状态码和header的设置要放到getWriter和getOutputStream前面。

    5.HttpServletResponse代码示例:

    5.1.设置不同的状态码

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/status")
    8. public class StatusServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //约定一下浏览器的query string传一个参数过来
    12. //127.0.0.1:8080/servlet/status?type=1
    13. //如果type=1返回200,如果为2返回404
    14. String type = req.getParameter("type");
    15. if(type.equals("1")){
    16. resp.setStatus(200);
    17. }else if(type.equals("2")){
    18. resp.setStatus(404);
    19. }else if(type.equals("3")){{
    20. resp.setStatus(500);
    21. }}else{
    22. resp.setStatus(504);
    23. }
    24. }
    25. }

    5.2.设置响应的header,实现页面的自动刷新

    1. 在header中设置refresh属性,值是一个秒数,浏览器会在时间到了之后自动刷新
    2. 尽管我设置了3秒刷新一次,但是并不是精确的3000ms,会比3000略多一点
    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/autoRefresh")
    8. public class AutoRefreshServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //直接返回响应就行
    12. resp.setHeader("refresh","3");
    13. resp.getWriter().write(System.currentTimeMillis()+"");
    14. }
    15. }

    5.3.构造一个重定向响应

    1. 可以设置header中的Location属性,实现跳转;也可以使用sendRedirect方法。 
    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/redirect")
    8. public class RedirectServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //进行重定向,收到请求,跳转到哔哩哔哩
    12. //第一种写法
    13. //resp.setStatus(302);
    14. //resp.setHeader("Location","http://www.bilibili.com");
    15. //第二种写法
    16. resp.sendRedirect("http://www.bilibili.com");
    17. }
    18. }

    6.代码案例:

    1. 实现表白墙:在页面上点击提交,希望在服务器这里保存数据,把数据发送给服务器;当关闭页面再启动,需要从服务器上读取之前保存过的数据,在页面上显示出来。
    2. 先要规划好请求和响应的细节。
    3. 提供俩种版本:顺序表和数据库。

     使用顺序表的版本:

    1. import com.fasterxml.jackson.databind.ObjectMapper;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.annotation.WebServlet;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. import java.util.ArrayList;
    9. @WebServlet("/message")
    10. public class MessageServlet extends HttpServlet {
    11. public ObjectMapper objectMapper = new ObjectMapper();
    12. public ArrayList arrayList = new ArrayList<>();
    13. @Override
    14. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    15. resp.setContentType("text/json; charset=utf8");
    16. resp.getWriter().write(objectMapper.writeValueAsString(arrayList));
    17. }
    18. //浏览器提交数据
    19. @Override
    20. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    21. //获取到body中的数据并且解析
    22. Message message = objectMapper.readValue(req.getInputStream(),Message.class);
    23. //将得到的数据保存
    24. arrayList.add(message);
    25. resp.setStatus(200);
    26. System.out.println("提交数据成功,form:" + message.getFrom() +
    27. " to: " + message.getTo() + " Message: " + message.getMessage());
    28. }
    29. }
    30. class Message {
    31. private String From;
    32. private String To;
    33. private String Message;
    34. public String getFrom() {
    35. return From;
    36. }
    37. public void setFrom(String from) {
    38. From = from;
    39. }
    40. public String getTo() {
    41. return To;
    42. }
    43. public void setTo(String to) {
    44. To = to;
    45. }
    46. public String getMessage() {
    47. return Message;
    48. }
    49. public void setMessage(String message) {
    50. Message = message;
    51. }
    52. }

    使用数据库的版本:

    1. //使用这个类来封装DataSource
    2. public class DBUtil {
    3. private static volatile DataSource dataSource = null;
    4. public static DataSource getDataSource(){
    5. if(dataSource == null){
    6. synchronized (DBUtil.class){
    7. if(dataSource == null){
    8. dataSource = new MysqlDataSource();
    9. ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java105?characterEncoding=utf8&useSSL=false");
    10. ((MysqlDataSource)dataSource).setUser("root");
    11. ((MysqlDataSource)dataSource).setPassword("111111");
    12. }
    13. }
    14. }
    15. return dataSource;
    16. }
    17. private DBUtil() {}
    18. }
    19. import com.fasterxml.jackson.databind.ObjectMapper;
    20. import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
    21. import javax.servlet.ServletException;
    22. import javax.servlet.annotation.WebServlet;
    23. import javax.servlet.http.HttpServlet;
    24. import javax.servlet.http.HttpServletRequest;
    25. import javax.servlet.http.HttpServletResponse;
    26. import javax.sql.DataSource;
    27. import java.io.IOException;
    28. import java.sql.Connection;
    29. import java.sql.PreparedStatement;
    30. import java.sql.ResultSet;
    31. import java.sql.SQLException;
    32. import java.util.ArrayList;
    33. import java.util.List;
    34. @WebServlet("/message")
    35. public class MessageServlet extends HttpServlet {
    36. // 这个对象在多个方法中都需要使用
    37. private ObjectMapper objectMapper = new ObjectMapper();
    38. // 负责让页面获取到数据
    39. @Override
    40. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    41. // 显式声明当前的响应数据格式 不要让客户端去猜!!!
    42. resp.setContentType("application/json; charset=utf8");
    43. // 把 messageList 转成 json 字符串, 并且返回给页面就行了.
    44. List messageList = null;
    45. try {
    46. messageList = load();
    47. } catch (SQLException e) {
    48. e.printStackTrace();
    49. }
    50. resp.getWriter().write(objectMapper.writeValueAsString(messageList));
    51. }
    52. // 提交数据
    53. @Override
    54. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    55. // 获取到 body 中的数据并解析
    56. Message message = objectMapper.readValue(req.getInputStream(), Message.class);
    57. // 把这个 message 保存一下. 简单的办法就是保存在内存中.
    58. // messageList.add(message);
    59. try {
    60. save(message);
    61. } catch (SQLException e) {
    62. e.printStackTrace();
    63. }
    64. resp.setStatus(200);
    65. System.out.println("提交数据成功: from=" + message.getFrom()
    66. + ", to=" + message.getTo() + ", message=" + message.getMessage());
    67. }
    68. private List load() throws SQLException {
    69. // 从数据库查询数据
    70. // 1. 先有一个数据源
    71. DataSource dataSource = DBUtil.getDataSource();
    72. // 2. 建立连接
    73. Connection connection = dataSource.getConnection();
    74. // 3. 构造 SQL
    75. String sql = "select * from message";
    76. PreparedStatement statement = connection.prepareStatement(sql);
    77. // 4. 执行 SQL
    78. ResultSet resultSet = statement.executeQuery();
    79. // 5. 遍历结果集合
    80. List messageList = new ArrayList<>();
    81. while (resultSet.next()) {
    82. Message message = new Message();
    83. message.setFrom(resultSet.getString("from"));
    84. message.setTo(resultSet.getString("to"));
    85. message.setMessage(resultSet.getString("message"));
    86. messageList.add(message);
    87. }
    88. // 6. 关闭连接
    89. statement.close();
    90. connection.close();
    91. return messageList;
    92. }
    93. private void save(Message message) throws SQLException {
    94. // 把数据保存到数据库中
    95. // 1. 先有一个数据源
    96. DataSource dataSource = DBUtil.getDataSource();
    97. // 2. 建立连接
    98. Connection connection = dataSource.getConnection();
    99. // 3. 构造 SQL
    100. String sql = "insert into message values(?, ?, ?)";
    101. PreparedStatement statement = connection.prepareStatement(sql);
    102. statement.setString(1, message.getFrom());
    103. statement.setString(2, message.getTo());
    104. statement.setString(3, message.getMessage());
    105. // 4. 执行 SQL
    106. int ret = statement.executeUpdate();
    107. System.out.println("ret = " + ret);
    108. // 5. 关闭连接
    109. statement.close();
    110. connection.close();
    111. }
    112. }

    如果对您有帮助的话,

    不要忘记点赞+关注哦,蟹蟹

    如果对您有帮助的话,

    不要忘记点赞+关注哦,蟹蟹

    如果对您有帮助的话,

    不要忘记点赞+关注哦,蟹蟹

  • 相关阅读:
    算法:(七)队列
    java中的nio相对于普通的IO区别和联系?
    代码随想录算法训练营第23期day12| 239. 滑动窗口最大值 、347. 前K个高频元素
    基于GCC的工具objdump实现反汇编
    Python基础——简介
    CATT的应用
    实践自定义弹框列表数据 slot 操作数据
    UI自动化测试之selenium工具(浏览器窗口的切换)
    DJ8-2 主存储器的组织
    前端(四)
  • 原文地址:https://blog.csdn.net/qq_68993495/article/details/127934027