该实战教程旨在通过前后端分离的方式,构建一个基于Spring Boot后端与Vue.js前端的登录系统。首先,创建并启动Spring Boot项目作为后端服务,确保能正常访问首页。接着,搭建前端项目,利用Vue CLI创建Vue应用,安装axios以处理HTTP请求,vue-router实现页面路由跳转,less和less-loader支持样式预编译。在IDEA中打开Vue项目后,分别创建登录和首页组件,并配置路由视图。编写应用根组件及主入口脚本,设置反向代理解决跨域问题,完成前端开发后访问登录页面。
同时,在后端进行相应开发,创建用户实体类和结果实体类来封装数据模型,设计登录控制器处理前端发来的登录请求。配置服务器端口号以便于部署运行。
最后,整合测试阶段,分别启动前端login-vue项目和后端LoginDemo项目,通过前端界面发起登录请求至后端接口,验证用户登录功能是否正确实现。整个过程涵盖了从项目创建到前后端交互测试的全流程实践。
设置项目名称 LoginDemo
、保存位置、语言、类型、组标识、构件名、包名、JDK版本、Java语言级、打包类型
单击【Next】按钮,在弹出的对话框里选择Spring Boot版本,添加项目相关依赖
单击【Create】按钮,得到初始化项目
LoginDemoApplication
http://localhost:8080
,弹出错误页面resources
目录里创建首页index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h3 style="text-align: center; color: red">Welcome to Spring Boot World~</h3>
</body>
</html>
LoginDemoApplication
代码http://localhost:8080
,查看结果nmp install -g @vue/cli
vue create login-vue
,选择Default ([Vue 3] babel, eslint)login-vue
目录,执行命令:npm install axios --save
npm install vue-router@4 --save
npm install --save-dev less less-loader
npm run serve
http://local:8080
login-vue
src/components
目录里,删除HelloWorld.vue
组件,创建LoginView.vue
组件<template>
<table class="login-table" border="0" cellpadding="10">
<tr>
<td align="center">用户名</td>
<td><input id='username' type="text" v-model="username" placeholder="请输入用户名"/></td>
</tr>
<tr>
<td align="center">密 码</td>
<td><input id='password' type="password" v-model="password" placeholder="请输入密码"/></td>
</tr>
<tr align="center">
<td colspan="2">
<button @click="handleLogin">登录</button>
</td>
</tr>
</table>
</template>
<script setup>
import {ref} from 'vue';
import {useRouter} from 'vue-router';
import axios from "axios";
const router = useRouter();
const username = ref('');
const password = ref('');
async function handleLogin() {
try {
const response = await axios.post('/api/login', {username: username.value, password: password.value});
console.log(response.data.code)
if (response.data.code === 200) {
router.replace('/index'); // 使用后端返回的路径
} else if (response.data.code === 400) {
alert('用户名或密码错误!请重新登录!');
username.value = '';
password.value = '';
document.getElementById('username').focus();
}
} catch (error) {
console.error("Error during login:", error.message); // 添加错误处理,打印错误信息
}
}
</script>
<style lang="less" scoped>
/* 重置table样式 */
.login-table {
width: 100%;
max-width: 300px;
margin: 50px auto;
border-collapse: collapse;
border-spacing: 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.login-table td {
padding-bottom: 16px;
padding-top: 16px;
padding-right: 0px;
padding-right: 8px;
vertical-align: middle;
text-align: left;
border-bottom: 1px solid #ddd;
}
.login-table input[type="text"],
.login-table input[type="password"] {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
outline: none;
box-sizing: border-box;
}
.login-table button {
display: block;
width: 100%;
padding: 12px;
background-color: #007bff;
color: white;
font-size: 16px;
border: none;
border-radius: 4px;
cursor: pointer;
text-align: center;
transition: all 0.3s ease;
&:hover,
&:focus {
background-color: #0056b3;
}
}
</style>
src/components
里创建IndexView.vue
组件<template>
<div class="welcome-container">
Welcome to Vue 3 World~
</div>
</template>
<script>
export default {
name: "IndexView"
}
</script>
<style scoped>
.welcome-container {
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #f5f5f5;
text-align: center;
max-width: 400px;
margin: 0 auto;
color: red;
font-weight: bold;
font-size: 30px;
}
</style>
IndexView
,渲染一个居中显示的欢迎信息框,样式包括内边距、边框、背景色等,并通过CSS设置了自动水平居中布局及字体样式。src
里创建router
目录,在router
目录里创建index.js
脚本// 引入Vue3以及新的vue-router
import { createRouter, createWebHistory } from 'vue-router';
import Login from '@/components/LoginView.vue';
import Index from "@/components/IndexView.vue";
// 定义路由
const routes = [
{
path: '/login',
name: 'LoginView',
component: Login
},
{
path: '/index',
name: 'IndexView',
component: Index
}
];
// 创建路由器实例
const router = createRouter({
history: createWebHistory(),
routes,
});
// 导出全局注册
export default router;
App.vue
是 Vue.js 应用程序的根组件,负责整个应用的布局与整体结构,所有其他组件在其内部组织和渲染。<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<router-view />
</div>
</template>
<script>
</script>
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
<router-view/>
)。样式设置字体、抗锯齿及居中对齐。main.js
是Vue应用的主入口脚本,负责初始化Vue应用实例、注册全局组件与插件(如路由、状态管理等),并挂载到DOM指定元素。// 导入Vue3的核心API,用于创建Vue应用实例
import {createApp} from 'vue';
// 导入根组件App.vue,它是整个应用程序的主视图模板
import App from './App.vue';
// 导入已配置好的路由模块(index.js或router.ts等),它管理着应用内的页面跳转逻辑
import router from "@/router";
// 使用createApp方法创建一个Vue应用实例,并注册全局路由配置
const app = createApp(App).use(router);
// 将Vue应用挂载到HTML文档中id为'app'的元素上
// 这将把整个应用程序渲染到这个DOM元素内部
app.mount('#app');
createApp
初始化应用并注册路由,最后将整个应用挂载到DOM中id为’app’的元素上。vue.config.js
代码,设置反向代理和跨域支持module.exports = {
// 设置在保存文件时禁用ESLint自动检查
lintOnSave: false,
// 配置Vue开发服务器相关选项
devServer: {
// 配置HTTP代理,以便在开发过程中将特定请求转发到其他服务器
proxy: {
// 当请求以 '/api' 开头时进行代理
'/api': {
// 指定目标服务器地址(例如后台API接口)
target: 'http://localhost:8888',
// 设置为true,允许跨域请求时重写源信息(Origin header)
changeOrigin: true,
// 路径重写规则,将前端应用中'/api'前缀去掉,映射到后端服务器的实际路径上
pathRewrite: { '^/api': '' },
}
}
}
}
/api
开头的请求时,该请求会被代理至http://localhost:8888
服务器,并通过pathRewrite
规则进行路径重写,解决前后端分离开发中的跨域问题。http://localhost:8080/login
bean
子包,在子包里创建User
类package net.huawei.login.bean;
/**
* 功能:用户实体类
* 作者:华卫
* 日期:2024年01月14日
*/
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
result
子包,在子包里创建Result
类,封装响应码package net.huawei.login.result;
/**
* 功能:结果实体类
* 作者:华卫
* 日期:2024年01月14日
*/
public class Result {
private int code;
public Result(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
controller
子包,在子包里创建LoginController
类package net.huawei.login.controller;
import net.huawei.login.bean.User;
import net.huawei.login.result.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.HtmlUtils;
/**
* 功能:登录控制器
* 作者:华卫
* 日期:2024年01月14日
*/
@Controller
public class LoginController {
@CrossOrigin
@PostMapping(value = "api/login")
@ResponseBody
public Result login(@RequestBody User requestUser) {
// 获取用户名和密码
String username = requestUser.getUsername();
String password = requestUser.getPassword();
// 对html标签进行转义,防止XSS攻击
username = HtmlUtils.htmlEscape(username);
// 判断登录是否成功
if (username.equals("无心剑") && password.equals("903213")) {
return new Result(200);
} else {
System.out.println("用户名或密码有误!");
return new Result(400);
}
}
}
在前端项目里配置了目标服务器地址,端口是8888
在应用属性文件application.properties
里配置服务器端口号
npm run serve
LoginDemoApplication
访问http://localhost:8080/login
登录页面
如果输入的用户名或密码有误,弹出消息框提示用户
输入正确的用户名或密码(无心剑 :903213)
单击【登录】按钮,跳转到首页
操作录屏演示