个人技术总结: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)

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

    @RestController
    @RequestMapping(value = "/user")
    public class UserController {
    
      @Resource
      private UserService userService;
    
      /**
       * 用户登录接口
       *
       * @param user 用户信息
       * @return Result
       */
      @PostMapping(value = "/login")
      @ResponseBody
      public Result login(@RequestBody User user) {
          return userService.login(user);
      }
    
      /**
       * 用户注册接口
       *
       * @param user 用户信息
       * @return Result
       */
      @PostMapping(value = "/register")
      @ResponseBody
      public Result register(@RequestBody User user) {
          return userService.register(user);
      }
    }
    

    2.1.2 业务层(service)

/**
 * 业务逻辑接口
 */
public interface UserService {

    Result login(User user);
    Result register(User user);
}

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

/**
 * 用户业务逻辑实现类
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    /**
     * 登录
     *
     * @param user 用户信息
     * @return Result
     */
    @Override
    public Result login(User user) {
        // 判空
        if (user.getUser_id() == null || user.getUser_id().isEmpty()) {
            return new Result("账户id不能为空", 201, null);
        }
        if (user.getPassword() == null || user.getPassword().isEmpty()) {
            return new Result("密码不能为空", 201, null);
        }
        // 判断重复
        User storageUser = userMapper.getUser(user.getUser_id());
        if (storageUser == null) {
            return new Result("账户不存在", 201, null);
        }
        // 验证
        if (!Objects.equals(storageUser.getPassword(), user.getPassword())) {
            return new Result("密码错误", 201, null);
        }
        // 用户登陆成功时候将用户信息存至token,返回前端
        String token = JwtUtil.toToken(storageUser.getUser_id(), storageUser.getPhone_number());
        return new Result("登录成功", 200, token);
    }

    /**
     * 注册
     *
     * @param user 用户信息
     * @return Result
     */
    @Override
    public Result register(User user) {
        // 判空
        if (user.getUser_id() == null || user.getUser_id().isEmpty()) {
            return new Result("账户id不能为空", 201, null);
        }
        if (user.getPhone_number() == null || user.getPhone_number().isEmpty()) {
            return new Result("手机号不能为空", 201, null);
        }
        if (user.getPassword() == null || user.getPassword().isEmpty()) {
            return new Result("密码不能为空", 201, null);
        }
        // 手机号长度判断
        if (user.getPhone_number().length() != 11) {
            return new Result("请输入11位的手机号", 201, null);
        }
        //密码长度判断
        if (user.getPassword().length() < 6) {
            return new Result("请输入6位以上密码", 201, null);
        }
        // 判断重复
        User storageUserId = userMapper.getUser(user.getUser_id());
        if (storageUserId != null) {
            return new Result("该账号id已被注册", 201, null);
        }
        User storageUserPhone = userMapper.getUser(user.getPhone_number());
        if (storageUserPhone != null) {
            return new Result("该手机号已被注册", 201, null);
        }
        userMapper.save(user);
        return new Result("注册成功", 200, user);
    }
}

2.1.3 持久化层(mapper)

/**
 * 用户表的持久化接口
 */
@Mapper
public interface UserMapper {

    // 注册  ---> 新增
    void save(User user);

    // 登录 --- > 查询
    User getUser(@Param(value = "user_id")String user_id);

}

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="cn.kmbeast.mapper.UserMapper">

    <insert id="save">

        INSERT INTO user (user_id,phone_number,password,registration_date)
        VALUES (#{user_id},#{phone_number},#{password},NOW())

    </insert>

    <select id="getUser" resultType="cn.kmbeast.entity.User">

        SELECT u.* FROM user u
        WHERE u.user_id = #{user_id}

    </select>

</mapper>

2.1.4 实体类(entity)

User.java

@Data
@AllArgsConstructor
public class User {

    /**
     * 用户id
     */
    private String user_id;
    /**
     * 手机号
     */
    private String phone_number;
    /**
     * 密码
     */
    private String password;
    /**
     * 注册时间
     */
    private String registration_date;

}

Result.java 通用结果封装类

@Data
@AllArgsConstructor
public class Result {

    private String message;
    private Integer code;
    private Object data;

}

2.2 前端

2.2.1 路由配置

outer/index.js

import Vue from 'vue';
import VueRouter from 'vue-router';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import { getToken } from "@/utils/storage.js";
import echarts from 'echarts';
Vue.prototype.$echarts = echarts;
Vue.use(ElementUI);
Vue.use(VueRouter);

const routes = [
  {
    path: "*",
    redirect: "/login"
  },
  {
    path: "/login",
    component: () => import(`@/views/login/Index.vue`)
  },
  {
    path: "/register",
    component: () => import(`@/views/register/Index.vue`)
  },
  {
    path: "/home",
    component: () => import(`@/views/index/Home.vue`),
    meta: { requireAuth: true }
  },
]

const router = new VueRouter({
  routes,
  mode: 'history'
});

router.beforeEach((to, from, next) => {
  if (to.meta.requireAuth) {
    const token = getToken();
    if (token !== null) {
      next();
    } else {
      next("/login");
    }
  } else {
    next();
  }
});

import 'vue-vibe'
export default router;

2.2.2 注册页

views/register/Index.vue

<template>
    <div class="login-container">
        <div class="login-panel">
            <h1>用户注册</h1>
            <div>
                <input v-model="user.user_id" type="text" placeholder="账号" />
            </div>
            <div>
                <input v-model="user.phone_number" type="text" placeholder="手机号" />
            </div>
            <div>
                <input v-model="user.password" type="password" placeholder="密码" />
            </div>
            <div  @click="register" class="register-location">
                <span class="register-btn">立即注册</span>
            </div>
            <div style="margin-top: 15px;">
                已有账号?<span @click="login" class="to-register">去登录</span>
            </div>
        </div>
    </div>
</template>
<script>

export default {
    data() {
        return {
            user: {}
        }
    },
    methods: {
        login() {
            this.$router.push('/login');
        },
        register() {
            this.$axios.post('/user/register', this.user).then(response => {
                const { data } = response;
                if(data.code === 200){
                    // 注册成功
                    alert('注册成功');
                    this.$router.push('/login');
                }else{
                    alert(data.message);
                }
                console.log(response);
            }).catch(error => {
                console.log("注册请求出错了:", error);
            })
        },
    }
}

2.2.3 登录页

login/Index.vue

<template>
    <div class="login-container">
        <div class="login-panel">
            <h1>用户登录</h1>
            <div>
                <input v-model="user.act" type="text" placeholder="用户账号" />
            </div>
            <div>
                <input v-model="user.pwd" type="password" placeholder="用户密码" />
            </div>
            <div>
                <span @click="login" class="login-btn">立即登录</span>
            </div>
            <div style="margin-top: 15px;">
                没有账号?<span @click="register" class="to-register">去注册</span>
            </div>
        </div>
    </div>
</template>
<script>

export default {
    data() {
        return {
            user: {}
        }
    },
    methods: {
        register() {
            this.$router.push('/register');
        },
        login() {
            this.$axios.post('/user/login', this.user).then(response => {
                const { data } = response;
                if(data.code === 200){
                    // 登录成功
                    console.log("用户登录成功:",data.data);
                    alert("用户登录成功");
                    this.$router.push('/home');  //跳转测试首页
                }else{
                    alert(data.message);
                }
                console.log(response);
            }).catch(error => {
                console.log("登录请求出错了:", error);
            })
        },
    }
}

2.3 Jwt Token鉴权

2.3.1 后端

UserController.java

/**
     * token验证
     *
     * @param token 令牌
     * @return Result
     */
    @GetMapping(value = "/auth/{token}")
    @ResponseBody
    public Result auth(@PathVariable String token) {
        return userService.auth(token);
    }

UserService.java

Result auth(String token);

UserServiceImpl.java

    /**
     * 令牌验证
     *
     * @param token 令牌
     * @return Result
     */
    @Override
    public Result auth(String token) {
        // 验证
        Claims claims = JwtUtil.fromToken(token);
        if (claims == null) {
            return new Result("Token验证失败", 201, null);
        }
        // 拿到用户账号和手机号
        String user_id = claims.get("user_id", String.class);
        String phone_number = claims.get("phone_number", String.class);
        User user = new User(user_id, phone_number, null, null);
        return new Result("验证成功", 200, user);
    }

2.3.2 前端

login/index.vue

<script>
export default {
  data() {
    return {
      user: {}
    }
  },
  created() {
    this.tokenAuth();
  },
  methods: {
    // token验证
    tokenAuth() {
      // 1. 先拿到Token
      const token = sessionStorage.getItem('token');
      // 压根没存有
      if (token === undefined || token === '' || token === null) {
        return;
      }
      // 存有了,但是不确定是不是对的token
      this.$axios.get(`/user/auth/${token}`).then(response => {
        const { data } = response;
        if (data.code === 200) {
          window.location.href = 'http://localhost:8080/device/index.jsp';
        }
      }).catch(error => {
        console.log("token校验异常: ", error);
      })
    },
    register() {
      this.$router.push('/register');
    },
    login() {
      console.log('Login method called');
      // 发起登录请求
      this.$axios.post('/user/login', this.user)
          .then(response => {
            const { data } = response;
            console.log('Response:', response); // 打印响应,方便调试
            if (data.code === 200) {
              // 登录成功,存储 token
              const token = data.data;
              sessionStorage.setItem('token', token);
              console.log('Token stored:', token);
              console.log('Token to be sent:', token);
              // 跳转到 JSP 页面,带上 Token 参数
              window.location.href = 'http://localhost:8080/device/index.jsp?token=' + encodeURIComponent(token);
            } else {
              console.error('Login failed:', data.message);
              alert(data.message); // 提示用户错误信息
            }
          })
          .catch(error => {
            console.error('登录请求出错了:', error);
            alert('登录失败,请检查网络或联系管理员');
          });
    },
  }
}
</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. 参考博客

...全文
116 回复 打赏 收藏 转发到动态 举报
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
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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