Servlet
注意点:
- 在
cmd
中设置servlet相关的编译路径:set classpath=%classpath%;D:\0hsx\
,然后在运行相关的servlet的Java程序。
apache-tomcat-7.0.67\lib\servlet-api.jar
手动编写Servlet过程
- 建立JavaWeb应用的目录
Hello --- 应用名称
WEB-INF --- 目录
classes --- 目录:对应的Servlet的java文件就放在这里,比如:HelloServlet.java
lib --- 目录
web.xml --- 配置文件
- 在classes目录中建立HelloServlet.java文件,具体代码如下:
package com.hsx;
import java.io.*;
import javax.servlet.*;
public class HelloServlet extends GenericServlet {
public void init() throws ServletException {
System.out.println("init");
}
public void service(ServletRequest req, ServletResponse res) throws ServletException,java.io.IOException {
//向客户端输出数据
String data = "Hello Servlet";
OutputStream out = res.getOutputStream();
out.write(data.getBytes());
}
public void destroy() {
System.out.println("destory");
}
}
- web.xml文件的配置,代码:
<?xml version="1.0" encoding="UTf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<servlet>
<servlet-name>HelloServlet</servlet-name> <!-- Servlet的名称 -->
<servlet-class>com.hsx.HelloServlet</servlet-class> <!-- Servlet的全名-路径 -->
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name> <!-- Servlet的名称,与<servlet>中的<servlet-name>中的内容要一致 -->
<url-pattern>/helloServlet</url-pattern> <!-- URL:用户访问的映射路径 -->
</servlet-mapping>
</web-app>
- 编译HelloServlet.java文件,注意,编译需要用到servlet-api.jar(在Tomcat的lib目录中),在
cmd
目录中编译时,需要设置classpath的路径,命令set classpath=%classpath%;D:\0hsx\
,接着在classes目录下编译该java类,命令:
apache-tomcat-7.0.67\lib\servlet-api.jarjavac -d . HelloServlet.java
,这是可以在classes目录中查看其是否编译成功。 - 启动Tomcat。
- 在浏览器中输入:
http://localhost:8080/hello/helloServlet
,页面上回显示”Hello Servlet”。
感觉用intellij Idea开发Servlet不好。
开发servlet的三种方式
- 实现servlet接口
- 继承GenericServlet类
- 继承HttpServlet类 * 一般用这个
修改MyEclipse中的Servlet模板
MyEclipse2014:在MyEclipse的安装目录中找到这个com.genuitec.eclipse.wizards_11.5.0.me201310291746.jar文件,打开其中的templates找到Servlet.java文件(注意:需要关闭MyEclipse,修改是应该养成良好的备份习惯)
Servlet的一些细节
细节1
- 由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用
<servlet>
元素和<servlet-mapping>
元素完成。 <servlet>
元素用于注册Servlet,它包含两个主要的子元素:
<servlet-name>
:设置Servlet的注册名<servlet-class>
:设置Servlet的完整类名
<servlet-mapping>
元素用于映射一个已注册的Servlet的一个对外访问的路径,它包好两个子元素:
<servlet-name>
:指定Servlet的注册名<url-pattern>
:Servlet对外访问路径
- 示例:
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.hsx.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
细节2
- 同一个Servlet可以被映射到多个URL上,即多个
<servlet-mapping>
元素的<servlet-name>
子元素的值可以相同,即同一个Servlet的注册名。 - 在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:
- 一种格式是
*.扩展名
(注:*前没有其他内容) - 另一种格式是以正斜杠(/)开头并以(/*)结尾
- 一种格式是
注:*.扩展名
的匹配优先级低。
细节3
- 如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前web应用程序的缺省Servlet,即默认的Servlet。
- 凡是在web.xml文件中找不到匹配的元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省的Servlet用于处理所有其他的Servlet群殴不处理的访问请求。
- 在[tomcat的安装目录]\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省的Servlet。
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
即访问Tomcat服务器中某个静态HTML文件盒图片时,实际上是在访问这个缺省的Servlet。
Servlet的生命周期
- Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎控制和调度。
- 针对客户端的多次请求,通常,服务器只会创建一个Servlet实例对象,也就说Servlet实例对象一旦创建,它就会驻留在内存中,为后继的其他请求服务,直至web容器退出,Servlet实例对象才会销毁。
- 在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用Servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给他调用的Servlet的service()方法,service方法再根据请求方式调用doXXX方法。
<load-on-startup>
的取值说明这个Servlet的启动顺序。
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.hsx.HelloServlet</servlet-class>
<load-on-startop>2</load-on-startup>
</servlet
Servlet线程安全问题
- 当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
- 如果Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。
- SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。
- 对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每一个线程分别调用一个独立的Servlet实例对象。
- 实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。
解决并发问题
- 使用Java同步机制对多线程同步:运行效率低。
- 使用SingleThreadModel接口。
- 合理决定在Servlet中定义的变量的作用域。
ServletConfig对象
- 在Servlet的配置文件中,可以使用一个或多个
<init-param>
标签为Servlet配置一些初始化参数。 - 当Servlet配置了初始化参数后,web容器在创建Servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用Servlet的init方法时,将ServletConfig对象传递给Servlet,从而,程序员通过ServletConfig对象就可以得到当前Servlet的初始化参数信息。
<init-param>
<param-name>enconding</param-name>
<param-value>utf-8</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
注:要配置在的下面。
补充:
- 只能给某个Servlet配置参数,当然也只能作用于对应的Servlet。
- 是给所有的Servlet配置参数,当然要配置在所有的Servlet外面,作用于所有的Servlet。
- 示例:
<!-- web.xml -->
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
<context-param>
<param-name>welcome</param-name>
<param-value>hhh</param-value>
</context-param>
//结合ServletContext对象
ServletConfig servletConfig = this.getServletConfig();
ServletContext servletContext = servletConfig.getServletContext();
Enumeration<String> e = servletContext.getInitParameterNames();
while (e.hasMoreElements()) {
String name = e.nextElement();
Object value = servletContext.getInitParameter(name);
System.out.println(value);
}
ServletContext对象
- Web容器在启动时,它会为每一个Web应用程序都创建一个对应的ServletContext对象,它代表的是当前的Web应用。
- ServletConfig对象中维护了ServletContext对象的引用,我们在编写程序时,可以通过:
- servletConfig.getServletContext方法
this.getServletConfig().getServletContext();
获得ServletContext对象。 - 在继承HttpServlet中,直接
ServletContext sc = getServletContext();
获得ServletContext对象。
- servletConfig.getServletContext方法
- 由于一个Web应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象实现通讯。ServletContext对象通常也被称为context域对象。
ServletContext应用
- 实现Servlet的转发示例:
//ServletContextDemo3中的代码
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher("/ServletContextDemo4");
rd.forward(request, response);
//ServletContextDemo4中的代码
response.getOutputStream().write("nihao".getBytes());
- 转发的特点:
- 请求的地址栏不变。
- 转发前的Servlet和转发后的Servlet,两者之间共享request和response对象。
- 转发前的页面是不会有输出的,显示的始终是转发后的页面。示例:
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher("/ServletContextDemo4");
System.out.println("转发前ServletContextDemo3"); //后台会打印
response.getOutputStream().write("Demo3 before".getBytes()); //页面不会显示
response.getOutputStream().flush(); //强制刷新缓存 - 这是显示的Dome3的内容,而不会显示Demo4的内容
//注:转发前不要刷新response输出流
//转发前会清空response中输出流的内容
rd.forward(request, response);
System.out.println("转发后ServletContextDemo3"); //后台会打印
response.getOutputStream().write("Demo3 after".getBytes()); //页面不会显示
- ServletContext读取资源配置文件,示例:
package com.hsx;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 读取文本中的某个资源文件,下载的方式打开
* @author hsx
*
*/
public class ServletContextDemo5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1 http.png的真实路径
String httpPath = "/image/http.png"; //在web开发中"/"就代表当前web应用的根目录,本应用就是servletContext
ServletContext sc = getServletContext();
String realPath = sc.getRealPath(httpPath); //得到绝对路径
System.out.println(realPath);
InputStream in = new FileInputStream(realPath);
OutputStream out = response.getOutputStream();
//通知客户端下载的方式
response.setHeader("Content-Disposition", "attachment;filename=http.png");
byte[] buffer = new byte[1024];
int len = -1;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.close();
out.close(); //有没有没有什么关系,servlet容器会自动将其关闭
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
注:getRealPath():获取指定相对路径资源的绝对路径,相对路径在WebRoot目录下必须以”/”开始。
- 读取WEB-INF目录下的配置文件
String realPath = sc.getRealPath("/WEB-INF/db.properties");
- 读取类目录下的配置文件
String realPath = sc.getRealPath("/WEB-INF/classes/db.properties");
- 读取类目录中的某个包中的配置文件
String realPath = sc.getRealPath("/WEB-INF/classes/com/hsx/db.properties");
- 采用类加载器读取配置文件,ClassLoader只能加载类目录中的资源(类加载不适合加载大的配置文件)
ClassLoader cl = ServletContextDemo6.class.getClassLoader(); //or this.getClass().getClassLoader();
InputStream in = cl.getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
System.out.println(properties.getProperty("name"));
System.out.println(properties.getProperty("password"));
HttpURLConnection
- HttpURLConnection类的作用是通过HTTP协议向服务器发送请求,并可以获取服务器发回的数据。
- HttpURLConnection来自于jdk,它的完整名称为:java.net.HttpURLConnection。
- HttpURLConnection类没有公开的构造方法,但我们可以通过java.net.URL的openConnection方法获取一个URLConnection的实例,而HttpURLConnection是它的子类。
- 示例:
URL url = new URL("http://localhost:8080");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- 示例:简单获取服务器数据
- connection.getResponseCode() : 获取响应码
- connection.getResponseMessage() : 获取响应码描述
- connection.getHeaderField(“Server”) : 获取响应头
- connection.getInputStream(): 获取正文输入流
package com.hsx;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpURLConnectionTest {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 获取响应码
int code = connection.getResponseCode();
// 获取响应码描述
String status = connection.getResponseMessage();
// 获取一个响应头
String header = connection.getHeaderField("Server");
// 获取响应正文
InputStream in = connection.getInputStream();
System.out.println("响应码" + code + "\t响应码描述" + status + "\t响应头" + header);
byte[] buffer = new byte[1024];
int len = -1;
while ((len = in.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
in.close();
connection.disconnect();
}
}
- 示例:向服务器发送消息默认请求到doGet方式
URL url = new URL("http://localhost:8080/servletContext/ServletContextDemo1");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
//向服务器发送消息头
connection.setRequestProperty("mheader", "pp");
//向服务器发送请求参数
OutputStream out = connection.getOutputStream();
out.write("username=huang".getBytes());
System.out.println(connection.getResponseCode());
connection.disconnect();
- 示例:向服务器发送消息默认请求到doPost方式,只需要在上述代码中加上
connection.setRequestMethod("POST")
,默认的是doGet方式。
Servlet类图
request和response
- Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象。
- request和response对象既然代表请求和响应,要获取客户机提交过来的数据,只需要找request对象;要想客户机输出数据,只需要response对象。
HttpServletResponse
- HttpServletResponse对象代表服务器的响应。这个对象中封装了向客户端发送数据、发送响应头、发送响应状态码的方法。
response常见应用
向客户端输出中文数据,以字节为单位的四种方式:
package com.hsx;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 以字节为单位向客户端发送中文数据
* @author hsx
*
*/
public class ServletTest extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//test1(response);
//test2(response);
//test3(response);
test4(response);
}
/**
* 以UTF-8编码向客户端发送中文数据,并告诉客户端编码方式
* @param response
* @throws IOException
*/
private void test4(HttpServletResponse response) throws IOException {
String data = "中华";
response.setContentType("text/html;charset=UTF-8"); //实际上就是设置响应头
OutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8"));
// 告诉客户端编码方式
out.close();
}
/**
* 以UTF-8编码向客户端发送中文数据,并通过meta标签模拟请求头
* @param response
* @throws IOException
*/
private void test3(HttpServletResponse response) throws IOException {
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"));
}
/**
* 以UTF-8编码向客户端发送中文数据,并告诉客户端编码方式
* @param response
* @throws IOException
*/
private void test2(HttpServletResponse response) throws IOException {
String data = "中华";
OutputStream out = response.getOutputStream();
out.write(data.getBytes("UTF-8"));
// 告诉客户端编码方式
response.setHeader("Content-Type", "text/html;charset=UTF-8");
out.close();
}
/**
* 以本地平台默认编码向客户端发送中文数据 - GBK
* @param response
* @throws IOException
*/
private void test1(HttpServletResponse response) throws IOException {
String data = "中华";
OutputStream out = response.getOutputStream();
out.write(data.getBytes()); //默认编码GBK
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
总结:程序以什么编码输出,就要告知客户端以什么编码显示。
注:浏览器“查看”编码,再修改编码是不可取的。
注意:以字节流的方式向客户端发送1,一定要把int型的转换成String型
int i = 1;
OutputStream out = response.getOutputStream();
out.write((i + "").getBytes());
out.close();
向客户端输出中文数据,以字符为单位的两种方式:
package com.hsx;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 以字符为单位向客户端发送中文数据
*
* @author hsx
*
*/
public class ServletTest2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//test1(response);
test2(response);
}
/**
* 字符流用这一种方式就可以搞定中文乱码问题response.setContentType("text/html;charset=UTF-8");
* @param response
* @throws IOException
*/
private void test2(HttpServletResponse response) throws IOException {
String data = "你好,啊打发";
response.setContentType("text/html;charset=UTF-8");
PrintWriter pw = response.getWriter();
pw.write(data);
pw.close();
}
/**
* 制定向客户端发送的数据的编码是UTF-8,告诉客户端编码方式[即时客户端打开时显示的数据时以UTF-8编码显示的]
* @param response
* @throws IOException
*/
private void test1(HttpServletResponse response) throws IOException {
String data = "你好,黄阿斯";
response.setCharacterEncoding("UTF-8"); //制定向客户端发送的数据的编码是UTF-8
PrintWriter pw = response.getWriter(); //默认的编码是ISO-8859-1(ISO-8859-1码表中没有中文)
response.setHeader("Content-Type", "text/html;charset=UTF-8"); //告诉客户端编码方式
pw.write(data);
pw.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
中文文件下载时的中文显示问题
package com.hsx;
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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
public class ServletTest3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1 得到文件的真实路径
String realPath = getServletContext().getRealPath("/image/http请求过程.jpg");
String name = realPath.substring(realPath.lastIndexOf("\\") + 1); //文件名
System.out.println(name);
//2 构建输入流
InputStream in = new FileInputStream(realPath);
//3 利用response向客户端输出,告知客户端的下载方式
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8")); //这里需要将文件的中文名进行编码,这里指定的编码是UTF-8
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while((len = in.read()) != -1) {
out.write(buffer, 0, len);
}
in.close();
//out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
输出随机图片
输出随机图片(CAPTCHA图像):Completely Automated Public Turing Test to Tell Computer and Humans Apart(全自动区分计算和人类的测试),相关的主要类[JDK查看API]:
- BufferedImage:内存图像
- Graphics:画笔
- ImageIO:输出图像
- 放在HTML页面上
注意:浏览器默认会缓存图片。
- 控制客户端不要缓存
response.addHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Expires", "0");
package com.hsx;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 输出随机图像
* @author hsx
*
*/
public class ServletTest4 extends HttpServlet {
private static int WIDTH = 120;
private static int HIGHT = 30;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.addHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Expires", "0");
//1 创建一个内存图像,并设置长和高 :BufferedImage
BufferedImage image = new BufferedImage(WIDTH, HIGHT, BufferedImage.TYPE_INT_RGB);
//2 得到该图像的画笔 :Graphics
Graphics g = image.getGraphics();
//2.1 画边框
g.setColor(Color.BLUE);
g.drawRect(0, 0, WIDTH, HIGHT);
//2.2 画背景色
g.setColor(Color.GRAY);
g.fillRect(1, 1, WIDTH - 2, HIGHT - 2);
//2.3 画干扰线9条
Random random = new Random();
for (int i = 0; i < 9; i++) {
g.setColor(Color.YELLOW);
g.drawLine(random.nextInt(WIDTH), random.nextInt(HIGHT), random.nextInt(WIDTH), random.nextInt(HIGHT));
}
//2.4 画验证树数字4个
int count = 5;
for (int i = 0; i < 4; i++) {
g.setColor(Color.RED);
g.setFont(new Font("宋体", Font.BOLD, 25));
g.drawString(random.nextInt(9) + "", count, 25);
count += 30;
}
//3 输出daoresponse的输出流中 :ImageIO
ImageIO.write(image, "jpeg", response.getOutputStream());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
- js能刷新页面
<body>
<form action="" method="post">
<input type="text" name="username" value=""/><br/><br/>
<input type="password" name="password" value=""/><br/>
<input type="text" name="code" value=""/><img id="codeImg" src="/servletContext/ServletTest4">
<a href="javascript:change()">看不清,换一张</a><br/>
<input type="submit" value="登录"/>
</form>
<script type="text/javascript">
function change() {
var imgObj = document.getElementById("codeImg");
imgObj.src = "/servletContext/ServletTest4?" + new Date().getTime();
}
</script>
</body>
刷新页面
- 每隔3秒刷新页面(Servlet控制)
response.setHeader("Refresh", "3"); //每隔3秒中刷新一次
- 刷新到新的页面(Servlet控制)
response.getOutputStream().write("<meta http-equiv=\"Refresh\" content=\"3;URL=/servletContext/login.html\">".getBytes());
- 页面跳转到Servlet控制的页面上上去
··
<meta http-equiv="Refresh" content="0;URL=/servletContext/ServletTest5">
- 模仿注册成功,提示3秒后跳转到主页,或者点击‘这里’,直接跳转到主页
response.setContentType("text/html;charset=GBK");
PrintWriter pw = response.getWriter();
response.setHeader("Refresh", "3;URL=/servletContext/default.html");
pw.println("注册成功!3秒后会自动转向主页。若没有发生跳转,请猛点<a href='/servletContext/default.html'>这里</a>");
控制客户端的缓存
- 设置客户端缓存一个月
// 设置客户端缓存一个月
response.setContentType("text/html;charset=UTF-8");
response.setDateHeader("Expires", System.currentTimeMillis() + 30 * 24 * 60 * 60 * 1000);
response.getOutputStream().write("你好".getBytes("UTF-8"));;
通过response现实请求重定向
- 请求重定向是指:一个Web资源收到客户端请求后,通知客户端去访问另外一个web资源,这称之为请求重定向。
- 地址栏会变,并发送2次请求,增加服务器负担。
- 实现方式:
- response.sendRedirect()
- 实现原理:
- 302状态码和location头即可实现重定向。
//重定向到login.html页面
response.sendRedirect("/servletContext/login.html");
response细节
- getOutputStream()和getWriter()方法分别用于得到输出二进制数据、输出文本数据的ServletOutputStream、PrintWriter对象。
- getOutputStream()和getWriter()这两个方法互相排斥,调用了其中的任何有一个方法后,就不能再调用另一个方法。会抛异常。
- Servlet程序向ServletOutputStream或者PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当做响应消息的正文,然后再与响应状态行和各响应头组合后输出DOA客户端。( Servlet程序向ServletOutputStream或者PrintWriter对象将数据写到了response对象中,容器从response对象中获取响应行、响应头和正文)。
- Servlet的service()方法结束后,Servlet引擎将检查getWriter()或getOutputStream()方法返回的输出流对象是否已经调用close()方法,如果没有,Servlet引擎将调用close()方法关闭输出流对象。
HttpServletRequest
- HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获取客户端这些消息。
request常用的方法
- 获取客户机 + 服务器信息
- getRequestURL方法返回客户端发出请求时的完整URL。
- getRequestURI方法返回请求行中的资源名部分。
- getQueryString方法返回请求行中的参数部分。
- getRemoteAddr方法返回发出请求的客户机的IP地址。
- getRemoteHost方法发出请求的客户机的完整主机名。
- getRemotePort方法返回客户机所使用的网络端口号。
- getLocalAddr方法返回WEB服务器的IP地址。
- getLocalName方法返回WEB服务器的主机名。
- getMethod返回客户机的请求方式。
String url = request.getRequestURL().toString();
String uri = request.getRequestURI();
String attr = request.getQueryString();
String remoteAddr = request.getRemoteAddr();
String remoteHost = request.getRemoteHost();
int remotePort = request.getRemotePort();
String localAddr = request.getLocalAddr();
String localName = request.getLocalName();
String method = request.getMethod();
- 获得客户机请求头
- getHeader(name) 获取某个请求头的值
- getHeaders(name) 获取某个请求头的值(有多个,全部返回出来)
- getHeaderNames() 获取请求头的所有的键,而不是值。
String header = request.getHeader("Accept");
pw.println(header + "<br/>");
pw.print("<br/>");
Enumeration<String> headers = request.getHeaders("Accept");
while (headers.hasMoreElements()) {
String string = (String) headers.nextElement();
pw.println(string + "<br/>");
}
pw.print("<br/>");
Enumeration<String> hh = request.getHeaderNames();
while (hh.hasMoreElements()) {
String key = (String) hh.nextElement();
String value = request.getHeader(key);
pw.println(key + " = " + value + "<br/>");
}
- 获得客户机请求参数(客户提交的数据)
- getParameter(name) 获取对应的值
- getParameteValues(name) 获取对应的值[数组]
- getParameterNames() 获取对应的键
- getParameterMap()
- getInputStream()
request处理中文乱码问题
- 浏览器是什么编码就以什么编码传送数据。
- 解决:
- request.setCharacterEncoding(“UTF-8”); //POST有效
- new String(username.getBytes(“ISO-8859-1”),”UTF-8”); //GET方式
- 超链接:cn //GET方式
- 更改Tomcat的配置解决URL编码问题:
request对象实现请求转发
- request对象实现请求转发:请求转发指一个Web资源收到客户端请求后,通知服务器去调用另外一个Web资源进行处理。
- request对象提供了一个getRequestDispatcher方法,该方法返回一个RequestDispathcher对象,调用这个对象的forword方法可以实现请求转发。
- request对象同时也是一个域对象,开发人员通过request对象在实现转发时,把数据通过request对象带给其他Web资源处理。
- setAttribute()
- getAttribute()
- removeAttribute()
- getAttributeNames()
//得到请求转发器RequestDispatcher
RequestDispatcher rd = request.getRequestDispatcher("/servlet/ServletDemo");
rd.forward(request, response);
转发与包含
- forward:浏览器访问Servlet1,Servlet1转发到Servlet2,Servlet2把结果返回给浏览器。
- include:浏览器访问Servlet1,Servlet1包含了Servlet2,Servlet1把结果返回给浏览器。[这里指的是动态包含]
RequestDispatcher
表示请求分发器,两个方法:
- forward(): 把请求转发给目标组件
- include(): 包含目标组件的响应结果
得到RequestDispatcher对象
- ServletContext对象的getRequestDispather(String path1),path1必须用绝对路径,即以”/”开头,若用相对路径会抛出异常。
- ServletRequest对象的getRequestDispather(String path2),path2可以使用绝对路径也可以使用相对路径。
路径的写法
- 绝对路径:ServletContext都必须用绝对路径。”/”
- 相对路径:其他的都可以使用相对路径,也可以使用绝对路径
在使用绝对路径时,要不要加”/”或者项目名:
- 是服务器调用的,不用加项目名,用”/”就可以代表了;
是客户端调用的,必须加上项目名。
转发:request.getRequestDispather(String url); – 当使用绝对路径时: “/ServletDemo” — 服务器
- 重定向:response.sendRedirect(String url); – 当使用绝对路径时: “/servlet/ServletDemo” — 客户端
- 超链接: – 当使用绝对路径时: “/servlet/ServletDemo” — 服务器
- 类加载文件的路径 – web应用中只能用相对路径,相对于classes目录的
- – 当使用绝对路径时: “/servlet/ServletDemo” — 服务器
- 页面分帧(frame) – 当使用绝对路径时: “/servlet/ServletDemo”
- ServletContext.getRealpath(url) – 当使用绝对路径时: “/servlet/ServletDemo”