2012-02-26 2 views
1

J'essaie de configurer un cas d'utilisateur, où j'ai un formulaire générique qui peut gérer tous les types de téléchargements utilisateur UploadedFile. Alors, voici ma configuration:Conversion de la classe parent en classe enfant dans une table unique par classe Hiérarchie

@Entity(name="UploadedForm") 
@Table(name="uploaded_file") 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING) 
public class UploadedFile implements Serializable{ 

    /** 
    * 
    */ 
    private static final long serialVersionUID = -6810328674369487649L; 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name="id") 
    protected Long id; 

    @Column(name="name") 
    protected String name = null; 

    @Column(name="bytes",unique=true) 
    @Lob 
    protected byte[] bytes; 

    @Column(name="type",nullable=false, updatable=false, insertable=false) 
    protected String type; 


    @ManyToOne(fetch=FetchType.LAZY, targetEntity=User.class) 
    @JoinColumn(name="user_id") 
    protected User user; 

    @Column(name="date_submitted") 
    @Temporal(TemporalType.DATE) 
    protected Date dateSubmitted; 

    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 

    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 
    public User getUser() { 
     return user; 
    } 
    public void setUser(User user) { 
     this.user = user; 
    } 
    public Date getDateSubmitted() { 
     return dateSubmitted; 
    } 
    public void setDateSubmitted(Date dateSubmitted) { 
     this.dateSubmitted = dateSubmitted; 
    } 

    @PrePersist 
    @PreUpdate 
    public void populateDateSubmitted(){ 
     this.dateSubmitted = new java.sql.Date(new java.util.Date().getTime()); 
    } 
    public byte[] getBytes() { 
     return bytes; 
    } 
    public void setBytes(byte[] bytes) { 
     this.bytes = bytes; 
    } 
    public String getType() { 
     return type; 
    } 

} 


@Entity(name="Document") 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorValue(value="Document") 
public class DocumentFile extends UploadedFile { 

    public void setDateSubmitted(Date dateSubmitted) { 
     this.dateSubmitted = dateSubmitted; 
    } 

    @PrePersist 
    @PreUpdate 
    public void populateDateSubmitted(){ 
     this.dateSubmitted = new java.sql.Date(new java.util.Date().getTime()); 
    } 
    public byte[] getBytes() { 
     return bytes; 
    } 
    public void setBytes(byte[] bytes) { 
     this.bytes = bytes; 
    } 
} 


@RequestMapping(value="{type}",method=RequestMethod.GET) 
    public String showForm(ModelMap model, @PathVariable("type") String type){ 
     UploadedFile form = null; 
     if((model.get("FORM") == null)){ 
      if(type.equals("document")){ 
       form = new DocumentFile(); 
      } 
      else if(type.equals("image")){ 
       form = new ImageFile(); 
      } 
     }else{ 
      form = (UploadedFile)model.get("FORM"); 
      if(form.getClass() == DocumentFile.class) 
       form = (DocumentFile)form; 
      else if(form.getClass() == ImageFile.class) 
       form = (ImageFile)form; 
     } 


     model.addAttribute("message", "Please select your file and hit submit."); 

     model.addAttribute("FORM", form); 

     model.addAttribute("type", type); 

     return "upload_form"; 
    } 
    @RequestMapping(method=RequestMethod.POST) 
    public String processForm(Model model, @RequestParam(value="type") String type, @ModelAttribute(value="FORM") UploadedFile form,BindingResult result, Principal principal) throws FileSaveException, Exception{ 
     if(!result.hasErrors()){ 

      UploadedFile savedFile = null; 

      try { 
       // Find the currently logged in user. There has to be a more eloquent way... 
       String username = principal.getName(); 
       User user = uService.findByName(username); 

       // Set the associated user to the UploadedFile 
       form.setUser(user); 

       if(type.equals("document")) 
        form = (DocumentFile)form; 
       else if(type.equals("image")) 
        form = (ImageFile)form; 

       // Persist the file 
       savedFile = this.saveFile(form); 
      } catch (Exception e) { 

       FileSaveException fse = new FileSaveException("Unable to save file: " + e.getMessage()); 

       fse.setStackTrace(e.getStackTrace()); 

       throw fse; 

      } 
      model.addAttribute("message", "SUCCESS!"); 
      model.addAttribute("FORM", savedFile); 
      return "upload_success"; 

     }else{ 

      return "upload_form"; 

     } 
    } 

<%@ include file="/WEB-INF/views/includes.jsp" %> 
<%@ page session="false" %> 
<%@ include file="/WEB-INF/views/header.jsp" %> 
<head> 
<title>upload</title> 
</head> 
<body> 
    <h1>Upload Stuff -</h1> 
    ${message} 
    <br /> 
    <br /> 

    <form:form commandName="FORM" action="/upload" 
     enctype="multipart/form-data" method="POST"> 
     <input type="hidden" name="type" value="${ type }"/> 
     <table> 
      <tr> 
       <td colspan="2" style="color: red;"><form:errors path="*" 
         cssStyle="color : red;" /> ${errors}</td> 
      </tr> 
      <tr> 
       <td>Name :</td> 
       <td> 
        <form:input type="text" path="name" /> 
       </td> 
      </tr> 
      <tr> 
       <td>File:</td> 
       <td> 
        <form:input type="file" path="bytes" /> 
       </td> 
      </tr> 
      <tr> 
       <td colspan="2"><input type="submit" value="Upload File" /> 
       </td> 
      </tr> 
     </table> 
    </form:form> 
    <br /> 
    <a href="/">Go home</a> 
</body> 
<%@ include file="/WEB-INF/views/footer.jsp"%> 

Et l'erreur que je reçois est:

Impossible de jeter l'objet UploadedFile à DocumentFile

Toute idée Pourquoi?

MISE À JOUR: J'ai trouvé une solution de contournement en ne passant pas le fichier UploadedFile, en passant à la place la classe Concrete que je veux réellement conserver. J'ai également dû supprimer les méthodes controller/service/dao et en créer une pour chaque enfant UploadedFile. On dirait qu'il devrait y avoir une meilleure façon de le faire. S'il vous plaît donner vos suggestions. Merci d'avance! :)

Répondre

0

Votre problème semble être plus sur Spring que Hibernate. Ce:

@ModelAttribute(value="FORM") UploadedFile form 

Spring n'a aucun moyen de savoir, quand il se traduit par la requête entrante, que vous voulez créer un DocumentFile instaead d'un UploadedFile. Il est peut-être possible de créer votre propre ConversionService, mais il est probablement plus facile d'avoir différents mappages de requêtes pour vos différents formulaires. Comme

@RequestMapping(value="/post/uploadedfile", method=RequestMethod.POST) 
public String processUploadedFileForm(Model model, @RequestParam(value="type") String type, @ModelAttribute(value="FORM") UploadedFile form,BindingResult result, Principal principal) throws FileSaveException, Exception{ 
... 
} 

@RequestMapping(value="/post/documentfile", method=RequestMethod.POST) 
public String processDocumentFileForm(Model model, @RequestParam(value="type") String type, @ModelAttribute(value="FORM") DocumentFile form,BindingResult result, Principal principal) throws FileSaveException, Exception{ 
... 
} 
+0

Ouais, c'est ce que j'ai fini par faire. J'ai posté cela dans mon message de mise à jour. J'espérais juste qu'il y avait une façon plus propre de le faire. Merci beaucoup pour votre suggestion. :) " –

+0

" Printemps n'a aucun moyen de savoir, quand il traduit la demande entrante, que vous voulez qu'il crée un instaead d'un . " Cette déclaration me perturbe, car si j'envoie un objet "enfant" au formulaire, et que la réflexion est utilisée pour remplir les champs de formulaire, je m'attends à ce que le framework comprenne, ou "se souvienne", renvoyer un objet "enfant" via un méthode POST respective dans le contrôleur. – Rick

+0

@Rick alors j'ai peur que vous ne soyez déçu avec Spring MVC. Il est différent de ASP ou JSF, il ne maintient pas l'état d'affichage complexe et la vue est faiblement couplée au modèle. Si vous recherchez ce niveau d'intelligence, alors Spring n'est pas bon pour vous. D'un autre côté, vous constaterez que les frameworks plus complexes et étroitement liés se lient les mains de bien d'autres façons, donc il y a toujours un compromis :) – pap

Questions connexes