您好,登录后才能下订单哦!
在现代Web应用中,动态菜单是一个非常常见的需求。动态菜单可以根据用户的角色或权限动态生成,从而实现不同用户看到不同的菜单项。本文将详细介绍如何使用Spring Boot和Vue.js实现一个动态菜单系统。
Spring Boot是一个基于Spring框架的快速开发框架,它简化了Spring应用的初始搭建和开发过程。Spring Boot提供了大量的自动配置,使得开发者可以快速构建独立的、生产级别的Spring应用。
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
首先,我们需要设计数据库表来存储菜单信息。假设我们有两个表:menu和role,以及一个关联表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
}
我们使用Spring Data JPA来操作数据库。
public interface MenuRepository extends JpaRepository<Menu, Long> {
    List<Menu> findByParentId(Long parentId);
}
public interface RoleRepository extends JpaRepository<Role, Long> {
}
在Service层,我们实现获取菜单的逻辑。
@Service
public class MenuService {
    @Autowired
    private MenuRepository menuRepository;
    public List<Menu> getMenusByRoleId(Long roleId) {
        return menuRepository.findByRoleId(roleId);
    }
}
在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 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实现一个动态菜单系统。我们从数据库设计、后端实现、前端实现、前后端联调、权限控制、优化与扩展、部署与上线等方面进行了全面的讲解。希望本文能够帮助读者更好地理解和掌握动态菜单的实现方法。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。