疫情防控交流社区平台——2.1 开发社区登录注册模块

本文档详细介绍了如何使用SpringBoot集成邮件服务发送注册激活邮件,包括邮箱设置、SpringEmail的配置与使用,以及Thymeleaf模板引擎发送HTML邮件。此外,还涵盖了用户注册功能的实现,包括前端页面、后端服务、数据验证、激活链接的生成与验证。最后,讨论了验证码的生成与应用,为登录功能做准备。
摘要由CSDN通过智能技术生成

开发社区登录注册模块

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上的图片是死的,我们需要将其做成动态的。
在这里插入图片描述
在这里插入图片描述
结果:
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

11_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值