暑假在家作一個相似知乎的問答型網站(代碼可見:Github/wenda 喜歡的能夠給個star或者本身fork而後修改,目前功能還未很完善),其中有一個站內郵件通知系統(這裏簡單的講一個例子:若是用戶登陸的時候出現異常,那麼就會經過郵件發送通知用戶)。然而卻碰到一個問題。問題錯誤信息以下:html
發送郵件失敗Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: smtp.qq.com, port: 465;
nested exception is: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure. Failed messages: javax.mail. MessagingException: Could not connect to SMTP host: smtp.qq.com, port: 465;
nested exception is: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failurejava
本身在將錯誤信息代碼google了一下,找了好久發現不少解決方案,包括stackoverflow上的一些解決方案,但仍是沒用。而後呢用百度試了下,結果在第一條是開源中國的一篇博客:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure。git
點進去是這樣的:(以下圖)github
結果就是:這個問題是jdk致使的,jdk1.8裏面有一個jce的包,安全性機制致使的訪問https會報錯,官網上有替代的jar包,若是替換掉就能夠了。問題的解決方法還能夠就是在整個項目中把你的jdk換成是1.7去,一樣也能夠解決這個我問題。這兩個jar包的下載地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.htmlweb
而後下載以後,把這個壓縮文件解壓,獲得兩個jar包去覆蓋jdk安裝目錄下的jre\lib\security\下相同的jar包就能解決java8的郵件發送問題。接着用QQ郵箱我親測有用,可是要注意一點就是:開啓SMTP服務後要記得將你的16位受權碼做爲你的qq郵箱登陸密碼。spring
MailSender.java中mailSender.setPassword("16位受權碼");
mailSender.setHost("smtp.qq.com");
mailSender.setPort(465);apache
下面把完整代碼發佈出來:
1. LoginExceptionHandler.java安全
package com.nowcoder.async.handler; import com.nowcoder.async.EventHandler; import com.nowcoder.async.EventModel; import com.nowcoder.async.EventType; import com.nowcoder.util.MailSender; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by 10412 on 2016/8/10. */ @Component public class LoginExceptionHandler implements EventHandler { @Autowired MailSender mailSender; @Override public void doHandle(EventModel model) { // xxxx判斷髮現這個用戶登錄異常 Map<String, Object> map = new HashMap<String, Object>(); map.put("username", model.getExt("username")); mailSender.sendWithHTMLTemplate(model.getExt("email"), "登錄IP異常", "mails/login_exception.html", map); } @Override public List<EventType> getSupportEventTypes() { return Arrays.asList(EventType.LOGIN); } }
2. LoginController.java服務器
package com.nowcoder.controller; import com.nowcoder.async.EventModel; import com.nowcoder.async.EventProducer; import com.nowcoder.async.EventType; import com.nowcoder.service.UserService; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.util.Map; /** * Created by 10412 on 2016/7/2. */ @Controller public class LoginController { private static final Logger logger = LoggerFactory.getLogger(LoginController.class); @Autowired UserService userService; @Autowired EventProducer eventProducer; @RequestMapping(path = {"/reg/"}, method = {RequestMethod.POST}) public String reg(Model model, @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("next") String next, @RequestParam(value="rememberme", defaultValue = "false") boolean rememberme, HttpServletResponse response) { try { Map<String, Object> map = userService.register(username, password); if (map.containsKey("ticket")) { Cookie cookie = new Cookie("ticket", map.get("ticket").toString()); cookie.setPath("/"); if (rememberme) { cookie.setMaxAge(3600*24*5); } response.addCookie(cookie); if (StringUtils.isNotBlank(next)) { return "redirect:" + next; } return "redirect:/"; } else { model.addAttribute("msg", map.get("msg")); return "login"; } } catch (Exception e) { logger.error("註冊異常" + e.getMessage()); model.addAttribute("msg", "服務器錯誤"); return "login"; } } @RequestMapping(path = {"/reglogin"}, method = {RequestMethod.GET}) public String regloginPage(Model model, @RequestParam(value = "next", required = false) String next) { model.addAttribute("next", next); return "login"; } @RequestMapping(path = {"/login/"}, method = {RequestMethod.POST}) public String login(Model model, @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam(value="next", required = false) String next, @RequestParam(value="rememberme", defaultValue = "false") boolean rememberme, HttpServletResponse response) { try { Map<String, Object> map = userService.login(username, password); if (map.containsKey("ticket")) { Cookie cookie = new Cookie("ticket", map.get("ticket").toString()); cookie.setPath("/"); if (rememberme) { cookie.setMaxAge(3600*24*5); } response.addCookie(cookie); eventProducer.fireEvent(new EventModel(EventType.LOGIN) .setExt("username", username).setExt("email", "***@qq.com") .setActorId((int)map.get("userId"))); if (StringUtils.isNotBlank(next)) { return "redirect:" + next; } return "redirect:/"; } else { model.addAttribute("msg", map.get("msg")); return "login"; } } catch (Exception e) { logger.error("登錄異常" + e.getMessage()); return "login"; } } @RequestMapping(path = {"/logout"}, method = {RequestMethod.GET, RequestMethod.POST}) public String logout(@CookieValue("ticket") String ticket) { userService.logout(ticket); return "redirect:/"; } }
3. EventHandler.javacookie
package com.nowcoder.async; import java.util.List; /** * Created by 10412 on 2016/8/10. */ public interface EventHandler { void doHandle(EventModel model); List<EventType> getSupportEventTypes(); }
4. MailSender.java
package com.nowcoder.util; import org.apache.velocity.app.VelocityEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; import org.springframework.ui.velocity.VelocityEngineUtils; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeUtility; import java.util.Map; import java.util.Properties; /** * Created by 10412 on 2016/8/10. // ***@qq.com wnppafhsbrcgbfbh(16位受權碼) */ @Service public class MailSender implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(MailSender.class); private JavaMailSenderImpl mailSender; @Autowired private VelocityEngine velocityEngine; public boolean sendWithHTMLTemplate(String to, String subject, String template, Map<String, Object> model) { try { String nick = MimeUtility.encodeText("***"); InternetAddress from = new InternetAddress(nick + "<***@qq.com>"); MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage); String result = VelocityEngineUtils .mergeTemplateIntoString(velocityEngine, template, "UTF-8", model); mimeMessageHelper.setTo(to); mimeMessageHelper.setFrom(from); mimeMessageHelper.setSubject(subject); mimeMessageHelper.setText(result, true); mailSender.send(mimeMessage); return true; } catch (Exception e) { logger.error("發送郵件失敗" + e.getMessage()); return false; } } @Override public void afterPropertiesSet() throws Exception { mailSender = new JavaMailSenderImpl(); mailSender.setUsername("***@qq.com"); mailSender.setPassword("wnppafhsbrcgbfbh"); //qq郵箱開啓smtp服務後使用16位受權碼在第三方登陸 // mailSender.setHost("smtp.exmail.qq.com"); mailSender.setHost("smtp.qq.com"); mailSender.setPort(465); // mailSender.setHost("smtp.163.com"); //163郵箱 // mailSender.setPort(25); mailSender.setProtocol("smtps"); mailSender.setDefaultEncoding("utf8"); Properties javaMailProperties = new Properties(); javaMailProperties.put("mail.smtp.ssl.enable", true); //javaMailProperties.put("mail.smtp.auth", true); //javaMailProperties.put("mail.smtp.starttls.enable", true); mailSender.setJavaMailProperties(javaMailProperties); } }
5. login_exception.html 發送消息模板(可自定義)
你好$username,你的登錄有問題!
一切都好了,運行。登陸。發送郵件過來了。
總結來講:這個錯誤就是jdk1.8中的一個jce的包,安全性機制致使訪問https會報錯。