Luffy /4/ 多方式登录接口&登录注册前端页面

现在比较常见的登录方式:手机号+验证码,邮箱+密码,用户名+密码,下面实现一下多方式登录接口

需求接口

# 登陆和注册功能--->5个接口
-多方式登陆接口(手机号,邮箱,用户名 +密码)
-验证手机号是否存在接口 -发送短信验证码接口 # 借助于第三方发送短信:阿里,腾讯,容联云通讯,刚注册会送100条短信
-手机号+验证码登陆接口
-手机号+验证码+密码注册接口

腾讯云短信

这里的短信功能使用的是第三方腾讯云,注册公众号申请腾讯云短信功能,会送100条短信供你玩;

申请好公众号,通过该地址https://console.cloud.tencent.com/smsv2/guide,设置

"""
创建短信签名
-签名管理---》创建签名--》使用公众号提交申请---》审核
创建短信正文模板
-正文模板管理---》创建正文模板--》等审核
发送短信
-API,SDK
"""

官网文档

API和SDK区别

-API接口,通过HTTP调用腾讯云发送短信接口,腾讯负责把短信发送到手机上,HTTP接口基于它来写,比较麻烦,需要我们处理请求参数,或者携带很多参数···

-SDK:第三方使用不同语言封装好了,只需下载导入,调用函数处理即可

使用SDK

# 发短信sdk的使用
# 3.x的发送短信sdk,tencentcloud 包含的功能更多
pip install tencentcloud-sdk-python
# 2.x发送短信sdk:https://cloud.tencent.com/document/product/382/11672
# 只是发短信的sdk,功能少,py3.8以后不支持
pip install qcloudsms_py

登录注册前端页面

在实现页面前我们思考如下问题:

如何实现点击登录或图片进行跳转

# 思路:使用vue-router实现页面跳转,跳转就涉及到路由,我们可以先把路由配置好

1.router/index.js中配置要跳转的路由,这里登录举例,写一个Login组件(登录页面),然后在index.js导入使用:import Login from "@/views/Login";
"""
{
path: '/login',
name: 'login',
component: Login
}
"""
2. 访问/login路径就能够跳转到登录页面组件 # 实现点击跳转的两种常用方法
## 方法一:绑定点击事件,实现点击跳转
this.$router.push('/login')
## 方法二:使用 <router-link to=""></router-link>标签实现跳转
注册:<router-link to="/login"><span>注册</span></router-link>
图片:<router-link to="/">
<img src="../assets/img/head-logo.svg" alt="">
</router-link>

<router-link to=""></router-link>标签实现跳转第三方

数据库添加第三方link

demo

<!--  跳第三方  -->
<!--如果图片的跳转路径不包含http,那么就跳转本地 -->
<div v-if="!(item.link.indexOf('http')>-1)">
<router-link :to="item.link">
<img :src="item.image" alt="课程图">
</router-link>
</div>
<!-- 如果图片包含了http那么就跳转第三方 -->
<div v-else>
<a :href="item.link">
<img :src="item.image" alt="课程图">
</a>
</div>

如果不进行处理,router-link标签只能跳转本地,如果想要跳转第三方(百度,博客···)需要进一步处理!

登录注册前端页面实现

实现的样式是基于弹出框实现,弹出的是模态框

Login.vue

<template>
<div class="login">
<div class="box">
<i class="el-icon-close" @click="close_login"></i>
<div class="content">
<div class="nav">
<span :class="{active: login_method === 'is_pwd'}"
@click="change_login_method('is_pwd')">密码登录</span>
<span :class="{active: login_method === 'is_sms'}"
@click="change_login_method('is_sms')">短信登录</span>
</div>
<el-form v-if="login_method === 'is_pwd'">
<el-input
placeholder="用户名/手机号/邮箱"
prefix-icon="el-icon-user"
v-model="username"
clearable>
</el-input>
<el-input
placeholder="密码"
prefix-icon="el-icon-key"
v-model="password"
clearable
show-password>
</el-input>
<el-button type="primary">登录</el-button>
</el-form>
<el-form v-if="login_method === 'is_sms'">
<el-input
placeholder="手机号"
prefix-icon="el-icon-phone-outline"
v-model="mobile"
clearable
@blur="check_mobile">
</el-input>
<el-input
placeholder="验证码"
prefix-icon="el-icon-chat-line-round"
v-model="sms"
clearable>
<template slot="append">
<span class="sms" @click="send_sms">{{ sms_interval }}</span>
</template>
</el-input>
<el-button type="primary">登录</el-button>
</el-form>
<div class="foot">
<span @click="go_register">立即注册</span>
</div>
</div>
</div>
</div>
</template> <script>
export default {
name: "Login",
data() {
return {
username: '',
password: '',
mobile: '',
sms: '',
login_method: 'is_pwd',
sms_interval: '获取验证码',
is_send: false,
}
},
methods: {
close_login() {
this.$emit('close')
},
go_register() {
this.$emit('go')
},
change_login_method(method) {
this.login_method = method;
},
check_mobile() {
if (!this.mobile) return;
if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
this.$message({
message: '手机号有误',
type: 'warning',
duration: 1000,
onClose: () => {
this.mobile = '';
}
});
return false;
}
this.is_send = true;
},
send_sms() { if (!this.is_send) return;
this.is_send = false;
let sms_interval_time = 60;
this.sms_interval = "发送中...";
let timer = setInterval(() => {
if (sms_interval_time <= 1) {
clearInterval(timer);
this.sms_interval = "获取验证码";
this.is_send = true; // 重新回复点击发送功能的条件
} else {
sms_interval_time -= 1;
this.sms_interval = `${sms_interval_time}秒后再发`;
}
}, 1000);
}
}
}
</script> <style scoped>
.login {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 10;
background-color: rgba(0, 0, 0, 0.3);
} .box {
width: 400px;
height: 420px;
background-color: white;
border-radius: 10px;
position: relative;
top: calc(50vh - 210px);
left: calc(50vw - 200px);
} .el-icon-close {
position: absolute;
font-weight: bold;
font-size: 20px;
top: 10px;
right: 10px;
cursor: pointer;
} .el-icon-close:hover {
color: darkred;
} .content {
position: absolute;
top: 40px;
width: 280px;
left: 60px;
} .nav {
font-size: 20px;
height: 38px;
border-bottom: 2px solid darkgrey;
} .nav > span {
margin: 0 20px 0 35px;
color: darkgrey;
user-select: none;
cursor: pointer;
padding-bottom: 10px;
border-bottom: 2px solid darkgrey;
} .nav > span.active {
color: black;
border-bottom: 3px solid black;
padding-bottom: 9px;
} .el-input, .el-button {
margin-top: 40px;
} .el-button {
width: 100%;
font-size: 18px;
} .foot > span {
float: right;
margin-top: 20px;
color: orange;
cursor: pointer;
} .sms {
color: orange;
cursor: pointer;
display: inline-block;
width: 70px;
text-align: center;
user-select: none;
}
</style>

Register.vue

<template>
<div class="register">
<div class="box">
<i class="el-icon-close" @click="close_register"></i>
<div class="content">
<div class="nav">
<span class="active">新用户注册</span>
</div>
<el-form>
<el-input
placeholder="手机号"
prefix-icon="el-icon-phone-outline"
v-model="mobile"
clearable
@blur="check_mobile">
</el-input>
<el-input
placeholder="密码"
prefix-icon="el-icon-key"
v-model="password"
clearable
show-password>
</el-input>
<el-input
placeholder="验证码"
prefix-icon="el-icon-chat-line-round"
v-model="sms"
clearable>
<template slot="append">
<span class="sms" @click="send_sms">{{ sms_interval }}</span>
</template>
</el-input>
<el-button type="primary">注册</el-button>
</el-form>
<div class="foot">
<span @click="go_login">立即登录</span>
</div>
</div>
</div>
</div>
</template> <script>
export default {
name: "Register",
data() {
return {
mobile: '',
password: '',
sms: '',
sms_interval: '获取验证码',
is_send: false,
}
},
methods: {
close_register() {
this.$emit('close', false)
},
go_login() {
this.$emit('go')
},
check_mobile() {
if (!this.mobile) return;
if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
this.$message({
message: '手机号有误',
type: 'warning',
duration: 1000,
onClose: () => {
this.mobile = '';
}
});
return false;
}
this.is_send = true;
},
send_sms() {
if (!this.is_send) return;
this.is_send = false;
let sms_interval_time = 60;
this.sms_interval = "发送中...";
let timer = setInterval(() => {
if (sms_interval_time <= 1) {
clearInterval(timer);
this.sms_interval = "获取验证码";
this.is_send = true; // 重新回复点击发送功能的条件
} else {
sms_interval_time -= 1;
this.sms_interval = `${sms_interval_time}秒后再发`;
}
}, 1000);
}
}
}
</script> <style scoped>
.register {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 10;
background-color: rgba(0, 0, 0, 0.3);
} .box {
width: 400px;
height: 480px;
background-color: white;
border-radius: 10px;
position: relative;
top: calc(50vh - 240px);
left: calc(50vw - 200px);
} .el-icon-close {
position: absolute;
font-weight: bold;
font-size: 20px;
top: 10px;
right: 10px;
cursor: pointer;
} .el-icon-close:hover {
color: darkred;
} .content {
position: absolute;
top: 40px;
width: 280px;
left: 60px;
} .nav {
font-size: 20px;
height: 38px;
border-bottom: 2px solid darkgrey;
} .nav > span {
margin-left: 90px;
color: darkgrey;
user-select: none;
cursor: pointer;
padding-bottom: 10px;
border-bottom: 2px solid darkgrey;
} .nav > span.active {
color: black;
border-bottom: 3px solid black;
padding-bottom: 9px;
} .el-input, .el-button {
margin-top: 40px;
} .el-button {
width: 100%;
font-size: 18px;
} .foot > span {
float: right;
margin-top: 20px;
color: orange;
cursor: pointer;
} .sms {
color: orange;
cursor: pointer;
display: inline-block;
width: 70px;
text-align: center;
user-select: none;
}
</style>

Header.vue

<template>
<div class="header">
<div class="slogan">
<p>路飞学城 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p>
</div>
<div class="nav">
<ul class="left-part">
<li class="logo">
<router-link to="/">
<img src="../assets/img/head-logo.svg" alt="">
</router-link>
</li>
<li class="ele">
<span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span>
</li>
<li class="ele">
<span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span>
</li>
<li class="ele">
<span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span>
</li>
</ul> <div class="right-part">
<div>
<span @click="put_login">登录</span>
<span class="line">|</span>
<span @click="put_register">注册</span>
</div>
</div>
<Login v-if="is_login" @close="close_login" @go="put_register"/>
<Register v-if="is_register" @close="close_register" @go="put_login"/> </div>
</div> </template> <script>
import Login from "@/components/Login";
import Register from "@/components/Register"; export default {
name: "Header",
data() {
return {
url_path: sessionStorage.url_path || '/',
is_login: false,
is_register: false
}
},
methods: {
goPage(url_path) {
// 已经是当前路由就没有必要重新跳转
if (this.url_path !== url_path) {
this.$router.push(url_path);
}
sessionStorage.url_path = url_path;
},
close_login() {
this.is_login = false
},
close_register() {
this.is_register = false
},
put_register() {
this.is_register = true
this.is_login = false
},
put_login() {
this.is_register = false
this.is_login = true
} },
created() {
sessionStorage.url_path = this.$route.path;
this.url_path = this.$route.path;
},
components: {
Login, Register
}
}
</script> <style scoped>
.header {
background-color: white;
box-shadow: 0 0 5px 0 #aaa;
} .header:after {
content: "";
display: block;
clear: both;
} .slogan {
background-color: #eee;
height: 40px;
} .slogan p {
width: 1200px;
margin: 0 auto;
color: #aaa;
font-size: 13px;
line-height: 40px;
} .nav {
background-color: white;
user-select: none;
width: 1200px;
margin: 0 auto; } .nav ul {
padding: 15px 0;
float: left;
} .nav ul:after {
clear: both;
content: '';
display: block;
} .nav ul li {
float: left;
} .logo {
margin-right: 20px;
} .ele {
margin: 0 20px;
} .ele span {
display: block;
font: 15px/36px '微软雅黑';
border-bottom: 2px solid transparent;
cursor: pointer;
} .ele span:hover {
border-bottom-color: orange;
} .ele span.active {
color: orange;
border-bottom-color: orange;
} .right-part {
float: right;
} .right-part .line {
margin: 0 10px;
} .right-part span {
line-height: 68px;
cursor: pointer;
}
</style>

接口实现1

验证手机号是否存在接口

思路:数据库查询,存在返回{“code”:“100”,“msg”:“成功”}

users/views.py

from .models import User
from utils.reponse import APIResponse
from rest_framework.exceptions import APIException
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action class MobilePhone(ViewSet):
@action(methods=['GET'],detail=False)
def check_mobile(self,request):
try:
# 从请求参数获取手机号
mobile = request.query_params.get('mobile')
User.objects.get(mobile=mobile)
# 存在返回`{“code”:“100”,“msg”:“成功”}`
return APIResponse()
except Exception as e:
raise APIException(str(e))

users/urls.py


from django.urls import path, include
from rest_framework.routers import SimpleRouter
from .views import UserView router = SimpleRouter()
# 127.0.0.1:8000/api/v1/user/mobile/check_mobile
router.register('mobile',UserView , 'mobile')
urlpatterns = [
path('', include(router.urls)),
]


多方式登录接口

视图

from .models import User
from utils.reponse import APIResponse
from rest_framework.exceptions import APIException
from rest_framework.viewsets import ViewSet,GenericViewSet
from rest_framework.decorators import action # 验证手机号是否存在
class MobileView(ViewSet):
@action(methods=['GET'],detail=False)
def check_mobile(self,request):
try:
# 从请求参数获取手机号
mobile = request.query_params.get('mobile')
User.objects.get(mobile=mobile)
# 存在返回`{“code”:“100”,“msg”:“成功”}`
return APIResponse()
except Exception as e:
raise APIException(str(e)) # 多方式登录
from .serializer import MulLoginSerializer class LoginView(GenericViewSet):
serializer_class = MulLoginSerializer
queryset = User # 两个登陆方式都写在这里面(多方式,一个是验证码登陆)
# login不是保存,但是用post,咱们的想法是把验证逻辑写到序列化类中
@action(methods=["post"], detail=False)
def mul_login(self, request):
try:
ser = MulLoginSerializer(data=request.data, context={'request': request})
ser.is_valid(raise_exception=True) # 如果校验失败,直接抛异常,不需要加if判断了
token = ser.context.get('token')
username = ser.context.get('username')
icon = ser.context.get('icon')
return APIResponse(token=token, username=username, icon=icon) # {code:100,msg:成功,token:dsadsf,username:Hammer}
except Exception as e:
raise APIException(str(e))

序列化类

from .models import User
from rest_framework import serializers
from rest_framework.exceptions import ValidationError # 这个序列化类,只用来做反序列化,数据校验,最后不保存,不用来做序列化
class MulLoginSerializer(serializers.ModelSerializer):
# 一定要重写username这个字段,因为username这个字段校验规则是从User表映射过来的,
# username是唯一,假设数据库中存在HammerZe用户,传入HammerZe用户,字段自己的校验规则就会校验失败,失败原因是数据库存在一个HammerZe用户了
# 所以需要重写这个字段,取消 掉它的unique
username = serializers.CharField(max_length=18, min_length=3) # 一定要重写,不重写,字段自己的校验过不去,就到不了全局钩子 class Meta:
model = User
fields = ['username', 'password'] def validate(self, attrs):
# 在这里面完成校验,如果校验失败,直接抛异常
# 1 多方式得到user
user = self._get_user(attrs)
# 2 user签发token
token = self._get_token(user)
# 3 把token,username,icon放到context中
self.context['token'] = token
self.context['username'] = user.username
# 写死的路径
# self.context['icon'] = 'http://127.0.0.1:8000/media/'+str(user.icon) # 对象ImageField的对象
request = self.context['request']
# request.META['HTTP_HOST']取出服务端的ip地址
icon = 'http://%s/media/%s' % (request.META['HTTP_HOST'], str(user.icon))
self.context['icon'] =icon
return attrs # 正则校验登录方式
# 意思是该方法只在类内部用,但是外部也可以用,如果写成__就只能再内部用了
def _get_user(self, attrs):
import re
username = attrs.get('username')
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 not user:
# raise ValidationError('用户不存在')
raise ValidationError('用户名或密码错误') # 取出前端传入的密码
password = attrs.get('password')
if not user.check_password(password): # 学auth时讲的,通过明文校验密码
raise ValidationError("用户名或密码错误") return user def _get_token(self, user):
# jwt模块中提供的
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return token

路由

from django.urls import path,include
from user import views
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('mobile',views.MobileView,'mobile') # 127.0.0.1:8000/api/v1/user/mobile/check_mobile
router.register('login',views.LoginView , 'login') # 127.0.0.1:8000/api/v1/user/login/mul_login
urlpatterns = [
path('',include(router.urls)),
]

测试


接口实现2

实现发送短信接口配置和验证

配置发送短信

\libs\tencent_sms_v3_init_.py

from .sms import get_code, send_sms

\libs\tencent_sms_v3\sms.py

import random
from . import settings
from utils.log import logger
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 # 写两个函数,
# 获取验证码的函数
def get_code(count=4):
code_str = ''
for i in range(count):
num = random.randint(0, 9)
code_str += str(num)
return code_str # 发送短信的函数 def send_sms(phone, code):
try:
cred = credential.Credential(settings.SECRETID, settings.SECRETKEY)
# 实例化一个http选项,可选的,没有特殊需求可以跳过。
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.APPID
req.SignName = settings.SIGNAME
req.TemplateId = settings.TemplateId
req.TemplateParamSet = [code,]
req.PhoneNumberSet = ["+86%s"%phone,]
req.SessionContext = ""
req.ExtendCode = ""
req.SenderId = ""
client.SendSms(req)
# print(resp.to_json_string(indent=2))
return True
except TencentCloudSDKException as err:
# 如果短信发送失败,记录一下日志--》一旦使用了记录日志,使用的是django 的日志,以后这个包,给别的框架用,要改日志
logger.error('手机号为:%s发送短信失败,失败原因:%s'%phone,str(err))

tencent_sms_v3\settings.py

# 都配置成自己的就行了,参考官网文档https://console.cloud.tencent.com/cam/capi
# https://cloud.tencent.com/document/product/382/43196
SECRETID=''
SECRETKEY=''
APPID = ""
SIGNAME=''
TemplateId = ""

发送短信接口

视图

from libs import tencent_sms_v3

class SendSmsView(ViewSet):
@action(methods=['GET'],detail=False)
def send_message(self, request):
try:
phone = request.query_params.get('phone')
# 生成验证码
code = tencent_sms_v3.get_code()
# code要保存,否则后面没法验证
res = tencent_sms_v3.send_sms(phone, code)
if res:
return APIResponse(msg='短信发送成功')
else:
raise APIException("短信发送失败")
except Exception as e:
raise APIException(str(e))

路由

router.register('send',views.SendSmsView , 'send')  #  127.0.0.1:8000/api/v1/user/send/send_message/--->get请求

测试

Luffy /4/ 多方式登录接口&登录注册前端页面的更多相关文章

  1. Flask--第三个例子,写一个接口,该接口返回html前端页面,模板的使用

     将接口数据返回至html前端页面有两种方法 方法一: 1 @app.route('/index',methods=['get']) 2 def open_index(): 3 page=open(' ...

  2. 授权QQ登录的qq端前端页面变迁

    ac_type = 'qq' if ac_type == 'qq': myid, mypwd = qq_key xp = '/html/body/div/div/div[2]/div/div/div/ ...

  3. Django实战(一)-----用户登录与注册系统3(前端页面、登录视图)

    基本框架搭建好了后,我们就要开始丰富页面内容了.最起码,得有一个用户登录的表单不是么?(注册的事情我们先放一边.) 一. 原生HTML页面 删除原来的login.html文件中的内容,写入下面的代码: ...

  4. Django商城项目笔记No.10用户部分-登录接口

    Django商城项目笔记No.10用户部分-登录接口 添加url路由 接下来第二步,增加返回内容: 增加结果如下: 配置:上边的方法定义了返回的内容都有哪些,那这个方法jwt还不知道,需要配置: 修改 ...

  5. CI框架 QQ接口(第三方登录接口PHP版)

    本帖内容较多,大部分都是源码,要修改的地方只有一个,其他只要复制过去,就可以完美运行.本帖主要针对CI框架,不用下载SDK,按我下面的步骤,建文件,复制代码就可以了.10分钟不要,接口就可完成.第一步 ...

  6. 新浪微博登录接口(PHP版)

    CI框架下 新浪微博登录接口完整版说明:本贴只适合CI框架.功能实现:登录接口跳转链接成功,获取用户信息(包括最重要的u_id)成功,将用户与本地平台连接起来,用户登录成功后信息的存储,本地数据库第三 ...

  7. QQ登录接口(第三方登录接口)

    CI框架 QQ接口(第三方登录接口PHP版) 本帖内容较多,大部分都是源码,要修改的地方只有一个,其他只要复制过去,就可以完美运行.本帖主要针对CI框架,不用下载SDK,按我下面的步骤,建文件,复制代 ...

  8. SpringBoot注册登录(三):注册--验证账号密码是否符合格式及后台完成注册功能

    SpringBoot注册登录(一):User表的设计点击打开链接SpringBoot注册登录(二):注册---验证码kaptcha的实现点击打开链接      SpringBoot注册登录(三):注册 ...

  9. day1作业--登录接口

    作业:编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定     知识: 1.循环的使用: 2.continue,break在循环中中断的作用: 3.文件的写入,读取: 4.各基础知 ...

随机推荐

  1. 记录NLTK安装使用全过程--python

    前言 之前做实验用到了情感分析,就下载了一下,这篇博客记录使用过程. 下载安装到实战详细步骤 NLTK下载安装 先使用pip install nltk 安装包 然后运行下面两行代码会弹出如图得GUI界 ...

  2. 什么是BASH?

    BASH是Bourne Again SHell的缩写.它由Steve Bourne编写,作为原始Bourne Shell(由/ bin / sh表示)的替代品.它结合了原始版本的Bourne Shel ...

  3. spring源码-扩展点

    /** * @Author quan * @Date 2020/11/13 * 扩展原理 * BeanPostProcessor bean后置处理器,bean创建对象初始化前后进行拦截工作 * * * ...

  4. 比较一下 Java 和 JavaSciprt?

    JavaScript 与 Java 是两个公司开发的不同的两个产品.Java 是原 Sun Microsystems 公司推出的面向对象的程序设计语言,特别适合于互联网应用程序 开发:而 JavaSc ...

  5. 用TLS/SSL保证EMQ的网络传输安全

    作为基于现代密码学公钥算法的安全协议,TLS/SSL能在计算机通讯网络上保证传输安全,EMQ的MQTT broker支持TLS,也可以用这种方式来确保传输安全. 参考官网:https://www.em ...

  6. 给定一个奇数n,比如n=3,生成1到n平方的数,如1到9,填入九宫格,使得横竖斜的和都相等。

    对于N阶幻方,从1开始把数字从小到大按以下规则依次写入: 一.在第一行中间一列写入1 二.依次向右上方写入2.3.4...... 三.如果某数字写在了表格的某个方向外面,那就把这个数字向相反方向移动N ...

  7. 什么是 MyBatis 的接口绑定?有哪些实现方式?

    接口绑定,就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑 定, 我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方法我们可 以有更加灵活的选择和 ...

  8. 学习SVN03

    SVN版本控制系统最佳实践   第1章SVN介绍及应用场景 1.1什么是SVN(Subversion) Svn(subversion)是近年来崛起非常优秀的版本管理工具,与CVS管理工具一样,SVN是 ...

  9. AGENS算法

    3.2 层次方法 下图,上面是从左到右由5个簇逐渐合并成1个簇的过程,下面是从右到左由一个簇逐渐分裂成5个簇的过程 AGENS算法 最后面一句话是重点,假设有<A,B>,<C,D&g ...

  10. 从八道面试题看JavaScript DOM事件机制

    As we all know,事件机制其实很简单,无非冒泡和捕获这两点,笔者不再赘述,网上相关文章一大堆,下面让我们直接看面试题 题目一到七,统一设置css .test2 { height: 50px ...