Google-GSON 的 Spring MVC 映射视图?

Posted

技术标签:

【中文标题】Google-GSON 的 Spring MVC 映射视图?【英文标题】:Spring MVC mapping view for Google-GSON? 【发布时间】:2011-04-14 19:41:28 【问题描述】:

有谁知道Gson 是否有Spring MVC 映射视图?我正在寻找类似于org.springframework.web.servlet.view.json.MappingJacksonJsonView 的东西。

理想情况下,它将采用我的 ModelMap 并将其呈现为 JSON,尊重我在 ContentNegotiatingViewResolver 声明中设置的 renderAttributes

我们计划在应用程序中广泛使用 Gson,因为它看起来比 Jackson 更安全、更好。也就是说,我们需要有两个不同的 JSON 库才能执行原生 JSON 视图。

提前致谢!

[交叉发布到Spring forums]

【问题讨论】:

想详细说明“似乎更安全、更好”?如,以什么方式更好? (或者更安全,就此而言) +1,正是我想要的。 对于从 Spring boot 5.0 开始来到这里的任何人,请查看我的回答 force spring to use GSON, instead of Jackson 【参考方案1】:

我建议像 MappingJacksonJsonView 一样扩展 AbstractView。

就个人而言,对于 JSON,我更喜欢使用 @Responsebody,并且只返回对象而不是模型和视图,这样更容易测试。如果您想为此使用 GSON,只需像这样创建一个自定义 HttpMessageConverter:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.vitalimages.string.StringUtils;
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 org.springframework.stereotype.Component;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.sql.Timestamp;

@Component
public class GSONHttpMessageConverter extends AbstractHttpMessageConverter<Object> 

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

    private GsonBuilder gsonBuilder = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation()
            .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
            .registerTypeAdapter(Timestamp.class, new GSONTimestampConverter());

    public GSONHttpMessageConverter() 
        super(new MediaType("application", "json", DEFAULT_CHARSET));
    

    @Override
    protected boolean supports(Class<?> clazz) 
        // should not be called, since we override canRead/Write instead
        throw new UnsupportedOperationException();
    

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) 
        return MediaType.APPLICATION_JSON.isCompatibleWith(mediaType);
    

    public boolean canWrite(Class<?> clazz, MediaType mediaType) 
        return MediaType.APPLICATION_JSON.isCompatibleWith(mediaType);
    

    public void registerTypeAdapter(Type type, Object serializer) 
        gsonBuilder.registerTypeAdapter(type, serializer);
    

    @Override
    protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException 
        try 
            Gson gson = gsonBuilder.create();
            return    gson.fromJson(StringUtils.convertStreamToString(inputMessage.getBody()), clazz);
         catch (JsonParseException e) 
            throw new HttpMessageNotReadableException("Could not read JSON: " + e.getMessage(), e);
        
    

    @Override
    protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException 
        Type genericType = TypeToken.get(o.getClass()).getType();

        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputMessage.getBody(), DEFAULT_CHARSET));
        try 
            // See http://code.google.com/p/google-gson/issues/detail?id=199 for details on SQLTimestamp conversion
            Gson gson = gsonBuilder.create();
            writer.append(gson.toJson(o, genericType));
         finally 
            writer.flush();
            writer.close();
        
    

然后将其添加到处理程序适配器中的转换器列表中,如下所示:

@Bean
public HandlerAdapter handlerAdapter() 
    final AnnotationMethodHandlerAdapter handlerAdapter = new AnnotationMethodHandlerAdapter();
    handlerAdapter.setAlwaysUseFullPath(true);
    List<HttpMessageConverter<?>> converterList = new ArrayList<HttpMessageConverter<?>>();
    converterList.addAll(Arrays.asList(handlerAdapter.getMessageConverters()));
    converterList.add(jibxHttpMessageConverter);
    converterList.add(gsonHttpMessageConverter);
    handlerAdapter.setMessageConverters(converterList.toArray(new HttpMessageConverter<?>[converterList.size()]));
    return handlerAdapter;

【讨论】:

你能对 bean 做同样的事情,但在 applicationContext.xml 中吗?【参考方案2】:

aweigold 帮助我完成了大部分工作,但为了具体概述基于 Spring 3.1 Java 的配置的解决方案,这就是我所做的。

从spring-android-rest-template 项目中获取GsonHttpMessageConverter.java。

在您的 MVC 配置中使用消息转换器注册您的 GsonHttpMessageConverter

@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter 
  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) 
    converters.add(new GsonHttpMessageConverter());
  

Spring 文档概述了这个过程,但并不十分清楚。为了让它正常工作,我不得不扩展WebMvcConfigurerAdapter,然后覆盖configureMesageConverters。完成此操作后,您应该能够在控制器方法中执行以下操作:

@Controller
public class AppController 
  @RequestMapping(value = "messages", produces = MediaType.APPLICATION_JSON_VALUE)
  public List<Message> getMessages() 
    // .. Get list of messages
    return messages;
  

瞧! JSON 输出。

【讨论】:

谢谢,这对我很有帮助!使用 Spring 3.2.2 和 jackson,我无法摆脱它说的问题:406 not accaptable。我这样做了,它奏效了,但我还必须将 添加到服务 xml 文件中。

以上是关于Google-GSON 的 Spring MVC 映射视图?的主要内容,如果未能解决你的问题,请参考以下文章

使用google-gson类库解析json文件

google-gson库下的gson的基本使用

Spring MVC学习笔记---Spring MVC 的HelloWorld

Spring MVC学习笔记---Spring MVC 的HelloWorld

Spring MVC学习—MVC的介绍以及Spring MVC的入门案例

spring mvc怎么存cookie