文章目录一览
开发社区登录注册模块
1.发送邮件
1.1 邮箱设置
- 启用客户端SMTP服务
QQ邮箱 → 设置 → POP3/SMTP服务 → 开启
1.2 Spring Email
- 导入jar包
1.2.1 pom.xml
<!--Spring mail发送邮件(视频中为2.1.5)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
1.2.2 application.properties
- 邮箱参数配置
application.properties
#MailProperties
spring.mail.host=smtp.qq.com
spring.mail.port=465
spring.mail.username=2700151197@qq.com
spring.mail.password=utwpsukykhzmdcji
#指定协议,启动安全协议,加密的
spring.mail.protocol=smtps
spring.mail.properties.mail.smtp.ssl.enable=true
1.2.3 MailClient工具类
- 使用JavaMailSender发送邮件
先创一个工具包,里面新建MailClient工具类
MailClient
@Component
public class MailClient {
/*先声明一个日志*/
private static final Logger logger = LoggerFactory.getLogger(MailClient.class);
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
public void sendMail(String to,String subject,String content){
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setFrom(from); //设置发件人
helper.setTo(to); //设置收件人
helper.setSubject(subject); //设置邮件主体
helper.setText(content,true); //设置邮件内容;true即支持html文本
mailSender.send(helper.getMimeMessage());
} catch (MessagingException e) {
logger.error("邮件发送失败!"+e.getMessage());
}
}
}
1.2.4 测试及结果
MailTests
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class MailTests {
@Autowired
private MailClient mailClient;
@Test
public void testTextMail(){
//调用MainClient中发送邮件方法
mailClient.sendMail("2547260060@qq.com","test!!","测试成功!月薪45K");
}
}
结果:
测试通过!
1.3 模板引擎
- 使用Thymeleaf发送HTML邮件
1.3.1 创建模板引擎页面
demo.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>邮件示例</title>
</head>
<body>
<p>欢迎你,<span style="color: red;" th:text="${username}"></span>!</p>
</body>
</html>
1.3.2 测试及结果
测试第二个Test
MailTests
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class MailTests {
@Autowired
private MailClient mailClient;
@Autowired
/*注入模板引擎,它能帮我们获取自制的模板路径*/
private TemplateEngine templateEngine;
@Test
public void testTextMail(){
//调用MainClient中发送邮件方法
mailClient.sendMail("2547260060@qq.com","test!!","测试成功!月薪45K");
}
@Test
public void testHtmlMail(){
Context context = new Context();
//构建参数
context.setVariable("username","StephenCurry");
//调模板引擎
/*模板引擎主要目的就是生成动态网页,发邮件还得是MailClient*/
String content = templateEngine.process("/mail/demo", context);
System.out.println(content);
//调用MainClient中发送邮件方法
mailClient.sendMail("2547260060@qq.com","模板引擎Html的test!","测试又成功!月薪50K!");
}
}
结果:
1.
2.
3.
2.开发注册功能
功能主要由三次请求所构成,一次一次解决;
2.1 访问注册页面
- 点击顶部区域的链接,打开注册页面
就是修改index、register页面,让thymeleaf复用index的头部模板给register用,前端。
LoginController
@Controller
public class LoginController {
//处理注册页面的请求
@RequestMapping(value = "/register",method = RequestMethod.GET)
public String getRegisterPage(){
return "/site/register";
}
}
2.2 提交注册数据
- 通过表单提交数据
- 服务端验证账号是否已存在、邮箱是否已注册
- 服务端发送激活邮件
2.2.1 导包
第一步,导包
<!--提供一些判断字符串,集合的工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
2.2.2 xml配置
第二步,application.properties做一个配置;那我们网站的域名配置好,因为开发阶段没有域名,就配一个我们的本机地址;
因为在注册过程中,我们要发邮件,邮件里面带有激活链接,这个链接就是连到我们的网站;
#community
community.path.domain=http://localhost:8080
2.2.3 CommunityUtil工具类
第三步,写一个工具类,工具类里写两个方法,后面注册的时候要用。
CommunityUtil
public class CommunityUtil {
//生成随机字符串
public static String generateUUID(){
//随机生成的字符串,并将字符串中的-全部替换成空;
return UUID.randomUUID().toString().replaceAll("-","");
}
//MD5加密
//只能加密,不能解密
public static String md5(String key) {
if (StringUtils.isBlank(key)) {
return null;
} else {
return DigestUtils.md5DigestAsHex(key.getBytes());
}
}
}
2.2.4 UserService
第四步,写我们的注册service方法
UserService
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Autowired
private MailClient mailClient;
@Autowired
private TemplateEngine templateEngine;
@Value("${community.path.domain}")
private String domain;
@Value("${server.servlet.context-path}")
private String contextPath;
//1.根据用户id查询用户名,之前用的,这里没用到
public User findByUserId(int id){
return userMapper.selectById(id);
}
//2.注册方法
public Map<String,Object> register(User user){
Map<String, Object> map = new HashMap<>();
//对传过来的参数空值做判断
if (user == null){
throw new IllegalArgumentException("参数不能为空!");
}
if (StringUtils.isBlank(user.getUsername())){
map.put("usernameMsg","用户名不能为空!");
return map;
}
if (StringUtils.isBlank(user.getPassword())){
map.put("passwordMsg","密码不能为空!");
return map;
}
if (StringUtils.isBlank(user.getEmail())){
map.put("emailMsg","邮箱不能为空!");
return map;
}
//验证账号
User u1 = userMapper.selectByName(user.getUsername());
if (u1 != null){
map.put("usernameMsg","该用户名已注册!");
return map;
}
//验证邮箱
User u2 = userMapper.selectByEmail(user.getEmail());
if (u2 != null){
map.put("emailMsg","该邮箱已注册!");
return map;
}
//注册用户
//给传过来的user对象参数设置随机盐,并截取前5位
user.setSalt(CommunityUtil.generateUUID().substring(0,5));
user.setPassword(CommunityUtil.md5(user.getPassword()+user.getSalt()));//密码为用户密码+盐值
user.setType(0);
user.setStatus(0);
user.setActivationCode(CommunityUtil.generateUUID());
user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png",new Random().nextInt(1000)));
user.setCreateTime(new Date());
int i = userMapper.insertUser(user);
//激活邮件
Context context = new Context();
context.setVariable("email",user.getEmail());
//http://localhost:8080/community/activation/101/code 目标url
//拼接url成为上面的目标形式
String url=domain+contextPath+"/activation/"+user.getId()+"/"+user.getActivationCode();
context.setVariable("url",url);
//利用模板引擎生成模板内容
String content = templateEngine.process("/mail/activation", context);
mailClient.sendMail(user.getEmail(),"激活账号",content);
return map;
}
}
activation.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/>
<title>疫情防控交流社区平台-激活账号</title>
</head>
<body>
<div>
<p>
<b th:text="${email}">xxx@xxx.com</b>, 您好!
</p>
<p>
您正在注册防控交流社区平台, 这是一封激活邮件, 请点击
<a th:href="${url}">此链接</a>,
激活您的免疫账号!
</p>
</div>
</body>
</html>
其中register.html、operate-result.html都有修改;
2.2.5 LoginController
@Controller
public class LoginController {
@Autowired
private UserService userService;
//处理注册页面的请求
@RequestMapping(path = "/register",method = RequestMethod.GET)
public String getRegisterPage(){
return "/site/register";
}
//注册
@RequestMapping(path = "/register",method = RequestMethod.POST)
public String register(Model model, User user){
Map<String, Object> map = userService.register(user);
if (map == null || map.isEmpty()){
model.addAttribute("msg","注册成功,我们已向您的邮箱发送了激活邮件,请尽快激活!");
model.addAttribute("target","/index");
return "/site/operate-result";
}else {
model.addAttribute("usernameMsg",map.get("usernameMsg"));
model.addAttribute("passwordMsg",map.get("passwordMsg"));
model.addAttribute("emailMsg",map.get("emailMsg"));
return "/site/register";
}
}
}
2.2.6 测试
两个if判断图
测试成功图
这时点击此链接
没有用,因为激活服务的逻辑还没有写。如下,开始激活服务逻辑!
2.3 激活注册账号
- 点击邮件中的链接,访问服务端的激活服务
2.3.1 CommunityConstant接口
用来对激活做一个情况处理——成功、失败、重复激活
public interface CommunityConstant {
/*激活成功*/
public int ACTIVATION_SUCCESS = 0;
/*重复激活*/
public int ACTIVATION_REPEAT = 1;
/*激活失败*/
public int ACTIVATION_FAILURE = 2;
}
2.3.2 UserService
然后在UserService里实现这个接口,并写邮件激活的方法
//邮件激活的方法
public int activation(int userId,String code){
User user = userMapper.selectById(userId);
if (user.getStatus()==1){
return ACTIVATION_REPEAT;
}else if (user.getActivationCode().equals(code)){
//如果用户的激活码和数据库的对比是一样的,就成功!并且将用户状态从0修改为1
userMapper.updateStatus(userId,1);
return ACTIVATION_SUCCESS;
}else {
return ACTIVATION_FAILURE;
}
}
2.3.3 LoginController
同样,为了让结果更详细,仍需要实现CommunityConstant接口
LoginController
//邮箱激活账号-激活码
// http://localhost:8080/community/activation/101/code
@RequestMapping(path = "/activation/{userId}/{code}",method = RequestMethod.GET)
public String activation(Model model, @PathVariable("userId") int userId,
@PathVariable("code") String code){
int result = userService.activation(userId, code);
if (result == ACTIVATION_SUCCESS){
model.addAttribute("msg","激活成功,您的账号已经可以使用了!");
model.addAttribute("target","/login");
}else if (result == ACTIVATION_REPEAT){
model.addAttribute("msg","账号已经激活,无需重复!");
model.addAttribute("target","/index");
}else {
model.addAttribute("msg","激活失败,激活码不正确!");
model.addAttribute("target","/index");
}
return "/site/operate-result";
}
2.3.4 测试结果
收到激活邮件。
点击此链接进行激活;点击之后,调到此页面展示三种结果——成功、失败、重复:
同时数据库中的Status字段也从0变成了1;
注册功能到此全部成功!
3.生成验证码
为后面登录功能做准备。
3.1 导jar包
<!--验证码-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
3.2 KaptchaConfig配置类
/*标记这不是一个普通类,而是一个配置类*/
@Configuration
public class KaptchaConfig {
/*声明一个bean,这个bean被spring所管理*/
@Bean
public Producer kaptchaProducer(){
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width","100");//图片宽度
properties.setProperty("kaptcha.image.height","40");//图片高度
properties.setProperty("kaptcha.textproducer.font.size","32");//图片中的字体
properties.setProperty("kaptcha.textproducer.font.color","0,0,0");//图片中的字体颜色 黑
properties.setProperty("kaptcha.textproducer.char.string","0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");//图片中字符串的范围
properties.setProperty("kaptcha.textproducer.char.length","4");//图片中文字个数
//是否添加噪音:其实就是对文字进行一个曲解,比如多了几个横线贯穿数字,这是为了防止机器暴力破解;默认不加也可以,因为自带曲解
properties.setProperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");
//实现类
DefaultKaptcha kaptcha = new DefaultKaptcha();
//然后给它传入一些配置,参数;将配置、参数封装到config中,然后注入
Config config = new Config(properties);
kaptcha.setConfig(config);
return kaptcha;
}
}
3.3 controller测试删除验证码图片方法
//声明一个日志对象
private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
@Autowired
private Producer kaptchaProducer;
//生成验证码的方法
@RequestMapping(path = "/kaptcha",method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse response, HttpSession session){
//生成验证码
String text = kaptchaProducer.createText(); //先 生成字符串text
BufferedImage image = kaptchaProducer.createImage(text); //利用字符串text去生成一个图片
//将验证码存入session
session.setAttribute("kaptcha",text);
//将图片输出给浏览器
response.setContentType("image/png");
try {
OutputStream os = response.getOutputStream();
ImageIO.write(image,"png",os);
} catch (IOException e) {
logger.error("响应验证码失败:"+e.getMessage());
}
3.3.1 测试结果
每次刷新都会生成一个新的验证码图片!
3.4 将此方法用到登录页面上去
此时我们的login.html上的图片是死的,我们需要将其做成动态的。
→
结果:
→