Django REST Framework入门之序列化器

news2024/11/26 2:51:04

文章目录

  • 一、概述
  • 二、安装
  • 三、序列化与反序列化介绍
  • 四、之前常用三种序列化方式
    • json
    • Django内置Serializers模块
    • Django内置JsonResponse模块
  • 五、DRF序列化器
    • 序列化器工作流程
      • 序列化(读数据)
      • 反序列化(写数据)
    • 序列化器常用方法与属性
    • 序列化器参数
    • 扩展验证规则
      • 局部钩子:validate_字段名(self, 字段值)
      • 全局钩子:validate(self, 所有校验的数据字典)
    • 序列化器支持三种类型:
      • Serializer
        • 创建应用myapp
        • 注册myapp
        • 定义数据模型并同步数据库
        • 定义序列化器
        • 视图里使用序列化器
        • 定义路由
        • 启动项目
        • 实现POST方法
        • 获取单个用户
        • 更新用户
        • 删除用户
      • `ModelSerializer[推荐使用]`
        • Meta类常用属性
        • 示例
      • HyperModelSerializer
    • 关联表显示
      • 定义数据模型(myapp/models.py)
      • 定义序列化器(myapp/serializers.py)
      • 定义视图(myapp/views.py)
      • 定义路由(myapp/urls.py)
      • 创建数据库表
      • 启动Django项目
      • 插入测试数据
      • 显示外键对应的详细信息
        • 方法一
        • 方法二
    • 序列化器:SerializerMethodField
      • 示例:给项目API增加一个字段,这个字段数据可从别的表中获取
    • 改变序列化和反序列化的行为
      • 示例1:
      • 示例2:希望给返回的数据添加一个统计应用数量的字段
  • 参考


一、概述

Django REST framework (简称:DRF)是一个强大而灵活的 Web API 工具。遵循RESTFullAPI风格,功能完善。

能简化序列化及开发REST API视图的代码,大大提高REST API的开发速度;提供灵活的路由API,内置了强大的认证和授权机制

二、安装

Django REST framework 最新版使用要求
在这里插入图片描述

pip install djangorestframework

在settings.py文件的INSTALLED_APPS添加rest_framework
在这里插入图片描述

三、序列化与反序列化介绍

序列化:将python对象转json
反序列化:将json转为python对象

四、之前常用三种序列化方式

json

import json
# 序列化
computer = {"主机":5000,"显示器":1000,"鼠标":60,"键盘":150}
json.dumps(computer)
# 反序列化
json.loads(json_obj)

Django内置Serializers模块

是Django内置的一个序列化器,可直接将Python QuerySet对象转为JSON格式,但不支持反序列化

from django.core import serializers
obj = User.objects.all()
data = serializers.serialize('json'
, obj)

Django内置JsonResponse模块

JsonResponse模块自动将Python对象转为JSON对象并响应。

res = {"code": 200, msg: "查询成功"}
return JsonResponse(res)

五、DRF序列化器

DRF中有一个serializers模块专门负责数据序列化,DRF提供的方案更先进、更高级别的序列化方案。

序列化器工作流程

序列化(读数据)

视图里通过ORM从数据库获取数据查询集对象 -> 传入序列化器-> 序列化器将数据进行序列化 -> 调用序列化器的.data获取数据 -> 返回前端

反序列化(写数据)

视图获取前端提交的数据 -> 传入序列化器 -> 调用序列化器的.is_valid方法进行效验 -> 调用序列化器的.save()方法保存数据

序列化器常用方法与属性

  • serializer.is_valid():调用序列化器验证是否通过,传入raise_exception=True可以在验证失败时由DRF响应400异常。
  • serializer.errors:获取反序列化器验证的错误信息
  • serializer.data:获取序列化器返回的数据
  • serializer.save():将验证通过的数据保存到数据库(ORM操作)

序列化器参数

在这里插入图片描述
示例:

class UserSerializer(serializers.Serializer):
    # 这里的字段必须与使用模型的字段对应
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=30,
                                 error_messages={ # 设置错误提示
                                     "blank": "请输入姓名",
                                     "required": "该字段必要",
                                     "max_length": "字符长度不超过30",
                                 })

扩展验证规则

如果常用参数无法满足验证要求时,可通过钩子方法扩展验证规则

局部钩子:validate_字段名(self, 字段值)

class UserSerializer(serializers.Serializer):
	…………
	# 局部钩子
    # 姓名不能包含数字
    def validate_name(self, attrs): # attrs是该字段的值
        from re import findall
        if findall('\d+', attrs):
            raise serializers.ValidationError("姓名不能包含数字")
        else:
            return attrs

在视图函数里面通过如下方法查看异常信息

user_ser = UserSerializer(data=request.data)
print(user_ser.errors)

效果如下:
在这里插入图片描述

全局钩子:validate(self, 所有校验的数据字典)

class UserSerializer(serializers.Serializer):
	…………
    # 全局钩子
    def validate(self, attrs):  # attrs是所有字段组成的字典
    sex = attrs.get("sex")
    if sex not in ['男','女']:
        raise serializers.ValidationError("性别只能为男或者女")
    else:
        return attrs

序列化器支持三种类型:

• Serializer:对Model(数据模型)进行序列化,需自定义字段映射。
• ModelSerializer:对Model进行序列化,会自动生成字段和验证规则,默认还包含简单的create()和update()方法。
• HyperlinkedModelSerializer:与ModelSerializer类似,只不过使用超链接来表示关系而不是主键ID

Serializer

创建应用myapp
python manage.py startapp myapp
注册myapp

在settings.py文件的INSTALLED_APPS添加myapp
在这里插入图片描述

定义数据模型并同步数据库

myapp/models.py

from django.db import models

# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=30)
    city = models.CharField(max_length=30)
    sex = models.CharField(max_length=10)
    age = models.IntegerField()

python manage.py makemigrations
python manage.py migrate

定义序列化器

创建myapp_api/serializers.py

from rest_framework import serializers

class UserSerializer(serializers.Serializer):
    # 这里的字段必须与使用模型的字段对应
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=30)
    city = serializers.CharField(max_length=30)
    sex = serializers.CharField(max_length=10)
    age = serializers.IntegerField()
视图里使用序列化器
from myapp.models import User   # 导入模型
from .serializers import UserSerializer # 导入序列化器
from rest_framework.views import APIView
from rest_framework.response import Response

class UserView(APIView):
    def get(self, requset):
        queryset = User.objects.all()   # 获取所有用户
        # 调用序列化器将queryset对象转换为json
        user_ser = UserSerializer(queryset, many=True)  # 如果序列化多条数据,需要指定many=True
        return Response(user_ser.data)  # 从.data属性获取序列化结果
定义路由

test01(项目名)/urls.py

from django.contrib import admin
from django.urls import path,re_path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('myapp/', include('myapp.urls')),
]

myapp_api/urls.py

from django.urls import re_path
from myapp import views

urlpatterns = [
    re_path('^api/user/$', views.UserView.as_view()),
]
启动项目

访问地址:http://127.0.0.1:8001/myapp/api/user/,可以查看数据
在这里插入图片描述
现在数据库是空的,下面写一个POST方法,来实现数据的创建

实现POST方法

myapp/views.py,在class UserView的get方法下面增加post方法

def post(self, request):
    user_ser = UserSerializer(data=request.data)    # 调用序列化器将传入的数据反序列化,转换为Python对象
    if user_ser.is_valid():     # 验证数据格式是否正确
        user_ser.save()         # 保存数据到数据库
        msg = '创建用户成功'
        code = 200
    else:
        msg = '数据格式不正确'
        code = 400
    res = {'code': code, 'msg': msg}
    return Response(res)

在myapp/serializers.py下面增加如下方法

from myapp.models import User
def create(self, validated_data):   # validated_data为提交的JSON数据
    return User.objects.create(**validated_data)

在这里插入图片描述
刷新页面,发现下面多了个输入框,右下角有POST按钮
输入JSON数据,点击POST
在这里插入图片描述
返回创建成功
在这里插入图片描述
再次查看发现多了条数据
在这里插入图片描述
再添加几条数据,结果如下
在这里插入图片描述
上面的方法是查看所有用户,那么如何查看单个用户呢?

获取单个用户

修改myapp/views.py中的get方法为:

def get(self, requset, pk=None):
    if pk:
        user_obj = User.objects.get(id=pk)  # 获取单个用户数据
        user_ser = UserSerializer(user_obj)
    else:
        queryset = User.objects.all()   # 获取所有用户
        # 调用序列化器将queryset对象转换为json
        user_ser = UserSerializer(queryset, many=True)  # 如果序列化多条数据,需要指定many=True
    res = {'code': 200, 'msg': '获取用户成功', 'data': user_ser.data}
    return Response(res)  # 从.data属性获取序列化结果

myapp/urls.py增加如下路由

re_path('^api/user/(?P<pk>\d+)/$', views.UserView.as_view()),

在这里插入图片描述
效果
在这里插入图片描述

更新用户

myapp/views.py,在class UserView的get方法下面增加put方法

def put(self, request, pk=None):
    user_obj = User.objects.get(id=pk)  # 从数据库查找现有的值
    #调用序列化器传入已有对象和提交的数据
    user_ser = UserSerializer(instance=user_obj, data=request.data)
    if user_ser.is_valid():
        user_ser.save()
        msg = '更新用户成功'
        code = 200
    else:
        msg = '更新用户失败,数据格式不对'
        code = 400
    res = {'code': code, 'msg': msg}
    return Response(res)

在myapp/serializers.py下面增加如下方法

def update(self, instance, validated_data):     # instance为当前操作的对象,validated_data为提交JSON数据
    instance.name = validated_data.get('name')
    instance.city = validated_data.get('city')
    instance.sex = validated_data.get('sex')
    instance.age = validated_data.get('age')
    instance.save()
    return instance

实际效果
在这里插入图片描述

删除用户

myapp/views.py,在class UserView的get方法下面增加delete方法

def delete(self, request, pk=None):
    user_obj = User.objects.get(id=pk)
    try:
        user_obj.delete()
        msg = '用户删除成功'
        code = 200
    except Exception as e:
        msg = '用户删除失败'
        code = 400
    res = {'code': code, 'msg': msg}
    return Response(res)

效果
在这里插入图片描述

ModelSerializer[推荐使用]

ModelSerializer 类型不需要自定义字段映射和定义create、update方法,使用起来方便很多!

Meta类常用属性

• fields:显示所有或指定字段
• exclude:排除某个字段,元组格式,不能与fields同时用
• read_only_fields:只读字段,即只用于序列化,不支持修改
• extra_kwargs:添加或修改原有的字段参数,字典格式
• depth:根据关联的数据递归显示,一般是多表

示例
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User    # 指定数据模型
        fields = '__all__'  # 显示所有字段
        #exclude = ('id', )  # 排除字段
        read_only_fields = ('id', )
        extra_kwargs = {
            'name': {'max_length': 30, 'requierd': True},
            'city': {'max_length': 10, 'requierd': True},
            'age': {'max_length': 30, 'requierd': True},
            'sex': {'mix_value': 16, 'max_value': 100, 'requierd': True},
        }

HyperModelSerializer

与MedelSerializer使用方法一样。只不过它使用超链接来表示关系而不是主键ID。

# 更改序列化器
class UserSerializer(serializers.HyperlinkedModelSerializer):
	class Meta:
		model = User
		fields = "__all__"
# 更改视图
user_ser = UserSerializer(queryset, many=True, context={'request': request})
# 更改路由
re_path('^api/user/$', views.UserView.as_view(), name="user-detail"),
re_path('^api/user/(?P<pk>\d+)/$', views.UserView.as_view(), name="user-detail")

关联表显示

例如:应用发布系统项目涉及表
一对多:一个项目有多个应用,一个应用只能属于一个项目
多对多:一个应用部署到多台服务器,一个服务器部署多个应用
在这里插入图片描述

定义数据模型(myapp/models.py)

from django.db import models

# 项目表
class Project(models.Model):
    name = models.CharField(max_length=30)

# 应用表
class App(models.Model):
    name = models.CharField(max_length=30)
    project = models.ForeignKey(Project, on_delete=models.CASCADE)  # 一对多

# 服务器表
class Server(models.Model):
    hostname = models.CharField(max_length=30)
    ip = models.GenericIPAddressField()
    app = models.ManyToManyField(App)   # 多对多

定义序列化器(myapp/serializers.py)

from rest_framework import serializers
from myapp.models import Project, App, Server

class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = "__all__"

class AppSerializer(serializers.ModelSerializer):
    class Meta:
        model = App
        fields = "__all__"

class ServerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Server
        fields = "__all__"

定义视图(myapp/views.py)

from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.models import Project, App, Server
from .serializers import ProjectSerializer, AppSerializer, ServerSerializer

class ProjectView(APIView):
    def get(self, request):
        queryset = Project.objects.all()  # 获取所有用户
        project_ser = ProjectSerializer(queryset, many=True)
        res = {'code': 200, 'msg': '获取用户成功', 'data': project_ser.data}
        return Response(res)  # 从.data属性获取序列化结果
    def post(self, requset):
        project_ser = ProjectSerializer(data=requset.data)
        project_ser.is_valid(raise_exception=True)
        project_ser.save()
        return Response(data=project_ser.data)

class AppView(APIView):
    def get(self, request):
        queryset = App.objects.all()  # 获取所有用户
        app_ser = AppSerializer(queryset, many=True)
        res = {'code': 200, 'msg': '获取用户成功', 'data': app_ser.data}
        return Response(res)  # 从.data属性获取序列化结果
    def post(self, requset):
        app_ser = AppSerializer(data=requset.data)
        app_ser.is_valid(raise_exception=True)
        app_ser.save()
        return Response(data=app_ser.data)

class ServerView(APIView):
    def get(self, request):
        queryset = Server.objects.all()  # 获取所有用户
        server_ser = AppSerializer(queryset, many=True)
        res = {'code': 200, 'msg': '获取用户成功', 'data': server_ser.data}
        return Response(res)  # 从.data属性获取序列化结果
    def post(self, requset):
        server_ser = ServerSerializer(data=requset.data)
        server_ser.is_valid(raise_exception=True)
        server_ser.save()
        return Response(data=server_ser.data)

定义路由(myapp/urls.py)

from django.urls import re_path
from myapp import views

urlpatterns = [
    re_path('^api/project/$', views.ProjectView.as_view()),
    re_path('^api/app/$', views.AppView.as_view()),
    re_path('^api/server/$', views.ServerView.as_view()),
]

创建数据库表

python manage.py makemigrations
python manage.py migrate

启动Django项目

插入测试数据

打开python控制台
在这里插入图片描述

#创建项目:
from myapp.models import Project, App, Server
Project.objects.create(name="电商")
Project.objects.create(name="教育")
#创建应用并指定项目:
project_obj = Project.objects.get(name="电商")
App.objects.create(name="portal", project=project_obj)
App.objects.create(name="gateway", project=project_obj)
#创建服务器:
Server.objects.create(hostname="test1", ip="192.168.31.10")
Server.objects.create(hostname="test2", ip="192.168.31.11")
#将应用部署到服务器:
app_obj = App.objects.get(name="portal")
server_obj = Server.objects.get(hostname="test1")
server_obj.app.add(app_obj)

结果如下:
在这里插入图片描述

显示外键对应的详细信息

序列化器返回的是当前模型中的字段,如果字段是外键时,返回的是外键对应id。如下图所示
在这里插入图片描述
有两种解决方法

方法一

定义字段为外键对应序列化类,这种适合针对某个外键字段
例如:

project=ProjectSerializer(read_only=True)	# 一对多
app = AppSerializer(many=True) # 多对多

在这里插入图片描述

方法二

序列化类中Meta类启用depth:深度获取关联表数据,这种所有外键都会显示出来
在这里插入图片描述
效果如下:
在这里插入图片描述

序列化器:SerializerMethodField

DRF序列化器默认仅返回数据模型中已存在资源,如果想新增返回字段或者二次处理,该
如何操作呢?用SerializerMethodFiled

示例:给项目API增加一个字段,这个字段数据可从别的表中获取

class ProjectSerializer(serializers.ModelSerializer):
    app_count = serializers.SerializerMethodField
    class Meta:
        model = Project
        fields = "__all__"

    # get_字段名
    def get_app_count(self, obj):
        return len(obj.app_get.all())

改变序列化和反序列化的行为

可以通过重写下面两个方法改变序列化和反序列化的行为:
• to_internal_value():处理反序列化的输入数据,自动转换Python对象,方便处理。
• to_representation():处理序列化数据的输出

示例1:

如果提交API的数据与序列化器要求的格式不符合,序列化器就会出现错误。
这时就可以重写to_internal_value()方法只提取出我们需要的数据
在这里插入图片描述

示例2:希望给返回的数据添加一个统计应用数量的字段

在这里插入图片描述

参考

https://www.aliangedu.cn/course/learn?cid=20&sid=10&pid=2197

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Node 创建 Web 服务器

Node.js 提供了 http 模块&#xff0c;http 模块主要用于搭建 HTTP 服务端和客户端&#xff0c;使用 HTTP 服务器或客户端功能必须调用 http 模块&#xff0c;代码如下&#xff1a; var http require(http); 以下是演示一个最基本的 HTTP 服务器架构(使用 8080 端口)&#x…

acwing讲解篇之94. 递归实现排列型枚举

文章目录 题目描述题解思路题解代码 题目描述 题解思路 定义递归深度deep&#xff0c;数字使用情况used&#xff0c;选择的数字顺序path 进行递归 终止条件为递归深度达到n层时&#xff0c;打印path&#xff0c;然后返回 深度加一 遍历未使用的数字&#xff0c;选择数字&am…

web架构师编辑器内容-编辑器组件图层面板功能开发-锁定隐藏、键盘事件功能的开发

我们这一部分主要是对最右侧图层面板功能进行剖析&#xff0c;完成对应的功能的开发: 每个图层都对应编辑器上面的元素&#xff0c;有多少个元素就对应多少个图层&#xff0c;主要的功能如下&#xff1a; 锁定功能&#xff1a;点击锁定&#xff0c;在编辑器中没法编辑对应的组…

Elasticsearch的映射操作

本文来记录下Elasticsearch的映射操作 文章目录 映射的概述 映射的概述 Elasticsearch与mysql数据库对比 映射的概述 有了索引库&#xff0c;等于有了数据库中的 database。索引库(index)中的映射&#xff0c;类似于数据库(database)中的表结构(table)。创建数据库表需要设置字…

3、非数值型的分类变量

非数值型的分类变量 有很多非数字的数据,这里介绍如何使用它来进行机器学习。 在本教程中,您将了解什么是分类变量,以及处理此类数据的三种方法。 本课程所需数据集夸克网盘下载链接:https://pan.quark.cn/s/9b4e9a1246b2 提取码:uDzP 文章目录 1、简介2、三种方法的使用1…

Flutter 与 Android原生 相互通信:BasicMessageChannel、MethodChannel、EventChannel

前言 本文主要讲解&#xff0c;使用不同的 Channel 让 Flutter 和 Android原生 进行通信&#xff0c;由于只是讲解两端通信&#xff0c;所以可视化效果不好&#xff1b; 不过我写了一篇专门讲解 Flutter 嵌入 Android原生View的文章 Flutter 页面嵌入 Android原生 View-CSDN…

小程序使用echarts图表-雷达图

本文介绍下小程序中如何使用echarts 如果是通过npm安装&#xff0c;这样是全部安装的&#xff0c;体积有点大 我这边是使用echarts中的一个组件来实现的&#xff0c;下边是具体流程&#xff0c;实际效果是没有外边的红色边框的&#xff0c;加红色边框的效果是这篇说明 1.echa…

精品基于Uniapp+springboot疫情防控管理系统App

《[含文档PPT源码等]精品基于Uniappspringboot疫情防控管理系统App》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 后台框架&#xff1a;springboot、ssm …

keil软件仿真

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要…

Excel 根据日期按月汇总公式

Excel 根据日期按月汇总公式 数据透视表日期那一列右击&#xff0c;选择“组合”&#xff0c;步长选择“月” 参考 Excel 根据日期按月汇总公式Excel如何按着日期来做每月求和

Centos 8 安装 Elasticsearch

简介&#xff1a;CentOS 8是一个基于Red Hat Enterprise Linux&#xff08;RHEL&#xff09;源代码构建的开源操作系统。它是一款稳定、可靠、安全的服务器操作系统&#xff0c;适合用于企业级应用和服务的部署。CentOS 8采用了最新的Linux内核和软件包管理系统&#xff0c;提供…

测试覆盖与矩阵

4. Coverage - 衡量测试的覆盖率 我们已经掌握了如何进行单元测试。接下来&#xff0c;一个很自然的问题浮现出来&#xff0c;我们如何知道单元测试的质量呢&#xff1f;这就提出了测试覆盖率的概念。覆盖率测量通常用于衡量测试的有效性。它可以显示您的代码的哪些部分已被测…

【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

创建自定义的IOCTL&#xff08;输入/输出控制&#xff09;或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。 一、IOCTL 方法 1. 定义IOCTL命令 在内核模块中&#xff0c;需要使用宏定义你的IOCTL命令。通常情况下&#xff0c;IOCTL命令…

【js】js 异步机制详解 Generator / Async / Promise

三种语法功能放在一起&#xff0c;是因为他们都有相似特点&#xff1a; 维护某种状态在未来恢复状态并执行 本文重点回答以下几个问题&#xff1a; 为什么 Generator 和 Async 函数的 代码执行流 都可以简化成树形结构&#xff1f;async 函数为什么返回一个 promise&#xf…

关于常见分布式组件高可用设计原理的理解和思考

文章目录 1. 数据存储场景和存储策略1.1 镜像模式-小规模数据1.2 分片模式-大规模数据 2. 数据一致性和高可用问题2.1 镜像模式如何保证数据一致性2.2 镜像模式如何保证数据高可用2.2.1 HA模式2.2.2 分布式选主模式 2.3 分片模式如何数据一致性和高可用 3. 大规模数据集群的架构…

Qt事件过滤

1.相关说明 监控鼠标进入组件、出组件、点击组件、双击组件的事件&#xff0c;需要重写eventFilter函数 2.相关界面 3.相关代码 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-&…

【MySQL】一文总结MVCC多版本并发控制

目录 MVCC 介绍当前读和快照读当前读快照读 MVCC 原理解析隐式字段Undo Log版本链Read ViewRead View 可见性原则 RC 和 RR 下的 Read ViewRC 下的 Read ViewRR 下的 Read View小结RR 级别下能否防止幻读总结 MVCC 介绍 在当今高度并发的数据库环境中&#xff0c;有效的并发控…

【Python学习】Python学习21- 正则表达式(1)

目录 【Python学习】Python学习21- 正则表达式&#xff08;1&#xff09; 前言re.match函数实例 re.search方法re.match与re.search的区别参考 文章所属专区 Python学习 前言 本章节主要说明Python的正则表达式。 正则表达式是一个特殊的字符序列&#xff0c;它能帮助你方便的…

鸿蒙 HarmonyOS ArkTS ArkUI 动画 中心缩放、顶部缩放、纵向缩放

EntryComponentstruct Index {State widthA: number 200State heightA: number 200onPageShow():void{animateTo ( {duration: 2000,iterations: -1,curve:Curve.Linear}, () > {this.widthA 0this.heightA 0} )}build() {Column() {// 中心缩放Column(){}.width(this.wi…

Golang 搭建 WebSocket 应用(八) - 完整代码

本文应该是本系列文章最后一篇了&#xff0c;前面留下的一些坑可能后面会再补充一下&#xff0c;但不在本系列文章中了。 整体架构 再来回顾一下我们的整体架构&#xff1a; 在我们的 demo 中&#xff0c;包含了以下几种角色&#xff1a; 客户端&#xff1a;一般是浏览器&am…