学习Servlet看这一篇就够了

Servlet入门

1.概念

server applet 运行在服务器端的小程序

  • Servlet就是一个接口规范,定义了Java类被浏览器访问(tomcat所识别)的规则

  • 如果我们需要自定义一个类被tomcat所识别 需要实现Servlet接口 重写其抽象方法

在这里插入图片描述

2.快速入门

  1. 创建一个JavaEE项目

  2. 定义一个类 实现Servlet接口

  3. 重写其抽象方法

  4. 配置Servlet

    在 web.xml中配置以下信息

<!--将自定义的Servlet类配置到web.xml中以便于 tomcat运行时能够识别该类  ServletDemo01 -->
<servlet>
	<servlet-name>demo1</servlet-name>  <!--别名 随意取-->
	<servlet-class>com.huike.web.servlet.ServletDemo01</servlet-class>   <!--自定义类的全限定类名-->
</servlet>
		
<!--servlet的映射标签  每一个Servlet类都需要有一个映射标签 -->
<servlet-mapping>
	<servlet-name>demo1</servlet-name>  <!--别名 需要跟上面的一致-->
	<url-pattern>/demo1</url-pattern>      <!-- 虚拟路径 url中要访问该类应该写的路径-->
</servlet-mapping>

3.执行原理

  1. 当服务器接收到客户端浏览器的请求后 会解析对应的url路径 获取访问的Servlet的资源路径(虚拟目录/demo1)
  2. 查找web.xml文件,是否有对应的标签体内容与之一致.
  3. 如果有, 则再找到对应的的全类名
  4. tomcat会将字节码文件加载至内存,创建该类对象,调用该类的方法

在这里插入图片描述

4.Servlet的生命周期

  1. 被创建:执行init方法 只执行一次

    • Servlet什么时候被创建? 第一次访问时被创建且只会被创建一次

    • 可以通过进行相关配置去修改Servlet创建的时间

      <servlet>
           <servlet-name>demo1</servlet-name>  <!--别名 随意取-->
           <servlet-class>com.huike.servlet.AnnoServlet</servlet-class>   <!--自定义类的全限定类名-->
           <!--默认为-1    负数(默认值)代表第一次访问被创建    0或者正数代表服务器启动时创建-->
           <load-on-startup>1</load-on-startup>
      </servlet>
      
      <!--servlet的映射标签  每一个Servlet类都需要有一个映射标签 -->
      <servlet-mapping>
           <servlet-name>demo1</servlet-name>  <!--别名 需要跟上面的一致-->
           <url-pattern>/demo1</url-pattern>      <!-- 虚拟路径 url中要访问该类应该写的路径-->
      </servlet-mapping>
      
    • Servlet在内存中只存在一个对象

      Servlet的init方法只执行一次 说明一个Servlet在内存中只会存在一个对象 Servlet是单例模式的

    • 多个用户同时访问同一个Servlet资源的时候,会存在并发问题(线程安全问题)

      解决方案:尽量不要在service方法中访问成员变量 不要修改成员变量的值

  2. 提供服务:执行service方法,执行多次

    每次访问Servlet时,都会执行一次

  3. 被销毁:执行destory方法,只执行一次

    • Servlet被销毁时执行,服务器关闭时,Servlet会被销毁
    • 只有服务器正常关闭时才会执行该方法
    • destory方法在Servlet销毁前执行 一般用于资源的释放

5.Servlet的优化

  1. Servlet3.0及其以上版本 和 Servlet3.0以下版本的区别

    • 以上版本 支持注解配置的,不需要配置文件了
  2. Servlet3.0以上版本使用注解创建项目的步骤

    1.创建JavaEE项目 选择3.0版本以上 不需要再创建web.xml文件了

    2.定义一个类 实现Servlet接口 实现其方法

    3.在类上使用@WebServlet注解即可

  3. 注解的优化

<servlet>
	<servlet-name>demo1</servlet-name>  <!--别名 随意取-->
	<servlet-class>com.huike.web.servlet.ServletDemo01</servlet-class>   <!--自定义类的全限定类名-->
	<load-on-startup>5</load-on-startup> <!-- 修改Servlet创建的时间 -->
</servlet>
		
<servlet-mapping>
	<servlet-name>demo1</servlet-name>  <!--别名 需要跟上面的一致-->
	<url-pattern>/demo1</url-pattern>      <!-- 虚拟路径 url中药访问该类应该写的路径-->
</servlet-mapping>


<!-- @WebServlet注解: -->
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
String name() default "";  //相当于<servlet-name>标签

String[] value() default {};   //相当于<url-pattern>标签  String[]  注意是个数组
								  //两个作用差不多
String[] urlPatterns() default {};  //相当于<url-pattern>标签  String[] 注意是个数组

int loadOnStartup() default -1;  //相当于<load-on-startup>标签

WebInitParam[] initParams() default {};

boolean asyncSupported() default false;

String smallIcon() default "";

String largeIcon() default "";

String description() default "";

String displayName() default "";
}
//元注解(描述注解的注解(注解前面的注解))复习:
@Target:描述注解能够作用的位置
	ElementType取值:
		TYPE:可以作用于类上
        FIELD:可以作用于成员变量上
		METHOD:可以作用于方法上
@Retention:描述注解被保留的阶段
	SOURCE:	源代码阶段, 被编译器忽略
	CLASS:  注解将会被保留在Class文件中,但在运行时并不会被JVM保留。这是默认行为,所有没有用Retention注解的注解,都会采用这种策略。
	RUNTIME:保留至运行时。所以我们可以通过反射去获取注解信息。
	@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
        
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承

注解默认只有一个属性,且为value则可以省略

//以下三种相同
@WebServlet("/annoServlet")
@WebServlet(urlPatterns = "/annoServlet")
@WebServlet(value = "/annoServlet")

//因为 urlPatterns和value是个数组,所以可以
@WebServlet("/annoServlet1","/annoServlet2","/annoServlet3")
//Servlet访问路径
@WebServlet("/annoServlet")    //1.
@WebServlet("/annoServlet/a")  //2.
@WebServlet("/annoServlet/*")  //3.通配符,路径为/annoServlet/XXX  什么都可以访问
@WebServlet("/*")  //3.通配符,/XXX  什么都可以访问
@WebServlet("*.d")  //4.后缀名匹配  /XXX.d

6.IDEA和tomcat的相关配置信息的底层原理

  • Q:IDEA会将项目部署到tomcat当中,到底采用的是哪一种方式呢?

    答:IDEA会为tomcat部署的每一个项目单独建一份配置文件,文件所在的目录就是控制台上 log输出的"CATALINA_BASE"目录

在这里插入图片描述

  • Q:工作空间的项目 和 tomcat中部署的项目 是不是同一个项目呢?

    答:不是同一个,tomcat真正访问的是"tomcat中部署的项目"

  • Q:工作空间的项目 和 tomcat中部署的项目 有什么区别呢?

    答:“tomcat中部署的项目” 其实就是 "工作空间的项目"中的web目录下的所有资源

  • 注意事项: WEB-INF目录下的资源是不能被浏览器所访问的

7.Servlet的体系结构

在这里插入图片描述

体系结构:
    Servlet:接口
        |实现类
    GenericServlet:抽象类 不怎么常用
        |子类
    HttpServlet:抽象类 (最常用 重点掌握)
        |
    自定义servlet

servlet常用方法:
    void init(ServletConfig config):初始化
    void service(ServletRequest request,ServletResponse response):服务 处理业务逻辑
    void destroy():销毁
    ServletConfig getServletConfig():获取当前servlet的配置对象

GenericServlet常用方法: 
    将Servlet接口中其他的方法做了默认的空实现,只将service()方法作为抽象
    空参的Init() 若我们自己想对servlet进行初始化操作,重写这个init()方法即可
    将来定义Servlet类的时候,只需要继承GenericServlet 重写其中的service()方法即可

HttpServlet常用方法:对HTTP协议的一种封装 可以简化我们的操作
		1. 定义一个类继承HttpServlet
		2. 重写其中的doGet()/doPost()方法
    service做了实现,把参数强转,调用了重载的service方法
        重载的service方法获取请求的方式,根据请求方式的不同调用相应doXxx()方法
    doGet和doPost方法

在这里插入图片描述


HTTP

1.概念:超文本传输协议

  • 传输协议:客户端和服务器端通信时发送数据的格式
  • 特点:
    1. 基于TCP/IP的高级协议
    2. 默认端口号:80
    3. 基于请求/响应模型的 发送一次请求,对应一次响应(一对一)
    4. 无状态的:每一次请求和响应之间互相独立的,不干扰的,所以无法进行多次请求之间的数据交互
  • 发展史(历史版本):
    • 1.0:每一次请求和响应都会建立一个新的连接
    • 1.1:进行连接的复用 (类似于线程和线程池的关系)

2. 请求数据的数据格式 request

1.请求行

  • 格式: 请求方式 请求url 请求协议/版本

    • GET /login.html HTTP/1.1
  • 请求方式:

    • HTTP协议中共有7种请求方式,常用的有两种

      GET: 无请求体

      1. 请求参数在请求行中,在url的后面 多个请求参数以&连接

        username=yzc123&password=123456

      2. 请求的url长度是有限制的

      3. 不太安全的

      POST:有请求体

      1. 请求参数在请求体中
      2. 请求的url长度是没有限制的
      3. 相对比较安全

2.请求头

客户端浏览器告诉服务器一些信息

  • 格式: 属性名:属性值

  • 包含若干个属性,服务端据此获取客户端的信息。与缓存相关的规则信息,均包含在header中

  • 常见的请求头:

    1. User-Agent:浏览器要告诉服务器,我访问你使用的浏览器相关的版本信息

    作用: 可以在服务器的代码中通过request对象获取该头的信息,解决浏览器之间的兼容性问题

    1. Referer:http://localhost/05_12_servlet/login.html A页面跳转到B页面 会发送一个请求 代表A页面的url地址

    含义:告诉服务器,该请求是从哪个页面跳转过来的

    作用:

    1. 统计数据  在百度|新浪|谷歌投放广告  我们可以通过Referer去判断该用户是从哪个地方跳转过来的,从而比较其性价比
    2. 防盗链:防止盗取链接操作
    

3.请求空行

  • 本质上就是一个空行 主要是用于分割POST请求的请求头和请求体的

4.请求体(正文)

  • 封装了POST请求消息的参数的
  • 将一个页面表单中的组件值通过param1=value1&param2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。

在这里插入图片描述

在这里插入图片描述


request

1.request对象和response对象的执行原理

  • request对象和response对象都是由服务器创建的

  • 我们可以用request对象获取请求数据信息, 用response对象设置响应数据信息

2.request对象继承体系结构

ServletRequest --接口
| 继承
HttpServletRequest – 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat提供的)

3.request功能

在这里插入图片描述

1.获取请求消息数据

1.获取请求行数据
  • GET /login.html HTTP/1.1

  • 方法:

    1. 获取请求方式 GET

    String getMethod()

    1. 获取虚拟目录: /05_12_servlet 重要

    String getContextPath()

    1. 获取Servlet路径: /servletDemo01

    String getServletPath()

    1. 获取get方式的请求参数: username=123

    String getQueryString()

    1. 获取请求URI: /05_12_servlet/servletDemo01

    String getRequestURI() : /05_12_servlet/servletDemo01

    StringBuffer getRequestURL() : http://localhost/05_12_servlet/servletDemo01

    • URI:统一资源标识符
    • URL:统一资源定位符
    1. 获取协议及其版本号: HTTP/1.1

    String getProtocol()

    1. 获取客户机的IP地址: 如果获取本机 ipv6的地址

    String getRemoteAddr()

/**
 * 演示 Request对象获取请求行信息
 */
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

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

        //1.获取请求方式: GET
        String method = request.getMethod();
        System.out.println(method);
        //2.获取虚拟目录: /05_12_servlet
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //3.获取Servlet路径: /servletDemo02
        String servletPath = request.getServletPath();
        System.out.println(servletPath);
        //4.获取get方式的请求参数: username=123
        String queryString = request.getQueryString();
        System.out.println(queryString);
        //5.获取请求URI: /05_12_servlet/servletDemo01
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURL);
        //6.获取协议及其版本号: HTTP/1.1
        String protocol = request.getProtocol();
        System.out.println(protocol);
        //7.获取客户机的IP地址: 如果获取本机 ipv6的地址
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);
    }
}

运行servletDemo02结果:

GET
/05_12_http
/servletDemo02
null                             //请求参数为空
/05_12_http/servletDemo02
http://localhost:8080/05_12_http/servletDemo02
HTTP/1.1
0:0:0:0:0:0:0:1

新建html:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
    </head>
    <body>
        <form action="/05_12_http/servletDemo02" method="get">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit" value="提交">
        </form>
    </body>
</html>

运行login.html结果:

GET
/05_12_http
/servletDemo02
username=yzc123&password=123456  
/05_12_http/servletDemo02
http://localhost:8080/05_12_http/servletDemo02
HTTP/1.1
0:0:0:0:0:0:0:1
2.获取请求头数据
  • 方法:

    • String getHeader(String name):通过请求头的名称获取请求头的值

      User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。

      一些网站常常通过判断 UA 来给不同的操作系统、不同的浏览器发送不同的页面

      //判断使用的是哪个浏览器
      @WebServlet("/requestDemo01")
      public class RequestDemo01 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      
              String header = request.getHeader("user-agent");
              if (header.contains("Chrome")){
                  //使用的谷歌浏览器
                  System.out.println("你使用的是谷歌浏览器");
              }else  if(header.contains("Firefox")){
                  System.out.println("你使用的是火狐浏览器");
              }
      
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
          }
      }
      
      //防盗链
      @WebServlet("/requestDemo02")
      public class RequestDemo02 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            
              String header = request.getHeader("referer");
              if (header.contains("jump.html")){
                  //如果是正常访问,http://localhost/05_13/login.html
                  response.setContentType("text/html;charset=utf-8");
                  response.getWriter().write("播放电影.....");
              }else{
                  //盗链
                  response.setContentType("text/html;charset=utf-8");
                  response.getWriter().write("想看电影吗,来爱奇艺充钱看吧.....");
      
              }
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
          }
      }
      
      <!-- daolian.html -->
      <!DOCTYPE html>
      <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>跳转</title>
          </head>
          <body>
          <form action="/05_13/requestDemo02" method="post">
              <input type="text" name="username1">
              <input type="submit" value="跳转">
        </form>
          </body>
      </html>
      
      <!-- login.html -->
      <!DOCTYPE html>
      <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>注册</title>
          </head>
          <body>
          <form action="/05_13/requestDemo02" method="post">
              <input type="text" name="username">
              <input type="text" name="password">
              <input type="submit" value="跳转">
        </form>
          </body>
      </html>
      
    • Enumeration getHeaderNames(): 获取所有的请求头名称 返回值相当于一个iterator迭代器

      Enumeration<String> headerNames = request.getHeaderNames();
      //遍历
      while(headerNames.hasMoreElements()){
          //获取响应头名称
          String name = headerNames.nextElement();  
          String value = request.getHeader(name);
          System.out.println(name+"----------->"+value);
      }
      
3.获取请求体数据 POST请求的请求体
  • 请求体:只有POST请求才会有请求体 在请求体中封装了 POST请求的请求参数

  • 步骤:

    1.获取流对象

    ​ 1.BufferedReader getReader():获取字符输入流 只能操作字符数据

    <!-- login.html -->
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>注册</title>
        </head>
        <body>
        <form action="/05_13/requestDemo04" method="post">
            <input type="text" name="username">
            <input type="text" name="password">
            <input type="submit" value="跳转">
        </form>
        </body>
    </html>
    
    //http://localhost:8080/05_13/login.html
    BufferedReader reader = request.getReader();
    
    String line = null;
    while((line = reader.readLine())!=null){
    	System.out.println(line);
    }
    

    ​ 2.ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据

    2.从流对象中获取数据

2.其他功能

  1. 获取请求参数的通用方式 不管是POST还是GET都可使用
需求方法备注
根据参数名称获取参数对应的值String getParameter(String name)username–>zhangsan
获取特定参数所对应的值的数组String[] getParameterValues(String name)通常用于处理复选框
获取所有请求的参数名称Enumeration getParameterNames()
获取所有参数的map集合Map<String,String[]> getParameterMap()

(hobby=study&&haobby=swimming)

获取参数中文乱码问题

设置流的编码格式即可: request.setCharacterEncoding(“utf-8”);

@WebServlet("/requestDemo05")
public class RequestDemo05 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //解决中文乱码
        request.setCharacterEncoding("utf-8");
        // 1. String getParameter(String name):根据参数名称获取参数对应的值 username-->zhangsan
        String username = request.getParameter("username");
        System.out.println("username:"+username);
        System.out.println("---------------------------------------->");
        //2. String[] getParameterValues(String name):根据参数名称获取参数对应的值的数组 (hobby=study&&haobby=swimming)
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("hobby:"+ Arrays.toString(hobbies));
        System.out.println("---------------------------------------->");
        //3. Enumeration<String> getParameterNames():获取所有请求的参数名称
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            String value = request.getParameter(name);
            System.out.println(name+":"+value);
        }
        System.out.println("---------------------------------------->");
        //4.Map<String,String[]> getParameterMap():获取所有参数的map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
        for (Map.Entry<String, String[]> entry : entries) {
            String key = entry.getKey();
            String[] value = entry.getValue();
            System.out.println(key+":"+Arrays.toString(value));
        }
        System.out.println("---------------------------------------->");
		Set<String> keys = parameterMap.keySet();
        for (String key:keys) {
            System.out.println(key+":"+parameterMap.get(key)[0]);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
<!-- register.html -->
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册</title>
    </head>
    <body>
    <form action="/05_13/requestDemo05" method="get">
       姓名: <input type="text" name="username"> <br>
       密码: <input type="text" name="password"> <br>
        <input type="checkbox" name="hobby" value="game" >游戏
        <input type="checkbox" name="hobby" value="sleep" >睡觉
        <input type="checkbox" name="hobby" value="eat" >吃饭 <br>
        <input type="submit" value="跳转">
    </form>
    </body>
</html>
  1. 请求转发 forward:一种在服务器内部的资源跳转方式

    • 后续会讲解一个 重定向 redirect
    • 面试题: redirect和forward区别

    1.步骤:

    1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
    2. 使用RequestDispatcher对象进行转发:void forward(ServletRequest request, ServletResponse response)
    request.getRequestDispatcher("/DemoServlet").forward(request, response);
    

    2.特点:

    1. 浏览器地址栏的路径不会发生任何改变
    2. 只能转发到当前服务器内部资源
    3. 转发是一次请求
  2. 数据共享

    • 域对象:一个有作用范围的对象,可以在范围内共享数据

    • request域:代表一次请求的范围 一般用于请求转发的多个资源共享数据

      • 方法:
      1. void setAttribute(String name, Object o) :存储数据

      2. Object getAttribute(String name) :获取数据

      3. void removeAttribute(String name) :移除数据

@WebServlet("/requestDemo06")
public class RequestDemo06 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("requestDemo06..............");

        //1.存储数据
        request.setAttribute("msg","今天你真帅");
        request.setAttribute("msg02","今天你真漂亮");
        //3.删除数据
        request.removeAttribute("msg");

        //1. 参数为要跳转的资源路径
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo07");
          //不能转发到其他服务器资源
//        RequestDispatcher requestDispatcher = request.getRequestDispatcher("http://wwww.baidu.com");
        //2.
        requestDispatcher.forward(request,response);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
//获取存储中的数据
@WebServlet("/requestDemo07")
public class RequestDemo07 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("requestDemo07..............");
        //2.获取6中request存储的数据
        String msg = (String) request.getAttribute("msg");
        String msg02 = (String) request.getAttribute("msg02");
        System.out.println("msg:"+msg);
        System.out.println("msg02:"+msg02);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

response

响应消息:服务器端发送给客户端的消息

  • 数据格式:

    1.响应行:

    1. 组成:协议/版本 响应状态码 状态码的描述 HTTP/1.1 200 ok

    2. 响应状态码:服务器告诉客户端浏览器 本次请求和响应的一个状态

      设置响应状态码:setStatus(int sc)

      response.setStatus(302);
      
    3. 特点: 都是三位数字(1xx~5xx)

    4. 分类:

      1. 1xx:服务器接收客户端消息 但是服务器没有将消息接收完成. 等待一段时间后 服务器会发送1xx状态码

      2. 2xx:代表请求已成功被服务器接收、理解、并接受。 成功. 代表 200

      3. 3xx:重定向. 代表:302(重定向) 304(访问缓存)
        在这里插入图片描述
        在这里插入图片描述

      4. 4xx:客户端错误

      响应状态码意思
      404客户端路径错误 请求路径没有对应的资源
      405请求方式没有对应的doXxx方法
      1. 5xx:服务器端错误

        代表:500(服务器内部出现异常) 一般页面出现500,该页面也会显示出现500错误的原因

    2.响应头:

    1. 格式: 头名称:值

    2. 常见的响应头:

      • Content-Type:服务器告诉客户端本次响应体数据格式以及编码的格式

      • Content-disposition:服务器告诉客户端以什么格式打开响应数据

        in-line(默认值):在当前页面打开

        attachment:filename=xxx 以附件形式打开响应体 下载链接

      设置响应头:setHeader(String name,String value);

      功能设置响应头
      一秒刷新页面一次response.setHeader(“refresh”,“1”);
      二秒跳到其他页面response.setHeader(“refresh”,“2;URL=otherPagename”);
      没有缓存response.setHeader(“Pragma”, “No-cache”);
      response.setHeader(“Cache-Control”, “no-cache”);
      设置过期的时间期限response.setDateHeader(“Expires”, System.currentTimeMillis()+自己设置的时间期限);
      访问别的页面response.setStatus(302); response.setHeader(“location”,“url”);

    3.响应空行

    4.响应体: 传输的数据

HTTP/1.1 200 ok    --->响应行
//下面是响应头
Accept-Ranges: bytes
ETag: W/"420-1589453109675"
Last-Modified: Thu, 14 May 2020 10:45:09 GMT
Content-Type: text/html
Content-Length: 420
Date: Thu, 14 May 2020 12:05:57 GMT
					 			--->响应空行
//下面是响应体
<!DOCTYPE html>    			
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Title</title>
</head>
<body>
	<form action="/05_17_response/responseDemo02" method="post">
	<input type="text">
   <input type="submit" value="提交">
</form>

</body>
</html>

设置响应体:

  • 步骤:

    1. 获取输出流:

      字符输出流:PrintWriter getWriter()

      字节输出流:ServletOutputStream getOutputStream()

    2. 使用输出流

      将数据输出到客户端浏览器:void write(String s)

  • JSP实质上会转换成一个java文件(Servlet) 里面的html元素 都是通过输出流去写进去的(原理和我们使用response设置响应体一致)


案例

1. 完成重定向

  • 重定向:资源跳转的方式

  • 步骤:
    1.设置状态码302 response.setStatus(302);
    2.设置响应头location response.setHeader(“location”,"/05_17_response/responseDemo02");

  • 简单的重定向的方式:
    动态获取虚拟目录
    String contextPath = request.getContextPath();
    //参数为要跳转的页面路径

    response.sendRedirect(contextPath+"/responseDemo02");
    
    response.sendRedirect("http://www.4399.com");//可以访问其他服务器中的网站
    
  • Q:如果在Demo01通过request存储了一个数据,请问重定向后能不能在Demmo02中获取?

    A:不行,request存储的数据的有效范围为一个请求中的多个资源 重定向为两个请求

  • redirect 和 forward的区别 (重要)

    1. 重定向的特点:
      1. 重定向地址栏路径发生了变化
      2. 重定向可以访问其他站点(服务器)的资源
      3. 重定向是两次请求,不可以使用request对象来共享数据
    2. 转发的特点:
      1. 转发地址栏路径不变
      2. 转发只能访问当前服务器的资源
      3. 转发是一次请求,可以使用request对象来共享数据
  • 路径的写法

    路径分类:

    判断路径为相对或者绝对路径的方法:看是以/开头还是.开头

    /(绝对) .(相对)

    1. 相对路径:通过相对路径不可以确定唯一资源

      • 如:./index.jsp 不以/开头 以.开头

      • 如何确定相对路径的准确性

        1.找到当前资源和目标资源之间的相对位置关系

        http://localhost/05_17_response/hello.html
        http://localhost/05_17_response/responseDemo02
        
        http://localhost/05_17_response/html/haha.html
        http://localhost/05_17_response/responseDemo01
        

        2.确认相对目录

        • ./:当前目录
        • …/上一级目录
    2. 绝对路径:通过绝对路径可以确定唯一资源

      http://localhost/05_17_response/responseDemo02     
      /05_17_response/responseDemo02
      

      都是绝对路径

    • 如何判断路径是否需要携带虚拟目录:

      判断路径给谁用的?

      • 给客户端浏览器用:需要加虚拟目录的(项目访问路径)

        建议虚拟目录动态获取:request.getContextPath();

        例如: 重定向…都需要携带虚拟目录

      • 给服务器自身使用:不需要加虚拟目录

        转发路径不需要携带虚拟目录

在这里插入图片描述

2.服务器输出字符数据到浏览器中

步骤:

  1. 获取输出流:
    • 字符输出流:PrintWriter getWriter()
    • 字节输出流:ServletOutputStream
  2. 使用输出流,将数据输出到客户端浏览器
    • void write(String s)

注意:

  • 乱码问题:

    1. 方案1:

      1. 获取流对象之前,设置流的默认编码 将默认的ISO-8859-1 设置成GBK

        response.setCharacterEncoding("GBK");
        
      2. 获取输出流:

      3. 使用输出流,将数据输出到客户端浏览器

    2. 方案2:

      1. 告诉浏览器,服务器发送的消息体数据的编码, 建议浏览器使用该编码

        response.setHeader("content-type","text/html;charset=utf-8");
        
      2. 获取输出流:

      3. 使用输出流,将数据输出到客户端浏览器

    3. 方案3: 推荐使用

      1. 告诉浏览器,服务器发送的消息体数据的编码, 建议浏览器使用该编码(简写形式)

        response.setContentType("text/html;charset=utf-8");
        
      2. 获取输出流:

      3. 使用输出流,将数据输出到客户端浏览器

在这里插入图片描述

3.解决文件名中文乱码问题

//解决中文乱码问题
String agent = request.getHeader("user-agent");
filename = DownLoadUtils.getFileName(agent,filename);
// 3.2:content-disposition:attachment;filename=xxx
response.setHeader("content-disposition","attachment;filename="+filename);
public class DownLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            Base64.Encoder base64Encoder = Base64.getEncoder();
//            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
            filename = "=?utf-8?B?"+base64Encoder.encodeToString(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

ServletContext对象

1.概念

代表整个web应用,可以和程序的容器(服务器)进行通信

2.获取

  1. 通过request对象获取

    ServletContext getServletContext()

    获取上次调度此ServletRequest的servlet上下文。

  2. 通过HttpeServlet对象获取

    this.getServletContext();

  • 结论:无论是哪一种方式获取的ServletContext对象 都为同一个对象
//1.
ServletContext servletContext01 = request.getServletContext();
//2.
ServletContext servletContext02 = this.getServletContext();
System.out.println(servletContext01); //org.apache.catalina.core.ApplicationContextFacade@35107d21
System.out.println(servletContext02); // org.apache.catalina.core.ApplicationContextFacade@35107d21
System.out.println(servletContext01 == servletContext02); // true

3.功能

1. 获取MIME类型

  • MIME类型:在互联网通信过程中定义的一种文件数据类型:

    格式: 大类型/小类型 text/html image/png

  • 获取

    String getMimeType(String file)

String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
response.setHeader("content-type",mimeType);

2.域对象

共享数据(作用范围?)

  1. void setAttribute(String name, Object object)

  2. Object getAttribute(String name)

  3. void removeAttribute(String name)

  • ServletContext的作用范围: 所有用户所有请求的数据

3. 获取文件的真实(服务器)路径

String getRealPath(String path)

  • 分别在src目录下创建一个a.txt文件
  • web目录下创建一个b.txt文件
  • WEB-INF目录下创建一个c.txt文件 如何获取其真实路径
ServletContext context = this.getServletContext();

String b = context.getRealPath("/b.txt");//web目录下的资源访问
System.out.println(b);
//C:\Users\zc980807\IdeaProjects\huike\tomcat\out\artifacts\05_17_servlet_war_exploded\b.txt

String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
System.out.println(c);
//C:\Users\zc980807\IdeaProjects\huike\tomcat\out\artifacts\05_17_servlet_war_exploded\WEB-INF\c.txt

String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
System.out.println(a);
//C:\Users\zc980807\IdeaProjects\huike\tomcat\out\artifacts\05_17_servlet_war_exploded\WEB-INF\classes\a.txt

重点记忆\05_17_servlet_war_exploded\后的目录结构


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值