文件不保存在spring jpa文件管理器应用程序中 [英] document not saving in spring jpa document manager application

查看:86
本文介绍了文件不保存在spring jpa文件管理器应用程序中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 spring 中使用 jpa MySQL开发文档管理应用程序。 code>。该应用程序当前接受来自用户web表单 createOrUpdateDocumentForm.jsp 的文档及其元数据到控制器 DocumentController.java 。但是,数据并未进入 MySQL 数据库。有人能告诉我如何改变我的代码,以便文档及其元数据存储在底层数据库中吗?

数据流(包括pdf文档)似乎贯穿以下对象:

  createOrUpdateDocumentForm.jsp //为简明起见省略,因为它将数据发送给控制器(见下文)
Document.java
DocumentController.java
ClinicService.java
JpaDocumentRepository.java
MySQL数据库

我将总结这些每个的相关部分对象,如下所示:
$ b $ jsp 会在 DocumentController.java 中触发以下方法 code>:

  @RequestMapping(value =/ patients / {patientId} / documents / new,headers = Content-Type = multipart / *,method = RequestMethod.POST)
public String processCreationForm(@ModelAttribute(document)文档文档,BindingResult结果,SessionStatus状态,@RequestParam(file)final MultipartFile文件){
document.setCreated();
byte []内容;
Blob blob = null;
尝试{
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();}
新的DocumentValidator()。validate(document,result); ()result.getFieldErrors());
if
返回documents / createOrUpdateDocumentForm;
}
else {
this.clinicService.saveDocument(document);
status.setComplete();
返回重定向:/ patients?patientID = {patientId};
}
}

当我通过Web表单提交文档 jsp 控制器 System.out.println()控制器代码中的c>命令会输出以下内容,这表明数据实际上正在发送到服务器:

  ----------- document.getContentType()是:application / pdf 
----------- document。 getCreated()是:2013-12-16
----------- document.getDescription()是:paper
-----------文档。 getFileName()是:apaper.pdf
----------- document.getId()是:null
----------- document.getName( )是: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']
-----------文档.getType()是:ScannedPatientForms
[[[[BLOB长度是:71223 8]]]] //这表示文件内容已转换为blob

Document.java 模型是:

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

@ManyToOne
@JoinColumn(name =client_id)
私人患者;

@ManyToOne
@JoinColumn(name =type_id)
私人DocumentType类型;

@Column(name =name)
私有字符串名称;

@Column(name =description)
私有字符串描述;

@Column(name =filename)
私有字符串文件名;

@Column(name =content)
@Lob
私人Blob内容;

@Column(name =content_type)
private String contentType;

@Column(name =created)
私人创建日期;
$ b 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;}
$ b $ 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;}
$ b $ public String getFileName(){return filename; }
public void setFileName(String fn){filename = fn;}
$ b $ 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 vo } 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);}


ClinicService.java DocumentController 是:

  private DocumentRepository documentRepository; 
私人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);}

JpaDocumentRepository.java 中的相关代码是:

  @PersistenceContext 
私人EntityManager em;

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

创建数据库的SQL代码的相关部分包括:

  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患者(
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文件(
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,
描述文本NOT NULL,
filename varchar(200)NOT NULL,
content mediumblob NOT NULL,
content_type varchar(255)NOT NULL,
创建时间戳NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY(client_id)REFERENCES患者(id),
FOREIGN KEY(type_id)REFERENCES documenttypes(id)
);

我对此代码做了哪些更改,以便保存文档<使用 jpa 数据库的文档表 code>?

解决方案

你的JPA映射看起来不错。显然,@Lob要求数据类型为byte [] / Byte [] /或java.sql.Blob。基于此,加上你的症状和调试打印输出,看起来你的代码做了正确的数据操作(JPA注释很好),但是spring + MySQL的组合并没有提交。这表明你的spring事务配置或你的MySQL数据类型存在一个小问题。



1。交易行为


JpaDocumentRepository.java中的相关代码是:




  @PersistenceContext 
private EntityManager em;

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




  • 您没有使用EJB(因此没有自动容器管理事务)。

  • 您在Servlets / java类中使用JPA(因此您需要'手动'事务分隔 - 在servlet容器之外;在您的代码中或通过Spring配置)。

  • 您通过 @PersistenceContext 注入实体管理器(即由JTA支持的容器管理实体管理器,而不是实体管理器资源 - 本地交易, em.getTransaction()

  • 您已将'parent'方法标记为 @Transactional (例如,Spring专有的transcations - 稍后在Java EE 7中标准化的注释)。


注释和代码应该给交易行为。你有没有正确配置JTA事务的Spring? (使用JtaTransactionManager,而不是DataSourceTransactionManager,它提供JDBC驱动程序本地事务)Spring XML应该包含一些非常类似于以下内容的内容:

 <! -  -  JTA需要一个容器管理的数据源 - > 
< jee:jndi-lookup id =jeedataSourcejndi-name =jdbc / mydbname/>

<! - 启用基于注释的事务行为配置 - >
< tx:annotation-driven transaction-manager =txManager/>

<! - 一个PlatformTransactionManager仍然是必需的 - >
< bean id =txManagerclass =org.springframework.transaction.jta.JtaTransactionManager>
<! - (此依赖关系jeedataSource必须在其他地方定义) - >
< property name =dataSourceref =jeedataSource/>
< / bean>

怀疑其他参数/​​设置。

<这是Spring必须做的手动编码版本(仅供了解 - 不要编码)。使用UserTransaction(JTA),而不是类型为EntityTransaction(JDBC local)的em.getTransaction():

  //将参考注入servlet容器JTA tx 
@Resource UserTransaction jtaTx;

// servlet容器管理的EM
@PersistenceContext private EntityManager em;

public void save(Document document){
try {
jtaTx.begin();
try {
if(document.getId()== null){this.em.persist(document);}
else {this.em.merge(document);}
jtaTx.commit();
} catch(Exception e){
jtaTx.rollback();
//做一些错误报告/抛出异常...
}
} catch(Exception e){
//系统错误 - 处理来自UserTransaction方法的异常
// ...
}
}

2。 MySQL数据类型



如图所示 here(at bottom),与其他数据库相比,MySql Blob有点特别。各种Blobs和它们的最大存储容量是:

TINYBLOB - 255字节
BLOB - 65535字节
MEDIUMBLOB - 16,777,215字节(2 ^ 24 - 1)
LONGBLOB - 4G字节(2 ^ 32 - 1)

如果(2)证明是你的问题:


  • 将MySQL类型增加到MEDIUMBLOB或LONGBLOB

  • 调查为什么没有看到错误消息(v重要)。您的日志记录是否正确配置您是否检查日志?


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?

解决方案

Your JPA mappings seem good. Obviously, @Lob requires data type to be byte[] / Byte[] / or java.sql.Blob. Based on that, plus your symptoms and debugging printout it seems your code doing the correct data manipulation (JPA annotations good), but the combination of spring + MySQL isn't commiting. This suggests a minor problem with your spring transactional config OR with your MySQL data type.

1. Transactional Behaviour

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

  • You're not using EJBs (hence no 'automatic' container-managed transactions).
  • You're using JPA within Servlets/java classes (hence you require 'manual' transaction demarcation - outside servlet container; in your code or via Spring config).
  • You are injecting the entity manager via @PersistenceContext (i.e. container-managed entity manager backed by JTA, not a Entity Manager resource-local transaction, em.getTransaction())
  • You have marked your 'parent' method as @Transactional (i.e. spring proprietary transcations - annotation later standardised in Java EE 7).

The annotations and code should give transactional behaviour. Do you have a Spring correctly configured for JTA transactions? (Using JtaTransactionManager, not DataSourceTransactionManager which gives JDBC driver local transactions) Spring XML should contain something very similar to:

<!-- JTA requires a container-managed datasource -->
<jee:jndi-lookup id="jeedataSource" jndi-name="jdbc/mydbname"/> 

<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>

<!-- a PlatformTransactionManager is still required -->
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
  <!-- (this dependency "jeedataSource" must be defined somewhere else) -->
  <property name="dataSource" ref="jeedataSource"/>  
</bean>

Be suspicious of additional parameters / settings.

This is the manually coded version of what Spring must do (for understanding only - don't code this). Uses UserTransaction (JTA), not em.getTransaction() of type EntityTransaction (JDBC local):

// inject a reference to the servlet container JTA tx
@Resource UserTransaction jtaTx;

// servlet container-managed EM
@PersistenceContext private EntityManager em; 

public void save(Document document) {
    try {
        jtaTx.begin();
        try {
            if (document.getId() == null) {this.em.persist(document);}
            else {this.em.merge(document);}
            jtaTx.commit();
        } catch (Exception e) {
             jtaTx.rollback();
             // do some error reporting / throw exception ...
        }
    } catch (Exception e) {
        // system error - handle exceptions from UserTransaction methods
        // ...
    }
}

2. MySQL Data Type

As shown here (at bottom), MySql Blobs are a bit special compared to other databases. The various Blobs and their maximum storage capacities are:

TINYBLOB - 255 bytes BLOB - 65535 bytes MEDIUMBLOB - 16,777,215 bytes (2^24 - 1) LONGBLOB - 4G bytes (2^32 – 1)

If (2) turns out to be your problem:

  • increase the MySQL type to MEDIUMBLOB or LONGBLOB
  • investigate why you didn't see an error message (v important). Was your logging properly configured? Did you check logs?

这篇关于文件不保存在spring jpa文件管理器应用程序中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆