yangmao 2 년 전
커밋
4c3f778991
62개의 변경된 파일3952개의 추가작업 그리고 0개의 파일을 삭제
  1. 68 0
      Dockerfile
  2. 134 0
      Makefile
  3. 107 0
      README.md
  4. 235 0
      README_project.md
  5. 0 0
      access_log.log
  6. 9 0
      business/controller/base_controller.go
  7. 21 0
      business/controller/init_test.go
  8. 221 0
      business/controller/report_controller.go
  9. 113 0
      business/controller/report_controller_test.go
  10. 26 0
      business/dao/init_test.go
  11. 91 0
      business/dao/report_peccancy_dao.go
  12. 291 0
      business/dao/report_peccancy_dao_test.go
  13. 30 0
      business/dto/city_config_dto.go
  14. 15 0
      business/dto/ebike_factory_api_third_dto.go
  15. 65 0
      business/dto/report_dto.go
  16. 40 0
      business/dto/urban_violation_dto.go
  17. 20 0
      business/exception/controller.go
  18. 22 0
      business/exception/dao.go
  19. 18 0
      business/exception/global.go
  20. 13 0
      business/exception/service.go
  21. 20 0
      business/exception/third.go
  22. 22 0
      business/job/rocket_mq_consumer.go
  23. 24 0
      business/middleware/middleware.go
  24. 103 0
      business/model/report_peccancy.go
  25. 17 0
      business/service/base_service.go
  26. 16 0
      business/service/init_test.go
  27. 197 0
      business/service/report_service.go
  28. 138 0
      business/service/resource_test.go
  29. 40 0
      business/third/city_config_third.go
  30. 31 0
      business/third/city_config_third_test.go
  31. 47 0
      business/third/ebike_factory_api_third.go
  32. 22 0
      business/third/ebike_factory_api_third_test.go
  33. 16 0
      business/third/init_test.go
  34. 37 0
      business/util/httpclient.go
  35. 105 0
      business/util/httputil.go
  36. 191 0
      business/util/mockHttpClient.go
  37. 91 0
      business/util/test.go
  38. 20 0
      business/util/util_test.go
  39. 129 0
      cicd/build.sh
  40. 237 0
      cicd/deploy.sh
  41. 42 0
      cmd/main.go
  42. 5 0
      config/apollo/apollo.dev.json
  43. 5 0
      config/apollo/apollo.release.json
  44. 5 0
      config/apollo/apollo.slave.json
  45. 5 0
      config/apollo/apollo.test.json
  46. 5 0
      config/apollo/apollo.test2.json
  47. 5 0
      config/apollo/apollo.test3.json
  48. 27 0
      config/apollo/namespaces.json
  49. 53 0
      config/env.dev.ini
  50. 15 0
      config/env.release.ini
  51. 15 0
      config/env.slave.ini
  52. 15 0
      config/env.test.ini
  53. 15 0
      config/env.test2.ini
  54. 15 0
      config/env.test3.ini
  55. 11 0
      go.mod
  56. 605 0
      go.sum
  57. 0 0
      monitor_log.log
  58. 23 0
      router/op_router.go
  59. 11 0
      router/router.go
  60. 33 0
      router/sys_router.go
  61. 0 0
      task_log.log
  62. 0 0
      third.log

+ 68 - 0
Dockerfile

@@ -0,0 +1,68 @@
+FROM centos:7
+
+# about author eamil
+MAINTAINER fanhaodong516@gmail.com
+
+## install golang 1.13.5
+ARG GO_VERSOION=1.13.5
+RUN yum install -y wget git\
+    && wget https://golang.org/dl/go${GO_VERSOION}.linux-amd64.tar.gz -O /tmp/go{GO_VERSOION}.linux-amd64.tar.gz \
+    && tar -zxvf /tmp/go{GO_VERSOION}.linux-amd64.tar.gz -C /usr/local \
+    && rm -f /tmp/go{GO_VERSOION}.linux-amd64.tar.gz
+ENV PATH=${PATH}:/usr/local/go/bin
+
+## update yum repo
+RUN rm -rf /etc/yum.repos.d/*.repo \
+    && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo \
+    && curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
+
+## install 工具(添加工具较为灵活,防止重复构建上层)
+RUN yum install -y \
+    net-tools \
+    vim \
+    htop \
+    sysstat \
+    iproute \
+    dstat \
+    telnet \
+    unzip \
+    curl \
+    tcpdump \
+    lrzsz
+
+# install gcc lib and make
+RUN yum install -y gcc \
+    automake \
+    autoconf \
+    libtool \
+    make
+
+
+# install qconf
+RUN  wget https://github.com/Qihoo360/QConf/releases/download/1.2.1/QConf-1.2.1-1.el6.x86_64.rpm -O  /tmp/QConf-1.2.1-1.el6.x86_64.rpm \
+    && rpm -ivh /tmp/QConf-1.2.1-1.el6.x86_64.rpm && ln -s /usr/local/qconf/lib/libqconf.so /usr/lib/libqconf.so \
+    && ldconfig \
+    && rm -f /tmp/QConf-1.2.1-1.el6.x86_64.rpm
+
+# Lang and timezone ENV
+ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8
+RUN echo Asia/Shanghai > /etc/timezone  && ln -sf /usr/share/zoneinfo/$(cat /etc/timezone) /etc/localtime
+
+# GO ENV
+ENV GOPRIVATE=gitea.ckfah.com*
+ENV GOPROXY=https://goproxy.cn,direct
+RUN git config --global url."git@gitea.ckfah.com:".insteadOf "https://gitea.ckfah.com/"
+
+# 容器内项目地址
+WORKDIR /data/go-template
+
+# copy ssh文件
+COPY .ssh /root/.ssh
+
+## go 编译加速
+## /tmp 目录是编译的临时目录, 只有启动--work参数才有
+## /root/.cache/go-build 是go文件的编译目录
+## /root/go/pkg 是mod的缓存目录
+
+# 启动参数需要根据需求定!
+CMD [ "/bin/bash"]

+ 134 - 0
Makefile

@@ -0,0 +1,134 @@
+# #######################################################
+# Function :Makefile for go                             #
+# Platform :All Darwin Based Platform                   #
+# Version  :1.0                                         #
+# Date     :2020-12-17                                  #
+# Author   :fanhaodong516@gmail.com                     #
+# Usage    :make help			                        #
+# #######################################################
+
+# 项目路径
+PROJECT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+# Go相关参数参考: https://juejin.cn/post/6844903848583266311
+GOBUILD_ARGS := go build -v -ldflags "-s -w"
+GORUN_ARGS := GODEBUG=gctrace=1
+GOMOD_VENDOR := $(shell if [ -d vendor ];then echo -mod=vendor; fi)
+# 如果没有设置-race,则默认开启race
+ifndef race
+	GOBUILD_ARGS += -race
+endif
+
+# go test 相关
+ifndef test_pkg
+	test_pkg := ./...
+endif
+
+# Go的全局的环境变量, GOFLAGS必须清空, 防止其他参数干扰
+GOFLAGS :=
+GO111MODULE := on
+GOPROXY := https://goproxy.cn,direct
+GOPRIVATE := gitea.ckfah.com/cjjy*
+export GO111MODULE
+export GOPROXY
+export GOPRIVATE
+export GOFLAGS
+# 项目配置文件位置
+export ROOT_PATH := $(PROJECT_DIR)
+
+# 第一个是:全路径文件/ 第二个是:git diff文件
+GO_FILE := $(shell find . -name '*.go' | grep -v vendor )
+#GO_FILE := $(shell git diff --name-only --diff-filter=ACM | grep '.go' | grep -v vendor | grep -v _test.go)
+PKG_LIST := $(shell go list go-template/... | grep -v vendor )
+
+# 防止本地文件有重名的问题
+.PHONY : all init build run fmt gofmt goimports govet golint clean get get-gocommon-last-tag get-gocommon-master test testall benchmark help docker docker_image docker_network prometheus
+
+all: fmt govet run ## 启动项目程序
+
+init: ## 初始化项目环境依赖
+	@git config --global url."git@gitea.ckfah.com:".insteadOf "https://gitea.ckfah.com"
+	@if [ ! -e config/env.ini ];then cp config/env.dev.ini config/env.ini; fi
+	@if [ ! -e config/apollo/apollo.json ];then cp config/apollo/apollo.dev.json config/apollo/apollo.json; fi
+
+build: init ## 构建go程序
+	$(GOBUILD_ARGS) $(GOMOD_VENDOR) -o bin/app cmd/main.go
+
+run: build ## 启动Go程序
+	$(GORUN_ARGS) bin/app
+
+fmt: gofmt goimports ## 格式化Go项目代码
+
+gofmt:
+	@for item in $(GO_FILE); do gofmt -d -w $$item; done
+
+goimports:
+	@if [ ! -d ${HOME}/go/bin ]; then mkdir -p ${HOME}/go/bin; fi
+	@if [ ! -e ${HOME}/go/bin/goimports ]; then curl -o ${HOME}/go/bin/goimports https://anthony-wangpan.oss-accelerate.aliyuncs.com/software/2020/12-29/788bd0e30957478488d4159859d29a0e && chmod 0744 ${HOME}/go/bin/goimports; fi
+	@for item in $(GO_FILE); do ${HOME}/go/bin/goimports -d -w $$item; done
+
+govet: ## 静态代码检测工具
+	go vet $(GOMOD_VENDOR) $(PKG_LIST)
+
+golint: ## 检测代码规范工具
+	@if [ ! -d ${HOME}/go/bin ]; then mkdir -p ${HOME}/go/bin; fi
+	@if [ ! -e ${HOME}/go/bin/golint ]; then curl -o ${HOME}/go/bin/golint https://anthony-wangpan.oss-accelerate.aliyuncs.com/software/2020/12-30/6fda119141b84c77b0924e9d140704d0 && chmod 0744 ${HOME}/go/bin/golint; fi
+	@${HOME}/go/bin/golint $(PKG_LIST)
+
+clean: ## 清理无用文件
+	$(RM) -r bin coverage.txt app.pid
+
+get: ## go get 包, eg: make get import=github.com/apache/rocketmq-client-go/v2@v2.0.0
+	go get -u -v $(import)
+	go mod tidy
+
+get-gocommon-last-tag: ## 获取gocommon框架最新的依赖tag
+	go get -u -v gitea.ckfah.com/cjjy/gocommon
+	go mod tidy
+
+get-gocommon-master: ## 获取gocommon框架的master分支
+	go get -u -v gitea.ckfah.com/cjjy/ebike-city-op/gocommon@master
+	go mod tidy
+
+test: fmt clean ## 单元测试, eg: make test test_func=TestDemo test_pkg=./business/util
+	go test -v -race -short -cover -coverprofile=coverage.txt -covermode=atomic -run=$(test_func) $(test_pkg)
+
+benchmark: fmt clean ## 性能测试, eg: make benchmark test_func=BenchmarkDemo test_pkg=./business/util
+	go test -v -run=none -bench=$(test_func) -benchmem $(test_pkg)
+
+testall: fmt clean ## 测试整个项目
+	go test -v -race -short -cover -coverprofile=coverage.txt -covermode=atomic $(test_pkg)
+	go tool cover -html=coverage.txt
+
+coverage: ## 打开浏览器展示测试覆盖率, 前提是你已经测试通过了
+	go tool cover -html=coverage.txt
+
+docker_network:
+	@docker network list  | grep go-project; if [ $$? -eq 1 ]; then docker network create go-project; fi
+
+docker_image:
+	cp -r ${HOME}/.ssh ./
+	docker build -t go-template:latest .
+
+docker: docker_image docker_network ## 使用docker容器进行启动, 依靠绑定目录实现快速构建
+	docker run -it --rm \
+	--name go-template \
+	-p 8080:8080 \
+	--network go-project \
+	-v ${HOME}/go/pkg:/root/go/pkg \
+	-v /tmp/go/.cache/go-build:/root/.cache/go-build \
+	-v /tmp/go/tmp:/tmp \
+	-v $(PROJECT_DIR):/data/go-template \
+	-v /data/log/go-template:/data/log/go-template \
+	go-template:latest make run
+
+prometheus: docker_network ## 本地的prometheus监控,由于mac os 操作系统本身的原因导致无法看到进程信息,参考文档:https://prometheus.io/docs/prometheus
+	@if [ ! -e bin/prometheus/prometheus.yml ]; then mkdir -p bin/prometheus; curl -o bin/prometheus/prometheus.yml https://anthony-wangpan.oss-accelerate.aliyuncs.com/software/2021/4-9/863df45f80cf42cbb45dfc745e5fac3e.yml ; fi
+	docker run --rm \
+	-p 9090:9090 \
+	-v $(PROJECT_DIR)/bin/prometheus/prometheus.yml:/opt/bitnami/prometheus/conf/prometheus.yml \
+	-v $(PROJECT_DIR)/bin/prometheus/data:/opt/bitnami/prometheus/data \
+	--network go-project \
+	bitnami/prometheus:latest
+
+help: ## 帮助
+	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf " \033[36m%-20s\033[0m  %s\n", $$1, $$2}' $(MAKEFILE_LIST)

+ 107 - 0
README.md

@@ -0,0 +1,107 @@
+# go-template 项目
+
+## 目录
+
+### [1. 本项目介绍和使用](./README_project.md)
+
+### [2. 脚手架搭建项目](#脚手架使用)
+
+## 脚手架使用
+
+### 1、下载`go-app`脚本
+
+项目地址(为**gocommon**框架的**script**分支), 下载编译此项目,最后在 `/data/tmp/gocommmon/bin/go-app` 
+
+```shell
+rm -rf /data/tmp/gocommmon && git clone -b script git@gitea.ckfah.com/cjjy/gocommon.git /data/tmp/gocommmon && cd /data/tmp/gocommmon && make tool && cd /data/tmp/gocommmon/bin
+```
+
+### 2、使用`go-app`脚本构建项目
+
+- 使用帮助
+
+```shell
+➜  ~ /data/tmp/gocommmon/bin/go-app build -h
+NAME:
+   build - 生成脚手架项目
+
+USAGE:
+   build [command options] [arguments...]
+
+OPTIONS:
+   --git ssh, -g ssh         the git ssh of go-common project (default: "git@gitea.ckfah.com/cjjy/go-template.git")
+   --branch value, -b value  the git branch of go-common (default: "master")
+   --dir value, -d value     the clone dir for the build project (default: "./")
+   --mod value, -m value     the go mod name for the build project
+   --help, -h                show help (default: false)
+```
+
+- 构建项目
+
+比如构建`go-demo`项目,需要执行:   `/data/tmp/gocommmon/bin/go-app build -m go-demo -d /data/test/go-demo` 
+
+```shell
+➜  ~ /data/tmp/gocommmon/bin/go-app build -m go-demo -d /data/test/go-demo
+[GO-TOOL] 2021/04/09 18:48:00 api.go:29: [INFO] [build] command load config:
+{
+  "branch": "master",
+  "dir": "/data/test/go-demo",
+  "git": "git@gitea.ckfah.com/cjjy/go-template.git",
+  "mod": "go-demo"
+}
+Cloning into '/data/test/go-demo'...
+remote: Counting objects: 4646, done.
+remote: Compressing objects: 100% (2690/2690), done.
+remote: Total 4646 (delta 1697), reused 4594 (delta 1676)
+Receiving objects: 100% (4646/4646), 6.66 MiB | 3.90 MiB/s, done.
+Resolving deltas: 100% (1697/1697), done.
+[GO-BUILD] 2021/04/09 18:48:02 [INFO] 克隆项目成功
+[Shell] 2021/04/09 18:48:02 [INFO] delete file [/data/test/go-demo/.git /data/test/go-demo/README.md]
+[GO-BUILD] 2021/04/09 18:48:02 [INFO] 删除 git 文件成功
+[GO-BUILD] 2021/04/09 18:48:02 [INFO] 创建 README.md 文件成功
+[GO-BUILD] 2021/04/09 18:48:02 [INFO] 修改模版文件: /data/test/go-demo/business/third/ebike_factory_api_third_test.go
+## ......
+[GO-BUILD] 2021/04/09 18:48:02 [INFO] 模版全部替换成功
+[GO-BUILD] 2021/04/09 18:48:02 [INFO] copy 配置文件成功
+[GO-BUILD] 2021/04/09 18:48:02 [INFO] 请输入确认依赖的组件,如果选择默认回车即可,如果不选择此组件请输入no/n即可!
+## 注意这里是选择交互栏
+是否使用 DB  [yes/no]:
+是否使用 NacosRegister  [yes/no]:
+是否使用 Pprof  [yes/no]:
+是否使用 RocketMQProducer  [yes/no]:
+是否使用 Redis  [yes/no]:
+是否使用 Trace  [yes/no]:
+是否使用 LocalCache  [yes/no]:
+## 最后初始化即可
+[GO-BUILD] 2021/04/09 18:49:14 [INFO] 初始化Main文件成功
+[GO-BUILD] 2021/04/09 18:49:14 [INFO] 格式化代码, file: /data/test/go-demo/business/service/init_test.go
+[GO-BUILD] 2021/04/09 18:49:14 [INFO] 格式化代码, file: /data/test/go-demo/business/controller/init_test.go
+[GO-BUILD] 2021/04/09 18:49:14 [INFO] 格式化代码, file: /data/test/go-demo/business/controller/report_controller_test.go
+[GO-BUILD] 2021/04/09 18:49:14 [INFO] 格式化代码, file: /data/test/go-demo/cmd/main.go
+[GO-BUILD] 2021/04/09 18:49:14 [INFO] 格式化代码成功
+[GO-BUILD] 2021/04/09 18:49:14 [INFO] 构建成功, 谢谢使用, 请切换到项目目录: /data/test/go-demo , 然后执行make命令即可运行, 或者运行 go build -race -o bin/app -v cmd/main.go
+```
+
+### 3、启动项目
+
+```shell
+➜  ~ cd /data/test/go-demo
+➜  go-demo make
+go build -v -ldflags "-s -w" -race  -o bin/app cmd/main.go
+go-demo/business/model
+go-demo/business/exception
+go-demo/business/job
+go-demo/business/dao
+go-demo/business/dto
+go-demo/business/util
+go-demo/business/third
+go-demo/business/service
+go-demo/business/controller
+go-demo/router
+
+## .....
+[GO-COMMON] 2021/04/09 18:49:56 config.go:200: [DEBUG] NacosConfig load config success, 
+## .......
+```
+
+

+ 235 - 0
README_project.md

@@ -0,0 +1,235 @@
+# go-template 项目
+
+## 目录
+
+#### [1. 项目结构](#项目结构)
+
+#### [2. 项目介绍](#项目介绍)
+
+## 项目结构
+
+> ​	各级目录、包功能介绍,有些点需要注意一下
+
+```go
+➜  go-template git:(master) ✗ tree -L 3
+.
+├── README.md // 项目README.md
+├── bin
+│   └── app // 编译后的二进制文件
+├── cicd // cicd脚本
+│   ├── build.sh // 构建脚本(目前发不到容器内的不需要),需要构建机器上执行,目前是root用户 git config --global url."git@gitea.ckfah.com:".insteadOf "https://gitea.ckfah.com/"
+│   └── deploy.sh // 发布脚本(目前发不到容器内的不需要),需要手动修改一下 CURRPORT 变量记得修改
+├── cmd
+│   └── main.go  // 主函数
+├── business
+│   ├── controller // controller 
+│   │   ├── base_controller.go // 这个文件放置全局变量,这个项目不推荐以包隔离
+│   ├── dao // dao
+│   ├── dto // 数据传输对象,包含返回给前段的数据,也包含有调用远程的数据
+│   ├── exception // 全局异常变量
+│   ├── job // job,目前不推荐go项目写定时任务,里面放有 kafka的消费
+│   ├── model // 数据库模型对象
+│   ├── service // service
+│   │   ├── base_service.go // 这个文件放置全局变量,这个项目不推荐以包隔离
+│   └── third // 调用三方接口
+│   ├── middleware // 自定义中间件
+│   └── util // 自定义工具包,优先使用框架自带工具包:import "gitea.ckfah.com/cjjy/gocommon/pkg/common"
+├── config // 配置文件目录
+│   ├── apollo // 使用apollo时需要配置,注意 apollo和nacos不可以一起使用
+│   ├── env.ini // 当前运行的配置文件
+│   ├── env.dev.ini // 各环境配置
+│   ├── env.release.ini
+│   ├── env.slave.ini
+│   ├── env.test.ini
+│   ├── env.test2.ini
+│   └── env.test3.ini
+├── router // http 路由
+│   ├── op_router.go // 自定义路由
+│   ├── router.go // 所有路由放到这里配置
+│   └── sys_router.go // 项目路由,包含web_status
+├── go.mod // go mod 配置
+├── go.sum // go sum 文件
+├── Makefile //make 脚本,需要手动修改一下 PORT 变量
+├── Dockerfile //Dokcerfile文件,是的可以依赖容器去启动
+├── coverage.txt //go test 测试完后展示的覆盖测试文件
+└── app.pid // 当前运行中程序的pid
+```
+
+## 项目介绍
+
+### 1、环境依赖
+
+- Go Version >=1.11 (最好 1.13), 安装Git 、Go 即可
+
+```shell
+➜  ~ go version
+go version go1.13.5 darwin/amd64
+➜  ~ git version
+git version 2.24.3 (Apple Git-128)
+```
+
+- gocommon项目权限,找组内人申请权限开通!
+- `libqconf.dylib` 包 ,也可以使用容器去启动项目
+
+### 2、启动项目
+
+- 下载本项目: `git clone git@gitea.ckfah.com/cjjy/go-template.git` 到本地
+- 创建日志目录:`mkdir /data/log/go-template`
+- 执行`make` 命令即可运行
+
+### 3、帮助
+
+```shell
+➜  go-template git:(master) ✗ make help
+all                            启动项目程序
+init                           初始化项目环境依赖
+build                          构建go程序
+run                            启动Go程序
+fmt                            格式化Go项目代码
+govet                          静态代码检测工具
+golint                         检测代码规范工具
+clean                          清理无用文件
+get                            go get 包, eg: make get import=github.com/apache/rocketmq-client-go/v2@v2.0.0
+get-gocommon-last-tag          获取gocommon框架最新的依赖tag
+get-gocommon-master            获取gocommon框架的master分支
+test                           单元测试, eg: make test test_func=Test_cityConfigThird_CityInfo test_pkg=./business/third
+benchmark                      性能测试, eg: make benchmark test_func=Test_cityConfigThird_CityInfo test_pkg=./business/third
+testall                        测试整个项目
+docker                         使用docker容器进行启动, 依靠绑定目录实现快速构建
+prometheus                     本地的prometheus监控,由于mac os 操作系统本身的原因导致无法看到进程信息,参考文档:https://prometheus.io/docs/prometheus/latest/getting_started/
+```
+
+### 4、启动项目
+
+1、在项目根目录执行 `make` 即可
+
+```shell
+➜  go-template git:(master) ✗ make
+go build -v -ldflags "-s -w" -race  -o bin/app cmd/main.go
+GODEBUG=gctrace=1 bin/app
+[GO-COMMON] 2021/04/09 17:31:32 boot.go:113: [INFO] [Config] start init...
+```
+
+2、检测项目是否启动成功,执行 `curl http://localhost:8080/go-template/web_status -v`
+
+```shell
+➜  ~ curl http://localhost:8080/go-template/web_status -v
+*   Trying ::1...
+* TCP_NODELAY set
+* Connected to localhost (::1) port 8080 (#0)
+> GET /go-template/web_status HTTP/1.1
+> Host: localhost:8080
+> User-Agent: curl/7.64.1
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Content-Type: application/json; charset=utf-8
+< Date: Fri, 09 Apr 2021 09:24:34 GMT
+< Content-Length: 12
+<
+"status_ok"
+* Connection #0 to host localhost left intact
+* Closing connection 0
+```
+
+### 5、单元测试、benchmark
+
+- 测试 `go-template/business/util` 包下的 `TestDemo` 方法,执行 ` make test test_func=TestDemo test_pkg=./business/util` 即可!
+
+```shell
+➜  go-template git:(master) ✗ make test test_func=TestDemo test_pkg=./business/util
+rm -f -r bin coverage.txt app.pid
+go test -v -race -short -cover -coverprofile=coverage.txt -covermode=atomic -run=TestDemo ./business/util
+=== RUN   TestDemo
+--- PASS: TestDemo (0.00s)
+    util_test.go:17: arr: []int{9, 8, 7, 6, 5, 4, 3, 2, 1}
+    util_test.go:19: sorted arr: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
+PASS
+coverage: 0.0% of statements
+ok  	go-template/business/util	1.037s	coverage: 0.0% of statements
+```
+
+- benchmark  `go-template/business/util` 包下的 `BenchmarkDemo` 方法,执行 ` make benchmark test_func=BenchmarkDemo test_pkg=./business/util` 即可!
+
+```shell
+➜  go-template git:(master) ✗ make benchmark test_func=BenchmarkDemo test_pkg=./business/util
+rm -f -r bin coverage.txt app.pid
+go test -v -run=none -bench=BenchmarkDemo -benchmem ./business/util
+goos: darwin
+goarch: amd64
+pkg: go-template/business/util
+BenchmarkDemo-12    	14818328	        78.5 ns/op	      32 B/op	       1 allocs/op
+PASS
+ok  	go-template/business/util	1.261s
+```
+
+### 6、项目调试
+
+使用**Goland**工具进行调试项目的时候切记要设置一下输出目录 !
+
+![image-20210409174935422](https://tyut.oss-accelerate.aliyuncs.com/image/2021/4-9/a5ac031029f54bb995f0a574b0e0e34c.png)
+
+### 7、使用docker容器启动
+
+首先你本地需要装docker,容器启动后,绑定的是你本机的 `8080`端口,和你本地启动基本是一样的,你本机可以访问服务路由
+
+```shell
+➜  go-template git:(master) ✗ make docker
+cp -r /Users/fanhaodong/.ssh ./
+docker build -t go-template:latest .
+Sending build context to Docker daemon  201.2kB
+Step 1/19 : FROM centos:7
+## ........
+Step 19/19 : CMD [ "/bin/bash"]
+ ---> Running in 95c8cac0cc45
+Removing intermediate container 95c8cac0cc45
+ ---> 698785dd6e95
+Successfully built 698785dd6e95
+Successfully tagged go-template:latest
+e3a231c7c0f8        go-project          bridge              local
+docker run -it --rm \
+	--name go-template \
+	-p 8080:8080 \
+	--network go-project \
+	-v /Users/fanhaodong/go:/root/go \
+	-v /Users/fanhaodong/project/go-template:/data/go-template \
+	-v /data/log/go-template:/data/log/go-template \
+	-v /tmp/go-build:/root/.cache/go-build \
+	go-template:latest make run
+go build -v -ldflags "-s -w" -race  -o bin/app cmd/main.go
+GODEBUG=gctrace=1 bin/app
+[GO-COMMON] 2021/04/09 17:51:12 boot.go:113: [INFO] [Config] start init...
+## .........
+```
+
+### 8、使用prometheus监控项目
+
+1、访问 `curl http://localhost:8080/metrics`
+
+2、使用容器启动server端进行监控,记得修改项目路径下 `bin/prometheus/prometheus.yml` 配置文件,为你本机的IP,服务名称写你的服务名称,比如我本地网卡是 `en0`,ip是 `172.15.64.10`,服务名是 `go-template` !
+
+```shell
+targets: ['172.15.64.10:8080','go-template:8080']
+```
+
+3、启动的时候会帮助把配置文件下载下来
+
+```shell
+➜  go-template git:(master) ✗ make prometheus
+e3a231c7c0f8        go-project          bridge              local
+  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
+                                 Dload  Upload   Total   Spent    Left  Speed
+100  1004  100  1004    0     0   9471      0 --:--:-- --:--:-- --:--:--  9471
+docker run --rm \
+	-p 9090:9090 \
+	-v /Users/fanhaodong/project/go-template/bin/prometheus/prometheus.yml:/opt/bitnami/prometheus/conf/prometheus.yml \
+	-v /Users/fanhaodong/project/go-template/bin/prometheus/data:/opt/bitnami/prometheus/data \
+	--network go-project \
+	bitnami/prometheus:latest
+level=info ts=2021-04-09T09:53:59.316Z caller=main.go:322 msg="No time or size retention was set so using the default time retention" duration=15d
+level=info ts=2021-04-09T09:53:59.317Z caller=main.go:360 msg="Starting Prometheus" version="(version=2.23.0, branch=HEAD, revision=26d89b4b0776fe4cd5a3656dfa520f119a375273)"
+level=info ts=2021-04-09T09:53:59.317Z caller=main.go:365 build_context="(go=go1.15.5, user=root@37609b3a0a21, date=20201126-10:56:17)"
+```
+
+4、可以访问本机的 [http://localhost:9090/graph](http://localhost:9090/graph) 查看监控信息!
+

+ 0 - 0
access_log.log


+ 9 - 0
business/controller/base_controller.go

@@ -0,0 +1,9 @@
+package controller
+
+import (
+	"go-template/business/service"
+)
+
+var (
+	reportService = service.NewReportService()
+)

+ 21 - 0
business/controller/init_test.go

@@ -0,0 +1,21 @@
+package controller
+
+import (
+	"flag"
+	"go-template/business/util"
+	"os"
+	"testing"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/boot"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/middleware"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	boot.Init(boot.Qconf, boot.DB, boot.Redis, boot.Trace, boot.NacosDiscover, boot.RocketMQProducer)
+	util.AddMiddleWareHandlerFunc(middleware.AccessLogMiddleware())
+	util.AddMiddleWareHandlerFunc(middleware.AddTraceId())
+	boot.Start()
+	exitCode := m.Run()
+	os.Exit(exitCode)
+}

+ 221 - 0
business/controller/report_controller.go

@@ -0,0 +1,221 @@
+package controller
+
+import (
+	"go-template/business/dto"
+	"go-template/business/exception"
+	"strconv"
+	"time"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/common"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/logger"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+)
+
+type reportController struct {
+}
+
+func NewReportController() *reportController {
+	return new(reportController)
+}
+
+// 普通请求
+func (rc *reportController) ReportInfo(ctx *engines.Context) {
+	request := new(dto.ReportInfoRequest)
+	err := ctx.ShouldBindJSON(request)
+	if err != nil {
+		logger.Warnc(ctx, "[ReportInfo] bind params err,err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	logger.Infoc(ctx, "[ReportInfo] start,request=%+v", request)
+	result, cerr := reportService.ReportInfo(ctx, &request.Params)
+	if cerr != nil {
+		logger.Warnc(ctx, "[ReportInfo] end err,err=%v", cerr)
+		common.FailJson(ctx, cerr)
+		return
+	}
+	logger.Infoc(ctx, "[ReportInfo] end,result=%+v", result)
+	common.SuccessJson(ctx, result)
+}
+
+// 分页请求查询
+func (rc *reportController) ReportList(ctx *engines.Context) {
+	request := new(dto.ReportListRequest)
+	err := ctx.ShouldBindJSON(request)
+	if err != nil {
+		logger.Warnc(ctx, "[ReportList] bind params err,err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	logger.Infoc(ctx, "[ReportList] start,request=%+v", request)
+	result, cerr := reportService.ReportList(ctx, &request.Params)
+	if cerr != nil {
+		logger.Warnc(ctx, "[ReportList] end err,err=%v", cerr)
+		common.FailJson(ctx, cerr)
+		return
+	}
+	logger.Infoc(ctx, "[ReportList] end,result=%+v", result)
+	common.SuccessJson(ctx, result)
+}
+
+/**
+下载excel文件
+url: http://localhost:8080/go-template/download/xlsx/file?row=1000&column=12&&sheet=2
+*/
+func (rc *reportController) DownLoadXlsxFile(ctx *engines.Context) {
+	// get请求的参数请使用 ctx.Query
+	rowStr := ctx.Query("row")
+	columnStr := ctx.Query("column")
+	sheetStr := ctx.Query("sheet")
+	row, err := strconv.ParseInt(rowStr, 10, 64)
+	if err != nil {
+		logger.Warnc(ctx, "[DownLoadXlsxFile] start,bind params find err, err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	column, err := strconv.ParseInt(columnStr, 10, 64)
+	if err != nil {
+		logger.Warnc(ctx, "[DownLoadXlsxFile] start,bind params find err, err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	sheet, err := strconv.ParseInt(sheetStr, 10, 64)
+	if err != nil {
+		logger.Warnc(ctx, "[DownLoadXlsxFile] start,bind params find err, err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	params := dto.DownLoadXlsxFileParams{
+		Row:    int(row),
+		Column: int(column),
+		Sheet:  int(sheet),
+	}
+
+	logger.Infoc(ctx, "[DownLoadXlsxFile] start,request=%+v", &params)
+	if err := reportService.DownLoadXlsxFile(ctx, ctx.Writer, &params); err != nil {
+		logger.Warnc(ctx, "[DownLoadXlsxFile] end err,err=%v", err)
+		common.FailJson(ctx, err)
+		return
+	}
+	logger.Infoc(ctx, "[DownLoadXlsxFile] end success")
+}
+
+/**
+下载csv文件
+url: http://localhost:8080/go-template/download/csv/file?row=10000&column=10
+*/
+func (rc *reportController) DownLoadCsvFile(ctx *engines.Context) {
+	// get请求的参数请使用 ctx.Query
+	rowStr := ctx.Query("row")
+	columnStr := ctx.Query("column")
+	row, err := strconv.ParseInt(rowStr, 10, 64)
+	if err != nil {
+		logger.Warnc(ctx, "[DownLoadCsvFile] start,bind params find err, err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	column, err := strconv.ParseInt(columnStr, 10, 64)
+	if err != nil {
+		logger.Warnc(ctx, "[DownLoadCsvFile] start,bind params find err, err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	params := dto.DownLoadCsvFileParams{
+		Row:    int(row),
+		Column: int(column),
+	}
+	logger.Infoc(ctx, "[DownLoadCsvFile] start,request=%+v", &params)
+	if err := reportService.DownLoadCsvFile(ctx, ctx.Writer, &params); err != nil {
+		logger.Warnc(ctx, "[DownLoadCsvFile] end err,err=%v", err)
+		common.FailJson(ctx, err)
+		return
+	}
+	logger.Infoc(ctx, "[DownLoadCsvFile] end success")
+}
+
+/**
+下载excel文件
+url: http://localhost:8080/go-template/download/xlsx/file?row=1000&column=12&&sheet=2
+*/
+func (rc *reportController) UploadXlsxFile(ctx *engines.Context) {
+	// 参数为 sheet_name
+	sheetName := ctx.Request.FormValue("sheet_name")
+	params := dto.UploadXlsxFileParams{
+		SheetName: sheetName,
+	}
+	logger.Infoc(ctx, "[UploadXlsxFile] start, params=%v", &params)
+
+	// 首先拿到 参数为 file的文件
+	fileDesc, err := ctx.FormFile("file")
+	if err != nil {
+		logger.Warnc(ctx, "[UploadXlsxFile] get file err, err=%v", err)
+		common.FailJson(ctx, exception.DefaultError(err))
+		return
+	}
+	file, err := fileDesc.Open()
+	if err != nil {
+		logger.Errorc(ctx, "[UploadXlsxFile] open file err, err=%v", err)
+		common.FailJson(ctx, exception.DefaultError(err))
+		return
+	}
+	// 记得关闭流
+	defer file.Close()
+
+	// 处理业务
+	response, cerror := reportService.UploadXlsxFile(ctx, file, &params)
+	if cerror != nil {
+		logger.Errorc(ctx, "[UploadXlsxFile] end find err, err=%v", cerror)
+		common.FailJson(ctx, cerror)
+	}
+
+	logger.Infoc(ctx, "[UploadXlsxFile] end,result=%+v", response)
+	common.SuccessJson(ctx, response)
+	return
+}
+
+// 发送MQ消息
+func (rc *reportController) SendMQ(ctx *engines.Context) {
+	request := new(dto.SendMQRequest)
+	err := ctx.ShouldBindJSON(request)
+	if err != nil {
+		logger.Warnc(ctx, "[SendMQ] bind params err,err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	logger.Infoc(ctx, "[SendMQ] start,request=%+v", request)
+	result, cerr := reportService.SendMQ(ctx, &request.Params)
+	if cerr != nil {
+		logger.Warnc(ctx, "[SendMQ] end err,err=%v", cerr)
+		common.FailJson(ctx, cerr)
+		return
+	}
+	logger.Infoc(ctx, "[SendMQ] end,result=%+v", result)
+	common.SuccessJson(ctx, result)
+}
+
+/**
+模拟超时请看 access_log
+url: http://localhost:8080/go-template/timeout?sleep=25
+*/
+func (rc *reportController) SleepTimeout(ctx *engines.Context) {
+	sleepStr := ctx.Query("sleep")
+	sleepSeconds, err := strconv.ParseInt(sleepStr, 10, 64)
+	if err != nil {
+		logger.Warnc(ctx, "[SleepTimeout] start,bind params find err, err=%v", err)
+		common.FailJson(ctx, exception.ParamsBindError)
+		return
+	}
+	logger.Infoc(ctx, "[SleepTimeout] start, sleep=%sm", sleepSeconds)
+	time.Sleep(time.Second * time.Duration(sleepSeconds))
+	logger.Infoc(ctx, "[SleepTimeout] end success !")
+	common.SuccessJson(ctx, nil)
+}
+
+/**
+模拟panic 请看 access_log 和 error log
+url: http://localhost:8080/go-template/panic
+*/
+func (rc *reportController) TestPanic(ctx *engines.Context) {
+	logger.Infoc(ctx, "[SleepTimeout] start")
+	panic("test panic !!!")
+}

+ 113 - 0
business/controller/report_controller_test.go

@@ -0,0 +1,113 @@
+package controller
+
+import (
+	"go-template/business/util"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+// make test test_func=Test_reportController_Query test_pkg=./business/controller
+func Test_reportController_Query(t *testing.T) {
+	t.Run("普通查询", func(t *testing.T) {
+		response, err := util.NewTestPostHttpRequest(`{"params":{"id":1}}`, NewReportController().ReportInfo)
+		util.NewTesting(t).CheckResult(response, err)
+	})
+	t.Run("分页查询-1", func(t *testing.T) {
+		response, err := util.NewTestPostHttpRequest(`{"params":{"user_id":3768605}}`, NewReportController().ReportList)
+		util.NewTesting(t).CheckResult(response, err)
+	})
+	t.Run("分页查询-2", func(t *testing.T) {
+		response, err := util.NewTestPostHttpRequest(`{"params":{"user_id":3768605,"page":1,"page_size":5}}`, NewReportController().ReportList)
+		util.NewTesting(t).CheckResult(response, err)
+	})
+}
+
+// make test test_func=Test_reportController_DownLoadCsvFile test_pkg=./business/controller
+// mkdir -p /data/tmp/go-template
+// http://localhost:8080/go-template/download/csv/file?row=1000&column=20
+func Test_reportController_DownLoadCsvFile(t *testing.T) {
+	response, err := util.NewTestHttpRequestWithDownLoadFile(map[string]string{"row": "1000", "column": "20"}, NewReportController().DownLoadCsvFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+	body, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	fileName := filepath.Join("/data/tmp/go-template", "test.csv")
+	t.Logf("open file : %s\n", fileName)
+	file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer file.Close()
+
+	if _, err := file.Write(body); err != nil {
+		t.Fatal(err)
+	}
+}
+
+// make test test_func=Test_reportController_DownLoadAndUploadXlsxFile test_pkg=./business/controller
+// mkdir -p /data/tmp/go-template
+// 下载 http://localhost:8080/go-template/download/xlsx/file?row=1000&column=20&&sheet=3
+func Test_reportController_DownLoadAndUploadXlsxFile(t *testing.T) {
+	fileName := "test.xlsx"
+	filePath := filepath.Join("/data/tmp/go-template", fileName)
+
+	t.Run("下载excel文件: "+filePath, func(t *testing.T) {
+		response, err := util.NewTestHttpRequestWithDownLoadFile(map[string]string{"row": "1000", "column": "20", "sheet": "3"}, NewReportController().DownLoadXlsxFile)
+		if err != nil {
+			t.Fatal(err)
+		}
+		body, err := ioutil.ReadAll(response.Body)
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Logf("open file : %s\n", filePath)
+		file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer file.Close()
+
+		if _, err := file.Write(body); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	t.Run("上传excel文件: "+filePath, func(t *testing.T) {
+		response, err := util.NewTestHttpRequestWithUploadFile(
+			map[string]string{"sheet_name": "demo数据-0"},
+			[]util.FileForm{util.NewFileFormFromFile("file", fileName, filePath)},
+			NewReportController().UploadXlsxFile)
+		util.NewTesting(t).CheckResult(response, err)
+	})
+}
+
+// make test test_func=Test_reportController_SendMQ test_pkg=./business/controller
+func Test_reportController_SendMQ(t *testing.T) {
+	t.Run("test-1", func(t *testing.T) {
+		response, err := util.NewTestPostHttpRequest(`{"params":{"topic":"test_topic","message":"hello world , my name is go-template !!!!"}}`, NewReportController().SendMQ)
+		util.NewTesting(t).CheckResult(response, err)
+	})
+	t.Run("test-2", func(t *testing.T) {
+		response, err := util.NewTestPostHttpRequest(`{"params":{"message":"hello world , my name is go-template !!!!"}}`, NewReportController().SendMQ)
+		util.NewTesting(t).CheckResult(response, err)
+	})
+}
+
+// 记得检测日志!
+// make test test_func=Test_reportController_Panic test_pkg=./business/controller
+func Test_reportController_Panic(t *testing.T) {
+	response, err := util.NewTestGetHttpRequest(map[string]string{}, NewReportController().TestPanic)
+	if err != nil {
+		t.Fatal(err)
+	}
+	body, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Logf("response body: %s, status: %v", body, response.StatusCode)
+}

+ 26 - 0
business/dao/init_test.go

@@ -0,0 +1,26 @@
+package dao
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/boot"
+)
+
+/**
+每个test 都会使用这个函数调用
+*/
+func TestMain(m *testing.M) {
+	// 解析参数记得
+	flag.Parse()
+
+	// 初始化资源,前置处理器
+	boot.Init(boot.DB, boot.Trace)
+
+	// 执行我们的test,其实就是个切面
+	exitCode := m.Run()
+
+	// 退出,后置处理器
+	os.Exit(exitCode)
+}

+ 91 - 0
business/dao/report_peccancy_dao.go

@@ -0,0 +1,91 @@
+package dao
+
+import (
+	"context"
+	"go-template/business/exception"
+	"go-template/business/model"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/common"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/database/db"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/logger"
+	"xorm.io/xorm"
+)
+
+type reportPeccancyDao struct {
+}
+
+func NewReportPeccancyDao() *reportPeccancyDao {
+	return &reportPeccancyDao{}
+}
+
+var (
+	_ReportPeccancy = new(model.ReportPeccancy)
+)
+
+func (*reportPeccancyDao) TableName() string {
+	return _ReportPeccancy.TableName()
+}
+
+func (rpd *reportPeccancyDao) GetById(ctx context.Context, id uint64) (*model.ReportPeccancy, cerror.Cerror) {
+	result := &model.ReportPeccancy{}
+	isExist, err := db.NewSlaveSession(ctx).Where("id=?", id).Cols("*").Get(result)
+	if err != nil {
+		logger.Errorc(ctx, "[GetById] err,id=%d", id)
+		return nil, exception.DbExecError(err)
+	}
+	if !isExist {
+		return nil, nil
+	}
+	return result, nil
+}
+
+/**
+这个方法根据业务去使用,不推荐直接删除,数据库表设计应该为标记删除,可以设置一个is_valid 字段标记是否有效
+*/
+func (rpd *reportPeccancyDao) DeleteById(ctx context.Context, session *xorm.Session, id uint64) (int64, cerror.Cerror) {
+	effectRow, err := session.Where("id=?", id).Delete(rpd)
+	if err != nil {
+		logger.Errorc(ctx, "[DeleteById] err,id=%d", id)
+		return 0, exception.DbDeleteError(err)
+	}
+	return effectRow, nil
+}
+
+func (rpd *reportPeccancyDao) UpdateById(ctx context.Context, session *xorm.Session, id uint64, params map[string]interface{}) (int64, cerror.Cerror) {
+	effectRow, err := session.Table(rpd).Where("id=?", id).Update(params)
+	if err != nil {
+		logger.Errorc(ctx, "[UpdateById] err,id=%d,params=%+v", id, params)
+		return 0, exception.DbUpdateError(err)
+	}
+	return effectRow, nil
+}
+
+func (rpd *reportPeccancyDao) SaveOne(ctx context.Context, session *xorm.Session, param *model.ReportPeccancy) (int64, cerror.Cerror) {
+	effectRow, err := session.InsertOne(param)
+	if err != nil {
+		logger.Errorc(ctx, "[SaveOne] err,param=%+v", param)
+		return 0, exception.DbInsertError(err)
+	}
+	return effectRow, nil
+}
+
+func (rpd *reportPeccancyDao) GetByUserId(ctx context.Context, userId uint64, paginator common.Paginator) ([]model.ReportPeccancy, cerror.Cerror) {
+	list := make([]model.ReportPeccancy, 0)
+	err := db.NewSlaveSession(ctx).Where("user_id=?", userId).Limit(paginator.PageSize, paginator.LimitStart).Find(&list)
+	if err != nil {
+		logger.Errorc(ctx, "[GetByIds] err,user_id=%v", userId)
+		return nil, exception.DbExecError(err)
+	}
+	return list, nil
+}
+
+func (rpd *reportPeccancyDao) GetCountByUserId(ctx context.Context, userId uint64) (int64, cerror.Cerror) {
+	count, err := db.NewSlaveSession(ctx).Table(rpd.TableName()).Where("user_id=?", userId).Count()
+	if err != nil {
+		logger.Errorc(ctx, "[GetCountByUserId] err,user_id=%v", userId)
+		return 0, exception.DbExecError(err)
+	}
+	return count, nil
+}

+ 291 - 0
business/dao/report_peccancy_dao_test.go

@@ -0,0 +1,291 @@
+package dao
+
+import (
+	"fmt"
+	"go-template/business/model"
+	"go-template/business/util"
+	"testing"
+	"time"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/common"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/database/db"
+)
+
+// make test test_func=Test_reportPeccancyDao_NoSession test_pkg=./business/dao
+func Test_reportPeccancyDao_NoSession(t *testing.T) {
+	var (
+		searchId uint64 = 0
+		userId   uint64 = 10086
+
+		userName   = "init_name"
+		updateName = "update_name"
+	)
+	context := util.MockContext()
+
+	// 插入
+	t.Run("插入和查询 id", func(t *testing.T) {
+		session := db.NewMasterSession(context)
+		t.Logf("保存数据,user_id: %d, user_name: %s", userId, userName)
+		saveData := model.ReportPeccancy{
+			UserID:         userId,
+			UserName:       userName,
+			DiscoveryTime:  time.Now(),
+			OperateTime:    time.Now(),
+			StartCycleTime: time.Now(),
+			EndCycleTime:   time.Now(),
+		}
+		effectRow, err := NewReportPeccancyDao().SaveOne(context, session, &saveData)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if effectRow == 0 {
+			t.Fatal("未插入到数据库中!!")
+		}
+		t.Logf("save success , save_data_id: %d, effect_row: %d", saveData.ID, effectRow)
+		searchId = saveData.ID
+	})
+
+	// 查询(本地环境没有主从)
+	t.Run(fmt.Sprintf("查询 id %d", searchId), func(t *testing.T) {
+		data, err := NewReportPeccancyDao().GetById(context, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if data == nil {
+			t.Fatal("数据库中未找到")
+		}
+		t.Logf("查询成功,id: %d, user_id: %d, user_name: %s", data.ID, data.UserID, data.UserName)
+	})
+
+	// 查询分页
+	t.Run(fmt.Sprintf("查询 id %d user_id %d", searchId, userId), func(t *testing.T) {
+		list, err := NewReportPeccancyDao().GetByUserId(context, userId, common.PageRequest{}.GetPaginator())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if list == nil {
+			t.Fatal("分页查询失败,列表为空不正确")
+		}
+		t.Logf("查询分页成功, len list: %d", len(list))
+
+		count, err := NewReportPeccancyDao().GetCountByUserId(context, userId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if count == 0 {
+			t.Fatal("分页查询失败,总量不能为0")
+		}
+		t.Logf("查询分页成功, count: %d", count)
+	})
+
+	// 更新
+	t.Run(fmt.Sprintf("更新 id %d", searchId), func(t *testing.T) {
+		session := db.NewMasterSession(context)
+		effectRow, err := NewReportPeccancyDao().UpdateById(context, session, searchId, map[string]interface{}{"user_name": updateName})
+		if err != nil {
+			t.Fatal(err)
+		}
+		if effectRow == 0 {
+			t.Fatal("更新失败!")
+		}
+		t.Logf("更新成功, effectRow: %d", effectRow)
+
+		data, err := NewReportPeccancyDao().GetById(context, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if data == nil {
+			t.Fatal("更新失败,未查询到数据!")
+		}
+		if data.UserName == updateName {
+			t.Logf("更新成功,username 一致!")
+		} else {
+			t.Fatal("更新失败,username 不一致")
+		}
+	})
+
+	// 删除
+	t.Run(fmt.Sprintf("删除 id %d", searchId), func(t *testing.T) {
+		session := db.NewMasterSession(context)
+		effectRow, err := NewReportPeccancyDao().DeleteById(context, session, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if effectRow == 0 {
+			t.Fatal("删除失败")
+		}
+		t.Logf("删除成功, effectRow: %d", effectRow)
+
+		data, err := NewReportPeccancyDao().GetById(context, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if data == nil {
+			t.Logf("删除成功,未查询到数据!")
+		}
+	})
+}
+
+// make test test_func=Test_reportPeccancyDao_WithSession test_pkg=./business/dao
+func Test_reportPeccancyDao_WithSession(t *testing.T) {
+	var (
+		searchId uint64 = 0
+		userId   uint64 = 10010
+
+		userName     = "init_name"
+		updateName   = "update_name"
+		rollbackName = "rollback_name"
+	)
+	context := util.MockContext()
+
+	// 插入
+	t.Run("插入和查询 id", func(t *testing.T) {
+		session := db.NewMasterSession(context)
+		session.Begin()
+		defer session.Close()
+		t.Logf("保存数据,user_id: %d, user_name: %s", userId, userName)
+		saveData := model.ReportPeccancy{
+			UserID:         userId,
+			UserName:       userName,
+			DiscoveryTime:  time.Now(),
+			OperateTime:    time.Now(),
+			StartCycleTime: time.Now(),
+			EndCycleTime:   time.Now(),
+		}
+		effectRow, err := NewReportPeccancyDao().SaveOne(context, session, &saveData)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if effectRow == 0 {
+			t.Fatal("未插入到数据库中!!")
+		}
+		session.Commit()
+		t.Logf("save success , save_data_id: %d, effect_row: %d", saveData.ID, effectRow)
+		searchId = saveData.ID
+	})
+
+	// 查询(本地环境没有主从)
+	t.Run(fmt.Sprintf("查询 id %d", searchId), func(t *testing.T) {
+		data, err := NewReportPeccancyDao().GetById(context, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if data == nil {
+			t.Fatal("数据库中未找到")
+		}
+		t.Logf("查询成功,id: %d, user_id: %d, user_name: %s", data.ID, data.UserID, data.UserName)
+	})
+
+	// 查询分页
+	t.Run(fmt.Sprintf("查询 id %d user_id %d", searchId, userId), func(t *testing.T) {
+		list, err := NewReportPeccancyDao().GetByUserId(context, userId, common.PageRequest{}.GetPaginator())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if list == nil {
+			t.Fatal("分页查询失败,列表为空不正确")
+		}
+		t.Logf("查询分页成功, len list: %d", len(list))
+
+		count, err := NewReportPeccancyDao().GetCountByUserId(context, userId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if count == 0 {
+			t.Fatal("分页查询失败,总量不能为0")
+		}
+		t.Logf("查询分页成功, count: %d", count)
+	})
+
+	// 更新回滚
+	t.Run(fmt.Sprintf("更新回滚测试 id %d", searchId), func(t *testing.T) {
+		// 更新,defer
+		func() {
+			session := db.NewMasterSession(context)
+			session.Begin()
+			defer session.Close()
+
+			effectRow, err := NewReportPeccancyDao().UpdateById(context, session, searchId, map[string]interface{}{"user_name": rollbackName})
+			if err != nil {
+				t.Fatal(err)
+			}
+			if effectRow == 0 {
+				t.Fatal("回滚失败!")
+			}
+			// 不用写rowback,返回出去自动回滚
+			t.Logf("更新确认进行回滚, effectRow: %d", effectRow)
+		}()
+
+		data, err := NewReportPeccancyDao().GetById(context, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if data == nil {
+			t.Fatal("回滚失败,未查询到数据!")
+		}
+		if data.UserName == userName {
+			t.Logf("回滚成功,username和回滚前保持 一致!")
+		} else {
+			t.Fatal("回滚失败,username和回滚前不保持 一致!")
+		}
+	})
+
+	// 更新
+	t.Run(fmt.Sprintf("更新 id %d", searchId), func(t *testing.T) {
+		// 更新,defer
+		func() {
+			session := db.NewMasterSession(context)
+			session.Begin()
+			defer session.Close()
+
+			effectRow, err := NewReportPeccancyDao().UpdateById(context, session, searchId, map[string]interface{}{"user_name": updateName})
+			if err != nil {
+				t.Fatal(err)
+			}
+			if effectRow == 0 {
+				t.Fatal("更新失败!")
+			}
+			t.Logf("更新成功, effectRow: %d", effectRow)
+			session.Commit()
+		}()
+
+		data, err := NewReportPeccancyDao().GetById(context, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if data == nil {
+			t.Fatal("更新失败,未查询到数据!")
+		}
+		if data.UserName == updateName {
+			t.Logf("更新成功,username 一致!")
+		} else {
+			t.Fatal("更新失败,username 不一致")
+		}
+	})
+
+	// 删除
+	t.Run(fmt.Sprintf("删除 id %d", searchId), func(t *testing.T) {
+		func() {
+			session := db.NewMasterSession(context)
+			session.Begin()
+			defer session.Close()
+			effectRow, err := NewReportPeccancyDao().DeleteById(context, session, searchId)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if effectRow == 0 {
+				t.Fatal("删除失败")
+			}
+			session.Commit()
+			t.Logf("删除成功, effectRow: %d", effectRow)
+		}()
+
+		data, err := NewReportPeccancyDao().GetById(context, searchId)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if data == nil {
+			t.Logf("删除成功,未查询到数据!")
+		}
+	})
+}

+ 30 - 0
business/dto/city_config_dto.go

@@ -0,0 +1,30 @@
+package dto
+
+type CityInfoParams struct {
+	CityId uint64 `json:"city_id"`
+}
+
+type CityInfoResponse struct {
+	Result CityInfoResult
+}
+type CityInfoResult struct {
+	ID            uint64 `json:"id"`
+	MapCode       uint64 `json:"map_code"`
+	Name          string `json:"name"`
+	Shortname     string `json:"shortname"`
+	BikeOpen      int    `json:"bike_open"`
+	CarOpen       int    `json:"car_open"`
+	OpenTime      int    `json:"open_time"`
+	Mode          int    `json:"mode"`
+	BailMode      int    `json:"bail_mode"`
+	IsCustom      int    `json:"is_custom"`
+	IsStop        int    `json:"is_stop"`
+	StopReason    string `json:"stop_reason"`
+	StopStartTime int    `json:"stop_start_time"`
+	StopEndTime   int    `json:"stop_end_time"`
+	OpMode        int    `json:"op_mode"`
+	CreateTime    int    `json:"create_time"`
+	UpdateTime    int    `json:"update_time"`
+	SysUserID     int    `json:"sys_user_id"`
+	SysUserName   string `json:"sys_user_name"`
+}

+ 15 - 0
business/dto/ebike_factory_api_third_dto.go

@@ -0,0 +1,15 @@
+package dto
+
+type OpWorkerDetailData struct {
+	Id            uint64 `json:"id"`              // id
+	Type          int    `json:"type"`            // 员工类型:1 代理商员工,2 平台员工, 3 兼职员工,4 厂商员工,5 加盟商员工  6 加盟商老板 7 政府人员 8 多城市员工 9代运营员工
+	UserName      string `json:"user_name"`       // 用户名
+	Mobile        string `json:"mobile"`          // 手机号
+	Name          string `json:"real_name"`       // 真实姓名
+	Status        int    `json:"status"`          // 账户状态:0 关闭,1 开启, 2删除
+	CurrentCityId int    `json:"current_city_id"` // 用户当前运维城市
+}
+
+type GetOpWorkerDetailResponse struct {
+	Data []OpWorkerDetailData `json:"data"`
+}

+ 65 - 0
business/dto/report_dto.go

@@ -0,0 +1,65 @@
+package dto
+
+import (
+	"go-template/business/model"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/common"
+)
+
+type ReportInfoRequest struct {
+	Params ReportInfoParams `json:"params" binding:"required"`
+}
+
+type ReportInfoParams struct {
+	Id uint64 `json:"id"`
+}
+
+type ReportInfoResult struct {
+	Infos []interface{}
+}
+
+type ReportListRequest struct {
+	Params ReportListParams `json:"params" binding:"required"`
+}
+
+type ReportListParams struct {
+	common.PageRequest
+	UserId uint64 `json:"user_id"`
+}
+
+type ReportListResult struct {
+	Items []model.ReportPeccancy `json:"items"`
+	common.PageResponse
+}
+
+type SendMQRequest struct {
+	Params SendMQParams `json:"params" binding:"required"`
+}
+type SendMQParams struct {
+	Topic   string `json:"topic"`
+	Message string `json:"message"`
+}
+type SendMQResult struct {
+	Result interface{} `json:"result"`
+}
+
+type DownLoadXlsxFileParams struct {
+	Row    int `json:"-"`
+	Column int `json:"-"`
+	Sheet  int `json:"-"`
+}
+
+type DownLoadCsvFileParams struct {
+	Row    int `json:"-"`
+	Column int `json:"-"`
+}
+
+type UploadXlsxFileParams struct {
+	SheetName string `json:"-"`
+}
+
+type UploadXlsxFileResponse struct {
+	Rows    int      `json:"rows"`
+	Columns int      `json:"columns"`
+	Header  []string `json:"header"`
+}

+ 40 - 0
business/dto/urban_violation_dto.go

@@ -0,0 +1,40 @@
+package dto
+
+type ReportPeccancyDto struct {
+	ID                uint64 `json:"id"`                  //主键
+	UserID            uint64 `json:"user_id"`             //松果APP端用户ID
+	OpWorkerID        uint64 `json:"op_worker_id"`        //运维用户编号(反馈)
+	OperateID         uint64 `json:"operate_id"`          //操作处理违章运维人员ID
+	UserMobile        string `json:"user_mobile"`         //用户手机号
+	UserName          string `json:"user_name"`           //用户名称
+	CityID            uint64 `json:"city_id"`             //用户所在城市ID
+	BikeSn            string `json:"bike_sn"`             //车辆编号
+	BikeQrCode        string `json:"bike_qr_code"`        //车辆二维码编号
+	PeccancyTypeID    uint64 `json:"peccancy_type_id"`    //违章类型id(0表示其他)
+	TemplateID        int    `json:"template_id"`         //违章类型模板id
+	TypeName          string `json:"type_name"`           //违章类型
+	PeccancyTypeName  string `json:"peccancy_type_name"`  //违章影响
+	DiscoveryTime     int64  `json:"discovery_time"`      //发现时间
+	Remark            string `json:"remark"`              //举报违章-备注信息
+	DiscoveryPlace    string `json:"discovery_place"`     //发现地点
+	Images            string `json:"images"`              //图片,json格式,"[{},{}]"
+	Amount            int    `json:"amount"`              //罚金金额
+	LimitTime         int    `json:"limit_time"`          //限制用车时间,单位:天(9999代表永久)
+	Status            uint8  `json:"status"`              //违章处理状态,0 未处理 1不处罚 2处罚
+	UserFineDetailID  uint64 `json:"user_fine_detail_id"` //罚金记录ID
+	IsWarning         uint8  `json:"is_warning"`          //违章是否为警告 0 否 1 是
+	WarningType       uint8  `json:"warning_type"`        //警告类型 1 用户初始警告 2 循环周期免罚占比警告 3 单项警告  4 可答题的警告
+	InfluenceImage    string `json:"influence_image"`     //违章实例图片及描述 json[{}]
+	BlackID           int    `json:"black_id"`            //黑名单记录表主键ID
+	From              uint8  `json:"from"`                //数据来源 0 代表运维正常举报 1 代表从违规骑行得到
+	FollowType        uint8  `json:"follow_type"`         //跟进状态:1,未跟进 2,跟进中 3,误判  4,非误判
+	FollowMethod      uint8  `json:"follow_method"`       //1客服抽查跟进 2安全合规抽查跟进 3客户投诉跟进 4系统跟进
+	PayFineStatus     uint8  `json:"pay_fine_status"`     //缴纳罚金状态 0 否 1 是
+	IsAnswerReduction uint8  `json:"is_answer_reduction"` //是否通过答题免缴 0 否 1 是
+	UserShow          uint8  `json:"user_show"`           //用户端是否显示 0 否 1 是
+	CreateTime        int64  `json:"create_time"`         //创建时间
+	UpdateTime        int64  `json:"update_time"`
+	OperateTime       int64  `json:"operate_time"`     //操作时间
+	StartCycleTime    int64  `json:"start_cycle_time"` //循环周期开始时间
+	EndCycleTime      int64  `json:"end_cycle_time"`   //循环周期结束时间
+}

+ 20 - 0
business/exception/controller.go

@@ -0,0 +1,20 @@
+package exception
+
+import (
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+)
+
+// 记录controller层的异常
+
+// error_code , code从10001开始
+const (
+	controllerBaseErrorCode = 10000 + iota
+	paramsErrorCode
+	authErrorCode
+)
+
+// error_info
+var (
+	ParamsBindError = cerror.NewCerror(paramsErrorCode, "请求参数错误")
+	AuthError       = cerror.NewSCerror(authErrorCode)
+)

+ 22 - 0
business/exception/dao.go

@@ -0,0 +1,22 @@
+package exception
+
+import (
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+)
+
+// 记录dao层的异常  cong  30001开始
+const (
+	dbBaseErrorCode = 30000 + iota
+	dbExecutorError
+	dbInsertError
+	dbUpdateError
+	dbDeleteError
+)
+
+var (
+	//DbExecError db执行错误
+	DbExecError   = cerror.NewECerror(dbExecutorError)
+	DbInsertError = cerror.NewECerror(dbInsertError)
+	DbUpdateError = cerror.NewECerror(dbUpdateError)
+	DbDeleteError = cerror.NewECerror(dbDeleteError)
+)

+ 18 - 0
business/exception/global.go

@@ -0,0 +1,18 @@
+package exception
+
+import "gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+
+// 默认的错误码
+const (
+	DefaultErrorCode = -1
+)
+
+var (
+	DefaultError = func(err error) cerror.Cerror {
+		if err == nil {
+			return nil
+		}
+		return cerror.NewCerror(DefaultErrorCode, err.Error())
+	}
+	DefaultSError = cerror.NewSCerror(DefaultErrorCode)
+)

+ 13 - 0
business/exception/service.go

@@ -0,0 +1,13 @@
+package exception
+
+import "gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+
+// 记录service层的异常 , code从20001开始
+const (
+	serviceBaseErrorCode = 20000 + iota
+	reportListErrorCode
+)
+
+var (
+	ReportListError = cerror.NewSCerror(reportListErrorCode)
+)

+ 20 - 0
business/exception/third.go

@@ -0,0 +1,20 @@
+package exception
+
+import (
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+)
+
+// 调用第三方接口的异常,从40000开始
+
+const (
+	thirdBaseErrorCode = 40000 + iota
+	cityInfoErrorCode
+	reportInfoErrorCode
+	getOpWorkerDetailError
+)
+
+var (
+	CityInfoError          = cerror.NewECerror(cityInfoErrorCode)
+	ReportInfoError        = cerror.NewECerror(reportInfoErrorCode)
+	GetOpWorkerDetailError = cerror.NewSCerror(getOpWorkerDetailError)
+)

+ 22 - 0
business/job/rocket_mq_consumer.go

@@ -0,0 +1,22 @@
+package job
+
+import (
+	"context"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/logger"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/mq/rocketmq"
+	"github.com/apache/rocketmq-client-go/v2/primitive"
+)
+
+/**
+开启 Rocket-MQ Consumer
+*/
+func StartRocketMQConsumer() error {
+	if err := rocketmq.GetConsumer().Subscribe("test_topic", func(ctx context.Context, message *primitive.MessageExt) {
+		logger.Infoc(ctx, "【消费者-1】trace_id: %s, 消息: %#v\n", rocketmq.GetMessageTraceId(message), message)
+	}); err != nil {
+		return err
+	}
+	return nil
+}

+ 24 - 0
business/middleware/middleware.go

@@ -0,0 +1,24 @@
+package middleware
+
+import (
+	"gitea.ckfah.com/cjjy/gocommon/pkg/logger"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+)
+
+/**
+DemoMiddleware 以方法去返回!!
+*/
+func DemoMiddleware() engines.HandlerFunc {
+	return func(context *engines.Context) {
+		var err error // 业务逻辑
+		if err != nil {
+			logger.Warnc(context, "[DemoMiddleware] find err, err: %s", err)
+			// 异常不会继续处理
+			context.Abort()
+			return
+		}
+		//  logger
+		logger.Infoc(context, "[DemoMiddleware]  err, err: %s", err)
+		context.Next()
+	}
+}

+ 103 - 0
business/model/report_peccancy.go

@@ -0,0 +1,103 @@
+package model
+
+import (
+	"time"
+)
+
+/**
+CREATE TABLE `report_peccancy` (
+  `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `user_id` bigint(20) NOT NULL COMMENT '松果APP端用户ID',
+  `op_worker_id` bigint(20) NOT NULL COMMENT '运维用户编号(反馈)',
+  `operate_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '操作处理违章运维人员ID',
+  `user_mobile` varchar(15) DEFAULT '' COMMENT '用户手机号',
+  `user_name` varchar(15) DEFAULT '' COMMENT '用户名称',
+  `city_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '用户所在城市ID',
+  `bike_sn` varchar(15) DEFAULT '' COMMENT '车辆编号',
+  `bike_qr_code` varchar(10) NOT NULL DEFAULT '' COMMENT '车辆二维码编号',
+  `peccancy_type_id` bigint(20) NOT NULL COMMENT '违章类型id(0表示其他)',
+  `template_id` int(11) DEFAULT '0' COMMENT '违章类型模板id',
+  `type_name` varchar(2047) DEFAULT '' COMMENT '违章类型',
+  `peccancy_type_name` varchar(2047) DEFAULT '' COMMENT '违章影响',
+  `discovery_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '发现时间',
+  `remark` varchar(1024) DEFAULT NULL COMMENT '举报违章-备注信息',
+  `discovery_place` varchar(255) NOT NULL DEFAULT '' COMMENT '发现地点',
+  `images` varchar(3072) NOT NULL DEFAULT '' COMMENT '图片,json格式,"[{},{}]"',
+  `amount` int(11) NOT NULL DEFAULT '0' COMMENT '罚金金额',
+  `limit_time` int(11) NOT NULL DEFAULT '0' COMMENT '限制用车时间,单位:天(9999代表永久)',
+  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '违章处理状态,0 未处理 1不处罚 2处罚',
+  `user_fine_detail_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '罚金记录ID',
+  `is_warning` tinyint(4) NOT NULL DEFAULT '0' COMMENT '违章是否为警告 0 否 1 是',
+  `warning_type` tinyint(2) DEFAULT '0' COMMENT '警告类型 1 用户初始警告 2 循环周期免罚占比警告 3 单项警告  4 可答题的警告',
+  `influence_image` varchar(2048) DEFAULT '' COMMENT '违章实例图片及描述 json[{}]',
+  `black_id` int(11) NOT NULL DEFAULT '0' COMMENT '黑名单记录表主键ID',
+  `from` tinyint(4) NOT NULL DEFAULT '0' COMMENT '数据来源 0 代表运维正常举报 1 代表从违规骑行得到',
+  `follow_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '跟进状态:1,未跟进 2,跟进中 3,误判  4,非误判',
+  `follow_method` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1客服抽查跟进 2安全合规抽查跟进 3客户投诉跟进 4系统跟进',
+  `pay_fine_status` tinyint(4) DEFAULT '0' COMMENT '缴纳罚金状态 0 否 1 是',
+  `is_answer_reduction` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否通过答题免缴 0 否 1 是',
+  `user_show` tinyint(4) DEFAULT '1' COMMENT '用户端是否显示 0 否 1 是',
+  `create_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `operate_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '操作时间',
+  `start_cycle_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '循环周期开始时间',
+  `end_cycle_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '循环周期结束时间',
+  PRIMARY KEY (`id`),
+  KEY `idx_cid_bsn` (`city_id`,`bike_sn`),
+  KEY `idx_status_operate_time` (`status`,`operate_time`),
+  KEY `idx_status_user_name` (`status`,`user_name`),
+  KEY `idx_user_name` (`user_name`),
+  KEY `idx_ufid` (`user_fine_detail_id`),
+  KEY `idx_user_id` (`user_id`),
+  KEY `idx_user_operate_time` (`user_id`,`operate_time`),
+  KEY `idx_cityid_discoverytime` (`city_id`,`discovery_time`),
+  KEY `idx_discovery_time` (`discovery_time`),
+  KEY `idx_opworkerid_createtime` (`op_worker_id`,`create_time`),
+  KEY `index_update_time` (`update_time`),
+  KEY `idx_bid` (`black_id`),
+  KEY `idx_bike_sn` (`bike_sn`)
+) ENGINE=InnoDB AUTO_INCREMENT=517412 DEFAULT CHARSET=utf8mb4 COMMENT='举报违章'
+*/
+
+type ReportPeccancy struct {
+	ID                uint64    `xorm:"pk autoincr id"`
+	UserID            uint64    `xorm:"user_id"`
+	OpWorkerID        uint64    `xorm:"op_worker_id"`
+	OperateID         uint64    `xorm:"operate_id"`
+	UserMobile        string    `xorm:"user_mobile"`
+	UserName          string    `xorm:"user_name"`
+	CityID            uint64    `xorm:"city_id"`
+	BikeSn            string    `xorm:"bike_sn"`
+	BikeQrCode        string    `xorm:"bike_qr_code"`
+	PeccancyTypeID    uint64    `xorm:"peccancy_type_id"`
+	TemplateID        int       `xorm:"template_id"`
+	TypeName          string    `xorm:"type_name"`
+	PeccancyTypeName  string    `xorm:"peccancy_type_name"`
+	DiscoveryTime     time.Time `xorm:"discovery_time"`
+	Remark            string    `xorm:"remark"`
+	DiscoveryPlace    string    `xorm:"discovery_place"`
+	Images            string    `xorm:"images"`
+	Amount            int       `xorm:"amount"`
+	LimitTime         int       `xorm:"limit_time"`
+	Status            uint8     `xorm:"status"`
+	UserFineDetailID  uint64    `xorm:"user_fine_detail_id"`
+	IsWarning         uint8     `xorm:"is_warning"`
+	WarningType       uint8     `xorm:"warning_type"`
+	InfluenceImage    string    `xorm:"influence_image"`
+	BlackID           int       `xorm:"black_id"`
+	From              uint8     `xorm:"from"`
+	FollowType        uint8     `xorm:"follow_type"`
+	FollowMethod      uint8     `xorm:"follow_method"`
+	PayFineStatus     uint8     `xorm:"pay_fine_status"`
+	IsAnswerReduction uint8     `xorm:"is_answer_reduction"`
+	UserShow          uint8     `xorm:"user_show"`
+	CreateTime        time.Time `xorm:"created create_time"`
+	UpdateTime        time.Time `xorm:"updated update_time"`
+	OperateTime       time.Time `xorm:"operate_time"`
+	StartCycleTime    time.Time `xorm:"start_cycle_time"`
+	EndCycleTime      time.Time `xorm:"end_cycle_time"`
+}
+
+func (*ReportPeccancy) TableName() string {
+	return "report_peccancy"
+}

+ 17 - 0
business/service/base_service.go

@@ -0,0 +1,17 @@
+package service
+
+import (
+	"go-template/business/dao"
+	"go-template/business/third"
+)
+
+// dao
+var (
+	reportDao = dao.NewReportPeccancyDao()
+)
+
+// third
+var (
+	cityService    = third.NewCityConfigThird()
+	factoryService = third.NewEbikeFactoryApi()
+)

+ 16 - 0
business/service/init_test.go

@@ -0,0 +1,16 @@
+package service
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/boot"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	boot.Init(boot.DB, boot.Qconf, boot.Redis, boot.Trace, boot.NacosDiscover, boot.RocketMQProducer, boot.RocketMQConsumer)
+	exitCode := m.Run()
+	os.Exit(exitCode)
+}

+ 197 - 0
business/service/report_service.go

@@ -0,0 +1,197 @@
+package service
+
+import (
+	"context"
+	"encoding/csv"
+	"fmt"
+	"go-template/business/dto"
+	"go-template/business/exception"
+	"go-template/business/model"
+	"go-template/business/util"
+	"io"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/common"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/mq/rocketmq"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+	"github.com/google/uuid"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+)
+
+type reportService struct {
+}
+
+func NewReportService() *reportService {
+	return new(reportService)
+}
+
+// 举报详情
+func (rs *reportService) ReportInfo(context context.Context, params *dto.ReportInfoParams) (*dto.ReportInfoResult, cerror.Cerror) {
+	reportInfo, err := reportDao.GetById(context, params.Id)
+	if err != nil {
+		return nil, err
+	}
+	if reportInfo == nil {
+		return nil, exception.ReportListError("举报详情为空")
+	}
+	cityInfo, err := cityService.CityInfo(context, &dto.CityInfoParams{
+		CityId: reportInfo.CityID,
+	})
+	if err != nil {
+		return nil, err
+	}
+	opInfo, err := factoryService.GetOpWorkerDetailById(context, reportInfo.OpWorkerID)
+	if err != nil {
+		return nil, err
+	}
+	return &dto.ReportInfoResult{Infos: []interface{}{cityInfo, reportInfo, opInfo}}, nil
+}
+
+func (rs *reportService) ReportList(context context.Context, params *dto.ReportListParams) (*dto.ReportListResult, cerror.Cerror) {
+	page := params.GetPaginator()
+	count, err := reportDao.GetCountByUserId(context, params.UserId)
+	if err != nil {
+		return nil, err
+	}
+	if count == 0 {
+		return &dto.ReportListResult{
+			Items:        []model.ReportPeccancy{},
+			PageResponse: page.GetPageResponse(count),
+		}, nil
+	}
+	result, err := reportDao.GetByUserId(context, params.UserId, page)
+	if err != nil {
+		return nil, err
+	}
+	return &dto.ReportListResult{
+		Items:        result,
+		PageResponse: page.GetPageResponse(count),
+	}, nil
+}
+
+func (rs *reportService) SendMQ(ctx context.Context, params *dto.SendMQParams) (interface{}, cerror.Cerror) {
+	if params.Topic == "" {
+		params.Topic = "test_topic"
+	}
+	if params.Message == "" {
+		params.Message = "hello, go-template"
+	}
+	if err := rocketmq.GetProducer().Send(ctx, params.Topic, []byte(params.Message)); err != nil {
+		return nil, exception.DefaultError(err)
+	}
+	return map[string]string{"result": "发送成功"}, nil
+}
+
+func (rs *reportService) getDownLoadFileHeader(ctx context.Context, column int) []string {
+	header := make([]string, 0, column)
+	for x := 0; x < column; x++ {
+		header = append(header, fmt.Sprintf("header-%d", x))
+	}
+	return header
+}
+
+func (rs *reportService) getDownLoadResult(ctx context.Context, row, column int) [][]string {
+	generateList := func(length int) []string {
+		list := make([]string, 0, length)
+		for x := 0; x < length; x++ {
+			list = append(list, uuid.New().String())
+		}
+		return list
+	}
+	list := make([][]string, row)
+	for index := range list {
+		list[index] = generateList(column)
+	}
+	return list
+}
+
+func (rs *reportService) DownLoadXlsxFile(ctx context.Context, writer engines.ResponseWriter, params *dto.DownLoadXlsxFileParams) cerror.Cerror {
+	// 生成数据!
+	list := rs.getDownLoadResult(ctx, params.Row, params.Column)
+
+	// 生成header
+	header := rs.getDownLoadFileHeader(ctx, params.Column)
+
+	// 写excel
+	excel := common.NewWriter360Excel()
+
+	// 写sheet
+	for x := 0; x < params.Sheet; x++ {
+
+		// 写sheet
+		if err := excel.WriteSheet(fmt.Sprintf("demo数据-%d", x), header, func(r common.Row) (hasNext bool) {
+			if r.RowIndex() > len(list)-1 { // 如果当前写的index 超过了数组的index的最大值 就return false
+				return false
+			}
+			row := list[r.RowIndex()]
+			for _, elem := range row {
+				r.Write(elem)
+			}
+			// 由于row_index是先写后加,所以当你写到最后一个的时候
+			return true
+		}); err != nil {
+			return exception.DefaultError(err)
+		}
+	}
+
+	// 先写响应头
+	util.ResponseFileV2(writer, "输出文件.xlsx")
+
+	// 后写body,顺序必须是这个
+	if err := excel.FlushWrite(writer); err != nil {
+		return exception.DefaultError(err)
+	}
+	return nil
+}
+
+func (rs *reportService) DownLoadCsvFile(ctx context.Context, writer engines.ResponseWriter, params *dto.DownLoadCsvFileParams) cerror.Cerror {
+	// 生成数据!
+	list := rs.getDownLoadResult(ctx, params.Row, params.Column)
+	// 生成header
+	header := rs.getDownLoadFileHeader(ctx, params.Column)
+
+	// 先写响应头
+	util.ResponseFileV2(writer, "输出文件.csv")
+
+	// 再写csv (csv只能写一个sheet)
+	csvFile := csv.NewWriter(writer)
+
+	// 写header
+	if err := csvFile.Write(header); err != nil {
+		return exception.DefaultError(err)
+	}
+	// 写body
+	if err := csvFile.WriteAll(list); err != nil {
+		return exception.DefaultError(err)
+	}
+	// 最后记得flush一下,因为csv使用了buffer的原因
+	csvFile.Flush()
+	return nil
+}
+
+func (rs *reportService) UploadXlsxFile(ctx context.Context, file io.Reader, params *dto.UploadXlsxFileParams) (*dto.UploadXlsxFileResponse, cerror.Cerror) {
+	excel, err := common.NewReader360Excel(file)
+	if err != nil {
+		return nil, exception.DefaultError(err)
+	}
+	// 读取sheet中的内容,第一行是header
+	content, err := excel.ReadSheet(params.SheetName)
+	if err != nil {
+		return nil, exception.DefaultError(err)
+	}
+	// 为空返回数据
+	if content == nil || len(content) == 0 {
+		return &dto.UploadXlsxFileResponse{
+			Header: []string{},
+		}, nil
+	}
+
+	// todo 处理业务
+
+	// 响应
+	return &dto.UploadXlsxFileResponse{
+		Rows:    len(content),
+		Columns: len(content[0]),
+		Header:  content[0],
+	}, nil
+}

+ 138 - 0
business/service/resource_test.go

@@ -0,0 +1,138 @@
+package service
+
+import (
+	"context"
+	"go-template/business/dto"
+	"go-template/business/util"
+	"testing"
+	"time"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cache/redis"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/conf"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/mq/rocketmq"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/nacos"
+	"github.com/apache/rocketmq-client-go/v2/primitive"
+)
+
+// make test test_func=Test_Redis_Resource test_pkg=./business/service
+func Test_Redis_Resource(t *testing.T) {
+	t.Run("测试redis-set", func(t *testing.T) {
+		key := "key-demo"
+		value := "value"
+		setResult, err := redis.Instance().SetString(redis.PrefixKey(key), value)
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Logf("redis 插入成功: %v", setResult)
+
+		t.Run("测试redis-get", func(t *testing.T) {
+			resultStr, err := redis.Instance().GetString(redis.PrefixKey(key))
+			if err != nil {
+				t.Fatal(err)
+			}
+			if resultStr == value {
+				t.Logf("redis 查询成功: %v", resultStr)
+			}
+		})
+	})
+
+	t.Run("测试redis-get-nil", func(t *testing.T) {
+		_, err := redis.Instance().GetString(redis.PrefixKey("null"))
+		if redis.CheckIsNilErr(err) {
+			t.Logf("测试redis查询为空成功")
+		} else {
+			t.Fatal("redis查询失败")
+		}
+	})
+	t.Run("测试redis-set ex", func(t *testing.T) {
+		_, err := redis.Instance().SetExString(redis.PrefixKey("ex"), "demo", 1)
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Run("测试redis未过期", func(t *testing.T) {
+			result, err := redis.Instance().GetString(redis.PrefixKey("ex"))
+			if err != nil {
+				t.Fatal(err)
+			}
+			t.Logf("获取成功: %s", result)
+		})
+		t.Run("测试redis已过期", func(t *testing.T) {
+			time.Sleep(time.Second)
+			_, err := redis.Instance().GetString(redis.PrefixKey("ex"))
+			if redis.CheckIsNilErr(err) {
+				t.Logf("测试过期成功")
+			} else {
+				t.Fatal("测试过期失败")
+			}
+		})
+	})
+}
+
+// make test test_func=Test_MQ_Resource test_pkg=./business/service
+func Test_MQ_Resource(t *testing.T) {
+	t.Run("生产和消费消息", func(t *testing.T) {
+		topic := "test_topic"
+		t.Run("普通发送", func(t *testing.T) {
+			result, err := NewReportService().SendMQ(util.MockContext(), &dto.SendMQParams{
+				Topic:   topic,
+				Message: `{"data":"yyyy","code":0,"message":"success"}`,
+			})
+			if err != nil {
+				t.Fatal(err)
+			}
+			t.Logf("发送成功: %v", result)
+		})
+		t.Run("获取消息ID", func(t *testing.T) {
+			result, err := rocketmq.GetProducer().SendV2(util.MockContext(), topic, []byte(`{"data":"yyyy","code":0,"message":"success"}`))
+			if err != nil {
+				t.Fatal(err)
+			}
+			t.Logf("发送成功 msg_id: %v", result.MsgID)
+		})
+		t.Run("消费消息", func(t *testing.T) {
+			err := rocketmq.GetConsumer().Subscribe(topic, func(ctx context.Context, message *primitive.MessageExt) {
+				t.Logf("收到消息: %v", message)
+			})
+			if err != nil {
+				t.Fatal(err)
+			}
+			if err := rocketmq.GetConsumer().GetRocketMqConsumer().Start(); err != nil {
+				t.Fatal(err)
+			}
+			time.Sleep(time.Millisecond * 10)
+		})
+	})
+	t.Run("发送MQ消息模拟失败", func(t *testing.T) {
+		_, err := rocketmq.GetProducer().SendV2(util.MockContext(), "test_topic_1", []byte(`{"data":"yyyy","code":0,"message":"success"}`))
+		if err != nil {
+			t.Logf("失败信息: %v", err)
+		} else {
+			t.Fatal("未获取到失败信息")
+		}
+	})
+}
+
+// make test test_func=Test_Nacos_Config_Discover_Register test_pkg=./business/service
+func Test_Nacos_Config_Discover_Register(t *testing.T) {
+	t.Run("测试注册服务", func(t *testing.T) {
+		err := nacos.InitNacosRegisterClient()
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Logf("注册成功")
+	})
+
+	t.Run("获取服务", func(t *testing.T) {
+		time.Sleep(time.Second)
+		host, err := nacos.GetHost("ebike-factory-api")
+		if err != nil {
+			t.Logf("获取服务异常: %s", err)
+		} else {
+			t.Logf("获取服务成功: %s", host)
+		}
+	})
+	t.Run("测试config", func(t *testing.T) {
+		t.Logf("获取配置:%v", conf.GetStringV2("application.project_name"))
+	})
+
+}

+ 40 - 0
business/third/city_config_third.go

@@ -0,0 +1,40 @@
+package third
+
+import (
+	"context"
+	"go-template/business/dto"
+	"go-template/business/exception"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/logger"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/httpclent"
+)
+
+type cityConfigThird struct {
+}
+
+func NewCityConfigThird() *cityConfigThird {
+	return &cityConfigThird{}
+}
+
+func (*cityConfigThird) GetServerName() string {
+	return "city-config"
+}
+
+// 统一抽象一个方法,方便管理
+func (this *cityConfigThird) httpRequest(ctx context.Context, path string, params interface{}, result interface{}, options ...httpclent.Option) error {
+	return httpclent.HttpRequestAndDecode(ctx, this.GetServerName(), path, params, result, options...)
+}
+
+// 获取城市信息
+func (this *cityConfigThird) CityInfo(ctx context.Context, params *dto.CityInfoParams) (*dto.CityInfoResponse, cerror.Cerror) {
+	path := "/city-config/city/info"
+	response := new(dto.CityInfoResponse)
+	err := this.httpRequest(ctx, path, params, response, httpclent.CloseRetry)
+	if err != nil {
+		// 三方日志要打印warn日志,如果必要的话才打印error日志
+		logger.Warnc(ctx, "[CityInfo] request err,params=%+v,err=%v", params, err)
+		return nil, exception.CityInfoError(err)
+	}
+	return response, nil
+}

+ 31 - 0
business/third/city_config_third_test.go

@@ -0,0 +1,31 @@
+package third
+
+import (
+	"context"
+	"go-template/business/dto"
+	"testing"
+)
+
+// make test test_func=Test_cityConfigThird_CityInfo test_pkg=./business/third/
+func Test_cityConfigThird_CityInfo(t *testing.T) {
+	t.Run("测试成功调用", func(t *testing.T) {
+		resp, err := NewCityConfigThird().CityInfo(context.Background(), &dto.CityInfoParams{
+			CityId: 1,
+		})
+		if err != nil {
+			t.Fatal(err)
+		}
+		if resp == nil {
+			t.Fatal("未获取到结果")
+		}
+		t.Logf("获取结果: %+v", resp)
+	})
+	t.Run("测试失败调用", func(t *testing.T) {
+		_, err := NewCityConfigThird().CityInfo(context.Background(), &dto.CityInfoParams{
+			CityId: 0,
+		})
+		if err != nil {
+			t.Logf("调用失败测试成功,失败信息: %+v", err)
+		}
+	})
+}

+ 47 - 0
business/third/ebike_factory_api_third.go

@@ -0,0 +1,47 @@
+package third
+
+import (
+	"context"
+	"go-template/business/dto"
+	"go-template/business/exception"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/cerror"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/logger"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/httpclent"
+)
+
+// doc:
+type ebikeFactoryApi struct {
+}
+
+func NewEbikeFactoryApi() *ebikeFactoryApi {
+	return new(ebikeFactoryApi)
+}
+
+func (*ebikeFactoryApi) GetServerName() string {
+	return "ebike-factory-api"
+}
+
+// 统一抽象一个方法,方便管理
+func (this *ebikeFactoryApi) httpRequest(ctx context.Context, path string, params interface{}, result interface{}, options ...httpclent.Option) error {
+	return httpclent.HttpRequestAndDecode(ctx, this.GetServerName(), path, params, result, append(options, httpclent.NacosServerHostOption)...)
+}
+
+func (this *ebikeFactoryApi) GetOpWorkerDetailById(ctx context.Context, opWorkerId uint64) (*dto.OpWorkerDetailData, cerror.Cerror) {
+	path := "/service/v1/op-worker/search-by-ids"
+	params := map[string]interface{}{
+		"ids": []uint64{opWorkerId},
+	}
+	response := dto.GetOpWorkerDetailResponse{}
+	err := this.httpRequest(ctx, path, params, &response)
+	if err != nil {
+		// 三方日志要打印warn日志,如果必要的话才打印error日志
+		logger.Warnc(ctx, "[GetOpWorkerDetail] err,op_worker_id=%d,err=%v", opWorkerId, err)
+		return nil, exception.GetOpWorkerDetailError("获取op_worker信息失败")
+	}
+	if response.Data == nil || len(response.Data) == 0 {
+		logger.Warnc(ctx, "[GetOpWorkerDetail] not fond op_worker,op_worker_id=%d", opWorkerId)
+		return nil, nil
+	}
+	return &response.Data[0], nil
+}

+ 22 - 0
business/third/ebike_factory_api_third_test.go

@@ -0,0 +1,22 @@
+package third
+
+import (
+	"go-template/business/util"
+	"testing"
+)
+
+// make test test_func=Test_ebikeFactoryApi_GetOpWorkerDetailById test_pkg=./business/third/
+func Test_ebikeFactoryApi_GetOpWorkerDetailById(t *testing.T) {
+	context := util.MockContext()
+	t.Run("调用测试", func(t *testing.T) {
+		resp, err := NewEbikeFactoryApi().GetOpWorkerDetailById(context, 201)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if resp == nil {
+			t.Logf("未获取到结果")
+		} else {
+			t.Logf("获取结果: %+v", resp)
+		}
+	})
+}

+ 16 - 0
business/third/init_test.go

@@ -0,0 +1,16 @@
+package third
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/boot"
+)
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	boot.Init(boot.Qconf, boot.Trace, boot.NacosDiscover)
+	exitCode := m.Run()
+	os.Exit(exitCode)
+}

+ 37 - 0
business/util/httpclient.go

@@ -0,0 +1,37 @@
+package util
+
+import (
+	"context"
+	"net/http"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/httpclent"
+)
+
+/**
+自定义一些Http-Client的一些通用的方法
+*/
+const (
+	GlobalUserId = "global-user-id"
+)
+
+var (
+	CustomerHeaderHttpOption httpclent.Option = func(options *httpclent.Options) {
+		options.HandlerRequestHeader = func(ctx context.Context, header http.Header) {
+			// 首先使用默认的处理器处理header
+			httpclent.DefaultHandlerRequestHandler(ctx, header)
+			// 自定义的信息从ctx中拿到
+			userId, _ := ctx.Value(GlobalUserId).(string)
+			header.Add(GlobalUserId, userId)
+		}
+	}
+)
+
+/**
+自定义添加校验http响应异常的方法,这个方法只需要全局调用一次,介意写在main函数初始化上,默认已经支持有 error.message,code.data.message格式的异常
+*/
+func AddVialidator() {
+	httpclent.AddValidatorResponseBody("data.message", func(body []byte) (err error) {
+		//抓取到error
+		return nil
+	})
+}

+ 105 - 0
business/util/httputil.go

@@ -0,0 +1,105 @@
+package util
+
+import (
+	"io"
+	"mime/multipart"
+	"net/http"
+	"os"
+)
+
+/**
+http-server 响应file流
+*/
+func ResponseFile(writer http.ResponseWriter, fileName string, body io.Reader) error {
+	writer.Header().Set("Content-Type", "application/octet-stream")
+	writer.Header().Set("Content-Disposition", "attachment; filename="+fileName)
+	writer.Header().Set("Content-Transfer-Encoding", "binary")
+	_, err := io.Copy(writer, body)
+	return err
+}
+
+func ResponseFileV2(writer http.ResponseWriter, fileName string) {
+	writer.Header().Set("Content-Type", "application/octet-stream")
+	writer.Header().Set("Content-Disposition", "attachment; filename="+fileName)
+	writer.Header().Set("Content-Transfer-Encoding", "binary")
+}
+
+/**
+http-client 请求文件流
+*/
+type FileForm struct {
+	filedName string
+	fileName  string
+
+	// form file
+	filePath string
+
+	// form stream
+	reader io.Reader
+}
+
+func NewFileFormFromFile(fieldName, fileName, filePath string) FileForm {
+	return FileForm{
+		filedName: fieldName,
+		fileName:  fileName,
+		filePath:  filePath,
+	}
+}
+
+func NewFileFormFromStream(fieldName, fileName string, reader io.Reader) FileForm {
+	return FileForm{
+		filedName: fieldName,
+		fileName:  fileName,
+		reader:    reader,
+	}
+}
+
+/**
+创建 Content-Type: multipart/form-data 的请求
+返回参数1是 请求体
+返回参数2是 Content-Type的value ,记得设置请求header Content-Type:参数2
+返回参数3是 异常
+*/
+func NewMultiFormRequest(params map[string]string, fileTypeParams []FileForm) (_ io.Reader, _ string, err error) {
+	requestBody := newRequestBody()
+	bodyWriter := multipart.NewWriter(requestBody)
+	defer func() {
+		err = bodyWriter.Close()
+	}()
+	writeFile := func(file FileForm) (err error) {
+		fileWriter, err := bodyWriter.CreateFormFile(file.filedName, file.fileName)
+		if err != nil {
+			return err
+		}
+		if file.reader == nil {
+			fileReader, err := os.Open(file.filePath)
+			if err != nil {
+				return err
+			}
+			defer func() {
+				err = fileReader.Close()
+			}()
+			file.reader = fileReader
+		}
+		_, err = io.Copy(fileWriter, file.reader)
+		if err != nil {
+			return err
+		}
+		return nil
+	}
+	writeParams := func(key, value string) error {
+		return bodyWriter.WriteField(key, value)
+	}
+	for key, value := range params {
+		if err := writeParams(key, value); err != nil {
+			return nil, "", err
+		}
+	}
+	for _, file := range fileTypeParams {
+		if err := writeFile(file); err != nil {
+			return nil, "", err
+		}
+	}
+	contentType := bodyWriter.FormDataContentType()
+	return requestBody, contentType, nil
+}

+ 191 - 0
business/util/mockHttpClient.go

@@ -0,0 +1,191 @@
+package util
+
+import (
+	"bytes"
+	"context"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"strings"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+)
+
+const (
+	defaultHttpRequestMethod = http.MethodPost
+	defaultHttpRequestPath   = "/"
+)
+
+var (
+	middleWareHandlerFunc []engines.HandlerFunc
+	handlerRequestHeaders []func(ctx context.Context, header http.Header)
+)
+
+/**
+添加全局的Middle ware
+*/
+func AddMiddleWareHandlerFunc(fun engines.HandlerFunc) {
+	if fun == nil {
+		return
+	}
+	middleWareHandlerFunc = append(middleWareHandlerFunc, fun)
+}
+
+/**
+添加全局的Header处理器
+*/
+func AddHandlerRequestHeaders(fun func(ctx context.Context, header http.Header)) {
+	if fun == nil {
+		return
+	}
+	handlerRequestHeaders = append(handlerRequestHeaders, fun)
+}
+
+var (
+	PostMethodOption Option = func(request *TestHttpRequest) {
+		request.Method = http.MethodPost
+	}
+	GetMethodOption Option = func(request *TestHttpRequest) {
+		request.Method = http.MethodGet
+	}
+	RequestHeaderOption = func(handler func(ctx context.Context, header http.Header)) Option {
+		return func(request *TestHttpRequest) {
+			request.handlerRequestHeaders = append(request.handlerRequestHeaders, handler)
+		}
+	}
+	AddFormParamOption = func(key string, value string) Option {
+		return func(request *TestHttpRequest) {
+			request.params.Set(key, value)
+		}
+	}
+	JsonBodyOption = func(jsonBody string) Option {
+		return func(request *TestHttpRequest) {
+			request.RequestBody = strings.NewReader(jsonBody)
+		}
+	}
+	MultipartFormDataOption = func(params map[string]string, fileTypeParams []FileForm) (Option, error) {
+		reader, headerValue, err := NewMultiFormRequest(params, fileTypeParams)
+		if err != nil {
+			return nil, err
+		}
+		return func(request *TestHttpRequest) {
+			option := RequestHeaderOption(func(ctx context.Context, header http.Header) {
+				header.Set("Content-Type", headerValue)
+			})
+			option(request)
+			request.RequestBody = reader
+		}, nil
+	}
+	HandlerFuncOption = func(handler engines.HandlerFunc) Option {
+		return func(request *TestHttpRequest) {
+			request.handlerFunctions = append(request.handlerFunctions, handler)
+		}
+	}
+	WithContextOption = func(ctx context.Context) Option {
+		return func(request *TestHttpRequest) {
+			request.Ctx = ctx
+		}
+	}
+)
+
+type Option func(request *TestHttpRequest)
+type TestHttpRequest struct {
+	Ctx                   context.Context
+	Method                string
+	Path                  string
+	RequestBody           io.Reader
+	handlerRequestHeaders []func(ctx context.Context, header http.Header)
+	header                http.Header
+	handlerFunctions      []engines.HandlerFunc
+	params                url.Values
+}
+
+/**
+Post &&\
+Json
+*/
+func NewTestHttpRequestWithDefault(jsonBody string, handler ...engines.HandlerFunc) (*http.Response, error) {
+	return NewTestPostHttpRequest(jsonBody, handler...)
+}
+
+func NewTestPostHttpRequest(jsonBody string, handler ...engines.HandlerFunc) (*http.Response, error) {
+	params := make([]Option, 0, len(handler)+1)
+	params = append(params, JsonBodyOption(jsonBody))
+	for _, elem := range handler {
+		params = append(params, HandlerFuncOption(elem))
+	}
+	return NewTestHttpRequest(params...).MockHttpRequest()
+}
+
+/**
+Post &&\
+multipart/form-data
+*/
+func NewTestHttpRequestWithUploadFile(requestParams map[string]string, fileTypeParams []FileForm, handler ...engines.HandlerFunc) (*http.Response, error) {
+	params := make([]Option, 0, len(handler)+1)
+	option, err := MultipartFormDataOption(requestParams, fileTypeParams)
+	if err != nil {
+		return nil, err
+	}
+	params = append(params, option)
+	for _, elem := range handler {
+		params = append(params, HandlerFuncOption(elem))
+	}
+	return NewTestHttpRequest(params...).MockHttpRequest()
+}
+
+/**
+GET
+*/
+func NewTestHttpRequestWithDownLoadFile(requestParams map[string]string, handler ...engines.HandlerFunc) (*http.Response, error) {
+	return NewTestGetHttpRequest(requestParams, handler...)
+}
+
+func NewTestGetHttpRequest(requestParams map[string]string, handler ...engines.HandlerFunc) (*http.Response, error) {
+	params := make([]Option, 0, len(handler)+1+len(requestParams))
+	for key, value := range requestParams {
+		params = append(params, AddFormParamOption(key, value))
+	}
+	params = append(params, GetMethodOption)
+	for _, elem := range handler {
+		params = append(params, HandlerFuncOption(elem))
+	}
+	return NewTestHttpRequest(params...).MockHttpRequest()
+}
+
+func NewTestHttpRequest(ops ...Option) *TestHttpRequest {
+	request := new(TestHttpRequest)
+	request.Path = defaultHttpRequestPath
+	request.Method = defaultHttpRequestMethod
+	request.Ctx = context.Background()
+	request.params = map[string][]string{}
+	request.handlerFunctions = append([]engines.HandlerFunc{}, middleWareHandlerFunc...)
+	request.handlerRequestHeaders = append([]func(ctx context.Context, header http.Header){}, handlerRequestHeaders...)
+	for _, elem := range ops {
+		elem(request)
+	}
+	return request
+}
+
+func (request *TestHttpRequest) MockHttpRequest() (*http.Response, error) {
+	mux := http.NewServeMux()
+	engine := engines.New()
+	engine.Handle(request.Method, request.Path, request.handlerFunctions...)
+	mux.Handle(request.Path, engine)
+	r, err := http.NewRequestWithContext(request.Ctx, request.Method, request.Path, request.RequestBody)
+	if err != nil {
+		return nil, err
+	}
+	for _, elem := range request.handlerRequestHeaders {
+		elem(request.Ctx, r.Header)
+	}
+	r.URL.RawQuery = request.params.Encode()
+	w := httptest.NewRecorder()
+	mux.ServeHTTP(w, r)
+	return w.Result(), nil
+}
+
+func newRequestBody() io.ReadWriter {
+	return &bytes.Buffer{}
+}

+ 91 - 0
business/util/test.go

@@ -0,0 +1,91 @@
+package util
+
+import (
+	"io/ioutil"
+	"net/http"
+	"testing"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/common"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/logger"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+)
+
+func MockContext() *engines.Context {
+	ctx := &engines.Context{}
+	ctx.Set(logger.TraceIdKey, logger.GenerateTraceId())
+	return ctx
+}
+
+type Testing interface {
+	CheckResult(result interface{}, err interface{})
+}
+type _testing struct {
+	testing.TB
+}
+
+func NewTesting(t testing.TB) Testing {
+	return &_testing{TB: t}
+}
+
+// 测试必备包!!
+// 后期改进,支持动态参数识别,自动抓取error
+func (t *_testing) CheckResult(result interface{}, err interface{}) {
+	printError := func(err interface{}) {
+		t.Fatalf("\n================ Error ================\n\n"+
+			"%s"+
+			"\n\n================= End =================\n\n", err)
+		return
+	}
+	if err != nil {
+		printError(err)
+		return
+	}
+	printSuccess := func(jsonBody []byte) {
+		jsonBody, err = common.JsonFormat(jsonBody)
+		if err != nil {
+			printError(err)
+			return
+		}
+		t.Logf("\n================ Success ================\n\n"+
+			"%s"+
+			"\n\n==================  End ==================\n\n", jsonBody)
+	}
+	printResponse := func(response *http.Response) {
+		status := response.StatusCode
+		header := response.Header
+		jsonBody, err := ioutil.ReadAll(response.Body)
+		if err != nil {
+			printError(err)
+			return
+		}
+		jsonBody, err = common.JsonFormat(jsonBody)
+		if err != nil {
+			printError(err)
+			return
+		}
+		t.Logf("\n================ Success ================\n"+
+			"HTTP-STATUS: %v\n"+
+			"HTTP-HEADER: %#v\n"+
+			"HTTP-BODY:\n%s\n"+
+			"\n\n==================  End ==================\n\n", status, header, jsonBody)
+	}
+	var (
+		jsonBody []byte
+	)
+	switch typeResult := result.(type) {
+	case []byte:
+		jsonBody = typeResult
+	case string:
+		jsonBody = []byte(typeResult)
+	case *http.Response:
+		printResponse(typeResult)
+		return
+	default:
+		jsonBody, err = common.MarshalJsonFormat(&result)
+	}
+	if err != nil {
+		printError(err)
+		return
+	}
+	printSuccess(jsonBody)
+}

+ 20 - 0
business/util/util_test.go

@@ -0,0 +1,20 @@
+package util
+
+import (
+	"sort"
+	"testing"
+)
+
+func BenchmarkDemo(b *testing.B) {
+	var arr = []int{9, 8, 7, 6, 5, 4, 3, 2, 1}
+	for i := 0; i < b.N; i++ {
+		sort.Ints(arr)
+	}
+}
+
+func TestDemo(t *testing.T) {
+	var arr = []int{9, 8, 7, 6, 5, 4, 3, 2, 1}
+	t.Logf("arr: %#v", arr)
+	sort.Ints(arr)
+	t.Logf("sorted arr: %#v", arr)
+}

+ 129 - 0
cicd/build.sh

@@ -0,0 +1,129 @@
+#!/bin/bash
+# author: sre.list@songguo7.com
+# 2020.04.01
+# 脚本执行输入参数:一个参数 项目名 $project(可以不输入)
+# 输出构建包  二进制文件及相关构建日志
+
+#########################################################################
+# devops build go project script
+#
+# PROJECT: 项目名称;
+# RESULT_NAME:${PROJECT}-app
+# BUILD_DEST_TARGET:
+# 手动调试构建某版本代码例如 cd /data/ci_build/sre/devops/93042d7b_20200328145142 && bash cicd/build.sh
+#########################################################################
+#set -x
+#golang配置
+source /etc/profile
+GOLANG=$(which go)
+
+PROJECT_DIR=`pwd`
+if [[ "x$1" != "x" ]] ;then
+    PROJECT=$1
+else
+    PROJECT=$(basename `pwd`)
+fi
+CURDIR=${PROJECT_DIR}
+#GOPATH="${CURDIR}"
+APP_BIN=${PROJECT}-app
+BUILD_DEST_TARGET='bin'
+DEPLOY_TARGET='deploy_target'
+#export GOPATH="${CURDIR}"
+export GOBIN="${CURDIR}/bin/"
+#echo 'GOPATH:' ${GOPATH}
+echo 'GOBIN:' ${GOBIN}
+echo 'GO:' ${GOLANG}
+echo "PROJECT ${PROJECT}"
+echo "BUILD_DEST_TARGET ${BUILD_DEST_TARGET}"
+echo "APP-BIN ${APP_BIN}"
+
+
+#根据脚本执行结果;判断输出信息
+function echoTime(){
+    limitTime=$(date "+%Y-%m-%d %H:%M:%S")
+    echo ${limitTime}
+}
+
+function setMsg() {
+    run_result=$?
+    msg=$1
+    if [[ "${run_result}" -eq 0 ]];then
+	echoTime
+        echo -e "[devops build] : ${msg} success"
+    else
+        echo -e "[devops build] : !!!ERR!!!!  ${msg} fail"
+        echo -e ""
+        exit 123
+    fi
+}
+
+function echoMsg() {
+    msg=$1
+    echoTime
+    echo -e "[devops build] : ${msg} "
+}
+
+#优化 log
+function logSplite() {
+    line='------------------------------------------------------------------------'
+    typeSplitetype=$1
+    if [[ ${typeSplitetype} == 'head' ]]; then
+        headMsg=$2
+        echoMsg ${line}
+        echoMsg "             ${headMsg}            "
+        echoMsg ${line}
+    else
+        echoMsg ${line}
+        echoMsg ''
+    fi
+}
+
+# 如生成二进制可执行文件${PROJECT}-app
+# 此处不做压缩归档。 devops 会把指定的产物压缩归档,然后挪到相应位置 提供下载部署使用。部署的时候解压使用。
+function mvPackage() {
+    if [[ -e "${BUILD_DEST_TARGET}/${APP_BIN}" ]];then
+        mv ${BUILD_DEST_TARGET}/${APP_BIN} ${DEPLOY_TARGET}/${APP_BIN}
+    else
+        echoMsg "BUILD ERROR"
+        exit 1
+    fi
+    if [[ -d "config" ]]; then
+        cp -r config ${DEPLOY_TARGET}/
+    else
+        echoMsg "无config 需要 拷贝"
+    fi
+}
+
+# 构建部署产物(各个环境统一一个)
+function buildGo() {
+    logSplite 'head' 'BUILD START0 ...'
+    OLDGO111MODULE="$GO111MODULE"
+    OLDGOPROXY="$GOPROXY"
+    OLDGOPRIVATE="$GOPRIVATE"
+    OLDGOFLAGS="$GOFLAGS"
+    export GO111MODULE=on
+    export GOPROXY=https://goproxy.cn,direct
+    export GOPRIVATE=gitea.ckfah.com*
+    export GOFLAGS=
+    raceArgs=" -race "
+    mkdir -p ${BUILD_DEST_TARGET} ${DEPLOY_TARGET}
+    echo go build  -o ${BUILD_DEST_TARGET}/${APP_BIN} ${raceArgs} -v -gcflags "-N -l"  cmd/main.go
+    logSplite 'head' 'BUILD START1 ...'
+    go build -o ${BUILD_DEST_TARGET}/${APP_BIN} ${raceArgs} -v -gcflags "-N -l"  cmd/main.go
+    export GO111MODULE=${OLDGO111MODULE}
+    export GOPROXY=${OLDGOPROXY}
+    export GOPRIVATE=${OLDGOPRIVATE}
+    export GOFLAGS=${OLDGOFLAGS}
+    if [[ $? -ne 0 ]] ;then
+       echo "BUILD ERROR"
+       exit -1
+    fi
+    setMsg 'BUILD END'
+    mvPackage
+}
+
+function runBuild () {
+    buildGo
+}
+
+runBuild

+ 237 - 0
cicd/deploy.sh

@@ -0,0 +1,237 @@
+#!/bin/bash
+# author: sre.list@songguo7.com
+# 2020.03.17
+#
+# 脚本执行输入参数:
+#     第一个参数:start | stop | restart | deploy
+#     第二个参数对应ENV变量(环境列表): dev | test | perf | prepub | online
+# 脚本执行输出状态码:
+#       0: 成功
+#     非0: 失败
+# 脚本执行输出字符串为devops页面输出内容;
+#
+# 示例:
+#     服务启动运行 bash cicd/deploy.sh deploy $ENV
+# 脚本执行目录为项目部署目录,所有操作不会切换目录
+# 示例 例如iot 部署目录为 /data/apps/iot/
+
+
+ACTION=$1
+ENV=$2
+
+
+# 自动获项目名
+PROJECT=$(basename $(pwd))
+# ip
+IP=`ip a|grep "10\."|grep inet|grep -v lo:|awk -F"/" '{print $1}'|awk '{print $NF}'`
+
+# 服务端口号,与sre 确认
+CURRPORT=8008
+
+# 以下两项可以自定义,最好按照统一的规范
+# 服务健康检查接口
+CHECK_WEBPATH="/${PROJECT}/web_status"
+# 服务健康检查接口返回值
+CHECK_PATTEN="status_ok"
+
+# 项目部署路径
+DEPLOY_DIR="/data/apps/${PROJECT}"
+# 使用supervisor进程时,脚本生成项目对应的进程管理配置文件
+START_CONFIG=${PROJECT}.ini
+# supervisor控制命令
+SUPERVISOR_BIN="supervisorctl"
+# jar 包及配置文件目录
+DEPLOY_TARGET_DIR='deploy_target'
+# 健康检查url
+HEALTH_URL="http://${IP}:${CURRPORT}${CHECK_WEBPATH}"
+
+
+# Java启动命令,此处可以自定义
+cmd_online="/data/apps/${PROJECT}/bin/${PROJECT}-app"
+cmd_prepub=${cmd_online}
+cmd_test=${cmd_online}
+cmd_dev=${cmd_online}
+cmd_perf=${cmd_online}
+
+# 应用配置源文件名称
+app_source_ini=""
+
+if [[ "${ENV}#" == "test#" ]] ;then
+    cmd=${cmd_test}
+    app_source_ini="env.test.ini"
+    app_apollo_ini="apollo.test.json"
+fi
+if [[ "${ENV}#" == "dev#" ]] ;then
+    cmd=${cmd_dev}
+    app_source_ini="env.dev.ini"
+    app_apollo_ini="apollo.dev.json"
+fi
+if [[ "${ENV}#" == "perf#" ]] ;then
+    cmd=${cmd_perf}
+    app_source_ini="env.performance.ini"
+    app_apollo_ini="apollo.performance.json"
+fi
+if [[ "${ENV}#" == "prepub#" ]] ;then
+    cmd=${cmd_prepub}
+    app_source_ini="env.slave.ini"
+    app_apollo_ini="apollo.slave.json"
+fi
+if [[ "${ENV}#" == "online#" ]] ;then
+    cmd=${cmd_online}
+    app_source_ini="env.release.ini"
+    app_apollo_ini="apollo.release.json"
+fi
+
+#############################################################
+
+# 生成supervisor进程管理配置文件
+function genSupervisorConfig() {
+    echo "[program:${PROJECT}]">${START_CONFIG}
+    echo "command = ${cmd}">>${START_CONFIG}
+    echo "directory = ${DEPLOY_DIR}" >>${START_CONFIG}
+    echo "stdout_logfile = ${DEPLOY_DIR}/logs/${PROJECT}.log">>${START_CONFIG}
+    echo "redirect_stderr = true">> ${START_CONFIG}
+    echo "numprocs = 1" >>${START_CONFIG}
+    echo "autorestart = 1">>${START_CONFIG}
+    echo "autostart = 1">>${START_CONFIG}
+    echo "user = ttyc">>${START_CONFIG}
+    echo "startsecs = 5">>${START_CONFIG}
+    if [[ ! -L "/etc/supervisord.d/${START_CONFIG}" ]];then
+        ln -s "${DEPLOY_DIR}/$START_CONFIG" /etc/supervisord.d/${START_CONFIG}
+    fi
+    if [[ ! -d "${DEPLOY_DIR}/logs" ]];then
+        mkdir "${DEPLOY_DIR}/logs"
+    fi
+}
+
+# supervisor检查服务状态
+function check_status() {
+    supervisorctl status ${PROJECT}
+}
+
+function status() {
+    if [[ "$1" -eq 0 ]];then
+        echo '状态正常'
+    else
+        echo '状态异常'
+        exit 1
+    fi
+
+}
+
+# 日志输出
+function echoStageMsg() {
+    msg=$1
+    echo -e "[stage]: $msg "
+}
+
+
+# 健康检查 正常不用返回,异常返回非0
+# 此处可以自定义
+function health_check() {
+    echo -e ${HEALTH_URL}
+    for in in $(seq 1 1 30) ;do
+        code=`curl  -s -o /dev/null -w '%{http_code}' -m 2  "${HEALTH_URL}"`
+        if [[ ${code} -eq 200 ]] ; then
+            echoStageMsg "健康检查 成功"
+            break
+        else
+            sleep 1
+        fi
+    done
+    if [[ ${code} -ne 200 ]]; then
+        echoStageMsg "健康检查 失败"
+        exit 1
+    fi
+
+}
+
+function initAppLogFile() {
+  ## 创建日志目录
+  mkdir -p "/data/log/${PROJECT}"
+  chown ttyc:ttyc "/data/log/${PROJECT}" -R
+}
+
+# 项目启动前初始化,此处可以自定义
+function init() {
+    echo "deploy init start"
+    initAppLogFile
+    genSupervisorConfig
+    ## 构建产物通过devops,下载 和 原样解压至项目顶级目录 如下
+    ## deploy_target/
+    ## cicd/deploy.sh
+    ## 如需其他操作请在这里添加
+    mkdir -p bin
+    cp ${DEPLOY_TARGET_DIR}/${PROJECT}-app ./bin/
+    cp -r ${DEPLOY_TARGET_DIR}/config ./
+    ## 拷贝对应环境配置文件 为 env.ini
+    /bin/cp -f ./config/${app_source_ini} ./config/env.ini
+    /bin/cp -f ./config/apollo/${app_apollo_ini} ./config/apollo/apollo.json
+    mkdir -p logs
+    ## 设置权限
+    chown ttyc:ttyc ./ -R
+}
+
+# 停止服务
+function stop() {
+    echo "supervisorctl stop ${PROJECT}"
+    supervisorctl stop ${PROJECT}
+    supervisorctl reread
+    if [[ $? -eq 0 ]] ;then
+        supervisorctl update
+    fi
+    check_status ${PROJECT}|egrep -i "stopped"
+    # status $?
+}
+
+# 启动服务
+function start(){
+    supervisorctl reread
+    if [[ $? -eq 0 ]] ;then
+        supervisorctl update
+    fi
+    echo "supervisorctl start ${PROJECT}"
+    # supervisorctl start $PROJECT
+    supervisorctl restart ${PROJECT}
+    check_status ${PROJECT}|egrep -i "running"
+    status $?
+    health_check
+
+}
+
+function usage(){
+    echo $"Usage: $0   {start|stop|restart|deploy} {ENV}"
+    exit 1
+}
+
+function main() {
+    if [[ "${ACTION}" == "" ]]; then
+        usage
+    fi
+    case "${ACTION}" in
+        start)
+            start
+        ;;
+        stop)
+            stop
+        ;;
+        restart)
+            echo "重启服务"
+            stop
+            start
+        ;;
+        deploy)
+            echo "部署服务"
+            stop
+            init
+            start
+        ;;
+        *)
+            usage
+        ;;
+    esac
+}
+
+main
+# 正常执行结束,成功返回状态:0
+exit 0

+ 42 - 0
cmd/main.go

@@ -0,0 +1,42 @@
+package main
+
+import (
+	"fmt"
+	"go-template/router"
+	"net/http"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/boot"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/conf"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/middleware"
+)
+
+func main() {
+	// 初始化环境,需要哪些资源添加哪些资源
+	boot.Init(boot.DB, boot.Redis, boot.Pprof)
+
+	r := engines.New()
+	engines.SetMode(conf.GetEnv())
+
+	// 全局中间件
+	r.Use(middleware.AccessLogMiddleware())
+	//r.Use(middleware.SkyWalkingTracerMiddleware(r))
+	r.Use(middleware.AddTraceId())
+
+	// 注册路由
+	router.Router(r)
+
+	// 开启 消费RocketMQConsumer 必须在 boot.Start之前
+	//if err := job.StartRocketMQConsumer(); err != nil {
+	//	panic(err)
+	//}
+
+	// 启动
+	boot.Start()
+
+	fmt.Printf("Listening and serving HTTP on %s, server start running !!!\n", fmt.Sprintf(":%d", conf.GetAppPort()))
+	// 启动http
+	if err := http.ListenAndServe(fmt.Sprintf(":%d", conf.GetAppPort()), r); err != nil {
+		panic(err)
+	}
+}

+ 5 - 0
config/apollo/apollo.dev.json

@@ -0,0 +1,5 @@
+{
+  "appId":"go-template",
+  "cluster":"default",
+  "ip":"dev-apollo.in.abc.com:8080"
+}

+ 5 - 0
config/apollo/apollo.release.json

@@ -0,0 +1,5 @@
+{
+  "appId":"go-template",
+  "cluster":"default",
+  "ip":"online-apollo.in.abc.com:8080"
+}

+ 5 - 0
config/apollo/apollo.slave.json

@@ -0,0 +1,5 @@
+{
+  "appId":"go-template",
+  "cluster":"default",
+  "ip":"slave-apollo.in.abc.com:8080"
+}

+ 5 - 0
config/apollo/apollo.test.json

@@ -0,0 +1,5 @@
+{
+  "appId":"go-template",
+  "cluster":"default",
+  "ip":"test-apollo.in.abc.com:8080"
+}

+ 5 - 0
config/apollo/apollo.test2.json

@@ -0,0 +1,5 @@
+{
+  "appId":"go-template",
+  "cluster":"default",
+  "ip":"test2-apollo.in.abc.com:8080"
+}

+ 5 - 0
config/apollo/apollo.test3.json

@@ -0,0 +1,5 @@
+{
+  "appId":"go-template",
+  "cluster":"default",
+  "ip":"test3-apollo.in.abc.com:8080"
+}

+ 27 - 0
config/apollo/namespaces.json

@@ -0,0 +1,27 @@
+{
+  "namespaces": [
+    {
+      "namespace": "application",
+      "sections": [
+        {
+          "name": "application",
+          "keys": [
+            {
+              "name": "application.host",
+              "mapTo": "host"
+            }
+          ]
+        },
+        {
+          "name": "mysql",
+          "keys": [
+            {
+              "name": "mysql.host",
+              "mapTo": "host"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 53 - 0
config/env.dev.ini

@@ -0,0 +1,53 @@
+[conf]
+# file|apollo|nacos,file直接读取文件
+driver = file
+
+[application]
+# env : (debug|test|release) test测试环境
+env = test
+
+# application,这里启动的时候记得变更port
+project_name=go-template
+
+port=8080
+
+# logger,配置前需要创建/data/log/project_name
+[log]
+access_log=/data/log/go-template/access.log
+monitor_log=/data/log/go-template/monitor.log
+task_log=/data/log/go-template/task.log
+project_log=/data/log/go-template/project_name.log
+# 三方日志
+third_log=/data/log/go-template/third.log
+third_log_switch=on
+
+#multi_db
+#multi_db.db_name = mysql,urban_op
+
+# mysql master
+[mysql]
+host = 127.0.0.1
+port = 3306
+user = root
+password = 123456
+dbname=mysql
+# mysql salve
+slave_host = 127.0.0.1
+slave_port = 3306
+slave_user = root
+slave_password = 123456
+slave_dbname=mysql
+#mysql config
+log_file=/data/log/go-template/mysql.log
+max_idle = 2
+max_conn = 27
+read_timeout = 5
+write_timeout = 5
+
+[redis]
+host = 127.0.0.1:6379
+cache_prefix =go-template
+password =
+is_direct = true
+max_conn=100
+max_idle=50

+ 15 - 0
config/env.release.ini

@@ -0,0 +1,15 @@
+[application]
+# env : (debug|test|release) test测试环境
+env = release
+
+[conf]
+# file|apollo|nacos,file直接读取文件
+driver = nacos
+
+[nacos-config]
+host = 10.100.101.20:8848,10.100.103.230:8848,10.100.99.14:8848
+log_path = /data/log/go-template
+namespace_id = ed35034b-634e-4ed5-9266-d7366d389351
+user_name = nacos
+password = nacos
+data_id = go-template

+ 15 - 0
config/env.slave.ini

@@ -0,0 +1,15 @@
+[application]
+# env : (debug|test|release) test测试环境
+env = release
+
+[conf]
+# file|apollo|nacos,file直接读取文件
+driver = nacos
+
+[nacos-config]
+host = 10.100.101.20:8848,10.100.103.230:8848,10.100.99.14:8848
+log_path = /data/log/go-template
+namespace_id = ed35034b-634e-4ed5-9266-d7366d389351
+user_name = nacos
+password = nacos
+data_id = go-template

+ 15 - 0
config/env.test.ini

@@ -0,0 +1,15 @@
+[application]
+# env : (debug|test|release) test测试环境
+env = test
+
+[conf]
+# file|apollo|nacos,file直接读取文件
+driver = nacos
+
+[nacos-config]
+host = 10.100.101.20:8848,10.100.103.230:8848,10.100.99.14:8848
+log_path = /data/log/go-template
+namespace_id = ed35034b-634e-4ed5-9266-d7366d389351
+user_name = nacos
+password = nacos
+data_id = go-template

+ 15 - 0
config/env.test2.ini

@@ -0,0 +1,15 @@
+[application]
+# env : (debug|test|release) test测试环境
+env = test
+
+[conf]
+# file|apollo|nacos,file直接读取文件
+driver = nacos
+
+[nacos-config]
+host = 10.100.101.20:8848,10.100.103.230:8848,10.100.99.14:8848
+log_path = /data/log/go-template
+namespace_id = ed35034b-634e-4ed5-9266-d7366d389351
+user_name = nacos
+password = nacos
+data_id = go-template

+ 15 - 0
config/env.test3.ini

@@ -0,0 +1,15 @@
+[application]
+# env : (debug|test|release) test测试环境
+env = test
+
+[conf]
+# file|apollo|nacos,file直接读取文件
+driver = nacos
+
+[nacos-config]
+host = 10.100.101.20:8848,10.100.103.230:8848,10.100.99.14:8848
+log_path = /data/log/go-template
+namespace_id = ed35034b-634e-4ed5-9266-d7366d389351
+user_name = nacos
+password = nacos
+data_id = go-template

+ 11 - 0
go.mod

@@ -0,0 +1,11 @@
+module go-template
+
+go 1.13
+
+require (
+	gitea.ckfah.com/cjjy/gocommon v1.0.0
+	github.com/apache/rocketmq-client-go/v2 v2.0.0
+	github.com/google/uuid v1.1.1
+	github.com/prometheus/client_golang v1.8.0
+	xorm.io/xorm v1.0.5
+)

+ 605 - 0
go.sum

@@ -0,0 +1,605 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+gitea.ckfah.com/cjjy/gocommon v1.0.0 h1:YNpX06OBDh0YkkZpOiuSK/ZD2fQeP9rhEUd7uFtPq/0=
+gitea.ckfah.com/cjjy/gocommon v1.0.0/go.mod h1:aLwIPlECfA7BY7W7G/IA7WTsMLHB38HXWl/UQfO60GA=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
+github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1 h1:j56fC19WoD3z+u+ZHxm2XwRGyS1XmdSMk7058BLhdsM=
+github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1/go.mod h1:gXEhMjm1VadSGjAzyDlBxmdYglP8eJpYWxpwJnmXRWw=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
+github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/SkyAPM/go2sky v0.5.0 h1:9RDBQviaeazG7PJMLLnMcU4U++PORbqEls4ix4OEgQw=
+github.com/SkyAPM/go2sky v0.5.0/go.mod h1:TANzYw5EvIlTidGWvQxtvO87rM6C746HkM0xkWqnPQw=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
+github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
+github.com/apache/rocketmq-client-go/v2 v2.0.0 h1:D6jFj3DcNjWyjWn5N/R7Eq8v5kLqlgkFnT/DNQFnWlM=
+github.com/apache/rocketmq-client-go/v2 v2.0.0/go.mod h1:oEZKFDvS7sz/RWU0839+dQBupazyBV7WX5cP6nrio0Q=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU=
+github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
+github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
+github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
+github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
+github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4=
+github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo=
+github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE=
+github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgUSP4zdTUZYZgAGGtN5Lxk92rK+JUFOwf+FT99EEI4=
+github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8=
+github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5jFF4BHGAEDSqwPW1NJS3XshxbRCxtjFAZc=
+github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0=
+github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
+github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
+github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nacos-group/nacos-sdk-go v1.0.6 h1:0OqjS37qIKKKZKRQSJ5pNFGRrfzP7+gD4L6dvOkPFZw=
+github.com/nacos-group/nacos-sdk-go v1.0.6/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olivere/elastic v6.2.35+incompatible h1:MMklYDy2ySi01s123CB2WLBuDMzFX4qhFcA5tKWJPgM=
+github.com/olivere/elastic v6.2.35+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
+github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
+github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI=
+github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
+github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
+github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1 h1:oMnRNZXX5j85zso6xCPRNPtmAycat+WcoKbklScLDgQ=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a h1:AhmOdSHeswKHBjhsLs/7+1voOxT+LLrSk/Nxvk35fug=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
+github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto=
+github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
+github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA=
+github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w=
+github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
+github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
+github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
+github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
+github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
+github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 h1:kF/7m/ZU+0D4Jj5eZ41Zm3IH/J8OElK1Qtd7tVKAwLk=
+github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE=
+github.com/ugorji/go v1.2.0 h1:6eXlzYLLwZwXroJx9NyqbYcbv/d93twiOzQLDewE6qM=
+github.com/ugorji/go v1.2.0/go.mod h1:1ny++pKMXhLWrwWV5Nf+CbOuZJhMoaFD+0GMFfd8fEc=
+github.com/ugorji/go/codec v1.2.0 h1:As6RccOIlbm9wHuWYMlB30dErcI+4WiKWsYsmPkyrUw=
+github.com/ugorji/go/codec v1.2.0/go.mod h1:dXvG35r7zTX6QImXOSFhGMmKtX+wJ7VTWzGvYQGIjBs=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf h1:spotWVWg9DP470pPFQ7LaYtUqDpWEOS/BUrSmwFZE4k=
+github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk=
+github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
+go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
+golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/image v0.0.0-20200922025426-e59bae62ef32 h1:E+SEVulmY8U4+i6vSB88YSc2OKAFfvbHPU/uDTdQu7M=
+golang.org/x/image v0.0.0-20200922025426-e59bae62ef32/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0 h1:MsuvTghUPjX762sGLnGsxC3HM0B5r83wEtYcYR8/vRs=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20181010134911-4d1c5fb19474/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
+gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
+gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
+gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
+gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
+stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
+stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0=
+xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
+xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
+xorm.io/xorm v1.0.5 h1:LRr5PfOUb4ODPR63YwbowkNDwcolT2LnkwP/TUaMaB0=
+xorm.io/xorm v1.0.5/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=

+ 0 - 0
monitor_log.log


+ 23 - 0
router/op_router.go

@@ -0,0 +1,23 @@
+package router
+
+import (
+	"go-template/business/controller"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+)
+
+var (
+	reportController = controller.NewReportController()
+)
+
+func operationRouter(e *engines.Engine) {
+	group := e.Group("/go-template")
+	group.POST("/info", reportController.ReportInfo)                    // 普通业务
+	group.POST("/list", reportController.ReportList)                    // 分页业务
+	group.POST("/upload/xlsx/file", reportController.UploadXlsxFile)    // 上传文件业务
+	group.GET("/download/xlsx/file", reportController.DownLoadXlsxFile) // 下载excel业务
+	group.GET("/download/csv/file", reportController.DownLoadCsvFile)   // 下载csv业务
+	group.GET("/timeout", reportController.SleepTimeout)                // 超时业务
+	group.GET("/panic", reportController.TestPanic)                     // 测试panic是否可以捕获
+	group.POST("/send/mq", reportController.SendMQ)                     // 发送mq业务
+}

+ 11 - 0
router/router.go

@@ -0,0 +1,11 @@
+package router
+
+import (
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+)
+
+//Router 路由注册
+func Router(e *engines.Engine) {
+	sysRoute(e)
+	operationRouter(e)
+}

+ 33 - 0
router/sys_router.go

@@ -0,0 +1,33 @@
+package router
+
+import (
+	"net/http"
+
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+
+	"gitea.ckfah.com/cjjy/gocommon/pkg/net/engines"
+)
+
+func sysRoute(e *engines.Engine) {
+	g := e.Group("")
+	// 首页,prometheus,健康检查
+	g.GET("/", welcome)
+	g.GET("/metrics", getHandler(promhttp.Handler()))
+	g.GET("/go-template/web_status", webStatus)
+}
+
+// 欢迎页面
+func welcome(c *engines.Context) {
+	c.JSON(http.StatusOK, "Welcome, go-template")
+}
+
+// 健康检查
+func webStatus(c *engines.Context) {
+	c.JSON(http.StatusOK, "status_ok")
+}
+
+func getHandler(handler http.Handler) engines.HandlerFunc {
+	return func(ctx *engines.Context) {
+		handler.ServeHTTP(ctx.Writer, ctx.Request)
+	}
+}

+ 0 - 0
task_log.log


+ 0 - 0
third.log