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域对象
    在整个应用程序中有效,服务器关闭后失效
    
  • 相关阅读:
    flask全栈开发3 模板
    flask全栈开发2 URL与视图
    flask全栈开发1 课程简介
    微信公众号开发中遇到的问题总结
    python web学习路线
    内存数据库Memcached和redis基本使用
    2019年8月12号成长题目
    2019年8月10号成长题目
    2019年8月7号成长题目
    SpringCloud简介与5大常用组件
  • 原文地址:https://www.cnblogs.com/youngleesin/p/14466491.html
Copyright © 2011-2022 走看看