我想与Google Gson一起使用Ajax。
因此,我试图弄清楚如何实现自己的HttpMessageConverter以便将其与@ResponseBody批注一起使用。有人可以花点时间告诉我我应该走的路吗?我应该打开什么配置?我也想知道我是否可以这样做并且仍然使用?
提前致谢。
好吧…很难找到答案,我不得不遵循很多线索来查找不完整的信息,因此我认为在此处发布完整的答案会很好。因此,下一个搜索将更容易。
首先,我必须实现自定义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 ""; } } }
然后,我不得不剥离annantotaion驱动的标签,并用自己的双手在spring-mvc配置文件上进行所有配置:
<?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>
看到,要使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 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); } }
有趣的事情是,为了使配置在没有注释驱动标签的情况下工作,我们必须手动配置AnnotationMethodHandlerAdapter和DefaultAnnotationHandlerMapping。为了使AnnotationMethodHandlerAdapter能够处理格式和验证,我们必须配置一个验证器,一个conversionService并构建一个自定义的webBindingInitializer。