Servlet技术——request、respone详解

Request

(一) 概述

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

HttpServletRequest对象表明客户端的请求,当客户端经过HTTP协议访问服务器时,HTTP请求头中的全部信息都封装在这个对象中,开发人员经过这个对象的方法,能够得到客户这些信息java

(二) 经常使用方法

(1) 域方法

存储web

//用来存储一个对象,也能够称之为存储一个域属性
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() 复制代码

为了方便记忆,咱们画一张图辅助记忆安全

(4) 案例练习

案例一:防盗链服务器

顾名思义,就是说让用户只能在咱们站内访问对应网页,而经过复制连接到地址栏以及贴连接到别人的网站进行盗链,则所有跳转回本身的连接页面app

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

先看一下效果:jsp

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

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

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

下面是具体的代码实现

  • a.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</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请求方式进行抓包)

而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");
复制代码

(五) 实现转发

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</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("<meta http-equiv='content-type' content='text/html;charset=UTF-8>".getBytes());

servletOutputStream.write("你好世界".getBytes().getBytes("UTF-8"));
复制代码

C:推荐方法

//设置浏览器用UTF-8编码显示数据
resp.setContentType("text/html;charset=UTF-8");

//获取到printWriter对象
PrintWriter printWriter = resp.getWriter();
printWriter.writer("你好世界")
复制代码

好处:不仅会调用response.setCharaceterEncoding(“utf-8”),还会设置content-type响应头(客户端浏览器会使用content-type头来解读响应数据)

总结:响应正文内容为字符,那么使用respone.getWriter(),若是响应内容是字节,例以下载文件,可使用 response.getOutputStream()

注意:在同一个请求中,不能同时使用这两个流,不然会抛出 IllegalStateException 异常

getWriter() 的缓冲区问题

它的类型是PrintWriter类型的,因此它有缓冲区,缓冲区的默认大小为8KB,在限定代销范围之内,数据先存放在缓冲区,等到超过范围后,服务器刷新流,缓冲区中的数据发送倒客户端,若是想要响应数据立刻发送到客户端,能够调用response.flushBuffer()方法来手动刷新缓冲区

(二) 设置响应头信息、状态码以及其余

(1) 设置响应头

使用 response 对象的 setHeader() 方法来设置响应头

//设置content-type响应头,告诉浏览器响应内容为html类型,编码为utf-8。并且同时会设置response的字符流编码为utf-8,即response.setCharaceterEncoding(“uaav tf-8”);

response.setHeader(“content-type”, “text/html;charset=utf-8”)

//5秒后自动跳转到指定主页
response.setHeader("Refresh","5; URL=http://www.xxx.com"):
复制代码

(2) 设置状态码

//设置状态码
response.setStatus(200)

//当发送错误状态码时,跳转到指定错误页面,但能够显示错误信息
response.sendError(404, “您要查找的资源不存在”)
复制代码

(3) 其余

//等同于response.setHeader(“content-type”, “text/html;charset=utf-8”)
response.setContentType("text/html;charset=utf-8")

//设置字符响应流的字符编码为UTF-8 
response.setCharacterEncoding(“utf-8”)
    
//下例表示定时刷新,3秒后跳转页面
response.setHeader("Refresh", "3;URL=Bservlet");
复制代码

(三) 重定向

当你访问 www.xxx.com的时候,页面被跳转到了另外一个页面,而且浏览器地址栏中的URL也发生了变化,这种技术就叫作重定向

完成重定向有两个关键的地方

  • 设置响应码
  • 设置Location头

响应码200的意思是响应成功,而重定向对应的响应码为302,因此咱们须要设置响应码

由于重定向的原理为,发出二次请求,因此你须要给浏览器指定第二次请求的URL,因此须要蛇者Location头

注意:同服务器下可使用相对路径

response.setStatus(302);
response.setHeader("Location", "www.xxx.com");
复制代码

简单的写法

response.sendRedirect("www.xxx.com");
复制代码

(四) 转发和重定向的区别与使用场景

(1) 区别

(一) 实际发生未知不一样,地址栏不一样

A:转发是发生在服务器的

B:转发是由服务器进行跳转的,转发时,浏览器的地址栏是没有发生变化的,(访 问了Servlet1后即便页面跳转到了Servlet2,但浏览器的地址仍是Servlet1的) 也就是说浏览器是不知道该跳转的动做,实现转发只是一次的http请求,一次转 发中request和response对象都是同一个,这也解释了为何可使用request 做为域对象进行Servlet之间的通信

C:重定向是发生在浏览器的

D:重定向是由浏览器进行跳转的,进行重定向跳转的时候,浏览器的地址会发生变化,实现重定向的原理是由response的状态码和location头组合而实现的,这 是由浏览器进行的页面跳转实现会发出两个http请求,request域对象是无效的, 由于它不是同一个request对象

(二) 用法不一样

原则:给服务器用的直接从资源名开始写,给浏览器用的要把应用名协写上

Requst.getRequestDispatcher(“/资源名 URL”).forward(request,response);

转发时“/”表明的是本应用程序的根目录(web-01)

Response.send(“/web应用/资源名URL”);

重定向时“/”表明的是webapps目录

(三) 可以去往的URL的范围不一样

转发是服务器跳转,只能去往当前web应用的资源

重定向是服务器跳转,能够去往任何的资源

(四) 传递数据的类型不一样

转发的request对象能够传递各类类型的数据,包括对象

重定向只能传递字符串

(五) 跳转的时间不一样

转发时:执行到跳转语句就会马上跳转

重定向:整个页面执行完后才会执行跳转

(2) 应用场景

总结:转发是带着转发前的请求的参数。重定向时新的请求

典型的应用场景:

1:转发:访问Servlet处理业务逻辑,而后转发到jsp中去处理结果,浏览器里URL不变

2:重定向:提交表单,处理成功后重定向到另外一个jsp,防止表单重复提交,浏览器里的URL变了

结尾:

若是内容中有什么不足,或者错误的地方,欢迎你们给我留言提出意见, 蟹蟹你们 !^_^

若是能帮到你的话,那就来关注我吧!(系列文章均会在公众号第一时间更新)

在这里的咱们素不相识,却都在为了本身的梦而努力 ❤

一个坚持推送原创Java技术的公众号:理想二旬不止

相关文章
相关标签/搜索