[英]Render a PDF file and save to object using grails Rendering and Attachmentable plugins
I am attempting to generate a PDF file that contains object information and then attach it to another object that is stored in the database. 我试图生成一个包含对象信息的PDF文件,然后将其附加到存储在数据库中的另一个对象。 The attachmentable plugin I am using is working now for user end attachments, but I need my system to be able to do it automatically.
我正在使用的可附件插件现在可以用于用户端附件,但是我需要我的系统能够自动执行此操作。
I am using: 我在用:
Grails 1.3.9 Grails 1.3.9
Attachmentable 0.3.0 http://grails.org/plugin/attachmentable 可附加的0.3.0 http://grails.org/plugin/attachmentable
Rendering 0.4.3 http://grails.org/plugin/rendering 渲染0.4.3 http://grails.org/plugin/rendering
I have been able to generate and display the pdf, but do not know how to attach it using the attachmentable plugin. 我已经能够生成和显示pdf,但不知道如何使用可附加附件来附加它。 I need some way to take the generated pdf byte array and convert it to a MultipartFile for the attachmentable plugin function I call.
我需要某种方式来生成生成的pdf字节数组,并将其转换为MultipartFile,以供我调用的可附加插件功能。 The error I get shows that my argument types are invalid.
我得到的错误表明我的参数类型无效。
I save object1 and object2, then generate the pdf of object1 and try to attach it to object2. 我保存了object1和object2,然后生成object1的pdf,然后尝试将其附加到object2。
Thanks in advance for you help! 预先感谢您的帮助!
Thing1 Controller Snippets: Thing1控制器片段:
ByteArrayOutputStream bytes = pdfRenderingService.render(template: "/thing1/pdf", model: [thing1: thing1])
attachmentableService.addAttachment("unknown", thing2.id, bytes)
AttachmentableService function I am attempting to call: 我正在尝试调用AttachmentableService函数:
def addAttachment(def poster, def reference, CommonsMultipartFile file) {
addAttachment(CH.config, poster, reference, file)
}
def addAttachment(def config,
def poster,
def reference,
CommonsMultipartFile file) {
if (reference.ident() == null) {
throw new AttachmentableException(
"You must save the entity [${delegate}] before calling addAttachment.")
}
if (!file?.size) {
throw new EmptyFileException(file.name, file.originalFilename)
}
String delegateClassName = AttachmentableUtil.fixClassName(reference.class)
String posterClass = (poster instanceof String) ? poster : AttachmentableUtil.fixClassName(poster.class.name)
Long posterId = (poster instanceof String) ? 0L : poster.id
String filename = file.originalFilename
// link
def link = AttachmentLink.findByReferenceClassAndReferenceId(
delegateClassName, reference.ident())
if (!link) {
link = new AttachmentLink(
referenceClass: delegateClassName,
referenceId: reference.ident())
}
// attachment
Attachment attachment = new Attachment(
// file
name: FilenameUtils.getBaseName(filename),
ext: FilenameUtils.getExtension(filename),
length: 0L,
contentType: file.contentType,
// poster
posterClass: posterClass,
posterId: posterId,
// input
inputName: file.name)
link.addToAttachments attachment
if (!link.save(flush: true)) {
throw new AttachmentableException(
"Cannot create Attachment for arguments [$user, $file], they are invalid.")
}
// save file to disk
File diskFile = AttachmentableUtil.getFile(config, attachment, true)
file.transferTo(diskFile)
attachment.length = diskFile.length()
// interceptors
if(reference.respondsTo('onAddAttachment')) {
reference.onAddAttachment(attachment)
}
attachment.save(flush:true) // Force update so searchable can try to index it again.
return reference
}
Grails runtime error: Grails运行时错误:
groovy.lang.MissingMethodException: No signature of method: com.macrobit.grails.plugins.attachmentable.services.AttachmentableService.addAttachment() is applicable for argument types: (java.lang.String, java.lang.Long, java.io.ByteArrayOutputStream) values: [unknown, 80536, %PDF-1.4 and a long string of unreadable data...]
Possible solutions: addAttachment(java.lang.Object, java.lang.Object, org.springframework.web.multipart.commons.CommonsMultipartFile), addAttachment(java.lang.Object, java.lang.Object, java.lang.Object, org.springframework.web.multipart.commons.CommonsMultipartFile)
Service Method I Added: 我添加的服务方法:
def customAddMethod(def poster, def reference, def pdfBytes) {
customAddMethod(CH.config, poster, reference, pdfBytes)
}
def customAddMethod(def config,
def poster,
def reference,
def pdfBytes) {
if (reference.ident() == null) {
throw new AttachmentableException(
"You must save the entity [${delegate}] before calling customAddMethod.")
}
String delegateClassName = AttachmentableUtil.fixClassName(reference.class)
String posterClass = (poster instanceof String) ? poster : AttachmentableUtil.fixClassName(poster.class.name)
Long posterId = (poster instanceof String) ? 0L : poster.id
String filename = "File Name"
// link
def link = AttachmentLink.findByReferenceClassAndReferenceId(
delegateClassName, reference.ident())
if (!link) {
link = new AttachmentLink(
referenceClass: delegateClassName,
referenceId: reference.ident())
}
// attachment
Attachment attachment = new Attachment(
// file
name: "File Name",
ext: "pdf",
length: 0L,
contentType: "application/pdf",
// poster
posterClass: posterClass,
posterId: posterId,
// input
inputName: "File Name")
link.addToAttachments attachment
if (!link.save(flush: true)) {
throw new AttachmentableException(
"Cannot create Attachment for arguments [$user, $file], they are invalid.")
}
// save file to disk
byte[] bytes = pdfBytes.toByteArray(); //convert ByteArrayOutputStream to ByteArray
File diskFile = AttachmentableUtil.getFile(config, attachment, true) //file path
FileOutputStream fos = new FileOutputStream(diskFile); //open file output stream to write to
fos.write(bytes); //write rendered pdf bytes to file
fos.flush();
fos.close();
attachment.length = diskFile.length()
// interceptors
if(reference.respondsTo('onAddAttachment')) {
reference.onAddAttachment(attachment)
}
attachment.save(flush:true) // Force update so searchable can try to index it again.
return reference
}
It looks like the AttachmentableService you referenced (from the Attachmentable plugin) assumes it's dealing with a file-upload scenario, such that you could easily grab the MultipartFile instance via request.getFile(). 好像您引用的AttachmentableService(来自Attachmentable插件)假定它正在处理文件上载情况,因此您可以通过request.getFile()轻松获取MultipartFile实例。 That's not the case for you - you're creating the file via the Rendering plugin, and you want that file attached to a domain object, right?
事实并非如此-您正在通过“渲染”插件创建文件,并且希望将该文件附加到域对象,对吗?
You could try constructing a CommonsMultipartFile instance manually by first writing the pdf bytes to disk, and then create a DiskFileItem via DiskFileItemFactory. 您可以尝试通过首先将pdf字节写入磁盘,然后通过DiskFileItemFactory创建DiskFileItem来手动构造CommonsMultipartFile实例。 See this post for an example of what I'm thinking: How to make CommonsMultipartFile from absolute file path?
请参阅这篇文章,以了解我的想法: 如何从绝对文件路径制作CommonsMultipartFile?
Another, better, option might be to checkout that plugin's source and add a method that doesn't require you to go through those gyrations - perhaps a version of the addAttachment method that accepts a File or an OutputStream instead - and submit a PR to the plugin author. 另一个更好的选择可能是签出该插件的源代码,并添加不需要您进行旋转的方法-也许是addAttachment方法的版本,该方法可以接受File或OutputStream-并将PR提交给插件作者。 (Looks like they're adding an 'addAttachment' method to qualifying domain objects, which also expects a CommonsMultipartFile).
(看起来他们正在为合格的域对象添加“ addAttachment”方法,这也需要一个CommonsMultipartFile)。
Otherwise, you might just have to create your own service to basically provide the same end result, which apparently is to create an AttachmentLink and associated Attachment instance. 否则,您可能只需要创建自己的服务即可提供基本的最终结果,这显然是创建AttachmentLink和关联的Attachment实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.