java 生成数据库表中每条记录的PDF并作为附件发送到电子邮件

nr7wwzry  于 2023-06-04  发布在  Java
关注(0)|答案(1)|浏览(201)

我在数据库表中有4条记录。该表具有id、name、score1、score2、score3、total、email列。每个记录具有不同的电子邮件。代码的目的是循环通过每个记录,通过记录“ID”为每个记录生成PDF,并将PDF作为电子邮件发送到记录的电子邮件值。我使用了while循环,但我很努力地尝试,我的代码生成了所有记录的PDF,并发送给每个收件人的电子邮件。'我只希望它只生成每个记录的PDF,并一次发送给收件人电子邮件'。我真的不知道我错在哪里。

try{
String sql="select * from score_table where id=score_table.id";
pst=con.prepareStatement(sql);
rs=pst.executeQuery();
// Loop through each record
while (rs.next()) {
  // Retrieve data for current record
  String name = rs.getString("name");
  String score1 = rs.getString("score1");
  String score2 = rs.getString("score2");
  String score3 = rs.getString("score3");
  String score4 = rs.getString("score4"); 
  int total = rs.getInt("total");
  String recipientEmail = rs.getString("email");

  // Create parameters for the report
  Map<String, Object> parameters = new HashMap<>();
  parameters.put("name", name);
  parameters.put("score1", score1);
  parameters.put("score2", score2);
  parameters.put("score3", score3);
  parameters.put("score4", score4);
  parameters.put("total", total);

  // Load report template
  JasperReport jasperReport = JasperCompileManager.compileReport("studentSco.jrxml");

  // Populate report with data
  JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, con);

  // Export report to PDF file
  byte[] pdfBytes = JasperExportManager.exportReportToPdf(jasperPrint);

  // Create new email message
  Properties props = new Properties();
  props.put("mail.smtp.host", "smtp.gmail.com");
  props.put("mail.smtp.port", "587");
  props.put("mail.smtp.auth", "true");
  props.put("mail.smtp.starttls.enable", "true");
  props.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");

  Session session = Session.getInstance(props, new javax.mail.Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("rodysoftonline@gmail.com", "wdmssbarmwfgxxxw");
    }
});

  Message message = new MimeMessage(session);
  message.setFrom(new InternetAddress("rodysoftonline@gmail.com"));
  message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail));
  message.setSubject("Report for " + name);

MimeBodyPart attachment = new MimeBodyPart();
ByteArrayDataSource source = new ByteArrayDataSource(pdfBytes, "application/pdf");
attachment.setDataHandler(new DataHandler(source));
attachment.setFileName("report_" + name + ".pdf");

  Multipart multipart = new MimeMultipart();
  multipart.addBodyPart(attachment);

  message.setContent(multipart);

  // Send email
  Transport.send(message);
  System.out.println("email sent successfully");
}
    }catch(SQLException | MessagingException | JRException e){
JOptionPane.showMessageDialog(null,e);
}
// Close database connection and resources
finally{
try{
rs.close();
pst.close();
  }
catch(SQLException e){
      }
        }

这就是我目前所拥有的。虽然它在while循环中,但它只为所有记录生成一次pdf,并发送到记录中的每个电子邮件。我希望它只为每个记录生成PDF并发送到记录的电子邮件,生成下一个记录的PDF,发送到电子邮件等…直到完成表中的所有记录

jogvjijk

jogvjijk1#

下面是我如何重构你的代码。我最终得到了四个接口和四个类。您需要为其中两个接口添加实现。
首先对数据进行封装-User

package report;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class User {

    private final String name;

    private final String email;
    private final List<Double> scores;

    public User(String name, String email, List<Double> scores) {
        if ((name == null) || (name.trim().length() == 0)) throw new IllegalArgumentException("Name cannot be blank or null");
        if ((email == null) || (email.trim().length() == 0)) throw new IllegalArgumentException("Email cannot be blank or null");
        this.name = name.trim();
        this.email = email.trim();
        this.scores = (scores != null) ? new ArrayList<>(scores) : new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public List<Double> getScores() {
        return Collections.unmodifiableList(scores);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (!getName().equals(user.getName())) return false;
        if (!getEmail().equals(user.getEmail())) return false;
        return getScores().equals(user.getScores());
    }

    @Override
    public int hashCode() {
        int result = getName().hashCode();
        result = 31 * result + getEmail().hashCode();
        result = 31 * result + getScores().hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", scores=" + scores +
                '}';
    }
}

我使用运行在JDK 17下的IntelliJ 2023.1创建了User类。这可能是使用记录类的一个很好的例子。
创建一个接口UserRepository和一个实现,它只与关系数据库交互:

package report;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public interface UserRepository {

    User findByName(String name);

    default void close(ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            // log at best
        }
    }
    default void close(Statement st) {
        try {
            if (st != null) {
                st.close();
            }
        } catch (SQLException e) {
            // log at best.
        }
    }

    default void close(Connection connection) {
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            // log at best.
        }
    }
}

下面是一个实现:

package report;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UserRepositoryImpl implements UserRepository {

    public static final String FIND_BY_NAME = "SELECT NAME, EMAIL, SCORE1, SCORE2, SCORE3, SCORE4 FROM SCORE_TABLE WHERE NAME = ?";

    private final Connection connection;

    public UserRepositoryImpl(Connection connection) {
        this.connection = connection;
    }

    @Override
    public User findByName(String name) {
        User user;
        ResultSet rs = null;
        PreparedStatement ps = null;
        try {
            ps = this.connection.prepareStatement(FIND_BY_NAME);
            rs = ps.executeQuery();
            user = new UserMapper().mapRow(rs);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs);
            close(ps);
        }
        return user;
    }
}

存储库实现使用RowMapper接口和UserMapper实现:

package report;

import java.sql.ResultSet;

public interface RowMapper<T> {
    T mapRow(ResultSet rs);
}

下面是UserMapper的实现:

package report;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class UserMapper implements RowMapper<User> {

    @Override
    public User mapRow(ResultSet rs) {
        User user = null;
        try {
            while (rs.next()) {
                String name = rs.getString("NAME");
                String email = rs.getString("EMAIL");
                List<Double> scores = new ArrayList<>();
                scores.add(rs.getDouble("SCORE1"));
                scores.add(rs.getDouble("SCORE2"));
                scores.add(rs.getDouble("SCORE3"));
                scores.add(rs.getDouble("SCORE4"));
                user = new User(name, email, scores);
            }
        } catch (SQLException e) {
            user = null;
        }
        return user;
    }
}

碧玉报告生成器和电子邮件客户端有以下接口:

package report;

public interface JasperReportGenerator<T> {

    byte [] generate(String jrxml, T data);
}

package report;

public interface EmailClient {

    void send(String from, String to, String subject, String body, byte [] attachment);
}

这是比你的单一方法更多的类。这种方法有几个优点:

  • 每个班做好一件事(单一责任原则)
  • 使用Junit单独测试每个类很容易。

看看这个方法是否对你有帮助。

相关问题