DRF从入门到精通五(路由组件、认证组件、权限组件、频率组件及认证、权限源码分析)

文章目录

  • 一、路由组件
    • REST framework提供了两个router
    • action装饰器
  • 二、认证组件(Authentication)
  • 三、权限组件(Permissions)
    • 内置权限类
  • 四、频率组件(Throttling)
  • 五、权限组件源码分析
  • 六、认证组件源码分析

一、路由组件

对于视图集ViewSetMixin,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。

REST framework提供了两个router

  • SimpleRouter
  • DefaultRouter

也就是通过路由组件帮助我们自动生成路由,它会根据URL及请求匹配对应的视图方法,而这些方法则是来自视图集,如果我们需要自定义方法来处理请求的话,后续可以搭配action装饰器实现。

SimpleRouter为每个URL添加一个斜杠后缀,可以在初始化的时候提供trailing_slash参数,并设置为False

创建router对象,并注册视图集

	'导入'from rest_framework.routers import SimpleRouter,DefaultRouter'导入的模块不是继承就是实例化'router = SimpleRouter() 或者DefaultRouter()  # 创建对象'''DefaultRouter会生成一个根路径/的配置项DefaultRouter生成的每个配置项后都可以跟上.json,直接返回json数据还可以显示注册过的路由以及美化的页面SimpleRouter和DefaultRouter用法一致,功能几乎一样''''注册路径,可以注册多个'router.register('publish',views.PublishView)  # 注册路由,并选择视图函数'注册:第一个参数是路径,第二个参数为视图类,第三个参数起别名用得少所有这里没用'urlpatterns = []'把生成的路由添加到urlpatterns路由列表中,有两种方式:'# 将生成的路由加入到Django需要调用的路由列表内'方式一:直接添加+='urlpatterns += router.urls'方式二:直接添加到urlpatterns里面使用include'from django.urls import path,includeurlpatterns = [path('',include(router.urls))]

def register(self, prefix, viewset, basename=None):

注册参数说明:

  • prefix:路由的前缀
  • viewset:视图集(内部必须继承了ViewSetMixin类)
  • basename:路由的别名

上序代码会生成如下路由:

	path('publish/',views.PublishView.as_view()),path('publish/<int:pk>',views.PublishView.as_view()),''''^publish/$' [name='publish-list^publish/(?P<pk>[^/.]+)/$' [name='publish-detail']'''

每个路由对应的接口功能

	publish/:get请求的话则会执行视图集里面的list方法publish/:post请求的话则会执行视图集里面的create方法publish/<int:pk>/:get请求执行视图集里面的retrieve方法publish/<int:pk>/:put请求执行视图集里面的update方法publish/<int:pk>/:delete请求执行视图集里面的destroy方法

实际展示
视图类

	from rest_framework.viewsets import ModelViewSet'必须是继承了ViewSetMixin类的视图类才能使用这种自动生成路由的方法'class PublishView(ModelViewSet):queryset = models.Publish.objects.all()serializer_class = PublishSerializer

路由

	from rest_framework.routers import SimpleRouterrouter = SimpleRouter()router.register('publish',views.PublishView)urlpatterns = []urlpatterns += router.urls

此时上面代码就可以自动生成路由了,完成了增、删、改、查(一条或多条数据)的接口了,但是不包括在视图集里面自定义的方法。

如果要给我们自定义的方法也加上路由,那么则需要使用action装饰器来声明。


SimpleRouter生成URL的方式
在这里插入图片描述


DefaultRouter生成URL的方式
在这里插入图片描述


action装饰器

在视图集中,如果想要让Router自动帮助我们为自定义的方法生成路由信息,需要使用rest_framework.decorators.action装饰器。

使用action装饰器的方法名会作为路由的后缀,例如:

	/publish/使用action装饰器的方法名/

并且action装饰器会接收两个参数:

  • methods:声明该action对应的请求方式,列表传递:['get','post']表示该路由get请求与post请求。
  • detail:声明该action的路由是否与单一资源(就是单条数据)对应,如果需要的话设置True。
	/publish/<int:pk>/使用action装饰器的方法名/True:表示路径格式是:/publish/pk/action方法名/False:表示路径格式是:/publish/action方法名/
  • url_path:控制生成的/使用action装饰器的方法名/后面的路径是什么,如果不写默认以方法名
  • url_name:别名,用于反向解析

实际案例
视图类

	from rest_framework.viewsets import ModelViewSetfrom rest_framework.response import Responsefrom rest_framework.decorators import actionclass PublishView(ModelViewSet):queryset = models.Publish.objects.all()serializer_class = PublishSerializer@action(methods=['post'], detail=False)def login(self,request):return Response({'message':'登录成功'})@action(methods=['get'],detail=True)def test(self,request,pk):return Response({'message':'测试成功'})

效果展示
在这里插入图片描述
在这里插入图片描述
此时可以从浏览器上看到自动生成的路由

	api/v1/ ^publish/$ [name='publish-list']api/v1/ ^publish/login/$ [name='publish-login']api/v1/ ^publish/(?P<pk>[^/.]+)/$ [name='publish-detail']api/v1/ ^publish/(?P<pk>[^/.]+)/test/$ [name='publish-test']

它使用的是正则来匹配,中间使用了有名分组,以关键字:pk=xx的形式传给视图。


二、认证组件(Authentication)

在DRF中,我们要进行登录认证的话需要使用DRF内部的认证组件,为什么不用auth组件?因为DRF重新封装了request方法,而当我们使用原来reqeust.user时,则会调用_authenticate方法,然后在调用我们编写的认证类里面的authenticate方法进行认证。

开启认证有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.LoginAuth"]# value值是我们认证组件类在当前项目的路径}

局部开启:在视图类里面指定认证类

	'导入登录认证类'from .auth import LoginAuthauthentication_classes = [test.LoginAuth, ]# 认证可以有多个,在调用_authenticate方法时会将列表里面类实例成对象,然后执行对象里面的authenticate方法。# 执行顺序从前至后,如果某个对象返回了正确结果则后面对象不会执行。'如果全局认证了但是又不想让某一个不认证,需要再视图类里面写入authenticate_classes = []清空即可'

登录认证类

	from rest_framework.authentication import BaseAuthenticationfrom . import modelsfrom rest_framework.exceptions import AuthenticationFailed'''通过认证类完成,使用步骤1 写一个认证类,继承BaseAuthentication2 重写authenticate方法,在内部做认证3 如果认证通过,返回2个值4 认证不通过抛AuthenticationFailed异常5 只要返回了两个值,在后续的request.user 就是当前登录用户'''class LoginAuth(BaseAuthentication):def authenticate(self, request):  重写authenticate方法,做内部认证# 完成对用户的校验# 当次请求的requesttoken = request.query_params.get('token')  获取tokenuser_token = models.UserToken.objects.filter(token=token).first()if user_token:user = user_token.user  # 如果通过认证返回两个值,不通过则抛异常'return后,在后续的视图类的方法中,就可以通过reqeust.user取到当前登录的用户''如果不按照这个规则来写,后续视图类的request.user是取不到当前登录用户'return user,user_token'质押返回了两个值,在后续的request.user就是当前登录用户'else:raise AuthenticationFailed('您没有登录!')

三、权限组件(Permissions)

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

开启权限有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ['app01.permission.CommonPermission',],}'注意,不要再配置文件乱导入不使用的东西,否则没有加载过就使用会直接报错。'

局部开启:在视图类里面指定权限类

	'导入权限类'from .permission import CommonPermissionpermission_classes = [CommonPermission]'如果全局设置权限了但是又不想让某一个不设置权限,需要再视图类里面写入permission_classes = []清空即可'

补充

	如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部-'.has_permission(self,request,view)'是否可以访问视图,view表示当前视图对象-'.has_object_permission(self,request,view,obj)'是否可以访问数据对象,view表示当前视图,obj为数据对象

权限类的定义

	'models.py定义的用户表'class User(models.Model):username = models.CharField(max_length=64)password = models.CharField(max_length=64)user_type = models.IntegerField(default=1, choices=((1, '普通用户'), (2, '管理员'), (3, '超级管理员')))from rest_framework.permissions import BasePermission'''权限类其实跟认证类一样只需要继承类修改方法使用步骤1 写一个类,继承BasePermission2 重写has_permission方法(也可以不继承BasePermission,但是重写这个方法,一样有用,因为python是鸭子类型)3 在方法中校验用户是否有权限(request.user就是当前登录用户)4 如果有权限,就返回True,没有权限,返回False5 self.message 是显示给前端的中文提示信息''''我这里创建是一个只有超级管理员才能访问其他人都不能访问的例子'class CommonPermission(BasePermission):   # 随意定义一个类继承BasePermissiondef has_permission(self, request, view):  # 重写has_permission方法'''到了这里,正常步骤应该登录完了,可以使用reqeust.user来查看当前登录用户然后拿到用户后判断用户是否有权限,去用户表中查看用户类型字段user_type,然后根据类型判断是否有权限-ACL:访问控制列表-rbac:公司内部系统,基于角色的访问控制-abac:rbac升级版,加了属性认证'''try:  # 这里进行异常捕捉,因为有可能有匿名用户所以需要进行捕捉user_type = request.user.user_type  print(f"用户:{request.user.get_user_type_display()}")print(f"编号:{user_type}")if user_type == 3: # 获取用户的管理员信息,如果有权限返回True,否则Falsereturn Trueelse:'报错信息渲染,这里的reqeust.user.get_user_type_display()是返回这个字段的choice对应的文字'self.message = f"你是{request.user.get_user_type_display()}。没有权限进行操作!"return Falseexcept Exception as e:  # 当是匿名用户或者说是没有登录的用户,走这里# print(request.path) '这里的判断是为了给登录和注册页进行解除设限'if 'login' in request.path: # 获取return Trueelif 'register' in request.path:return True'渲染报错信息渲染'self.message = "您没有登录,没有权限进行操作!"return False

内置权限类

当我们通过create_user或者createsuperuser也可以具备权限,DRF提供了以下权限类。

	from rest_framework.permissions import AllowAny,IsAuthenticated,IsAdminUser,IsAuthenticatedOrReadOnly- AllowAny	允许所有用户- IsAuthenticated	仅通过认证的用户- IsAdminUser	仅管理员用户- IsAuthenticatedOrReadOnly	以及登录认证的用户可以对数据进行增删改查操作,没有登录认证的只能查看数据

我们可以根据哪个视图的需要来进行引入。
全局使用:这就表示所有视图都只能通过认证的用户访问

	REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated',],}

如果需要某几个视图不想使用这种效果的话,则可以进行局部禁用

	permission_classes = [] # 设置空即可,或者指定别的权限类

如果未指定的话,则使用DRF默认的

	REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny',]}

四、频率组件(Throttling)

我们也可以称其为:限流。其主要作用:

  • 可以对接口访问的次数进行限制,以减轻服务器压力
  • 一般用于付费购买次数,投票等场景使用。

开启频率有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],}'注意,不要再配置文件乱导入不使用的东西,否则没有加载过就使用会直接报错。'

局部开启:在视图类里面指定权限类

	'导入权限类'from .throttling import CommonThrottlethrottle_classes = [CommonThrottle]'如果全局设置权限了但是又不想让某一个不设置权限,需要再视图类里面写入permission_classes = []清空即可'

频率类的定义

	from rest_framework.throttling import BaseThrottle,SimpleRateThrottlefrom . import models'''使用步骤:1.写一个类继承SimleRateThrottle2.重写get_cache_key方法,返回一个唯一的字符串,会以这个字符串做频率限制3.有两种写法3.1 写一个类属性 scope='随意命名',使用这个方法的必须要与配置文件中定义使用配置文件中写REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'key要跟类中的scop定义的名字对应': '5/m',},# 表示该接口一分钟只能被访问5次,key值就是我们频率类里面的scope属性值这个字典后面value值里面的/前面的是访问次数,后面是超过次数后等待的时间,可以根据下面参数来进行选择即可。{'s':1,'m':60,'h':3600,'d':86400}  # 都是使用秒来计算我们也可以直接使用英文单词来:秒:second,分:minute,时:hour,天:day}3.2 写一个类属性 rate = '5/minute' 这种写法就无需配合配置文件中写了,相当于直接整合了''''这里我以一个登录用户id进行限制一分钟访问三次'class CommonThrottle(SimpleRateThrottle):rate = '3/minute'  # second minute hour daydef get_cache_key(self, request, view):user = request.userobj = models.User.objects.filter(username=user.username).first()'''返回什么,频率就可以做什么限制比如也可以通过IP地址进行限制,ip = request.META.get('REMOTE_ADDR')'''return obj.pk  # ip

在settings中使用匿名用户、普通用户的限制

	REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': ('rest_framework.throttling.AnonRateThrottle', # 匿名用户限流'rest_framework.throttling.UserRateThrottle', # 普通用户限流),'DEFAULT_THROTTLE_RATES': {'anon': '3/m', # 设置匿名用户每分钟只能访问3次'user': '5/m', # 设置普通用户每分钟只能访问5次}}

五、权限组件源码分析

	'''我们知道在DRF的APIView中有三大认证是在执行视图类的方法之前就执行了三大认证,也就是APIView中的dispatch方法中的self.initial。在之前几篇DRF博客中,以及介绍解读过APIView的源码了所以这里我就不重头开始解读了,直接从dispatch里面开始了'''def dispatch(self, request, *args, **kwargs):try:'就是在这里执行了三大认证:认证、权限、频率'self.initial(request, *args, **kwargs)'执行视图类的方法开始'if request.method.lower() in self.http_method_names:handler = getattr(self, request.method.lower(),self.http_method_not_allowed)else:handler = self.http_method_not_allowedresponse = handler(request, *args, **kwargs)'执行视图类的方法结束'except Exception as exc:  全局异常捕捉response = self.handle_exception(exc)self.response = self.finalize_response(request, response, *args, **kwargs)return self.response'''我们找到了这个dispatch里面执行三大认证的地方后,我们知道,这个self是视图类的对象,而视图类是继承了APIView这个类所以我们先去APIView这个类中找一下有没有这个initial的方法,结果是有的'''找到了APIView里的initialdef initial(self, request, *args, **kwargs):self.perform_authentication(request) # 认证组件self.check_permissions(request) # 权限组件self.check_throttles(request) # 频率组件'因为我们这里是分析权限组件的,所以在这里只看一下权限的,跟上面一样,这个self还是视图类的对象'在APIView里面找到了check_permissions方法# 检查请求是否具有所需的权限def check_permissions(self, request):# 遍历视图或视图集的权限类列表'这里的self还是视图类的对象,然后我们又得去APIView里面找看有没有get_permissions方法''''def get_permissions(self):return [permission() for permission in self.permission_classes]在这个get_permissions里面直接返回了一个列表生成式,我们得去看看这个self.permission_class是什么permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES从上面点击查看到的可以得知,self.permission_class就是咱们配置在视图类中的列表,里面是一个个权限类,并且没加括号执行。然后我们可以知道它每次从我们自己的视图类的permission_class列表中拿出一个值出来所以这里的返回值就是每次拿到一个值然后加括号执行,其实就是我们配置的一个个权限类的对象'''所以这里self.get_permissions()就是拿到一个个我们配置的权限类的对象的列表,然后在这里又进行循环一个个拿出for permission in self.get_permissions(): 所以这里的permission就是我们写的一个个的权限类的对象# 调用每个权限类的 has_permission 方法进行权限检查'''这里看到has_permission,这个就是为什么我们需要再权限类中重写这个方法,因为在这里它在调用它并且传入了两个参数,这个request就是APIView包装后的新的request,而这个self它还是我们视图类的对象因为还是在APIView中。这就是为什么我们在权限类中重写has_permission方法括号中加入了一个view参数,就是接收了这个的self也就是视图类对象。所以我们这个权限类中的view其实就可以直接拿到view.request,也可以直接拿到view.action等参数'''if not permission.has_permission(request, self):'而这里在权限类中has_permission方法如果返回值是True就不会执行这里的代码,反之就会走这里'# 如果权限检查失败,调用 permission_denied 方法,拒绝访问self.permission_denied('这里的self还是视图类的对象,当执行了这个permission_denied就是说明没有权限''''这里注意一个点,如果配置了多个权限类,如果第一个权限类就没过,就不会执行后面的权限类,所以得把想要过的放最前面'''request,# 获取权限类中可能定义的消息和代码message=getattr(permission, 'message', None),'这里的message和code都是从我们权限类的对象中反射过来的'code=getattr(permission, 'code', None))'在这里我们还可以看看,这个permission_denied,它还是在APIView中'def permission_denied(self, request, message=None, code=None):if request.authenticators and not request.successful_authenticator:raise exceptions.NotAuthenticated()raise exceptions.PermissionDenied(detail=message, code=code)'''可以看到它执行抛了异常,因为抛了异常,最后会被APIView中的全局异常捕捉到并且把上面的message和code都传入过去message会放在响应体中,code会放在响应状态码中'''

总结:

	权限类源码的执行流程:1.先去视图类继承的APIView中的dispatch方法中执行self.initial方法2.然后又执行APIView的initial方法中的self.check_permissions(request)3.然后从里面取出配置在视图类中的权限类,实例化得到对象。4.然后for循环一个个执行对象的has_permission方法(重写的方法),如果返回False就直接结束,不再往下执行权限就认证通过'小细节'1.为什么写一个类继承BasePermission,重写has_permission方法-也可以不继承这个类,只重写这个方法也可以(因为python是鸭子类型)2.权限类中 self.message  会返回给前端3.局部配置:放在视图类中:permission_classes = [权限类名]4.全局配置,配置在配置文件中也可以,那么视图类中就没有-如果视图类上不配做权限类,permission_classes = [],会默认使用配置文件的api_settings.DEFAULT_PERMISSION_CLASSES-执行的顺序:优先使用项目配置文件----->其次使用drf内配置文件

六、认证组件源码分析

	'因为也是继承了APIView,从上面权限组件源码分析中我们知道在它的dispatch方法中有一个initial方法''里面也有一个认证组件的'def initial(self, request, *args, **kwargs):self.perform_authentication(request) # 认证组件self.check_permissions(request) # 权限组件self.check_throttles(request) # 频率组件'因为我们这里是分析只分析认证组件的,然后self还是视图类的对象'在APIView里面找到了perform_authentication方法def perform_authentication(self, request):'''可以看到里面只写了一句代码,因为这里还是APIView所以这里的self还是视图类的,这里的reqeust就是APIView包装的新的request。'''request.user'这里可以看到request.user,可以会觉得它是一个属性,但是其实它是一个方法,是伪装成数据属性的''这样我们就得回到APIView源码中找了,因为我们这个新的reqeust是在Request中,所以我们得去看它了'我们直接在视图中导入这个然后找到这个user位置:from rest_framework.request import Request@propertydef user(self):  这里的self就是Request的对象,因为它并没有继承任何一个类。所以就是它自己的对象if not hasattr(self, '_user'):'然后这里是看有没有这个_user,但是我们确实是没有,所以是False,但是又if了not所以变成True'with wrap_attributeerrors():  # 上下文管理器self._authenticate()  所以会执行这一句return self._user'sel_authenticate()这里的self就是Resquest对象,所以我们找找Resquest中有没有这个方法'def _authenticate(self):'''这里循环跟权限组件那块差不多self.authenticators,就是我们配置在视图类中认证类的一个个对象,放在列表中所以这里循环出来的authenticator就是一个个我们配置的认证类对象'''for authenticator in self.authenticators:此处对上面几句的解释'''这个self还是Resquest对象,我们在Resquest中找authenticators,而它不是一个方法,而是一个属性,所以我们直接按住Ctrl+鼠标左键点击跳转即可def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):self.authenticators = authenticators or ()从我们点击跳转找到的我们可以看到这个是Resquest类实例化后得到的对象的初始化方法,会把对象的authenticators传入给了,self.authenticators对象,所以我们在类实例化调用这个初始化方法是什么时候实例化类的,我们得去APIView中找找,在我们之前博客中有写过APIView的源码分析中知道,在它的dispatch中request = self.initialize_request(request, *args, **kwargs)这里实例化得到对象了,所以我们去看看def initialize_request(self, request, *args, **kwargs):return Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),negotiator=self.get_content_negotiator(),parser_context=parser_context)从上面代码中可以看到返回了authenticators=self.get_authenticators(),这里的self又是谁?现在是在APIView中,所以这里的self是视图类的对象然后直接跳转到这个self.get_authenticators()def get_authenticators(self):return [auth() for auth in self.authentication_classes]self.self.authentication_classes,self就是视图类的对象,而authentication_classes就是在视图类中配置的认证类中的一个个对象,它是一个列表'''try:'''因为上面我们知道了authenticator就是我们配置的一个个认证类,而这里的authenticate就是我们在认证类中重写的方法,因为在这里调用它了。而这里的self就还是APIView包装的新的Resquest对象,所以在认证类中重写这个方法后面接收了它然后执行认证类的这个方法,后返回值就赋值给了user_auth_tuple这里在我们认证类的这个方法中返回了两个值:第一个是当前登录用户,第二个的token,只走这一个认证类,后面的不再走了也可以返回None,这样就会继续执行下一个认证类'''user_auth_tuple = authenticator.authenticate(self)'''如果这里没有重写这个方法就抛出异常,它并没有捕获AuthenticationFailed,而是APIException但是AuthenticationFailed是继承了APIException。所以我们在认证类抛出异常使用AuthenticationFailed'''except exceptions.APIException:self._not_authenticated()raise'这里如果user_auth_tuple不是空的话,就走这里,就是正常返回了认证类方法的两个值'if user_auth_tuple is not None:self._authenticator = authenticator'''这里的self就还是Resquest的对象,并且使用了解压赋值,然后把user_auth_tuple的两个值分别赋值这就是为什么后续在视图类中,reqeust.user就是当前登录的用户,request.auth就是另一个参数当认证类没有返回值,那么这里就是空,如果有第二个认知类那么就会进行第二次循环,如果有返回值就解压赋值完毕后,直接结束了。'''self.user, self.auth = user_auth_tuple'''所以这里我们可以知道,在视图类中配置认证类是可以配置多个的,如果第一个认知类有返回值就不会再执行第二个认证类,如果没有返回值,则会执行第二个认证类。而返回的两个值,第一个给了reqeust.user,第二个给了reqeust.auth,这样在后续视图类中就可以取到'''returnself._not_authenticated()

总结

	1.在认证类中,重写authenticate方法(不重写就无法调用)2.为什么校验失败抛异常,因为我们写了AuthenticationFailed,又AuthenticationFailed是继承了APIException所以能捕获3.通过认证就会返回两个值或者None(如果没有返回值就会执行下一个认证类,或者没有在后续视图类中request.user和reqeust.auth就拿不到值)4.视图类上局部配置和配置文件全局配置跟权限类的一模一样。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaWeb的Servlet的入门和使用方法

1 什么是Servlet Servlet是Server Applet的简称&#xff0c;是用Java编写的是运行在 Web 服务器上的程序&#xff0c;它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet&#xff0c;可以收集来自网页表单的用户输…

Elasticsearch:无需搜索 “Christmas” 即可找到有关圣诞节的书籍

随着假期的临近&#xff0c;我期待着变得舒适&#xff0c;拿起一本新书&#xff0c;享受轻松的时光。 但是使用搜索栏在线发现图书并不像看起来那么容易......大多数零售搜索引擎仅依赖于关键字搜索&#xff0c;当我们确切地知道我们正在寻找什么书名时&#xff0c;这很好&…

Servlet见解2

4 创建servlet的三种方式 4.1 实现Servlet接口的方式 import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException;WebServlet("/test1") public class Servlet1 implements Servlet {Overridepublic void init(ServletConf…

【前端技术】Vite vs Webpack

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

克魔助手工具下载、注册和登录指南

下载安装克魔助手 摘要 本文介绍了如何下载安装克魔助手工具&#xff0c;以及注册和登录流程。通过简单的步骤&#xff0c;用户可以轻松获取并使用该工具&#xff0c;为后续的手机应用管理操作做好准备。 引言 克魔助手是一款免费的手机管理工具&#xff0c;通过该工具用户…

Python实现张万森下雪了的效果

写在前面 即将步入婚宴殿堂的女主林北星&#xff0c;遭遇了男友展宇的毁约&#xff0c;生活和工作也变得一团糟。与此同时&#xff0c;她被时光老人带回了十八岁的高三时光&#xff0c;重新开启了自己的人生。林北星摆脱了展宇的束缚&#xff0c;认真准备高考&#xff0c;想要…

同城配送小程序解决方案

前言 同城配送小程序解决方案。 一、用户用车 用户打开小程序后发货地址自动定位到用户当前位置&#xff0c;用户可通过地址后的>号在地图上选择新的发货地址和卸货地址&#xff0c;小程序会自动规划出行线路&#xff0c;计算距离和运费价格。 用户仅用简单操作后就可以…

w16php系列之基础数组

一、索引数组 概念 索引数组 是指键名为整数的数组。默认情况下&#xff0c;索引数组的键名是从0开始&#xff0c;并依次递增。它主要适用于利用位置&#xff08;0、1、2……&#xff09;来标识数组元素的情况。另外&#xff0c;索引数组的键名也可以自己指定 示例代码 <…

讲座思考 | 周志华教授:新型机器学习神经元模型的探索

12月22日&#xff0c;有幸听了南京大学周志华教授题为“新型机器学习神经元模型的探索”的讲座。现场热闹非凡&#xff0c;大家像追星一样拿着“西瓜书”找周教授签名。周教授讲得依旧循循善诱&#xff0c;由浅入深&#xff0c;听得我很入迷&#xff0c;故作此记。 周教授首先就…

RocketMQ系统性学习-RocketMQ高级特性之消息大量堆积处理、部署架构和高可用机制

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 【11来了】文章导读地址&#xff1a;点击查看文章导读&#xff01; &#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f3…

kasan

目录 主要参考文章&#xff1a;linux之kasan原理及解析-CSDN博客 kasn大致原理 shadow memory映射建立 kasn检查代码具体实现 kasn大致原理 之前使用slub debug定位重复释放&#xff0c;内存越界等问题时比较麻烦。无法对异常行为进行实时捕捉。看网上说kasan能做到这一点…

etcd-workbench一款免费好用的ETCD客户端,支持SSHTunnel、版本对比等功能

介绍 今天推荐一款完全免费的ETCD客户端&#xff0c;可以私有化部署: etcd-workbench 开源地址&#xff1a;https://github.com/tzfun/etcd-workbench Gitee地址&#xff1a;https://gitee.com/tzfun/etcd-workbench 下载 本地运行 从 官方Release 下载最新版的 jar 包&am…

【FPGA】分享一些FPGA视频图像处理相关的书籍

在做FPGA工程师的这些年&#xff0c;买过好多书&#xff0c;也看过好多书&#xff0c;分享一下。 后续会慢慢的补充书评。 【FPGA】分享一些FPGA入门学习的书籍【FPGA】分享一些FPGA协同MATLAB开发的书籍 【FPGA】分享一些FPGA视频图像处理相关的书籍 【FPGA】分享一些FPGA高速…

QT、C++实验室管理系统

一、需求介绍&#xff1a; 题目:基于Qt的实验室管理系统的设计 项目命名以LabSystem姓名拼音首字母&#xff08;例如: LabSystemwXC) 功能要求: 一&#xff0c;基本必要功能: 1&#xff0c;使用QSQLITE数据库完成数据库的设计。 2&#xff0c;注册功能:包含学生注册&#xff0…

哪个牌子的猫冻干好又安全?分享安全的主食冻干猫粮牌子

近几年&#xff0c;冻干猫粮在宠物圈内非常流行&#xff0c;许多品牌都推出了冻干猫粮。在所有的猫食品中&#xff0c;冻干无疑是最具营养、动物蛋白含量最高的食品之一。冻干作为现在宠物圈最火的猫食品&#xff0c;受到了众多猫友们的喜爱和追捧。但有些铲屎官在选择冻干猫粮…

axios进行图片上传组件封装

文章目录 前言图片上传接口&#xff08;axios通信)图片上传使用upload上传头像效果展示总结 前言 node项目使用 axios 库进行简单文件上传的模块封装。 图片上传接口&#xff08;axios通信) 新建upload.js文件&#xff0c;定义一个函数&#xff0c;该函数接受一个上传路径和一…

简单的喷淋实验(2):(1)根据土壤湿度自动控制喷淋开关;(2)根据光照强度控制风扇以及灯的开关---嵌入式实训

目录 简单的喷淋实验(2)&#xff1a; &#xff08;1&#xff09;根据土壤湿度自动控制喷淋开关&#xff1b; &#xff08;2&#xff09;根据光照强度控制风扇以及灯的开关---嵌入式实训 任务2&#xff1a; 具体过程&#xff1a; 所用的头文件&#xff1a; data_global.h …

【接口测试】Postman(一)--接口测试知识准备 _

1.0 前言 ​ 应用程序编程接口&#xff08;Application Programming Interface, API&#xff09;是这些年来最流行的技术之一&#xff0c;强大的Web应用程序和领先的移动应用程序都离不开后端强大的API。API技术的应用给系统开发带来了便利&#xff0c;但也对测试人员提出了更高…

PYTHON基础:最小二乘法

最小二乘法的拟合 最小二乘法是一种常用的统计学方法&#xff0c;用于通过在数据点中找到一条直线或曲线&#xff0c;使得这条直线或曲线与所有数据点的距离平方和最小化。在线性回归中&#xff0c;最小二乘法被广泛应用于拟合一条直线与数据点之间的关系。 对于线性回归&…

k8s的二进制部署(一)

k8s的二进制部署&#xff1a;源码包部署 环境&#xff1a; k8smaster01: 20.0.0.71 kube-apiserver kube-controller-manager kube-schedule ETCD k8smaster02: 20.0.0.72 kube-apiserver kube-controller-manager kube-schedule Node节点01: 20.0.0.73 kubelet kube-pr…