Compare commits
301 Commits
taobao_mod
...
master
Author | SHA1 | Date |
---|---|---|
|
19022bdbe1 | 3 years ago |
|
c7386f5f66 | 3 years ago |
|
7b930fa4b8 | 3 years ago |
|
a4ad90c90e | 4 years ago |
|
f974d75f45 | 4 years ago |
|
ba61d9dd58 | 4 years ago |
|
5a2c15a835 | 4 years ago |
|
fde8e73bdc | 4 years ago |
|
b1e346d48d | 4 years ago |
|
98b78339ab | 4 years ago |
|
08d7745f4e | 4 years ago |
|
f0c01dfd16 | 4 years ago |
|
66f5493e52 | 4 years ago |
|
efe46ff3e1 | 4 years ago |
|
a16a7aa2d3 | 4 years ago |
|
f8b8e5fca1 | 4 years ago |
|
06f400fb81 | 4 years ago |
|
0e20e75752 | 4 years ago |
|
1ef78cf582 | 4 years ago |
|
9ca2488f73 | 4 years ago |
|
e1cc2c982d | 4 years ago |
|
0b609305b1 | 4 years ago |
|
4eae92b033 | 4 years ago |
|
3ceb8cdc93 | 4 years ago |
|
fc82fab1cf | 4 years ago |
|
c573a5118d | 4 years ago |
|
2d6370ba1b | 4 years ago |
|
f09e00ddd7 | 4 years ago |
|
ccca3c26ee | 4 years ago |
|
764d492449 | 4 years ago |
|
4fe912ab58 | 4 years ago |
|
2d8948fd5a | 4 years ago |
|
2150d499bb | 4 years ago |
|
4055210942 | 4 years ago |
|
7819f21fbf | 4 years ago |
|
aaef05525e | 4 years ago |
|
e1b860c75a | 4 years ago |
|
472942e93e | 4 years ago |
|
a1fdf71f3e | 4 years ago |
|
bf977b2218 | 4 years ago |
|
c8fb583c7a | 4 years ago |
|
412a061668 | 4 years ago |
|
9c3bafdd92 | 4 years ago |
|
3804bf33a7 | 4 years ago |
|
31202908a4 | 4 years ago |
|
ef0c09cb02 | 4 years ago |
|
7ec542abce | 4 years ago |
|
8543754888 | 4 years ago |
|
f753faed66 | 4 years ago |
|
842f3a2ae5 | 4 years ago |
|
8aeb6c16bf | 4 years ago |
|
9058022933 | 4 years ago |
|
66f88ddf30 | 4 years ago |
|
307d63e21e | 4 years ago |
|
1b938b6ac2 | 4 years ago |
|
0430bb9bf6 | 4 years ago |
|
df8368cafc | 4 years ago |
|
c38939ae4b | 4 years ago |
|
66e5276360 | 4 years ago |
|
9188916926 | 4 years ago |
|
8cdb1fd031 | 4 years ago |
|
bf022b2da2 | 4 years ago |
|
7dccb19161 | 4 years ago |
|
de22c333d0 | 4 years ago |
|
db9a2f4e23 | 4 years ago |
|
1b19b65d81 | 4 years ago |
|
c05f08cc36 | 4 years ago |
|
1f1509f6db | 4 years ago |
|
581b4c869b | 4 years ago |
|
3fb6ac30e6 | 4 years ago |
|
3379ae1020 | 4 years ago |
|
f3ade3e7db | 4 years ago |
|
f32eccd492 | 4 years ago |
|
a01a6e88d3 | 4 years ago |
|
008c0f830f | 4 years ago |
|
73fbd7a072 | 4 years ago |
|
888825ba50 | 4 years ago |
|
d0fe92a96c | 4 years ago |
|
995d5ba623 | 4 years ago |
|
181b881bc5 | 4 years ago |
|
91f8c82f0e | 4 years ago |
|
5d00092cc5 | 4 years ago |
|
2c765af036 | 4 years ago |
|
d223659376 | 4 years ago |
|
419f041786 | 4 years ago |
|
7bae549b30 | 4 years ago |
|
4b135a62dd | 4 years ago |
|
a9a3dcdd0a | 4 years ago |
|
a577df49c1 | 4 years ago |
|
306742b72f | 4 years ago |
|
43bd300f4a | 4 years ago |
|
c475a1b8cd | 4 years ago |
|
5af379160c | 4 years ago |
|
0f5f659b48 | 5 years ago |
|
2f707cc99d | 5 years ago |
|
8efd1fc7b4 | 5 years ago |
|
e09f332fe6 | 5 years ago |
|
d642a4f9c6 | 5 years ago |
|
8d071e2ac3 | 5 years ago |
|
a3d97a4f8c | 5 years ago |
|
b053c7b4e5 | 5 years ago |
|
883a6afd0b | 5 years ago |
|
14e0383617 | 5 years ago |
|
32425e7903 | 5 years ago |
|
db384fe8a0 | 5 years ago |
|
9fa4ccce2b | 5 years ago |
|
4451918acb | 5 years ago |
|
f12b6e7b01 | 5 years ago |
|
1ff4303d2f | 5 years ago |
|
dee635ba6c | 5 years ago |
|
44e321720a | 5 years ago |
|
ced55fb3b2 | 5 years ago |
|
950e8a53c3 | 5 years ago |
|
e40d885078 | 5 years ago |
|
3fce909a35 | 5 years ago |
|
eecbce1e4d | 5 years ago |
|
019fa9db09 | 5 years ago |
|
e92f7c480d | 5 years ago |
|
f59223b36e | 5 years ago |
|
37f61700c1 | 5 years ago |
|
354d9c70b0 | 5 years ago |
|
3d68ea80cd | 5 years ago |
|
ae717f094f | 5 years ago |
|
c0e165f59b | 5 years ago |
|
376c5179b2 | 5 years ago |
|
01937163b3 | 5 years ago |
|
4e6de894f0 | 5 years ago |
|
a79272df2d | 5 years ago |
|
47b7037a12 | 5 years ago |
|
32c3925986 | 5 years ago |
|
bdd02abda2 | 5 years ago |
|
6bc596efe1 | 5 years ago |
|
d3bb2a6c29 | 5 years ago |
|
35161c300a | 5 years ago |
|
503631fcbe | 5 years ago |
|
413327df63 | 5 years ago |
|
63d9033858 | 5 years ago |
|
4b1fa84f36 | 5 years ago |
|
eeda6b36f2 | 5 years ago |
|
3247f4528a | 5 years ago |
|
b3aa515d01 | 5 years ago |
|
35564e66d8 | 5 years ago |
|
e1b287240e | 5 years ago |
|
1203aaf246 | 5 years ago |
|
3ab4e70be9 | 5 years ago |
|
a9a17731b2 | 5 years ago |
|
d5d987c3d2 | 5 years ago |
|
13e30c87b6 | 5 years ago |
|
2243a93f5b | 5 years ago |
|
7f6eee4c07 | 5 years ago |
|
bf42779369 | 5 years ago |
|
3a8be78532 | 5 years ago |
|
d76a2d7b68 | 5 years ago |
|
973c8a142d | 5 years ago |
|
326eba4d5a | 5 years ago |
|
309707f4a3 | 5 years ago |
|
84856e6865 | 5 years ago |
|
ae3ffd4f39 | 5 years ago |
|
832c6cb5fd | 5 years ago |
|
eb7f9d69c0 | 5 years ago |
|
a79eeb0208 | 5 years ago |
|
1f9b82776d | 5 years ago |
|
27ec6c5915 | 5 years ago |
|
2b08d4d9f2 | 5 years ago |
|
307065dded | 5 years ago |
|
6ab696dfaf | 5 years ago |
|
1370883af9 | 5 years ago |
|
c49b6eecaa | 5 years ago |
|
8c8b1c7442 | 5 years ago |
|
ad16abe9f4 | 5 years ago |
|
ca6021a67c | 5 years ago |
|
287dba9c89 | 5 years ago |
|
80003c44d3 | 5 years ago |
|
4ce2fc826d | 5 years ago |
|
dc584c36d6 | 5 years ago |
|
6f4c635855 | 5 years ago |
|
8e833c295f | 5 years ago |
|
3cef44dc96 | 5 years ago |
|
5e906bc4ba | 5 years ago |
|
446b98ea7a | 5 years ago |
|
06dbb21796 | 5 years ago |
|
80cc48b3b1 | 5 years ago |
|
4c552199fb | 5 years ago |
|
70b8525ccc | 5 years ago |
|
9dfaca5c6f | 5 years ago |
|
3b1b1845f8 | 5 years ago |
|
fc8f305e3d | 5 years ago |
|
a360fe713a | 5 years ago |
|
a94b8e2770 | 5 years ago |
|
dc8d28a256 | 5 years ago |
|
418c9ffc7a | 5 years ago |
|
02d3955d00 | 5 years ago |
|
3b2a7f92d7 | 5 years ago |
|
71d420c22e | 5 years ago |
|
ace5e1d5f6 | 5 years ago |
|
3c55c17818 | 5 years ago |
|
62bbb9a130 | 5 years ago |
|
92d2ba6a20 | 5 years ago |
|
9f83da1cda | 5 years ago |
|
58d42dc382 | 5 years ago |
|
645a14e4f2 | 5 years ago |
|
dc24e511a1 | 5 years ago |
|
34fed4b924 | 5 years ago |
|
c38c31031a | 5 years ago |
|
b4a805ccef | 5 years ago |
|
c4194817d5 | 5 years ago |
|
e661f45bd1 | 5 years ago |
|
5e081b5cfd | 5 years ago |
|
3ea29e8bf0 | 5 years ago |
|
c2489e4d7e | 5 years ago |
|
af69ccb730 | 5 years ago |
|
9ea5626074 | 5 years ago |
|
65342b54ee | 5 years ago |
|
98f2900e13 | 5 years ago |
|
676771f5d0 | 5 years ago |
|
0c4dd04bc7 | 5 years ago |
|
1850d6d567 | 5 years ago |
|
d0d4ab09f2 | 5 years ago |
|
ad742128b7 | 5 years ago |
|
87a2a3a629 | 5 years ago |
|
994960da31 | 5 years ago |
|
faa9310759 | 5 years ago |
|
3ca80dd6a6 | 5 years ago |
|
2eca422224 | 5 years ago |
|
c9b6f73a46 | 5 years ago |
|
636bbf20df | 5 years ago |
|
4ed9da7707 | 5 years ago |
|
f66d8bed59 | 5 years ago |
|
95f2ecf7dc | 5 years ago |
|
c6e5a20a81 | 5 years ago |
|
01bb3eae06 | 5 years ago |
|
c318534922 | 5 years ago |
|
9c507c8bd3 | 5 years ago |
|
725e08d8e7 | 5 years ago |
|
066e6a7d57 | 5 years ago |
|
2270c50886 | 5 years ago |
|
3f9365f5d5 | 5 years ago |
|
8410b90001 | 5 years ago |
|
6e54384571 | 5 years ago |
|
f223a56fd5 | 5 years ago |
|
8e8f24f5e8 | 5 years ago |
|
ebae72d883 | 5 years ago |
|
4fad0d67ef | 5 years ago |
|
34519ee280 | 5 years ago |
|
bdf3334732 | 5 years ago |
|
7468ce3524 | 5 years ago |
|
45ceebc34b | 5 years ago |
|
25fa143dda | 5 years ago |
|
f6f412d102 | 5 years ago |
|
77ecbb668c | 5 years ago |
|
e86296ad5b | 5 years ago |
|
4d260c72ab | 5 years ago |
|
27d5b0135c | 5 years ago |
|
a22bfb84db | 5 years ago |
|
9e905666c8 | 5 years ago |
|
5aa11c734e | 5 years ago |
|
43e5707c01 | 5 years ago |
|
1ac069fae8 | 5 years ago |
|
7dab8da699 | 5 years ago |
|
160e57df0e | 5 years ago |
|
42979771ee | 5 years ago |
|
315177677c | 5 years ago |
|
f1d8cc8318 | 5 years ago |
|
49cd8f7fda | 5 years ago |
|
8239a536b9 | 5 years ago |
|
c8598b5a0e | 5 years ago |
|
67a3119e5d | 5 years ago |
|
8a87e945de | 5 years ago |
|
5b58f110a2 | 5 years ago |
|
a20c3fa14c | 5 years ago |
|
199cb67fa3 | 5 years ago |
|
57c8f34c3b | 5 years ago |
|
4456d15182 | 5 years ago |
|
e163dbc2a8 | 5 years ago |
|
c62f13e897 | 5 years ago |
|
4d6693aca2 | 5 years ago |
|
f86e569c03 | 5 years ago |
|
ab56f20939 | 5 years ago |
|
71bcf2da1b | 5 years ago |
|
8e0677a86e | 5 years ago |
|
294b58a7f6 | 5 years ago |
|
4c1197e181 | 5 years ago |
|
33e50a1fae | 5 years ago |
|
0fea955db9 | 5 years ago |
|
ee30f18d53 | 5 years ago |
|
a68ac1a10c | 5 years ago |
|
6df91ddfda | 5 years ago |
|
57d0ccbede | 5 years ago |
|
c120788857 | 5 years ago |
|
d4225aff9d | 5 years ago |
|
cc8bb34bb0 | 5 years ago |
|
06229d6b90 | 5 years ago |
|
a90d0214a8 | 5 years ago |
|
f2e6ea6201 | 5 years ago |
|
e8b251ddb8 | 5 years ago |
|
acb259fe6f | 5 years ago |
|
a1f2954544 | 5 years ago |
|
2d10d58935 | 5 years ago |
|
3118f07bbc | 5 years ago |
|
6406f023db | 5 years ago |
|
7f83dbe5b0 | 5 years ago |
@ -0,0 +1,16 @@ |
|||||||
|
FROM java:8 |
||||||
|
VOLUME /tmp |
||||||
|
VOLUME /sop |
||||||
|
|
||||||
|
# 将所有应用放到一个镜像当中 |
||||||
|
ADD sop-gateway/target/*.jar sop/sop-gateway/sop-gateway.jar |
||||||
|
ADD sop-admin/sop-admin-server/target/*.jar sop/sop-admin/sop-admin.jar |
||||||
|
ADD sop-website/sop-website-server/target/*.jar sop/sop-website/sop-website.jar |
||||||
|
ADD sop-auth/target/*.jar sop/sop-auth/sop-auth.jar |
||||||
|
ADD sop-example/sop-story/target/*.jar sop/sop-story/sop-story.jar |
||||||
|
|
||||||
|
# 拷贝启动脚本 |
||||||
|
COPY docker-entrypoint.sh /usr/local/bin/ |
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh |
||||||
|
|
||||||
|
ENTRYPOINT ["docker-entrypoint.sh"] |
@ -0,0 +1,27 @@ |
|||||||
|
/target/ |
||||||
|
!.mvn/wrapper/maven-wrapper.jar |
||||||
|
|
||||||
|
### STS ### |
||||||
|
.apt_generated |
||||||
|
.classpath |
||||||
|
.factorypath |
||||||
|
.project |
||||||
|
.settings |
||||||
|
.springBeans |
||||||
|
.sts4-cache |
||||||
|
|
||||||
|
### IntelliJ IDEA ### |
||||||
|
.idea |
||||||
|
*.iws |
||||||
|
*.iml |
||||||
|
*.ipr |
||||||
|
*.png |
||||||
|
|
||||||
|
### NetBeans ### |
||||||
|
/nbproject/private/ |
||||||
|
/nbbuild/ |
||||||
|
/dist/ |
||||||
|
/nbdist/ |
||||||
|
/.nb-gradle/ |
||||||
|
/build/ |
||||||
|
|
@ -1,39 +1,36 @@ |
|||||||
* [首页](/?t=1591927043815) |
* [首页](/?t=1616211903021) |
||||||
* 开发文档 |
* 开发文档 |
||||||
* [快速体验](files/10010_快速体验.md?t=1591927043817) |
* [快速体验](files/10010_快速体验.md?t=1616211903027) |
||||||
* [项目接入到SOP](files/10011_项目接入到SOP.md?t=1591927043835) |
* [项目接入到SOP](files/10011_项目接入到SOP.md?t=1616211903048) |
||||||
* [新增接口](files/10020_新增接口.md?t=1591927043836) |
* [新增接口](files/10020_新增接口.md?t=1616211903048) |
||||||
* [开发流程](files/10021_开发流程.md?t=1591927043836) |
* [开发流程](files/10021_开发流程.md?t=1616211903048) |
||||||
* [业务参数校验](files/10030_业务参数校验.md?t=1591927043836) |
* [用户注册](files/10022_用户注册.md?t=1616211903049) |
||||||
* [错误处理](files/10040_错误处理.md?t=1591927043836) |
* [业务参数校验](files/10030_业务参数校验.md?t=1616211903049) |
||||||
* [编写文档](files/10041_编写文档.md?t=1591927043836) |
* [错误处理](files/10040_错误处理.md?t=1616211903049) |
||||||
* [接口交互详解](files/10050_接口交互详解.md?t=1591927043836) |
* [编写文档](files/10041_编写文档.md?t=1616211903049) |
||||||
* [easyopen支持](files/10070_easyopen支持.md?t=1591927043836) |
* [接口交互详解](files/10050_接口交互详解.md?t=1616211903049) |
||||||
* [使用签名校验工具](files/10080_使用签名校验工具.md?t=1591927043836) |
* [使用签名校验工具](files/10080_使用签名校验工具.md?t=1616211903049) |
||||||
* [ISV管理](files/10085_ISV管理.md?t=1591927043836) |
* [ISV管理](files/10085_ISV管理.md?t=1616211903050) |
||||||
* [自定义返回结果](files/10087_自定义返回结果.md?t=1591927043837) |
* [自定义返回结果](files/10087_自定义返回结果.md?t=1616211903050) |
||||||
* [自定义过滤器](files/10088_自定义过滤器.md?t=1591927043837) |
* [自定义过滤器](files/10088_自定义过滤器.md?t=1616211903050) |
||||||
* [自定义校验token](files/10089_自定义校验token.md?t=1591927043837) |
* [自定义校验token](files/10089_自定义校验token.md?t=1616211903050) |
||||||
* [网关拦截器](files/10090_网关拦截器.md?t=1591927043837) |
* [网关拦截器](files/10090_网关拦截器.md?t=1616211903050) |
||||||
* [路由授权](files/10090_路由授权.md?t=1591927043837) |
* [路由授权](files/10091_路由授权.md?t=1616211903050) |
||||||
* [接口限流](files/10092_接口限流.md?t=1591927043837) |
* [接口限流](files/10092_接口限流.md?t=1616211903051) |
||||||
* [路由监控](files/10093_路由监控.md?t=1591927043837) |
* [路由监控](files/10093_路由监控.md?t=1616211903051) |
||||||
* [SDK开发](files/10095_SDK开发.md?t=1591927043837) |
* [SDK开发](files/10095_SDK开发.md?t=1616211903051) |
||||||
* [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1591927043837) |
* [应用授权](files/10097_应用授权.md?t=1616211903051) |
||||||
* [应用授权](files/10097_应用授权.md?t=1591927043837) |
* [提供restful接口](files/10100_提供restful接口.md?t=1616211903051) |
||||||
* [提供restful接口](files/10100_提供restful接口.md?t=1591927043838) |
* [文件上传](files/10104_文件上传.md?t=1616211903051) |
||||||
* [文件上传](files/10104_文件上传.md?t=1591927043838) |
* [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1616211903052) |
||||||
* [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1591927043838) |
* [预发布灰度发布](files/10110_预发布灰度发布.md?t=1616211903052) |
||||||
* [预发布灰度发布](files/10110_预发布灰度发布.md?t=1591927043838) |
* [动态修改请求参数](files/10111_动态修改请求参数.md?t=1616211903052) |
||||||
* [动态修改请求参数](files/10111_动态修改请求参数.md?t=1591927043838) |
* [使用eureka](files/10112_使用eureka.md?t=1616211903052) |
||||||
* [使用eureka](files/10112_使用eureka.md?t=1591927043838) |
* [超时设置](files/10113_超时设置.md?t=1616211903052) |
||||||
* [扩展其它注册中心](files/10113_扩展其它注册中心.md?t=1591927043838) |
|
||||||
* 原理分析 |
* 原理分析 |
||||||
* [网关性能测试](files/90001_网关性能测试.md?t=1591927043838) |
* [网关性能测试](files/90001_网关性能测试.md?t=1616211903052) |
||||||
* [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1591927043838) |
* [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1616211903052) |
||||||
* [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1591927043838) |
* [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1616211903052) |
||||||
* [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1591927043839) |
* [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1616211903052) |
||||||
* [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1591927043839) |
* [原理分析之预发布灰度发布](files/90014_原理分析之预发布灰度发布.md?t=1616211903052) |
||||||
* [原理分析之预发布灰度发布](files/90014_原理分析之预发布灰度发布.md?t=1591927043839) |
* [常见问题](files/90100_常见问题.md?t=1616211903053) |
||||||
* [2.x升3.x注意事项](files/90099_2.x升3.x注意事项.md?t=1591927043839) |
|
||||||
* [常见问题](files/90100_常见问题.md?t=1591927043839) |
|
||||||
|
@ -0,0 +1,11 @@ |
|||||||
|
# 用户(ISV)注册 |
||||||
|
|
||||||
|
新增ISV有两种方式 |
||||||
|
|
||||||
|
- 方式1 |
||||||
|
|
||||||
|
启动sop-admin,在admin后台`ISV管理添加` |
||||||
|
|
||||||
|
- 方式2 |
||||||
|
|
||||||
|
启动`sop-website-server`,用户访问自主注册 |
@ -1,78 +0,0 @@ |
|||||||
# easyopen支持 |
|
||||||
|
|
||||||
SOP对easyopen项目提供了很好的支持,如果您的服务端使用了easyopen框架,相关配置步骤如下: |
|
||||||
|
|
||||||
## 服务端配置 |
|
||||||
|
|
||||||
首先是服务端相关配置 |
|
||||||
|
|
||||||
- pom添加依赖 |
|
||||||
|
|
||||||
```xml |
|
||||||
<!-- sop接入依赖 --> |
|
||||||
<dependency> |
|
||||||
<groupId>com.gitee.sop</groupId> |
|
||||||
<artifactId>sop-service-common</artifactId> |
|
||||||
<version>最新版本</version> |
|
||||||
</dependency> |
|
||||||
|
|
||||||
<!-- 使用nacos注册中心 |
|
||||||
版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。 |
|
||||||
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-alibaba-nacos-discovery |
|
||||||
--> |
|
||||||
<dependency> |
|
||||||
<groupId>org.springframework.cloud</groupId> |
|
||||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
|
||||||
<version>0.2.2.RELEASE</version> |
|
||||||
<exclusions> |
|
||||||
<exclusion> |
|
||||||
<groupId>com.alibaba.nacos</groupId> |
|
||||||
<artifactId>nacos-client</artifactId> |
|
||||||
</exclusion> |
|
||||||
</exclusions> |
|
||||||
</dependency> |
|
||||||
<dependency> |
|
||||||
<groupId>com.alibaba.nacos</groupId> |
|
||||||
<artifactId>nacos-client</artifactId> |
|
||||||
<version>1.1.0</version> |
|
||||||
</dependency> |
|
||||||
|
|
||||||
<dependency> |
|
||||||
<groupId>net.oschina.durcframework</groupId> |
|
||||||
<artifactId>easyopen</artifactId> |
|
||||||
<version>1.16.1</version> |
|
||||||
</dependency> |
|
||||||
<!-- sop接入依赖 end --> |
|
||||||
``` |
|
||||||
|
|
||||||
easyopen版本必须升级到1.16.1 |
|
||||||
|
|
||||||
- 启动类上面添加注解@EnableDiscoveryClient,将自己注册到注册中心 |
|
||||||
- 新增一个配置类,继承EasyopenServiceConfiguration,内容为空 |
|
||||||
|
|
||||||
```java |
|
||||||
@Configuration |
|
||||||
public class SopConfig extends EasyopenServiceConfiguration { |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
服务端配置完毕,重启服务。 |
|
||||||
|
|
||||||
## 网关端配置 |
|
||||||
|
|
||||||
接下来是网关的配置 |
|
||||||
|
|
||||||
- 打开ZuulConfig.java,注释掉原本的@Configuration,新增如下Configuration |
|
||||||
|
|
||||||
```java |
|
||||||
@Configuration |
|
||||||
public class ZuulConfig extends EasyopenZuulConfiguration { |
|
||||||
|
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
配置完毕,重启网关服务,可运行测试用例`EasyopenClientPostTest.java`验证 |
|
||||||
|
|
||||||
**注:** 配置完成后easyopen签名校验将会关闭,改用网关端来校验;网关对easyopen返回的结果不进行处理,直接返回服务端的结果。 |
|
||||||
|
|
||||||
完整配置可查看sop-example/sop-easyopen项目 |
|
@ -1,103 +1,39 @@ |
|||||||
# 自定义过滤器 |
# 自定义过滤器 |
||||||
|
|
||||||
## zuul过滤器 |
演示在网关追加一个header |
||||||
|
|
||||||
zuul过滤器列表如下: |
|
||||||
|
|
||||||
| 类型 | 顺序 | 过滤器 | 功能 | |
|
||||||
| ----- | ---- | ----------------------- | ---------------------------- | |
|
||||||
| pre | -1000 | PreValidateFilter (SOP自带) | 校验签名 | |
|
||||||
| pre | -998 | PreLimitFilter (SOP自带) | 限流拦截器 | |
|
||||||
| pre | -3 | ServletDetectionFilter | 标记处理 Servlet 的类型 | |
|
||||||
| pre | -2 | Servlet30WrapperFilter | 包装 HttpServletRequest 请求 | |
|
||||||
| pre | -1 | FormBodyWrapperFilter | 包装请求体 Servlet30WrapperFilter | |
|
||||||
| pre | 1 | DebugFilter | 标记调试标志 | |
|
||||||
| pre | 5 | PreDecorationFilter | 决定路由转发过滤器 | |
|
||||||
| route | 10 | RibbonRoutingFilter | serviceId 请求转发 | |
|
||||||
| route | 100 | SimpleHostRoutingFilter | url 请求转发 | |
|
||||||
| route | 500 | SendForwardFilter | forward 请求转发 | |
|
||||||
| post | 0 | SendErrorFilter | 处理有错误的请求响应 | |
|
||||||
| post | 1000 | SendResponseFilter | 处理正常的请求响应 | |
|
||||||
|
|
||||||
顺序值小的优先执行,`-3`之前是sop自带的过滤器,`-3`开始是zuul自带的过滤器。 |
|
||||||
|
|
||||||
创建自定义过滤器可以从`-500`开始(-1000 ~ -501留给SOP)。下面是一个自定义过虑器的例子: |
|
||||||
|
|
||||||
```java |
```java |
||||||
public class PreXXXFilter extends BaseZuulFilter { |
public class CustomFilter implements GlobalFilter, Ordered { |
||||||
@Override |
|
||||||
protected FilterType getFilterType() { |
|
||||||
return FilterType.PRE; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected int getFilterOrder() { |
|
||||||
return -500; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected Object doRun(RequestContext requestContext) throws ZuulException { |
|
||||||
HttpServletRequest request = requestContext.getRequest(); |
|
||||||
ApiParam apiParam = ZuulContext.getApiParam(); |
|
||||||
String appKey = apiParam.fetchAppKey(); |
|
||||||
// ...业务处理 |
|
||||||
|
|
||||||
// 固定返回null |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
过滤器编写完毕后,在Config中使用: |
|
||||||
|
|
||||||
```java |
|
||||||
@Configuration |
|
||||||
public class ZuulConfig extends AlipayZuulConfiguration { |
|
||||||
|
|
||||||
... |
|
||||||
|
|
||||||
@Bean |
|
||||||
PreXXXFilter preXXXFilter() { |
|
||||||
return new PreXXXFilter(); |
|
||||||
} |
|
||||||
... |
|
||||||
|
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
## spring cloud gateway |
|
||||||
|
|
||||||
跟zuul同理 |
|
||||||
|
|
||||||
```java |
|
||||||
public class XXXFilter implements GlobalFilter, Ordered { |
|
||||||
|
|
||||||
@Override |
@Override |
||||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
||||||
ApiParam apiParam = (ApiParam)exchange.getAttribute(SopConstants.CACHE_API_PARAM); |
// 演示在网关追加header |
||||||
String appKey = apiParam.fetchAppKey(); |
ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange); |
||||||
// ...业务处理 |
String token = apiParam.fetchAccessToken(); |
||||||
... |
ServerWebExchange serverWebExchange = ServerWebExchangeUtil.addHeaders(exchange, httpHeaders -> { |
||||||
return chain.filter(exchange); |
httpHeaders.add("token", token); |
||||||
|
}); |
||||||
|
return chain.filter(serverWebExchange); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public int getOrder() { |
public int getOrder() { |
||||||
return -500; |
// 自定义过滤器可以从0开始 |
||||||
|
return 0; |
||||||
} |
} |
||||||
} |
} |
||||||
``` |
``` |
||||||
|
|
||||||
使用过滤器: |
使用过滤器,在sop-gateway中找到MyConfig,添加: |
||||||
|
|
||||||
```java |
```java |
||||||
@Configuration |
@Configuration |
||||||
public class GatewayConfig extends AlipayGatewayConfiguration { |
public class MyConfig { |
||||||
|
|
||||||
... |
... |
||||||
@Bean |
@Bean |
||||||
XXXFilter xxxFilter() { |
CustomFilter customFilter() { |
||||||
return new XXXFilter(); |
return new CustomFilter(); |
||||||
} |
} |
||||||
... |
... |
||||||
} |
} |
||||||
|
@ -1,16 +0,0 @@ |
|||||||
# 使用SpringCloudGateway |
|
||||||
|
|
||||||
修改`sop-gateway/pom.xml`配置,artifactId部分改成`sop-bridge-gateway`即可 |
|
||||||
|
|
||||||
```xml |
|
||||||
<dependency> |
|
||||||
<groupId>com.gitee.sop</groupId> |
|
||||||
<!-- 使用zuul作为网关 --> |
|
||||||
<!--<artifactId>sop-bridge-zuul</artifactId>--> |
|
||||||
<!-- 使用spring cloud gateway作为网关 --> |
|
||||||
<artifactId>sop-bridge-gateway</artifactId> |
|
||||||
<version>对应版本</version> |
|
||||||
</dependency> |
|
||||||
``` |
|
||||||
|
|
||||||
修改完毕,重启sop-gateway |
|
@ -1,53 +1,3 @@ |
|||||||
# 使用eureka |
# 使用eureka |
||||||
|
|
||||||
## 修改网关 |
切换到`eureka`分支 |
||||||
|
|
||||||
- 打开`/sop-gateway/pom.xml` |
|
||||||
|
|
||||||
注释nacos相关依赖 |
|
||||||
|
|
||||||
添加eureka依赖: |
|
||||||
|
|
||||||
```xml |
|
||||||
<dependency> |
|
||||||
<groupId>org.springframework.cloud</groupId> |
|
||||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> |
|
||||||
</dependency> |
|
||||||
``` |
|
||||||
|
|
||||||
- 打开sop-gateway下`application-dev.properties` |
|
||||||
|
|
||||||
注释nacos配置 |
|
||||||
|
|
||||||
```properties |
|
||||||
# nacos cloud配置 |
|
||||||
#spring.cloud.nacos.discovery.server-addr=${nacos.url} |
|
||||||
#nacos.config.server-addr=${nacos.url} |
|
||||||
``` |
|
||||||
|
|
||||||
添加eureka配置 |
|
||||||
|
|
||||||
```properties |
|
||||||
# eureka注册中心 |
|
||||||
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ |
|
||||||
``` |
|
||||||
|
|
||||||
## 微服务端修改 |
|
||||||
|
|
||||||
步骤同上 |
|
||||||
|
|
||||||
## admin修改 |
|
||||||
|
|
||||||
打开`application-dev.properties`,新增配置 |
|
||||||
|
|
||||||
```properties |
|
||||||
# 网关地址,多个用逗号隔开 |
|
||||||
# 在不使用nacos时有用,使用nacos时注释掉 |
|
||||||
gateway.host=127.0.0.1:8081 |
|
||||||
|
|
||||||
# eureka注册中心 |
|
||||||
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ |
|
||||||
# 如果使用eureka,填eureka,使用nacos,填eureka |
|
||||||
registry.name=eureka |
|
||||||
``` |
|
||||||
|
|
||||||
|
@ -1,86 +0,0 @@ |
|||||||
# 扩展其它注册中心 |
|
||||||
|
|
||||||
SOP默认使用的注册中心是[nacos](https://nacos.io/),可以扩展实现其它注册中心,其中`eureka`分支是已经扩展好的,使用eureka注册中心。 |
|
||||||
|
|
||||||
现在以扩展[consul](https://www.consul.io/)为例,说下具体扩展步骤: |
|
||||||
|
|
||||||
- 扩展注册中心监听 |
|
||||||
|
|
||||||
在`sop-gateway-common`工程下,找到com.gitee.sop.gatewaycommon.route包,可以看到有两个类 |
|
||||||
|
|
||||||
`EurekaRegistryListener`和`NacosRegistryListener` |
|
||||||
|
|
||||||
这两个类的作用是监听注册中心服务注册,从而触发事件,然后获取新注册的服务。 |
|
||||||
|
|
||||||
新建一个类:`ConsulRegistryListener`,继承`BaseRegistryListener` |
|
||||||
|
|
||||||
实现onEvent方法,具体内容可参考`EurekaRegistryListener`类 |
|
||||||
|
|
||||||
```java |
|
||||||
public class ConsulRegistryListener extends BaseRegistryListener { |
|
||||||
/** |
|
||||||
* 注册中心触发事件,可以从中获取服务<br> |
|
||||||
* |
|
||||||
* 这个方法做的事情有2个:<br> |
|
||||||
* |
|
||||||
* 1. 找出新注册的服务,调用pullRoutes方法<br> |
|
||||||
* 2. 找出删除的服务,调用removeRoutes方法<br> |
|
||||||
* |
|
||||||
* @param applicationEvent 事件体 |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void onEvent(ApplicationEvent applicationEvent) { |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
配置类中新增: |
|
||||||
|
|
||||||
```java |
|
||||||
@Bean |
|
||||||
@ConditionalOnProperty("spring.cloud.consul.host") |
|
||||||
RegistryListener registryListenerConsul() { |
|
||||||
return new ConsulRegistryListener(); |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
其中`@ConditionalOnProperty("spring.cloud.consul.host")`的意思是只有配置了`spring.cloud.consul.host`属性,这个Bean才会被Spring注入 |
|
||||||
|
|
||||||
`sop-gateway`工程添加`Spring Cloud Consul`相关依赖,配置文件新增consul配置 |
|
||||||
|
|
||||||
- 扩展admin实现 |
|
||||||
|
|
||||||
找到`sop-admin-server`工程下com.gitee.sop.adminserver.service包,可以看到有两个类,`RegistryServiceEurekaImpl`和`RegistryServiceNacosImpl` |
|
||||||
它们实现了`com.gitee.sop.adminserver.service.RegistryService`接口,因此我们要新建一个consul对应的类 |
|
||||||
|
|
||||||
新建`RegistryServiceConsulImpl`,然后实现RegistryService接口中的方法,具体可参考RegistryServiceEurekaImpl |
|
||||||
|
|
||||||
```java |
|
||||||
public class RegistryServiceConsulImpl implements RegistryService { |
|
||||||
|
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
打开`com.gitee.sop.adminserver.config.WebConfig`类 |
|
||||||
|
|
||||||
新增一条配置 |
|
||||||
|
|
||||||
```java |
|
||||||
/** |
|
||||||
* 当配置了registry.name=eureka生效。 |
|
||||||
* |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
@Bean |
|
||||||
@ConditionalOnProperty(value = "registry.name", havingValue = "consul") |
|
||||||
RegistryService registryServiceEureka() { |
|
||||||
return new RegistryServiceConsulImpl(); |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
application配置文件新增一条配置: |
|
||||||
|
|
||||||
```properties |
|
||||||
registry.name=consul |
|
||||||
``` |
|
@ -0,0 +1,14 @@ |
|||||||
|
# 超时设置 |
||||||
|
|
||||||
|
当微服务处理业务逻辑时间过长,网关会报超时错误,默认等待时间是5秒。 |
||||||
|
|
||||||
|
可在网关指定`spring.cloud.gateway.httpclient.response-timeout`参数设置超时时间,单位毫秒 |
||||||
|
|
||||||
|
```properties |
||||||
|
# 设置响应超时10秒 |
||||||
|
spring.cloud.gateway.httpclient.response-timeout=10000 |
||||||
|
``` |
||||||
|
|
||||||
|
更多配置参见:`org.springframework.cloud.gateway.config.HttpClientProperties` |
||||||
|
|
||||||
|
测试用例参见:`com.gitee.sop.test.TimeoutTest` |
@ -1,21 +0,0 @@ |
|||||||
# 原理分析之@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`类开始解读。 |
|
||||||
|
|
@ -1,77 +1,33 @@ |
|||||||
# 原理分析之如何路由 |
# 原理分析之如何路由 |
||||||
|
|
||||||
## zuul如何路由 |
Spring Cloud Gateway通过一系列的Filter来进行数据的传输,如下图所示: |
||||||
|
|
||||||
SOP网关默认使用zuul,当然也默认使用了zuul提供的路由功能。zuul默认使用过滤器来实现路由转发, |
 |
||||||
我们看下zuul中自带的过滤器: |
|
||||||
|
|
||||||
| 类型 | 顺序 | 过滤器 | 功能 | |
SOP网关在此基础上新增了几个Filter用来处理自己的逻辑,如:前置校验、结果返回。 |
||||||
| ----- | ---- | ----------------------- | ---------------------------- | |
|
||||||
| pre | -3 | ServletDetectionFilter | 标记处理 Servlet 的类型 | |
|
||||||
| pre | -2 | Servlet30WrapperFilter | 包装 HttpServletRequest 请求 | |
|
||||||
| pre | -1 | FormBodyWrapperFilter | 包装请求体 | |
|
||||||
| pre | 1 | DebugFilter | 标记调试标志 | |
|
||||||
| pre | 5 | PreDecorationFilter | 决定路由转发过滤器 | |
|
||||||
| route | 10 | RibbonRoutingFilter | serviceId 请求转发 | |
|
||||||
| route | 100 | SimpleHostRoutingFilter | url 请求转发 | |
|
||||||
| route | 500 | SendForwardFilter | forward 请求转发 | |
|
||||||
| post | 0 | SendErrorFilter | 处理有错误的请求响应 | |
|
||||||
| post | 1000 | SendResponseFilter | 处理正常的请求响应 | |
|
||||||
|
|
||||||
上图就是zuul提供的默认过滤器,可在org.springframework.cloud.netflix.zuul.filters下查看。 |
|
||||||
|
|
||||||
zuul的过滤器顺序值小的优先执行,其中的`PreDecorationFilter`是我们重点关注的类,由它来决定路由转发去向。 |
|
||||||
|
|
||||||
打开PreDecorationFilter类,看到类注释有一句话:`that determines where and how to route based on the supplied` |
|
||||||
|
|
||||||
翻译过来就是说,决定从哪里获取路由,然后怎样去路由。 |
|
||||||
|
|
||||||
PreDecorationFilter类的核心方法是run()方法。找到run方法中这一句代码: |
|
||||||
|
|
||||||
`Route route = this.routeLocator.getMatchingRoute(requestURI);` |
| 过滤器 | 类型 | Order | 功能 | |
||||||
|
| ----- | ---- | ----------------------- | ---------------------------- | |
||||||
这句代码很重要,表示路由从哪里获取,如果我们能够重写getMatchingRoute方法那就可以返回自己定义的路由了。 |
|IndexFilter| `自定义` | -2147483648 | 入口过滤器,获取参数、签名校验 | |
||||||
|
|ParameterFormatterFilter | `自定义` | -2147482647 | 格式化参数 | |
||||||
接下来找到RouteLocator类的定义,发现是通过构造方法传进来的,那么我们就去找使用构造方法的类。(IDEA下右键构造方法--Find Usage) |
|LimitFilter|`自定义`|-2147482447|限流| |
||||||
|
|ForwardPathFilter|系统自带|0 |设置转发的path| |
||||||
在org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration类中找到了定义 |
|RouteToRequestUrlFilter|系统自带|10000|设置转发host| |
||||||
|
|SopLoadBalancerClientFilter|`自定义`|10100|LoadBalance获取转发实例| |
||||||
```java |
|NettyRoutingFilter|系统自带|2147483647|获取httpclient发送请求| |
||||||
// pre filters |
|ForwardRoutingFilter|系统自带|2147483647|请求分发| |
||||||
@Bean |
|GatewayModifyResponseGatewayFilter|`自定义`|-2|处理响应结果| |
||||||
@ConditionalOnMissingBean(PreDecorationFilter.class) |
|
||||||
public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) { |
|
||||||
return new PreDecorationFilter(routeLocator, this.server.getServlet().getContextPath(), this.zuulProperties, |
|
||||||
proxyRequestHelper); |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
方法默认注入了RouteLocator类,默认注入的实现是CompositeRouteLocator类(通过打断点可以查看)。 |
一个完整的请求会自上而下经过这些Filter,下面讲解如何动态设置路由。 |
||||||
|
|
||||||
同时方法上用了`@ConditionalOnMissingBean`注解,表示如果其它地方没有声明,则默认使用这个。 |
## 动态设置路由 |
||||||
|
|
||||||
因此我们可以自己声明一个PreDecorationFilter,然后注入自定义的RouteLocator就行了。 |
网关启动后会从注册中心拉取微服务实例,然后请求微服务提供的一个接口(`/sop/routes`),获取开放接口信息(被`@Open`注解的接口)。 |
||||||
|
|
||||||
SOP自定义的RouteLocator为:`com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator`,可自行前往查看。 |
监听处理类在:`com.gitee.sop.bridge.route.NacosRegistryListener` |
||||||
|
|
||||||
然后再我们的Config中定义: |
获取到路由信息后,将路由信息缓存到本地,并保存到数据库,代码在:`com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache.load` |
||||||
|
|
||||||
```java |
然后动态设置Gateway路由,代码在:`com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteRepository.refresh` |
||||||
/** |
|
||||||
* 选取路由 |
|
||||||
* @param zuulRouteRepository |
|
||||||
* @param proxyRequestHelper |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
@Bean |
|
||||||
public PreDecorationFilter preDecorationFilter(ZuulRouteRepository zuulRouteRepository, ProxyRequestHelper proxyRequestHelper) { |
|
||||||
// 自定义路由 |
|
||||||
RouteLocator routeLocator = new SopRouteLocator(zuulRouteRepository); |
|
||||||
return new PreDecorationFilter(routeLocator, |
|
||||||
this.server.getServlet().getContextPath(), |
|
||||||
this.zuulProperties, |
|
||||||
proxyRequestHelper); |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
到此,我们只需要实现RouteLocator接口,就能使用zuul默认的路由功能,非常方便。 |
当有微服务重新启动时,网关会监听到微服务实例有变更,会重复上述步骤,确保网关存有最新的路由。 |
||||||
|
@ -1,23 +0,0 @@ |
|||||||
# 2.x升3.x注意事项 |
|
||||||
|
|
||||||
升级到3.x后`本地访问接口`方式会有不同。 |
|
||||||
|
|
||||||
```java |
|
||||||
@ApiMapping(value = "alipay.story.get") |
|
||||||
public StoryResult getStory(StoryParam param) { |
|
||||||
StoryResult story = new StoryResult(); |
|
||||||
story.setId(1L); |
|
||||||
story.setName("海底小纵队(alipay.story.get1.0), port:" + environment.getProperty("server.port") + ", param:" + param); |
|
||||||
return story; |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
- 2.x版本访问方式: |
|
||||||
|
|
||||||
`http://localhost:2222/alipay.story.get/?name=Jim&version=1.0` |
|
||||||
|
|
||||||
- 3.x版本访问方式: |
|
||||||
|
|
||||||
`http://localhost:2222/alipay.story.get/1.0/?name=Jim` |
|
||||||
|
|
||||||
3.x版本中把版本号融合在了url中,如果这个功能没有用到,可以放心升级。 |
|
After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 315 KiB After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,12 @@ |
|||||||
|
#!/bin/sh |
||||||
|
|
||||||
|
# 打包 |
||||||
|
mvn clean package |
||||||
|
# 创建镜像 |
||||||
|
docker build -t gitee.com/sop . |
||||||
|
|
||||||
|
# 获取镜像id |
||||||
|
image_id=`docker images gitee.com/sop --format "{{.ID}}" | awk '{print $1}'` |
||||||
|
|
||||||
|
# 运行镜像 |
||||||
|
docker run --name sop -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8087:8087 -p 2222:2222 -d $image_id |
@ -0,0 +1,13 @@ |
|||||||
|
#!/bin/sh |
||||||
|
|
||||||
|
JAVA_OPTS="-Xms128m -Xmx128m" |
||||||
|
|
||||||
|
# mysql, nacos配置 |
||||||
|
args="--mysql.host=10.1.30.110:3306 --mysql.username=root --mysql.password=root --register.url=10.1.30.110:8848" |
||||||
|
|
||||||
|
java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-gateway/sop-gateway.jar $args --logging.file.path=/sop/sop-gateway/log & |
||||||
|
java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-admin/sop-admin.jar $args --logging.file.path=/sop/sop-admin/log & |
||||||
|
java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-website/sop-website.jar $args --logging.file.path=/sop/sop-website/log & |
||||||
|
java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-auth/sop-auth.jar $args --logging.file.path=/sop/sop-auth/log & |
||||||
|
# 最后一条没有& |
||||||
|
java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-story/sop-story.jar $args --logging.file.path=/sop/sop-story/log |
@ -1,13 +0,0 @@ |
|||||||
package com.gitee.sop.adminserver.api.config; |
|
||||||
|
|
||||||
import com.gitee.easyopen.annotation.ApiService; |
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDoc; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author tanghc |
|
||||||
*/ |
|
||||||
@ApiService |
|
||||||
@ApiDoc("配置列表") |
|
||||||
public class ConfigListApi { |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,80 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service; |
||||||
|
|
||||||
|
import com.gitee.easyopen.annotation.Api; |
||||||
|
import com.gitee.easyopen.annotation.ApiService; |
||||||
|
import com.gitee.fastmybatis.core.query.Query; |
||||||
|
import com.gitee.fastmybatis.core.query.Sort; |
||||||
|
import com.gitee.fastmybatis.core.support.PageEasyui; |
||||||
|
import com.gitee.fastmybatis.core.util.MapperUtil; |
||||||
|
import com.gitee.sop.adminserver.api.service.param.InstanceMonitorSearchParam; |
||||||
|
import com.gitee.sop.adminserver.api.service.param.MonitorErrorMsgParam; |
||||||
|
import com.gitee.sop.adminserver.api.service.param.MonitorInfoErrorSolveParam; |
||||||
|
import com.gitee.sop.adminserver.api.service.param.MonitorSearchParam; |
||||||
|
import com.gitee.sop.adminserver.bean.RouteErrorCount; |
||||||
|
import com.gitee.sop.adminserver.entity.MonitorInfoError; |
||||||
|
import com.gitee.sop.adminserver.entity.MonitorSummary; |
||||||
|
import com.gitee.sop.adminserver.mapper.MonitorInfoErrorMapper; |
||||||
|
import com.gitee.sop.adminserver.mapper.MonitorInfoMapper; |
||||||
|
import com.github.pagehelper.PageHelper; |
||||||
|
import com.github.pagehelper.PageInfo; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* 路由监控 |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@ApiService |
||||||
|
public class MonitorNewApi { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MonitorInfoMapper monitorInfoMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MonitorInfoErrorMapper monitorInfoErrorMapper; |
||||||
|
|
||||||
|
@Api(name = "monitornew.data.page") |
||||||
|
PageInfo<Object> listMonitor(MonitorSearchParam param) { |
||||||
|
Query query = Query.build(param); |
||||||
|
query.orderby("errorCount", Sort.DESC) |
||||||
|
.orderby("avgTime", Sort.DESC); |
||||||
|
return PageHelper.offsetPage(query.getStart(), query.getLimit()) |
||||||
|
.doSelectPage(() -> monitorInfoMapper.listMonitorSummary(query)) |
||||||
|
.toPageInfo(); |
||||||
|
} |
||||||
|
|
||||||
|
@Api(name = "monitornew.routeid.data.get") |
||||||
|
List<MonitorSummary> listInstanceMonitor(InstanceMonitorSearchParam param) { |
||||||
|
Query query = Query.build(param); |
||||||
|
query.orderby("errorCount", Sort.DESC) |
||||||
|
.orderby("avgTime", Sort.DESC); |
||||||
|
return monitorInfoMapper.listInstanceMonitorInfo(query); |
||||||
|
} |
||||||
|
|
||||||
|
private Map<String, Integer> getRouteErrorCount() { |
||||||
|
List<RouteErrorCount> routeErrorCounts = monitorInfoErrorMapper.listRouteErrorCount(); |
||||||
|
return routeErrorCounts.stream() |
||||||
|
.collect(Collectors.toMap(RouteErrorCount::getRouteId, RouteErrorCount::getCount)); |
||||||
|
} |
||||||
|
|
||||||
|
@Api(name = "monitornew.error.page") |
||||||
|
PageEasyui<MonitorInfoError> listError(MonitorErrorMsgParam param) { |
||||||
|
Query query = param.toQuery() |
||||||
|
.orderby("gmt_modified", Sort.DESC); |
||||||
|
return MapperUtil.queryForEasyuiDatagrid(monitorInfoErrorMapper, query); |
||||||
|
} |
||||||
|
|
||||||
|
@Api(name = "monitornew.error.solve") |
||||||
|
void solve(MonitorInfoErrorSolveParam param) { |
||||||
|
Query query = Query.build(param); |
||||||
|
Map<String, Object> set = new HashMap<>(4); |
||||||
|
set.put("is_deleted", 1); |
||||||
|
set.put("count", 0); |
||||||
|
monitorInfoErrorMapper.updateByMap(set, query); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service; |
||||||
|
|
||||||
|
import com.gitee.easyopen.annotation.Api; |
||||||
|
import com.gitee.easyopen.annotation.ApiService; |
||||||
|
import com.gitee.sop.adminserver.api.system.param.IspPageParam; |
||||||
|
import com.gitee.sop.adminserver.api.system.param.IspResourceParam; |
||||||
|
import com.gitee.sop.adminserver.common.CopyUtil; |
||||||
|
import com.gitee.sop.adminserver.entity.IspResource; |
||||||
|
import com.gitee.sop.adminserver.mapper.IspResourceMapper; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@ApiService |
||||||
|
public class ResourceApi { |
||||||
|
|
||||||
|
public static final byte RESOURCE_TYPE_SDK = (byte) 0; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IspResourceMapper ispResourceMapper; |
||||||
|
|
||||||
|
|
||||||
|
@Api(name = "isp.sdk.list") |
||||||
|
List<IspResource> list(IspPageParam param) { |
||||||
|
return ispResourceMapper.list(param.toQuery()); |
||||||
|
} |
||||||
|
|
||||||
|
@Api(name = "isp.sdk.add") |
||||||
|
void addSdk(IspResourceParam param) { |
||||||
|
IspResource ispResource = CopyUtil.copyBean(param, IspResource::new); |
||||||
|
ispResource.setType(RESOURCE_TYPE_SDK); |
||||||
|
ispResourceMapper.saveIgnoreNull(ispResource); |
||||||
|
} |
||||||
|
|
||||||
|
@Api(name = "isp.sdk.update") |
||||||
|
void updateSdk(IspResourceParam param) { |
||||||
|
IspResource resource = ispResourceMapper.getById(param.getId()); |
||||||
|
CopyUtil.copyProperties(param, resource); |
||||||
|
ispResourceMapper.update(resource); |
||||||
|
} |
||||||
|
|
||||||
|
@Api(name = "isp.sdk.delete") |
||||||
|
void deleteSdk(@NotNull Long id) { |
||||||
|
IspResource resource = ispResourceMapper.getById(id); |
||||||
|
if (resource != null) { |
||||||
|
ispResourceMapper.deleteById(id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service.param; |
||||||
|
|
||||||
|
import com.gitee.fastmybatis.core.query.annotation.Condition; |
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Getter |
||||||
|
@Setter |
||||||
|
public class InstanceMonitorSearchParam { |
||||||
|
@Condition(column = "t.route_id") |
||||||
|
private String routeId; |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service.param; |
||||||
|
|
||||||
|
import com.gitee.fastmybatis.core.query.annotation.Condition; |
||||||
|
import com.gitee.fastmybatis.core.query.param.PageParam; |
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Getter |
||||||
|
@Setter |
||||||
|
public class MonitorErrorMsgParam extends PageParam { |
||||||
|
@NotBlank(message = "routeId不能为空") |
||||||
|
private String routeId; |
||||||
|
|
||||||
|
@Condition(ignoreEmptyString = true) |
||||||
|
private String instanceId; |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service.param; |
||||||
|
|
||||||
|
import com.gitee.fastmybatis.core.query.annotation.Condition; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class MonitorInfoErrorSolveParam { |
||||||
|
/** 错误id,md5(error_msg), 数据库字段:error_id */ |
||||||
|
@NotBlank |
||||||
|
@Condition(index = 1) |
||||||
|
private String errorId; |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service.param; |
||||||
|
|
||||||
|
import com.gitee.easyopen.doc.annotation.ApiDocField; |
||||||
|
import com.gitee.fastmybatis.core.query.Operator; |
||||||
|
import com.gitee.fastmybatis.core.query.annotation.Condition; |
||||||
|
import com.gitee.fastmybatis.core.query.param.PageParam; |
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Getter |
||||||
|
@Setter |
||||||
|
public class MonitorSearchParam extends PageParam { |
||||||
|
@ApiDocField(description = "服务名serviceId") |
||||||
|
@Condition(column = "service_id", operator = Operator.like, ignoreEmptyString = true) |
||||||
|
private String serviceId; |
||||||
|
|
||||||
|
@ApiDocField(description = "路由id") |
||||||
|
@Condition(column = "route_id", operator = Operator.like, ignoreEmptyString = true) |
||||||
|
private String routeId; |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service.param; |
||||||
|
|
||||||
|
import com.gitee.easyopen.doc.annotation.ApiDocField; |
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
import org.hibernate.validator.constraints.Length; |
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank; |
||||||
|
import javax.validation.constraints.NotNull; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Getter |
||||||
|
@Setter |
||||||
|
public class RouteStatusUpdateParam { |
||||||
|
|
||||||
|
/** |
||||||
|
* 路由的Id |
||||||
|
*/ |
||||||
|
@NotBlank(message = "id不能为空") |
||||||
|
@ApiDocField(description = "路由id") |
||||||
|
private String id; |
||||||
|
|
||||||
|
/** |
||||||
|
* 状态 |
||||||
|
*/ |
||||||
|
@NotNull |
||||||
|
@ApiDocField(description = "状态,0:审核,1:启用,2:禁用") |
||||||
|
private Byte status; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.service.result; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class MonitorInfoErrorMsgResult { |
||||||
|
|
||||||
|
private String routeId; |
||||||
|
|
||||||
|
private String errorId; |
||||||
|
|
||||||
|
/** 错误信息, 数据库字段:error_msg */ |
||||||
|
private String errorMsg; |
||||||
|
|
||||||
|
private Integer errorStatus; |
||||||
|
|
||||||
|
private Integer count; |
||||||
|
|
||||||
|
/** 数据库字段:gmt_modified */ |
||||||
|
private Date gmtModified; |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.system.param; |
||||||
|
|
||||||
|
import com.gitee.fastmybatis.core.query.param.PageParam; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
public class IspPageParam extends PageParam { |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.system.param; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 表名:isp_resource |
||||||
|
* 备注:ISP资源表 |
||||||
|
* |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class IspResourceParam { |
||||||
|
|
||||||
|
private Long id; |
||||||
|
|
||||||
|
/** 资源名称, 数据库字段:name */ |
||||||
|
private String name; |
||||||
|
|
||||||
|
private String version; |
||||||
|
|
||||||
|
/** 资源内容(URL), 数据库字段:content */ |
||||||
|
private String content; |
||||||
|
|
||||||
|
private String extContent; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.gitee.sop.adminserver.api.system.result; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 表名:isp_resource |
||||||
|
* 备注:ISP资源表 |
||||||
|
* |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class IspResourceResult { |
||||||
|
|
||||||
|
private Long id; |
||||||
|
|
||||||
|
/** 资源名称, 数据库字段:name */ |
||||||
|
private String name; |
||||||
|
|
||||||
|
private String version; |
||||||
|
|
||||||
|
/** 资源内容(URL), 数据库字段:content */ |
||||||
|
private String content; |
||||||
|
|
||||||
|
private String extContent; |
||||||
|
|
||||||
|
} |
@ -1,89 +0,0 @@ |
|||||||
package com.gitee.sop.adminserver.bean; |
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONField; |
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDocField; |
|
||||||
import lombok.Data; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author tanghc |
|
||||||
*/ |
|
||||||
@Data |
|
||||||
public class RouteDefinition { |
|
||||||
/** |
|
||||||
* 路由的Id |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "路由id") |
|
||||||
private String id = ""; |
|
||||||
|
|
||||||
/** |
|
||||||
* 接口名 |
|
||||||
*/ |
|
||||||
private String name; |
|
||||||
|
|
||||||
/** |
|
||||||
* 版本号 |
|
||||||
*/ |
|
||||||
private String version; |
|
||||||
|
|
||||||
/** |
|
||||||
* 路由断言集合配置 |
|
||||||
*/ |
|
||||||
@JSONField(serialize = false) |
|
||||||
private List<GatewayPredicateDefinition> predicates = new ArrayList<>(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 路由过滤器集合配置 |
|
||||||
*/ |
|
||||||
@JSONField(serialize = false) |
|
||||||
private List<GatewayFilterDefinition> filters = new ArrayList<>(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 路由规则转发的目标uri |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "uri") |
|
||||||
private String uri; |
|
||||||
|
|
||||||
/** |
|
||||||
* uri后面跟的path |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "path") |
|
||||||
private String path; |
|
||||||
|
|
||||||
/** |
|
||||||
* 路由执行的顺序 |
|
||||||
*/ |
|
||||||
private int order = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否忽略验证,业务参数验证除外 |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "是否忽略验证,业务参数验证除外,1:忽略,0:不忽略") |
|
||||||
private int ignoreValidate; |
|
||||||
|
|
||||||
/** |
|
||||||
* 状态,0:待审核,1:启用,2:禁用 |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "状态,0:待审核,1:启用,2:禁用") |
|
||||||
private int status = 1; |
|
||||||
|
|
||||||
/** |
|
||||||
* 合并结果,统一格式输出 |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "合并结果,统一格式输出,1:合并,0:不合并") |
|
||||||
private int mergeResult = 1; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否需要授权才能访问 |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "是否需要授权才能访问,1:是,0:否") |
|
||||||
private int permission; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否是自定义路由 |
|
||||||
*/ |
|
||||||
@ApiDocField(description = "是否是自定义路由,1:是,0:否") |
|
||||||
private int custom; |
|
||||||
} |
|
@ -0,0 +1,13 @@ |
|||||||
|
package com.gitee.sop.adminserver.bean; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class RouteErrorCount { |
||||||
|
|
||||||
|
private String routeId; |
||||||
|
private Integer count; |
||||||
|
} |
@ -1,16 +1,29 @@ |
|||||||
package com.gitee.sop.adminserver.bean; |
package com.gitee.sop.adminserver.bean; |
||||||
|
|
||||||
import lombok.Data; |
|
||||||
|
|
||||||
import java.util.List; |
import java.util.List; |
||||||
|
|
||||||
/** |
/** |
||||||
* @author tanghc |
* @author tanghc |
||||||
*/ |
*/ |
||||||
@Data |
|
||||||
public class ServiceInfo { |
public class ServiceInfo { |
||||||
/** 服务名称 */ |
/** 服务名称 */ |
||||||
private String serviceId; |
private String serviceId; |
||||||
/** 实例列表 */ |
/** 实例列表 */ |
||||||
private List<ServiceInstance> instances; |
private List<ServiceInstance> instances; |
||||||
|
|
||||||
|
public String getServiceId() { |
||||||
|
return serviceId; |
||||||
|
} |
||||||
|
|
||||||
|
public void setServiceId(String serviceId) { |
||||||
|
this.serviceId = serviceId; |
||||||
|
} |
||||||
|
|
||||||
|
public List<ServiceInstance> getInstances() { |
||||||
|
return instances; |
||||||
|
} |
||||||
|
|
||||||
|
public void setInstances(List<ServiceInstance> instances) { |
||||||
|
this.instances = instances; |
||||||
|
} |
||||||
} |
} |
||||||
|
@ -1,26 +0,0 @@ |
|||||||
package com.gitee.sop.adminserver.bean; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
|
|
||||||
import java.util.Date; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author tanghc |
|
||||||
*/ |
|
||||||
@Data |
|
||||||
public class ServiceRouteInfo { |
|
||||||
/** 服务名称,对应spring.application.name */ |
|
||||||
private String serviceId; |
|
||||||
|
|
||||||
private Date createTime = new Date(); |
|
||||||
|
|
||||||
private Date updateTime = new Date(); |
|
||||||
|
|
||||||
private String description; |
|
||||||
|
|
||||||
private List<RouteDefinition> routeDefinitionList; |
|
||||||
|
|
||||||
/** 是否是自定义服务,1:是,0:否 */ |
|
||||||
private int custom; |
|
||||||
} |
|
@ -0,0 +1,75 @@ |
|||||||
|
package com.gitee.sop.adminserver.common; |
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.BeanUtils; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Objects; |
||||||
|
import java.util.function.Consumer; |
||||||
|
import java.util.function.Supplier; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class CopyUtil { |
||||||
|
|
||||||
|
public static void copyProperties(Object from, Object to) { |
||||||
|
BeanUtils.copyProperties(from, to); |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> T copyBean(Object from, Supplier<T> supplier) { |
||||||
|
Objects.requireNonNull(from); |
||||||
|
T to = supplier.get(); |
||||||
|
BeanUtils.copyProperties(from, to); |
||||||
|
return to; |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> T copyBeanNullable(Object from, Supplier<T> supplier) { |
||||||
|
if (from == null) { |
||||||
|
return supplier.get(); |
||||||
|
} |
||||||
|
T to = supplier.get(); |
||||||
|
BeanUtils.copyProperties(from, to); |
||||||
|
return to; |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> T copyBean(Object from, Supplier<T> supplier, Consumer<T> after) { |
||||||
|
if (from == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
T to = supplier.get(); |
||||||
|
BeanUtils.copyProperties(from, to); |
||||||
|
after.accept(to); |
||||||
|
return to; |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> List<T> copyList(List<?> fromList, Supplier<T> toElement) { |
||||||
|
if (fromList == null) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return fromList.stream() |
||||||
|
.map(source -> { |
||||||
|
T target = toElement.get(); |
||||||
|
BeanUtils.copyProperties(source, target); |
||||||
|
return target; |
||||||
|
}) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> List<T> copyList(List<?> fromList, Supplier<T> toElement, Consumer<T> after) { |
||||||
|
if (fromList == null) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return fromList.stream() |
||||||
|
.map(source -> { |
||||||
|
T target = toElement.get(); |
||||||
|
BeanUtils.copyProperties(source, target); |
||||||
|
after.accept(target); |
||||||
|
return target; |
||||||
|
}) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
} |
||||||
|
} |
@ -1,58 +0,0 @@ |
|||||||
package com.gitee.sop.adminserver.entity; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
|
|
||||||
import java.util.Date; |
|
||||||
|
|
||||||
import javax.persistence.Column; |
|
||||||
import javax.persistence.GeneratedValue; |
|
||||||
import javax.persistence.GenerationType; |
|
||||||
import javax.persistence.Id; |
|
||||||
import javax.persistence.Table; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 表名:config_route_limit |
|
||||||
* 备注:路由限流配置 |
|
||||||
* |
|
||||||
* @author tanghc |
|
||||||
*/ |
|
||||||
@Table(name = "config_route_limit") |
|
||||||
@Data |
|
||||||
public class ConfigRouteLimit { |
|
||||||
@Id |
|
||||||
@Column(name = "id") |
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|
||||||
/** 数据库字段:id */ |
|
||||||
private Integer id; |
|
||||||
|
|
||||||
/** 路由id, 数据库字段:route_id */ |
|
||||||
private String routeId; |
|
||||||
|
|
||||||
/** serviceId, 数据库字段:service_id */ |
|
||||||
private String serviceId; |
|
||||||
|
|
||||||
/** 限流策略,1:漏桶策略,2:令牌桶策略, 数据库字段:limit_type */ |
|
||||||
private Byte limitType; |
|
||||||
|
|
||||||
/** 每秒可处理请求数, 数据库字段:exec_count_per_second */ |
|
||||||
private Integer execCountPerSecond; |
|
||||||
|
|
||||||
/** 返回的错误码, 数据库字段:limit_code */ |
|
||||||
private String limitCode; |
|
||||||
|
|
||||||
/** 返回的错误信息, 数据库字段:limit_msg */ |
|
||||||
private String limitMsg; |
|
||||||
|
|
||||||
/** 令牌桶容量, 数据库字段:token_bucket_count */ |
|
||||||
private Integer tokenBucketCount; |
|
||||||
|
|
||||||
/** 1:开启,0关闭, 数据库字段:limit_status */ |
|
||||||
private Byte limitStatus; |
|
||||||
|
|
||||||
/** 数据库字段:gmt_create */ |
|
||||||
private Date gmtCreate; |
|
||||||
|
|
||||||
/** 数据库字段:gmt_modified */ |
|
||||||
private Date gmtModified; |
|
||||||
} |
|
@ -0,0 +1,50 @@ |
|||||||
|
package com.gitee.sop.adminserver.entity; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import javax.persistence.Column; |
||||||
|
import javax.persistence.GeneratedValue; |
||||||
|
import javax.persistence.GenerationType; |
||||||
|
import javax.persistence.Id; |
||||||
|
import javax.persistence.Table; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 表名:isp_resource |
||||||
|
* 备注:ISP资源表 |
||||||
|
* |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Table(name = "isp_resource") |
||||||
|
@Data |
||||||
|
public class IspResource { |
||||||
|
/** 数据库字段:id */ |
||||||
|
@Id |
||||||
|
@Column(name = "id") |
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY) |
||||||
|
private Long id; |
||||||
|
|
||||||
|
/** 资源名称, 数据库字段:name */ |
||||||
|
private String name; |
||||||
|
|
||||||
|
private String version; |
||||||
|
|
||||||
|
/** 资源内容(URL), 数据库字段:content */ |
||||||
|
private String content; |
||||||
|
|
||||||
|
private String extContent; |
||||||
|
|
||||||
|
/** 资源类型:0:SDK链接, 数据库字段:type */ |
||||||
|
private Byte type; |
||||||
|
|
||||||
|
/** 数据库字段:is_deleted */ |
||||||
|
@com.gitee.fastmybatis.core.annotation.LogicDelete |
||||||
|
private Byte isDeleted; |
||||||
|
|
||||||
|
/** 数据库字段:gmt_create */ |
||||||
|
private Date gmtCreate; |
||||||
|
|
||||||
|
/** 数据库字段:gmt_modified */ |
||||||
|
private Date gmtModified; |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package com.gitee.sop.adminserver.entity; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import javax.persistence.Column; |
||||||
|
import javax.persistence.GeneratedValue; |
||||||
|
import javax.persistence.GenerationType; |
||||||
|
import javax.persistence.Id; |
||||||
|
import javax.persistence.Table; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 表名:monitor_info |
||||||
|
* 备注:接口监控信息 |
||||||
|
* |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Table(name = "monitor_info") |
||||||
|
@Data |
||||||
|
public class MonitorInfo { |
||||||
|
/** 数据库字段:id */ |
||||||
|
@Id |
||||||
|
@Column(name = "id") |
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY) |
||||||
|
private Long id; |
||||||
|
|
||||||
|
/** 路由id, 数据库字段:route_id */ |
||||||
|
private String routeId; |
||||||
|
|
||||||
|
/** 接口名, 数据库字段:name */ |
||||||
|
private String name; |
||||||
|
|
||||||
|
/** 版本号, 数据库字段:version */ |
||||||
|
private String version; |
||||||
|
|
||||||
|
/** 数据库字段:service_id */ |
||||||
|
private String serviceId; |
||||||
|
|
||||||
|
/** 数据库字段:instance_id */ |
||||||
|
private String instanceId; |
||||||
|
|
||||||
|
/** 请求耗时最长时间, 数据库字段:max_time */ |
||||||
|
private Integer maxTime; |
||||||
|
|
||||||
|
/** 请求耗时最小时间, 数据库字段:min_time */ |
||||||
|
private Integer minTime; |
||||||
|
|
||||||
|
/** 总时长,毫秒, 数据库字段:total_time */ |
||||||
|
private Long totalTime; |
||||||
|
|
||||||
|
/** 总调用次数, 数据库字段:total_request_count */ |
||||||
|
private Long totalRequestCount; |
||||||
|
|
||||||
|
/** 成功次数, 数据库字段:success_count */ |
||||||
|
private Long successCount; |
||||||
|
|
||||||
|
/** 失败次数(业务主动抛出的异常算作成功,如参数校验,未知的错误算失败), 数据库字段:error_count */ |
||||||
|
private Long errorCount; |
||||||
|
|
||||||
|
/** 数据库字段:gmt_create */ |
||||||
|
private Date gmtCreate; |
||||||
|
|
||||||
|
/** 数据库字段:gmt_modified */ |
||||||
|
private Date gmtModified; |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package com.gitee.sop.adminserver.entity; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import javax.persistence.Column; |
||||||
|
import javax.persistence.GeneratedValue; |
||||||
|
import javax.persistence.GenerationType; |
||||||
|
import javax.persistence.Id; |
||||||
|
import javax.persistence.Table; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 表名:monitor_info_error |
||||||
|
* |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Table(name = "monitor_info_error") |
||||||
|
@Data |
||||||
|
public class MonitorInfoError { |
||||||
|
/** 数据库字段:id */ |
||||||
|
@Id |
||||||
|
@Column(name = "id") |
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY) |
||||||
|
private Long id; |
||||||
|
|
||||||
|
/** 错误id,md5Hex(instanceId + routeId + errorMsg), 数据库字段:error_id */ |
||||||
|
private String errorId; |
||||||
|
|
||||||
|
/** 实例id, 数据库字段:instance_id */ |
||||||
|
private String instanceId; |
||||||
|
|
||||||
|
/** 数据库字段:route_id */ |
||||||
|
private String routeId; |
||||||
|
|
||||||
|
/** 数据库字段:error_msg */ |
||||||
|
private String errorMsg; |
||||||
|
|
||||||
|
/** http status,非200错误, 数据库字段:error_status */ |
||||||
|
private Integer errorStatus; |
||||||
|
|
||||||
|
/** 错误次数, 数据库字段:count */ |
||||||
|
private Integer count; |
||||||
|
|
||||||
|
/** 数据库字段:is_deleted */ |
||||||
|
@com.gitee.fastmybatis.core.annotation.LogicDelete |
||||||
|
private Byte isDeleted; |
||||||
|
|
||||||
|
/** 数据库字段:gmt_create */ |
||||||
|
private Date gmtCreate; |
||||||
|
|
||||||
|
/** 数据库字段:gmt_modified */ |
||||||
|
private Date gmtModified; |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
package com.gitee.sop.adminserver.entity; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import javax.persistence.Column; |
||||||
|
import javax.persistence.GeneratedValue; |
||||||
|
import javax.persistence.GenerationType; |
||||||
|
import javax.persistence.Id; |
||||||
|
import javax.persistence.Table; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.List; |
||||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class MonitorSummary { |
||||||
|
|
||||||
|
private static final AtomicInteger i = new AtomicInteger(); |
||||||
|
|
||||||
|
private Integer id = i.incrementAndGet(); |
||||||
|
|
||||||
|
private String routeId; |
||||||
|
|
||||||
|
private String name; |
||||||
|
private String version; |
||||||
|
|
||||||
|
/** 数据库字段:service_id */ |
||||||
|
private String serviceId; |
||||||
|
|
||||||
|
/** 数据库字段:instance_id */ |
||||||
|
private String instanceId; |
||||||
|
|
||||||
|
/** 请求耗时最长时间, 数据库字段:max_time */ |
||||||
|
private Integer maxTime; |
||||||
|
|
||||||
|
/** 请求耗时最小时间, 数据库字段:min_time */ |
||||||
|
private Integer minTime; |
||||||
|
|
||||||
|
/** 总时长,毫秒, 数据库字段:total_time */ |
||||||
|
private Long totalTime; |
||||||
|
|
||||||
|
/** 总调用次数, 数据库字段:total_request_count */ |
||||||
|
private Long totalRequestCount; |
||||||
|
|
||||||
|
/** 成功次数, 数据库字段:success_count */ |
||||||
|
private Long successCount; |
||||||
|
|
||||||
|
/** 失败次数(业务主动抛出的异常算作成功,如参数校验,未知的错误算失败), 数据库字段:error_count */ |
||||||
|
private Long errorCount; |
||||||
|
|
||||||
|
/** 未解决的错误数量 */ |
||||||
|
private Long unsolvedErrorCount; |
||||||
|
|
||||||
|
private Float avgTime; |
||||||
|
|
||||||
|
private Boolean hasChildren; |
||||||
|
} |
@ -1,12 +0,0 @@ |
|||||||
package com.gitee.sop.adminserver.mapper; |
|
||||||
|
|
||||||
import com.gitee.fastmybatis.core.mapper.CrudMapper; |
|
||||||
|
|
||||||
import com.gitee.sop.adminserver.entity.ConfigRouteLimit; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @author tanghc |
|
||||||
*/ |
|
||||||
public interface ConfigRouteLimitMapper extends CrudMapper<ConfigRouteLimit, Integer> { |
|
||||||
} |
|
@ -0,0 +1,11 @@ |
|||||||
|
package com.gitee.sop.adminserver.mapper; |
||||||
|
|
||||||
|
import com.gitee.fastmybatis.core.mapper.CrudMapper; |
||||||
|
import com.gitee.sop.adminserver.entity.IspResource; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
public interface IspResourceMapper extends CrudMapper<IspResource, Long> { |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
package com.gitee.sop.adminserver.mapper; |
||||||
|
|
||||||
|
import com.gitee.fastmybatis.core.mapper.CrudMapper; |
||||||
|
import com.gitee.sop.adminserver.bean.RouteErrorCount; |
||||||
|
import com.gitee.sop.adminserver.entity.MonitorInfoError; |
||||||
|
import org.apache.ibatis.annotations.Select; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
public interface MonitorInfoErrorMapper extends CrudMapper<MonitorInfoError, Long> { |
||||||
|
|
||||||
|
|
||||||
|
@Select("SELECT route_id routeId, count(*) `count` FROM monitor_info_error \n" + |
||||||
|
"WHERE is_deleted=0 \n" + |
||||||
|
"GROUP BY route_id") |
||||||
|
List<RouteErrorCount> listRouteErrorCount(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package com.gitee.sop.adminserver.mapper; |
||||||
|
|
||||||
|
import com.gitee.fastmybatis.core.mapper.CrudMapper; |
||||||
|
import com.gitee.fastmybatis.core.query.Query; |
||||||
|
import com.gitee.sop.adminserver.entity.MonitorInfo; |
||||||
|
import com.gitee.sop.adminserver.entity.MonitorSummary; |
||||||
|
import org.apache.ibatis.annotations.Param; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @author tanghc |
||||||
|
*/ |
||||||
|
public interface MonitorInfoMapper extends CrudMapper<MonitorInfo, Long> { |
||||||
|
List<MonitorSummary> listMonitorSummary(@Param("query") Query query); |
||||||
|
|
||||||
|
List<MonitorSummary> listInstanceMonitorInfo(@Param("query") Query query); |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||||
|
<!-- 注意:文件名必须跟Dao类名字一致,因为是根据文件名做关联。 --> |
||||||
|
<mapper namespace="com.gitee.sop.adminserver.mapper.MonitorInfoMapper"> |
||||||
|
|
||||||
|
|
||||||
|
<select id="listMonitorSummary" resultType="com.gitee.sop.adminserver.entity.MonitorSummary"> |
||||||
|
SELECT t.*, IFNULL(t2.unsolvedErrorCount, 0) unsolvedErrorCount |
||||||
|
FROM ( |
||||||
|
SELECT |
||||||
|
t.`service_id` serviceId, |
||||||
|
CONCAT(t.name, t.version) routeId, |
||||||
|
t.`name` name, |
||||||
|
t.`version` version, |
||||||
|
SUM(t.`max_time`) maxTime, |
||||||
|
SUM(t.`min_time`) minTime, |
||||||
|
SUM(t.`total_time`) totalTime, |
||||||
|
SUM(t.`total_request_count`) totalRequestCount, |
||||||
|
SUM(t.`success_count`) successCount, |
||||||
|
SUM(t.`error_count`) errorCount, |
||||||
|
SUM(t.`total_time`)/SUM(t.`total_request_count`) avgTime, |
||||||
|
1 hasChildren |
||||||
|
FROM |
||||||
|
`monitor_info` t |
||||||
|
<include refid="common.where"/> |
||||||
|
GROUP BY t.service_id, t.name, t.version |
||||||
|
<include refid="common.orderBy"/> |
||||||
|
) t |
||||||
|
LEFT JOIN |
||||||
|
( |
||||||
|
SELECT route_id, count(*) unsolvedErrorCount |
||||||
|
FROM monitor_info_error WHERE is_deleted=0 GROUP BY route_id |
||||||
|
) t2 on t.routeId = t2.route_id |
||||||
|
</select> |
||||||
|
|
||||||
|
<select id="listInstanceMonitorInfo" resultType="com.gitee.sop.adminserver.entity.MonitorSummary"> |
||||||
|
SELECT |
||||||
|
t.`service_id` serviceId, |
||||||
|
t.`instance_id` instanceId, |
||||||
|
t.route_id routeId, |
||||||
|
t.`name` name, |
||||||
|
t.`version` version, |
||||||
|
t.`max_time` maxTime, |
||||||
|
t.`min_time` minTime, |
||||||
|
t.`total_time` totalTime, |
||||||
|
t.`total_request_count` totalRequestCount, |
||||||
|
t.`success_count` successCount, |
||||||
|
t.`error_count` errorCount, |
||||||
|
IFNULL(t2.unsolvedErrorCount, 0) unsolvedErrorCount, |
||||||
|
t.`total_time`/t.`total_request_count` avgTime, |
||||||
|
0 hasChildren |
||||||
|
FROM |
||||||
|
`monitor_info` t |
||||||
|
LEFT JOIN |
||||||
|
( |
||||||
|
SELECT instance_id, route_id, count(*) unsolvedErrorCount |
||||||
|
FROM monitor_info_error WHERE is_deleted=0 GROUP BY instance_id, route_id |
||||||
|
) t2 on t.route_id = t2.route_id AND t.instance_id = t2.instance_id |
||||||
|
<include refid="common.where" /> |
||||||
|
<include refid="common.orderBy" /> |
||||||
|
</select> |
||||||
|
|
||||||
|
</mapper> |
@ -0,0 +1,10 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> |
||||||
|
<configuration> |
||||||
|
|
||||||
|
<plugins> |
||||||
|
<!-- com.github.pagehelper为PageHelper类所在包名 --> |
||||||
|
<plugin interceptor="com.github.pagehelper.PageInterceptor" /> |
||||||
|
</plugins> |
||||||
|
|
||||||
|
</configuration> |
@ -1 +1 @@ |
|||||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.c6dfb7ee.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],f=n[1],i=n[2],d=0,l=[];d<a.length;d++)c=a[d],u[c]&&l.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);h&&h(n);while(l.length)l.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-25908fca":"66819987","chunk-2c1f2e8f":"f092c0a0","chunk-2d0d32e7":"213708f2","chunk-2d2085ef":"91d75f3c","chunk-2d221c34":"20057287","chunk-4de1c2b6":"e74e3d03","chunk-626b7094":"97d3a892","chunk-73b2dcec":"60c5d8e9","chunk-9b31c83a":"52bc6b2c","chunk-9f479afe":"4609bf8b","chunk-c3ce42fe":"9517b588"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-25908fca":1,"chunk-2c1f2e8f":1,"chunk-4de1c2b6":1,"chunk-626b7094":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1,"chunk-c3ce42fe":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-25908fca":"a66354ec","chunk-2c1f2e8f":"0314067f","chunk-2d0d32e7":"31d6cfe0","chunk-2d2085ef":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-4de1c2b6":"a37cd815","chunk-626b7094":"e41ad972","chunk-73b2dcec":"ed391cc5","chunk-9b31c83a":"3b12267b","chunk-9f479afe":"31d6cfe0","chunk-c3ce42fe":"6b789903"}[e]+".css",u=f.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var i=o[a],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===r||d===u))return n()}var l=document.getElementsByTagName("style");for(a=0;a<l.length;a++){i=l[a],d=i.getAttribute("data-href");if(d===r||d===u)return n()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=n,h.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],h.parentNode.removeChild(h),t(o)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,f.nc&&d.setAttribute("nonce",f.nc),d.src=a(e),i=function(n){d.onerror=d.onload=null,clearTimeout(l);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var l=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var l=0;l<i.length;l++)n(i[l]);var h=d;t()})([]);</script><script src=static/js/chunk-elementUI.298ac98c.js></script><script src=static/js/chunk-libs.75deb05f.js></script><script src=static/js/app.c6e80241.js></script></body></html> |
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.6095bfbf.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var c,r,a=n[0],f=n[1],i=n[2],d=0,h=[];d<a.length;d++)r=a[d],u[r]&&h.push(u[r][0]),u[r]=0;for(c in f)Object.prototype.hasOwnProperty.call(f,c)&&(e[c]=f[c]);l&&l(n);while(h.length)h.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],c=!0,r=1;r<t.length;r++){var a=t[r];0!==u[a]&&(c=!1)}c&&(o.splice(n--,1),e=f(f.s=t[0]))}return e}var c={},r={runtime:0},u={runtime:0},o=[];function a(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-25908fca":"cc77b01c","chunk-2c1f2e8f":"f092c0a0","chunk-2d0d6219":"18813e69","chunk-2d2085ef":"91d75f3c","chunk-2d221c34":"20057287","chunk-2d238661":"23693be8","chunk-30c6c34f":"b288bbf5","chunk-4de1c2b6":"e74e3d03","chunk-73b2dcec":"60c5d8e9","chunk-9b31c83a":"494fc338","chunk-9f479afe":"2093f9d0","chunk-c3ce42fe":"9517b588"}[e]+".js"}function f(n){if(c[n])return c[n].exports;var t=c[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-25908fca":1,"chunk-2c1f2e8f":1,"chunk-30c6c34f":1,"chunk-4de1c2b6":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1,"chunk-c3ce42fe":1};r[e]?n.push(r[e]):0!==r[e]&&t[e]&&n.push(r[e]=new Promise(function(n,t){for(var c="static/css/"+({}[e]||e)+"."+{"chunk-25908fca":"a66354ec","chunk-2c1f2e8f":"0314067f","chunk-2d0d6219":"31d6cfe0","chunk-2d2085ef":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-2d238661":"31d6cfe0","chunk-30c6c34f":"3b12267b","chunk-4de1c2b6":"a37cd815","chunk-73b2dcec":"ed391cc5","chunk-9b31c83a":"c4612b4a","chunk-9f479afe":"31d6cfe0","chunk-c3ce42fe":"6b789903"}[e]+".css",u=f.p+c,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var i=o[a],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===c||d===u))return n()}var h=document.getElementsByTagName("style");for(a=0;a<h.length;a++){i=h[a],d=i.getAttribute("data-href");if(d===c||d===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var c=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+c+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=c,delete r[e],l.parentNode.removeChild(l),t(o)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)}).then(function(){r[e]=0}));var c=u[e];if(0!==c)if(c)n.push(c[2]);else{var o=new Promise(function(n,t){c=u[e]=[n,t]});n.push(c[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,f.nc&&d.setAttribute("nonce",f.nc),d.src=a(e),i=function(n){d.onerror=d.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var c=n&&("load"===n.type?"missing":n.type),r=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+c+": "+r+")");o.type=c,o.request=r,t[1](o)}u[e]=void 0}};var h=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},f.m=e,f.c=c,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var c in e)f.d(t,c,function(n){return e[n]}.bind(null,c));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var h=0;h<i.length;h++)n(i[h]);var l=d;t()})([]);</script><script src=static/js/chunk-elementUI.298ac98c.js></script><script src=static/js/chunk-libs.75deb05f.js></script><script src=static/js/app.7297829f.js></script></body></html> |