使用Google App Engine Java提供动态图像

使用Google App Engine Java提供动态图像,java,database,google-app-engine,servlets,google-cloud-datastore,Java,Database,Google App Engine,Servlets,Google Cloud Datastore,我一直在学习如何使用GoogleAppEngine和JDO将图像上传到数据库 我试过那个例子。当我运行localhost:8888/image?title=matrix时,我得到以下错误 HTTP ERROR 500 Problem accessing /image. Reason: Could not initialize class com.google.appengine.demo.PMF Caused by: java.lang.NoClassDefFoundError: Coul

我一直在学习如何使用GoogleAppEngine和JDO将图像上传到数据库

我试过那个例子。当我运行localhost:8888/image?title=matrix时,我得到以下错误

HTTP ERROR 500

Problem accessing /image. Reason:

Could not initialize class com.google.appengine.demo.PMF
Caused by:

java.lang.NoClassDefFoundError: Could not initialize class com.google.appengine.demo.PMF
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at com.google.appengine.tools.development.agent.runtime.RuntimeHelper.checkRestricted(RuntimeHelper.java:70)
    at com.google.appengine.tools.development.agent.runtime.Runtime.checkRestricted(Runtime.java:64)
    at com.google.appengine.demo.GetImageServlet.getMovie(GetImageServlet.java:46)
    at com.google.appengine.demo.GetImageServlet.doGet(GetImageServlet.java:22)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    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.DevAppServerServersFilter.doDirectRequest(DevAppServerServersFilter.java:369)
    at com.google.appengine.tools.development.DevAppServerServersFilter.doDirectServerRequest(DevAppServerServersFilter.java:352)
    at com.google.appengine.tools.development.DevAppServerServersFilter.doFilter(DevAppServerServersFilter.java:115)
    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:480)
    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)
代码如下:

StoreMovieServlet.java
Movie.java
package com.google.appengine.demo;

import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Key;

/**
 * JDO-annotated model class for storing movie properties; movie's promotional
 * image is stored as a Blob (large byte array) in the image field.
 */
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Movie {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent
    private String title;

    @Persistent
    @Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
    private String imageType;

    @Persistent
    private Blob image;

    //...

    public Long getId() {
        return key.getId();
    }

    public String getTitle() {
        return title;
    }

    public String getImageType() {
        return imageType;
    }

    public byte[] getImage() {
        if (image == null) {
            return null;
        }

        return image.getBytes();
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setImageType(String imageType) {
        this.imageType = imageType;
    }

    public void setImage(byte[] bytes) {
        this.image = new Blob(bytes);
    }

    //...

}
GetImageServlet.java
: 编辑:
PMF.java
: 你试过添加吗

import com.google.appengine.demo.repo.PMF;

到您的两个servlet源文件?

导入时,我得到的导入com.google.appengine.demo无法解析。我已经编辑了我的问题,其中包含PMF类的代码。但我仍然收到相同的错误。我的导入建议包括
repo
,而您的错误消息响应中没有。你可能想检查一下。我还猜想您的
PMF
类列表摘录省略了标题行
package com.google.appengine.demo.repo。(我假设你的
PMF
代码来自)你用什么工具来构建这个?这似乎是一个类路径问题。(PMF住在同一个包裹里,对吗?)
package com.google.appengine.demo;

import java.io.IOException;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * GET requests return the promotional image associated with the movie with the
 * title specified by the title query string parameter.
 */
public class GetImageServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        String title = req.getParameter("title");
        Movie movie = getMovie(title);

        if (movie != null && movie.getImageType() != null &&
                movie.getImage() != null) {
            // Set the appropriate Content-Type header and write the raw bytes
            // to the response's output stream
            resp.setContentType(movie.getImageType());
            resp.getOutputStream().write(movie.getImage());
        } else {
            // If no image is found with the given title, redirect the user to
            // a static image
            resp.sendRedirect("/static/noimage.jpg");
        }
    }

    //...

    /**
     * Queries the datastore for the Movie object with the passed-in title. If
     * found, returns the Movie object; otherwise, returns null.
     *
     * @param title movie title to look up
     */
    private Movie getMovie(String title) {
        PersistenceManager pm = PMF.get().getPersistenceManager();

        // Search for any Movie object with the passed-in title; limit the number
        // of results returned to 1 since there should be at most one movie with
        // a given title
        Query query = pm.newQuery(Movie.class, "title == titleParam");
        query.declareParameters("String titleParam");
        query.setRange(0, 1);

        try {
            List<Movie> results = (List<Movie>) query.execute(title);
            if (results.iterator().hasNext()) {
                // If the results list is non-empty, return the first (and only)
                // result
                return results.get(0);
            }
        } finally {
            query.closeAll();
            pm.close();
        }

        return null;
    }

}
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <servlet>
        <servlet-name>StoreMovie</servlet-name>
        <servlet-class>com.google.appengine.demo.StoreMovieServlet
        </servlet-class>
    </servlet>
    <servlet>
        <servlet-name>GetImage</servlet-name>
        <servlet-class>com.google.appengine.demo.GetImageServlet
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>StoreMovie</servlet-name>
        <url-pattern>/addMovie</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>GetImage</servlet-name>
        <url-pattern>/image</url-pattern>
    </servlet-mapping>
</web-app>
public final class PMF {

  private static final PersistenceManagerFactory INSTANCE =
      JDOHelper.getPersistenceManagerFactory("transactional");

  public static PersistenceManagerFactory get() {
    return INSTANCE;
  }

  private PMF() {}
}
import com.google.appengine.demo.repo.PMF;