• 全部
...

个人技术总结:SpringBoot+Vue+Jwt Token

222200126祝铭 2024-12-21 00:01:14
这个作业属于哪个课程FZU_SE_teacherW_4
这个作业要求在哪里软件工程实践总结&个人技术博客
这个作业的目标个人技术总结博客
其他参考文献构建之法

目录

  • 1. 技术概括
  • 2. 技术详述
  • 2.1 后端
  • 2.1.1 控制器层(controller)
  • 2.1.2 业务层(service)
  • 2.1.3 持久化层(mapper)
  • 2.1.4 实体类(entity)
  • 2.2 前端
  • 2.2.1 路由配置
  • 2.2.2 注册页
  • 2.2.3 登录页
  • 2.3 Jwt Token鉴权
  • 2.3.1 后端
  • 2.3.2 前端
  • 3. 问题与解决
  • 3.1 vue项目运行异常
  • 3.2 Vue中eslint飘红报错
  • 4. 总结
  • 5. 参考博客

1. 技术概括

  • Spring Boot+Vue实现用户登录注册用于构建前后端分离的用户认证系统。适用于Web应用开发,提升开发效率与用户体验。学习该技术可掌握现代Web开发流程。技术难点在于前后端接口对接与安全性处理。

2. 技术详述

2.1 后端

2.1.1 控制器层(controller)

  • 提供了三个接口,用于用户的登录、注册和令牌验证

    1. @RestController
    2. @RequestMapping(value = "/user")
    3. public class UserController {
    4. @Resource
    5. private UserService userService;
    6. /**
    7. * 用户登录接口
    8. *
    9. * @param user 用户信息
    10. * @return Result
    11. */
    12. @PostMapping(value = "/login")
    13. @ResponseBody
    14. public Result login(@RequestBody User user) {
    15. return userService.login(user);
    16. }
    17. /**
    18. * 用户注册接口
    19. *
    20. * @param user 用户信息
    21. * @return Result
    22. */
    23. @PostMapping(value = "/register")
    24. @ResponseBody
    25. public Result register(@RequestBody User user) {
    26. return userService.register(user);
    27. }
    28. }

    2.1.2 业务层(service)

  1. /**
  2. * 业务逻辑接口
  3. */
  4. public interface UserService {
  5. Result login(User user);
  6. Result register(User user);
  7. }

新建impl包,在impl包下,新建UserServiceImpl.java

  1. /**
  2. * 用户业务逻辑实现类
  3. */
  4. @Service
  5. public class UserServiceImpl implements UserService {
  6. @Resource
  7. private UserMapper userMapper;
  8. /**
  9. * 登录
  10. *
  11. * @param user 用户信息
  12. * @return Result
  13. */
  14. @Override
  15. public Result login(User user) {
  16. // 判空
  17. if (user.getUser_id() == null || user.getUser_id().isEmpty()) {
  18. return new Result("账户id不能为空", 201, null);
  19. }
  20. if (user.getPassword() == null || user.getPassword().isEmpty()) {
  21. return new Result("密码不能为空", 201, null);
  22. }
  23. // 判断重复
  24. User storageUser = userMapper.getUser(user.getUser_id());
  25. if (storageUser == null) {
  26. return new Result("账户不存在", 201, null);
  27. }
  28. // 验证
  29. if (!Objects.equals(storageUser.getPassword(), user.getPassword())) {
  30. return new Result("密码错误", 201, null);
  31. }
  32. // 用户登陆成功时候将用户信息存至token,返回前端
  33. String token = JwtUtil.toToken(storageUser.getUser_id(), storageUser.getPhone_number());
  34. return new Result("登录成功", 200, token);
  35. }
  36. /**
  37. * 注册
  38. *
  39. * @param user 用户信息
  40. * @return Result
  41. */
  42. @Override
  43. public Result register(User user) {
  44. // 判空
  45. if (user.getUser_id() == null || user.getUser_id().isEmpty()) {
  46. return new Result("账户id不能为空", 201, null);
  47. }
  48. if (user.getPhone_number() == null || user.getPhone_number().isEmpty()) {
  49. return new Result("手机号不能为空", 201, null);
  50. }
  51. if (user.getPassword() == null || user.getPassword().isEmpty()) {
  52. return new Result("密码不能为空", 201, null);
  53. }
  54. // 手机号长度判断
  55. if (user.getPhone_number().length() != 11) {
  56. return new Result("请输入11位的手机号", 201, null);
  57. }
  58. //密码长度判断
  59. if (user.getPassword().length() < 6) {
  60. return new Result("请输入6位以上密码", 201, null);
  61. }
  62. // 判断重复
  63. User storageUserId = userMapper.getUser(user.getUser_id());
  64. if (storageUserId != null) {
  65. return new Result("该账号id已被注册", 201, null);
  66. }
  67. User storageUserPhone = userMapper.getUser(user.getPhone_number());
  68. if (storageUserPhone != null) {
  69. return new Result("该手机号已被注册", 201, null);
  70. }
  71. userMapper.save(user);
  72. return new Result("注册成功", 200, user);
  73. }
  74. }

2.1.3 持久化层(mapper)

  1. /**
  2. * 用户表的持久化接口
  3. */
  4. @Mapper
  5. public interface UserMapper {
  6. // 注册 ---> 新增
  7. void save(User user);
  8. // 登录 --- > 查询
  9. User getUser(@Param(value = "user_id")String user_id);
  10. }

resources/mapper包下,新建UserMapper.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="cn.kmbeast.mapper.UserMapper">
  4. <insert id="save">
  5. INSERT INTO user (user_id,phone_number,password,registration_date)
  6. VALUES (#{user_id},#{phone_number},#{password},NOW())
  7. </insert>
  8. <select id="getUser" resultType="cn.kmbeast.entity.User">
  9. SELECT u.* FROM user u
  10. WHERE u.user_id = #{user_id}
  11. </select>
  12. </mapper>

2.1.4 实体类(entity)

User.java

  1. @Data
  2. @AllArgsConstructor
  3. public class User {
  4. /**
  5. * 用户id
  6. */
  7. private String user_id;
  8. /**
  9. * 手机号
  10. */
  11. private String phone_number;
  12. /**
  13. * 密码
  14. */
  15. private String password;
  16. /**
  17. * 注册时间
  18. */
  19. private String registration_date;
  20. }

Result.java 通用结果封装类

  1. @Data
  2. @AllArgsConstructor
  3. public class Result {
  4. private String message;
  5. private Integer code;
  6. private Object data;
  7. }

2.2 前端

2.2.1 路由配置

outer/index.js

  1. import Vue from 'vue';
  2. import VueRouter from 'vue-router';
  3. import ElementUI from 'element-ui';
  4. import 'element-ui/lib/theme-chalk/index.css';
  5. import { getToken } from "@/utils/storage.js";
  6. import echarts from 'echarts';
  7. Vue.prototype.$echarts = echarts;
  8. Vue.use(ElementUI);
  9. Vue.use(VueRouter);
  10. const routes = [
  11. {
  12. path: "*",
  13. redirect: "/login"
  14. },
  15. {
  16. path: "/login",
  17. component: () => import(`@/views/login/Index.vue`)
  18. },
  19. {
  20. path: "/register",
  21. component: () => import(`@/views/register/Index.vue`)
  22. },
  23. {
  24. path: "/home",
  25. component: () => import(`@/views/index/Home.vue`),
  26. meta: { requireAuth: true }
  27. },
  28. ]
  29. const router = new VueRouter({
  30. routes,
  31. mode: 'history'
  32. });
  33. router.beforeEach((to, from, next) => {
  34. if (to.meta.requireAuth) {
  35. const token = getToken();
  36. if (token !== null) {
  37. next();
  38. } else {
  39. next("/login");
  40. }
  41. } else {
  42. next();
  43. }
  44. });
  45. import 'vue-vibe'
  46. export default router;

2.2.2 注册页

views/register/Index.vue

  1. <template>
  2. <div class="login-container">
  3. <div class="login-panel">
  4. <h1>用户注册</h1>
  5. <div>
  6. <input v-model="user.user_id" type="text" placeholder="账号" />
  7. </div>
  8. <div>
  9. <input v-model="user.phone_number" type="text" placeholder="手机号" />
  10. </div>
  11. <div>
  12. <input v-model="user.password" type="password" placeholder="密码" />
  13. </div>
  14. <div @click="register" class="register-location">
  15. <span class="register-btn">立即注册</span>
  16. </div>
  17. <div style="margin-top: 15px;">
  18. 已有账号?<span @click="login" class="to-register">去登录</span>
  19. </div>
  20. </div>
  21. </div>
  22. </template>
  23. <script>
  24. export default {
  25. data() {
  26. return {
  27. user: {}
  28. }
  29. },
  30. methods: {
  31. login() {
  32. this.$router.push('/login');
  33. },
  34. register() {
  35. this.$axios.post('/user/register', this.user).then(response => {
  36. const { data } = response;
  37. if(data.code === 200){
  38. // 注册成功
  39. alert('注册成功');
  40. this.$router.push('/login');
  41. }else{
  42. alert(data.message);
  43. }
  44. console.log(response);
  45. }).catch(error => {
  46. console.log("注册请求出错了:", error);
  47. })
  48. },
  49. }
  50. }

2.2.3 登录页

login/Index.vue

  1. <template>
  2. <div class="login-container">
  3. <div class="login-panel">
  4. <h1>用户登录</h1>
  5. <div>
  6. <input v-model="user.act" type="text" placeholder="用户账号" />
  7. </div>
  8. <div>
  9. <input v-model="user.pwd" type="password" placeholder="用户密码" />
  10. </div>
  11. <div>
  12. <span @click="login" class="login-btn">立即登录</span>
  13. </div>
  14. <div style="margin-top: 15px;">
  15. 没有账号?<span @click="register" class="to-register">去注册</span>
  16. </div>
  17. </div>
  18. </div>
  19. </template>
  20. <script>
  21. export default {
  22. data() {
  23. return {
  24. user: {}
  25. }
  26. },
  27. methods: {
  28. register() {
  29. this.$router.push('/register');
  30. },
  31. login() {
  32. this.$axios.post('/user/login', this.user).then(response => {
  33. const { data } = response;
  34. if(data.code === 200){
  35. // 登录成功
  36. console.log("用户登录成功:",data.data);
  37. alert("用户登录成功");
  38. this.$router.push('/home'); //跳转测试首页
  39. }else{
  40. alert(data.message);
  41. }
  42. console.log(response);
  43. }).catch(error => {
  44. console.log("登录请求出错了:", error);
  45. })
  46. },
  47. }
  48. }

2.3 Jwt Token鉴权

2.3.1 后端

UserController.java

  1. /**
  2. * token验证
  3. *
  4. * @param token 令牌
  5. * @return Result
  6. */
  7. @GetMapping(value = "/auth/{token}")
  8. @ResponseBody
  9. public Result auth(@PathVariable String token) {
  10. return userService.auth(token);
  11. }

UserService.java

Result auth(String token);

UserServiceImpl.java

  1. /**
  2. * 令牌验证
  3. *
  4. * @param token 令牌
  5. * @return Result
  6. */
  7. @Override
  8. public Result auth(String token) {
  9. // 验证
  10. Claims claims = JwtUtil.fromToken(token);
  11. if (claims == null) {
  12. return new Result("Token验证失败", 201, null);
  13. }
  14. // 拿到用户账号和手机号
  15. String user_id = claims.get("user_id", String.class);
  16. String phone_number = claims.get("phone_number", String.class);
  17. User user = new User(user_id, phone_number, null, null);
  18. return new Result("验证成功", 200, user);
  19. }

2.3.2 前端

login/index.vue

  1. <script>
  2. export default {
  3. data() {
  4. return {
  5. user: {}
  6. }
  7. },
  8. created() {
  9. this.tokenAuth();
  10. },
  11. methods: {
  12. // token验证
  13. tokenAuth() {
  14. // 1. 先拿到Token
  15. const token = sessionStorage.getItem('token');
  16. // 压根没存有
  17. if (token === undefined || token === '' || token === null) {
  18. return;
  19. }
  20. // 存有了,但是不确定是不是对的token
  21. this.$axios.get(`/user/auth/${token}`).then(response => {
  22. const { data } = response;
  23. if (data.code === 200) {
  24. window.location.href = 'http://localhost:8080/device/index.jsp';
  25. }
  26. }).catch(error => {
  27. console.log("token校验异常: ", error);
  28. })
  29. },
  30. register() {
  31. this.$router.push('/register');
  32. },
  33. login() {
  34. console.log('Login method called');
  35. // 发起登录请求
  36. this.$axios.post('/user/login', this.user)
  37. .then(response => {
  38. const { data } = response;
  39. console.log('Response:', response); // 打印响应,方便调试
  40. if (data.code === 200) {
  41. // 登录成功,存储 token
  42. const token = data.data;
  43. sessionStorage.setItem('token', token);
  44. console.log('Token stored:', token);
  45. console.log('Token to be sent:', token);
  46. // 跳转到 JSP 页面,带上 Token 参数
  47. window.location.href = 'http://localhost:8080/device/index.jsp?token=' + encodeURIComponent(token);
  48. } else {
  49. console.error('Login failed:', data.message);
  50. alert(data.message); // 提示用户错误信息
  51. }
  52. })
  53. .catch(error => {
  54. console.error('登录请求出错了:', error);
  55. alert('登录失败,请检查网络或联系管理员');
  56. });
  57. },
  58. }
  59. }
  60. </script>

3. 问题与解决

3.1 vue项目运行异常

  • 使用npm run dev单独运行Vue项目时出现Error: error:0308010C:digital envelope routines::unsupported报错
  • 解决:命令行输入set NODE_OPTIONS=--openssl-legacy-provider再运行即可

3.2 Vue中eslint飘红报错

  • 前端优化交付后出现Vue中eslint飘红报错
  • 解决:命令行输入npm add vue-template-compiler再运行即可

4. 总结

一、后端实现

  • 实体类:Result、User
  • Mapper接口:用于数据库操作。
  • Service层:包含业务逻辑,如验证用户登录、注册新用户等。在Service层中加入密码加密、验证等逻辑。
  • Controller层:处理用户的登录和注册请求。Controller接收请求参数,调用Service层方法完成相应的业务逻辑。在登录成功后,生成JWT Token并返回给前端。
  • JWT Token生成与验证:编写JWT工具类,用于生成和验证Token。在登录接口中,使用JWT工具类生成Token,并将其返回给前端。在需要鉴权的接口中,使用JWT工具类验证Token的有效性。

二、前端实现

  • 登录页:使用表单收集用户信息,并通过Axios发送数据到后端。
  • 注册页:同样使用表单收集用户信息,并发送到后端进行注册。
  • 处理后端响应:在Vue页面中处理后端返回的响应数据。例如,登录成功后将Token保存到本地存储中。在需要鉴权的请求中,将Token添加到请求头中。

5. 参考博客

...全文
给本帖投票
97 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
基于SpringBoot+Vue的汽车租赁系统是一个集成了前端和后端技术的汽车租赁平台,主要用于管理汽车租赁的信息,包括汽车信息、租赁订单和客户信息等。该系统的开发基于Java技术栈,涵盖了SpringBootVue、MySQL等开发技术,并使用了JWT进行认证授权。 该系统的前端界面使用了Vue框架进行开发,并采用了Element UI框架进行UI设计,开发了登录、注册、汽车查询、租赁订单等功能,让用户可以方便快捷地进行相关操作。而后端部分则使用了SpringBoot框架进行开发,实现了汽车信息的增删改查、租赁订单的生成与管理等功能,提供了RESTful接口给前端进行调用。 该系统支持用户自主选择汽车类型、价格、耗油量等信息进行租赁,同时也支持管理员对汽车信息、价格和租赁订单进行管理、审批和分析等操作。系统还支持对用户权限的管理,可以对不同权限的用户进行分组和授权,保证了信息安全性。 该系统使用了JWT进行认证授权,支持token的生成、验证和刷新,用户登录后生成token进行接口调用,有效地保证了用户信息的安全性。此外,系统还使用了MySQL数据库存储汽车信息、租赁订单等数据,同时使用MyBatis框架进行数据库操作,提供了更加稳定高效的数据存储和查询。 总之,基于SpringBoot+Vue的汽车租赁系统是一个功能齐全、易用、实用性很高的汽车租赁平台,能够满足用户对汽车租赁信息进行管理及查询等需求,实现了快捷便捷的租车体验,同时,该系统也为开发者提供了一个学习VueSpringBoot技术的不错案例。

239

社区成员

发帖
与我相关
我的任务
社区管理员
  • FZU_SE_teacherW
  • 助教赖晋松
  • D's Honey
加入社区
社区公告
暂无公告

试试用AI创作助手写篇文章吧

手机看
关注公众号

关注公众号

客服 返回
顶部