• Python+requests+unittest+excel实现接口自动化测试框架


    一、框架结构:

     工程目录

    二、Case文件设计

    三、基础包 base

    3.1 封装get/post请求(runmethon.py)

    1. 1 import requests
    2. 2 import json
    3. 3 class RunMethod:
    4. 4 def post_main(self,url,data,header=None):
    5. 5 res = None
    6. 6 if header !=None:
    7. 7 res = requests.post(url=url,data=data,headers=header)
    8. 8 else:
    9. 9 res = requests.post(url=url,data=data)
    10. 10 return res.json()
    11. 11
    12. 12 def get_main(self,url,data=None,header=None):
    13. 13 res = None
    14. 14 if header !=None:
    15. 15 res = requests.get(url=url,data=data,headers=header,verify=False)
    16. 16 else:
    17. 17 res = requests.get(url=url,data=data,verify=False)
    18. 18 return res.json()
    19. 19
    20. 20 def run_main(self,method,url,data=None,header=None):
    21. 21 res = None
    22. 22 if method == 'Post':
    23. 23 res = self.post_main(url,data,header)
    24. 24 else:
    25. 25 res = self.get_main(url,data,header)
    26. 26 return json.dumps(res,ensure_ascii=False,sort_keys=True,indent=2

    3.2 封装mock(mock.py)

    1. 1 from mock import mock
    2. 2 #模拟mock 封装
    3. 3 def mock_test(mock_method,request_data,url,method,response_data):
    4. 4 mock_method = mock.Mock(return_value=response_data)
    5. 5 res = mock_method(url,method,request_data)
    6. 6 return res

    四、数据操作包 operation_data

    4.1 获取excel单元格中的内容(get_data.py)  

    1. 1 #coding:utf-8
    2. 2 from tool.operation_excel import OperationExcel
    3. 3 import data_config
    4. 4 from tool.operation_json import OperetionJson
    5. 5 from tool.connect_db import OperationMysql
    6. 6 class GetData:
    7. 7 def __init__(self):
    8. 8 self.opera_excel = OperationExcel()
    9. 9
    10. 10 #去获取excel行数,就是case的个数
    11. 11 def get_case_lines(self):
    12. 12 return self.opera_excel.get_lines()
    13. 13
    14. 14 #获取是否执行
    15. 15 def get_is_run(self,row):
    16. 16 flag = None
    17. 17 col = int(data_config.get_run())
    18. 18 run_model = self.opera_excel.get_cell_value(row,col)
    19. 19 if run_model == 'yes':
    20. 20 flag = True
    21. 21 else:
    22. 22 flag = False
    23. 23 return flag
    24. 24
    25. 25 #是否携带header
    26. 26 def is_header(self,row):
    27. 27 col = int(data_config.get_header())
    28. 28 header = self.opera_excel.get_cell_value(row,col)
    29. 29 if header != '':
    30. 30 return header
    31. 31 else:
    32. 32 return None
    33. 33
    34. 34 #获取请求方式
    35. 35 def get_request_method(self,row):
    36. 36 col = int(data_config.get_run_way())
    37. 37 request_method = self.opera_excel.get_cell_value(row,col)
    38. 38 return request_method
    39. 39
    40. 40 #获取url
    41. 41 def get_request_url(self,row):
    42. 42 col = int(data_config.get_url())
    43. 43 url = self.opera_excel.get_cell_value(row,col)
    44. 44 return url
    45. 45
    46. 46 #获取请求数据
    47. 47 def get_request_data(self,row):
    48. 48 col = int(data_config.get_data())
    49. 49 data = self.opera_excel.get_cell_value(row,col)
    50. 50 if data == '':
    51. 51 return None
    52. 52 return data
    53. 53
    54. 54 #通过获取关键字拿到data数据
    55. 55 def get_data_for_json(self,row):
    56. 56 opera_json = OperetionJson()
    57. 57 request_data = opera_json.get_data(self.get_request_data(row))
    58. 58 return request_data
    59. 59
    60. 60 #获取预期结果
    61. 61 def get_expcet_data(self,row):
    62. 62 col = int(data_config.get_expect())
    63. 63 expect = self.opera_excel.get_cell_value(row,col)
    64. 64 if expect == '':
    65. 65 return None
    66. 66 return expect
    67. 67
    68. 68 #通过sql获取预期结果
    69. 69 def get_expcet_data_for_mysql(self,row):
    70. 70 op_mysql = OperationMysql()
    71. 71 sql = self.get_expcet_data(row)
    72. 72 res = op_mysql.search_one(sql)
    73. 73 return res.decode('unicode-escape')
    74. 74
    75. 75 def write_result(self,row,value):
    76. 76 col = int(data_config.get_result())
    77. 77 self.opera_excel.write_value(row,col,value)
    78. 78
    79. 79 #获取依赖数据的key
    80. 80 def get_depend_key(self,row):
    81. 81 col = int(data_config.get_data_depend())
    82. 82 depent_key = self.opera_excel.get_cell_value(row,col)
    83. 83 if depent_key == "":
    84. 84 return None
    85. 85 else:
    86. 86 return depent_key
    87. 87
    88. 88 #判断是否有case依赖
    89. 89 def is_depend(self,row):
    90. 90 col = int(data_config.get_case_depend())
    91. 91 depend_case_id = self.opera_excel.get_cell_value(row,col)
    92. 92 if depend_case_id == "":
    93. 93 return None
    94. 94 else:
    95. 95 return depend_case_id
    96. 96
    97. 97 #获取数据依赖字段
    98. 98 def get_depend_field(self,row):
    99. 99 col = int(data_config.get_field_depend())
    100. 100 data = self.opera_excel.get_cell_value(row,col)
    101. 101 if data == "":
    102. 102 return None
    103. 103 else:
    104. 104 return data

    4.2 获取excel中每个列(data_config.py)

    1. 1 #coding:utf-8
    2. 2 class global_var:
    3. 3 #case_id
    4. 4 Id = '0'
    5. 5 request_name = '1'
    6. 6 url = '2'
    7. 7 run = '3'
    8. 8 request_way = '4'
    9. 9 header = '5'
    10. 10 case_depend = '6'
    11. 11 data_depend = '7'
    12. 12 field_depend = '8'
    13. 13 data = '9'
    14. 14 expect = '10'
    15. 15 result = '11'
    16. 16 #获取caseid
    17. 17 def get_id():
    18. 18 return global_var.Id
    19. 19
    20. 20 #获取url
    21. 21 def get_url():
    22. 22 return global_var.url
    23. 23
    24. 24 def get_run():
    25. 25 return global_var.run
    26. 26
    27. 27 def get_run_way():
    28. 28 return global_var.request_way
    29. 29
    30. 30 def get_header():
    31. 31 return global_var.header
    32. 32
    33. 33 def get_case_depend():
    34. 34 return global_var.case_depend
    35. 35
    36. 36 def get_data_depend():
    37. 37 return global_var.data_depend
    38. 38
    39. 39 def get_field_depend():
    40. 40 return global_var.field_depend
    41. 41
    42. 42 def get_data():
    43. 43 return global_var.data
    44. 44
    45. 45 def get_expect():
    46. 46 return global_var.expect
    47. 47
    48. 48 def get_result():
    49. 49 return global_var.result
    50. 50
    51. 51 def get_header_value():
    52. 52 return global_var.header

    4.3 解决数据依赖(dependent.py )

    1. 1 #coding:utf-8
    2. 2 import sys
    3. 3 import json
    4. 4 sys.path.append('C:/Users/lxz/Desktop/InterFace_JIA')
    5. 5 from tool.operation_excel import OperationExcel
    6. 6 from base.runmethod import RunMethod
    7. 7 from operation_data.get_data import GetData
    8. 8 from jsonpath_rw import jsonpath,parse
    9. 9 class DependdentData:
    10. 10 def __init__(self,case_id):
    11. 11 self.case_id = case_id
    12. 12 self.opera_excel = OperationExcel()
    13. 13 self.data = GetData()
    14. 14
    15. 15 #通过case_id去获取该case_id的整行数据
    16. 16 def get_case_line_data(self):
    17. 17 rows_data = self.opera_excel.get_rows_data(self.case_id)
    18. 18 return rows_data
    19. 19
    20. 20 #执行依赖测试,获取结果
    21. 21 def run_dependent(self):
    22. 22 run_method = RunMethod()
    23. 23 row_num = self.opera_excel.get_row_num(self.case_id)
    24. 24 request_data = self.data.get_data_for_json(row_num)
    25. 25 #header = self.data.is_header(row_num)
    26. 26 method = self.data.get_request_method(row_num)
    27. 27 url = self.data.get_request_url(row_num)
    28. 28 res = run_method.run_main(method,url,request_data)
    29. 29 return json.loads(res)
    30. 30
    31. 31 #根据依赖的key去获取执行依赖测试case的响应,然后返回
    32. 32 def get_data_for_key(self,row):
    33. 33 depend_data = self.data.get_depend_key(row)
    34. 34 response_data = self.run_dependent()
    35. 35 json_exe = parse(depend_data)
    36. 36 madle = json_exe.find(response_data)
    37. 37 return [math.value for math in madle][0]
    38. 38
    39. 39 if __name__ == '__main__':
    40. 40 order = {
    41. 41 "data": {
    42. 42 "_input_charset": "utf-8",
    43. 43 "body": "京东订单-1710141907182334",
    44. 44 "it_b_pay": "1d",
    45. 45 "notify_url": "http://order.imooc.com/pay/notifyalipay",
    46. 46 "out_trade_no": "1710141907182334",
    47. 47 "partner": "2088002966755334",
    48. 48 "payment_type": "1",
    49. 49 "seller_id": "yangyan01@tcl.com",
    50. 50 "service": "mobile.securitypay.pay",
    51. 51 "sign": "kZBV53KuiUf5HIrVLBCcBpWDg%2FnzO%2BtyEnBqgVYwwBtDU66Xk8VQUTbVOqDjrNymCupkVhlI%2BkFZq1jOr8C554KsZ7Gk7orC9dDbQl pr%2BaMmdjO30JBgjqjj4mmM%2Flphy9Xwr0Xrv46uSkDKdlQqLDdGAOP7YwOM2dSLyUQX%2Bo4%3D",
    52. 52 "sign_type": "RSA",
    53. 53 "string": "_input_charset=utf-8&body=京东订单-1710141907182334&it_b_pay=1d¬ify_url=http://order.imooc.com/pay/ notifyalipay&out_trade_no=1710141907182334&partner=2088002966755334&payment_type=1&seller_id=yangyan01@ tcl.com&service=mobile.securitypay.pay&subject=京东订单-1710141907182334&total_fee=299&sign=kZBV53KuiUf5H IrVLBCcBpWDg%2FnzO%2BtyEnBqgVYwwBtDU66Xk8VQUTbVOqDjrNymCupkVhlI%2BkFZq1jOr8C554KsZ7Gk7orC9dDbQlpr%2BaMmdjO30 JBgjqjj4mmM%2Flphy9Xwr0Xrv46uSkDKdlQqLDdGAOP7YwOM2dSLyUQX%2Bo4%3D&sign_type=RSA",
    54. 54 "subject": "京东订单-1710141907182334",
    55. 55 "total_fee": 299
    56. 56 },
    57. 57 "errorCode": 1000,
    58. 58 "errorDesc": "成功",
    59. 59 "status": 1,
    60. 60 "timestamp": 1507979239100
    61. 61 }
    62. 62 res = "data.out_trade_no"
    63. 63 json_exe = parse(res)
    64. 64 madle = json_exe.find(order)
    65. 65 print [math.value for math in madle][0]

    五、工具类包 tool5.1 操作excel (operation_excel.py)

    1. 1 #coding:utf-8
    2. 2 import xlrd
    3. 3 from xlutils.copy import copy
    4. 4 class OperationExcel:
    5. 5 def __init__(self,file_name=None,sheet_id=None):
    6. 6 if file_name:
    7. 7 self.file_name = file_name
    8. 8 self.sheet_id = sheet_id
    9. 9 else:
    10. 10 self.file_name = '../dataconfig/case1.xls'
    11. 11 self.sheet_id = 0
    12. 12 self.data = self.get_data()
    13. 13
    14. 14 #获取sheets的内容
    15. 15 def get_data(self):
    16. 16 data = xlrd.open_workbook(self.file_name)
    17. 17 tables = data.sheets()[self.sheet_id]
    18. 18 return tables
    19. 19
    20. 20 #获取单元格的行数
    21. 21 def get_lines(self):
    22. 22 tables = self.data
    23. 23 return tables.nrows
    24. 24
    25. 25 #获取某一个单元格的内容
    26. 26 def get_cell_value(self,row,col):
    27. 27 return self.data.cell_value(row,col)
    28. 28
    29. 29 #写入数据
    30. 30 def write_value(self,row,col,value):
    31. 31 '''
    32. 32 写入excel数据
    33. 33 row,col,value
    34. 34 '''
    35. 35 read_data = xlrd.open_workbook(self.file_name)
    36. 36 write_data = copy(read_data)
    37. 37 sheet_data = write_data.get_sheet(0)
    38. 38 sheet_data.write(row,col,value)
    39. 39 write_data.save(self.file_name)
    40. 40
    41. 41 #根据对应的caseid 找到对应行的内容
    42. 42 def get_rows_data(self,case_id):
    43. 43 row_num = self.get_row_num(case_id)
    44. 44 rows_data = self.get_row_values(row_num)
    45. 45 return rows_data
    46. 46
    47. 47 #根据对应的caseid找到对应的行号
    48. 48 def get_row_num(self,case_id):
    49. 49 num = 0
    50. 50 clols_data = self.get_cols_data()
    51. 51 for col_data in clols_data:
    52. 52 if case_id in col_data:
    53. 53 return num
    54. 54 num = num+1
    55. 55
    56. 56
    57. 57 #根据行号,找到该行的内容
    58. 58 def get_row_values(self,row):
    59. 59 tables = self.data
    60. 60 row_data = tables.row_values(row)
    61. 61 return row_data
    62. 62
    63. 63 #获取某一列的内容
    64. 64 def get_cols_data(self,col_id=None):
    65. 65 if col_id != None:
    66. 66 cols = self.data.col_values(col_id)
    67. 67 else:
    68. 68 cols = self.data.col_values(0)
    69. 69 return cols
    70. 70
    71. 71
    72. 72 if __name__ == '__main__':
    73. 73 opers = OperationExcel()
    74. 74 print opers.get_cell_value(1,2)

    5.2判断字符串包含,判断字典是否相等(common_util.py)

    1. 1 #coding:utf-8
    2. 2 import json
    3. 3 class CommonUtil:
    4. 4 def is_contain(self,str_one,str_two):
    5. 5 '''
    6. 6 判断一个字符串是否再另外一个字符串中
    7. 7 str_one:查找的字符串
    8. 8 str_two:被查找的字符串
    9. 9 '''
    10. 10 flag = None
    11. 11 if isinstance(str_one,unicode):
    12. 12 str_one = str_one.encode('unicode-escape').decode('string_escape')
    13. 13 return cmp(str_one,str_two)
    14. 14 if str_one in str_two:
    15. 15 flag = True
    16. 16 else:
    17. 17 flag = False
    18. 18 return flag
    19. 19
    20. 20
    21. 21 def is_equal_dict(self,dict_one,dict_two):
    22. 22 '''
    23. 23 判断两个字典是否相等
    24. 24 '''
    25. 25 if isinstance(dict_one,str):
    26. 26 dict_one = json.loads(dict_one)
    27. 27 if isinstance(dict_two,str):
    28. 28 dict_two = json.loads(dict_two)
    29. 29 return cmp(dict_one,dict_two)

    5.3 操作header(operation_herder.py)

    1. 1 #coding:utf-8
    2. 2 import requests
    3. 3 import json
    4. 4 from operation_json import OperetionJson
    5. 5
    6. 6
    7. 7 class OperationHeader:
    8. 8
    9. 9 def __init__(self,response):
    10. 10 self.response = json.loads(response)
    11. 11
    12. 12 def get_response_url(self):
    13. 13 '''
    14. 14 获取登录返回的token的url
    15. 15 '''
    16. 16 url = self.response['data']['url'][0]
    17. 17 return url
    18. 18
    19. 19 def get_cookie(self):
    20. 20 '''
    21. 21 获取cookie的jar文件
    22. 22 '''
    23. 23 url = self.get_response_url()+"&callback=jQuery21008240514814031887_1508666806688&_=1508666806689"
    24. 24 cookie = requests.get(url).cookies
    25. 25 return cookie
    26. 26
    27. 27 def write_cookie(self):
    28. 28 cookie = requests.utils.dict_from_cookiejar(self.get_cookie())
    29. 29 op_json = OperetionJson()
    30. 30 op_json.write_data(cookie)
    31. 31
    32. 32 if __name__ == '__main__':
    33. 33
    34. 34 url = "http://www.jd.com/passport/user/login"
    35. 35 data = {
    36. 36 "username":"18513199586",
    37. 37 "password":"111111",
    38. 38 "verify":"",
    39. 39 "referer":"https://www.jd.com"
    40. 40 }
    41. 41 res = json.dumps(requests.post(url,data).json())
    42. 42 op_header = OperationHeader(res)
    43. 43 op_header.write_cookie()

    5.4 操作json文件(operation_json.py)

    1. 1 #coding:utf-8
    2. 2 import json
    3. 3 class OperetionJson:
    4. 4
    5. 5 def __init__(self,file_path=None):
    6. 6 if file_path == None:
    7. 7 self.file_path = '../dataconfig/user.json'
    8. 8 else:
    9. 9 self.file_path = file_path
    10. 10 self.data = self.read_data()
    11. 11
    12. 12 #读取json文件
    13. 13 def read_data(self):
    14. 14 with open(self.file_path) as fp:
    15. 15 data = json.load(fp)
    16. 16 return data
    17. 17
    18. 18 #根据关键字获取数据
    19. 19 def get_data(self,id):
    20. 20 print type(self.data)
    21. 21 return self.data[id]
    22. 22
    23. 23 #写json
    24. 24 def write_data(self,data):
    25. 25 with open('../dataconfig/cookie.json','w') as fp:
    26. 26 fp.write(json.dumps(data))
    27. 27
    28. 28
    29. 29
    30. 30 if __name__ == '__main__':
    31. 31 opjson = OperetionJson()
    32. 32 print opjson.get_data('shop')

    5.5 操作数据库(connect_db.py)

    1. 1 #coding:utf-8
    2. 2 import MySQLdb.cursors
    3. 3 import json
    4. 4 class OperationMysql:
    5. 5 def __init__(self):
    6. 6 self.conn = MySQLdb.connect(
    7. 7 host='localhost',
    8. 8 port=3306,
    9. 9 user='root',
    10. 10 passwd='123456',
    11. 11 db='le_study',
    12. 12 charset='utf8',
    13. 13 cursorclass=MySQLdb.cursors.DictCursor
    14. 14 )
    15. 15 self.cur = self.conn.cursor()
    16. 16
    17. 17 #查询一条数据
    18. 18 def search_one(self,sql):
    19. 19 self.cur.execute(sql)
    20. 20 result = self.cur.fetchone()
    21. 21 result = json.dumps(result)
    22. 22 return result
    23. 23
    24. 24 if __name__ == '__main__':
    25. 25 op_mysql = OperationMysql()
    26. 26 res = op_mysql.search_one("select * from web_user where Name='ailiailan'")
    27. 27 print res

    5.6 发送报告邮件(send_email.py)

    1. 1 #coding:utf-8
    2. 2 import smtplib
    3. 3 from email.mime.text import MIMEText
    4. 4 class SendEmail:
    5. 5 global send_user
    6. 6 global email_host
    7. 7 global password
    8. 8 email_host = "smtp.163.com"
    9. 9 send_user = "jiaxiaonan666@163.com"
    10. 10 password = "jia_668"
    11. 11 def send_mail(self,user_list,sub,content):
    12. 12 user = "jiaxiaonan"+"<"+send_user+">"
    13. 13 message = MIMEText(content,_subtype='plain',_charset='utf-8')
    14. 14 message['Subject'] = sub
    15. 15 message['From'] = user
    16. 16 message['To'] = ";".join(user_list)
    17. 17 server = smtplib.SMTP()
    18. 18 server.connect(email_host)
    19. 19 server.login(send_user,password)
    20. 20 server.sendmail(user,user_list,message.as_string())
    21. 21 server.close()
    22. 22
    23. 23 def send_main(self,pass_list,fail_list):
    24. 24 pass_num = float(len(pass_list))
    25. 25 fail_num = float(len(fail_list))
    26. 26 count_num = pass_num+fail_num
    27. 27 #90%
    28. 28 pass_result = "%.2f%%" %(pass_num/count_num*100)
    29. 29 fail_result = "%.2f%%" %(fail_num/count_num*100)
    30. 30
    31. 31
    32. 32 user_list = ['609037724@qq.com']
    33. 33 sub = "接口自动化测试报告"
    34. 34 content = "此次一共运行接口个数为%s个,通过个数为%s个,失败个数为%s,通过率为%s,失败率为%s" %(count_num,pass_num,fail_num,pass_result,fail_result )
    35. 35 self.send_mail(user_list,sub,content)
    36. 36
    37. 37 if __name__ == '__main__':
    38. 38 sen = SendEmail()
    39. 39 sen.send_main([1,2,3,4],[2,3,4,5,6,7])

    六、主函数run_test.py

    1. 1 #coding:utf-8
    2. 2 import sys
    3. 3 sys.path.append("C:/Users/lxz/Desktop/InterFace_JIA")
    4. 4 from base.runmethod import RunMethod
    5. 5 from operation_data.get_data import GetData
    6. 6 from tool.common_util import CommonUtil
    7. 7 from operation_data.dependent_data import DependdentData
    8. 8 from tool.send_email import SendEmail
    9. 9 from tool.operation_header import OperationHeader
    10. 10 from tool.operation_json import OperetionJson
    11. 11 class RunTest:
    12. 12 def __init__(self):
    13. 13 self.run_method = RunMethod()
    14. 14 self.data = GetData()
    15. 15 self.com_util = CommonUtil()
    16. 16 self.send_mai = SendEmail()
    17. 17
    18. 18 #程序执行的
    19. 19 def go_on_run(self):
    20. 20 res = None
    21. 21 pass_count = []
    22. 22 fail_count = []
    23. 23 #10 0,1,2,3
    24. 24 rows_count = self.data.get_case_lines()
    25. 25 for i in range(1,rows_count):
    26. 26 is_run = self.data.get_is_run(i)
    27. 27 if is_run:
    28. 28 url = self.data.get_request_url(i)
    29. 29 method = self.data.get_request_method(i)
    30. 30 request_data = self.data.get_data_for_json(i)
    31. 31 expect = self.data.get_expcet_data_for_mysql(i)
    32. 32 header = self.data.is_header(i)
    33. 33 depend_case = self.data.is_depend(i)
    34. 34 if depend_case != None:
    35. 35 self.depend_data = DependdentData(depend_case)
    36. 36 #获取的依赖响应数据
    37. 37 depend_response_data = self.depend_data.get_data_for_key(i)
    38. 38 #获取依赖的key
    39. 39 depend_key = self.data.get_depend_field(i)
    40. 40 request_data[depend_key] = depend_response_data
    41. 41 if header == 'write':
    42. 42 res = self.run_method.run_main(method,url,request_data)
    43. 43 op_header = OperationHeader(res)
    44. 44 op_header.write_cookie()
    45. 45
    46. 46 elif header == 'yes':
    47. 47 op_json = OperetionJson('../dataconfig/cookie.json')
    48. 48 cookie = op_json.get_data('apsid')
    49. 49 cookies = {
    50. 50 'apsid':cookie
    51. 51 }
    52. 52 res = self.run_method.run_main(method,url,request_data,cookies)
    53. 53 else:
    54. 54 res = self.run_method.run_main(method,url,request_data)
    55. 55
    56. 56 if self.com_util.is_equal_dict(expect,res) == 0:
    57. 57 self.data.write_result(i,'pass')
    58. 58 pass_count.append(i)
    59. 59 else:
    60. 60 self.data.write_result(i,res)
    61. 61 fail_count.append(i)
    62. 62 self.send_mai.send_main(pass_count,fail_count)
    63. 63
    64. 64 #将执行判断封装
    65. 65 #def get_cookie_run(self,header):
    66. 66
    67. 67
    68. 68 if __name__ == '__main__':
    69. 69 run = RunTest()
    70. 70 run.go_on_run()

    【整整200集】超超超详细的Python接口自动化测试进阶教程合集,真实模拟企业项目实战

  • 相关阅读:
    【JavaSE】初识泛型
    RabbitMQ--基础--5.1--部署--命令
    vue3使用elementPlus进行table合并处理
    GeoNet: Unsupervised Learning of Dense Depth, Optical Flow and Camera Pose 论文阅读
    Aspose.Slides 21.11.0 For .NET Crack
    计算机毕业设计 SSM在线心理评测系统 心理咨询系统 在线心理测试系统Java Vue MySQL数据库 远程调试 代码讲解
    .NET下 支持大小写不敏感的JSON Schema验证方法
    Java Web 33道面试题汇总
    墨门云上网行为管控系统的特点和优势
    es6.x和es7.x如何创建索引?
  • 原文地址:https://blog.csdn.net/mashang123123123/article/details/133321153