十二、Django表单

news2025/7/14 15:35:35

表单

在之前的案例中,每次我们需要提交表单数据的时候。我们都需要去手动编辑html表单,根据不同的字段,字段名,进行编码。做了很多重复的部分,所以django提供了一个专门用来处理表单的类,django.forms.Form

通过它,我们不仅能够自动生成前端页面,也可以用来验证数据的合法性。我们通过改写添加修改学生的表单来学习它。

创建表单

在app根目录下,创建一个forms.py的模块,代码如下:

from django import forms
from .models import Channel


class StudentForm(forms.Form):
    name = forms.CharField(label='姓名', max_length=20)
    age = forms.IntegerField(label='年龄', required=False)
    sex = forms.ChoiceField(label='性别', choices=((1, '男'), (0, '女')))
    phone = forms.CharField(label='手机号码', required=False, max_length=20)
    channel = forms.ModelChoiceField(label='渠道', required=False, queryset=Channel.objects.all())

每一个模型表单,都是forms.Form的一个子类,类属性与模型的类属性类似,都表示不同类型的字段。不同的字段,将会渲染成不同的input类型。字段名与每一个input标签的name属性对应。

每一个字段都是一个字段类的实例,其中label参数渲染成label标签的内容。max_length用来限制用户输入字符长度。required参数表示该字段是否必填,默认为True,要指定一个字段是不必填的,设置required=False

在模板中使用表单

只需要讲表单实例放到模板上下文就可以通过模板变量使用表单。

渲染表单对象

修改学生添加页面视图如下:

from .forms import StudentForm


class StudentCreateView(View):
    """
    学生添加视图
    """
    def get(self, request):
        """学生添加页面"""
        # 1. 获取渠道对象
        channels = Channel.objects.all()
        form = StudentForm()
        return render(request, 'crm/student_detail.html', context={'channels': channels, 'form': form})

在视图中,实例化了一个表单对象,然后传递变量form给了模板。那么在模板中通过{{ form }}将会渲染对应的<label><input>元素,下面是StduentForm实例用{{from}}的输出:

<tr><th><label for="id_name">姓名:</label></th><td><input type="text" name="name" maxlength="20" required id="id_name"></td></tr>
<tr><th><label for="id_age">年龄:</label></th><td><input type="number" name="age" id="id_age"></td></tr>
<tr><th><label for="id_sex">性别:</label></th><td><select name="sex" id="id_sex">
  <option value="1">男</option>
  <option value="0">女</option>
  <option value="1">百度</option>
  <option value="2">抖音</option>
  <option value="3">b站</option>
</select></td></tr>

我们看到表单对象默认渲染了表格格式的字段,所以记住需要在模板中提供外层<form>标签和submit控件。

那么在模板中可以安装如下方式渲染:

<form >
    <talbe>
        {{ form }}
    </talbe>
    <input type="submit" value="添加" />
</form>    

对于表单字段的渲染,还有如下格式:

  • {{ form.as_table }} 字段会渲染成表格元素<tr>
  • {{ form.as_p }} 字段会渲染成<p>标签
  • {{ form.as_ul }} 字段会渲染成<li>标签

注意记得提供外层的<table><ul>元素

手动渲染字段

直接渲染表单对象,不是太灵活,我们可以手动处理。每个字段都可以用{{ form.name_of_field }}作为表单的一个属性,并被相应的渲染在模板中。例如:

{{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.subject.errors }}
    <label for="{{ form.subject.id_for_label }}">Email subject:</label>
    {{ form.subject }}
</div>
<div class="fieldWrapper">
    {{ form.message.errors }}
    <label for="{{ form.message.id_for_label }}">Your message:</label>
    {{ form.message }}
</div>
<div class="fieldWrapper">
    {{ form.sender.errors }}
    <label for="{{ form.sender.id_for_label }}">Your email address:</label>
    {{ form.sender }}
</div>
<div class="fieldWrapper">
    {{ form.cc_myself.errors }}
    <label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
    {{ form.cc_myself }}
</div>

 

 

 

完整的<label>元素还可以使用label_tag()来生成。例如:

<div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject }}
</div>

渲染表单错误信息

表单的错误信息分两种,一种是{{ form.name_of_field.errors }}显示对应字段的错误信息列表,它默认被渲染成为无序列表,看起来如下:

<ul class="errorlist">
    <li>Sender is required.</li>
</ul>

该列表有一个CSS class errorlist ,允许自定义样式。如果想要进一步定义错误信息的显示,可以通过遍历来实现:

{% if form.subject.errors %}
    <ol>
    {% for error in form.subject.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ol>
{% endif %}

第二种是{{ form.non_field_errors }}显示非字段验证错误信息,它渲染后看起来如下:

<ul class="errorlist nonfield">
    <li>Generic validation error</li>
</ul>

该列表会额外带上一个classnonfield以便与字段验证错误信息区分。

遍历表单字段

如果表单字段使用相同的结构,可以对表单对象进行迭代:

{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
        {% if field.help_text %}
        <p class="help">{{ field.help_text|safe }}</p>
        {% endif %}
    </div>
{% endfor %}

有用的字段属性:

  • {{ field.lable }}

字段的label,比如Email address

  • {{ field.label_tag }}

该字段的label标签,它包含表单的label_suffix,默认是个冒号,例如:

<label for="id_email">Email address:</label>
  • {{ field.id_for_label }}

该字段的id,用于手动构建label

  • {{ field.value }}

该字段的值

  • {{ field.html_name }}

字段名称,用于输入元素的name属性中。如果设置了表单前置,它也会被加进去。

  • {{ field.help_text }}

与该字段关联的帮助文本

  • {{ field.errors }}

输出错误信息列表

  • {{ field.is_hidden }}

如果该字段是隐藏字段,这个属性是True,否则为False

部件

每一个表单字段,都会有一个对应的HTML元素与之对应。部件用来处理HTML渲染,以及从对应的GET/POST字典中提取数据。

指定部件

每一个表单字段,django都会使用一个默认的部件来显示数据类型。要想知道哪个字段使用哪个部件,请查看内置Field类。

有时候我们可能需要修改默认的部件,通过字段参数widget来处理。例如:

from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)

字段comment将会使用Textarea部件,而不是默认的TextInput部件。

样式化部件实例

默认情况下,部件渲染的表单标签没有css类,没有额外属性。可以通过attrs参数进行设置:

class CommentForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
    url = forms.URLField()
    comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

也可以在表单定义中修改部件:

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

    name.widget.attrs.update({'class': 'special'})
    comment.widget.attrs.update(size='40')

或者如果该字段没有直接在表单上声明(比如模型表单字段),可以使用Form.fields属性:

class CommentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class': 'special'})
        self.fields['comment'].widget.attrs.update(size='40')

Django会将这写属性包含在渲染的输出中:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40" required></td></tr>

表单的校验

django中的表单除了渲染html外,还有一个很重要的作用就是校验数据。

看添加学生的视图案例:

class StudentCreateView(View):
    """
    学生添加视图
    """

    def post(self, request):
        """添加学生"""
        form = StudentForm(request.POST)
        if form.is_valid():
            obj = Student.objects.create(**form.cleaned_data)
            return redirect(reverse('student-list'))
        return render(request, 'crm/student_detail.html', context={'form': form})

实例化表单时,可以将GET/POST参数传入,然后调用表单对象的is_valid()方法进行校验。如果校验通过,这个方法会返回True,否则返回False

校验通过后通过cleaned_data属性访问干净的数据。

指定字段校验

定义表单时,可以定义方法clean_<fieldname>()方法对指定的字段进行校验,该方法不接受参数。在方法中通过self.cleaned_data获取该字段的值。

如果校验不通过需要触发一个ValidationError的异常,校验通过请return该值。

在学生创建的逻辑中,我们没有验证电话号码的格式,在表单中编写一个校验方法如下:

import re

from django import forms
from django.core.exceptions import ValidationError

from .models import Channel, Student

class StudentForm(forms.ModelForm):
    class Meta:
        model = Student  # 指定要生成表单的模型
        exclude = ['c_time']    # 指定不需要生成的字段

    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        if phone is not None:
            if not re.match(r'1[3-9]\d{9}$', phone):
                raise ValidationError('手机号码格式不正确!')
        return phone

验证相互依赖的字段

有时候需要同时校验多个字段,比如注册时,校验密码和重复密码。这时复写clean()方法是一个很好的办法:

from django import forms
from django.core.exceptions import ValidationError

class RegistorForm(forms.Form):
    # Everything as before.

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password_confirm = cleaned_data.get('password_confirm')
        if not password == password_confirm:
            raise ValidationError('输入的密码不一致!')
        return cleaned_data

在表单的clean()方法被调用前,上一节中的单字段校验方法都会先被运行。clean()方法中如果出现验证错误,在模板中使用{{form.non_field_errors}}显示。

模型表单

django提供了一个辅助类,可以从一个模型创建一个Form类,而不需要重复定义字段。

修改学生表单如下:

from django import forms
from .models import Channel, Student


class StudentForm(forms.ModelForm):
    class Meta:
        model = Student  # 指定要生成表单的模型
        exclude = ['c_time']    # 指定不需要生成的字段

每一个模型表单都是forms.ModelForm的一个子类,和普通表单不同。由于模型已经定义了字段,在模型表单中,只需要在Meta类中指定模型和字段。

字段可以通过属性fields=['field1', 'field2', ..]指定需要的字段,fields='all'表示生成所有的字段, 也可以通过exclude = ['field1', 'field2', ..]排除字段。

save()

模型表单与普通的表单还有一个不同就是save()方法。在校验过的表单实例上调用save()方法,会自动调用对应的模型在数据库中创建数据或修改数据。

学生添加案例:

class StudentCreateView(View):
    """
    学生添加视图
    """

    def post(self, request):
        """添加学生"""
        # 实例化表单
        form = StudentForm(request.POST)
        # 校验
        if form.is_valid():
            # 保存数据
            form.save()
            return redirect(reverse('student-list'))
        return render(request, 'crm/student_detail.html', context={'form': form})

上面的代码中,如果表单校验通过,执行form.save()会创建返回Student实例并保存到数据库。

学生更新案例:

class StudentUpdateView(View):
    """
    学生更新视图
    """

    def get_obj(self, pk):
        obj = get_object_or_404(Student, pk=pk)
        return obj

    def get(self, request, pk):
        # 1. 获取修改对象
        obj = self.get_obj(pk)
        # 2. 实例化表单对象,并填充模型对象
        form = StudentForm(instance=obj)
        # 2. 渲染并返回修改页面
        return render(request, 'crm/student_detail.html', context={'form': form})

    def post(self, request, pk):
        # 1. 获取修改对象
        obj = self.get_obj(pk)
        # 2. 实例化表单对象,填充前端传递的数据和模型对象
        form = StudentForm(request.POST, instance=obj)
        # 3. 校验
        if form.is_valid():
            form.save()     # 保存更新
            return redirect(reverse('student-list'))
        return render(request, 'crm/student_detail.html', context={'form': form})

上面的代码中实例化表单时传递POST参数,同时把要更新的模型对象传给instance参数,在校验通过后,执行form.save()会使用校验后的参数更新模型对象。

学生创建,更新视图案例

表单

# crm/froms.py
import re

from django import forms
from django.core.exceptions import ValidationError

from .models import Student


class StudentForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name in self.fields:
            self.fields[name].widget.attrs.update({'class': 'form-control'})

    class Meta:
        model = Student  # 指定要生成表单的模型
        exclude = ['c_time']    # 指定不需要生成的字段

    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        if not re.match(r'1[3-9]\d{9}$', phone):
            raise ValidationError('手机号码格式不正确!')
        return phone

视图

# crm/views.py
class StudentCreateView(View):
    """
    学生添加视图
    """
    def get(self, request):
        """学生添加页面"""
        # 1. 获取渠道对象
        channels = Channel.objects.all()
        form = StudentForm()
        return render(request, 'crm/student_detail.html', context={'channels': channels, 'form': form})

    def post(self, request):
        """添加学生"""
        form = StudentForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect(reverse('student-list'))
        return render(request, 'crm/student_detail.html', context={'form': form})


class StudentUpdateView(View):
    """
    学生更新视图
    """

    def get_obj(self, pk):
        obj = get_object_or_404(Student, pk=pk)
        return obj

    def get(self, request, pk):
        # 1. 获取修改对象
        obj = self.get_obj(pk)
        # 2. 实例化表单对象,并填充模型对象
        form = StudentForm(instance=obj)
        # 2. 渲染并返回修改页面
        return render(request, 'crm/student_detail.html', context={'form': form})

    def post(self, request, pk):
        # 1. 获取修改对象
        obj = self.get_obj(pk)
        # 2. 实例化表单对象,填充前端传递的数据和模型对象
        form = StudentForm(request.POST, instance=obj)
        # 3. 校验
        if form.is_valid():
            form.save()     # 保存更新
            return redirect(reverse('student-list'))
        return render(request, 'crm/student_detail.html', context={'form': form})

模板

<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>{% if obj %}修改{% else %}添加{% endif %}学生</title>

    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
          integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">

    <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
    <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
    <!--[if lt IE 9]>
    <![endif]-->
</head>
<body>
<div class="container">
    <div style="width: 800px">
        <h1>学生{% if obj %}修改{% else %}添加{% endif %}页面</h1>
        <form class="form-horizontal" method="post">
            {% for field in form %}
                <div class="form-group {% if field.errors %}has-error{% endif %}">
                    <label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
                    <div class="col-sm-10">
                        {{ field }}
                        {% for error in field.errors %}
                            <span class="help-block">{{ error }}</span>
                        {% endfor %}
                    </div>
                </div>
            {% endfor %}

            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <button type="submit" class="btn btn-default">{% if form.instance %}修改{% else %}
                        添加{% endif %}</button>
                </div>
            </div>
        </form>
    </div>
</div>


<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"
        integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ"
        crossorigin="anonymous"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"
        integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
        crossorigin="anonymous"></script>
</body>
</html>

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

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

相关文章

23年PMP真的值得考吗?分析+资料分享

我觉得&#xff0c;如过是真的想学习项目管理&#xff0c;或者工作要求考PMP&#xff0c;招聘要求又的确“PMP证书”优先&#xff0c;那考一个是划算的&#xff0c;毕竟在项目管理这一块&#xff0c;PMP是专业和知名度最高的证书了。 它是由美国项目管理协会(PMI)在全球范围内推…

Java 给视频添加背景音乐 | Java工具

目录 前言 Maven依赖 环境依赖 代码 总结 前言 本文提供给视频添加背景音乐的java工具&#xff0c;一如既往的实用主义。 Maven依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1.1…

Towards Efficient Adversarial Training on Vision Transformers

视觉转换器(ViT)作为卷积神经网络(CNN)的有力替代方案&#xff0c;受到了广泛的关注。最近的研究表明&#xff0c;vit也容易受到cnn等对抗实例的攻击。为了构建健壮的vit&#xff0c;一种直观的方法是应用对抗性训练&#xff0c;因为它已被证明是实现健壮cnn的最有效方法之一。…

笔记本cpu温度多少正常?温度过高的4个常见原因

电脑CPU指的是中央处理器&#xff0c;它与电脑运行速度的快慢存在很大关系。如果电脑的处理器温度过高&#xff0c;就会影响我们电脑的运行速度&#xff0c;甚至出现蓝屏、卡顿的情况。 那么&#xff0c;对于电脑来说&#xff0c;笔记本cpu温度多少正常&#xff1f;有什么原因…

如何高效开发一个OA办公系统?

如何才能高效开发一个OA办公系统&#xff1f;这篇教你使用零代码工具从0-1搭建一个OA办公系统&#xff0c;无需代码基础&#xff0c;只要你懂业务&#xff0c;只需3步即可搭建&#xff01; 先来看看效果—— 系统模板>>https://www.jiandaoyun.com/ 整个系统包含物资管理…

2023年可穿戴智能设备三大应用领域的发展前景

科技化进程的不断推进&#xff0c;让可穿戴智能设备在智能设备市场占比逐渐增多&#xff0c;通过传感器和无线通信等技术的结合&#xff0c;为用户带来良好体验&#xff0c;为智能设备市场发展注入活力。消费类电子产品也朝着移动化、便携化、可穿戴化方向发展&#xff0c;可穿…

【蓝桥杯集训7】并查集专题(3 / 5)

目录 并查集模板 1249. 亲戚 - 并查集 837. 连通块中点的数量 - 并查集 240. 食物链 - 带权并查集 238. 银河英雄传说 - 并查集模板 活动 - AcWing int find(int x) //返回x的祖宗结点状态压缩 {if(p[x]!x) p[x]find(p[x]);return p[x]; }p[find(a)]find(b); //合并操作…

Jest使用

一、测试到底测什么 提到测试的时候&#xff0c;即使是最简单的一个代码块可能都让初学者不知所措。最常问的问题的是“我怎么知道要测试什么&#xff1f;”。如果你正在写一个 Web 应用&#xff0c;那么你每个页面每个页面的测试用户交互的方式&#xff0c;就是一个很好的开端…

技术干货!如何玩转Salesforce测试类 (Test Class)?

测试类主要用于评估其他代码片段&#xff0c;确保一切正常且可靠地运行。这可以作为一种早期预警系统&#xff0c;提醒开发人员出现了错误或问题。 不同类型的程序化测试 测试类可以分为多种不同的类型&#xff0c;这改变了我们编写测试的方式及其预期结果。对于Apex测试类&…

【机器学习】DBSCAN密度聚类算法(理论 + 图解)

文章目录一、前言二、DBSCAN聚类算法三、DBSCAN算法步骤四、算法的理解五、常用评估方法&#xff1a;轮廓系数一、前言 之前学聚类算法的时候&#xff0c;有层次聚类、系统聚类、K-means聚类、K中心聚类&#xff0c;最后呢&#xff0c;被DBSCAN聚类算法迷上了。 为什么呢&…

等保2.0丨5分钟速览:小白也能看懂的等保2.0介绍

等级保护2.0自2019年12月1日正式实施起&#xff0c;到现在已经有两个多月的时间&#xff0c;但是仍然有刚刚进入等保领域的“萌新”反馈&#xff0c;需要小编再做一个简单的介绍&#xff0c;那么今天的干货内容&#xff0c;我们就来一起了解什么是等保2.0&#xff0c;最新实施的…

数学(一)-- LeetCode[12][13] 整数转罗马数字

1 整数转罗马数字 1.1 题目描述 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符数值I1V5X10L50C100D500M1000例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即为两个并列的 1。12 写做 XII &…

消灭EMC的三大利器:电容器/电感/磁珠

滤波电容器、共模电感、磁珠在EMC设计电路中是常见的身影&#xff0c;也是消灭电磁干扰的三大利器。 对于这三者在电路中的作用&#xff0c;相信还有很多工程师搞不清楚&#xff0c;文章从设计中详细分析了消灭EMC三大利器的原理。 1 、滤波电容 尽管从滤除高频噪声的角度…

json-server的入门到抢后端饭碗

1.json-server概述 json-server是一个 Node 模块&#xff0c;运行 Express 服务器&#xff0c;你可以指定一个 json 文件作为 api 的数据源。 通俗来说&#xff0c; json-server模拟服务端接口数据&#xff0c;一般用在前端人员可以不依赖后端的API开发&#xff0c;而在本地搭…

基于Spring Boot的教务管理系统

文章目录项目介绍主要功能截图&#xff1a;登录首页学生信息管理班级信息管理教师信息管理教师评价部分代码展示设计总结项目获取方式&#x1f345; 作者主页&#xff1a;Java韩立 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题…

Java服务导致CPU爆表异常排查

一、前言之前的博客有提到过面对Tomcat部署的java服务出现内存溢出该如何定位&#xff0c;今天来记录下Tomcat部署的java服务出现CPU爆表的事故该如何定位。二、正文针对Linux系统在处理CPU爆满时会有相关指令可以一步到位&#xff0c;相关资料度娘有很多。本文重点以Windows系…

九龙证券|权重股引领A股强势反弹 沪指创今年以来最大单日涨幅

周一&#xff0c;沪深两市强势反弹&#xff0c;上证综指全天收涨超2%&#xff0c;创本年以来最大单日涨幅。到收盘&#xff0c;上证综指报3290.34点&#xff0c;上涨2.06%&#xff1b;深证成指报11954.13点&#xff0c;上涨2.03%&#xff1b;创业板指报2480.79点&#xff0c;上…

JAVA集合之并发集合

从Java 5 开始&#xff0c;在java.util.concurrent 包下提供了大量支持高效并发访问的集合接口和实现类&#xff0c;如下图所示&#xff1a; 以CopyOnWrite开头的集合即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候&#xff0c;不直接往容器添加&#xff0c;而…

Spring依赖注入(一):字段注入的方式是如何工作的?

前言写这篇文章的起因&#xff0c;是因为我想写篇文章来分享一下&#xff1a;Spring是如何解决循环依赖的&#xff1f;然后在分析的时候&#xff0c;我发现如果要想说清楚Spring是如何解决循环依赖的&#xff0c;那么就必须得先说清楚什么是循环依赖&#xff1f;从字面理解&…

智慧公厕系统为管理方提供更丰富的管理手段

很多时候&#xff0c;当人们外出游玩、在写字楼办公、商场购物、乘坐地铁火车出行时&#xff0c;都会看到公厕前面会有排队的现象&#xff0c;特别是对于人口流动大&#xff0c;公厕设施少的公共区域&#xff0c;队伍更是极其的长。智慧公厕可以解决传统公厕的脏乱差、异味和管…