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' // 导入 useRouter

import '../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 = false
      registerShow.value = true
    }

    const changeToLogin = async () => {
      loginShow.value = true
      registerShow.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 user
        where username = #{username}
        and password = #{password}
    </select>


    <!--    通过用户名查找对应用户,用于注册检验用户名是否已存在-->
    <select id="findUserByName" resultMap="result" parameterType="User">
        select * from user
        where 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 {
    // 通过用户名和密码查找对应id
    public 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 {
    @Resource
    private UserMapper userMapper;

    // 通过用户名和密码查找对应id
    @Resource
    public User findUserByNameAndPwd(User user){
        return userMapper.findUserByNameAndPwd(user);
    }

    // 通过用户名查找用户
    @Resource
    public User findUserByName(User user){
        return userMapper.findUserByName(user);
    }

//     添加用户
    @Resource
    public 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 {
    @Resource
    UserService 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中查看,成功连接到后端,并且当登录注册进行测试输入时能成功返回不同的提示信息并弹窗提示:

登录成功之后:

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 14:12:05       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 14:12:05       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 14:12:05       58 阅读
  4. Python语言-面向对象

    2024-07-11 14:12:05       69 阅读

热门阅读

  1. AWS需要实名吗?

    2024-07-11 14:12:05       22 阅读
  2. Redis新手教程

    2024-07-11 14:12:05       21 阅读
  3. 薄冰英语语法学习--代词1

    2024-07-11 14:12:05       19 阅读
  4. 03-图像基础-视音频参数

    2024-07-11 14:12:05       27 阅读
  5. mysql中count的区别

    2024-07-11 14:12:05       21 阅读
  6. springboot对象参数赋值变化

    2024-07-11 14:12:05       18 阅读
  7. 什么是数据挖掘(python)

    2024-07-11 14:12:05       25 阅读
  8. python的类变量和实例变量

    2024-07-11 14:12:05       24 阅读
  9. JDK-CompletableFuture

    2024-07-11 14:12:05       25 阅读
  10. Python 获取 SQL 指纹和 HASH 值

    2024-07-11 14:12:05       26 阅读
  11. 井字棋 AI-Python

    2024-07-11 14:12:05       25 阅读