Cod*_*Med 12 java spring hibernate jpa spring-mvc
我正在spring使用jpa和开发文档管理应用程序MySQL.应用程序当前正在从用户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
Run Code Online (Sandbox Code Playgroud)
我将总结每个对象的相关部分如下:
所述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}";
}
}
Run Code Online (Sandbox Code Playgroud)
当我提交一份文件,通过网页表单中jsp的controller,将System.out.println()在命令controller代码输出以下,这表明该数据实际上是越来越发送到服务器:
----------- 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
Run Code Online (Sandbox Code Playgroud)
该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);}
}
Run Code Online (Sandbox Code Playgroud)
ClinicService.java从中调用的代码DocumentController是:
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);}
Run Code Online (Sandbox Code Playgroud)
相关代码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);}
}
Run Code Online (Sandbox Code Playgroud)
最后,创建数据库的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)
);
Run Code Online (Sandbox Code Playgroud)
我对此代码进行了哪些更改,以便使用?保存document在数据库documents表中?MySQLjpa
@CodeMed,我花了一段时间,但我能够重现这个问题.这可能是配置问题:@PersistenceContext可能会扫描两次,可能会被您的根上下文和您的Web上下文扫描.这导致@PersistenceContext共享,因此它不保存您的数据(Spring不允许这样做).我发现没有显示的消息或日志很奇怪.如果您在保存(文档文档)上尝试了下面的代码片段,您将看到实际错误:
Session session = this.em.unwrap(Session.class);
session.persist(document);
Run Code Online (Sandbox Code Playgroud)
要解决此问题,您可以执行以下操作(避免@PersistenceContext两次扫描):
1-确保所有控制器都在一个单独的包中com.mycompany.myapp.controller,并且在您的Web上下文中使用组件扫描<context:component-scan annotation-config="true" base-package="com.mycompany.myapp.controller" />
2-确保其他组件位于控制器包以外的其他组件中,例如:com.mycompany.myapp.dao,com.mycompany.myapp.service....然后在根上下文中使用组件扫描
<context:component-scan annotation-config="true" base-package="com.mycompany.myapp.service, com.mycompany.myapp.dao" />
或者告诉我你的spring xml配置和你的web.xml,我会指出你正确的方向
您的 JPA 映射看起来不错。显然,@Lob 要求数据类型为 byte[] / Byte[] / 或 java.sql.Blob。基于此,加上您的症状和调试打印输出,您的代码似乎执行了正确的数据操作(JPA 注释很好),但 spring + MySQL 的组合并未提交。这表明您的 spring 事务配置或 MySQL 数据类型存在小问题。
\n\n1. 交易行为
\n\n\n\n\nJpaDocumentRepository.java中的相关代码为:
\n
@PersistenceContext\nprivate EntityManager em;\n\n@Override\npublic void save(Document document) {\n if (document.getId() == null) {this.em.persist(document);}\n else {this.em.merge(document);}\n} \nRun Code Online (Sandbox Code Playgroud)\n\n@PersistenceContext您通过(即由 JTA 支持的容器管理实体管理器,而不是实体管理器资源本地事务em.getTransaction())注入实体管理器@Transactional(即 spring 专有交易 - 后来在 Java EE 7 中标准化的注释)。注释和代码应该给出事务行为。您是否为 JTA 事务正确配置了 Spring?(使用 JtaTransactionManager,而不是提供 JDBC 驱动程序本地事务的 DataSourceTransactionManager)Spring XML 应该包含与以下内容非常相似的内容:
\n\n<!-- JTA requires a container-managed datasource -->\n<jee:jndi-lookup id="jeedataSource" jndi-name="jdbc/mydbname"/> \n\n<!-- enable the configuration of transactional behavior based on annotations -->\n<tx:annotation-driven transaction-manager="txManager"/>\n\n<!-- a PlatformTransactionManager is still required -->\n<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" >\n <!-- (this dependency "jeedataSource" must be defined somewhere else) -->\n <property name="dataSource" ref="jeedataSource"/> \n</bean>\nRun Code Online (Sandbox Code Playgroud)\n\n对其他参数/设置保持怀疑。
\n\n这是 Spring 必须执行的操作的手动编码版本(仅用于理解 - 不要对此进行编码)。使用 UserTransaction (JTA),而不是 EntityTransaction 类型的 em.getTransaction()(JDBC 本地):
\n\n// inject a reference to the servlet container JTA tx\n@Resource UserTransaction jtaTx;\n\n// servlet container-managed EM\n@PersistenceContext private EntityManager em; \n\npublic void save(Document document) {\n try {\n jtaTx.begin();\n try {\n if (document.getId() == null) {this.em.persist(document);}\n else {this.em.merge(document);}\n jtaTx.commit();\n } catch (Exception e) {\n jtaTx.rollback();\n // do some error reporting / throw exception ...\n }\n } catch (Exception e) {\n // system error - handle exceptions from UserTransaction methods\n // ...\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n2.MySQL数据类型
\n\n如图所示(底部),与其他数据库相比,MySql Blob 有点特殊。各种 Blob 及其最大存储容量为:
\n\nTINYBLOB - 255 字节\nBLOB - 65535 字节\nMEDIUMBLOB - 16,777,215 字节 (2^24 - 1)\nLONGBLOB - 4G 字节 (2^32 \xe2\x80\x93 1)
\n\n如果 (2) 是您的问题:
\n\n| 归档时间: |
|
| 查看次数: |
1731 次 |
| 最近记录: |