目录
- 目录
- 简介
- request的常用方法
- request接收中文数据乱码问题
- request对象实现请求转发
- 使用请求转发的注意事项
- RequestDispatcher的页面包含方法include
- Web工程中各类URL地址的写法
- 防盗链
简介
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户端的信息。
request的常用方法
- 获取客户端信息
方法名 | 描述 |
getRequestURL | 返回客户端发出请求时的完整URL |
getRequestURI | 返回请求行中的资源名部分 |
getQueryString | 返回请求行中的参数部分 |
getRemoteAddr | 返回发出请求的客户机的IP地址 |
getRemoteHost | 返回发出请求的客户机的完整主机名(前提是有主机名,否则将返回IP地址) |
getRemotePort | 返回客户机所使用的网络端口号 |
getLocalAddr | 返回Web服务器的IP地址 |
getLocalName | 返回Web服务器的主机名 |
getMethod | 得到客户机请求方式 |
示例:
package com.wm103.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by DreamBoy on 2017/4/29.
*/
/**
* request的常用方法
*/
@WebServlet(name = "RequestDemo1", urlPatterns = {"/RequestDemo1"})
public class RequestDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String uri = request.getRequestURI();
String url = request.getRequestURL().toString();
String queryString = request.getQueryString();
System.out.println("uri: " + uri);
System.out.println("url: " + url);
System.out.println("QueryString: " + queryString);
System.out.println(request.getRemoteAddr());
System.out.println(request.getRemoteHost()); // 返回客户端的主机名(要求客户端在DNS上注册过域名,配置了主机名,否则仍返回主机IP地址)
System.out.println(request.getRemotePort());
System.out.println("-----------------------");
System.out.println(request.getMethod());
}
}
注:URI和URL——如:/news/1.html 是URI;http://www.sina.com/news/1.html 是URL。URL也属于URI。
- 获取请求头信息
- getHeader
- getHeaders
- getHeaderNames
- 获取客户端提交的数据
- getParameter
- getParameterNames
- getParameterValues
- getParameterMap
- getInputStream
示例:
User.java
package com.wm103.request;
/**
* Created by DreamBoy on 2017/4/29.
*/
public class User {
private String username[];
private String password;
public String[] getUsername() {
return username;
}
public void setUsername(String[] username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
RequestDemo2.java(注意该案例中使用到了BeanUtils,要求项目需要引入 beanutils的jar,这里为:commons-beanutils-1.8.0.jar
和commons-logging-1.1.1.jar
)
package com.wm103.request;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
/**
* Created by DreamBoy on 2017/4/29.
*/
/**
* 获取请求头和请求数据
* 获取数据时一般来说都要先检查再使用
*/
@WebServlet(name = "RequestDemo2", urlPatterns = {"/RequestDemo2"})
public class RequestDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
test2(request);
}
/**
* 获取请求数据的方法
* @param request
*/
private void test2(HttpServletRequest request) {
String username = request.getParameter("username");
if(username != null && !username.trim().equals("")) {
System.out.println(username);
}
System.out.println("-----------------------");
Enumeration<String> en = request.getParameterNames();
while (en.hasMoreElements()) {
String name = en.nextElement();
String 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]);
}
System.out.println("-----------------------");
// 重要!!!
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, map); // 通过BeanUtils将map集合中的键值对设置到bean对象对应属性中去
// BeanUtils.copyProperties(user, formbean); // 拷贝一个bean的属性值到另外一个bean
} catch (Exception e) {
e.printStackTrace();
}
String[] usernames = user.getUsername();
String password = user.getPassword();
System.out.println(usernames[0] + " " + usernames[1] + " " + password);
System.out.println("-----------------------");
// 有点毛病~~
/*InputStream in = request.getInputStream();
int len;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {
System.out.println(new String(buffer, 0, len));
}*/
}
/**
* 获取请求头信息的方法
* @param request
*/
private void test1(HttpServletRequest request) {
String headerValue = request.getHeader("Accept-Encoding");
System.out.println(headerValue);
System.out.println("-----------------------");
Enumeration<String> en = request.getHeaders("Accept-Encoding");
while (en.hasMoreElements()) {
String value = en.nextElement();
System.out.println(value);
}
System.out.println("-----------------------");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String value = request.getHeader(name);
System.out.println(name + ": " + value);
}
}
}
表单提交接收案例:
form1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Form</title>
<style>
.form-container {
width: 400px;
margin: 50px auto;
}
</style>
</head>
<body>
<div class="form-container">
<form action="/day06/RequestDemo3" method="post">
<p>头 像:<input type="file" name="image"></p>
<p>用户名:<input type="text" name="username"></p>
<p>密 码:<input type="password" name="password"></p>
<p>性 别:<input type="radio" name="gender" value="male">男
<input type="radio" name="gender" value="female">女
</p>
<p>所在地:
<select name="city">
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="cs">长沙</option>
</select>
</p>
<p>爱 好:
<input type="checkbox" name="likes" value="sing">唱歌
<input type="checkbox" name="likes" value="dance">跳舞
<input type="checkbox" name="likes" value="basketball">篮球
<input type="checkbox" name="likes" value="football">足球
</p>
<p>备 注:
<textarea name="description" cols="30" rows="10"></textarea>
</p>
<input type="hidden" name="id" value="12345">
<p><input type="submit" value="提交"></p>
</form>
</div>
</body>
</html>
RequestDemo3.java
package com.wm103.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by DreamBoy on 2017/4/29.
*/
@WebServlet(name = "RequestDemo3", urlPatterns = {"/RequestDemo3"})
public class RequestDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8"); // 默认采用的是ISO-8859-1进行转码,但是提交过来的数据以UTF-8(根据页面的编码)进行编码,所以需要先设置转化数据的码表为UTF-8。
String username = request.getParameter("username");
System.out.println("username=" + username);
String password = request.getParameter("password");
System.out.println("password=" + password);
String gender = request.getParameter("gender");
System.out.println("gender=" + gender);
String city = request.getParameter("city");
System.out.println("city=" + city);
String[] likes = request.getParameterValues("likes");
for(int i = 0; likes != null && i < likes.length; i++) {
System.out.println("likes=" + likes[i]);
}
String description = request.getParameter("description");
System.out.println("description=" + description);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
request接收中文数据乱码问题
- post方式提交的数据(post方式提交的数据的编码方式根据页面显示编码方式进行编码),可以通过设置:
request.setCharacterEncoding("UTF-8"); // 默认采用的是ISO-8859-1进行转码,但是提交过来的数据以UTF-8(根据页面的编码)进行编码,所以需要先设置转化数据的码表为UTF-8。但是默认只对post提交有效。如果在server.xml中设置Connector标签的属性useBodyEncodingForURI为true,则对get请求方式也有效。
示例:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 默认只对post提交有效。如果在server.xml中设置Connector标签的属性useBodyEncodingForURI为true,则对get请求方式也有效。
request.setCharacterEncoding("UTF-8"); // 默认采用的是ISO-8859-1进行转码,但是提交过来的数据以UTF-8(根据页面的编码)进行编码,所以需要先设置转化数据的码表为UTF-8。但是只对post有效
String username = request.getParameter("username");
System.out.println("username=" + username);
}
- get方式提交的数据(包括form和链接跳转提交数据这两种方式)
tomcat8.0默认URIEncoding为ISO-8859-1,从tomcat8.0开始,URIEncoding默认值不再是ISO-8859-1,而变成了UTF-8。所以对于设置了UTF-8编码的页面来说get请求提交的数据没有中文乱码的问题。但是对于tomcat8.0以前则需要解决,如:
String username = request.getParameter("username");
username = new String(username.getBytes("iso8859-1"), "UTF-8");
System.out.println("username=" + username);
示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
// 值得注意的是,从tomcat8.0开始,URIEncoding默认值不再是ISO-8859-1,而变成了UTF-8。参考:http://www.cnblogs.com/hyl8218/p/5811769.html
// 现在这里不用进行编码的转换,也不会乱码了!!当前环境为Tomcat 9.0.0.M4。参考:https://tomcat.apache.org/tomcat-9.0-doc/config/http.html
// username = new String(username.getBytes("iso8859-1"), "UTF-8");
System.out.println("username=" + username);
}
request对象实现请求转发
请求转发指一个Web资源收到客户端请求后,通知服务器去调用另外一个Web资源进行处理。通过使用请求转发可以使Web项目实现MVC设计模式。
1. request对象提供了一个getRequestDispatcher
方法,该方法返回一个RequestDispatcher
对象,调用这个对象的forward
方法可以实现请求转发。
2. request对象同时也是一个域对象(此前提到的ServletContext同样也是一个域对象,其作用于整个Web应用,而request对象则作用于当前请求),开发人员通过request对象在实现转发时,把数据通过request对象带给其它Web资源处理。
3. 请求转发时,传递数据的方法(调用request对象中的方法):
- setAttribute方法
- getAttribute方法
- removeAttribute方法
- getAttributeNames方法
示例:
package com.wm103.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by DreamBoy on 2017/4/29.
*/
/**
* 请求转发,以及使用request域对象把数据带给转发资源
* 请求转发的特点:
* 1. 客户端只发送一次请求,而服务器端有多个资源调用
* 2. 客户端浏览器地址栏没有变化
*/
@WebServlet(name = "RequestDemo5", urlPatterns = {"/RequestDemo5"})
public class RequestDemo5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String data = "This is RequestDemo5.";
request.setAttribute("data", data);
// 除了使用ServletContext进行转发外,也可以使用request对象实现转发
request.getRequestDispatcher("/info.jsp").forward(request, response);
}
}
info.jsp (通过EL表达式从request中获取setAttribute的数据)
<%--
Created by IntelliJ IDEA.
User: DreamBoy
Date: 2017/4/29
Time: 17:46
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP</title>
</head>
<body>
${data} <!-- El表达式 -->
<br/>
<%
String data = (String) request.getAttribute("data");
out.write(data);
%>
</body>
</html>
使用请求转发的注意事项
- forward方法用于将请求转发到RequestDispatcher对象封装的资源。
- 如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常。
- 如果在调用forward方法之前向Servlet引擎的缓冲区(response)中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空,但是,已写入到HttpServletResponse对象中的响应头字段信息保持有效。
示例:
package com.wm103.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by DreamBoy on 2018/3/5.
*/
/**
* forward方法
*/
@WebServlet(name = "RequestDemo6", urlPatterns = {"/RequestDemo6"})
public class RequestDemo6 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
test1(request, response);
}
// 如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常
private void test1(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String data = "This is RequestDemo6";
request.setAttribute("data", data);
PrintWriter writer = response.getWriter();
writer.write(data);
writer.close(); // 将数据传送给客户端
request.getRequestDispatcher("/info.jsp").forward(request, response);
}
// 如果在调用forward方法之前向Servlet引擎的缓冲区(response)中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空
private void test2(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String data = "This is RequestDemo6";
request.setAttribute("data", data);
PrintWriter writer = response.getWriter();
writer.write(data);
request.getRequestDispatcher("/info.jsp").forward(request, response);
}
// 转发后JSP中进行内容的输出,后续再调用`request.getRequestDispatcher`进行转发,仍将抛出:java.lang.IllegalStateException: Cannot forward after response has been committed 异常
private void test3(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String data = "This is RequestDemo6";
request.setAttribute("data", data);
if(true) {
request.getRequestDispatcher("/info.jsp").forward(request, response);
// return; // 加入 return 语句解决
}
// 执行下面语句后将抛出:java.lang.IllegalStateException: Cannot forward after response has been committed 异常
request.getRequestDispatcher("/info.jsp").forward(request, response);
}
}
RequestDispatcher的页面包含方法include
- RequestDispatcher.include方法用于将RequestDispatcher对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能。
- 被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略。
示例:
public/head.jsp
<%--
Created by IntelliJ IDEA.
User: DreamBoy
Date: 2017/4/29
Time: 18:15
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>RequestDemo7</title>
</head>
<body>
head<br/>
public/foot.jsp
foot<br/>
</body>
</html>
使用include方法:
request.getRequestDispatcher("/public/head.jsp").include(request, response);
response.getWriter().write("Test Include<br/>");
request.getRequestDispatcher("/public/foot.jsp").include(request, response);
Web工程中各类URL地址的写法
如果编写的URL是给服务器使用的,则“/”代表当前Web应用目录;如果编写的URL是给浏览器使用的,则“/”代表网站目录。
示例:
// 1.
request.getRequestDispatcher("/index.jsp").forward(request, response);
// 2.
response.sendRedirect("/day06/index.jsp");
// 3.
this.getServletContext().getRealPath("/index.jsp");
// 4.
this.getServletContext().getResourceAsStream("/index.jsp");
// 5.
/*
<a href="/day06/index.jsp">点击此链接</a>
<form action="/day06/index.jsp">
</form>
*/
防盗链
实际上即判断当前请求从“哪里”来。根据请求头中的referer进行判断。判断如果referer的值不为我们“http://服务器的主机名”,则为盗链。
package com.wm103.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by DreamBoy on 2017/4/29.
*/
/**
* 防盗链
*/
@WebServlet(name = "RequestDemo9", urlPatterns = {"/RequestDemo9"})
public class RequestDemo9 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, 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("/day06/index.jsp");
return;
}
response.getWriter().write("This is RequsetDemo9.");
}
}