python 全栈开发,Day106(结算中心(详细),立即支付)
python 全栈开发,Day106(结算中心(详细),立即支付)
昨日内容回顾
1. 为什么要开发路飞学城?提供在线教育的学成率;特色:学,看视频,单独录制增加趣味性。练,练习题改,改学生代码管,管理测,阶段考核线下:8次留级考试2. 组织架构- 开发- 后端- 前端- 测试- UI- 产品经理- 运维- 销售- 运营- 全职导师- 行政- 财务3. 项目架构- 主站- nginx + uwsgi + django - 导师后台- 管理后台4. 开发周期和人数2017-07:开始做2017-11:第一版上线2018-02:功能完善和迭代2018-03:题库系统/wiki5. 前后端分离vue.jsrestful api 6. 跨域相关正式:无测试:有跨域,使用CORS解决;- 简单请求- 复杂请求7. 你负责项目中的什么?课程购物车深科技15个接口
View Code
一、结算中心(详细)
完整代码
先来看payment.py完整代码
import json import redis from django.conf import settings from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from rest_framework.response import Response from api.utils.auth import LuffyAuthentication from api import models from api.utils.response import BaseResponse# CONN = redis.Redis(host='192.168.11.61',port=6379) from django_redis import get_redis_connection CONN = get_redis_connection("default")class CourseNotExistsException(Exception):def __init__(self,msg):self.msg = msgclass PaymentView(ViewSetMixin,APIView):authentication_classes = [LuffyAuthentication,]def create(self,request,*args,**kwargs):"""在结算中添加课程:param request::param args::param kwargs::return:"""response = BaseResponse()try:# 1.接受用户选择的要结算的课程ID列表userid = request.user.id# [1,3,55]courseid_list = request.data.get('courseid') # 拿到的是一个列表# 2.清空当前用户request.user.id结算中心的数据pattern = 'payment_%s_%s' % (userid, '*')# 方式一:key_list = CONN.keys(pattern)CONN.delete(*key_list)# 方式二:# for key in CONN.keys(pattern):# CONN.delete(key) # 清空结算中心# 3.循环要加入结算中的所有课程ID列表import datetimetoday = datetime.date.today()for course_id in courseid_list:shop_car_key = "shopping_car_%s_%s" %(userid,course_id)# 3.1 判断购物车中是否存在此keyif not CONN.exists(shop_car_key):raise CourseNotExistsException('购物车中不存在该课程')# 3.2 去购物车中获取课程信息id = CONN.hget(shop_car_key, 'id').decode('utf-8')name = CONN.hget(shop_car_key, 'name').decode('utf-8')img = CONN.hget(shop_car_key, 'img').decode('utf-8')default_price_id = CONN.hget(shop_car_key, 'default_price_id').decode('utf-8')price_policy_dict = json.loads(CONN.hget(shop_car_key, 'price_policy_dict').decode('utf-8'))price_policy = price_policy_dict[default_price_id]"""{'id':1,'price':99.99,'valid_period':60,'valid_period_display':2个月}"""# 3.3 根据课程ID获取该课程可用的优惠券 coupon_list = models.CouponRecord.objects.filter(account_id=userid,status=0,coupon__valid_begin_date__lte=today,coupon__valid_end_date__gte=today,coupon__object_id=course_id,coupon__content_type__model='course')# 加入结算中心"""for course_id in 用户提交课程ID列表:3.1 根据course_id,request.user.id去购物车中获取商品信息:商品名称、图片、价格(id,周期,显示周期,价格)3.2 根据course_id,request.user.id获取 - 当前用户- 当前课程- 可用的优惠券加入结算中心提示:可以使用contenttypes"""# 4.获取当前用户所有未绑定课程优惠券# - 未使用# - 有效期内# - 加入结算中心:glocal_coupon_用户ID global_coupon_list = models.CouponRecord.objects.filter(account_id=userid,status=0,coupon__valid_begin_date__lte=today,coupon__valid_end_date__gte=today,coupon__content_type__isnull=True)# 加入到结算中心except CourseNotExistsException as e:response.code = 1010response.error = e.msgexcept Exception as e:passreturn Response('...')def list(self,request,*args,**kwargs):"""查看结算中心:param request::param args::param kwargs::return:"""# 1. 根据用户ID去结算中心获取该用户所有要结算课程# 2. 根据用户ID去结算中心获取该用户所有可用未绑定课程的优惠券# 3. 用户表中获取贝里余额# 4. 以上数据构造成一个字典return Response('...')def update(self,request,*args,**kwargs):"""更新优惠券:param request::param args::param kwargs::return:"""# 1. 获取用户提交:# course_id=1,coupon_id=3# course_id=0,coupon_id=6# 2. course_id=1 --> 去结算中心获取当前用户所拥有的绑定当前课程优惠,并进行校验# - 成功:defaul_coupon_id=3# - 否则:非法请求# 2. course_id=0 --> 去结算中心获取当前用户所拥有的未绑定课程优惠,并进行校验# - 成功:defaul_coupon_id=3# - 否则:非法请求
View Code
代码解释
1
接收用户选择的要结算的课程ID列表
userid = request.user.id
当用户认证成功后,request.user就是一个Account表的一个对象。所以request.user.id就能取到用户id。至于为什么request.user就是一个Account表的一个对象,请参考DRF认证源码解析
2
清空当前用户request.user.id结算中心的数据
结算中心的数据在redis中,它的键值为payment_用户id_课程id。由于redis存储的是key-value,所以清空就是删除!
查询当前用户的结算中心,使用模糊匹配
pattern = 'payment_%s_%s' % (userid, '*')
删除有2种方式:
方式一:
key_list = CONN.keys(pattern) CONN.delete(*key_list)
方式二:
for key in CONN.keys(pattern):CONN.delete(key)
推荐使用方式一,*key_list表示打散,再将每一个值分别传给CONN.delete
3
循环要加入结算中的所有课程ID列表
结算中心的数据,是来源于购物车,由于购物车数据在redis中,直接查询就可以了
for course_id in courseid_list:shop_car_key = "shopping_car_%s_%s" %(userid,course_id)
前端传给后端的课程是一个列表,它是使用html的复选框,默认数据类型为列表。所以需要使用for循环
购物车的键值为shopping_car_用户id_课程id,它的数据结构如下:
购物车 = {'shopping_car_用户id_课程id':{id:'课程id',name:'课程名'img:'课程图片'default_price_id:'默认价格策略id',# 所有价格策略price_policy_dict = {'价格策略id':{'id':价格策略id,'price':'原价','valid_period':'有效期','valid_period_display':'有效期中文显示'}}}, }
注意:下面展示的部分代码是在for循环中的
3.1 判断购物车中是否存在此key
if not CONN.exists(shop_car_key):raise CourseNotExistsException('购物车中不存在该课程')
CourseNotExistsException是自定义的一个方法,用来做自定义的异常。
raise 表示主动抛出异常,那么下面的代码,将不会执行!也不会被Exception捕获到!
这里为什么要判断购物车课程是否存在呢?如果是正常用户,当然不会有问题。但如果是爬虫用户,它可以伪造数据,发给后端服务器。所以这里要判断数据的真实性!
3.2 去购物车中获取课程信息
下面的代码,分别获取课程id,课程名,课程图片,默认价格策略id,所有价格策略,当前课程价格策略。
id = CONN.hget(shop_car_key, 'id').decode('utf-8') name = CONN.hget(shop_car_key, 'name').decode('utf-8') img = CONN.hget(shop_car_key, 'img').decode('utf-8') default_price_id = CONN.hget(shop_car_key, 'default_price_id').decode('utf-8') price_policy_dict = json.loads(CONN.hget(shop_car_key, 'price_policy_dict').decode('utf-8')) price_policy = price_policy_dict[default_price_id]
价格策略说明:有些课程有3个价格策略,比如1周,1个月,3个月。那么用户选择一个价格策略后,点击加入购物车之后。这个默认价格策略id,就是用户选择的。通过这个,就可以从所有的价格策略中,取出当前价格策略的相关信息。
price_policy应该是这个样子
{'id':1,'price':99,'valid_period':60,'valid_period_display':1个月 }
上面之所以,取出这么多数据,是为了得到这个效果:
3.3 根据课程ID获取该课程可用的优惠券
需要从CouponRecord,它是优惠券发放、消费纪录表。从这个表中,取出相关信息!
先来看完整的ORM查询语句
coupon_list = models.CouponRecord.objects.filter(account_id=userid,status=0,coupon__valid_begin_date__lte=today,coupon__valid_end_date__gte=today,coupon__object_id=course_id,coupon__content_type__model='course')
再来对一个条件,做具体分析!
account_id=userid 表示用户id等于当前登录用户id。通俗来讲,就是谁领用的优惠券!
status=0 表示优惠券状态为:未使用。当用户结算时,使用了优惠券,并付款成功后。这个优惠券的状态,应该要改成已使用。
重点来了,优惠券是有时间限制的。如何判断优惠券是否过期?
根据当前时间来判断!举例:
import datetime #比较大小 today = datetime.date.today().strftime("%Y-%m-%d") # 当前日期 start_time= "2017-01-04" # 开始时间print("%s大于等于%s:"%(today,start_time),today>=start_time)
执行输出:
2018-08-16大于2017-01-04: True
那么在ORM中,也是这么比较的。大于使用gte,小于使用lte
由于Course和coupon表做了content_type关联。
所以coupon__content_type__model='course' 表示django_content_type表中的model字段的值为course,也就表示course表
coupon__object_id=course_id 表示course表的主键id。
那么这2句,就可以查询到优惠券具体绑定到课哪个课程了!
二、立即支付
点击立即支付,就会跳转到支付宝支付,那么在这个过程中,经历了怎样的步骤呢?
伪代码
在views目录中,创建文件order.py,伪代码如下:
import json import redis from django.conf import settings from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from rest_framework.response import Response from api.utils.auth import LuffyAuthentication from api import models from api.utils.response import BaseResponse# CONN = redis.Redis(host='192.168.11.61',port=6379) from django_redis import get_redis_connection CONN = get_redis_connection("default")""" {payment_2_1:{id:1,name:'Python基础',img:'xxx',price:99.99,period:90,period_display:3个月,default_coupon_id:0,coupon_dict:{'1':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},'2':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},'3':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},}},payment_2_3:{id:2,name:'Python进阶',img:'xxx',price:99.99,period:90,period_display:3个月,default_coupon_id:0,coupon_dict:{'1':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},'2':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},'3':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},}},global_coupon_2:{'1':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},'2':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},'3':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},} }"""class OrderView(ViewSetMixin,APIView):authentication_classes = [LuffyAuthentication, ]def create(self,request,*args,**kwargs):"""立即支付:param args::param kwargs::return:"""response = BaseResponse()try:# 1. 接收用户发送的数据"""{'balance':1000,'alipay':228 }"""balance = request.data.get('balance')alipay = request.data.get('alipay')# 2. 检验贝里余额是否够用if request.user.balance < balance:raise Exception('贝里余额不足')# 3.获取结算中心的每个课程信息并应用优惠券"""3.1 获取当前用户结算中心的所有keykey = "payment_%s*" %request.user.idkey_list = CONN.keys(key)total_price = 0discount = 0coupon_id_list = []course_dict = {}3.2 根据key获取结算中心的课程for key in key_list:id = CONN.hget(key,'id').decode()name = CONN.hget(key,'name').decode()price = CONN.hget(key,'price').decode()period = CONN.hget(key,'period').decode()default_coupon_id = CONN.hget(key,'default_coupon_id').decode()coupon_dict = json.loads(CONN.hget(key,'coupon_dict').decode())# 用于计算总原价total_price += priceif default_coupon_id == 0:# 未使用discount += 0else:# 使用优惠券if coupon_dict['type'] == 0: discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']elif coupon_dict['type'] == 1:pass elif coupon_dict['type'] == 2:discount += price * (100-折扣)/ 100coupon_id_list.append(default_coupon_id)course_dict[id] = {id = CONN.hget(key,'id').decode()name = CONN.hget(key,'name').decode()price = CONN.hget(key,'price').decode()period = CONN.hget(key,'period').decode()default_coupon_id = CONN.hget(key,'default_coupon_id').decode(),price:999,discount:99,}3"""# 4.处理未绑定课程的优惠券"""4.1 去redis中获取 global_coupon_2default_coupon_id = CONN.hget('global_coupon_2','default_coupon_id')coupon_dict = CONN.hget('global_coupon_2','coupon_dict')4.2 判断是否使用优惠券if default_coupon_id == 0:passelse:# 使用优惠券if coupon_dict['type'] == 0: discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']elif coupon_dict['type'] == 1:pass elif coupon_dict['type'] == 2:discount += price * (100-折扣)/ 100coupon_id_list.append(default_coupon_id)"""# 5. 判断是否:total_price-discount-balance/10 = alipay# total_price = 0# discount = 0# balance# alipay# raise Exception('价格对不上')# 6. 生成订单"""with transcation.atomic():6.1 obj = models.Order.objects.create(...)6.2 创建多个订单详细for k,v in course_dict.items():detail = OrderDetail.objects.create(order=obj)EnrolledCourse.objects.create(..,order_detail=detail)6.3 更新优惠券count = models.CouponRecord.objects.filter(id__in=coupon_id_list).update(status=2)if count != len(coupon_id_list):报错..6.4 更新贝里余额models.account.objects.filter(id=request.user.id).update(balance=F('balance')-balance)6.5 创建贝里转账记录models.TransactionRecord.objects.create(,,balance)"""# 7. 生成去支付宝支付的连接except Exception as e:pass
View Code
代码解释
1
接收用户发送的数据
""" {'balance':1000,'alipay':228 } """ balance = request.data.get('balance') alipay = request.data.get('alipay')
点击立即支付后,前端只需要向后端发送2个数据就可以了
一个是花费的贝里,一个是要付款的总价!那课程信息从哪里获取呢?从结算中心获取!
结算中心的数据,就是用户要买的所有东西。
为什么要发这2个数据呢?首先用户使用贝里,可以抵扣价格。比如10贝里,可以抵扣1块钱。
前端计算好金额后,发送给后端。后端再计算一遍金额。确保金额一致,跳转到支付宝!为什么不直接跳转到支付宝呢?
因为前端发送的数据,用爬虫手段可以伪造!
2
检验贝里余额是否够用
if request.user.balance < balance:raise Exception('贝里余额不足')
为什么要检测余额呢?因为数据可以伪造嘛,我发送1000万的贝里到后端,实际账号的贝里只有10。
不验证的话,岂不血亏!
3
获取结算中心的每个课程信息并应用优惠券
3.1 获取当前用户结算中心的所有key
key = "payment_%s*" %request.user.id key_list = CONN.keys(key)
结算中心的key规则为:payment_用户id_课程id。使用模糊匹配payment_用户id*就可以得到当前登录用户的所有课程。
结算中心的数据结构为:
{payment_用户id_课程id:{id:课程id,name:'课程名',img:'课程图片',price:'原价',period:'有效期',period_display:'有效期中文显示',default_coupon_id:'默认优惠券id',# 当前课程所有绑定的优惠券 coupon_dict:{# 这里的1,2,3是正序的序号而已。可以有几十张优惠券!'1':{'type':0,'text':'立减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':None},'2':{'type':0,'text':'满减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':'最低消费'},'3':{'type':0,'text':'折扣','money_equivalent_value':None,'off_percent':'百分比','minimum_consume':None},}},# 未绑定课程优惠券,也就是通用优惠券 global_coupon_用户id:{default_coupon_id:'默认优惠券id',# 当前用户所有通用优惠券 coupon_dict:{# 这里的1,2,3是正序的序号而已。可以有几十张优惠券!'1':{'type':0,'text':'立减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':None},'2':{'type':0,'text':'满减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':'最低消费'},'3':{'type':0,'text':'折扣','money_equivalent_value':None,'off_percent':'百分比','minimum_consume':None},}} }
3.2 根据key获取结算中心的课程
下面获取的数据,分别为:课程id,课程名,课程图片,原价,有效期,有效期中文显示,默认优惠券id,当前课程所有绑定的优惠券
for key in key_list:id = CONN.hget(key,'id').decode('utf-8')name = CONN.hget(key,'name').decode('utf-8')img = CONN.hget(key,'img').decode('utf-8')price = CONN.hget(key,'price').decode('utf-8')period = CONN.hget(key,'period').decode('utf-8')period_display = CONN.hget(key,'period_display').decode('utf-8')default_coupon_id = CONN.hget(key,'default_coupon_id').decode('utf-8')coupon_dict = json.loads(CONN.hget(key,'coupon_dict').decode('utf-8'))
3.3 计算总原价
total_price += price
这里表示结算中心所有课程的总原价
3.4 计算要抵扣的价格
if default_coupon_id == 0:# 未使用discount += 0 else:# 使用优惠券if coupon_dict['type'] == 0: discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']elif coupon_dict['type'] == 1:pass elif coupon_dict['type'] == 2:discount += price * (100-折扣)/ 100coupon_id_list.append(default_coupon_id)
coupon_dict['type'] 为0,表示立减。它只和money_equivalent_value(等值货币)有关。等值货币,相当于人民币,可以直接扣
coupon_dict['type'] 为1,表示满减券,它与money_equivalent_value和minimum_consume(最低消费)有关。
coupon_dict['type'] 为2,表示折扣券,它只和off_percent有关。80表示80%,所以计算的时候,要除以100
4
处理未绑定课程的优惠券(通用优惠券)
4.1 去redis中获取 global_coupon_用户id
下面的代码,表示获取默认优惠券以及所有的
default_coupon_id = CONN.hget('global_coupon_1','default_coupon_id') coupon_dict = CONN.hget('global_coupon_1','coupon_dict')
4.2 判断是否使用优惠券
if default_coupon_id == 0:pass else:# 使用优惠券if coupon_dict['type'] == 0: discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']elif coupon_dict['type'] == 1:pass elif coupon_dict['type'] == 2:discount += price * (100-折扣)/ 100coupon_id_list.append(default_coupon_id)
View Code
5
判断前端发送的金额和后端计算的金额是否一致
if total_price-discount-balance/10 != alipay:raise Exception('价格对不上')
意思是总价格-要抵扣的价格-贝里/10。10贝里,表示1块钱。
alipay 表示后台计算的价格
6
生成订单
6.1 插入订单表,注意:使用事务。因为接下来要插入多张表
with transcation.atomic():obj = models.Order.objects.create(...)
6.2 创建多个订单详细
for k,v in course_dict.items():detail = OrderDetail.objects.create(order=obj)EnrolledCourse.objects.create(..,order_detail=detail)
EnrolledCourse 是 报名专题课表
6.3 更新优惠券
count = models.CouponRecord.objects.filter(id__in=coupon_id_list).update(status=2) if count != len(coupon_id_list):报错..
上面这条数据,表示批量更新。至于count的返回值是什么,我不确定。
在使用更新一条数据时,如果成功返回1,否则返回0
6.4 更新贝里余额
models.account.objects.filter(id=request.user.id).update(balance=F('balance')-balance)
因为需要对某条字段的数值进行更新,需要用到F查询。
6.5 创建贝里转账记录
models.TransactionRecord.objects.create(,,balance)
如果用户使用了贝里抵扣,这里需要创建一条记录才行
7. 生成去支付宝支付的连接
生成链接,主要让ajax跳转的。前端不能直接跳转,需要后端提供链接才行
到这里基本上,就结束了。有兴趣的,可以继续写下面的需求
8. 更新订单状态
obj = models.Order.objects.filter(id=xx).update(payment_type_choices=1,payment_number=xxx,status=0)
payment_type_choices 表示支付方式,1为支付宝。目前只支持支付宝!
payment_number 表示支付第3方订单号。用户付款成功后,支付宝会发送一条POST请求,此时会携带支付宝的订单号。这个字段就是记录它的,用于以后的账单查询!
status=0 表示交易成功
9. 发送一条信息给boss
有人买了课程了,boss当然是很开心的!
相关代码,请访问github
https://github.com/987334176/luffycity/archive/v1.6.zip
作业
1. 结算中心
2. 立即支付
这2个功能,继续完善代码!
路飞学城项目,到这里,就结束了!
没有前端页面,真不好调试。
使用django增加加了几个页面,功能只到购物车!
首页
课程
课程详情
购物车
完整代码,请参数github
https://github.com/987334176/luffycity/archive/v1.7.zip
python 全栈开发,Day106(结算中心(详细),立即支付)相关推荐
- python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)
python 全栈开发,Day104(DRF用户认证,结算中心,django-redis) 考试第二部分:MySQL数据库 6. MySQL中char和varchar的区别(1分) char是定长, ...
- python 全栈开发,Day103(微信消息推送,结算中心业务流程)
python 全栈开发,Day103(微信消息推送,结算中心业务流程) 昨日内容回顾 第一部分:考试题(Python基础)第二部分:路飞相关 1. 是否遇到bug?难解决的技术点?印象深刻的事?- o ...
- 收藏!最详细的Python全栈开发指南 看完这篇你还不会Python全栈开发 你来打我!!!
Python Web全栈开发入门实战教程教程 大家好,我叫亓官劼(qí guān jié ),这个<Python Web全栈开发入门实战教程教程>是一个零基础的实战教程,手把手带你开 ...
- 路飞学城python全栈开发_[Python] 老男孩路飞学城Python全栈开发重点班 骑士计划最新100G...
简介 老男孩&路飞学城Python全栈开发重点班课程,作为Python全栈教学系列的重头戏,投入了全新的课程研发和教学精力,也是Python骑士计划的核心教学,由ALEX老师开班镇守,一线技术 ...
- python 全栈开发之路 day1
python 全栈开发之路 day1 本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可以进 ...
- python 全栈开发,Day45(html介绍和head标签,body标签中相关标签)
python 全栈开发,Day45(html介绍和head标签,body标签中相关标签) 一.html介绍 1.web标准 web准备介绍: w3c:万维网联盟组织,用来制定web标准的机构(组织) ...
- python全栈开发中级班全程笔记(第二模块、第四章)(常用模块导入)
python全栈开发笔记第二模块 第四章 :常用模块(第二部分) 一.os 模块的 详解 1.os.getcwd() :得到当前工作目录,即当前python解释器所在目录路径 impor ...
- 参加python全栈开发培训需要多少钱?
python是一门高级的编程语言,也是非常受欢迎的编程语言,应用领域广泛.薪资待遇高,可以从业范围多,越来越多人都想要学习python,那么参加python全栈开发需要多少钱? 许多人对python的 ...
- python 全栈开发,Day136(爬虫系列之第3章-Selenium模块)
python 全栈开发,Day136(爬虫系列之第3章-Selenium模块) 一.Selenium 简介 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直 ...
最新文章
- css属性pointer-events
- 开发日记-20190821 关键词 读书笔记《掌控习惯》DAY 1
- java 头尾 队列_探索JAVA并发 - 并发容器全家福
- 第三次学JAVA再学不好就吃翔(part6)--基础语法之char数据类型
- 工业交换机安全性能的必要性
- 怎样一次性将一个word文档中所有图片保存
- 计算机与工程建设项目结合,计算机科学与技术在工程建设项目管理中应用.doc...
- 发生心梗后,家属做些什么才能保证患者获救,降低死亡?
- paip.基于navicate mysql的自动化报表工具总结
- 基于SSM框架的公交车调度管理系统
- excel转置怎么操作_EXCEL技巧-行列快速转换
- AD158A4语音芯片介绍
- Visual SourceSafe如何支持并行开发
- RTSP支持MPEG-4格式监控
- 一个游戏策划的八年回忆录
- 如何让消息队列达到最大吞吐量?
- 苏黎世联邦理工学院计算机系研究生,大神offer | 恭喜四位再来人学员斩获苏黎世联邦理工学院-电子工程与信息技术硕士 !...
- 阿里php开发规范,阿里巴巴java开发手册学习记录,php版
- 轨迹时空数据存储对比分析
- Windows Server 2012/2016 在桌面上显示“我的电脑”图标