java Как совместить почту itextpdf и java?

эй, я работаю над веб-приложением, и у меня есть проблемы с объединением двух функций (создайте PDF-файл и отправьте его в виде вложения по электронной почте). Обе части работают отдельно, но я не знаю, как получить путь к файлу созданного PDF-файла, чтобы добавить его в почтовое вложение.

Ниже приведены важные фрагменты кода:

  1. Я создаю новый файл PDF (с itext 5) с помощью Java-сервлета CreatePDF и показываю его на новой вкладке:

СоздатьPDF-сервлет:

    //initial new ByteArrayOutputStream
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    //get absolute path of the logo
    String relativeLogoWebPath = "/logo.jpg";
    String absoluteLogoDiskPath = getServletContext().getRealPath(relativeLogoWebPath);

    //build PDF with itextpdf
    new BuildPDF(baos, acc, absoluteLogoDiskPath, header, body, footer, vat);

    // setting the content type
    response.setHeader("Expires", "0");
    response.setHeader("Cache-Control","must-revalidate, post-check=0,precheck=0");
    response.setHeader("Pragma", "public");
    response.setContentType("application/pdf");
    response.setContentLength(baos.size());

    // write ByteArrayOutputStream to the ServletOutputStream
    OutputStream os = response.getOutputStream();
    baos.writeTo(os);
    os.flush();
    os.close();

Класс сборки PDF:

public BuildPDF(ByteArrayOutputStream baos, Accounting acc, String absolutLogoPath, 
  Collection<String> header, Collection<String> body, Collection<String> footer, Double vat){
    //init document
    Document document = new Document(PageSize.A4, 60, 30, 140, 90);
    document.setMarginMirroring(false);

    //init pdf writer
    PdfWriter writer = PdfWriter.getInstance(document, baos);
    writer.setBoxSize("art", new com.itextpdf.text.Rectangle(36, 54, 559, 788));

    //add header and footer
    HeaderFooter event = new HeaderFooter(header, footer, absolutLogoPath);
    writer.setPageEvent(event);

    //open the document
    document.open();

    //add title and body
    addTitle(document, acc)
    addBody(document, acc, body, vat, writer);

    //close document and pdf writer
    document.close();
    writer.close();
}
  1. На другой вкладке я перехожу на следующую страницу jsp, и после нажатия кнопки (чтобы открыть сервлет SendAccouningPage) должна быть возможность отправить этот созданный PDF-файл по электронной почте (с почтой Java):

Сервлет SendAccountingPage:

//TODO: get path of created PDF
String[] attachFiles = new String[1]; 
//attachFiles[0] = (String) request.getSession().getAttribute("pdfPath");
//request.getSession().removeAttribute("pdfPath");

EmailUtility.sendEmailWithAttachments(host, port, fromMail, passwort,
     mail, subject, message, attachFiles);

Класс EmailUtility:

 public static void sendEmailWithAttachments(String host, String port,
        final String userName, final String password, String toAddress,
        String subject, String message, String[] attachFiles)
        throws AddressException, MessagingException {

    // sets SMTP server properties
    Properties properties = new Properties();
    properties.put("mail.smtp.host", host);
    properties.put("mail.smtp.port", port);
    properties.put("mail.smtp.auth", "true");
    properties.put("mail.smtp.starttls.enable", "true");
    properties.put("mail.user", userName);
    properties.put("mail.password", password);

    // creates a new session with an authenticator
    Authenticator auth = new Authenticator() {
        public PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(userName, password);
        }
    };
    Session session = Session.getInstance(properties, auth);

    // creates a new e-mail message
    Message msg = new MimeMessage(session);

    msg.setFrom(new InternetAddress(userName));
    InternetAddress[] toAddresses = { new InternetAddress(toAddress) };
    msg.setRecipients(Message.RecipientType.TO, toAddresses);
    msg.setSubject(subject);
    msg.setSentDate(new Date());

    // creates message part
    MimeBodyPart messageBodyPart = new MimeBodyPart();
    messageBodyPart.setContent(message, "text/html");

    // creates multi-part
    Multipart multipart = new MimeMultipart();
    multipart.addBodyPart(messageBodyPart);

    // adds attachments
    if (attachFiles != null && attachFiles.length > 0) {
        for (String filePath : attachFiles) {
            MimeBodyPart attachPart = new MimeBodyPart();

            try {
                attachPart.attachFile(filePath);
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            multipart.addBodyPart(attachPart);
        }
    }

    // sets the multi-part as e-mail's content
    msg.setContent(multipart);

    // sends the e-mail
    Transport.send(msg);

}

Итак, есть ли способ получить путь к файлу созданного pdf и сохранить его, например. в сессию? (и если да: Насколько устойчив этот путь? Потеряется ли он, если я закрою вкладку с созданным pdf?)

Если не:

Как я могу совместить это иначе?

Нужно ли сохранять pdf (если да: какие шансы у меня есть, и можно ли сохранить его только временно?)


person SaScH_MaN    schedule 29.11.2017    source источник
comment
Я ответил на ваш вопрос, но хотел бы знать, почему вы решили использовать iText 5 вместо iText 7. Причин может быть несколько. Например: это устаревший проект, а iText 5 уже есть в кодовой базе. Однако ответ, который я действительно ищу, таков: как мы можем продвигать iText 7? Как мы можем увеличить внедрение iText 7? У меня сложилось впечатление, что разработчики не знают, что они могут зарабатывать деньги, разрабатывая надстройки поверх Платформа iText 7.   -  person Bruno Lowagie    schedule 29.11.2017
comment
Эй, причина проста: это мой первый веб-проект, поэтому мне пришлось узнать много нового до разработки. Раньше я работал с iText 5, поэтому я знал, что это будет работать так, как я хочу. Так что я сэкономил немного времени, чтобы использовать старую известную версию =) Но мне нравится iText, и я уверен, что буду работать над iText 7, когда закончу этот проект. (Возможно, я изменю версию и в этом проекте, если у меня останется время после завершения этого проекта)   -  person SaScH_MaN    schedule 30.11.2017


Ответы (1)


Вы создаете PDF-файл в памяти, используя ByteArrayOutputStream (с именем baos), а затем записываете этот файл в выходной поток сервлета:

OutputStream os = response.getOutputStream();
baos.writeTo(os);

Это хорошая практика, но есть и альтернативный способ. В ByteArrayOutputStream есть метод с именем toByteArray()< /a>, поэтому вы также можете сделать это так:

OutputStream os = response.getOutputStream();
byte[] bytes = baos.toByteArray();
os.write(bytes, 0, bytes.length);
os.flush();
os.close();

Теперь у вас есть полный файл в byte[] с именем bytes, вам нужно адаптировать класс EmailUtility так, чтобы он принимал массив байтов вместо пути к файлу. Это объясняется в ответе на следующий вопрос: Почтовые вложения с массивом байтов:

MimeBodyPart att = new MimeBodyPart(); 
ByteArrayDataSource bds = new ByteArrayDataSource(byte, "application/pdf"); 
att.setDataHandler(new DataHandler(bds));
att.setFileName(bds.getName());

И вот как вы отправляете письмо с вложением файла, который создается в памяти и никогда не сохраняется в виде файла на диске на сервере.

person Bruno Lowagie    schedule 29.11.2017
comment
Привет, спасибо за ответ. Я меняю его таким образом, но теперь я получаю javax.mail ParseException: в строке Conten-Type ‹result.pdf› ожидался '/', получил null - person SaScH_MaN; 30.11.2017
comment
(Изменения более специфичны :) Я сохраняю файл byte[] в сеансе и получаю его в SendAccountingPage. Я также меняю параметр из EmailUtility с String[] attachFile на byte[] и вызываю его в 1. параметр в new ByteArrayDataSource(attachFile, result.pdf); - person SaScH_MaN; 30.11.2017
comment
Ваши комментарии выглядят как английский, но я не понимаю этого английского. - person Bruno Lowagie; 30.11.2017
comment
Ха-ха, хорошо, извини. Я не великий талант говорил и не на практике. Пробую снова: - person SaScH_MaN; 30.11.2017
comment
Я меняю свой код, как описано выше, но теперь я каждый раз получаю это исключение: javax.mail.internet.ParseExeption: в строке Content-Type ‹result.pdf›, ожидаемый '/', получил значение null. - person SaScH_MaN; 30.11.2017
comment
(дополнительные изменения:) 1. Я сохраняю byte[] bytes (в сервлете CreatePDF) в сеанс проекта (response.getSession().setAttribute(pdf, bytes)) и вызываю его в другом сервлете (SendAccountingPage: byte[] atteachFile = (byte[]) response.getSession().getAttribute(pdf)). 2. После этого вызываю метод EmailUtility.sendEmailWithAttachments(host, port, fromMail, password, mail, subject, message, attachFiles); Я меняю тип последнего параметра с String[] attachFiles на byte[] attachFiles и использую этот параметр как 1. параметр конструктора для ByteArrayDataSource - person SaScH_MaN; 30.11.2017
comment
Это вопрос JavaMail, а не вопрос iText. Я могу помочь вам только с вопросами по JavaMail. Также: вы не должны использовать комментарии для добавления кода, составления списка,... Как вы сами видите, это очень тяжело читать. Либо обновите свой существующий вопрос, либо опубликуйте новый вопрос (потому что для меня это звучит как новый вопрос). - person Bruno Lowagie; 30.11.2017
comment
ps: Решение 2. Проблема: ByteArrayDataSource bds = new ByteArrayDataSource (attachFile, application/pdf); att.setDataHandler (новый DataHandler (bds)); att.setFileName(название); - person SaScH_MaN; 30.11.2017
comment
Хорошо, спасибо, что сообщили мне. Я обновил свой ответ для дальнейшего использования. Также большое спасибо за принятие моего ответа. - person Bruno Lowagie; 30.11.2017