zoukankan      html  css  js  c++  java
  • JavaWeb—Servlet

    Servlet

    1、servlet简介

    • servlet就是sun公司开发动态web的一门技术
    • sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
      • 编写一个类,实现Servlet接口
      • 把开发好的Java类部署到Web服务器中。

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

    2、HelloServlet

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

    1.构建一个普通的Maven项目,删掉里面的src目录,以后学习就在这个项目里面建立Moudel;这个空的工程就是Maven主工程;

    2.关于Maven父子工程的理解:

    父项目中会有

    <modules>
            <module>servlet-01</module>
        </modules>
    

    子项目中会有:

     <parent>
            <artifactId>javaweb-02-servlet</artifactId>
            <groupId>com.jiang</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    

    父项目中的java子项目可以直接使用

    son extends father
    

    3.Maven环境优化

    1. 修改web.xml为最新的
    2. 将Maven的结构搭建完整

    4.编写一个Servlet程序

    3.package com.jiang.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class HelloServlet extends HttpServlet {
    
        //由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //ServletOutputStream outputStream = resp.getOutputStream();
            PrintWriter writer = resp.getWriter();
            writer.println("Hello,Servlet");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.doPost(req, resp);
        }
    }
    
    

    5.编写一个Servlet的映射

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

      <!--注册Servlet-->
      <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.jiang.servlet.HelloServlet</servlet-class>
      </servlet>
      <!--Servlet的请求路径-->
      <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/jiang</url-pattern>
      </servlet-mapping>
    </web-app>
    

    6.配置Tomcat

    注意:配置项目发布的路径就可以了

    7.启动测试,成功

    3、Servlet原理

    Servlet是由Web服务器调用,web服务器在收到浏览器请求之后,会:

    4、Mapping问题

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

        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello</url-pattern>
        </servlet-mapping>
      
    2. 一个Servlet可以指定多个映射路径

      <!--Servlet的请求路径-->
        <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>
      
      
    3. 一个Servlet可以指定通用映射路径

      <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello/*</url-pattern>
        </servlet-mapping>
      
    4. 指定一些后缀或者前缀等等

        <!--可以自定义后缀实现请求映射
        注意点:*前面不能加项目映射的路径
        例如:hello/asdasdas.java
        -->
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>*.java</url-pattern>
        </servlet-mapping>
      
    5. 请求默认路径

      <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/*</url-pattern>
        </servlet-mapping>
      
    6. 优先级问题
      指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求

        <servlet>
          <servlet-name>error</servlet-name>
          <servlet-class>com.jiang.servlet.ErrorServlet</servlet-class>
        </servlet>
        <servlet-mapping>
          <servlet-name>error</servlet-name>
          <url-pattern>/*</url-pattern>
        </servlet-mapping>
      
      package com.jiang.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;
      
      public class ErrorServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              resp.setCharacterEncoding("utf-8");
              resp.setContentType("text/html");
              PrintWriter writer = resp.getWriter();
              writer.println("<h1>404</h1>");
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              super.doPost(req, resp);
          }
      }
      
      

    5、ServletContext

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

    5.1、共享数据

    1、在这个Servlet中保存的数据,可以在另外一个servlet中拿到;

    package com.jiang;
    
    import javax.servlet.ServletContext;
    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 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 = "秦疆"; //数据
            context.setAttribute("username",username); //将一个数据保存在了ServletContext中,名字为:username 。值 username
    
        }
    
    }
    
    

    2、写另外一个Servlet

    package com.jiang;
    
    import javax.servlet.ServletContext;
    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 GetServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext context = this.getServletContext();
            String username = (String) context.getAttribute("username");
    
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            resp.getWriter().print("名字"+username);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    

    3、注册Servlet

    <servlet>
            <servlet-name>hello</servlet-name>
            <servlet-class>com.kuang.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.kuang.servlet.GetServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>getc</servlet-name>
            <url-pattern>/getc</url-pattern>
        </servlet-mapping>
    

    测试访问结果;

    1. 没走hello之前,请求getc为:名字null
    2. 走了一遍hello,再请求getc为:名字姜嘉航

    5.2、获取初始化参数

    1、在web.xml配置一些web应用初始化参数

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

    2、编写获取初始化参数的Servlet

    package com.jiang;
    
    import javax.servlet.ServletContext;
    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 ServletDemo03 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext context = this.getServletContext();
            String url = context.getInitParameter("url");
            resp.getWriter().print(url);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    

    3、注册Servlet

    <servlet>
            <servlet-name>gp</servlet-name>
            <servlet-class>com.jiang.ServletDemo03</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>gp</servlet-name>
            <url-pattern>/gp</url-pattern>
        </servlet-mapping>
    

    测试:

    5.3、请求转发

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        System.out.println("进入了ServletDemo04");
        //RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp"); //转发的请求路径
        //requestDispatcher.forward(req,resp); //调用forward实现请求转发;
        context.getRequestDispatcher("/gp").forward(req,resp);
    }
    

    原理图:

    5.4、读取资源文件

    Properties

    • 在java目录下新建properties
    • 在resources目录下新建properties

    发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath:

    思路:需要一个文件流;

    1、在resources目录下创建一个db.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/classes/com/jiang/servlet/aa.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);
        }
    }
    
    

    访问测试即可ok;

    6、HttpServletResponse

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

    • 如果要获取客户端请求过来的参数:找HttpServletRequest
    • 如果要给客户端响应一些信息:找HttpServletResponse

    6.1、简单分类

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

    ServletOutputStream getOutputStream() throws IOException;
    PrintWriter getWriter() throws IOException;
    

    负责向浏览器发送响应头的方法

        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);
    

    响应的状态码

        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;
    

    6.2、下载文件

    1. 向浏览器输出消息
    2. 下载文件
      1. 要获取下载文件的路径
      2. 下载的文件名是啥?
      3. 设置想办法让浏览器能够支持下载我们需要的东西
      4. 获取下载文件的输入流
      5. 创建缓冲区
      6. 获取OutputStream对象
      7. 将FileOutputStream流写入到buffer缓冲区
      8. 使用OutputStream将缓冲区中的数据输出到客户端!
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 要获取下载文件的路径
        String realPath = "D:\图片\1.png";
        System.out.println("下载文件的路径:"+realPath);
        // 2. 下载的文件名是啥?
        String fileName = realPath.substring(realPath.lastIndexOf("\") + 1);
        // 3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名URLEncoder.encode编码,否则有可能乱码
        resp.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(fileName,"UTF-8"));
        // 4. 获取下载文件的输入流
        FileInputStream in = new FileInputStream(realPath);
        // 5. 创建缓冲区
        int len = 0;
        byte[] buffer = new byte[1024];
        // 6. 获取OutputStream对象
        ServletOutputStream out = resp.getOutputStream();
        // 7. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端!
        while ((len=in.read(buffer))>0){
            out.write(buffer,0,len);
        }
    
        in.close();
        out.close();
    }
    

    6.3、验证码功能

    验证怎么来的?

    • 前端实现
    • 后端实现,需要用到 Java 的图片类,生产一个图片
    package com.kuang.servlet;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.Random;
    
    public class ImageServlet extends HttpServlet {
    
        @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;
        }
    
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    

    6.4、实现重定向

    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不会产生变化
    • 重定向时候,url地址栏会发生变化;

    5、简单实现登录重定向

    <%--这里提交的路径,需要寻找到项目的路径--%>
    <%--${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");
        }
    
    
      <servlet>
        <servlet-name>requset</servlet-name>
        <servlet-class>com.kuang.servlet.RequestTest</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>requset</servlet-name>
        <url-pattern>/login</url-pattern>
      </servlet-mapping>
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    
    <h1>Success</h1>
    
    </body>
    </html>
    
    

    7、HttpServletRequest

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

    获取参数,请求转发

    @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("=============================");
        //后台接收中文乱码问题
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbys));
        System.out.println("=============================");
    
    
        System.out.println(req.getContextPath());
        //通过请求转发
        //这里的 / 代表当前的web应用
        req.getRequestDispatcher("/success.jsp").forward(req,resp);
    
    }
    

    面试题:请你聊聊重定向和转发的区别?

    相同点

    • 页面都会实现跳转

    不同点

    • 请求转发的时候,url不会产生变化 307
    • 重定向时候,url地址栏会发生变化; 302
  • 相关阅读:
    每日一篇文献:Robotic pick-and-place of novel objects in clutter with multi-affordance grasping and cross-domain image matching
    每日一篇文献:Intuitive Bare-Hand Teleoperation of a Robotic Manipulator Using Virtual Reality and Leap Motion
    每日一篇文献:Virtual Kinesthetic Teaching for Bimanual Telemanipulation
    HEBI Robotic Arm VR Teleoperation
    「iQuotient Case」AR device teleoperated robotic arm
    VR and Digital Twin Based Teleoperation of Robotic Arm
    HEBI Robotic Arm VR Teleoperation
    Human Robot Interaction
    Immersive Teleoperation Project
    机器人演示学习
  • 原文地址:https://www.cnblogs.com/godles/p/12296028.html
Copyright © 2011-2022 走看看