Servlet(二)

一、请求对象和响应对象

HttpServletRequest和HttpServletResponse

(1)请求和响应的原理

       当服务器收到请求以后,服务器会创建 request请求对象和response响应对象,并将请求消息封装到请求对象里面,然后服务器会通过反射创建Servlet对象,并调用其service()并将请求对象和响应对象作为参数传递给service方法,当服务器做出响应之前,会从响应对象里面取出响应的信息给浏览器做出响应,这一次请求一次响应结束,服务器会销毁这个请求对象和响应对象。

(2)request 和response 对象都是由服务器创建、管理、销毁。

(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

未完待续。。。

猜你喜欢

转载自blog.csdn.net/wzj_110/article/details/80601346