怎么使用SpringBoot+Vue实现动态菜单

发布时间:2022-07-15 10:23:51 作者:iii
来源:亿速云 阅读:249

怎么使用SpringBoot+Vue实现动态菜单

目录

  1. 引言
  2. 技术栈介绍
  3. 项目结构
  4. 后端实现
  5. 前端实现
  6. 前后端联调
  7. 权限控制
  8. 优化与扩展
  9. 部署与上线
  10. 总结

引言

在现代Web应用中,动态菜单是一个非常常见的需求。动态菜单可以根据用户的角色或权限动态生成,从而实现不同用户看到不同的菜单项。本文将详细介绍如何使用Spring Boot和Vue.js实现一个动态菜单系统。

技术栈介绍

Spring Boot

Spring Boot是一个基于Spring框架的快速开发框架,它简化了Spring应用的初始搭建和开发过程。Spring Boot提供了大量的自动配置,使得开发者可以快速构建独立的、生产级别的Spring应用。

Vue.js

Vue.js是一个渐进式JavaScript框架,用于构建用户界面。Vue.js的核心库只关注视图层,易于与其他库或现有项目集成。Vue.js的响应式数据绑定和组件化开发方式使得前端开发更加高效和灵活。

项目结构

后端项目结构

src
├── main
│   ├── java
│   │   └── com
│   │       └── example
│   │           ├── controller
│   │           ├── entity
│   │           ├── repository
│   │           ├── service
│   │           └── DemoApplication.java
│   └── resources
│       ├── application.properties
│       └── static
└── test
    └── java
        └── com
            └── example
                └── DemoApplicationTests.java

前端项目结构

src
├── assets
├── components
├── router
├── services
├── store
├── views
└── main.js

后端实现

数据库设计

首先,我们需要设计数据库表来存储菜单信息。假设我们有两个表:menurole,以及一个关联表role_menu

CREATE TABLE menu (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    path VARCHAR(100),
    parent_id INT,
    icon VARCHAR(50),
    sort INT
);

CREATE TABLE role (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL
);

CREATE TABLE role_menu (
    role_id INT,
    menu_id INT,
    PRIMARY KEY (role_id, menu_id),
    FOREIGN KEY (role_id) REFERENCES role(id),
    FOREIGN KEY (menu_id) REFERENCES menu(id)
);

实体类设计

接下来,我们设计对应的实体类。

@Entity
public class Menu {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String path;
    private Long parentId;
    private String icon;
    private Integer sort;

    // Getters and Setters
}

@Entity
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @ManyToMany
    @JoinTable(
        name = "role_menu",
        joinColumns = @JoinColumn(name = "role_id"),
        inverseJoinColumns = @JoinColumn(name = "menu_id")
    )
    private Set<Menu> menus;

    // Getters and Setters
}

Repository层

我们使用Spring Data JPA来操作数据库。

public interface MenuRepository extends JpaRepository<Menu, Long> {
    List<Menu> findByParentId(Long parentId);
}

public interface RoleRepository extends JpaRepository<Role, Long> {
}

Service层

在Service层,我们实现获取菜单的逻辑。

@Service
public class MenuService {
    @Autowired
    private MenuRepository menuRepository;

    public List<Menu> getMenusByRoleId(Long roleId) {
        return menuRepository.findByRoleId(roleId);
    }
}

Controller层

在Controller层,我们暴露API供前端调用。

@RestController
@RequestMapping("/api/menu")
public class MenuController {
    @Autowired
    private MenuService menuService;

    @GetMapping("/{roleId}")
    public List<Menu> getMenusByRoleId(@PathVariable Long roleId) {
        return menuService.getMenusByRoleId(roleId);
    }
}

前端实现

Vue项目初始化

首先,我们使用Vue CLI创建一个新的Vue项目。

vue create dynamic-menu

路由配置

src/router/index.js中配置路由。

import Vue from 'vue';
import Router from 'vue-router';
import Home from '@/views/Home.vue';

Vue.use(Router);

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  }
];

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

export default router;

动态菜单组件

我们创建一个DynamicMenu.vue组件来展示动态菜单。

<template>
  <div>
    <ul>
      <li v-for="menu in menus" :key="menu.id">
        <router-link :to="menu.path">{{ menu.name }}</router-link>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      menus: []
    };
  },
  created() {
    this.fetchMenus();
  },
  methods: {
    async fetchMenus() {
      const response = await this.$http.get('/api/menu/1'); // 假设角色ID为1
      this.menus = response.data;
    }
  }
};
</script>

菜单数据获取

src/services/menuService.js中封装获取菜单数据的逻辑。

import axios from 'axios';

export default {
  getMenusByRoleId(roleId) {
    return axios.get(`/api/menu/${roleId}`);
  }
};

前后端联调

跨域问题解决

在Spring Boot中,我们可以通过配置CorsConfig来解决跨域问题。

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true);
    }
}

接口联调

启动Spring Boot应用和Vue项目,确保后端API可以正常访问,并且前端能够正确获取菜单数据。

权限控制

基于角色的权限控制

在后端,我们可以通过Spring Security来实现基于角色的权限控制。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/api/menu/**").hasRole("USER")
            .anyRequest().authenticated()
            .and()
            .httpBasic();
    }
}

前端权限控制

在前端,我们可以根据用户的角色动态生成菜单。

export default {
  data() {
    return {
      menus: []
    };
  },
  created() {
    this.fetchMenus();
  },
  methods: {
    async fetchMenus() {
      const roleId = this.$store.state.user.roleId; // 假设用户角色ID存储在Vuex中
      const response = await this.$http.get(`/api/menu/${roleId}`);
      this.menus = response.data;
    }
  }
};

优化与扩展

菜单缓存

为了提高性能,我们可以将菜单数据缓存到Redis中。

@Service
public class MenuService {
    @Autowired
    private MenuRepository menuRepository;

    @Autowired
    private RedisTemplate<String, List<Menu>> redisTemplate;

    public List<Menu> getMenusByRoleId(Long roleId) {
        String key = "menus:" + roleId;
        List<Menu> menus = redisTemplate.opsForValue().get(key);
        if (menus == null) {
            menus = menuRepository.findByRoleId(roleId);
            redisTemplate.opsForValue().set(key, menus);
        }
        return menus;
    }
}

菜单图标

我们可以在菜单实体类中添加图标字段,并在前端展示图标。

<template>
  <div>
    <ul>
      <li v-for="menu in menus" :key="menu.id">
        <i :class="menu.icon"></i>
        <router-link :to="menu.path">{{ menu.name }}</router-link>
      </li>
    </ul>
  </div>
</template>

多级菜单

我们可以通过递归组件来实现多级菜单。

<template>
  <div>
    <ul>
      <li v-for="menu in menus" :key="menu.id">
        <i :class="menu.icon"></i>
        <router-link :to="menu.path">{{ menu.name }}</router-link>
        <DynamicMenu v-if="menu.children" :menus="menu.children" />
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'DynamicMenu',
  props: {
    menus: {
      type: Array,
      required: true
    }
  }
};
</script>

部署与上线

后端部署

我们可以将Spring Boot应用打包成JAR文件,并通过java -jar命令运行。

mvn clean package
java -jar target/demo-0.0.1-SNAPSHOT.jar

前端部署

我们可以将Vue项目打包成静态文件,并通过Nginx进行部署。

npm run build

然后将生成的dist目录下的文件上传到服务器,并配置Nginx。

server {
    listen 80;
    server_name example.com;

    location / {
        root /path/to/dist;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://localhost:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

总结

通过本文的介绍,我们详细讲解了如何使用Spring Boot和Vue.js实现一个动态菜单系统。我们从数据库设计、后端实现、前端实现、前后端联调、权限控制、优化与扩展、部署与上线等方面进行了全面的讲解。希望本文能够帮助读者更好地理解和掌握动态菜单的实现方法。

推荐阅读:
  1. iview-admin 动态菜单
  2. layui递归实现动态左侧菜单

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot vue

上一篇:怎么使用python sklearn画出决策树并保存为PDF

下一篇:怎么使用Vue+canvas实现视频截图功能

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》