python 全栈开发,Day100(restful 接口,DRF组件,DRF跨域(cors组件))
昨日内容回顾
1. 为什么要做前后端分离?
- 前后端交给不同的人来编写,职责划分明确。方便快速开发
- 针对pc,手机,ipad,微信,支付宝... 使用同一个接口 2. 简述http协议?
- 基于socket
- 数据格式:
"GET /index?name=123&age=19 http1.1\r\nhost:www.luffyciti.com\r\ncontent-type:application/json...\r\n\r\n" "POST /index http1.1\r\nhost:www.luffyciti.com\r\ncontent-type:application/json...\r\n\r\n{name:'alex',age:18}" "POST /index http1.1\r\nhost:www.luffyciti.com\r\ncontent-type:application/enform.....\r\n\r\nname=alex&age=18&xx=19"
- 无状态短链接
一次请求一次响应之后断开连接 3. 简述restful 规范?
https://www.luffycity.com/api/v1/courses/?sub_category=0
看上面一段url,可以说出5个
1. 使用https代替http 2.在URL中体现自己写的是API 3. 在URL中体现版本 4. 使用名词 5.参数要合理
之后,请求方式,响应信息。可以说后面5个
6. 根据请求方式不同,处理不同的操作 7. 4. django rest framework组件的作用?
- 快速实现restful 规范 5. 列举django rest framework组件(10)? 6. 路飞的表结构
一、restful 接口
根据昨天代码,继续编写。
或者下载代码:
https://github.com/987334176/luffycity/archive/v1.2.zip
注意:删除api目录下的views.py文件,它没有用了
下载数据库使用:
https://github.com/987334176/luffycity/blob/master/db.sqlite3
第一种方式
修改api_urls.py
from django.conf.urls import url
from api.views import course,degreecourse urlpatterns = [
# url(r'login/$', views.LoginView.as_view()),
url(r'courses/$',course.CoursesView.as_view()),
url(r'courses/(?P<pk>\d+)/$',course.CourseDetailView.as_view()), url(r'degreecourse/$',degreecourse.DegreeCourseView.as_view()),
url(r'degreecourse/teachers/$',degreecourse.DegreeCourseTeachersView.as_view()),
url(r'degreecourse/scholarship/$',degreecourse.DegreeCourseScholarshipView.as_view()), ]
修改views目录下的course.py
from rest_framework.views import APIView
from rest_framework.response import Response from api import models
from api.serializers.course import CourseModelSerializer from api.utils.response import BaseResponse
from api.utils.serialization_general import SerializedData class CoursesView(APIView): def get(self, request, *args, **kwargs):
"""
查询所有
:param request:
:param args:
:param kwargs:
:return:
"""
queryset = models.Course.objects.all()
serializer_class = CourseModelSerializer
data = SerializedData(request, queryset, serializer_class).get_data()
return Response(data) def post(self, request, *args, **kwargs):
"""
增加一条
:param request:
:param args:
:param kwargs:
:return:
""" class CourseDetailView(APIView):
def get(self, request, pk,*args, **kwargs):
"""
查询单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
def put(self, request, pk,*args, **kwargs):
"""
修改单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
def delete(self, request, pk,*args, **kwargs):
"""
删除单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
上面的方式,更趋近于原始
第二种方式(推荐)
django-rst-framework为我们提供了ViewSet类, ViewSet为我们提供了默认的URL结构, 使得我们能更专注于API本身. ViewSet类与View类几乎是相同的, 但提供的是read或update, 而不是http动作get或put.
ViewSet类在实例化后, 通过Router类, 最终将URL与ViewSet方法绑定
ViewSet类的父类ViewSetMixin,其实重写了as_view方法
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
"""
Because of the way class based views create a closure around the
instantiated view, we need to totally reimplement `.as_view`,
and slightly modify the view function that is created and returned.
"""
...
那么url方式也发生了变化
修改api_urls.py
from django.conf.urls import url
from api.views import course urlpatterns = [
url(r'courses/$', course.CoursesView.as_view({'get': 'list', 'post': 'create'})),
url(r'courses/(?P<pk>\d+)/$', course.CoursesView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))
]
解释:看这一段{'get':'list','post':'create'}
它表示get请求时,转发到list方法。post请求转发到create方法。
这里面定义的方法名,都是约定俗成的。推荐使用这些名字!也可以自定义。
修改views目录下的course.py
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin
from rest_framework.response import Response from api import models
from api.serializers.course import CourseModelSerializer from api.utils.response import BaseResponse
from api.utils.serialization_general import SerializedData class CoursesView(ViewSetMixin,APIView): def list(self, request, *args, **kwargs):
"""
查询所有
:param request:
:param args:
:param kwargs:
:return:
"""
queryset = models.Course.objects.all()
serializer_class = CourseModelSerializer
data = SerializedData(request, queryset, serializer_class).get_data()
return Response(data) def create(self, request, *args, **kwargs):
"""
增加一条
:param request:
:param args:
:param kwargs:
:return:
""" class CourseDetailView(APIView):
def retrieve(self, request, pk,*args, **kwargs):
"""
查询单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
def update(self, request, pk,*args, **kwargs):
"""
修改单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
def destroy(self, request, pk,*args, **kwargs):
"""
删除单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
以上方式适用于:用户请求处理时业务逻辑复杂的情况。
注意:如果继承了GenericViewSet,并且返回序列化数据使用了Response
必须要定义queryset属性,否则报错
看源码
必须要定义queryset变量,否则执行assert(断言)。
还有一种解决方式,使用JSONRenderer。它也可以返回json数据,但是没有像Response那样,有好看的页面!
三、DRF跨域(cors组件)
运行的vue项目,发现出现跨域
查看Pycharm控制台输出:
[18/Aug/2018 20:14:31] "GET /api/v1/courses/ HTTP/1.1" 200 212
可以发现,请求实际已经到达了后端。并且做了正确的返回,但是浏览器拒绝接收!
这为什么呢?这是因为浏览器的同源策略
1.什么是同源策略
2.同源策略的目的
关于更多的同源策略信息,请参考链接:
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
总结:
浏览器具有同源策略,打开某个网站后,通过ajax向另外一个网站发送http请求时候,数据回来时会被浏览器阻止(跨域)
解决跨域
方式一
在api端设置响应头 CORS
修改views目录下的course.py,增加响应头
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin
from rest_framework.response import Response from api import models
from api.serializers.course import CourseModelSerializer from api.utils.response import BaseResponse
from api.utils.serialization_general import SerializedData class CoursesView(ViewSetMixin,APIView): def list(self, request, *args, **kwargs):
"""
查询所有
:param request:
:param args:
:param kwargs:
:return:
"""
queryset = models.Course.objects.all()
serializer_class = CourseModelSerializer
data = SerializedData(request, queryset, serializer_class).get_data()
# 增加响应头,http://localhost:8080表示前端的地址
return Response(data,headers={'Access-Control-Allow-Origin': 'http://localhost:8080'}) def create(self, request, *args, **kwargs):
"""
增加一条
:param request:
:param args:
:param kwargs:
:return:
""" class CourseDetailView(APIView):
def retrieve(self, request, pk,*args, **kwargs):
"""
查询单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
def update(self, request, pk,*args, **kwargs):
"""
修改单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
def destroy(self, request, pk,*args, **kwargs):
"""
删除单个
:param request:
:param pk:
:param args:
:param kwargs:
:return:
"""
Access-Control-Allow-Origin字段,表示http://localhost:8080可以请求数据。该字段也可以设为星号,表示同意任意跨源请求
客户端浏览器检查自己的域是否在允许列表中,决定是否处理响应
刷新vue页面,发现没有报错了。说明接收了数据!
上面是简单请求
简单请求 OR 非简单请求
条件:
1、请求方式:HEAD、GET、POST
2、请求头信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 对应的值是以下三个中的任意一个
application/x-www-form-urlencoded
multipart/form-data
text/plain
注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
简单请求和非简单请求的区别
简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用
关于"预检"
- 请求方式:OPTIONS
- "预检"其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何"预检"
=> 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则"预检"不通过
Access-Control-Request-Method
=> 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则"预检"不通过
Access-Control-Request-Headers text/plain
数据展示
修改settings.py,将分页改成20
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
'VERSION_PARAM':'version',
'DEFAULT_VERSION':'v1',
'ALLOWED_VERSIONS':['v1','v2'],
'PAGE_SIZE':20,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
}
修改vue项目的HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h1>课程列表</h1>
<ul v-for="item in courseList">
<li>{{item.name}}</li>
</ul>
</div>
</template> <script>
export default {
name: 'HelloWorld',
data () {
return {
msg: '欢迎使用路飞学城',
courseList:[],
}
},
mounted(){ //页面加载完成后
this.initCourse(); //执行此方法
},
methods:{
initCourse:function () {
let that = this
//向后台发送ajax请求
this.$axios.request({
url:'http://127.0.0.1:8000/api/v1/courses/',
method:'GET',
responseType:'json',
}).then(function (arg) {
//成功之后
console.log(arg);
if (arg.data.code == 1000){
//更新数据
that.courseList = arg.data.data;
}else {
//弹出错误
alert(arg.data.error);
} }).catch(function (err) {
//发生错误
console.log(err);
})
}
},
}
</script> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
刷新网页,效果如下:
第二种
使用自定义中间件
修改views目录下的course.py,去掉headers
def list(self, request, *args, **kwargs):
"""
查询所有
:param request:
:param args:
:param kwargs:
:return:
"""
queryset = models.Course.objects.all()
serializer_class = CourseModelSerializer
data = SerializedData(request, queryset, serializer_class).get_data()
return Response(data)
在api目录下创建md文件夹,在里面创建cors.py
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings class CorsMiddleware(MiddlewareMixin): def process_response(self,request,response):
# 设置响应头
response['Access-Control-Allow-Origin'] = 'http://localhost:8080' return response
修改settings.py,注册自定义中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'api.md.cors.CorsMiddleware',
]
刷新vue页面,效果同上!
模拟复杂请求
修改HelloWorld.vue,增加登录按钮。发送固定的用户名和密码,指定数据格式为json
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<button v-on:click="doLogin">登录</button>
<h1>课程列表</h1>
<ul v-for="item in courseList">
<li>{{item.name}}</li>
</ul>
</div>
</template> <script>
export default {
name: 'HelloWorld',
data () {
return {
msg: '欢迎使用路飞学城',
courseList:[],
}
},
mounted(){ //页面加载完成后
this.initCourse(); //执行此方法
},
methods:{
initCourse:function () {
let that = this
//向后台发送ajax请求
this.$axios.request({
url:'http://127.0.0.1:8000/api/v1/courses/',
method:'GET',
responseType:'json',
}).then(function (arg) {
//成功之后
console.log(arg);
if (arg.data.code == 1000){
//更新数据
that.courseList = arg.data.data;
}else {
//弹出错误
alert(arg.data.error);
} }).catch(function (err) {
//发生错误
console.log(err);
})
},
doLogin(){
this.$axios.request({
url:'http://127.0.0.1:8000/api/v1/auth/',
method:'POST',
data:{
//用户名和密码
user:'xiao',
pwd:'',
},
//增加headers头
headers:{
//指定数据格式
'Content-Type':'application/json',
},
//响应格式为json
responseType:'json',
}).then(function (arg) {
//成功之后
console.log(arg);
}).catch(function (err) {
//发生错误
console.log(err);
})
}
},
}
</script> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
修改api_urls.py,增加路径
from django.conf.urls import url
from api.views import course,auth urlpatterns = [
url(r'auth/$', auth.AuthView.as_view({'post': 'login'})),
url(r'courses/$', course.CoursesView.as_view({'get': 'list', 'post': 'create'})),
url(r'courses/(?P<pk>\d+)/$', course.CoursesView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))
]
在views目录下,创建文件auth.py
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin
from rest_framework.response import Response from api import models
from api.serializers.course import CourseModelSerializer from api.utils.response import BaseResponse
from api.utils.serialization_general import SerializedData class AuthView(ViewSetMixin,APIView):
def login(self, request, *args, **kwargs):
print('用户发了POST请求了',request)
return Response({'code':'ok'})
刷新vue页面,点击登录
查看Console,提示对方不允许
查看Network,它是一个OPTIONS请求
查看Pycharm控制台输出:
[18/Aug/2018 21:37:04] "OPTIONS /api/v1/auth/ HTTP/1.1" 200 163
通过以上信息,可以看出。浏览器发送OPTIONS请求,也就是在预检。但是后端没有同意,所以浏览器没有发送POST请求。
怎么才能让它通过预检呢?
修改md目录下的cors,做一个if判断,允许一下!
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings class CorsMiddleware(MiddlewareMixin): def process_response(self,request,response):
# 设置响应头
response['Access-Control-Allow-Origin'] = 'http://localhost:8080'
# 当为OPTIONS时
if request.method == "OPTIONS":
# 允许通过的请求方式
response["Access-Control-Allow-Methods"] = "POST,PUT,DELETE"
# 允许通过的请求头
response["Access-Control-Allow-Headers"] = "Content-Type" return response
刷新页面,再次点击登录
查看Console,发现请求正常
查看Network,发现有2次请求
查看第一个请求,它是OPTIONS请求方式
查看第二个请求,它是POST请求方式
查看Pycharm控制台输出:
[18/Aug/2018 21:43:24] "GET /api/v1/courses/ HTTP/1.1" 200 394
[18/Aug/2018 21:43:32] "OPTIONS /api/v1/auth/ HTTP/1.1" 200 163
用户发了POST请求了 <rest_framework.request.Request object at 0x0000024630CD85C0>
[18/Aug/2018 21:43:32] "POST /api/v1/auth/ HTTP/1.1" 200 13
通过以上信息,可以看到。数据接收正常!
通过这样,无论是简单,还是复杂,都允许。
django cors组件
CORS,全称为跨域资源共享。它允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。
上面的cors.py,帮我们实现了cors。这个手写的,但是官方提供了cors组件,专门用来解决跨域问题的!
1.安装django-cors-headers
pip install django-cors-headers
2.配置settings.py文件
INSTALLED_APPS = [
...
'corsheaders', # 注册应用cors
] MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware', # 注册组件cors )
#跨域增加忽略
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
'*'
) CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
) CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)
注释掉自定义组件,settings.py完整代码如下:
"""
Django settings for s11luffycity project. Generated by 'django-admin startproject' using Django 1.11. For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
""" import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '-i@r%a=tf*0n6!kzd=m#gx9g82i7@!x=n9jx=jta&(7%zw67#!' # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api.apps.ApiConfig',
'rest_framework',
'corsheaders', # 注册应用cors
] MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# 'api.md.cors.CorsMiddleware',
'corsheaders.middleware.CorsMiddleware', # 注册组件cors
] ROOT_URLCONF = 's11luffycity.urls' TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
] WSGI_APPLICATION = 's11luffycity.wsgi.application' # Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
} # Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
] # Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/'
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
'VERSION_PARAM':'version',
'DEFAULT_VERSION':'v1',
'ALLOWED_VERSIONS':['v1','v2'],
'PAGE_SIZE':20,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
} #跨域增加忽略
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
'*'
) CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
) CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)
重启django项目,刷新页面,重启登录。效果同上!
OK!问题解决!
本文参考:
https://blog.csdn.net/apple9005/article/details/54427902
python 全栈开发,Day100(restful 接口,DRF组件,DRF跨域(cors组件))的更多相关文章
- python 全栈开发,Day101(redis操作,购物车,DRF解析器)
昨日内容回顾 1. django请求生命周期? - 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端 请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者po ...
- python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)
一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...
- python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)
昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...
- Python全栈开发【面向对象】
Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...
- Python全栈开发【模块】
Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...
- python 全栈开发之路 day1
python 全栈开发之路 day1 本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...
- python全栈开发中级班全程笔记(第二模块、第四章)(常用模块导入)
python全栈开发笔记第二模块 第四章 :常用模块(第二部分) 一.os 模块的 详解 1.os.getcwd() :得到当前工作目录,即当前python解释器所在目录路径 impor ...
- 学习笔记之Python全栈开发/人工智能公开课_腾讯课堂
Python全栈开发/人工智能公开课_腾讯课堂 https://ke.qq.com/course/190378 https://github.com/haoran119/ke.qq.com.pytho ...
- python全栈开发目录
python全栈开发目录 Linux系列 python基础 前端~HTML~CSS~JavaScript~JQuery~Vue web框架们~Django~Flask~Tornado 数据库们~MyS ...
随机推荐
- 【收藏】轻松导出全民K歌里任何人录制的短视频(MV)、歌曲的方法
有一次想把她在全民K歌里唱过的所有歌下载到电脑上,然后合成一个视频.但不知道怎么导出全民K歌里的歌曲,经过各种百度Google终于找到了一个用起来很简单的工具.不仅可以下载保存任何人录制的歌曲,还可以 ...
- 版本管理——git
一.git简介 git是一个 分布式版本控制系统 ,学习git之前首先要了解什么是分布式版本控制系统. 集中式版本控制:版本库集中存放在中央服务器,我们工作的时候先从中央服务器获取最新版本,干完活后把 ...
- jackson的自动检测机制
jackson允许使用任意的构造方法或工厂方法来构造实例 使用@JsonAutoDetect(作用在类上)来开启/禁止自动检测 fieldVisibility:字段的可见级别 ANY:任何级别的字段都 ...
- windows Zookeeper本地服务化
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功 ...
- PHP7 学习笔记(三)关于PHP7如何安装调试工具Xdebug扩展以及Zephir的问题
前言: 1.自己摸索安装 2.快速安装 安装这个扩展是由于Zephir 编译不能始终通过,迫不得已啊,使用Zephir写扩展,总是出现以下错误: www@ubuntu1:~/phalcon-zephi ...
- 工控安全入门之Ethernet/IP
这一篇依然是协议层面的,协议层面会翻译三篇,下一篇是电力系统中用的比较多的DNP3.这一篇中大部分引用的资料都可以访问到,只有一篇reversemode.com上的writeup(http://rev ...
- android SQLiteOpenHelper 使用
1.实体 package mydemo.mycom.demo2.entity; public class UserInfo { private int id; private String usern ...
- Java SE之反射技术[Class](三)
/** * * @author Zen Johnny * */ package com.cpms.test; import java.lang.reflect.Field; import java.u ...
- Eclipse通用设置
分类 Eclipse分为64位.32位,安装版.免安装版 查看Eclipse版本信息 Help - About Eclipse - Installation Details
- Linux inotify功能及实现原理【转】
转自:http://blog.csdn.net/myarrow/article/details/7096460 1. inotify主要功能 它是一个内核用于通知用户空间程序文件系统变化的机制. 众所 ...