路飞项目--04

news2024/11/24 12:53:06

分析后端接口

# 用户板块--原型图--分析需要写哪些接口
    多方式登录接口
    短信登录接口
    发送短信接口
    短信注册接口
    校验手机号是否注册接口

手机号是否存在接口

思路:

       1 用了全局异常捕获,直接抛出异常报错

       2 路由用了自定义路由,由总路由拼接而来

# apps/user/views.py
from utills.common_response import APIResponse
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import User
from rest_framework.exceptions import APIException

# 校验手机号是否存在接口
class UserMobileView(ViewSet):
    @action(methods=['POST'], detail=False,url_path='check_mobile')
    def mobile(self, request):
        try:
            mobile = request.data.get('mobile')
            User.objects.get(mobile=mobile)  # 能拿到说明手机号存在
            return APIResponse(msg='手机号存在')  # 定制返回格式
        except Exception as e:
            raise APIException(detail='手机号不存在')
# apps/user/urls.py
from rest_framework.routers import SimpleRouter
from  .views import UserMobileView

router = SimpleRouter()
# /api/v1/user/mobile/check_mobile/
router.register('mobile',UserMobileView,'mobile')
urlpatterns = [
    path('logger/', TestLoggerView.as_view()),
    path('exception/', TestExceptionView.as_view()),
    path('response/', TestResponseView.as_view()),
]
urlpatterns += router.urls

多方式登录接口

# 多方式登录接口,其实也是对登录接口的一种封装

# 思路:

        1、拿到前端传入的用户名[用户名、手机、邮箱] 和密码

        2、取数据库校验,拿到user

        3、校验通过,用user签发token

        4、返回前端

# apps/user/views.py
# 多方式登录接口
class UserLoginView(GenericViewSet):
    serializer_class = MoreLoginSerializer

    @action(methods=['POST'], detail=False)
    def more_login(self, request):
        ser = self.get_serializer(data=request.data, context={'request': request})
        ser.is_valid(raise_exception=True)  # 校验数据,就会执行serializer
        token = ser.context.get('token')
        username = ser.context.get('username')
        icon = ser.context.get('icon')
        return APIResponse(data={'token': token, 'username': username, 'icon': icon})
# apps/user/serializer.py
from rest_framework import serializers
from .models import User
import re
from rest_framework.exceptions import APIException
from rest_framework_simplejwt.tokens import RefreshToken
from django.conf import settings

# 这个序列化类只用来做反序列化,不需要将数据传到前端
class MoreLoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

    class Meta:
        model = User
        fields = ['username', 'password']

    # 验证数据
    def validate(self, attrs):
        user = self._get_user(attrs)  # 获取用户
        token = self._get_token(user)  # 签发token
        self._set_context(token, user)  # 放到context中
        return attrs

    #  校验成功获取用户
    def _get_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = User.objects.filter(mobile=username).first()
        elif re.match(r'^.+@.+$', username):  # 邮箱登录
            user = User.objects.filter(email=username).first()
        else:
            user = User.objects.filter(username=username).first()
        if user and user.check_password(password):  # auth表里验证密码
            return user
        else:
            raise APIException(detail='用户名或密码错误')

    # 拿到user签发token
    def _get_token(self, user):
        refresh = RefreshToken.for_user(user)
        return str(refresh.access_token)

    #  将token和user放到context中
    def _set_context(self, token, user):
        self.context['token'] = token
        self.context['username'] = user.username
        self.context['icon'] = settings.BACKEND_URL + '/media/' + str(user.icon)  # user.icon 文件对象
# apps/user/urls.py
from  .views import UserMobileView,UserLoginView

router = SimpleRouter()
# /api/v1/user/login/more_login/
router.register('login',UserLoginView,'login')
urlpatterns = [
]
urlpatterns += router.urls

腾讯云发送短信

# 项目中使用发送短信功能,借助于第三方:
    腾讯云短信(咱们)
    阿里、容联云短信
# 补充:短信轰炸,是违法的行为,不可以尝试

# 登录成功:https://console.cloud.tencent.com/smsv2

   短信发送:https://cloud.tencent.com/document/product/382/55981
    API:api接口,请求地址,携带参数,返回某些格式
    sdk:使用某种语言对api接口进行封装
        有sdk,优先用sdk,简单

        下载sdk,导入,掉方法执行,传入参数即可
# 下载sdk:pip install tencentcloud-sdk-python

# 代码直接贴下来,改动一下数据就可以使用了:

# script/1-发送短信.py
# -*- coding: utf-8 -*-
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的client models。
from tencentcloud.sms.v20210111 import sms_client, models

# 导入可选配置类
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
try:
    # 必要步骤:
    # 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。
    # 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。
    # 您也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人,
    # 以免泄露密钥对危及您的财产安全。
    # SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi
    cred = credential.Credential("AKIDT0gF0iU8gJ5XEvW0cLyWzZME97yQipya", "gJsS0X8vlkfkyKmJzgO4kKlm2OuW4Wug")
    # cred = credential.Credential(
    #     os.environ.get(""),
    #     os.environ.get("")
    # )

    # 实例化一个http选项,可选的,没有特殊需求可以跳过。
    httpProfile = HttpProfile()
    # 如果需要指定proxy访问接口,可以按照如下方式初始化hp(无需要直接忽略)
    # httpProfile = HttpProfile(proxy="http://用户名:密码@代理IP:代理端口")
    httpProfile.reqMethod = "POST"  # post请求(默认为post请求)
    httpProfile.reqTimeout = 30    # 请求超时时间,单位为秒(默认60秒)
    httpProfile.endpoint = "sms.tencentcloudapi.com"  # 指定接入地域域名(默认就近接入)

    # 非必要步骤:
    # 实例化一个客户端配置对象,可以指定超时时间等配置
    clientProfile = ClientProfile()
    clientProfile.signMethod = "TC3-HMAC-SHA256"  # 指定签名算法
    clientProfile.language = "en-US"
    clientProfile.httpProfile = httpProfile

    # 实例化要请求产品(以sms为例)的client对象
    # 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8
    client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)

    # 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
    # 您可以直接查询SDK源码确定SendSmsRequest有哪些属性可以设置
    # 属性可能是基本类型,也可能引用了另一个数据结构
    # 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明
    req = models.SendSmsRequest()

    # 基本类型的设置:
    # SDK采用的是指针风格指定参数,即使对于基本类型您也需要用指针来对参数赋值。
    # SDK提供对基本类型的指针引用封装函数
    # 帮助链接:
    # 短信控制台: https://console.cloud.tencent.com/smsv2
    # 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81

    # 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666
    # 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
    req.SmsSdkAppId = "1400885290"
    # 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名
    # 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
    req.SignName = "蟒蛇梦想家公众号"
    # 模板 ID: 必须填写已审核通过的模板 ID
    # 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
    req.TemplateId = "2057994"
    # 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空
    req.TemplateParamSet = ["6666"]
    # 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
    # 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号
    req.PhoneNumberSet = ["+8613093703948"]
    # 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回
    req.SessionContext = ""
    # 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手]
    req.ExtendCode = ""
    # 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。注:月度使用量达到指定量级可申请独立 SenderId 使用,详情请联系 [腾讯云短信小助手](https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81)。
    req.SenderId = ""

    resp = client.SendSms(req)

    # 输出json格式的字符串回包
    print(resp.to_json_string(indent=2))

except TencentCloudSDKException as err:
    print(err)



'''

{
  "SendStatusSet": [
    {
      "SerialNo": "3369:323809362217060692711588557",
      "PhoneNumber": "+8618066185575",
      "Fee": 1,
      "SessionContext": "",
      "Code": "Ok",
      "Message": "send success",
      "IsoCode": "CN"
    }
  ],
  "RequestId": "dbfe8874-af6c-42c9-827d-67dc7de342a4"
}

'''

腾讯云短信封装

# 将腾讯云代码封装成一个包,这样在自己写的项目中不管哪个位置都可以导入使用

# 封装了两个函数,一个是随机生成验证码,一个是腾讯云发送短信

        验证码:导入执行函数后随机生成

        手机号:由前端的请求地址栏中GET取得

# 做了动态的setting,以供方便改动账号信息

# 在包下的__init__中导入一下才可以后续导入其他代码体中使用

# lib/send_information/__init__.py
from .sms import get_code,common_send_sms
# libs/send_information/settings.py
SECRET_ID = 'AKIDXwBFAATk5lQydSLGAuR5e7LK5tvxtme6'
SECRET_KEY = 'dHuYIvWVMJ9ApYN6xv5LYo7QahhH3gAf'

# 申请的短信应用 SDK AppID
APP_ID = '1400885403'

# 申请的短信模板ID,需要在短信控制台中申请
TEMPLATE_ID = '2060860'

# 申请的签名,参数使用的是`签名内容`,而不是`签名ID`
SIGN = "佳佳的工作日记公众号"
# lib/send_information/sms.py
# 提供函数,给外部使用
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sms.v20210111 import sms_client, models
# 导入可选配置类
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
import json
from rest_framework.exceptions import APIException
from libs.send_information import settings
import random


#  随机生成4位的验证码
def get_code(count=4):
    code = ''
    for i in range(count):
        code += str(random.randint(0, 9))
    return code


# 发送短信函数
def common_send_sms(code, mobile):
    try:
        cred = credential.Credential(settings.SECRET_ID, settings.SECRET_KEY)
        httpProfile = HttpProfile()
        httpProfile.reqMethod = "POST"  # post请求(默认为post请求)
        httpProfile.reqTimeout = 30  # 请求超时时间,单位为秒(默认60秒)
        httpProfile.endpoint = "sms.tencentcloudapi.com"  # 指定接入地域域名(默认就近接入)
        clientProfile = ClientProfile()
        clientProfile.signMethod = "TC3-HMAC-SHA256"  # 指定签名算法
        clientProfile.language = "en-US"
        clientProfile.httpProfile = httpProfile
        client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)
        req = models.SendSmsRequest()
        req.SmsSdkAppId = settings.APP_ID
        # 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名
        # 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
        req.SignName = settings.SIGN
        # 模板 ID: 必须填写已审核通过的模板 ID
        # 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
        req.TemplateId = settings.TEMPLATE_ID
        # 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空
        req.TemplateParamSet = [code]
        # 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
        # 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号
        req.PhoneNumberSet = ["+86" + mobile]
        # 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回
        req.SessionContext = ""
        # 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手]
        req.ExtendCode = ""
        # 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。注:月度使用量达到指定量级可申请独立 SenderId 使用,详情请联系 [腾讯云短信小助手](https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81)。
        req.SenderId = ""
        resp = client.SendSms(req)
        # 输出json格式的字符串回包
        resp = json.loads(resp.to_json_string(indent=2))
        if resp.get('SendStatusSet')[0].get('Code') == 'Ok':
            return True
        else:
            return False

    except TencentCloudSDKException as err:
        raise APIException(detail=str(err))
    except Exception as e:
        raise APIException(detail=str(e))


if __name__ == '__main__':
    print(get_code())

3、​​​​​

发送短信接口

# 我们以后一定要多分类,

        由此我将验证手机号是否存在的接口和发送短信的接口归类写在了一起

        多方式登录【邮箱,手机号,用户名】单独写了一个类

# 接口取的是请求地址栏中的手机号以供前端使用,用get请求

from libs.send_information import get_code, common_send_sms
from django.utils.datastructures import MultiValueDictKeyError
from django.core.cache import cache
from threading import Thread


# 关于手机号和短信的接口
class UserMobileView(ViewSet):
    ...
    # 发送短信接口
    @action(methods=['get'], detail=False, url_path='send_information')
    def send_sms(self, request):
        try:
            mobile = request.query_params['mobile']  # 取的手机号放在请求地址栏中
            code = get_code()  # 生成验证码
            cache.set('sms_code_%s' % mobile, code)  # 放在缓存中,以手机号做区
            t = Thread(target=common_send_sms, args=[code, mobile])
            t.start()  # 启动线程发送短信
            return APIResponse(msg='短信已发送')

        except MultiValueDictKeyError as e:
            raise APIException(detail='手机号必须携带')
        except Exception as e:
            raise APIException(detail=str(e))

短信登录功能及代码优化

# 因为短信登录和多方式登录代码有很多相同的地方,由此,我们优化了代码,进行封装

# apps/user/views.py
from rest_framework.decorators import action
from rest_framework.exceptions import APIException
from .serializer import MoreLoginSerializer,InformationLoginSerializer

# 多方式登录和短信登录接口
class UserLoginView(GenericViewSet):
    serializer_class = MoreLoginSerializer

    @action(methods=['POST'], detail=False)
    def more_login(self, request):
        return self._common_login(request)

    @action(methods=['POST'], detail=False)
    def informetion_login(self, request):
        return self._common_login(request)

    def get_serializer_class(self):
        if self.action == 'informetion_login':
            return InformationLoginSerializer
        else:
            return super().get_serializer_class()

    def _common_login(self, request):
        ser = self.get_serializer(data=request.data, context={'request': request})
        ser.is_valid(raise_exception=True)  # 校验数据,就会执行serializer
        token = ser.context.get('token')
        username = ser.context.get('username')
        icon = ser.context.get('icon')
        return APIResponse(data={'token': token, 'username': username, 'icon': icon})

# apps/user/serializer.py
from rest_framework import serializers
from .models import User
import re
from rest_framework.exceptions import APIException
from rest_framework_simplejwt.tokens import RefreshToken
from django.conf import settings
from django.core.cache import cache


# 只用来做继承
class BaseLoginSerializer(serializers.Serializer):
    # 验证数据
    def validate(self, attrs):
        user = self._get_user(attrs)  # 获取用户
        token = self._get_token(user)  # 签发token
        self._set_context(token, user)  # 放到context中
        return attrs

    #  校验成功获取用户
    def _get_user(self, attrs):
        raise Exception('这个方法必须被重写')

    # 拿到user签发token
    def _get_token(self, user):
        refresh = RefreshToken.for_user(user)
        return str(refresh.access_token)

    #  将token和user放到context中
    def _set_context(self, token, user):
        self.context['token'] = token
        self.context['username'] = user.username
        self.context['icon'] = settings.BACKEND_URL + '/media/' + str(user.icon)  # user.icon 文件对象


# 这个序列化类只用来做反序列化,不需要将数据传到前端
# 继承就行,修改获得的用户,因为一个是多方式取手机号、邮箱、用户名等,一个是短信
class MoreLoginSerializer(BaseLoginSerializer):
    username = serializers.CharField()
    password = serializers.CharField()

    #  校验成功获取用户
    def _get_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = User.objects.filter(mobile=username).first()
        elif re.match(r'^.+@.+$', username):  # 邮箱登录
            user = User.objects.filter(email=username).first()
        else:
            user = User.objects.filter(username=username).first()
        if user and user.check_password(password):  # auth表里验证密码
            return user
        else:
            raise APIException(detail='用户名或密码错误')


class InformationLoginSerializer(BaseLoginSerializer):
    mobile = serializers.CharField()
    code = serializers.CharField()

    def _get_user(self, attrs):
        # 取出验证码,在序列化类里取值是attrs
        code = attrs.get('code')
        mobile = attrs.get('mobile')
        old_code = cache.get('sms_code_%s' % mobile)
        # 验证码验证
        if code == old_code or (settings.DEBUG and code == '8888'):
            # 验证码正确的情况,拿着手机号查询用户,看是否已经注册
            user = User.objects.filter(mobile=mobile).first()
            if user:
                return user
            else:
                raise  APIException(detail='用户不存在')
        else:
            raise APIException(detail='验证码错误')

短信注册功能

# 前端传入的 {mobile,code,password}

   User表中字段:username必填,自动生成 fake 我们让手机号做用户名

# apps/user/views.py
# 短信注册功能
from rest_framework.viewsets import ViewSet, GenericViewSet
from .serializer import RegisterSerializer


class UserRegisterView(GenericViewSet):
    serializer_class = RegisterSerializer

    # @action(methods=['POST'], detail=False)
    # def register(self, request):
    def create(self, request):
        ser = self.get_serializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        return APIResponse(msg='注册成功')
# apps/user/serializer.py
# 短信注册功能
class RegisterSerializer(serializers.ModelSerializer):
    code = serializers.CharField()  # 因为code不是表的字段,所以必须重写

    class Meta:
        model = User
        fields = ['mobile', 'code', 'password']

    def validate(self, attrs):
        # 验证验证码
        code = attrs.pop('code')
        mobile = attrs.get('mobile')
        old_code = cache.get('sms_code_%s' % mobile)
        if code == old_code or (settings.DEBUG and code == '6666'):
            # 把手机号作为用户名存入
            attrs['username'] = mobile
        else:
            raise APIException(detail='验证码错误')
        return attrs

    #  重写create方法,因为create_user,密码用的是明文
    # validated_data拿的是上面的attrs数据
    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user
# apps/user/urls.py
from django.urls import path
from .views import TestLoggerView,TestExceptionView,TestResponseView
from rest_framework.routers import SimpleRouter
from  .views import UserRegisterView

router = SimpleRouter()
router.register('register',UserRegisterView,'register')
urlpatterns = [
]
urlpatterns += router.urls

今日思维导图:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑指offer——删除链表的节点

题目描述&#xff1a;给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。返回删除后的链表的头节点。 数据范围&#xff1a; 0 <链表节点值 < 10000 0 <链表长度 < 10000 示例1&#xff1a; 输入&#xff1a;{2,5,1,9}&#xff…

NIO-Selector详解

NIO-Selector详解 Selector概述 Selector选择器&#xff0c;也可以称为多路复⽤器。它是Java NIO的核⼼组件之⼀&#xff0c;⽤于检查⼀个或多个Channel的状态是否处于可读、可写、可连接、可接收等。通过⼀个Selector选择器管理多个Channel&#xff0c;可以实现⼀个线程管理…

STM32标准库——(5)EXTI外部中断

1.中断系统 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继续运行 中断优先级&#xff…

Ribbon 体系架构解析

前面已经介绍了服务治理相关组件&#xff0c;接下来趁热打铁&#xff0c;快速通关Ribbon&#xff01;前面我们了解了负载均衡的含义&#xff0c;以及客户端和服务端负载均衡模型&#xff0c;接下来我们就来看下SpringCloud 下的客户端负载均衡组件Ribbon 的特点以及工作模型。 …

day04 两两交换链表中的节点、删除链表倒数第N个节点、链表相交、环形链表II

题目链接&#xff1a;leetcode24-两两交换链表中的节点, leetcode19-删除链表倒数第N个节点, leetcode160-链表相交, leetcode142-环形链表II 两两交换链表中的节点 基础题没有什么技巧 解题思路见代码注释 时间复杂度: O(n) 空间复杂度: O(1) Go func swapPairs(head *Li…

Android Handler完全解读

一&#xff0c;概述 Handler在Android中比较基础&#xff0c;本文笔者将对此机制做一个完全解读。读者可简单参考上述类图与时序图&#xff0c;便于后续理解。 二&#xff0c;源码解读 1&#xff0c;主线程伊始 众所周知&#xff0c;通过Zygote的fork方式&#xff0c;新创建…

腾讯云轻量应用Ubuntu服务器如何一键部署幻兽帕鲁Palworld私服?

幻兽帕鲁/Palworld是一款2024年Pocketpair开发的开放世界生存制作游戏&#xff0c;在帕鲁的世界&#xff0c;玩家可以选择与神奇的生物“帕鲁”一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。而帕鲁可以进行战斗、繁殖、协助玩家做农活&#xff0c;也…

网页转文件下载工具

为了更快捷copy博客 做了个 网页转文件下载工具 1.0.1 更新如下&#xff1a; javaphpjava提供页面转换文件的微服务APIphp调用接口&#xff0c;输出文件下载支持网页转md 1.0.2 更新如下&#xff1a; 样式表切换&#xff0c;白天or黑夜&#xff0c;cookie七天保质期 未…

全国首条智慧高速开通,“车牌付” 会取代传统 ETC 收费吗?

2024年1月19日&#xff0c;全国首条智慧高速--杭绍甬高速杭绍段正式建成通车&#xff01;项目全长约52.8公里&#xff0c;设计速度120公里/小时&#xff0c;是长三角智慧交通示范项目。 01 杭绍甬 “慧眼”感知系统 全国首条智慧高速公路--杭绍甬高速在视频AI算法、IoT物联网、…

SpringBoot系列之MybatisPlus实现分组查询

SpringBoot系列之MybatisPlus实现分组查询 我之前博主曾记写过一篇介绍SpringBoot2.0项目怎么集成MybatisPlus的教程&#xff0c;不过之前的博客只是介绍了怎么集成&#xff0c;并没有做详细的描述各种业务场景&#xff0c;本篇博客是对之前博客的补充&#xff0c;介绍在mybat…

mac裁剪图片

今天第一次用mac裁剪图片&#xff0c;记录一下过程&#xff0c;差点我还以为我要下载photoshop了&#xff0c; 首先准备好图片 裁剪的目的是把图片的标题给去掉&#xff0c;但是不能降低分辨率&#xff0c;否则直接截图就可以了 解决办法 打开原始图片(不要使用预览&#xf…

【机器学习笔记】0 基础知识之python基础

注&#xff1a;本文内容仅为个人学习笔记&#xff0c;教程为黄海广老师主讲的机器学习入门系列&#xff0c; 课程链接&#xff08;中国大学慕课&#xff0c;有习题和证书&#xff09; 课程资源&#xff08;pdf版本课件和代码&#xff09;公布在Github链接 课程视频也可以在b站观…

python10-Python的字符串之拼接字符串

如果直接将两个字符串紧挨着写在一起&#xff0c;Python就会自动拼接它们&#xff0c;例如如下代码。 s1 "软件测试划水老师傅&#xff0c;"软件测试老痞print(s1) 上面代码将会输出: 软件测试划水老师傅&#xff0c;软件测试老痞 上面这种写法只是书写字符串的一…

数学知识第三期 欧拉函数

前言 相信大家在高中的时候接触过欧拉函数&#xff0c;希望大家通过本篇文章能够进一步理解欧拉函数&#xff01;&#xff01;&#xff01; 一、什么是欧拉函数&#xff1f; 欧拉函数是一个在数论中用于描述特定正整数的互质数的概念。具体来说&#xff0c;对于一个正整数n&…

初识人工智能,一文读懂机器学习之逻辑回归知识文集(7)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

电商API接口|爬虫案例|采集某东商品评论信息

前言&#xff1a; 平常大家都有网上购物的习惯&#xff0c;在商品下面卖的好的产品基本都会有评论&#xff0c;当然也不排除有刷评论的情况&#xff0c;因为评论会影响我们的购物决策。今天主要分享用pythonre正则表达式获取京东商品评论。API接口获取京东平台商品详情SKU数据…

API网关-Apinto压缩包方式自动化安装配置教程

文章目录 前言一、Apinto安装教程1. 复制脚本2. 增加执行权限3. 执行脚本4. Apinto命令4.1 启动Apinto4.2 停止Apinto4.3 重启Apinto4.4 查看Apinto版本信息4.5 加入Apinto集群4.6 离开Apinto集群4.7 查看Apinto节点信息 5. 卸载Apinto 二、Apserver(Apinto Dashboard V3)安装教…

powermock: 一个支持 gRPC 的 Mock Server

文章目录 背景选型架构安装配置使用教程快速开始接口定义配置启动 Mock 规则redis 插件HTTP Mock高级配置前置准备场景一 特定 ID 返回特定用户信息场景二 通过脚本返回用户数据 总结参考资料 本文介绍的是如何基于 bilibili 的开源方案 powermock 搭建一套通用的适用于自己公司…

11. 双目视觉之立体视觉基础

目录 1. 深度恢复1.1 单目相机缺少深度信息1.2 如何恢复场景深度&#xff1f;1.3 深度恢复的思路 2. 对极几何约束2.1 直观感受2.2 数学上的描述 1. 深度恢复 1.1 单目相机缺少深度信息 之前学习过相机模型&#xff0c;最经典的就是小孔成像模型。我们知道相机通过小孔成像模…

uniapp scroll-view用法[下拉刷新,触底事件等等...](4)

前言:可滚动视图区域。用于区域滚动 话不多说 直接上官网属性 官网示例 讲一下常用的几个 scroll 滚动时触发 scrolltoupper 滚动到顶部或左边&#xff0c;会触发 scrolltoupper 事件 scrolltolower 滚动到底部或右边&#xff0c;会触发 scrolltolower 事件 1.纵向滚动…