Python 框架学习 Django篇 (六) 数据表关联、ORM关联

在后端服务器开发中,特别是前后端分离的架构中数据库是非常重要的,后端主要就是负责管理数据,而我们经常使用的mysql、oracle 都是关系型数据库,什么是关系型数据库?就是建立在关系模型基础上的数据库,而最难处理的就是各个表之间的关联关系,一般这种关系分为三种: 一对一 、一对多、多对多

 一、数据表关联

1、一对多

表之间以对多的关系就是数据库中的 "外键"  ,下面我们举个例子,比如一个医药系统中肯定会有客户的信息吧,我们先定义一个客户的基本信息(客户名称、联系电话、居住地址)

  vi Django_demo/paas/models.py

class Customer(models.Model):
    # 客户名称
    name = models.CharField(max_length=200)

    # 联系电话
    phonenumber = models.CharField(max_length=200)

    # 地址
    address = models.CharField(max_length=200)

我们是一个医药系统,肯定存在很多不同的药品类型,同样也需要定义一个药品类型的表

Medicine药品表 ,包含一些(药品名称、编号、描述信息)

  vi Django_demo/paas/models.py

class Medicine(models.Model):
    # 药品名
    name = models.CharField(max_length=200)
    # 药品编号
    sn = models.CharField(max_length=200)
    # 描述
    desc = models.CharField(max_length=200)

有了药品信息、客户信息,那么只要存在销售的话就一定会有订单信息

想一想,我们订单的信息是不是和上面的两张表多少有一些关联,比如订单中需要用到客户信息和药品信息

在实际观察中,我们发现订单表里面会同时需要拿到上面两张表中的数据,在下图中我们可以看到一个客户同时可能会有多个订单,这种情况就是一对多,或者说多对一

 

像是这种一对多的关系,在数据库中是以外键形式表示的,如果说一个表中的字段是外键,那么他的值一定来源与其他表的主键

另外,我们定义表的 Model类的时候,如果没有指定主键字段,migrate 的时候 Django 会为该Model对应的数据库表自动生成一个id字段,作为主键

#导入数据库
python manage.py makemigrations
python manage.py migrate 

#查看
desc paas_customer;

现在我们要生成订单表,按照实际情况我们订单表的字段里面也会有客户的信息表示谁下的订单,而用户的信息需要使用外键去关联客户的主键,而客户表也就是customer表的主键就是id字段,Django中定义外键 的方法就是 Model类的该属性字段 值为(ForeignKey)

 vi Django_demo/paas/models.py

import datetime
class Order(models.Model):
    # 订单名
    name = models.CharField(max_length=200,null=True,blank=True)

    # 创建日期
    create_date = models.DateTimeField(default=datetime.datetime.now)

    # 客户
    customer = models.ForeignKey(Customer,on_delete=models.PROTECT)

上面定义的customer是外键,让他去找Customer表的主键获取数据,而这里设置了一个on_delete的参数,这个意思是当主键被删除了那么外键这个数据还要不要了

1、CASCADE: 跟随主机一起把外键数据删除

2、PROTECT   禁止删除,如果非要删除就先清除外键数据后,才能删除对应主键

3、SET_NULL   删除后外键数据修改为null

注意

      外键字段,实际在数据库表中的字段名是DjangoForeignKey定义字段名加上后缀"_id"

比如上面,在执行了 migrate 命令更新数据库后,customer 这个外键字段实际上在 数据库表中的字段名 是 customer_id

python manage.py makemigrations
python manage.py migrate 

#查看
desc paas_info;

返回

mysql> desc paas_order;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | bigint       | NO   | PRI | NULL    | auto_increment |
| name        | varchar(200) | YES  |     | NULL    |                |
| create_date | datetime(6)  | NO   |     | NULL    |                |
| customer_id | bigint       | NO   | MUL | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

2、一对一

上面的外键案例,可以说是一对多或者多对一,而有时候是一对一的情况

比如,某个学校的学生表 和学生的地址表,就形成一对一的关系,即 一条主键所在表的记录 只能对应一条 外键所在表的记录,而Django 中 用 OneToOneField 对象 实现 一对一 的关系

 vi Django_demo/paas/models.py

class Student(models.Model):
    # 姓名
    name = models.CharField(max_length=200)
    # 班级
    classname = models.CharField(max_length=200)
    # 描述
    desc = models.CharField(max_length=200)


class ContactAddress(models.Model):
    # 一对一 对应学生 
    student = models.OneToOneField(Student, on_delete=models.PROTECT)
    # 家庭
    homeaddress = models.CharField(max_length=200)
    # 电话号码
    phone = models.CharField(max_length=200)

 Django发现这样一对一定定义,它会在migrate的时候,在数据库中定义该字段为外键的同时, 加上 unique=True 约束,表示在此表中,所有记录的该字段 取值必须唯一,不能重复

 3、多对多

数据库中还存在一种多对多的关系,在order订单表中

一个订单可以采购多种药品,就对应 Medicine表里面的多种药品;

而一种药品也可以被多个订单采购, 那么Order表 和 Medicine表 之间就形成了多对多的关系

 

 Django是通过 ManyToManyField 对象 表示 多对多的关系的

 vi Django_demo/paas/models.py

import datetime
class Order(models.Model):
    # 订单名
    name = models.CharField(max_length=200,null=True,blank=True)

    # 创建日期
    create_date = models.DateTimeField(default=datetime.datetime.now)

    # 客户
    customer = models.ForeignKey(Customer,on_delete=models.PROTECT)

    # 订单购买的药品,和Medicine表是多对多 的关系
    medicines = models.ManyToManyField(Medicine, through='OrderMedicine')

class OrderMedicine(models.Model):
    #添加外键
    order = models.ForeignKey(Order, on_delete=models.PROTECT)
    medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT)

    # 订单中药品的数量  一种特殊的类型,表示非负整数
    amount = models.PositiveIntegerField()  

我们上面通过medicines = models.ManyToManyField(Medicine, through='OrderMedicine')

去指定Order表和Medicine表的对应关系,其实不会在Order表上面创建medicines的字段

python manage.py makemigrations
python manage.py migrate 

#查看
desc paas_OrderMedicine;

 

4、管理药品实现

我们在 mgr 目录下面新建 medicine.py,处理 客户端发过来的 列出药品、添加药品、修改药品、删除药品 的请求,需要运用前面的数据库增删改查的方法

vi Django_demo/mgr/medicine.py

from django.http import JsonResponse

# 导入 Medicine 对象定义(这块可能显示模块导入不正常,忽略)
from  paas.models import  Medicine

import json

def Orderdispatcher(request):
    # 根据session判断用户是否是登录的管理员用户
    if 'usertype' not in request.session:
        return JsonResponse({
            'ret': 302,
            'msg': '未登录',
            'redirect': '/mgr/sign.html'},
            status=302)

    if request.session['usertype'] != 'mgr':
        return JsonResponse({
            'ret': 302,
            'msg': '用户非mgr类型',
            'redirect': '/mgr/sign.html'},
            status=302)


    # 将请求参数统一放入request 的 params 属性中,方便后续处理

    # GET请求 参数 在 request 对象的 GET属性中
    if request.method == 'GET':
        request.params = request.GET

    # POST/PUT/DELETE 请求 参数 从 request 对象的 body 属性中获取
    elif request.method in ['POST','PUT','DELETE']:
        # 根据接口,POST/PUT/DELETE 请求的消息体都是 json格式
        request.params = json.loads(request.body)


    # 根据不同的action分派给不同的函数进行处理
    action = request.params['action']
    if action == 'list_medicine':
        return listmedicine(request)
    elif action == 'add_medicine':
        return addmedicine(request)
    elif action == 'modify_medicine':
        return modifymedicine(request)
    elif action == 'del_medicine':
        return deletemedicine(request)

    else:
        return JsonResponse({'ret': 1, 'msg': '不支持该类型http请求'})



def listmedicine(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Medicine.objects.values()

    # 将 QuerySet 对象 转化为 list 类型
    # 否则不能 被 转化为 JSON 字符串
    retlist = list(qs)

    return JsonResponse({'ret': 0, 'retlist': retlist})


def addmedicine(request):

    info    = request.params['data']

    # 从请求消息中 获取要添加客户的信息
    # 并且插入到数据库中
    medicine = Medicine.objects.create(name=info['name'] ,
                                       sn=info['sn'] ,
                                       desc=info['desc'])


    return JsonResponse({'ret': 0, 'id':medicine.id})


def modifymedicine(request):

    # 从请求消息中 获取修改客户的信息
    # 找到该客户,并且进行修改操作

    medicineid = request.params['id']
    newdata    = request.params['newdata']

    try:
        # 根据 id 从数据库中找到相应的客户记录
        medicine = Medicine.objects.get(id=medicineid)
    except Medicine.DoesNotExist:
        return  {
            'ret': 1,
            'msg': f'id 为`{medicineid}`的药品不存在'
        }


    if 'name' in  newdata:
        medicine.name = newdata['name']
    if 'sn' in  newdata:
        medicine.sn = newdata['sn']
    if 'desc' in  newdata:
        medicine.desc = newdata['desc']

    # 注意,一定要执行save才能将修改信息保存到数据库
    medicine.save()

    return JsonResponse({'ret': 0})


def deletemedicine(request):

    medicineid = request.params['id']

    try:
        # 根据 id 从数据库中找到相应的药品记录
        medicine = Medicine.objects.get(id=medicineid)
    except Medicine.DoesNotExist:
        return  {
            'ret': 1,
            'msg': f'id 为`{medicineid}`的客户不存在'
        }

    # delete 方法就将该记录从数据库中删除了
    medicine.delete()

    return JsonResponse({'ret': 0})




添加路由

vi Django_demo/mgr/urls.py

from django.urls import path

from .k8s import dispatcher
from .sign_in_out import signin,signout

from .medicine import orderdispatcher  #添加
urlpatterns = [
    path('customers/', dispatcher),
    path('medicines/', orderdispatcher),  #添加 必须带斜杠

    path('signin', signin),
    path('signout', signout),


]

5、添加药品

vi main.py

import  requests,pprint

#添加认证
payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')




# 构建添加 客户信息的 消息体,是json格式
payload = {
    "action":"add_medicine",
    "data":{
        "name":"板蓝根",
        "sn":"133",
        "desc":"感冒药"
    }
}
url='http://127.0.0.1:8000/api/mgr/medicines/'
if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送请求给web服务
    response = requests.post(url,json=payload,headers=headers)
    pprint.pprint(response.json())

json类型说明

刚才上面我们使用了查询和添加数据,但是发现一个问题,两个请求传参的时候稍有不同

#data=payload  表示这个请求携带的参数是以表单的形式也就是字符串形式传输给后端的
requests.post(url,data=payload)


#json=payload   表示参数是以json的形式传输给后端的
requests.post(url,json=payload)

在使用时要特别注意,我卡了半天才看到。。

6、查询药品

vi main.py

import  requests,pprint

payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')
if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送带有Cookie的新请求 修改url到新的路由
    response = requests.get('http://127.0.0.1:8000/api/mgr/medicines/?action=list_medicine',headers=headers)
    pprint.pprint(response.json())

返回

{'ret': 0,
 'retlist': [{'desc': '192.168.1.2', 'id': 1, 'name': 'abc', 'sn': '133'},
             {'desc': '感冒药', 'id': 2, 'name': '板蓝根', 'sn': '133'}]}

第一行是我写错了添加上的,一会当作删除的案例

遇到的问题

在访问url的时候,要确定url访问时是否需要带上/  如果定义的urls上有/,那边必须要带上斜杠不然会报错

7、修改药品

vi main.py

import  requests,pprint

#添加认证
payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')




# 构建添加 客户信息的 消息体,是json格式
payload = {
    "action":"modify_medicine",
    "id": "1",
    "newdata":{
        "name":"诺氟沙星",
        "sn":"141",
        "desc":"无"
    }
}
url='http://127.0.0.1:8000/api/mgr/medicines/'

if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送请求给web服务
    response = requests.post(url,json=payload,headers=headers)
    pprint.pprint(response.json())

再次查询

{'ret': 0,
 'retlist': [{'desc': '无', 'id': 1, 'name': '诺氟沙星', 'sn': '141'},
             {'desc': '感冒药', 'id': 2, 'name': '板蓝根', 'sn': '133'}]}

8、删除药品

import  requests,pprint

#添加认证
payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')




# 构建添加 客户信息的 消息体,是json格式
payload = {
    "action":"del_medicine",
    "id":"1",
}
url='http://127.0.0.1:8000/api/mgr/medicines/'

if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送请求给web服务
    response = requests.post(url,json=payload,headers=headers)
    pprint.pprint(response.json())

 返回

{'ret': 0, 'retlist': [{'desc': '感冒药', 'id': 2, 'name': '板蓝根', 'sn': '133'}]}

可以看到除了查询以外,增加、修改、删除的操作基本是一致的,只需要修改携带参数中的动作以及传入的参数值即可

二、数据库关联操作(sql)

1、一对多

#先查询用户的id,然后基于id查询外键对应的订单
select * from paas_order where customer_id = (select id from paas_customer where name = "zhangsan");

一对多,我们查询指定的一个客户id,然后基于id去订单表中获取所以用户相关的订单

2、多对多

我们上面使用的时候添加过这么一个表  OrderMedicine 

class OrderMedicine(models.Model):
    #添加外键
    order = models.ForeignKey(Order, on_delete=models.PROTECT)
    medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT)

    # 订单中药品的数量  一种特殊的类型,表示非负整数
    amount = models.PositiveIntegerField()  

多对多,表示什么意思呢,我们建立的上面的表是将order订单表 和Medicine药品表进行关联的一个中间表,我们在给前面两张表添加数据的时候,还需要单独去给中间表添加一次数据,用来声明订单和药品的关系,通过这张中间表,我们就能查询药品是那些客户进行购买,也可以查询那些客户购买了那些药品,我们做一个案例

 Django_demo/mgr/admin.py

from  paas.models import Customer,Medicine,Order,OrderMedicine
admin.site.register([Customer,Medicine,Order,OrderMedicine])

 访问admin页面,前面我们添加了很多的数据除了客户表信息以外都先删除一下

 

我们先给Medicines药品表  和orders 订单表 添加一条信息

 

上面给药品添加了感冒颗粒,订单表中给张三用户添加了一个test的订单 ,现在是没有任何关联机制的,这两张表也没有交互,我们在order medicines表中添加下两个订单的关联

 我们关联了第一条数据,将刚才的订单信息和药品信息以及数量一并放入到了中间表中

mysql> select * from paas_ordermedicine;
+----+--------+-------------+----------+
| id | amount | medicine_id | order_id |
+----+--------+-------------+----------+
|  1 |     10 |           6 |        5 |
+----+--------+-------------+----------+
1 row in set (0.00 sec)

 这里因为存放了药品的id和订单的id,我们就可以根据这个表来查询关联的数据信息,比如我想要看看订单表里面test订单对应下单了什么药品,买了多少

#找到订单中的id
select id from paas_order where name = "test";


#基于id查询关系表中药品
select medicine_id,amount  from paas_ordermedicine where order_id = 5;


#命令组合
mysql> select medicine_id,amount  from paas_ordermedicine where order_id = (select id from paas_order where name = "test");
+-------------+--------+
| medicine_id | amount |
+-------------+--------+
|           6 |     10 |
+-------------+--------+
1 row in set (0.00 sec)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/107847.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

android studio启动Task配置

Android studio 高版本默认不开启Task配置,需要自己手动开启 1.低版本配置路径:(复制他人图片) 2.高版本路径:添加下图勾选配置即可 3.gradle task 3.1 初识task gradle中所有的构建工作都是由task完成的,它帮我们处…

Ubuntu中查看电脑有多少个核——lscpu

1. 使用lscpu命令: 打开终端并输入以下命令: lscpu你会看到与CPU相关的详细信息。查找"CPU(s)"这一行来看总的核心数。另外,“Core(s) per socket”表示每个插槽或每个物理CPU的核数,“Socket(s)”表示物理CPU的数量。将这两个值相乘即得到总…

重要环节不可忽视,CSS性能优化引领用户体验!

🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 一、前…

Java 浅拷贝会带来的问题

Java 浅拷贝会带来的问题 一,常见问题 Java 中的浅拷贝是指在对象拷贝时,只复制对象的引用,而不是对象本身。这意味着浅拷贝会导致多个对象共享同一块内存空间,当一个对象修改共享内存时,其他对象也会受到影响。 下…

ArcGIS笔记13_利用ArcGIS制作岸线与水深地形数据?建立水动力模型之前的数据收集与处理?

本文目录 前言Step 1 岸线数据Step 2 水深地形数据Step 3 其他数据及资料 前言 在利用MIKE建立水动力模型(详见【MIKE水动力笔记】系列)之前,需要收集、处理和制作诸多数据和资料,主要有岸线数据、水深地形数据、开边界潮位驱动数…

Ajax学习笔记第三天

做决定之前仔细考虑,一旦作了决定就要勇往直前、坚持到底! 【1 ikunGG邮箱注册】 整个流程展示: 1.文件目录 2.页面效果展示及代码 mysql数据库中的初始表 2.1 主页 09.html:里面代码部分解释 display: inline-block; 让块元素h1变成行内…

美颜SDK集成指南:为应用添加视频美颜功能

随着社交媒体和直播应用的兴起,视频美颜功能已成为用户追求的一项热门特性。用户希望能够在拍摄照片或进行实时视频直播时,使用美颜功能来增强其外观。为了满足这一需求,开发者可以考虑集成美颜SDK,为其应用增加这一吸引人的功能。…

【Docker】Python Flask + Redis 练习

一、构建flask镜像 1.准备文件 创建app.py,内容如下 from flask import Flask from redis import Redis app Flask(__name__) redis Redis(hostos.environ.get(REDIS_HOST,127.0.0.1),port6379)app.route(/) def hello():redis.incr(hits)return f"Hello Container W…

融云AIGC专题:高知识密度与大数据处理双向奔赴的「金融大模型」

融云出海方案全线升级 点击上方小程序报名「爱嗨游」线上发布会 “怎么用大语言模型去提升生产效率和服务表现?”在时代交替之际,这是每个行业都要回答的问题。关注【融云 RongCloud】,了解协同办公平台更多干货。 而新技术的渗透不会在所有…

Kibana功能栏中找不到Timelion功能模块的解决

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

echarts中横向柱状图的数字在条纹上方

实现效果: 数字在条纹的上方 实现方法:这些数字是用新添加一个坐标轴来实现的 直接添加坐标轴数字显示是在条纹的正右边 所以需要配置一下偏移 完整代码 var option {grid: {left: "3%",right: "4%",bottom: "3%",cont…

【工具问题】IDEA每次关闭的时候都会弹框显示closing project,然后弹框持续很久就像卡住了

idea关闭的时候出现问题 问题展示为什么会出现这种情况怎么解决 问题展示 我idea已经关闭了,但是这个弹框要持续很久才能关闭 为什么会出现这种情况 我的plugins原本是加载不出来的,所以我按照网上说法去做 怎么解决 file->setting,再如图选择…

HBuilderX代码变量名称翻译插件

对于许多开发者而言,怎么规范的命名变量是一个非常痛苦的事,而在HBuilderX中有一个的插件可以快速的帮助你完成中文转带格式的变量名,格式可以选择小驼峰、大驼峰、下划线、常量、CSS类名等。 以下为添加此插件的步骤 1、打开插件安装 选择…

Unity Spine 指定导入新Spine动画的默认材质

指定导入新Spine动画的默认材质 找到Spine的Editor导入配置如何修改方法一: 你可以通过脚本 去修改Assets/Editor/SpineSettings.asset文件方法二:通过面板手动设置 找到Spine的Editor导入配置 通常在 Assets/Editor/SpineSettings.asset 配置文件对应着 Edit/Prefe…

【机器学习合集】优化目标与评估指标合集 ->(个人学习记录笔记)

文章目录 优化目标与评估指标1. 优化目标1.1 两类基础任务与常见优化目标1.2 分类任务损失0-1损失交叉熵损失与KL散度softmax损失的理解与改进Hinge损失 1.3 回归任务损失L1/L2距离L1/L2距离的改进 Huber loss 2. 评测指标2.1 分类任务中评测指标准确率(查准率)/召回率(查全率)…

037-第三代软件开发-系统音量设置

第三代软件开发-系统音量设置 文章目录 第三代软件开发-系统音量设置项目介绍系统音量设置QML 实现C 实现 总结一下 关键字: Qt、 Qml、 volume、 声音、 GPT 项目介绍 欢迎来到我们的 QML & C 项目!这个项目结合了 QML(Qt Meta-Obj…

bitlocker 加密锁定的固态硬盘,更换到别的电脑上,怎么把原密钥写进新电脑TPM芯片内,开启无需手动填密钥

环境: Win11 专业版 联想E14笔记本 512G ssd 问题描述: 一台笔记本因充电故障,需要拿去维修,不想重装系统,将bitlocker 加密锁定的固态硬盘拆下更换到别的笔记本电脑上,现在开机要手动填密钥,怎么把原密钥写进新电脑TPM芯片内,开启无需手动填密钥和之前那台电脑一…

Mybatis基础

文章目录 Mybatis基础XML语言概述使用Mybatis配置Mybatis增删改查复杂查询事务操作动态 SQLifchoose、when、otherwise 缓存机制注解开发 Mybatis基础 虽然我们能够通过JDBC来连接和操作数据库,但是哪怕只是完成一个SQL语句的执行,都需要编写大量的代码…

Unity性能优化一本通

文章目录 关于Unity性能优化一、资源部分:1、图片1.1、 图片尺寸越小越好1.2、使用2N次幂大小1.3、取消勾选Read/Write Enabled1.4、图片压缩1.5、禁用多余的Mip Map1.6、合并图集 2、模型2.1.限制模型面数2.2.限制贴图的大小2.3.禁用Read/Write Enables2.4.不勾选其…

使用Selenium和Java编写爬虫程序

以下是一个使用Selenium和Java编写的音频爬虫程序,该程序使用了proxy的代码。请注意,这个示例需要在IDE中运行,并且可能需要根据您的系统和需求进行调整。 import java.io.IOException; import java.util.List; import java.util.concurrent…
最新文章