06 Request&Response

1、Request和Response的概述

  • Request是请求对象,Response是响应对象
  • request:获取请求数据
    • 浏览器会发送HTTP请求到后台服务器[Tomcat]
    • HTTP的请求中会包含很多请求数据[请求行+请求头+请求体]
    • 后台服务器[Tomcat]会对HTTP请求中的数据进行解析并把解析结果存入到一个对象中
    • 所存入的对象即为request对象,所以我们可以从request对象中获取请求的相关参数
    • 获取到数据后就可以继续后续的业务,比如获取用户名和密码就可以实现登录操作的相关业务
  • response:设置响应数据
    • 业务处理完后,后台就需要给前端返回业务处理的结果即响应数据
    • 把响应数据封装到response对象中
    • 后台服务器[Tomcat]会解析response对象,按照[响应行+响应头+响应体]格式拼接结果
    • 浏览器最终解析结果,把内容展示在浏览器给用户浏览

2、Request对象

  1. Request继承体系

    • RequestFacade类实现了HttpServletRequest接口,也间接实现了ServletRequest接口。
    • Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat]来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建
    • 要想了解RequestFacade中都提供了哪些方法,我们可以直接查看JavaEE的API文档中关于ServletRequest和HttpServletRequest的接口文档,因为RequestFacade实现了其接口就需要重写接口中的方法
  2. Request获取请求数据

    • 获取请求行数据
      请求行包含三块内容,分别是请求方式请求资源路径HTTP协议及版本

       // (1) String getMethod():获取请求方式: GET
       String method = req.getMethod();
       System.out.println(method);//GET
      
       // (2)String getContextPath():获取虚拟目录(项目访问路径):/request-demo
       String contextPath = req.getContextPath();
       System.out.println(contextPath);
      
       // (3)StringBuffer getRequestURL(): 获取URL(统一资源定位符):http://localhost:8080/request-demo/req1
       StringBuffer url = req.getRequestURL();
       System.out.println(url.toString());
      
       // (4)String getRequestURI():获取URI(统一资源标识符): /request-demo/req1
       String uri = req.getRequestURI();
       System.out.println(uri);
      
       // (5)String getQueryString():获取请求参数(GET方式): username=zhangsan
       String queryString = req.getQueryString();
       System.out.println(queryString);
      

      启动服务器,访问:
      http://localhost:8080/request-demo/req1?username=zhangsan&passwrod=123
      获取的结果如下:

    • 获取请求头数据
      请求头数据格式key: value

      protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException {
          //获取请求头: user-agent: 浏览器的版本信息
          String agent = req.getHeader("user-agent");
      	System.out.println(agent);
      }
      
    • 获取请求体数据

      • 浏览器在发送GET请求的时候是没有请求体的,所以需要把请求方式变更为POST
      • Request对象提供了两种方式来获取请求体数据
      // (1)获取字节输入流
      //如果前端发送的是字节数据,比如传递的是文件数据,则使用该方法
      ServletInputStream getInputStream()
      
      // (2)获取字符输入流
      //如果前端发送的是纯文本数据,则使用该方法
      BufferedReader getReader() //会自动关闭,不需要手动关闭流
      
    • 获取请求参数的通用方式
      通用指POST和GET都适用

      // (1)获取所有参数Map集合
      Map<String,String[]> getParameterMap()
      // (2)根据名称获取参数值(数组)
      String[] getParameterValues(String name)
      // (3)根据名称获取参数值(单个值)
      String getParameter(String name)
      
      @WebServlet("/req2")
      public class RequestDemo2 extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
          throws ServletException, IOException {
              //1. 获取所有参数的Map集合
              Map<String, String[]> map = req.getParameterMap();
              for (String key : map.keySet()) {
                  // username:zhangsan lisi
                  System.out.print(key+":");
      
                  //获取值
                  String[] values = map.get(key);
                  for (String value : values) {
                      System.out.print(value + " ");
                  }
                  System.out.println();
      
      			System.out.println("------------");
      	        String[] hobbies = req.getParameterValues("hobby");
      	        for (String hobby : hobbies) {
      	            System.out.println(hobby);
      	        }
      	        String username = req.getParameter("username");
      	        String password = req.getParameter("password");
      	        System.out.println(username);
      	        System.out.println(password);
              }
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
          throws ServletException, IOException {
           	this.doGet(req,resp);//代码一样不用再重复写
          }
      }
      
  3. IDEA快速创建Servlet

    • 按照自己的需求,修改Servlet创建的模板内容
    • 使用servlet模板创建Servlet类
  4. 请求参数中文乱码问题
    (1)Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8
    (2)POST请求解决方案是:设置输入流的编码

    request.setCharacterEncoding("UTF-8");//(注意:设置的字符集要和页面保持一致)
    

    (3)通用方式(GET/POST):需要先解码,再编码

    new String(username.getBytes("ISO-8859-1"),"UTF-8");
    
  5. Request请求转发

    • 请求转发(forward):一种在服务器内部的资源跳转方式

    • 请求转发的实现方式:

      req.getRequestDispatcher("资源B路径").forward(req,resp);
      
    • request对象提供的三个方法:

      // (1)存储数据到request域[范围,数据是存储在request对象]中
      void setAttribute(String name,Object o);
      // (2)根据key获取值
      Object getAttribute(String name);
      // (3)根据key删除该键值对
      void removeAttribute(String name);
      
    • 请求转发的特点

      • 浏览器地址栏路径不发生变化
      • 只能转发到当前服务器的内部资源
      • 一次请求,可以在转发资源间使用request共享数据
    @WebServlet("/req5")
    public class RequestDemo5 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("demo5...");
            //存储数据
            request.setAttribute("msg","hello");
            //请求转发
            request.getRequestDispatcher("/req6").forward(request,response);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request, response);
        }
    }
    
    /**
     * 请求转发
     */
    @WebServlet("/req6")
    public class RequestDemo6 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("demo6...");
            //获取数据
            Object msg = request.getAttribute("msg");
            System.out.println(msg);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request, response);
        }
    }
    

    访问http://localhost:8080/request-demo/req5,就可以在控制台看到如下内容:

3、Response对象

  1. Response继承体系

  2. Response设置响应数据功能介绍
    HTTP响应数据总共分为三部分内容,分别是响应行、响应头、响应体

    • 响应行

      常用设置响应状态码:void setStatus(int sc);
    • 响应头
      设置响应头键值对:void setHeader(String name,String value);
    • 响应体
      • 获取字符输出流:PrintWriter getWriter();
      • 获取字节输出流:ServletOutputStream getOutputStream();
  3. Respones请求重定向

    • Response重定向(redirect):一种资源跳转方式

      (1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求
      (2)资源A现在无法处理该请求,就会给浏览器响应一个302的状态码+location的一个访问资源B的路径
      (3)浏览器接收到响应状态码为302就会重新发送请求到location对应的访问地址去访问资源B
      (4)资源B接收到请求后进行处理并最终给浏览器响应结果,这整个过程就是重定向

    • 重定向的实现方式:

      resp.setStatus(302);
      resp.setHeader("location","资源B的访问路径");
      
      resposne.sendRedirect("资源B的访问路径")//简化方法
      
    • 重定向的特点

      • 浏览器地址栏路径发送变化
      • 可以重定向到任何位置的资源(服务内容、外部均可)
      • 两次请求,不能在多个资源使用request共享数据

  1. 路径问题

    • 浏览器使用:需要加虚拟目录(项目访问路径)
    • 服务端使用:不需要加虚拟目录
    //简化方式完成重定向
    //动态获取虚拟目录
     String contextPath = request.getContextPath();
     response.sendRedirect(contextPath+"/resp2");
    
  2. Response响应字符数据

    • 步骤
      • 通过Response对象获取字符输出流: PrintWriter writer = resp.getWriter();
      • 通过字符输出流写数据: writer.write(“aaa”);
    @WebServlet("/resp3")
    public class ResponseDemo3 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
            //设置响应的数据格式及数据的编码
    		response.setContentType("text/html;charset=utf-8");
    		
    		//(1)通过Response对象获取字符输出流
            PrintWriter writer = response.getWriter();
    		
    		//(2)通过字符输出流写数据
    		writer.write("aaa");
    		 
    		 //告诉浏览器返回的数据类型是HTML类型数据,浏览器才会解析HTML标签
    		response.setHeader("content-type","text/html");
    		writer.write("<h1>aaa</h1>");
    		
    		writer.write("你好");
    
        }
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
            this.doGet(request, response);
        }
    }
    
  3. Response响应字节数据

    • 步骤
      • 通过Response对象获取字节输出流:ServletOutputStream outputStream = resp.getOutputStream();
      • 通过字节输出流写数据: outputStream.write(字节数据);
    @WebServlet("/resp4")
    public class ResponseDemo4 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1. 读取文件
            FileInputStream fis = new FileInputStream("d://a.jpg");
            //2. 获取response字节输出流
            ServletOutputStream os = response.getOutputStream();
            //3. 完成流的copy
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = fis.read(buff))!= -1){
                os.write(buff,0,len);
            }
            fis.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request, response);
        }
    }
    

    使用别人提供好的方法来简化代码的开发
    (1)pom.xml添加依赖

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
    

    (2)调用工具类方法

    //3. 完成流的copy
    IOUtils.copy(fis,os);//fis:输入流  os:输出流
    fis.close();
    

4、用户注册登录案例

  1. 环境准备

    • (1)前端页面
      复制资料中的静态页面到项目的webapp目录下

    • (2)数据库
      创建db1数据库,创建tb_user表

    • (3)项目依赖
      在项目的pom.xml导入Mybatis和Mysql驱动坐标

      <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.5</version>
      </dependency>
      
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.34</version>
      </dependency>
      
    • (4)MyBatis配置
      创建mybatis-config.xml核心配置文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE configuration
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
          <!--起别名-->
          <typeAliases>
              <package name="com.itheima.pojo"/>
          </typeAliases>
      
          <environments default="development">
              <environment id="development">
                  <transactionManager type="JDBC"/>
                  <dataSource type="POOLED">
                      <property name="driver" value="com.mysql.jdbc.Driver"/>
                      <!--
                          useSSL:关闭SSL安全连接 性能更高
                          useServerPrepStmts:开启预编译功能
                          &amp; 等同于 & ,xml配置文件中不能直接写 &符号
                      -->
                      <property name="url" value="jdbc:mysql:///db1?useSSL=false&amp;useServerPrepStmts=true"/>
                      <property name="username" value="root"/>
                      <property name="password" value="1234"/>
                  </dataSource>
              </environment>
          </environments>
          <mappers>
              <!--扫描mapper-->
              <package name="com.itheima.mapper"/>
          </mappers>
      </configuration>
      
    • (5)数据库表对象类
      创建User实体类

    • (6)SQL语句编写
      创建UserMapper.xml映射文件,UserMapper接口

  2. 用户登录

    • 需求分析

      1. 用户在登录页面输入用户名和密码,提交请求给LoginServlet
      2. 在LoginServlet中接收请求和数据[用户名和密码]
      3. 在LoginServlt中通过Mybatis实现调用UserMapper来根据用户名和密码查询数据库表
      4. 将查询的结果封装到User对象中进行返回
      5. 在LoginServlet中判断返回的User对象是否为null
      6. 如果为nul,说明根据用户名和密码没有查询到用户,则登录失败,返回"登录失败"数据给前端
      7. 如果不为null,则说明用户存在并且密码正确,则登录成功,返回"登录成功"数据给前端
    • 代码实现

      • (1)编写接口(SQL语句)
        在UserMapper接口中提供一个根据用户名和密码查询用户对象的方法
        @Select("select * from tb_user where username = #{username} and password = #{password}")
            User select(@Param("username") String username,@Param("password")  String password);
        
      • (2)修改前端代码
        修改loign.html
        <form action="/request-demo/loginServlet" method="post" id="form">
        
      • (3)编写服务代码
        编写LoginServlet
        @WebServlet("/loginServlet")
        public class LoginServlet extends HttpServlet {
            @Override
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //1. 接收用户名和密码
                String username = request.getParameter("username");
                String password = request.getParameter("password");
        
                //2. 调用MyBatis完成查询
                //2.1 获取SqlSessionFactory对象
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
                //2.2 获取SqlSession对象
                SqlSession sqlSession = sqlSessionFactory.openSession();
                //2.3 获取Mapper
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                //2.4 调用方法
                User user = userMapper.select(username, password);
                //2.5 释放资源
                sqlSession.close();
        
        
                //获取字符输出流,并设置content type
                response.setContentType("text/html;charset=utf-8");
                PrintWriter writer = response.getWriter();
                //3. 判断user释放为null
                if(user != null){
                    // 登陆成功
                    writer.write("登陆成功");
                }else {
                    // 登陆失败
                    writer.write("登陆失败");
                }
            }
        
            @Override
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doGet(request, response);
            }
        }
        
      • (4)完成
        启动服务器测试
  3. 用户注册

    • 需求分析
      1. 用户在注册页面输入用户名和密码,提交请求给RegisterServlet
      2. 在RegisterServlet中接收请求和数据[用户名和密码]
      3. 在RegisterServlet中通过Mybatis实现调用UserMapper来根据用户名查询数据库表
      4. 将查询的结果封装到User对象中进行返回
      5. 在RegisterServlet中判断返回的User对象是否为null
      6. 如果为nul,说明根据用户名可用,则调用UserMapper来实现添加用户
      7. 如果不为null,则说明用户不可以,返回"用户名已存在"数据给前端
    • 代码实现
      • (1)编写接口(SQL语句)
        编写UserMapper提供根据用户名查询用户数据方法和添加用户方法

        @Select("select * from tb_user where username = #{username}")
        User selectByUsername(String username);
        
        @Insert("insert into tb_user values(null,#{username},#{password})")
        void add(User user);
        
      • (2)修改前端代码
        修改register.html

        <form id="reg-form" action="/request-demo/registerServlet" method="post">
        
      • (3)编写服务代码
        创建RegisterServlet类

        @WebServlet("/registerServlet")
        public class RegisterServlet extends HttpServlet {
            @Override
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //1. 接收用户数据
                String username = request.getParameter("username");
                String password = request.getParameter("password");
        
                //封装用户对象
                User user = new User();
                user.setUsername(username);
                user.setPassword(password);
        
                //2. 调用mapper 根据用户名查询用户对象
                //2.1 获取SqlSessionFactory对象
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
                //2.2 获取SqlSession对象
                SqlSession sqlSession = sqlSessionFactory.openSession();
                //2.3 获取Mapper
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        
                //2.4 调用方法
                User u = userMapper.selectByUsername(username);
        
                //3. 判断用户对象释放为null
                if( u == null){
                    // 用户名不存在,添加用户
                    userMapper.add(user);
        
                    // 提交事务
                    sqlSession.commit();
                    // 释放资源
                    sqlSession.close();
                }else {
                    // 用户名存在,给出提示信息
                    response.setContentType("text/html;charset=utf-8");
                    response.getWriter().write("用户名已存在");
                }
        
            }
        
            @Override
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doGet(request, response);
            }
        }
        
        • (4)完成
          启动服务器测试
  4. 工具类抽取

    • 问题:代码重复、资源浪费(SqlSessionFactory工厂类重复创建)

    • 编写SqlSessionFactory工具类

      public class SqlSessionFactoryUtils {
      
          private static SqlSessionFactory sqlSessionFactory;
      
          static {
              //静态代码块会随着类的加载而自动执行,且只执行一次
              try {
                  String resource = "mybatis-config.xml";
                  InputStream inputStream = Resources.getResourceAsStream(resource);
                  sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
          public static SqlSessionFactory getSqlSessionFactory(){
              return sqlSessionFactory;
          }
      }
      
    • 使用

      SqlSessionFactory sqlSessionFactory =SqlSessionFactoryUtils.getSqlSessionFactory();
      
  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值