问题
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()
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.
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
- 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
回答1:
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:
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;
}
}
Then some helper classes:
@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();
}
}
来源:https://stackoverflow.com/questions/53431447/how-to-add-and-remove-mime-attachments-correctly