• Web中Servlet简单总结


    Web阶段

    HTTP协议概述

    主要可以理解为:客户端-发起请求=====服务器-响应请求

    • HTTP(Hyper Text Transfer Protocol):超文本传输协议

    • HTTP 协议是基于 TCP/IP 协议的

    • 超文本:比普通文本更加强大

    • 传输协议:客户端和服务器端的通信规则(握手规则)

    请求部分

    请求行 请求头 请求空行 请求体

    请求的方式:get/post

    注意:只有 POST 请求方式才有请求体

    常用状态码介绍:

    状态码说明
    200 一切都OK>
    302/307 请求重定向(客户端行为,两次请求,地址栏发生改变)
    304 请求资源未发生变化,使用缓存
    404 请求资源未找到
    500 服务器错误

    Servlet(重中之重)

    servlet介绍:

    Servlet 是运行在 Java 服务器端的程序,用于接收和响应来自客户端基于 HTTP 协议的请求

    • 第一:Servlet是一个运行在web服务端的java小程序

    • 第二:它可以用于接收和响应客户端的请求

    • 第三:要想实现Servlet功能,可以实现Servlet接口,继承GenericServlet或者HttpServlet

    • 第四:每次请求都会执行service方法

    • 第五:Servlet还支持配置

    servlet的执行流程

    Servlet关系视图

    Servlet实现方式

    共有3种方式(一般只用第三种)

    1. 第一种 实现 Servlet 接口,实现所有的抽象方法。该方式支持最大程度的自定义。

    2. 第二种 继承 GenericServlet 抽象类,必须重写 service 方法,其他方法可选择重写。该方式让我们开发 Servlet 变得简单。但是这种方式和 HTTP 协议无关。

    3. 第三种 继承 HttpServlet 抽象类,需要重写 doGet 和 doPost 方法。该方式表示请求和响应都需要和 HTTP 协议相关。

    Servlet的生命周期

    总结来说,只要有请求就是Servlet的诞生之日,请求结束服务器停止,Servlet死亡

    Servlet的线程安全

    和线程安全一样,需要加锁,注意上锁的对象要唯一

    package com.itheima.servlet;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;

    /*
      Servlet线程安全
    */
    public class ServletDemo04 extends HttpServlet{
      //1.定义用户名成员变量
      //private String username = null;

      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //       String username = null;
          synchronized (this) { //锁需要唯一,Servlet对象就是唯一的,所以用this
              //2.获取用户名
              username = req.getParameter("username");

              try {
                  Thread.sleep(3000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }

              //3.获取输出流对象
              PrintWriter pw = resp.getWriter();

              //4.响应给客户端浏览器
              pw.print("welcome:" + username);

              //5.关流
              pw.close();
          }
      }

      @Override
      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          doGet(req,resp);
      }
    }

    Servlet的映射方式

    三种:(经常使用第一种)

    1. 第一种 具体名称的方式。访问的资源路径必须和映射配置完全相同

    2. 第二种 / 开头 + 通配符的方式。只要符合目录结构即可,不用考虑结尾是什么

    3. 第三种 通配符 + 固定格式结尾的方式。只要符合固定结尾格式即可,不用考虑前面的路径

    注意:优先级问题。越是具体的优先级越高,越是模糊通用的优先级越低。第一种 -> 第二种 -> 第三种

    Servlet多映射的使用场景

    场景分析:

    • 如果访问的资源路径是 /vip 商品价格打9折

    • 如果访问的资源路径是 /vvip 商品价格打5折

    • 如果访问的资源路径是其他 商品价格不打折

    package com.itheima.servlet;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    /*
      Servlet 多路径映射
    */
    public class ServletDemo06 extends HttpServlet {
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //1. 定义一个商品金额
          int money = 1000;

          //2. 获取访问的资源路径
          String name = req.getRequestURI();
          name = name.substring(name.lastIndexOf("/"));
           
          //3. 条件判断
          if("/vip".equals(name)) {
              //如果访问资源路径是/vip 商品价格为9折
              System.out.println("商品原价为:" + money + "。优惠后是:" + (money*0.9));
          } else if("/vvip".equals(name)) {
              //如果访问资源路径是/vvip 商品价格为5折
              System.out.println("商品原价为:" + money + "。优惠后是:" + (money*0.5));
          } else {
              //如果访问资源路径是其他 商品价格原样显示
              System.out.println("商品价格为:" + money);
          }
      }

      @Override
      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          doGet(req,resp);
      }
    }

    ServletConfig的使用

    • <servlet>标签中,通过<init-param>标签来配置。有两个子标签。

    • <param-name>:代表初始化参数的 key。

    • <param-value>:代表初始化参数的 value。

    常用方法

    ServletContext

    作用:可以获得应用的全局初始化参数和达到 Servlet 之间的数据共享。

    ServletContext图示:

    域对象概念

    • 域对象指的是对象有作用域也就是有作用范围

    • 域对象可以实现数据的共享

    • 不同作用范围的域对象,共享数据的能力也不一样

    • 在 Servlet 规范中,一共有 4 个域对象

      ServletContext 就是其中的一个

    ServletContext的使用

    ServletContext 并不属于某个 Servlet 的配置,而是针对于整个应用的配置,也叫全局的初始化参数

    <web-app>标签中,通过<context-param>标签来配置。有两个子标签

    <param-name>:代表全局初始化参数的 key

    <param-value>:代表全局初始化参数的 value

     

    配置Servlet,并且配置ServletContext

    <web-app>
      ....
      <!--配置Servlet-->
      <servlet>
          <servlet-name>servletContextDemo</servlet-name>
          <servlet-class>com.itheima.servlet.ServletContextDemo</servlet-class>
      </servlet>
      <servlet-mapping>
          <servlet-name>servletContextDemo</servlet-name>
          <url-pattern>/servletContextDemo</url-pattern>
      </servlet-mapping>


      <!--配置ServletContext-->
      <context-param>
          <param-name>globalEncoding</param-name>
          <param-value>UTF-8</param-value>
      </context-param>
      <context-param>
          <param-name>globalDesc</param-name>
          <param-value>This is ServletContext</param-value>
      </context-param>
    </web-app>

    常用方法

     //获取ServletContext对象
    ServletContext context = getServletContext();
    //修改ServletContextDemo:存储数据
    //向域对象中存储数据
    context.setAttribute("username","zhangsan");
    //修改ServletConfigDemo:获取数据
      //获取ServletContextDemo设置共享的数据
      Object username = context.getAttribute("username");
      System.out.println(username);

    自动注解开发Servlet

    不需要web下的WEB-INF, web.xml也没有了

    index.jsp也没用

    Servlet应用案例-学生管理系统 ***

    案例效果介绍

    • 效果

      • 访问案例首页,看到一个可以保存学生信息的界面

      • 输入内容,点击保存,通过java服务器,然后最终保存到txt中

      • 最后java服务器返回成功结果

    案例实现

    1. 创建一个 web 项目:servlet_test,配置虚拟目录/stu

      • 选择javaee 7,这里我们还是用web.xml

    2. 创建一个用于保存学生信息的 html 文件:web下新建addStudent.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
         <meta charset="UTF-8">
         <title>添加学生</title>
      </head>
      <body>
        -- ?username=张三&age=18&score=718
         <form action="/stu/studentServlet" method="get" autocomplete="off">
            学生姓名:<input type="text" name="username"> <br/>
            学生年龄:<input type="number" name="age"> <br/>
            学生成绩:<input type="number" name="score"> <br/>
             <button type="submit">保存</button>
         </form>
      </body>
      </html>
    3. 创建一个类com.itheima.servlet.StudentServlet,继承 HttpServlet

    4. 重写 doGet 和 doPost 方法

      package com.itheima.servlet;

      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.BufferedWriter;
      import java.io.FileWriter;
      import java.io.IOException;
      import java.io.PrintWriter;

      public class StudentServlet extends HttpServlet {
         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        }

         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             doGet(req,resp);
        }
      }
    5. 在 web.xml 文件中修改默认主页和配置 Servlet

       <!--修改默认主页-->
         <welcome-file-list>
             <welcome-file>/addStudent.html</welcome-file>
         </welcome-file-list>

         <!--配置Servlet-->
         <servlet>
             <servlet-name>studentServlet</servlet-name>
             <servlet-class>com.itheima.servlet.StudentServlet</servlet-class>
         </servlet>
         <servlet-mapping>
             <servlet-name>studentServlet</servlet-name>
             <url-pattern>/studentServlet</url-pattern>
         </servlet-mapping>
    6. 在 doGet 方法中接收表单数据保存到文件中,并响应给浏览器结果

      // -- ?username=张三&age=18&score=718
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             //获取表单中的数据
             String username = req.getParameter("username"); // 获取url后边的?的参数
             String age = req.getParameter("age");
             String score = req.getParameter("score");

             //将数据保存到stu.txt文件中
             BufferedWriter bw = new BufferedWriter(new FileWriter("d:\stu.txt",true));
             bw.write(username + "," + age + "," + score);
             bw.newLine();
             bw.close();

             //给浏览器回应
             PrintWriter pw = resp.getWriter();
             pw.println("Save Success~");
             pw.close();
        }
    7. 部署并启动项目

    8. 通过浏览器测试

    请求对象

    请求对象常用方法1-获取各种路径

    request.

    获取请求参数工具类封装,可以使用apache的beanutils包

     

    用流的形式读取请求信息

    注意:

    获取文字 字符时用getReader(字符流,如果采用字符流必须使用post请求方式)

    获取图片 文件时用getInputStream(字节流)

    请求正文中文编码问题

    post方式请求

    //设置编码格式
    req.setCharacterEncoding("UTF-8");

    get请求方式

    //输出到浏览器:注意响应的乱码问题已经解决了
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.write(username);

    请求域

    可以在一次请求范围内共享数据,一般用于请求,转发的多个资源中 共享数据

     

    代码展示

    响应对象

    • 响应:回馈结果。在 BS 架构中,就是服务器给客户端浏览器反馈结果

    • 响应对象:就是在项目中用于发送响应的对象

    //解决中文乱码
    resp.setContentType("text/html;charset=UTF-8");

    案例:响应图片

    1. 创建字节输入流对象,关联读取的图片路径

    2. 通过响应对象获取字节输出流对象

    3. 循环读取和写出图片

    4. 案例:新建ServletDemo03

    /*
      响应图片到浏览器
    */
    @WebServlet("/servletDemo03")
    public class ServletDemo03 extends HttpServlet {
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          //1. 创建字节输入流对象,关联图片路径
          String realPath = getServletContext().getRealPath("/img/hm.png");
          System.out.println(realPath);
          BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
      //注意:不能直接指定图片路径,需要同getRealPath获取,因为项目还要发布,我们需要获取到发布之后的图片路径
          //BufferedInputStream bis = new BufferedInputStream(new FileInputStream(/img/hm.png));
          //2. 获取字节输出流对象
          ServletOutputStream sos = resp.getOutputStream();

          //3. 循环读写
          byte[] arr = new byte[1024];
          int len;
          while((len = bis.read(arr)) != -1) {
              sos.write(arr,0,len);
          }

          bis.close();
          sos.close();
      }

      @Override
      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          doGet(req,resp);
      }
    }

    设置缓存时间

    String news = "这是一条很火爆的新闻~~";

    //设置缓存时间:1小时的缓存时间
    //参数1:Expires : 失效的意思
    //参数2:当前时间+1小时毫秒值(意思就是在1小时之后过期)
    resp.setDateHeader("Expires",(System.currentTimeMillis()+1*60*60*1000L));

    //设置编码格式
    resp.setContentType("text/html;charset=UTF-8");
    //写出数据
    resp.getWriter().write(news);
    System.out.println("aaa");
    }

    设置定时刷新

     String news = "您的用户名或密码错误,3秒后自动跳转到登录页面...";

          //设置编码格式
          resp.setContentType("text/html;charset=UTF-8");
          //写出数据
          resp.getWriter().write(news);

          //设置响应消息头定时刷新
      //Refresh:刷新
          //第二个参数第一部分:3,3设之后
          //第二个参数第二部分:跳转到哪个路径
          //resp.setHeader("Refresh","3;URL=/response/login.html");
          resp.setHeader("Refresh","3;URL="+req.getContextPath()+"/login.html");
      }

    请求重定向

    /*
      请求重定向
    */
    @WebServlet("/servletDemo06")
    public class ServletDemo06 extends HttpServlet {
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          //设置请求域数据
          req.setAttribute("username","zhangsan");

          //设置重定向
          resp.sendRedirect(req.getContextPath() + "/servletDemo07");
      //resp.sendRedirect("/response/servletDemo07");
    // resp.sendRedirect("https://www.baidu.com");
      }
    /*
      请求重定向
    */
    @WebServlet("/servletDemo07")
    public class ServletDemo07 extends HttpServlet {
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          System.out.println("servletDemo07执行了...");
          Object username = req.getAttribute("username");//获取不到
          System.out.println(username);
      }

    总之一句话:重定向是两次请求,设置的数据不会共享

    • 重定向与转发的区别

    • 重定向:

      • 两次请求

      • 地址栏发生变化

      • 不可以使用request域共享数据 (既然是两次请求,那肯定不能使用请求域中共享的数据)

      • 可以重定向到其他服务器的url

    • 转发:

      • 一次请求

      • 地址栏不发生变化

      • 可以使用request域共享数据

      • 只能转发到自己服务器内部的url

    响应对象-文件下载

     //1.创建字节输入流,关联读取的文件
            //获取文件的绝对路径
            String realPath = getServletContext().getRealPath("/img/hm.png");
            //创建字节输出流对象
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
    
            //2.设置响应头支持的类型  应用支持的类型为字节流
            /*
                Content-Type 消息头名称   支持的类型
                application/octet-stream   消息头参数  应用类型为字节流
             */
            resp.setHeader("Content-Type","application/octet-stream");
    
            //3.设置响应头以下载方式打开  以附件形式处理内容
            /*
                Content-Disposition  消息头名称  处理的形式
                attachment;filename=  消息头参数  附件形式进行处理;指定下载文件名称
             */
            resp.setHeader("Content-Disposition","attachment;filename=hm.png");
    
            //4.获取字节输出流对象
            ServletOutputStream sos = resp.getOutputStream();
    
            //5.循环读写文件
            byte[] arr = new byte[1024];
            int len;
            while((len = bis.read(arr)) != -1) {
                sos.write(arr,0,len);
            }
    
            //6.释放资源
            bis.close();
            //sos.close();
        }

     

  • 相关阅读:
    TensorFlowMNIST数据集逻辑回归处理
    TensorFlow多元线性回归实现
    TensorFlow简单线性回归
    mysql ON DUPLICATE KEY UPDATE
    20200908 morning diary
    LambdaUtil
    数据库SQL自我书写册
    getMyFriendsListFromWeChat()
    MySQL8.*的JSON语法知多少
    Exception in thread "main" java.lang.IllegalArgumentException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token at [Source: UNKNOWN; line: -1, c
  • 原文地址:https://www.cnblogs.com/sunhao410526/p/14308368.html
Copyright © 2020-2023  润新知