JavaWeb基础——Servlet

1、Servlet简介
Servlet是运行在Web服务器或应用服务器上的程序,简而言之就是服务器与和浏览器信息交互的一个中介,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
这里写图片描述
这里写图片描述
2、Tomcat和Servlet的关系
 Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户。
这里写图片描述
   ①:Tomcat将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象,所有的HTTP头数据读可以通过request对象调用对应的方法查询到。

   ②:Tomcat同时会要响应的信息封装为HttpServletResponse类型的response对象,通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给tomcat,tomcat就会将其变成响应文本的格式发送给浏览器。
3、Servlet的创建
这里写图片描述
这里写图片描述
4、Servlet的创建原理
4.1 Servlet的生命周期
服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf)
该servlet对象去处理所有客户端请求,在service(ServletRequest req,ServletResponse res)方法中执行。
最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
4.2 为什么创建的servlet是继承自httpServlet,而不是直接实现Servlet接口?
servlet的生命周期中,可以看出,执行的是service方法,为什么我们就只需要写doGet和doPost方法呢?
httpServlet继承GenericServlet。懂的人立马就应该知道,GenericServlet(通用Servlet)的作用是什么?大概的就是将实现Servlet接口的方法,简化编写servlet的步骤。具体下面详解
这里写图片描述
GenericServlet的继承结构,实现了Servlet接口和ServletConfig接口,
这里写图片描述
Servlet接口内容
这里写图片描述
从这里可以看到,Servlet生命周期的三个关键方法,init、service、destroy。还有另外两个方法,一个getServletConfig()方法来获取ServletConfig对象,ServletConfig对象可以获取到Servlet的一些信息,ServletName、ServletContext、InitParameter、InitParameterNames、通过查看ServletConfig这个接口就可以知道
ServletConfig接口内容:
这里写图片描述
其中ServletContext对象是servlet上下文对象,功能有很多,获得了ServletContext对象,就能获取大部分我们需要的信息,比如获取servlet的路径,等方法。到此,就知道了Servlet接口中的内容和作用,总结起来就是,三个生命周期运行的方法,获取ServletConfig,而通过ServletConfig又可以获取到ServletContext。
而GenericServlet实现了Servlet接口后,也就说明我们可以直接继承GenericServlet,就可以使用上面我们所介绍Servlet接口中的那几个方法了,能拿到ServletConfig,也可以拿到ServletContext,不过那样太麻烦,不能直接获取ServletContext,所以GenericServlet除了实现Servlet接口外,还实现了ServletConfig接口,那样,就可以直接获取ServletContext了。
这里写图片描述
看上图,用红色框框起来的就是实现Servlet和ServletConfig接口所实现的方法,有9个,这很正常,但是我们可以发现,init方法有两个,一个是带有参数ServletConfig的,一个有无参的方法,为什么这样设计?这里需要知道其中做了什么事情,来看看这两个方法分别做了什么事?

init(ServletConfig config)

这里写图片描述

init()

这里写图片描述
一个成员变量config:
这里写图片描述

getServletConfig()

这里写图片描述
通过这几个方法一起来讲解,首先看init(ServletConfig config)方法,因为只有init(ServletConfig config)中带有ServletConfig对象,为了方便能够在其他地方也能直接使用ServletConfig对象,而不仅仅局限在init(ServletConfig config)方法中,所以创建一个私有的成员变量config,在init(ServletConfig config)方法中就将其赋值给config,然后通过getServletConfig()方法就能够获取ServletConfig对象了,这个可以理解,但是在init(ServletConfig config)中,158行,还调用了一个init()方法,并且这个init()方法是空的,什么读没有,这是为什么呢?

这个原因是为了防止一件事情,当我们需要在init方法中做一点别的事情,我们想到的方法就是继承GenericServlet并且重写了init(ServletConfig config)方法,这样依赖,就破坏了原本在GenericServlet类中init(ServletConfig config)写的代码了,也就是在GenericServlet类中的成员变量config会一直是null,无法得到赋值,因为被重写了,就不会在执行GenericServlet中init(ServletConfig config)方法中的代码。
要想赋值,就必须在重写的init(ServletConfig config)方法中调用父类的init(ServletConfig config)方法,也就是super.init(ServletConfig config),这样一来,就很不方便,怕有时候会忘了写这句代码,所以在GenericServlet类中增加一个init()方法,以后需要在init方法中需要初始化别的数据,只需要重写init()这个方法,而不需要去覆盖init(ServletConfig config)这个方法,这样设计,就好很多,不用在管init(ServletConfig config)这个其中的内容了。也不用出现其他的问题。

service(ServletRequest req, ServletResponse res)

这里写图片描述
一个抽象方法,说明在GenericServlet类中并没有实现该内容,那么我们想到的是,在它上面肯定还有一层,也就是还有一个子类继承它,实现该方法,要是让我们自己写的Servlet继承GenericServlet,需要自己写service方法,那岂不是累死,并且我们可以看到,service方法中的参数还是ServletRequest,ServletResponse。并没有跟http相关对象挂钩,所以我们接着往下面看。
当我们实现Servlet方法的时候,我们需要自己实现Service方法,service方法中的参数还是ServletRequest,ServletResponse。并没有跟http相关对象挂钩,而我们继承HttpServlet的时候不仅实现了Service方法,而且还与http相关对象挂钩,实现了各种请求相关的方法。所以创建的servlet是继承自httpServlet,而不是直接实现Servlet接口

HttpServlet类详解:
继承了GenericServlet类,通过我们上面的推测,这个类主要的功能肯定是实现service方法的各种细节和设计。并且通过类名可以知道,该类就跟http挂钩了。
这里写图片描述
关注service(HttpServletRequest req, HttpServletResponse resp)方法和service(ServletRequest req, ServletResponse res)方法。

service(ServletRequest req, ServletResponse res)方法
这里写图片描述
该方法中就做一件事情,就是将ServletRequest和ServletResponse这两个对象强转为HttpServletRequest和HttpServletResponse对象。为什么能这样转?

首先要知道req、res是什么类型,通过打印System.out.println(req),可以知道,req实际上的类型是org.apache.catalina.connector.RequestFacade
Tomcat中的源码。     
这里写图片描述
这里写图片描述
通过图可以得知,req的继承结构:RequestFacade、httpServletRequest、ServletRequest,我们知道本身req是ServletRequest,那么从继承结构上看,它也可以看成HttpServletRequest,也可以看成ServletRequest,所以强转为HttpServletRequest是可以的.
如果不明白,我举个例子,ArrayList、List、Object 这个,Object obj = new ArrayList(); List list = new ArrayList(); 一个ArrayList对象可以看成List对象, 也可以看成一个Object对象,现在obj是不是可以堪称List对象呢?答案是可以的,因为obj就是ArrayList对象,既然是ArrayList对象,那么就可以看成是List对象。一样的道理,RequestFacade 对应 ArrayList、httpServleRequest对应 List、 ServletRequest 对应 Object。

转换为httpServletRequest和HttpServletResponse对象之后,在调用service(HttpServletRequest req, HttpServletResponse resp)方法。
这个方法就是判断浏览器过来的请求方式是哪种,每种的处理方式不一样,我们常用的就是get,post,并且,我们处理的方式可能有很多的内容,所以,在该方法内会将get,post等其他5种请求方式提取出来,变成单个的方法,然后我们需要编写servlet时,就可以直接重写doGet或者doPost方法就行了,而不是重写service方法,更加有针对性。
所以这里就回到了我们上面编写servlet时的情况,继承httpServlet,而只要重写两个方法,一个doGet,一个doPost,其实就是service方法会调用这两个方法中的一个(看请求方式)。这也是为什么执行的是service方法,而我们就只需要写doGet和doPost方法

实现Servlet接口的Service方法:

package cn.itcast;

import java.io.IOException;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class ServletDemo1 extends GenericServlet {

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        // TODO Auto-generated method stub
        res.getOutputStream().write("hello servlet!!!".getBytes());
    }

}

继承HttpServlet实现方法:

package cn.itcast;

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

/**
 * Servlet implementation class ServletDemo2
 */
@WebServlet("/ServletDemo2")
public class ServletDemo2 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getOutputStream().write("hello servlet".getBytes());
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

4.3 几个重点的对象。ServletConfig、ServletContext,request、response

4.3.1 ServletConfig对象
获取途径:getServletConfig();
功能:上面大概提及了一下,能得到四个东西:
这里写图片描述

getServletName(); //获取servlet的名称,也就是我们在web.xml中配置的servlet-name
getServletContext(); //获取ServletContext对象,该对象的作用看下面讲解
getInitParameter(String); //获取在servlet中初始化参数的值。这里注意与全局初始化参数的区分。这个获取的只是在该servlet下的初始化参数。

在实际开发中有一些东西不适合在servlet程序中写死,这类数据就可以通过配置注解方,配给servlet,例如servlet采用哪个码表,servlet连接哪个库,servlet哪个配置文件,servletConfig对象,用于封装servlet的配置信息。以下的就是其应用:
这里写图片描述

getInitParameterNames(); //获取在Servlet中所有初始化参数的名字,也就是key值,可以通过key值,来找到各个初始化参数的value值。注意返回的是枚举类型
这里写图片描述
这里写图片描述
这里写图片描述
注意:上面的web.xml中的方式在Servlet3.0中换成了采用注解的方式,在上面我们所分析的源码过程中,我们就知道,其实可以不用先获得ServletConfig,然后在获取其各种参数,可以直接使用其方法,比如上面我们用的ServletConfig().getServletName();可以直接写成getServletName();而不用在先获取ServletConfig();了,原因就是在GenericServlet中,已经帮我们获取了这些数据,我们只需要直接拿就行。
4.3.2 ServletContext
这里写图片描述
 功能:tomcat为每个web项目都创建一个ServletContext实例,tomcat在启动时创建,服务器关闭时销毁,在一个web项目中共享数据,管理web项目资源,为整个web配置公共信息等,通俗点讲,就是一个web项目,就存在一个ServletContext实例,每个Servlet都可以访问到它。
 这里写图片描述

package cn.itcast;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * Servlet implementation class ServletDemo4
 */
//在实际开发中有一些东西不适合在servlet程序中写死,这类数据就可以通过配置注解方式
//配给servlet,例如servlet采用哪个码表,servlet连接哪个库,servlet哪个配置文件
//servletConfig对象,用于封装servlet的配置信息

//获取web应用的初始化参数
//Context-Param(上下文初始化参数)供所有Servlet共享,而初始化参数//InitParam只供本Servlet用

@WebServlet(urlPatterns= {"/ServletDemo6"})//这就是注解
public class ServletDemo6 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        //得到servletContext的方式1
        ServletContext context=this.getServletConfig().getServletContext();
        //得到ServletContext的方法2
        //ServletContext context=this.getServletContext();
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

ServletDemo5

package cn.itcast;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
 * servletContext域:
 * 1、这是一个容器
 * 2、servletContext域这句话说明了这个容器的作用范围,也就是应用程序范围
 * 
 * */
@WebServlet(urlPatterns= {"/ServletDemo5"})
public class ServletDemo5 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //实现两个Servlet的数据共享,即Servlet5和Servlet5_1之间的额data共享
        String data="aaa";
        this.getServletContext().setAttribute("data", data);

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

ServletDemo5_1

package cn.itcast;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns= {"/ServletDemo5_1"})
public class ServletDemo5_1 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String value=(String)this.getServletContext().getAttribute("data");
        System.out.println(value);

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

转发
1.jsp
这里写图片描述

package cn.itcast;

import java.io.IOException;

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;

/**
 * Servlet转发:你找我借钱,我没有,我帮你找他
 * 重定向:你找我借钱,我没有,你找他
 */
@WebServlet("/ServletDemo10")
public class ServletDemo10 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String data="aaaa";
        //把数据带给1.jsp(不能通过该域带数据,因为ServletContext的数据是共享的,如果此时另一个ServletContex来访,服务器去执行则会把另一个数据给了该ServletContext,覆盖了前面的,导致显示出问题)
        this.getServletContext().setAttribute("data", data);

        RequestDispatcher rd=this.getServletContext().getRequestDispatcher("/1.jsp");
        rd.forward(request, response);//转发
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

读取资源配置文件

db.properties

url=jdbc:mysql://localhost:3306/test
username=root;
password=root;
package cn.itcast;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

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

/**
 * 读取资源配置文件最好采用ServletContex去读,而不要采用传统方式去读
 */
/*
 * private void test() throws IOException{
 *  //"classes/db.properties"这种相对路径是相对java虚拟机的,而我们服务器的Java虚拟机在tomcat根目录下,但它的下面没有classes这个文件
 *  FileInputStream in=new FileInputStream("classes/db.properties");
 *  Properties props=new Properties();
 *  props.load(in);
 * }
 * 
 * */
@WebServlet("/ServletDemo11")
public class ServletDemo11 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        // 目录等价 /src=WEB-INF/classes    WebContent=/
        //WEB-INF/classes/db.properties相当于/src/db.properties
        InputStream in=this.getServletContext().getResourceAsStream("WEB-INF/classes/db.properties");

        Properties pros=new Properties();
        pros.load(in);
        String url=pros.getProperty("url");
        String username=pros.getProperty("username");
        String password=pros.getProperty("password");

        System.out.println(url);
        System.out.println(username);
        System.out.println(password);


    }
    //读取资源文件的方法二,通过ServletContext的getRealPath的得到资源的绝对路径后,再通过传统流读取资源文件
    //通过这种方式可以获取到资源文件名称,有时需要获取文件的名称就可以使用该方法
    /*
    private void test() throws IOException {
        String path=this.getServletContext().getRealPath("WEB-INF/classes/db.properties");
        FileInputStream in=new FileInputStream(path);

        String filename=path.substring(path.lastIndexOf("\\")+1);//找到最后一个斜杠的位置(双斜杠有一个是转义字符),然后从改位置截取到最后
        System.out.println("当前读取到的资源文件名称是:"+filename);

        Properties pros=new Properties();
        pros.load(in);
        String url=pros.getProperty("url");
        String username=pros.getProperty("username");
        String password=pros.getProperty("password");

        System.out.println(url);
        System.out.println(username);
        System.out.println(password);


    }
*/
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

例2:

dao.java

package cn.itcast.dao;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

//如果读取资源文件的程序不是Servlet的话,就只能通过类装载器去读了(文件不能太大)
public class Dao {
    //通过类装载器获取资源文件
    //这种方法当web应用访问了一次之后,此时我们的db.properties文件被修改了的话,再次访问读取到的还是原来的数据
    //因为类加载器只加载一次,我们配置文件的名称没有变化,所以还是原来第一次加载的数据
    /*public void update() throws IOException {
    InputStream in=Dao.class.getClassLoader().getResourceAsStream("db.properties");
    Properties prop=new Properties();
    prop.load(in);
    System.out.println(prop.getProperty("url"));*/
    public void update() throws IOException {
        //通过类装载器的方式得到资源文件的位置,再通过传统方式读取资源文件的数据,这样就可以读取到更新后的数据
        String path=Dao.class.getClassLoader().getResource("db.properties").getPath();
        FileInputStream in=new FileInputStream(path);
        Properties prop=new Properties();
        prop.load(in);
        System.out.println(prop.getProperty("url"));
    }

}
package cn.itcast;

import java.io.IOException;
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 cn.itcast.dao.Dao;

/**
 * Servlet调用其他程序,在其它程序中如何读取资源文件(通过类装载器的方法) 
 */
@WebServlet("/ServletDemo12")
public class ServletDemo12 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        Dao dao=new Dao();
        dao.update();
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

4.3.3 Response
这里写图片描述
这里写图片描述
这里写图片描述

中文乱码问题

package cn.itcast.response;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

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

/**
 * Servlet输出数据的问题以及输出中文的问题
 */
@WebServlet("/ResponseDemo1")
public class ResponseDemo1 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        test1(response);
        //用html中的meta标签来模拟http响应头来控制浏览器的输出行为
        test2(response);

        test3(response);

    }

    private void test4(HttpServletResponse response) throws IOException, UnsupportedEncodingException {
        //注意,浏览器输出的不会是1,而是1对应的GB2312的编码
        OutputStream out=response.getOutputStream();

        out.write(1);//浏览器直接读到1,由于浏览器默认是GB2312编码,所以显示会出问题
    }

    private void test3(HttpServletResponse response) throws IOException, UnsupportedEncodingException {
        //注意,下面写错了,浏览器会提示下载
        response.addHeader("content-type","text/html,charset=utf-8");

        String data="中国";
        OutputStream out=response.getOutputStream();

        out.write(data.getBytes("UTF-8"));//Servlet以UTF-8格式编码该字符,而浏览器默认是GB2312编码,所以显示会出问题
    }

    private void test2(HttpServletResponse response) throws IOException, UnsupportedEncodingException {
        //解决下面乱码的方法,可以通过设置html的编码格式(改变浏览器的默认编码格式,meta标签用于模拟一个头)
        //程序以什么码表输出,就一定要控制浏览器以什么码表打开,方法2

        String data="中国";
        OutputStream out=response.getOutputStream();

        out.write("<meta http-equiv='content-type' content='text/html;charset=utf-8'>".getBytes());
        out.write(data.getBytes("UTF-8"));//Servlet以UTF-8格式编码该字符,而浏览器默认是GB2312编码,所以显示会出问题
    }


    private void test1(HttpServletResponse response) throws IOException, UnsupportedEncodingException {
        //解决下面乱码的方法,可以通过设置html的编码格式(改变浏览器的默认编码格式)
        //程序以什么码表输出,就一定要控制浏览器以什么码表打开
        response.setHeader("Content-type","text/html;charset=UTF-8");


        String data="中国";
        OutputStream out=response.getOutputStream();
        out.write(data.getBytes("UTF-8"));//Servlet以UTF-8格式编码该字符,而浏览器默认是GB2312编码,所以显示会出问题
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

字符输出方式中文乱码:

package cn.itcast.response;

import java.io.IOException;
import java.io.PrintWriter;

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

/**
 * 通过response的write流输出数据的问题,但只能写字符或字符串
 */
@WebServlet("/ResponseDemo2")
public class ResponseDemo2 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        test1(response);
    }

    private void test2(HttpServletResponse response) throws IOException {
        //设置response使用的码表,以控制response以什么码表向浏览器写出数据
        response.setCharacterEncoding("UTF-8");
        //指定浏览器以什么码表打开服务器发送的数据
        //response.setHeader("content-type", "text/html;charset=UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String data="中国";
        PrintWriter out=response.getWriter();
        out.write(data);
    }

    private void test1(HttpServletResponse response) throws IOException {
        //设置response使用的码表,以控制response以什么码表向浏览器写出数据
        response.setCharacterEncoding("UTF-8");
        //指定浏览器以什么码表打开服务器发送的数据
        response.setHeader("content-type", "text/html;charset=UTF-8");

        String data="中国";
        PrintWriter out=response.getWriter();
        out.write(data);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

文件下载:

package cn.itcast.response;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

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

/**
 * 文件下载
 */
@WebServlet("/ResponseDemo3")
public class ResponseDemo3 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*文件名称是英文的
         * String path=this.getServletContext().getRealPath("/download/DOM.png");
        String filename=path.substring(path.lastIndexOf("//")+1);
        response.setHeader("content-disposition", "attachment;filename="+filename);*/

        //如果下载文件是中文文件名的,则文件名需要经过url编码
        String path=this.getServletContext().getRealPath("/download/servlet细节2.png");
        String filename=path.substring(path.lastIndexOf("//")+1);
        response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename, "utf-8"));


        InputStream in=null;
        OutputStream out=null;
        try {
            in=new FileInputStream(path);
            int len=0;
            byte buffer[]=new byte[1024];
            out=response.getOutputStream();
            while((len=in.read(buffer))>0) {
                out.write(buffer,0,len);
            }

        }finally {
            if(in!=null) {
                try {
                    in.close();
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

输出一张验证码图片:

Register.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        认证码:<input type="text" name="checkcode"><img src="ResponseDemo4"><br/>
        <input type="submit" value="注册">
    </form>
</body>
</html>

Register1.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        认证码:<input type="text" name="checkcode"><img src="ResponseDemo4"><br/>
        <input type="submit" value="注册">
    </form>
</body>
</html>
package cn.itcast.response;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

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;

/**
 * 输出一张随机图片
 */
@WebServlet("/ResponseDemo4")
public class ResponseDemo4 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public static final int WIDTH=120;
    public static final int HEIGHT=25;
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        BufferedImage image=new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);//构建出一张图片
        Graphics g=image.getGraphics();//使得能在图片上进行设置

        //1、设置背景色
        setBackGround(g);
        //2、设置边框
        setBorder(g);
        //3、画干扰线
        drawRandomLine(g);
        //4、写随机数
        drawRandomNum((Graphics2D) g);

        //5、图形写给浏览器
        //发头控制浏览器不要缓存,如果没有这步的话当我们访问Register网页时不点刷新,直接按回车,图片还是保持不变
        //点击刷新的时候会产生两个动作:一是重新清空缓存;二是重新运行程序
        response.setDateHeader("expire", -1);//控制所有浏览器都不要缓存
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        response.setContentType("image/jpeg");
        ImageIO.write(image, "jpg", response.getOutputStream());


    }

    private void drawRandomNum(Graphics2D g) {
        // TODO Auto-generated method stub
        g.setColor(Color.RED);
        g.setFont(new Font("宋体",Font.BOLD,20));

        String base="\u6d4e\u8499\u68cb\u7aef\u817f\u62db\u91ca\u4ecb\u70e7\u8bef";

        //[\u4e00-\u9fa5]
        int x=5;
        for(int i=0;i<4;i++) {

            int degree=new Random().nextInt()%30;//从-30-30之间产生一个随机数

            //Graphics2D类才有旋转功能
            //new Random().nextInt(base.length()):在base的长度以内产生一个随机数
            String ch=base.charAt(new Random().nextInt(base.length()))+"";
            g.rotate(degree*Math.PI/180,x,20);//设置旋转角度
            g.drawString(ch, x, 20);
            g.rotate(-degree*Math.PI/180,x,20);//转回去
            x+=30;
        }
    }

    private void drawRandomLine(Graphics g) {
        // TODO Auto-generated method stub
        g.setColor(Color.GREEN);
        for(int i=0;i<5;i++) {
            int x1=new Random().nextInt(WIDTH);
            int y1=new Random().nextInt(HEIGHT);

            int x2=new Random().nextInt(WIDTH);
            int y2=new Random().nextInt(HEIGHT);
            g.drawLine(x1, y1, x2, y2);
        }
    }

    private void setBorder(Graphics g) {
        // TODO Auto-generated method stub
        g.setColor(Color.BLUE);
        g.drawRect(1, 1,WIDTH-2, HEIGHT-2);
    }

    private void setBackGround(Graphics g) {
        // TODO Auto-generated method stub
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

控制浏览器定时刷新:

message.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <%
        String message=(String)application.getAttribute("message");
        out.write(message);
    %>
</body>
</html>

index.jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    Hi
</body>
</html>
package cn.itcast.response;

import java.io.IOException;
import java.util.Random;

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

/**
 * 控制浏览器定时刷新
 */
@WebServlet("/ResponseDemo5")
public class ResponseDemo5 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //test1(response);
        //test2(response);
        test3(request,response);
    }
    //实用的自动跳转技术
    private void test3(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
        //假设这是一个用于处理登陆的servlet,这才是实际工程应用得到的


        String message="<meta http-equiv='refresh' content='3;url=index.jsp'>登录成功,该页面将在3秒后,跳转到首页,如果没有跳,请点击<a href=''>超链接</a>";
        this.getServletContext().setAttribute("message", message);
        //在Response响应的消息到达浏览器之前将resquest的请求转发到message.jsp,由message.jsp进行回应
        //而message.jsp会显先显示“登录成功,该页面将在3秒后,跳转到首页,如果没有跳,请点击”,因为要过3秒才能跳转到index.jsp页面
        this.getServletContext().getRequestDispatcher("/message.jsp").forward(request, response);
    }

    private void test2(HttpServletResponse response) throws IOException {
        //假设这是一个用于处理登陆的servlet

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


        response.setHeader("refresh","3;url='index.jsp'");//控制浏览器每隔3秒刷新一次
        response.getWriter().write("登录成功,该页面将在3秒后,跳转到首页,如果没有跳,请点击<a href=''>超链接</a>");
    }

    private void test1(HttpServletResponse response) throws IOException {
        response.setHeader("refresh","3");//控制浏览器每隔3秒刷新一次

        String data=new Random().nextInt(100000)+"";
        response.getWriter().write(data);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

控制缓存:

CacheDemo6.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <a href="ResponseDemo6">访问图书馆</a>
</body>
</html>
package cn.itcast.response;

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

/**
 * 控制缓存
 */
@WebServlet("/ResponseDemo6")
public class ResponseDemo6 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setDateHeader("expires", System.currentTimeMillis()+1000*3600);//获取浏览器的缓存时间为1个小时,当多次访问CacheDemo6中的超链接它返回的信息:aaaaa会直接去缓存中的,而不会多次去找Servlet要数据
        String data="aaaaaaa";
        response.getWriter().write(data);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

重定向:

package cn.itcast.response;

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

/**
 * 实现请求重定向
 * 
 * 重定向的特点:
 * 1、浏览器会向服务器发送两次,意味着就有两个request\response
 * 2、用重定向技术。浏览器地址栏会发生变化
 * 
 * 用户登录和显示购物车,通常会用到重定向技术(用转发则刷新一次页面,就会重新购买一次)
 */
@WebServlet("/ResponseDemo7")
public class ResponseDemo7 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*
         * response.setStatus(302);
         * response.setHeader("location","index.jsp");
         * */
        response.sendRedirect("index.jsp");//相当于上面两句,实现了重定向,一般不建议用重定向,因为它会发送两次请求,加剧了浏览器的载荷
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

4.3.4 Request

Request一些常用方法:
这里写图片描述

package cn.itcast.request;

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

/**
 *Request的常用方法
 */
@WebServlet("/RequestDemo1")
public class RequestDemo1 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(request.getRequestURI());///day2/RequestDemo1
        System.out.println(request.getRequestURL());//http://localhost:8080/day2/RequestDemo1

        //localhost:8080/day2/RequestDemo1?name=aaa
        System.out.println(request.getQueryString());//获取查询信息,即name=aaa
        System.out.println(request.getRemoteAddr());//获取客户端(来访者)的IP
        System.out.println(request.getRemoteHost());//获取客户端(来访者)的主机名,若没在DNS上注册,则返回的还是IP
        System.out.println(request.getRemotePort());//获取客户端(来访者)的所使用的网络端口号
        System.out.println(request.getLocalAddr());//返回WEB服务器的IP地址
        System.out.println(request.getLocalName());//返回WEB服务器的主机名
        System.out.println(request.getMethod());//得到客户机请求方式
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

获取请求头和请求数据:

test.html

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <a href="ResponseDemo6">访问图书馆</a>
</body>
</html>
package cn.itcast.request;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Map;

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

/**
 * 获取请求头和请求数据
 */
@WebServlet("/RequestDemo2")
public class RequestDemo2 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //test1(request);
        test2(request);
    }
    //获取请求数据(获取请求数据时一般来说都要先检查再使用)
    private void test2(HttpServletRequest request) throws IOException {
        String value=request.getParameter("username");
        if(value!=null && !value.trim().equals("")) {
            System.out.println(value);
        }
        System.out.println("-----------");
        //获取数据的第二种方式
        Enumeration e=request.getParameterNames();
        while(e.hasMoreElements()) {
            String name=(String)e.nextElement();//username password
            value=request.getParameter(name);
            System.out.println(name+"="+value);
        }
        //获取数据的第三种方式,获取所有的数据
        //获取请求数据(获取请求数据时一般来说都要先检查再使用)
        System.out.println("------------------");
        String[] values=request.getParameterValues("username");
        for(int i=0;values!=null && i<values.length;i++) {
            System.out.println(values[i]);
        }
        //获取数据的第四种方式
        /*Map<String,String[]> map=request.getParameterMap();//将test.html中获取到的数据封装到map集合中
        //user对应的密码可能会有多个(密码错误的情况,即输入多次密码)
        User user=new User();
        try {
            BeanUtils.populate(user,map);//通过BeanUtils这个框架将map的数据填充到User中
            //BeanUtils.copyProperties(user,formbean);//bean的拷贝
        }catch(Exception e1) {
            e1.printStackTrace();
        }
        System.out.println(user);*/
        //获取数据的第五种方式(主要是文件上传的)
        InputStream in=request.getInputStream();
        int len=0;
        byte buffer[]=new byte[1024];
        while((len=in.read(buffer))>0) {
            System.out.println(new String(buffer,0,len));
        }

    }

    private void test1(HttpServletRequest request) {
        String headValue=request.getHeader("Accept-Encoding");//获取头为Accept-Encoding的信息(只有第一个的)
        System.out.println(headValue);

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

        Enumeration e=request.getHeaders("Accept-Encoding");//获取头为Accept-Encoding的信息
        while(e.hasMoreElements()) {
            String value=(String)e.nextElement();
            System.out.println(value);
        }

        System.out.println("------------");
        //第二种获取头的名称方式
        e=request.getHeaderNames();
        while(e.hasMoreElements()) {
            String name=(String)e.nextElement();
            String value=request.getHeader(name);
            System.out.println(name+"="+value);
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

通过表单收集客户机数据:

form.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="RequestDemo3" method="post">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        性别:
            <input type="radio" name="gender" value="male"/><input type="radio" name="gender" value="femal"><br/>

        所在地:
            <select name="city">
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="changsha">长沙</option>
            </select>
            <br/>

        爱好:
            <input type="checkbox" name="likes" value="sing">唱歌
            <input type="checkbox" name="likes" value="dacne">跳舞
            <input type="checkbox" name="likes" value="basketball">篮球
            <input type="checkbox" name="likes" value="football">足球
            <br/>

        备注:<textarea rows="6" cols="60" name="description"></textarea>
        大头照:<input type="file" name="image"><br/>

        <input type="hidden" name="id" value="12356">

        <input type="submit" value="提交"><br/>       
    </form>
</body>
</html>
package cn.itcast.request;

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

/**
 * 通过表单收集客户机数据
 */
@WebServlet("/RequestDemo3")
public class RequestDemo3 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println(request.getParameter("username"));
        System.out.println(request.getParameter("password"));
        System.out.println(request.getParameter("gender"));
        System.out.println(request.getParameter("city"));
        String likes[]=request.getParameterValues("likes");
        if(likes!=null) {
            for(int i=0;i<likes.length;i++) {
                System.out.println(likes[i]);
            }
        }
        System.out.println(request.getParameter("description"));
        System.out.println(request.getParameter("id"));

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

获取请求数据中文乱码:

form2.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>中文乱码</title>
</head>
<body>
    <form action="RequestDemo2" method="post">
        用户名:<input type="text" name="username">
        <input type="submit" value="提交">
    </form>

    <!-- get提交方式 -->
    <form action="RequestDemo2" method="get">
        用户名:<input type="text" name="username">
        <input type="submit" value="提交">
    </form>
    <!-- 超链接提交的中文,服务器不乱码,也只能手工处理,因为它也是get提交方式-->
    <a href="RequestDemo2?username=中国">点点</a>

</body>
</html>
package cn.itcast.request;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

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

/**
 * Servlet implementation class RequestDemo4
 */
@WebServlet("/RequestDemo4")
public class RequestDemo4 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        test2(request);
        test1(request);
    }

    private void test2(HttpServletRequest request) throws UnsupportedEncodingException {
        //当输入的是中文的时候则会乱码,因为浏览器默认是是utf-8(假设)
        //访问网页提交数据后会把数据提交给request,然后request在提交给Servlet
        //但request是ISO8599-1,即对应里面的码表,而Servlet是utf-8,所以必然乱码
        //解决方式是通过改变request的编码格式也为utf-8就行了
        request.setCharacterEncoding("utf-8");//只对post提交方式有效
        String username=request.getParameter("username");
        System.out.println(username);
    }

    private void test1(HttpServletRequest request) throws UnsupportedEncodingException {
        //处理get提交方式乱码
        //先通过username.getBytes("iso-8859-1")获取到原来的字符,然后再通过“utf-8”进行转码过来即可
        String username=request.getParameter("username");
        username=new String(username.getBytes("iso-8859-1"),"utf-8");
        System.out.println(username);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

请求转发:

Demo5.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <%
        String data=(String)request.getAttribute("data");
        out.write(data);
    %> 
</body>
</html>
package cn.itcast.request;

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

/**
 * 请求转发以及使用request域对象把数据带给转发资源
 * MVC设计模式:M   model(javabean)  V  view(jsp)   c cotroller(Servlet)
 */
@WebServlet("/RequestDemo5")
public class RequestDemo5 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String data="aaa";
        request.setAttribute("data", data);//每一个请求都有一个request,不是共享的所以可以,而Servlet则是共享的
        //request实现转发
        request.getRequestDispatcher("/Demo5.jsp").forward(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

request需要注意的细节:

package cn.itcast.request;

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

/**
 * 以下代码将抛异常
 */
@WebServlet("/RequestDemo6")
public class RequestDemo6 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        /*在forward之前输入到response缓冲区中的数据,但是还没有发送到客户端,forward可以执行,但是缓冲区将被清空,之前的数据丢失。注意丢失的只是请求体中的内容,头内容仍然有效。
        在一个Servlet中进行多次forward也是不行的,因为第一次forward结束,response已经被提交了,没有机会再forward了
        总之,一条原则,一次请求只能有一次响应,响应提交走后,就再没有机会输出数据给浏览器了。*/

        String data="aaaa";
        if(true) {
            request.getRequestDispatcher("/index.jsp").forward(request, response);
            return;//加了这个就解决了,但是只会跳转到index.jsp
        }
        //以下跳转会导致: Cannot forward after response has been committed
        request.getRequestDispatcher("/message.jsp").forward(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
package cn.itcast.request;

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

/**
 * request细节
 */
@WebServlet("/ResquestDemo7")
public class ResquestDemo7 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String data="aaaa";
        response.getWriter().write(data);

        //请求转发的特点:客户端只发一次请求,而服务器端有多个资源调用    客户端浏览器地址栏没有变化

         /*//forward时会清空response中的数据    但为什么不是先显示上面的?
          * 
          * 如果在调用forward方法之前向Servlet引擎的缓冲区(response)中写入了内容, 
           只要写入到缓冲区的内容还没有被真正输出到客户端,forward方法就可以被正常执行, 
           原来写入到缓冲区中的内容将被清空,但是,以写入到HttpServletResponse对象中的响应头字段信息保持有效

           对于一次请求,Response的getOutputStream方法和getWriter方法是互斥,只能调用其一,特别注意forward后也不要违反这一规则。
           利用Response输出数据的时候,并不是直接将数据写给浏览器,而是写到了Response的缓冲区中,等到整个service方法返回后,由服务器拿出response中的信息组成HTTP响应消息返回给浏览器。
          service方法返回后,服务器会自己检查Response获取的OutputStream或者Writer是否关闭,如果没有关闭,服务器自动帮你关闭,一般情况下不要自己关闭这两个流。  
            */
        request.getRequestDispatcher("index.jsp").forward(request, response);
        /*
         * String data="aaaa";
         * PrintWriter writer=response.getWriter();
         * writer.write(data);
         * write.close();//因为它的存在  执行下面的就会抛异常,response已经关闭了下面的就不能执行,导致异常
         * request.getRequestDispatcher("index.jsp").forward(request, response);
         * */
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

页面包含

head.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    head<br/>
</body>
</html>

foot.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    foot<br/>
</body>
</html>
package cn.itcast.request;

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

/**
 * 用include实现页面包含,就是可以实现两个页面出现在同一个页面中
 */
@WebServlet("/RequestDemo8")
public class RequestDemo8 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("/public/head.jsp").include(request, response);
        response.getWriter().write("hahaha<br/>");
        request.getRequestDispatcher("/public/foot.jsp").include(request, response);
        /*结果:
         * head
           hahaha
           foot*/
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

有关地址写法

package cn.itcast.request;

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

/**
 * Servlet implementation class RequestDemo9
 */
@WebServlet("/RequestDemo9")
public class RequestDemo9 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1、地址以斜杠开头,如果是地址给服务器用的,“/”就代表当前应用,如果地址是给浏览器用的,“/”就代表网站,网站下面有多个web应用
        request.getRequestDispatcher("/form.html").forward(request, response);//给服务器用的,当前应用是指/WebRoot


        //2、
        response.sendRedirect("/day2/form.html");//给浏览器用的
        //3、
        this.getServletContext().getRealPath("/form.html");//给服务器用的
        //4、
        this.getServletContext().getResourceAsStream("/public/foot.jsp");//给服务器用的
        //5、
        /*
         * <a href="/day2/form.html">点点</a>//给浏览器用
         * 
         * <form action="/day2/form1.html">//给浏览器用
         * 
         * </form>
         * 
         * */

        //使用磁盘下的资源用"\\"
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

防盗链

package cn.itcast.request;

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

/**
 * 防盗链:假如我们要访问资源:http://blog.csdn.net/Beacher_Ma 有两种情况:
1. 我们直接在浏览器上输入该网址。那么该请求的HTTP Referer 就为null
2. 如果我们在其他页面中,通过点击,如 http://www.csdn.net 上有一个 http://blog.csdn.net/Beacher_Ma 这样的链接,那么该请求的HTTP Referer 就为http://www.csdn.net
 简而言之:我们直接通过某个链接访问就是null,而我们在该网站主页上点击某个链接就不是空
 */
@WebServlet("/RequestDemo10")
public class RequestDemo10 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String referer=request.getHeader("referer");//获取访问的网站地址
        if(referer==null || !referer.startsWith("http://localhost")) {
            response.sendRedirect("/day2/index.jsp");
            return;
        }
        String data="防盗链";
        response.getWriter().write(data);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值