# Bild in derby DB speichern



## markai (7. Jun 2012)

Ich würde gerne meinen User(-Entities) die Möglichkeit geben ein Bild hochzuladen (in die derby DB zu speichern). Dazu habe ich folgendes Attribut definiert...

```
@Entity @Table(name="Users")
public class User implements Serializable {
    //...
    @Column @Lob
    private Byte[] photo;
//Getter, Setter
```
... und daraus dann meine JSF-pages generiert. Nun weiß ich aber nicht wie ich ein Bild in dieses Byte[] bekommen soll.
Hab mal gegoogelt wie man die Sache am besten angeht. Mir ist aufgefallen dass viele dafür ein eigenes Servlet schreiben. Bin mir aber nicht sicher ob ich das mit den Servlets überhaupt verstanden hab, darum versuch ichs mal zu erklären:
In der web.xml werden url-Pattern auf das jeweilige Servlet gematcht. Standardmäßig wird (zumindest bei mir) das Faces-Servlet als Controller verwendet. Will ich nun zb. Bilder hochladen kann/muss ich mein eigenes Servlet erstellen, welches dann verwendet wird wenn zb. "img/*" in der URL vorkommt.

Wl. ist das der größte Blödsinn. Kann mir nicht vorstellen dass das nicht einfacher geht, also bitte korrigiert mich. Gibt doch sicher einen einfacheren Weg Bilder in meine DB zu speichern?


----------



## JimPanse (7. Jun 2012)

Eine Möglichkeit wäre eine Komponenten-Bibliothek einzusetzen z.b. Tomahawk
FileUpload


```
@ManagedBean
@RequestScoped
public class Bean {
    private UploadedFile uploadedFile;

    public void submit() throws IOException {
        byte[] bytes = uploadedFile.getBytes();
       //speichern
    }

    public UploadedFile getUploadedFile() {
        return uploadedFile;
    }

    public void setUploadedFile(UploadedFile uploadedFile) {
        this.uploadedFile = uploadedFile;
    }
}
```

Die Frage ist eher ob es Sinn macht Bilder in eine Datenbank zu speichern...


----------



## markai (7. Jun 2012)

Wo soll ich denn meine Bilder sonst speichern? Hätte gerne dass meine Benutzer für ihr jeweiliges Benutzerkonto ein Icon hochladen können und sehe keine andere Möglichkeit als dieses in eine DB zu speichern.


----------



## turtle (7. Jun 2012)

Hab diesen Code-Snippet gefunden, zwar nicht ausprobiert müsste aber funktionieren:


```
PreparedStatement ps;
    ps = con.prepareStatement("insert into employee(name,photo) " + "values(?,?)");
    ps.setString(1, "Duke");

    Blob blob = con.createBlob();
    ImageIcon ii = new ImageIcon("duke.png");

    ObjectOutputStream oos;
    oos = new ObjectOutputStream(blob.setBinaryStream(1));
    oos.writeObject(ii);
    oos.close();
    ps.setBlob(2, blob);
    ps.execute();
    blob.free();
    ps.close();
```


----------



## JimPanse (7. Jun 2012)

markai hat gesagt.:


> Wo soll ich denn meine Bilder sonst speichern? Hätte gerne dass meine Benutzer für ihr jeweiliges Benutzerkonto ein Icon hochladen können und sehe keine andere Möglichkeit als dieses in eine DB zu speichern.



Wie wäre es direkt im xampp und anstatt dem byte array die relativen pfad information zu dem Bild? 

Dann ersparst du der Datenbank - eventuelle größere byte-felder auslesen zu müssen  - gerade bei größen Übersichtslisten (Benutzer + Bilder) eventuell deine DB in die Knie zwingen könnte.


----------



## markai (7. Jun 2012)

Danke für eure Tipps. Das Icon soll nicht besonders groß sein, würde es also schon ganz gerne in meiner DB haben. (Verwende übrigens den Glassfish Server). Versuche gerade mit dem FileUploader von Primefaces zurechtzukommen, allerdings sagt mir mein Compiler immer dass er die Methode nicht findet. Habe das Beispiel aber von der Primefaces HP entnommen, und da scheint es zu funktionieren...

Hier meine imageUpload.xhtml
[XML]
<ui:composition template="/WEB-INF/template/Template.xhtml"
                xmlns="http://www.w3.org/1999/xhtml"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns="http://primefaces.org/ui"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:ui="http://java.sun.com/jsf/facelets">

    <ui:define name="content">

        <h:form enctype="multipart/form-data">  

            <p:fileUpload fileUploadListener="#{imageUpload.handleFileUpload}"  
                          mode="advanced"   
                          update="messages"  
                          sizeLimit="100000"   
                          allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>  

            <p:growl id="messages" showDetail="true"/>  

        </h:form>  

    </ui:define>
</ui:composition>
[/XML]

... und meine ImageUpload bean


```
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ManagedBean;

@ManagedBean
@SessionScoped
public class imageUpload implements Serializable {
    
    public void handleFileUplaod(FileUploadEvent event) {
            FacesMessage msg = new FacesMessage("Succesfull", event.getFile().getFileName() + " is uploaded.");
            FacesContext.getCurrentInstance().addMessage(null, msg);
    }
}
```

Was mache ich denn falsch??


----------



## turtle (7. Jun 2012)

Hab meinen Code-Snippet in der Zwischenzeit probiert.

Geht in Derby problemlos!:toll:


----------



## JimPanse (7. Jun 2012)

markai hat gesagt.:


> Danke für eure Tipps. Das Icon soll nicht besonders groß sein, würde es also schon ganz gerne in meiner DB haben. (Verwende übrigens den Glassfish Server). Versuche gerade mit dem FileUploader von Primefaces zurechtzukommen, allerdings sagt mir mein Compiler immer dass er die Methode nicht findet. Habe das Beispiel aber von der Primefaces HP entnommen, und da scheint es zu funktionieren...



Welche Methode findet der Compiler nicht? Poste doch einfach mal den Stacktrace.


----------



## markai (7. Jun 2012)

Die handleFileUpload Methode wird nie aufgerufen.

```
<p:fileUpload fileUploadListener="#{imageUpload.handleFileUpload}"  ...
```

Hab keinen Stacktrace, schon der Compiler sagt mir dass es die Methode nicht gibt (was er aber auch bei anderen Methoden macht die später doch noch aufgerufen werden). Wenn ich auf upload klicke passiert einfach nichts  Hab mir gedacht dass es daran liegt das die Methode ein Event erwartet das ich nicht mitübergebe, aber bei der Primefaces Demo wirds auch so gemacht. (Ohne parameter funktionierts aber auch nicht)

@turtle: wenn ich jemals soweit komme dass ich meine methode aufrufen kann werde ich deinen Code ausprobieren...


----------



## turtle (7. Jun 2012)

Bist du dir mit dem Methodennamen sicher?

```
handleFileUplaod
```


----------



## markai (7. Jun 2012)

Ja da hab ich mich vertippt. Die Methode heißt aber so. Codecompletion funktioniert komischerweise, aber dann muss ich immer ein Event mitübergeben, was ja in der Demo so nicht gemacht wird...


----------



## JimPanse (7. Jun 2012)

markai hat gesagt.:


> Die handleFileUpload Methode wird nie aufgerufen.
> 
> ```
> <p:fileUpload fileUploadListener="#{imageUpload.handleFileUpload}"  ...
> ...



äääh???? Du meinst den Editor oder? Wenn mein Compiler eine Klasse oder Methode nicht findet kann dieser nicht compilieren...




> aber dann muss ich immer ein Event mitübergeben, was ja in der Demo so nicht gemacht wird...



Du musst bei JSF-Eventhandlern nie das konkrete event mitgeben.

Kontrollier mal ob in deinem Template.xhtml <h:head> verwendet wird (beliebter fehler) bzw. ob auch alle JScript's geladen worden sind in den head der Seite


----------



## markai (7. Jun 2012)

Editor? Dachte immer der Compiler überprüft das... Was du mit der Template.xhtml meinst versteh ich nicht. <h:head... wird in meinem Template verwendet. Darf ich das nicht?
Hier meine Template.xhtml:


```
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:lang="http://java.sun.com/jsf/composite/components/languageUtils">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <h:outputStylesheet library="css" name="cssLayout.css"/>
        <h:outputStylesheet library="css" name="default.css"/>
        <title>Title</title>
    </h:head>

    <h:body>
        <p:growl id="growl" showDetail="true" sticky="false"/>
        <div>
            <div id="top">
                <ui:insert name="top">top</ui:insert>
            </div>
            <div id="menu">
                <ui:insert name="home"><lang:selector locales="de,en"/></ui:insert>
            </div>
        </div>
        <div id="content" class="center_content">
            <ui:insert name="content">Content</ui:insert>
        </div>
        <div id="bottom">
            <ui:insert name="bottom">bottom</ui:insert>
        </div>
    </h:body>
</html>
```


----------



## markai (7. Jun 2012)

Ok jetzt hab ich auch eine Exception bekommen:


```
WARNING: /pages/cilab/imageUpload.xhtml @18,53 fileUploadListener="#{imageUpload.handleFileUpload}": Method not found: at. ....controller.imageUpload@994358e.handleFileUpload(org.primefaces.event.FileUploadEvent)
javax.el.MethodNotFoundException: /pages/cilab/imageUpload.xhtml @18,53 fileUploadListener="#{imageUpload.handleFileUpload}": Method not found: ....controller.imageUpload@994358e.handleFileUpload(org.primefaces.event.FileUploadEvent)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:109)
	at org.primefaces.component.fileupload.FileUpload.broadcast(FileUpload.java:279)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:759)
	at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:935)
	at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:77)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:722)
```


----------



## JimPanse (7. Jun 2012)

<h:head> ist richtig. 


```
@ManagedBean
@SessionScoped
public class imageUpload implements Serializable {
    
    public void handleFileUplaod(FileUploadEvent event) {
            FacesMessage msg = new FacesMessage("Succesfull", event.getFile().getFileName() + " is uploaded.");
            FacesContext.getCurrentInstance().addMessage(null, msg);
    }
}
```

Schreib mal den Klassennamen groß -> ImageUpload.


----------



## markai (7. Jun 2012)

Heute vertipp ich mich ständig... Die Exception kam wohl auch wegen eines Tippfehlers :/ Hab nun endlich mein byte[] wo mein Bild drin ist. Jetzt muss ich dieses nur mehr in meinen User übergeben. Dazu hab ich mir folgendes gedacht: 

In meiner ImageUpload Klasse wandle ich das Bild in ein byte[] um:

```
@Named("imageUpload")
@RequestScoped
public class ImageUpload implements Serializable {

    private UploadedFile uploadedFile;
    private byte[] fileContentsByteArray;
...
```

Dann hätte ich gerne in meinem UserController dieses byte[]. Dazu mache ich:

```
@ManagedBean(name = "userController")
@SessionScoped
public class UserController implements Serializable {

    private User current;
    private DataModel items = null;
    @EJB
    private UserFacade ejbFacade;

    @Inject
    private ImageUpload imageUploader;
```

Scheinbar kann ich meinen imageUploader aber nicht in meinen Controller injezieren, denn wenn ich in der Methode welche meinen User erzeugt folgendes mache:

```
public String create() {
        try {

            current.setPhoto(imageUploader.getFileContentsByteArray());

            if(ValidationUtil.isValid(current)){
            getFacade().create(current);
            JsfUtil.addSuccessMessage("UserCreated");
            return prepareCreate();
            ...
```
... liefert mir der getter für mein byte[] null zurück.

Mir ist nur diese Lösung eingefallen, diese funktioniert aber nicht  Leider schnall ich dieses Java EE noch nicht so ganz...


----------



## JimPanse (7. Jun 2012)

Du kannst eine JSF-Beans in einer anderen JSF-Bean nur injekten wenn der Scope gleich oder größer ist und Session ist eindeutig größer als Request d.h. Mach es einfach anders herum ;-)

Du injektes den UserController in der ImageUploadBean.

Greetz


----------



## markai (7. Jun 2012)

Vielen Dank! Es funktioniert  Ist eigentlich eh logisch dass man keine RequestScoped bean in eine SessionScoped bean injecten kann... Hab mal beide beans mit SessionScope versucht. Das hat nicht geklappt, erst mit ApplicationScope ging es. Werd morgen mal überlegen ob ich den Spieß umdrehe - wie du es mir empfohlen hast - aber jetzt freu ich mich erstmal dass in meiner Datenbank mal was anderes als null ankommt :toll:


----------



## JimPanse (7. Jun 2012)

kein Problem. Nicht vergessen den Thread 'als erledigt' markieren.


----------

