目录
5.1.1.如果在数据库查询到了用户信息,然后将用户信息保存
1.前端使用:
vue + elementui + axios + css + html
2.后端使用:
springboot+mybatis-plus +mybatis+druid+shiro+swagger2+redis
3.前端页面--登录页面
3.1.在views下新建一个视图,作为登录的视图
3.2.在登录试图视图中,写入登录页面需要的代码
3.2.1.登录页面
<template>
<!--这里必须使用一个双标签-->
<div id="login_box">
<div class="img_position">
<el-avatar :size="140" :src="imgUrl"></el-avatar>
</div>
<el-card class="box-card">
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="用户名" prop="name">
<el-input type="text" v-model="ruleForm.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<!--登录按钮-->
<el-button type="primary"
size="mini"
:plain="true"
@click="login"
style="margin-left: 100px;width: 100px">登录</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
3.2.2.登录页面的数据和方法
<script>
export default {
name: "Login",
data(){
return{
ruleForm: {
name: '',
password: ''
},
rules: {
name: [
{required: true, message:'用户名不能为空', trigger: 'blur'},
],
password: [
{required: true, message: '密码不能为空', trigger: 'blur'},
]
},
imgUrl:'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
}
},
methods:{
login(){
this.$refs['ruleForm'].validate((valid) => {
if(valid) {
this.$message.success("登录成功")
} else {
this.$message.error("登录失败")
}
})
}
}
}
3.2.3.登录页面的样式
<style>
#login_box{
position: relative;
width: 500px;
margin: 250px auto;
}
#login_box div.img_position{
position: absolute;
left: 200px;
top: -70px;
}
.text {
font-size: 14px;
}
.item {
padding: 18px 0;
}
.box-card {
padding: 100px 50px 0 0;
width: 480px;
}
</style>
3.2.4.渲染主件
3.2.5.设置路由
打开网页之后输入login或者/login,就会去找路由下的index .js 在里面去找有没有/login的路径,找到之后根据import Login from "../views/Login";这句话,去找views下的视图页面,然后再网页上显示
3.2.6.跳转页面
刚打开网页的时候上面的网址是http://localhost:8080/#/,显示一片空白,想要登录页面还得输入login或者/login,有点麻烦,而且一打开页面应该是登录页面,不是空白的页面,上面的代码是,一打开页面重定向的login
3.2.7.运行之后的样子
3.4.8.登录按钮事件
我想登录成功之后,跳转到主页面,这个就用到了axios
方法:
methods:{
login(){
//表单校验
this.$refs['ruleForm'].validate((valid) => {
if(valid){
//url:后端登录接口的路径 this.ruleForm是表单
this.$http.post("http://localhost:8808/user/login",this.ruleForm).then(result=>{
//登录成功之后跳转到主页面--路由跳转
this.$router.push("/home")
});
}
})
}
}
路由设置
{
path: '/home',
name: '/Home',
component: ()=>import("../views/Home")
}
4.后端登录接口
4.1.新建一个springboot工程
注意:选择版本,要不然会报错--8的版本
4.2.引入相关的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.guan</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-plus-vue</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.3.mp的代码生成器
package com.guan.demo;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
/**
* TODO
*
* @author lenovo
* @version 1.0
* @since 2022-08-08 10:02:23
*/
public class Generator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/day?serverTimezone=Asia/Shanghai", "root", "grt081141" +
"")
.globalConfig(builder -> {
builder.author("guan") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir(".\\src\\main\\java\\"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.guan.demo") // 设置父包名
.moduleName("system") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, "src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("acl_user","acl_role","acl_permission")// 设置需要生成的表名
.addTablePrefix("acl_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
4.4.运行代码生成器
4.5.配置application文件
#设置端口号--一定要设置端口号,不设置的话,端口号会冲突
server.port=8888
spring.datasource.druid.url=jdbc:mysql://localhost:3306/day?serverTimezone=Asia/Shanghai
spring.datasource.druid.username=root
spring.datasource.druid.password=grt081141
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
4.6.配置swagger的工具类
@Configuration //该注解为配置类相当于xml
public class SwaggerConfig {
@Bean
//swagger中所有的功能都封装到了Docket类中
public Docket docket(){
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.groupName("接口文档")
设置api文档信息
.apiInfo(apiInfo())
//为那个包下的类生成接口文档
.select()
.apis(RequestHandlerSelectors.basePackage("com.guan.demo.system.controller"))
.build();
return docket;
}
//定义自己接口文档信息
public ApiInfo apiInfo(){
//description 描述 description 团队地址 license 企业的名字
Contact DEFAULT_CONTACT = new Contact("哈哈哈", "http://www.bidu.com", "1234@qq.com");
ApiInfo apiInfo=new ApiInfo("亿个小项目", "针对小孩子的", "1.0", "http://www.jd.com", DEFAULT_CONTACT, "牛家企业", "http://www.taobao.com", new ArrayList<VendorExtension>());
return apiInfo;
}
}
4.7.创建同一返回的数据信息加swagger的注解
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("返回同一的信息")
public class CommonResult {
@ApiModelProperty("状态码 2000成功,5000失败")
private int code;
@ApiModelProperty("信息")
private String msg;
@ApiModelProperty("数据")
private Object data;
}
4.7.创建登录参数的实体类加swagger注解
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("登录的参数的实体类")
public class VoLogin {
//这里面的参数必须和你前端请求的参数相同
@ApiModelProperty("账号")
private String name;
@ApiModelProperty("密码")
private String password;
}
4.8.后端登录接口加swagger的注解
@RestController
@RequestMapping("/system")
@Api(tags = "登录的类")
public class LoginController {
@Autowired
private IUserService userService;
@Autowired
private RedisTemplate redisTemplate;
@PostMapping("/user")
@ApiOperation(value = "登录的接口")
/*
* origins: 允许哪些域可以跨域访问我这个接口
allowedHeaders:允许哪些请求头信息跨域
methods: 允许哪些请求方式跨域
* */
// @CrossOrigin //默认不写是*--解决跨域的问题
public CommonResult login(@RequestBody VoLogin voLogin){
QueryWrapper<User> wrapper=new QueryWrapper<>();
wrapper.eq("username",voLogin.getName());
wrapper.eq("password",voLogin.getPassword());
wrapper.eq("is_deleted",0);
User one = userService.getOne(wrapper);
if (one!= null) {
return new CommonResult(2000,"登录成功",null);
}else {
return new CommonResult(5000,"登录失败",null);
}
}
}
5.登录的bug
5.1.修改登录接口
5.1.1.如果在数据库查询到了用户信息,然后将用户信息保存
@RestController
@RequestMapping("/system")
@Api(tags = "登录的类")
public class LoginController {
@Autowired
private IUserService userService;
@Autowired
private RedisTemplate redisTemplate;
@PostMapping("/user")
@ApiOperation(value = "登录的接口")
/*
* origins: 允许哪些域可以跨域访问我这个接口
allowedHeaders:允许哪些请求头信息跨域
methods: 允许哪些请求方式跨域
* */
// @CrossOrigin //默认不写是*--解决跨域的问题
public CommonResult login(@RequestBody VoLogin voLogin){
QueryWrapper<User> wrapper=new QueryWrapper<>();
wrapper.eq("username",voLogin.getName());
wrapper.eq("password",voLogin.getPassword());
wrapper.eq("is_deleted",0);
User one = userService.getOne(wrapper);
if (one!= null) {
//登录成功之后随机生成唯一的字符串
String token = UUID.randomUUID().toString();
// System.out.println(token+"---------");
//把token作为key,user的信息是value
ValueOperations forValue = redisTemplate.opsForValue();
forValue.set(token,one,24,TimeUnit.HOURS);
//把token返回给前端,作为主体
return new CommonResult(2000,"登录成功",token);
}else {
return new CommonResult(5000,"登录失败",null);
}
}
5.1.2.将保存的信息给前端
methods:{
login(){
this.$refs['ruleForm'].validate((valid) => {
if(valid) {
// url:后端登录接口的路径
this.axios.post("http://localhost:8888/system/user", this.ruleForm).then(result => {
if(result.data.code===2000){
//登录成功,获取token
var token = result.data.data;
// console.log(result.data.data)
//把token保存
sessionStorage.setItem("token",token);
//登录成功之后跳转到主页面--路由跳转
this.$router.push("/home")
}
});
}
由于每次前端都往后端请求都得要人为添加参数token. 我们可以使用axios得请求拦截器。
5.1.3.axios得请求拦截器、
//使用axios的请求拦截器,--在请求头上添加token
//interceptors--拦截器 request--请求方法 use--用
axios.interceptors.request.use(config=>{
//获取token
var token = sessionStorage.getItem("token");
//判断toke里面是不是有值
if (token){
//请求头中会携带token
config.headers.token=token;
}
return config;
})
6.前置路由守卫
6.1.什么是前置路由守卫
路由跳转之前, 会触发的一个函数 叫前置路由守卫
6.2.前置路由守卫的语法
6.3.使用前置路由守卫 --在main.js
router.beforeEach((to, from, next) =>{
var path = to.path;
//判断是不是登录页面
if (path==="/login"){
//放行
return next();
}
//判断其他页面是否登录,登录放行
var token = sessionStorage.getItem("token");
if(token){
return next();
}
//没有登录的话,跳转到登录页面
return next("/login");
} )
7.整合shiro
7.1.添加shiro依赖
7.2.shiro得配置类
这里面注入RedisTemplate的原因,请看跨域那一篇的笔记
package com.guan.demo.system.config;
import com.guan.demo.system.filter.LoginFilter;
import com.guan.demo.system.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
/**
* TODO
*
* @author lenovo
* @version 1.0
* @since 2022-08-05 20:05:38
*/
@Configuration
public class ShiroConfig {
@Bean
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm());
return securityManager;
}
@Bean
public Realm realm(){
MyRealm myRealm = new MyRealm();
设置密码加密器
myRealm.setCredentialsMatcher(credentialsMatcher());
return myRealm;
}
@Bean
public CredentialsMatcher credentialsMatcher(){
//设置密码加密器
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//加密的次数
hashedCredentialsMatcher.setHashIterations(1024);
//应那种加密方式加密
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
return hashedCredentialsMatcher;
}
@Autowired
private RedisTemplate redisTemplate;
@Bean("shiroFilter")
public ShiroFilterFactoryBean filterFactoryBean(){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
//设置shiro过滤规则
Map<String, String> map = new HashMap<>();
//那些允许放行
map.put("/system/login","anon");
//拦截所有
map.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
//设置未登录过滤器
Map<String, Filter> filters = new HashMap<>();
filters.put("authc",new LoginFilter(redisTemplate));
shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
}
@Bean
public FilterRegistrationBean<Filter> filterProxy(){
FilterRegistrationBean<Filter> filterRegistrationBean=new FilterRegistrationBean<>();
//设置过滤器
filterRegistrationBean.setFilter(new DelegatingFilterProxy());
//那个路径过滤
filterRegistrationBean.setName("shiroFilter");
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
7.3.增加一个realm类对象
package com.guan.demo.system.realm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.guan.demo.system.entity.User;
import com.guan.demo.system.service.IUserService;
import com.guan.demo.system.vo.VoLogin;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* TODO
*
* @author lenovo
* @version 1.0
* @since 2022-08-05 20:07:04
*/
public class MyRealm extends AuthorizingRealm {
@Autowired
private IUserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//根据token拿到账号
String username = (String) token.getPrincipal();
//根据账号查询信息
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
wrapper.eq("is_deleted",0);
User user = userService.getOne(wrapper);
//如果user里面查询到了,有值不为空,从数据库中获取密码
if(user!=null){
//从数据库中获取的密码
//第一个参数是唯一标识,第二个参我们获取到user的密码,第三个参数就是获取到当前的名字
ByteSource bytes = ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),bytes,this.getName());
return info;
}
return null;
}
}
7.4.新增一个拦截器
//如果类没有交于spring容器来管理 那么该类中得属性也不能让spring帮你注入
public class LoginFilter extends FormAuthenticationFilter {
private RedisTemplate redisTemplate; //没有自动注入,原因该类没有交于spring管理LoginFilter必须交于spring容器来管理。
//构造方法
public LoginFilter(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
//当登录成功后执行得方法,如果该方法返回false,则执行onAccessDenied方法,true则不会执行onAccessDenied方法
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
System.out.println(redisTemplate);
HttpServletRequest req = (HttpServletRequest) request;
//1.请求方式是否为OPTIONS
String method = req.getMethod();
//如果请求方式不为空,并且请求方式是OPTIONS,则不执行onAccessDenied方法
if(method!=null && method.equals("OPTIONS")){
return true;
}
//2.判断请求头是否有token值
String token = req.getHeader("token");
if(token!=null && redisTemplate.hasKey(token)){
return true;
}
return false;
}
//当没有登录时会经过该方法。如果想让他返回json数据那么必须重写方法
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
CommonResult commonResult = new CommonResult(4001, "未登录", null);
ObjectMapper objectMapper=new ObjectMapper();
String json = objectMapper.writeValueAsString(commonResult);
writer.print(json); //响应给客户json数据
writer.flush();
writer.close();
return false;
}
}
7.5.修改controller代码
//登录
@PostMapping("/login")
@ApiOperation(value = "登录的接口")
/*
* origins: 允许哪些域可以跨域访问我这个接口
allowedHeaders:允许哪些请求头信息跨域
methods: 允许哪些请求方式跨域
* */
// @CrossOrigin //默认不写是*--解决跨域的问题
public CommonResult login(@RequestBody VoLogin voLogin){
try {
//获取subject对象
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(voLogin.getName(),voLogin.getPassword());
//登录
subject.login(usernamePasswordToken);
//获取主体
Object one = subject.getPrincipal();
//登录成功之后随机生成唯一的字符串
String token = UUID.randomUUID().toString();
// System.out.println(token+"---------");
//把token作为key,user的信息是value
ValueOperations forValue = redisTemplate.opsForValue();
forValue.set(token,one,24,TimeUnit.HOURS);
//把token返回给前端,作为主体
return new CommonResult(2000,"登录成功",token);
}catch (Exception e){
return new CommonResult(5000,"登录失败",null);
}
}
8.主页得布局
8.1.前端
<template>
<el-container>
<el-header>
<span id="logo" style="display: inline-block;width: 50%;height: 100%;float: left" >
<a href="https://www.bilibili.com/video/BV14g41197PY/"><img src="../assets/logo.png" height="100%" width="180px"></a>
</span>
<span id="avatar" style="float: right">
<el-dropdown @command="handleCommand">
<span class="el-dropdown-link" style="margin-top: 10px; display: inline-block;" >
<el-avatar ></el-avatar>
</span>
<el-dropdown-menu slot="dropdown" style="margin-top: -9px">
<el-dropdown-item command="personal">个人信息</el-dropdown-item>
<el-dropdown-item command="loginOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
</el-header>
<!--左侧菜单-->
<el-container height="600px">
</el-container>
</template>
样式
<style>
body{
margin: 0px;
padding: 0px;
}
.el-menu{
border:0px;
background-color:#C0C4CC;
}
.el-header, .el-footer {
background-color: #818181;
color: #333;
height: 60px;
line-height: 60px;
}
.el-aside {
background-color: #C0C4CC;
color: #333;
height: 600px;
line-height: 600px;
/*overflow: hidden;*/
}
.el-aside::-webkit-scrollbar {
display: none;
}
.el-main {
background-color: #E9EEF3;
color: #333;
text-align: center;
height: 600px;
line-height: 600px;
overflow: hidden;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
.el-dropdown {
vertical-align: top;
}
.el-dropdown + .el-dropdown {
margin-left: 15px;
}
.el-icon-arrow-down {
font-size: 12px;
}
/*设置标签页第一个不可删除*/
.el-tabs__nav .el-tabs__item:nth-child(1) span{
display: none;
}
</style>
9.退出登录
9.1.前端
//退出
handleCommand(command){
if (command==='loginOut'){
this.axios.post("/system/loginOut").then(result=>{
if (result.data.code===2000){
//删除缓存的信息
sessionStorage.getItem("token");
//跳转到登录页面
this.$router.push("/login")
}
})
}
}
9.2.后端
@Autowired
private RedisTemplate redisTemplate;
//退出
@PostMapping("/loginOut")
public CommonResult loginOut(HttpServletRequest request){
String token = request.getHeader("token");
redisTemplate.delete(token);
return new CommonResult(2000,"退出成功",null);
}
10.查询左侧菜单
10.1.前端
<!--左侧菜单-->
<el-container height="600px">
<el-aside width="200px">
<el-menu
default-active="2"
class="el-menu-vertical-demo"
background-color="#C0C4CC"
text-color="#000"
active-text-color="#ffd04b">
<el-submenu :index="menu.id+''" v-for="menu in leftMenus">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{menu.name}}</span>
</template>
<el-menu-item :index="second.id+''" v-for="second in menu.children">
<i :class="el-icon-menu"></i>
<span slot="title">
<a style="color: white; text-decoration: none ">{{second.name}}</a></span>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main></el-main>
</el-container>
10.2.请求路径
data(){
return{
leftMenus:[],
}
},
created() {
this.initLeftMenu();
},
methods:{
initLeftMenu(){
this.axios.post("/system/permission/leftMenu").then(result=>{
if(result.data.code===2000){
this.leftMenus=result.data.data;
}
})
},
10.3.controller层
@RestController
@RequestMapping("/system/permission")
public class PermissionController {
@Autowired
private IPermissionService permissionService;
@PostMapping("leftMenu")
public CommonResult leftMenu(HttpServletRequest request){
//获取登录者的信息
String token = request.getHeader("token");
return permissionService.findPermissionByUserId(token);
}
}
10.4.service层
public interface IPermissionService extends IService<Permission> {
CommonResult findPermissionByUserId(String token);
}
10.5.mapper层
public interface PermissionMapper extends BaseMapper<Permission> {
List<Permission> selectByUserId(String id);
}
10.6.seriveimpl业务代码
@Autowired
private PermissionMapper permissionMapper;
@Autowired
private RedisTemplate redisTemplate;
@Override
public CommonResult findPermissionByUserId(String token) {
//根据token获取用户信息
ValueOperations forValue = redisTemplate.opsForValue();
User o = (User) forValue.get(token);
String id = o.getId();
//根据用户id查询该用户具有得权限。
List<Permission> permissionList = permissionMapper.selectByUserId(id);
//设置层级关系
List<Permission> firstMenus = new ArrayList<>();
for (Permission first : permissionList) {
//找一级菜单
if (first.getPid().equals("1")) {
firstMenus.add(first);
}
}
//为一级菜单设置二级菜单
for (Permission first : firstMenus) {
//根据一级菜单id 查询 该菜单得二级菜单。如果出现不确定有几级菜单 那么我们可以使用方法得递归调用
first.setChildren(findChildren(permissionList, first.getId()));
}
return new CommonResult(2000,"查询成功",firstMenus);
}
//方法递归
private List<Permission> findChildren(List<Permission> permissionList, String id) {
List<Permission> children = new ArrayList<>();
for (Permission p : permissionList) {
if (p.getPid().equals(id)) {
children.add(p);
}
}
for (Permission child : children) {
child.setChildren(findChildren(permissionList, child.getId()));
}
return children;
}
}
10.7.连表
<select id="selectByUserId" resultType="com.guan.demo.system.entity.Permission">
select distinct p.* from acl_user_role ur join acl_role_permission rp on ur.role_id=rp.role_id join acl_permission
p on rp.permission_id=p.id where ur.user_id=#{userid} and type=1
</select>