Servlet学习笔记(四):Servlet的请求与响应

时间:2022-02-08 17:04:09

客户端浏览器发送一个请求,服务器作出一系列操作后作出一个响应,发送给客户端,完成一次Web过程过程操作。Web编程的过程就是通过分析客户需要什么信息或者进行了什么操作,然后进行一系列的处理,最后通过响应结果显示给客户。即一次请求-响应的过程。


一、请求-HttpServletRequest对象


客户端浏览器的请求被封装成一个HttpServletRequest对象。所有的信息包括请求的地址,请求的参数,提交的数据,上传的文件,客户端的IP地址甚至客户端操作系统都包含在HttpServletRequest对象中。


封装信息以及获取的方法:

1、编码信息和文档类型。

1)编码信息:设置与获取编码信息

A、request.setCharacterEncoding("UTF-8") :设置编码,统一使用 setCharacterEncodingFilter 

B、request.getCharacterEncoding() :获取编码方法。

2)文档信息:设置与获取文档信息

A、response.setContentType("text/html") :设置 文档类型为HTML类型。这边可以设置输出数据的类型,text/html、image/jpeg、application/msword

B、request.getContentType() :获取文档类型。

3)代码示例:

			// 1-设置编码方式,可以用时setCharacterEncodingFilter过滤器统一处理
request.setCharacterEncoding("UTF-8");// 设置 request 的编码方式
response.setCharacterEncoding("UTF-8");// 设置 response 的编码方式
response.setContentType("text/html");// 设置 文档类型为HTML类型

request.getCharacterEncoding();
request.getContentType();

2、服务器信息。

1)Authorization信息:request.getAuthType()

2)本地IP, 即服务器IP:request.getLocalAddr()

A、实际项目中,一般会用到java.net包下 InetAddress 来获取服务器的真实 IP 地址:

			// 2-1 实际项目中,一般会用到java.net包下 InetAddress 来获取服务器的真实 IP 地址
String myLocalIp = InetAddress.getLocalHost().getHostAddress();// 本地地址,服务器IP地址
logger.debug("利用java.net包下 InetAddress 来获取服务器真实 IP 地址: " + myLocalIp);

B、Linux下获取服务器IP地址,InetAddress获取IP的方法在windows下没有问题

			// InetAddress获取IP的方法在windows下没有问题,在Linux有问题,主要是在linux下返回的是/etc/hosts
// 中配置的ip地址,而不是网卡的绑定地址。现在改用网卡的绑定地址,可以取到本机的ip地址:
// 利用NetworkInterface 可以封装成一个方法
String serverip = null;
Enumeration<NetworkInterface> netInterfaces = null;
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = netInterfaces.nextElement();
// System.out.println("DisplayName:" + ni.getDisplayName());
// System.out.println("Name:" + ni.getName());
Enumeration<InetAddress> ips = ni.getInetAddresses();
while (ips.hasMoreElements()) {
InetAddress ip = ips.nextElement();

// IP地址分为普通地址和特殊地址。利用InetAddress类提供的十个方法来确定一个IP地址是否是一个特殊的IP地址。
// 判断是否地区本地地址
if (ip.isSiteLocalAddress()) {
serverip = ip.getHostAddress();
break;
}
}
}
logger.debug("Linux下 来获取服务器真实 IP 地址: " + serverip);


3)本地名称, 即服务器名称: request.getLocalName()

4)本地端口号, 即Tomcat 端口号: request.getLocalPort()

5)本地环境: Locale locale = request.getLocale();

			Locale locale = request.getLocale();// 本地环境
String localLangurage = getLocaleLangurage(locale);// 语言环境
String localCountry = locale.getCountry();// 国家

6)服务器名称:request.getServerName()

7)服务器端口:request.getServerPort()


3、客户端信息。

1)远程IP,即客户端IP:request.getRemoteAddr()

2)远程端口,即客户端端口:request.getRemotePort()

3)客户端的IP,往往会有代理,所以一般的获取方法,需要处理代理信息:

			// 客户端的IP,往往会有代理,所以一般的获取方法,需要处理信息
String realCusIp = getRealCusIpAddr(request);//真实客户端IP地址

/**
* 获得用户真实IP
*
* @param request 请求对象
* @return 真实IP地址
*/
public String getRealCusIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}

4)远程用户:request.getRemoteUser()。如果提供了Authorization头,则代表其用户部分。它代表发出请求的用户的名字。


4、获取请求信息。

1)获取本次请求的协议信息

A、协议,这里为HTTP协议:request.getProtocol()

B、协议头,这里为Http: request.getScheme()


2)获取头信息 利用浏览器都可以看到

A、浏览器支持的格式,访问Accept的HTTP头: request.getHeader("accept")

B、从哪个页面单机链接到了本页:直接输入为空。request.getHeader("referer")

C、User Agent 信息:request.getHeader("user-agent")

D、其他:request.getHeader("Host")  | request.getHeader("Accept-Language") | 

 request.getHeader("Accept-Encoding") | request.getHeader("Connection")| 

  request.getHeader("Cookie");


3)获取本次请求的一些基本信息

A、访问的方式:Get还是Post。request.getMethod()

B、查询字符串,即访问时 ? 后面的字符串。request.getQueryString()

C、用户请求的URI:request.getRequestURI(),权限使用。

D、用户请求的URL: request.getRequestURL()

用户请求的URL: http://localhost:8080/JavaWeb/servlet/RequestServlet,那么用户请求的URI为: /JavaWeb/servlet/RequestServlet 


4)获取请求的Servlet的信息

A、Context路径:request.getContextPath()。上下文路径,一般是“/工程名”,如:/JavaWeb

B、Servlet的路径: request.getServletPath()。访问的servlert的路径,一般可以在filter中使用,作为拦截。如:/servlet/RequestServlet 。

C、URL中Servlet路径之后、查询字符串之前的那部分: request.getPathInfo()

D、映射到服务器实际路径之后的路径信息: getPathTranslated()

F、request.getServletPath() 和 request.getPathInfo()的差别,见文章


5、其他信息。

1)客户端Session的ID: request.getRequestedSessionId()

2)获取Session信息:request.getSession()

3)获取CooKie信息:request.getCookies()

4)当前授权用户的名称: request.getUserPrincipal()

5)本Servlet运行的服务器信息:this.getServletContext().getServerInfo() 


6、附加补充:利用以下四个方法,获取绝对路径。也可以单独使用getContextPath()获取相对路径。

String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

在实际项目中可以放入某个公用页面,这样可以解决大部分的路径问题。


7、完整的代码。

package servlet.base;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.Locale;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

import util.IPSeeker;

/**
*
* RequestServlet.java
*
* @title HttpServletRequest-请求
* @description
* @author SAM-SHO
* @Date 2014-9-26
*/
public class RequestServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

// 一定要把log4j的jar包放入lib目录下,不能只是添加build path,不然类加载器加载不到
public Logger logger = Logger.getLogger(this.getClass());

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log("使用servlet内置的log, 调用了doGet方法");
doService(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doService(request, response);

}

/**
* 通用业务方法
*
* @param request
* @param response
* @throws UnsupportedEncodingException
* @throws UnknownHostException
* @throws SocketException
*/
private void doService(HttpServletRequest request, HttpServletResponse response) {

try {

/** 1-编码方法 ************************************************************************/

// 1-设置编码方式,可以用时setCharacterEncodingFilter过滤器统一处理
request.setCharacterEncoding("UTF-8");// 设置 request 的编码方式
response.setCharacterEncoding("UTF-8");// 设置 response 的编码方式
response.setContentType("text/html");// 设置 文档类型为HTML类型

request.getCharacterEncoding();
request.getContentType();

/** 2-获取服务器信息 ********************************************************************/

// 2-0-基本的获取服务器信息
String authType = request.getAuthType();// Authorization头
String localAddr = request.getLocalAddr();// 本地IP, 即服务器IP
String localName = request.getLocalName();// 本地名称, 即服务器名称
int localPort = request.getLocalPort();// 本地端口号, 即Tomcat 端口号
Locale locale = request.getLocale();// 本地环境
String localLangurage = getLocaleLangurage(locale);// 语言环境
String localCountry = locale.getCountry();// 国家
logger.debug("验证: " + authType + " |服务器IP: " + localAddr + " |服务器名称: " + localName + " |端口号: " + localPort + " |用户的语言环境: " + localLangurage + " |国家: " + localCountry);

String serverName = request.getServerName();// 服务器名称
int serverPort = request.getServerPort();// 服务器端口
logger.debug("服务器名称: " + serverName + " |服务器端口: " + serverPort);

// 2-1 实际项目中,一般会用到java.net包下 InetAddress 来获取服务器的真实 IP 地址
String myLocalIp = InetAddress.getLocalHost().getHostAddress();// 本地地址,服务器IP地址
logger.debug("利用java.net包下 InetAddress 来获取服务器真实 IP 地址: " + myLocalIp);

// 2-2
// InetAddress获取IP的方法在windows下没有问题,在Linux有问题,主要是在linux下返回的是/etc/hosts
// 中配置的ip地址,而不是网卡的绑定地址。现在改用网卡的绑定地址,可以取到本机的ip地址:
// 利用NetworkInterface 可以封装成一个方法
String serverip = null;
Enumeration<NetworkInterface> netInterfaces = null;
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = netInterfaces.nextElement();
// System.out.println("DisplayName:" + ni.getDisplayName());
// System.out.println("Name:" + ni.getName());
Enumeration<InetAddress> ips = ni.getInetAddresses();
while (ips.hasMoreElements()) {
InetAddress ip = ips.nextElement();

// IP地址分为普通地址和特殊地址。利用InetAddress类提供的十个方法来确定一个IP地址是否是一个特殊的IP地址。
// 判断是否地区本地地址
if (ip.isSiteLocalAddress()) {
serverip = ip.getHostAddress();
break;
}
}
}
logger.debug("Linux下 来获取服务器真实 IP 地址: " + serverip);

/** 3-获取客户端信息 *********************************************************************/

// 3- 获取客户端基本信息
String remoteAddr = request.getRemoteAddr();// 远程IP,即客户端IP
int remotePort = request.getRemotePort();// 远程端口,即客户端端口
String remoteUser = request.getRemoteUser();// 远程用户,如果提供了Authorization头,则代表其用户部分。它代表发出请求的用户的名字。
logger.debug("客户端IP: " + remoteAddr + " |客户端端口: " + remotePort + " |远程用户: " + remoteUser);

// 客户端的IP,往往会有代理,所以一般的获取方法,需要处理信息
String realCusIp = getRealCusIpAddr(request);//真实客户端IP地址
logger.debug("客户端真实IP,附带代理的IP地址: "+realCusIp);


/** 4-获取请求信息 *********************************************************************/

// 4-1 获取本次请求的协议信息
String protocol = request.getProtocol();// 协议,这里为HTTP协议
String scheme = request.getScheme();// 协议头,这里为Http
logger.debug("协议: " + protocol + " |协议头: " + scheme);

// 4-2 获取头信息 利用浏览器都可以看到
String accept = request.getHeader("accept");// 浏览器支持的格式,访问Accept的HTTP头
String referer = request.getHeader("referer");// 从哪个页面单机链接到了本页
String userAgent = request.getHeader("user-agent");// User Agent 信息,
// 包括操作系统及版本号、浏览器类型及版本号
request.getHeader("Host");
request.getHeader("Accept-Language");
request.getHeader("Accept-Encoding");
request.getHeader("Connection");
request.getHeader("Cookie");

logger.debug("浏览器支持的格式: " + getAccept(accept) + " |从哪个页面单机链接到了本页: " + referer + " |操作系统信息: " + getOS(userAgent)+" |客户端浏览器信息 "+ getNavigator(userAgent));

// 4-3 获取本次请求的一些基本信息
String method = request.getMethod();// 访问的方式:Get还是Post
String queryString = request.getQueryString();// 查询字符串,即访问时 ? 后面的字符串
String requestURI = request.getRequestURI();// 用户请求的URI
StringBuffer requestURL = request.getRequestURL();// 用户请求的URL
logger.debug("访问的方式: " + method + " |查询字符串,即访问时 ? 后面的字符串: " + queryString + " |用户请求的URI: " + requestURI + " |用户请求的URL: " + requestURL);

// 4-4 获取请求的Servlet的信息
String contextPath = request.getContextPath(); // Context路径
String servletPath = request.getServletPath(); // Servlet的路径
String pathInfo = request.getPathInfo(); // URL中Servlet路径之后、查询字符串之前的那部分。
String pathTranslated = request.getPathTranslated(); // 映射到服务器实际路径之后的路径信息。


/** 5-其他信息 *********************************************************************/
// 5-1 其他信息
String requestedSessionId = request.getRequestedSessionId(); // 客户端Session的ID
HttpSession session = request.getSession(); // 获取Session信息
Cookie[] cookies = request.getCookies(); //获取CooKie信息
Principal userPrincipal = request.getUserPrincipal(); // 当前授权用户的名称

String serverInfo = this.getServletContext().getServerInfo(); // 本Servlet运行的服务器信息

logger.debug("Context路径: " + contextPath + " |Servlet的路径: " + servletPath + " |本Servlet运行的服务器信息: " + serverInfo + " |客户端Session的ID: " + requestedSessionId);



} catch (Exception e) {
e.printStackTrace();
}
}

/**
* linux下获取服务器真实 IP
*
* @return
*/
public static String getServerIP() {
String serverip = "";

try {
// InetAddress addr = InetAddress.getLocalHost();
// serverip = addr.getHostAddress();
// Modify by YiQiang 20130710
// InetAddress获取IP的方法在windows下没有问题,在Linux有问题(下只是读取/etc/hosts下的配置)
Enumeration<NetworkInterface> netInterfaces = null;
netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
NetworkInterface ni = netInterfaces.nextElement();
Enumeration<InetAddress> ips = ni.getInetAddresses();
while (ips.hasMoreElements()) {
InetAddress ip = ips.nextElement();
if (ip.isSiteLocalAddress()) {
serverip = ip.getHostAddress();
break;
}
}
}
} catch (Exception ex) {
serverip = "127.0.0.1";
}
return serverip;
}

/**
* 用户的语言环境
*
* @param locale
* @return 语言环境名称
*/
private String getLocaleLangurage(Locale locale) {
if (Locale.SIMPLIFIED_CHINESE.equals(locale))
return "简体中文";
if (Locale.TRADITIONAL_CHINESE.equals(locale))
return "繁体中文";
if (Locale.ENGLISH.equals(locale))
return "英文";
if (Locale.JAPANESE.equals(locale))
return "日文";
return "未知语言环境";
}

/**
* @param accept
* @return 客户端浏览器接受的文件类型
*/
private String getAccept(String accept) {
StringBuffer buffer = new StringBuffer();
if (accept.contains("image/gif"))
buffer.append("GIF 文件, ");
if (accept.contains("image/x-xbitmap"))
buffer.append("BMP 文件, ");
if (accept.contains("image/jpeg"))
buffer.append("JPG 文件, ");
if (accept.contains("application/vnd.ms-excel"))
buffer.append("Excel 文件, ");
if (accept.contains("application/vnd.ms-powerpoint"))
buffer.append("PPT 文件, ");
if (accept.contains("application/msword"))
buffer.append("Word 文件, ");
return buffer.toString().replaceAll(", $", "");
}

/**
* @param ip
* IP地址
* @return IP地址对应的物理位置
*/
private String getAddress(String ip) {

try {
return IPSeeker.getInstance().getAddress(ip);
} catch (Exception e) {
e.printStackTrace();
}
return "未知区域";

}

/**
* @param userAgent
* @return 客户端浏览器信息
*/
private String getNavigator(String userAgent) {
if (userAgent.indexOf("TencentTraveler") > 0)
return "腾讯浏览器";
if (userAgent.indexOf("Maxthon") > 0)
return "Maxthon浏览器";
if (userAgent.indexOf("MyIE2") > 0)
return "MyIE2浏览器";
if (userAgent.indexOf("Firefox") > 0)
return "Firefox浏览器";
if (userAgent.indexOf("MSIE") > 0)
return "IE 浏览器";
if(userAgent.indexOf("Chrome") > 0)
return "Chrome 浏览器";
return "未知浏览器";
}

/**
* @param userAgent
* @return 客户端操作系统
*/
private String getOS(String userAgent) {
if (userAgent.indexOf("Windows NT 5.1") > 0)
return "Windows XP";
if (userAgent.indexOf("Windows 98") > 0)
return "Windows 98";
if (userAgent.indexOf("Windows NT 5.0") > 0)
return "Windows 2000";
if (userAgent.indexOf("Linux") > 0)
return "Linux";
if (userAgent.indexOf("Unix") > 0)
return "Unix";
if (userAgent.indexOf("Windows NT 6.1") > 0)
return "Windows 7";
return "未知";
}

/**
* 获得用户真实IP
*
* @param request 请求对象
* @return 真实IP地址
*/
public String getRealCusIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}

}

8、使用头信息request.getHeader("referer"), 实现防盗链。


二、响应-HttpServletResponse

服务器对客户端浏览器作出的响应被封装成一个HttpServletResponse 对象。要对浏览器进行操作,只要要操作HttpServletResponse 对象就可以了。通过HttpServletResponse.getWriter()获得一个 PrintWriter 对象,该对象为 OutputStream 的子类。


1、HttpServletResponse.getWriter():对象只能写字符型的数据。HttpServletResponse.getOutputStream ():写二进制数据,如输出图片等。注意:这两个方法不能同时使用,特别是多层转发的时候,使用的还是同一个request对象,不能同时调用这两个方法。(getOutputStream () has already bean called for this response)

2、输出必须设置输出类型:response.setContentType("image/jpeg"),需要与输出方式统一。例子:输出图片验证码:

package servlet.base;

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

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
*
* IdentityServlet.java
*
* @title
* @description
* @author SAM-SHO
* @Date 2014-9-27
*/
public class IdentityServlet extends HttpServlet {

private static final long serialVersionUID = -479885884254942306L;

// 随机字符字典
public static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z' };

public static Random random = new Random();// 随机数



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

response.setContentType("image/jpeg");// 设置输出类型

String randomString = getRandomString();// 获取随机字符串
request.getSession(true).setAttribute("randomString", randomString);// 放入session

int width = 100; // 图片宽度
int height = 30; // 图片高度

Color color = getRandomColor();// 随机颜色,用于背景色
Color reverse = getReverseColor(color);// 反色,用于前景色

BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//创建一个彩色图片
Graphics2D g = bi.createGraphics();// 获取绘图对象
g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 16));//设置字体
g.setColor(color);//设置颜色
g.fillRect(0, 0, width, height);// 绘制背景
g.setColor(reverse);//设置颜色
g.drawString(randomString, 18, 20);//绘制随机字符

//画最多100个噪音点
for (int i = 0, n = random.nextInt(100); i < n; i++) {
g.drawRect(random.nextInt(width), random.nextInt(height), 1, 1);
}

// 转成JPEG格式
ServletOutputStream out = response.getOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);//编码器
encoder.encode(bi);//对图片进行编码
out.flush();
}

/**
* 获取 6 位 随机数
*
* @return
*/
public static String getRandomString() {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < 6; i++) {// 循环 6 次
buffer.append(CHARS[random.nextInt(CHARS.length)]);// 每次取一个随机字符
}
return buffer.toString();
}

/**
* 获取随机的颜色
*
* @return
*/
public static Color getRandomColor() {
return new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
}

/**
* 返回某颜色的反色
*
* @param c
* @return
*/
public static Color getReverseColor(Color c) {
return new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c.getBlue());
}

/**
* 测试
* @param args
*/
public static void main(String[] args) {
System.out.println(getRandomString());
}
}



3、控制浏览器是否缓存。

1)不缓存。

		response.setHeader("progma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 0);//时间头


2)利用Expires时间头,控制页面缓存。记得加上当前时间。System.currentTimeMillis()

		//设置缓存 一定要是当前时间 + 控制的缓存时间
response.setDateHeader("Expires", System.currentTimeMillis() + 1000*3600);


4、利用HttpServletResponse实现下载:

		// 2-1实现下载
// 注意中文的文件名文件下载时,注意编码 URLEncoder
// 使用getRealPath(),为了实现文件名称的显示
// String realPath = this.getServletContext().getRealPath("/downLoad/mcm.png");
String realPath = this.getServletContext().getRealPath("/downLoad/蒙奇奇.jpg");//中文
System.out.println("文件的绝对路径: " + realPath);

String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
System.out.println("文件的名称为: " + fileName);

//设置浏览器下载
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

// 固定输出
InputStream in = null;
OutputStream out = null;
try {

in = new FileInputStream(realPath);
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) {
}

}
}


三、Servlet的跳转


利用Servlet的跳转,实现了MVC框架,把程序分成三个独立模块:业务模块(Model)、视图模块(View)、控制模块(Control)。其中Model负责处理业务,View负责显示数据,Control负责控制。在struts框架中三个部分分别为3个Servlet,程序在3个Servlet之间跳转。

Servlet的跳转有两种方式:转发(Forward)和重定向(Redirect)。


1、转发(Forward):

是通过 RequestDispatcher 对象的 forward()方法实现。RequestDispatcher 可以通过HttpServletRequest 的getRequestDispatcher()方法获得。或者使用ServletContext.getRequestDispatcher()方法获取。

1)代码:

			RequestDispatcher dispatcher = request.getRequestDispatcher("/servlet/LifecyclesServlet");
dispatcher.forward(request, response);

2)getRequestDispatcher()方法的参数必须为以“/”开始,“/”表示本Web应用程序的根路径。如果要跳转到Servlet为http://localhost:8080/servlet/RequestServlet。则参数应该为“/servlet/RequestServlet”。


3)当使用Forward形式跳转Servlet时,地址栏会显示跳转前的Servlet访问地址。因为该跳转是在服务器端实现,客户端浏览器并不知道该跳转动作。也就是说Forward跳转对客户端浏览器是透明的。

4)Forward是最常用的方式。在struts等框架中,都是用Servlet来处理用户请求,把结果通过request.setAttribute()放到 request 中,然后Forward到JSP显示。

5)当执行Forward动作的时候不能有任何输出到达客户端,否则会抛出illegalStateException。也就是在 Forward 之前尽量不要使用 out.println()语句向客户端输出结果。

6)转发:同一个HttpServletRequest 这时,web数据的共享要使用Request 域即可。



2、重定向(Redirect)

1)重定向是利用服务器返回的状态来实现的。客户端浏览器请求服务器的时候,服务器端会返回一个状态码。服务器端通过 HttpServletResponse 的 setStatus()方式设置状态码。如果服务器返回301 或者302,则浏览器会到新的网址重新请求该资源。状态码的意思如下:

Servlet学习笔记(四):Servlet的请求与响应

2)301 、302都表示重定向,区别是 301是永久性重定向,302是临时性重定向。下面的代码将访问该Servlet的请求重定向到另一个网址。

response.setStates(HttpServletResponse.SC_MOVED_PERMANENTLY);//设置状态码为301

response.setHeader("Location","http://www.baidu.com") 新网址


3)HttpServletResponse 类中把重用的状态码封装成了静态常量。并且把setStates()与setHeader()方法封装成另一个方法sendRedirect(String location),只需要调用sendRedirect就能实现重定向。

4)与转发不同,重定向(Redirect)的跳转是在客户端实现的。实际上客户端浏览器请求了 2 次服务器,第1 次获取重定向的状态码与重定向的网址,第 2 次访问真实地址。

5)重定向:不同的HttpServletRequest 对象,每一次访问都会new一个HttpServletRequest 对象。这时,web数据的共享要使用 session 域和 context 域。


		// request域的数据,转发可以获取,重定向获取不到
String data = "12345";
request.setAttribute("data", data);

/********* 转发 *******************/
// 转发,可以获取request域的数据。只有一个请求,服务器跳转。url不会变化。
// 1-1 获取 RequestDispatcher对象,然后转发
RequestDispatcher rd = request.getRequestDispatcher("/MyJsp.jsp");
RequestDispatcher rd2 = getServletContext().getRequestDispatcher("/MyJsp.jsp");
rd.forward(request, response);
rd2.forward(request, response);

// 2-1 直接转发
request.getRequestDispatcher("/MyJsp.jsp").forward(request, response);
getServletContext().getRequestDispatcher("/MyJsp.jsp").forward(request, response);


/********* 重定向 *******************/
// 重定向 ,2次request请求,客户端跳转跳转,url显示第二次跳转的url地址,不能获取request域的数据。
response.sendRedirect("/MyJsp.jsp");

3、自动刷新(Refresh)

自动刷新不仅可以实现一段时间之后自动跳转到另一个页面,还可以实现一段时间之后刷新本页面。Servlet中通过设置HttpServletResponse 对象的Header属性实现自动刷新效果。例如:

response.setHeader("Refresh","1000; url=http://www.baidu.com")

1)其中 1000 为时间,单位为毫秒。
2)URL参数指定的网址就是1 秒之后跳转的页面。当URL设置的路径为Servlet自己的路径时,就会每隔1秒钟自动舒鑫页面一次。

3)自动刷新与重定向原理是差不多。如果时间设为 0,把URL设为另一个网址,效果就是重定向。

response.setHeader("Refresh","0; url=http://www.baidu.com")