一、处理器方法返回值

使用@Controller注解的处理器方法,返回值会有四种类型:ModelAndView、String、Void、自定义Java对象

1、ModelAndView

ModelAndView:有数据和视图

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

若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 Ajax 异步响应),此时返回 ModelAndView 将不适合

@RequestMapping(value = "/receiveproperty.do")
    public ModelAndView doSome(String name,Integer age){
        System.out.println("doSome, name="+name+"   age="+age);

        //处理 some.do请求,相当于service调用处理完成
        ModelAndView mdv = new ModelAndView();
        mdv.addObject("myname",name);
        mdv.addObject("myage",Integer.valueOf(age));
        mdv.setViewName("show");

        return mdv;
    }

2、String

String:表示视图,可以是逻辑名称,也可以是完整视图路径

(1)逻辑视图路径

此时在 springmvc.xml 中需要配置视图解析器

<!-- 声明SpringMVC框架中的视图解析器,设置视图文件的路径:InternalResourceViewResolver
        注:处理器方法返回String,表示完整视图路径,此时不能配置视图解析器
     -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀:视图文件的路径 -->
        <property name="prefix" value="/WEB-INF/view/" />
        <!-- 后缀:视图文件的扩展名 -->
        <property name="suffix" value=".jsp" />
    </bean>

@Controller注解处理器 

/**
     * 1、处理器方法返回String
     * (1)表示逻辑视图名称,需要配置视图解析器
     * (2)表示完整视图路径,不能配置视图解析器
     */
    @RequestMapping(value = "/returnString-view.do")
    public String doReturnStringView(HttpServletRequest request,String name,Integer age){
        System.out.println("doReturnStringView, name="+name+"   age="+age);

        request.setAttribute("myname",name);
        request.setAttribute("myage",age);

        // show : 逻辑视图名称,项目中配置了视图解析器
        // 框架对视图执行forward转发操作
        return "show";
    }

(2)完整视图路径

返回完整视图路径时,不需要设置视图解析器,不然会报错

HTTP状态 404 - 未找到 

文件 [/WEB-INF/view/WEB-INF/view/show.jsp.jsp] 未找到

//处理器方法返回String,表示完整视图路径,此时不能配置视图解析器
    @RequestMapping(value = "/returnString-view1.do")
    public String doReturnStringView1(HttpServletRequest request,String name,Integer age){
        System.out.println("doReturnStringView1, name="+name+"   age="+age);

        request.setAttribute("myname",name);
        request.setAttribute("myage",age);

        // 完整视图路径,项目中不能配置视图解析器
        // 框架对视图执行forward转发操作,如果配置了视图解析器会出现如下结果
        // HTTP状态 404 - 未找到 文件 [/WEB-INF/view/WEB-INF/view/show.jsp.jsp] 未找到
        return "/WEB-INF/view/show.jsp";
    }

3、void

处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void

处理器方法返回 void 的应用场景,AJAX 响应

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

(1)在 pom.xml 文件中加入处理json工具库的依赖,SpringMVC默认使用jackson

<!--Jackson依赖-->
    <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>

(2)引入jQuery库 

由于要使用 jQuery 的 ajax()方法提交 AJAX 请求,所以项目中需要引入 jQuery 的库

(3)index.jsp视图

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>

<head>
    <title>Title</title>

    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function (){
            $("button").click(function (){
                //alert("button click");
                $.ajax({
                    url:"returnVoid-ajax.do", //处理器返回void,响应Ajax请求
                    data:{
                        name:"zhangsan",
                        age:18
                    },
                    type:"post",
                    dataType:"json",
                    success:function (resp){
                        //resp从服务器端返回的是json的字符串 {"name":"zhangsan","age":18}
                        //jQuery会将字符串转为json对象,赋值给resp形参
                        alert(resp.name + "    "+resp.age);
                    }
                })
            })
        })
    </script>
</head>

<body>
    <p>SpringMVC项目</p>

    <button id="btn"> 发起Ajax请求 </button>

</body>
</html>

(4)创建Java对象Student类

package com.mycompany.domain;

public class Student {
    // 属性名和请求中参数名一样
    private String name;
    private Integer age;

    public Student() {
        System.out.println("===Student的无参数构造方法===");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("setName"+name);
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        System.out.println("setAge"+age);
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

(5) 处理器类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做数据格式
        Student student = new Student();
        student.setName("张三");
        student.setAge(18);

        String json = "";
        //将结果对象转为json格式数据
        if (student != null){
            ObjectMapper objectMapper = new ObjectMapper();
            json = objectMapper.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();
    }

点击按钮,发起请求,可以看到web端页面输出,右键点击【检查】,可以看到请求头以及响应头内容

 后台控制台输出如下

4、自定义Java对象

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

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

(1)在 pom.xml 文件中加入处理json工具库的依赖,SpringMVC默认使用jackson

<!--Jackson依赖-->
    <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>

(2)声明注解驱动 

springmvc.xml

<!-- 注解驱动
        http://www.springframework.org/schema/mvc
        <mvc:annotation-driven> 注解驱动实现的功能:完成Java对象到json,xml,text,二进制等数据格式的转换
     -->
    <mvc:annotation-driven />

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

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

当 Spring 容器进行初始化过程中,在<mvc:annotation-driven/>处创建注解驱动时,默认创建了八个 HttpMessageConverter 对象

HttpMessageConverter 接口 : HttpMessageConverter<T>是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息

HttpMessageConverter<T>接口定义的方法:

public interface HttpMessageConverter<T> {
    /**
    * 指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为clazz 类型的对         
      象,同时指定支持MIME类型(text/html,applaiction/json 等)
    */
    boolean canRead(Class<?> var1, @Nullable MediaType var2);

    /**
    * 指定转换器是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型在 MediaType 中定义
    */
    boolean canWrite(Class<?> var1, @Nullable MediaType var2);

    //该转换器支持的媒体类型
    List<MediaType> getSupportedMediaTypes();

    //将请求信息流转换为 T 类型的对象
    T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;

    //将 T 类型的对象写到响应流中,同时指定相应的媒体类型为 contentType
    void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}

(3)在处理器方法上加入@ResponseBody注解

index.jsp视图

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>

<head>
    <title>Title</title>

    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function (){
            $("button").click(function (){
                //alert("button click");
                $.ajax({
                    //url:"returnVoid-ajax.do", //处理器返回void,响应Ajax请求
                    //url:"returnStudentJson.do", //处理器方法返回Java对象Student
                    //url:"returnStudentListJson.do", //处理器方法返回集合List<Student>
                    url:"returnStringData.do", //有@ResponseBody注解,处理器方法返回的是String,String表示数据
                    data:{
                        name:"zhangsan",
                        age:18
                    },
                    type:"post",
                    //dataType:"json",
                    dataType:"text",
                    success:function (resp){
                        //resp从服务器端返回的是json的字符串 {"name":"zhangsan","age":18}
                        //jQuery会将字符串转为json对象,赋值给resp形参
                        //alert(resp.name + "    "+resp.age);

                        //处理器方法返回集合List<Student>
                        /*$.each(resp,function (i,n){
                            alert(n.name+"   "+n.age)
                        })*/

                        alert("返回的是文本数据:"+resp);
                    }
                })
            })
        })
    </script>
</head>

<body>
    <p>SpringMVC项目</p>

    <button id="btn"> 发起Ajax请求 </button>

</body>
</html>

(1)Java对象

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

(2)List集合

/**
     * 处理器方法返回集合List<Student>
     * 处理流程如上
     */
    @RequestMapping(value = "/returnStudentListJson.do")
    @ResponseBody
    public List<Student> doStudentListJsonObject(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(18);
        list.add(student);

        return list;
    }

(3)String数据

处理器方法返回String(此处String表示数据,不是视图路径)

区分String是视图路径还是数据,关键就看是否有@ResponseBody注解;有@ResponseBody注解,返回String就是数据,反之就是视图路径

默认响应头Response Headers中Content-Type: text/plain;charset=ISO-8859-1,导致中文有乱码

给@RequestMapping增加一个属性 produces,使用此属性指定Content-Type;

@RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")

 

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

总结:

1、Ajax使用,主要使用json的数据,实现步骤如下:

(1)加入处理json工具库的依赖,SpringMVC默认使用jackson

(2)在SpringMVC配置文件中加入 <mvc:annotation-driven> 注解驱动

json = ObjectMapper.writeValueAsString(student);

(3)在处理器方法上加入@ResponseBody注解 

response.setContentType("application/json;charset=utf-8");
    PrintWriter pw  = response.getWriter();
    pw.println(json);

2、SpringMVC处理器方法返回object,可以转为json输出到浏览器,响应Ajax内部原理

(1)<mvc:annotation-driven> 注解驱动

【1】<mvc:annotation-driven> 注解驱动实现的功能:

完成Java对象到json,xml,text,二进制等数据格式的转换 <mvc:annotation-driven>加入到SpringMVC配置文件后,会自动创建HttpMessageConverter接口的8个实现类对象,

包括 MappingJackson2HttpMessageConverter (使用jackson工具库中的ObjectMapper实现java对象转为json字符串)

【2】HttpMessageConverter接口:消息转换器

功能:定义了Java转json,xml等数据格式的方法,这个接口有很多实现类 这些实现类完成 java对象到json, java对象到xml,java对象到二进制数据的转换 两个方法是控制器类把结果输出给浏览器时使用:

boolean canWrite(Class<?> var1, @Nullable MediaType var2)

void write(T va1, @Nullable MediaType va2, 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,18)能不能转为var2表示的数据格式;如果检查能转为json,canWrite返回true MediaType:表示数据格式的,如json,xml等

【2】write:将处理器方法的返回值对象,调用jackson中的ObjectMapper转为json字符串

json  = objectMapper.writeValueAsString(student);

(2)@ResponseBody注解 放在处理器方法的上面,通过HttpServletResponse输出数据,响应ajax请求

PrintWriter pw = response.getWriter(); 
pw.println(json); 
pw.flush(); 
pw.close();

DispatcherServlet 类中此处加入断点

public class DispatcherServlet extends FrameworkServlet {
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ......
        HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
        ......
    }
}

没有加入注解驱动标签<mvc:annotation-driven /> 时的状态

0 = {ByteArrayHttpMessageConverter@5029}
1 = {StringHttpMessageConverter@5030}
2 = {SourceHttpMessageConverter@5031}
3 = {AllEncompassingFormHttpMessageConverter@5032}

加入注解驱动标签时<mvc:annotation-driven />的状态

//负责读取二进制格式的数据和写出二进制格式的数据
0 = {ByteArrayHttpMessageConverter 
//负责读取字符串格式的数据和写出字符串格式的数据
1 = {StringHttpMessageConverter@5161}
//负责读取资源文件和写出资源文件数据
2 = {ResourceHttpMessageConverter@5162}
//
3 = {ResourceRegionHttpMessageConverter@5163}
//能够读 / 写 来 自 HTTP 的 请 求 与 响 应 的
javax.xml.transform.Source ,支持 DOMSource, 
SAXSource, 和 StreamSource 的 XML 格式
4 = {SourceHttpMessageConverter@5164}
//负责处理表单(form)数据
5 = {AllEncompassingFormHttpMessageConverter@5165}
//使用 JAXB 负责读取和写入 xml 标签格式的数据
6 = {Jaxb2RootElementHttpMessageConverter@5166}
//负责读取和写入 json 格式的数据。利用Jackson 的 ObjectMapper 读写 json 数据,操作Object 类型据,可读取 application/json,响应媒体类型为 application/json
7 = {MappingJackson2HttpMessageConverter@5167}

更多推荐