一、请求对象和响应对象
HttpServletRequest和HttpServletResponse
(1)请求和响应的原理
当服务器收到请求以后,服务器会先创建 request请求对象和response响应对象,并将请求消息封装到请求对象里面,然后服务器会通过反射创建Servlet对象,并调用其service()并将请求对象和响应对象作为参数传递给service方法,当服务器做出响应之前,会从响应对象里面取出响应的信息给浏览器做出响应,这一次请求一次响应结束,服务器会销毁这个请求对象和响应对象。
(3)继承体系结构----服务器创建的对象
ServletRequest(接口)<---------继承<-------HttpServletRequest(接口)<--------实现-------- RequestFacade(打印对象可知)
ServletResponse(接口)<---------继承<-------HttpServletResponse(接口)<---------实现------ResponseFacade
(4)首先介绍响应对象--response
说明:给浏览器做出响应
需求1:向浏览器输出内容(字符--getWriter())
引出的问题:中文乱码
方案1:指定浏览器的解码和服务器的编码方式(一致)
引出响应头:
Content-Type: text/html; charset=GB2312
作用:告诉浏览器你用什么字符集去解码
方案2(优化):既然编解码一致,可以通过简写方式合并上述两步
response.setContentType("text/html;charset=utf-8");
相应的代码
package org.wzj.servlet;
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;
@WebServlet(name = "Servlet01",value = "/demo01")
public class Servlet01 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//(1)设置服务器编码的字符集---字符对应的编码字节流的形式
response.setCharacterEncoding("utf-8");
//(2)同时告诉浏览器的解码形式---第一个响应头信息
response.setHeader("Content-Type","text/html;charset=utf-8");
//(3)简写方式---重点掌握!!!
//response.setContentType("text/html;charset=utf-8");
System.out.println("请求对象"+request);//org.apache.catalina.connector.RequestFacade@69d6c83b
System.out.println("响应对象"+response);//org.apache.catalina.connector.ResponseFacade@63f2a3be
//需求1:向浏览器输出内容(做出响应)
PrintWriter writer = response.getWriter();//字符打印流
writer.write("嗨!浏览器,我是服务器!");
//出现问题:中文乱码
//原因:服务器和浏览器的编码和解码方式不一致所致;
//tomcat服务器默认的编码是ISO-8859-1,而浏览器未收录此字符集
//由于服务器向浏览器传递数据也是以字节流的形式,而浏览器没有此编码,
//只能改变服务器的编码并向浏览器指定解码:原因---用户体验(用户可能不会调)
//因此要设置服务器的编码方式和浏览器的解码方式,见最上面---
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
需求2:向浏览器显示一副图片
说明:字节流传递(不涉及编码,因此无须指定编解码的方式,如果编码会报错!!!)
相应的代码:
package org.wzj.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet(name = "Servlet02",value = "/demo02")
public class Servlet02 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//需求:向浏览器展示一张图片,资源放在WEB-INF中
//(1)获取字节输出流对象---准备写入数据
ServletOutputStream out = response.getOutputStream();
//(2)说明:由于获取Web文件的路径,所有要使用上下文对象
String path = this.getServletContext().getRealPath("/xing.jpg");//理解路径的写法(lib的位置)
//(3)创建文件流,去读取数据
FileInputStream in = new FileInputStream(path);
//(4)创建缓冲区
byte[] bytes = new byte[1024];
//(5)定义一个变量
int len=0;
while((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
out.flush();//虽然没有用(字符流有作用),但是也写上吧!
} //说明(同上)--工具类对流进行传递:IOUtils.copy(in,out);
//(6)释放资源
in.close();
out.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
说明:如果使用对应的IO流的jar包,一般放在WEB-INF的目录下,新建一个lib目录。
3、重定向(设置响应信息--response)
通俗理解:浏览器请求服务器,但是服务器当前项目下没有这个资源,但是服务器知道哪里有,开一个路条你去这个地方去找!
说明:定向定向,向指定的地方寻找资源!!!
作用:实现页面跳转
代码的方式设置重定向
package org.wzj.servlet;
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;
//小问题:总是报404错误???
@WebServlet(name = "Servlet03",value = "/demo03")
public class Servlet03 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("请求来了");
//(1)设置响应状态码---302表示重定向
response.setStatus(302);
//(2)告诉浏览器去哪里寻找资源
response.setHeader("Location","http://www,baidu.com");
//(3)重定向---重点掌握!!!
//response.sendRedirect("http://www.baidu.com");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
重定向特点:
1. 两次请求, 两次响应;
2. 地址栏会发生 变化;
3.重定向既可以访问内部资源,也可访问外部资源
关键字:请求、地址栏、资源。
4、小案例(验证码)
package org.wzj.servlet;
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet(name = "Servlet04",value = "/demo04")
public class Servlet04 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//(1)用代码来画图片
int width=200;
int height=100;
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);//画图片
//美化图片
//改变图片背景
//获取画笔
Graphics g = image.getGraphics();
//设置颜色
g.setColor(Color.PINK);
//填充背景
g.fillRect(0,0,width,height);
//画边框
g.setColor(Color.BLUE);
//注意给宽高 减去一个像素
g.drawRect(0,0,width-1,height-1);
//写字
g.setColor(Color.RED);
//设置文字大小
Font font = new Font("宋体",Font.PLAIN,20);
g.setFont(font);
//随机生成
String msg = "abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789";
Random ran = new Random();
for(int i=1;i<=4;i++){
int index = ran.nextInt(msg.length());//通过索引来随机的获取一个字符
char c = msg.charAt(index);//生成的验证码的一个字符
g.drawString(c+"",width/5*i,height/2);//设置字符的间距
}
//画干扰线(成年人可以辨识)--颜色和条数
g.setColor(Color.GREEN);
for(int i=1;i<=10;i++){
int x1 = ran.nextInt(width);
int x2= ran.nextInt(width);
int y1 = ran.nextInt(width);
int y2 = ran.nextInt(width);
g.drawLine(x1,y1,x2,y2);
}
//最后我们要把图片响应回去
ImageIO.write(image,"jpg",response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
(5)request 对象
作用1:获取请求消息(拼接出请求行的信息)
1.获取请求行: GET /MyServlet/index.jsp?name=zhangsan&age=23 HTTP/1.1
request.getMethod(); //获取请求方式
request.getContextPath(); //获取项目名称--"/项目"--请求的上下文部分
request.getRequestURI(); //获取URI --获取统一资源标识符(范围大)--/MyServlet2/demo5
request.getRequestURL(); //获取URL --获取统一资源定位符---"http://localhost:8090/MyServlet2/demo5
request.getRemoteAddr(); //获取IP地址 --自己测试的话可能是回环地址;对不同的ip做不同的处理
request.getQueryString(); //获取请求参数--GET独有的方式
request.getProtocol(); //获取协议版本 --HTTP1.1
请求行的信息说明:请求方法、URI、HTTP的版本
补充:URL是URI子集的原因:URI适用所有的协议,而URL只适用HTTP协议
作用2:获取请求头(常用的)
request.getHeader("user-agent");//获取请求头的值----主要作用是兼容浏览器的
request.getDateHeader(name); //获取日期头
request.getIntHeader(name) //获取数字头
作用3:获取请求体的内容
说明:请求体专门用于封装Post请求的请求参数
获取字符数据: getReader(); 返回一个高效的字符流《我们通过一次读取一行的方法来获取请求参数数据,然后拆分字符串获取我们想要的数据
补充:获取字节数据---get
Inpu
tStream(); 后期
上传文件时讲解
作用4:通用的方式来获取请求参数(处理逻辑)
request.getParameter(name); 通过请求参数的名称来获取值
request.getParameterValues("hobby"); 通过请求参数的名称,来获取值的数组,一般用于"复选框"
request.getParameterMap(); 获取所有参数的map集合--键值对的形式--通常由键找值
request.getParameterNames(); 获取所有参数的名称,枚举(不常用---了解)
作用5:request请求的处理中文乱码问题(后台展示是乱码---URL地址的编码)
处理方式1:(了解)
//通用处理方式:处理get post 请求提交中文数据乱码问题
String username = request.getParameter("username");
byte[] bytes = username.getBytes("ISO-8859-1");//将字符串还原成字节,相当于解码
username=new String(bytes,"utf-8");//将字节重新编码
处理方式2:(理解)
说明:由于GET提交方式,提交的参数会在URL地址栏(请求行)中,而浏览器会将其进行加密(编码)发送到后台,后台想获取数据,必须相同的方式进行解码!;如果是POST,其提交的数据在请求体中(不能采用这种方式)
package org.westos.demo;
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.BufferedReader;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
@WebServlet(name = "ServletDemo2",value = "/demo2")
public class ServletDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//POST方式获取请求参数
BufferedReader reader = request.getReader();
String s = reader.readLine();
System.out.println(s);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求行
String string = request.getQueryString();//username=%E5%BC%A0%E4%B8%89&password=123456
string = URLDecoder.decode(string,"utf-8");//URL解码--重点!!!
//URLEncoder.encode("张三","utf-8");//URL编码(了解,一般不用)
System.out.println(string);//username=王五&password=123456
// %E5%BC%A0%E4%B8%89(不是乱码!!!)---浏览器会对中文进行URLencode编码
String[] split = string.split("&");
String[] split1 = split[0].split("=");
System.out.println(split1[0]);
System.out.println(split1[1]);
String[] split2 = split[1].split("=");
System.out.println(split2[0]);
System.out.println(split2[1]);
}
}
处理方式3:(重点掌握!!!)
注:POST请求特有的方式处理中文乱码(GET方式tomcat服务器默认自己处理了,不需要自己担心接受数据是中文乱码的问题)
POST
request.setCharacterEncoding("utf-8");
GET不需要设置,直接获取(键找值)
String username = request.getParameter("username");
代码:
package org.westos.demo;
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(name = "ServletDemo7",value = "/demo7")
public class ServletDemo7 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//处理响应乱码
response.setContentType("text/html;charset=utf-8");
//处理post请求的中文乱码
request.setCharacterEncoding("utf-8");
//GET请求方式提交上来的中文,tomcat8.0以上的版本 默认对GET请求的中文做了处理
String username = request.getParameter("username");
//ISO-8859-1 UTF-8 字节
//POST的手动编解码
// byte[] bytes = username.getBytes("ISO-8859-1");//解码
// username=new String(bytes,"utf-8");//重新编码
System.out.println(username);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
理解(三步走)下面代码的含义:
this.doPost(request, response);
思考:提交方式不同,获取参数的方式不同,作为开发人员能不能屏蔽底层(获取参数)的差异,对任意的提交做相同的处理?
过程:可以写一个方法处理不同的提交方式,然后让doPost和doPost调用→进阶→在一个方法里对参数做处理(底层已经屏蔽差异--二者可以以相同的方式获取数据),另一个方法中调用该方法
注意:这时候里面的request和response是对应请求方式封装的对象。
作用6:请求转发(request)
特点1. 一次请求一次响应
2. 地址栏不发生变化
3.只能访问 内部站点资源
代码
request.getRequestDispatcher("/myservlet2").forward(request, response);
注意:请求转发是内部转发,或者说是当前项目里面资源间的转发,所以不需要加项目名!!!
补充:请求转发是服务器的事情(暗度陈仓,偷偷摸摸的干活),而重定向是浏览器的事情(地址栏变化---用户体验不好)
(6)request请求域对象
1、作用范围
范围:在一次请求的多个资源之间共享数据;
通俗解释:一次请求(在请求的过程中地址栏不发生变化)
思考:重定向是不是一次请求?---of course not---回顾重定向的特点
请求转发的说明:即使你多次请求,最终也要向浏览器响应(兜了一圈又回去了),才算一次请求和一次响应结束。
2、向域对象中设置和获取共享数据
request.setAttribute("name","zhangsan");
request.getAttribute("name"); //一般是在另外一个Servlet中获取数据
request.removeAttribute("name");//删除域对象中的数据
3、什么时候使用重定向?
一次性的数据存入请求域中
4、什么时候使用转发?
如果需要在一次请求的多个资源中共享数据,则使用转发
(7)路径的书写(重中之重!!!)
思考:什么时候需要加项目路径,什么时候不需要加项目路径?
加项目路径:所有页面的上的路径(html 页面、jsp页面)上的路经都需要加上项目路径
形如1:
<form actiont="/MyServlet1/demo9"> <!--表单的提交-->
<img src="/MyServlet1/demo9"> <!--图片资源-->
<a href="/MyServlet1/demo9"> <!--超链接-->
形如2:
//2.重定向跳转内部资源你也需要加上项目路径 当然这个项目路径是"动态获取"
response.sendRedirect(request.getContextPath()+"/demo9");
response.sendRedirect("/MyServelt1/demo9");
不加项目路径
形如1:
//1.请求转发不能加项目路径(具体原因见上面)
request.getRequestDispatcher("/demo9").forward(request,response);
练习:登录注册案例(后续补充)
后续补充(HTTP的相关知识)
主要:请求和响应的行、体、头信息、状态码、缓存、负载均衡、代理、网关、隧道、HTTPS
未完待续。。。