2 处理器方法的返回值

使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:

➢ 第一种:ModelAndView
➢ 第二种:String
➢ 第三种:无返回值 void
➢ 第四种:返回自定义类型对象

根据不同的情况,使用不同的返回值。

SpringMVC 返回对象报错 springmvc处理返回值_ajax

1返回 ModelAndView前几篇博客就是返回ModelAndView

若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。当然,若要返回 ModelAndView,则处理器方法中需要定义 ModelAndView 对象。

在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将总是有一部分多余:要么 Model 多余,要么 View 多余。即此时返回 ModelAndView 将不合适。

2.返回 String

处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址

返回内部资源逻辑视图名

若要跳转的资源为内部资源,则视图解析器可以使用 InternalResourceViewResolver 内部资源视图解析器。此时处理器方法返回的字符串就是要跳转页面的文件名去掉文件扩展名后的部分。这个字符串与视图解析器中的 prefix、suffix 相结合,即可形成要访问的 URI。

<!--声明 springmvc框架中的视图解析器, 帮助开发人员设置视图文件的路径-->
    <bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀:视图文件的路径-->
        <property name="prefix" value="/WEB-INF/view/" />
        <!--后缀:视图文件的扩展名-->
        <property name="suffix" value=".jsp" />
    </bean>
  • 直接修改处理器类 MyController
/**
     * 处理器方法返回String--表示逻辑视图名称,需要配置视图解析器
     */
    @RequestMapping(value = "/returnString-view.do")
    public String doReturnView(HttpServletRequest request,String name, Integer age){
        System.out.println("doReturnView, name="+name+"   age="+age);
        //可以自己手工添加数据到request作用域
        request.setAttribute("myname",name);
        request.setAttribute("myage",age);
        // show : 逻辑视图名称,项目中配置了视图解析器
        // 框架对视图执行forward转发操作
        return "show";
    }
  • 测试如下:
  • 当然,也可以直接返回资源的物理视图名。不过,此时就不需要再在视图解析器中再配
    置前辍与后辍了。
//处理器方法返回String,表示完整视图路径, 此时不能配置视图解析器
    @RequestMapping(value = "/returnString-view2.do")
    public String doReturnView2(HttpServletRequest request,String name, Integer age){
        System.out.println("===doReturnView2====, name="+name+"   age="+age);
        //可以自己手工添加数据到request作用域
        request.setAttribute("myname",name);
        request.setAttribute("myage",age);
        // 完整视图路径,项目中不能配置视图解析器
        // 框架对视图执行forward转发操作
        // /WEB-INF/view//WEB-INF/view/show.jsp.jsp
        // /WEB-INF/view/WEB-INF/view/show.jsp.jsp
        return "/WEB-INF/view/show.jsp";
    }
  • 这时候如果不把视图解析器中的前缀和后缀去除就把报错:如下

3. 返回 void (了解

对于处理器方法返回 void 的应用场景,AJAX 响应.若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。

例如,对于 AJAX 的异步请求的响应。

项目:returnVoid-ajax。在 primary-annotation 基础上进行修改。

  • Step1:maven 加入 jackson 依赖

由于本项目中服务端向浏览器传回的是 JSON 数据,需要使用一个工具类将字符串包装为 JSON 格式,所以需要导入 JSON 的依赖。

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
  • Step2:引入 jQuery 库

由于本项目要使用 jQuery 的 ajax()方法提交 AJAX 请求,所以项目中需要引入 jQuery 的库。在 WebRoot 下新建一个 Folder(文件夹),命名为 js,并将 jquery-1.11.1.js 文件放入其

中。

  • Step3:定义 index 页面
index 页面由两部分内容构成:一个是<button/>,用于提交 AJAX 请求;一个是<script/>,用于处理 AJAX 请求。

![]()
  • Step4: 定义对象 Student
  • Step5:修改处理器类 MyController

处理器对于 AJAX 请求中所提交的参数,可以使用逐个接收的方式,也可以以对象的方式整体接收。只要保证 AJAX 请求参数与接收的对象类型属性同名。

以逐个方式接收参数:

//处理器方法返回void, 响应ajax请求
    //手工实现ajax,json数据: 代码有重复的 1. java对象转为json; 2. 通过HttpServletResponse输出json数据
    @RequestMapping(value = "/returnVoid-ajax.do")
    public void doReturnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
        System.out.println("===doReturnVoidAjax====, name="+name+"   age="+age);
       //处理ajax, 使用json做数据的格式
       //service调用完成了, 使用Student表示处理结果
        Student student  = new Student();
        student.setName("张飞同学");
        student.setAge(28);

        String json = "";
        //把结果的对象转为json格式的数据
        if( student != null){
            ObjectMapper om  = new ObjectMapper();
            json  = om.writeValueAsString(student);
            System.out.println("student转换的json===="+json);
        }

        //输出数据,响应ajax的请求
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw  = response.getWriter();
        pw.println(json);
        pw.flush();
        pw.close();

    }

4.返回对象 Object重点

处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象,Map,List 等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。

返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。

( 1 ) 环境搭建

A 、 maven pom.xml

由于返回 Object 数据,一般都是将数据转化为了 JSON 对象后传递给浏览器页面的。而这个由 Object 转换为 JSON,是由 Jackson 工具完成的。所以需要导入 Jackson 的相关 Jar 包。

依赖:

<dependency>
 <groupId>com.fasterxml.jackson.core</groupId>
 <artifactId>jackson-core</artifactId>
 <version>2.9.0</version>
</dependency>
<dependency>
 <groupId>com.fasterxml.jackson.core</groupId>
 <artifactId>jackson-databind</artifactId>
 <version>2.9.0</version>
</dependency>

B 、 声明注解驱动

将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由mvc:annotation-driven/来完成。

SpringMVC 使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间的自动转换

当 Spring 容器进行初始化过程中,在mvc:annotation-driven/处创建注解驱动时,默认创建了七个 HttpMessageConverter 对象。也就是说,我们注册mvc:annotation-driven/,就是为了让容器为我们创建 HttpMessageConverter 对象。

SpringMVC 返回对象报错 springmvc处理返回值_ajax_02

没有加入注解驱动标签<mvc:annotation-driven /> 时的状态
org.springframework.http.converter.ByteArrayHttpMessageConverter
org.springframework.http.converter.StringHttpMessageConverter
org.springframework.http.converter.xml.SourceHttpMessageConverter
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter


加入注解驱动标签时<mvc:annotation-driven />的状态
org.springframework.http.converter.ByteArrayHttpMessageConverter
org.springframework.http.converter.StringHttpMessageConverter
org.springframework.http.converter.ResourceHttpMessageConverter
org.springframework.http.converter.ResourceRegionHttpMessageConverter
org.springframework.http.converter.xml.SourceHttpMessageConverter
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

HttpMessageConverter 接口 : HttpMessageConverter是 Spring3.0 新添加的一个接口,

负责将请求信息转换为一个对象(类型为 T ),将对象(类型为 T )输出为响应信息

HttpMessageConverter接口定义的方法:

boolean canRead(Class<?> clazz,MediaType mediaType): 指定转换器可以读取的对象类型,即

转 换 器 是 否 可 将 请 求 信 息 转 换 为 clazz 类 型 的 对 象 , 同 时 指 定 支 持 MIME 类 型

(text/html,applaiction/json 等)

boolean canWrite(Class<?> clazz,MediaType mediaType):指定转换器是否可将 clazz 类型的对

象写到响应流中,响应流支持的媒体类型在 MediaType 中定义。

LIst getSupportMediaTypes():该转换器支持的媒体类

型。

T read(Class<? extends T> clazz,HttpInputMessage inputMessage):将请求信息流转换为 T 类型

的对象。

void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):将 T 类型的对象写

到响应流中,同时指定相应的媒体类型为 contentType

加入注解驱动mvc:annotation-driven/后适配器类的 messageConverters 属性值

SpringMVC 返回对象报错 springmvc处理返回值_json_03

SpringMVC 返回对象报错 springmvc处理返回值_json_04

( 2 ) 返回自定义类型对象

返回自定义类型对象时,不能以对象的形式直接返回给客户端浏览器,而是将对象转换为 JSON 格式的数据发送给浏览器的。

由于转换器底层使用了Jackson转换方式将对象转换为JSON数据,所以需要导入Jackson

的相关 Jar 包。

项目:returnObject-custom。在 returnVoid-ajax 基础上进行修改。

  • Step1:定义数据类
  • Step2:修改处理器 MyController
-- 手工
        //处理器方法返回void, 响应ajax请求
    //手工实现ajax,json数据: 代码有重复的 1. java对象转为json; 2. 通过HttpServletResponse输出json数据
    @RequestMapping(value = "/returnVoid-ajax.do")
    public void doReturnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
        System.out.println("===doReturnVoidAjax====, name="+name+"   age="+age);
       //处理ajax, 使用json做数据的格式
       //service调用完成了, 使用Student表示处理结果
        Student student  = new Student();
        student.setName("张飞同学");
        student.setAge(28);

        String json = "";
        //把结果的对象转为json格式的数据
        if( student != null){
            ObjectMapper om  = new ObjectMapper();
            json  = om.writeValueAsString(student);
            System.out.println("student转换的json===="+json);
        }

        //输出数据,响应ajax的请求
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw  = response.getWriter();
        pw.println(json);
        pw.flush();
        pw.close();

    }

--通过框架

/**
     * 处理器方法返回一个Student,通过框架转为json,响应ajax请求
     * @ResponseBody:
     *    作用:把处理器方法返回对象转为json后,通过HttpServletResponse输出给浏览器。
     *    位置:方法的定义上面。 和其它注解没有顺序的关系。
     * 返回对象框架的处理流程:
     *  1. 框架会把返回Student类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
     *     检查那个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter
     *
     *  2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法
     *    把李四同学的student对象转为json, 调用Jackson的ObjectMapper实现转为json
     *    contentType: application/json;charset=utf-8
     *
     *  3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
     */
    @RequestMapping(value = "/returnStudentJson.do")
    @ResponseBody
    public Student doStudentJsonObject(String name, Integer age) {
        //调用service,获取请求结果数据 , Student对象表示结果数据
        Student student = new Student();
        student.setName("李四同学");
        student.setAge(20);
        return student; // 会被框架转为json

    }

( 3 ) 返回 List 集合

/**
     *  处理器方法返回List<Student>
     * 返回对象框架的处理流程:
     *  1. 框架会把返回List<Student>类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
     *     检查那个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter
     *
     *  2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法
     *    把李四同学的student对象转为json, 调用Jackson的ObjectMapper实现转为json array
     *    contentType: application/json;charset=utf-8
     *
     *  3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
     */
    @RequestMapping(value = "/returnStudentJsonArray.do")
    @ResponseBody
    public List<Student> doStudentJsonObjectArray(String name, Integer age) {

        List<Student> list = new ArrayList<>();
        //调用service,获取请求结果数据 , Student对象表示结果数据
        Student student = new Student();
        student.setName("李四同学");
        student.setAge(20);
        list.add(student);

        student = new Student();
        student.setName("张三");
        student.setAge(28);
        list.add(student);


        return list;

( 4 ) 返回字符串对象

若要返回非中文字符串,将前面返回数值型数据的返回值直接修改为字符串即可。但若返 回 的 字 符 串 中 带 有 中 文 字 符 , 则 接 收 方 页 面 将 会 出 现 乱 码 。 此 时 需 要 使 用@RequestMapping 的 produces 属性指定字符集。

produces,产品,结果,即该属性用于设置输出结果类型。

/**
     * 处理器方法返回的是String , String表示数据的,不是视图。
     * 区分返回值String是数据,还是视图,看有没有@ResponseBody注解
     * 如果有@ResponseBody注解,返回String就是数据,反之就是视图
     *
     * 默认使用“text/plain;charset=ISO-8859-1”作为contentType,导致中文有乱码,
     * 解决方案:给RequestMapping增加一个属性 produces, 使用这个属性指定新的contentType.
     * 返回对象框架的处理流程:
     *  1. 框架会把返回String类型,调用框架的中ArrayList<HttpMessageConverter>中每个类的canWrite()方法
     *     检查那个HttpMessageConverter接口的实现类能处理String类型的数据--StringHttpMessageConverter
     *
     *  2.框架会调用实现类的write(), StringHttpMessageConverter的write()方法
     *    把字符按照指定的编码处理 text/plain;charset=ISO-8859-1
     *
     *  3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成
     */
    @RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String doStringData(String name,Integer age){
        return "Hello SpringMVC 返回对象,表示数据";
    }

总结:

1.ModelAndView: 有数据和视图,对视图执行forward。
2.String:表示视图,可以逻辑名称,也可以是完整视图路径
3.void: 不能表示数据,也不能表示视图。
  在处理ajax的时候,可以使用void返回值。 通过HttpServletResponse输出数据。响应ajax请求。
  ajax请求服务器端返回的就是数据, 和视图无关。
4.Object: 例如String , Integer , Map,List, Student等等都是对象,
  对象有属性, 属性就是数据。 所以返回Object表示数据, 和视图无关。
  可以使用对象表示的数据,响应ajax请求。

  现在做ajax, 主要使用json的数据格式。 实现步骤:
   1.加入处理json的工具库的依赖, springmvc默认使用的jackson。
   2.在sprigmvc配置文件之间加入 <mvc:annotation-driven> 注解驱动。
     json  = om.writeValueAsString(student);
   3.在处理器方法的上面加入@ResponseBody注解
       response.setContentType("application/json;charset=utf-8");
       PrintWriter pw  = response.getWriter();
       pw.println(json);

  springmvc处理器方法返回Object, 可以转为json输出到浏览器,响应ajax的内部原理
  1. <mvc:annotation-driven> 注解驱动。
     注解驱动实现的功能是 完成java对象到json,xml, text,二进制等数据格式的转换。
     <mvc:annotation-driven>在加入到springmvc配置文件后, 会自动创建HttpMessageConverter接口
     的7个实现类对象, 包括 MappingJackson2HttpMessageConverter (使用jackson工具库中的ObjectMapper实现java对象转为json字符串)

     HttpMessageConverter接口:消息转换器。
     功能:定义了java转为json,xml等数据格式的方法。 这个接口有很多的实现类。
           这些实现类完成 java对象到json, java对象到xml,java对象到二进制数据的转换

     下面的两个方法是控制器类把结果输出给浏览器时使用的:
     boolean canWrite(Class<?> var1, @Nullable MediaType var2);
     void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3)


     例如处理器方法
     @RequestMapping(value = "/returnString.do")
     public Student doReturnView2(HttpServletRequest request,String name, Integer age){
             Student student = new Student();
             student.setName("lisi");
             student.setAge(20);
             return student;
     }

     1)canWrite作用检查处理器方法的返回值,能不能转为var2表示的数据格式。
       检查student(lisi,20)能不能转为var2表示的数据格式。如果检查能转为json,canWrite返回true
       MediaType:表示数格式的, 例如json, xml等等

     2)write:把处理器方法的返回值对象,调用jackson中的ObjectMapper转为json字符串。
        json  = om.writeValueAsString(student);


 2. @ResponseBody注解
   放在处理器方法的上面, 通过HttpServletResponse输出数据,响应ajax请求的。
           PrintWriter pw  = response.getWriter();
           pw.println(json);
           pw.flush();
           pw.close();