目录

昨日补充:将自己写的 login_auth 装饰装在 CBV 上

类里面的方法一般都是类绑定方法 或者 对象绑定方法,第一个参数是类 或者 对象本身,那么前面写的装饰器就要改参数才能用了,不过这里我们可以用 django 给我们写好的装饰器,从不需要更改写好的装饰器

三种方式 (别忘了导模块)

from django.utils.decorators import method_decorator

# @method_decorator(login_auth, name='get')  # 第一种, name 参数必须指定
class MyHome(View):
# @method_decorator(login_auth) # 第二种, get 和 post 都会被装饰(登录验证)(直接把 dispatch 拿过来,加个装饰器)
def dispatch(self, request, *args, **kwargs):
super().dispatch(request, *args, **kwargs) @method_decorator(login_auth) # 第三种,直接装饰在单个方法上
def get(self, request):
return HttpResponse('get') def post(self, request):
return HttpResponse('post')

django 中间件

django 中间件 就类似于是 django 的门户,请求来的时候需要先经过 中间件 才能到达 django 后端(urls),响应走的时候也需要经过 中间件 才能到达 web服务网关接口(wsgif 模块)

django 中间件可以用来做什么

  • 做网站全局的身份校验,限制访问频率,权限校验(反爬)... 只要是涉及到全局的校验几乎都可以在中间件中完成,第一时间该想到的也是中间件

django 的中间件是设计比较完善的,逻辑最清晰,最简单(flask的中间件不如它)

讲完这个中间件就知道为什么我们前面每次提交 post 请求都会写上先去 settings.py 里把 csrf 这个中间件暂时注释掉了

django 请求生命周期 *****

经过 中间件 之后才能进入 urls.py(再 views.py ... 一层一层递进)

科普:

  1. wsgiref 不能够承受高并发,所以上线之后会换成 uwsgi 模块(前面再加一个 nginx 做反向代理)
  • WSGI 与 wsgi 以及 uwsgi 分别什么意思

​ WSGI是一个协议标准,wsgiref 和 uwsgi 都是实现了 WSGI 协议的功能模块

  1. 请求在进入第一层中间件时会去缓存数据库中判断有没有数据
  • 如果有的话会直接拿到数据并返回请求(这样可以节约资源,降低服务器以及数据库的压力)
  • 如果没有的话会接着一层一层地走中间件,然后路由配置、views.py ...,等请求再次来到最后一层中间件时,在返回数据的同时,会保存一份在缓存数据库中。(下次就可以直接在缓存数据库中拿到数据了)

具体原理等后期涉及到展开来讲, 先知道这个概念就行

默认中间件及其大概方法组成

django 默认有七个中间件

django 支持用户自定义自己的中间件,并且暴露给用户,还暴露给用户五个可以自定义中间件的方法

# 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',
]

点进去观察 中间件源码

'''
django.middleware.security.SecurityMiddleware
--> 本质是动态导入(可以看最后面的那个模仿案例)
# from django.middleware.security import SecurityMiddleware django.middleware.csrf.CsrfViewMiddleware
--> from django.middleware.csrf import CsrfViewMiddleware
'''

发现 **django 中间件 **中有五个用户可以自定义的方法

# django.middleware.csrf.CsrfViewMiddleware  --> from django.middleware.csrf import CsrfViewMiddleware
class CsrfViewMiddleware(MiddlewareMixin):
def _accept(self, request):
def _reject(self, request, reason):
def _get_token(self, request):
def _set_token(self, request, response):
def process_request(self, request):
def process_view(self, request, callback, callback_args, callback_kwargs):
def process_response(self, request, response): # django.middleware.security.SecurityMiddleware --> django.middleware.security.SecurityMiddleware
class SecurityMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
def process_request(self, request):
def process_response(self, request, response): # django.contrib.sessions.middleware.SessionMiddleware
class SessionMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
def process_request(self, request):
def process_response(self, request, response):
  • 需要我们掌握的方法有
  1. process_ request() 方法
  2. process_ response ()方法
  • 需要了解的方法
  1. process_ view()
  2. process exception ()
  3. process_ template_ response ()

中间件的执行顺序

大体同 django 请求生命周期 那张图,可能会受以下情况的影响

自定义中间件探究不同操作对中间件执行顺序的影响

测试思路:

  • 在 settings.py 里注册不同中间件,探究默认的执行顺序
  • 在不同中间件的 process_request 和 process_response 等方法中 return HttpResponse 对象会对执行顺序造成什么影响
  • 了解五种方法的触发时机

自定义中间件

  1. 新建一个文件夹(放在全局或 app 内)
  2. 写一个类继承 MiddlewareMiXin 类
  3. 里面书写需要的(五个方法中的某些)方法
  4. 一定要在 settings.py 里配置中间件

代码

mymiddleware/mdd.py 自定义中间件

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse class MyMdd(MiddlewareMixin):
def process_request(self, request):
print('我是第一个中间件里面的process_request方法') def process_response(self, request, response):
print('我是第一个中间件里面的process_response方法')
return response def process_view(self, request, view_func, view_args, view_kwargs):
print(view_func)
print(view_args)
print(view_kwargs)
print('我是第一个中间件里面的process_view方法') def process_exception(self, request, exception):
print('我是第一个中间件里面的process_exception') def process_template_response(self, request, response):
print('我是第一个中间件里面的process_template_response')
return response class MyMdd1(MiddlewareMixin):
def process_request(self, request):
print('我是第二个中间件里面的process_request方法') def process_response(self, request, response):
print('我是第二个中间件里面的process_response方法')
return response def process_view(self, request, view_func, view_args, view_kwargs):
print(view_func)
print(view_args)
print(view_kwargs)
print('我是第二个中间件里面的process_view方法') def process_exception(self, request, exception):
print('我是第二个中间件里面的process_exception') def process_template_response(self, request, response):
print('我是第二个中间件里面的process_template_response')
return response class MyMdd2(MiddlewareMixin):
def process_request(self, request):
print('我是第三个中间件里面的process_request方法') def process_response(self, request, response):
print('我是第三个中间件里面的process_response方法')
return response def process_view(self, request, view_func, view_args, view_kwargs):
print(view_func)
print(view_args)
print(view_kwargs)
print('我是第三个中间件里面的process_view方法') def process_exception(self, request, exception):
print('我是第三个中间件里面的process_exception') def process_template_response(self, request, response):
print('我是第三个中间件里面的process_template_response')
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',
'mymiddleware.mdd.MyMdd', # 配置上
'mymiddleware.mdd.MyMdd1', # 配置上
'mymiddleware.mdd.MyMdd2', # 配置上
]

需要掌握的方法

process_request

请求来的时候会依次执行 settings.py 配置文件中注册了的中间件里的该方法

  • 如果没有该方法则直接跳过,走下一个中间件
  • 如果该方法里返回了 HttpResponse 对象,那么会直接从当前中间件的 process_response 方法 从下往上依次执行返回,不会再接着往下执行
  • 执行顺序:从上往下
  • 该方法可以实现对用户身份的校验,访问频率的限制,用户权限的校验...

基于该特点就可以做访问频率限制

process_response

响应走的时候会依次执行 settings.py 配置文件中注册了的中间件里的该方法(必须将 response 形参返回,因为这个 response 指代的就是返回给前端的数据)

  • 如果没有该方法则直接跳过,走下一个中间件
  • 执行顺序:从下往上
  • 该方法可以帮你实现缓存机制(减缓服务器、数据库的压力)

需要了解的方法

process_view

路由匹配成功 执行视图函数之前 自动触发(从上往下依次执行)

process_exception

视图函数报错了,自动触发(从下往上依次执行)

process_template_response

视图函数返回的 HttpResponse 对象中包含了 render 属性时会触发,或者是表明一个对象时 TemplateResponse 对象或等价方法 的时候也会触发(从下往上依次执行)

def index(request):
print("我是 index 视图函数")
def render():
return HttpRespone('用户最终能够看到的结果') # ******
obj = HttpResponse('index')
obj.render = render # 返回的 HttpResponse 对象中必须包含 render 属性,才能触发中间件里定义的 process_template_response 方法
return obj

强调:

在写中间件的时候,只要形参中有 response ,就要记得将其返回,这个Response 是要给前端的信息

csrf 中间件 跨站请求伪造

钓鱼网站

原理:写了一个一模一样的网站,一个隐藏框,发送往隐藏当做收钱方

问题:如何区分当前用户朝我们网站发送的请求页面是不是我们本网站给的

防止思路

网站会给返回给用户的 form 表单页面 偷偷塞一个随机字符串

请求到来的时候,会先比对随机字符串是否一致,如果不一致,直接拒绝(403 FORBIDDEN)

解决方案

在页面上放一个 隐藏的 input 框,value 里面放的是一个字符串,每次刷新都会更新里面的 value,这样别人的网站就不知道;,这个 value 就无法伪造了

django 的实现 {% csrf_token %}

该随机字符串有以下特点:

  • 同一个浏览器每一次访问都不一样
  • 不同浏览器绝对不一样

post请求提交数据通过 csrf 校验

form 表单

form 表单发送 post 请求的时候,需要你做的是写一段代码 {% csrf_token %} 即可,不需要注释 csrf 中间件了

ajax 发送

三种方式(第三种可以用在前后端分离时)

  1. 先在页面上写 {% csrf_token %},利用标签查找,获取到该 input 键值信息,放到 data 里

  2. ajax data 值 那里直接写 {{ csrf_token }}data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},

  3. 参考官方文档推荐,自定义 js 文件,在要用到的页面载入这个 js 脚本,自动获取并传递 csrf 校验 *****

    • 你可以将下面的 js 代码 放到一个 js 文件中
    // js 代码(一般放在 static 文件夹下)
    function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
    var cookies = document.cookie.split(';');
    for (var i = 0; i < cookies.length; i++) {
    var cookie = jQuery.trim(cookies[i]);
    // Does this cookie string begin with the name we want?
    if (cookie.substring(0, name.length + 1) === (name + '=')) {
    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
    break;
    }
    }
    }
    return cookieValue;
    } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    } $.ajaxSetup({
    beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
    xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
    }
    });
    • 之后要用到的的地方 <script src="{% static 'setjs.js' %}"></script> 导入就行
    • 这样就不需要 在 html 中写 {% csrf_token %} 或在 ajax 中写 {{ csrf_token }}

csrf 装饰器相关

其他中间件也可以效仿下面的方法来校验或者取消校验

两个问题

当你网站全局都需要校验 csrf 的时候(未注释掉 csrf 中间件时),有几个不需要校验该如何处理? @csrf_exempt

当你的网站全局不校验 csrf 的时候(注释掉 csrf 中间件时),有几个需要校验该如何处理 ?@csrf_protect

未注释掉 csrf 中间件时 单功能取消 csrf 校验:csrf_exempt

FBV

from django.views.decorators.csrf import csrf_exempt

# 全局开启时,局部禁用
@csrf_exempt
def index(request):
pass

CBV

有两种方式,不能针对单个方法,是针对全局的

# CBV比较特殊,不能单独加在某个方法上
# 只能加在类上或dispatch方法上
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt # @method_decorator(csrf_exempt,name='dispatch') # 第一种
class Csrf_Token(View):
@method_decorator(csrf_exempt) # 第二种
def dispatch(self,request,*args,**kwargs):
res = super().dispatch(request,*args,**kwargs)
return res
# @method_decorator(csrf_exempt) # 这里这么写不行!!!
def get(self,request):
pass
def post(self,request):
pass

注释掉 csrf 中间件时 单功能开启 csrf 校验:csrf_protect

FBV

from django.views.decorators.csrf import csrf_protect

@csrf_protect
def lll(request):
return HttpResponse('lll')

CBV 还要改改

有三种方式,既可以针对全局的,也可以针对单个的

from django.views.decorators.csrf import csrf_protect

from django.views import View
from django.utils.decorators import method_decorator # 第一种方式
# @method_decorator(csrf_protect,name='post') # 有效的
class MyView(View):
@method_decorator(csrf_protect) # 第三种方式
def dispatch(self, request, *args, **kwargs):
res = super().dispatch(request, *args, **kwargs)
return res def get(self, request):
return HttpResponse('get') # 第二种方式
# @method_decorator(csrf_protect) # 有效的
def post(self, request):
return HttpResponse('post')

总结:csrf 装饰器中只有 csrf_exempt 是特例,其他的装饰器在给CBV 装饰的时候 都可以有三种方式

Auth 模块

科普提示小点:

  • 一个方法的放回结果打印出来是 “字符串” 最好 type 确认一下,可能是对象重写了 __str__() 方法
  • django 后台管理只有超级用户才能进入
  • 用了 Auth 模块的方法 ,就最好都用 Auth 模块的方法
  • 修改密码必须调用 .save() 保存,否则无效

使用 django 自带的 auth 表做登录功能

涉及到的 auth 相关方法

python3 manage.py createsuperuser  # 命令行下创建超级用户(可以拥有登录 django admin 后台管理的权限)

# 查询用户是否存在
user_obj = auth.authenticate(username=username, password=password) # 数据库中的密码是密文的(该方法不能只传用户名一个参数),返回值要么是对象,要么是 None # 记录用户状态
auth.login(request, user_obj) # 登录,会自动存 session
# 优点:只要执行了这一句话,你就可以在后端任意位置通过 request.user 拿到当前登录的用户对象(未登录会报错,AnonymousUser 匿名用户) # 获取用户对象
request.user # 用户登录了直接获取用户对象,用户没登录获取到 AnonymousUser 匿名用户 # 判断当前用户是否登录,未登录(AnonymousUser)会返回 False,其他情况下返回 True
request.user.is_authenticated # 验证用户密码是否正确
is_right = request.user.check_password(old_password) # 将获取的用户密码,自动加密,然后去数据库中对比(返回布尔值) # 修改密码
request.user.set_password(new_password) # 修改密码
request.user.save() # 需要保存才能生效 # 注销用户
auth.logout(request) # 等价于 request.session.flush() (删除了 session
表中记录,浏览器 cookie) # 登录验证装饰器
from django.contrib.auth.decorators import login_required # @login_required # 自动校验当前用户是否登录,如果没有登录,(未传参数的情况下)默认跳转到 django 自带的登录页面(还是 404 ?)
# ------ 局部配置
@login_required(login_url='/login/')
def set_password(request):
pass # ------ 全局配置(不用在里面写配置了)
# 在 settings.py 中写
LOGIN_URL = '/login/' # 注册用户
from django.contrib.auth.models import User # 这就是那张 auth 表
# 创建普通用户
User.objects.create_user(username=username, password=password)
# 创建超级用户
User.objects.create_superuser(username=username, password=password, email='12323132@qq.com') # 创建超级用户必须传邮箱
# 不能用 User.objects.create(username=username, password=password) (这样密码没有加密)

核心代码

app01/views.py

from django.shortcuts import render, HttpResponse
from django.contrib import auth def xxx(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 取数据库查询当前用户数据
# models.User.objects.filter(username=username,password=password).first()
user_obj = auth.authenticate(username=username, password=password) # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文
print(user_obj)
# print(user_obj)
# print(user_obj.username)
# print(user_obj.password)
# 保存用户状态
# request.session['user'] = user_obj
auth.login(request, user_obj) # 将用户状态记录到session中
"""只要执行了这一句话 你就可以在后端任意位置通过request.user获取到当前用户对象"""
return render(request, 'xxx.html') def yyy(request):
print(request.user) # 如果没有执行auth.login那么拿到的是匿名用户
print(request.user.is_authenticated) # 判断用户是否登录 如果是你们用户会返回False
# print(request.user.username)
# print(request.user.password)
return HttpResponse('yyy') from django.contrib.auth.decorators import login_required # 修改用户密码
@login_required # 自动校验当前用户是否登录 如果没有登录 默认跳转到 一个莫名其妙的登陆页面
def set_password(request):
if request.method == 'POST':
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
# 先判断原密码是否正确
is_right = request.user.check_password(old_password) # 将获取的用户密码 自动加密 然后去数据库中对比当前用户的密码是否一致
if is_right:
print(is_right)
# 修改密码
request.user.set_password(new_password)
request.user.save() # 修改密码的时候 一定要save保存 否则无法生效
return render(request, 'set_password.html') @login_required
def logout(request):
# request.session.flush()
auth.logout(request)
return HttpResponse("logout") from django.contrib.auth.models import User def register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user_obj = User.objects.filter(username=username)
if not user_obj:
# User.objects.create(username =username,password=password) # 创建用户名的时候 千万不要再使用create 了
# User.objects.create_user(username =username,password=password) # 创建普通用户
User.objects.create_superuser(username=username, password=password, email='123@qq.com') # 创建超级用户
return render(request, 'register.html')

自定义扩展 autor 表字段

前提:

settings.py 添加额外配置

# ... 其他配置
# 告诉 django 不再使用 auth 默认的表 而是使用你自定义的表
AUTH_USER_MODEL = 'app01.Userinfo' # '应用名.模型表类名'
# ... 其他配置

两种方式

app01/models.py

from django.db import models
from django.contrib.auth.models import AbstractUser # Create your models here.
# 第一种 使用一对一关系 不考虑 # 第二种方式 使用类的继承
class Userinfo(AbstractUser):
# 千万不要跟原来表(AbstractUser)中的字段有冲突
phone = models.BigIntegerField()
avatar = models.CharField(max_length=32)
# 别忘了去 settings.py 里配置

后续操作

执行数据库迁移命令(python3 manage.py makemigrations、python3 manage.py migrate

这样以后,所有的 auth 模块功能,全部都基于你创建的表,而不再使用 auth_user(不会再自动创那些表了)

效仿 django中间件配置 实现 功能插拔式效果

django 的中间件 其实就是一个类,一个个功能可以写成类,注释掉就不执行了

我们效仿中间件(后面要学的 restframework 的设计思想也是这样的),做一个通知功能, 可以发微信通知、短信通知、右键通知

代码实现

重点配置部分(设计思想好好学学)

start.py 入口文件

import notify

notify.send_all('国庆放假了 记住放八天哦')

notify/__init__.py 关键代码(结合了 importlib 动态导入、反射 等知识点)

import settings
import importlib def send_all(content):
for path_str in settings.NOTIFY_LIST: # 1.拿出一个个的字符串 'notify.email.Email'
module_path, class_name = path_str.rsplit('.', maxsplit=1) # 2.从右边开始 按照点切一个 ['notify.email', 'Email']
module = importlib.import_module(module_path) # from notity import msg/email/wechat
cls = getattr(module, class_name) # 利用反射 一切皆对象的思想 从文件中获取属性或者方法 cls = 一个个的类名
obj = cls() # 类实例化生成对象
obj.send(content) # 对象调方法

settings.py 配置(可以在这里开启或关闭功能)

NOTIFY_LIST = [
'notify.email.Email',
'notify.msg.Msg',
# 'notify.wechat.WeChat', # 注释掉了,这个功能就不执行了
'notify.qq.QQ',
]

功能扩展部分

然后是各个功能的文件(拆分成了各个文件,搭配 settings.py 起到可插拔式效果),要想新增这种功能直接加个文件实现这几个代码即可

notify/email.py

class Email(object):
def __init__(self):
pass # 发送邮件需要的代码配置 def send(self, content):
print('邮件通知:%s' % content)

notify/msg.py

class Msg(object):
def __init__(self):
pass # 发送短信需要的代码配置 def send(self, content):
print('短信通知:%s' % content)

notify/qq.py

class QQ(object):
def __init__(self):
pass # 发送qq需要的代码准备 def send(self, content):
print('qq通知:%s' % content)

notify/wechat.py

class WeChat(object):
def __init__(self):
pass # 发送微信需要的代码配置 def send(self, content):
print('微信通知:%s' % content)
补充:pycharm 使用技巧

想知道当前跳进来的代码的位置,可以点击图中的图标,快速定位,可以让你知道目录结构(看看推测对不对)

Django-中间件-csrf扩展请求伪造拦截中间件-Django Auth模块使用-效仿 django 中间件配置实现功能插拔式效果-09的更多相关文章

  1. Django中间件-跨站请求伪造-django请求生命周期-Auth模块-seettings实现可插拔配置(设计思想)

    Django中间件 一.什么是中间件 django中间件就是类似于django的保安;请求来的时候需要先经过中间件,才能到达django后端(url,views,models,templates), ...

  2. cbv装饰器 中间件 跨站请求伪造

    给cbv下面的函数加装饰器 写一个验证用户登录的程序 前端页面 # 写一个装饰器验证session def login_auth(func): def inner(request,*args,**kw ...

  3. django之跨站请求伪造csrf

    目录 跨站请求伪造 csrf 钓鱼网站 模拟实现 针对form表单 ajax请求 csrf相关的两个装饰器 跨站请求伪造 csrf 钓鱼网站 就类似于你搭建了一个跟银行一模一样的web页面 , 用户在 ...

  4. Django SCRF跨站点请求伪造

    使用Django发POSTt请求的时候经常会遇到Forbidden的错误,然后直接了当的方法就是去setting里面吧csrf中间件注释掉,其实csrf是django给我们提供的防护措施. CSRF就 ...

  5. django的权限认证:登录和退出。auth模块和@login_required装饰器

    在settings.py中配置LOGIN_URL参数: # 用户访问带有(@login_required)标签的页面(view)时,如果没有登录,就会跳转到LOGIN_URL(即登陆url). LOG ...

  6. WebAuthorize(中间件对所有请求进行拦截)core只有通过添加中间件过滤请求方式 而非继承然后写特性的那种方式

    一.WebAuthorize 1.项目名称 WebAuthorize 2.加个中间件 过滤请求. using Microsoft.AspNetCore.Builder; using Microsoft ...

  7. [Django高级之中间件、csrf跨站请求伪造]

    [Django高级之中间件.csrf跨站请求伪造] Django中间件 什么是中间件? Middleware is a framework of hooks into Django's request ...

  8. csrf跨站请求伪造、csrf相关装饰器、auth认证模块、基于django中间件设计项目功能

    目录 csrf跨站请求网站 什么是csrf跨站请求网站 经典例子-钓鱼网站 模拟 如何避免这种现象(预防) 如何在django中解决这个问题 form表单 ajax csrf相关装饰器 FBV CBV ...

  9. Django CBV装饰器 中间件 auth模块 CSRF跨站请求

    CBV添加装饰器 给CBV添加装饰器有三种方法,三种方法都需要导入模块: from django.utils.decorators import method_decorator 第一种直接在方法上面 ...

随机推荐

  1. wav封装格式

    wav文件格式作为一种常用的多媒体音频文件格式,其由MS在1991年8月在Windows 3.1上推出,文件扩展名为WAV,是WaveFom的简写.通常存储未压缩的pcm数据,也可存储压缩的pcm数据 ...

  2. Eclipse中安装JRebel热部署教程

    Eclipse中安装JRebel热部署教程 前言        Eclipse安装JRebel插件可快速实现热部署,节省了大量重启时间,提高开发效率. 本文只介绍Eclipse安装JRebel插件版本 ...

  3. Spring MVC内置支持的4种内容协商方式【享学Spring MVC】

    每篇一句 十个光头九个富,最后一个会砍树 前言 不知你在使用Spring Boot时是否对这样一个现象"诧异"过:同一个接口(同一个URL)在接口报错情况下,若你用rest访问,它 ...

  4. 图解一致性hash算法和实现

    更多内容,欢迎关注微信公众号:全菜工程师小辉.公众号回复关键词,领取免费学习资料. 一致性hash算法是什么? 一致性hash算法,是麻省理工学院1997年提出的一种算法,目前主要应用于分布式缓存当中 ...

  5. python学习——列表和元组

    一.列表 1)列表介绍 列表是Python内置的一种数据类型. >一组有序项目的集合(从第一个成员序号为0开始依次递增排序) >可变的数据类型(可进行增删改查) >列表中可以包含任何 ...

  6. SpringBoot读取配置文件源码探究

    1. SpringBoot读取配置文件源码探究 1.1. 概览 springboot的源码是再原来的Spring源码上又包了一层,看过spring源码都知道,当我们从入口debug进去的时候,原来的S ...

  7. DOM选择器之元素选择器

    DOM中元素选择器 在DOM中我们可以将元素选择器分为两类:1.元素节点选择器:2.其它节点选择器.通过选择器选择HTML中的元素以对其进行操作,以此实现用JS对页面的操作. 一.元素节点选择器 1. ...

  8. Javaweb之文件的上传与下载

    Javaweb之文件的上传与下载 一.基于表单的文件上传 如果在表单中使用表单元素 <input type=“file” />,浏览器在解析表单时,会自动生成一个输入框和一个按钮,输入框可 ...

  9. VS code 进行 flutter 调试时启动后就停止,无法调试的问题

    在编写flutter时,更新需要按 r 或着 R,这就有点麻烦,当然强大的VS code给我们提供了自动更新的功能,那就是调试功能. 首先需要给VS code安装Flutter与Dart插件. 在VS ...

  10. node.js的特点与模块化开发

    node.js的代码都是构建在模块化开发的基础之上,模块化开始也是node.js的核心之一. node.js跳过了服务器,它自己不用建设在任何服务器软件之上,node.js的许多设计理念与经典架构(L ...