`
十三哥
  • 浏览: 17803 次
文章分类
社区版块
存档分类
最新评论

SpringMVC处理ajax请求

    博客分类:
  • SSH
阅读更多

【Spring-MVC AJAX请求】

前言

准备筹划一个自己的个人网站,初步的架构设计采用SSH(Spring-MVC,Spring,Hibernate),

在这里顺便记录一下设计和开发过程,以备参考。后续会陆续更新文档,如有任何问题,

欢迎各位不吝指出,共同学习。

环境

开发环境 版本
eclipse 4.3.2
maven 3.2.1
Spring-MVC 3.2.3.RELEASE
Spring Spring
Hibernate 3.2.5

十三哥将来的架构是后台不渲染页面,只返回JSON数据,所以在此详细

介绍下SpirngMVC对ajax请求的处理。

【添加处理JSON数据的jar包】

pom.xml添加spring-mvc的依赖 

<!-- jack core annotation databind begin-->  
        <dependency>  
            <groupId>com.fasterxml.jackson.core</groupId>  
            <artifactId>jackson-core</artifactId>  
            <version>2.2.2</version>  
        </dependency>  
        <dependency>  
            <groupId>com.fasterxml.jackson.core</groupId>  
            <artifactId>jackson-annotations</artifactId>  
            <version>2.2.2</version>  
        </dependency>  
        <dependency>  
            <groupId>com.fasterxml.jackson.core</groupId>  
            <artifactId>jackson-databind</artifactId>  
            <version>2.2.2</version>  
        </dependency>  
        <dependency>  
            <groupId>org.codehaus.jackson</groupId>  
            <artifactId>jackson-mapper-lgpl</artifactId>  
            <version>1.9.12</version>  
        </dependency>  
        <!-- jack core annotation databind end-->
<!--  Fastjson begin(这个可以不需要,因为Fastjson要比Jackson的效率高,
当自己组织JSON数据时可以使用)-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.1.30</version>
    </dependency>
    <!--  Fastjson end-->

 

【Controller代码】

package com.xbs.ready.ssh.controller;

import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 *
 * @author xbs
 */
@Controller
@RequestMapping("hello")
public class HelloController {

    /**
     * ajax请求不需要返回页面,只需要得到response中的数据即可,所以方法签名为void即可
     * 
     * @param request
     * @param response 
     */
    @RequestMapping(value = "ajax", method = RequestMethod.POST)
    public void ajaxDatas(HttpServletRequest request, HttpServletResponse response) {
        String jsonResult = getJSONString(request);
        renderData(response, jsonResult);
    }

    private String getJSONString(HttpServletRequest request) {
        //故意构造一个数组,使返回的数据为json数组,数据更复杂些
        List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>(5);
        Map<String, Object> map1 = new HashMap<String, Object>(10);
        //可以获得ajax请求中的参数
        map1.put("a", request.getParameter("a"));
        map1.put("b", request.getParameter("b"));
        map1.put("c", request.getParameter("c"));
        datas.add(map1);
        //故意构造一个数组,使返回的数据为json数组,数据更复杂些
        Map<String, Object> map2 = new HashMap<String, Object>(10);
        map2.put("a", "11");
        map2.put("b", "22");
        map2.put("c", "33");
        datas.add(map2);
        String jsonResult = JSON.toJSONString(datas);
        return jsonResult;
    }

    /**
     * 通过PrintWriter将响应数据写入response,ajax可以接受到这个数据
     * 
     * @param response
     * @param data 
     */
    private void renderData(HttpServletResponse response, String data) {
        PrintWriter printWriter = null;
        try {
            printWriter = response.getWriter();
            printWriter.print(data);
        } catch (IOException ex) {
            Logger.getLogger(HelloController.class.getName()).log(Level.SEVERE, 
null, ex);
        } finally {
            if (null != printWriter) {
                printWriter.flush();
                printWriter.close();
            }
        }
    }
}  

 

【HTML代码】

html文件路径:.../webapp/views/index.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">

<html >
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <!--<script type="text/javascript" src="../static/js/jquery-1.7.2.min.js">
</script>-->
        <!--JS的地址可以写成下面这样,将来部署的时候,这些静态文件就可以单独部署了,
不依赖于后台路径-->
        <script type="text/javascript" src="http://localhost:8080/sshdemo
/static/js/jquery-1.7.2.min.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
                ajaxRequest();
            });

            function ajaxRequest() {
                $.ajax({
                    url: "http://localhost:8080/sshdemo/hello/ajax",
                    type: "POST",
                    dataType: "json",
                    data: {
                        "a": 1,
                        "b": 2,
                        "c": 3
                    },
                    async: false,
                    success: function(data) {
                        alert("success");
                        $.each(data, function(index, element) {
                            alert(element.a);
                            alert(element.b);
                            alert(element.c);
                        });
                    },
                    error: function() {
                        alert("error");
                    }
                });
            }
        </script>
    </head>
    <body>
        <div>Hello World!</div>
    </body>
</html>
  

访问路径:http://localhost:8080/sshdemo/views/index.html

(或者:http://localhost:8080/sshdemo/)

使用@ResponseBody注解

Spring的官方文档中这样说:

The @ResponseBody annotation is similar to @RequestBody. This annotation can be put on a

method and indicates that the return type should be written straight to the HTTP response body

(and not placed in a Model, or interpreted as a view name).

意思是:@ResponseBody与@RequestBody差不多。@ResponseBody可以用在方法上,这样说

明方法的返回结果会被直接写在HTTP的response内。既然写在了response的body内,那么就不是

一个Model或者视图的名字。从而判断出返回的肯定不是页面了。

Sping官网给的例子如下:

@RequestMapping(value = "/something", method = RequestMethod.PUT)
@ResponseBody
public String helloWorld()  {
  return "Hello World";
}
  

如果上面的代码中没有使用@ResponseBody注解,那么返回的就是一个页面,页面名字是【Hello

World】(例如:Hello World.jsp)。 但是使用了@ResponseBody注解后,response的body内会

写入Hello World这个字符串,ajax当然也就可以获取到了。

Spring文档给出了一段说明:

As with @RequestBody, Spring converts the returned object to a response body by using an

HttpMessageConverter.

意思是:使用@RequestBody时,Spring会使用HttpMessageConverter将返回结果写到response的

body里。所以,如果有想了解这方面原理的朋友,可以去官网看看 http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/remoting.html#rest-message-conversion

Spring提供的HttpMessageConverter大致有以下这几个:

StringHttpMessageConverter,FormHttpMessageConverter,ByteArrayMessageConverter,

MarshallingHttpMessageConverter,MappingJacksonHttpMessageConverter,

SourceHttpMessageConverter,BufferedImageHttpMessageConverter

使用ResponseEntity

Spring的官方文档这样说:

A HttpEntity<?> or ResponseEntity<?> object to provide access to the Servlet response HTTP

headers and contents. The entity body will be converted to the response stream using

HttpMessageConverters.

意思是:HttpEntity或者ResponseEntity可以访问Servlet的响应头和正文。使用

HttpMessageConverters将实体写到响应流中。这样的话,ajax就可以获得后台的响应数据了。

HttpEntity支持泛型,可以通过HttpEntity获得请求中的参数。

【Controller代码】

 

@RequestMapping("entity")
public ResponseEntity<Map> handle(HttpEntity<String> requestEntity) {
    //获得ajax的请求数据
    String body = requestEntity.getBody();
    System.out.println("requestParams:" + body);
    //构造一个map作为返回数据,前端会接收到JSON格式的数据
    Map<String, Object> map = new HashMap<String, Object>(10);
    map.put("a", "11");
    map.put("b", "22");
    map.put("c", "33");
    return new ResponseEntity<Map>(map, HttpStatus.OK);
}

 

【AJAX代码】

//url = "http://localhost:8080/sshdemo/hello/entity";
function responseEntity(url) {
    $.ajax({
        url: url,
        type: "POST",
        dataType: "json",
        data: {
            "a": 1,
            "b": 2,
            "c": 3
        },
        async: false,
        success: function(data) {
            alert("success");
            alert(data.a);
            alert(data.b);
            alert(data.c);
        },
        error: function() {
            alert("error");
        }
    });
}
  

【问题说明】

问题1:当使用ResponseEntity处理ajax请求时,出现406 Not Acceptable

HTTP Status 406 -

type Status report

message

description The resource identified by this request is only capable of 
generating responses with characteristics not acceptable according to 
the request "accept" headers.

Apache Tomcat/7.0.34
  

解决方案:这个问题与SpringMVC的版本和配置有关。

修改springMVC-servlet.xml中spring-mvc的文档版本为3.2,增加

ContentNegotiationManagerFactoryBean。

原配置文件:

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  

修改为:

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 增加以下配置,这样可以使ajax的请求返回JSON数据,
否则返回text/html格式,那么会报406 -->
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" /> 
<bean id="contentNegotiationManager" 
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean" />

 

 

另外,pom.xml中一定要添加jackson的依赖,springMVC通过使用jackson把返回结果转换成JSON格式

的数据。

在以上的三种处理ajax请求的方式中(1:方法声明层void 2:使用@ResponseBody

3:使用ResponseEntity),极力推荐使用@ResponseBody这种方式。

因为@ResponseBody不用修改配置文件为3.2,不依赖于jackson包。

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics