2009-10-03 10 views
6

Kurze Frage: Ich muss ein dynamisches Bild aus einer Datenbank in eine URL, ohne Hinzufügen einer Komponente auf der angezeigten Seite (wie ein NonCachingImage) mit Wicket.Wicket Dynamic Image URL

Die perfekte Lösung (die ich in anderen Frameworks implementiert habe) besteht einfach darin, eine Seite zu erstellen, die die Image-ID als URL-Parameter verwendet und das Bild in den Antwortstream rendert. Leider erweitert die Page-Klasse von Wicket MarkupContainer, der sich um MarkupStreams dreht. MarkupStreams sind nicht sehr günstig, um Byte-Daten direkt zu rendern.

Lange Frage: Ich verwende Wicket 1.4.0, läuft in Tomcat 6.0.18. Das Bild wird in einer Postgres-Datenbank gespeichert und über JDBC abgerufen. Das Image muss von einer Drittanbieter-API gerendert werden, die nur Bild-URLs akzeptiert. Ich habe ein Modellobjekt, das die Byte-Daten, den MIME-Typ und ein Resource-Objekt enthält, das das Modell aus der Datenbank abrufen und einem Antwort-Stream hinzufügen kann.

Irgendwelche Ideen?

Antwort

19

Ich habe gerade erst begonnen, mit Wicket selbst zu arbeiten, aber ich würde einfach die Ressource als freigegebene Ressource mit einer eigenen URL bereitstellen. Sie überschreiben nur init() in Ihrem Application und registrieren die Ressource mit

getSharedResources().add(resourceKey, dynamicImageResource); 

Dann montieren Sie es als gemeinsame Ressource mit

mountSharedResource(path, resourceKey); 

Aus irgendeinem Grund, dass ich immer noch nicht ganz fassen, Sie haben den Klassennamen der Anwendung dem Ressourcenschlüssel voranstellen, den Sie an mountSharedResource() übergeben.


Lassen Sie uns ein voll funktionierendes Beispiel für einige Bonus-Stimmen hinzufügen! Erstellen Sie zunächst eine leere Wicket-Vorlage mit

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

Dann überschreiben die init() Methode in WicketApplication durch Zugabe:

@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); 
} 

Der kleine dynamische PNG Ressource nur schreibt die Abfrage-Parameter auf schwarzem Hintergrund. Natürlich können Sie auf Ihre Datenbank zugreifen oder alles machen, was Sie möchten, um die Bilddaten zu erzeugen.

Schließlich ausführen mvn jetty:run, und Sie können auf die Ressource unter this URL zugreifen.

+0

Und um dies zu ergänzen: Verwenden eines IInitializer implementierende Klasse und 'getSharedResources(). PutClassAlias ​​(ListInitializer.class," list "); new ListInitializer(). init (this); 'Sie sollten in der Lage sein, den gesamten Klassenpfad für Ihre Bild-URL vorwegzunehmen. – Tim

+0

Können Sie mehr Informationen geben, Tim? Ich kann die Klasse "ListInitializer" in Wicket nicht finden und die verfügbare Dokumentation zu 'putClassAlias' ist ebenfalls nicht hilfreich. – janko

+0

ListInitializer ist nur meine Implementierung .. Ich werde mein Beispiel in eine eigene Antwort erweitern .. – Tim

1

Hier ist mein Beispiel, das das gleiche für eine dynamisch kompilierte Liste der Kennungen der Fall ist, serviert mit einer statischen URL als gemeinsame Ressource up ..

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); 
    } 

Und meine ListInitializer, die die Ressourcen als DBNAME_SUBSELECTION1 Register (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); 
    } 
} 

es tut mir leid, aber ich kann nicht scheinen, um das Tutorial zu finde ich verwendet, um dieses mehr einzurichten, aber es sollte klar sein, wie diese auf das obige Beispiel bezieht und kann angepasst werden, dasselbe für Bilder zu tun. (Sorry für die spärliche Erklärung, wenn ich Es ist immer noch unklar, ich könnte zurückkommen und meine Antwort bearbeiten)

+0

Erhalten eine keine Erklärung down-vote .. Pflege zu erarbeiten? – Tim