Java 未在spring jpa文档管理器应用程序中保存文档
我正在使用Java 未在spring jpa文档管理器应用程序中保存文档,java,spring,hibernate,spring-mvc,jpa,Java,Spring,Hibernate,Spring Mvc,Jpa,我正在使用jpa和MySQL在spring中开发一个文档管理应用程序。应用程序当前正在从用户web表单createOrUpdateDocumentForm.jsp接受文档及其元数据,并将其放入控制器DocumentController.java。但是,数据没有进入MySQL数据库。有人能告诉我如何修改代码,使文档及其元数据存储在底层数据库中吗 数据流(包括pdf文档)似乎通过以下对象: createOrUpdateDocumentForm.jsp //omitted for brevity,
jpa
和MySQL
在spring
中开发一个文档管理应用程序。应用程序当前正在从用户web表单createOrUpdateDocumentForm.jsp
接受文档及其元数据,并将其放入控制器DocumentController.java
。但是,数据没有进入MySQL
数据库。有人能告诉我如何修改代码,使文档及其元数据存储在底层数据库中吗
数据流(包括pdf文档)似乎通过以下对象:
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
我将对每个对象的相关部分总结如下:
jsp
在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}";
}
}
当我通过jsp
中的web表单向控制器提交文档时,控制器中的System.out.println()
命令会输出以下内容,这表明数据实际上正在发送到服务器:
----------- 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
Document.java
模型是:
@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);}
}
从DocumentController
调用的ClinicService.java
代码是:
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);}
@PersistenceContext
private EntityManager em;
@Override
public void save(Document document) {
if (document.getId() == null) {this.em.persist(document);}
else {this.em.merge(document);}
}
JpaDocumentRepository.java
中的相关代码是:
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);}
@PersistenceContext
private 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 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)
);
我对这段代码做了哪些更改,以便它使用jpa
,将文档保存在MySQL
数据库的文档表中?我不是一个带注释专家的Hibernate(我从2004年开始使用它,但使用XML配置)。不管怎么说,我认为你把注解混错了。您已经指出不希望使用@Transient
持久化文件
字段,但您还说它是一个@Lob
,这意味着您确实希望它持久化。看起来@Lob
获胜了,Hibernate正在尝试使用字段名将字段解析为列
脱掉@ LB,我想你会被设置。
< P>这不是你的问题的直接回答(抱歉,但我不是Hibernate的粉丝,所以不能真正帮助你)。但是你应该考虑使用一个NoSQL数据库,比如MunGDB,而不是MySQL这样的工作。我已经尝试了这两种方法,NoSQL数据库更适合这种需求
您会发现,在这种情况下,它的性能比MySQL好得多,SpringData MongoDB允许您非常轻松地保存和加载自动映射到MongoDB的Java对象。您的JPA映射看起来不错。显然,@Lob要求数据类型为byte[]/byte[]/或java.sql.Blob。在此基础上,再加上您的症状和调试打印输出,您的代码似乎进行了正确的数据操作(JPA注释很好),但spring+MySQL的组合并不令人满意。这表明spring事务配置或MySQL数据类型存在一个小问题
1。交易行为
JpaDocumentRepository.java中的相关代码是:
- 您没有使用EJB(因此没有“自动”容器管理事务)李>
- 您在servlet/java类中使用JPA(因此需要“手动”事务划分-在servlet容器之外;在代码中或通过Spring配置)李>
- 您正在通过
@PersistenceContext
注入实体管理器(即由JTA支持的容器管理的实体管理器,而不是实体管理器资源本地事务,em.getTransaction()
)
- 您已将“父”方法标记为
@Transactional
(即spring专有事务处理-注释稍后在JavaEE7中标准化)
注释和代码应该提供事务行为。您是否为JTA事务正确配置了Spring?(使用JtaTransactionManager,而不是提供JDBC驱动程序本地事务的DataSourceTransactionManager)Spring XML应该包含以下内容:
<!-- 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>
2。MySQL数据类型
如图所示,MySql blob与其他数据库相比有点特殊。各种BLOB及其最大存储容量为:
TINYBLOB-255字节
BLOB-65535字节
MEDIUMBLOB-16777215字节(2^24-1)
LONGBLOB-4G字节(2^32–1)
如果(2)是您的问题:
- 将MySQL类型增加为MEDIUMBLOB或LONGBLOB
- 调查您没有看到错误消息的原因(v重要)。您的日志记录配置是否正确?你查过日志了吗
@CodeMed,我花了一段时间,但我能够重现这个问题。这可能是配置问题:
@PersistenceContext
可能被扫描两次,它可能被根上下文和web上下文扫描。这会导致共享@PersistenceContext
,因此它不会保存您的数据(Spring不允许这样做)。我觉得奇怪的是没有显示任何消息或日志。如果您在保存(文档)时尝试以下代码段,您将看到实际错误:
Session session = this.em.unwrap(Session.class);
session.persist(document);
要解决此问题,可以执行以下操作(避免将@PersistenceContext
扫描两次):
1-确保所有控制器都在一个单独的包中,如com.mycompany.myapp.controller
,并在您的web上下文中使用组件扫描作为
2-确保其他组件位于控制器包以外的不同包中,例如:com.mycompany.myapp.dao
,com.mycompany.myapp.service
。。。。
然后在根上下文中使用组件扫描作为
或者向我展示您的spring xml配置和web.xml,我将为您指出正确的方向+1感谢您指出了一个可能的解决方案。我试过你的建议