如何正确添加和删除MIME附件 [英] How to Add and Remove MIME attachments correctly

查看:111
本文介绍了如何正确添加和删除MIME附件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将MIME附件添加到这样的文档中

I am adding MIME attachments to a document like this

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

然后我再次提供一个删除按钮

and in a repeat I provide a delete button

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

附件已从文档中删除,在Ytria中,我看到$ FILE项已删除,但BODY项却未删除.问题是,如果我将新附件添加到同一文档中,那么以前删除的所有附件都会返回

the attachment are removed from the document, in Ytria I can see that the $FILE items are removed but not the BODY items. the problem with this is that if I add a new attachment to the same document all the attachments I removed previously come back

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

This is how the document looks before removing the attachments.

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

The file size here is unfortnuately 0Kb because I used the wrong screenshot. from the beginnin all $File items have correct size

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

This is how the document look after I removed the attachments (using the script above)

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

This is what the document look like after I add one attachment (using the script above) after I removed them

  • 添加或删除附件时我可能做错了什么? (看 脚本)
  • 正文"字段中是否有商店"似乎并不重要 内容是否设置为MIME"选项
  • 另请参阅此问题 如何使用MIME添加和删除附件
  • Could I be doing something wrong when adding or removing the attachments? (see script)
  • It does not seem to matter if the Body field has the "store content as MIME" option set or not
  • see also this question How to Add and Remove attachments using MIME

推荐答案

如果您使用MIME方法附加文件,为什么不使用MIME方法也将其删除?

If you work with MIME methods to attach the file why not work with MIME methods to remove it as well?

我使用自己的框架,因此以下代码可能给您带来使事情变得过于复杂的印象,但希望您能从中得到要点:

I use my own framework so the following code might give you the impression to overcomplicate things but hopefully you should get the gist of it:

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

I have an enum that helps me navigate through the various MIME types. In this case you are dealing with 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);
    }

}

最后将完成这项工作的方法:

Finally the method that would do the job:

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();
    }

}

这篇关于如何正确添加和删除MIME附件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆