vue3+springboot+mybatis+mysql项目实践--简单登录注册功能实现

这里是一次对vue3+springboot+mybatis+mysql的项目实现,简单实现前后端分离的登录注册功能,主要工具:idea,navicat

目录

一、创建vue3项目并初始配置

创建vue3项目

2.修改项目结构

1)原始目录结构

2)修改后目录结构

​编辑编写登录注册页面

1)LoginAndRegister.vue

2)Home.vue

3)router

4)Login.css

5)登录注册页面展示

二、创建springboot+mysql+mybatis项目并连接数据库

三、编写登录注册后端功能

1.登录逻辑

2.注册逻辑

3.后端代码部分

四、运行项目


一、创建vue3项目并初始配置

1.创建vue3项目

创建项目可参考我的一篇文章:

用IDEA创建自定义vue3项目_idea vue3-CSDN博客

创建后的初始目录结构:

2.修改项目结构

首先需要修改原始目录结构

1)原始目录结构

assets放图片

components中放组件,通常可复用

router是路由,所有主要页面的文件路径在其中配置

store一般是用于vuex状态管理,如存储token等

views中是主要页面

App.vue是Vue应用的根组件。

main.js是应用的入口文件,通常用于引入vue和vue router等依赖。

2)修改后目录结构

要实现登录注册功能,修改后的目录结构:


3.编写登录注册页面

1)LoginAndRegister.vue

在components文件夹下创建LoginAndRegister.vue,用于实现登录注册页面及功能,这里我的登录和注册只创建一个.vue文件,在其中通过v-if来决定登录块和注册快的元素部分是否被渲染,从而影响它们的显示。

初始时设置

v-if="loginShow"为true, v-if="registerShow"为false

当点击按钮进行切换时,将true和false切换。

注册成功后切换回登录部分。

这里为了方便以及用户习惯,虽然用户的属性有id,username,password,phone,gender五个,但注册时只填写用户名和密码,且只是简单实现功能,未对密码进行加密处理不够安全,之后可能会再更新文章,写写更安全的登录注册方式,以及登录后如何完善个人信息。

LoginAndRegister.vue:

<template><div class="container"><div class="login-box" v-if="loginShow">
<!--      菱形群--><div class="decoration1 decoration"></div><div class="decoration2 decoration"></div><div class="decoration3 decoration"></div><div class="decoration4 decoration"></div><div class="decoration5 decoration"></div><div class="decoration decoration4 decoration6"></div><div class="decoration decoration7 decoration2"></div><div class="decoration decoration8 decoration3"></div><div class="login-title"><h1>Login</h1></div><div class="login-part"><input class="login-input" v-model="username" placeholder="Username" /><input class="login-input" type="password" v-model="password" placeholder="Password" /><button class="login-button" @click="login">Login</button><div>还未注册?点击<a class="change-link" @click="changeToRegister">这里</a>注册</div></div></div><div class="login-box" v-if="registerShow"><!--      菱形群--><div class="decoration1 decoration"></div><div class="decoration2 decoration"></div><div class="decoration3 decoration"></div><div class="decoration4 decoration"></div><div class="decoration5 decoration"></div><div class="decoration decoration4 decoration6"></div><div class="decoration decoration7 decoration2"></div><div class="decoration decoration8 decoration3"></div><div class="login-title"><h1>Register</h1></div><div class="login-part"><input class="login-input" v-model="username" placeholder="Username" /><input class="login-input" type="password" v-model="password" placeholder="Password" /><button class="login-button" @click="register">Register</button><span class="change-link" @click="changeToLogin">返回登录</span></div></div>
<!--    <div class="decoration decoration1"></div>-->
<!--    <div class="decoration decoration2"></div>-->
<!--    <div class="decoration decoration3"></div>-->
<!--    <div class="decoration decoration4"></div>--></div>
</template><script>
import { ref } from 'vue'
import { useRouter } from 'vue-router' // 导入 useRouterimport '../style/Login.css' // 导入css
export default {name: 'LoginVue',setup () {const username = ref('')const password = ref('')const phone = ref('')const loginShow = ref(true)const registerShow = ref(false)const router = useRouter()const changeToRegister = async () => {loginShow.value = falseregisterShow.value = true}const changeToLogin = async () => {loginShow.value = trueregisterShow.value = false}const login = async () => {console.log('Login with:', username.value, password.value)try {const formData = new FormData()formData.append('username', username.value)formData.append('password', password.value)const response = await fetch('http://localhost:8081/api/user/login', {method: 'POST',body: formData})const data = await response.json()if (response.ok) {console.log('Link success', data)if (data.code === 200) {// 登录成功alert('登录成功!')await router.push('/home')} else {alert(data.msg)}} else {console.error('Link failed', data)}} catch (error) {console.error('Error login', error)}}const register = async () => {console.log('Register with:', username.value, password.value)try {const formData = new FormData()formData.append('username', username.value)formData.append('password', password.value)const response = await fetch('http://localhost:8081/api/user/register', {method: 'POST',body: formData})const data = await response.json()if (response.ok) {if (data.code === 200) {console.log('Register success', data)alert('注册成功!')await changeToLogin()} else {console.log('Register failed', data)alert(data.msg)}} else {console.error('Register failed', data)}} catch (error) {console.error('Error during register', error)}}return { username, password, phone, login, loginShow, registerShow, changeToRegister, register, changeToLogin }}
}
</script><style></style>

2)Home.vue

Home.vue为登录成功后跳转到的主页面。

Home.vue:

<template>
首页<br><br><button class="login-button" @click="signOut">退出登录</button>
</template><script>
import { useRouter } from 'vue-router'export default {name: 'HomeVue',setup () {const router = useRouter()const signOut = async () => {await router.push('/')}return { signOut }}
}
</script><style scoped></style>

3)router

页面路由配置,路径为/时重定向到登录页,/login为登录页,/home为首页。

index.js:

import { createRouter, createWebHistory } from 'vue-router'
import Login from '../components/LoginAndRegister.vue'
import Home from '../views/Home.vue'const routes = [{path: '/',redirect: '/login'},{path: '/login',name: 'Login',component: Login},{path: '/home',name: 'Home',component: Home}
]const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes
})export default router

4)Login.css

对登录注册页面的css设计。

Login.css:

*{margin: 0;padding: 0;
}
.container{height: 100vh;display: flex;justify-content: center;align-items: center;overflow: hidden;position: relative;
}
.login-box{background-color: white;padding: 40px 100px;border-radius: 8px;box-shadow: 0 0 5px 1px gainsboro;position: relative;
}
.login-part{display: flex;flex-direction: column;justify-content: center;margin-top: 20px;gap: 20px;
}
.login-input{width: 250px;height: 30px;border-radius: 8px;
}
.login-button{height: 40px;border-radius: 8px;background-color: #2c3e50;color: white;transition: 0.5s;
}
.login-button:hover{background-color: darkcyan;font-size: 15px;transition: 0.5s;
}
.login-button:active{background-color: darkslateblue;
}
.change-link{color: #00BFFF;text-decoration: underline;
}
.change-link:hover{color: cornflowerblue;
}.decoration {position: absolute;width: 200px;height: 200px;background: linear-gradient(to left, #FDF5E6, #96CDCD );clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);z-index: 1;
}
.decoration1 {top: 150px;left: -210px;
}
.decoration2 {top: 20px;right: -20px;width: 100px; /* 第二个菱形的大小 */height: 100px;background: linear-gradient(to right, #FFF5EE, #E6E6FA);
}
.decoration3 {top: 50px;right: -180px;width: 200px; /* 第三个菱形的大小 */height: 200px;background: linear-gradient(to right, #7FFFD4, cadetblue);
}
.decoration4 {top: 200px;right: -200px;width: 500px; /* 第三个菱形的大小 */height: 500px;z-index: -1;clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);background: linear-gradient(to right, #FFFACD, #00BFFF);
}
.decoration5 {top: -100px;right: 200px;width: 400px; /* 第三个菱形的大小 */height: 400px;z-index: -1;clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);background: linear-gradient(to right, #AFEEEE, #00BFFF);
}
.decoration6 {top: 10px;right: -680px;
}.decoration7 {top: -170px;right: -500px;
}.decoration8 {top: -140px;right: -655px;
}

5)登录注册页面展示

其中的菱形块是随便排布的,一开始是这样的:

后来多加了几个菱形块,改变他们的位置和颜色,最终效果如下:

二、创建springboot+mysql+mybatis项目并连接数据库

用springboot,mysql,mybatis简单建一个后端项目并连接数据库,参考:

idea,spring boot+MySQL+MyBatis项目创建并在网页中显示数据库表中内容_idea将数据库显示到网页-CSDN博客

对文章补充:

觉得创建实体类每次都要写set和get方法比较麻烦,可以在pom.xml中添加如下依赖:

		<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>

然后在entity的实体类中用@Data注解,就可省略写set和get方法:

过程差不多,不过此次创建我的数据不太一样,主要是user表属性和数据发生变化(差别不大,换汤不换药):

遇到问题:maven一直下载依赖,很久没反应

但是在创建项目途中还是出了点儿问题的,这次使用的是新电脑创建后端项目,第一次建,结果maven启动后一直在下载各种依赖和插件,并且很久没有反应:

解决方式:

清空缓存重启idea,但效果不大。

后来发现可能是因为Maven默认使用国外的中央仓库,且我用的是idea中的maven插件,所以下载速度会很慢。

所以还是在本地下载了maven,参考教程:

maven的下载与安装教程(超详细)_maven安装-CSDN博客

按教程下载,在maven安装路径->conf->settings.xml中修改镜像的url,不过我没有配置环境变量,直接在idea中file->settings->Build,Execution,Deployment->Build Tools->Maven中,将Maven home path改为本地路径:

改完之后下载速度果然快了很多。

最终后端项目的目录结构如下:

三、编写登录注册后端功能

1.登录逻辑

获取前端传递的填写信息,包括用户名和密码,在数据库中根据用户名和密码进行查询,如果找到用户,说明用户存在且用户名与密码对应,登录成功,否则失败。

2.注册逻辑

获取前端传递的填写信息,包括用户名和密码,判断输入信息不为空后,在数据库中先根据用户名查找用户,如果找到了,即用户名已存在,注册失败,返回失败信息,如果未找到用户,则可以注册,向数据库中插入该条记录,并且注册成功后展示登录块,隐藏注册块。

3.后端代码部分

其中resources->mapper->UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.example.demo.mapper.UserMapper" ><resultMap id="result" type="com.example.demo.entity.User"><result property="id" column="id" /><result property="username" column="username" /><result property="password" column="password" /><result property="phone" column="phone" /><result property="gender" column="gender"/></resultMap><!--    通过用户名和密码查找对应用户,用于登录--><select id="findUserByNameAndPwd" resultMap="result" parameterType="User">select * from userwhere username = #{username}and password = #{password}</select><!--    通过用户名查找对应用户,用于注册检验用户名是否已存在--><select id="findUserByName" resultMap="result" parameterType="User">select * from userwhere username = #{username}</select><!--    添加用户--><insert id="addUser" parameterType="User">insert into user (username, password)values ( #{username}, #{password} )</insert></mapper>

java->com.example.demo->mapper->UserMapper.java:

package com.example.demo.mapper;import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper {// 通过用户名和密码查找对应用户public User findUserByNameAndPwd(User user);// 通过用户名查找用户public User findUserByName(User user);// 添加用户public void addUser(User user);
}

java->com.example.demo->service->UserService.java:

package com.example.demo.service;import com.example.demo.entity.User;public interface UserService {// 通过用户名和密码查找对应idpublic User findUserByNameAndPwd(User user);// 通过用户名查找用户public User findUserByName(User user);
//     添加用户public void addUser(User user);
}

java->com.example.demo->service->UserServiceImpl.java:

package com.example.demo.service;import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;// 通过用户名和密码查找对应id@Resourcepublic User findUserByNameAndPwd(User user){return userMapper.findUserByNameAndPwd(user);}// 通过用户名查找用户@Resourcepublic User findUserByName(User user){return userMapper.findUserByName(user);}//     添加用户@Resourcepublic void addUser(User user){userMapper.addUser(user);}
}

java->com.example.demo->controller->UserController.java:

package com.example.demo.controller;import com.example.demo.entity.User;
import com.example.demo.result.Result;
import com.example.demo.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/user")
public class UserController {@ResourceUserService userService;// 登录@CrossOrigin@PostMapping(value = "/login")public Result login(@ModelAttribute("user") User user){String username=user.getUsername();String password=user.getPassword();System.out.println("Login received username: " + username);System.out.println("Login received password: " + password);User userCheck = new User();userCheck.setUsername(username);userCheck.setPassword(password);System.out.println(userCheck.getUsername() + " " + userCheck.getPassword());try{User findUser = userService.findUserByNameAndPwd(userCheck);if(findUser != null){return Result.success(findUser);}else {return Result.failure(401,"用户名或密码错误");}}catch (Exception e){return Result.failure(500,"服务器异常");}}// 注册@CrossOrigin@PostMapping(value = "/register")public Result register(@ModelAttribute("user") User user){
//        String username = "222";
//        String password = "222";User userCheck = new User();userCheck.setUsername(user.getUsername());userCheck.setPassword(user.getPassword());if(userCheck.getUsername() == null || userCheck.getUsername().isEmpty() || userCheck.getPassword() == null || userCheck.getPassword().isEmpty()){System.out.println("用户名或密码不可为空");return Result.failure(201,"用户名和密码不可为空");}else {System.out.println("Register received username: " + userCheck.getUsername());System.out.println("Register received password: " + userCheck.getPassword());try{// 先在数据库中查找是否已有用户名相同的用户User findUser = userService.findUserByName(userCheck);if(findUser != null){// 用户名已存在return Result.failure(202,"用户名已存在!");}else {// 新用户,数据库添加记录userService.addUser(userCheck);return Result.success(userCheck);}}catch (Exception e) {return Result.failure(500, "服务器异常");
//            }}}}
}

四、运行项目

前后端分别运行启动,这里我把后端的端口在application.properties中改为了8081,前端为默认的8080,所以在前后端项目都成功运行后,在浏览器输入http://localhost:8080即可,在开发者工具的network中查看,成功连接到后端,并且当登录注册进行测试输入时能成功返回不同的提示信息并弹窗提示:

登录成功之后:

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

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

相关文章

RFID技术简介

1.RFID&#xff08;无线射频设别技术&#xff09;介绍 &#xff08;1&#xff09;RFID是一种通信技术&#xff0c;通过无线电讯号耦合识别特点目标并读写相关数据。 &#xff08;2&#xff09;类型 &#xff08;3&#xff09;应用 智慧仓库&#xff0c;AGV&#xff0c;ETC …

自动驾驶中,实现三维点旋转原理

文章目录 1. 三维点旋转的方案2. 使用复数表示二维点的旋转2.1. 复数的概念2.2. 复数的三种形式及相互转换2.3. 复数概念扩展&#xff1a;实数、虚数、复数 3. 四元数旋转三维点原理4. 使用四元数进行旋转的公式5. 旋转叠加6. 四元数转换为三维点7. 代码实现 1. 三维点旋转的方…

一文学会用RKE部署高可用Kubernetes集群

k8s架构图 RKE简介 RKE全称Rancher Kubernetes Engine&#xff0c;是一个快速的&#xff0c;多功能的 Kubernetes 安装工具。通过RKE&#xff0c;我们可以快速的安装一个高可用K8S集群。RKE 支持多种操作系统&#xff0c;包括 MacOS、Linux 和 Windows。 K8S原生安装需要的先…

【YOLOv5/v7改进系列】改进池化层为SimSPPF

一、导言 SimSPPF&#xff08;Simplified Spatial Pyramid Pooling with Fixed-size kernel&#xff09;模块是在YOLOv6架构中引入的一个关键组件&#xff0c;它旨在优化原始SPPF&#xff08;Spatial Pyramid Pooling Fixed-size&#xff09;模块的效率。以下是SimSPPF的一些优…

开发TEE的踩坑之开发TEE

系统&#xff1a;Ubuntu20.04&#xff08;双系统&#xff0c;非虚拟机&#xff09; 一、前置说明1、TEE平台的选择2、机器间的通信方式3、程序和数据集的示例4、结果文件的解密 二、服务器部署三、客户端部署四、工程应用 本系列为笔者开发TEE&#xff08;Trusted Execution En…

【笔记】虚拟机中的主从数据库连接实体数据库成功后的从数据库不同步问题解决方法2

错误&#xff1a; Last_Errno: 1008 Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction ANONYMOUS at source log mysql-bin.000014, end_log_pos 200275. See error lo…

开放式耳机哪款好一点?开放式耳机科普五款推荐!

“选择开放式耳机真的太难了” “哥&#xff0c;怎么才能选到心仪的开放式耳机啊” 这种评论总是会出现后台或者现实的朋友也会问起来&#xff0c;所以作为耳机测评的博主&#xff0c;在这里给大家科普一下到底一款好用的开放式耳机到底怎么选&#xff0c;这篇文章我花了三天…

Centos系统内磁盘分区

Centos系统内磁盘分区 建议如果有重要数据提前做好备份 以根目录扩容50G为例&#xff1a; 1、卸载/home目录 umount /home 2、删除逻辑卷 y确认即可 lvremove /dev/mapper/centos-home 3、df -h查询一下&#xff0c;/home目录已经不见了 4、向根目录分区追加50G容量 lv…

网易云小程序资料分享

链接: https://pan.baidu.com/s/1jzP52Zq4R-nUTxN334XMJg 提取码: xhny

STM32基础篇:EXTI × 事件 × EXTI标准库

EXTI EXTI简介 EXTI&#xff1a;译作外部中断/事件控制器&#xff0c;STM32的众多片上外设之一&#xff0c;能够检测外部输入信号的边沿变化并由此产生中断。 例如&#xff0c;在检测按键时&#xff0c;按键按下时会使电平产生翻转&#xff0c;因此可以使用EXTI来读取按下时…

线上线下一体开源的Hugging Face?| 这些问题不可不看……

7月&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议&#xff08;WAIC 2024&#xff09;在上海盛大启幕&#xff0c;以“以共商促共享&#xff0c;以善治促善智”为主题进行展览&#xff0c;OpenCSG首次亮相“CSGHub和StarShip”两大产品&#xff0c;全方位展现公…

HTML5新增的input元素类型:number、range、email、color、date等

HTML5 大幅度地增加与改良了 input 元素的种类&#xff0c;可以简单地使用这些元素来实现 HTML5 之前需要使用 JavaScript 才能实现的许多功能。 到目前为止&#xff0c;大部分浏览器都支持 input 元素的种类。对于不支持新增 input 元素的浏览器&#xff0c;input 元素被统一…

kotlin数据容器

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 容器是用于存放数据的载体。容器分为数组、集合。 Kotlin作为一门全新的语言&#xff0c;肯定还是要有自己的容…

网优学习干货:xx5G速率优化现场实战版

速率概述 无线网络仍然是5G网络能力最容易受限的环节&#xff0c;无线网络技术的应用将最终决定5G网络能力的木桶深度。移动通信中传统关键技术在5G将会继续使用。5G NR在继承了LTE原有部分技术基础上&#xff0c;采用了一些技术演进和新技术创新。比如NR继承了LTE的OFDM和SC-…

ArduPilot开源飞控之AP_Mount_Topotek

ArduPilot开源飞控之AP_Mount_Topotek 1. 源由2. 框架设计3. 重要函数3.1 动态过程3.1.1 AP_Mount_Topotek::update3.1.2 AP_Mount_Backend::calculate_poi 3.2 基础能力3.2.1 AP_Mount_Topotek::healthy3.2.2 AP_Mount_Topotek::has_pan_control 3.3 设备功能3.3.1 AP_Mount_T…

python 实验八 数据分析与展示

一、实验目的 掌握掌握matplotlib库中pyplot模块的使用。 二、实验环境 Window10&#xff08;x64&#xff09;&#xff0c;Python 3.8&#xff08;x64&#xff09;&#xff0c;PyCharm Community Edition 2020.3.2&#xff08;x64&#xff09; 三、实验内容 现有列表hight…

初学SpringMVC之过滤器解决乱码

写个 login.jsp 页面 提交的 method 一般为 post&#xff08;写 get 不安全&#xff0c;地址栏上会显示&#xff09; action 表示提交后跳转的地址 &#xff08;不直接写控制器里的路径是因为配置 Tomcat 时设置了前缀路径&#xff0c;默认走 http://localhost:8080&#xf…

市面上的护眼台灯哪个牌子最好?分享学生护眼台灯十大排名

家长们对孩子的用眼健康很重视&#xff0c;为什么&#xff1f;现在是科技电子时代&#xff0c;人们对电子屏幕的依赖性高&#xff0c;小孩子年纪小&#xff0c;眼部还处于正在发育的阶段&#xff0c;他们在学校中长时间的学习读写&#xff0c;用眼时间长。而且随着科技渗入教学…

如何选择小型超声波清洗机? 2024年值得买的四款眼镜清洗机总结

久了不擦洗的眼镜&#xff0c;往往会滋生很多细菌病毒&#xff0c;久而久之就会影响到视力和眼睛健康。而超声波清洗机作为一款高效清洁物品&#xff0c;可以帮助人们快速且深度地清洁眼镜&#xff0c;很多清洗机使用久一点清洁力就减弱了&#xff0c;所以要找一款性价比高的清…

【Java EE】统一功能返回

一、拦截器 1.1 拦截器的作用 在对于数据库进行增删查改的时候&#xff0c;如果当前页面不检查用户是否登录&#xff0c;然后就能操作成功是不合理的&#xff0c;解决方法有两个&#xff1a; 对于已经写好的每个接口都加上一个判断&#xff0c;从Session中获取用户信息&…