Springboot + Mybatis + Vue3 实现登陆界面

创建项目

开发环境热部署

代码修改自动重新部署

pom.xml:

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

application.properties:

1
2
spring.devtools.resstart.enabled=true
spring.devtools.restart.addtionall-paths=src/main/java

MyBatis

pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- MyBatisPlus 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

<!-- Mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>

<!-- 数据连接池 依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>

application.properties:

1
2
3
4
5
6
7
8
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db_name?useSSL=false
spring.datasource.username=root
spring.datasource.password=abc123
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

server.port=8088

修改 Springboot 版本,3+ 版本与 MyBatis 不兼容:

1
2
3
4
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/>

实现登陆注册功能

后端

前置条件:安装 MySql

创建Entity

1
2
3
4
5
6
7
public class User {
private int userid;
private String username;
private String password;
// 变量名与数据库的Table保持一致
// generate setter and getter
}

创建Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@RestController
@CrossOrigin
public class UserController {

@Autowired
private UserMapper userMapper;

//test
@GetMapping("/user")
public String findAll() {
return userMapper.findAll().toString();
}


//登录
@PostMapping("/login")
public User login(@RequestBody User user) {
User user1 = userMapper.findByUsername(user.getUsername());
if (user1 != null) {
if (user1.getPassword().equals(user.getPassword())) {
return user1;
}
}
return null;
}


//注册
@PostMapping("/register")
public User register(@RequestBody User user) {
User user1 = userMapper.findByUsername(user.getUsername());
if (user1 == null) {
userMapper.insert(user);
return user;
}
return null;
}

//删除账号(未测试)
@PostMapping("/delete")
public User delete(int userid) {
User user = userMapper.findById(userid);
if (user != null) {
userMapper.deleteById(userid);
return user;
}
return null;
}
}

创建Mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface UserMapper {

@Select("select * from t_user")
public List<User> findAll();

@Insert("insert into t_user (username, password) values (#{username}, #{password})")
public void insert(User user);

@Select("select * from t_user where username = #{username}")
public User findByUsername(String username);

@Select("select * from t_user where id = #{id}")
public User findById(Integer id);

@Delete("delete from t_user where id = #{id}")
public void deleteById(Integer id);
}

启动类中映射数据库

1
2
3
4
5
6
7
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

前端

前置条件:安装 nodejs

安装 Vue Cli

  • 创建 Vue 项目的脚手架
1
npm install -g @vue/cli

安装 Element UI

  • 页面组件
1
npm install element-plus --save

安装 Vue Router

  • 页面路由
1
npm install vue-router@4

安装 Axios

  • 将请求体转为 Json
1
npm install axios

创建 Vue 项目

1
vue create demo

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { createApp } from 'vue'
import App from './App.vue'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

import router from './router'

const app = createApp(App)

app.use(ElementPlus)
app.use(router)

app.mount('#app')

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { createRouter, createWebHistory } from 'vue-router'

import LoginComp from '@/components/LoginComp.vue'
import HelloWorld from "@/components/HelloWorld.vue"
import RegisterComp from "@/components/RegisterComp.vue"
import WelcomeView from "@/views/WelcomeView.vue"

const routes = [
{
path: '/',
component: WelcomeView,
children: [
{
path: '',
component: LoginComp
},
{
path: 'register',
component: RegisterComp
}
]
},

{ path: '/helloworld', component: HelloWorld},
];

const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;

LoginComp.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<template>
<div style="text-align: center;margin: 0 20px">
<div style="margin-top: 150px">
<div style="font-size: 25px;font-weight: bold">demo</div>
</div>
<div style="margin-top: 50px">
<el-form :model="loginForm">
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" placeholder="用户名/邮箱">
<template #prefix>
<el-icon><User /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" placeholder="密码">
<template #prefix>
<el-icon><Lock /></el-icon>
</template>
</el-input>
</el-form-item>
</el-form>
</div>
<div style="margin-top: 40px">
<el-button @click="login()" style="width: 270px" type="success" plain>立即登录</el-button>
</div>
<el-divider>
<span style="color: grey;font-size: 13px">没有账号</span>
</el-divider>
<div>
<el-button style="width: 270px" @click="router().push('/register')" type="warning" plain>注册账号</el-button>
</div>
</div>
</template>

<script>


import axios from 'axios'
import {User, Lock} from '@element-plus/icons-vue'
import router from "@/router";

export default {
components: {User, Lock},
data() {
return {
loginForm: {
username: '',
password: '',
},
};
},
methods: {
router() {
return router
},
login() {
axios({
method: 'post',
url: 'http://localhost:8088/login',
data: {
username: this.loginForm.username,
password: this.loginForm.password
}
})
.then(response => {
if (response.data) {
console.log('Login successful:', response.data);
this.$router.push('/helloworld');
} else {
console.error('Login failed:', 'Invalid credentials');
}
})
.catch(error => {
console.error('Login failed:', error);
})
}
},
};
</script>

<style>

</style>

RegisterComp.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<template>
<div style="text-align: center;margin: 0 20px">
<div style="margin-top: 100px">
<div style="font-size: 25px;font-weight: bold">注册新用户</div>
</div>
<div style="margin-top: 50px">
<el-form :model="signupForm">
<el-form-item prop="username">
<el-input v-model="signupForm.username" :maxlength="8" type="text" placeholder="用户名">
<template #prefix>
<el-icon><User /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="signupForm.password" :maxlength="16" type="password" placeholder="密码">
<template #prefix>
<el-icon><Lock /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password_repeat">
<el-input v-model="signupForm.password_repeat" :maxlength="16" type="password" placeholder="重复密码">
<template #prefix>
<el-icon><Lock /></el-icon>
</template>
</el-input>
</el-form-item>
</el-form>
</div>
<div style="margin-top: 80px">
<el-button style="width: 270px" type="warning" @click="register" plain>立即注册</el-button>
</div>
<div style="margin-top: 20px">
<span style="font-size: 14px;line-height: 15px;color: grey">已有账号? </span>
<el-link type="primary" style="translate: 0 -2px" @click="router().push('/')">立即登录</el-link>
</div>
</div>
</template>
<script>
import {EditPen, Lock, Message, User} from "@element-plus/icons-vue";
import axios from "axios";
import router from "@/router";

export default {
components: {EditPen, Lock, Message, User},
data() {
return {
signupForm: {
username: '',
password: '',
},
};
},
methods: {
router() {
return router
},
register() {
if (this.signupForm.password !== this.signupForm.password_repeat) {
this.$message({
message: '密码不一致',
type: "error"
});
console.error('Passwords do not match');
return;
}
axios({
method: 'post',
url: 'http://localhost:8088/register',
data: {
username: this.signupForm.username,
password: this.signupForm.password,
}
})
.then(response => {
if (response.data) {
console.log('Signup successful:', response.data);
this.$message({
message: '注册成功',
type: 'success'
});
this.$router.push('/');
} else {
console.error('Login failed:', 'Invalid credentials');
}
})
.catch(error => {
console.error('Login failed:', error);
})
}
},
};
</script>

WelcomeView.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<div style="width: 98vw;height: 98vh;overflow: hidden;display: flex;">
<div style="flex: 1">
<el-image style="width: 100%;height: 100%" fit="cover"
:src="require('../assets/wallhaven.jpg')"/>
</div>
<div class="welcome-title">
<div style="font-size: 30px;font-weight: bold">demo</div>
</div>
<div style="width: 400px;background-color: white;z-index: 1">
<router-view v-slot="{ Component }">
<transition name="el-fade-in-linear" mode="out-in">
<component :is="Component" style="height: 100%"/>
</transition>
</router-view>
</div>
</div>
</template>

<script>

</script>

<style scoped>
.welcome-title {
position: absolute;
bottom: 30px;
left: 30px;
color: white;
text-shadow: 0 0 10px black;
}
</style>

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<router-view></router-view>
</template>

<script>
export default {
name: 'App',
};
</script>

<style>
</style>

效果