后台管理页面(bootdo)

article/2025/8/27 2:56:12

项目源码:bootdo: 面向学习型的开源框架,简洁高效,减少过渡封装,展现技术本质

左边的菜单栏分析

数据库结构

样式实例 

 用树结构封装菜单数据,方便获取前后节点,通过自身id和父id相匹配,构建菜单。通过type确定类型,perms控制权限。

将菜单转换成树结构

import com.bootdo.common.domain.Tree;
import com.bootdo.common.utils.BuildTree;
import com.bootdo.system.dao.MenuDao;
import com.bootdo.system.dao.RoleMenuDao;
import com.bootdo.system.domain.MenuDO;
import com.bootdo.system.service.MenuService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.*;@Service
@Transactional(readOnly = true,rollbackFor = Exception.class)
public class MenuServiceImpl implements MenuService {@AutowiredMenuDao menuMapper;@AutowiredRoleMenuDao roleMenuMapper;/*** @param* @return 树形菜单  树结构方便获取父节点,子节点,节点属性*/@Cacheable@Overridepublic Tree<MenuDO> getSysMenuTree(Long id) {List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();List<MenuDO> menuDOs = menuMapper.listMenuByUserId(id);for (MenuDO sysMenuDO : menuDOs) {Tree<MenuDO> tree = new Tree<MenuDO>();tree.setId(sysMenuDO.getMenuId().toString());tree.setParentId(sysMenuDO.getParentId().toString());tree.setText(sysMenuDO.getName());Map<String, Object> attributes = new HashMap<>(16);attributes.put("url", sysMenuDO.getUrl());attributes.put("icon", sysMenuDO.getIcon());tree.setAttributes(attributes);trees.add(tree);}// 默认顶级菜单为0,根据数据库实际情况调整Tree<MenuDO> t = BuildTree.build(trees);return t;}@Overridepublic List<MenuDO> list(Map<String, Object> params) {List<MenuDO> menus = menuMapper.list(params);return menus;}// 开启事务,rollbackFor设置事务回滚的异常类型@Transactional(readOnly = false,rollbackFor = Exception.class)@Overridepublic int remove(Long id) {int result = menuMapper.remove(id);return result;}@Transactional(readOnly = false,rollbackFor = Exception.class)@Overridepublic int save(MenuDO menu) {int r = menuMapper.save(menu);return r;}@Transactional(readOnly = false,rollbackFor = Exception.class)@Overridepublic int update(MenuDO menu) {int r = menuMapper.update(menu);return r;}@Overridepublic MenuDO get(Long id) {MenuDO menuDO = menuMapper.get(id);return menuDO;}@Overridepublic Tree<MenuDO> getTree() {List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();List<MenuDO> menuDOs = menuMapper.list(new HashMap<>(16));for (MenuDO sysMenuDO : menuDOs) {Tree<MenuDO> tree = new Tree<MenuDO>();tree.setId(sysMenuDO.getMenuId().toString());tree.setParentId(sysMenuDO.getParentId().toString());tree.setText(sysMenuDO.getName());trees.add(tree);}// 默认顶级菜单为0,根据数据库实际情况调整Tree<MenuDO> t = BuildTree.build(trees);return t;}@Overridepublic Tree<MenuDO> getTree(Long id) {// 根据roleId查询权限List<MenuDO> menus = menuMapper.list(new HashMap<String, Object>(16));List<Long> menuIds = roleMenuMapper.listMenuIdByRoleId(id);List<Long> temp = menuIds;for (MenuDO menu : menus) {if (temp.contains(menu.getParentId())) {menuIds.remove(menu.getParentId());}}List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();List<MenuDO> menuDOs = menuMapper.list(new HashMap<String, Object>(16));for (MenuDO sysMenuDO : menuDOs) {Tree<MenuDO> tree = new Tree<MenuDO>();tree.setId(sysMenuDO.getMenuId().toString());tree.setParentId(sysMenuDO.getParentId().toString());tree.setText(sysMenuDO.getName());Map<String, Object> state = new HashMap<>(16);Long menuId = sysMenuDO.getMenuId();if (menuIds.contains(menuId)) {state.put("selected", true);} else {state.put("selected", false);}tree.setState(state);trees.add(tree);}// 默认顶级菜单为0,根据数据库实际情况调整Tree<MenuDO> t = BuildTree.build(trees);return t;}@Overridepublic Set<String> listPerms(Long userId) {List<String> perms = menuMapper.listUserPerms(userId);Set<String> permsSet = new HashSet<>();for (String perm : perms) {if (StringUtils.isNotBlank(perm)) {permsSet.addAll(Arrays.asList(perm.trim().split(",")));}}return permsSet;}@Overridepublic List<Tree<MenuDO>> listMenuTree(Long id) {List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();List<MenuDO> menuDOs = menuMapper.listMenuByUserId(id);for (MenuDO sysMenuDO : menuDOs) {Tree<MenuDO> tree = new Tree<MenuDO>();tree.setId(sysMenuDO.getMenuId().toString());tree.setParentId(sysMenuDO.getParentId().toString());tree.setText(sysMenuDO.getName());Map<String, Object> attributes = new HashMap<>(16);attributes.put("url", sysMenuDO.getUrl());attributes.put("icon", sysMenuDO.getIcon());tree.setAttributes(attributes);trees.add(tree);}// 默认顶级菜单为0,根据数据库实际情况调整List<Tree<MenuDO>> list = BuildTree.buildList(trees, "0");return list;}}

关于@Transactional

后台管理页面源码

整个页面通过页面嵌套组成,由index_v1.html和main.html组成

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="renderer" content="webkit"><title>面向学习型的开源框架,简洁高效,减少过渡封装,展现技术本质</title><meta name="keywords" content="面向学习型的开源框架,简洁高效,杜绝过渡封装,展现技术本质本质"><meta name="description" content="面向学习型的开源框架,简洁高效,杜绝过渡封装,展现技术本质本质"><!--[if lt IE 9]><meta http-equiv="refresh" content="0;ie.html"/><![endif]--><link rel="shortcut icon" href="favicon.ico"><link href="/css/bootstrap.min.css?v=3.3.6" rel="stylesheet"><link href="/css/font-awesome.min.css?v=4.4.0" rel="stylesheet"><link href="/css/plugins/toastr/toastr.min.css" rel="stylesheet"><link href="/css/animate.css" rel="stylesheet"><link href="/css/style.css?v=4.1.0" rel="stylesheet">
</head>
<body class="fixed-sidebar full-height-layout gray-bg"style="overflow: hidden">
<div id="wrapper"><!--左侧导航开始--><nav class="navbar-default navbar-static-side" role="navigation"><div class="nav-close"><i class="fa fa-times-circle"></i></div><div class="sidebar-collapse"><ul class="nav" id="side-menu"><li class="nav-header"><div><span><img alt="image" class="img-circle" height="60" width="60" th:src="${picUrl}"/></span><h3 class="" style="color: #ffffff"></i>BootDo后台管理系统</h3></div><div class="dropdown profile-element hidden"><a data-toggle="dropdown" class="dropdown-toggle" href="#"><span class="clear"><span class="block m-t-xs"><strong class="font-bold"th:text="${username}">admin</strong></span><span class="text-muted text-xs block">超级管理员<b class="caret"></b></span></span></a><ul class="dropdown-menu animated fadeInRight m-t-xs"><li><a @click="personal" href="#">修改头像</a></li><li><a @click="personal" href="#">个人资料</a></li><li><a @click="personal" href="#">密码修改</a></li><li><a @click="personal" href="#">信箱</a></li><li class="divider"></li><li><a href="/logout">安全退出</a></li></ul><div class="logo-element">BootDo</div></div></li><li><a href="#"> <i class="fa fa-home"></i> <spanclass="nav-label">主页</span> <span class="fa arrow"></span></a><ul class="nav nav-second-level"><li><a id="index001" class="J_menuItem" href="index_v1.html"data-index="0" th:href="@{/main}">了解BootDo</a></li></ul></li><li th:each="menu : ${menus}"><a href="#"> <iclass="fa fa fa-bar-chart-o" th:class="${menu.attributes.icon}"></i><span class="nav-label" th:text="${menu.text}">基础信息</span> <spanclass="fa arrow"></span></a><ul class="nav nav-second-level"><li th:each="cmenu : ${menu.children}"><a class="J_menuItem" href="graph_echarts.html"th:text="${cmenu.text}"th:href="${cmenu.attributes.url}">系统管理</a></li></ul></li></ul></div></nav><!--左侧导航结束--><!--右侧部分开始--><div id="page-wrapper" class="gray-bg dashbard-1"><div class="row border-bottom"><nav class="navbar navbar-static-top" role="navigation"style="margin-bottom: 0"><div class="navbar-header"><a class="navbar-minimalize minimalize-styl-2 btn btn-default "href="#" title="收起菜单"><i class="fa fa-bars"></i> </a><form role="search" class="navbar-form-custom"method="post" action=""><div class="form-group"><input type="text" placeholder="请输入您需要查找的内容 …"class="form-control" name="top-search" id="top-search"></div></form></div><ul class="nav navbar-top-links navbar-right"><li class="hidden-xs"><a href="/blog" target="_Blank"class=""><i class="fa fa-rss-square"></i>博客</a></li><li class="dropdown"><a class="dropdown-toggle count-info"data-toggle="dropdown" href="#"> <i class="fa fa-envelope"></i><span class="label label-warning">{{total}}</span>通知</a><ul class="dropdown-menu dropdown-messages"><li v-for="row in rows" class="m-t-xs"><div class="dropdown-messages-box"><a class="pull-left"> <iclass="fa fa-server"></i></a><div class="media-body"><small class="pull-right">{{row.before}}</small><strong>{{row.sender}}</strong>{{row.title}} <br><small class="text-muted">{{row.updateDate}}</small></div></div><div class="divider"></div></li><li><div class="text-center link-block"><a class="J_menuItem" href="/oa/notify/selfNotify"> <iclass="fa fa-envelope"></i> <strong> 查看所有消息</strong></a></div></li></ul></li><li class="hidden-xs"><a @click="personal" href="#" ><i class="fa fa-id-card"></i> 个人</a></li><li class="dropdown hidden-xs"><aclass="right-sidebar-toggle" aria-expanded="false"> <iclass="fa fa-tasks"></i> 主题</a></li></ul></nav></div><div class="row content-tabs"><button class="roll-nav roll-left J_tabLeft"><i class="fa fa-backward"></i></button><nav class="page-tabs J_menuTabs"><div class="page-tabs-content"><a href="javascript:;" class="active J_menuTab"data-id="index_v1.html">首页</a></div></nav><button class="roll-nav roll-right J_tabRight"><i class="fa fa-forward"></i></button><div class="btn-group roll-nav roll-right"><button class="dropdown J_tabClose" data-toggle="dropdown">关闭操作<span class="caret"></span></button><ul role="menu" class="dropdown-menu dropdown-menu-right"><li class="J_tabShowActive"><a>定位当前选项卡</a></li><li class="divider"></li><li class="J_tabCloseAll"><a>关闭全部选项卡</a></li><li class="J_tabCloseOther"><a>关闭其他选项卡</a></li></ul></div><a href="/logout" class="roll-nav roll-right J_tabExit"><iclass="fa fa fa-sign-out"></i> 退出</a></div><div class="row J_mainContent" id="content-main"><iframe class="J_iframe" name="iframe0" width="100%" height="100%"src="" th:src="@{/main}" frameborder="0" data-id="index_v1.html"seamless></iframe></div><div class="footer"><div class="pull-right">BootDo面向学习型的开源框架</div></div></div><!--右侧部分结束--><!--右侧边栏开始--><div id="right-sidebar"><div class="sidebar-container"><ul class="nav nav-tabs navs-3"><li class="active"><a data-toggle="tab" href="#tab-1"> <iclass="fa fa-gear"></i> 主题</a></li><li class=""><a data-toggle="tab" href="#tab-2"> 通知 </a></li><li><a data-toggle="tab" href="#tab-3"> 项目进度 </a></li></ul><div class="tab-content"><div id="tab-1" class="tab-pane active"><div class="sidebar-title"><h3><i class="fa fa-comments-o"></i> 主题设置</h3><small><i class="fa fa-tim"></i>你可以从这里选择和预览主题的布局和样式,这些设置会被保存在本地,下次打开的时候会直接应用这些设置。</small></div><div class="skin-setttings"><div class="title">主题设置</div><div class="setings-item"><span>收起左侧菜单</span><div class="switch"><div class="onoffswitch"><input type="checkbox" name="collapsemenu"class="onoffswitch-checkbox" id="collapsemenu"> <labelclass="onoffswitch-label" for="collapsemenu"> <spanclass="onoffswitch-inner"></span> <spanclass="onoffswitch-switch"></span></label></div></div></div><div class="setings-item"><span>固定顶部</span><div class="switch"><div class="onoffswitch"><input type="checkbox" name="fixednavbar"class="onoffswitch-checkbox" id="fixednavbar"> <labelclass="onoffswitch-label" for="fixednavbar"> <spanclass="onoffswitch-inner"></span> <spanclass="onoffswitch-switch"></span></label></div></div></div><div class="setings-item"><span> 固定宽度 </span><div class="switch"><div class="onoffswitch"><input type="checkbox" name="boxedlayout"class="onoffswitch-checkbox" id="boxedlayout"> <labelclass="onoffswitch-label" for="boxedlayout"> <spanclass="onoffswitch-inner"></span> <spanclass="onoffswitch-switch"></span></label></div></div></div><div class="title">皮肤选择</div><div class="setings-item default-skin nb"><span class="skin-name "> <a href="#" class="s-skin-0">默认皮肤 </a></span></div><div class="setings-item blue-skin nb"><span class="skin-name "> <a href="#" class="s-skin-1">蓝色主题 </a></span></div><div class="setings-item yellow-skin nb"><span class="skin-name "> <a href="#" class="s-skin-3">黄色/紫色主题 </a></span></div></div></div><div id="tab-2" class="tab-pane"><div class="sidebar-title"><h3><i class="fa fa-comments-o"></i> 最新通知</h3><small><i class="fa fa-tim"></i> 您当前有10条未读信息</small></div></div><div id="tab-3" class="tab-pane"><div class="sidebar-title"><h3><i class="fa fa-cube"></i> 最新任务</h3><small><i class="fa fa-tim"></i> 您当前有14个任务,10个已完成</small></div></div></div></div></div>
</div>
<!-- 全局js -->
<script src="/js/jquery.min.js?v=2.1.4"></script>
<script src="/js/bootstrap.min.js?v=3.3.6"></script>
<script src="/js/plugins/metisMenu/jquery.metisMenu.js"></script>
<script src="/js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<script src="/js/plugins/layer/layer.min.js"></script>
<!-- 自定义js -->
<script src="/js/app.js?v=4.1.0"></script>
<script type="text/javascript" src="/js/contabs.js"></script>
<!-- 第三方插件 -->
<script src="/js/plugins/pace/pace.min.js"></script>
<!-- vue -->
<script type="text/javascript"src="/js/vue.min.js"></script>
<script src="/js/appjs/oa/webSocket/sockjs.min.js"></script>
<script src="/js/appjs/oa/webSocket/stomp.min.js"></script>
<!-- Toastr script -->
<script src="/js/plugins/toastr/toastr.min.js"></script>
<script type="text/javascript">var stompClient = null;$(function () {connect();});function connect() {var sock = new SockJS("/endpointChat");var stomp = Stomp.over(sock);stomp.connect('guest', 'guest', function(frame) {/**
 订阅了/user/queue/notifications 发送的消息,这里雨在控制器的 convertAndSendToUser 定义的地址保持一致,
*  这里多用了一个/user,并且这个user 是必须的,使用user 才会发送消息到指定的用户。
*  */stomp.subscribe("/user/queue/notifications", handleNotification);stomp.subscribe('/topic/getResponse', function (response) { //订阅/topic/getResponse 目标发送的消息。这个是在控制器的@SendTo中定义的。toastr.options = {"closeButton": true,"debug": false,"progressBar": true,"positionClass": "toast-bottom-right","onclick": null,"showDuration": "400","hideDuration": "1000","timeOut": "7000","extendedTimeOut": "1000","showEasing": "swing","hideEasing": "linear","showMethod": "fadeIn","hideMethod": "fadeOut"}toastr.info(JSON.parse(response.body).responseMessage);});});function handleNotification(message) {wrapper.notify();toastr.info(message.body);}}var wrapper = new Vue({el: '#wrapper',data: {total: '',rows: '',},methods: {notify: function () {$.getJSON('/oa/notify/message', function (r) {wrapper.total = r.total;wrapper.rows = r.rows;});},personal: function () {layer.open({type: 2,title: '个人设置',maxmin: true,shadeClose: false,area: ['800px', '600px'],content: '/sys/user/personal'});}},created: function () {this.notify()}})
</script>
</body>
</html>

嵌套

        <div class="row J_mainContent" id="content-main"><iframe class="J_iframe" name="iframe0" width="100%" height="100%"src="" th:src="@{/main}" frameborder="0" data-id="index_v1.html"seamless></iframe></div>

了解链接

关于sockjs即时通信:SockJS实践:即时通信关键点 - 简书

关于iframe页面嵌套:Web前端之iframe详解 - 滥好人 - 博客园


http://chatgpt.dhexx.cn/article/unIId2Xm.shtml

相关文章

BootDo项目

因为本地项目需要使用bootdo和springCloud结合&#xff0c;所以&#xff0c;我今天开始学习一下bootdo的知识 但是从官网下载下一个bootdo项目导入idea之后发现并不能运行起来&#xff0c;报cant found git.exe 然后需要在官网下载对应版本的git。并且在setting–git中配置一下…

BootDo:源代码打包与自启动

一、内容介绍 BootDo是在SpringBoot基础上搭建的一个Java基础开发平台&#xff0c;很有学习价值&#xff0c;本文将介绍BootDo的源代码打包与自启动。 二、前置工作 1.本文bootdo下载的地址为https://gitee.com/lcg0124/bootdo&#xff0c;压缩包名为lcg0124-bootdo-master.…

BootDO框架的使用及介绍

BootDo是一个用于微服务的高效、低包、面向学习的开源Java EE开发框架。 BootDo是一个基于SpringBoot的Java基本开发平台。MyBatis是数据访问层&#xff0c;ApacheShiro是权限授权层&#xff0c;Ehcache缓存常用数据。 BootDo主要定位在后台管理系统中学习通信。内置后端管理…

API网关设计与实现(一)

API网关使用场景API网关技术选型与应用架构 API网关使用场景 在使用微服务架构场景下&#xff0c;客户端在调用后台微服务时&#xff0c;都需要进行登陆认证、权限认证、流量控制、负载均衡、健康检查等操作&#xff0c;这些操作是调用每一个微服务都必须。因此需要将该操作交给…

API 网关实现功能

负载均衡 当网关后面挂接同一应用的多个副本时&#xff0c;每次用户的请求都会通过网关的负载均衡算法&#xff0c;路由到对应的服务上面。例如&#xff1a;随机算法&#xff0c;权重算法&#xff0c;Hash 算法等等。 如果上游服务采取微服务的架构&#xff0c;也可以和注册中…

API 网关

前言 假设你正在开发一个电商网站&#xff0c;那么这里会涉及到很多后端的微服务&#xff0c;比如会员、商品、推荐服务等等。 那么这里就会遇到一个问题&#xff0c;APP/Browser 怎么去访问这些后端的服务&#xff1f;如果业务比较简单的话&#xff0c;可以给每个业务都分配一…

API网关在API安全性中的作用

从单一应用程序切换到微服务时&#xff0c;客户端的行为不能与客户端具有该应用程序的一个入口点的行为相同。简单来说就是微服务上的某一部分功能与单独实现该应用程序时存在不同。 目前在使用微服务时&#xff0c;客户端必须处理微服务体系结构带来的所有复杂性&#xff0c;…

API网关-APISIX简介

本文分享自天翼云开发者社区《API网关-APISIX简介》&#xff0c;作者:w****n Apache APISIX 是一个动态、实时、高性能的云原生 API 网关&#xff0c;提供了负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能。APISIX 构建于nginxngx_lua的技术…

初识API网关

网关是什么 百度百科&#xff1a;网关(Gateway)又称网间连接器、协议转换器&#xff0c;在网络层以上实现&#xff0c;连接两个或者多个广域网或者局域网。 我们这里说的是API网关&#xff0c;指的是所有api调用的统一入口。 api网关的在架构中的位置&#xff0c;如下图 ​…

API Gateway(API网关)介绍

API Gateway是一个服务器&#xff0c;也可以说是进入系统的唯一节点。这跟面向对象设计模式中的Facade模式很像。API Gateway封装内部系统的架构&#xff0c;并且提供API给各个客户端。它还可能有其他功能&#xff0c;如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处…

API网关简介|TaobaoAPI接入

API网关是什么 在日常工作中&#xff0c;不同的场合下&#xff0c;我们可能听说过很多次网关这个名称&#xff0c;这里说的网关特指API网关&#xff08;API Gataway&#xff09;。字面意思是指将所有API的调用统一接入API网关层&#xff0c;由网关层负责接入和输出。 那么在什…

谈谈 API 网关

作者&#xff1a;预流 链接&#xff1a;https://www.jianshu.com/p/b52a2773e75f 背景 理论上&#xff0c;客户端可以直接向微服务发送请求&#xff0c;每个微服务都有一个公开的URL&#xff0c;该URL将映射到微服务的负载均衡器&#xff0c;由它负责在可用实例之间分发请求。…

API网关之Kong网关简介

1. Kong简介 Kong是一款基于OpenResty&#xff08;Nginx Lua模块&#xff09;编写的高可用、易扩展的&#xff0c;由Mashape公司开源的API Gateway项目。Kong是基于NGINX和Apache Cassandra或PostgreSQL构建的&#xff0c;能提供易于使用的RESTful API来操作和配置API管理系统…

如何手撕一个API 网关(API Gateway)?

一、什么是API Gateway 一个比较普遍的定义如下&#xff1a; API网关是一个服务器&#xff0c;是系统的唯一入口。从面向对象设计的角度看&#xff0c;它与外观模式类似。API网关封装了系统内部架构&#xff0c;为每个客户端提供一个定制的API。 API网关方式的核心要点是&…

接口网关

1、什么是接口网关&#xff1f; 接口网关的作用&#xff1a;拦截请求&#xff0c;类似Nginx&#xff08;在nginx中配置拦截策略&#xff09;&#xff0c;对该请求进行权限控制&#xff0c;负载均衡、日志管理、接口调用监控等 所有请求都交给接口网关&#xff0c;让网关再进行…

微服务中的 API 网关(API Gateway)

以下是个人于搭建脚手架过程中的一些理念。 SpringCloud微服务架构中&#xff0c;会使用到网关服务。那么可想而知&#xff0c;网关作为边缘服务&#xff0c;其承受的压力是最大的&#xff0c;当然是要考虑网关的高可用&#xff0c;那么就需要多个网关服务集群部署&#xff0c…

API网关,网关平台API流量统一入口

API网关作为API网关平台的API流量的统一入口承担着非常重要的数据输入输出工作&#xff0c;API网关最核心的作用是对服务进行路由并进行数据转发&#xff0c;API网关将成为前后端交互以及内外网交互的唯一数据进出口&#xff0c;所以API网关适合于进行服务鉴权.数据缓存.流量控…

API 网关 (API Gataway)

API 网关 &#xff08;API Gataway&#xff09; API 网关出现的原因是微服务架构的出现&#xff0c;不同的微服务一般会有不同的网络地址&#xff0c;而外部客户端可能需要调用多个服务的接口才能完成一个业务需求&#xff0c;如果让客户端直接与各个微服务通信&#xff0c;会…

云原生中为什么需要API网关?

目录 一、API 的状态二、API 价值链三、API 挑战四、安全和访问控制五、可靠性和性能六、可见性和治理七、什么是 API 网关?八、为什么需要 API 网关?九、结论越来越多的组织正在转向 API 驱动的架构。 这种强大的方法可帮助他们快速创新,与同类最佳的外部服务集成,并以前所…

API网关介绍及选型(kong)

文章目录 为什么需要 API 网关API网关的功能API网关选型API 网关实现对比 kong vs tyk kongKong 支持功能Kong 的管理方式kong端点kong策略模式 docker启动kong基于kong oauth2 acl的用户接入权限管理整体流程需求实现 API网关是一个服务器&#xff0c;是系统的唯一入口。从面…