Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am developing a document management application in spring using jpa and MySQL. The application is currently accepting a document and its meta data from a user web form createOrUpdateDocumentForm.jsp into the controller DocumentController.java. However, the data is not making its way into the MySQL database. Can someone show me how to alter my code so that the document and its metadata get stored in the underlying database?

The flow of data (including the pdf document) seems to go through the following objects:

createOrUpdateDocumentForm.jsp  //omitted for brevity, since it is sending data to controller (see below)
Document.java  
DocumentController.java  
ClinicService.java
JpaDocumentRepository.java
The MySQL database  

I will summarize relevant parts of each of these objects as follows:

The jsp triggers the following method in DocumentController.java:

@RequestMapping(value = "/patients/{patientId}/documents/new", headers = "content-type=multipart/*", method = RequestMethod.POST)
public String processCreationForm(@ModelAttribute("document") Document document, BindingResult result, SessionStatus status, @RequestParam("file") final MultipartFile file) {
    document.setCreated();
    byte[] contents;
    Blob blob = null;
    try {
        contents = file.getBytes();
        blob = new SerialBlob(contents);
    } catch (IOException e) {e.printStackTrace();}
    catch (SerialException e) {e.printStackTrace();}
    catch (SQLException e) {e.printStackTrace();}
    document.setContent(blob);
    document.setContentType(file.getContentType());
    document.setFileName(file.getOriginalFilename());
    System.out.println("----------- document.getContentType() is: "+document.getContentType());
    System.out.println("----------- document.getCreated() is: "+document.getCreated());
    System.out.println("----------- document.getDescription() is: "+document.getDescription());
    System.out.println("----------- document.getFileName() is: "+document.getFileName());
    System.out.println("----------- document.getId() is: "+document.getId());
    System.out.println("----------- document.getName() is: "+document.getName());
    System.out.println("----------- document.getPatient() is: "+document.getPatient());
    System.out.println("----------- document.getType() is: "+document.getType());        
    try {System.out.println("[[[[BLOB LENGTH IS: "+document.getContent().length()+"]]]]");}
    catch (SQLException e) {e.printStackTrace();}
    new DocumentValidator().validate(document, result);
    if (result.hasErrors()) {
        System.out.println("result.getFieldErrors() is: "+result.getFieldErrors());
        return "documents/createOrUpdateDocumentForm";
    }
    else {
        this.clinicService.saveDocument(document);
        status.setComplete();
        return "redirect:/patients?patientID={patientId}";
    }
}

When I submit a document through the web form in the jsp to the controller, the System.out.println() commands in the controller code output the following, which indicate that the data is in fact getting sent to the server:

----------- document.getContentType() is: application/pdf
----------- document.getCreated() is: 2013-12-16
----------- document.getDescription() is: paper
----------- document.getFileName() is: apaper.pdf
----------- document.getId() is: null
----------- document.getName() is: apaper
----------- document.getPatient() is: [Patient@564434f7 id = 1, new = false, lastName = 'Frank', firstName = 'George', middleinitial = 'B', sex = 'Male', dateofbirth = 2000-11-28T16:00:00.000-08:00, race = 'caucasian']
----------- document.getType() is: ScannedPatientForms
[[[[BLOB LENGTH IS: 712238]]]]  //This indicates the file content was converted to blob

The Document.java model is:

@Entity
@Table(name = "documents")
public class Document {
    @Id
    @GeneratedValue
    @Column(name="id")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "client_id")
    private Patient patient;

    @ManyToOne
    @JoinColumn(name = "type_id")
    private DocumentType type;

    @Column(name="name")
    private String name;

    @Column(name="description")
    private String description;

    @Column(name="filename")
    private String filename;

    @Column(name="content")
    @Lob
    private Blob content;

    @Column(name="content_type")
    private String contentType;

    @Column(name = "created")
    private Date created;

    public Integer getId(){return id;}
    public void setId(Integer i){id=i;}

    protected void setPatient(Patient patient) {this.patient = patient;}
    public Patient getPatient(){return this.patient;}

    public void setType(DocumentType type) {this.type = type;}
    public DocumentType getType() {return this.type;}

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

    public String getDescription(){return description;}
    public void setDescription(String desc){description=desc;}

    public String getFileName(){return filename;}
    public void setFileName(String fn){filename=fn;}

    public Blob getContent(){return content;}
    public void setContent(Blob ct){content=ct;}

    public String getContentType(){return contentType;}
    public void setContentType(String ctype){contentType=ctype;}

    public void setCreated(){created=new java.sql.Date(System.currentTimeMillis());}
    public Date getCreated() {return this.created;}

    @Override
    public String toString() {return this.getName();}
    public boolean isNew() {return (this.id == null);}

}

The ClinicService.java code that is called from the DocumentController is:

private DocumentRepository documentRepository;
private PatientRepository patientRepository;

@Autowired
public ClinicServiceImpl(DocumentRepository documentRepository, PatientRepository patientRepository) {
    this.documentRepository = documentRepository;
    this.patientRepository = patientRepository;
}

@Override
@Transactional
public void saveDocument(Document doc) throws DataAccessException {documentRepository.save(doc);}

The relevant code in JpaDocumentRepository.java is:

@PersistenceContext
private EntityManager em;

@Override
public void save(Document document) {
    if (document.getId() == null) {this.em.persist(document);}
    else {this.em.merge(document);}
}  

Finally, the relevant parts of the SQL code that creates the database include:

CREATE TABLE IF NOT EXISTS documenttypes (
  id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(80),
  INDEX(name)
);

CREATE TABLE IF NOT EXISTS patients (
  id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  first_name VARCHAR(30),
  middle_initial VARCHAR(5), 
  last_name VARCHAR(30),
  sex VARCHAR(20), 
  date_of_birth DATE,
  race VARCHAR(30), 
  INDEX(last_name)
);

CREATE TABLE IF NOT EXISTS documents (
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  client_id int(4) UNSIGNED NOT NULL,
  type_id INT(4) UNSIGNED, 
  name varchar(200) NOT NULL,
  description text NOT NULL,
  filename varchar(200) NOT NULL,
  content mediumblob NOT NULL, 
  content_type varchar(255) NOT NULL,
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (client_id) REFERENCES patients(id),
  FOREIGN KEY (type_id) REFERENCES documenttypes(id)
);  

What changes do I make to this code so that it saves the document in the documents table of the MySQL database using jpa?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
136 views
Welcome To Ask or Share your Answers For Others

1 Answer

@CodeMed, it took me a while, but I was able to reproduce the issue. It might be a configuration issue : @PersistenceContext might be scanned twice, it might be scanned by your root-context and your web-context. This cause the @PersistenceContext to be shared, therefore it is not saving your data (Spring doesn't allow that). I found it weird that no messages or logs where displayed . if you tried this snippet below on you Save(Document document) you will see the actual error :

Session session = this.em.unwrap(Session.class);
session.persist(document);

To solve the problem, you can do the following (avoid the @PersistenceContext to be scanned twice) :

1- Make sure that all your controller are in a separate package like com.mycompany.myapp.controller, and in your web-context use the component-scan as <context:component-scan annotation-config="true" base-package="com.mycompany.myapp.controller" />

2- Make sure that others component are in differents package other than the controller package , for example : com.mycompany.myapp.dao, com.mycompany.myapp.service .... and then in your root-context use the component-scan as <context:component-scan annotation-config="true" base-package="com.mycompany.myapp.service, com.mycompany.myapp.dao" />

Or show me yours spring xml configurations and your web.xml, I will point you to the right direction


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...