Servlet技术——request、respone详解

Servlet之request、respone详解

Servlet技术——request、respone详解_第1张图片

Request

(一) 概述

request是Servlet.service()方法的一个参数,在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法

HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息

(二) 常用方法

(1) 域方法

存储

//用来存储一个对象,也可以称之为存储一个域属性
void setAttribute(String name, Object value)
    
Eg:servletContext.setAttribute(“xxx”, “XXX”)
//在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX

获取

//用来获取ServletContext中的数据
Object getAttribute(String name)
//获取名为xx的域属性
Eg:String value = (String)servletContext.getAttribute(“xxx”);

//获取所有域属性的名称;
Enumeration getAttributeNames()

移除

//用来移除ServletContext中的域属性
void removeAttribute(String name)

(2) 获取请求头数据

//获取指定名称的请求头
String getHeader(String name)
 
//获取所有请求头名称
Enumeration getHeaderNames()
    
//获取值为int类型的请求头
int getIntHeader(String name)

(3) 获取请求相关的其他方法

//获取请求体的字节数,GET请求没有请求体,没有请求体返回-1;
int getContentLength()

/*	
	获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认
	为application/x-www-form-urlencoded,表示请求体内容使用了URL编码;
*/
String getContentType()

//返回请求方法,例如:GET/POST
String getMethod()
  
//返回当前客户端浏览器的Locale。java.util.Locale表示国家和言语,这个东西在国际化中很有用;
Locale getLocale()
    
/*
	获取请求编码,如果没有setCharacterEncoding(),那么返回null,表示使用
	ISO-8859-1编码;
*/
String getCharacterEncoding()
    
/*
	设置请求编码,只对请求体有效!注意,对于GET而言,没有请求体!!!所以此方法
	只能对POST请求中的参数有效!
*/
void setCharacterEncoding(String code)
 
//返回上下文路径,例如:/Dmoe1
String getContextPath()
    
//返回请求URL中的参数,例如:username=zhangSan
String getQueryString()
    
//返回请求URI路径,例如:/Demo1/ServletDemo1
String getRequestURI()
    
/*
	返回请求URL路径,例如:http://localhost/Demo1/ServletDemo1即返回除了参数
	以外的路径信息;
*/
StringBuffer getRequestURL()
    
//返回Servlet路径,例如:/ServletDemo1
String getServletPath()
    
//返回当前客户端的IP地址
String getRemoteAddr()
    
//返回当前客户端的主机名,但这个方法的实现还是获取IP地址
String getRemoteHost()
    
//返回请求协议,例如:http
String getScheme()

//返回主机名,例如:localhost
String getServerName()
    
//返回服务器端口号,例如:8080
int getServerPort()

为了方便记忆,我们画一张图辅助记忆

Servlet技术——request、respone详解_第2张图片

(4) 案例练习

案例一:防盗链

顾名思义,就是说让用户只能在我们站内访问对应网页,而通过复制链接到地址栏以及贴链接到别人的网站进行盗链,则全部跳转回自己的链接页面

注意:有一部分响应代码未接触,可先照着敲,大致体会,后期回来看

先看一下效果:

这是我们所制定的网站,简单理解为官网

Servlet技术——request、respone详解_第3张图片

在官网中,正常点击链接访问,页面跳转正常

Servlet技术——request、respone详解_第4张图片

如果我们本地写一个页面,直接绕过 a.html 去访问 http://localhost:8080/web-001/ServletDemo3" 此时页面就会跳转回a.html中去,也就会回到了我们的官网,并且控制台输出:非法盗链,已经跳回原页面访问!

Servlet技术——request、respone详解_第5张图片

下面是具体的代码实现

  • a.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <a href="/web-001/ServletDemo3">葫芦娃最新资源!!!a>
body>
html>
  • ServletDemo3
package cn.ideal.web.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;

@WebServlet("/ServletDemo3")
public class RequestDemo1 extends HttpServlet {

    public RequestDemo1() {
        super();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取网页来源
        String referer = req.getHeader("referer");
        //非法盗链
        if (referer == null || !referer.contains("localhost:8080/web-001/a.html")) {
            System.out.println("非法盗链,已经跳回原页面访问!");
            resp.sendRedirect("a.html");
            return;
        }
        //正常访问
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("是他就是他,是他就是他,我们的英雄葫芦娃!!!");
    }
}

(三) request获取请求参数

(1) GET/POST请求的使用位置

  • 浏览器地址栏直接输入:一定是GET请求
  • 超链接:一定是GET请求
  • 表单:可以是GET,也可以是POST

(2) GET/POST请求的区别

A:GET请求
  • 请求参数会在浏览器的地址栏中显示,所以不安全
  • 请求参数长度限制长度在1K之内
  • GET请求没有请求体,无法通过request.setCharacterEncoding()来设置参数的编码
B:POST请求
  • 请求参数不会显示浏览器的地址栏,相对安全
  • 请求参数长度没有限制

(3) 获取请求参数的通用方式(Get/Post均可)

//根据参数名称获取参数值
String getParameter(String name)

//根据参数名称获取参数值的数组 
String[] getParameterValues(String name)

//获取所有请求的参数名称
Enumeration<String> getParameterNames()

//获取所有参数的map集合
Map<String,String[]> getParameterMap()

(一)表单提交数据【通过post方式提交数据】

  • b.html

<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
head>
<body>
<form action="/web-001/RequestDemo3" method="post">
   <table>
      <tr>
         <td>用户名td>
         <td><input type="text" name="username">td>
      tr>
      <tr>
         <td>密码td>
         <td><input type="password" name="password">td>
      tr>
      <tr>
         <td>性别td>
         <td><input type="radio" name="gender" value=""><td><input type="radio" name="gender" value="">td>
      tr>
      <tr>
         <td>爱好td>
         <td>
            <input type="checkbox" name="hobbies" value="游泳">游泳
            <input type="checkbox" name="hobbies" value="跑步">跑步
            <input type="checkbox" name="hobbies" value="网球">网球
      tr>
      <input type="hidden" name="aaa" value="this is hidden text!">
      <tr>
         <td>从哪来的?td>
         <td>
            <select name="address">    
               <option value="广州">广州option>
               <option value="北京">北京option>
               <option value="深圳">深圳option>
            select>
         td>
      tr>     
      <tr>
         <td>补充说明td>
         <td>
            <textarea rows="2" cols="30" name="textarea">textarea>
         td>
      tr>
      <tr>
         <td><input type="submit" value="提交">td>
         <td><input type="reset" value="重置">td>
      tr>
   table>
   form>
body>
html>
  • RequestDemo3
package cn.ideal.web.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.util.Arrays;

@WebServlet("/RequestDemo3")
public class RequestDemo3 extends HttpServlet {
    public RequestDemo3() {
        super();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置request字符编码的格式
        req.setCharacterEncoding("UTF-8");

        //通过html的name属性,获取到值
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String gender = req.getParameter("gender");

        //复选框和下拉框有多个值,获取到多个值
        String[] hobbies = req.getParameterValues("hobbies");
        String[] address = req.getParameterValues("address");

        //获取到文本域的值
        String description = req.getParameter("textarea");

        //得到隐藏域的值
        String hiddenValue = req.getParameter("aaa");

        System.out.println("username: " + username);
        System.out.println("password: " + password);
        System.out.println("gender: " + gender);
        System.out.println("hobbies: " + Arrays.toString(hobbies));
        System.out.println("address: " + Arrays.toString(address));
        System.out.println("description: " + description);
        System.out.println("hiddenValue: " + hiddenValue);
    }

}

(二)超链接方式提交数据【通过get方式提交数据】

  • c.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<hr/>
<form action="/web-001/RequestDemo4" method="get">
    参数1:<input type="text" name="p1"/><br/>
    参数2:<input type="text" name="p2"/><br/>
    <input type="submit" value="提交"/>
form>
body>
html>
  • RequestDemo4
//省略包
@WebServlet("/RequestDemo4")
public class RequestDemo4 extends HttpServlet {
    public RequestDemo4() {
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String v1 = req.getParameter("p1");
        String v2 = req.getParameter("p2");
        System.out.println("p1=" + v1);
        System.out.println("p2=" + v2);
    }
}

(四) 中文乱码问题

乱码问题主要针对Tomcat8以前的版本,Tomcat8以上版本默认编码格式是UTF-8,而不是ISO 8859-1了

//设置request字符编码的格式
request.setCharacterEncoding("UTF-8");

Tomcat服务器的默认编码是ISO 8859-1,而浏览器使用的是UTF-8编码。浏览器的中文数据提交给服务器,Tomacat以ISO 8859-1编码对中文编码,当我在Servlet读取数据的时候自然拿到乱码。所以设置request的编码为UTF-8,乱码就解决了

注意:按照上述例子中(使用post方式)乱码问题已经解决了,但是在get方式中尝试仍然是乱码。在此我们需要了解post方法是怎么进行参数传递的。

当我们点击提交按钮的时候,数据封装进了Form Data中,http请求中把实体主体带过去了【传输的数据称之为主体】,既然request对象封装了http请求,所以request对象可以解析到发送过来的数据,于是只要把编码设置成UTF-8就可以解决乱码问题

(对上例中post请求方式进行抓包)

[外链图片转存失败(img-pl4PkiZy-1566972233727)(G:\公众号\markdown文件\05-Servlet\Servlet\中文乱码.png)]

而get方式不同,它的数据是从消息行带过去的,没有封装到request中,所以使用request设置编码是无效的。

解决方法: 我们既然知道Tomcat默认的编码是ISO 8859-1,那么get方式由消息体带过去给浏览器的时候肯定是用ISO 8859-1编码了。

(还可以通过修改Tomcat服务器的配置来解决,但是不推荐,因为会太依赖服务器了)

//此时得到的数据已经是被ISO 8859-1编码后的字符串了,这个是乱码
String name = request.getParameter("username);

//乱码通过反向查ISO 8859-1得到原始的数据
byte[] bytes = name.getBytes("ISO 8859-1);

//通过原始的数据,设置正确的码表,构建字符串
String value = new String(bytes,"UTF-8");

(五) 实现转发

服务器内部的资源跳转方式


<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
head>
<body>
<form action="/web-001/RequestDemo" method="get">
	<h1>这是转发后的首页,地址栏地址也没有发生变化h1>		
form>
body>
html>
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//获取到requestDispatcher对象,跳转到c.html
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("/c.html");
		//调用requestDispatcher对象的forward()实现转发,传入req和resp方法
		requestDispatcher.forward(reqt, resp);

转发的结果就是地址栏没有发生变化,但是页面已经跳转到c.html页面

学习Response后我们会学习重定向问题,到时候与转发做区分对别,请留意这一部分

(六) Servlet之间的通讯

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		request.setAttribute("username", "admin");
		//获取到requesetDispatcher对象
		RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servletB");
		//调用requestDispatcher对象的forward()实现转发,传入req和resp方法
		requestDispatcher.forward(req, resp);
	}
  • ServletB
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//获取到存进requeset对象的值
		String username = (String)req.getAttribute("username");
		//在浏览器输出该值
		respe.getWriter().write("i am: " + username);
	}

我们可以同时使用ServletContext和request实现Servlet之间的通讯

一般来说我们尽量使用request,因为ServletContext代表着整个web应用,使用ServetContext会消耗大量的资源,而request对象会随着请求的结束而技术,资源会被回收,使用request域进行Servlet进行Servlet之间的通讯在开发中是非常频繁的

细节:

如果在调用foreard方法之前,在Servlet程序中写入的部分已经被真正地传到了客户端,forward方法将抛出IllegalStateException异常,也就是说,不要在在转发之前写数据给浏览器

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

Respone

前面学习的 Request 对象可以帮助我们获取到浏览器发过来的请求,想对应的,我们就需要学习代表响应的 response 对象,它可以帮助我们进行对客户端的响应工作

(一) 响应正文

response作为响应对象,他提供了两个响应流对象,可以向客户端输出响应正文

//获取字符流
l PrintWriter out = response.getWriter()

//获取字节流
l ServletOutputStream out = response.getOutputStream()
ServletOutputStream servletOutputStream = resp.getOutputStream();
servletOutputStream.write("你好世界".getBytes());
servletOutputStream.write("Just for test".getBytes());

如果Tomcat版本在8以下 在outputStream中使用print()方法接收字符串,由于编码的问题,输出中文字符串的时候,就会出现乱码问题

原因是,outputStream是输出二进制的数据,print()方法先有一个将字符串转为二进制的过程,Tomcat会使用IOS 8859-1编码转换,所以出现了问题

但是使用write()却可以很好的解决这个问题,这是因为,write("Just for test".getBytes());转换为byte[]数组的时候默认使用的是gb2312编码,所以不会出现问题

但是为了后续方便,我们还是要使用UFT-8编码,如果我们在上一步骤中指定编码,看看如何

response.getOutputStream.write("你好世界".getBytes().getBytes("UTF-8"));

结果就是会出现乱码,这是因为客户端浏览器不知道响应数据是什么编码的,那么如何解决这个问题呢

解决方案:

A:设置消息头

//设置头信息,告诉浏览器我回送的数据是UTF-8的
response.setHeader("Content-Type""text/html;charset=UTF-8");

response.getOutputStream.write("你好世界".getBytes().getBytes("UTF-8"));

B:使用html标签模拟一个http消息头

ServletOutputStream servletOutputStream = resp.getOutputStream();

//使用meta标签模拟http消息头,告诉浏览器回送数据的编码和格式
servletOutputStream.write("
                                
                                
  • 数学是科学技术的语言 comsci 工作活动领域模型
      从小学到大学都在学习数学,从小学开始了解数字的概念和背诵九九表到大学学习复变函数和离散数学,看起来好像掌握了这些数学知识,但是在工作中却很少真正用到这些知识,为什么?    最近在研究一种开源软件-CARROT2的源代码的时候,又一次感觉到数学在计算机技术中的不可动摇的基础作用,CARROT2是一种用于自动语言分类(聚类)的工具性软件,用JAVA语言编写,它
  • Linux系统手动安装rzsz 软件包 daizj linuxszrz
    1、下载软件 rzsz-3.34.tar.gz。登录linux,用命令 wget http://freeware.sgi.com/source/rzsz/rzsz-3.48.tar.gz下载。 2、解压 tar zxvf  rzsz-3.34.tar.gz 3、安装  cd rzsz-3.34 ; make posix 。注意:这个软件安装与常规的GNU软件不
  • 读源码之:ArrayBlockingQueue dieslrae java
        ArrayBlockingQueue是concurrent包提供的一个线程安全的队列,由一个数组来保存队列元素.通过 takeIndex和 putIndex来分别记录出队列和入队列的下标,以保证在出队列时 不进行元素移动. //在出队列或者入队列的时候对takeIndex或者putIndex进行累加,如果已经到了数组末尾就又从0开始,保证数
  • C语言学习九枚举的定义和应用 dcj3sjt126com c
    枚举的定义 # include <stdio.h> enum WeekDay { MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturDay, SunDay }; int main(void) { //int day; //day定义成int类型不合适 enum WeekDay day = Wedne
  • Vagrant 三种网络配置详解 dcj3sjt126com vagrant
    Forwarded port Private network Public network Vagrant 中一共有三种网络配置,下面我们将会详解三种网络配置各自优缺点。 端口映射(Forwarded port),顾名思义是指把宿主计算机的端口映射到虚拟机的某一个端口上,访问宿主计算机端口时,请求实际是被转发到虚拟机上指定端口的。Vagrantfile中设定语法为: c
  • 16.性能优化-完结 frank1234 性能优化
    性能调优是一个宏大的工程,需要从宏观架构(比如拆分,冗余,读写分离,集群,缓存等), 软件设计(比如多线程并行化,选择合适的数据结构), 数据库设计层面(合理的表设计,汇总表,索引,分区,拆分,冗余等) 以及微观(软件的配置,SQL语句的编写,操作系统配置等)根据软件的应用场景做综合的考虑和权衡,并经验实际测试验证才能达到最优。 性能水很深, 笔者经验尚浅 ,赶脚也就了解了点皮毛而已,我觉得
  • Word Search hcx2013 search
    Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or ve
  • Spring4新特性——Web开发的增强 jinnianshilongnian springspring mvcspring4
    Spring4新特性——泛型限定式依赖注入 Spring4新特性——核心容器的其他改进 Spring4新特性——Web开发的增强 Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC  Spring4新特性——Groovy Bean定义DSL Spring4新特性——更好的Java泛型操作API  Spring4新
  • CentOS安装配置tengine并设置开机启动 liuxingguome centos
    yum install gcc-c++  yum install pcre pcre-devel  yum install zlib zlib-devel  yum install openssl openssl-devel Ubuntu上可以这样安装 sudo aptitude install libdmalloc-dev libcurl4-opens
  • 第14章 工具函数(上) onestopweb 函数
    index.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/
  • Xelsius 2008 and SAP BW at a glance blueoxygen BOXelsius
    Xelsius提供了丰富多样的数据连接方式,其中为SAP BW专属提供的是BICS。那么Xelsius的各种连接的优缺点比较以及Xelsius是如何直接连接到BEx Query的呢? 以下Wiki文章应该提供了全面的概览。   http://wiki.sdn.sap.com/wiki/display/BOBJ/Xcelsius+2008+and+SAP+NetWeaver+BW+Co
  • oracle表空间相关 tongsh6 oracle
    在oracle数据库中,一个用户对应一个表空间,当表空间不足时,可以采用增加表空间的数据文件容量,也可以增加数据文件,方法有如下几种: 1.给表空间增加数据文件    ALTER TABLESPACE "表空间的名字" ADD DATAFILE    '表空间的数据文件路径' SIZE 50M;   &nb
  • .Net framework4.0安装失败 yangjuanjava .netwindows
    上午的.net framework 4.0,各种失败,查了好多答案,各种不靠谱,最后终于找到答案了 和Windows Update有关系,给目录名重命名一下再次安装,即安装成功了! 下载地址:http://www.microsoft.com/en-us/download/details.aspx?id=17113 方法: 1.运行cmd,输入net stop WuAuServ 2.点击开