Wicket Dynamic Image URL

16,660

Solution 1

I've only just started to work with Wicket myself, but I would simply mount the resource as a shared resource with its own URL. You just override init() in your Application and register the resource with

getSharedResources().add(resourceKey, dynamicImageResource);

Then, you mount it as a shared resource with

mountSharedResource(path, resourceKey);

For some reason, that I still do not completely grasp, you have to prepend the class name of the application to the resource key you pass to mountSharedResource().


Let's add a fully working example for some bonus votes! First create an empty Wicket template with

mvn archetype:create -DarchetypeGroupId=org.apache.wicket \
    -DarchetypeArtifactId=wicket-archetype-quickstart \
    -DarchetypeVersion=1.4.0 -DgroupId=com.mycompany \
    -DartifactId=myproject

Then, override the init() method in WicketApplication by adding:

@Override
protected void init() {
    final String resourceKey = "DYN_IMG_KEY";
    final String queryParm = "id";

    getSharedResources().add(resourceKey, new Resource() {
        @Override
        public IResourceStream getResourceStream() {
            final String query = getParameters().getString(queryParm);

            // generate an image containing the query argument
            final BufferedImage img = new BufferedImage(100, 100,
                    BufferedImage.TYPE_INT_RGB);
            final Graphics2D g2 = img.createGraphics();
            g2.setColor(Color.WHITE);
            g2.drawString(query, img.getWidth() / 2, img.getHeight() / 2);

            // return the image as a PNG stream
            return new AbstractResourceStreamWriter() {
                public String getContentType() {
                    return "image/png";
                }
                public void write(OutputStream output) {
                    try { ImageIO.write(img, "png", output); }
                    catch (IOException ex) { /* never swallow exceptions! */ }
                }
            };
        }
    });

    mountSharedResource("/resource", Application.class.getName() + "/" +
            resourceKey);
}

The little dynamic PNG resource just writes the query parameter on black background. Of course, you can access your DB or do whatever you like to produce the image data.

Finally, execute mvn jetty:run, and you will be able to access the resource at this URL.

Solution 2

I'll add another answer to say Martin Grigorov wrote a really nice blogpost over at wicketinaction.com to detail how to serve up images loaded from a database in Wicket 1.5:

http://wicketinaction.com/2011/07/wicket-1-5-mounting-resources/

This matches exactly with @Michael's question.

Solution 3

Here's my example that does the same for a dynamically compiled list of identifiers, served up as a shared resource with a static URL..

public class WicketApplication extends WebApplication {
    ...snip...
    @Override
    protected void init() {
        //Spring
        addComponentInstantiationListener(new SpringComponentInjector(this));

        //Register export lists as shared resources
        getSharedResources().putClassAlias(ListInitializer.class, "list");
        new ListInitializer().init(this);
    }

And my ListInitializer that registers the resources as DBNAME_SUBSELECTION1(2/3/..)

public class ListInitializer implements IInitializer {
    public ListInitializer() {
        InjectorHolder.getInjector().inject(this);
    }

    @SpringBean
    private DatabankDAO dbdao;

    @Override
    public void init(Application application) {
        //For each databank
        for (Databank db : dbdao.getAll()) {
            String dbname = db.getName();
            //and all collection types
            for (CollectionType ct : CollectionType.values()) {
                //create a resource
                Resource resource = getResource(dbname, ct);
                //and register it with shared resources
                application.getSharedResources().add(this.getClass(), dbname + '_' + ct, null, null, resource);
            }
        }
    }

    @SpringBean
    private MyApp   MyApp;

    public Resource getResource(final String db, final CollectionType collectionType) {
        return new WebResource() {
            @Override
            public IResourceStream getResourceStream() {
                List<String> entries = MyApp.getEntries(db, collectionType.toString());
                StringBuilder sb = new StringBuilder();
                for (String entry : entries) {
                    sb.append(entry.toString());
                    sb.append('\n');
                }
                return new StringResourceStream(sb, "text/plain");
            }

            @Override
            protected void setHeaders(WebResponse response) {
                super.setHeaders(response);
                response.setAttachmentHeader(db + '_' + collectionType);
            }
        }.setCacheable(false);
    }
}

I'm sorry but I can't seem to find the tutorial I used to set this up anymore, but it should be evident how this relates to the above example and can be adjusted to do the same for images.. (Sorry for the sparse explanation, if it's still unclear I could come back and edit my answer)

Share:
16,660
Michael Krauklis
Author by

Michael Krauklis

Java and .NET Developer, Architect, and Project Manager based out of Rochester, NY and Philadelphia, PA.

Updated on June 04, 2022

Comments

  • Michael Krauklis
    Michael Krauklis almost 2 years

    Short question: I need to turn a dynamic image pulled from a database into a URL without adding a component to the displaying page (such as using a NonCachingImage) using Wicket.

    The perfect solution (that I've implemented in other Frameworks) is simply to create a page that takes the image ID as a url parameter and renders the image to the response stream. Unfortunately Wicket's Page class extends MarkupContainer, which revolves around MarkupStreams. MarkupStreams aren't very conducive to rendering byte data directly.

    Long question: I'm using Wicket 1.4.0, running in Tomcat 6.0.18. The image is stored in a Postgres database, retrieved via JDBC. The image needs to be rendered by a third party API that only accepts image URLs. I have a model object that contains the byte data, mime type, and a Resource object that can pull the model from the DB and add it to a response stream.

    Any ideas?

  • Tim
    Tim over 14 years
    And to complement this: Using an IInitializer implementing class and getSharedResources().putClassAlias(ListInitializer.class, "list"); new ListInitializer().init(this); you should be able to get around prepending the whole classpath for you image url.
  • janko
    janko over 14 years
    Can you provide more information, Tim? I can't find the ListInitializer class in Wicket and the available documentation on putClassAlias isn't helpful, either.
  • Tim
    Tim over 14 years
    ListInitializer is just my implementation.. I'll expand my example into an own answer..
  • Michael Krauklis
    Michael Krauklis over 14 years
    Ahhh, brilliant. The piece I was missing was getParameter on Resource; I had completely overlooked that. I was looking for it to be passed via the constructor as in the page model. Thanks Janko!
  • Michael Krauklis
    Michael Krauklis over 14 years
    A note about the URL provided to test: localhost:8080/myproject/resource/org.apache.wicket.Applicat‌​ion/… Really anything under /resource would work, e.g.: localhost:8080/myproject/resource?id=someId