import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.xdja.dsc.common.util.properties.PropUtil;
import com.xdja.dsc.common.util.thread.ThreadPoolUtils;
import com.xdja.dsc.gateway.mail.bean.Mail;
import com.xdja.dsc.gateway.mail.bean.MailJson;
import com.xdja.dsc.gateway.mail.service.MailService;
import freemarker.template.Template;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import static com.xdja.dsc.common.constant.DscConst.FORWARD_SLASH;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
/**
* @author Created by wangbo on 2020/05/14/16:54
*/
@Slf4j
@Service
public class MailServiceImpl implements MailService {
public static final ObjectMapper MAPPER = new ObjectMapper();
private static final String FALSE = "false";
private static final String TRUE = "true";
private static MailJson mailJson = getMailJson();
static {
MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
watch();
}
FreeMarkerConfigurer configurer;
JavaMailSenderImpl javaMailSender;
public MailServiceImpl(JavaMailSenderImpl javaMailSender, FreeMarkerConfigurer configurer) {
this.javaMailSender = javaMailSender;
this.configurer = configurer;
}
private static MailJson getMailJson() {
try {
return MAPPER.readValue(String.join("", Files.readAllLines(Paths.get(getMailConfPath()))), MailJson.class);
} catch (Exception ignored) {
return new MailJson();
}
}
@SneakyThrows
private static void watch() {
FileSystemResource fileSystemResource = new FileSystemResource(getMailConfPath());
WatchService watchService = FileSystems.getDefault().newWatchService();
Paths.get(fileSystemResource.getFile().getParent()).register(watchService, ENTRY_MODIFY);
ThreadPoolUtils.getExecutor().execute(() -> listen(watchService));
}
@SneakyThrows
private static void listen(WatchService watchService) {
WatchKey watchKey = null;
//noinspection InfiniteLoopStatement
while (true) {
try {
watchKey = watchService.take();
boolean match = watchKey.pollEvents().stream().anyMatch(watchEvent -> Objects.equals(watchEvent.context().toString(), getMailConfPath().substring(getMailConfPath().lastIndexOf(FORWARD_SLASH) + 1)));
if (match) {
mailJson = getMailJson();
log.info("{}", mailJson);
}
} finally {
if (watchKey != null) {
watchKey.reset();
}
}
}
}
@SneakyThrows
private static String getMailConfPath() {
return Objects.requireNonNull(PropUtil.getPropertyValue("mail.json.path"));
}
@Override
@SneakyThrows
@Async
public void send(Mail mail) {
initSender();
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(new InternetAddress(mailJson.getFrom(), StringUtils.trimToEmpty(mailJson.getFromName()), StandardCharsets.UTF_8.name()));
helper.setTo(mailJson.getUsers());
helper.setSubject(mail.getSubject());
helper.setText(render(mail), true);
try {
javaMailSender.send(message);
log.info("使用spring发送");
} catch (Exception e) {
sendByJavaMail(mail);
log.info("使用java发送");
}
}
@SneakyThrows
void sendByJavaMail(Mail mail) {
Properties props = getProp();
props.setProperty("mail.transport.protocol", mailJson.getProtocol());
props.setProperty("mail.smtp.host", mailJson.getHost());
props.setProperty("mail.smtp.socketFactory.port", String.valueOf(mailJson.getPort()));
MimeMessage message = new MimeMessage(Session.getDefaultInstance(props));
MimeMessageHelper helper = new MimeMessageHelper(message, true, StandardCharsets.UTF_8.name());
helper.setFrom(new InternetAddress(mailJson.getFrom(), StringUtils.trimToEmpty(mailJson.getFromName()), StandardCharsets.UTF_8.name()));
helper.setTo(mailJson.getUsers());
helper.setSubject(mail.getSubject());
helper.setText(render(mail), true);
Transport.send(message, mailJson.getUsername(), mailJson.getPassword());
}
@SneakyThrows
private void initSender() {
javaMailSender.setHost(mailJson.getHost());
javaMailSender.setPassword(mailJson.getPassword());
javaMailSender.setPort(mailJson.getPort());
javaMailSender.setProtocol(mailJson.getProtocol());
javaMailSender.setUsername(mailJson.getUsername());
javaMailSender.setDefaultEncoding(StandardCharsets.UTF_8.name());
javaMailSender.setJavaMailProperties(getProp());
}
private Properties getProp() {
String timeout = PropUtil.getPropertyValue("mail.timeout");
Properties props = new Properties();
props.setProperty("mail.debug", mailJson.getMailDebug());
props.setProperty("mail.smtp.timeout", timeout);
props.setProperty("mail.smtp.connectiontimeout", timeout);
props.setProperty("mail.smtp.writetimeout", timeout);
props.setProperty("mail.smtp.ssl.socketFactory.fallback", FALSE);
props.setProperty("mail.smtp.starttls.enable", TRUE);
return props;
}
@SneakyThrows
private String render(Mail mail) {
Map<String, Object> map = new HashMap<>(2);
map.put("data", mail.getText());
Template template = configurer.getConfiguration().getTemplate("mail.ftl", StandardCharsets.UTF_8.name());
return FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
}
}