spring mvc整合json

http://my.oschina.net/u/724985/blog/101963

http://starscream.iteye.com/blog/1067606


Spring mvc处理json需要使用jackson的类库,因此为支持json格式的输入输出需要先修改pom.xml增加jackson包的引用

Xml代码   收藏代码
  1. <!-- json -->  
  2. <dependency>  
  3.     <groupId>org.codehaus.jackson</groupId>  
  4.     <artifactId>jackson-core-lgpl</artifactId>  
  5.     <version>1.8.1</version>  
  6. </dependency>  
  7.   
  8. <dependency>  
  9.     <groupId>org.codehaus.jackson</groupId>  
  10.     <artifactId>jackson-mapper-lgpl</artifactId>  
  11.     <version>1.8.1</version>  
  12. </dependency>  



先修改之前的helloworld.jsp,增加客户端json格式的数据输入。
Javascript代码   收藏代码
  1.     var cfg =   {  
  2.         type: 'POST',   
  3.         data: JSON.stringify({userName:'winzip',password:'password',mobileNO:'13818881888'}),   
  4.         dataType: 'json',  
  5.         contentType:'application/json;charset=UTF-8',         
  6.         success: function(result) {   
  7.             alert(result.success);   
  8.         }   
  9.     };  
  10.   
  11. function doTestJson(actionName){  
  12.     cfg.url = actionName;  
  13.     $.ajax(cfg);  
  14. }  



根据前面的分析,在spring mvc中解析输入为json格式的数据有两种方式
1:使用@RequestBody来设置输入
Java代码   收藏代码
  1.     @RequestMapping("/json1")  
  2.     @ResponseBody  
  3.     public JsonResult testJson1(@RequestBody User u){  
  4.         log.info("get json input from request body annotation");  
  5.         log.info(u.getUserName());  
  6.         return new JsonResult(true,"return ok");  
  7. }  


2:使用HttpEntity来实现输入绑定
Java代码   收藏代码
  1.     @RequestMapping("/json2")      
  2.     public ResponseEntity<JsonResult> testJson2(HttpEntity<User> u){  
  3.         log.info("get json input from HttpEntity annotation");  
  4.         log.info(u.getBody().getUserName());  
  5.         ResponseEntity<JsonResult> responseResult = new ResponseEntity<JsonResult>( new JsonResult(true,"return ok"),HttpStatus.OK);  
  6.         return responseResult;  
  7. }  


Json格式的输出也对应有两种方式
1:使用@responseBody来设置输出内容为context body
2:返回值设置为ResponseEntity<?>类型,以返回context body
另外,第三种方式是使用ContentNegotiatingViewResolver来设置输出为json格式,需要修改servlet context配置文件如下
Xml代码   收藏代码
  1. <bean  
  2.     class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">  
  3.     <property name="order" value="1" />  
  4.     <property name="mediaTypes">  
  5.         <map>  
  6.             <entry key="json" value="application/json" />  
  7.         </map>  
  8.     </property>  
  9.     <property name="defaultViews">  
  10.         <list>  
  11.             <bean  
  12.                 class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />  
  13.         </list>  
  14.     </property>  
  15.     <property name="ignoreAcceptHeader" value="true" />  
  16. </bean>  

但这种格式的输出会返回{model类名:{内容}} 的json格式,
例如,以下代码
Java代码   收藏代码
  1. @RequestMapping("/json3.json")  
  2. public JsonResult testJson3(@RequestBody User u){  
  3.     log.info("handle json output from ContentNegotiatingViewResolver");  
  4.     return new JsonResult(true,"return ok");  
  5. }  

期望的返回是 {success:true,message:”return ok”};
但实际返回的却是 {"jsonResult":{"success":true,"msg":"return ok"}}
原因是MappingJacksonJsonView中对返回值的处理未考虑modelMap中只有一个值的情况,直接是按照mapName:{mapResult}的格式来返回数据的。
修改方法,重载MappingJacksonJsonView类并重写filterModel方法如下
Java代码   收藏代码
  1. protected Object filterModel(Map<String, Object> model) {    
  2.     Map<?, ?> result = (Map<?, ?>) super.filterModel(model);    
  3.     if (result.size() == 1) {    
  4.         return result.values().iterator().next();    
  5.     } else {    
  6.         return result;    
  7.     }    
  8. }    


对应的ContentNegotiatingViewResolver修改如下
Xml代码   收藏代码
  1. <bean  
  2.         class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">  
  3.         <property name="order" value="1" />  
  4.         <property name="mediaTypes">  
  5.             <map>  
  6.                 <entry key="json" value="application/json" />  
  7.             </map>  
  8.         </property>  
  9.         <property name="defaultViews">  
  10.             <list>  
  11.                 <bean  
  12.                     class="net.zhepu.json.MappingJacksonJsonView" />  
  13.             </list>  
  14.         </property>  
  15.         <property name="ignoreAcceptHeader" value="true" />  
  16.     </bean> 




  最近team要开发一个App,负责server端。原本准备是用SSH2框架的,但是感觉struts2还是比较适合用来与jsp结合使用,想了又想决定用spring mvc整合json来做。网上查了很多资料,调试了一整天,终于把调通。在这里分享一下我的经验:


  1. 第一步当然创建一个新项目,加入spring啦^-^  貌似现在只有3.0版本以上才支持整合json哦。
  2. 在项目中加入两个json的jar包:jackson-core-asl-x.x.x.jar和jackson-mapper-asl.x.x.x.jar。其中xxx是jar包的版本,网上很多说用1.4.2,但是我加入1.4.2版本后,部署会出错。在请求中会出现ObjectMapper:NoClassDefFoundException的错,仔细查看原来tomcat启动的时候就错了,报的是isFullyTyped:NoSuchMethodError的错误。这个错真心纠结了很久,最后在官网上看到原来是core包里里面一个类没有这个方法。查看jar包,1.4.2真的没有这个方法。仔细查看官网API,尼玛json竟然不是向下兼容的,伤不起....最后看到了1.1版本还是支持的,于是就下载了1.1.2的版本。于是两个jar包就是:jackson-core-asl-1.1.2.jar和jackson-mapper-asl.1.1.2.jar。
  3. 在web.xml添加spring mvc
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    < context-param >
         < param-name >contextConfigLocation</ param-name >
             < span ></ span >         < span ></ span > < param-value >
             /WEB-INF/classes/applicationContext.xml,
             /WEB-INF/classes/spring-servlet.xml
         </ param-value >
       </ context-param >
       < listener >
         < listener-class >
             org.springframework.web.context.ContextLoaderListener
         </ listener-class >
       </ listener >
       <!-- spring mvc的servlet,处理所有.json请求 -->
       < servlet >
         < servlet-name >spring</ servlet-name >
         < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
         < init-param >
             < param-name >contextConfigLocation</ param-name >
             < param-value >/WEB-INF/classes/spring-servlet.xml</ param-value >
         </ init-param >
         < load-on-startup >1</ load-on-startup >
       </ servlet >
       < servlet-mapping >
         < servlet-name >spring</ servlet-name >
         < url-pattern >*.json</ url-pattern >
       </ servlet-mapping >
  4. 编写spring-servlet.xml,配置spring mvc
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <? xml version = "1.0" encoding = "UTF-8" ?>
    < beans
         xmlns = "http://www.springframework.org/schema/beans"
         xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
         xmlns:p = "http://www.springframework.org/schema/p"
         xmlns:context = "http://www.springframework.org/schema/context"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
     
         < context:annotation-config />
         <!-- Controller 类注解标识 -->
         < context:component-scan base-package = "com.gswtek.controller" />
         
         < bean class = "org.springframework.web.servlet.view.ContentNegotiatingViewResolver" >
             < property name = "mediaTypes" >
                 < map >
                     <!-- 告诉视图解析器,返回的类型为json格式 -->
                     < entry key = "json" value = "application/json" />
                 </ map >
             </ property >
             < property name = "defaultViews" >
                 < list >
                     <!-- ModelAndView里的数据变成JSON -->
                     < bean class = "org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                 </ list >
             </ property >
         </ bean >
    </ beans >
  5. 编写Controller类,返回的ModelAndView会自动将数据转换成json数据
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    package com.gswtek.controller;
     
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
     
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.portlet.ModelAndView;
     
    import com.gswtek.service.UserService;
    import com.gswtek.service.UserServiceImpl;
     
    @Controller         /注解这个是个Controller
    public class UserController {
     
         public static Logger log = Logger.getLogger(UserController. class );
         @Autowired
         @Qualifier ( "UserServiceImpl" )
         private UserServiceImpl userService;
         
         public void setUserService(UserServiceImpl userService) {
             this .userService = userService;
         }
     
             /*
             * @RequestMapping配置请求地址
             * @RequestParam将请求中的参数注入
             */
             <span></span> @RequestMapping (value= "/register" )    <span></span> public ModelAndView register( @RequestParam ( "username" ) String username
                                     , @RequestParam ( "password" ) String password) {
             log.debug( "register a new user" );
             ModelAndView modelView = new ModelAndView();
             Map<String, Object> modelMap = new HashMap<String, Object>();
             boolean status = userService.addUser(username, password);
             /*if(status) {
                 modelMap.put("status", true);
             } else {
                 modelMap.put("status", false);
             }*/
                     modelMap.put( "status" ,status); //感谢二楼的指正,已修改
                     modelMap.put( "date" , new Date());
             modelView.addAllObjects(modelMap);
             return modelView;
         }
         
    }
  6. service层的代码就不贴了,大家都懂的^-^
  7. 部署测试,测试的地址是http://localhost:8080/spring_mvc/register.json?username=kevin&password=hahahah浏览器中返回数据是
    {"modelAndView":{"empty":false,"reference":false,"viewName":null,"view":null,"modelMap":{"status":true,"date":1358091863067},"model":{"status":true,"date":1358091863067}}}
    ok,成功!确实是json数据。
  8. 观察一下,数据冗余有木有!没关系,定义我们自己的数据转换类:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.gswtek.util;
     
    import java.util.Map;
     
    import org.springframework.web.portlet.ModelAndView;
    import org.springframework.web.servlet.view.json.MappingJacksonJsonView;
     
    public class MappingJacksonJsonViewExd extends MappingJacksonJsonView {
     
         @Override
         protected Object filterModel(Map<String, Object> model) {
             Map<?, ?> result = (Map<?, ?>) super .filterModel(model);
             ModelAndView mav =  (ModelAndView) (result.size() != 1 ? result : result.values().iterator().next());
             return mav.getModelMap();
         }
     
    }
    更改spring-servlet.xml:
    ?
    1
    2
    3
    4
    5
    6
                     < property name = "defaultViews" >
                 < list >
                     <!-- ModelAndView里的数据变成JSON -->
                     < bean class = "com.gswtek.util.MappingJacksonJsonViewExd" />
                 </ list >
             </ property >

  9. 再次布局,测试:
    {"status":true,"date":1358092422728}
    ok,这次数据就比较简洁了。

   

     到此整个例子就结束了。这是我第一次穿写博客,貌似废话有点多,欢迎大家拍砖,哈哈~只是想把自己的经验与大家分享一下,希望初学者能少走弯路。明天还要上班,Good night everyone!^-^


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值