博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
三天敲一个前后端分离的员工管理系统
阅读量:2113 次
发布时间:2019-04-29

本文共 22908 字,大约阅读时间需要 76 分钟。

文章目录

第一章、项目概述

人事管理系统是每个公司必备的管理系统,可以更方便的管理员工。

需求分析

hr实现对员工的增删改查,管理员实现对hr的更改。对员工进行搜索等功能。

总述

本项目是前后端分离项目,在服务器中运行。前端页面友好。

技术栈选择

  • 前端:vue3、vite2、axios、router、element UI 、nodejs
  • 后端:springboot、springsecurity、springdatajpa、maven、tomcat

环境介绍

  • 前端使用webstorm开发
  • 后端使用idea开发
  • 数据库使用MySQL8.0
  • 可视化工具使用Navicat
  • JDK版本:15
  • maven版本:3.6
  • tomcat版本:9.0
  • npm版本:7.17

效果图展示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

第二章、设计思路

该系统主要是前端设计页面接受后端的JSON数据,前后端所有数据除了登录页面使用key values 形式,其余全部使用JSON格式。后端使用springdatajpa自动生成的restful风格接口。前端通过axios发起请求获取接口数据。但是在开发中,我们需要克服跨域所带来的的问题。部署阶段就不存在跨域,因为我们会把前端打包到后端,一起部署。这样就不涉及到跨域问题了。当然也可以使用nigx进行代理。

数据库设计

在这里插入图片描述

数据表结构

员工表:

在这里插入图片描述

hr表:

在这里插入图片描述

角色表:

在这里插入图片描述

第三章、功能设计

  • hr登录
  • 权限鉴定
  • 对hr的增删改查
  • 对员工的增删改查

流程图

在这里插入图片描述

第四章、功能实现

后端功能实现

环境准备

在这里插入图片描述

添加springdata rest依赖

org.springframework.boot
spring-boot-starter-data-rest

目录结构

在这里插入图片描述

hr相关功能实现

登录功能

创建vhrdb数据库

在这里插入图片描述

配置jpa连接数据库

#配置数据库spring.datasource.url=jdbc:mysql://localhost:3306/vhrdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaispring.datasource.username=rootspring.datasource.password=123456#配置jpa#1.jpa数据库spring.jpa.database=mysql#2.在控制台打印sqlspring.jpa.show-sql=true#3.jpa数据库平台spring.jpa.database-platform=mysql#4.当对象改变更新表spring.jpa.hibernate.ddl-auto=update#5.指定方言!!!重要!!!spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect#.....

创建用户相关的表

  • 角色表

    package com.wz.vhrdb.entity;import javax.persistence.*;/** * @author: 王泽 */@Entity@Table(name = "t_role")public class Role {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String nameZh; //角色的中文名 public Long getId() {
    return id; } public void setId(Long id) {
    this.id = id; } public String getName() {
    return name; } public void setName(String name) {
    this.name = name; } public String getNameZh() {
    return nameZh; } public void setNameZh(String nameZh) {
    this.nameZh = nameZh; }}
  • 用户表

    package com.wz.vhrdb.entity;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import javax.persistence.*;import java.util.ArrayList;import java.util.Collection;import java.util.List;/** * @author: 王泽 */@Entity(name = "t_user")public class User implements UserDetails {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String password; private boolean accountNonExpired; private boolean accountNonLocked; private boolean credentialsNonExpired; private boolean enabled; @ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.PERSIST) private List
    roles; public Long getId() {
    return id; } public void setId(Long id) {
    this.id = id; } public void setUsername(String username) {
    this.username = username; } public void setPassword(String password) {
    this.password = password; } public void setAccountNonExpired(boolean accountNonExpired) {
    this.accountNonExpired = accountNonExpired; } public void setAccountNonLocked(boolean accountNonLocked) {
    this.accountNonLocked = accountNonLocked; } public void setCredentialsNonExpired(boolean credentialsNonExpired) {
    this.credentialsNonExpired = credentialsNonExpired; } public void setEnabled(boolean enabled) {
    this.enabled = enabled; } public List
    getRoles() {
    return roles; } public void setRoles(List
    roles) {
    this.roles = roles; } @Override public Collection
    getAuthorities() {
    List
    authorities = new ArrayList<>(); for (Role role : getRoles()) {
    authorities.add(new SimpleGrantedAuthority(role.getName())); } return authorities; } @Override public String getPassword() {
    return password; } @Override public String getUsername() {
    return username; } @Override public boolean isAccountNonExpired() {
    return accountNonExpired; } @Override public boolean isAccountNonLocked() {
    return accountNonLocked; } @Override public boolean isCredentialsNonExpired() {
    return credentialsNonExpired; } @Override public boolean isEnabled() {
    return enabled; }}
  • 运行程序,创建表。

在这里插入图片描述

创建UserDao接口

package com.wz.vhrdb.dao;import com.wz.vhrdb.entity.User;import org.springframework.data.jpa.repository.JpaRepository;public interface UserDao extends JpaRepository
{
User findUserByUsername(String username);}

创建UserService类

package com.wz.vhrdb.service;import com.wz.vhrdb.dao.UserDao;import com.wz.vhrdb.entity.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;/** * @author: 王泽 */public class UserService implements UserDetailsService {
@Autowired private UserDao userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final User user = userDao.findUserByUsername(username); if (user == null){
throw new UsernameNotFoundException("用户不存在"); } return user; }}

配置springsecurity

package com.wz.vhrdb.config;import com.wz.vhrdb.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.security.access.hierarchicalroles.RoleHierarchy;import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.builders.WebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.password.NoOpPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;/** * @author: 王泽 */public class SecurityConfig extends WebSecurityConfigurerAdapter {
//密码不加密 @Bean PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance(); } //校验的数据源 @Autowired UserService userService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService); } //角色关系 @Bean RoleHierarchy roleHierarchy() {
RoleHierarchyImpl hierarchy = new RoleHierarchyImpl(); hierarchy.setHierarchy("ROLE_admin > ROLE_user"); return hierarchy; } //放行静态资源 @Override public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**","/css/**","/image/**"); } //配置拦截规则和表单配置 //表单配置待完善 @Override protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() .antMatchers("/admin/**").hasRole("admin")//具备某个角色 .antMatchers("/user/**").hasAnyRole("admin","user") .anyRequest().authenticated()//除了上述两个只要登录就能访问 .and() .formLogin() .permitAll() .and() .csrf().disable(); }}

注册功能

直接在service中添加增添方法,jpa为我们提供了save

//用户注册功能(增加用户)    public User insertUser(User user) {
return userDao.save(user); }}

在controller中写接口

/**     * 新增用户 post /users     */    @PostMapping("")    public User addUser(@RequestBody User user){
return userService.insertUser(user); }

postman测试

{
"username":"王泽", "password":"123", "accountNonExpired":true, "accountNonLocked":true, "credentialsNonExpired":true, "enabled":true, "roles":[{
"name":"admin", "nameZh":"管理员" }]}

我们可以给实体类设置一些默认值:

private boolean accountNonExpired =true;    private boolean accountNonLocked = true;    private boolean credentialsNonExpired =true;    private boolean enabled =true;

测试:

package com.wz.vhrdb;import com.wz.vhrdb.dao.UserDao;import com.wz.vhrdb.entity.Role;import com.wz.vhrdb.entity.User;import com.wz.vhrdb.service.UserServiceImpl;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.ArrayList;import java.util.List;@SpringBootTestclass VhrdbApplicationTests {
@Autowired UserServiceImpl userService; @Test void contextLoads() {
User u1 = new User(); u1.setUsername("liu"); u1.setPassword("123");// u1.setAccountNonExpired(true);// u1.setAccountNonLocked(true);// u1.setCredentialsNonExpired(true);// u1.setEnabled(true); List
rs1 = new ArrayList<>(); Role r1 = new Role(); r1.setName("ROLE_admin"); r1.setNameZh("管理员"); rs1.add(r1); u1.setRoles(rs1); userService.insertUser(u1); User u2 = new User(); u2.setUsername("小刘"); u2.setPassword("123");// u2.setAccountNonExpired(true);// u2.setAccountNonLocked(true);// u2.setCredentialsNonExpired(true);// u2.setEnabled(true); List
rs2 = new ArrayList<>(); Role r2 = new Role(); r2.setName("ROLE_user"); r2.setNameZh("普通用户"); rs2.add(r2); u2.setRoles(rs2); userService.insertUser(u2); }}

在这里插入图片描述

优化登录注册

主要问题有两方面:1.不能重复注册 2.密码加密问题

密码加密问题

首先我们注册的时候要添加密码加密

//用户注册功能(增加用户)    public User insertUser(User user) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10); user.setPassword(encoder.encode(user.getPassword())); return userDao.saveAndFlush(user); }

然后我们需要在springsecurity中配置

@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {
//密码加密 @Bean PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10); } //校验的数据源 @Autowired UserServiceImpl userService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder()); }}

检查重复用户

public User insertUser(User user) {
User username = userDao.findUserByUsername(user.getUsername()); if (username == null) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10); user.setPassword(encoder.encode(user.getPassword())); return userDao.save(user); }else {
throw new RuntimeException("用户名已经存在"); } }}

测试:

我们先用userDao.deleteAll()删除所有记录,然后来测试重复添加

在这里插入图片描述

员工相关功能

我们首先需要一个员工的表(实体类),员工有姓名,性别,年龄,电话,部门,入职时间

创建实体类Personnel

package com.wz.vhrdb.entity;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import java.util.Date;/** * @author: 王泽 */@Entity(name = "t_personnel")public class Personnel {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String pName; private String pSex; private Integer pAge; private String pClass; private String pTel; private Date pJoin; public Long getId() {
return id; } public void setId(Long id) {
this.id = id; } public String getpName() {
return pName; } public void setpName(String pName) {
this.pName = pName; } public String getpSex() {
return pSex; } public void setpSex(String pSex) {
this.pSex = pSex; } public Integer getpAge() {
return pAge; } public void setpAge(Integer pAge) {
this.pAge = pAge; } public String getpClass() {
return pClass; } public void setpClass(String pClass) {
this.pClass = pClass; } public String getpTel() {
return pTel; } public void setpTel(String pTel) {
this.pTel = pTel; } public Date getpJoin() {
return pJoin; } public void setpJoin(Date pJoin) {
this.pJoin = pJoin; }}

在这里插入图片描述

对于员工表我们的需求有,特定的查询,以及增删改查,分页等。

springdatajpa自带的接口基本足够我们本项目的使用

目前所需要的自动生成的接口有:

1.查询所有用户: http://localhost:8989/users  (get)2.查询所有员工: http://localhost:8989/personnels  (get)3.增加用户hr: http://localhost:8989/user/adduser (post)4.增加员工:  http://localhost:8989/personnels  (post)5.分页查询员工: http://localhost:8989/personnels?page=0&size=56.删除hr: http://localhost:8989/users/id   (delete)7.删除员工: http://localhost:8989/personnels/id (delete)8.修改员工: http://localhost:8989/personnels/id (put)

优化与前端的交互体验

主要思路:成功与失败都有信息来提示前端

编码:

编写vo包(传值的)中的result类

package com.wz.vhrdb.vo;/** * @author: 王泽 */public class Result {
private Boolean status =true; private String msg; public Boolean getStatus() {
return status; } public void setStatus(Boolean status) {
this.status = status; } public String getMsg() {
return msg; } public void setMsg(String msg) {
this.msg = msg; }}

编写controller

@PostMapping("/adduser")    public Result addUser(@RequestBody User user){
Result result =new Result(); try{
userService.insertUser(user); result.setMsg("hr增加成功"); }catch (Exception e){
result.setStatus(false); result.setMsg("新增hr失败"+e.getMessage()); } return result; }

其余接口均使用springdatajpa自动生成的接口!

前端功能实现

环境搭建

目录结构

在这里插入图片描述

用vite 进行环境搭建

响应尤大的号召,使用vite!

  • npm init @vitejs/app vhrui --template vue

  • cd vhrui

  • npm install

至此项目创建完成!接下来我们需要引入我们所需要的其他组件

引入路由

  • npm install vue-router@next

  • 创建router目录来存放router配置

    import {
    createRouter,createWebHistory} from "vue-router";// 路由信息const routes = [ {
    path: "/", name: "Index", component: () => import('../views/idnex.vue'), },];// 导出路由const router = createRouter({
    history: createWebHistory(), routes});export default router;
  • 在main.js中使用路由

    import {
    createApp } from 'vue'import App from './App.vue'import router from "./router/router";const app = createApp(App)app.mount('#app')app.use(router)

注意:在使用的时候要到inde.vue

在这里插入图片描述


引入UI组件库

npm install element-plus --save

在main.js中使用

import {
createApp } from 'vue'import ElementPlus from 'element-plus';import 'element-plus/lib/theme-chalk/index.css';import App from './App.vue';const app = createApp(App)app.use(ElementPlus)app.mount('#app')

引入axios

npm install --save axios vue-axios

在main.js 中使用

import Vue from 'vue'import axios from 'axios'import VueAxios from 'vue-axios'Vue.use(VueAxios, axios)

使用方法:

this.$http.get(api).then((response) => {
console.log(response.data)})

开发界面

项目路由:

import {
createRouter,createWebHistory} from "vue-router";// 路由信息const routes = [ {
path: "/", name: "index", component: () => import('../components/index.vue'), }, {
path: "/login", name: "login", component: () => import('../components/login.vue'), }, {
path: "/register", name: "register", component: () => import('../views/user/add.vue'), }, {
path: "/personnel", name: "personnel", component: () => import('../components/personnel.vue'), children:[ {
path: "/users", name: "users", component: () => import('../views/user/users.vue'), }, {
path: "/pindex", name: "pindex", component: () => import('../views/personnel/pindex.vue'), }, {
path: "/class", name: "class", component: () => import('../views/personnel/class.vue'), }, {
path: "/personnels", name: "personnels", component: () => import('../views/personnel/personnels.vue'), }, ] },];// 导出路由const router = createRouter({
history: createWebHistory(), routes});export default router;

组件的开发

这里只写出首页的主要代码

第五章、前后端整合所遇到的问题

1.springsecurity+vue如何实现登录验证??

在前后端分离这样的开发架构下,前后端的交互都是通过 JSON 来进行,无论登录成功还是失败,都不会有什么服务端跳转或者客户端跳转之类。

登录成功了,服务端就返回一段登录成功的提示 JSON 给前端,前端收到之后,该跳转该展示,由前端自己决定,就和后端没有关系了。

登录失败了,服务端就返回一段登录失败的提示 JSON 给前端,前端收到之后,该跳转该展示,由前端自己决定,也和后端没有关系了。

successHandler 的功能十分强大,甚至已经囊括了 defaultSuccessUrl 和 successForwardUrl 的功能。

.successHandler((req, resp, authentication) -> {
Object principal = authentication.getPrincipal(); resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); out.write(new ObjectMapper().writeValueAsString(principal)); out.flush(); out.close();})

2.springdatajpa+springsecurity+vue如何实现跨域?

只有开发时存在这种跨域的情况。

解决思路:

  • 部署:前端部署到nigx上,后端通过nigx做请求转发。或者部署到一起
  • 开发环境下:用node.js 做请求转发。

正解:

在这里插入图片描述

3.后端传来的json数据如何与前端交互?

前端接收:发送axios异步请求,用tableData接收

//tableData[] findAll(){
this.axios.get('http://localhost:8989/users').then(res=>{
this.tableData=res.data; })}// 初始化的时候调用方法created() {
this.findAll(); }

前端发来的post,后端接收

这时候,我们就需要再复习一下后端所用到的一些注解:

@RequestBody :可以将body里面所有的json数据传到后端,后端再进行解析。

@RequestParam :接收的参数是来自requestHeader中,即请求头通常用于GET请求

  • @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestBody可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。

  • 注解@RequestParam接收的参数是来自requestHeader中,即请求头通常用于GET请求,比如常见的url:http://localhost:8081/spring-boot-study/novel/findByAuthorAndType?author=唐家三少&type=已完结

  • @RequestParam有三个配置参数:

    • required 表示是否必须,默认为 true,必须。
    • defaultValue 可设置请求参数的默认值。
    • value 为接收url的参数名(相当于key值)。
  • 如果参数前写了@RequestParam(xxx),那么前端必须有对应的xxx名字才行(不管其是否有值,当然可以通

    过设置该注解的required属性来调节是否必须传),如果没有xxx名的话,那么请求会出错,报400。

  • 如果参数前不写@RequestParam(xxx)的话,那么就前端可以有可以没有对应的xxx名字才行,如果有xxx名

    的话,那么就会自动匹配;没有的话,请求也能正确发送。

  • @JsonAlias注解,实现:json转模型时,使json中的特定key能转化为特定的模型属性;但是模型转json时,

    对应的转换后的key仍然与属性名一致.

    @JsonAlias("Name","name123")private String name;
    此时,json字符串转换为模型时,json中key为Name或为name123或为name的都能识别。

    结论②:@JsonProperty注解,实现:json转模型时,使json中的特定key能转化为指定的模型属性;同样的,模

    型转json时,对应的转换后的key为指定的key,见:示例中的motto字段的请求与响应。
    以下图进一步说明:

    @JsonProperty("name123")private String name;
    此时,json字符串转换为模型时,key为name123的能识别,但key为name的不能识别。

    结论③:@JsonAlias注解需要依赖于setter、getter,而@JsonProperty注解不需要。

    结论④:在不考虑上述两个注解的一般情况下,key与属性匹配时,默认大小写敏感。

    结论⑤:有多个相同的key的json字符串中,转换为模型时,会以相同的几个key中,排在最后的那个key的值给模

    型属性复制,因为setter会覆盖原来的值。见示例中的gender属性。

    结论⑥:后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面

    的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值
    符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性。

4.后端返回的msg如何显示到前端?

后端:

package com.wz.vhrdb.vo;/** * @author: 王泽 */public class Result {
private Boolean status =true; private String msg; public Boolean getStatus() {
return status; } public void setStatus(Boolean status) {
this.status = status; } public String getMsg() {
return msg; } public void setMsg(String msg) {
this.msg = msg; }}
@PostMapping("/adduser")    public Result addUser(@RequestBody User user){
Result result =new Result(); try{
userService.insertUser(user); result.setMsg("hr增加成功"); }catch (Exception e){
result.setStatus(false); result.setMsg("新增hr失败"+e.getMessage()); } return result; }

前端:

submitForm(){
//提交表单到后端 this.$http.post("http://localhost:8989/user/adduser",this.pForm).then(res=>{
console.log(res.data); if(res.data.status){
this.$message({
message:'恭喜你'+res.data.msg, type:'success' }) // 成功后的处理:清空表单信息,刷新所有 this.pForm={
}; this.$emit('findAll'); }else {
this.$message.error(this.date.msg); } }) },

5.后端传来的数据中嵌套“…”:[{“…”:“…”}]该怎么交互??

在这里插入图片描述

6.url中字组件使用父组件的表格行id?

问题等价于父组件向子组件传值!

  • 在父组件的 子组件标签 写要传的值

  • 在子组件中使用

  • props:['id'],  methods: {
    submitForm() {
    console.log(this.id); this.$http.put("http://localhost:8989/users/"+this.id).then(res=>{
    console.log(res.data); this.$emit('findAll'); }) }, }

7.登录的值是json,但是后台用的key values??怎么转换

导入 qs;import qs from 'qs';然后data 使用data:qs.stringify(param)
let params = {
username: this.loginForm.username, password: this.loginForm.password};console.log(params);let kv =qs.stringify(params);console.log(kv);this.$http.post('http://localhost:8989/login',kv)

8.关于项目的是否有状态登录

这前后端分离开发后,认证这一块到底是使用传统的 session 还是使用像 JWT 这样的 token 来解决呢?

这确实代表了两种不同的方向。

传统的通过 session 来记录用户认证信息的方式我们可以理解为这是一种有状态登录,而 JWT 则代表了一种无状态登录。可能有小伙伴对这个概念还不太熟悉,我这里就先来科普一下有状态登录和无状态登录。

8.1 什么是有状态

有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如 Tomcat 中的 Session。例如登录:用户登录后,我们把用户的信息保存在服务端 session 中,并且给用户一个 cookie 值,记录对应的 session,然后下次请求,用户携带 cookie 值来(这一步有浏览器自动完成),我们就能识别到对应 session,从而找到用户的信息。这种方式目前来看最方便,但是也有一些缺陷,如下:

  • 服务端保存大量数据,增加服务端压力
  • 服务端保存用户状态,不支持集群化部署

8.2 什么是无状态

微服务集群中的每个服务,对外提供的都使用 RESTful 风格的接口。而 RESTful 风格的一个最重要的规范就是:服务的无状态性,即:

  • 服务端不保存任何客户端请求者信息
  • 客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份

那么这种无状态性有哪些好处呢?

  • 客户端请求不依赖服务端的信息,多次请求不需要必须访问到同一台服务器
  • 服务端的集群和状态对客户端透明
  • 服务端可以任意的迁移和伸缩(可以方便的进行集群化部署)
  • 减小服务端存储压力

8.3 如何实现无状态

无状态登录的流程:

  • 首先客户端发送账户名/密码到服务端进行认证
  • 认证通过后,服务端将用户信息加密并且编码成一个 token,返回给客户端
  • 以后客户端每次发送请求,都需要携带认证的 token
  • 服务端对客户端发送来的 token 进行解密,判断是否有效,并且获取用户登录信息

8.4 各自优缺点

使用 session 最大的优点在于方便。你不用做过多的处理,一切都是默认的即可。松哥本系列前面几篇文章我们也都是基于 session 来讲的。

但是使用 session 有另外一个致命的问题就是如果你的前端是 Android、iOS、小程序等,这些 App 天然的就没有 cookie,如果非要用 session,就需要这些工程师在各自的设备上做适配,一般是模拟 cookie,从这个角度来说,在移动 App 遍地开花的今天,我们单纯的依赖 session 来做安全管理,似乎也不是特别理想。

这个时候 JWT 这样的无状态登录就展示出自己的优势了,这些登录方式所依赖的 token 你可以通过普通参数传递,也可以通过请求头传递,怎么样都行,具有很强的灵活性。

第六章、总结

此项目是我写第一个前后端分离项目,项目功能很简单,但是遇到的问题很多,解决问题的过程让我对前后端分离的开发有了更深刻的理解,也让我对springsecurity的安全更加敬佩。对于前端vue中router以及axios的使用更加熟练,学会了ui组件库的使用方法。对于后端,对springboot以及springdatajpa和springsecurity都有新的收获!springboot+vue的开发方式更明确的定位了程序员的分工。但是一个出色的程序员我认为应该是对技术栈都有所掌握的。当然一种技术有更深的造诣是我们所追求的,但是知识面千万不能窄。这就是我本次项目开发的总结。

第七章、致谢

本次项目开发,感谢bilibili中suns老师的课程,他的课程垫定了我的spring基础。还有百知教育的陈老师,讲的vue与elementui课程很好。感谢 王松(江南一点雨)的springboot与springsecurity以及springdatajpa,mybatis…的教学。让我真正的学会了开发知识!

第八章、参考文献

springboot官方文档

vue官方文档

axios官方文档

element ui 官方文档

vite官方文档

深入浅出springsecurity ——王松(江南一点雨)

MySQL官方文档

转载地址:http://uksef.baihongyu.com/

你可能感兴趣的文章
JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof 详解
查看>>
Java - JVM TLAB、对象在内存中安置顺序、垃圾收集、回收算法
查看>>
转: 关于Linux与JVM的内存关系分析
查看>>
(转)Java 程序员必备的高效 Intellij IDEA 插件
查看>>
局域网(内网)docker安装及代理访问
查看>>
软考 英语学习
查看>>
maven 文件上传到远程服务器目录
查看>>
shell 脚本免密远程访问
查看>>
Linux平台Oracle多个实例启动说明
查看>>
在LINUX平台上手动创建数据库(oracle 10g)(在一个oracle服务器上启动两个实例)
查看>>
Oracle 10g 下载地址
查看>>
Linux 下 新增Oracle10g 实例
查看>>
LRM-00123 ORA-01078
查看>>
ORA-01102: cannot mount database in EXCLUSIVE mode
查看>>
专栏结语
查看>>
BERT 实战
查看>>
BERT 基础
查看>>
什么是 Transformer
查看>>
简述 XLNet 的原理和应用
查看>>
实战:为图片生成文本摘要
查看>>