zoukankan      html  css  js  c++  java
  • java.servlet

    image-20210228213836601

    HTTP协议

    浏览器中的书写格式

    image-20210228221103997

    HTTP请求

    Get请求

    image-20210228222708036

    Post请求

    image-20210228222815950

    格式

    请求行
    请求头1
    请求头2
    
    请求空体
    请求体
    

    HTTP响应

    image-20210228224219100

    格式

    状态行
    响应头1
    响应头2
    
    响应空行
    响应体
    

    Servlet的实现

    servlet的生命周期

    先看与Servlet生命周期有关的三个方法:init(), service(), destroy(). Servlet生命周期可被定义为从创建
    直到毁灭的整个过程。以下是三个方法分别对应的Servlet过程:
        init():Servlet进行初始化;
        service():Servlet处理客户端的请求;
        destroy():Servlet结束,释放资源;
    在调用destroy()方法后,Servlet由JVM的垃圾回首器进行垃圾回收。
    

    init()方法

    Servlet被装载后,Servlet容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化在Servlet生

    命周期中init()方法只被调用一次

    当用户调用一个Servlet时,Servlet容器就会创建一个Servlet实例,每一个用户请求都会产生一个新的

    线程,init()方法简单的创建或加载一些数据,这些数据将会被用在Servlet的整个生命周期。

    init()方法的定义如下:

    public void init() throws ServletException {
        // 初始化代码... 
    }
    

    service()方法

    service()方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service()方法来处理来

    自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

    每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service()方法检查

    HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用doGet()、doPost()等方法。

    service()的定义如下:

    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{
        // service()代码... 
    }
    

    destroy()方法

    destroy()方法只会被调用一次,在Servlet生命周期结束时被调用。destroy()方法可以让Servlet关闭数

    据库连接、停止后台、把cookie列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

    在调用destroy()方法之后,Servlet对象被标记为垃圾回收。

    destroy()方法的定义如下所示:

    public void destroy() {
        // 终止化代码... 
    }
    

    总结:

    1. 在首次访问某个Servlet时,init()方法会被执行,而且也会执行service()方法。
    2. 再次访问时,只会执行service()方法,不再执行init()方法。
    3. 在关闭Web容器时会调用destroy()方法。

    创建WEB项目

    image-20210228230655927

    image-20210228230849103

    实现Servlet

    image-20210228231110220

    image-20210228231217787

    配置servlet的两种方式

    1.通过web.xml文件配置servlet

    <servlet>
        <servlet-name>servlet01</servlet-name>
        <servlet-class>com.ccl.servlet.servlet01</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>servlet01</servlet-name>
        <url-pattern>/ser.do</url-pattern>
    </servlet-mapping>
    

    image-20210301220413282

    2.通过注解配置servlet

    image-20210301220555933

    注意:两种配置方法不能同时使用

    创建servlet的三种方式

    1.实现javax.servlet.Servlet接口,这个接口定义了servlet的生命周期,所有的方法都要实现

    @WebServlet("/HelloServlet")
    public class UserServlet implements Servlet {
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
    
        }
    
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
    
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            servletResponse.getWriter().print("<h1>hello servlet</h1>");
        }
    
        @Override
        public String getServletInfo() {
            return null;
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    

    image-20210301222250230

    2.继承javax.servlet.GenericServlet类

    public class GenServlet extends GenericServlet {
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            servletResponse.getWriter().print("<h1>hello GenericServlet</h1>");
        }
    }
    

    image-20210301223043024

    3.继承javax.servlet.http.HttpServlet类,会根据请求的类型进行特殊的调用

    public class HServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().print("<h1>hello HttpServlet</h1>");
        }
    }
    

    image-20210301223842017

    servlet的匹配规则

    精确匹配

    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/user.html</url-pattern>
        <url-pattern>/user.do</url-pattern>
    </servlet-mapping>
    

    在浏览器中输入如下几种url时,都会被匹配到该servlet

    http://localhost:4444/servlet01/user.html
    http://localhost:4444/servlet01/user.do
    

    image-20210301232409042

    image-20210301232425832

    路径匹配 ,以"/"开头,并以"/*"结尾的字符串用于路径匹配

    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/user/*</url-pattern>
    </servlet-mapping>
    

    路径以/user/开始,后面的路径可以任意。比如下面的url都会被匹配

    image-20210301233307086

    扩展名匹配,以"*"结尾的字符串用于扩展名匹配

    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    

    则任何扩展名为jsp或action的url请求都会匹配,比如下面的url都会被匹配

    image-20210301232604317

    image-20210301232733993

    缺省匹配

    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    

    以任意字符开头,/结尾该servlet被匹配

    image-20210301232949888

    匹配顺序

    1. 精准匹配
    2. 路径匹配,优先最长路径匹配
    3. 扩展名匹配

    请求和响应

    RERUEST

    概述

    request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法,这说明在service()方法中可以通过request对象来获取请求数据。

    request的功能可以分为以下几种:

    • 封装了请求头数据;
    • 封装了请求正文数据,如果是GET请求,那么就没有正文;
    • request是一个域对象,可以把它当成Map来添加获取数据;
    • request提供了请求转发和请求包含功能。(以后学习)

    常用方法

    方法名 描述
    getRequestURL() 获取客户端发出请求时的完整URL
    getRequestURI() 获取请求行中的资源名称部分(项目名称开始)
    getQueryString() 获取请求行中的参数部分
    getMethod() 获取客户端请求方式
    getProtocol() 获取HTTP版本号
    getContextPath() 获取webapp名字
    // 获取客户端请求的完整URL (从http开始,到?前面结束)
    String url = req.getRequestURL().toString();
    System.out.println("获取客户端请求的完整URL:" + url);
    // 获取客户端请求的部分URL (从站点名开始,到?前面结束)
    String uri = req.getRequestURI();
    System.out.println("获取客户端请求的部分URL:" + uri);
    // 获取请求行中的参数部分 (从?后面开始,到最后)
    String queryString = req.getQueryString();
    System.out.println("获取请求行中的参数部分:" + queryString);
    // 获取客户端的请求方式
    String method = req.getMethod();
    System.out.println("获取客户端的请求方式:" + method);
    // 获取HTTP版本号
    String protocol = req.getProtocol();
    System.out.println("获取HTTP版本号:" + protocol);
    // 获取webapp名字(站点名)
    String webapp = req.getContextPath();
    System.out.println("获取webapp:" + webapp);
    
    方法名 描述
    getParaMeter(name) 获取指定名称的参数
    getParamerterValues(String name) 获取指定名称参数的所有值
    setCharcterEncoding("UTF-8") 针对POST乱码问题的处理方式
    // 针对POST乱码问题的处理方式
    req.setCharacterEncoding("UTF-8");
    // 获取指定名称的参数,返回字符串
    String uname = req.getParameter("uname");
    System.out.println("uname的参数:" + uname);
    // 获取指定名称参数的所有参数值,返回数组
    String[] hobbys = req.getParameterValues("hobby");
    System.out.println("获取指定名称参数的所有参数值:" + Arrays.toString(hobbys));
    

    请求转发

    请求转发表示由 多个Servlet共同来处理一个请求 。例如Servlet1来处理请求,然后Servlet1又转发给Servlet2来继续处理这个请求。

    public class AServlet extends HttpServlet { 
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
            System.out.println("AServlet"); 
            RequestDispatcher rd = request.getRequestDispatcher("/BServlet"); 
            rd.forward(request, response); 
        }
    }
    
    public class BServlet extends HttpServlet { 
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
            System.out.println("BServlet"); 
        } 
    }
    

    request域方法

    一个请求会建一个request对象,如果在一个请求中经历了多个Servlet,那么多个Servlet就可以使用

    request来共享数据。

    下面是request的域方法:

    1. void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,
    2. Object getAttribute(String name):用来获取request中的数据,当前在获取之前需要先去存储才行,例如:String value = (String)request.getAttribute(“xxx”);,获取名为xxx的域属性;
    3. void removeAttribute(String name):用来移除request中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
    4. Enumeration getAttributeNames():获取所有域属性的名称;

    域方法通常在进行重定向时使用,多个servlet共享数据。

    RESPONSE

    概述

    response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse。在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作。

    response对象的功能分为以下四种:

    • 设置响应头信息;
    • 发送状态码;
    • 设置响应正文;
    • 重定向;

    响应正文

    response是响应对象,向客户端输出响应正文(响应体)可以使用response的响应流,repsonse一共提供了两个响应流对象:

    • PrintWriter out = response.getWriter():获取字符流,处理字符;
    • ServletOutputStream out = response.getOutputStream():获取字节流,处理文件;

    在一个请求中,不能同时使用这两个流!也就是说,要么你使用repsonse.getWriter(),要么使用response.getOutputStream(),但不能同时使用这两个流。不然会抛出IllegalStateException异常。

    public class Servlet01 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            /**
             * 字符输出流
             */
            PrintWriter writer = resp.getWriter();
            writer.write("<h2>你好</h2>");
            writer.flush();
            writer.close();
    
            /**
             * 字节输出流
             */
            ServletOutputStream out = resp.getOutputStream();
            out.write("你好".getBytes());
            out.write("<h2>你好</h2>".getBytes());
            out.flush();
            out.close();
        }
    }
    

    响应乱码问题

    * 字符流
    * getWriter()
    *      一定会乱码,应为服务器默认的解析编码时ISO-8869-1,该编码不支持中文
    *
    * 字节流
    * getOutputStream()
    *      可能乱码,当前服务器的编码与客户端的编码不一致时,会出现乱码
    *      
    * 解决方案
    *          1.设置服务端的编码格式
    *          2.设置客户端的编码格式
    * 总结:
    *      设置客户端和服务端的编码格式保持一致,且支持中文
    *      响应json格式的数据时,设置响应类型为application/json
    
    public class Servlet02 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //方法一
            //同时设置客户端和服务端的编码
            resp.setContentType("text/html;charset=UTF-8");
    
    	    //方法二
            //设置服务端的编码格式
            resp.setCharacterEncoding("UTF-8");
            //设置客户端的编码格式
            resp.setHeader("content-type","text/html;charset=UTF-8");
    
            PrintWriter writer = resp.getWriter();
            writer.write("<h2>你好</h2>");
            writer.flush();
            writer.close();
        }
    }
    

    重定向

    设置状态码重定向

    响应码为200表示响应成功,而响应码为302表示重定向。所以完成重定向的第一步就是设置响应码为302。

    因为重定向是通知浏览器再第二个请求,所以浏览器需要知道第二个请求的URL,所以完成重定向的第二步是设置Location头,指定第二个请求的URL地址。

    public class Servlet03 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ///设置状态码重定向
            resp.setStatus(302);
            resp.setHeader("Location","http://www.baidu.com");
        }
    }
    

    便捷重定向

    public class Servlet03 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //便捷重定向
            resp.sendRedirect("http://www.baidu.com");
            //如果要重定向的URL是在同一个服务器内,那么可以使用相对路径,例如:
            resp.sendRedirect("/serspn/ser04");
        }
    }
    

    重定向小结

    • 重定向是两次请求,请求转发是一次
    • 重定向的URL可以是其他应用,不局限于当前应用;
    • 重定向的响应头为302,并且必须要有Location响应头;
    • 重定向就不要再使用response.getWriter()或response.getOutputStream()输出数据,不然可能会出现异常;

    请求转发与重定向的区别

    • 重定向是两次请求,转发是一个请求
    • 重定向是浏览器的行为,请求转发是服务器行为
    • 重定向浏览器的地址会发生改变,转发不会
    • 重定向可以重定向到任何地址,转发只能在项目内转发

    Cookie对象

    Cookie的创建和发送

    通过new Cookie("key" , "value");来创建一个Cookie对象,要想将Cookie随响应发送到客户端,需要先添加到response对象中,response.addCookie(cookie);此时该Cookie对象随着响应发送到客户端,在浏览器上可以看见

    public class scookie01 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //创建Cookie
            Cookie cookie = new Cookie("name","zhangsan");
            //发送cookie
            resp.addCookie(cookie);
        }
    }
    

    image-20210307195306092

    Cookie的获取

    在服务器端只提供了一个getCookie()方法用来获取客户端回传的所有cookie组成的一个数组,如果需要获取单个cookie则需要通过遍历,getName()获取Cookie的名称getValue()获取Cookie值

    public class SCookie02 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Cookie[] cookies = req.getCookies();
            if (cookies != null & cookies.length > 0){
                for (Cookie cookie : cookies){
                    System.out.println(cookie.getName());
                    System.out.println(cookie.getValue());
                }
            }
        }
    }
    

    Cookie设置到期时间

    默认当前浏览器关闭即失效。我们可以手动设定cookie的有效时间(通过到期时间计算),通过setMaxAge(int time);方法设定cookie的最大有效时间,以秒为单位

    负整数

    cookie的maxAge属性的默认值就是-1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那么cookie就会消失

    正整数

    表示cookie对象可存活指定的秒数,当生命大于0时,浏览器会把Cookie保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie也会存活相应的时间

    表示cookie作废,如果原来浏览器已经保存了这个Cookie,那么可以通过setMaxAge(0)来删除这个Cookie

    public class SCookie03 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Cookie cookie = new Cookie("aa","AAA");
            // 负整数,表示浏览器关闭即失效
            //cookie.setMaxAge(-1);
            // 正整数,表示存活指定秒数
            //cookie.setMaxAge(15);
            // 零,表示删除cookie
            cookie.setMaxAge(0);
            //响应cookie
            resp.addCookie(cookie);
            
            // 删除已有cookie
            Cookie cookie1 = new Cookie("name", null);
            cookie1.setMaxAge(0);
            resp.addCookie(cookie1);
    
        }
    }
    

    Cookie的注意点

    输入中文

    public class SCookie04 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String name = "姓名";
            String value = "李青";
            // 通过URLEncoder.encode()进行编码
            name = URLEncoder.encode(name);
            value = URLEncoder.encode(value);
            // 创建Cookie对象
            Cookie cookie = new Cookie(name, value);
            // 发送Cookie对象
            resp.addCookie(cookie);
        }
    }
    

    同名问题

    如果浏览器发送重复的Cookie会覆盖原有的Cookie

    浏览器存放Cookie的数量

    不同的浏览器对Cookie有限定,Cookie的存储是有上限的。Cookie是存储在客户端(浏览器)的,而且一般是由服务器创建和设定。后期结合Session来实现回话跟踪。

    Cookie的路径

    public class SCookie06 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //当前项目下的资源可获取Cookie对象(默认不设置Cookie的path)
            Cookie cookie = new Cookie("a1", "A1");
            resp.addCookie(cookie);
    
            // 当前服务器中,任意资源都可以访问
            Cookie cookie1 = new Cookie("a2", "A2");
            cookie1.setPath("/");
            resp.addCookie(cookie1);
    
            //指定目录下的资源可以获取Cookie对象
            Cookie cookie2 = new Cookie("a3", "A3");
            cookie2.setPath("/serspn/test/scok02");
            resp.addCookie(cookie2);
    
            //指定项目下的资源可获取Cookie对象(指定站点名)
            Cookie cookie3 = new Cookie("a4", "A4");
            cookie3.setPath("/ser");
            resp.addCookie(cookie3);
        }
    }
    

    HttpSession对 象

    基本使用

    public class Session01 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取Session对象(如果session对象不存在,则新建session对象;如果session存在,则获取session对象)
            HttpSession session = req.getSession();
            //获取session的标识符
            System.out.println(session.getId());
            //获取第一次访问时间
            System.out.println(session.getCreationTime());
            //获取最后一次访问时间
            System.out.println(session.getLastAccessedTime());
            //是否是新的session对象
            System.out.println(session.isNew());
            //设置session域对象(一次对话有效)
            session.setAttribute("uname","admin");
            //获取指定名称的session域对象
            String uname = (String) req.getAttribute("uname");
            //移除指定名称的session域对象
            session.removeAttribute("uname");
        }
    }
    

    session对象的销毁

    默认时间到期

    Tomcat中conf目录下的web.xml文件中进行修改

        <session-config>
            <session-timeout>30</session-timeout>
        </session-config>
    

    自己设定到期时间

    通过session.setMaxInactiveInterval(int)来设定session的最大活动时间,单位为秒

    //获取session对象
    HttpSession session = req.getSession();
    //设置session的最大活动时间
    session.setMaxInactiveInterval(15);
    //获取session的最大不活动时间
    int time = session.getMaxInactiveInterval();       
    

    立刻失效

    //销毁session对象
    session.invalidate();
    

    关闭浏览器

    seesion的底层依赖cookie实现,cookie的有效时间为关闭浏览器,从而seesion在浏览器关闭时也会失效

    关闭浏览器

    关闭服务器意味着此次会话结束,数据共享结束

    ServletContext对象

    public class ServletContext extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //通过request获取对象
            javax.servlet.ServletContext servletContext = req.getServletContext();
            //通过Session获取
            javax.servlet.ServletContext servletContext1 = req.getSession().getServletContext();
            //通过ServletConfig对象获取
            javax.servlet.ServletContext servletContext2 = getServletConfig().getServletContext();
            //直接获取
            javax.servlet.ServletContext servletContext3 = getServletContext();
    
            //常用方法
            //获取服务器版本信息
            String serverInfo = servletContext.getServerInfo();
            System.out.println("获取服务器的版本信息:" + serverInfo);
    
            //获取项目的真实路径
            String realPath = servletContext.getRealPath("/");
            System.out.println("获取项目的真实路径:" + realPath);
        }
    }
    
    

    Servlet三大作用域

    request域对象
    再一次请求中有效,请求妆发有效,重定向有效
    session域对象
    在一次会话中有效,请求转发和重定向都有效,seesion销毁后失效
    servletContext域对象
    在整个应用程序中有效,服务器关闭后失效
    
  • 相关阅读:
    UVA 10618 Tango Tango Insurrection
    UVA 10118 Free Candies
    HDU 1024 Max Sum Plus Plus
    POJ 1984 Navigation Nightmare
    CODEVS 3546 矩阵链乘法
    UVA 1625 Color Length
    UVA 1347 Tour
    UVA 437 The Tower of Babylon
    UVA 1622 Robot
    UVA127-"Accordian" Patience(模拟)
  • 原文地址:https://www.cnblogs.com/youngleesin/p/14466491.html
Copyright © 2011-2022 走看看