GWT RPC 测试数据库连接

Posted

技术标签:

【中文标题】GWT RPC 测试数据库连接【英文标题】:GWT RPC Testing DB connection 【发布时间】:2010-10-02 00:33:25 【问题描述】:

我正在使用 GWT RPC 连接到服务器端。在服务器端,我必须连接到 mysql 数据库,从中获取我需要的数据。我的问题是当我想测试我的应用程序时哪个是最佳实践,因为我还没有在 Tomcat 应用程序服务器上部署它,而且如果它没有部署,我似乎无法测试它。当我在开发模式下测试它时,我无法连接到数据库。我是否必须将其部署在 Tomcat 上才能测试我的应用程序,还是有其他方法。

附:我包含了 JDBC 驱动程序,所以这不是问题。

【问题讨论】:

您应该能够使用 Tomcat 之外的数据库测试您的应用程序。你遇到了什么错误? 【参考方案1】:

您无需部署到 Tomcat 或任何其他网络服务器即可测试您的应用程序。将你的测试分成几层(JDBC 或 JPA 层、Service 层),使用 JUnit 和 Spring 测试就可以了。

看看这个文档: http://static.springsource.org/spring/docs/2.5.x/reference/testing.html

【讨论】:

【参考方案2】:

由于您没有发布任何异常,因此目前不知道您遇到了什么问题,但是当我在开发模式下测试我的 GWT 代码时,我遵循的最佳实践是将来自 GWT 的请求代理到在不同的应用服务器上运行的后端实现。由于您计划将代码移动到 tomcat,因此我假设您将在运行在 tomcat 上的 J2EE 项目的 war 目录下移动 GWT 编译的代码,并且实际的 db 调用将从这个 J2EE 项目中完成。请按照以下步骤操作。

基本上,在您的 GWT 应用程序中,在“服务器”端,您需要创建一个代理 servlet,它将所有请求代理到不同的端口(运行您的后端应用程序的端口 - 例如 tomcat 的港口)。

您需要同时运行两个应用程序(显然在不同的端口上)。这样,当您处于 GWT 开发模式时,所有请求都会首先发送到 jetty 应用服务器,然后转发到 tomcat,这样您就可以继续测试,而无需来回复制文件并测试您的真实后端实现。

代理Servlet(来自http://edwardstx.net/wiki/attach/HttpProxyServlet/ProxyServlet.java)


package com.xxxxxxx.xxxxx.gwt.xxxxx.server;


import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;

/**
 * ProxyServlet from http://edwardstx.net/wiki/attach/HttpProxyServlet/ProxyServlet.java
 * (This seems to be a derivative of Noodle -- http://noodle.tigris.org/)
 * 
 * Patched to skip "Transfer-Encoding: chunked" headers, avoid double slashes
 * in proxied URLs, handle GZip and allow GWT RPC.
 */
public class ProxyServlet extends HttpServlet 

    private static final int FOUR_KB = 4196;

    /**
     * Serialization UID.
     */
    private static final long serialVersionUID = 1L;
    /**
     * Key for redirect location header.
     */
    private static final String STRING_LOCATION_HEADER = "Location";
    /**
     * Key for content type header.
     */
    private static final String STRING_CONTENT_TYPE_HEADER_NAME = "Content-Type";
    /**
     * Key for content length header.
     */
    private static final String STRING_CONTENT_LENGTH_HEADER_NAME = "Content-Length";
    /**
     * Key for host header
     */
    private static final String STRING_HOST_HEADER_NAME = "Host";
    /**
     * The directory to use to temporarily store uploaded files
     */
    private static final File FILE_UPLOAD_TEMP_DIRECTORY = new File(System.getProperty("java.io.tmpdir"));

    // Proxy host params
    /**
     * The host to which we are proxying requests. Default value is "localhost".
     */
    private String stringProxyHost = "localhost";
    /**
     * The port on the proxy host to wihch we are proxying requests. Default value is 80.
     */
    private int intProxyPort = 80;
    /**
     * The (optional) path on the proxy host to wihch we are proxying requests. Default value is "".
     */
    private String stringProxyPath = "";
    /**
     * Setting that allows removing the initial path from client. Allows specifying /twitter/* as synonym for twitter.com.
     */
    private boolean removePrefix;
    /**
     * The maximum size for uploaded files in bytes. Default value is 5MB.
     */
    private int intMaxFileUploadSize = 5 * 1024 * 1024;
    private boolean isSecure;
    private boolean followRedirects;

    /**
     * Initialize the ProxyServlet
     * @param servletConfig The Servlet configuration passed in by the servlet container
     */
    public void init(ServletConfig servletConfig) 
        // Get the proxy host
        String stringProxyHostNew = servletConfig.getInitParameter("proxyHost");
        if (stringProxyHostNew == null || stringProxyHostNew.length() == 0) 
            throw new IllegalArgumentException("Proxy host not set, please set init-param 'proxyHost' in web.xml");
        
        this.setProxyHost(stringProxyHostNew);
        // Get the proxy port if specified
        String stringProxyPortNew = servletConfig.getInitParameter("proxyPort");
        if (stringProxyPortNew != null && stringProxyPortNew.length() > 0) 
            this.setProxyPort(Integer.parseInt(stringProxyPortNew));
        
        // Get the proxy path if specified
        String stringProxyPathNew = servletConfig.getInitParameter("proxyPath");
        if (stringProxyPathNew != null && stringProxyPathNew.length() > 0) 
            this.setProxyPath(stringProxyPathNew);
        
        // Get the maximum file upload size if specified
        String stringMaxFileUploadSize = servletConfig.getInitParameter("maxFileUploadSize");
        if (stringMaxFileUploadSize != null && stringMaxFileUploadSize.length() > 0) 
            this.setMaxFileUploadSize(Integer.parseInt(stringMaxFileUploadSize));
        
    

    /**
     * Performs an HTTP GET request
     * @param httpServletRequest The @link HttpServletRequest object passed
     *                            in by the servlet engine representing the
     *                            client request to be proxied
     * @param httpServletResponse The @link HttpServletResponse object by which
     *                             we can send a proxied response to the client
     */
    public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
            throws IOException, ServletException 
        // Create a GET request
        String destinationUrl = this.getProxyURL(httpServletRequest);
        debug("GET Request URL: " + httpServletRequest.getRequestURL(),
              "Destination URL: " + destinationUrl);
        GetMethod getMethodProxyRequest = new GetMethod(destinationUrl);
        // Forward the request headers
        setProxyRequestHeaders(httpServletRequest, getMethodProxyRequest);
        setProxyRequestCookies(httpServletRequest, getMethodProxyRequest);
        // Execute the proxy request
        this.executeProxyRequest(getMethodProxyRequest, httpServletRequest, httpServletResponse);
    

    /**
     * Performs an HTTP POST request
     * @param httpServletRequest The @link HttpServletRequest object passed
     *                            in by the servlet engine representing the
     *                            client request to be proxied
     * @param httpServletResponse The @link HttpServletResponse object by which
     *                             we can send a proxied response to the client
     */
    public void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
            throws IOException, ServletException 
        // Create a standard POST request
        String contentType = httpServletRequest.getContentType();
        String destinationUrl = this.getProxyURL(httpServletRequest);
        debug("POST Request URL: " + httpServletRequest.getRequestURL(),
              "    Content Type: " + contentType,
              " Destination URL: " + destinationUrl);
        PostMethod postMethodProxyRequest = new PostMethod(destinationUrl);
        // Forward the request headers
        setProxyRequestHeaders(httpServletRequest, postMethodProxyRequest);
        setProxyRequestCookies(httpServletRequest, postMethodProxyRequest);
        // Check if this is a mulitpart (file upload) POST

            if (contentType == null || PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equals(contentType)) 
                this.handleStandardPost(postMethodProxyRequest, httpServletRequest);
             else 
                this.handleContentPost(postMethodProxyRequest, httpServletRequest);
            

        // Execute the proxy request
        this.executeProxyRequest(postMethodProxyRequest, httpServletRequest, httpServletResponse);
    



    /**
     * Sets up the given @link PostMethod to send the same standard POST
     * data as was sent in the given @link HttpServletRequest
     * @param postMethodProxyRequest The @link PostMethod that we are
     *                                configuring to send a standard POST request
     * @param httpServletRequest The @link HttpServletRequest that contains
     *                            the POST data to be sent via the @link PostMethod
     */
    @SuppressWarnings("unchecked")
    private void handleStandardPost(PostMethod postMethodProxyRequest, HttpServletRequest httpServletRequest) 
        // Get the client POST data as a Map
        Map mapPostParameters = (Map) httpServletRequest.getParameterMap();
        // Create a List to hold the NameValuePairs to be passed to the PostMethod
        List listNameValuePairs = new ArrayList();
        // Iterate the parameter names
        for (String stringParameterName : mapPostParameters.keySet()) 
            // Iterate the values for each parameter name
            String[] stringArrayParameterValues = mapPostParameters.get(stringParameterName);
            for (String stringParamterValue : stringArrayParameterValues) 
                // Create a NameValuePair and store in list
                NameValuePair nameValuePair = new NameValuePair(stringParameterName, stringParamterValue);
                listNameValuePairs.add(nameValuePair);
            
        
        // Set the proxy request POST data
        postMethodProxyRequest.setRequestBody(listNameValuePairs.toArray(new NameValuePair[]));
    

    /**
     * Sets up the given @link PostMethod to send the same content POST
     * data (JSON, XML, etc.) as was sent in the given @link HttpServletRequest
     * @param postMethodProxyRequest The @link PostMethod that we are
     *                                configuring to send a standard POST request
     * @param httpServletRequest The @link HttpServletRequest that contains
     *                            the POST data to be sent via the @link PostMethod
     */
    private void handleContentPost(PostMethod postMethodProxyRequest, HttpServletRequest httpServletRequest) throws IOException, ServletException 
        StringBuilder content = new StringBuilder();
        BufferedReader reader = httpServletRequest.getReader();
        for (;;) 
            String line = reader.readLine();
            if (line == null) break;
            content.append(line);
        

        String contentType = httpServletRequest.getContentType();
        String postContent = content.toString();

        if (contentType.startsWith("text/x-gwt-rpc")) 
            String clientHost = httpServletRequest.getLocalName();
            if (clientHost.equals("127.0.0.1")) 
                clientHost = "localhost";
            

            int clientPort = httpServletRequest.getLocalPort();
            String clientUrl = clientHost + ((clientPort != 80) ? ":" + clientPort : "");
            String serverUrl = stringProxyHost + ((intProxyPort != 80) ? ":" + intProxyPort : "") + httpServletRequest.getServletPath();
            //debug("Replacing client (" + clientUrl + ") with server (" + serverUrl + ")");
            postContent = postContent.replace(clientUrl , serverUrl);
        

        String encoding = httpServletRequest.getCharacterEncoding();
        debug("POST Content Type: " + contentType + " Encoding: " + encoding,
              "Content: " + postContent);
        StringRequestEntity entity;
        try 
            entity = new StringRequestEntity(postContent, contentType, encoding);
         catch (UnsupportedEncodingException e) 
            throw new ServletException(e);
        
        // Set the proxy request POST data
        postMethodProxyRequest.setRequestEntity(entity);
    

    /**
     * Executes the @link HttpMethod passed in and sends the proxy response
     * back to the client via the given @link HttpServletResponse
     * @param httpMethodProxyRequest An object representing the proxy request to be made
     * @param httpServletResponse An object by which we can send the proxied
     *                             response back to the client
     * @throws IOException Can be thrown by the @link HttpClient.executeMethod
     * @throws ServletException Can be thrown to indicate that another error has occurred
     */
    private void executeProxyRequest(
            HttpMethod httpMethodProxyRequest,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse)
            throws IOException, ServletException 
        // Create a default HttpClient
        HttpClient httpClient = new HttpClient();
        httpMethodProxyRequest.setFollowRedirects(false);
        // Execute the request
        int intProxyResponseCode = httpClient.executeMethod(httpMethodProxyRequest);
        String response = httpMethodProxyRequest.getResponseBodyAsString();

        // Check if the proxy response is a redirect
        // The following code is adapted from org.tigris.noodle.filters.CheckForRedirect
        // Hooray for open source software
        if (intProxyResponseCode >= HttpServletResponse.SC_MULTIPLE_CHOICES /* 300 */ && intProxyResponseCode  responseHeaders = Arrays.asList(headerArrayResponse);

        if (isBodyParameterGzipped(responseHeaders)) 
            debug("GZipped: true");
            if (!followRedirects && intProxyResponseCode == HttpServletResponse.SC_MOVED_TEMPORARILY) 
                response = httpMethodProxyRequest.getResponseHeader(STRING_LOCATION_HEADER).getValue();
                httpServletResponse.setStatus(HttpServletResponse.SC_OK);
                intProxyResponseCode = HttpServletResponse.SC_OK;
                httpServletResponse.setHeader(STRING_LOCATION_HEADER, response);
             else 
                response = new String(ungzip(httpMethodProxyRequest.getResponseBody()));
            
            httpServletResponse.setContentLength(response.length());
        

        // Send the content to the client
        debug("Received status code: " + intProxyResponseCode,
              "Response: " + response);

        httpServletResponse.getWriter().write(response);
    


    /**
     * The response body will be assumed to be gzipped if the GZIP header has been set.
     *
     * @param responseHeaders of response headers
     * @return true if the body is gzipped
     */
    private boolean isBodyParameterGzipped(List responseHeaders) 
        for (Header header : responseHeaders) 
            if (header.getValue().equals("gzip")) 
                return true;
            
        
        return false;
    

    /**
     * A highly performant ungzip implementation. Do not refactor this without taking new timings.
     * See ElementTest in ehcache for timings
     *
     * @param gzipped the gzipped content
     * @return an ungzipped byte[]
     * @throws java.io.IOException when something bad happens
     */
    private byte[] ungzip(final byte[] gzipped) throws IOException 
        final GZIPInputStream inputStream = new GZIPInputStream(new ByteArrayInputStream(gzipped));
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(gzipped.length);
        final byte[] buffer = new byte[FOUR_KB];
        int bytesRead = 0;
        while (bytesRead != -1) 
            bytesRead = inputStream.read(buffer, 0, FOUR_KB);
            if (bytesRead != -1) 
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            
        
        byte[] ungzipped = byteArrayOutputStream.toByteArray();
        inputStream.close();
        byteArrayOutputStream.close();
        return ungzipped;
    

    public String getServletInfo() 
        return "GWT Proxy Servlet";
    

    /**
     * Retrieves all of the headers from the servlet request and sets them on
     * the proxy request
     *
     * @param httpServletRequest The request object representing the client's
     *                            request to the servlet engine
     * @param httpMethodProxyRequest The request that we are about to send to
     *                                the proxy host
     */
    @SuppressWarnings("unchecked")
    private void setProxyRequestHeaders(HttpServletRequest httpServletRequest, HttpMethod httpMethodProxyRequest) 
        // Get an Enumeration of all of the header names sent by the client
        Enumeration enumerationOfHeaderNames = httpServletRequest.getHeaderNames();
        while (enumerationOfHeaderNames.hasMoreElements()) 
            String stringHeaderName = (String) enumerationOfHeaderNames.nextElement();
            if (stringHeaderName.equalsIgnoreCase(STRING_CONTENT_LENGTH_HEADER_NAME)) 
                continue;
            
            // As per the Java Servlet API 2.5 documentation:
            //      Some headers, such as Accept-Language can be sent by clients
            //      as several headers each with a different value rather than
            //      sending the header as a comma separated list.
            // Thus, we get an Enumeration of the header values sent by the client
            Enumeration enumerationOfHeaderValues = httpServletRequest.getHeaders(stringHeaderName);
            while (enumerationOfHeaderValues.hasMoreElements()) 
                String stringHeaderValue = (String) enumerationOfHeaderValues.nextElement();
                // In case the proxy host is running multiple virtual servers,
                // rewrite the Host header to ensure that we get content from
                // the correct virtual server
                if (stringHeaderName.equalsIgnoreCase(STRING_HOST_HEADER_NAME)) 
                    stringHeaderValue = getProxyHostAndPort();
                
                Header header = new Header(stringHeaderName, stringHeaderValue);
                // Set the same header on the proxy request
                httpMethodProxyRequest.setRequestHeader(header);
            
        
    

    /**
     * Retrieves all of the cookies from the servlet request and sets them on
     * the proxy request
     *
     * @param httpServletRequest The request object representing the client's
     *                            request to the servlet engine
     * @param httpMethodProxyRequest The request that we are about to send to
     *                                the proxy host
     */
    @SuppressWarnings("unchecked")
    private void setProxyRequestCookies(HttpServletRequest httpServletRequest, HttpMethod httpMethodProxyRequest) 
        // Get an array of all of all the cookies sent by the client
        Cookie[] cookies = httpServletRequest.getCookies();
        if (cookies == null) 
            return;
        

        for (Cookie cookie : cookies) 
            cookie.setDomain(stringProxyHost);
            cookie.setPath(httpServletRequest.getServletPath());
            httpMethodProxyRequest.setRequestHeader("Cookie", cookie.getName() + "=" + cookie.getValue() + "; Path=" + cookie.getPath());
        
    

    // Accessors
    private String getProxyURL(HttpServletRequest httpServletRequest) 
        // Set the protocol to HTTP
        String protocol = (isSecure) ? "https://" : "http://";
        String stringProxyURL = protocol + this.getProxyHostAndPort() + "/gui";

        // simply use whatever servlet path that was part of the request as opposed to getting a preset/configurable proxy path
        if (!removePrefix) 
            if (httpServletRequest.getServletPath() != null) 
                stringProxyURL += httpServletRequest.getServletPath();              
            
        
        stringProxyURL += "/";

        // Handle the path given to the servlet
        String pathInfo = httpServletRequest.getPathInfo();
        if (pathInfo != null && pathInfo.startsWith("/")) 
            if (stringProxyURL != null && stringProxyURL.endsWith("/")) 
                // avoid double '/'
                stringProxyURL += pathInfo.substring(1);
            
         else 
            stringProxyURL += httpServletRequest.getPathInfo();
        
        // Handle the query string
        if (httpServletRequest.getQueryString() != null) 
            stringProxyURL += "?" + httpServletRequest.getQueryString();
        

        stringProxyURL = stringProxyURL.replaceAll("/null", "");
        //System.out.println("----stringProxyURL: " + stringProxyURL);
        return stringProxyURL;
    

    private String getProxyHostAndPort() 
        if (this.getProxyPort() == 80) 
            return this.getProxyHost();
         else 
            return this.getProxyHost() + ":" + this.getProxyPort();
        
    

    protected String getProxyHost() 
        return this.stringProxyHost;
    

    protected void setProxyHost(String stringProxyHostNew) 
        this.stringProxyHost = stringProxyHostNew;
    

    protected int getProxyPort() 
        return this.intProxyPort;
    

    protected void setSecure(boolean secure) 
        this.isSecure = secure;
    

    protected void setFollowRedirects(boolean followRedirects) 
        this.followRedirects = followRedirects;
    

    protected void setProxyPort(int intProxyPortNew) 
        this.intProxyPort = intProxyPortNew;
    

    protected String getProxyPath() 
        return this.stringProxyPath;
    

    protected void setProxyPath(String stringProxyPathNew) 
        this.stringProxyPath = stringProxyPathNew;
    

    protected void setRemovePrefix(boolean removePrefix) 
        this.removePrefix = removePrefix;
    

    protected int getMaxFileUploadSize() 
        return this.intMaxFileUploadSize;
    

    protected void setMaxFileUploadSize(int intMaxFileUploadSizeNew) 
        this.intMaxFileUploadSize = intMaxFileUploadSizeNew;
    

    private void debug(String ... msg) 
        for (String m : msg) 
            //System.out.println("[DEBUG] " + m);
        
    

然后您需要对其进行子类化并提供端口:


package xxx.xxxx.xxxxx;

import javax.servlet.ServletConfig;

public class MyProxyServlet extends ProxyServlet 
    public void init(ServletConfig servletConfig) 

        //System.out.println("in the init");
        setFollowRedirects(true);

        setRemovePrefix(false);
        //setProxyPath("gui/" + getProxyPath());
        setProxyPort(8080);

    



【讨论】:

以上是关于GWT RPC 测试数据库连接的主要内容,如果未能解决你的问题,请参考以下文章

GWT rpc 在本地机器没有互联网连接的情况下无法工作,但在互联网上它可以工作

连接两个 GWT 应用程序 - 客户端/服务器

部署 GWT 项目的问题

如何集成 GWT-RPC、Android 和 GAE?

gwt rpc 序列化泛型类

gwt rpc 调用的零星 502 错误