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域对象
在整个应用程序中有效,服务器关闭后失效
原文地址:https://www.cnblogs.com/youngleesin/p/14466491.html