Web---字节输出流和字符输出流的共存问题、转发、重定向、请求包含知识点讲解

本章博客的知识点:

1、字节输出流和字符输出流的共存问题
2、转发时,两个servlet都输出信息的问题
详细知识,见OneServlet和TwoServlet源代码中的注释
转发:传参,访问顺序(doGet还是doPost)
3、重定向:传参,访问顺序(doGet还是doPost)
4、请求包含:传参,访问顺序(doGet还是doPost)

有些演示,不怎么好分段用博客写处理,如果想加深理解的,最好自己取写一遍。

1、字节输出流和字符输出流的共存问题

index.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>

<body>
    <!--   1、字节输出流和字符输出流的共存问题---不能共存(跟get或post方式没关系)。即

        :在同一个servlet响应中,不能同时采两种输出流。
        另外:如果要用字节流输出中文,用write(byte[])方法 -->
    <a href="servlet/OutServlet">字节输出流和字符输出流的共存问题</a>
    <form action="servlet/OutServlet" method="post">
        <input type="text" name="name" /><br />
        <input type="submit"value="提交" />
    </form>

</body>
</html>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>
  <servlet>
    <servlet-name>OutServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.OutServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>OutServlet</servlet-name>
    <url-pattern>/servlet/OutServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

OutServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class OutServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        //1、用字节输出流向客户端写信息
        ServletOutputStream out = response.getOutputStream();//获取字节输出流

        out.print("HELLO--doGet");//全部写英文是没有问题的
        //out.print("你好");//500错误。出异常,因为内部是用iso8859-1读取,已经写死了,因此中文不行
        out.write("你好".getBytes("utf-8"));//如果中文要用字节流输出,用write(byte[])方法,而且最好给编码方式

        //2、同时用字符输出流向客户端写信息-也是出现500错误。
        PrintWriter out2 = response.getWriter();
        out2.print("hello,你好");

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //1、用字节输出流向客户端写信息
        ServletOutputStream out = response.getOutputStream();//获取字节输出流

        out.print("HELLO--doGet");//全部写英文是没有问题的
        //out.print("你好");//500错误。出异常,因为内部是用iso8859-1读取,已经写死了,因此中文不行
        out.write("你好".getBytes("utf-8"));//如果中文要用字节流输出,用write(byte[])方法,而且最好给编码方式

        //2、同时用字符输出流向客户端写信息-也是出现500错误。
        PrintWriter out2 = response.getWriter();
        out2.print("hello,你好");

    }

}

小总结:

大家自己写的时候,注意知道把哪里注释了,同时写了response.getOutputStream();//获取字节输出流和response.getWriter();-是不能共存的,也就是说,只能写其中一个!!!

2、转发时,两个servlet都输出信息的问题、传参,访问顺序(doGet还是doPost)

详细知识,见OneServlet和TwoServlet源代码中的注释

index.jsp:

    <a href="servlet/OneServlet">转发时,两个servlet都输出信息的问题、传参问题、访问顺序问题</a><br />
    <form action="servlet/OneServlet" method="post">
        <input type="text" name="name" /><br />
        <input type="submit"value="提交" />
    </form>

web.xml:

<servlet>
    <servlet-name>OneServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.OneServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>TwoServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.TwoServlet</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>OneServlet</servlet-name>
    <url-pattern>/servlet/OneServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>TwoServlet</servlet-name>
    <url-pattern>/servlet/TwoServlet</url-pattern>
  </servlet-mapping>    

OneServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class OneServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("你好...OneServlet...");

        //out.flush();
//Tomcat对于同response,只输出一次(把缓存中的内容刷出去)。刷了(close也一样),流就关闭了,下面的转发就无法进行了,因为此时response已经提交了(整个转发链只会响应一次,即提交了)

        //传参---设置属性(只要key不同,随便存几个)---放入request对象中
        request.setAttribute("age", "23-OneServlet");

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/TwoServlet");
        rd.forward(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("你好...OneServlet...");

        //out.flush();
//Tomcat对于同response,只输出一次(把缓存中的内容刷出去)。刷了(close也一样),流就关闭了,下面的转发就无法进行了,因为此时response已经提交了(整个转发链只会响应一次,即提交了)

        //传参---设置属性(只要key不同,随便存几个)---放入request对象中
        request.setAttribute("age", "23-OneServlet");

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/TwoServlet");
        rd.forward(request, response);

    }

}

TwoServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TwoServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");//如果前一个转发过来的Servlet已经设了,可以不用再写

        PrintWriter out = response.getWriter();
        out.println("get...<br/>");
        out.print("周末愉快。。。<br/>");
        //第二个servlet会先把缓存中之前的内容情空,然后再把当前servlet的输出内容写入缓存,刷出去。

        String name = (String) request.getAttribute("age");
        out.print("name:"+name+"<br/>");
        out.flush();//写在这里是没有什么影响的

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");//如果前一个转发过来的Servlet已经设了,可以不用再写

        PrintWriter out = response.getWriter();
        out.println("post...<br/>");
        out.print("周末愉快。。。<br/>");
        //第二个servlet会先把缓存中之前的内容情空,然后再把当前servlet的输出内容写入缓存,刷出去。

        String name = (String) request.getAttribute("age");
        out.print("name:"+name+"<br/>");
        out.flush();//写在这里是没有什么影响的

    }

}

小总结:

转发时,两个servlet都输出信息的问题
详细知识,见OneServlet和TwoServlet源代码中的注释
传参,访问顺序(doGet还是doPost) —转发是共享同一个request和同一个response对象的
1)第一个是doGet,第二个走的也是doGet
2)第一个是doPost,第二个走的也是doPost
(因为request传过来的参数一样,访问方式也是一样的)
3)传参:可以通过request.setAttribute()设置,通过request.getAttribute()获取 —doGet或doPost都一样

3、重定向:传参,访问顺序(doGet还是doPost)

index.jsp:

<a href="servlet/RedirOneServlet">重定向时,两个servlet都输出信息的问题、传参问题、访问顺序问题</a><br />
    <form action="servlet/RedirOneServlet" method="post">
        <input type="text" name="name" /><br />
        <input type="submit"value="提交" />
    </form>

web.xml:

<servlet>
    <servlet-name>RedirOneServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.RedirOneServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>RedirTwoServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.RedirTwoServlet</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>RedirOneServlet</servlet-name>
    <url-pattern>/servlet/RedirOneServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>RedirTwoServlet</servlet-name>
    <url-pattern>/servlet/RedirTwoServlet</url-pattern>
  </servlet-mapping>

RedirOneServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RedirOneServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("11111111111");//这是一个无效的输出,我们看不到!!

        response.sendRedirect("/myServletDemo4/servlet/RedirTwoServlet");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("11111111111");//这是一个无效的输出,我们看不到!!
        //out.flush();
        //如果刷了,后面就不能故去了。
        String name = request.getParameter("name");
        System.out.println("11111para-name:"+name);//这个也只有这里能接收到,如果想要传过去,得通过 地址栏+?+name= 的方式,如最后一行
        request.setAttribute("age", 23);//这一句是没用的,对方收不到!

        //response.sendRedirect("/myServletDemo4/servlet/RedirTwoServlet");
        response.sendRedirect("/myServletDemo4/servlet/RedirTwoServlet?name="+name+"&age=23");
    }

}

RedirTwoServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RedirTwoServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("doget........22222222<br/>");

        String name = request.getParameter("name");
        out.print("2222para-name:"+name);
        String age = request.getParameter("age");
        out.print("<br/>2222para-age:"+age);
        //得到地址栏?号后的属性值

        Integer age2 = (Integer) request.getAttribute("age");
        out.print("<br>attr-age:"+age2);//null. web.xml 中没有设置

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("doget........22222222<br/>");
    }

}

小总结:

两个servlet都输出信息的问题,这里和转发的情况其实可以理解是相同的,你第一个servlet如果out调用flush(),一样的,不会再重定向到后面的第二个servlet中去了。

1)无论第一个是doGet还是doPost,第二个走的都是doGet
(可以理解成:通过地址栏访问的)
2)传参:第二个servlet中的request和第一个是完全不同的对象,因此无法通过:request.setAttribute()和request.getAttribute() 实现传参。

3)第二个servlet中是无法通过request.getParameter()的方式获取页面提交的参数数据

4)重定向方式下,如果要进行传参,可采用:在地址栏的url后添加类似如下的格式传参:?name=Jack&age=23

注意,采用地址栏url传参的方式,在浏览器地址栏是能够看到的,因此要注意隐私(安全)问题—如果有隐私参数,那么要加密!!!
5)转发只能在站内进行(路径默认在项目内,即路径不用带项目名),重定向可以在站外进行(如果是站外路径要带“http://”开头,站内路径要带项目名)。如果非要项目之间(站外)进行跳转,那么必须要选择重定向。

4、请求包含:传参,访问顺序(doGet还是doPost)

index.jsp:

<a href="servlet/IncludeOneServlet">请求包含时,两个servlet都输出信息的问题、传参问题、访问顺序问题</a><br />
    <form action="servlet/IncludeOneServlet" method="post">
        <input type="text" name="name" /><br />
        <input type="submit"value="提交" />
    </form>

web.xml:

 <servlet>
    <servlet-name>IncludeOneServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.IncludeOneServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>IncludeTwoServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.IncludeTwoServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>IncludeOneServlet</servlet-name>
    <url-pattern>/servlet/IncludeOneServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>IncludeTwoServlet</servlet-name>
    <url-pattern>/servlet/IncludeTwoServlet</url-pattern>
  </servlet-mapping>    

IncludeOneServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IncludeOneServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("<html><body>");
        out.print("Include111111..doGet...");

        //传参,和转发时一样的!
        request.setAttribute("age", 25);

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/IncludeTwoServlet");
        rd.include(request, response);
        //它的机制可理解成函数调用。相当于把第二个servlet的doGet()方法中的代码拷到这里来运行。

        //后面的还可以继续运行!!!
        out.print("<br/>Include11111...daGet...请求包含之后!");

        out.print("</body></html>");

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("<html><body>");
        out.print("Include111111..doPost...");

        //传参,和转发时一样的!
        request.setAttribute("age", 25);

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/IncludeTwoServlet");
        rd.include(request, response);
        //它的机制可理解成函数调用。相当于把第二个servlet的doPost()方法中的代码拷到这里来运行。

        //后面的还可以继续运行!!!
        out.print("<br/>Include11111...doPost...请求包含之后!");

        out.print("</body></html>");

    }

}

IncludeTwoServlet.java

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IncludeTwoServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        //因为上一个servlet已经设过,这里可以不设
        PrintWriter out = response.getWriter();
        //out.print("<html><body>");

        out.print("<br/>Include222222中文...doGet");

        //接参
        Integer age = (Integer) request.getAttribute("age");

        out.print("<br/>Include222222...doGet...:"+age);

        //下面这两句会导致无穷递归
        //RequestDispatcher rd = request.getRequestDispatcher("/servlet/IncludeOneServlet");
        //rd.include(request, response);

        //out.print("</body></html>");

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //因为上一个servlet已经设过,这里可以不设
        PrintWriter out = response.getWriter();
        //

        out.print("<br/>Include222222中文...doPost");

        //接参
        Integer age = (Integer) request.getAttribute("age");

        out.print("<br/>Include222222...doPost...:"+age);

    }

}

小总结:

1)两个servlet的输出都有效!—中途调用flush,流不会关闭,后续的输出都会执行。如果在第一个servlet中执行了out.close(),那么后续的输出(无论是第一还是第二个servlet)都不会执行,但程序不会出异常!!!!
2)第一个是doGet,第二个走的也是doGet
3)第一个是doPost,第二个走的也是doPost
4)对于请求包含,第二个servlet在执行完之后,还会回到第一个servlet的rd.include()这行代码之后。
5)传参方面,和转发是完全一样的,因为都是共享同一个request和同一个response.
6)页面输出时,注意html标签不要输出冲突,如:在第一个servlet中输出了“<html><body>”和“</body></html>”,同时在第二个servlet中也输出这些标记。这样会出现html标记嵌套冲突!!
※重定向和转发:跳转之后不会回到原来的那个servlet中。
而“请求转发”在跳转之后会回到原来servlet的“rd.include()”这句代码之后继续执行。

演示:

可以看到,客户端只请求了一次!!!转发是请求两次的。

如果2个服务器都向客户端输出了<html><body> </body></html>

会出现:

时间: 2024-09-26 16:42:49

Web---字节输出流和字符输出流的共存问题、转发、重定向、请求包含知识点讲解的相关文章

两个不同字符编码的java web网站交互中文字符如何处理乱码?

问题描述 两个不同字符编码的java web网站交互中文字符如何处理乱码? 例如:从GBK编码的网站提交中文字符到UTF-8编码的网站,接收到的中文就是乱码,怎么解决乱码问题? 解决方案 进行编码转换http://www.sharejs.com/codes/java/5422 解决方案二: 在UTF-8的页面先对GBK的字符串进行转码,具体转码方法太多了,就不一一介绍了

字节流转成字符流(串) 乱码

问题描述 word字节流转成字符串会出现乱码,解决不了,各种编码都试过了,只能班.保存到本地.. 解决方案 解决方案二:啥意思???-解决方案三:就是读取word的字节流不能转成string字符串

web开发如何防止用户自己直接用url来自己请求

问题描述 web开发如何防止用户自己直接用url来自己请求 我用的是struts....然后遇到一个问题....如果让用户知道了请求url以及参数.他 完全可以直接用请求来访问,...当然,我已经过滤掉了所谓的get请求了...但问题来了 ,如果用户自己写一个form表单来实现post请求....这该怎么办... 解决方案 用户的访问权限过滤器,防止用户直接输入URL直接访问资源. 解决方案二: 都有机器人了.... 解决方案三: 好比那些自动注册机,也是 post请求,获取验证码,这好像有点难

详解Java中ByteArray字节数组的输入输出流的用法_java

ByteArrayInputStream 介绍ByteArrayInputStream 是字节数组输入流.它继承于InputStream. 它包含一个内部缓冲区,该缓冲区包含从流中读取的字节:通俗点说,它的内部缓冲区就是一个字节数组,而ByteArrayInputStream本质就是通过字节数组来实现的. 我们都知道,InputStream通过read()向外提供接口,供它们来读取字节数据:而ByteArrayInputStream 的内部额外的定义了一个计数器,它被用来跟踪 read() 方法

高性能linux web集群搭建详细步骤 可达每秒百万请求

本文教程比较详细,可以说是手把手,所以如果你有这个需求而无从下手,请放点耐心阅读 如何生成每秒百万级别的 HTTP 请求? 负载生成工具(Load-Generating Tools) 在进行负责测试时要牢记一件重要的事:你能在 Linux 上建立多少个 socket 连接.这个限制是硬编码在内核里的,最典型的就是临时 W 端口的限制.(在某种程度上)你可以在 /etc/sysctl.conf 里扩展它.但是基本上,一台 Linux 机器只能同时打开大约 64,000 个 socket .因此在负

PostgreSQL 中如何找出记录中是否包含编码范围内的字符,例如是否包含中文

标签 PostgreSQL , 是否含有中文 背景 从已有字符串内容中找出含有中文,或者找出含有单字节字符的记录. 方法要从字符串在数据库中的编码和存储说起.比如多字节字符集,单字节字符SQL_ASCII. 比如PostgreSQL中UTF8, EUC_CN属于多字节字符集,编码为变长编码. SQL_ASCII为无编码字符集,存储为字节流. 要从不同字符集中找出含有中文的记录,该怎么找? 测试环境 已有数据库如下,注意编码 postgres=# \l List of databases Name

ORACLE自带的JDBC源代码解析

oracle|源代码         大凡使用过JDBC连ORACLE的人都会知道这样一个事实:我们需要的库文件classes12.zip存在于$ORACLE_HOME/jdbc/lib目录下(但仍有部分菜鸟每每在论坛上求此库文件,真是辛苦):但很少有人知道ORACLE还为我们准备了使用jdbc的示例,它存在于 $ORACLE_HOME/jdbc/demo/demo.zip 中.        前一段时间,我学习ORACLE的OOP技术,很受触动.当时我想:JDBC中一定存在某些OO技术以支持它

请求转发和请求包含

1.Servlet 容器 编程中的容器我们可以理解为程序运行时需要的环境,那么Tomcat 就是Servlet 的运行环境,就是一个Servlet 容器.Servlet 容器的作用是负责处理客户请求,当Servlet 容器获取到用户请求后,调用某个Servlet,并把Servlet 的执行结果返回给用户.  Servlet 容器的工作流程: ● 当用户请求某个资源时,Servlet 容器使用ServletRequest 对象将用户的请求信息封装起来,然后调用 java Servlet API 中

java io学习(二十三) BufferedWriter(字符缓冲输出流)

BufferedWriter 介绍 BufferedWriter 是缓冲字符输出流.它继承于Writer. BufferedWriter 的作用是为其他字符输出流添加一些缓冲功能. BufferedWriter 函数列表 // 构造函数 BufferedWriter(Writer out) BufferedWriter(Writer out, int sz) void close() // 关闭此流,但要先刷新它. void flush() // 刷新该流的缓冲. void newLine()