一.概述
要为家教平台添加登录功能,建议先从后端开始,因为这样可以确保前端有一个明确的 API 进行交互,从而在开发前端时更容易进行调试和验证。
后端开发:
-
创建登录接口:
- 在后端创建一个 RESTful API,用于处理用户登录请求。
- 验证用户提交的登录号码和密码是否与数据库中的记录匹配。
-
后端验证流程:
- 接收请求:通过 POST 请求接收用户提交的登录号码和密码。
- 查询数据库:在数据库中查找对应的用户记录(通常使用 MyBatis 或 JPA)。
- 密码验证:比较提交的密码和数据库中存储的密码(注意:存储密码时应使用哈希加密,如 bcrypt)。
- 生成令牌:如果验证成功,生成并返回一个 JWT(JSON Web Token)或其他形式的令牌,用于后续的身份验证。
- 返回响应:返回登录结果(成功或失败)以及令牌(如果成功)。
-
后端代码:
- UserService 负责用户查询和密码验证逻辑。
- JWTTokenProvider 负责生成 JWT。
前端开发:
-
创建登录页面:
- 创建一个简单的登录页面,用户可以输入他们的登录号码和密码。
- 在用户点击“登录”按钮后,前端会向后端的登录接口发送请求。
-
前端验证流程:
- 表单验证:在提交之前,前端可以先进行简单的表单验证(例如,检查号码格式是否正确,密码是否为空等)。
- 发送请求:使用
axios
或fetch
向后端发送登录请求(POST 请求)。 - 处理响应:根据后端返回的响应,决定登录是否成功。如果成功,将收到的令牌存储在
localStorage
或sessionStorage
中,并重定向到主页面。 - 错误处理:如果登录失败,显示适当的错误信息给用户。
-
前端代码
验证:
- 后端验证:使用 Postman 或 cURL 来测试后端登录接口,确保它能够正确处理请求并返回预期的响应。
- 前端验证:在浏览器中测试登录页面,输入有效和无效的登录号码及密码,检查前端如何响应。
综合建议:
- 先写后端:确保后端登录逻辑和 API 接口正常工作,并返回正确的响应。
- 再写前端:开发登录页面并连接到后端 API,处理响应和错误显示。
二.后端编写:
User实体类:
package com.example.entity; import lombok.Data; @Data public class User { private Integer userId; private String userPhone; private String userPassword; }
UserMapper接口:
package com.example.mapper; import com.example.entity.User; public interface UserMapper { User selectByPhone1(String userPhone); }
UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--对应接口--> <mapper namespace="com.example.mapper.UserMapper"> <select id="selectByPhone1" resultType="com.example.entity.User"> select * from user_view where user_phone=#{userPhone} </select> </mapper>
UserService接口:
package com.example.service; import com.example.entity.User; public interface UserService { User selectByPhone2(String userPhone); //比较用户输入的密码和数据库中的密码 boolean checkPassword(String rawPassword, String storedPassword); }
UserServiceImpl实现类:
package com.example.service.impl; import com.example.entity.User; import com.example.mapper.UserMapper; import com.example.service.UserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class UserServiceImpl implements UserService { @Resource private UserMapper userMapper; @Override public User selectByPhone2(String userPhone) { User user = userMapper.selectByPhone1(userPhone); return user; } @Override public boolean checkPassword(String rawPassword, String storedPassword) { return rawPassword.equals(storedPassword); } }
UserController实现类:
package com.example.controller; //登录验证类 import com.example.config.ApiResponse; import com.example.entity.User; import com.example.service.UserService; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/auth") public class UserController { @Autowired private UserService userService; @PostMapping("/login") public ResponseEntity<ApiResponse<?>> login(@RequestBody LoginRequest loginRequest) { User user = userService.selectByPhone2(loginRequest.getPhoneNumber()); if (user != null && userService.checkPassword(loginRequest.getPassword(), user.getUserPassword())) { // 在实际应用中,你可能会生成并返回一个 JWT 或 session token return ResponseEntity.ok(ApiResponse.success("登录成功",user)); } else { return ResponseEntity.status(401).body(ApiResponse.error("登录失败")); } } // 登录请求的内部类 @Data public static class LoginRequest { private String phoneNumber; private String password; } }
三.使用postman进行后端验证:
四.前端代码编写:
Login.vue:
<template> <div class="login-container"> <h2>登录界面</h2> <form @submit.prevent="login"> <div class="form-group"> <label for="phoneNumber">账号:</label> <input type="text" id="phoneNumber" v-model="phoneNumber" placeholder="请输入登录账号" required /> </div> <div class="form-group"> <label for="password">密码:</label> <input type="password" id="password" v-model="password" placeholder="请输入密码" required /> </div> <button type="submit">登录</button> </form> <p v-if="errorMessage" class="error">{{ errorMessage }}</p> </div> </template> <script> import axios from 'axios'; export default { data() { return { phoneNumber: '', password: '', errorMessage: null, }; }, methods: { async login() { try { // console.log('发送的手机号:', this.phoneNumber); // console.log('发送的密码:', this.password); const response = await axios.post('http://localhost:8081/api/auth/login', { phoneNumber: this.phoneNumber, password: this.password, }); // console.log('后端返回的响应:', response.data); if (response.data.success) { // 登录成功,触发父组件的登录成功事件 this.$emit('login-success'); alert(response.data.message); } else { this.errorMessage = response.data.message; } } catch (error) { this.errorMessage = '登录失败,请检查账号和密码。'; } }, }, }; </script> <style scoped> .login-container { max-width: 400px; margin: 50px auto; padding: 20px; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input[type="text"], input[type="password"] { width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px; } button { width: 100%; padding: 10px; background-color: #007bff; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; } button:hover { background-color: #0056b3; } .error { color: red; margin-top: 15px; text-align: center; } </style>
App.vue:
<template> <div> <el-container v-if="isLoggedIn" style="height: 100%;"> <el-header style="width: 100% ;padding: 0"> <Header /> </el-header> <div class="divider"></div> <!-- 分割线 --> <el-container style="width: 100%"> <el-aside width="200px"> <Sidebar @select="updateContent" /> </el-aside> <el-main> <Content :selectedSection="selectedSection" /> </el-main> </el-container> </el-container> <div v-else> <Login @login-success="handleLoginSuccess" /> </div> </div> </template> <script> import Header from './components/Header.vue'; import Sidebar from './components/Sidebar.vue'; import Content from './components/Content.vue'; import Login from './components/Login.vue'; export default { components: { Header, Sidebar, Content, Login, }, data() { return { selectedSection: '1', isLoggedIn: false, // 登录状态 }; }, methods: { updateContent(index) { this.selectedSection = index; }, handleLoginSuccess() { this.isLoggedIn = true; // 登录成功后更新状态 } } }; </script> <style> body, html, #app { margin: 0; padding: 0; height: 100%; } .divider { height: 1px; background-color: #e0e0e0; /* 分割线颜色,可以根据需要调整 */ margin: 0; } </style>
出现的问题及学到的方法:
1.一直显示登录失败,原因是前端url选择错误(应使用http://localhost:/api/auth/login')完整路径
2.可以在前后端输出数据进行错误检验:
3.侧边栏及主体大小不固定,添加CSS样式进行修改:
<style> .sidebar { height: 100vh; border-right: none; display: flex; flex-direction: column; } .el-menu { flex: 1; border-right: none !important; /* 强制移除右侧边框 */ } </style>标签:vue,springboot,登录,User,import,家教,com,example,String From: https://blog.csdn.net/2301_77613763/article/details/141596437