Servlet

1. Servlet简介

Servlet就是sun公司开发动态web的一门技术

Sun在这些API中提供一个接口叫做:Servlet

开发Servlet程序的步骤:

  • 编写一个类,实现Servlet接口
  • 把开发好的Java类部署到web服务器中。

把实现了Servlet接口的Java程序叫做,Servlet

2. Servlet入门

Serlvet接口Sun公司有两个默认的实现类:HttpServlet,GenericServlet

image-20210907113522313
Image
image-20210907133911841
Image

第一个Servlet程序

  1. 编写一个普通类

  2. 实现Servlet借口,根据上图,可以直接继承HttpServlet

    public class HelloServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // ServletOutputStream outputStream = resp.getOutputStream();
            PrintWriter writer = resp.getWriter(); // 响应流
            writer.print("Hello,Serlvet");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  3. 编写Servlet的映射

    为什么需要映射:我们写的是JAVA程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要再web服务中注册我们写的Servlet,还需给他一个浏览器能够访问的路径;

    WEB-INF/web.xml中新增如下映射:

    <!--注册Servlet-->
    <servlet>
      <servlet-name>hello</servlet-name>
      <servlet-class>com.gs.servlet.HelloServlet</servlet-class>
    </servlet>
    
    <!--映射Servlet的请求路径-->
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
  4. 配置Tomcat

  5. 启动测试

3. Servlet原理

servlet工作原理
Image
servlet工作流程图
Image

工作流程

  1. Web Client 向Servlet容器(Tomcat)发出Http请求
  2. Servlet容器接收Web Client的请求
  3. Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中。
  4. Servlet容器创建一个HttpResponse对象
  5. Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet 对象。
  6. HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息。
  7. HttpServlet调用HttpResponse对象的有关方法,生成响应数据。
  8. Servlet容器把HttpServlet的响应结果传给Web Client。

处理请求流程

  1. 用户点击一个链接,指向了一个servlet而不是一个静态页面。
  2. 容器“看出”这个请求是一个Servlet,所以它创建了两个对象HttpServletRequest和HttpServletResponse。
  3. 容器根据请求中的URL找到正确的Servlet,为这个请求创建或分配一个线程,并把请求和响应对象传递给这个Servlet线程。

4. Mapping

  1. 一个Servlet可以指定一个或者多个映射路径

    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello2</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello3</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello4</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello5</url-pattern>
    </servlet-mapping>
    
  2. 一个Servlet可以指定通用映射路径

    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello/*</url-pattern>
    </servlet-mapping>
    
  3. 默认请求路径

    <!--默认请求路径-->
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
  4. 指定一些前缀或者后缀

    <!--可以自定义后缀实现请求映射
        注意点,*前面不能加项目映射的路径
        -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    
  5. 优先级问题

    指定了固有映射路径的优先级最高,找不到就会走默认的处理请求

    <!--404-->
    <servlet>
        <servlet-name>error</servlet-name>
        <servlet-class>com.gs.servlet.ErrorServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>error</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    

5. ServletContext

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用。

  1. 共享数据

    在一个Servlet中保存的数据,可以在另一个Servlet中得到。

    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //this.getInitParameter()   初始化参数
            //this.getServletConfig()   Servlet配置
            //this.getServletContext()  Servlet上下文
            ServletContext context = this.getServletContext();
            String username = "root"; //数据
            context.setAttribute("username",username); //将一个数据保存在了ServletContext中,名字为:username 。值 username
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    public class GetServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              // 设置响应编码
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
    
            ServletContext context = this.getServletContext();
            String username = (String) context.getAttribute("username");
            resp.getWriter().print("名字"+username);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

    ```xml

    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.gs.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
   <servlet>
       <servlet-name>getc</servlet-name>
       <servlet-class>com.gs.servlet.GetServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>getc</servlet-name>
       <url-pattern>/getc</url-pattern>
   </servlet-mapping>

2. 获取初始化参数

   web.xml

   ```xml
   <!--配置一些web应用初始化参数-->
   <context-param>
     <param-name>url</param-name>
     <param-value>jdbc:mysql://localhost:3306/test</param-value>
   </context-param>

Servlet

   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       ServletContext context = this.getServletContext();
       String url = context.getInitParameter("url");
       resp.getWriter().print(url);
   }
  1. 请求转发

    请求转发,是服务器端内部进行转发,过程对客户端透明,在客户端看来,客户端所请求的地址不变。

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        System.out.println("12312312");
        // RequestDispatcher requestDispatcher = context.getRequestDispatcher("/testrd"); // 转发的请求路径
        // requestDispatcher.forward(req,resp); // 调用forward实现请求转发    context.getRequestDispatcher("/testrd").forward(req,resp);
    }
    
  2. 读取资源文件

    Properties配置文件

    在Java目录下或者在Resource目录下的文件都会被打包在类路径(classpath)下。如果资源文件在源代码目录中编译后没有被打包,参考这个链接

    准备一个文件流,放在Resources目录下

    user.properties

    username=root
    password=123456
    
    public class ServletDemo05 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/user.properties");
    
            Properties prop = new Properties();
            prop.load(is);
            String user = prop.getProperty("username");
            String pwd = prop.getProperty("password");
            resp.getWriter().print(user+":"+pwd);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

    测试即可

6. HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse。

  • 获取客户端请求过来的参数,用HttpServletRequest。
  • 返回客户端一些响应信息,用HttpServletResponse。

  • 常用方法

    1. 负责向浏览器发送数据的方法

      ServletOutputStream getOutputStream() throws IOException;
      PrintWriter getWriter() throws IOException;
      
    2. 负责向浏览器发送响应头的方法

      void setCharacterEncoding(String var1);
      
      void setContentLength(int var1);
      
      void setContentLengthLong(long var1);
      
      void setContentType(String var1);
      
      void setDateHeader(String var1, long var2);
      
      void addDateHeader(String var1, long var2);
      
      void setHeader(String var1, String var2);
      
      void addHeader(String var1, String var2);
      
      void setIntHeader(String var1, int var2);
      
      void addIntHeader(String var1, int var2);
      
    3. 常见响应状态码

      int SC_CONTINUE = 100;
      int SC_SWITCHING_PROTOCOLS = 101;
      int SC_OK = 200;
      int SC_CREATED = 201;
      int SC_ACCEPTED = 202;
      int SC_NON_AUTHORITATIVE_INFORMATION = 203;
      int SC_NO_CONTENT = 204;
      int SC_RESET_CONTENT = 205;
      int SC_PARTIAL_CONTENT = 206;
      int SC_MULTIPLE_CHOICES = 300;
      int SC_MOVED_PERMANENTLY = 301;
      int SC_MOVED_TEMPORARILY = 302;
      int SC_FOUND = 302;
      int SC_SEE_OTHER = 303;
      int SC_NOT_MODIFIED = 304;
      int SC_USE_PROXY = 305;
      int SC_TEMPORARY_REDIRECT = 307;
      int SC_BAD_REQUEST = 400;
      int SC_UNAUTHORIZED = 401;
      int SC_PAYMENT_REQUIRED = 402;
      int SC_FORBIDDEN = 403;
      int SC_NOT_FOUND = 404;
      int SC_METHOD_NOT_ALLOWED = 405;
      int SC_NOT_ACCEPTABLE = 406;
      int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
      int SC_REQUEST_TIMEOUT = 408;
      int SC_CONFLICT = 409;
      int SC_GONE = 410;
      int SC_LENGTH_REQUIRED = 411;
      int SC_PRECONDITION_FAILED = 412;
      int SC_REQUEST_ENTITY_TOO_LARGE = 413;
      int SC_REQUEST_URI_TOO_LONG = 414;
      int SC_UNSUPPORTED_MEDIA_TYPE = 415;
      int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
      int SC_EXPECTATION_FAILED = 417;
      int SC_INTERNAL_SERVER_ERROR = 500;
      int SC_NOT_IMPLEMENTED = 501;
      int SC_BAD_GATEWAY = 502;
      int SC_SERVICE_UNAVAILABLE = 503;
      int SC_GATEWAY_TIMEOUT = 504;
      int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
      
  • 利用HttpServletResponse下载文件

    步骤:

    1. 获取下载路径,解决下载的文件名的问题
    2. 让浏览器支持下载
    3. 获取下载文件的输入流
    4. 创建缓冲区
    5. 获取HttpServletResponse的OutputStream对象
    6. 将输入流的数据输入到buffer缓冲区
    7. 使用OutputStream将缓冲区中的数据输出到客户端。

    代码实现:

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      String realPath = "/Users/admin/Downloads/1.jpg";
      // 如果是Windows系统,要考虑斜杠转义问题
      String fileName = realPath.substring(realPath.lastIndexOf("/") + 1);
      // 设置响应头,值得注意的是文件名需要使用URLEncoder.encode(fileName, "UTF-8")进行编码,防止中文乱码
      resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
      // 流的套路
      FileInputStream in = new FileInputStream(realPath);
      int len = 0;
      byte[] buffer = new byte[1024];
      ServletOutputStream out = resp.getOutputStream();
      while ((len = in.read(buffer)) > 0) {
        out.write(buffer, 0, len);
      }
      in.close();
      out.close();
    }
    
  • 实现验证码功能

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
      // 如何让浏览器3秒自动刷新一次;
      resp.setHeader("refresh","3");
    
      // 在内存中创建一个图片
      BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
      // 得到图片
      Graphics2D g = (Graphics2D) image.getGraphics(); //笔
      // 设置图片的背景颜色
      g.setColor(Color.white);
      g.fillRect(0,0,80,20);
      // 给图片写数据
      g.setColor(Color.BLUE);
      g.setFont(new Font(null,Font.BOLD,20));
      g.drawString(makeNum(),0,20);
    
      // 告诉浏览器,这个请求用图片的方式打开
      resp.setContentType("image/jpeg");
      // 网站存在缓存,不让浏览器缓存
      resp.setDateHeader("expires",-1);
      resp.setHeader("Cache-Control","no-cache");
      resp.setHeader("Pragma","no-cache");
    
      // 把图片写给浏览器
      ImageIO.write(image,"jpg", resp.getOutputStream());
    
    }
    
    // 生成随机数
    private String makeNum(){
      Random random = new Random();
      String num = random.nextInt(9999999) + "";
      StringBuffer sb = new StringBuffer();
      for (int i = 0; i < 7-num.length() ; i++) {
        sb.append("0");
      }
      num = sb.toString() + num;
      return num;
    }
    
  • 重定向

    B一个web资源收到客户端A请求后,B会通知A客户端去访问另外一个web资源C,这个过程叫重定向。

    常见场景:用户登陆

    方法:

    void sendRedirect(String var1) throws IOException;
    

    测试:

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       /*
           resp.setHeader("Location","/r/img");
           resp.setStatus(302);
            */
       resp.sendRedirect("/r/img");    // 重定向
    }
    

    重定向和转发的区别

    相同点

    • 页面都会实现跳转

    不同点

    • 请求转发的时候,url不会产生变化 307
    • 重定向时候,url地址栏会发生变化 302

    实现登陆重定向

    <%--${pageContext.request.contextPath}代表当前的项目--%>
    
    <form action="${pageContext.request.contextPath}/login" method="get">
       用户名:<input type="text" name="username"> <br>
       密码:<input type="password" name="password"> <br>
       <input type="submit">
    </form>
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     // 处理请求
     String username = req.getParameter("username");
     String password = req.getParameter("password");
     System.out.println(username+":"+password);
    
     // 重定向时候一定要注意,路径问题,否则404;
     resp.sendRedirect("/r/success.jsp");
    }
    

7. HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息。

常用方法:

// 请求转发
RequestDispatcher getRequestDispatcher(String var1).forward(HttpServletRequest req, HttpServletResponse resp);

// 获取当前的工程目录
String getContextPath();

// 获取请求的内容
String getParameter(String var1);

// 获取请求的内容(数组) 如多选框
String[] getParameterValues(String var1);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置请求和响应的编码格式
    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");

    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String[] hobbys = req.getParameterValues("hobbys");

    System.out.println(username);
    System.out.println(password);
    System.out.println(Arrays.toString(hobbys));

    // 通过请求转发
    // 这里的 / 代表当前的web应用
    req.getRequestDispatcher("/success.jsp").forward(req,resp);

}
Copyright © rootwhois.cn 2021-2022 all right reserved,powered by GitbookFile Modify: 2023-03-05 10:55:52

results matching ""

    No results matching ""