JavaWeb学习笔记(十)--HttpServletRequest

 1. HttpServletRequest简介

HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中

2. HttpServletRequest常用方法

2.1获取客户机信息

  • getRequestURL方法返回客户端发出请求时的完整URL
  • getRequestURI方法返回请求行中的资源名
  • getQueryString方法返回请求行中的参数部分
  • getRemoteAddr方法返回发出请求的客户机的IP地址
  • getRemoteHost方法返回发出请求的客户机的完整主机名,没有在DNS服务器上注册的时,返回IP地址
  • getRemotePort方法返回客户机所使用的网络端口号
  • getLocalAddr返回WEB服务器的IP地址
  • getMethod返回请求的方法,GET POST等
 1 @WebServlet(name = "HttpServletRequestDemo1")
 2 public class HttpServletRequestDemo1 extends HttpServlet {
 3 
 4     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 5         doGet(request, response);
 6     }
 7 
 8     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 9         response.setCharacterEncoding("utf-8");
10         response.setContentType("text/html;charset=utf-8");
11         PrintWriter out = response.getWriter();
12         out.write("URI: " + request.getRequestURI());
13         out.write("<br/>");
14         out.write("URL: " + request.getRequestURL());
15         out.write("<br/>");
16         out.write("请求行的参数: " + request.getQueryString());
17         out.write("<br/>");
18         out.write("客户机的IP: " + request.getRemoteAddr());
19         out.write("<br/>");
20         out.write("客户机的主机名: " + request.getRemoteHost());
21         out.write("<br/>");
22         out.write("客户机的网络端口号: " + request.getRemotePort());
23         out.write("<br/>");
24         out.write("服务器的IP地址: " + request.getLocalAddr());
25         out.write("<br/>");
26         out.write("请求方法: " + request.getMethod());
27         out.write("<br/>");
28     }
29 }

运行结果:

2.2 获取客户机请求头

  • String getHeader(String name) 方法返回指定请求头的值,如果有多个值,返回第一个
  • Enumeration<String> getHeaders() 方法返回指定请求头所有值的枚举,如果没有指定的请求头,返回空Enumeration<String> ;如果servlet不允许使用此方法,则返回null
  • Enumeration<String> getHeaderNames(String name) 方法返回请求包含的所有标头名称的枚举,如果没有指定的请求头,返回空Enumeration<String>;如果servlet不允许使用此方法,则返回null
 1 /**
 2  * 获取客户机请求头
 3  */
 4 @WebServlet(name = "HttpServletRequestDemo2")
 5 public class HttpServletRequestDemo2 extends HttpServlet {
 6 
 7     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 8         response.setCharacterEncoding("utf-8");
 9         response.setContentType("text/html;charset=utf-8");
10         PrintWriter out = response.getWriter();
11         out.write("<b>getHeader()</b>");
12         out.write("<br/>");
13         out.write("Accept-Encoding:" + request.getHeader("Accept-Encoding") );
14         out.write("<br/>");
15         out.write("Host:" + request.getHeader("Host"));
16         out.write("<hr>");
17         out.write("<b>getHeaders()</b>");
18         out.write("<br/>");
19         Enumeration<String> headers = request.getHeaders("Accept-Language");
20         while (headers.hasMoreElements()) {
21             out.write("Accept-Language:" + headers.nextElement());
22             out.write("<br/>");
23         }
24         out.write("<hr>");
25         out.write("<b>getHeaderNames()</b>");
26         out.write("<br/>");
27         Enumeration<String> headerNames = request.getHeaderNames();
28         while (headerNames.hasMoreElements()) {
29             String name = headerNames.nextElement();
30             String value = request.getHeader(name);
31             out.write(name + ": " + value);
32             out.write("<br/>");
33         }
34     }
35 }

运行结果:

2.3 获取客户机请求参数

  • String getParameter(String name) 方法以String返回请求参数的值,如果参数不存在返回null
  • String[] getParameterValues(String name) 方法返回包含给定请求参数所具有的所有值的String对象数组,如果参数不存在返回null
  • Enumeration<String> getParameterNames() 方法返回请求的所有参数名称,如果没有返回一个空枚举
  • Map<String, String[]> getParameterMap() 方法返回请求参数的map,key为名称,value为String数组

创建一个表单:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8 
 9 <form action="/HttpServletRequestDemo3" method="post">
10     用户名:<input type="text" name="username"/><br>
11     密码:<input type="password" name="password"/><br>
12     性别:
13     <!--radio checkbox中name保持一致,这样才能确保是同一个radio或checkbox-->
14     <input type="radio" name="sex" value="男">15     <input type="radio" name="sex" value="女"><br>
16     爱好:
17     <input type="checkbox" name="hobby" value="唱歌">唱歌
18     <input type="checkbox" name="hobby" value="跳舞">跳舞
19     <input type="checkbox" name="hobby" value="篮球">篮球
20     <input type="checkbox" name="hobby" value="足球">足球
21     <br>
22     所在地:
23     <select name="city">
24         <option value="北京">北京</option>
25         <option value="深圳">上海</option>
26         <option value="上海">深圳</option>
27     </select>
28     <br>
29     简介:<br>
30     <textarea rows="5" cols="60" name="description"></textarea>
31     <br>
32     <input type="hidden" name="id" value="1">
33     <input type="submit" value="提交"/>
34 </form>
35 </body>
36 </html>

使用getParameter,getParameterValues获取数据:

 1 /**
 2  * 获取请求数据,一般来说都要先检查后使用
 3  */
 4 @WebServlet(name = "HttpServletRequestDemo3")
 5 public class HttpServletRequestDemo3 extends HttpServlet {
 6     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 7         doGet(request, response);
 8     }
 9 
10     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
11         request.setCharacterEncoding("utf-8");
12         response.setCharacterEncoding("utf-8");
13         response.setContentType("text/html;charset=utf-8");
14 
15         String username = request.getParameter("username");
16         String password = request.getParameter("password");
17         String sex = request.getParameter("sex");
18         String[] hobbies = request.getParameterValues("hobby");
19         String hobbiesStr = "";
20         // 先判空,防止空指针异常NullPointerException
21         for (int i = 0; hobbies != null && i < hobbies.length; i++) {
22             hobbiesStr += hobbies[i] + ",";
23         }
24 
25         String description = request.getParameter("description");
26         String hiddenId = request.getParameter("id");
27 
28         PrintWriter out = response.getWriter();
29         out.write("用户名:" + username);
30         out.write("<br>");
31         out.write("密码:" + password);
32         out.write("<br>");
33         out.write("性别:" + sex);
34         out.write("<br>");
35         out.write("爱好:" + hobbiesStr);
36         out.write("<br>");
37         out.write("简介:" + description);
38         out.write("<br>");
39         out.write("隐藏的ID:" + hiddenId);
40         out.write("<br>");
41     }
42 }

运行结果:

 

 

 使用getParameterNames获取数据:

 1     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2         request.setCharacterEncoding("utf-8");
 3         response.setCharacterEncoding("utf-8");
 4         response.setContentType("text/html;charset=utf-8");
 5         PrintWriter out = response.getWriter();
 6         Enumeration<String> names = request.getParameterNames();
 7         while(names.hasMoreElements()) {
 8             String name = names.nextElement();
 9             String value = request.getParameter(name);
10             out.write(name + ": " + value);
11             out.write("<br>");
12         }
13     }

运行结果:

 

使用getParameterMap获取数据,此方法常用于将表单数据封装到一个JavaBean中,我们使用BeanUtils对象进行bean的赋值和拷贝:

需要导入commons-beanutils,和其依赖的jar包commons-logging, commons-collections, http://commons.apache.org/proper/commons-beanutils/dependencies.html

按照依赖的版本进行下载,否则会报java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap错误

 1 package com.domain;
 2 
 3 public class User {
 4     private String[] username;
 5     private String password;
 6     private String sex;
 7     private String[] hobby;
 8     private String city;
 9     private String description;
10     private String id;
11 
12     public String getSex() {
13         return sex;
14     }
15 
16     public void setSex(String sex) {
17         this.sex = sex;
18     }
19 
20     public String[] getHobby() {
21         return hobby;
22     }
23 
24     public void setHobby(String[] hobby) {
25         this.hobby = hobby;
26     }
27 
28     public String getCity() {
29         return city;
30     }
31 
32     public void setCity(String city) {
33         this.city = city;
34     }
35 
36     public String getDescription() {
37         return description;
38     }
39 
40     public void setDescription(String description) {
41         this.description = description;
42     }
43 
44     public String getId() {
45         return id;
46     }
47 
48     public void setId(String id) {
49         this.id = id;
50     }
51 
52     public String[] getUsername() {
53         return username;
54     }
55 
56     public void setUsername(String[] username) {
57         this.username = username;
58     }
59 
60     public String getPassword() {
61         return password;
62     }
63 
64     public void setPassword(String password) {
65         this.password = password;
66     }
67 }
 1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2         request.setCharacterEncoding("utf-8");
 3         response.setCharacterEncoding("utf-8");
 4         response.setContentType("text/html;charset=utf-8");
 5         PrintWriter out = response.getWriter();
 6         User formbean = new User();
 7         User user = new User();
 8         Map<String, String[]> map = request.getParameterMap();
 9         try {
10             BeanUtils.populate(formbean, map);  // 用map集合填充bean,表单中的名字和bean的名字
11             BeanUtils.copyProperties(user, formbean); // 将formbean拷贝到user中
12         } catch (IllegalAccessException e) {
13             e.printStackTrace();
14         } catch (InvocationTargetException e) {
15             e.printStackTrace();
16         }
17 
18         for (Map.Entry<String, String[]> entry : map.entrySet()) {
19             String name = entry.getKey();
20             String[] values = entry.getValue();
21             String valueStr = "";
22             for (int i = 0; values != null && i < values.length; i++ ) {
23                 valueStr += values[i] + ",";
24             }
25             out.write(name + ": " + valueStr);
26             out.write("<br>");
27         }
28     }

运行结果:

 

打个断点,可以看到user中的数据:

3. request请求参数的中文乱码问题

乱码的根因:编码和解码使用的字符集不一样

request请求主要有以下三种方式:

  • POST方式提交表单数据乱码问题
  • GET方式提交表单数据乱码问题
  • 超链接方式的请求

针对这三种分别展示乱码问题和解决方案,先创建一个html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <a href="/HttpServletRequestDemo4?username=中国">乱码问题</a>
    <form action="/HttpServletRequestDemo4" method="post">
        <br><br>
        用户名:
        <input type="text" name="username">
        <input type="submit" value="提交(post)">
    </form>
    <br><br><br><br>
    <form action="/HttpServletRequestDemo4" method="get">
        用户名:
        <input type="text" name="username">
        <input type="submit" value="提交(get)">
    </form>
</body>
</html>

3.1 POST方式提交表单数据乱码问题

在Servlet中获取参数:

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Post方式:");
        response.getWriter().write(request.getParameter("username"));
    }

浏览器中访问表单,并使用POST方式提交,可以看到乱码问题:

 

解决方案:设置编码格式与HTML post提交方式相同的编码,我们HTML使用的是UTF-8,那么我们也需要设置服务器以UTF-8的方式接收数据。

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Post方式:");
        request.setCharacterEncoding("UTF-8");
        System.out.println(request.getParameter("username"));
    }

运行结果:

3.2 GET方式提交表单数据乱码问题

GET提交的编码不能通过request.setCharacterEncoding("utf-8")设置

Tomcat7以及以前的版本GET提交时URL使用的是ISO-8859-1编码,需要手动处理:

URIEncoding    This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"), "UTF-8") ;   

运行结果:

 

Tomcat8以后默认提交使用UTF-8编码,无需转码,直接获取即可:

URIEncoding    This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. 
If not specified, UTF-8 will be used unless the org.apache.catalina.STRICT_SERVLET_COMPLIANCE system property is set to true in which case ISO-8859-1 will be used.
String username = request.getParameter("username");

 

疑问:试了下,将HTML改成GB2312,再进行转码操作,还是乱码,没有找到解决方案。。。

3.3 超链接方式的请求

<a href="/HttpServletRequestDemo4?username=中国">乱码问题</a>

此种方式和GET提交相同,因为超链接本身就是以GET方式提交请求的。说明:IE报404错误,Chrome正常。

4. request实现请求转发

请求转发指一个web资源收到客户端请求后,通知服务器去调用灵位一个web资源进行处理。

request对象提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forword方法可以实现请求转发。

request对象同时也是一个域对象,开发人员可以通过request对象在实现转发时,把数据通过request对象带给其他web资源处理。

  • setAttribute方法
  • getAttribute方法
  • getAttributeNames方法
  • removeAttribute方法

4.1 实现请求转发

访问HttpServletRequestDemo5,使用request将其转发到HttpServletRequestDemo6中,并在request中传递参数:

 1 /**
 2  * request实现请求转发,并传递数据
 3  */
 4 @WebServlet(name = "HttpServletRequestDemo5")
 5 public class HttpServletRequestDemo5 extends HttpServlet {
 6 
 7     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 8         request.setAttribute("name", "bear");
 9         request.getRequestDispatcher("/HttpServletRequestDemo6").forward(request, response);
10     }
11 }
 1 /**
 2  * 获取request中存储的数据
 3  */
 4 @WebServlet(name = "HttpServletRequestDemo6")
 5 public class HttpServletRequestDemo6 extends HttpServlet {
 6 
 7     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 8         response.getWriter().write((String)request.getAttribute("name"));
 9     }
10 }

运行结果:

ServletContext对象也可实现请求转发(JavaWeb学习笔记(八)--ServletConfig和ServletContext对象介绍):

this.getServletContext().getRequestDispatcher("/HttpServletRequestDemo6").forward(request, response);

4.2 转发时需要注意的细节:

如果在调用forward方法之前,在Servlet程序中写入部分内容已经被真正的传送到了客户端,forword方法将抛出IllegalStateException异常:

例如,如下两种方式都会抛异常,所以最好在每个跳转后加上return语句

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    out.write("aaaa");
    // 关闭流,将导致数据写到浏览器上
    out.close();
    request.getRequestDispatcher("/message.html").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    if (true) {
        request.getRequestDispatcher("/form.html").forward(request, response);
    }
    // 下面这个会报java.lang.IllegalStateException: Cannot forward after response has been committed
    // 所以每个跳转后最好加上return语句
    request.getRequestDispatcher("/message.html").forward(request, response);
}

运行结果:

能输出aaaa或者跳转到form.html,但是代码会抛异常:

如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区的内容还没有被真正的输出到客户端,forword方法就可以正常被执行,原来写入到输出缓冲区中的内容将被清空,但是,已经写入到HttpServletResponse对象中的响应头字段信息保持有效。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    // aaaa将不会在message.html中出现
    out.write("aaaa");
    request.getRequestDispatcher("/message.html").forward(request, response);
}

运行结果:

4.3 请求重定向和请求转发的区别

一个web资源收到客户端请求后,通知服务器去调用另一个web资源进行处理,称之为请求转发。

一个web资源收到客户端请求后,通知浏览器去访问另一个web资源,称之为请求重定向。

RequestDispatcher.forward方法只能将请求转发给同一个web应用中的组件;而HttpServletResponse.sendRedirect方法还可以定位到同一站点的其他web应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。

HttpServletResponse.sendRedirect方法重定向后,浏览器地址栏的URL会发生变化,由初始的URL变成重定向后的目标URL;RequestDispatcher.forward请求转发,浏览器地址栏URL不会变化。

HttpServletResponse.sendRedirect会有两次访问请求;RequestDispatcher.forward只有一次访问请求。

5. 利用referer实现防盗链

我们经常会遇到别人在微信群发了一个连接,点击进去后发现直接跳转到了网站首页,通过首页才能跳转到想看的网页。这个就利用了referer实现防盗链:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title></title>
  </head>
  <body>
      首页
      <a href="/HttpServletRequestDemo7">消息显示</a>
  </body>
</html>
/**
 * 利用referer实现防盗链
 */
@WebServlet(name = "HttpServletRequestDemo7")
public class HttpServletRequestDemo7 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String referer = request.getHeader("referer");
        System.out.println(referer);
        if (referer == null || !referer.startsWith("http://localhost")) {
            response.sendRedirect("/index.jsp");
            return;
        }
        request.getRequestDispatcher("/message.html").forward(request, response);
    }
}

运行结果:

可以看到都是调用HttpServletRequestDemo7,直接输入(referer为null)是不能获取到message.html的,通过首页跳转才可以。

6. web工程中各类地址的写法

写地址的时候最好以“/”开头,如果是给服务器用的地址,表示当前的web应用;如果是给浏览器用(地址栏)指的是web应用目录(虚拟映射目录)。

以下样例都设置当前web应用虚拟映射的目录为/aaa/bbb:

6.1 “/”代表当前web应用

1. 在Servlet中获取web应用的资源

this.getServletContext().getResource("/test.txt").getPath();
this.getServletContext().getRealPath("/test.txt");

2. 请求转发

request.getRequestDispatcher("/message.html").forward(request, response);

运行结果:

messag.html直接从当前web应用中查找,Servlet中无须写/aaa/bbb路径。

6.2 “/”代表当前web应用目录(虚拟映射目录)

1. 重定向

response.sendRedirect("/aaa/bbb/message.html");

这个是给浏览器用的,就必须写完整的映射路径,否则会找不到资源。但是“/aaa/bbb”映射的路径可能会变化,可通过下面的方式获取web应用的路径:

response.sendRedirect(request.getContextPath() + "/message.html");

运行结果:

2. 超链接

<a href="/aaa/bbb/HttpServletRequestDemo8">消息显示</a>

3. 表单提交

<form action="/aaa/bbb/HttpServletRequestDemo8">
    <input type="submit" value="测试web地址写法">
</form>

没搞清楚HTML中如何获取当前web应用目录映射,只能先写死了。。。

posted @ 2019-03-05 20:44  暴躁的毛毛熊  阅读(269)  评论(0编辑  收藏  举报