使用@ResponseBody自定义HttpMessageConverter来执行Json事情 [英] Custom HttpMessageConverter with @ResponseBody to do Json things

查看:95
本文介绍了使用@ResponseBody自定义HttpMessageConverter来执行Json事情的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不喜欢杰克逊。



我想使用ajax,但使用Google Gson。



所以我想弄清楚如何实现我自己的HttpMessageConverter以使用它与@ResponseBody注释。
有人可以花时间向我展示我应该去的方式吗?我应该打开哪些配置?
我也想知道如果我可以做到这一点,仍然使用< mvc:annotation-driven />?



预先感谢。



大约3天前我已经在Spring Community Foruns中提出过,但没有回答,所以我在这里问我是否有更好的机会。
Spring社区论坛链接到我的问题



我也在网上做了详尽的搜索,发现了一些关于这个主题的有趣的内容,但似乎他们正在考虑把它放在Spring 3.1中,而且我仍然使用Spring 3.0。 5:
Jira的Spring改进请求



好了......现在我正在尝试调试Spring代码以找出自己如何执行此操作,但我遇到了一些问题,如我在这里说过的:
Spring框架构建错误



如果有另一种方法可以做到这一点,我错过了它,请告诉我。

解决方

嗯...这是很难找到答案,我只好跟着这么多的线索,我认为这将是很好的,张贴在这里完整的答案不完整的信息。所以下一个搜索这个会更容易。



首先,我必须实现自定义的HttpMessageConverter:

 

包net.iogui.web.spring.converter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;

导入org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

public class GsonHttpMessageConverter extends AbstractHttpMessageConverter< Object> {

private Gson gson = new Gson();

public static final Charset DEFAULT_CHARSET = Charset.forName(UTF-8);
$ b $ public GsonHttpMessageConverter(){
super(new MediaType(application,json,DEFAULT_CHARSET));

$ b @Override
保护对象readInternal(Class< ;? extends Object> clazz,
HttpInputMessage inputMessage)throws IOException,HttpMessageNotReadableException {

试试{
return gson.fromJson(convertStreamToString(inputMessage.getBody()),clazz);
catch(JsonSyntaxException e){
throw new HttpMessageNotReadableException(Could not read JSON:+ e.getMessage(),e);
}

}

@Override
受保护的布尔支持(Class <?> clazz){
return true;
}

@Override
protected void writeInternal(Object t,
HttpOutputMessage outputMessage)throws IOException,HttpMessageNotWritableException {

// TODO:适应这个也能够接收json对象列表

String json = gson.toJson(t);

outputMessage.getBody()。write(json.getBytes());
}
$ b $ // TODO:把它移到一个更适用的utils类中
public String convertStreamToString(InputStream is)throws IOException {
/ *
*为了将InputStream转换为String,我们使用Reader.read(char []
* buffer)方法。我们迭代,直到Reader返回-1,这意味着
*没有更多的数据要读取。我们使用StringWriter类来
*产生字符串。
* /
if(is!= null){
Writer writer = new StringWriter();

char [] buffer = new char [1024];
尝试{
Reader reader = new BufferedReader(new InputStreamReader(is,UTF-8));
int n; ((n = reader.read(buffer))!= -1){
writer.write(buffer,0,n);
while
}
} finally {
is.close();
}
返回writer.toString();
} else {
return;








$ b

然后我不得不取消annnotaion驱动的标记,并在spring-mvc配置文件中完全由我自己配置​​:

 

<?xml version =1.0encoding =UTF-8?>
< beans xmlns =http://www.springframework.org/schema/beans
xmlns:xsi =http://www.w3.org/2001/XMLSchema-instance
xmlns:context =http://www.springframework.org/schema/context
xmlns:mvc =http://www.springframework.org/schema/mvc
xsi :schemaLocation =http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
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 /模式/上下文/弹簧上下文3.0.xsd>

<! - 配置@Controller编程模型 - >

<! - 仅用于类路径中的JSR-303提供程序
< bean id =validatorclass =org.springframework.validation.beanvalidation.LocalValidatorFactoryBean />
- >

< bean id =conversionServiceclass =org.springframework.format.support.FormattingConversionServiceFactoryBean/>

< bean class =org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter>
< property name =webBindingInitializer>
< bean class =net.iogui.web.spring.util.CommonWebBindingInitializer/>
< / property>
< property name =messageConverters>
< list>
< bean class =org.springframework.http.converter.ByteArrayHttpMessageConverter/>
< bean class =org.springframework.http.converter.StringHttpMessageConverter/>
< bean class =org.springframework.http.converter.ResourceHttpMessageConverter/>
< bean class =net.iogui.web.spring.converter.GsonHttpMessageConverter/>
< bean class =org.springframework.http.converter.xml.SourceHttpMessageConverter/>
< bean class =org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter/>
<! - bean class =org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter/ ​​- >
< / list>
< / property>
< / bean>
< bean id =handlerMappingclass =org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping/>


< context:component-scan base-package =net.iogui.teste.web.controller/>

<! - 将请求转发到/资源到登录视图 - >
< mvc:view-controller path =/view-name =home/>

<! - 通过有效提供$ {webappRoot} / resources /目录中的静态资源来处理/ resources / **的HTTP GET请求 - >
< mvc:resources mapping =/ resources / **location =/ resources //>

< bean id =viewResolverclass =org.springframework.web.servlet.view.InternalResourceViewResolver>
< property name =viewClassvalue =org.springframework.web.servlet.view.JstlView/>
< property name =prefixvalue =/ WEB-INF / view //>
< property name =suffixvalue =。jsp/>
< / bean>

< / beans>

看到这个,为了制作 Formater Validator 工作,我们也必须构建一个自定义的 webBindingInitializer

 

package net.iogui.web.spring.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;

public class CommonWebBindingInitializer实现WebBindingInitializer {

@Autowired(required = false)
私有验证器验证器;

@Autowired
私有ConversionService conversionService;

@Override
public void initBinder(WebDataBinder活页夹,WebRequest请求){
binder.setValidator(validator);
binder.setConversionService(conversionService);
}

}

有趣的事情我们需要手动配置一个AnnotationMethodHandlerAdapter和一个DefaultAnnotationHandlerMapping 。为了使AnnotationMethodHandlerAdapter能够处理格式和验证,我们必须配置一个验证器,一个 conversionService 并构建一个自定义的 em> webBindingInitializer



我希望所有这些都可以帮助除我之外的其他人。



绝望的搜索, @Bozho后是非常util。我也很感谢@GaryF他的回答让我去了 @Bozho post
对于那些正在尝试在Spring 3.1中做到这一点的人,请参阅@Robby Pond答案..更容易,是不是?

I don't like Jackson.

I want to use ajax but with Google Gson.

So I'm trying to figure out how to implement my own HttpMessageConverter to use it with @ResponseBody annotation. Can someone take a time to show me the way I should go? What configurations should I turn on? Also I'm wondering if I can do this and still use <mvc:annotation-driven />?

Thanks in advance.

I've already asked it in Spring Community Foruns about 3 days ago with no answer so I'm asking here to see if I get a better chance. Spring Community Forums link to my question

I've also made an exhaustive search on the web and found something interesting on this subject but it seems they're thinking to put it in Spring 3.1 and I'm still using spring 3.0.5: Jira's Spring Improvement ask

Well... now I'm trying to debug Spring code to find out myself how to do this, but I'm having some problems like I've said here: Spring Framework Build Error

If there is another way to do this and I'm missing it, please let me know.

解决方案

Well... it was so hard to find the answer and I had to follow so many clues to incomplete information that I think it will be good to post the complete answer here. So it will be easier for the next one searching for this.

First I had to implement the custom HttpMessageConverter:


package net.iogui.web.spring.converter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

    private Gson gson = new Gson();

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    public GsonHttpMessageConverter(){
        super(new MediaType("application", "json", DEFAULT_CHARSET));
    }

    @Override
    protected Object readInternal(Class<? extends Object> clazz,
                                  HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {

        try{
            return gson.fromJson(convertStreamToString(inputMessage.getBody()), clazz);
        }catch(JsonSyntaxException e){
            throw new HttpMessageNotReadableException("Could not read JSON: " + e.getMessage(), e);
        }

    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return true;
    }

    @Override
    protected void writeInternal(Object t, 
                                 HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

        //TODO: adapt this to be able to receive a list of json objects too

        String json = gson.toJson(t);

        outputMessage.getBody().write(json.getBytes());
    }

    //TODO: move this to a more appropriated utils class
    public String convertStreamToString(InputStream is) throws IOException {
        /*
         * To convert the InputStream to String we use the Reader.read(char[]
         * buffer) method. We iterate until the Reader return -1 which means
         * there's no more data to read. We use the StringWriter class to
         * produce the string.
         */
        if (is != null) {
            Writer writer = new StringWriter();

            char[] buffer = new char[1024];
            try {
                Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                int n;
                while ((n = reader.read(buffer)) != -1) {
                    writer.write(buffer, 0, n);
                }
            } finally {
                is.close();
            }
            return writer.toString();
        } else {
            return "";
        }
    }

}

Then I had to strip off the annnotaion-driven tag and configure all by my own hands on the spring-mvc configuration file:


<?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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        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">

    <!-- Configures the @Controller programming model -->

    <!-- To use just with a JSR-303 provider in the classpath 
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
    -->

    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="webBindingInitializer">
            <bean class="net.iogui.web.spring.util.CommonWebBindingInitializer" />
        </property>
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
                <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
                <bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
                <bean class="net.iogui.web.spring.converter.GsonHttpMessageConverter" />
                <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
                <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" />
                <!-- bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /-->
            </list>
        </property>
    </bean>
    <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />


    <context:component-scan base-package="net.iogui.teste.web.controller"/>

    <!-- Forwards requests to the "/" resource to the "login" view -->
    <mvc:view-controller path="/" view-name="home"/>

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
    <mvc:resources mapping="/resources/**" location="/resources/" />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

See that, to make the Formater and Validator to work, we have to build a custom webBindingInitializer too:


package net.iogui.web.spring.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;

public class CommonWebBindingInitializer implements WebBindingInitializer {

    @Autowired(required=false)
    private Validator validator;

    @Autowired
    private ConversionService conversionService;

    @Override
    public void initBinder(WebDataBinder binder, WebRequest request) {
        binder.setValidator(validator);
        binder.setConversionService(conversionService);
    }

}

An Interesting thing to see is that In order to make the configuration work without the annotaion-driven tag, we have to manually configure a AnnotationMethodHandlerAdapter and a DefaultAnnotationHandlerMapping. And in order to make the AnnotationMethodHandlerAdapter capable of handling formatting and validation, we had to configure a validator, a conversionService and to build a custom webBindingInitializer.

I hope all this helps someone else besides me.

On my desperate search, this @Bozho post was extremely util. I am also grateful to @GaryF couse his answer took me to the @Bozho post. To you that are trying to do this in Spring 3.1, see @Robby Pond answer.. A lot easier, isn't it?

这篇关于使用@ResponseBody自定义HttpMessageConverter来执行Json事情的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆