現在很多網站,實現登錄或者註冊的時候都會用到驗證碼之類的方式確保安全,Spring Boot,接觸Spring Boot沒多久,今天完成了Spring Boot 整合郵件服務實現利用郵箱完成註冊的功能
這裏給一個測試訪問地址:180.76.99.142:8080,
所有註釋以及全部代碼都在下面,方便隨時查閱
下面開始從零搭建
1、創建數據庫
數據庫名:springemail
2、idea創建一個maven工程pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<name>EmailPro</name>
<groupId>site.tian</groupId>
<artifactId>EmailPro</artifactId>
<version>1.0</version>
<!--Spring Boot父依賴-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<dependencies>
<!--郵件服務-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--web模塊-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--引入連接池druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<!--添加log4j不然德魯伊配置項目無法啓動-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--引入自動生成get set方法,還可以使用日誌-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--添加jdbc啓動器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--添加數據庫驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<!--引入通用mapper的啓動器,包括了mybatis,注意:如果之前使用的是mybatis啓動器,要在@MapperScan重新導包-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!--加入thymeleaf啓動器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--測試的啓動器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<!--打成jar包-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.工程目錄結構
功能雖小但五臟俱全 靜態文件下載地址:http://180.76.99.142/jt.zip
4、login頁面(其實沒必要這麼多,純屬好看,登陸註冊都在這裏面)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Astronauts sign up & login Form a Flat Responsive Widget Template :: xmoban.cn </title>
<!-- Meta tags -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="keywords" content=" Astronauts sign up & login Form Responsive Widget, Audio and Video players, Login Form Web Template, Flat Pricing Tables, Flat Drop-Downs, Sign-Up Web Templates, Flat Web Templates, Login Sign-up Responsive Web Template, Smartphone Compatible Web Template, Free Web Designs for Nokia, Samsung, LG, Sony Ericsson, Motorola Web Design"
/>
<script>
addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); }
</script>
<!-- Meta tags -->
<!--pop-ups-->
<link th:href="@{~/css/popuo-box.css}" rel="stylesheet" type="text/css" media="all" />
<!-- //pop-ups-->
<!--stylesheets-->
<link th:href="@{~/css/style.css}" rel='stylesheet' type='text/css' media="all">
<!--//style sheet end here-->
<link href="//fonts.googleapis.com/css?family=Barlow:300,400,500" rel="stylesheet">
</head>
<body>
<h1 class="header-w3ls">
登錄 或者~ 註冊
</h1>
<div class="art-bothside">
<div class="mid-cls">
<div class="art-right-w3ls">
<h2>Astronauts sign up and login</h2>
<p>consectetur adipiscing elit, sed do eiusmod tempor incididunt Lorem ipsum dolor sit amet</p>
<form id="myForm" th:action="reg" method="post">
<div class="main">
<div class="form-left-to-w3l">
<input type="text" name="username" placeholder="用戶名" required="">
</div>
<div class="form-right-w3ls">
<input type="email" name="email" placeholder="註冊郵箱~ ~ " required="">
</div>
</div>
<div class="main">
<div class="form-left-to-w3l">
<input type="password" name="password" placeholder="Password" id="password" required="">
<div class="clear"></div>
</div>
<div class="form-right-w3ls ">
<input type="password" placeholder="Confirm Password" id="confirm_password" required="">
</div>
</div>
<div class="btnn">
<button th:id="submit" type="submit">註冊</button>
<span class="btn-block" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}" style="color: red"></span>
</div>
</form>
<div class="banner-agileits-btm">
<div class="w3layouts_more-buttn">
<h3>Already have an account..? <a href="#small-dialog1 " class="play-icon popup-with-zoom-anim">login</a></h3>
</div>
<div id="small-dialog1" class="mfp-hide w3ls_small_dialog wthree_pop">
<div class="agileits_modal_body">
<!--login form-->
<div class="letter-w3ls">
<form id="TowForm" action="login" method="post">
<div class="form-left-to-w3l">
<input type="text" name="username" placeholder="Name" required="">
</div>
<div class="form-right-w3ls">
<input type="email" name="email" placeholder="Email" required="">
</div>
<div class="form-right-w3ls ">
<input type="password" name="password" placeholder="Password" required="">
</div>
<div class="btnn">
<button th:id="login" type="submit">登錄</button><br>
</div>
</form>
<div class="clear"></div>
</div>
<!--//login form-->
</div>
</div>
</div>
</div>
<div class="art-left-w3ls">
<img th:src="@{~/images/right1.jpg}" class="img-fluid" alt="">
</div>
</div>
</div>
<div class="copy">
<p>©2020 Astronauts sign up & login Form. All Rights Reserved | Design by
</div>
<!--js working-->
<script th:src='@{~/js/jquery-2.2.3.min.js}'></script>
<!--//js working-->
<script>
var password = document.getElementById("password")
, confirm_password = document.getElementById("confirm_password");
function validatePassword(){
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
} else {
confirm_password.setCustomValidity('');
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
</script>
<!--//scripts-->
<script th:src="@{~/js/jquery.magnific-popup.js}"></script>
<!-- //pop-up-box -->
<script>
$(document).ready(function () {
$('.popup-with-zoom-anim').magnificPopup({
type: 'inline',
fixedContentPos: false,
fixedBgPos: true,
overflowY: 'auto',
closeBtnInside: true,
preloader: false,
midClick: true,
removalDelay: 300,
mainClass: 'my-mfp-zoom-in'
});
});
</script>
<script>
$("#submit").click(function () {
$("#myForm").submit();
});
$("#login").click(function () {
$("#TowForm").submit();
})
</script>
</body>
</html>
4.1 、登陸成功後主頁面main其實就是從session中取出用戶名
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
歡迎您:[[${session.user.username}]]
</body>
</html>
5、yml.xml 文件
#設置默認端口
server:
port: 8080
#設置啓動時加載控制器
spring:
mail:
host: smtp.126.com #發送郵件服務器
username: [email protected] #發送郵件的郵箱地址,這裏設置成你們自己的就行
password: ~~xxxxxxxx~~ #客戶端授權碼,不是郵箱密碼,網易的是自己設置的,百度搜索網易授權碼操作獲取
properties.mail.smtp.port: 465 #465或者994
from: [email protected] # 發送郵件的地址,和上面username一致
#下面配置有興趣可以自行查閱
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true
default-encoding: utf-8
mvc:
servlet:
load-on-startup: 1
datasource: #配置數據源
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/springemail?characterEncoding=utf8
username: "root"
password: "tiantian" #這裏有一個坑,這種方式的配置數據庫即使數據庫密碼正確,若數據庫密碼是由純數字組成的,依然會報錯
type: com.alibaba.druid.pool.DruidDataSource #指定數據源
thymeleaf: #關閉緩存,防止更改頁面不能即使刷新
cache: false
mode: HTML5
encoding: utf-8
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: site.tian.pojo
configuration: #駝峯命名法配置
map-underscore-to-camel-case: true
#靜態資源的訪問要放在資源文件夾中纔不會被過濾掉,如:static,Public
6、連接數據庫還需要配置數據源
package site.tian.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class DruidConfig {
/*配置數據庫*/
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid() {
return new DruidDataSource();
}
}
7、爲了防止非授權登錄,這裏簡單用攔截器配置一下
package site.tian.interceptor;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String user = (String)request.getSession().getAttribute("user");
if(user == null){
request.setAttribute("msg","您沒有權限,請先登錄");
request.getRequestDispatcher("/login").forward(request,response);
return false;
}else {
return true;
}
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
8、把攔截器配置到容器中
package site.tian.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import site.tian.interceptor.LoginInterceptor;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/*添加攔截器,添加到最上面最好*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/","/checkCode","/reg","/login","/js/**","/css/**","/images/**");
}
@Override
/*設置默認跳轉的請求視圖*/
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/login").setViewName("login");
}
}
9、創建實體類
package site.tian.pojo;
import lombok.Data;
@Data
public class User {
private Long id;
private String username;
private String password;
private String email;
/**
* 狀態:0代表未激活,1代表激活
*/
private Integer status;
/**
* 利用UUID生成一段數字,發動到用戶郵箱,當用戶點擊鏈接時
* 在做一個校驗如果用戶傳來的code跟我們發生的code一致,更改狀態爲“1”來激活用戶
*/
private String code;
}
10、OK上面都是準備工作,下面步入正題
10.1
controller
package site.tian.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import site.tian.email.UUIDUtils;
import site.tian.pojo.User;
import site.tian.service.UserService;
import javax.servlet.http.HttpServletRequest;
@Controller
public class LoginController {
@Autowired
private UserService userService;
/*註冊*/
@RequestMapping("/reg")
public String res(User user, Model model) {
user.setStatus(0);
String code = UUIDUtils.getUUID() + UUIDUtils.getUUID();
user.setCode(code);
userService.register(user);
model.addAttribute("msg", "註冊成功前往郵箱激活!");
return "login";
}
/**
* 校驗郵箱中的code激活賬戶
* 首先根據激活碼code查詢用戶,之後再把狀態修改爲"1"
*/
@RequestMapping(value = "/checkCode")
public String checkCode(String code) {
User user = userService.checkCode(code);
System.out.println(user);
//如果用戶不等於null,把用戶狀態修改status=1
if (user != null) {
user.setStatus(1);
//把code驗證碼清空,已經不需要了
user.setCode("");
System.out.println(user);
userService.updateUserStatus(user);
}
return "login";
}
@RequestMapping("/login")
public String login(User user, HttpServletRequest request) {
if (user.getPassword() != null && user.getEmail() != null && user.getUsername() != null) {
User token= userService.login(user);
request.getSession().setAttribute("user",token);
return "main";
}else {
return "login";
}
}
}
10.2 、配置email主要配置有以下幾個類
接口
package site.tian.email;
public interface MailService {
void sendHtmlMail(String to, String subject, String content);
}
實現類
package site.tian.email;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
@Service
public class MailServiceImpl implements MailService {
/*開啓日誌*/
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private JavaMailSender mailSender;
/**
* 配置文件中我的qq郵箱
*/
@Value("${spring.mail.from}")
private String from;
/**
* 發送HTML郵件
* @param to 收件者
* @param subject 郵件主題
* @param content 文本內容
*/
@Override
public void sendHtmlMail(String to,String subject,String content) {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = null;
try {
helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(subject);
helper.setTo(to);
helper.setText(content, true);
mailSender.send(message);
//日誌信息
logger.info("郵件已經發送。");
} catch (MessagingException e) {
logger.error("發送郵件時發生異常!", e);
}
}
}
驗證碼實現工具類
package site.tian.email;
import java.util.UUID;
public class UUIDUtils {
public static String getUUID(){
return UUID.randomUUID().toString().replace("-","");
}
}
10.3 、業務接口和實現類
接口
package site.tian.service;
import site.tian.pojo.User;
public interface UserService {
public void register(User user);
User checkCode(String code);
void updateUserStatus(User user);
User login(User user);
}
實現類
package site.tian.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import site.tian.email.MailService;
import site.tian.mapper.UserMapper;
import site.tian.pojo.User;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private MailService mailService;
@Override
public void register(User user) {
userMapper.insert(user);
//獲取激活碼
String code = user.getCode();
System.out.println("code:"+code);
//主題
String subject = "來自天天網站的激活郵件";
//激活碼是我們點擊郵件鏈接之後根據激活碼查詢用戶,如果存在說明一致,將用戶狀態修改爲“1”激活,有用戶來訪問服務器
//上面的激活碼發送到用戶註冊郵箱
String context = "<a href='http://127.0.0.1:8080/checkCode?code="+code+"'>激活請點擊:"+code+"進行激活您的賬號</a>";
//發送激活郵件
mailService.sendHtmlMail(user.getEmail(),subject,context);
}
@Override
public User checkCode(String code) {
return userMapper.checkCode(code);
}
@Override
public void updateUserStatus(User user) {
userMapper.updateUserStatus(user);
}
@Override
public User login(User user) {
return userMapper.login(user);
}
}
10.4、mapper文件及對應xml
接口
package site.tian.mapper;
import site.tian.pojo.User;
public interface UserMapper {
void insert(User user);
User checkCode(String code);
void updateUserStatus(User user);
User login(User user);
}
xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="site.tian.mapper.UserMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username,password,status,code,email) VALUES(#{username},#{password},#{status},#{code},#{email}) ;
</insert>
<update id="updateUserStatus">
UPDATE user SET status = #{status},code=#{code} WHERE id = #{id} ;
</update>
<select id="checkCode" resultType="site.tian.pojo.User">
select * from user where code=#{code}
</select>
<select id="login" resultType="site.tian.pojo.User">
select * from user where status=1 and username=#{username} and email=#{email} and password=#{password}
</select>
</mapper>