diff --git a/doc/docs/_sidebar.md b/doc/docs/_sidebar.md index eecfd729..12cddaba 100644 --- a/doc/docs/_sidebar.md +++ b/doc/docs/_sidebar.md @@ -1,8 +1,11 @@ -* 文档目录 - - * [快速体验](files/10010_快速体验.md?t=1553485733133) - * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1553485733154) - * [新增接口](files/10020_新增接口.md?t=1553485733154) - * [业务参数校验](files/10030_业务参数校验.md?t=1553485733154) - * [错误处理](files/10040_错误处理.md?t=1553485733154) - * [接口交互详解](files/10050_接口交互详解.md?t=1553485733155) +* [首页](/?t=1553513181526) +* 开发文档 + * [快速体验](files/10010_快速体验.md?t=1553513181526) + * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1553513181547) + * [新增接口](files/10020_新增接口.md?t=1553513181547) + * [业务参数校验](files/10030_业务参数校验.md?t=1553513181547) + * [错误处理](files/10040_错误处理.md?t=1553513181547) + * [接口交互详解](files/10050_接口交互详解.md?t=1553513181547) +* 原理分析 + * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1553513181547) + * [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1553513181547) diff --git a/doc/docs/files/90010_原理分析之@ApiMapping.md b/doc/docs/files/90010_原理分析之@ApiMapping.md new file mode 100644 index 00000000..3b823294 --- /dev/null +++ b/doc/docs/files/90010_原理分析之@ApiMapping.md @@ -0,0 +1,21 @@ +# 原理分析之@ApiMapping注解 + +@ApiMapping注解的使用方式参考了Spring自带的@PostMapping注解。 + +查看org.springframework.web.bind.annotation.PostMapping的类注释,有这么一句话: + + +> Specifically, @PostMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.POST). + +翻译过来就是说,@PostMapping是一个组合模式的注解,可以看成是@RequestMapping(method = RequestMethod.POST)快捷方式。 + +如果我们自己定义个Mapping,仿照@PostMapping的方式,然后作用在方法上面会不会成功呢?实践证明是可以的。 + +@ApiMapping注解正是仿照了@PostMapping注解,然后再添加了几个自己的属性,比如版本号字段。 + +那么如何才能通过path + 版本号来确定一个接口呢? + +springmvc提供了RequestCondition接口来实现这个功能,具体的操作可参考这篇文章:[让SpringMVC支持可版本管理的Restful接口](http://www.cnblogs.com/jcli/p/springmvc_restful_version.html) + +SOP对应的是`com.gitee.sop.servercommon.mapping.ApiMappingRequestCondition`,这个类在com.gitee.sop.servercommon.mapping下。可以从`ApiMappingHandlerMapping`类开始解读。 + diff --git a/doc/docs/files/90011_原理分析之路由存储.md b/doc/docs/files/90011_原理分析之路由存储.md new file mode 100644 index 00000000..cf456fa2 --- /dev/null +++ b/doc/docs/files/90011_原理分析之路由存储.md @@ -0,0 +1,25 @@ +# 原理分析之路由存储 + +SOP将路由信息存到了zookeeper当中,服务在启动时,将自己的路由信息上传到zookeeper中。 +网关监听存放路由的节点,动态更新到本地。 + +zookeeper存储路由的结构如下: + +```xml +/com.gitee.sop.route- 根节点 + /serviceId 服务节点,名字为服务名 + /route1 路由节点,名字为:name+version,存放路由信息 + /route2 + /... +``` + +服务启动时,创建`/serviceId`节点,然后遍历创建`/routeN`节点 + +同时,网关监听`服务节点`和`路由节点`,当有新服务加入时,网关会获取到新加入的路由节点信息, +同时路由节点下面的子节点也会被监听到。后续子节点的增删改都会被网关监听到,然后更新到本地。 + +服务上传路由相关代码在`com.gitee.sop.servercommon.manager.ServiceZookeeperApiMetaManager`类中 + +网关监听相关代码在`com.gitee.sop.gatewaycommon.manager.BaseRouteManager`中 + + diff --git a/doc/src/main/java/com/gitee/sop/doc/SidebarTest.java b/doc/src/main/java/com/gitee/sop/doc/SidebarTest.java index 1ab8dae0..9ca2632a 100644 --- a/doc/src/main/java/com/gitee/sop/doc/SidebarTest.java +++ b/doc/src/main/java/com/gitee/sop/doc/SidebarTest.java @@ -2,46 +2,90 @@ package com.gitee.sop.doc; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; /** * 生成_sidebar.md文件,直接运行即可 + * * @author tanghc */ public class SidebarTest { - static String format = " * [%s](files/%s?t=%s)\r\n"; - static String sidebar_format = "* 文档目录\r\n\r\n%s"; - - public static void main(String[] args) throws Exception { - String path = SidebarTest.class.getClassLoader().getResource("").getPath(); - String root = path.substring(0, path.indexOf("doc")) + "doc"; - String fileDir = root + "/docs/files"; - File dir = new File(fileDir); - File[] files = dir.listFiles(); - Stream filesStream = Stream.of(files); - List fileList = filesStream - .sorted(Comparator.comparing(File::getName)) - .collect(Collectors.toList()); - StringBuilder output = new StringBuilder(); - for (File file : fileList) { - String filename = file.getName(); - String title = filename.substring(filename.indexOf("_") + 1, filename.length() - 3); - String line = String.format(format, title, filename, System.currentTimeMillis()); - output.append(line); - } - - String sidebarContent = String.format(sidebar_format, output.toString()); - - System.out.println(sidebarContent); - - String sidebarFilepath = root + "/docs/_sidebar.md"; - - FileOutputStream out = new FileOutputStream(new File(sidebarFilepath)); - out.write(sidebarContent.getBytes()); - out.close(); - } + static String format = " * [%s](files/%s?t=%s)\r\n"; + static Map levelMap = new HashMap<>(8); + + static { + int i = 0; + levelMap.put("1", new Menu("* 开发文档\n", i++)); + levelMap.put("9", new Menu("* 原理分析\n", i++)); + } + + public static void main(String[] args) throws Exception { + String path = SidebarTest.class.getClassLoader().getResource("").getPath(); + String root = path.substring(0, path.indexOf("doc")) + "doc"; + String fileDir = root + "/docs/files"; + File dir = new File(fileDir); + File[] files = dir.listFiles(); + Stream filesStream = Stream.of(files); + Map> menuMap = filesStream + .sorted(Comparator.comparing(File::getName)) + .map(file -> { + FileExt fileExt = new FileExt(); + fileExt.menu = file.getName().substring(0, 1); + fileExt.file = file; + return fileExt; + }) + .collect(Collectors.groupingBy(FileExt::getMenu)); + + StringBuilder output = new StringBuilder(); + output.append("* [首页](/?t=" + System.currentTimeMillis() + ")\n"); + for (Map.Entry> entry : menuMap.entrySet()) { + Menu menu = levelMap.get(entry.getKey()); + output.append(menu.parentName); + for (FileExt fileExt : entry.getValue()) { + String filename = fileExt.file.getName(); + String title = filename.substring(filename.indexOf("_") + 1, filename.length() - 3); + String line = String.format(format, title, filename, System.currentTimeMillis()); + output.append(line); + } + } + + System.out.println(output); + + String sidebarFilepath = root + "/docs/_sidebar.md"; + + FileOutputStream out = new FileOutputStream(new File(sidebarFilepath)); + out.write(output.toString().getBytes()); + out.close(); + } + + static class Menu { + String parentName; + int order; + + public Menu(String parentName, int order) { + this.parentName = parentName; + this.order = order; + } + + } + + static class FileExt { + File file; + String menu; + + public File getFile() { + return file; + } + + public String getMenu() { + return menu; + } + } }