servlet简介

servlet简介

目录

1. Servlet 是什么?

2. web 项目的角色以及作用

3. Servlet规范介绍

4. Servlet接口实现类

5. Servlet接口实现类开发步骤

6. servlet对象的生命周期(web服务器如何管理web项目)

7. HttpServletResponse接口

    1. 介绍

    2. 主要功能

8. HttpServletRequest接口

    1. 介绍

    2. 作用

    3. 表单提交数据格式

    4. 常用方法

    5. HttpServletRequest是一个怎样的范围

9. 请求对象和响应对象的生命周期


1. Servlet 是什么?

    web 项目想要在 Web 服务器(TomCat, JBoss等)上运行, 必须满足一套规则, Servlet 就是规则
    这套规则由 SUN 公司制定(Servlet 规范的核心是 Servlet 接口), 属于 JavaEE 规范, 而我们 JAVA 程序员就是写 Servlet 的实现类

2. web 项目的角色以及作用

    web服务器:
        根据一定的规则管理 web 项目
        根据浏览器的 URL 查找到对应的 web 项目
    SUN公司:
        SUN 公司是 web 服务器和 web 项目交互规则的制定者 
        它制定了 Servlet 接口, 如果程序员想让 web 服务器管理自己的资源, 必须实现这个接口 
    开发web项目的java程序员:
        写 Servlet 接口的实现类, 写配置文件 XML (将用户的请求路径和底层的java程序绑定在一起)
        下面三行模拟一个 XML 文件
        /login=LoginServlet
        /delete=DeleteServlet
        /save=SaveServlet
        web项目的XML文件都是以类似路径=资源(类名)的形式保存的
        当用户输入一个资源时候, Web服务器可以根据路径(key)查找到对应的资源(value)
        再根据类名(资源)通过反射机制new对象

3. Servlet规范介绍

    1. Servlet宏观上讲是一种规范, 这个规范来自JavaEE规范中的一种
    2. 作用:
        在Servlet规范中, 指定"动态资源文件"开发步骤
        在Servlet规范中, 指定web服务器调用动态资源文件规则
        在Servlet规范中, 指定web服务器管理动态资源文件实例对象规则

4. Servlet接口实现类

    1. Servlet接口来自于Servlet规范下一个接口, 这个接口存在于web服务器提供的jar包中
    2. Tomcat服务器下lib文件有一个servlet-api.jar存放servlet接口(javax.servlet.Servlet接口)
    3. Servlet规范中认为, web服务器能调用的动态资源文件必须是一个Servlet接口实现类

5. Servlet接口实现类开发步骤

    第一步:创建一个java类, 让它实现Servlet接口
        Servlet接口的子类关系如下
        祖宗接口Servlet------爷爷类GenericServlet(抽象)------父类HttpServlet(抽象)------子类java程序员写的实现类
        Servlet接口有五个抽象方法(最重要的是service)
        GenericServlet类没有实现service, 别的都实现了
        HttpServlet类实现了service方法, 在service中, 通过request.getMethod()获取请求端的方法名(get,post等), 不是反射(Method是request类里面的一个属性)
        java程序员写的实现类需要重写具体的doXXX方法
        根据这个例子可以看出抽象类的一种作用:
            通过抽象类继承接口的方式(抽象类实现了接口中的部分抽象方法), 降低接口实现类对接口的依赖程度(接口实现类可以直接继承已经实现了部分方法的抽象类, 而不用继承什么都没有实现的接口)
        所以不直接实现Servlet接口, 而要继承HttpServlet接口的原因, 主要是为了简化开发步骤
    第二步:重写HttpServlet父类中的两个方法,doGet或者doPost
        web服务器会根据会根据路径名找到对应的实现类, 通过反射创建对象, 在由web服务器主动调用这个对象的service方法
        在实现类中又重写了doGet或者doPost方法, 而实现类又继承了HttPServlet类实现的service方法, 这里service方法的主要作用为, 
        通过反射获取请求端的方法名, 调用对应的doXXX方法     
    第三步:将Servlet接口实现类信息<注册>到web服务器
        这样web服务器就可以根据路径找到对应的实现类, 完成相关操作了.
        web.xml路径:web项目文件----web----WEB-INF---web.xml
        找到文件后加入如下:

            <servlet>
        <!--        下面一行代码实际上是指定oneServlet类的实例对象的名称-->
            <servlet-name>mm</servlet-name>
        <!--        声明servlet接口实现类的类路径, 注意是类的全限定名-->
            <servlet-class>oneServlet</servlet-class>
            </servlet>
        <!--    为了降低用户访问servlet接口实习类的难度, 需要设置简单的请求别名-->
            <servlet-mapping>
        <!--        下面实际上是将mm和路径建立映射关系-->
            <servlet-name>mm</servlet-name>
        <!--        设置简单的请求别名, 书写的时候必须以/开头-->
            <url-pattern>/one</url-pattern>
            </servlet-mapping>

        这时候请求URL为: http://localhost:8081/web项目名/one , 访问的资源为oneServlet类
        IDEA中项目名可以在 run----edit----Deployment最下面的Application context更改

6. servlet对象的生命周期(web服务器如何管理web项目)

    1. 在一个网站(web项目)中所有servlet接口实现类对象必须由web服务器创建(反射)
    2. 在默认情况下, web服务器收到当前Servlet接口实现类的第一次请求时, 会自动创建这个Servlet接口实现类的实例化对象
       在手动配置的情况下, 可以要求web服务器在启动的时候就创建出类的实例化对象
       在web.xml配置文件中手动设置

            <servlet>
            <servlet-name>mm</servlet-name>
            <servlet-class>oneServlet</servlet-class>
            <!--        填写一个大于0的数就会默认创建-->
            <load-on-startup>30</load-on-startup>
            </servlet>


    3. 在web服务器运行期间, 一个Servlet接口实现类只能被创建出一个实例对象
    4. 在web服务器关闭的时候, 自动的将网站中所有Servlet对象进行销毁

7. HttpServletResponse接口

    1. 介绍

        1. HttpServletResponse接口来自于Servlet规范中, 在Tomcat中存在于servlet-api.jar中
        2. HttpServletResponse接口的实现类由web服务器提供
        3. HttpServletResponse接口负责将doGet/doPost方法的执行结果写入到响应体中, 交给浏览器
        4. 开发人员习惯于将HttpServletResponse接口实例化的对象叫做响应对象

    2. 主要功能

        1. 将执行结果以二进制的形式写入到响应体中(序列化和反序列化)
        例:

        public class oneServlet extends HttpServlet {
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 扮演执行结果的角色
            String result = "Hello World";

            // 通过响应对象, 将结果写入响应体中
            // Tomcat中存在一个输出流, Tomcat将内容通过输出流以二进制的形式写入响应体中
            // 1. 通过响应对象, 向Tomcat索要输出流
            PrintWriter out = response.getWriter();
            // 2. 通过输出流, 将执行结果以二进制的形式写入到响应体中
            out.write(result);
            // 使用完毕不需要关闭, 因为这个是Tomcat的输出流
            }
            // doGet执行完毕后, Tomcat将响应包推送给浏览器
        }

        2. 可以设置响应头content-type属性值, 从而控制浏览器使用对应的编译器将响应体的二进制数据编译成对应的文字,图片,视频等
        例:

        public class TowServlet extends HttpServlet {

            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            int money = 50;
            PrintWriter out = response.getWriter();
            out.write(money);
            }
        }


        此时浏览器上显示的结果并不为50, 而为2
            原因:
                 out.writer(), 可以将字符, 字符串, ASCII码写入到响应体中
                 当参数为int时, 会将其认为是ASCII码, 在浏览器显示的时候就是打印ASCII码对应的字符
                 ASCII码为50时候对应的字符为2
            解决:
                 使用out.print();
        所以, 今后的开发中一律使用out.print()方法, writer()???没听说过        例:

        public class ThreeServlet extends HttpServlet {

            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String result = "java<br/>JavaScript<br/>C语言";
            PrintWriter out = response.getWriter();
            out.print(result);
            }
        }


        浏览器上的结果为: java<br/>JavaScript<br/>C??
        说明, 浏览器并没有把我们的响应包当做HTML, 而是当成了普通的文本
        原因: 浏览器在接受到响应包之后, 根据响应头的content-type属性的值的不同采用不同的编译器编译响应体中二进制的内容
              在默认的请求下, 我们content-type属性的值为"text", 此时浏览器将采用文本编译器对二进制的值进行解析
        解决: 要在得到输出流之前, 通过响应对象对响应头中的content-type属性进行重新赋值, 使浏览器采用对应的二进制编译器

        public class ThreeServlet extends HttpServlet {

            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String result = "java<br/>JavaScript<br/>C语言";
            // 设置响应头的content-type属性值
            // 设置将输出流中的二进制解释为text文本或者HTML
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.print(result);
            }
        }


        现在解决了HTML的问题, 但是现在的结果中还是有?, 抓个包看看Content-type的值, Content-Type: text/html;charset=ISO-8859-1
        改字符集
        response.setContentType("text/html;charset=UTF-8");
        显示结果一切正常, nice
        此时的抓个包看看Content-type为:text/html;charset=UTF-8        3. 设置响应头的location属性, 将一个请求地址赋值给location, 从而控制浏览器向指定服务器发送请求
        浏览器在接受到响应包之后, 如果发现响应头存在location属性, 自动通过地址栏向location指定的位置发送请求
        sendRedirect方法作用为远程控制浏览器的行为
        请求三要素为: 请求地址, 请求方式, 请求参数
        请求参数可以用queryString的方式加在URL之后
        例:

        public class FourServlet extends HttpServlet {

            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 我们希望通过服务器端控制浏览器的地址
            String result = "http://www.baidu.com";

            // 通过响应对象, 将地址赋值给响应头中的location属性
            //浏览器在接受到响应包之后, 如果发现响应头存在location属性, 自动通过地址栏向location指定的位置发送请求
            //        sendRedirect方法作用为远程控制浏览器的行为
            //        请求三要素为: 请求地址, 请求方式, 请求参数
            //      请求参数可以根据queryString的方式加在URL之后
            response.sendRedirect(result);
            }
        }

8. HttpServletRequest接口

    1. 介绍

        1. HttpServletRequest接口来自于Servlet规范中, 在Tomcat中存在于servlet-api.jar中
        2. HttpServletRequest接口的实现类由web服务器提供
        3. HttpServletRequest接口负责在doGet/doPost方法运行时读取Http请求协议包中的信息
        4. 开发人员习惯于将HttpServletRequest接口实例化的对象叫做请求对象
        5. 继承关系interface HTTPServletRequest extends ServletRequest{}
        6. HTTPServletRequest封装了什么信息?
            请求方法
            URI
            协议版本号
            表单提交数据
            ......
        7. 一次请求对应一个HttPServletRequest

    2. 作用

        1. 可以读取Http请求协议包中请求行(请求首行, 包括请求方法, URL, Http协议版本)中的信息
        例:

        public class oneServlet extends HttpServlet {

            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1. 通过请求对象, 读取{请求行}中的{URL}信息
            // request.getRequestURL(), 读取URL信息, 返回一个StringBuffer
            String url = request.getRequestURL().toString();
            // 2. 通过请求对象, 读取{请求行}中{method}信息
            // request.getMethod()返回值是Http请求的方法名
            String method = request.getMethod();

            System.out.println("URL = " + url);
            System.out.println("method = " + method);
            }
        }


        在控制台上打印:
        URL = http://localhost:8081/05/one
        method = GET
        
        也可以通过请求对象, 读取{请求行}中{URI}信息
        request.getRequestURI(), 读取URI, 返回结果是一个字符串
        URI: 资源文件精准定位地址, 在请求行中实际上没有这个属性, 实际上是根据URL截取的一个字符串
        这个字符串的格式为"/web项目名/资源文件名"
        URI用于让web服务器对被访问资源进行定位
        例:

        // 3. 通过请求对象, 读取{请求行}中{URI}信息
        // request.getRequestURI(), 读取URI信息, 返回结果为一个String
        String uri = request.getRequestURI();
        System.out.println("URI = " + uri);

        2. 可以读取保存在Http请求协议包中请求头或者请求体中的参数信息
        例:
        在一个web项目中建立静态资源(HTML文件), 这个静态资源如下:

        <body>
            <a href="/05/two?username=Tom&password=123">通过超链接访问TwoServlet, 并携带请求参数</a>
        </body>


        模拟访问某一个资源时带参数信息, 可见参数有username和password
        /two路径对应的Servlet接口实现类情况如下:

        public class TwoServlet extends HttpServlet {
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                // 1. 通过请求对象获得{请求头}中所有{请求参数名}
                // request.getParameterNames(), 将所有参数名统一保存进一个枚举对象中
                Enumeration paramNames = request.getParameterNames();
                while (paramNames.hasMoreElements()) {
                    String paramName = (String)paramNames.nextElement();
                    // 2. 通过请求参数名获取请求参数值
                    // request.getParameter(paramName), 参数为请求参数名, 返回它对应的值, 是String类型
                    String value = request.getParameter(paramName);
                    System.out.println(paramName + "=" + value);
                }
            }
        }


        控制台上打印的结果为:
            userName=Tom
            password=123
        上面的例子是从请求头中获取QueryString, 下面是从请求体中获取

        <body>
            <form action="/05/three" method="post">
            用户名&nbsp;<input type="text" name="username"><br/>
            <input type="submit" value="post方式提交">
            </form>
        </body>


        这个表单提交路径的Servlet实现类如下:

        public class ThreeServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 通过请求对象, 读取{请求体}的参数信息
            // 方法和请求头中一模一样
            String value = request.getParameter("username");
            System.out.println("username = " + value);
            }
        }


        在表单上打出 zhangsan
        控制台上显示结果如下:
            username = zhangsan
        
        可见不管从请求头还是请求体中获取queryString的信息, 代码都是一样的
        但是, 如果post方法的中queryString有中文时, 会出现乱码
        原因: 浏览器以Get方式发送请求, 参数保存在请求头中, 当Http请求协议包到达web服务器之后(协议包中的内容是二进制), 第一件事情就是解码
              请求头中的二进制内容是由Tomcat负责解码, 默认使用UTF-8
              如果以Post方式发送请求, 参数保存在请求体中, 当Http请求协议包到达web服务器之后(协议包中的内容是二进制), 第一件事情就是解码
              请求体中的二进制内容是由请求对象(request)负责解码, request默认使用[ISO-8859-1]字符集, 中文时候就会出现乱码
        解决: 在读取请求体内容之前, 先通知请求对象使用UTF-8字符集解码

        public class ThreeServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 通过请求对象, 读取{请求体}的参数信息
            // 方法和请求头中一模一样
            // 通知请求对象使用UTF-8字符集解码
            request.setCharacterEncoding("UTF-8");
            String value = request.getParameter("username");
            System.out.println("username = " + value);
            }
        }

        
        保险起见, 我们将在重写doGet和doPost方法中, 前两行加入如下代码指定解码方式
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        3. 可以代替浏览器向Web服务器申请资源文件调用
        就是重定向

    3. 表单提交数据格式

        例: username=admin&password=123&interest=sport&interest=music
        上面的例子可以看出, 表单提交数据信息的格式是类似键值对的格式
        键值对就可以抽象为Map, 但是我们发现interest对应了两个值(复选框中一个name可能对应多个value)
        所以这个Map的格式为<String, String[]>
        上面的例子Map格式如下:
 

        Map<String, String[]>
        ----------------------------------------
        key             value
        username       {"admin"}
        password       {"123"}
        interest       {"sport", "music"}

    4. 常用方法

        获取表单数据
        表单提交的数据, 会自动封装到request对象中, request对象中有一个Map<String, String[]>来存储这些数据

            String getParameter(String name)  // 通过key获取对应value(String[])的首元素, 这个方法使用最多
            Map getParameterMap()  // 获取整个Map集合
            Enumeration getParameterNames()  //获取整个Map集合的所有Key
            String[] getParameterValues(String name)  //通过Key获取对应的value(String[]), 这个方法适合获得复选框请求信息

        获取路径地址

            String getRemoteAddr()  // 获取客户端的ip地址
            String getContexPath()  // 获取上下文路径(web项目根路径)
            String getMethod()  // 获取请求方式
            String getRequestURI()  // 获取URI
            StringBuffer getRequestURL()  // 获取URL
            String getServletPath()  // 获取Servlet路径, 这里的路径是指web.xml和这个Servlet实现类相关的路径(/xxx)

        向request中存入信息,可以参考下面5. HttpServletRequest是一个怎样的范围

            void setAttribute(String name, Object o)  // 向request范围中存入数据, name为key, o为value, 类似于Map
            Object getAttribute(String name)  // 从request范围中读取数据
            void removeAttribute(String name)  // 移除request范围中的数据

        获取请求转发器, 让转发器对象指向某个资源, 这里的参数为web.xml文件中配置的"/xxx"
        具体可以参考下面5. HttpServletRequest是一个怎样的范围的解决

            RequestDispatcher getRequestDispatcher(String path)

        和会话有关方法

            Cookie[] getCookies()
            HttpSession getSession()

    5. HttpServletRequest是一个怎样的范围

        HttpServletRequest类型的对象通常命名为request, 代表本次请求
        一次请求对应一个request对象, 请求范围是很小的, request只能完成在同一次请求中的数据传递
        看下面一个例子        AServlet向request中存入对象, 之后又取出对象

        public class AServlet extends HttpServlet {

            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

            // 创建user对象
            User user = new User();
            user.setUsercode("111");
            user.setUsername("zhangsan");

            // 将user存储在request范围中
            request.setAttribute("userObj", user);

            // 从request范围中取出数据
            Object obj = request.getAttribute("userObj");
            response.getWriter().print(obj);
            }
        }

        此时浏览器上打印: User{usercode='111', username='zhangsan'}        如果在上面操作执行完毕之后让BServlet从request取数据
        BServlet类如下:

        public class BServlet extends HttpServlet {

            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 从request范围中取出数据AServlet存入的数据
            Object obj = request.getAttribute("userObj");
            response.getWriter().print(obj);  //浏览器打印为null
            }
        }

        浏览器上打印结果为: null
        这说明这两个Servlet的request不是一个对象        解决办法: 转发
            AServlet改成如下, BServlet不变

            public class AServlet extends HttpServlet {

                protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

                // 创建user对象
                User user = new User();
                user.setUsercode("111");
                user.setUsername("zhangsan");

                // 将user存储在request范围中
                request.setAttribute("userObj", user);

            //        // 从request范围中取出数据
            //        Object obj = request.getAttribute("userObj");
            //        response.getWriter().print(obj);

                // 跳转
                // 执行完AServlet之后, 跳转到BServlet执行, 将AServlet执行和BServlet执行放到一个请求中
                // 必须使用转发技术
                // forward [转发]
                // 1. 获取请求转发器对象
                // request.getRequestDispatcher("/路径") 获取请求转发器
                // 以下转发器指向了"/b"资源
                RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
                // 2. 调用请求转发器的forward方法即可完成转发
                dispatcher.forward(request, response);

                }
            }


            此时浏览器上显示: User{usercode='111', username='zhangsan'}
            注意, AServlet里没有打印到浏览器, 而BServlet有, 说明通过转发BServlet取到了数据
            我们抓个包看看, 发现只有一次请求, 这说明转发只有一次请求

9. 请求对象和响应对象的生命周期

    1. 在web服务器接受到浏览器发送的[Http请求协议包]之后, 
       自动为当前的[Http请求协议包]生成一个[请求对象]和一个[响应对象]
    2. 在web服务器去调用doGet或者doPost方法时, 负责将[请求对象]和[响应对象]当做实参传到这个方法中, 
       来确保doGet/doPost的正确执行
    3. 当doGet或者doPost运行完毕的时候, 意味着本次请求处理完毕, web服务器端生成了一个http响应协议包, 
       当web服务器准备将响应包发给服务器之前, 将这两个对象销毁(老工具人了).
    所以说[请求对象]和[响应对象]的生命周期贯穿一次请求处理的全过程
    [请求对象]将[请求协议包]中的内容解析出来, [响应对象]负责将doGet/doPost方法的执行结果告诉[响应协议包]
    所以[请求对象]和[响应对象]更像是web服务器和浏览器(或是用户)之间的捎话人

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值