0

我正在尝试生成一个包含对象信息的 PDF 文件,然后将其附加到存储在数据库中的另一个对象。我正在使用的可附加插件现在可用于用户端附件,但我需要我的系统能够自动执行此操作。

我正在使用:
Grails 1.3.9
Attachmentable 0.3.0 http://grails.org/plugin/attachmentable
渲染 0.4.3 http://grails.org/plugin/rendering

我已经能够生成和显示 pdf,但不知道如何使用可附件插件附加它。我需要一些方法来获取生成的 pdf 字节数组并将其转换为 MultipartFile 以用于我调用的可附加插件函数。我得到的错误表明我的参数类型无效。

我保存object1和object2,然后生成object1的pdf并尝试将其附加到object2。

提前感谢您的帮助!

Thing1 控制器片段:

ByteArrayOutputStream bytes = pdfRenderingService.render(template: "/thing1/pdf", model: [thing1: thing1])

attachmentableService.addAttachment("unknown", thing2.id, bytes)

我试图调用的 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 运行时错误:

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)

我添加的服务方式:

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
}
4

1 回答 1

0

看起来您引用的 AttachmentableService(来自 Attachmentable 插件)假设它正在处理文件上传场景,这样您就可以通过 request.getFile() 轻松获取 MultipartFile 实例。这不是你的情况——你通过渲染插件创建文件,并且你希望该文件附加到域对象,对吗?

您可以尝试通过首先将 pdf 字节写入磁盘来手动构建 CommonsMultipartFile 实例,然后通过 DiskFileItemFactory 创建一个 DiskFileItem。有关我的想法的示例,请参见这篇文章: 如何从绝对文件路径制作 CommonsMultipartFile?

另一个更好的选择可能是检查该插件的源代码并添加一个不需要您经历这些旋转的方法 - 可能是接受 File 或 OutputStream 的 addAttachment 方法的一个版本 - 并将 PR 提交给插件作者。(看起来他们正在向限定域对象添加一个“addAttachment”方法,它也需要一个 CommonsMultipartFile)。

否则,您可能只需要创建自己的服务即可基本上提供相同的最终结果,这显然是创建一个 AttachmentLink 和关联的 Attachment 实例。

于 2014-08-26T13:43:11.643 回答