Как правильно добавлять и удалять вложения MIME - PullRequest
0 голосов
/ 22 ноября 2018

Я добавляю 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 имеют правильный размер

enter image description here

Так выглядит документ после того, как я удалил вложения (используя приведенный выше скрипт)

enter image description here

Так выглядит документ после добавления одного вложения (с помощью приведенного выше сценария) после удаления их

enter image description here

1 Ответ

0 голосов
/ 22 ноября 2018

Если вы работаете с методами 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();
    }

}
...