项目实战之旅游网(十)前台用户注册

news2024/12/28 18:40:59

目录

一.网站首页

二.编写注册界面

三.生成验证码

四.注册流程

五.编写注册方法

六.发送邮件配置


一.网站首页

static/frontdesk下存放前台静态资源,而templates/frontdesk是前台页面

二.编写注册界面

在上个界面点击注册就可以跳转到注册界面

在这里遇到一个bug,就是从index.html(上面那个页面)进行跳转到注册界面跳不过去,状态码500,报错是

template might not exist or might not be accessible by any of the configured

这是模板不存在或者找不到register.html这个文件,我尝试了很多方法,但是都行不通,最后我随便在配置文件的classpath:/template后面加了个/就好了,即变成了classpath:/templates/

三.生成验证码

验证码的作用是验证操作者是否是真人,避免机器操作恶意提交。它是后台随机生成的一串字符串,但我们不能将该字符串直接传到前台,否则机器直接读到字符串,验证码将没有任何意义。
一般在后台生成验证码后, 一方面将验证码保存到session中,另一方面将验证码做成一张图片,将图片传到前台。用户认出验证码后,输入验证码传到后台,如果正确即可判断操作者为真人。.

1.引入生成验证码的servlet

/**
 * 验证码
 */
@WebServlet("/frontdesk/checkCode")
public class CheckCodeServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException {
		//服务器通知浏览器不要缓存
		response.setHeader("pragma","no-cache");
		response.setHeader("cache-control","no-cache");
		response.setHeader("expires","0");
		
		//在内存中创建一个长80,宽30的图片,默认黑色背景
		//参数一:长
		//参数二:宽
		//参数三:颜色
		int width = 80;
		int height = 30;
		BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		
		//获取画笔
		Graphics g = image.getGraphics();
		//设置画笔颜色为灰色
		g.setColor(Color.GRAY);
		//填充图片
		g.fillRect(0,0, width,height);
		
		//产生4个随机验证码,12Ey
		String checkCode = getCheckCode();
		//将验证码放入HttpSession中
		request.getSession().setAttribute("checkCode",checkCode);
		
		//设置画笔颜色为黄色
		g.setColor(Color.YELLOW);
		//设置字体的小大
		g.setFont(new Font("黑体",Font.BOLD,24));
		//向图片上写入验证码
		g.drawString(checkCode,15,25);
		
		//将内存中的图片输出到浏览器
		//参数一:图片对象
		//参数二:图片的格式,如PNG,JPG,GIF
		//参数三:图片输出到哪里去
		ImageIO.write(image,"PNG",response.getOutputStream());
	}

	/**
	 * 产生4位随机字符串 
	 */
	private String getCheckCode() {
		String base = "0123456789ABCDEFGabcdefg";
		int size = base.length();
		Random r = new Random();
		StringBuffer sb = new StringBuffer();
		for(int i=1;i<=4;i++){
			//产生0到size-1的随机值
			int index = r.nextInt(size);
			//在base字符串中获取下标为index的字符
			char c = base.charAt(index);
			//将c放入到StringBuffer中去
			sb.append(c);
		}
		return sb.toString();
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request,response);
	}
}

运行项目:

验证码点击一下就会更新。

四.注册流程

上面的流程图和手机验证码是一个道理,都能确认邮箱或者手机号的真实性。

为了保证用户注册的信息是真实的,往往在用户注册后不能直接登录,而需要用户激活后才
能登录。用户注册激活的步骤如下:

  1. 用户在页面填写个人信息,发送到后端代码。
  2. 后端验证数据后保存用户信息,但此时用户的状态为false,还不能登录。
  3. 后端拿到用户输入的邮箱,给用户邮箱发送一段随机字符串, 并将该字符串保存到数据库的用户表中。
  4. 用户登录个人邮箱,点击随机字符串访问项目,项目将该拥有字符串的用户状态变为true,此时用户即可登录。

五.编写注册方法

1.编写前台用户的MemberMapper

public interface MemberMapper extends BaseMapper<Member> {
}

2.由于注册方法结果很多,我们注册方法需要返回的是否注册成功,如果失败需要返回失败原因。我们要在bean目录下创建一个实体类Result,该实体类可以封装返回的数据。

// 结果对象
@Data
@AllArgsConstructor
public class Result {
    private boolean flag; // 结果
    private String message; // 提示信息
    private Object data; // 返回数据

    public Result(boolean flag,String message){
        this(flag,message,null);
    }
}

3.编写MemberService

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.first.travel.bean.Result;
import com.first.travel.mapper.MemberMapper;
import com.first.travel.pojo.Member;
import com.first.travel.util.MailUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@Service
public class MemberService {
    @Autowired
    private MemberMapper memberMapper;
    //@Autowired
    //private BCryptPasswordEncoder encoder;
    @Autowired
    private MailUtils mailUtils;
    @Value("${project.path}")
    private String projectPath;

    // 注册
    public Result register(Member member) {
        // 1.保存用户
        // 验证用户名是否重复
        QueryWrapper<Member> queryWrapper = new QueryWrapper();
        queryWrapper.eq("username", member.getUsername());
        List<Member> members = memberMapper.selectList(queryWrapper);
        if (members.size() > 0) {
            return new Result(false, "用户名已存在");
        }

        // 验证手机是否重复
        QueryWrapper<Member> queryWrapper1 = new QueryWrapper();
        queryWrapper1.eq("phoneNum", member.getPhoneNum());
        List<Member> members1 = memberMapper.selectList(queryWrapper1);
        if (members1.size() > 0) {
            return new Result(false, "手机已存在");
        }

        // 验证邮箱是否重复
        QueryWrapper<Member> queryWrapper2 = new QueryWrapper();
        queryWrapper2.eq("email", member.getEmail());
        List<Member> members2 = memberMapper.selectList(queryWrapper2);
        if (members2.size() > 0) {
            return new Result(false, "邮箱已存在");
        }

        // 加密密码
        String password = member.getPassword();
        //password = encoder.encode(password);
        member.setPassword(password);
        // 设置用户状态为false
        member.setActive(false);

        // 2.发送激活邮件
        // 生成激活码
        String activeCode = UUID.randomUUID().toString();
        // 给用户的邮箱发送一封邮件,该邮件包含一个链接,链接中包含激活码
        String activeUrl = projectPath + "/frontdesk/member/active?activeCode=" + activeCode;
        String text = "恭喜您注册成功!<a href = '" + activeUrl + "'>点击激活</a>完成账号认证";
        mailUtils.sendMail(member.getEmail(), text, "旅游网激活邮件");

        // 保存激活码,激活时比对
        member.setActiveCode(activeCode);
        // 保存用户
        memberMapper.insert(member);
        return new Result(true, "注册成功!");
    }

    // 激活用户
    public String active(String activeCode) {
        // 根据激活码查询用户
        QueryWrapper<Member> queryWrapper = new QueryWrapper();
        queryWrapper.eq("activeCode", activeCode);
        Member member = memberMapper.selectOne(queryWrapper);
        // 没有找到用户:激活失败
        if (member == null) {
            return "激活失败!激活码错误!";
        } else {
            member.setActive(true);
            memberMapper.updateById(member);
            return "激活成功,请<a href='" + projectPath + "/frontdesk/login'>登录</a>";
        }
    }

    public Result login(String name, String password) {
        Member member = null;

        // 根据用户名查询
        if (member == null) {
            QueryWrapper<Member> queryWrapper = new QueryWrapper();
            queryWrapper.eq("username", name);
            member = memberMapper.selectOne(queryWrapper);
        }
        // 根据手机查询
        if (member == null) {
            QueryWrapper<Member> queryWrapper = new QueryWrapper();
            queryWrapper.eq("phoneNum", name);
            member = memberMapper.selectOne(queryWrapper);
        }
        // 根据邮箱查询
        if (member == null) {
            QueryWrapper<Member> queryWrapper = new QueryWrapper();
            queryWrapper.eq("email", name);
            member = memberMapper.selectOne(queryWrapper);
        }
        // 没有查询到用户
        if (member == null) {
            return new Result(false, "用户名或密码错误");
        }

        // 验证密码
//        boolean flag = encoder.matches(password, member.getPassword());
//        if (!flag) {
//            return new Result(false, "用户名或密码错误");
//        }

        // 验证是否激活
        if (!member.isActive()) {
            return new Result(false, "用户未激活,请登录邮箱激活用户");
        }

        return new Result(true, "登录成功", member);
    }
}

controller:

import com.first.travel.bean.Result;
import com.first.travel.pojo.Member;
import com.first.travel.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/frontdesk/member")
public class MemberController {
    @Autowired
    private MemberService memberService;
    @RequestMapping("/register")
    public ModelAndView register(Member member, String checkCode, HttpSession session){
        ModelAndView modelAndView = new ModelAndView();
        // 判断验证码是否正确
        String sessionCheckCode = (String) session.getAttribute("checkCode");
        if (!sessionCheckCode.equalsIgnoreCase(checkCode)){
            modelAndView.addObject("message","验证码错误");
            modelAndView.setViewName("/frontdesk/register");
            return modelAndView;
        }

        // 注册
        Result result = memberService.register(member);
        if (!result.isFlag()){ // 注册失败
            modelAndView.addObject("message",result.getMessage());
            modelAndView.setViewName("/frontdesk/register");
        }else { // 注册成功
            modelAndView.setViewName("/frontdesk/register_ok");
        }
        return modelAndView;
    }

    @RequestMapping("/active")
    public ModelAndView active(String activeCode){
        ModelAndView modelAndView = new ModelAndView();
        String active = memberService.active(activeCode);
        modelAndView.addObject("message",active);
        modelAndView.setViewName("/frontdesk/active_result");
        return modelAndView;
    }

    @RequestMapping("/login")
    public ModelAndView login(String name,String password,HttpSession session){
        ModelAndView modelAndView = new ModelAndView();
        Result result = memberService.login(name, password);
        if (!result.isFlag()){ // 登录失败
            modelAndView.addObject("message",result.getMessage());
            modelAndView.setViewName("/frontdesk/login");
        }else{ // 登录成功
            // 将用户信息存入session
            session.setAttribute("member",result.getData());
            modelAndView.setViewName("redirect:/frontdesk/index");
        }
        return modelAndView;
    }

    @RequestMapping("/logout")
    public String logout(HttpSession session){
        session.removeAttribute("member");
        return "redirect:/frontdesk/index";
    }
}

六.发送邮件配置

在用户注册成功后,要向用户的邮箱发送一封激活邮件 ,发送邮件需要在系统中配置发件
人,同学们使用自己的邮箱作为发件人即可。


1.配置邮箱第三方登录。
我们在系统中使用邮箱发送邮件属于第三方登录,而市面.上的邮箱默认是不能第三方登
录的。我们需要登录邮箱,配置第三方登录。以QQ邮箱配置举例:

开启第三方登录服务,点击开启

按要求发送短信

然后在配置文件中配置:

注意发件人密码就是上面的授权码。

发送邮件的工具类:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

/**
 * 发邮件工具类
 */
@Component
public final class MailUtils {
    @Value("${mail.user}")
    private String USER; // 发件人邮箱地址
    @Value("${mail.password}")
    private String PASSWORD; // 如果是qq邮箱可以使户端授权码

    /**
     * 发送邮件
     * @param to 收件人邮箱
     * @param text 邮件正文
     * @param title 标题
     */
    public boolean sendMail(String to, String text, String title){
        try {
            final Properties props = new Properties();
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.host", "smtp.qq.com");

            // 发件人的账号
            props.put("mail.user", USER);
            //发件人的密码
            props.put("mail.password", PASSWORD);

            // 构建授权信息,用于进行SMTP进行身份验证
            Authenticator authenticator = new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    // 用户名、密码
                    String userName = props.getProperty("mail.user");
                    String password = props.getProperty("mail.password");
                    return new PasswordAuthentication(userName, password);
                }
            };
            // 使用环境属性和授权信息,创建邮件会话
            Session mailSession = Session.getInstance(props, authenticator);
            // 创建邮件消息
            MimeMessage message = new MimeMessage(mailSession);
            // 设置发件人
            String username = props.getProperty("mail.user");
            InternetAddress form = new InternetAddress(username);
            message.setFrom(form);

            // 设置收件人
            InternetAddress toAddress = new InternetAddress(to);
            message.setRecipient(Message.RecipientType.TO, toAddress);

            // 设置邮件标题
            message.setSubject(title);

            // 设置邮件的内容体
            message.setContent(text, "text/html;charset=UTF-8");
            // 发送邮件
            Transport.send(message);
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }


}

 引入邮件依赖:

        <!--发送邮件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

测试类:

@SpringBootTest
class TravelApplicationTests {

    @Autowired
    private MailUtils mailUtils;

    @Test
    void contextLoads() {
        //填自己的邮箱地址
        mailUtils.sendMail("10208@qq.com","这是一封测试邮件","测试");
    }
}

开始注册:

 然后右下角一般会有弹窗(收到了邮箱验证码),咱们登录QQ邮箱查看,果然收到了一封激活邮件

到数据库的member表里可以看到咱们注册的用户信息都在里面,而且只有激活之后active才会变成1(刚注册的时候是0)

蒹葭苍苍,白露为霜。所谓伊人,在水一方。
溯洄从之,道阻且长。溯游从之,宛在水中央。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022 年上海市大学生程序设计竞赛 M. My University Is Better Than Yours

大家总喜欢搞些什么排行榜。有一说一&#xff0c;排行榜通常不重要&#xff0c;除非——比如你老板要你做一下年终总 结。 为了实现建设世界一流大学和建设世界一流学科的目标&#xff0c;不少大学都用各种方式提升排名&#xff1a;发表论文、 申请基金、提升多样性. . . 不过…

Linux操作系统实验4——内存映射

实验要求&#xff1a; 1.在源码中查看file_operations和vm_operations_struct结构定义及其操作对象的方法&#xff0c;重点查看mmap方法fault方法的参选类型。 2.设备模块代码的编写和调试&#xff0c;重新编写file_operations结构中的mmap方法&#xff0c;和vm_operations_str…

美团一面:能不能通俗的解释下为什么要有意向锁这个东西?

面试真题&#xff0c;用通俗的例子解释清楚 MySQL 为什么有了表锁和行锁之后&#xff0c;还要引入意向锁 众所周知&#xff0c;InnoDB 中既有读锁也有写锁&#xff0c;也称为共享锁和排他锁&#xff0c;这两种锁既可以加在整张表上&#xff0c;也可以加在行上。 MySQL 自身就提…

【Apifox】设置apiFox自动获取token

文章目录问题描述解决方案注意事项参考文章问题描述 接口测试时&#xff0c;每次都需要手动登录获取token&#xff0c;先登录系统&#xff0c;从浏览器中复制token&#xff0c;再到apifox的接口上把token帖上去&#xff0c;然后才能去测试具体的接口&#xff1b;更麻烦的是&am…

【实时数仓】热度关键词接口、项目整体部署流程

文章目录一 热度关键词接口1 Sugar配置&#xff08;1&#xff09;图表配置&#xff08;2&#xff09;接口地址&#xff08;3&#xff09;数据格式&#xff08;4&#xff09;执行SQL2 数据接口实现&#xff08;1&#xff09;创建关键词统计实体类&#xff08;2&#xff09;Mappe…

小黑hbase终于勉强跑到了自己的m1 Macbook上啦,虽然终端用不了,但是能从happybase访问的日常积累:happybase简单使用

1.happybase连接 # 连接操作 import happybase# 建立连接 con happybase.Connection(localhost, 9090) con.open() # 输出所有表名称 print(con.tables()) # 关闭传输 con.close() con.open()2.创建表格 # 创建表格 con happybase.Connection(localhost, 9090) # 默认9090…

Android 图像混合技术

Android 图像混合技术 色彩知识 色彩 光学三原色 光学三原色由&#xff1a;红、绿、蓝组成。 色值分别是&#xff1a; 红&#xff08;red &#xff09;&#xff1a;#FF0000 RGB&#xff08;255&#xff0c;0&#xff0c;0&#xff09;绿&#xff08;green&#xff09;&am…

第十九讲:神州路由器基础知识

路由器简介路由器&#xff08;Router&#xff09;是连接Internet中多个网络或网段的网络设备&#xff0c;它能将不同网络或网段之间的数据信息进行“翻译”&#xff0c;以使它们能够相互“读”懂对方的数据&#xff0c;实现不同网络或网段的互联互通。此外&#xff0c;它会根据…

数据平台建设指南(上)

前言 年底了&#xff0c;整理了下过去做的一些项目&#xff0c;希望能够给大数据行业的同学提供些大数据平台建设的思路。内容大致分五部分&#xff1a;数据采集&#xff0c;数据存储、数据计算、基础平台以及数据治理篇。由于涉及到的内容较多&#xff0c;打算分成两篇文章&am…

PHY驱动注册部分

SOC可以对PHY 进行配置或者读取PHY 相关状态&#xff0c;这个就需要 PHY 内部寄存器去实现了。PHY 芯片寄存器地址空间为 5位&#xff08;支持访问32个寄存器).IEEE 定义了0~15这 16个寄存器的功能。而 16~31这16 个寄存器由厂商自行实现。 就是说不管你用的哪个厂家的 PHY 芯…

SAP ABAP——SAP简介(三)【S/4 HANA开发环境】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

linux常用命令(三)-目录操作

目录创建 - mkdir 我们可以使用mkdir&#xff08;make directory&#xff09;来创建目录。 示例 目录删除 - rm 可以使用rm&#xff08;remove&#xff09;来删除一个目录 语法 rm [-irf] name ...i&#xff1a;删除前逐一询问确认r&#xff1a;将目录及以下之档案亦逐一删…

转转AB平台的设计与实现

导读 在数据驱动时代&#xff0c;不管是在产品功能迭代还是策略决策时都需要数据的支撑。那么&#xff0c;当我们准备上线一个新功能或者策略时&#xff0c;如何评估新老版本优劣&#xff0c;即数据的可量化就成了问题。这个时候就需要引入 A/B Test 了。 一、A/B Test 是什么…

Tomcat基本用法

Tomcat基本用法一、Tomcat 是什么二、下载安装三、目录结构四、启动服务器五、部署静态页面一、Tomcat 是什么 汤姆猫&#xff1f; 事实上&#xff0c;Java 世界中的 “汤姆猫” 完全不是一回事&#xff0c;但是同样大名鼎鼎 ~ Tomcat 是一个 HTTP 服务器。 前面我们已经学…

公司如何做好舆情监控,舆情监控解决方案有哪些?

随着互联网快速发展&#xff0c;企业网络舆情动态成为决策发展的重要依据&#xff0c;所以做好网络舆情监控至关重要&#xff0c;接下来TOOM舆情监测小编带您简单了解公司如何做好舆情监控&#xff0c;舆情监控解决方案有哪些? 一、公司如何做好舆情监控 舆情监控是指通过不…

Spring Boot 使用 SpringDoc 库的 Swagger3.0

Swagger 定义 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法&#xff0c;参数和模型紧密集成到服务器端的代码&#xff0c;允许API来始终保持同步…

房产管理系统平台安全性分析?

房产管理系统是数图互通公司自主研发的FMCenterV5.0平台&#xff0c;是针对中国高校房产的管理特点和管理要求&#xff0c;研发的一套标准产品&#xff1b;通过在中国100多所高校的成功实施和迭代&#xff0c;形成了一套成熟、完善、全生命周期的房屋资源管理解决方案。 以下是…

FL Studio21电脑版免费音乐编曲宿主软件下载

编曲主要考验电脑的处理器&#xff08;CPU&#xff09;性能、声卡。所以配置电脑的时候有条件的伙伴可以着重考虑这两方面。现在市面上惠普、戴尔、华为、苹果等品牌的电脑&#xff0c;在四五千这个范围的商务本&#xff0c;就可以胜任编曲工作。但是在一些较为庞大的工程中可能…

SolarMesh(微服务监管平台)安装教程

SolarMesh简介 SolarMesh是基于服务网格构建的微服务监管平台。SolarMesh基于 Istio 及容器技术&#xff0c;提供微服务流量监控和管理&#xff0c;提供完善的非侵入式服务治理解决方案&#xff0c;在提供Istio流量管理等基础能力外&#xff0c;还提供多集群纳管、监控告警、W…

为什么全球科技巨头都在布局超高清?

我们能明显地感受到&#xff0c;进入21世纪以来&#xff0c;影像视频所占用人类生活的时间、空间已达到人类诞生以来的最大值。根据《2022全球互联网现象报告》&#xff0c;2021年流媒体视频占互联网带宽流量的53.7%&#xff0c;比2020年提升了4.8%。衣食住行&#xff0c;休闲娱…