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);
}
}