首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SpringMVC、Gson和GAE集成

SpringMVC、Gson和GAE集成
EN

Stack Overflow用户
提问于 2013-10-06 00:28:14
回答 2查看 3.5K关注 0票数 2

我正在使用RESTful、Gson制作一个简单的SpringMVC服务器,并将其部署到GAE中。一切都很好,如果我试图像这样映射我的请求:

代码语言:javascript
复制
import java.util.Arrays;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;

import com.generic.server.model.Widget;
import com.generic.server.services.WidgetService;
import com.google.gson.Gson;

@Component
@Path("/widget")
public class WidgetRestService {

    /**
     * @return All the widgets info.
     * @uri http://localhost:8888/rest/widget/
     */
    @GET @Path("/") @Produces(MediaType.APPLICATION_JSON)
    public @ResponseBody String getAll() {
    Gson g = new Gson();
    return g.toJson(Arrays.asList(new Widget("BuyerApp", "Buy something now!"),
            new Widget("DogSwitcher", "Tired of your dog? Switch it right now!")));
    }
}

这将打印所需的结果。但是我想摆脱那个烦人的Gson实例。所以我做了我自己的定制HttpMessageConverter

代码语言:javascript
复制
@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");

    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();
        }
    }
}

并将其添加到applicationContext.xml

代码语言:javascript
复制
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
           http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.1.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.3.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">


    <mvc:annotation-driven />

    <!-- If you hit /home/ on the browser this will redirect you to the login 
        view -->
    <mvc:view-controller path="/" view-name="login" />
    <mvc:resources location="/resources/" mapping="/resources/**" />

    <context:component-scan
        base-package="com.generic.server.services,
                                    com.generic.server.model,
                                    com.generic.server.rest,
                                    com.generic.server.ui.controller" />

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

    <mvc:default-servlet-handler />

    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="com.generic.server.util.GSONHttpMessageConverter"/>
            </list>
        </property>
    </bean>
</beans>

现在,我将更改映射为返回对象的请求的方式:

代码语言:javascript
复制
    /**
     * @return All the widgets info.
     * @uri http://localhost:8888/rest/widget/
     */
    @GET @Path("/") @Produces(MediaType.APPLICATION_JSON)
    public @ResponseBody List<Widget> getAll() {
        return Arrays.asList(new Widget("BuyerApp", "Buy something now!"),
                new Widget("DogSwitcher", "Tired of your dog? Switch it right now!"));
    }

但是,当我试图访问localhost:8888/rest/widget/服务器崩溃时,向我展示以下消息:

代码语言:javascript
复制
javax.ws.rs.WebApplicationException
at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:268)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1029)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:941)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:932)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:384)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:451)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:632)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:123)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:368)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:351)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:97)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:485)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

我是GAE的新手,但我搜索了这么多页面和另一个页面,我认为这是映射其他请求的方法。任何小费都是非常感谢的。

更新:

我还尝试使用来自RestTemplateRestTemplate类。另一件需要我注意的事情是,如果删除AnnotationMethodHandlerAdapter bean,就会得到相同的堆栈跟踪。GsonHttpMessageConverter没有被使用。

我还尝试实现自己的WebMvcConfigurationSupport,并通过编程将消息转换器添加到那里,如下所示:

代码语言:javascript
复制
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
   RequestMappingHandlerAdapter handlerAdapter = super.requestMappingHandlerAdapter();
   handlerAdapter.getMessageConverters().add(0, new GSONHttpMessageConverter());
   return handlerAdapter;
}

但这既不能覆盖requestMappingHandlerAdapter方法,也不能覆盖configureMessageConverters方法。如果没有任何更改,堆栈跟踪也是一样的。

解决方案:

我的应用程序上下文:

代码语言:javascript
复制
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:security="http://www.springframework.org/schema/security"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="
               http://www.springframework.org/schema/beans  
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/tx 
               http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context-3.1.xsd
               http://www.springframework.org/schema/security
               http://www.springframework.org/schema/security/spring-security-3.0.3.xsd
               http://www.springframework.org/schema/mvc
               http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">


        <!-- If you hit /home/ on the browser this will redirect you to the login 
            view -->
        <mvc:view-controller path="/" view-name="login" />
        <mvc:resources location="/resources/" mapping="/resources/**" />

        <context:component-scan
            base-package="com.generic.server.services,
                                        com.generic.server.model,
                                        com.generic.server.rest,
                                        com.generic.server.ui.controller" />

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

        <mvc:annotation-driven>
            <mvc:message-converters register-defaults="true">
                <bean class="com.generic.server.util.GsonHttpMessageConverter" />
            </mvc:message-converters>
        </mvc:annotation-driven>
    </beans>

我的网络服务:

代码语言:javascript
复制
    @Controller
    @RequestMapping("/rest")
    public class WidgetRestService {

        /**
         * @return All the widgets info.
         * @uri http://localhost:8888/rest/widget/
         */
        @RequestMapping(value="/widget", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON)
        public @ResponseBody List<Widget> getAll() {
            return Arrays.asList(new Widget("BuyerApp", "Buy something now!"), new Widget("DogSwitcher", "Tired of your dog? Switch it right now!"));    
        }
    }

主要的问题是我试图使用泽西岛来公开网络服务。相反,我改变了,现在我使用了SpringMVC注释。

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19204110

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档