提交 e0de742a32e7de116a0e94241d0ca90f2716da26

作者 nheweijun
1 个父辈 3db18ae3

2021.12.07 对接切片服务

... ... @@ -94,6 +94,11 @@ def create_app():
94 94 # 不检测https
95 95 os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
96 96
  97 +
  98 + @app.before_first_request
  99 + def init_data():
  100 + pass
  101 +
97 102 # start_schedule()
98 103 return app
99 104
... ...
... ... @@ -23,7 +23,6 @@ class Api(ApiTemplate):
23 23 res["result"] = False
24 24 try:
25 25 # 业务逻辑
26   -
27 26 if not Database.query.filter_by(guid=self.para.get("database_guid")).one_or_none():
28 27 res["msg"]="数据库不存在!"
29 28 return res
... ...
... ... @@ -86,7 +86,7 @@ class Api(ApiTemplate):
86 86 task_writer = TaskWriter(task_guid)
87 87
88 88 #进入创建金字塔的状态
89   - task_guid.sys_session.query(Image).filter_by(guid=image_guid).update({"has_pyramid": -1})
  89 + task_writer.session.query(Image).filter_by(guid=image_guid).update({"has_pyramid": -1})
90 90 task_writer.update_task({"state": 2})
91 91
92 92 #所有数据节点的影像都要建金字塔
... ...
... ... @@ -155,6 +155,7 @@ class ImageWMTSServer(ImageServer):
155 155 if not tile_scheme:
156 156 raise Exception("切片方案不存在!")
157 157 tile_scheme = ModelVisitor.object_to_json(tile_scheme)
  158 +
158 159 xml = '''<Capabilities xmlns="http://www.opengis.net/wmts/1.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" xsi:schemaLocation="http://www.opengis.net/wmts/1.0 http://schemas.opengis.net/wmts/1.0/wmtsGetCapabilities_response.xsd" version="1.0.0">
159 160 <!-- Service Identification -->
160 161 <ows:ServiceIdentification>
... ...
... ... @@ -137,7 +137,11 @@ class ImageService(db.Model):
137 137 __tablename__ = 'dmap_image_service'
138 138 guid = Column(String(256), primary_key=True)
139 139 name = Column(String,unique = True)
  140 + #切片方案
  141 + scheme = Column(Text)
  142 +
140 143 scheme_guid = Column(String)
  144 +
141 145 extent = Column(String(256))
142 146 # node = Column(Integer)
143 147 #可视范围geojson
... ... @@ -173,9 +177,7 @@ class ImageTag(db.Model):
173 177 images = db.relationship('Image',
174 178 secondary=dmap_image_tag_rel,
175 179 backref='image_tags',
176   - lazy='dynamic'
177   - )
178   -
  180 + lazy='dynamic')
179 181
180 182 class TileService(db.Model):
181 183 '''
... ... @@ -217,6 +219,9 @@ class TileService(db.Model):
217 219 #图层描述
218 220 layer_description = Column(String)
219 221
  222 + #切片方案
  223 + scheme = Column(Text)
  224 +
220 225 scheme_guid = Column(String,ForeignKey('dmap_tile_scheme.guid'))
221 226 service_guid = Column(String,ForeignKey('dmap_service.guid'))
222 227
... ...
... ... @@ -68,6 +68,12 @@ class Api(ApiTemplate):
68 68 "in": "formData",
69 69 "type": "string",
70 70 "description": "[切片服务,影像服务]切片方案"},
  71 +
  72 + {"name": "scheme_guid",
  73 + "in": "formData",
  74 + "type": "string",
  75 + "description": "[切片服务,影像服务]切片方案"},
  76 +
71 77 {"name": "functions",
72 78 "in": "formData",
73 79 "type": "string",
... ...
... ... @@ -7,7 +7,7 @@
7 7 from flasgger import swag_from
8 8 from flask import Blueprint
9 9 from app.util import BlueprintApi
10   -from . import upload_oview,tile_service_register,tile_service_edit
  10 +from . import upload_oview,tile_service_register,tile_service_edit,tile_service_reload
11 11
12 12
13 13
... ... @@ -45,3 +45,12 @@ class DataManager(BlueprintApi):
45 45 """
46 46 return tile_service_edit.Api().result
47 47
  48 + @staticmethod
  49 + @bp.route('/Reload', methods=['GET'])
  50 + @swag_from(tile_service_reload.Api.api_doc)
  51 + def api_tile_service_reload():
  52 + """
  53 + TileService Reload
  54 + """
  55 + return tile_service_reload.Api().result
  56 +
... ...
... ... @@ -4,11 +4,15 @@
4 4 #email: nheweijun@sina.com
5 5
6 6 from app.util.component.ApiTemplate import ApiTemplate
  7 +from app.util.component.ModelVisitor import ModelVisitor
7 8 import uuid
8 9 from ..models import TileService,Service,db,ServiceFunction
  10 +import datetime
  11 +import requests
  12 +from .util.ProjectFile import ProjectFile
9 13
  14 +from requests import Response
10 15
11   -import datetime
12 16 class Api(ApiTemplate):
13 17
14 18 api_name = "修改切片服务"
... ... @@ -25,7 +29,6 @@ class Api(ApiTemplate):
25 29 service = Service.query.filter_by(guid=guid)
26 30 this_time = datetime.datetime.now()
27 31
28   -
29 32 service_update = {"update_time":this_time}
30 33 tile_update = {}
31 34 for key in self.para.keys():
... ... @@ -36,10 +39,27 @@ class Api(ApiTemplate):
36 39 "layer_extent","layer_description","scheme_guid"]:
37 40 tile_update[key] = self.para.get(key)
38 41
39   - tile_service = TileService.query.filter_by(service_guid=guid)
  42 + #通知tileserver,更新缓存
  43 + ts = TileService.query.filter_by(service_guid=guid).one_or_none()
  44 + se = service.one_or_none()
40 45
41   - tile_type = self.para.get("tile_type")
  46 + ts_json = ModelVisitor.object_to_json(ts)
  47 + ts_json.update(tile_update)
  48 + project_file = ProjectFile.create(ts_json)
  49 +
  50 + para = {"name":self.para.get("name") if self.para.get("name") else se.name,
  51 + "title":self.para.get("title") if self.para.get("title") else se.title,
  52 + "type":"tileserver","capabilities":1,"project":project_file}
  53 +
  54 + tile_service_edit_url = ""
42 55
  56 + resp: Response = requests.post(tile_service_edit_url,para).json()
  57 + if not resp.json()["status"].__eq__("true"):
  58 + raise Exception("调用切片服务的注册服务接口失败!")
  59 +
  60 + #修改数据库
  61 + tile_service = TileService.query.filter_by(service_guid=guid)
  62 + tile_type = self.para.get("tile_type")
43 63 # 修改功能
44 64 if tile_type:
45 65 old_functions = ServiceFunction.query.filter_by(service_guid=guid).all()
... ... @@ -57,8 +77,8 @@ class Api(ApiTemplate):
57 77 tile_service.update(tile_update)
58 78
59 79 db.session.commit()
60   -
61 80 res["result"] = True
  81 +
62 82 except Exception as e:
63 83 raise e
64 84
... ... @@ -67,11 +87,14 @@ class Api(ApiTemplate):
67 87 api_doc = {
68 88 "tags": ["切片服务接口"],
69 89 "parameters": [
  90 + {"name": "guid",
  91 + "in": "formData",
  92 + "type": "string",
  93 + "description": "service guid"},
70 94
71 95 {"name": "name",
72 96 "in": "formData",
73 97 "type": "string",
74   - "required": "true",
75 98 "description": "[地图服务,切片服务,影像服务]"},
76 99 {"name": "title",
77 100 "in": "formData",
... ...
... ... @@ -5,14 +5,17 @@
5 5
6 6
7 7 from app.util.component.ApiTemplate import ApiTemplate
  8 +from app.util.component.ModelVisitor import ModelVisitor
8 9 import uuid
9   -from ..models import TileService,Service,db,ServiceFunction
  10 +from ..models import TileService,Service,db,ServiceFunction,TileScheme
10 11
11 12 import datetime
12 13 import configure
13 14 import requests
14 15 from requests import Response
15   -import json
  16 +
  17 +from .util.ProjectFile import ProjectFile
  18 +
16 19 class Api(ApiTemplate):
17 20
18 21 api_name = "注册切片服务"
... ... @@ -20,16 +23,20 @@ class Api(ApiTemplate):
20 23 def process(self):
21 24 # 返回结果
22 25 res = {}
23   -
24 26 try:
25   -
26 27 this_time = datetime.datetime.now()
27 28 service_guid = uuid.uuid1().__str__()
28 29 tile_service_guid = uuid.uuid1().__str__()
29 30 service_function_guid = uuid.uuid1().__str__()
30   -
31 31 # 调用切片服务的注册服务接口
32   - # 先调用切片服务接口,成功后才持久化
  32 + project_file = ProjectFile.create(self.para)
  33 + para = {"name":self.para.get("name"),"title":self.para.get("title"),
  34 + "type":"tileserver","capabilities":1,"project":project_file}
  35 + tile_service_register_url = ""
  36 +
  37 + resp: Response = requests.post(tile_service_register_url,para).json()
  38 + if not resp.json()["status"].__eq__("true"):
  39 + raise Exception("调用切片服务的注册服务接口失败!")
33 40
34 41 service = Service(
35 42 guid = service_guid,
... ... @@ -52,6 +59,8 @@ class Api(ApiTemplate):
52 59 if tile_service_isexist:
53 60 db.session.delete(tile_service_isexist)
54 61
  62 + tile_scheme: TileScheme = TileScheme.query.filter_by(guid=self.para.get("scheme_guid")).one_or_none()
  63 +
55 64 tile_service = TileService(
56 65 guid = tile_service_guid,
57 66 name = self.para.get("name"),
... ... @@ -69,8 +78,9 @@ class Api(ApiTemplate):
69 78 layer_extent = self.para.get("layer_extent"),
70 79 layer_description = self.para.get("layer_description"),
71 80 scheme_guid = self.para.get("scheme_guid"),
  81 + scheme = ModelVisitor.object_to_json(tile_scheme),
72 82 service_guid = service_guid,
73   - metadata_url="{}/DMap/Services/{}/MapServer/WMTSServer".format(configure.wmts_url,self.para.get("name"))
  83 + metadata_url = "{}/DMap/Services/{}/MapServer/WMTSServer".format(configure.wmts_url,self.para.get("name"))
74 84 )
75 85
76 86 service_function = ServiceFunction(guid=service_function_guid,
... ... @@ -82,18 +92,6 @@ class Api(ApiTemplate):
82 92 db.session.add(service_function)
83 93 db.session.commit()
84 94
85   - # 调用切片服务的注册服务接口
86   - try:
87   - url = "{}/dmap/api/manager/updatecache?servicename={}".format(configure.wmts_url,service.name)
88   - resp:Response = requests.get(url)
89   - if not resp.json()["status"].__eq__("true"):
90   - raise Exception("调用切片服务的注册服务接口失败!")
91   - except Exception as e:
92   - db.session.delete(service)
93   - db.session.delete(tile_service)
94   - db.session.delete(service_function)
95   - db.session.commit()
96   - raise e
97 95 res["data"] = service_guid
98 96 res["result"] = True
99 97 except Exception as e:
... ... @@ -101,6 +99,7 @@ class Api(ApiTemplate):
101 99 raise e
102 100 return res
103 101
  102 +
104 103 api_doc = {
105 104 "tags": ["切片服务接口"],
106 105 "parameters": [
... ...
  1 +# coding=utf-8
  2 +#author: 4N
  3 +#createtime: 2021/7/19
  4 +#email: nheweijun@sina.com
  5 +
  6 +
  7 +from app.util.component.ApiTemplate import ApiTemplate
  8 +from ..models import TileService,db,Service
  9 +import configure
  10 +from app.util.component.ModelVisitor import ModelVisitor
  11 +
  12 +from .util.ProjectFile import ProjectFile
  13 +
  14 +class Api(ApiTemplate):
  15 +
  16 + api_name = "切片服务reload"
  17 +
  18 + def process(self):
  19 + res = {}
  20 + try:
  21 + tile_services = TileService.query.join(Service).filter(Service.type=="切片服务").all()
  22 + res["data"] = {}
  23 + res["data"]["count"] = len(tile_services)
  24 + res["data"]["list"] = []
  25 + for ts in tile_services:
  26 + project_file = ProjectFile.create(ModelVisitor.object_to_json(ts))
  27 + service:Service = Service.query.filter_by(guid=ts.service_guid).one_or_none()
  28 + para = {"name":service.name,"title":service.title,
  29 + "type":"tileserver","capabilities":1,"project":project_file}
  30 + res["data"]["list"].append(para)
  31 + res["result"] = True
  32 + except Exception as e:
  33 + raise e
  34 + return res
  35 +
  36 + api_doc = {
  37 + "tags": ["切片服务接口"],
  38 + "parameters": [
  39 + ],
  40 + "responses": {
  41 + 200: {
  42 + "schema": {
  43 + "properties": {
  44 + }
  45 + }
  46 + }
  47 + }
  48 + }
\ No newline at end of file
... ...
  1 +# coding=utf-8
  2 +#author: 4N
  3 +#createtime: 2021/12/6
  4 +#email: nheweijun@sina.com
  5 +
  6 +
  7 +from app.modules.service.models import TileScheme
  8 +from app.util.component.ModelVisitor import ModelVisitor
  9 +import json
  10 +import base64
  11 +
  12 +
  13 +class ProjectFile:
  14 +
  15 + @classmethod
  16 + def create(cls,para):
  17 + if para.get("tile_type").__eq__("WMTS"):
  18 +
  19 + if para.get("scheme"):
  20 + tile_scheme = json.loads(para.get("scheme"))
  21 + else:
  22 + tile_scheme: TileScheme = TileScheme.query.filter_by(guid=para.get("scheme_guid")).one_or_none()
  23 + if not tile_scheme:
  24 + raise Exception("切片方案不存在!")
  25 + tile_scheme = ModelVisitor.object_to_json(tile_scheme)
  26 +
  27 + project_xml_format = '''<?xml version="1.0"?>
  28 + <dmap projectname="wmtstest" version="4.0">
  29 + <projectCrs>
  30 + <spatialrefsys>
  31 + <wkt>{wkt}</wkt>
  32 + <proj4>{proj4}</proj4>
  33 + <srid>{srid}</srid>
  34 + <description/>
  35 + <projectionacronym/>
  36 + </spatialrefsys>
  37 + </projectCrs>
  38 + <projectlayers>
  39 + <maplayer name="{name}" alias="{alias}" type="0">
  40 + <extent>
  41 + <xmin>{xmin}</xmin>
  42 + <ymin>{xmax}</ymin>
  43 + <xmax>{xmax}</xmax>
  44 + <ymax>{ymax}</ymax>
  45 + </extent>
  46 + <style>{layer_style}</style>
  47 + <format>{layer_format}</format>
  48 + <vendor>{vendor}</vendor>
  49 + <datasource>{datasource}</datasource>
  50 + <tileMatrixSets>
  51 + <tileMatrixSet>
  52 + <id>default</id>
  53 + <crs>{crs}</crs>
  54 + <tileCols>{cols}</tileCols>
  55 + <tileRows>{rows}</tileRows>
  56 + <dpi>{dpi}</dpi>
  57 + <tileOrigin>
  58 + <X>{x}</X>
  59 + <Y>{y}</Y>
  60 + </tileOrigin>
  61 + <levels>
  62 + {levels}
  63 + </levels>
  64 + </tileMatrixSet>
  65 + </tileMatrixSets>
  66 + </maplayer>
  67 + </projectlayers>
  68 + </dmap>
  69 + '''
  70 +
  71 + level_each = '''<level>
  72 + <id>{lev}</id>
  73 + <scaleDenominator>{scale}</scaleDenominator>
  74 + <resolution>{resolution}</resolution>
  75 + </level>'''
  76 +
  77 + levels = ""
  78 + for level in json.loads(tile_scheme.get("levels")):
  79 + levels = "{}{}".format(levels, level_each.format(lev=level["level"],
  80 + scale=level["scale"],
  81 + resolution=level["resolution"],
  82 + ))
  83 +
  84 + layer_extent = para.get("layer_extent").split(",")
  85 +
  86 + project_xml = project_xml_format.format(wkt="",
  87 + proj4="",
  88 + srid=para.get("crs").split("::")[-1],
  89 + name=para.get("layer_name"),
  90 + alias=para.get("alias"),
  91 + xmin=layer_extent[0],
  92 + xmax=layer_extent[1],
  93 + ymin=layer_extent[2],
  94 + ymax=layer_extent[3],
  95 + layer_style=para.get("layer_style"),
  96 + layer_format=para.get("layer_format"),
  97 + vendor=para.get("vendor"),
  98 + datasource=para.get("datasource"),
  99 + crs=para.get("crs"),
  100 + cols=tile_scheme.get("cols"),
  101 + rows=tile_scheme.get("rows"),
  102 + dpi=tile_scheme.get("dpi"),
  103 + x=tile_scheme.get("top_left").split(",")[0],
  104 + y=tile_scheme.get("top_left").split(",")[1],
  105 + levels=levels
  106 + )
  107 + else:
  108 +
  109 + project_xml_format = '''<?xml version="1.0"?>
  110 + <dmap projectname="tmstest" version="4.0">
  111 + <projectCrs>
  112 + <spatialrefsys>
  113 + <wkt>{wkt}</wkt>
  114 + <proj4>{proj4}</proj4>
  115 + <srid>{srid}</srid>
  116 + <description/>
  117 + <projectionacronym/>
  118 + </spatialrefsys>
  119 + </projectCrs>
  120 + <projectlayers>
  121 + <maplayer name="{name}" alias="{alias}" type="3">
  122 + <extent>
  123 + <xmin>{xmin}</xmin>
  124 + <ymin>{xmax}</ymin>
  125 + <xmax>{xmax}</xmax>
  126 + <ymax>{ymax}</ymax>
  127 + </extent>
  128 + <style>{layer_style}</style>
  129 + <format>{layer_format}</format>
  130 + <vendor>{vendor}</vendor>
  131 + <datasource>{datasource}</datasource>
  132 + </maplayer>
  133 + </projectlayers>
  134 + </dmap>
  135 +
  136 + '''
  137 + layer_extent = para.get("layer_extent").split(",")
  138 + project_xml = project_xml_format.format(wkt="",
  139 + proj4="",
  140 + srid=para.get("crs").split("::")[-1],
  141 + name=para.get("layer_name"),
  142 + alias=para.get("alias"),
  143 + xmin=layer_extent[0],
  144 + xmax=layer_extent[1],
  145 + ymin=layer_extent[2],
  146 + ymax=layer_extent[3],
  147 + layer_style=para.get("layer_style"),
  148 + layer_format=para.get("layer_format"),
  149 + vendor=para.get("vendor"),
  150 + datasource=para.get("datasource"),
  151 + )
  152 + return str(base64.b64encode(project_xml.encode('utf-8')), encoding="utf8")
\ No newline at end of file
... ...
  1 +# coding=utf-8
  2 +#author: 4N
  3 +#createtime: 2021/12/6
  4 +#email: nheweijun@sina.com
... ...
... ... @@ -107,4 +107,10 @@ class PGUtil:
107 107
108 108 @classmethod
109 109 def check_database_privilege(cls,table_name,pri_type,user,session):
110   - pass
\ No newline at end of file
  110 + pass
  111 +
  112 +if __name__ == '__main__':
  113 + session:Session = PGUtil.get_db_session("postgresql://postgres:chinadci@172.26.60.100:5432/template1")
  114 + result = session.execute("SELECT datname FROM pg_database;")
  115 + for re in result:
  116 + print(re)
\ No newline at end of file
... ...
... ... @@ -4,8 +4,8 @@ import logging
4 4 deploy_ip_host = "172.26.40.105:8840"
5 5 # 系统数据库
6 6
7   -# SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.60.100:5432/dmap_manager_test"
8   -SQLALCHEMY_DATABASE_URI = "postgresql://postgres:postgres@localhost:5433/dmap_dms_test"
  7 +SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.60.100:5432/dmap_manager"
  8 +# SQLALCHEMY_DATABASE_URI = "postgresql://postgres:postgres@localhost:5433/dmap_dms_test"
9 9
10 10 # 指定精华表所在位置(必须为空间库),设置为None则存放在各自的实体库中
11 11 #VACUATE_DB_URI = None
... ...
... ... @@ -356,12 +356,14 @@ LoadModule wsgi_module "/usr/lib64/httpd/modules/mod_wsgi-py37.cpython-37m-x86_6
356 356 "/var/gdal"
357 357
358 358 dmapmanager processes=4 threads=16 display-name=%{GROUP}
  359 +
359 360 dmapmanager
360 361 #Authorization请求头顺利转发
361 362 On
362 363 %{GLOBAL}
363 364
364 365 / /usr/src/app/run.wsgi
  366 +
365 367 <Directory /usr/>
366 368 Require all granted
367 369 </Directory>
... ...
... ... @@ -19,7 +19,7 @@ import time
19 19 # table="fs900w_1"
20 20 # sql ="SELECT geom FROM {} WHERE geom && 'BOX3D({})'::box3d limit 100000".format(table,bbox)
21 21
22   -
  22 +import base64
23 23 def query_thread():
24 24 def get_db_session(db_url, autocommit=False) -> Session:
25 25 engine = create_engine(db_url, pool_size=100)
... ... @@ -53,6 +53,5 @@ def query_thread():
53 53 ses.close()
54 54 # query_thread()
55 55 if __name__ == '__main__':
56   - kk = [1,2,3,4,5,6,7,8,9,10,11]
57   - print(len(kk))
58   - print(kk[10:20])
\ No newline at end of file
  56 + kk="PD94bWwgdmVyc2lvbj0iMS4wIj8+CiAgICAgICAgICAgIDxkbWFwIHByb2plY3RuYW1lPSJ3bXRzdGVzdCIgdmVyc2lvbj0iNC4wIj4KICAgICAgICAgICAgICA8cHJvamVjdENycz4KICAgICAgICAgICAgICAgIDxzcGF0aWFscmVmc3lzPgogICAgICAgICAgICAgICAgICA8d2t0Pjwvd2t0PgogICAgICAgICAgICAgICAgICA8cHJvajQ+PC9wcm9qND4KICAgICAgICAgICAgICAgICAgPHNyaWQ+NDQ5MDwvc3JpZD4KICAgICAgICAgICAgICAgICAgPGRlc2NyaXB0aW9uLz4KICAgICAgICAgICAgICAgICAgPHByb2plY3Rpb25hY3JvbnltLz4KICAgICAgICAgICAgICAgIDwvc3BhdGlhbHJlZnN5cz4KICAgICAgICAgICAgICA8L3Byb2plY3RDcnM+CiAgICAgICAgICAgICAgPHByb2plY3RsYXllcnM+CiAgICAgICAgICAgICAgICA8bWFwbGF5ZXIgbmFtZT0ibGF5ZXIiIGFsaWFzPSJOb25lIiB0eXBlPSIwIj4KICAgICAgICAgICAgICAgICAgPGV4dGVudD4KICAgICAgICAgICAgICAgICAgICA8eG1pbj4xMDcuNzg5ODE0OTQxODA2MTg8L3htaW4+CiAgICAgICAgICAgICAgICAgICAgPHltaW4+MTIwLjQzNTUzNjAzOTM1Njc1PC95bWluPgogICAgICAgICAgICAgICAgICAgIDx4bWF4PjEyMC40MzU1MzYwMzkzNTY3NTwveG1heD4KICAgICAgICAgICAgICAgICAgICA8eW1heD4yNS45OTk4Njg3NTc3MzcwMzM8L3ltYXg+CiAgICAgICAgICAgICAgICAgIDwvZXh0ZW50PgogICAgICAgICAgICAgICAgICA8c3R5bGU+ZGVmYXVsdDwvc3R5bGU+CiAgICAgICAgICAgICAgICAgIDxmb3JtYXQ+aW1hZ2UvcG5nPC9mb3JtYXQ+CiAgICAgICAgICAgICAgICAgIDx2ZW5kb3I+RVNSSV9WMTwvdmVuZG9yPgogICAgICAgICAgICAgICAgICA8ZGF0YXNvdXJjZT4vdXNyL2xvY2FsL2RtYXA0L2dkbWFwL19hbGxsYXllcnM8L2RhdGFzb3VyY2U+CiAgICAgICAgICAgICAgICAgIDx0aWxlTWF0cml4U2V0cz4KICAgICAgICAgICAgICAgICAgICA8dGlsZU1hdHJpeFNldD4KICAgICAgICAgICAgICAgICAgICAgIDxpZD5kZWZhdWx0PC9pZD4KICAgICAgICAgICAgICAgICAgICAgIDxjcnM+RVBTRzo6NDQ5MDwvY3JzPgogICAgICAgICAgICAgICAgICAgICAgPHRpbGVDb2xzPjI1NjwvdGlsZUNvbHM+CiAgICAgICAgICAgICAgICAgICAgICA8dGlsZVJvd3M+MjU2PC90aWxlUm93cz4KICAgICAgICAgICAgICAgICAgICAgIDxkcGk+OTY8L2RwaT4KICAgICAgICAgICAgICAgICAgICAgIDx0aWxlT3JpZ2luPgogICAgICAgICAgICAgICAgICAgICAgICA8WD40MDA8L1g+CiAgICAgICAgICAgICAgICAgICAgICAgIDxZPi00MDA8L1k+CiAgICAgICAgICAgICAgICAgICAgICA8L3RpbGVPcmlnaW4+CiAgICAgICAgICAgICAgICAgICAgICA8bGV2ZWxzPgogICAgICAgICAgICAgICAgICAgICAgICA8bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4wPC9pZD4KICAgICAgICAgICAgICAgICAgICAgICAgPHNjYWxlRGVub21pbmF0b3I+NTkwOTk1MTg2LjEyPC9zY2FsZURlbm9taW5hdG9yPgogICAgICAgICAgICAgICAgICAgICAgICA8cmVzb2x1dGlvbj4xLjQwNjI1MDAwMDAwNTk0ODg8L3Jlc29sdXRpb24+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvbGV2ZWw+PGxldmVsPgogICAgICAgICAgICAgICAgICAgICAgICA8aWQ+MTwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjI5NTQ5NzU5My4wNjwvc2NhbGVEZW5vbWluYXRvcj4KICAgICAgICAgICAgICAgICAgICAgICAgPHJlc29sdXRpb24+MC43MDMxMjUwMDAwMDI5NzQ0PC9yZXNvbHV0aW9uPgogICAgICAgICAgICAgICAgICAgICAgICA8L2xldmVsPjxsZXZlbD4KICAgICAgICAgICAgICAgICAgICAgICAgPGlkPjI8L2lkPgogICAgICAgICAgICAgICAgICAgICAgICA8c2NhbGVEZW5vbWluYXRvcj4xNDc3NDg3OTYuNTM8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjAuMzUxNTYyNTAwMDAxNDg3MjwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4zPC9pZD4KICAgICAgICAgICAgICAgICAgICAgICAgPHNjYWxlRGVub21pbmF0b3I+NzM4NzQzOTguMjY1PC9zY2FsZURlbm9taW5hdG9yPgogICAgICAgICAgICAgICAgICAgICAgICA8cmVzb2x1dGlvbj4wLjE3NTc4MTI1MDAwMDc0MzY8L3Jlc29sdXRpb24+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvbGV2ZWw+PGxldmVsPgogICAgICAgICAgICAgICAgICAgICAgICA8aWQ+NDwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjM2OTM3MTk5LjEzMjU8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjAuMDg3ODkwNjI1MDAwMzcxODwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD41PC9pZD4KICAgICAgICAgICAgICAgICAgICAgICAgPHNjYWxlRGVub21pbmF0b3I+MTg0Njg1OTkuNTY2MjU8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjAuMDQzOTQ1MzEyNTAwMTg1OTwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD42PC9pZD4KICAgICAgICAgICAgICAgICAgICAgICAgPHNjYWxlRGVub21pbmF0b3I+OTIzNDI5OS43ODMxMjU8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjAuMDIxOTcyNjU2MjUwMDkyOTU8L3Jlc29sdXRpb24+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvbGV2ZWw+PGxldmVsPgogICAgICAgICAgICAgICAgICAgICAgICA8aWQ+NzwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjQ2MTcxNDkuODkxNTYyNTwvc2NhbGVEZW5vbWluYXRvcj4KICAgICAgICAgICAgICAgICAgICAgICAgPHJlc29sdXRpb24+MC4wMTA5ODYzMjgxMjUwNDY0NzU8L3Jlc29sdXRpb24+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvbGV2ZWw+PGxldmVsPgogICAgICAgICAgICAgICAgICAgICAgICA8aWQ+ODwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjIzMDg1NzQuOTQ1NzgxMjU8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjAuMDA1NDkzMTY0MDYyNTIzMjM3NTwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD45PC9pZD4KICAgICAgICAgICAgICAgICAgICAgICAgPHNjYWxlRGVub21pbmF0b3I+MTE1NDI4Ny40NzI4OTA2MjU8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjAuMDAyNzQ2NTgyMDMxMjYxNjE4NzwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4xMDwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjU3NzE0My43MzY0NDUzMTI1PC9zY2FsZURlbm9taW5hdG9yPgogICAgICAgICAgICAgICAgICAgICAgICA8cmVzb2x1dGlvbj4wLjAwMTM3MzI5MTAxNTYzMDgwOTQ8L3Jlc29sdXRpb24+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvbGV2ZWw+PGxldmVsPgogICAgICAgICAgICAgICAgICAgICAgICA8aWQ+MTE8L2lkPgogICAgICAgICAgICAgICAgICAgICAgICA8c2NhbGVEZW5vbWluYXRvcj4yODg1NzEuODY4MjIyNjU2MjU8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjAuMDAwNjg2NjQ1NTA3ODE1NDA0NzwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4xMjwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjE0NDI4NS45MzQxMTEzMjgxMzwvc2NhbGVEZW5vbWluYXRvcj4KICAgICAgICAgICAgICAgICAgICAgICAgPHJlc29sdXRpb24+MC4wMDAzNDMzMjI3NTM5MDc3MDIzNDwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4xMzwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjcyMTQyLjk2NzA1NTY2NDA2PC9zY2FsZURlbm9taW5hdG9yPgogICAgICAgICAgICAgICAgICAgICAgICA8cmVzb2x1dGlvbj4wLjAwMDE3MTY2MTM3Njk1Mzg1MTE3PC9yZXNvbHV0aW9uPgogICAgICAgICAgICAgICAgICAgICAgICA8L2xldmVsPjxsZXZlbD4KICAgICAgICAgICAgICAgICAgICAgICAgPGlkPjE0PC9pZD4KICAgICAgICAgICAgICAgICAgICAgICAgPHNjYWxlRGVub21pbmF0b3I+MzYwNzEuNDgzNTI3ODMyMDM8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjguNTgzMDY4ODQ3NjkyNTU5ZS0wNTwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4xNTwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjE4MDM1Ljc0MTc2MzkxNjAxNjwvc2NhbGVEZW5vbWluYXRvcj4KICAgICAgICAgICAgICAgICAgICAgICAgPHJlc29sdXRpb24+NC4yOTE1MzQ0MjM4NDYyNzllLTA1PC9yZXNvbHV0aW9uPgogICAgICAgICAgICAgICAgICAgICAgICA8L2xldmVsPjxsZXZlbD4KICAgICAgICAgICAgICAgICAgICAgICAgPGlkPjE2PC9pZD4KICAgICAgICAgICAgICAgICAgICAgICAgPHNjYWxlRGVub21pbmF0b3I+OTAxNy44NzA4ODE5NTgwMDg8L3NjYWxlRGVub21pbmF0b3I+CiAgICAgICAgICAgICAgICAgICAgICAgIDxyZXNvbHV0aW9uPjIuMTQ1NzY3MjExOTIzMTM5NmUtMDU8L3Jlc29sdXRpb24+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvbGV2ZWw+PGxldmVsPgogICAgICAgICAgICAgICAgICAgICAgICA8aWQ+MTc8L2lkPgogICAgICAgICAgICAgICAgICAgICAgICA8c2NhbGVEZW5vbWluYXRvcj40NTA4LjkzNTQ0MDk3OTAwNDwvc2NhbGVEZW5vbWluYXRvcj4KICAgICAgICAgICAgICAgICAgICAgICAgPHJlc29sdXRpb24+MS4wNzI4ODM2MDU5NjE1Njk4ZS0wNTwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4xODwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjIyNTQuNDY3NzIwNDg5NTAyPC9zY2FsZURlbm9taW5hdG9yPgogICAgICAgICAgICAgICAgICAgICAgICA8cmVzb2x1dGlvbj41LjM2NDQxODAyOTgwNzg0OWUtMDY8L3Jlc29sdXRpb24+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvbGV2ZWw+PGxldmVsPgogICAgICAgICAgICAgICAgICAgICAgICA8aWQ+MTk8L2lkPgogICAgICAgICAgICAgICAgICAgICAgICA8c2NhbGVEZW5vbWluYXRvcj4xMTI3LjIzMzg2MDI0NDc1MTwvc2NhbGVEZW5vbWluYXRvcj4KICAgICAgICAgICAgICAgICAgICAgICAgPHJlc29sdXRpb24+Mi42ODIyMDkwMTQ5MDM5MjQ2ZS0wNjwvcmVzb2x1dGlvbj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbD48bGV2ZWw+CiAgICAgICAgICAgICAgICAgICAgICAgIDxpZD4yMDwvaWQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDxzY2FsZURlbm9taW5hdG9yPjU2My42MTY5MzAxMjIzNzU1PC9zY2FsZURlbm9taW5hdG9yPgogICAgICAgICAgICAgICAgICAgICAgICA8cmVzb2x1dGlvbj4xLjM0MTEwNDUwNzQ1MTk2MjNlLTA2PC9yZXNvbHV0aW9uPgogICAgICAgICAgICAgICAgICAgICAgICA8L2xldmVsPgogICAgICAgICAgICAgICAgICAgICAgPC9sZXZlbHM+CiAgICAgICAgICAgICAgICAgICAgPC90aWxlTWF0cml4U2V0PgogICAgICAgICAgICAgICAgICA8L3RpbGVNYXRyaXhTZXRzPgogICAgICAgICAgICAgICAgPC9tYXBsYXllcj4KICAgICAgICAgICAgICA8L3Byb2plY3RsYXllcnM+CiAgICAgICAgICAgIDwvZG1hcD4KICAgICAgICAgICAg"
  57 + print('解码:' + str(base64.b64decode(kk), "utf-8"))
... ...
注册登录 后发表评论