我一直在关注http://code.google.com/appengine/articles/java/serving_dynamic_images.html以了解如何使用 Google 应用引擎和 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
:
package com.google.appengine.demo;
import java.io.IOException;
import java.net.URL;
import javax.jdo.PersistenceManager;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
@SuppressWarnings("serial")
public class StoreMovieServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
resp.getWriter().println("Google app engine is a pain");
URLFetchService fetchService = URLFetchServiceFactory
.getURLFetchService();
// Fetch the image at the location given by the url query string
// parameter
HTTPResponse fetchResponse = fetchService.fetch(new URL(req
.getParameter("url")));
String fetchResponseContentType = null;
for (HTTPHeader header : fetchResponse.getHeaders()) {
// For each request header, check whether the name equals
// "Content-Type"; if so, store the value of this header
// in a member variable
if (header.getName().equalsIgnoreCase("content-type")) {
fetchResponseContentType = header.getValue();
break;
}
}
if (fetchResponseContentType != null) {
// Create a new Movie instance
Movie movie = new Movie();
movie.setTitle(req.getParameter("title"));
movie.setImageType(fetchResponseContentType);
// Set the movie's promotional image by passing in the bytes pulled
// from the image fetched via the URL Fetch service
movie.setImage(fetchResponse.getContent());
// ...
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
// Store the image in App Engine's datastore
pm.makePersistent(movie);
} finally {
pm.close();
}
}
}
}
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
:
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;
}
}
web.xml
:
<?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>
编辑:
PMF.java
:
public final class PMF {
private static final PersistenceManagerFactory INSTANCE =
JDOHelper.getPersistenceManagerFactory("transactional");
public static PersistenceManagerFactory get() {
return INSTANCE;
}
private PMF() {}
}