现在很多网站,实现登录或者注册的时候都会用到验证码之类的方式确保安全,Spring Boot,接触Spring Boot没多久,今天完成了Spring Boot 整合邮件服务实现利用邮箱完成注册的功能
这里给一个测试访问地址:180.76.99.142:8080,
所有注释以及全部代码都在下面,方便随时查阅
<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.0modelVersion>
<packaging>jarpackaging>
<name>EmailProname>
<groupId>site.tiangroupId>
<artifactId>EmailProartifactId>
<version>1.0version>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.3.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.6version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.37version>
dependency>
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
<version>2.1.5version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
功能虽小但五脏俱全 静态文件下载地址:http://180.76.99.142/jt.zip
<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 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>
<link th:href="@{~/css/popuo-box.css}" rel="stylesheet" type="text/css" media="all" />
<link th:href="@{~/css/style.css}" rel='stylesheet' type='text/css' media="all">
<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 loginh2>
<p>consectetur adipiscing elit, sed do eiusmod tempor incididunt Lorem ipsum dolor sit ametp>
<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">logina>h3>
div>
<div id="small-dialog1" class="mfp-hide w3ls_small_dialog wthree_pop">
<div class="agileits_modal_body">
<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>
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>
<script th:src='@{~/js/jquery-2.2.3.min.js}'>script>
<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>
<script th:src="@{~/js/jquery.magnific-popup.js}">script>
<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>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
head>
<body>
欢迎您:[[${session.user.username}]]
body>
html>
#设置默认端口
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
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();
}
}
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 {
}
}
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");
}
}
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;
}
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";
}
}
}
接口
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("-","");
}
}
接口
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 = "激活请点击:"+code+"进行激活您的账号";
//发送激活邮件
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);
}
}
接口
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
<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>