权限系统-------前后端分离

1.权限系统
1.前端使用: vue + elementui + axios + css + html
 2.后端使用: springboot+mybatis-plus +mybatis+druid+shiro+swagger2+redis

2. 登录界面
2.1前端布局
2.1.1创建Login.vue

2.1.2在Login.vue中写入登录的代码 

<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>

2.1.3登录界面的方法、数据

<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://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202010%2F16%2F20201016234725_52ed2.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1662528624&t=c2ac363744d360cd4d61b7a9ac9cffef'
            }
            },
        methods:{
            login(){
                this.$refs['ruleForm'].validate((valid) => {
                    if(valid) {
 
                         this.$message.success("登录成功")
                    } else {
                         this.$message.error("登录失败")
                     }
                })
            }
        }
 
 
    }

2.1.4 样式

<style>
    #login_box{
        position: relative;
        width: 500px;
        margin: 250px auto;
        background-image: url("../assets/2.jpeg");
    }
    #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>

2.1.5路由的渲染

2.1.6路由的设置

2.1.7页面的跳转

2.1.8登录按钮事件

如果想在vue工程中使用axios进行异步请求,则需要在main.js中导入axios


[1]//导入axios
import axios from "axios";


[2]//把axios挂载到vue对象中,以后在vue中如果使用axios直接可以用$http名称
Vue.prototype.$http=axios

登录方法

 methods:{
            login(){
                //表单校验
                this.$refs['ruleForm'].validate((valid) => {
                        if(valid){
                             //url:后端登录接口的路径
                             this.$http.post("http://localhost:8808/user/login",this.ruleForm).then(result=>{
 
                             });
                        }
                })
            }
        }

 2.1.9 浏览器打开的登录界面

2.2后端登录接口

2.2.1新建Springboot工程

2.2.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.ykq</groupId>
    <artifactId>qy151-springboot-vue</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>qy151-springboot-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>

 2.2.3MybatisPlus代码生成器

package com.ppp;
 
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 ppp
 * @version 1.0
 * @since 2022-07-25  19:07:17
 */
public class Generator {
	public static void main(String[] args) {
		FastAutoGenerator.create("jdbc:mysql://localhost:3306/shiropermission?serverTimezone=Asia/Shanghai", "root", "root")
				.globalConfig(builder -> {
					builder.author("ppp") // 设置作者
						.enableSwagger() // 开启 swagger 模式
						.fileOverride() // 覆盖已生成文件
						.outputDir(".\\src\\main\\java\\"); // 指定输出目录
				})
				.packageConfig(builder -> {
					builder.parent("com.ppp") // 设置父包名
						.moduleName("system") // 设置父包模块名
						.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
				})
				.strategyConfig(builder -> {
					builder.addInclude("acl_role_permission","acl_user","acl_role","acl_permission")// 设置需要生成的表名
						   .addTablePrefix("acl_"); // 设置过滤表前缀
				})
				.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
				.execute();
 
	}
}

 2.2.4配置Application文件

server.port=8809
 
spring.datasource.druid.url=jdbc:mysql://localhost:3306/shiropermission?serverTimezone=Asia/Shanghai
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.username=root
spring.datasource.druid.password=root
 
 
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.2.5测试登录接口

 2.2.6前端调用后端登录接口 

为跨域问题:

 当使用异步请求从一个网址访问另一个网址时可能会出现跨域问题。
前提:
   1. 必须为异步请求
   2. 当端口号或协议或ip不同时则会出现跨域

如何解决跨域:

后端解决---->这里也有几种方式:
   【1】可以借助nginx.
   【2】在代码中解决

在控制层接口上添加@CrossOrigin

(origins = {"192.168.0.111:8080","192.168.0.120:8081"},allowedHeaders="运行哪些请求头跨域",methods={"GET","POST"})

origins: 允许哪些域可以跨域访问我这个接口
allowedHeaders:允许哪些请求头信息跨域
methods: 允许哪些请求方式跨域
 

上面再控制层接口处加上注解的方式解决跨,麻烦的地方就需要对每个控制类都加该注解。 设置一个全局跨域配置类。

注意:加完配置类记得把接口上的注解去掉

 登录成功后前端路由跳转  

2.2.7使用swaager测试接口

(1)配置swaager的工具类

@Configuration
public class SwaggerConfig {
    @Bean
    public Docket docket(){
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.psh.system.controller"))
                .build();
          return docket;

    }

    public ApiInfo apiInfo(){
        Contact DEFAULT_CONTAT=new Contact("psh","http://www.aaa.com","111@qq.com");
        ApiInfo apiInfo= new ApiInfo("qy151在线文档","这是一个文档","A1.0","http://www.aaa.com",
                DEFAULT_CONTAT,"AAA","http://www.aaa.com",new ArrayList<VendorExtension>());
        return  apiInfo;
    }
}

 (2)在主启动类上开启swaager注解

建议使用这个版本这个比较稳定

要用redis的原因是因为如果高并发访问数据库数据库会崩溃,造成系统瘫痪 

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

application配置文件

#redis服务器的配置
spring.redis.host=localhost
spring.redis.port=6379

 RedisTemplate类需要序列化,加入一个配置类


@Configuration
public class RedisConfig {
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap序列化  filed value
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(redisSerializer);
        return template;
    }
}

2.3.1修改后端登录的接口


@RestController
@RequestMapping("system")
@Api(tags = "登录接口类")
public class LoginController {
    @Autowired
    private IUserService userService;
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    @PostMapping("login")
    @ApiOperation(value="登录接口")
    public CommonResult login(@RequestBody LoginVo loginVo){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",loginVo.getName());
        wrapper.eq("password",loginVo.getPassword());
        wrapper.eq("is_deleted",0);
        User one = userService.getOne(wrapper);
        if(one!=null){
            //随机生成一个唯一字符串。
            String token = UUID.randomUUID().toString();
            //把该token作为redis的key value为当前登录用户信息
            ValueOperations forValue = redisTemplate.opsForValue();
            forValue.set(token,one,24, TimeUnit.HOURS);
            return new CommonResult(2000,"登录成功",token);
        }else{
            return new CommonResult(5000,"登录失败",null);
        }
 
    }
 
}

2.3.2修改前端的登录方法

由于每次前端都往后端请求都得要人为添加参数token. 我们可以使用axios得请求拦截器 

2.3.3 axios请求拦截器

//设置axios得请求拦截器---在请求头上添加token
axios.interceptors.request.use(config=>{
    //从sessionStorage获取token值
    var token = sessionStorage.getItem("token");
    if(token){ //token不为空则为真
        //请求头中会携带token
        config.headers.token=token;
    }
    return config;
})

2.3.3验证token有没有被使用

前端方法:

<template>
    <div>
        <el-button type="primary" @click="getInfo">获取用户信息</el-button>
    </div>
</template>
 
<script>
    export default {
        name: "User",
        methods:{
            getInfo(){
                this.$http.get("http://localhost:8081/system/user/getInfo").then(result=>{
                    console.log(result)
                })
            }
        }
    }
</script>
 
<style scoped>
 
</style>

 后端接口:


@RestController
@RequestMapping("/system/user")
@Api(tags = "用户接口类")
public class UserController {
    @Autowired
    private RedisTemplate redisTemplate;
 
    @GetMapping("getInfo")
    public CommonResult getInfo(HttpServletRequest request){
        String token = request.getHeader("token");
        System.out.println(token);
        //根据token从redis中获取用户信息
        ValueOperations forValue = redisTemplate.opsForValue();
        User o = (User) forValue.get(token);
        return new CommonResult(2000,"获取用户信息成功",o);
    }
}

3 前置路由守卫

前置路由守卫:就是在路由跳转前加上自己得一些业务代码,在main.js中配置。类似于拦截器

//设置前置路由守卫 to:到哪个路由  from:从哪个路由来  next():放行到指定路由
router.beforeEach((to,from,next)=>{
      //获取跳转得路径
      var path = to.path;
      //判断是否为登录路由路径
      if(path==="/login"){
          console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
          //放行
          return next();
      }
      //其他路由路径 判断是否登录过
      var token = sessionStorage.getItem("token");
      if(token){
          return next();
      }
      //跳转登录
     return next("/login");
})

4. 整合shiro

4.1添加shiro依赖

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.7.0</version>
        </dependency>

4.2shiro的配置类


@Configuration //交于容器管理
public class ShiroConfig {
 
 
    //安全认证
    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(realm());
        return securityManager;
 
    }
 
 
 
    //安全数据源 自定义realm
    @Bean
    public Realm realm(){
        MyRealm myRealm=new MyRealm();
        myRealm.setCredentialsMatcher(credentialsMatcher());
        return myRealm;
    }
 
 
    //密码匹配器
    @Bean
    public CredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(1024);
        return credentialsMatcher;
    }
 
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    //shiro过滤器工厂 设置过滤的规则
    @Bean(value = "shiroFilter")
    public ShiroFilterFactoryBean filterFactoryBean(){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager());
 
        //设置拦截规则
        HashMap<String,String> map=new HashMap<>();
        map.put("/system/login","anon");
        map.put("/doc.html","anon");
        map.put("/swagger-ui.html","anon");
        map.put("/swagger/**","anon");
        map.put("/webjars/**", "anon");
        map.put("/swagger-resources/**","anon");
        map.put("/v2/**","anon");
        map.put("/static/**", "anon");
 
        map.put("/**","authc");
 
 
 
        factoryBean.setFilterChainDefinitionMap(map);
 
        //设置自定义认证过滤器
        HashMap<String,Filter> filterMap=new HashMap<String, Filter>();
        filterMap.put("authc",new LoginFilter(redisTemplate));
        factoryBean.setFilters(filterMap);
 
        return factoryBean;
    }
 
 
    //注册filter
    @Bean
    public FilterRegistrationBean<Filter> filterRegistrationBean(){
        FilterRegistrationBean<Filter> filterRegistrationBean=new FilterRegistrationBean<>();
        filterRegistrationBean.setName("shiroFilter");
        filterRegistrationBean.setFilter(new DelegatingFilterProxy());
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }
 
    //开始shiro注解
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
 
}

 4.3增加一个realm类对象


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 {
        String username = (String) token.getPrincipal();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        wrapper.eq("is_deleted",0);
        User user = userService.getOne(wrapper);
        if(user!=null){
            ByteSource bytes = ByteSource.Util.bytes(user.getSalt());
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),bytes,this.getName());
            return info;
        }
        return null;
    }
}

4.4修改controller代码


@RestController
@RequestMapping("system")
@Api(tags = "登录接口类")
public class LoginController {
    @Autowired
    private IUserService userService;
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    @PostMapping("login")
    @ApiOperation(value="登录接口")
    public CommonResult login(@RequestBody LoginVo loginVo){
        try{
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginVo.getName(), loginVo.getPassword(),loginVo.getSalt());
            subject.login(usernamePasswordToken);
 
            Object one = subject.getPrincipal();
 
            String token = UUID.randomUUID().toString();
            ValueOperations forValue = redisTemplate.opsForValue();
            forValue.set(token,one,24,TimeUnit.HOURS);
            return new CommonResult(2000,"登录成功",token);
        }catch (Exception e){
            return new CommonResult(5000,"登录失败",null);
        }
    }
 
}

5.主页布局 

<template >
    <el-container>
        <el-header>
            <div id="logo" style="display: inline-block;width:50%;height: 100%;float: left" >
                <img src="../assets/1.jpg" height="100%">
            </div>
            <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">
                        <el-dropdown-item command="info">个人信息</el-dropdown-item>
                        <el-dropdown-item command="logout">退出登录</el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
                </span>
        </el-header>
        <el-container>
            <el-aside width="200px">
                <el-menu
                        default-active="2"
                        class="el-menu-vertical-demo"
                        background-color="darkgrey"
                        text-color="#fff"
                        :router="true"
                        unique-opened="unique-opened"
                        active-text-color="#ffd04b">
                </el-menu>
            </el-aside>
            <el-main>
                <router-view/>
            </el-main>
        </el-container>
    </el-container>
</template>
 
<script>
    export default {
        name: "User",
        methods:{
            getInfo(){
                this.$http.get("http://localhost:8809/system/user/getInfo").then(result=>{
                    console.log(result)
                })
            }
        }
    }
</script>
 
<style>
    html, body, #app {
        height: 100%;
    }
 
    body, #app {
        padding: 0px;
        margin: 0px;
    }
 
    .el-container {
        height: 100%;
    }
 
    .el-header, .el-footer {
        background-color: grey;
        color: #333;
        line-height: 60px;
    }
 
    .el-aside {
        background-color: darkgrey;
        color: #333;
        line-height: 560px;
    }
 
    .el-aside > .el-menu {
        border: none;
    }
 
    .el-main {
        background-color: lightgrey;
        color: darkolivegreen;
    }
 
    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;
    }
</style>

5.1退出

5.1.1前端:

由于每个跳转都需要写ip和端口,我们可以在main.js中设置axios的基础路径

//设置axios基础路径
axios.defaults.baseURL="http://localhost:8808"

 

 

5.1.2后端接口

@GetMapping("logout")
    @ApiOperation(value = "退出接口")
    public CommonResult logout(HttpServletRequest request){
        String token = request.getHeader("token");
        if (redisTemplate.hasKey(token)) {
            redisTemplate.delete(token);
            return new CommonResult(2000, "退出成功", null);
        }
        return new CommonResult(5000,"退出失败",null);
    }

6.查询左侧菜单

6.1前端方法

initLeftMenu(){
                this.$http.get("/system/permission/leftMenu").then(result=>{
                      if(result.data.code===2000){
                           this.leftMenus=result.data.data;
                      }
                })
            },

 

6.2后端

6.2.1Controller层

远程仓库

java:

 https://gitee.com/panshih/springly.git

vue:

https://gitee.com/panshih/qianduanlaoyan.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值