【问题标题】:How to Add and Remove MIME attachments correctly如何正确添加和删除 MIME 附件
【发布时间】:2019-04-25 03:59:48
【问题描述】:

我正在向这样的文档添加 MIME 附件

try{
    var d = database.getView("Main").getFirstDocument()
    var it = d.getFirstItem("Body")
    var att:NotesEmbeddedObject = it.getEmbeddedObject("mydoc.docx")
    var streamDOC:NotesStream = session.createStream()

    streamDOC.setContents(att.getInputStream())


    var newd;
    newd = database.getView("NewD").getFirstDocument()
    if(newd==null){
        newd = database.createDocument()
        newd.replaceItemValue("Form","Main")
        var me = newd.createMIMEEntity("Body")
    }else{
        var me = newd.getMIMEEntity("Body") 
    }

    var filename = "test.pdf"
    var mc = me.createChildEntity();
    var he = mc.createHeader("Content-Disposition")
    he.setHeaderVal("attachment; filename=\"" + filename + "\"");
    he = mc.createHeader("Content-ID");
    he.setHeaderVal( "<" + filename + ">" );
    mc.setContentFromBytes(streamDOC, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", NotesMIMEEntity.ENC_IDENTITY_8BIT);
    newd.save()
    print("success")
}catch(e){
    print("fail " + e)
}

我提供了一个删除按钮

var eo = nd.getDocument().getAttachment(att)
eo.remove()
nd.save()

附件已从文档中删除,在 Ytria 中,我可以看到 $FILE 项目已删除,但 BODY 项目未删除。这样做的问题是,如果我在同一个文档中添加一个新附件,我之前删除的所有附件都会回来

这是删除附件之前文档的外观。

不幸的是,这里的文件大小为 0Kb,因为我使用了错误的屏幕截图。从一开始所有的 $File 项目都有正确的大小

这是我删除附件后文档的外观(使用上面的脚本)

这是我删除附件后添加一个附件(使用上面的脚本)后文档的样子

  • 添加或删除附件时我做错了什么吗? (看 脚本)
  • Body 字段是否有“商店”似乎无关紧要 内容为 MIME”选项设置与否
  • 另请参阅此问题 How to Add and Remove attachments using MIME

【问题讨论】:

    标签: xpages attachment mime


    【解决方案1】:

    如果您使用 MIME 方法来附加文件,为什么不使用 MIME 方法来删​​除它呢?

    我使用自己的框架,因此以下代码可能会让您觉得事情过于复杂,但希望您能明白其中的要点:

    我有一个枚举,可以帮助我浏览各种 MIME 类型。在这种情况下,您正在处理ATTACHMENT

    public enum MimeContentType {
    
        ATTACHMENT("attachment") {
    
            @Override
            public boolean matches(String[] headers) {
                int score = 0;
    
                for (String header : headers) {
                    if (header.startsWith("Content-Disposition")) {
                        score++;
                    }
    
                    if (header.contains("attachment")) {
                        score++;
                    }
    
                    if (header.contains("filename")) {
                        score++;
                    }
    
                    if (score == 3) {
                        return true;
                    }
                }
    
                return false;
            }
    
        },
        TEXT("text"),
        TEXT_HTML("text/html"),
        TEXT_PLAIN("text/plain");
    
        private final String type;
    
        private MimeContentType(String type) {
            this.type = type;
        }
    
        public boolean matches(String[] headers) {
            for (String header : headers) {
                if (header.startsWith("Content-Type") && header.contains(type)) {
                    return true;
                }
            }
    
            return false;
        }
    
    }
    

    然后是一些辅助类:

    @FunctionalInterface
    public interface ThrowableConsumer<T> extends Consumer<T> {
    
        @Override
        default void accept(final T t) {
            try {
                acceptOrThrow(t);
            } catch (final Throwable e) {
                throw new RuntimeException(e);
            }
        }
    
        void acceptOrThrow(T t) throws Throwable;
    
    }
    
    @FunctionalInterface
    public interface ThrowableFunction<T, R> extends Function<T, R> {
    
        @Override
        default R apply(T t) {
            try {
                return applyOrThrow(t);
            } catch (final Throwable e) {
                throw new RuntimeException(e);
            }
        }
    
        R applyOrThrow(T t) throws Throwable;
    
    }
    
    @FunctionalInterface
    public interface ThrowablePredicate<T> extends Predicate<T> {
    
        @Override
        default boolean test(T t) {
            try {
                return testOrThrow(t);
            } catch (final Throwable e) {
                throw new RuntimeException(e);
            }
        }
    
        boolean testOrThrow(T t) throws Throwable;
    
    }
    
    @FunctionalInterface
    public interface ThrowableSupplier<T> extends Supplier<T> {
    
        @Override
        default T get() {
            try {
                return getOrThrow();
            } catch (final Throwable e) {
                throw new RuntimeException(e);
            }
        }
    
        T getOrThrow() throws Throwable;
    
    }
    
    public enum DominoUtil {
        ;
    
        private static final Vector<String> MIME_FILTERED_HEADERS = new Vector<>();
    
        static {
            MIME_FILTERED_HEADERS.add("Content-Type");
            MIME_FILTERED_HEADERS.add("Content-Disposition");
        }
    
        public static List<MIMEEntity> getMimeEntitiesByContentType(MIMEEntity entity,
                MimeContentType contentType) throws NotesException {
            Objects.requireNonNull(entity, "Entity cannot be null");
            Objects.requireNonNull(contentType, "Content type cannot be null");
    
            List<MIMEEntity> subentities = new ArrayList<>();
            MIMEEntity nextEntity = null;
    
            try {
                nextEntity = entity.getNextEntity();
    
                while (nextEntity != null) {
                    String[] entityFilteredHeaders = nextEntity
                            .getSomeHeaders(MIME_FILTERED_HEADERS, true)
                            .split("\\n");
    
                    if (contentType.matches(entityFilteredHeaders)) {
                        subentities.add(nextEntity);
                    }
    
                    nextEntity = nextEntity.getNextEntity();
                }
            } finally {
                DominoUtil.recycle(nextEntity);
            }
    
            return subentities;
        }
    
        public final static MIMEEntity getMimeEntity(Document doc, String itemName,
                boolean createOnFail) throws NotesException {
            if (itemName == null) {
                throw new NullPointerException("Invalid MIME entity item name");
            }
    
            MIMEEntity mimeEntity = doc.getMIMEEntity(itemName);
    
            if (mimeEntity == null) {
                if (doc.hasItem(itemName)) {
                    doc.removeItem(itemName);
                }
    
                if (createOnFail) {
                    mimeEntity = doc.createMIMEEntity(itemName);
                }
            }
    
            return mimeEntity;
        }
    
        public static Optional<String> getMimeEntityAttachmentFilename(MIMEEntity entity) throws NotesException {
            Objects.requireNonNull(entity, "Entity cannot be null");
    
            return getMimeEntityHeaderValAndParams(
                    entity, (ThrowablePredicate<MIMEHeader>) h -> h.getHeaderVal().equals("attachment"))
                            .map(s -> {
                                Matcher m = Pattern.compile("filename=['\"]?([^'\"\\s]+)").matcher(s);
                                m.find();
                                return m.group(1);
                            });
        }
    
        public static Optional<String> getMimeEntityHeaderValAndParams(
                MIMEEntity entity, Predicate<MIMEHeader> matcher) throws NotesException {
            Objects.requireNonNull(entity, "Entity cannot be null");
            Objects.requireNonNull(matcher, "Matcher cannot be null");
    
            Vector<?> headers = entity.getHeaderObjects();
    
            try {
                return headers
                        .stream()
                        .map(MIMEHeader.class::cast)
                        .filter(matcher)
                        .map((ThrowableFunction<MIMEHeader, String>) MIMEHeader::getHeaderValAndParams)
                        .findFirst();
            } finally {
                recycle(headers);
            }
        }
    
        public static void recycle(Base... bases) {
            for (Base base : bases) {
                if (base != null) {
                    try {
                        base.recycle();
                    } catch (Exception e) {
                        // Do nothing
                    }
                }
            }
        }
    
        public static void recycle(Collection<? extends Object> objs) {
            objs.stream()
                    .filter(o -> o instanceof Base)
                    .map(o -> (Base) o)
                    .forEach(DominoUtil::recycle);
        }
    
    }
    

    最后是可以完成这项工作的方法:

    public class Example {
    
        public static void yourEntryPoint() {
            try {
                // The last param is just a way to create an attachment from text
                // You have InputStream to pass along obviously
                addAttachment(doc, "Body", "fake1.txt", "this is fake text1");
                addAttachment(doc, "Body", "fake2.txt", "this is fake text2");
                addAttachment(doc, "Body", "fake3.txt", "this is fake text3");
                removeAttachment(doc, "Body", "fake2.txt");
                removeAttachment(doc, "Body", "fake3.txt");
    
            } catch (NotesException e) {
                throw new RuntimeException(e);
            }
        }
    
        private static void addAttachment(Document doc, String itemName, String fileName, String data)
                throws NotesException {
            MIMEEntity mimeEntity = null;
            Stream stm = null;
    
            try {
                mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);
    
                Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);
    
                MIMEEntity attachmentEntity = null;
    
                if (optAttEntity.isPresent()) {
                    attachmentEntity = optAttEntity.get();
                } else {
                    attachmentEntity = mimeEntity.createChildEntity();
                    MIMEHeader header = attachmentEntity.createHeader("Content-Disposition");
                    header.setHeaderValAndParams("attachment; filename=\"" + fileName + "\"");
                }
    
                stm = doc.getParentDatabase().getParent().createStream();
                stm.writeText(data);
    
                attachmentEntity.setContentFromBytes(stm,
                        "application/octet-stream",
                        MIMEEntity.ENC_IDENTITY_BINARY);
    
                stm.close();
    
                doc.closeMIMEEntities(true, itemName);
            } finally {
                DominoUtil.recycle(stm);
                DominoUtil.recycle(mimeEntity);
            }
        }
    
        private static void removeAttachment(Document doc, String itemName, String fileName)
                throws NotesException {
            MIMEEntity mimeEntity = null;
    
            try {
                // Get MIME entity
                mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);
    
                Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);
    
                if (!optAttEntity.isPresent()) {
                    return;
                }
    
                optAttEntity.get().remove();
    
                // Header cleaning on empty entity
                if (mimeEntity.getFirstChildEntity() != null) {
                    doc.closeMIMEEntities(true, itemName);
                } else {
                    mimeEntity.remove();
                }
            } finally {
                DominoUtil.recycle(mimeEntity);
            }
        }
    
        private static Optional<MIMEEntity> getAttachmentMimeEntity(MIMEEntity root, String fileName)
                throws NotesException {
            return DominoUtil
                    .getMimeEntitiesByContentType(root, MimeContentType.ATTACHMENT)
                    .stream()
                    .filter((ThrowablePredicate<MIMEEntity>) mime -> {
                        Optional<String> opt = DominoUtil.getMimeEntityAttachmentFilename(mime);
    
                        return opt.isPresent() && opt.get().equals(fileName);
                    })
                    .findFirst();
        }
    
    }
    

    【讨论】:

    • 谢谢,这可能会有所帮助,但您的代码不完整 public static Map> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)
    • 对不起,我不明白你的意思。我通过剥离所有其余代码来将代码放在一起,但剩下的对我来说似乎是完整的。我瞎了吗?
    • 好的,我肯定忽略了导入语句。有哪些错误?你用的是 iava8 还是 6?
    • 不,看看我在评论中显示的方法签名。我正在使用 DDE10
    • 或者是三个点的某种语法
    猜你喜欢
    • 2019-04-24
    • 2012-06-11
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 2011-06-04
    • 2015-02-26
    • 1970-01-01
    相关资源
    最近更新 更多