版权声明:本文为闪耀太阳原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_16804847/article/details/116780342
package com.jt.controller;
import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author 刘昱江
* 时间 2021/5/11
*/
@RestController
@CrossOrigin
@RequestMapping("/user") //抽取公共的请求
public class UserController {
@Autowired
private UserService userService;
/**
* 1.url地址: /user/login
* 2.请求参数: 用户表单对象的JSON串 post类型
* 3.返回值结果 SysResult token?有值 正确 null 错误
*/
@PostMapping("/login")
public SysResult login(@RequestBody User user){
String token = userService.findUserByUP(user);
if(StringUtils.hasLength(token)){
return SysResult.success(token);
}else{
return SysResult.fail();
}
}
}
/**
* user对象: username/password 明文
* 业务思路:
* 1.将密码进行加密处理 md5加密方式
* 2.根据新的用户名和密码查询数据
* 3. 结果:null 没查到 u/p错误
* 不为null u/p正确 返回令牌 token UUID算法
*
* * @param user
* @return
*
* 数据库信息: 用户名 :admin 密码:admin123456
*/
@Override
public String findUserByUP(User user) {
//1.将密码加密 一般可能添加 盐值: 由公司域名构成
// hash(md5(www.baidu.com12345))
String md5Pass =DigestUtils
.md5DigestAsHex(user.getPassword().getBytes());
//2.根据用户名/密码查询数据库.
user.setPassword(md5Pass);
//根据对象中不为null的属性当做where条件
QueryWrapper queryWrapper = new QueryWrapper(user);
User userDB = userMapper.selectOne(queryWrapper);
//3.返回密钥token
String token = UUID.randomUUID().toString()
.replace("-", "");
return userDB==null?null:token;
}
在后端服务器中会有很多的地方需要添加,如果都写到业务代码中,会造成代码可读性差 如图:
@RestControllerAdvice //定义全局异常处理 拦截controller层 返回JSON
public class AOPException {
//实现原理 异常通知
//1.拦截什么类型的异常!!
//2.拦截之后如何处理!!
@ExceptionHandler({RuntimeException.class})
public Object exception(Exception e){
//将异常 控制台输出
e.printStackTrace();
return SysResult.fail();
}
}
说明: 去码云中的资源文件中查找组件Home/Welcome.导入项目中
当用户登录成功之后,需要重定向到home页面.这时用户token将会丢失.用户后端的操作要求用户必须登录之后才可以执行,因此必须保存用户的登录凭证 token!!!
问题: 浏览器如果保存服务器记录?
补充知识:
1.cookie 可以将用户信息永久的保存到cookie中. 有安全性问题 如果需要使用则需要特殊处理 IP绑定/手机的认证 30天免密登录 视频会员
2.Session 表示服务器的会话机制 可以将数据保存到Session中.当会话关闭时Session失效了.
当用户登录成功之后,需要通过session保存用户的token信息.代码如下:
要求: 如果用户没有登录(token),则不允许访问其他页面.
判断依据: 根据session中的token进行判断. token有数据 则放行请求 没有数据 跳转到登录页面.
难点: 如果实现请求的拦截?
实现策略: 使用路由导航守卫.
编辑router中的index.js 实现功能
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import Home from '../components/Home.vue'
Vue.use(VueRouter)
const routes = [
{path: '/', redirect: '/login'},
{path: '/login', component: Login},
{path: '/home', component: Home}
]
//1.定义路由对象
const router = new VueRouter({
routes
})
// 2.定义导航守卫(注意位置)
// beforeEach: 循环遍历用户的所有的请求.(拦截)
// 在其中需要定义一个回调函数(3个参数)
// 参数介绍: to :要访问的请求路径
// from: 从哪个页面跳转而来
// next: 表示请求放行
//业务需求: 1.如果用户请求/login
// 2.如果不是login则判断是否登录 token
router.beforeEach((to,from,next) => {
if(to.path === '/login') return next()
//2.获取token信息
let token = window.sessionStorage.getItem('token')
//3.判断token是否有数据?? if(token) 如果token不为null
//如果token为null 则跳转到登录页面
if(!token) return next('/login')
//表示放行
next()
})
export default router
当用户点击退出按钮时,应该删除session中的数据. 之后跳转到登录页面.
<el-container>
<el-header>Headerel-header>
<el-container>
<el-aside width="200px">Asideel-aside>
<el-main>Mainel-main>
el-container>
el-container>
说明: 当用户跳转到home页面中,之后发起Ajax请求获取模块信息.之后通过导航菜单的形式进行展现.
说明: 权限有父子级关系,通过parent_id实现父子关联
package com.jt.controller;
import com.jt.pojo.Rights;
import com.jt.service.RightsService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping("/rights")
public class RightsController {
@Autowired
private RightsService rightsService;
/**
* URL: /rights/getRightsList
* 参数: null
* 类型: get
* 返回值: SysResult对象 List
* 业务: 只查询前 2级权限
*/
@GetMapping("/getRightsList")
public SysResult getRightsList(){
List<Rights> rightsList =
rightsService.findRightsList();
return SysResult.success(rightsList);
}
}
package com.jt.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.RightsMapper;
import com.jt.pojo.Rights;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RightsServiceImpl implements RightsService{
@Autowired
private RightsMapper rightsMapper;
/**
* 查询一级/二级菜单
* 查询条件: 一级菜单 parent_id = 0
* 二级菜单 parent_id = 一级的Id
* 作业: 利用左连接的方式 实现数据的封装 restMap
* @return
*/
@Override
public List<Rights> findRightsList() {
//1.查询一级菜单数据
QueryWrapper<Rights> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id",0);
List<Rights> oneList =
rightsMapper.selectList(queryWrapper);
//2.如何查询二级菜单 父子关系的封装!!!
for (Rights oneRights : oneList){
//查询该元素的二级菜单
//QueryWrapper queryWrapper2 = new QueryWrapper<>();
queryWrapper.clear();
queryWrapper.eq("parent_id",oneRights.getId());
List<Rights> twoList = rightsMapper.selectList(queryWrapper);
oneRights.setChildren(twoList);
}
return oneList;
}
}
<el-container>
<!-- 当打开左侧菜单时 宽度为200, 当不打开时为默认值-->
<el-aside :width="isCollapse ? '64px' : '200px' ">
<!-- 这是左侧菜单-->
<!--定义折叠项-->
<div class="leftCollapse" @click="collspseClick">|||</div>
<!--
1.background-color="#2C3E50"
2.text-color="#fff" 文本颜色
3.active-text-color="#4094ff"
4.unique-opened=true 是否只打开一个菜单
5.collapse 是否折叠
6.collapse-transition 折叠时是否展现动画效果
7.default-active 默认选中的菜单
-->
<el-menu background-color="#2C3E50" text-color="#fff"
active-text-color="#4094ff"
unique-opened
:collapse="isCollapse" :collapse-transition="isCollapseTransition" router :default-active="defaultActive">
<!-- 定义一级菜单 -->
<el-submenu :index="menu.id+''" v-for="menu in menuList" :key="menu.id">
<!-- 定义一级菜单模版 -->
<template slot="title">
<!-- 定义左侧图标-->
<i :class="menuIcon[menu.id]"></i>
<!-- 定义菜单名称-->
<span>{{menu.name}}</span>
</template>
<!-- 定义二级菜单 -->
<el-menu-item :index="childrenMenu.path" v-for="childrenMenu in menu.children" :key="childrenMenu.id"
@click="defaultActiveMenu(childrenMenu.path)">
<template slot="title">
<i class="el-icon-menu"></i>
<span>{{childrenMenu.name}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 定义主页面结构-->
<el-main>
<!-- 定义路由展现页面-->
<router-view></router-view>
</el-main>
</el-container>
将来在view的位置,展现其他的页面组件
当前组件是谁: Home组件
如果需要在该位置展现组件,则必然是Home组件的子级