一、登录页面

from django.contrib import admin
from django.urls import path
from blog import views urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
]

urls.py

  创建login视图函数

from django.shortcuts import render

# Create your views here.

def login(request):
return render(request, 'login.html')

views.py

  login.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
<link rel="stylesheet" href="/static/blog/bootstrap-3.3.7/css/bootstrap.css">
</head>
<body>
<h3>登录页面</h3>
<div class="container">
<div class="row">
<div class="col-md-6 col-lg-offset-3">
<form action="">
<div class="form-group">
{# label标签的"for"属性可把label绑定到另外一个元素,因此要把for属性值与input的id属性相同。#}
{# 当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件 #}
<label for="user">用户名</label>
{# 这里没必要加name属性了,之前加是点击submit按钮自己组装键值发出去,现在用ajax发只要找到标签拿到里面的值即可 #}
<input type="text" id="user" class="form-control">
</div>
<div class="form-group">
<label for="pwd">密码</label>
<input type="password" id="pwd" class="form-control">
</div>
{# 这里提交按钮不能使用<input type="submit">这就变成form表单提交事件了。 button类型时,这个按钮没有任何事件,可以给这个按钮绑定一个事件 #}
<input type="button" class="btn btn-default login-btn pull-right" value="提交">
</form>
</div>
</div>
</div>
</body>
</html>

注意:

  1、label标签的"for"属性可把label绑定到另外一个元素,因此要把for属性值与input的id属性相同。当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件;

  2、这里没必要加name属性了,之前加是点击submit按钮自己组装键值发出去,现在用ajax发只要找到标签拿到里面的值即可。

  3、这里提交按钮不能使用<input type="submit">这样就变成form表单提交事件了。 设为button类型时,这个按钮没有任何事件,可以给这个按钮绑定一个事件

二、在页面中添加验证码图片请求路径

1、登录页面添加验证码

<div class="container">
<div class="row">
<div class="col-md-6 col-lg-offset-3">
<form action="">
<div class="form-group">
<label for="user">用户名</label>
<input type="text" id="user" class="form-control">
</div>
<div class="form-group">
<label for="pwd">密码</label>
<input type="password" id="pwd" class="form-control">
</div>
<div class="form-group">
<label for="pwd">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="text" class="valid_code form-control">
</div>
<div class="col-md-6">
{# src还可以设置请求路径 #}
<img width="270" height="40" src="/get_validCode_img/" alt="">
</div>
</div>
</div>
<input type="button" class="btn btn-default login-btn pull-right" value="提交">
</form>
</div>
</div>
</div>

  注意:<img src="">,src除了可以指定图片路径还是设置为请求路径。

2、验证码路由

path('get_validCode_img/', views.get_validCode_img),

三、验证码视图函数

1、方式一:读取静态图片文件

def get_validCode_img(request):
with open("lufei.jpg", "rb") as f:
data = f.read()

  显示效果如下:

  

  不推荐使用这种方法,验证图片不能仅仅指定一张图片,这种方法把程序写死了。

2、方式二:pillow生成动态图片

  生成动态随机图片,使用Python图像处理库:Pillow

  安装pillow库:pip3 install pillow

  引入Pillow中最重要的类Image,该类存在于同名的模块中。可以通过以下几种方式实例化:从文件中读取图片,处理其他图片得到,或者直接创建一个图片。

import random
def get_validCode_img(request): def get_random_color():
return (random.randint(0,255), random.randint(0, 255), random.randint(0, 255)) # 方式二:pip3 install pillow
from PIL import Image
img = Image.new("RGB", (270, 40), color=get_random_color()) # 得到img对象,颜色三要素:红绿蓝 with open("validCode.png", "wb") as f:
img.save(f, "png") # 保存动态生成的图片 with open("validCode.png", "rb") as f:
data = f.read() return HttpResponse(data)

  运行效果如下:

  

  每次刷新,随机图片的颜色会发生随机变换。但是这种方式是请求进来时,先把数据加载到磁盘上,再在磁盘把数据读出来返还给浏览器,而且磁盘的处理数据时非常慢的,因此应该交到内存中管理。

3、方式三:使用pillow生成动态页面的基础上,引入BytesIO将图片保存在内存中

import random
def get_validCode_img(request): def get_random_color():
return (random.randint(0,255), random.randint(0, 255), random.randint(0, 255)) # 方式三:要引入BytesIO
from PIL import Image
from io import BytesIO
img = Image.new("RGB", (270, 40), color=get_random_color()) # 得到img对象,颜色三要素:红绿蓝 # f为内存句柄
f= BytesIO() # 会自己处理内存回收
# 保存图片
img.save(f, "png")
data = f.getvalue() return HttpResponse(data)

4、方式四:添加验证码文字信息

  ImageDraw模块提供了图像对象的简单2D绘制。用户可以使用这个模块创建新的图像,注释或润饰已存在图像,为web应用实时产生各种图形。

draw.text()   写文字
参数: xy:坐标 text:文本内容 fill:文本颜色 font:文本样式
draw.line() 画线
draw.point() 画点

  ImageFont 模块中,可以使用 load() 函数加载一个 bitmap 字体,使用 truetype(fontfile, fontsize) 函数加载一个 OpenType/TrueType 字体(注意,这个函数需要额外安装_imageingft模块)。

  在static目录下创建font子目录,给用户存放字体文件。下载字体到该目录./cnblog/static/font/下。

import random
def get_validCode_img(request): # 随机颜色
def get_random_color():
return (random.randint(0,255), random.randint(0, 255), random.randint(0, 255)) # 方式四:
from PIL import Image, ImageDraw,ImageFont
from io import BytesIO img = Image.new("RGB", (270, 40), color=get_random_color()) # 得到img对象,颜色三要素:红绿蓝
# 创建Draw对象
draw = ImageDraw.Draw(img)
# 创建Font对象
kumo_font = ImageFont.truetype("static/font/kumo.ttf", size=20)
draw.text((0,5), "python", get_random_color(), font=kumo_font)
f = BytesIO() # f为内存句柄
img.save(f, "png")
data = f.getvalue() return HttpResponse(data)

  显示效果如下所示:

  

5、生成随机字符串验证码

  随机生成大写字母、小写字母、数字。

  针对随机字母需要用到chr()方法,用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符(当前整数对应的ascii字符)。

# 随机字母:
"""
>>> chr(65)
'A'
>>> chr(90)
'Z'
>>> chr(97)
'a'
>>> chr(122)
'z'
"""

  另外还需要用到choice() 方法,该方法可返回一个列表,元组或字符串的随机项。choice()是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法。

import random
def get_validCode_img(request): # 随机颜色
def get_random_color():
return (random.randint(0,255), random.randint(0, 255), random.randint(0, 255)) # 方式五:修改为随机字符串
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO img = Image.new("RGB", (270, 40), color=get_random_color()) # 得到img对象,颜色三要素:红绿蓝
# 创建Draw对象
draw = ImageDraw.Draw(img)
# 创建Font对象
kumo_font = ImageFont.truetype("static/font/kumo.ttf", size=28) for i in range(5):
random_num = str(random.randint(0, 9)) # 随机数字
random_low_alpha = chr(random.randint(95, 122)) # 随机小写字母
random_upper_alpha = chr(random.randint(65, 90)) # 随机大写字母 # 三选一:choice() 方法返回一个列表,元组或字符串的随机项。
random_char = random.choice([random_num, random_low_alpha, random_upper_alpha])
draw.text((i*50+20, 5), random_char, get_random_color(), font=kumo_font) # 坐标错开间距 f = BytesIO() # f为内存句柄
img.save(f, "png")
data = f.getvalue() return HttpResponse(data)

  显示效果如下所示:

  

四、验证码图片的噪点和噪线

  添加图片噪点和噪线的代码:

# 给验证码图片添加噪点噪线
width = 270
height = 40
for i in range(10):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill = get_random_color()) # 画出一条线 for i in range(50):
draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) # 画点
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y +4), 0, 90, fill=get_random_color())

  可以任意调配噪线和噪点的数量,尽量保证机器无法识别,但人可以识别。

  Draw 类提供了 arc(xy, start, end, options) 函数来绘制弧线,参数解析如下所示:

xy 是个长度为4的列表,用来表示一个 bounding box(边界区域)。如[x0, y0, x1, y1],分别表示 弧线最左侧距离左边、弧线最顶点距离上边、弧线最右侧距离左边、弧线最低点距离上边的距离。

start 和 end 则是弧的起止角度,单位是 °。其中水平向右的方向为 0°,竖直向下的方向为 90°,水平向左的方向为 180°,竖直向上的方向为 270°。

options 中可用选项:
fill = (R, G, B) :指定线条颜色

  验证码视图修改如下:

import random
def get_validCode_img(request): # 随机颜色
def get_random_color():
return (random.randint(0,255), random.randint(0, 255), random.randint(0, 255)) from PIL import Image, ImageDraw, ImageFont
from io import BytesIO img = Image.new("RGB", (270, 40), color=get_random_color()) # 得到img对象,颜色三要素:红绿蓝
# 创建Draw对象
draw = ImageDraw.Draw(img)
# 创建Font对象
kumo_font = ImageFont.truetype("static/font/kumo.ttf", size=28)
for i in range(5):
random_num = str(random.randint(0, 9)) # 随机数字
random_low_alpha = chr(random.randint(95, 122)) # 随机小写字母
random_upper_alpha = chr(random.randint(65, 90)) # 随机大写字母 # 三选一:choice() 方法返回一个列表,元组或字符串的随机项。注意:choice()是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法。
random_char = random.choice([random_num, random_low_alpha, random_upper_alpha])
draw.text((i*50+20, 5), random_char, get_random_color(), font=kumo_font) # 坐标错开间距 # 给验证码图片添加噪点噪线
width = 270
height = 40
for i in range(10):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill = get_random_color()) # 画出一条线 for i in range(50):
draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) # 画点
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y +4), 0, 90, fill=get_random_color()) f = BytesIO() # f为内存句柄
img.save(f, "png")
data = f.getvalue() return HttpResponse(data)

  显示效果如下所示:

  

五、验证码刷新功能

1、验证码图片刷新原理

(1)给验证码图片添加id属性:id="valid_code_img"

<div class="form-group">
<label for="pwd">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="text" class="valid_code form-control">
</div>
<div class="col-md-6">
{# src还可以设置请求路径 #}
<img width="270" height="40" id="valid_code_img" src="/get_validCode_img/" alt="">
</div>
</div>
</div>

(2)创建/static/js/目录,添加jquery-3.3.1.js,在login.html中引入jquery:

<script src="/static/js/jquery-3.3.1.js"></script>

(3)在页面控制台操作验证码图片:

  

  每次在$("#valid_code_img")[0].src后面添加一个“?”都会刷新验证码图片。

2、实现点击验证码,验证码刷新

<script src="/static/js/jquery-3.3.1.js"></script>
<script>
// 刷新验证码
$("#valid_code_img").click(function () {
$(this)[0].src+="?"
})
</script>

六、验证验证码字符串

1、给btn绑定ajax事件:登录验证

// 登录验证
$(".login-btn").click(function () {
$.ajax({
url: "",
type: "post",
data: {
user: $("#user").val(),
pwd: $("#pwd").val(),
valid_code: $("#valid_code").val(),
// 自己组csrf键值
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(), {# csrf_token的值 #}
},
success:function (data) {
console.log(data)
}
})
})

  给后端提交用户名密码、验证码做校验。

  注意:发post请求一定要通过csrf校验,因此要在form中找一个地方加入:

{% csrf_token %}

  但是光加这个是不能通过校验的,这里与发form请求不同,需要自己组csrf_token键值:

  

  可以在这里看到键名:csrfmiddlewaretoken,利用键名组csrf键值对。

// 自己组csrf键值
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(), {# csrf_token的值 #}

2、login视图函数处理POST请求

from django.http import JsonResponse

def login(request):
if request.method == "POST":
response = {"user": None, "msg": None}
user = request.POST.get("user")
pwd = request.POST.get("pwd")
valid_code = request.POST.get("valid_code")
# 从session中取到值,一个浏览器存一份,不会发生相互干扰
valid_code_str = request.session.get("valid_code_str") if valid_code.upper() == valid_code_str.upper(): # 添加upper()不区分大小写
pass
else:
response['msg'] = "valid code error!"
return JsonResponse(response) # 字典放进去直接序列化,ajax拿到的就是 格式,不用反序列化了 return render(request, 'login.html')

  (1)在校验用户名密码前,要先校验验证码。

  (2)注意这里做验证码校验,但是验证码在另一个视图函数中,要取到另一个函数的验证码,不能设置为全局变量,这样不同人登录时会互相干扰,校验无法保证正常完成。

  因为session本身就是一个会话跟踪,能够保存上一次做的行为、操作、数据,因此利用它能完成验证码验证。

  (3)在get_validcode_img视图函数中需要添加如下代码:

request.session["valid_code_str"] = valid_code_str
"""验证码生成过程
1 生成一个随机字符串
2 设置一个COOKIE,{"sessionid":"刚刚生成的随机字符串"}
3 django-session表中存储 session-key session-data
随机字符串 {"valid_code_str": "随机验证码字符"}
"""

  (4)另外由于验证码校验是不区分大小写的,在login中校验验证码时,添加upper()方法:

if valid_code.upper() == valid_code_str.upper():   # 添加upper()不区分大小写

  (5)由于ajax一般都需要return 一个响应字符串,在这里引入JsonResponse:

from django.http import JsonResponse

  字典放进去直接序列化,ajax拿到的就是对象,两边都不需要进行json的序列化与反序列化。

  

  验证码验证成功,django_session表保存浏览器对应ssession记录:

  

七、登录验证

1、引入用户认证组件auth模块

from django.contrib import auth

2、在验证码验证通过后,运用authenticate()方法完成用户认证,即验证用户名以及密码是否正确

user = auth.authenticate(username=user, password=pwd)

3、添加一个用户,在控制台执行如下命令

$ python3 manage.py createsuperuser

4、验证用户信息无误后,使用login函数给使用django的session框架给某个已认证的用户附加上session id等信息

auth.login(request, user)   # request.user:当前登录对象

  request.user是全局变量,在任何视图和模板中可以直接使用。

5、运用ajax,在页面显示报错信息

(1)修改提交按钮的input标签样式,并在后面加span标签

<input type="button" class="btn btn-default login-btn" value="提交"><span class="error"></span>

(2)编写ajax请求回调函数:

// 登录验证
$(".login-btn").click(function () {
$.ajax({
url: "",
type: "post",
data: {
user: $("#user").val(),
pwd: $("#pwd").val(),
valid_code: $("#valid_code").val(),
// 自己组csrf键值
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(), {# csrf_token的值 #}
},
success:function (data) {
console.log(data);
if (data.user){
// 如果有值:前端跳转
location.href = "/index/"
} else {
// 如果没值
$(".error").text(data.msg).css({"color": "red", "margin-left": "10px"})
}
}
})
})

  注意:前端跳转写法和错误信息样式修改方式。

(3)添加index路由和视图

path('index/', views.index),

  视图:

def index(request):

    return render(request, "index.html")

  index模板:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>首页{{ request.user.username }}</h3>
</body>
</html>

(4)效果图如下所示:

   

八、登录验证优化

1、在登录验证错误时,显示的错误提示一秒后自动消失

// 登录验证
$(".login-btn").click(function () {
$.ajax({
url: "",
type: "post",
data: {
user: $("#user").val(),
pwd: $("#pwd").val(),
valid_code: $("#valid_code").val(),
// 自己组csrf键值
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(), {# csrf_token的值 #}
},
success:function (data) {
console.log(data);
if (data.user){
// 如果有值:前端跳转
location.href = "/index/"
} else {
// 如果没值
$(".error").text(data.msg).css({"color": "red", "margin-left": "10px"})
setTimeout(function () {
$(".error").text(""); // 一秒后清空错误提示
}, 1000)
}
}
})
})

  这里主要是用到了javascript中的setTimeout()方法,用来设定一个时间, 时间到了, 就会执行一个指定的 method。

2、从视图中分离出验证码功能代码

  验证码功能代码非常多且逻辑复杂,将这一部分逻辑构建为一个模块,视图中调用这个模块,实现程序解耦:

(1)创建./blog/utils/目录,创建文件validCode.py,将验证码功能相关代码拷入该文件中:

import random

def get_random_color():
# 随机颜色
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) def get_valid_code_imge(request):
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO img = Image.new("RGB", (270, 40), color=get_random_color()) # 得到img对象,颜色三要素:红绿蓝
# 创建Draw对象
draw = ImageDraw.Draw(img)
# 创建Font对象
kumo_font = ImageFont.truetype("static/font/kumo.ttf", size=28) valid_code_str = "" for i in range(5):
random_num = str(random.randint(0, 9)) # 随机数字
random_low_alpha = chr(random.randint(95, 122)) # 随机小写字母
random_upper_alpha = chr(random.randint(65, 90)) # 随机大写字母 # 三选一:choice() 方法返回一个列表,元组或字符串的随机项。
random_char = random.choice([random_num, random_low_alpha, random_upper_alpha])
draw.text((i * 50 + 20, 5), random_char, get_random_color(), font=kumo_font) # 坐标错开间距 # 保存验证码字符串
valid_code_str += random_char # 给验证码图片添加噪点噪线
# width = 270
# height = 40
# for i in range(10):
# x1 = random.randint(0, width)
# x2 = random.randint(0, width)
# y1 = random.randint(0, height)
# y2 = random.randint(0, height)
# draw.line((x1, y1, x2, y2), fill = get_random_color()) # 画出一条线
#
# for i in range(50):
# draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) # 画点
# x = random.randint(0, width)
# y = random.randint(0, height)
# draw.arc((x, y, x + 4, y +4), 0, 90, fill=get_random_color()) print("valid_code_str", valid_code_str) # valid_code_str Ms4v0 # 为什么用request.session:
# 因为session本身就是一个会话跟踪,能够保存上一次做的行为、操作、数据,因此利用它能完成验证码验证
request.session["valid_code_str"] = valid_code_str f = BytesIO() # f为内存句柄
img.save(f, "png")
data = f.getvalue() return data

(2)在视图函数中引入该模块,实现验证码功能

def get_validCode_img(request):
"""
基于PIL模块动态生成响应状态码图片
:param request:
:return:
"""
from blog.utils.validCode import get_valid_code_imge
data = get_valid_code_imge(request) return HttpResponse(data)

九、总结登录验证重点

1、一次请求伴随了多次请求(伴随了多个静态文件的请求)

2、PIL模块掌握,验证码

3、session存储

4、验证码刷新

基于Ajax与用户认证系统的登录验证的更多相关文章

  1. django用户认证系统——重置密码7

    当用户不小心忘记了密码时,网站需要提供让用户找回账户密码的功能.在示例项目中,我们将发送一封含有重置用户密码链接的邮件到用户注册时的邮箱,用户点击收到的链接就可以重置他的密码,下面是具体做法. 发送邮 ...

  2. django用户认证系统——修改密码6

    再此之前我们已经完成了用户登录.注册.注销等功能,接下来让我们继续为用户提供修改密码的功能.该功能 Django 的 auth 应用也已经为我们提供,过程几乎和之前的登录功能完全一样. 编写修改密码模 ...

  3. 项目一:第十一天 2、运单waybill快速录入 3、权限demo演示-了解 5、权限模块数据模型 6、基于shiro实现用户认证-登录(重点)

    1. easyui DataGrid行编辑功能 2. 运单waybill快速录入 3. 权限demo演示-了解 4. Apache shiro安全框架概述 5. 权限模块数据模型 6. 基于shiro ...

  4. django用户认证系统——登录4

    用户已经能够在我们的网站注册了,注册就是为了登录,接下来我们为用户提供登录功能.和注册不同的是,Django 已经为我们写好了登录功能的全部代码,我们不必像之前处理注册流程那样费劲了.只需几分钟的简单 ...

  5. Django Authentication 用户认证系统

    一. Django的认证系统 Django自带一个用户认证系统,用于处理用户账户.群组.许可和基于cookie的用户会话. 1.1 概览 Django的认证系统包含了身份验证和权限管理两部分.简单地说 ...

  6. django用户认证系统——基本设置1

    网站提供登录.注册等用户认证功能是一个常见的需求.因此,Django 提供了一套功能完整的.灵活的.易于拓展的用户认证系统:django.contrib.auth.在本教程中,我将向你展示 auth ...

  7. Laravel用户认证系统的实现细节

    原文地址:http://www.php.cn/php-weizijiaocheng-406076.html 这篇文章主要介绍了关于Laravel用户认证系统的实现细节,有着一定的参考价值,现在分享给大 ...

  8. 统一用户认证系统CUAS实现要点

    背景: 基于目前存在多套员工使用的日常工作子系统,现状为各系统各自有一套用户体系,员工需要记住各系统的用户名.密码等信息,还需要登录多个系统,重复工作量颇多.统一用户认证组件将用户名.密码等信息统一存 ...

  9. JWT 实现基于API的用户认证

    基于 JWT-Auth 实现 API 验证 如果想要了解其生成Token的算法原理,请自行查阅相关资料 需要提及的几点: 使用session存在的问题: session和cookie是为了解决http ...

随机推荐

  1. 1. C/C++项目一

    需求: 使用C语言封装string 字符串,实现字符串的增.删.改.查等API函数. 要求: 不能使用 string 库函数,所有库函数必须自己手动实现. [项目实现] myString.h 代码如下 ...

  2. ubuntu 软件使用

    1.制作iso: mkisofs -r -o file.iso your_folder_name/

  3. JAVA基础——编程练习(三)

    熟悉String方法的使用之判断文件名是否合法 学习之余,写个小练习来巩固一下String的方法应用. 任务: 1.判断用户选择要输入的内容的类型 2.如果是java文件,输出“您输入的是java文件 ...

  4. 【语义分割】large kernel matters中GCN模块的pytorch实现

    GCN模块的实现比较简单,在giuhub上看到两种实现,轻微不同 实现一:https://github.com/ycszen/pytorch-segmentation/blob/master/gcn. ...

  5. C++_异常8-异常、类和基础

    异常.类和继承以三种方式相互关联. 首先,可以像标准C++库所做的那样,从一个异常类派生出另一个. 其次,可以在类定义中嵌套异常类声明来组合异常. 第三,这种嵌套声明本身可以被继承,还可以作为基类. ...

  6. windows_study_1

    描述:win8/windows server 设置用户登陆密码永不过期 解决:  第一步:打开控制面板,点击系统和安全第二部:管理工具第三步:本地安全组策略第四步:看图 第五步:把密码过期天数,改成0 ...

  7. Odd number problem

    描述 你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中.例如:5 2 81 3 _4 6 7在游戏过程中,可以把空格与其上.下 ...

  8. C - 思考使用差分简化区间操作

    FJ's N (1 ≤ N ≤ 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a positi ...

  9. WebApi接入Swagger

    1.新建webApi项目 2.nuget引入 swagger 3.在项目属性里配置输出 xml文件 4.打开SwaggerConfig.cs编辑 protected static string Get ...

  10. 踩坑--http返回码之302状态码

    项目介绍:springboot+shiro+maven 业务需求:拦截一切不登录的盗链URL,除了问卷调查,可以给任意用户填写和提交意外. 问题重现:表单提交过程中返回302状态码,我就觉得很奇怪.在 ...