开发者

Play Framework: Image Display question

ref: http://www.lunatech-research.com/playframework-file-upload-blob

I'm uneasy about one point in this example

  #{list items:models.User.findAll(), as:'user'}
  <img src="@{userPhoto(user.id)}">
  #{/list}

At this point I'm already holding the user object (including the image blob). Yet the userPhoto() method makes another dip into the backend to get the Image user.photo

    public static void userPhoto(long id) {
       final User user = User.findById(id);
       notFoundIfNull(user);
       response.setContentTypeIfNotSet(user.photo.type开发者_如何学C());
       renderBinary(user.photo.get());
    }

Any way to avoid this unnecessary findById call?


You're not actually holding the user object any more though, because the userPhoto action is invoked in a separate request that's sent when the browser tries to load the image from the URL generated by @{userPhoto(user.id)}.

Of course, you could use the cache to store data from each user's photo Blob, which would reduce the likelihood that you had to go to the database on the image request. It's more trouble than it's worth in this case though since you're just doing a simple primary key lookup for the user object, and that should be relatively inexpensive. Plus Blobs aren't serializable, so you have to pull out each piece of information separately.

Still, if you were to try that it might look something like this:

// The action that renders your list of images
public static void index() {
    List<User> users = User.findAll();

    for (User user : users) {
        cachePhoto(user.photo);
    }

    render(users);
}

// The action that returns the image data to display
public static void userPhoto(long id) {
    InputStream photoStream;
    String path = Cache.get("image_path_user_" + id);
    String type = Cache.get("image_type_user_" + id);

    // Was the data we needed in the cache?
    if (path == null || type == null) {
        // No, we'll have to go to the database anyway
        User user = User.findById(id);
        notFoundIfNull(user);
        cachePhoto(user.photo);
        photoStream = user.photo.get();
        type = user.photo.type();
    } else {
        // Yes, just generate the stream directly
        try {
            photoStream = new FileInputStream(new File(path));
        } catch (Exception ex) {
            throw new UnexpectedException(ex);
        }
    }

    response.setContentTypeIfNotSet(type);
    renderBinary(photoStream);
}

// Convenience method for caching the photo information
private static void cachePhoto(Blob photo) {
    if (photo == null) {
        return;
    }

    Cache.set("image_path_user_" + user.id,
            photo.getFile.getAbsolutePath());
    Cache.set("image_type_user_" + user.id,
            photo.getType());
}

Then you'd still have to worry about appropriately populating/invalidating the cache in your add, update, and delete actions too. Otherwise your cache would be polluted with stale data.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜