当前位置: 首页 > news >正文

[Spring实战] 整合Spring/SpringMVC/Mybatis(SSM)实现登录与注册功能(带前端)

目录

前言

功能展示

功能说明

数据库表设计

依赖

配置文件

后端

Controller

Entity实体类

Mapper

Service

Impl

前端

总结与改进方向


前言

  不出意料,果然一个登录还是不够的 ,先说明一下,看这篇前请先去看一下上一篇这里放上上一篇的链接 [Spring实战] 整合Spring/SpringMVC/Mybatis(SSM)实现登录功能(带前端)_天海奈奈的博客-CSDN博客,对于项目的创建和依赖的配置这篇不会再讲,这篇主要在之前的基础上对数据库进行一定的修改,新写一个主页页面,实现注册功能。

功能展示

功能说明

  之前只是在登录时验证密码时利用了MD5算法进行密码的转换与数据库中的密码去对比,注册时使用着这个工具类去将加密后的密码存到数据库中去,并在注册时检索数据库中是否已经有存在的用户名,在注册页面新加验证码功能,成功注册后自动跳转到登录页面。

数据库表设计

  由于没有涉及到用户权限的功能所以没有使用到权值。这里会把sql放在这里直接复制运行就能得到这张表,但是记得去第一篇文章里面去改自己的数据库连接。

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for manager
-- ----------------------------
DROP TABLE IF EXISTS `manager`;
CREATE TABLE `manager`  (
  `manager_id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '管理员编号',
  `username` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
  `password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
  `salt` int(0) NOT NULL COMMENT '盐值',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '昵称',
  PRIMARY KEY (`manager_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 520 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of manager
-- ----------------------------
INSERT INTO `manager` VALUES (1, 'MANAGER', 'ce20d2be56ca49d36ed2709e776187db', 1276, NULL, NULL);
INSERT INTO `manager` VALUES (516, 'user1', 'b8ddf129011519e083c25c6b05208da0', 1197, '2022-09-12 21:39:37', '用户1');
INSERT INTO `manager` VALUES (517, 'user2', '675f66d99f78db051bf8c73c3eff26a0', 1226, '2022-09-12 21:40:50', '拥护2');
INSERT INTO `manager` VALUES (518, 'user3', 'e8ee397e19a484c66c0edcde9c8e6c39', 1801, '2022-09-16 15:47:58', '用户三');
INSERT INTO `manager` VALUES (519, 'user4', '4dfcb81c7e01b6beaf0092ddbd8534fd', 1478, '2022-09-16 15:49:36', '用户4');

SET FOREIGN_KEY_CHECKS = 1;

依赖

 <!--    验证码-->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>

配置文件

 <!--    验证码-->
    <!-- 配置Kaptcha  完成对Kaptcha 初始化赋值的工作:字体大小,文本,背景色。。。。。。-->
    <bean id="kaptchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
        <!--                                          用于生成验证码图片-->
        <property name="config">
            <bean class="com.google.code.kaptcha.util.Config">
                <constructor-arg>
                    <!--                    构造参数-->
                    <props>
                        <!--验证码图片不生成边框-->
                        <prop key="kaptcha.border">no</prop>
                        <!-- 验证码图片宽度为120像素 -->
                        <prop key="kaptcha.image.width">120</prop>
                        <!-- 验证码图片字体颜色为蓝色 -->
                        <prop key="kaptcha.textproducer.font.color">blue</prop>
                        <!-- 每个字符最大占用40像素 -->
                        <prop key="kaptcha.textproducer.font.size">40</prop>
                        <!-- 验证码包含4个字符 -->
                        <prop key="kaptcha.textproducer.char.length">4</prop>
                    </props>
                </constructor-arg>
            </bean>

依赖和配置文件在原基础上加就好

后端

Controller

@RestController
@RequestMapping("/api/manager")
public class ManagerController {
    @Resource
    private ManagerService managerService;
    @PostMapping("/check_login1")
    public ResponseUtils checkLogin1(String username , String password){
        ResponseUtils resp ;
            resp = new ResponseUtils();

            try {
                Manager manager = managerService.checkLogin1(username, password);
                manager.setPassword(null);
                manager.setSalt(null);
                resp = new ResponseUtils().put("manager" , manager);
            }catch (Exception e){
                e.printStackTrace();
                resp = new ResponseUtils(e.getClass().getSimpleName(), e.getMessage());
            }
        return resp;
    }
    @PostMapping("/register")
    public ResponseUtils register(String username, String password, String nickname, String vc, HttpServletRequest request) {
        String verifyCode = (String) request.getSession().getAttribute("kaptchaVerifyCode");
        ResponseUtils resp;
        if (vc == null || verifyCode == null || !vc.equalsIgnoreCase(verifyCode)) {
            resp = new ResponseUtils("VerifyCodeError", "验证码错误");
        } else {
            resp = new ResponseUtils();
            //验证码比对成功后进行用户注册
            try {
                Manager manager = managerService.createManager(username, password, nickname);
                resp = new ResponseUtils();
            } catch (Exception e) {
                e.printStackTrace();
                resp = new ResponseUtils(e.getClass().getSimpleName(), e.getMessage());
            }
        }
        return resp;
    }
}

 与上一篇其实差不多,只是增加了验证码校验,调用新写了一个Service来创建对象。

Entity实体类

@TableName("manager")
public class Manager {
    @TableId(type = IdType.AUTO)
    private Long managerId;
    private String username;
    private String password;
    private Integer salt;
    private String nickname;
    private Date createTime;

    @Override
    public String toString() {
        return "Manager{" +
                "managerId=" + managerId +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", salt=" + salt +
                ", nickname='" + nickname + '\'' +
                ", createTime=" + createTime +
                '}';
    }

    public Long getManagerId() {
        return managerId;
    }

    public void setManagerId(Long managerId) {
        this.managerId = managerId;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Long getUserId() {
        return managerId;
    }

    public void setUserId(Long userId) {
        this.managerId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getSalt() {
        return salt;
    }

    public void setSalt(Integer salt) {
        this.salt = salt;
    }
}

  新加创建时间和昵称

Mapper

public interface ManagerMapper extends BaseMapper<Manager> {
}

因为整合了mubatis-plus所以并不需要自己写mapper以及xml文件

Service

public interface ManagerService {
    public Manager checkLogin1(String username, String password);
    public Manager createManager(String username, String password, String nickname);
}

这里也就加一个新建对象


Impl

@Service
//默认方法不开启事务
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public class ManagerServiceImpl implements ManagerService {

    @Resource
    private ManagerMapper managerMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Manager checkLogin1(String username, String password) {
        QueryWrapper<Manager> wrapper = new QueryWrapper();
        wrapper.eq("username", username);
        Manager manager = managerMapper.selectOne(wrapper);
        if (manager == null) {
            throw new MemberException("用户不存在");
        }
        String md5 = MD5Utils.md5Digest(password, manager.getSalt());
        if (!md5.equals(manager.getPassword())) {
            throw new MemberException("您输入的密码有误");
        }
        return manager;
    }

    @Override
    public Manager createManager(String username, String password, String nickname) {
        QueryWrapper<Manager> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        List<Manager> managers = managerMapper.selectList(wrapper);
        if(managers.size() > 0 ){
            throw new MemberException("用户已存在");
        }
        Manager manager = new Manager();
        manager.setUsername(username);
        manager.setNickname(nickname);
        manager.setCreateTime(new Date());
        int salt = new Random().nextInt(1000) + 1000;
        manager.setSalt(salt);
        String md5 = MD5Utils.md5Digest(password, salt);
        manager.setPassword(md5);
        managerMapper.insert(manager);
        return manager;
    }
}

  实现类里面也就先去搜索数据库看里面有没有已经存在的用户名,如果没有我们就创建一个新的。

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
    <!-- 引入样式 -->
    <link rel="stylesheet" type="text/css" href="assets/element-plus/index.css">
    <!-- 引入组件库 -->
    <script src="/assets/vue/vue.global.js"></script>
    <script src="/assets/element-plus/index.full.js"></script>
    <script src="/assets/axios/axios.js"></script>
    <style>
        .login-box {
            border: 1px solid #DCDFE6;
            width: 350px;
            margin: 180px auto;
            padding: 35px 35px 15px 35px;
            border-radius: 5px;
            -webkit-border-radius: 5px;
            -moz-border-radius: 5px;
            box-shadow: 0 0 25px #909399;
        }
        .login-title{
            text-align: center;
            margin: 0 auto 40px auto;
            color: #303133;
        }
    </style>
</head>
<body>
<div id="app">

    <el-form ref="registerForm" label-width="80px" :rules="rules" :model="form" class="login-box">
        <h2 class="login-title">注册</h2>
        <el-form-item label="账号" prop="username">
            <el-input type="text" placeholder="请输入账号" v-model="form.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
            <el-input type="password" placeholder="请输入密码" v-model="form.password"></el-input>
        </el-form-item>
        <el-form-item label="昵称" prop="nickname">
            <el-input type="text" placeholder="请输入昵称" v-model="form.nickname"></el-input>
        </el-form-item>
        <el-form-item label="验证码" prop="verifyCode">
            <el-row>
                <el-col :span="16">
                    <el-input type="verifyCode" placeholder="请输入验证码" v-model="form.verifyCode"></el-input>
                </el-col>
                <el-col :span="8">
                    <img id="imgVerifyCode" src="/api/verify_code"
                         style="width: 100%;height:44px;cursor: pointer" @click="reloadVerifyCode">
                </el-col>
            </el-row>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" v-on:click="onSubmit('registerForm')" style="width:200px">注册</el-button>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" v-on:click="returnBack" style="width:200px">退出</el-button>
        </el-form-item>
    </el-form>
</div>
<script>
    const Main = {
        data() {
            return {
                form: {
                    username: ''
                    ,password: ''
                    ,verifyCode:''
                    ,nickname:''
                }
                ,rules:{
                    username: [
                        {required: true,message : '账号不能为空' , trigger:'blur'}
                    ],
                    password:[
                        {required: true,message : '密码不能为空' , trigger:'blur'}
                    ],
                    verifyCode: [
                        {required:true,message : '验证码不能为空' , trigger:'blur'}
                    ],
                    nickname:[
                        {required:true,message : '昵称不能为空' , trigger:'blur'}
                    ]
                }
            }
        }
        ,methods : {
            onSubmit(formName){
                const objApp = this;
                const form = this.$refs[formName];
                form.validate((valid) => {
                    if(valid){
                        console.info("表单校验成功,准备提交数据");
                        const form = this.form;
                        const $message = this.$message;
                        const params = new URLSearchParams();
                        params.append("username", form.username);
                        params.append("password", form.password);
                        params.append("nickname", form.nickname);
                        params.append("vc", form.verifyCode);
                        axios.post("/api/manager/register", params)
                            .then(function (response) {
                            console.info(response);
                            const json = response.data;
                            if(json.code=="0"){
                                $message.success({message:"注册成功,进入登录界面", offset: 100});
                                    window.location.href = "/login.html";


                            }else{
                                $message.error({message:json.message, offset: 100});
                            }
                        });
                    }
                })
            }
            ,returnBack : function (){
                window.location.href = "/login.html";
            }
            , reloadVerifyCode: function () { //刷新验证码方案
                document.getElementById("imgVerifyCode").src = "/api/verify_code?ts=" + new Date().getTime();
            }
        }
    };
    //初始化Vue,绑定Main中的数据,利用ElementPlus对#app容器进行重新渲染
    const app = Vue.createApp(Main);
    app.use(ElementPlus);
    app.mount("#app");
</script>
</body>
</html>

总结与改进方向

  下次会更新验证码将网页实时生成的验证码改为邮箱验证,到此为止还是没有使用到session,如果有需求可以自己加,到这里有着基础功能的注册与登录功能的部分就实现了。这个前端登录页面也可以作为一个通用化的页面,只需要改变里面的的api接口就能做到重复使用。

相关文章:

  • [教你做小游戏] 滑动选中!PC端+移动端适配!完美用户体验!斗地主手牌交互示范
  • kafka的auto.offset.reset详解与测试
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • 内存分析总结
  • awk编辑器
  • 基于Java毕业设计游泳馆管理平台源码+系统+mysql+lw文档+部署软件
  • 2022年全国大学生数学建模竞赛C题思路与程序
  • `算法知识` 字符串哈希
  • 打造这样的“超级云APP”有什么优势?
  • 一篇文章带你理解Thread(多线程)的基础用法
  • harbor部署实录
  • 计算机毕业设计ssmEE的仓库管理系统93c6b系统+程序+源码+lw+远程部署
  • MySQL group by后取每个分组中最新一条数据
  • JVM:(十六)垃圾回收器
  • 节点流和处理流详解
  • Apache的80端口被占用以及访问时报错403
  • C++11: atomic 头文件
  • CAP理论的例子讲解
  • ES6 学习笔记(一)let,const和解构赋值
  • Fundebug计费标准解释:事件数是如何定义的?
  • Java程序员幽默爆笑锦集
  • node入门
  • PhantomJS 安装
  • 飞驰在Mesos的涡轮引擎上
  • 分类模型——Logistics Regression
  • 后端_ThinkPHP5
  • 基于HAProxy的高性能缓存服务器nuster
  • 开源地图数据可视化库——mapnik
  • 设计模式 开闭原则
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #考研#计算机文化知识1(局域网及网络互联)
  • ${factoryList }后面有空格不影响
  • %@ page import=%的用法
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (八)Spring源码解析:Spring MVC
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (黑马C++)L06 重载与继承
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (循环依赖问题)学习spring的第九天
  • 、写入Shellcode到注册表上线
  • .htaccess配置重写url引擎
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET 依赖注入和配置系统
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...