实现功能主要技术点:
代码示例
创建web工程,写一个***监听ServletContext对象的创建(创建时机:启动服务器,部署该工程),ServletContext对象创建时,开启定时器查询数据库用户表中当天过生日的用户,使用封装的MailUtils工具类,给用户发送生日邮件。
- BirthdayMailListener
/* ServletContextListener 作用:监听ServletContext对象的创建与销毁 扩展: servletcontext创建:启动服务器的时候 servletContext销毁:关闭服务器. 从服务器移除项目 */
@WebListener()
public class BirthdayMailListener implements ServletContextListener {
/** * 监听ServletContext对象的创建 */
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("启动服务器,创建ServletContext执行");
//实例化定时器对象
Timer timer = new Timer();
//得到定时器第一次执行的时间,如已过第一次执行的时间,则启动定时器时定时器任务就会执行一次
String firstTimeStr="2020-02-22 10:00:00";
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date firstTime=null;
try {
firstTime = simpleDateFormat.parse(firstTimeStr);
System.out.println("BirthdayMailListener firstTime"+firstTime);
} catch (ParseException e) {
e.printStackTrace();
}
/*给定时器对象指派任务。 参数说明: task:TimerTask接口,定时器任务对象,需要创建一个匿名内部类,把要执行的代码写在run方法里 firstTime:第一次执行的时间,类型是Date period:任务执行的周期间隔,单位毫秒 。 */
timer.schedule(new TimerTask() {
@Override
public void run() {
//调用业务逻辑层,得到今天过生日的用户
UserService userService = new UserService();
List<User> userList =userService.getBirthdayUsers();
System.out.println("BirthdayMailListener userList"+userList);
for (User user :userList) {
try {
MailUtils.sendMail(user.getEmail(),"生日邮件","祝您生日快乐!!!");
System.out.println("今天是"+user.getUsername()+"的生日,已给他/她发送了生日邮件");
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
},firstTime,24*60*60*1000);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
- UserService
public class UserService {
public List<User> getBirthdayUsers() {
List<User> birthdayUsers = null;
try {
//通过指定格式的SimpleDateFormat格式化Date对象,得到 月-日 (如:02-24)
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("MM-dd");
String today = simpleDateFormat.format(new Date());
System.out.println(today);
//调用数据访问层,查询今天过生日的用户
UserDao userDao=new UserDao();
birthdayUsers = userDao.getBirthdayUsers(today);
} catch (SQLException e) {
e.printStackTrace();
}
return birthdayUsers;
}
}
- UserDao
public class UserDao {
public List<User> getBirthdayUsers(String today) throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
/*Mysql数据类型-日期和时间类型- DATE类型 DATE类型用于仅需要日期值时。日期格式为 'YYYY-MM-DD',其中 YYYY 表示年,MM 表示月,DD 表示日。 在业务逻辑层得到的today="02-24" */
//使用LIKE的模糊查询
String sql="select * from t_user where birthday like ?";
//①要封装,则User类的属性名要与数据库的字段名相同。②百分号%是 MySQL中常用的一种通配符,在过滤条件中,百分号可以表示任何字符串。
List<User> userList = queryRunner.query(sql, new BeanListHandler<User>(User.class), "%" + today);
return userList;
}
}
数据库中的部分用户表:
- User
public class User {
private String username;
private Integer password;
private String email;
private Date birthday;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getPassword() {
return password;
}
public void setPassword(Integer password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"name='" + username + '\'' +
", password=" + password +
", email='" + email + '\'' +
", birthday=" + birthday +
'}';
}
}
- JDBCUtils
public class JDBCUtils {
//使用Druid数据库连接池技术获取数据库连接
private static DataSource createDataSource;
static{
try {
Properties pros = new Properties();
// InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pros.load(is);
createDataSource = DruidDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return createDataSource.getConnection();
}
public static DataSource getDataSource() throws SQLException {
return createDataSource;
}
//使用dbutils.jar中提供的DbUtils工具类,实现资源的关闭
public static void closeResource(Connection conn, Statement ps, ResultSet rs){
DbUtils.closeQuietly(conn);
DbUtils.closeQuietly(ps);
DbUtils.closeQuietly(rs);
}
public static void closeResource(Connection conn){
DbUtils.closeQuietly(conn);
}
public static void closeResource(Connection conn,ResultSet rs){
DbUtils.closeQuietly(conn);
DbUtils.closeQuietly(rs);
}
}
- MailUtils
/** * 发送邮件工具类 */
public final class MailUtils {
private MailUtils(){}
/** * 发送邮件 * @param email 收件人的邮箱地址 * @param subject 邮件主题 * @param emailMsg 邮件内容 */
public static void sendMail(String email, String subject, String emailMsg)
throws AddressException, MessagingException {
// 1.[连接发件服务器]创建一个程序与发件人的 发送邮件服务器会话对象 Session
Properties props = new Properties();
props.setProperty("mail.transport.protocol", "SMTP");//邮件发送协议
props.setProperty("mail.host", "smtp.qq.com");//邮件发送服务器的地址(如QQ邮箱的发件服务器地址SMTP服务器: smtp.qq.com)
props.setProperty("mail.smtp.auth", "true");//指定验证为true
// 创建验证器
Authenticator auth = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
//发件人的用户名(不带后缀的,如QQ邮箱的@qq.com不用写)和授权码(这里一般不使用密码,为避免密码泄露,用授权码代替密码登录第三方邮件客户端)
//授权码:用于登录第三方邮件客户端的专用密码。 第三方邮件客户端:如这个java程序。
return new PasswordAuthentication("QQ邮箱地址不带@qq.com", "开启POP3/SMTP服务得到的授权码");
}
};
Session session = Session.getInstance(props, auth);
// 2.[创建一封邮件]创建一个Message,它相当于是邮件内容
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("创建验证器时你用的用户名@qq.com")); // 设置发送者的邮箱地址
message.setRecipient(RecipientType.TO, new InternetAddress(email)); // 设置发送方式与接收者
message.setSubject(subject);//邮件主题
message.setContent(emailMsg, "text/html;charset=utf-8");//设置邮件的内容
// 3.[发送邮件]创建 Transport用于将邮件发送
Transport.send(message);
}
}
部署工程后,因已过第一次执行的时间,部署工程后就会启动定时器执行定时器任务一次,给当天生日用户发送生日邮件: