@ResponseBody和HttpServletResponse之间的区别

文章目录


参考博文,点击这里

1.两者的区别

@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML

数据,需要注意的呢,在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。

@RequestMapping("/login")
  @ResponseBody
  public User login(User user){
    return user;
  }
  User字段:userName pwd
  那么在前台接收到的数据为:'{"userName":"xxx","pwd":"xxx"}'

  效果等同于如下代码:(由此看出,使用 ResponseBody则比较省事些)
  @RequestMapping("/login")
  public void login(User user, HttpServletResponse response){
    response.getWriter.write(JSONObject.fromObject(user).toString());
  }

理解:很多情况我们需要在controller接收请求然后返回一些message。

在springmvc中当返回值是String时,如果不加@ResponseBody的话,返回的字符串就会找这个String对应的页面,如果找不到会报404错误。
如果加上@ResponseBody注解的话,返回的就是json字符串,并且把这个json字符串返回给发送请求的原页面。

当然也有时候不加@ResponseBody注解,那么就需要我们在controller的方法中传入response参数,然后在方法里面获取response.getWriter()赋给PrintWriter。然后通过PrintWriter把这个字符串以流的形式传递给原发送请求的页面。

应用场景:页面或者js异步请求Controller,Controller不需要返回view,而只需要返回数据时,就可以使用@ResponseBody注解。@ResponseBody注解会把return 的结果放到response对象中。

只要在页面或者js中ajax指定dataType,并且在Controller上使用@ResponseBody注解来修饰,SpringMVC就会帮我们把这个Controller返回的对象转为json格式的。

若想返回一段小的字符串到页面上,可以在Controller中使用PrintWriter类,直接 out.print(字符串),此时这个java方法不需要使用@ResponseBody注解修饰,若想用@ResponseBody注解修饰,只需要在ajax中指定dataType为text。


2.http 请求响应媒体类型一览

媒体类型 含义
text/html HTML 格式
text/plain 纯文本格式
text/xml, application/xml XML 数据格式
application/json JSON 数据格式
image/gif gif 图片格式
image/png png 图片格式
application/octet-stream 二进制流数据
application/ x-www-form-urlencoded form 表单数据
multipart/form-data 含文件的 form 表单

web 开发中我们常用的提交表单操作,其默认的媒体类型就是 application/ x-www-form-urlencoded,而当表单中包含文件时,大家估计都踩过坑,需要将 enctype=multipart/form-data 设置在 form 参数中。text/html 也就是常见的网页了,json 与 xml 常用于数据交互,其他不再赘述。

而在 JAVA 中,提供了 MediaType 这样的抽象,来与 http 的媒体类型进行对应。‘/’之前的名词,如 text,application 被称为类型(type),‘/’之后被称为子类型 (subType)。

response.getWriter().write()与out.print()的区别

不同的是response.getOutputStream()向浏览器输出的是二进制数据,是字节流,可以处理任意类型的数据,而response.getWriter()输出的是字符型数据,是字符流。

1、使用OutputStream流和PrintWriter流向客户端浏览器输出中文数据

在服务器端,数据的输出码表要和控制客户端浏览器相应的码表一致,比如:outputStream.write(“中文”.getBytes(“UTF-8”));使用OutputStream流向客户端浏览器输出中文,以UTF-8的编码进行输出,此时就要控制客户端浏览器以UTF-8的编码打开,否则显示的时候就会出现中文乱码。

在服务器端如何控制客户端浏览器以以UTF-8的编码显示数据呢?

  可以通过设置响应头控制浏览器的行为,例如:response.setHeader("content-type", "text/html;charset=UTF-8");通过设置响应头控制浏览器以UTF-8的编码显示数据。

1.1使用OutputStream流向浏览器输出中文

package controller;

import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo01 extends HttpServlet {
    private static final long serialVersionUID = 1L;

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

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

        String str="使用OutputStream输出中文:我心自在";
        //在服务器设置响应头,告诉浏览器以utf-8的编码显示数据,如果不写会出现中文乱码
        response.setHeader("content-type", "text/html;charset=UTF-8");
        //获取OutputStream输出流
        OutputStream os=response.getOutputStream();
        /**
         * getBytes的作用是将字符转化为字节数组,如果不带参数,默认根据系统环境来进行转化
         * 这里指定以utf-8的编码进行转换
         */
        byte[]b=str.getBytes("utf-8");
        //想客户端(浏览器)输出数据
        os.write(b);
    }
}

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo01,运行结果如下:
@ResponseBody和HttpServletResponse之间的区别

打开浏览器调试工具,可以看到相关编码信息:
@ResponseBody和HttpServletResponse之间的区别

1.2使用PrintWriter流向浏览器输出中文

package controller;

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 ServletDemo02 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String str="使用PrintWriter输出中文:我心自在";
        //设置中文编码格式
        response.setCharacterEncoding("utf-8");
        //获取流
        PrintWriter pw=response.getWriter();
        //输出
        pw.write(str);
        pw.close();
    }

}

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo02,运行结果如下:
@ResponseBody和HttpServletResponse之间的区别

这里需要注意的是: 在获取PrintWriter输出流之前首先使用"response.setCharacterEncoding(charset)"设置字符以什么样的编码输出到浏览器,如:response.setCharacterEncoding(“UTF-8”);设置将字符以"UTF-8"编码输出到客户端浏览器,然后再使用response.getWriter();获取PrintWriter输出流,这两个步骤不能颠倒.如果颠倒,设置将无效,还是会出现中文乱码!

通过比较可以看出,当需要向浏览器输出字符数据时,使用PrintWriter比较方便,因为不需要将字符转化为字节这一步!

1、使用OutputStream流和PrintWriter流下载文件

最近在做一个项目,涉及到文件的下载,所以特意整理出来做个比较。

文件下载,在实际开发中用到的很多,最近做的项目便是,查看图片的时候,点击图片的时候进行图片下载,这里将这两个下载文件的区别做简要比较。

文件下载,运用的步骤比较固定,大致分为以下几步:

  1.获取要下载的文件的绝对路径(注意是绝对路径)

2.获取要下载的文件名(获取文件名要注意中文文件名的问题,需进行编码)

3.设置content-disposition响应头控制浏览器,告诉浏览器以下载的形式打开文件

4.获取要下载的文件输入流

5.创建数据缓冲区

6.通过response对象获取OutputStream流

7.将FileInputStream流写入到buffer缓冲区

8.使用OutputStream将缓冲区的数据输出到客户端浏览器

2.1使用OutputStream流下载中文文件

package controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

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

public class ServletDemo03 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取文件的下载绝对路径
        String downloadPath=this.getServletContext().getRealPath("/download/阳光海滩.jpg");
        //获取文件名
        String fileName=downloadPath.substring(downloadPath.lastIndexOf("\\")+1);
        //设置响应头,告诉浏览器以下载的方式打来文件,设置中文编码,如果不设置会出现乱码
         response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
        //获取文件流
         InputStream is=new FileInputStream(downloadPath);
         int len=0;
         byte[]b=new byte[1024];
         OutputStream os=response.getOutputStream();
         while((len=is.read(b))!=-1){
             //将缓冲区数据输出到浏览器
             os.write(b,0,len);
         }
         is.close();
    }

}

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo03可以成功下载图片并且可以顺利打开,
@ResponseBody和HttpServletResponse之间的区别

2.1使用PrintWriter流下载中文文件

package controller;

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;

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

public class ServletDemo03 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取文件的下载绝对路径
        String downloadPath=this.getServletContext().getRealPath("/download/阳光海滩.jpg");
        //获取文件名
        String fileName=downloadPath.substring(downloadPath.lastIndexOf("\\")+1);
        //设置响应头,告诉浏览器以下载的方式打来文件,设置中文编码,如果不设置会出现乱码
         response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
        //获取文件流
         FileReader fr=new FileReader(downloadPath);
         int len=0;
         char[] b=new char[1024];
         PrintWriter os=response.getWriter();
         while((len=fr.read(b))!=-1){
             //将缓冲区数据输出到浏览器
             os.write(b,0,len);
         }
         fr.close();
    }

}

浏览器中输入:http://localhost:8080/servlet_study/ServletDemo03可以成功下载,但是打开的过程中却出现了一下情况:
@ResponseBody和HttpServletResponse之间的区别

这是什么原因造成的呢?

  PrintWriter流处理节数据,会导致数据丢失,因此在编写下载文件功能时,要使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。

上一篇:2021-04-05


下一篇:postman 上一个接口返回值传给下一个接口token【多测师_王sir】