SpringMVC学习笔记-05 处理器方法返回值

1. ModelAndView

    最常用的返回值类型,Model用于存储数据,最终被放置到request作用域;View代表视图,框架使用forward进行视图跳转。如果请求处理的结果既需要数据,又需要视图,那么使用ModelAndView比较方便。如果只需要数据,不需要页面跳转(例如Ajax异步响应更新局部数据);或者只需要页面跳转,不需要传递数据,此时使用ModelAndView并不合适,总有一部分是多余的。

    @RequestMapping(value = "/noLimit.do")
    public ModelAndView doNoLimit(){
        ModelAndView modelAndView = new ModelAndView();

        // 存放数据 框架会自动将数据放到request作用域
        modelAndView.addObject("msg","hello-nolimit");

        modelAndView.setViewName("show");

        return modelAndView;
    }

2. String

    当框架中配置了视图解析器时,返回的String结果会被当作是逻辑视图名,经过视图解析器拼接后形成地址;如果没有配置视图解析器,那么返回的String就会被当作是视图路径。

配置了视图解析器:

    <p>处理器方法返回String表示视图名称</p>
    <form action="test/returnString-view.do" method="post">
        姓名:<input type="text" name="name"><br>
        年龄:<input type="text" name="age"><br>
        <input type="submit" value="提交">
    </form>
    @RequestMapping(value = "/returnString.do")
    public String doReturnString(HttpServletRequest request, @RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age){
        System.out.println("name = " + name + ", age = " + age);
        // 手动将数据添加到request对象中
        request.setAttribute("name",name);
        request.setAttribute("age",age);
        return "showProperty";
    }

此时如果我们返回试图路径:

    @RequestMapping(value = "/returnString.do")
    public String doReturnString(HttpServletRequest request, @RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age){
        System.out.println("name = " + name + ", age = " + age);
        // 手动将数据添加到request对象中
        request.setAttribute("name",name);
        request.setAttribute("age",age);
        return "/WEB-INF/view/showProperty.jsp";
    }

    

很明显,框架把我们返回的String结果当作逻辑视图名,经过了视图解析器拼接。

注意:当我们返回String类型时,如果需要同时转发数据,必须得在request对象中手动加入对象。

3.void

    void用于请求处理后,不需要跳转到其他视图的场合。例如可以用于对Ajax的异步请求响应:通过HttpServletResponse输出数据,响应Ajax请求。

1. 导入jquery库文件

2. Ajax处理数据使用json格式,我们还需要导入json的依赖包,用于将字符串包装为json格式

    <!--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>

3.在页面中设定发起Ajax请求的触发事件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.5.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"test/returnVoid_ajax.do", // 请求路径
                    data:{ // 请求的数据
                        name:"zzt",
                        age:21
                    },
                    type:"post", // 请求方式
                    dataType:"json", // 返回数据的解析方式 json为把json格式的字符串解析为对象
                    success:function (resp) { // resp结果数据解析后的结果
                        alert(resp);
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起Ajax请求</button>
</body>
</html>

4. 在处理器方法中,使用response对象传回数据

    @RequestMapping(value = "/returnVoid_ajax.do")
    public void doReturnVoid(HttpServletResponse response,@RequestParam("name") String name, @RequestParam("age") Integer age) throws IOException {
        System.out.println("name = " + name + ", age = " + age);
        // 1.(假装)调用业务方法获取数据
        Student student = new Student(name, age);
        // 2.将结果转换成json格式的字符串
        String json = "";
        if(student != null){
            ObjectMapper objectMapper = new ObjectMapper();
            json = objectMapper.writeValueAsString(student);
            System.out.println("对象转换为json格式为 : " + json);
        }
        // 3.设置相应格式,响应请求
        response.setContentType("application/json;charset=utf-8");
        PrintWriter printWriter = response.getWriter();
        printWriter.println(json);
        printWriter.flush();
        printWriter.close();
        return;
    }

5.执行结果

扫描二维码关注公众号,回复: 12346346 查看本文章

jquery将返回的字符串以json格式解析为对象并赋值给接收参数,当然对象中的值我们也是可以取出来的。

        success:function (resp) { // resp结果数据解析后的结果
                alert("name = " + resp.name + " age = " + resp.age);
        }

值得注意的是dataType属性,它用于指明想要的结果类型,是在请求头的声明的:

但是我们已经在代码中,为响应头也指明了数据的格式为json字符串,jquery也会尝试解析为json对象(使用JSON.parse方法):

4.Object

        在第三种方式中,对于Ajax请求的响应,我们需要固定地将对象转换为json字符串,并且用response对象回传数据。这是公共的冗余操作,当然我们也可以通过工具类的方式进行公共部分提取,但是SpringMVC也提供了另一种方式,就是使用对象作为返回值。如果我们使用这种方式,即使传回的是String类型,框架也不会把他当作是视图名或者逻辑视图名,而是只把他当作传递过来的数据。

        @ResponseBody注解,会将结果数据放入到响应体中。

A. 传递普通对象类型

1. 加入jackson依赖

jaskson是SpringMVC默认的json依赖项。

    <!--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. 配置注解驱动<mvc:annotation-driven/>

    <!--配置注解驱动-->
    <mvc:annotation-driven/>

注意在Spring中也有注解驱动,这边我们要用的是SpringMVC中的注解驱动,别加错了。

<mvc:annotation-driven>在加入配置后,会自动创建HttpMessageConverter(消息转换器)接口的实现类。

我们常用的是StringHttpMessageConverter(默认创建)和MappingJackson2HttpMessageConverter(配置注解驱动后才会创建)。

HttpMessageConverter:消息转换器接口,定义了java对象转换为json、xml、二进制流等数据格式的方法,它有很多实现类,这些实现类负责实现java对象的转换。

转换步骤:1.调用接口中定义的canWrite方法,判断是否可以进行转换

                  2.调用接口中定义的write方法,完成数据格式的转换

这对应了我们刚刚手动实现的这一部分:

        String json = "";
        if(student != null){
            ObjectMapper objectMapper = new ObjectMapper();
            json = objectMapper.writeValueAsString(student);
            System.out.println("对象转换为json格式为 : " + json);
        }

3. 在处理器方法上增加@ResponseBody

@ResponseBody负责将输出放入响应体,另外具有@ResponseBody注解的方法,其返回值不会被当作逻辑视图名或者视图路径(特指String)。

    @ResponseBody
    @RequestMapping(value = "/returnVoid_ajax.do")
    public Student doReturnVoid(HttpServletResponse response,@RequestParam("name") String name, @RequestParam("age") Integer age) throws IOException {
        System.out.println("name = " + name + ", age = " + age);

        Student student = new Student(name, age);
        return student;
    }

这对应了我们刚刚手动实现的这一部分:

        response.setContentType("application/json;charset=utf-8");//响应数据格式
        PrintWriter printWriter = response.getWriter();
        printWriter.println(json);
        printWriter.flush();
        printWriter.close();

4.执行结果

5.执行步骤详解

1. 容器会用一个List用于存储所有的消息转换器ArrayList<HttpMessageConverter>(注解驱动生效后,MappingJackson2HttpMessageConverter对象会被创建并放入list)

2. 对于返回的Student对象,框架会遍历list里的所有消息转换器,调用他们的canWrite()方法,判断哪一个消息转换器实现类对象可以对该Student对象进行转换

3. 确定了消息转换器对象之后,使用它的write()方法完成转换(Student是对象,需要转换成json格式)

4. @ResponseBody注解表示将返回结果放置在response中

B.传递集合

    @ResponseBody
    @RequestMapping(value = "/returnVoid_ajaxList.do")
    public List<Student> doReturnVoidList(HttpServletResponse response, @RequestParam("name") String name, @RequestParam("age") Integer age) throws IOException {
        System.out.println("name = " + name + ", age = " + age);

        List<Student> students = new ArrayList<>();
        Student student = new Student(name, age);
        students.add(student);
        student = new Student("辅助",20);
        students.add(student);
        return students;
    }

此时返回的是一个json字符串的数组,我们可以用jquery自带的循环函数遍历取值:

                $.ajax({
                    url:"test/returnVoid_ajaxList.do", // 请求路径
                    data:{ // 请求的数据
                        name:"zzt",
                        age:21
                    },
                    type:"post", // 请求方式
                    dataType:"json", // 要求返回的数据类型是json格式的字符串
                    success:function (resp) { // resp结果数据解析后的结果
                        //alert("name = " + resp.name + " age = " + resp.age);
                        $.each(resp,function (i,student) {
                            alert(student.name + "--" + student.age)
                        })
                    }
                })

C.传递的String只作为普通的文本数据

    @ResponseBody
    @RequestMapping(value = "/returnStringAjax.do")
    public String doReturnStringAjax(){
        return "返回的是字符串不是数据";
    }

我们使用ajax提交请求:

                $.ajax({
                    url:"test/returnStringAjax.do", // 请求路径
                    data:{ // 请求的数据
                        name:"zzt",
                        age:21
                    },
                    type:"post", // 请求方式
                    dataType:"json", // 要求返回的数据类型是json格式的字符串
                    success:function (resp) { // resp结果数据解析后的结果
                        //alert("name = " + resp.name + " age = " + resp.age);
                        /*$.each(resp,function (i,student) {
                            alert(student.name + "--" + student.age)
                        })*/
                        alert("返回文本数据:" + resp);
                    }
                })

此时并没有任何弹窗,但是ajax请求确实成功发出也收到了响应,关键在于,由于我们设置了要求返回类型是json格式,可是我们实际返回的是String,它并不是由jackson提供的方法进行转换的,所以发生了格式的不匹配,执行中断了,解决办法就是改变dataType的值为text,表示结果为文本数据。

现在我们遇到了第二个问题,执行不出错了但是数据无法解析:

观察响应头发现,响应里的默认编码格式是ISO-8859-1,这种编码格式是没有办法正常解析中文的,我们需要手动设置编码格式为utf-8:[注]前面我们是有配置过过滤器的,但是Ajax请求返回的数据是不会经过过滤器的,因此需要手动设置。

使用@RequestMapping的produces属性设置编码格式ContentType:

    @ResponseBody
    @RequestMapping(value = "/returnStringAjax.do", produces = "text/plain;charset=utf-8")
    public String doReturnStringAjax(){
        return "返回的是字符串不是数据--SpringMVC";
    }

[注]:String类型的返回值是由StringHttpMessageConverter负责完成转换的。

猜你喜欢

转载自blog.csdn.net/qq_39304630/article/details/112919407
今日推荐