首先新建一个MyStorage.py,自定义Storage类
from io import BytesIO from django.core.files.storage import Storage from django.conf import settings from utils.minioClient import go_upload_file, go_delete_file, go_upload_file_have_size from utils.tools import img_bucket class MinioStorage(Storage): """ 自定义文件存储系统 """ def __init__(self): pass def _open(self, name, mode='rb'): """ 用于打开文件 :param name: 要打开的文件的名字 :param mode: 打开文件方式 :return: None """ pass def _save(self, name, content): """ 用于保存文件 :param name: 要保存的文件名字 :param content: 要保存的文件的内容 :return: None """ # print(name) name = name.replace('\\', '/') # ret = go_upload_file(BytesIO(content.read()), bucket=img_bucket, path_name=name) ret = go_upload_file_have_size(BytesIO(content.read()), content.size, bucket=img_bucket, path_name=name) assert ret == 1, '文件上传失败' path = '/' + name return path def delete(self, name): # im = get_file_path(instance.img) # print(name) # name = str(name).split('/')[-1] ret = go_delete_file(bucket=img_bucket, path_name=str(name)) # print(ret) def url(self, name): """ 返回name所指文件的绝对URL :param name: 要读取文件的引用 :return: """ host = settings.MINIOHTTP + settings.MINIOWEBHOST + ':' + settings.MINIOWEBPORT return host + "/" + img_bucket + name def exists(self, name): """ 检查文件存在 """ return False
这么实现 def url(self, name)这个函数,需要在Minio后台将 bucket 权限设置为public,就是开放的所有人皆可访问
Minio实现上传文件,新建minioClient.py
import copy import os from django.conf import settings from minio import Minio MINIO_CONF = { 'endpoint': settings.MINIOHOST + ':' + settings.MINIOPORT, 'access_key': settings.MINIOUSER, 'secret_key': settings.MINIOPWD, 'secure': False } client = Minio(**MINIO_CONF) def get_file_size(file): """ 获取文件大小 file: bytes return: int """ file.seek(0, os.SEEK_END) return file.tell() # im = io.BytesIO(file) # return im.getbuffer().nbytes def go_upload_file(file, bucket='media', path_name=''): """ 上传文件 """ try: # print(path_name) # print(type(file)) file_len = get_file_size(copy.copy(file)) # print(file_len) client.put_object(bucket_name=bucket, object_name=path_name, data=file, length=file_len) return 1 except Exception as e: print(e) return 0 def go_upload_file_have_size(file, size, bucket='media', path_name=''): """ 上传文件,已有文件大小 """ try: client.put_object(bucket_name=bucket, object_name=path_name, data=file, length=size) return 1 except Exception as e: print(e) return 0 def go_delete_file(bucket='media', path_name=''): """ 删除文件 """ try: # print(bucket, path_name) client.remove_object(bucket_name=bucket, object_name=path_name) return 1 except Exception as e: print(e) return 0 def go_delete_file_list(bucket='media', path_name_list=[]): """ 删除文件列表 未实现,据说需要删除完遍历结果 """ try: ret = client.remove_objects(bucket, path_name_list, bypass_governance_mode=False) print(ret) return 1 except Exception as e: print(e) return 0 def get_file_url(bucket='media', path_name=''): """ 获取文件url """ try: url = client.presigned_get_object(bucket_name=bucket, object_name=path_name) return url except Exception as e: print(e) return None def get_file_path(path): path = path.split('/')[2:] final_path = '/'.join(path) return final_path
新建一个tools.py
import datetime import os import random import time img_type_list = ['.jpg', '.png', '.jpeg'] img_bucket = 'media' def get_secret(request): """ 获取加密的key """ return request.META.get('HTTP_AUTHORIZATION') or 'wchime' def get_time_string(): """ :return: 20220525140635467912 :PS :并发较高时尾部随机数增加 """ time_string = str(datetime.datetime.fromtimestamp(time.time())).replace("-", "").replace(" ", "").replace(":","").replace(".", "") + str(random.randint(100, 999)) return time_string def split_file_type(file): """ 对文件名切割,获取名字和类型 """ file_li = os.path.splitext(file) return file_li[0], file_li[1] if __name__ == '__main__': im = 'a.png' s = split_file_type(im) print(s)
我的models.py
class TestImg(models.Model): name = models.CharField(verbose_name="名字", max_length=256) img = models.ImageField(upload_to='zzz')
新建一个视图文件
from io import BytesIO
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.utils.decorators import method_decorator
from rest_framework import status, serializers
from rest_framework.response import Response
from ani import models
from utils.decorators import request_decrypt
from utils.myView import MyPagination, MyView, MixinGetList, MixinPostCreateModel, MixinPutUpdateModel, \
MixinDeleteDestroyModel
from utils.tools import split_file_type, img_type_list, get_time_string, img_bucket
class TestImgSerializer(serializers.ModelSerializer):
class Meta:
model = models.TestImg
fields = '__all__'
def create(self, validated_data):
res = models.TestImg.objects.create(**validated_data)
return res
def update(self, instance, validated_data):
instance.name = validated_data.get('name')
if validated_data.get('img', False) is not False:
instance.img = validated_data.get('img')
instance.save()
return instance
@method_decorator(request_decrypt, name='get')
class TestImgView(MyView, MixinGetList):
queryset = models.TestImg.objects.all()
serializer_class = TestImgSerializer
all_serializer_class = TestImgSerializer
filter_class = ['name__icontains']
pagination_class = MyPagination
lookup_field = 'id'
ordeing_field = ('-id',)
def post(self, request, *args, **kwargs):
data = request.data
file_content = data.get('file').read()
file_name = get_time_string() + '.png'
# print(file_content)
content_file = ContentFile(file_content, file_name)
# print(content_file)
data['img'] = content_file
serializer_class = TestImgSerializer
serializer = serializer_class(data=data)
# print(serializer.is_valid())
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def put(self, request, *args, **kwargs):
data = request.data
try:
instance = self.queryset.get(id=data.get(self.lookup_field))
except Exception:
return Response({'state': 'fail', 'msg': '未找到该数据'}, status=status.HTTP_400_BAD_REQUEST)
file = data.get('file')
if file:
file_content = file.read()
file_name = get_time_string() + '.png'
# print(file_content)
content_file = ContentFile(file_content, file_name)
# print(content_file)
data['img'] = content_file
if instance.img:
default_storage.delete(instance.img)
serializer_class = TestImgSerializer
serializer = serializer_class(instance=instance, data=data, partial=True)
# print(serializer.is_valid())
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def delete(self, request, *args, **kwargs):
try:
instance = self.queryset.get(id=request.data.get(self.lookup_field))
except Exception:
return Response({'state': 'fail', 'msg': '未找到数据'}, status=status.HTTP_400_BAD_REQUEST)
default_storage.delete(instance.img)
instance.delete()
return Response({'state': 'success', 'msg': '删除成功'}, status=status.HTTP_204_NO_CONTENT)
在settings.py中加上
DEFAULT_FILE_STORAGE = 'utils.MyStorage.MinioStorage'
整个项目文件结构
postman调用的结果
本文已收录至:https://cunyu1943.blog.csdn.net/前言之前已经写过关于学生成绩管理系统以及点菜系统的文章,大家如果感兴趣,可以点击各自的传送门去看看呀!接下来开始我们今天的正题,我们日常生活中,想必有很多人都有记账的习惯,那今天,我们就来看看,如何设计并实现一个记账本。需求分析打开我们手机里的记账本,可以发现主要提供如下几个功能:添加账目删除账目修改账目查询账目查询所有账目按时间区间查询按账目类型查询退出记账本记账本功能预览及代码实现主菜单主菜单中,主要用于打印提示我们进行选择,然后根据我们的输入再进入不同的子功能模块中。预览代码实现代码实现很简单,只需要打印出提示信息即可,之后后续输入以及进入不同子功能模块,我们可以使用switch来进行选择。packagecom.cunyu; importjava.util.ArrayList; importjava.util.Arrays; importjava.util.List; importjava.util.Scanner; /** *CreatedwithIntelliJIDEA. * *@author:
一看就会的超详细教程:SpringBoot整合MybatisPlus!>>>这里根据官网新推出的springcloudHoxton.SR11版本去集成gateway的一个坑首先先写版本号:框架版本号springcloudHoxton.SR11springboot2.3.0根据官网推荐,springcloud这个版本支持的springboot是2.3.0。在集成gateway网关时会报错如下:*************************** APPLICATIONFAILEDTOSTART *************************** Description: Anattemptwasmadetocallamethodthatdoesnotexist.Theattemptwasmadefromthefollowinglocation: org.springframework.cloud.gateway.config.GatewayAutoConfiguration$NettyConfiguration.buildConnectionProvider
在面试中,候选人经常会被问到,你在项目里用到过哪些设计模式?对此,你可以按本文给出的步骤,系统地通过工厂模式展示自己在设计思想方面的能力。1通过工厂模式屏蔽创建细节工厂模式(FactoryMethod)是用来向使用者屏蔽创建对象的细节。之前我们在讲SAX解析XML文件时,已经用到过工厂模式,当时我们是通过如下代码用SAXParserFacotry这个工厂对象来创建用于解析的parse对象,代码如下所示。1 SAXParserFactoryfactory=SAXParserFactory.newInstance(); 2 SAXParserparser=factory.newSAXParser();复制作为使用者,我们只要能得到parser对象进行后继的解析动作,至于parser对象是如何创建的,我们不需要,也不应管。如果不用工厂模式,那么我们还得亲自关注如何创建parser对象,比如得考虑创建时传入的参数,以及是否改用“池”的方式来创建从而提升效率。这样亲力亲为的后果是,会让使用和创建parser对象的代码耦合度很高,这样一旦创建parser的方法发生改变,比如日后需要传入不同的参数,
<spanstyle="font-size:18px;">packagecom.test; publicclasstest{ publicstaticString[]split(Stringstr,intchars){ intn=(str.length()+chars-1)/chars; Stringret[]=newString[n]; for(inti=0;i<n;i++){ if(i<n-1){ ret[i]=str.substring(i*chars,(i+1)*chars); } else{ ret[i]=str.substring(i*chars); } } returnret; } publicstaticvoidmain(String[]args){ Strings="abcdefghij"; for(Strings1:split(s,2)){ System.out.println(s1); } } }</span>复制<spanstyle="font-size:18px;&
之前我们对单独的音频和视频的播放进行了分析。 但是实际上播放一段影片,还需要音视频同步播放。主要思路是在解码获得数据时,对frame的pts进行计算。在视频送显的时候,或者是音频赋值的时候,进行时间的纠正。 如果以音频时间为主的话,就需要修正视频的送显时间。 如果是视频的时间为主的,同样需要修正音频的播放时间。(通过减少音频的播放帧数。)1.计算PTScaseAVMEDIA_TYPE_VIDEO: //对视频进行解码。 ret=avcodec_decode_video2(d->avctx,frame,&got_frame,&d->pkt_temp); if(got_frame){ //默认情况下为-1 if(decoder_reorder_pts==-1){ //视频的时间戳pts可以通过av_frame_get_best_effort_timestamp来计算 frame->pts=av_frame_get_best_effort_timestamp(frame); }elseif(!decoder_reorder_pts){ frame->p
同步解决线程安全问题的三种实现/* *同步可以解决安全问题的根本原因就在那个对象上。 * *A:同步代码块的格式及其锁对象问题? *格式: *synchronized(对象名称){ *需要同步的代码; *} * *同步代码块的锁对象是谁呢? *任意对象。 * *B:同步方法的格式及其锁对象问题? *如果一个方法一进去就看到了代码被同步了,那么我就在想能不能把这个同步加在方法上呢?答:能。 *把同步关键字加在方法上。 *格式: *synchronizedprivatevoidsellTicket(){...} *privatesynchronizedvoidsellTicket(){...}//习惯上这样写 * *同步方法的锁对象是谁呢?(方法的内部有一个你看不到的对象是this啊,傻瓜哈) *this * *C:静态同步方法的格式及其锁对象问题? *格式: *privatestaticsynchronizedvoidsellTicket(){...} * *静态同步方法的锁对象是谁呢? *当前类的字节码文件对象。(反射会讲) * *类的初始化过程:Personp=newPerson()
概要:AI以一种更实际的形态作为数字化商业的关键组成要素获得了新生。来源:智能机器人资讯分享分析你需要知道的AI以一种更实际的形态作为数字化商业的关键组成要素获得了新生。AI的复兴是由多个关键部分的正向市场发展所驱动的,这些部分是:对于爆炸性非结构性数据的捕捉,预处理和存贮,用于“训练机器”; 用于机器学习的高互补性的处理单元和并行处理架构; 通过平台/API接口获得的更广泛的算法来处理更大量的商业应用; 不断增加的数据科学实践者和大众对于数据科学/机器学习的兴趣。由于以下几种原因,这里所展示的AI技术十分引人注目:41%被评为转型性的,另外44%被认为会带来高价值;87%被认为是正在或是在低谷期之前;54%被认为要在2022年甚至更晚才能够达到成熟期,能够带来可靠的生产力。对于企业来说,这些高颠覆性,价值丰富但往左偏移的技术模式代表着高风险高回报的提议,有几个比较突出的结论可供AI技术购买者参考:失败的风险非常大,但在数字化商业中过时而失去竞争力对于企业来说的风险更大;虽然潜在的利益很大,但它们通常都伴随着失败,倒退,和新兴技术典型的“低谷期”;赢家会在具备减轻风险的战略和技术
软件使用文本文件来记录数据,前些天以客户反映,数据写入时间太长,能不能设置不记录数据,因为之前测试的时候,测试400个点的数据,写入的时间也就在1秒钟的样子,而客户实际写入是需要到一分半钟。 起初以为是不是系统的问题,因为给客户配置的是笔记本电脑,使用的win10家庭版的系统,而之前一直使用的是win7的系统,我想那就给客户改下程序,不记录数据,暂时使用。 这两天空闲下来,进行测试,分别测试了win7和win10的系统,起初没有发现异常,写入速度都挺快的,但是经过多次写入的话,写入的数据就开始变慢了,不管是win7还是win10,都是一样的结果,排除了系统的原因。 经过测试,发现是因为数据写的越来越多,导致的速度越来越慢。 测试电脑系统属性 测试写入时间记录 每次写入的数据量大概是45K。 这样下来,数据写的越来越多,写入的时间越来越长,但是每次写入的数据量是一定的,那这种原因就是文件多来越大,那么写入的速度就越来越慢了。 记录数据的方式是使用window的写配置文件的API函数,每次将数据格式化后,写入文件中 //L strTemp.
链接:https://ac.nowcoder.com/acm/contest/5556/E来源:牛客网 时间限制:C/C++1秒,其他语言2秒 空间限制:C/C++32768K,其他语言65536K 64bitIOFormat:%lld 题目描述 一共有n个数,第i个数是xi xi 可以取[li,ri]中任意的一个值。 设S=∑xi2,求S的种类数。 输入描述: 第一行一个数n。 然后n行,每行两个数表示li,ri。 输出描述: 输出一行一个数表示答案。 示例1 输入 5 12 23 34 45 56复制 输出 26复制 备注: 1≤n,li,ri ≤100 不了解bitset的先看看这个: https://www.cnblogs.com/magisk/p/8809922.html 题解: 这题用bitset来优化动态规划 bitset其实就相当于我们平时使用的vis[]数组,bitset中的某一位是1就相当于
/************************摘抄*****************************/ 刚好遇到这个问题,在网上百度了一下,看到有人分享了引起该问题的几个原因: 1.手机设置问题。开USB调试 方法: 手机设置-开发人员选项-USB调试 -勾选 2.数据线问题。 有的数据线只能用来充电,有的可以连接存储。识别方法很简单。。插上机器有USB存储设备的提示的就可以用。另外数据线如果都露线皮了。。就赶紧扔了。十块八块的总比你为这个破问题纠结一下午的好。 3.是否下载了对应手机版本的SDK,以AndroidStudio为例,点开SDKManager之后。看你手机所使用的系统版本号对应的SDK是否已下载。。没有就赶紧下。。手机对应的Android版本查看方法是 手机设置 - 关于手机 -Android版本 作者:Sheh伟伟链接:https://www.zhihu.com/question/30588024/answer/70352952来源:知乎著作权归作者所有。商业转
--首先,以超级管理员的身份登录oracle sqlplussys/bjsxtassysdba --然后,解除对scott用户的锁 alteruserscottaccountunlock; --那么这个用户名就能使用了。 --(默认全局数据库名orcl) 1、selectename,sal*12fromemp;--计算年薪 2、select2*3fromdual;--计算一个比较纯的数据用dual表 3、selectsysdatefromdual;--查看当前的系统时间 4、selectename,sal*12anuual_salfromemp;--给搜索字段更改名称(双引号keepFormat别名有特殊字符,要加双引号)。 5、--任何含有空值的数学表达式,最后的计算结果都是空值。 6、selectename||salfromemp;--(将sal的查询结果转化为字符串,与ename连接到一起,相当于Java中的字符串连接) 7、selectename||'afasjkj'fromemp;--字符串的连接 8、selectdistinctdeptnofromemp;--消除dep
前言 因今年公司新产品线较多,为了降低耦合,达到业务分离、重用,提高内部开发效率的目的,采用了基于服务组件、前后端分离的架构体系。与之前传统单应用架构相比,系统部署、配置更加复杂,为了能够频繁地将软件的最新版本,及时、持续地交付给测试团队及质量控制团队,以供评审,所以引入持续集成工具Jenkins,从而实现公司新产品持续集成,自动化部署。 CI/CD介绍 互联网软件的开发和发布,已经形成了一套标准流程,假如把开发工作流程分为以下几个阶段: 编码→构建→集成→测试→交付→部署 正如你在上图中看到,持续集成(ContinuousIntegration)、持续交付(ContinuousDelivery)和持续部署(ContinuousDeployment)有着不同的软件自动化交付周期。 持续集成(CI) 上面整个流程中最重要的组成部分就是持续集成(Continuousintegration,简称CI)。 持续集成
SSH 因为工作原因我平时用ssh还是挺多的,但从来没有好好的抓一下ssh的报文,按理说我应该拿出RFC文档好好地的研读,但从以往的经历当中也没有遇到ssh的相关的大故障,最近在学习wireshark,那就用wireshark抓个包分析一下为什么ssh有时候为卡住?有的时候就会非常的顺畅? #操作系统是KALILINUX ┌──(root?kali)-[~] └─#uname-a Linuxkali5.14.0-kali4-amd64#1SMPDebian5.14.16-1kali1(2021-11-05)x86_64GNU/Linux ┌──(root?kali)-[~] └─#cat/proc/version Linuxversion5.14.0-kali4-amd64(devel@kali.org)(gcc-10(Debian10.3.0-12)10.3.0,GNUld(GNUBinutilsforDebian)2.37)#1SMPDebian5.14.16-1kali1(2021-11-05) 复制 ssh客户端:192.168.80.100 ssh服务端:192.168.
(1)APP组成部分部分以及功能: 顾客端:以身份信息获取对应签名 快递员端:当面接收信息;发送签名至服务器;根据服务器返回结果验证取货人信息 平台端:针对顾客信息和货物信息生成签名,处理核验快递小哥发送到信息,返回认证结果(2)交互过程:假设:A——顾客 B——快递员 C——平台1)顾客和快递员登录平台验证身份A->C:password||accountB->C:password||account2)平台给快递员和顾客发送订单信息C->A:ticket_A||order||lifetimeC->B:ticket_B||order||lifetime//平台给快递员和顾客各自的密钥和订单信息和时间限制3)快递员发送取件码给顾客B->C:ticket_B||command;//快递员将取件码发给平台,通过密钥验证身份C->A:command||lifetime;//平台转发给顾客,有时间限制4)快递员核查顾客身份:当面看取件码5)快递员确认派送完毕,用户确认收货完毕B->C:ticket_
题目链接、 ProblemDescription 国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎",具体的操作是这样的: 首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排; 然后,让各位新郎寻找自己的新娘.每人只准找一个,并且不允许多人找一个. 最后,揭开盖头,如果找错了对象就要当众跪搓衣板... 看来做新郎也不是容易的事情... 假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能. Input 输入数据的第一行是一个整数C,表示测试实例的个数,然后是C行数据,每行包含两个整数N和M(1<M<=N<=20)。 Output 对于每个测试实例,请输出一共有多少种发生这种情况的可能,每个实例的输出占一行。 SampleInput 2 22 32 SampleOutput 1 3 分析: 首先对于n个新郎里面有m个人来进行选择,就是一个简单的组合问题,但是如何保证这些人选的都是错误的呢,就要用到错排公式。 第一步,“错排”1号元素(将1号元素排在第2至
HPLoadrunner11中文教程的学习基本已经结束,最后困扰我的就是这个在创建MicrosoftWord报告时不停的提示“指定的转换无效”的问题。在网上搜索了好长时间,好多朋友回答说没有生成监控的数据。我想这个答案应该是正确的,但是问题一直没解决,因为没弄明白到底哪里没生成监控数据,其实我的数据应该是有生成的。还有说是中文版导致的,但是我一直用的英文版,所以这个是可以忽略的。今天看到一个朋友非常详细的截图回答,终于解决了这个问题。具体的操作方法我详细记录下来,供自己及其他碰到相同问题的朋友参考。 点击Reports->NewReport按钮,填写General,Format,Content等相关信息后,保存。点击GenerateReport按钮生成报告。然后问题就出现了,不停的弹出对话框“指定的转换无效”。 解决方法:出现这
【题目描述】 18位身份证标准在国家质量技术监督局于1999年7月1日实施的GB11643-1999《公民身份号码》中做了明确的规定,该标准规定了公民身份号码的编码对象、号码的结构和表现形式,使每个编码对象获得一个唯一的、不变的法定号码。号码的结构和表示形式如下: (1)号码的结构:公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。 (2)地址码:表示编码对象常住户口所在县(市、旗、区)的行政区划代码。例如370211代表山东省青岛市黄岛区。 (3)出生日期码:表示编码对象出生的年、月、日。 (4)顺序码:表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。 (5)校验码:根据十七位数字本体码加权求和公式,通过计算模得到对应的校验码。 【输入】 有多组测试用例。第一行输入一个整数T(0<T<5000),表示测试用例的组数,每组测试用例一行,包含1个18位的身份证号码。 【输出】 统计T行数据中非山东省考生的数
<head> <title>jquery点击按钮后灰色倒计时并且无法提交,倒计时结束后恢复</title> <scripttype="text/javascript"src="http://www.daimabiji.com/statics/js/jquery.min.js"></script> <scripttype="text/javascript"> $(function(){ $('#btn').click(function(){ varcount=10; varcountdown=setInterval(CountDown,1000); functionCountDown(){ $("#btn").attr("disabled",true); $("#btn").val("您在"+count+"秒后可以再次获取!"); if(count==0){ $("#btn").val("重新获取验证码").removeAttr("disabled"); clearInterval(countdown); } cou
一、统一返回数据格式 项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一,使前端(iOSAndroid,Web)对数据的操作更一致、轻松。 一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容 例如,我们的系统要求返回的基本数据格式如下: (1)列表: { "success":true, "code":20000, "message":"成功", "data":{ "items":[ { "id":"1", "name":"刘德华", "intro":"毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余" } ] } } 复制 (2)分页: { "success":true, "code":20000, "message":"成功", "data":{ "total":17, "rows":[ { "id":"1", "name":"刘德华", "intro":"毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余" } ] } } 复制 (3)没有返回数据:
1.可用性分析: 所关注的方面包括系统故障发生的频率、出现故障时会发生什么情况、允许系统有多长是将非正常运行、什么时候可以安全地出现故障、如何防止故障的发生以及发生故障时要求进行哪种通知。 场景设想:淘宝双十一活动时很多用户同时访问,系统出现崩溃 刺激源:太多的用户同时进行购买登录的操作 刺激:操作用户过多,服务器崩溃。 制品:系统的服务器 环境:正常的操作 响应:系统响应人数过多,无法正常进行登录,系统检测到事件:记录故障,通知系统 响应度量: 排除故障,系统可以继续正常使用 2.可修改性分析: 场景设想:由于进行活动促销,卖家修改商店界面 刺激源:卖家 刺激:希望修改商店界面。 制品:商店界面 环境:正常运行时 响应: 查找架构中需要修改的位置,进行修改且不会影响其他功能,对所做的修改进行测试,部署所做的修改 响应度量: 修改该界面对其他99.9%的功能不造成影响 3.性能分析: 场景设想:双十一活动时,大量用户希望登陆上淘宝网来选购想要的商品 刺激源:大量淘宝网用户 刺激:试图同时登陆淘宝网站进行选购商品 制品