Java基础 - servlet(一)

1、servlet应用实例

1、客户端提交一个表单数据访问服务端的整个流程图:

​ 客户端访问add.html页面并通过Http Request携带表单请求数据,通过web.xml中的映射关系,找到AddServlet类中的doPost方法,并执行该方法。
在这里插入图片描述

2、编写一个add.html表单提交页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="add" method="post">
        名称: <input type="text" name="fname"/></br/>
        价格: <input type="text" name="price"/></br/>
        库存: <input type="text" name="fcount"/></br/>
        备注: <input type="text" name="remark"/></br/>
        <input type="submit" value="添加" />
    </form>
</body>
</html>

3、提交表单到AddServlet类,问题,add方法是如何映射到AddServlet类中的方法的?

  • 在web.xml中配置映射关系

​ 1、用户发送请求,action=add
​ 2、项目中,web.xml中找到url-pattern = /add ->第12行
​ 3、找到第11行的servlet-name = AddServlet
​ 4、找和servlet-mapping中servlet-name一致的servlet,找到第8行
​ 5、再找到第9行servlet-class = com.atguigu.servlets.AddServlet
​ 6、用户发送的是post请求(method=post),因此tomcat会执行AddServlet类中的doPost方法

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>AddServlet</servlet-name>
        <servlet-class>com.atguigu.servlets.AddServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>AddServlet</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>

    <!--
        1、用户发送请求,action=add
        2、项目中,web.xml中找到url-pattern = /add  ->第12行
        3、找到第11行的servlet-name = AddServlet
        4、找和servlet-mapping中servlet-name一致的servlet,找到第8行
        5、再找到第9行servlet-class = com.atguigu.servlets.AddServlet
        6、用户发送的是post请求(method=post),因此tomcat会执行AddServlet类中的doPost方法
    -->
</web-app>

4、AddServlet类

  • 该类需要继承javax.servlet.http中的HttpServlet类
  • 由于表单提交时选择的是post方式请求,所有就会调用该类的doPost方法
  • HttpServletRequest request对象就可以获取到表单提交的数据
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 AddServlet extends HttpServlet {

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fname = request.getParameter("fname");
        String priceStr = request.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String fcountStr = request.getParameter("fcount");
        int fcount = Integer.parseInt(fcountStr);
        String remark = request.getParameter("remark");
        System.out.println("fname:" + fname);
        System.out.println("price:" + price);
        System.out.println("fcount:" + fcount);
        System.out.println("remark:" + remark);

    }

}

页面:
在这里插入图片描述

打印结果:

fname:apple
price:5
fcount:30
remark:ok

2、servlet中处理中文乱码问题

  • post请求
    设置字符编码。防止中文乱码,需要注意的是,设置编码这一句代码必须在所有的获取参数动作之前

    request.setCharacterEncoding("UTF-8");
    String fname = request.getParameter("fname");
    
  • get请求

    在tomcat8之后不需要处理。

3、servlet的继承关系

3.1 继承关系
javax.servlet.Servlet接口
	javax.servlet.GenericServlet抽象类
		javax.servlet.http.HttpServlet抽象子类

1、javax.servlet.http.HttpServlet抽象子类:

  • void service(request.response) --不是抽象的

    • protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              String method = req.getMethod(); // 获取请求方式
              long lastModified;
              if (method.equals("GET")) {
                  lastModified = this.getLastModified(req);
                  if (lastModified == -1L) {
                      this.doGet(req, resp);
                  } else {
                      long ifModifiedSince;
                      try {
                          ifModifiedSince = req.getDateHeader("If-Modified-Since");
                      } catch (IllegalArgumentException var9) {
                          ifModifiedSince = -1L;
                      }
      
                      if (ifModifiedSince < lastModified / 1000L * 1000L) {
                          this.maybeSetLastModified(resp, lastModified);
                          this.doGet(req, resp);
                      } else {
                          resp.setStatus(304);
                      }
                  }
              } else if (method.equals("HEAD")) {
                  lastModified = this.getLastModified(req);
                  this.maybeSetLastModified(resp, lastModified);
                  this.doHead(req, resp);
              } else if (method.equals("POST")) {
                  this.doPost(req, resp);
              } else if (method.equals("PUT")) {
                  this.doPut(req, resp);
              } else if (method.equals("DELETE")) {
                  this.doDelete(req, resp);
              } else if (method.equals("OPTIONS")) {
                  this.doOptions(req, resp);
              } else if (method.equals("TRACE")) {
                  this.doTrace(req, resp);
              } else {
                  String errMsg = lStrings.getString("http.method_not_implemented");
                  Object[] errArgs = new Object[]{method};
                  errMsg = MessageFormat.format(errMsg, errArgs);
                  resp.sendError(501, errMsg);
              }
      
          }
      
    • 各种if判断,根据请求方式不同,决定去调用不同的do方法

    • 在HttpServlet这个抽象类中,do方法都差不多

      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              String msg = lStrings.getString("http.method_post_not_supported");
              this.sendMethodNotAllowed(req, resp, msg);
          }
      
      
      private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {
              String protocol = req.getProtocol(); // 获取协议
              if (protocol.length() != 0 && !protocol.endsWith("0.9") && !protocol.endsWith("1.0")) {
                  resp.sendError(405, msg);
              } else {
                  resp.sendError(400, msg);
              }
      
          }
      

    2、 浏览器页面出现405的原因

    ​ 1)在AddServlet类中没有doGet()方法

    ​ 2)页面模拟发送get请求,断点调试

    由于是get请求,所有会执行HttpServlet类中service()方法中的doGet()方法
    在这里插入图片描述

    进入到doGet()方法
    在这里插入图片描述

    sendMethodNotAllowed()方法
    在这里插入图片描述

    页面显示
    在这里插入图片描述

3、小结

​ 1)继承关系:HttpServlet -> GenericServlet -> Servlet

​ 2)Servlet中的核心方法:init(),service(),destroy()

​ 3)服务方法:当有请求过来时,service方法会在那个响应(其实是tomcat容器调用的)

​ 在HttpServlet中我们会去分析请求的方式:到底是get、post、head、delete方法等等

​ 然后再决定调用的是哪个do开头的方法

​ 那么在HttpServlet中这些do方法默认都是405实现风格 - 要我们子类去实现对应的方法,否则默认会把405错误。

​ 4)因此,在新建Servlet时,我们才会去考虑请求方法,从而决定重写哪个do方法。

4、Servlet的生命周期

1)生命周期:从出生到死亡的过程就是生命周期。对应Servlet中的三个方法:init(),service() ,destroy()方法

2)默认情况下:

  • 第一次接收请求时,这个Servlet会进行实例化(调用构造方法)、初始化(调用init()方法)、然后服务(调用service()方法)
  • 从第二次请求开始。每一次都是调用服务方法
  • 当容器关闭时,其中的所有的servlet实例会被销毁,调用销毁方法

3)通过案例发现:

  • Servlet实例tomcat只会创建一个实例,所有的请求都是这一个实例去响应。
  • 默认情况下,第一次请求时,tomcat才会去实例化,初始化,然后再服务,这样的好处提高服务的启动速度;缺点是第一次请求时耗时较长。
  • 因此得出结论:如果需要提高系统的启动速度,当前默认情况就是这样。如果需要提高响应速度,我们应该设置Servlet启动时机。

4)Servlet的初始化时机

  • 默认是第一次接收请求时,实例化,初始化

        <servlet>
            <servlet-name>DemoServlet</servlet-name>
            <servlet-class>com.atguigu.servlets.DemoServlet</servlet-class>
            <!-- servlet启动的优先级,load-on-startup的值越小优先级越高 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
    

5)Servlet在容器中是:单例的、线程不安全的

  • 单例:所有的请求都是同一个实例去响应
  • 线程不安全:一个线程需要根据这个实例中的某个成员变量值去做逻辑判断。但是在中间某个时机,另外一个线程改变了这个值,从而导致这个线程的执行逻辑发生改变。
  • 因为servlet是线程不安全的,尽量不要在servlet中定义成员变量。如果不得不定义成员变量的值,① 那么不要去根据成员变量的值做一些逻辑判断。

5、HTTP协议

​ 1)Http称之为 超文本传输协议

​ 2)HTTP是无状态的

​ 3)HTTP包含两部分:请求和响应

  • 请求:

    请求包含三个部分:1.请求行;2.请求消息头;3.请求主体

    ​ 1)请求行包含三个信息:1.请求的方式;2.请求的URL;3.请求的协议(一般都是HTTP1.1)

    ​ 2)请求消息头包含很多客户端浏览器需要告诉服务器的信息。比如:浏览器的型号、版本…

    ​ 3)请求主体,三种情况

    ​ get方式,没有请求体,但是有一个queryString

    ​ post方式,有请求体,form data

    ​ json格式,有请求体,request payload

  • 响应

    响应也包含三部分:1.响应行;2.响应头;3.响应体

    1)响应行包含三个信息:1.协议 ;2.响应状态码(200);3.响应状态(ok)

    2)响应头:包含服务器的信息;服务器发送给浏览器的信息

    3)响应体:响应的实际内容(比如请求add.html页面时,响应的内容就是 …)

6、会话机制

6.1 案例分析

1、servlet类

public class Demo02Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        System.out.println("session ID:" + session.getId());
    }
}

2、web.xml

    <servlet>
        <servlet-name>Demo02Servlet</servlet-name>
        <servlet-class>com.atguigu.servlets.Demo02Servlet</servlet-class>
        <!-- servlet启动的优先级 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Demo02Servlet</servlet-name>
        <url-pattern>/demo02</url-pattern>
    </servlet-mapping>

3、浏览器请求,服务端生成sessionID,第一次会放到响应头里面返回给客户端浏览器
在这里插入图片描述

浏览器响应头中的JSSIONID就是服务器生成的并返回给浏览器的
在这里插入图片描述

浏览器第二次请求时,打印断点查看session信息,发现session信息不是新的,还是第一次创建时的那个session
在这里插入图片描述

第二次查看浏览器时发现在响应头里面就没有了JSESSIONID,此时的JSESSIONID放到了请求头的Cookie里面啦。
在这里插入图片描述

6.2 会话跟踪技术

1)客户端第一次发请求给服务器,服务器获取session,获取不到,则创建新的,然后响应给客户端浏览器。下次客户端给服务器发请求时,会把sessionID带给服务器,那么服务器就能获取到,服务器就可以判断这一次请求和上一次请求是同一个客户端,从而能够区分开。

6.3 session保存作用域
  • session保存作用域和具体的某一个session对应的

  • 常见的API

    void session.setAttribute(k,v);
    Object session.getAttribute(k)
    

在这里插入图片描述

1、demo03Servlet:向session中设置值

public class Demo03Selrvlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().setAttribute("uname","zhangsan");
    }
}

2、demo04Servlet:从session中获取值

public class Demo04Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object uname = request.getSession().getAttribute("uname");
        System.out.println(uname);
    }
}

3、第一次通过edgn浏览器请求demo03,向HttpSession里面设置值,再使用同样的浏览器访问demo04从HttpSession中获取值,发现可以获取到值。

在这里插入图片描述

4、再换用chrome浏览器请求demo04,发现没有获取到值。
在这里插入图片描述

7、服务器内部转发以及客户端重定向

7.1 服务器内部转发

一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的。
在这里插入图片描述

客户端请求demo06,执行以上代码,程序将会转发到demo07中执行代码,并由demo07返回结果给客户端。

代码演示:

Demo05Servlet:

public class Demo05Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo05.....");
        // 服务器端内部转发
        request.getRequestDispatcher("demo06").forward(request,response);
    }
}

Demo06Servlet:

public class Demo06Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo06......");
    }
}

客户端请求访问demo05,服务端首先请求demo05,在转发到demo06,客户端地址栏URL不会改变,整个过程客户端是不知道的

打印结果:
在这里插入图片描述

7.2 客户端重定向

两次请求响应的过程,客户端知道请求URL有变化。
在这里插入图片描述

代码:

public class Demo05Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo05.....");
        // 演示客户端重定向
        response.sendRedirect("demo06");
    }
}
public class Demo06Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo06......");

    }
}

客户端请求demo05,发现地址栏的URL变为demo06了。
在这里插入图片描述

8、保存作用域

8.1 保存作用域

​ 原始情况下,保存作用域我们可以认为有四个

​ 1)page(页面级别,现在几乎不用)

​ 2)request(一次请求响应范围)

​ 3)session(一次会话范围)

​ 4)application(整个应用范围)

8.1.1 request(一次请求响应范围)

(1)客户端重定向,这种方式是获取不到demo01中设置的数据,原因是服务器内部使用的是客户端请求转发,是两次请求,所以不在一个请求的作用域里面,请求1和响应1是一个请求流程,请求2是另外一个流程。

在这里插入图片描述

​ 代码demo01:

public class Demo01Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 演示request作用域
         *
         */
        // 向request作用域中添加数据
        request.setAttribute("name","lili");
        // 客户端重定向
        response.sendRedirect("demo02");
    }
}

demo02:

public class Demo06Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo06......");
        Object name = request.getAttribute("name");
        System.out.println("name===>" + name);
    }
}

打印结果:
在这里插入图片描述

(2)服务器请求转发
在这里插入图片描述

demo01:

public class Demo01Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 向request作用域中添加数据
        request.setAttribute("name","lili");

        // 服务器端转发
        request.getRequestDispatcher("demo06").forward(request,response);
    }
}

打印结果:
在这里插入图片描述

8.1.2 session

​ 一次会话范围有效
在这里插入图片描述

8.1.3 application

一次应用程序范围有效
在这里插入图片描述

9、路径问题

9.1 相对路径
../ 表示返回到上一级
``
![在这里插入图片描述](https://img-blog.csdnimg.cn/7a6f2d5470e4440ab1b3ced5afd7b31e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP5ZGY6ICB55-z,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)




#### 9.2 绝对路径

![在这里插入图片描述](https://img-blog.csdnimg.cn/d7163d35565c4cbd88825c6eeca20e34.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP5ZGY6ICB55-z,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)




### 10、Filter过滤器
![在这里插入图片描述](https://img-blog.csdnimg.cn/f21295caabbf49f382c3fac02ee15941.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP5ZGY6ICB55-z,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)


1)Filter也属于Servlet规范

2)Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy

3)配置Filter,可以用注解@WebFilter,也可以使用xml文件<filter> <filter-mapper>

4)**Filter在配置时,和servlet一样,也可以配置通配符,如:@WebFilter("*.do"):表示拦截所有以.do结尾的请求**

代码:

* Filter过滤器

  @WebFilter("*.do")

  ```java
  @WebFilter("/demo07.do")
  public class Demo07Filter implements Filter {
  
      @Override
      public void init(FilterConfig filterConfig) throws ServletException {
  
      }
  
      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
          System.out.println("helloA");
          // 放行
          filterChain.doFilter(servletRequest,servletResponse);
  
          System.out.println("helloA2");
      }
  
      @Override
      public void destroy() {
  
      }
  }
  • Demo07Servlet

    @WebServlet("/demo07.do")
    public class Demo07Servlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("执行demo07.....");
            request.getRequestDispatcher("add.html").forward(request,response);
        }
    }
    

    打印结果:
    在这里插入图片描述

5)过滤器链

  • 如果采用的是注解的方式进行配置,那么过滤器链拦截顺序是按照全类名的先后顺序排序的
  • 如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序的

在这里插入图片描述

filter01

@WebFilter("*.do")
public class Filter01 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("A");
        // 放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("A2");
    }
}

filter02

@WebFilter("*.do")
public class Filter02 implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("B");
        // 放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("B2");
    }

}

filter03

@WebFilter("*.do")
public class Filter03 implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("C");
        // 放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("C2");
    }

}

demoServlet

@WebServlet("/demo07.do")
public class Demo07Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("执行demo07.....");
        request.getRequestDispatcher("add.html").forward(request,response);
    }
}

打印结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值