Servlet、ServletRequest和ServletResponse


一、Servlet

1.1 概念

Servlet: server applet,运行在服务器端的小程序。

  • Servlet就是一个javax.servlet包下的接口,定义了Java类被 浏览器访问到(Tomcat识别) 的规则。
  • 将来我们自定义一个类,实现Servlet接口,复写方法。
  • 实现类:GenericServlet, HttpServlet

控制器小服务程序,经常被用于mvc设计模式中的contrller层,用于与tomcat服务请求url与java对应类之间的调用。本质是将服务器处理服务的过程封装为对应的对象,通过tomcat服务器以及对应的协议进行浏览器端与服务器端的通信以及服务的执行。(就是一个按照特定语法书写的java类,通过方法重写的形式提供服务,由配置服务器进行调用)

  • 作用

    servlet 是运行在 Web 服务器中的小型 Java 程序。servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求

  • 实现方式

    • 实现Servlet接口
    • 继承GenericServlet
    • 继承HttpServlet

1.2 Servlet程序创建步骤

  • 步骤1:创建JavaEE项目
  • 步骤2:定义一个class类,实现Servlet接口
    public class ServletDemo implements Servlet
  • 步骤3:实现接口中的抽象方法
    • 自定义类实现Servlet接口(重写service方法)
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

//创建class类实现 Servlet接口
//注意:Servlet由sun公司提供保存在tomcat中
//如果没有配置tomcat则找不到该接口(配置tomcat服务之后会将jar导入)
public class ServletDemo implements Servlet{

	@Override
	public void destroy() {
	}

	@Override
	public ServletConfig getServletConfig() {
		return null;
	}

	@Override
	public String getServletInfo() {
		return null;
	}

	@Override
	public void init(ServletConfig arg0) throws ServletException {
	}

	@Override
	public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
		 System.out.println("MyServlet被调用");
	}
}
  • 步骤4:配置Servlet
    web.xml中配置servlet的信息和访问路径(在<web-app></web-app>标签里书写)
     <!-- 配置Servlet类的基本信息(所在位置和类名) -->
    <servlet>
    	<!-- 唯一不可重复 一般使用java的类名 -->
    	<!-- 配置servlet类的名字 自定义命名 一般使用类名(唯一不可重复) -->
      	<servlet-name>HelloServlet</servlet-name>
      	<!-- 配置使用java类的全路径 -->
  		<!-- 可以使用ctrl+鼠标左键进行验证 -->
      	<servlet-class>HelloServlet的src中的具体路径(即:全类名)</servlet-class>
    </servlet>
    <!-- 配置Servlet的访问路径 -->
    <!-- 配置执行对应java类的url -->
    <servlet-mapping>
    	<!-- 就是上面已经配置好的servlet-name -->
      	<servlet-name>HelloServlet</servlet-name>
      	<!-- 浏览器请求服务器的地址 -->
    	<url-pattern>/HelloServlet别名</url-pattern>
    </servlet-mapping>

	<!-- 例: -->
	<servlet>
        <servlet-name>ServletDemo</servlet-name>
        <servlet-class>com.ys.web.servlet.ServletDemo</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>ServletDemo</servlet-name>
        <url-pattern>/demo</url-pattern>
    </servlet-mapping>
  • 步骤5:在浏览器访问

    http://localhost:8080/虚拟路径/HelloServlet别名
    http://localhost:8080/day0803/demo(别名如上所写demo,虚拟目录如下图中所写/day0803)

在Run-Run / Debug Configurations的Tomcat Server窗口中,点Deployment,为单个项目设置虚拟目录
在这里插入图片描述

  • servlet的快速创建

右键 —> 创建servlet —> 填写servlet的class name名字,next —> 填写name(即web.xml中的servlet-name),添加或修改URL mappings(即web.xml中的url-pattern),next —> 勾选想要创建的方法,Finish
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 注意事项
    • 1、会根据servlet-name查找获取对应执行的java类,所以在配置servlet中的servlet-name时不允许重复
    • 2、但是server-mapping中的servlet-name可以重复,因为有时我们需要将不同的url执行相同的服务
    • 3、服务器通过浏览器请求的url决定查找对应的class,所以servlet-mapping中的url不允许重复
    • 4、servlet-mapping中的servlet-name书写错误,在执行项目时tomcat会报错

1.3 Servlet程序执行原理

在这里插入图片描述

程序的执行流程:当浏览器请求服务器时,tomcat获取请求后,会解析请求,将请求的数据封装为一个一个对象,到对应项目中,先判断请求的是否是静态资源,如果静态资源查找对应的资源通过io的形式返回,如果不存在返回404页面(tomcat默认提供的当资源不存在时返回的页面),如果请求的是服务,那么会上web.xml中根据请求的url匹配所有servlet-mapping中的url,如果匹配则回去对应的servlet-name,根据servlet-name去所有servlet中查询匹配的name,获取对应的class执行对应方法。

  1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径。
  2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
  3. 如果有,则在找到对应的<servlet-class>全类名
  4. tomcat会将字节码文件加载进内存,并且创建其对象。
  5. 调用其方法。

1.4 Servlet的生命周期

import javax.servlet.*;
import java.io.IOException;

public class ServletDome2 implements Servlet {

    /**
     * 初始化方法
     * 在Servlet被创建时执行,只会执行一次。
     * @param servletConfig
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init....");
    }

    /**
     * 获取ServletConfig对象
     * ServletConfig:Servlet的配置对象
     * 获取Servlet的名称			String getServletName();
     * 获取ServletContext对象	ServletContext getServletContext();
     * 获取初始化参数			String getInitParameter(String var1);
     * 获取所有初始化参数名		Enumeration<String> getInitParameterNames();
     * @return
     */
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * 提供服务方法
     * 每一次Servlet被访问时执行,执行多次。
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("service....");
    }

    /**
     * 获取Servlet的一些信息,如:版本、作者
     * @return
     */
    @Override
    public String getServletInfo() {
        return null;
    }

    /**
     * 销毁方法
     * 在服务器正常关闭时执行,只执行一次
     */
    @Override
    public void destroy() {
        System.out.println("destroy....");
    }
}
  • 1、构造 Servlet,然后使用 init 方法将其初始化。
    • 第一次发送请求的时候。 执行一次
  • 2、处理来自客户端的对 service 方法的所有调用。
    • 客户端发送一次请求,调用service方法一次。执行多次
  • 3、从服务中取出 Servlet,然后使用 destroy 方法销毁它,最后进行垃圾回收并终止它。
    • tomcat服务器关闭的时候,销毁
  • 被创建:执行init()方法,只执行一次

    1、Servlet什么时候被创建?

    • 默认情况下,第一次被访问时,Servlet被创建
    • 可以配置执行Servlet的创建时机。
      • <servlet>标签下配置
      1. 第一次被访问时,被创建
        <load-on-startup>的值为负数
      2. 在服务器启动时,被创建
        <load-on-startup>的值为0或正整数

    2、Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的。

    • 问题:多个用户同时访问时,可能存在线程安全问题。
    • 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对其修改值。
  • 提供服务:执行service()方法,执行多次

    每次访问Servlet时,Service方法都会被调用一次。

  • 被销毁:执行destroy()方法,只执行一次

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

1.5 Servlet 3.0

选JavaEE 6(Servlet 3.0)之后版本都可以。

  • 好处

    支持注解配置。可以不需要web.xml

  • 步骤

    1、创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
    2、定义一个类,实现Servlet接口
    3、复写方法
    4、在类上使用@WebServlet注解,进行配置
    @WebServlet("资源路径")

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet(urlPatterns = "/demo1")
public class ServletDemo1 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 {
        System.out.println("我回来了...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
			//@WebServlet注解的实现
			@Target({ElementType.TYPE})
			@Retention(RetentionPolicy.RUNTIME)
			@Documented
			public @interface WebServlet {
			    String name() default "";//相当于<Servlet-name>
			
			    String[] value() default {};//代表urlPatterns()属性配置
			
			    String[] urlPatterns() default {};//相当于<url-pattern>
			
			    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 "";
			}

1.6 Servlet的体系结构

Servlet -- 接口
	|	实现
GenericServlet -- 类
	|	继承
HttpServlet -- 类
  • 实现Servlet 接口

    实现Servlet接口中的所有方法

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

//创建class类实现 Servlet接口
//注意:Servlet由sun公司提供保存在tomcat中
//如果没有配置tomcat则找不到该接口(配置tomcat服务之后会将jar导入)
@WebServlet(urlPatterns = "/demo1")
public class ServletDemo1 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 {
        System.out.println("我回来了...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
  • 继承GenericServlet
    • 将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
    • 将来定义Servlet类时,继承GenericServlet,实现service()方法即可;若想用其他方法,可直接重写。
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

//创建class类 继承GenericServlet类
//GenericServlet由sun公司提供 保存在tomcat提供的jar包中 所以需要配置tomcat环境
@WebServlet(urlPatterns = "/demo2")
public class ServletDemo2 extends GenericServlet {

	/**
	 * GenericServlet 实现了序列化接口 所以可以生成序列化id
	 */
	private static final long serialVersionUID = 1L;
	
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }
}
//GenericServlet抽象类的实现
package javax.servlet;

import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;

    public GenericServlet() {
    }

    public void destroy() {
    }

    public String getInitParameter(String name) {
        return this.getServletConfig().getInitParameter(name);
    }

    public Enumeration<String> getInitParameterNames() {
        return this.getServletConfig().getInitParameterNames();
    }

    public ServletConfig getServletConfig() {
        return this.config;
    }

    public ServletContext getServletContext() {
        return this.getServletConfig().getServletContext();
    }

    public String getServletInfo() {
        return "";
    }

    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {
    }

    public void log(String msg) {
        this.getServletContext().log(this.getServletName() + ": " + msg);
    }

    public void log(String message, Throwable t) {
        this.getServletContext().log(this.getServletName() + ": " + message, t);
    }

    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    public String getServletName() {
        return this.config.getServletName();
    }
}
  • 继承HttpServlet
    • 对HTTP协议的一种封装,简化操作
      • 1、定义类继承HttpServlet
      • 2、重写doGet/doPost方法
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

// 创建类 继承HttpServlet
// HttpServlet 由Sun公司提供一般在配置tomcat后导入对应的jar包
@WebServlet(urlPatterns = "/demo3")
public class ServletDemo3 extends HttpServlet {

	/**
	 * HttpServlet 不是抽象类,只不过是对应处理方法的默认实现
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * 通常通过重写的方式 书写对应http相应提供的处理方法
	 */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet....");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost....");
    }
}

1.7 Servlet相关配置

@WebServlet(urlPatterns = "/demo3")

  • urlpartten:Servlet访问路径
  • 一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})使用其中任意一个都可以访问到。
  • 路径定义规则:
    • /xxx:完全路径匹配;以/开头,配置文件中url-pattern怎么写,浏览器就怎么访问
    • /xxx/xxx:多层路径,目录结构
    • /xxx/*:以/开头,以*结尾(过滤器)
    • *.do:扩展名匹配;不以/开头,以扩展名结尾 (*.do*.action struts2框架)

注意:配置路径时一定不要忘记加 / ,不然程序会运行错误!!!

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//@WebServlet(urlPatterns = "/demo4")
//@WebServlet({"/d4","/dd4","ddd4"})
//@WebServlet("/user/demo4")
//@WebServlet("/user/*")
//@WebServlet("/*")
@WebServlet("*.do")
public class ServletDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet....");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost....");
    }
}

二、ServletRequest对象

在这里插入图片描述

2.1 ServletRequest对象和ServletResponse对象的原理

  • request和response对象是由服务器创建的、我们直接使用。
  • request对象是来获取请求消息数据,response对象是来设置响应消息数据

2.2 ServletRequest的体系结构

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

2.3 ServletRequest功能

2.3.1 获取请求消息数据

2.3.1.1 获取请求行数据
  • 请求行数据格式
    GET /day0803/requestDemo1?name=zhangsan HTTP/1.1

  • 方法

    • 获取请求方式 :GET
      String getMethod()

    • 获取虚拟目录 (*):/day0803
      String getContextPath()

    • 获取Servlet路径: /requestDemo1
      String getServletPath()

    • 获取get方式请求参数:name=zhangsan
      String getQueryString()

    • 获取请求URI (*):/day14/requestDemo1
      String getRequestURI(): /day0803/requestDemo1
      StringBuffer getRequestURL(): http://localhost/day0803/requestDemo1

      • URL:统一资源定位符 : http://localhost/day0803/requestDemo1(范围小,如:aaa.txt 只能获取到具体的资源)
      • URI:统一资源标识符 : /day0803/requestDemo1(所获取的范围更大,如:.txt 只要以.txt结尾的资源都可以获取到)
    • 获取协议及版本:HTTP/1.1
      String getProtocol()

    • 获取客户机的IP地址
      String getRemoteAddr()

  • 代码演示
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/requestDemo1")
public class RequestDemo1 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. (*)获取虚拟目录:/day0803
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //3. 获取Servlet路径: /requestDemo1
        String servletPath = request.getServletPath();
        System.out.println(servletPath);
        //4. 获取get方式请求参数:name=zhangsan
        String queryString = request.getQueryString();
        System.out.println(queryString);
        //5. (*)获取请求URI:/day0803/requestDemo1
        String requestURI = request.getRequestURI();
        // 获取请求URL:http://localhost:8080/day0803/requestDemo1
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURI);
        System.out.println(requestURL);
        //6. 获取协议及版本:HTTP/1.1
        String protocol = request.getProtocol();
        System.out.println(protocol);
        //7. 获取客户机的IP地址:127.0.0.1
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);
    }
}
//结果如下:
GET
/day0803
/requestDemo1
name=zhangsan
/day0803/requestDemo1
http://localhost:8080/day0803/requestDemo1
HTTP/1.1
127.0.0.1
2.3.1.2 获取请求头数据
  • 方法
    • (*)String getHeader(String name):通过请求头的名称获取请求头的值
    • Enumeration<String> getHeaderNames():获取所有的请求头名称

注意:请求头的名称输入不区分大小写,只要书写正确即可。

  • 代码演示
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

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

    }

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

        //1.获取所有的请求头名称
        Enumeration<String> headerNames = request.getHeaderNames();
        // 遍历
        while (headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            // 根据名称获取请求头的值
            String value = request.getHeader(name);
            System.out.println(name + "=>" + value);
        }

        //2.(*)通过请求头的名称获取请求头的值 user-agent
        String agent = request.getHeader("user - agent");
        // 通过agent的浏览器版本
        if(agent.equals("Chrome")){
            //谷歌浏览器
            System.out.println("谷歌来了...");
        }else if(agent.equals("Firefox")){
            System.out.println("火狐来了...");
        }
        // 通过请求头的名称获取请求头的值 referer
        String referer = request.getHeader("referer");
        System.out.println(referer);//如果直接访问,输出结果为null
        // 防盗链
        if(referer != null){
            if(referer.contains("/day0803_servlet")){
                System.out.println("正常使用");
            }else{
                System.out.println("禁止盗链");
            }
        }
    }
}
//getHeaderNames()方法获取所有的请求头名称,使用遍历和getHeader()方法获取所有请求头的值
host=>localhost:8080
user-agent=>Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0
accept=>text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
accept-language=>zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
accept-encoding=>gzip, deflate
connection=>keep-alive
cookie=>JSESSIONID=7FF733832CCE3F71D1DB3E2F89051038; Webstorm-50b938c9=985e83a3-3944-484c-8ce1-fc982cf8583c; Idea-661643a5=46889c73-18d0-4664-a2c1-ef190c5f5ae2
upgrade-insecure-requests=>1
sec-fetch-dest=>document
sec-fetch-mode=>navigate
sec-fetch-site=>none
sec-fetch-user=>?1
2.3.1.3 获取请求体数据

请求体:只有POST请求方式,才有请求体;在请求体中封装了POST请求的请求参数

  • 步骤

    1、获取流对象

    • BufferedReader getReader():获取字符输入流,只能操作字符数据
    • ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
      • 在文件上传知识点后讲解

    2、再从流对象中拿数据

  • 代码演示

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/requestDemo3")
public class RequestDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取字符流
        BufferedReader br = request.getReader();
        //2.读取数据
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }
    }

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

    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
	<!-- action在书写路径时,如果书写/代表请求根目录下对应服务 -->
	<!-- 所以在书写action路径时 注意 / 的使用 -->
	<!-- 可以使用带有项目路径的url 比如:/JavaWeb/MyHttpServlet -->
	<!-- 或者使用相对路径 -->
    <form action="/day0803/requestDemo3" method="post">
        <input type="text" placeholder="请输入用户名" name="username"><br>
        <input type="text" placeholder="请输入密码" name="password"><br>
        <input type="submit" value="注册">
    </form>
</body>
</html>
//在网页用post提交表单,控制台输出结果如下:
username=zfdht&password=12345

2.3.2 其他功能

2.3.2.1 获取请求参数通用方式

不论get还是post请求方式都可以使用下列方法来获取请求参数

  • String getParameter(String name):根据参数名称获取参数值 username=zs&password=123
  • String[] getParameterValues(String name):根据参数名称获取参数值的数组 hobby=xx&hobby=game
  • Enumeration<String> getParameterNames():获取所有请求的参数名称
  • Map<String,String[]> getParameterMap():获取所有参数的map集合
  • 中文乱码问题
    • get方式:tomcat 8 已经将get方式乱码问题解决了
    • post方式:会中文乱码
      • 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
  • 代码演示
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet("/requestDemo4")
public class RequestDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	// 设置流的编码
        request.setCharacterEncoding("utf-8");
        
        // post 获取请求参数
        // 根据参数名称获取参数值
        String username = request.getParameter("username");
        System.out.println("post");
        System.out.println(username);
        System.out.println("--------------------");

        // 根据参数名称获取参数值的数组
        String[] hobbies = request.getParameterValues("hobby");
        for (String hobby:hobbies) {
            System.out.println(hobby);
        }
        System.out.println("--------------------");

        // 获取所有请求的参数名称
        Enumeration<String> parameterNames = request.getParameterNames();
        while(parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            System.out.println(name);
            String value = request.getParameter(name);
            System.out.println(value);
        }
        System.out.println("--------------------");

        // 获取所有参数的map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        // 遍历
        Set<String> keySet = parameterMap.keySet();
        for (String name: keySet) {
            // 获取键 获取值
            String[] values = parameterMap.get(name);
            System.out.println(name);
            for (String value: values) {
                System.out.println(value);
            }
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // get 获取请求参数

        // 根据参数名称获取参数值
        //String username = request.getParameter("username");
        //System.out.println("get");
        //System.out.println(username);

        // doPost()方法和doGet()方法没有区别,
        // 因此如果表单用post提交,在doGet()方法中写this.doPost(request,response);
        // 若用get提交,则在doPost()方法中书写this.doGet(request,response);
        this.doPost(request,response);
        System.out.println("--------------------");
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
    <form action="/day0803/requestDemo4" method="post">
        <input type="text" placeholder="请输入用户名" name="username"><br>
        <input type="text" placeholder="请输入密码" name="password"><br>
        <input type="checkbox" name="hobby" value="game">游戏
        <input type="checkbox" name="hobby" value="study">学习
        <br>
        <input type="submit" value="注册">
    </form>
</body>
</html>
// 输入为
zhangsan
123456
游戏、学习 全选

// 根据参数名称获取参数值
post
zhangsan
--------------------
// 根据参数名称获取参数值的数组
game
study
--------------------
// 获取所有请求的参数名称
username
zhangsan
password
123456
hobby
game
--------------------
// 获取所有参数的map集合
username
zhangsan
password
123456
hobby
game
study
2.3.2.2 请求转发

一种在服务器内部的资源跳转方式

  • 转发的原理
    在这里插入图片描述

  • 步骤

    • 1、通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
    • 2、使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
  • 特点

    • 1、浏览器地址栏路径不发生变化
    • 2、只能转发到当前服务器内部资源中。
    • 3、转发是一次请求
  • 代码演示

//RequestDemo5
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/requestDemo5")
public class RequestDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("RequestDemo5被访问了...");
		// 转发到RequestDemo6资源
        //RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo6");
        //requestDispatcher.forward(request,response);
        request.getRequestDispatcher("/requestDemo6").forward(request,response);
    }

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

//RequestDemo6
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/requestDemo6")
public class RequestDemo6 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("RequestDemo6被访问了...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
//访问RequestDemo5跳转访问RequestDemo6
RequestDemo5被访问了...
RequestDemo6被访问了...
2.3.2.3 共享数据
  • 域对象:一个有作用范围的对象,可以在范围内共享数据
  • request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
  • 方法

    • void setAttribute(String name,Object obj):存储数据
    • Object getAttitude(String name):通过键获取值
    • void removeAttribute(String name):通过键移除键值对
  • 代码演示

// RequestDemo7保存数据、转发到RequestDemo8
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/requestDemo7")
public class RequestDemo7 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("RequestDemo7被访问了...");

        // 存储数据到request域中
        request.setAttribute("msg","hello");
        // 转发
        request.getRequestDispatcher("/requestDemo8").forward(request,response);
    }

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

// RequestDemo8 获取数据
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/requestDemo8")
public class RequestDemo8 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("RequestDemo8被访问了...");
        // 获取数据
        Object msg = request.getAttribute("msg");
        System.out.println(msg);
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
//在一次请求转发过程中,RequestDemo7保存数据、RequestDemo8可以获取数据
RequestDemo7被访问了...
RequestDemo8被访问了...
hello
2.3.2.4 获取ServletContext对象
  • 方法

    • ServletContext getServletContext()
  • 代码演示

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/requestDemo9")
public class RequestDemo9 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = request.getServletContext();
        System.out.println(servletContext);
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
// getServletContext() 方法获取结果如下:
org.apache.catalina.core.ApplicationContextFacade@22ac88b9

三、ServletResponse对象

功能:设置响应消息

3.1 设置响应行

  • 格式:HTTP/1.1 200 ok
  • 设置状态码
    • setStatus(int sc)

3.2 设置响应头

  • 方法
    • setHeader(String name, String value)

3.3 设置响应体

  • 使用步骤

    1、 获取输出流

    • 字符输出流PrintWriter getWriter()
    • 字节输出流ServletOutputStream getOutputStream()

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

3.4 案例

3.4.1 完成重定向

重定向:资源跳转的方式

  • 重定向的原理
    在这里插入图片描述
  • 代码实现
		//1. 设置状态码为302
	    response.setStatus(302);
	    //2.设置响应头location
	    response.setHeader("location","/day0803/responseDemo2");
	    
		//简单的重定向方法
	    response.sendRedirect("/day0803/responseDemo2");
	   //redirect(path) path为虚拟路径
	   response.sendRedirect(request.getContextPath() + "/servletDemo2");
  • 重定向的特点redirect(path)

    1、地址栏发生变化
    2、重定向可以访问其他站点(服务器)的资源
    3、重定向是两次请求。不能使用request对象来共享数据

使用重定向跳转web下的资源:response.sendRedirect(request.getContextPath() + "fail.html");

  • 转发的特点forward

    1、转发地址栏路径不变
    2、转发只能访问当前服务器下的资源
    3、转发是一次请求,可以使用request对象来共享数据

使用转发跳转到WEB-INF下的资源:request.getRequestDispatcher("WEB-INF/success.html").forward(request, response);

  • 重定向与转发的区别(redirect与forward的区别)

    • 转发的地址栏不会发生改变,但是重定向会发生改变
    • 转发是一次请求和一次响应,但是重定向是多次请求与响应
    • 转发的状态码是2xx,重定向是3xx
    • 转发可以使用request域对象传递数据,但是重定向不可以(必须将请求与响应对象传递)
    • 转发发生在服务器内部,转发的资源不需要携带项目名,重定向可以重定到任何公开资源(需要带项目名)。
  • 路径写法

    1、相对路径
    通过相对路径不可以确定唯一资源。如:./index.html

    • 不以 / 开头,以 . 开头路径
    • 规则:找到当前资源和目标资源之间的相对位置关系
      • ./:当前目录
      • ../:后退一级目录

    2、绝对路径:
    通过绝对路径可以确定唯一资源。如:/day15/responseDemo2

    • / 开头的路径
    • 规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
      • 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
        • 建议动态获取虚拟目录:request.getContextPath()
        • <a> ,<form> 重定向…
      • 给服务器使用:不需要加虚拟目录
        • 转发路径
  • 代码演示

// servletDemo1重定向 访问servletDemo2
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/servletDemo1")
public class ServletDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("servletDemo1......");
        // 访问servletDemo1,会自动跳转servletDemo2资源
        //1.设置状态码为302
        //response.setStatus(302);
        //2.设置响应头location
        //response.setHeader("location","/day0807_project/servletDemo2");

        // 存储数据到request域中
        request.setAttribute("msg","hello");

        // 动态获取虚拟目录
        String contextPath = request.getContextPath();

        // 简单的重定向方法
        response.sendRedirect(contextPath + "/servletDemo2");
        //response.sendRedirect("http://www.baidu.com");
    }

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

// servletDemo2
@WebServlet("/servletDemo2")
public class ServletDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("servletDemo2......");

        // 获取数据
        Object msg = request.getAttribute("msg");
        System.out.println(msg);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
//重定向后的结果:
servletDemo1......
servletDemo2......
//重定向不能使用request对象来共享数据,因此结果为null
null
  • 定时刷新
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 页面的定时的跳转
 */
 @WebServlet("/refresh1Servlet")
public class Refresh1Servlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		//设置响应的学习体的数据格式以及编码
		response.setContentType("text/html;charset=utf-8");
		// 先输出内容
		System.out.println("Refresh1Servlet执行了...");
		// 设置头信息
		response.setHeader("refresh", "5;url=/ResponseTest/response/demo1/suc.html");
		// 输出一句内容
		response.getWriter().print("5秒之后跳转");
	}

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

3.4.2 服务器输出字符数据到浏览器

  • 步骤

    1、获取字符输出流
    2、输出数据

  • 注意
    • 乱码问题
      1、PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1
      2、设置该流的默认编码response.setCharacterEncoding(“utf-8”);
      3、告诉浏览器响应体使用的编码response.setHeader(“content-type”,“text/html;charset=utf-8”);
		//简单的形式,设置编码,是在获取流之前设置
		response.setContentType("text/html;charset=utf-8");
  • 代码演示
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/servletDemo3")
public class ServletDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取对象之前,设置流的默认编码:ISO-8859-1 设置为utf-8
        //response.setCharacterEncoding("utf-8");
        // 告诉浏览器,服务器发送的消息体数据的编码。建议浏览器使用改编码解码
        //response.setHeader("content-type","text/html;charset=utf-8");

        // 简单的形式,设置编码
        response.setContentType("text/html;charset=utf-8");

        // 1.获取字符输出流
        PrintWriter pw = response.getWriter();
        // 2.输出数据
        pw.write("你好,response");
    }

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

3.4.3 服务器输出字节数据到浏览器

  • 步骤

    1、获取字节输出流
    2、输出数据

  • 代码演示

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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

        response.setContentType("text/html;charset=utf-8");

        // 1.获取字节输出流
        ServletOutputStream sos = response.getOutputStream();
        // 2.输出数据
        sos.write("你好".getBytes("utf-8"));
    }

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

3.4.4 验证码

  • 本质

    图片

  • 目的

    防止恶意表单注册

  • 代码演示

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int width = 100;
        int height = 50;

        // 1.创建一对象,在内存中图片(验证码图片对象)
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);

        // 2.美化验证码
        // 2.1 填充背景色
        Graphics g = image.getGraphics();//画笔对象
        g.setColor(Color.ORANGE);//设置画笔颜色
        g.fillRect(0,0,width,height);
        
        // 2.2画边框
        g.setColor(Color.blue);
        g.drawRect(0,0,width-1,height-1);
        
        // 2.3写验证码
        String str ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        // 生成随机角标
        Random ran = new Random();
        for(int i = 1;i <= 4;i++){
            // 生成四个验证码值
            int index = ran.nextInt(str.length());
            // 获取字符
            char ch = str.charAt(index);
            g.drawString(ch+"",width/5*i,height/2);
        }
        
        // 2.4画干扰线
        g.setColor(Color.GREEN);
        // 随机生成坐标点
        for(int i = 0;i < 10;i++){
            int x1 = ran.nextInt(width);
            int x2 = ran.nextInt(width);

            int y1 = ran.nextInt(height);
            int y2 = ran.nextInt(height);
            g.drawLine(x1,y1,x2,y2);
        }
        
        // 3.将图片输出到页面展示
        ImageIO.write(image,"jpg",response.getOutputStream());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        /**
         * 点击超链接或者图片,验证码换一张
         * 1.给超链接或图片绑定单击事件
         * 2.重新设置图片的src属性值
         */
        window.onload = function () {
            //1.获取图片对象
            var img = document.getElementById("checkCode");
            var change = document.getElementById("change");
            //2.绑定单击事件
            img.onclick = function () {
                //加时间戳
                let date = new Date();
                img.src = "/day0807_project/checkCodeServlet?" + date;
            }
            change.onclick = function () {
                //加时间戳
                let date = new Date();
                img.src = "/day0807_project/checkCodeServlet?" + date;
            }
        }
    </script>
</head>
<body>
<img id="checkCode" src="/day0807_project/checkCodeServlet">
<a id="change" href="">看不清换一张?</a>
</body>
</html>

3.5 BeanUtils工具类

简化数据封装,用于封装JavaBean

  • 成员变量
  • 属性:
    setter和getter方法截取后的产物:getUsername() --> Username--> username
  • 方法:
    • setProperty():设置属性值
    • getProperty():获取属性值
    • populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
// 导入commons-beanutils-1.8.0.jar包
import cn.itcast.domain.User;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;

public class BeanUtilsTest {

    @Test
    public void test(){
        User user = new User();
        try {
        	//setProperty(bean, name, value);
        	//setProperty的name值参数是gender对应的setter方法setUsername的set后面的名字(Username),开头字母转小写username
            BeanUtils.setProperty(user,"username","张三");
            System.out.println(user);

            String gender = BeanUtils.getProperty(user, "username");
            System.out.println(gender);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}
public class User {
	private int id;
	private String username;
	private String password;
	public User() {
		super();
	}
	
	public User(int id, String username, String password) {
		super();
		this.id = id;
		this.username = username;
		this.password = password;
	}

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
	}
	
}
  • JavaBean

    标准的Java类

    • 要求:
      • 1、类必须被public修饰
      • 2、必须提供空参的构造器
      • 3、成员变量必须使用private修饰
      • 4、提供公共setter和getter方法
    • 功能:封装数据

四、ServletContext对象

4.1 概念

  • 代表整个web应用,可以和程序的容器(服务器)来通信
  • 在web服务器启动后,就为每一个web应用创建该对象,在web应用中包含很多web资源,所有的资源共享一个ServletContext对象,就可以通过ServletContext传递数据。
    • 作用:获取全局化参数

4.2 获取方式

  • 1、通过request对象获取
    request.getServletContext();
  • 2、通过HttpServlet获取
    this.getServletContext();

无论是通过request对象获取还是HttpServlet获取,其获取结果相同。

  • 代码演示
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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

        //1.通过request对象获取
        ServletContext servletContext = request.getServletContext();
        //2.通过HttpServlet获取
        ServletContext servletContext1 = this.getServletContext();

        System.out.println(servletContext);
        System.out.println(servletContext1);
        System.out.println(servletContext == servletContext1);//输出为:true
    }

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

4.3 功能

  • 1、获取MIME类型:
    • MIME类型:在互联网通信过程中定义的一种文件数据类型
    • 格式: 大类型/小类型 text/html image/jpeg
    • 获取方法:
      String getMimeType(String file)

代码演示

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/servletContextDemo2")
public class ServletContextDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过HttpServlet获取
        ServletContext servletContext = this.getServletContext();
        // 2.定义文件名称
        String filename = "a.jpg";
        //3.获取MIME类型
        String mimeType = servletContext.getMimeType(filename);
        System.out.println(mimeType);//输出为:image/jpeg
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
  • 2、域对象:共享数据
    • setAttribute(String name,Object value)
    • getAttribute(String name)
    • removeAttribute(String name)

    ServletContext对象范围:所有用户所有请求的数据

代码演示

//servletContextDemo3 设置数据
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/servletContextDemo3")
public class ServletContextDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过HttpServlet获取
        ServletContext servletContext = this.getServletContext();
        // 2.设置数据
        servletContext.setAttribute("msg","servletContextDemo3");
    }

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

//servletContextDemo4 获取数据
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/servletContextDemo4")
public class ServletContextDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过HttpServlet获取
        ServletContext servletContext = this.getServletContext();
        // 2.获取数据
        Object msg = servletContext.getAttribute("msg");
        System.out.println(msg);//输出为:servletContextDemo3
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
  • 3、获取文件的真实(服务器)路径

    方法String getRealPath(String path)
    用于获取虚拟路径的真实路径

    • path:虚拟路径文件
    • String getRealPath(String path)返回值为:虚拟路径文件的真实路径。

代码演示

			String b = context.getRealPath("/b.txt");//web目录下资源访问
	        System.out.println(b);
	
	        String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
	        System.out.println(c);
	
	        String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
	        System.out.println(a);
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/servletContextDemo5")
public class ServletContextDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过HttpServlet获取
        ServletContext servletContext = this.getServletContext();
        // 2.获取真实(服务器)路径
        String a = servletContext.getRealPath("/WEB-INF/classes/a.xml");// src目录下的资源访问(src目录下的资源,在程序运行会被加载到WEB-INF/classes目录下)
        System.out.println(a);//输出为:E:\A-File\WebProjects\ys\day0803_servlet\out\artifacts\day0811_servlet_war_exploded\WEB-INF\classes\a.xml

        String b = servletContext.getRealPath("/b.xml");// web目录下的资源访问
        System.out.println(b);//输出为:E:\A-File\WebProjects\ys\day0803_servlet\out\artifacts\day0811_servlet_war_exploded\b.xml

        String c = servletContext.getRealPath("/WEB-INF/c.xml");// WEB-INF目录下的资源访问
        System.out.println(c);//输出为:E:\A-File\WebProjects\ys\day0803_servlet\out\artifacts\day0811_servlet_war_exploded\WEB-INF\c.xml
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

@WebServlet("/servletContextDemo6")
public class ServletContextDemo6 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过HttpServlet获取
        ServletContext servletContext = this.getServletContext();
        // 2.获取真实(服务器)路径
        String a = servletContext.getRealPath("/WEB-INF/classes/file.txt");// src目录下的资源访问(src目录下的资源,在程序运行会被加载到WEB-INF/classes目录下)
        System.out.println(a);//输出为:E:\A-File\WebProjects\ys\day0803_servlet\out\artifacts\day0811_servlet_war_exploded\WEB-INF\classes\file.txt
        // 3.读取文件内容、由ServletContext提供的方法
        InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/file.txt");
        byte[] b = new byte[1024];
        int len = 0;
        while ((len = is.read(b)) != -1){
            System.out.println(new String(b ,0,len));
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
  • 在web.xml配置全局化参数
<!-- 配置全局化参数 -->
<context-param>
	<param-name>encoding</param-name>
	<param-value>UTF-8</param-value>
</context-param>
  • 在Servlet中获取全局化参数
	//获取上下文对象
	ServletContext sc = getServletContext();
	//获取全局化参数
	String e = sc.getInitParameter("encoding");
	//设置resp的编码
	resp.setCharacterEncoding(e);

4.4 文件下载(补充内容)

  • 文件下载需求

    1、页面显示超链接
    2、点击超链接后弹出下载提示框
    3、完成图片文件下载

  • 分析

    1、超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。不满足需求
    2、任何资源都必须弹出下载提示框
    3、使用响应头设置资源的打开方式: content-disposition:attachment;filename=xxx

  • 步骤

    1、定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
    2、定义Servlet:

    • 1、获取文件名称
    • 2、使用字节输入流加载文件进内存
    • 3、指定response的响应头: content-disposition:attachment;filename=xxx
    • 4、将数据写出到response输出流
  • 问题

    中文文件问题

    • 解决思路:
      1. 获取客户端使用的浏览器版本信息
      2. 根据不同的版本信息,设置filename的编码方式不同
  • 代码实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
	<!-- 把图片放到 /web/img 目录下 -->
    <a href="/day0811_servlet/downloadServlet?filename=1.jpg">图片</a>
	<a href="/day0811_servlet/downloadServlet?filename=1.avi">视频</a>
</body>
</html>
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取请求参数,文件名称
        String filename = request.getParameter("filename");
        //2.使用字节输入流加载文件进内存
        //2.1找到文件服务器路径
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("/img/" + filename);
        //2.2用字节流关联
        FileInputStream fis = new FileInputStream(realPath);

        //3.设置response的响应头
        //3.1设置响应头类型:content-type
        String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
        response.setHeader("content-type",mimeType);
        //3.2设置响应头打开方式:content-disposition

        //解决中文文件名问题
        //1.获取user-agent请求头、
        String agent = request.getHeader("user-agent");
        //2.使用工具类方法编码文件名即可
        filename = DownLoadUtils.getFileName(agent, filename);

        response.setHeader("content-disposition","attachment;filename="+filename);
        //4.将输入流的数据写出到输出流中
        ServletOutputStream sos = response.getOutputStream();
        byte[] buff = new byte[1024 * 8];
        int len = 0;
        while((len = fis.read(buff)) != -1){
            sos.write(buff,0,len);
        }
        fis.close();
    }

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

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

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")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

每日一点点进步
不进则退

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

璃尔 °

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值