day10-Request&Response

一、request

咱们在上节课已经学过 对于servlet的基本使用 我们可以看到无论是在service方法中还是在doget和dopost方法中 都有两个形参 request response 那我们这节课就来学习请求和响应。

1.1 请求响应流程介绍

在这里插入图片描述

快速入门

http://localhost:8080/servlet-demo/demo1?user=zhangsan
@WebServlet("/demo1")
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //1.使用request获取请求数据
        String user = request.getParameter("user");//url?user=zhangsan
        //2.使用response将数据响应到页面中
        response.setHeader("content-type","text/html;charset=utf-8");
        response.getWriter().write("<h1>"+user+",欢迎你</h1>");
    }

1.2 Request继承体系

在学习这节内容之前,我们先思考一个问题,前面在介绍Request和Reponse对象的时候,比较细心的同学可能已经发现:

  • 当我们的Servlet类实现的是Servlet接口的时候,service方法中的参数是ServletRequest和ServletResponse
  • 当我们的Servlet类继承的是HttpServlet类的时候,doGet和doPost方法中的参数就变成HttpServletRequest和HttpServletReponse

那么,

  • ServletRequest和HttpServletRequest的关系是什么?

  • request对象是有谁来创建的?

  • request提供了哪些API,这些API从哪里查?

  • 首先,我们先来看下Request的继承体系:

    在这里插入图片描述

通过查看ServletRequest和HttpServletRequest是继承关系,并且两个都是接口,接口是无法创建对象,那么形参是由谁创建的呢?

这个时候,我们就需要用到Request继承体系中的RequestFacade:

  • 该类实现了HttpServletRequest接口,也间接实现了ServletRequest接口。
  • Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat]来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建
  • RequestFacade中实现了其接口就需要重写接口中的方法

验证RequestFacade:

@WebServlet("/demo2")
public class ServletDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(request);//org.apache.catalina.connector.RequestFacade@6158eeb4

    }

1.3 获取获取请求数据(行,头)

package com.itgaohe.web;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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.io.InputStream;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/*
* 1. 继承HttpServlet  重写doGet doPost  this.doPost()
* 2. 写映射
* 3. 写功能
*
* */
@WebServlet("/requestdemo1")
public class RequestDemo1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //一切请求由post解决
        this.doPost(req,resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        System.out.println("你来拉");
//       获取请求行里的信息   数据是由发起者(浏览器)
//        1.获取请求方式
        String method = req.getMethod();
        System.out.println("获取请求方式:"+method);
//        2.获取虚拟目录(项目访问路径):  /webservlet
        String contextPath = req.getContextPath();
        System.out.println("获取虚拟目录:"+contextPath);
//        3.获取URL(统一资源定位符):请求的网址,不是发起的页面。http://localhost:81/webservlet/requestdemo1
        StringBuffer requestURL = req.getRequestURL();
        System.out.println("获取URL(统一资源定位符):"+requestURL);
//        4. 获取URI(统一资源标识符)(更长用):/webservlet/requestdemo1
        String requestURI = req.getRequestURI();
        System.out.println("获取URI(统一资源标识符):"+requestURI);
//        获取请求头
        String header = req.getHeader("Accept-Encoding");
        System.out.println("请求头Accept-Encoding="+header);
  		 //获取请求头: user-agent: 浏览器的版本信息
        String agent = req.getHeader("user-agent");
		System.out.println(agent);
    }
}

1.4 获取获取请求数据(请求体)

在获取请求体数据的数据 我们先创建一个页面 method请求方式为post

具体实现的步骤如下:

1.准备一个页面,在页面中添加form表单,用来发送post请求

2.在Servlet的doPost方法中获取请求体数据

3.在doPost方法中使用request的getReader()或者getInputStream()来获取

4.访问页面测试

<!-- 
    action:form表单提交的请求地址
    method:请求方式,指定为post
-->

调用getReader()或者getInputStream()方法,因为目前前端传递的是纯文本数据,所以我们采用getReader()方法来获取

注意事项:

1.只能接收post请求的数据  doPost处理
2.流获取到的数据参数数据
3. 一个请求只能开启一个网络流
4.一旦使用了参数去接收数据,就不能使用流接收  getParamter方法冲突

请求体读取

/**
 * request 获取请求数据
 */
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //一切请求由post解决
        this.doPost(req,resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //获取post 请求体:请求参数
//        注意事项:
//        1.只能接收post请求的数据  doPost处理
//        2.流获取到的数据参数数据
//        3. 一个请求只能开启一个网络流
//        4.一旦使用了参数去接收数据,就不能使用流接收  getParamter方法冲突
        

//        用流的方式获取请求数据(了解):文件上传
//        字节流(上传)request.getInputStream()
//        1.1 字节流
//        InputStream is = req.getInputStream();
//        byte[] bytes = new byte[1024];
//        is.read(bytes);
//        is.close();
//        System.out.println(new String(bytes));

//		  1.2字节流(解决空格问题)
//        InputStream is = request.getInputStream();
//        字符转换流
//        InputStreamReader isr = new InputStreamReader(is, "utf-8");
//        char[] chars = new char[1024];
//        int len;
//        while ((len = isr.read(chars))!=-1){
//             line = new String(chars, 0, len);
//        }
//        System.out.println(line);
        
//        2.字符流
//		  1. 获取字符输入流
//        BufferedReader reader = req.getReader();
//        String line = reader.readLine();
//        System.out.println("readerline="+line);
    }
}

1.5 获取统一获取请求数据(请求参数)

package com.itgaohe.web;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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.io.InputStream;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/*
* 1. 继承HttpServlet  重写doGet doPost  this.doPost()
* 2. 写映射
* 3. 写功能
*
* */
@WebServlet("/requestdemo1")
public class RequestDemo1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          // 5.获取请求参数(GET方式)(做拦截会用):
        String queryString = req.getQueryString();
        System.out.println("获取请求参数(GET方式): "+queryString);
//        获取请求体 - 请求的数据
//        1.获取单个参数(重点)
        String username = req.getParameter("username");
        System.out.println("username="+username);
        String password = req.getParameter("password");
        System.out.println("password="+password);
        String hoppy = req.getParameter("hoppy");//不能拿多个数据,只能拿一个
        System.out.println("hoppy1="+hoppy);
//        3.获取一个键对应的多个数据
        String[] hoppies = req.getParameterValues("hoppy");
        System.out.println("hoppy2="+Arrays.toString(hoppies));
//        2.获取数据键值对结合
        Map<String, String[]> map = req.getParameterMap();
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
//            通过键获取值
            String[] values = map.get(key);
            for (String value : values) {
//                打印一下具体的键和值
                System.out.println("key="+key +"------" +"value="+value);
            }
        }
    }
}

1.6 IDEA快速创建模板

略。

1.7 请求参数中文乱码问题

问题展示:

(1)将req.html页面的请求方式修改为get

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/request-demo/req2" method="get">
    <input type="text" name="username"><br>
    <input type="password" name="password"><br>
    <input type="checkbox" name="hobby" value="1"> 游泳
    <input type="checkbox" name="hobby" value="2"> 爬山 <br>
    <input type="submit">

</form>
</body>
</html>

(2)在Servlet方法中获取参数,并打印

/**
 * 中文乱码问题解决方案
 */
@WebServlet("/req2")
public class RequestDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //1. 获取username
       String username = request.getParameter("username");
       System.out.println(username);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

(3)启动服务器,页面上输入中文参数

在这里插入图片描述

(4)查看控制台打印内容(乱码)

(5)把req.html页面的请求方式改成post,再次发送请求和中文参数

(6)查看控制台打印内容,依然为乱码

通过上面的案例,会发现,不管是GET还是POST请求,在发送的请求参数中如果有中文,在后台接收的时候,都会出现中文乱码的问题。具体该如何解决呢?

1.7.1 Post方式请求参数中文乱码处理

分析出现中文乱码的原因:

POST的请求参数是通过request的getReader()来获取流中的数据

TOMCAT在获取流的时候采用的编码是ISO-8859-1

ISO-8859-1编码是不支持中文的,所以会出现乱码

1.7.2 POST请求解决方案

页面设置的编码格式为UTF-8

把TOMCAT在获取流数据之前的编码设置为UTF-8

通过request.setCharacterEncoding(“UTF-8”)设置编码,UTF-8也可以写成小写

1. 解决乱码: POST getReader()

//设置字符输入流的编码,设置的字符集要和页面保持一致

   request.setCharacterEncoding("UTF-8");

重新发送POST请求,就会在控制台看到正常展示的中文结果。

至此POST请求中文乱码的问题就已经解决,但是这种方案不适用于GET请求,这个原因是什么呢,咱们下面再分析。

1.7.3 GET请求解决方案

刚才提到一个问题是POST请求的中文乱码解决方案为什么不适用GET请求?

  • GET请求获取请求参数的方式是request.getQueryString()
  • POST请求获取请求参数的方式是request.getReader()
  • request.setCharacterEncoding(“utf-8”)是设置request处理流的编码
  • getQueryString方法并没有通过流的方式获取数据

所以GET请求不能用设置编码的方式来解决中文乱码问题,那问题又来了,如何解决GET请求的中文乱码呢?

  1. 首先我们需要先分析下GET请求出现乱码的原因:

在这里插入图片描述

(1)浏览器通过HTTP协议发送请求和数据给后台服务器(Tomcat)

(2)浏览器在发送HTTP的过程中会对中文数据进行URL编码

(3)在进行URL编码的时候会采用页面<meta>标签指定的UTF-8的方式进行编码,张三编码后的结果为%E5%BC%A0%E4%B8%89

(4)后台服务器(Tomcat)接收到%E5%BC%A0%E4%B8%89后会默认按照ISO-8859-1进行URL解码

(5)由于前后编码与解码采用的格式不一样,就会导致后台获取到的数据为乱码。

思考: 如果把req.html页面的<meta>标签的charset属性改成ISO-8859-1,后台不做操作,能解决中文乱码问题么?

答案是否定的,因为ISO-8859-1本身是不支持中文展示的,所以改了标签的charset属性后,会导致页面上的中文内容都无法正常展示。

分析完上面的问题后,我们会发现,其中有两个我们不熟悉的内容就是URL编码URL解码,什么是URL编码,什么又是URL解码呢?

URL编码

这块知识我们只需要了解下即可,具体编码过程分两步,分别是:

(1)将字符串按照编码方式转为二进制

(2)每个字节转为2个16进制数并在前边加上%

张三按照UTF-8的方式转换成二进制的结果为:

1110 0101 1011 1100 1010 0000 1110 0100 1011 1000 1000 1001

这个结果是如何计算的?

使用http://www.mytju.com/classcode/tools/encode_utf8.asp,输入张三

在这里插入图片描述

就可以获取张和三分别对应的10进制,然后在使用计算器,选择程序员模式,计算出对应的二进制数据结果:

在这里插入图片描述

在计算的十六进制结果中,每两位前面加一个%,就可以获取到%E5%BC%A0%E4%B8%89

当然你从上面所提供的网站中就已经能看到编码16进制的结果了:

在这里插入图片描述

但是对于上面的计算过程,如果没有工具,纯手工计算的话,相对来说还是比较复杂的,我们也不需要进行手动计算,在Java中已经为我们提供了编码和解码的API工具类可以让我们更快速的进行编码和解码:

编码:

java.net.URLEncoder.encode("需要被编码的内容","字符集(UTF-8)")

解码:

java.net.URLDecoder.decode("需要被解码的内容","字符集(UTF-8)")

接下来咱们对张三来进行编码和解码

public class URLDemo {

  public static void main(String[] args) throws UnsupportedEncodingException {
        String username = "张三";
        //1. URL编码
        String encode = URLEncoder.encode(username, "utf-8");
        System.out.println(encode); //打印:%E5%BC%A0%E4%B8%89

       //2. URL解码
       //String decode = URLDecoder.decode(encode, "utf-8");//打印:张三
       String decode = URLDecoder.decode(encode, "ISO-8859-1");//打印:`å¼ ä¸ `
       System.out.println(decode);
    }
}

到这,我们就可以分析出GET请求中文参数出现乱码的原因了,

  • 浏览器把中文参数按照UTF-8进行URL编码
  • Tomcat对获取到的内容进行了ISO-8859-1的URL解码
  • 在控制台就会出现类上å¼ ä¸‰的乱码,最后一位是个空格
  1. 清楚了出现乱码的原因,接下来我们就需要想办法进行解决

在这里插入图片描述

从上图可以看住,

  • 在进行编码和解码的时候,不管使用的是哪个字符集,他们对应的%E5%BC%A0%E4%B8%89是一致的

  • 那他们对应的二进制值也是一样的,为:

    • 1110 0101 1011 1100 1010 0000 1110 0100 1011 1000 1000 1001
      
  • 为所以我们可以考虑把å¼ ä¸‰转换成字节,在把字节转换成张三,在转换的过程中是它们的编码一致,就可以解决中文乱码问题。

具体的实现步骤为:

1.按照ISO-8859-1编码获取乱码å¼ ä¸‰对应的字节数组

2.按照UTF-8编码获取字节数组对应的字符串

实现代码如下:

public class URLDemo {

  public static void main(String[] args) throws UnsupportedEncodingException {
        String username = "张三";
        //1. URL编码
        String encode = URLEncoder.encode(username, "utf-8");
        System.out.println(encode);
        //2. URL解码
        String decode = URLDecoder.decode(encode, "ISO-8859-1");

        System.out.println(decode); //此处打印的是对应的乱码数据

        //3. 转换为字节数据,编码
        byte[] bytes = decode.getBytes("ISO-8859-1");
        for (byte b : bytes) {
            System.out.print(b + " ");
        }
		//此处打印的是:-27 -68 -96 -28 -72 -119
        //4. 将字节数组转为字符串,解码
        String s = new String(bytes, "utf-8");
        System.out.println(s); //此处打印的是张三
    }
}

说明:在第18行中打印的数据是-27 -68 -96 -28 -72 -119张三转换成的二进制数据1110 0101 1011 1100 1010 0000 1110 0100 1011 1000 1000 1001为什么不一样呢?

其实打印出来的是十进制数据,我们只需要使用计算机换算下就能得到他们的对应关系,如下图:

在这里插入图片描述

至此对于GET请求中文乱码的解决方案,我们就已经分析完了,最后在代码中去实现下:

1.7.3 最终代码
/**
 * 中文乱码问题解决方案
 */
@WebServlet("/req4")
public class RequestDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 解决乱码:POST,getReader()
        //request.setCharacterEncoding("UTF-8");//设置字符输入流的编码

        //2. 获取username
        String username = request.getParameter("username");
        System.out.println("解决乱码前:"+username);
        
        // 解决办法1.
        // 按照"ISO-8859-1" 编码
		//String encode = URLEncoder.encode(username, "ISO-8859-1");
		//System.out.println(encode);
        // 按照"utf-8" 解码
		//String decode = URLDecoder.decode(encode, "utf-8");
		//System.out.println(decode);
        
        
        //解决办法2
        //3. GET,获取参数的方式:getQueryString
        // 乱码原因:tomcat进行URL解码,默认的字符集ISO-8859-1
       /* //3.1 先对乱码数据进行编码:转为字节数组
        byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);
        //3.2 字节数组解码
        username = new String(bytes, StandardCharsets.UTF_8);*/
username  = new String(username.getBytes(StandardCharsets.ISO_8859_1),
                       StandardCharsets.UTF_8);
        System.out.println("解决乱码后:"+username);
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

注意

  • request.setCharacterEncoding("UTF-8")代码注释掉后,会发现GET请求参数乱码解决方案同时也可也把POST请求参数乱码的问题也解决了
  • 只不过对于POST请求参数一般都会比较多,采用这种方式解决乱码起来比较麻烦,所以对于POST请求还是建议使用设置编码的方式进行。

另外需要说明一点的是Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8

1.8 小结

  1. 中文乱码解决方案
  • POST请求和GET请求的参数中如果有中文,后台接收数据就会出现中文乱码问题

    GET请求在Tomcat8.0以后的版本就不会出现了

  • POST请求解决方案是:设置输入流的编码

    request.setCharacterEncoding("UTF-8");
    注意:设置的字符集要和页面保持一致
    
  • 通用方式(GET/POST):需要先解码,再编码

    new String(username.getBytes("ISO-8859-1"),"UTF-8");
    
  1. URL编码实现方式:
  • 编码:

    URLEncoder.encode(str,"UTF-8");
    
  • 解码:

    URLDecoder.decode(s,"ISO-8859-1");
    

二、response

前面讲解完Request对象,接下来我们回到刚开始的那张图:

在这里插入图片描述

  • Request:使用request对象来获取请求数据
  • Response:使用response对象来设置响应数据

Reponse的继承体系和Request的继承体系也非常相似:

在这里插入图片描述

1.响应头行体+响应字符数据

package com.itgaohe.web;

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("/ResponseDemo1Servlet")
public class ResponseDemo1Servlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //        设置响应行--  状态码
        response.setStatus(202);
		//        设置响应头
		//      设置文本响应格式   text/html
		//  response.setHeader("content-type","text/html;charset=utf-8");
		//        处理相应数据格式的
        response.setContentType("text/html;charset=utf-8");

		//        响应数据-- 字符流响应
        response.getWriter().write("<h1>哈哈哈</h1>");
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         //一切请求由post解决
        this.doPost(request, response);
    }  
}

2.Response 响应字节数据

eg:字节流往前台刷图片

package com.itgaohe.web;

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;
import java.io.InputStream;
import java.io.OutputStream;

@WebServlet("/imgs")
public class ResponseDemo2Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//        字节流
//        OutputStream os = response.getOutputStream();
//        案例刷图片
//        图片路径-读取图片
        InputStream is = new FileInputStream("E:\\images\\a.png");
//        获取网络字节流流 - 写
        OutputStream os = response.getOutputStream();

//        一组一组的写
        byte[] bytes = new byte[1024];
        int len = -1;
        while ((len = is.read(bytes))!= -1){
            os.write(bytes,0,len);
        }
        // IOUtils.copy(is,os);

//        关闭本地流
        is.close();
//        网络流  不需要手动关闭,会在请求结束后自动关闭
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //一切请求由post解决
        this.doPost(request, response);
    }
}

导入坐标

<dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
</dependency>
 // IOUtils.copy(is,os);

3.download下载

案例:尝试把本地图片刷新到浏览器

步骤

1.创建本地流读

2.设置响应头

response.addHeader("Content-Disposition","attachment;filename="+UUID.randomUUID()+".png");

3.创建网络输出流

4.文件读写

5.关闭流

package com.itgaohe.web;

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.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

@WebServlet("/download")
public class ResponseDemo3Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//        字节流
//        OutputStream os = response.getOutputStream();

//        案例提供下载事件  filename就是下载的文件名字
        response.addHeader("Content-Disposition","attachment;filename="+ UUID.randomUUID()+".png");
//        图片路径-读取图片
        InputStream is = new FileInputStream("E:\\images\\a.png");
//        获取网络字节流流 - 写
        OutputStream os = response.getOutputStream();

//        一组一组的写
        byte[] bytes = new byte[1024];
        int len = -1;
        while ((len = is.read(bytes))!= -1){
            os.write(bytes,0,len);
        }
//        关闭本地流
        is.close();
//        网络流  不需要手动关闭,会在请求结束后自动关闭
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //一切请求由post解决
        this.doPost(request, response);
    }
}

三、请求转发重定向

3.1请求转发

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

在这里插入图片描述

(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求

(2)资源A处理完请求后将请求发给资源B

(3)资源B处理完后将结果响应给浏览器

(4)请求从资源A到资源B的过程就叫请求转发

@WebServlet("/AServlet")
public class AServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("我没有300块");
//        请求转发
//        特点:
//        1.浏览器地址栏路径不发生变化
//        2.不可以请求其他服务器 只能转发到当前服务器的内部资源   http://www.baidu.com
//        3. 性能比较快 一次请求,可以在转发的资源间使用request共享数据
        request.setAttribute("username","张三");
        request.getRequestDispatcher("BServlet").forward(request,response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //一切请求由post解决
        this.doGet(request, response);
    }
}
@WebServlet("/BServlet")
public class BServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("我有300块");
	    Object username = request.getAttribute("username");
        System.out.println(username);
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("我可以借给你300块");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //一切请求由post解决
        this.doGet(request, response);
    }
}

在这里插入图片描述

3.2 重定向

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

在这里插入图片描述

(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求

(2)资源A现在无法处理该请求,就会给浏览器响应一个302的状态码+location的一个访问资源B的路径

(3)浏览器接收到响应状态码为302就会重新发送请求到location对应的访问地址去访问资源B

(4)资源B接收到请求后进行处理并最终给浏览器响应结果,这整个过程就叫重定向

@WebServlet("/CServlet")
public class CServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("我没有300块,D有300块,你自己去找");
//        response.setStatus(302);
//        response.setHeader("location","DDServlet");
//        System.out.println("我来!");
        
        
//        重定向
//        特点:1. 浏览器地址栏路径发生变化
//        2. 可以重定向到任意位置的资源(服务器内部、外部均可)
//        3. 性能较差 两次请求,不能在多个资源使用request共享数据
//         4.绝对路径/DServlet    端口号后面的项目名会省略  http://localhost:81/DServlet
         
          response.sendRedirect("DDServlet");
//        response.sendRedirect("/webservlet/DServlet");
        
//        response.sendRedirect(request.getContextPath()+"/DServlet");
          
//        response.sendRedirect("https://www.baidu.com");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //一切请求由get解决
        this.doGet(request, response);
    }
}

Dservlet

@WebServlet("/DServlet")
public class DServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("我有300块");

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("我可以借给你300块");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //一切请求由post解决
        this.doGet(request, response);
    }
}

3.3 重定向和请求转发对比

在这里插入图片描述

3.4 路径问题

问题导入:项目名称路径!什么时候加什么时候不加?

请求转发不需要加 重定向在使用绝对路径的时候需要加虚拟路径 在使用相对路径的时候则不需要加 此时不能加/

  1. 问题1:转发的时候路径上没有加/request-demo而重定向加了,那么到底什么时候需要加,什么时候不需要加呢?

在这里插入图片描述

其实判断的依据很简单,只需要记住下面的规则即可:

  • 浏览器使用:需要加虚拟目录(项目访问路径)
  • 服务端使用:不需要加虚拟目录

对于转发来说,因为是在服务端进行的,所以不需要加虚拟目录

对于重定向来说,路径最终是由浏览器来发送请求,就需要添加虚拟目录。

掌握了这个规则,接下来就通过一些练习来强化下知识的学习:

  • <a href='路劲'>
  • <form action='路径'>
  • req.getRequestDispatcher(“路径”)
  • resp.sendRedirect(“路径”)

答案:

1.超链接,从浏览器发送,需要加
2.表单,从浏览器发送,需要加
3.转发,是从服务器内部跳转,不需要加
4.重定向,是由浏览器进行跳转,需要加。
  1. 问题2:在重定向的代码中,/request-demo是固定编码的,如果后期通过Tomcat插件配置了项目的访问路径,那么所有需要重定向的地方都需要重新修改,该如何优化?

在这里插入图片描述

答案也比较简单,我们可以在代码中动态去获取项目访问的虚拟目录,具体如何获取,我们可以借助前面咱们所学习的request对象中的getContextPath()方法,修改后的代码如下:

@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("resp1....");

        //简化方式完成重定向
        //动态获取虚拟目录
        String contextPath = request.getContextPath();
        response.sendRedirect(contextPath+"/resp2");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

重新启动访问测试,功能依然能够实现,此时就可以动态获取项目访问的虚拟路径,从而降低代码的耦合度。

四、请求和响应API小结

请求API

String getMethod()获取请求方式: GET
String getContextPath()获取虚拟目录(项目访问路径): /request-demo
StringBuffer getRequestURL()获取URL(统一资源定位符): http://localhost:8080/request-demo/req1
String getRequestURI()获取URI(统一资源标识符): /request-demo/req1
String getQueryString()获取请求参数(GET方式): username=zhangsan&password=123
String getHeader(String name)获取请求头信息
ServletInputStream getInputStream()获取字节流(一般用于上传功能)(只能接收处理post请求)
BufferedReader getReader()获取字符流(只能接收处理post请求)
req.getRequestDispatcher(“资源B路径”).forward(req,resp);请求转发

响应API

void setStatus(int sc);设置状态码
void setHeader(String name,String value);设置响应头键值对:
PrintWriter getWriter();获取字节输出流(一般输出文本)
ServletOutputStream getOutputStream();获取字符输出流(一般输出文件)
sendRedirect(“路径”);重定向
setContentType(“text/html;charset=utf-8”);设置响应数据格式:html并且utf-8编码
addHeader(“Content-Disposition”,“attachment;filename=a.png”);文件下载格式必须设置响应头信息

五、登录注册

需求分析

在这里插入图片描述

  1. 用户在登录页面输入用户名和密码,提交请求给LoginServlet
  2. 在LoginServlet中接收请求和数据[用户名和密码]
  3. 在LoginServlt中通过Mybatis实现调用UserMapper来根据用户名和密码查询数据库表
  4. 将查询的结果封装到User对象中进行返回
  5. 在LoginServlet中判断返回的User对象是否为null
  6. 如果为nul,说明根据用户名和密码没有查询到用户,则登录失败,返回"登录失败"数据给前端
  7. 如果不为null,则说明用户存在并且密码正确,则登录成功,返回"登录成功"数据给前端
环境准备
准备须知:
1.创建模块weblogin
2.补全目录、pom修改打包方式war、pom配置tomcat依赖、servlet依赖
3.把前端工程师开发的页面导入
4.搭建数据环境建库导入数据
5.搭建mybatis环境---test测试一下环境是否ok
	5.1 mybatis依赖、数据库依赖、(日志依赖可以有)、junit
	5.2 mybatis核心配置文件
	5.3 mybatis工厂工具类
	5.4 mybatis接口
    5.5 junit测试
6.写功能
	6.1 写数据库查询sql mapper层
	6.2 写servlet接收用户的登录信息类
	6.3 页面表单请求路径配置
7.测试功能

环境准备============

  • 项目目录

    在这里插入图片描述

  • pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.itgaohe</groupId>
        <artifactId>weblogin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <!--1-->
        <packaging>war</packaging>
        <!--3-->
        <dependencies>
            <!--servlet-->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.46</version>
            </dependency>
            <!--mybatis-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.5</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13</version>
            </dependency>
        </dependencies>
    
        <!--2-->
        <build>
            <plugins>
            <!--Tomcat插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!--端口号-->
                    <port>81</port>
                    <!--项目访问路径-->
                    <path>/weblogin</path>
                </configuration>
            </plugin>
            </plugins>
        </build>
    </project>
    
  • 页面略参考资料

  • 数据库sql

    -- 创建用户表
    CREATE TABLE tb_user(
    	id INT PRIMARY KEY AUTO_INCREMENT,
    	username VARCHAR(20) UNIQUE,
    	PASSWORD VARCHAR(32)
    );
    
    -- 添加数据
    INSERT INTO tb_user(username,PASSWORD) VALUES('zhangsan','123'),('lisi','234');
    
    SELECT * FROM tb_user;
    
  • pojo略

  • mybatis核心

    <?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.itgaohe.pojo"/>
        </typeAliases>
    
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///login?useSSL=false&amp;useServerPrepStmts=true"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <!--扫描mapper-->
            <package name="com.itgaohe.mapper"/>
        </mappers>
    </configuration>
    
  • mybatis工具类

    package com.itgaohe.util;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class MybatisUtil {
    
    //    获取sqlsession
        public static SqlSession getSqlSession(){
            InputStream is = null;
            SqlSessionFactory sqlSessionFactory = null;
            SqlSession sqlSession = null;
            try {
    //        读取mybatis核心配置文件
                is = Resources.getResourceAsStream("mybatis-config.xml");
    //        解析流获取工厂
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    //        获取sqlSession
                sqlSession = sqlSessionFactory.openSession();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return sqlSession;
        }
    }
    
  • UserMapper接口

    package com.itgaohe.mapper;
    
    import com.itgaohe.pojo.User;
    import org.apache.ibatis.annotations.Select;
    
    import java.util.List;
    
    public interface UserMapper {
    
        @Select("select * from tb_user")
        List<User> findAll();
    
    }
    
  • mapper测试

    import com.itgaohe.mapper.UserMapper;
    import com.itgaohe.pojo.User;
    import com.itgaohe.util.MybatisUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import java.util.List;
    public class UserTest {
        @Test
        public void test(){
    
            SqlSession sqlSession = MybatisUtil.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> all = mapper.findAll();
            System.out.println(all);
        }
    }
    

----------环境准备搞定了。---------

login

  • mapper

    @Select("select * from tb_user where username = #{username} and password = #{password}")
    User findByUsernameAndPassword(@Param("username") String username,
                                   @Param("password") String password);
    
  • service

    package com.itgaohe.service;
    import com.itgaohe.pojo.User;
    public interface UserService {
    //    login接口
        User login(String username,String password);
    }
    
package com.itgaohe.service.impl;

import com.itgaohe.mapper.UserMapper;
import com.itgaohe.pojo.User;
import com.itgaohe.service.UserService;
import com.itgaohe.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;

public class UserServiceImpl implements UserService {
    public User login(String username, String password) {

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User u = mapper.findByUsernameAndPassword(username, password);

        return u;
    }
}
  • 页面请求路径

  • loginServlet

    package com.itgaohe.web;
    
    import com.itgaohe.mapper.UserMapper;
    import com.itgaohe.pojo.User;
    import com.itgaohe.service.impl.UserServiceImpl;
    import com.itgaohe.util.MybatisUtil;
    import org.apache.ibatis.session.SqlSession;
    
    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;
    /*
    * //        1. 接收用户名和密码
    //        2. 调用mapper查询数据库拿到结果
    //        3. 判断User对象是否为null
    //           3.1 null 登录失败
    //           3.2 登录成功
    * */
    @WebServlet("/loginServlet")
    public class LoginServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //        乱码处理
            request.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=utf-8");
    
    //        1. 接收用户名和密码==页面中的name对应
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            System.out.println(username+"---"+password);
    
    //        2. 调用mapper查询数据库拿到结果
            UserServiceImpl userService = new UserServiceImpl();
            User u = userService.login(username,password);
    
    //        3. 判断User对象是否为null
            if (u == null){
    //           3.1 null 登录失败
                response.getWriter().write("登录失败:用户名或者密码错误!");
            }else {
    //           3.2 登录成功
                response.getWriter().write("登录成功!");
            }
        }
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //一切请求由post解决
            this.doPost(request, response);
        }
    }
    

register

  • mapper

    //    添加用户
        @Insert("insert into tb_user values(null,#{username},#{password})")
        int save(User user);
    
  • service

    //    注册
        int register(String username,String password);
    
    public int register(String username, String password) {

        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//        封装数据
        User u = new User();
        u.setUsername(username);
        u.setPassword(password);

        int save = mapper.save(u);
//        事务提交
        sqlSession.commit();

        return save;
    }
  • 和页面对应好registerServlet

  • registerServlet

    package com.itgaohe.web;
    
    import com.itgaohe.service.impl.UserServiceImpl;
    
    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;
    
    /**
     * 
     * 1. 接收数据
     * 2. 调用业务层实现功能
     * 3. 响应结果!
     * 
     */
    @WebServlet("/registerServlet")
    public class RegisterServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            request.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=utf-8");
    //        1.接收数据
            String username = request.getParameter("username");
            String password = request.getParameter("password");
    //        2. 调用业务层
            UserServiceImpl userService = new UserServiceImpl();
            int register = userService.register(username, password);
    //        3.响应
            if(register >0){
                response.getWriter().write("注册成功");
            }else {
                response.getWriter().write("注册失败");
            }
        }
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //一切请求由post解决
            this.doPost(request, response);
        }
    }
    

测试

  • 请求路径重点关注
  • 请求参数名

在这里插入图片描述

能力目标

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;

/**
*

    1. 接收数据
    1. 调用业务层实现功能
    1. 响应结果!

*/
@WebServlet(“/registerServlet”)
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding(“utf-8”);
response.setContentType(“text/html;charset=utf-8”);
// 1.接收数据
String username = request.getParameter(“username”);
String password = request.getParameter(“password”);
// 2. 调用业务层
UserServiceImpl userService = new UserServiceImpl();
int register = userService.register(username, password);
// 3.响应
if(register >0){
response.getWriter().write(“注册成功”);
}else {
response.getWriter().write(“注册失败”);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//一切请求由post解决
this.doPost(request, response);
}
}


测试

- 请求路径重点关注
- 请求参数名

[外链图片转存中...(img-QrWk83d9-1719719080896)]





# 能力目标

- 登录注册功能!
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UA_StatusCode OpcuaClient::ReadCNCValue(CString dataCategory,CNCStruct* m_pCncstruct) { const int arraySize = 7; UA_ReadValueId CNC_itemArray[arraySize]; for (int i = 0; i < arraySize; ++i) { UA_ReadValueId_init(&CNC_itemArray[i]); CNC_itemArray[i].attributeId = UA_ATTRIBUTEID_VALUE; } CNC_itemArray[0].nodeId = UA_NODEID_STRING(2, "不知道是哪一个变量);//cncType CNC_itemArray[1].nodeId = UA_NODEID_STRING(2, "/Channel/Configuration/numSpindles");//主轴数 CNC_itemArray[2].nodeId = UA_NODEID_STRING(2, "/Channel/Configuration/numGeoAxes");//伺服轴数 CNC_itemArray[3].nodeId = UA_NODEID_STRING(2, "/Channel/ProgramInfo/progName");//程序名称 CNC_itemArray[4].nodeId = UA_NODEID_STRING(2, "/Channel/Spindle/status");//运行状态 CNC_itemArray[5].nodeId = UA_NODEID_STRING(2, "/Channel/MachineAxis/actFeedRate");//进给速度 CNC_itemArray[6].nodeId = UA_NODEID_STRING(2, "/Channel/Spindle/actSpeed");//主轴转速 //读数据 UA_ReadRequest request; UA_ReadRequest_init(&request); request.nodesToRead = &valueIdCategory[0]; request.nodesToReadSize = arraySize; UA_ReadResponse response = UA_Client_Service_read(m_Client, request); UA_StatusCode *retStatusArray=NULL; UA_StatusCode retval = response.responseHeader.serviceResult; if (retval == UA_STATUSCODE_GOOD) { if (response.resultsSize == arraySize) { for (int i = 0; i < arraySize; ++i) { retStatusArray[i] = response.results[i].status; } } else { UA_ReadResponse_clear(&response); return UA_STATUSCODE_BADUNEXPECTEDERROR; } } //按顺序存储plc的节点值 vector<void*> cncNodeValue; for (int i = 0; i < arraySize; ++i) { if (retStatusArray[i] == UA_STATUSCODE_GOOD) { UA_DataValue res = response.results[i]; if (!res.hasValue) // no value { UA_ReadResponse_clear(&response); return UA_STATUSCODE_BADUNEXPECTEDERROR; } UA_Variant out; memcpy(&out, &res.value, sizeof(UA_Variant)); UA_Variant_init(&res.value); if (out.type == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) { UA_LocalizedText* ptr = (UA_LocalizedText*)out.data; printf("Text: %.*s\n", ptr->text.length, ptr->text.data); cncNodeValue.push_back(ptr->text.data); } else if (out.type == &UA_TYPES[UA_TYPES_UINT64]) { UA_UInt64* ptr = (UA_UInt64*)out.data; printf("UInt64 Value: %d\n", *ptr); cncNodeValue.push_back(ptr); } else if (out.type == &UA_TYPES[UA_TYPES_UINT32]) { UA_UInt32* ptr = (UA_UInt32*)out.data; printf("UInt32 Value: %d\n", *ptr); cncNodeValue.push_back(ptr); } else if (out.type == &UA_TYPES[UA_TYPES_FLOAT]) { UA_Float* ptr = (UA_Float*)out.data; printf("Float Value: %d\n", *ptr); cncNodeValue.push_back(ptr); } else if (out.type == &UA_TYPES[UA_TYPES_DATETIME]) { UA_DateTime* ptr = (UA_DateTime*)out.data; UA_DateTimeStruct ptrdts = UA_DateTime_toStruct(*ptr); printf("DateTime Value: %u-%u-%u %u:%u:%u.%03u\n", ptrdts.day, ptrdts.month, ptrdts.year, ptrdts.hour, ptrdts.min, ptrdts.sec, ptrdts.milliSec); cncNodeValue.push_back(ptr); } } } //问题三:数据如何处理成人可读或者可显示的形式?? UA_ReadResponse_clear(&response); return UA_STATUSCODE_GOOD; }
02-06

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值