`
sbfivwsll
  • 浏览: 63398 次
  • 性别: Icon_minigender_1
  • 来自: 四川
社区版块
存档分类
最新评论

spring mvc3 + fastjson 转换 REST 参数以及输出

 
阅读更多

spring 3可以支持Rest风格参数,其内置了jackson框架作为REST的json参数转换成javabean对象,以及bean对象转换成json参数。

下文以spring 3.1.1 + fastjson为例(低于这个版本的不知道能不能行),说明如何使用springmvc构造resuful参数及输出。

不说废话了,直接上代码:Controller类:

@Controller
public class TestCon
{
    @ResponseBody
    @RequestMapping("/test")
    public Object test(@RequestBody
    final TBean tBean)
    {
        System.out.println(tBean);
        final List<Object> lists = new ArrayList<Object>();
        lists.add("3434");
        lists.add(tBean);
        lists.add(new String[] { "a", "b" });

        return lists;
    }
}

其中:@RequestBody可以使请求中的REST风格的json字符串直接转换成我们想要的参数TBean(当然,低层是使用fastjson等框架转换).

此方法的返回值为一个List对象,经过转换成json输出后,是一个js数组格式的内容。

@RequestBody不可少,表示将方法的返回值作为响应内容。

 

数据bean对象。

public class TBean
{

    private String id;

    //....
}

 

好了,最关键的一步:在springmvc 的配置文件中(XXX-servlet.xml)配置json格式转换方式:

<!-- 方式一 -->
<!--

     <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" />
        </mvc:message-converters>
    </mvc:annotation-driven>
 -->
 
<!-- 方式二 -->
 
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"></bean>
            </list>
        </property>
    </bean>

需要注意的是:方式一和方式二,选择一种实现即可。其它方式一是使用了命名空间的引入,需要引入mvc的命名空间,sprng3.0 不支持这种写法。这两种写法不能同时存在,如果同时存在,功能将异常。

核心代码就是这样的。当然不可缺少的要把fastjson框架的jar包引入到工程中。

 

模拟发起请求:

其中:{id:'34'}为REST风格的字符串,将被fastjson转换成TBean对象,直接扔给控制器的方法调用。

Content-Type: application/json; charset=utf-8
Accept: application/json
为请求头信息,以上的代码只支持Context-Type为application/json格式的头,如果没有此头或头内容不是application/json,spring将抛出415的http返回码,导致失败:

如果配置了log4j打印spring debug级别的日志,

可以看到日志中出现如下信息:

************************************************************未设置Content-Type信息的错误日志********************************************************************************

DEBUG DefaultAnnotationHandlerMapping - Mapping [/test.do] to HandlerExecutionChain with handler [test.controllers.TestCon@c81672] and 1 interceptor
DEBUG AnnotationMethodHandlerExceptionResolver - Resolving exception from handler [test.controllers.TestCon@c81672]: org.springframework.web.HttpMediaTypeNotSupportedException: Cannot extract parameter (TBean tBean): no Content-Type found
DEBUG ResponseStatusExceptionResolver - Resolving exception from handler [test.controllers.TestCon@c81672]: org.springframework.web.HttpMediaTypeNotSupportedException: Cannot extract parameter (TBean tBean): no Content-Type found
DEBUG DefaultHandlerExceptionResolver - Resolving exception from handler [test.controllers.TestCon@c81672]: org.springframework.web.HttpMediaTypeNotSupportedException: Cannot extract parameter (TBean tBean): no Content-Type found
DEBUG DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling

************************************************************设置为非application/json的错误日志*********************************************************************************

DEBUG DefaultAnnotationHandlerMapping - Mapping [/test.do] to HandlerExecutionChain with handler [test.controllers.TestCon@c81672] and 1 interceptor
DEBUG AnnotationMethodHandlerExceptionResolver - Resolving exception from handler [test.controllers.TestCon@c81672]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/pan' not supported
DEBUG ResponseStatusExceptionResolver - Resolving exception from handler [test.controllers.TestCon@c81672]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/pan' not supported
DEBUG DefaultHandlerExceptionResolver - Resolving exception from handler [test.controllers.TestCon@c81672]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/pan' not supported
DEBUG DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling

 

如果content-type输入正确的话,将会看到正确的输出结果:

 

 

*******************************************分隔线*****************************************************************************************************************************************

 

如果你不需要要求输入Context-Type即可解析的话,还有另一种方式实现,参考:

(以下内容转自:http://zjumty.iteye.com/blog/1927890

自定义Spring MVC3的参数映射和返回值映射 + fastjson

首先说一下场景:在一些富客户端Web应用程序中我们会有比较多的Ajax调用,并且希望与服务器交互的数据需要是复杂的JSON对象。 fastjon是一个非常高效的JSON序列化和反序列化库,我希望我们输入的JSON串能通过fastjson直接反序列化为一个复杂的JavaBean对象,同时我的返回值能够能通过fastjson序列化为JSON串。

所谓复杂的JavaBean就是,不仅仅只有一层属性,而是属性也是JavaBean的情况, 例如:

Java代码 收藏代码
  1. public class FooBean {
  2. private String name;
  3. private Long id;
  4. private Date birthday;
  5. private List<Address> addresses;
  6. public String getName() {
  7. return name;
  8. }
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. public Long getId() {
  13. return id;
  14. }
  15. public void setId(Long id) {
  16. this.id = id;
  17. }
  18. public Date getBirthday() {
  19. return birthday;
  20. }
  21. public void setBirthday(Date birthday) {
  22. this.birthday = birthday;
  23. }
  24. public List<Address> getAddresses() {
  25. return addresses;
  26. }
  27. public void setAddresses(List<Address> addresses) {
  28. this.addresses = addresses;
  29. }
  30. @Override
  31. public String toString() {
  32. return "FooBean{" +
  33. "name='" + name + '\'' +
  34. ", id=" + id +
  35. ", birthday=" + birthday +
  36. ", addresses=" + addresses +
  37. '}';
  38. }
  39. }



Java代码 收藏代码
  1. public class Address {
  2. private String street;
  3. private int number;
  4. public String getStreet() {
  5. return street;
  6. }
  7. public void setStreet(String street) {
  8. this.street = street;
  9. }
  10. public int getNumber() {
  11. return number;
  12. }
  13. public void setNumber(int number) {
  14. this.number = number;
  15. }
  16. @Override
  17. public String toString() {
  18. return "Address{" +
  19. "street='" + street + '\'' +
  20. ", number=" + number +
  21. '}';
  22. }
  23. }




当然,结构还可以再复杂,Adress对象里还可以又复杂JavaBean的属性。

在SpringMVC3中我们可以把输入简单的映射为某个Action方法的参数, 例如:

Java代码 收藏代码
  1. @RequestMapping(value="/someAction", method=RequestMethod.POST)
  2. public String processSubmit(FooBean fooBean, Model model) {
  3. // 利用fooBean
  4. return “views/some_page”;
  5. }



用Spring MVC3, 我们可以把Form里的字段轻松的映射到JavaBean的属性。 Spring MVC3 提供了丰富的参数映射机制, 详细信息可以参见这里

同时对于Spring MVC3默认的提供的映射机制不能涵盖的对象,我们可以通过扩展HandlerMethodArgumentResolver和HttpMessageConverter的机制来实现。
HandlerMethodArgumentResolver对应输入, HttpMessageConverter对应输出

假设对于上面的FooBean, 我们有这样一个JSON对象和它对应:

Javascript代码 收藏代码
  1. var data = {
  2. name : "matianyi",
  3. id : 12345,
  4. birthday : "1983-07-01 01:12:12",
  5. addresses : [
  6. {
  7. street : "street1",
  8. number : 1
  9. },
  10. {
  11. street : "street2",
  12. number : 2
  13. }
  14. ]
  15. };



Spring MVC3 本身也提供直接把JSON对象映射到JavaBean的功能,例如MappingJackson2HttpMessageConverter和MappingJackson2JsonView。
在这里我们希望通过fastjson来实现序列化和反序列化。所以我们要自定义一个HandlerMethodArgumentResolver用来指定HttpServletRequest的Body映射到一个JavaBean。并且返回的JavaBean通过fastjson序列化。

方法的定义是这样的:

Java代码 收藏代码
  1. @RequestMapping(value = "/fastjson", method = RequestMethod.POST)
  2. public @ResponseBody FooBean fastjson2(@FastJson FooBean foo) {
  3. System.out.println(foo);
  4. return foo;
  5. }



首先这里有个@FastJson的标注,这是我们为了让自己的HandlerMethodArgumentResolver能够识别这个参数是需要自己来处理而定义的一个Annotation

Java代码 收藏代码
  1. @Target(ElementType.PARAMETER)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface FastJson {
  5. }



然后就是定义一个FastJsonArgumentResolver,来对HttpServletRequest的body进行解析:

Java代码 收藏代码
  1. public class FastJsonArgumentResolver implements HandlerMethodArgumentResolver {
  2. @Override
  3. public boolean supportsParameter(MethodParameter parameter) {
  4. return parameter.getParameterAnnotation(FastJson.class) != null;
  5. }
  6. @Override
  7. public Object resolveArgument(MethodParameter parameter,
  8. ModelAndViewContainer mavContainer,
  9. NativeWebRequest webRequest,
  10. WebDataBinderFactory binderFactory) throws Exception {
  11. HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
  12. // content-type不是json的不处理
  13. if (!request.getContentType().contains("application/json")) {
  14. return null;
  15. }
  16. // 把reqeust的body读取到StringBuilder
  17. BufferedReader reader = request.getReader();
  18. StringBuilder sb = new StringBuilder();
  19. char[] buf = new char[1024];
  20. int rd;
  21. while((rd = reader.read(buf)) != -1){
  22. sb.append(buf, 0, rd);
  23. }
  24. // 利用fastjson转换为对应的类型
  25. if(JSONObjectWrapper.class.isAssignableFrom(parameter.getParameterType())){
  26. return new JSONObjectWrapper(JSON.parseObject(sb.toString()));
  27. } else {
  28. return JSON.parseObject(sb.toString(), parameter.getParameterType());
  29. }
  30. }
  31. }



在这里,我们只针对content-type是application/json的对象做处理,最后通过JSON.parseObject方法简单的把JSON串反序列化为指定的类型。

这里有一个JSONObjectWrapper对象需要解释一下。 原本我是想如果Action方法的参数的类型是JSONObject这样的原始类型的话就直接利用JSON.parseObject(sb.toString())映射过去。 但是由于JSONObject实现了Map结果,所以Spring MVC3的默认处理器MapMethodProcessor会先起作用,这样就不能正常的映射成JSONObject对象了。 没有办法做了一个简单的JSONObject包装类,以使MapMethodProcessor不能对其进行处理。

Java代码 收藏代码
  1. public class JSONObjectWrapper {
  2. private JSONObject jsonObject;
  3. public JSONObjectWrapper(JSONObject jsonObject) {
  4. this.jsonObject = jsonObject;
  5. }
  6. public JSONObject getJSONObject() {
  7. return jsonObject;
  8. }
  9. }



这里顺便提一下,Spring MVC自己的HandlerMethodArgumentResolver有哪些,并且会以什么样的顺序执行呢?
其实定义在RequestMappingHandlerAdapter里:

Java代码 收藏代码
  1. /**
  2. * Return the list of argument resolvers to use including built-in resolvers
  3. * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
  4. */
  5. private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
  6. List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
  7. // Annotation-based argument resolution
  8. resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
  9. resolvers.add(new RequestParamMapMethodArgumentResolver());
  10. resolvers.add(new PathVariableMethodArgumentResolver());
  11. resolvers.add(new PathVariableMapMethodArgumentResolver());
  12. resolvers.add(new MatrixVariableMethodArgumentResolver());
  13. resolvers.add(new MatrixVariableMapMethodArgumentResolver());
  14. resolvers.add(new ServletModelAttributeMethodProcessor(false));
  15. resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
  16. resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
  17. resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
  18. resolvers.add(new RequestHeaderMapMethodArgumentResolver());
  19. resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
  20. resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
  21. // Type-based argument resolution
  22. resolvers.add(new ServletRequestMethodArgumentResolver());
  23. resolvers.add(new ServletResponseMethodArgumentResolver());
  24. resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
  25. resolvers.add(new RedirectAttributesMethodArgumentResolver());
  26. resolvers.add(new ModelMethodProcessor());
  27. resolvers.add(new MapMethodProcessor());
  28. resolvers.add(new ErrorsMethodArgumentResolver());
  29. resolvers.add(new SessionStatusMethodArgumentResolver());
  30. resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
  31. // Custom arguments
  32. if (getCustomArgumentResolvers() != null) {
  33. resolvers.addAll(getCustomArgumentResolvers());
  34. }
  35. // Catch-all
  36. resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
  37. resolvers.add(new ServletModelAttributeMethodProcessor(true));
  38. return resolvers;
  39. }



在这里我们可以看到:

  • Spring MVC本身提供了非常丰富的HandlerMethodArgumentResolver实现。
  • HandlerMethodArgumentResolver是按顺序执行,当然为了性能Spring本身是有Cache的,一旦确定了某一个参数可以应用的HandlerMethodArgumentResolver,下次就不会再遍历这个List了。
  • 自定的HandlerMethodArgumentResolver会晚于Spring自己的被执行,这也是上面提到的JSONObject会被MapMethodProcessor先处理的原因。
  • Spring自己的JSON映射机制是通过RequestResponseBodyMethodProcessor + AllEncompassingFormHttpMessageConverter来实现的
  • 很不幸这是一个private方法, 你没有办法简单的改变Spring MVC的默认行为,除非你重写RequestMappingHandlerAdapter



好了,有了FastJsonArgumentResolver, 接下来我们要让它生效:

Xml代码 收藏代码
  1. <mvc:annotation-driven>
  2. <mvc:argument-resolvers>
  3. <beans:bean class="org.springframework.samples.mvc.fastjson.FastJsonArgumentResolver"/>
  4. </mvc:argument-resolvers>
  5. <mvc:message-converters>
  6. <beans:bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/>
  7. </mvc:message-converters>
  8. </mvc:annotation-driven>



就是个Spring的配置,这里就不多讲了。除了FastJsonArgumentResolver,我们还配置了FastJsonHttpMessageConverter来对返回值进行序列化。

本来我是想自己写一个FastJsonHttpMessageConverter, 后来发现fastjson库里已经存在了, 我就不自己造轮子了。我们自己来看看实现吧,截取了一部分:

Java代码 收藏代码
  1. @Override
  2. protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException,
  3. HttpMessageNotWritableException {
  4. OutputStream out = outputMessage.getBody();
  5. String text = JSON.toJSONString(obj, features);
  6. byte[] bytes = text.getBytes(charset);
  7. out.write(bytes);
  8. }



实现很简单, 就不详细说了。

最后来看看如何通过Ajax调用上面的Action方法:

Java代码 收藏代码
  1. var data = {
  2. name : "matianyi",
  3. id : 12345,
  4. birthday : "1983-07-01 01:12:12",
  5. addresses : [
  6. {
  7. street : "street1",
  8. number : 1
  9. },
  10. {
  11. street : "street2",
  12. number : 2
  13. }
  14. ]
  15. };
  16. var link = $(this);
  17. $.ajax({
  18. url:"/spring-sample/fastjson1",
  19. dataType:"json",
  20. type:"POST",
  21. contentType: "application/json",
  22. data : JSON.stringify(data),
  23. success : function(obj){
  24. console.log(obj);
  25. }
  26. });



两点需要注意:

  • contentType: "application/json"
  • data : JSON.stringify(data)


这样JavaScript的对象会被转换为JSON串,并且最为HttpRequest的BODY传给服务器。

分享到:
评论

相关推荐

    springmvc+fastjson demo

    3. **Spring MVC 中使用 Fastjson**:在 Spring MVC 中,Fastjson 可用于接收 JSON 格式的请求参数,或者将处理结果转换成 JSON 响应。例如,使用 `@RequestBody` 注解接收 JSON 数据,使用 `@ResponseBody` 注解将...

    jar包整合:Springmvc+hibernate+Ehcache+shior+mysql+Oracle+fastjson

    1. **SpringMVC**:Spring MVC是Spring框架的一部分,它是一个基于模型-视图-控制器(MVC)设计模式的Web应用框架。它提供了处理HTTP请求、数据绑定、验证和视图渲染等功能,使得开发者可以轻松地构建可维护和测试的...

    Java项目:(小程序)全套商城系统(spring+spring mvc+mybatis+layui+微信小程)

    环境配置: 1.1 springframework4.3.7.RELEASE 1.2 mybatis3.1.0s MyBatis-Plus 3.1.0 1.3 shirol.3.2 1.4 servlet3.1.0 1.5 druid1.0.28 1.6 slf4j1.7.19 1.7 fastjson1.2.30 1.8 poi3.15 1.9 velocityl .7 1.10 ...

    springmvc4+spring4+hibernate5.1.3+二级缓存ehcache+fastjson配置

    在IT领域,尤其是在Java Web开发中,`SpringMVC`、`Spring`、`Hibernate`以及`Ehcache`和`Fastjson`是常见的技术组件,它们分别在不同的层面上发挥着关键作用。以下是这些技术的详细介绍: 1. **SpringMVC**: ...

    【Gson+fastjson】json转换工具

    在Java开发中,为了方便地进行JSON与Java对象之间的转换,我们常常会使用到Gson和Fastjson这两个库。 **Gson库** Gson是Google提供的一款开源库,它能够将Java对象转换为JSON字符串,同时也能够将JSON内容反序列...

    springboot 使用spring cache缓存 和 使用fastjson配置redis系列化

    在本篇文档中,我们将探讨如何使用Spring Cache来缓存数据,并结合Fastjson配置Redis序列化,确保数据正确存储和读取。 首先,我们需要在`pom.xml`中添加必要的依赖。Spring Boot的`spring-boot-starter-cache`模块...

    okhttp请求+FastJson解析数据

    在接收到服务器响应后,我们通常会使用FastJson将JSON字符串转换为Java对象或者将Java对象转换为JSON字符串。 例如,假设我们有一个简单的Java对象`User`,我们可以通过以下方式使用FastJson解析JSON: ```java ...

    ssm(spring+spring mvc+mybatis)高仿小米电子商城项目实例

    ssm(spring+spring mvc+mybatis)高仿小米电子商城项目实例 开发环境:Eclipse ,JDK 1.8 ,Tomcat7 技术选型: 后端技术 核心框架:Spring Framework 4.3.5 视图框架:Spring MVC 4.3.5 任务调度:Spring + ...

    redis +dubbo +mongo+fastjson

    4. FastJSON:FastJSON 是阿里巴巴的一个高性能的 JSON 库,它提供了 JSON 与 Java 对象之间的快速转换,包括 JSON 字符串到 Java 对象的解析,以及 Java 对象到 JSON 字符串的序列化。Fastjson-1.2.2 版本具有良好...

    SpringMVC+fastjson+Swagger集成示例源码

    3. 使用Fastjson:在Controller层的处理方法中,使用Fastjson进行对象到JSON的转换,如`JSON.toJSONString(obj)`和`JSON.parseObject(jsonStr, Class)`。 4. 集成Swagger:在SpringMVC配置中添加Swagger的相关配置...

    okhttp3+fastjson+识别身份证+生成自定义二维码.

    功能刚测试完毕,不知道什么原因审核不通过给我撤掉了,我上传的起码是亲测可用的吧,总比那些扣了积分下载的还不能用的强吧,功能部分登录进入主界面的扫一扫,二维码是自定义生成的,身份证识别是自定义相机图文...

    spring + spring mvc+mybatis plus

    里面包含了ssm基本整合以外,还包含了jackson demo、fastjson demo、freemarker demo、vus.js 2.5 demo、mybatis plus代码自动生成工具、mybatis plus 自定义分页示例、spring mvc各种类型参数传递demo、logback配置...

    Spring MVC4.3.5+MyBatis3.4.2+Apache Shiro1.3.2整合开发高仿小米商城的后台用户管理系统

    视图框架:Spring MVC 4.3.5 任务调度:Spring + Quartz 2.2.3 持久层框架:MyBatis 3.4.2 + Mybatis-plus 2.0.1 数据库连接池:Alibaba Druid 1.0 缓存框架:Ehcache 2.6 + Redis 2.9.0 日志管理:SLF4J 1.7 + Log4...

    基于springboot+druid+fastjson多数据源分布式事务处理源码.zip

    7. **代码组织结构**: "springboot-druid-master"这个文件名暗示了项目的代码组织可能基于Git仓库的master分支,包含了Spring Boot、Druid相关的配置和实现,以及Fastjson的使用示例。项目中可能包含`pom.xml`文件来...

    Java四大json库gson+fastjson+jackson+json-lib

    此外,它还支持JSON到Java对象的映射,以及JSON到XML的转换,适合于大量数据处理和性能敏感的应用场景。 3. Jackson: Jackson是另一个广受欢迎的JSON库,由FasterXML团队维护。Jackson以其高效性能和丰富的功能...

    SpringMvc+mybatis+fastJson+druid+resteasy...

    开发工具采用IDEA,用maven构建的项目,框架采用SpringMVC,数据库采用mysql与mybatis配合,数据格式采用阿里巴巴工具fastJson,数据源druid,另外还添加了resteasy中的功能

    ssm(spring+spring mvc+mybatis)电子商城项目

    视图框架:Spring MVC 4.3.5 任务调度:Spring + Quartz 2.2.3 持久层框架:MyBatis 3.4.2 + Mybatis-plus 2.0.1 日志管理:SLF4J 1.7 + Log4j2 2.7 工具类:Apache Commons、Jackson 2.2、fastjson 1.2.20 前端技术...

    httpxmlRequest+ajax+jquery+fastjson+jsp异步通讯实战案例精讲

    6.利用JQuery的$.ajax,$.post,$.get方法,分别返回text,xml,json等格式数据,通过fastjson生成JSON格式数据; 7.使用JQuery的ajax技术,在一个页面实现新增、修改、删除、查询、分页,文件上传等功能;

Global site tag (gtag.js) - Google Analytics