django 入门2

一、简介视图

   主要内容:URLconf、HttpRequest对象、HttpResponse

1)视图接受Web请求并且返回Web响应

2)视图就是一个python函数,被定义在views.py中

3)响应可以是一张网页的HTML内容,一个重定向,一个404错误等等

4)在http请求中产生两个核心对象,所在位置是,django.http

http请求:HttpRequest对象

http响应:HttpResponse对象

  这两个对象是由django帮我构造的

 

5)响应处理过程如下图:

 

二、URLconf

1. 一个url()对象包括

1.1 URLconf相关概述

  • 在settings.py文件中通过ROOT_URLCONF指定根级url的配置
  • urlpatterns是一个url()实例的列表,我们把它称为路由,它里面的每一个url()我们称为路由配置
  • 一个url()对象包括:
    • 正则表达式
    • 视图函数
    • 可选参数
    • 名称name
  • 编写URLconf的注意:
    • 若要从url中捕获一个值,需要在它周围设置一对圆括号
    • 不需要添加一个前导的反斜杠,如应该写作'test/',而不应该写作'/test/'
    • 每个正则表达式前面的r表示字符串不转义
  • 请求的url被看做是一个普通的python字符串,进行匹配时不包括get或post请求的参数及域名

1.2 url路由配置方式

       前一天,我们在最后实现了一次会话的全过程,我们也清楚的知道,一个网站当中有千千万万个会话,也就是说这些会话,我们都要去配置相应的路由。假设,我们现在这个网站有好多个会话,我们该如何配置路由呢?路由的配置,一般常用的有以下两种。

1.2.1 主路由配置

       所谓主路由,就是我们项目设置文件夹当中和settings.py文件同级的那个urls.py文件里面的urlpatterns,无论我们的网站当中有多少个路由,我们全部把这些路由写在我们的主路由当中,我们称为主路由配置。

我们按照昨天我们的想法,当我们输入127.0.0.1:8000的时候,返回字符串首页,当我们输入127.0.0.1:8000/news/的时候,返回新闻,当我们输入127.0.0.1:8000/girls/返回美女。我们可以去实现一下,全部配置在主路由当中,代码如下:

这样的话,我们可以在网址当中,分别输入上述三个网址,可以分别得到我们想要返回的信息。当然,我们配置完路由,是肯定要在应用的views视图文件当中添加相应的view视图函数去处理。代码如下:

这样,我们就实现了url的主路由配置。我们配置了三个路由,那么这些路由是怎么找到它相对应的视图函数的呢?假设我们输入的127.0.0.1:8000/news/,如下图所示

 

 

 

1.2.2 子路由配置

       在上面我们实现了主路由的配置,它的配置非常快捷无脑,也就是说,只要我们有会话,那么我们就在主路由当中给它配一个路由,然后就可以接着写视图处理函数。但是,我们大家想一想,假设我们的网站当中有100个会话,代表着我们的主路由当中会配100个路由,如果我们的网站是一个非常大的网站,那么大家可以猜到什么?

       这样的话,我们的网站当然可以运行,但是会给我们的维护带来非常大的麻烦,因此,我们就有另外一种路由配置,就是我们的子路由配置。

       前一天的课程当中,我们提到过,一个网站有多少个模块,也就代表了我们有多少个app(应用),那么,我们是否可以这么认为,所有app里面的会话总和就是我们网站的所有会话。这样的话,我们是否可以把对应app里面会话的路由,由这个app去管理,这样的话,我们主路由就没有那么复杂了。

       还是上面的例子,首页、新闻和美女。我们把新闻和美女当作我们网站里面两个独立的模块,因为新闻和美女网页当中还会有很多的与它相关的请求。那么我们就可以把他们作为独立的app去创建,目录结构如下:

创建项目和应用,我们已经熟悉了,但是记住后续创建了新的app我们就要把这些app添加进入我们的settings文件当中。

接下来,我们就可以配置我们的路由了,我们以一个news  app为例。配置流程如下:

1)、在相应的app下,手动创建一个urls.py文件作为子路由配置文件使用,也可以复制主路由配置文件urls.py,如下图所示:

2)、把主路由当作调度分发路由的工具,去分发子路由,在主路由当中,如下添加

fromdjango.conf.urls import include, url

fromdjango.contrib import admin

urlpatterns= [

    url(r'^admin/', include(admin.site.urls)),

   url(r'^news/',include('news.urls',namespace='news'))

]

       include这个方法,会把经过主路由匹配成功后剩下的路径,分发给我们app里面的子路由去处理,它并不是严格匹配,正则是没有结束符$的,第一个参数代表分发给哪个路由配置文件去处理,第二个参数namespace代表反向解析,和url()当中name参数作用类似。

例如:127.0.0.1:8000/news/

       这个url会先经过我们的主路由去匹配,匹配上news/之后,剩下的是空,那么会把空分发到子路由当中,因此,我们还要在子路由当中去做配置。

from django.conf.urls import include, url

from.views import show_news

urlpatterns =[

    url(r'^$',show_news,name='news')

]

测试效果和主路由配置一样。

       也就是说,如果我们不想主路由配置这个路由,可以将它分发给子路由去配置。一样可以得到我们想要的结果。从上面我们可以有这样一个启发,以后,主路由当中基本上不做url路由配置,仅仅是用来分发子路由用的。而真正的路由是在子路由当中去配置的,它们二者相互配合,就会把我们整个网站的会话路由,模块化进行处理。不但结构清晰,而且维护方便。

       以后,我们的路由配置全部都是使用子路由配置,不建议直接主路由配置!

1.3 路由传参

1.3.1 未命名正则表达式组传参(位置传参)

 

       在某些时候,视图函数当中需要从我们的路径当中去获取一些数据,这时候我们可以用到一个新的知识,那就是路由传参

       举个例子,我们现在可以得到news这个网页的内容,网页上有很多的新闻链接,根据时间分类。假设我们需要得到一个时间点的新闻,比如说我们要获取到2018年4月20日的新闻我们该如何配置呢?因为这个请求也是属于新闻这个模块的,所以,我们也是要以news/开头,那么我们可以像这样去配置路径/news/2018/4/20/,最前面的/配置的时候要省略。

       主路由当中,我们已经为news/分过子路由,所以,主路由当中不变,只要是属于这个news模块中的请求,也就是说只要是以new/开头的路径,我们以后都只需要在子路由当中配置剩余的路径即可,剩余的就是2018/4/20/配置如下:

但是,我们要知道一件事,所有的新闻信息都是存在数据库当中的,我们在视图函数中是要通过数据库操作去查询这个时间的新闻的,那么,这个日期对于我们来说就需要传到视图函数当中,我们可以通过正则分组的方式去捕获结果,传递给视图函数。把需要的数据加上小括号即可。视图函数当中要添加相应的形参去接受。子路由里配置如下:

视图函数如下:

效果如下:

这样的话,我们就通过路由传参的方式让视图函数拿到需要的信息。

但是问题又来了,如果我要获取到2017年3月21日的数据怎么做呢? 

/news/2018/4/20/

/news/2017/3/21/

       我们发现他们的路径,格式都很类似,就是参数值发生了变化,那么我们就想是否可以把路由里面的数字,变成通用的呢?答案是肯定的,那么我们可以像这样去改变我们的路由配置。

其余,都不变,测试,发现成功了。这样的话,我们就实现通用化的路由路径传参。

       这样的方式,我们为什么要叫做未命名正则表达式组传参或者位置传参呢,我做一下改变,大家来看,我把视图内的形参顺序改变如下:day和year的位置调换。

结果如下:

这样的话,就不是我们想要的结果了,也就是说,这样传参会有意外发生。视图函数形参位置决定了结果的准确与否。但是一般情况下,没人会这么干。既然有意外,就会有补救,因此我们又有了另外一种方式传参。

1.3.2 命名正则表达式组传参(关键字传参)

       命名正则表达式组传参也叫关键字传参,我们在上面发现,未命名正则表达式组传参存在风险,所以,我们可以使用这种方式做优化。方式如下:

视图函数当中的形参还是错误的顺序

结果我们还是可以保证准确:

 

       这样的话,我们就通过两种传参方式,使得视图函数获取到请求路径当中所传递的必要信息

      

 

 

2. URL的反向解析

  • 如果在视图、模板中使用硬编码的链接,在urlconf发生改变时,维护是一件非常麻烦的事情
  • 解决:在做链接时,通过指向urlconf的名称,也就是我们配置的namespace和name,动态生成链接地址
  • 视图:使用django.core.urlresolvers.reverse()函数
  • 模板:使用url模板标签

三、视图函数

1. 定义视图

1.1 视图定义

1)本质就是一个函数

2)视图的参数

A、一个HttpRequest实例

B、通过正则表达式组获取的位置参数

C、通过正则表达式组获得的关键字参数

3)在应用目录下默认有views.py文件,一般视图都定义在这个文件中,如果处理功能过多,可以将函数定义到不同的py文件中;但是建议就写在views.py里面,如果逻辑可以区分,可以写在一个新的应用里面。

 

2. 错误视图

  • Django原生自带几个默认视图用于处理HTTP错误

2.1 404(page not found) 视图

  • defaults.page_not_found(request, template_name='404.html')
  • 默认的404视图将传递一个变量给模板:request_path,它是导致错误的URL
  • 如果Django在检测URLconf中的每个正则表达式后没有找到匹配的内容也将调用404视图
  • 如果在settings中DEBUG设置为True,那么将永远不会调用404视图,而是显示URLconf 并带有一些调试信息
2.1.1 在settings.py中修改调试
DEBUG = False
ALLOWED_HOSTS = ['*', ]
2.1.2 请求一个不存在的地址,默认模板
http://127.0.0.1:8000/test/

 

2.1.3 自定义404模板

目标:

在templates中创建404.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

    <style>

        p{

            color: red;

        }

    </style>

</head>

<body>

    <p>我的妹呢,跑哪拉?妹的!</p>

    <br>

    {{ request_path }}

</body>

</html>

 

2.2 500(server error) 视图

2.2.1 认识500
  • defaults.server_error(request, template_name='500.html')
  • 在视图代码中出现运行时错误
  • 默认的500视图不会传递变量给500.html模板
  • 如果在settings中DEBUG设置为True,那么将永远不会调用505视图,而是显示URLconf 并带有一些调试信息
2.2.2 默认500视图

 

根据我们上面的例子:如果我要返回一个时间的新闻信息,那么访问127.0.0.1:8000/news/2016/12/3/就会返回这个时间的新闻信息。如果我们人为的在这个视图函数当中构造如下的错误,那么这个500视图就会默认调用。

接下来我们访问127.0.0.1:8000/news/2018/4/20/就会出现上面的默认500错误

 

2.2.3 自定义500 视图

在templates创建500.html内容如下:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

    <style>

        p{

            color: red;

        }

    </style>

</head>

<body>

    <p>挂了挂了,挂了阿</p>

    <br>

</body>

</html>

 

访问连接:127.0.0.1:8000/news/2018/4/20/ 得到自定义500错误页面

2.3 400(bad request) 视图

  • defaults.bad_request(request, template_name='400.html')
  • 错误来自客户端的操作
  • 当用户进行的操作在安全方面可疑的时候,例如篡改会话cookie

 

 

 

 

 

 

三、HttpReqeust对象

1. HttpReqeust对象说明

1.1 说明

1)服务器接收到http协议的请求后,会根据报文创建HttpRequest对象

2)视图函数的第一个参数是HttpRequest对象

3)在django.http模块中定义了HttpRequest对象的API

1.2 属性

下面除非特别说明,属性都是只读的,都是字符串

1)path:一个字符串,表示请求的页面的完整路径,不包含域名和请求参数

2)method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'

3)encoding:一个字符串,表示提交的数据的编码方式

A)如果为None则表示使用浏览器的默认设置,一般为utf-8

B)这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding

4)GET:一个类似于字典QueryDict的对象,包含get请求方式的所有参数

5)POST:一个类似于字典QueryDict的对象,包含post请求方式的所有参数

6)FILES:一个类似于字典的对象,包含所有的上传文件

7)COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串

8)session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见“状态保持”

1.3 方法

is_ajax():如果请求是通过XMLHttpRequest发起的,则返回True

2. QueryDict对象

2.1 QueryDict对象说明

1)定义在django.http.QueryDict

2)request对象的属性GET、POST都是QueryDict类型的对象

3)与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况。

例如:http://127.0.0.1:8000/booktest/?a=1&a=2&a=3

2.2 QueryDict对象方法

2.1.1 方法get()

根据键获取值

1)只能获取键的一个值

2)如果一个键同时拥有多个值,获取最后一个值

dict.get('',default)
或简写为
dict['']
2.1.2 方法getlist()

根据键获取值

将键的值以列表返回,可以获取一个键的多个值

dict.getlist('',default)

3. GET属性

1)QueryDict类型的对象

2)包含get请求方式的所有参数

3)与url请求地址中的参数对应,位于?后面

4)参数的格式是键值对,如key1=value1

5)多个参数之间,使用&连接,如key1=value1&key2=value2

键是开发人员定下来的,值是可变的。

4. POST属性

1)QueryDict类型的对象

2)包含post请求方式的所有参数

3)与form表单中的控件对应

问:表单中哪些控件会被提交?

答:控件要有name属性,则name属性的值为键,value属性的值为键,构成键值对提交

    • 对于checkbox控件,name属性一样为一组,当控件被选中后会被提交,存在一键多值的情况
    • 键是开发人员定下来的,值是可变的

5. 请求方式传参

       浏览器向后台发送请求的时候,有很多种方式,我们常见的两种方式就是get和post,例如在浏览器网址栏当中输入url以及我们点击网页上的超级链接,都会向后台发送请求,并且基本都是get请求,再比如我们登陆注册时候在form表单里面填写数据点击提交也会发送请求,并且基本都是post请求。

       get和post这两种方式的请求在进入django后会被做处理,把这两种请求方式封装为HttpRequest对象request的两个属性GET和POST,这两个属性当中存了请求方式对应传递到视图函数的所有参数。在视图函数当中,我们可以通过GET对象,拿到get请求方式传递过来的参数,可以通过POST对象拿到post请求方式传递过来的参数。

浏览器中get请求方式的参数是在url的最后通过键值对明文传递过来的,不安全。例如:

http://127.0.0.1:8000/路径/ ?a=1&b=2

http://127.0.0.1:8000/路径/ ?a=1&a=2

以?作为分割,?之后的就是我们get请求方式传递的参数。它们以键值对传递,但是和字典不同的是,它们可以是一个键多个值

 

       浏览器中form表单里面对应的数据,是通过post方式传参的方式提交到后台的如下图所示:

       当我们点击提交按钮的时候,两个文本输入框当中的数据会被当作值,而这两个文本输入框的name属性值被当作键。构造成键值对传递到后台的。它门传递参数,不会把参数明文显示在url上。

get请求参数的获取:可以在视图函数当中通过

data =  request.GET.get(‘键’,默认)获取

post请求参数的获取:可以在视图函数当中通过

data =  request.POST.get(‘键’,默认)获取

 

五、HttpResponse对象

1)在django.http模块中定义了HttpResponse对象的API

2)HttpRequest对象由Django自动创建,HttpResponse对象由程序员创建

 

不调用模板,直接返回数据

1. HttpResponse对象简单案例

1.1 视图response

直接返回数据

 

url配置:

url(r'^$',index,name='index'),

url(r'^news/$', show_news, name='show_news'),

url(r'^girls/$', show_girls, name='show_girls'),

 

视图函数

defindex(request):

    return HttpResponse('首页')

 

defshow_news(request):

    return HttpResponse('新闻')

 

defshow_girls(request):

    return HttpResponse('美女')

 

 

调用模板

url配置:

url(r'^get_page1/$', get_page1, name='get_page1'),

 

 

视图函数

defget_page1(request):

    #第一步:使用加载器加载我们的页面

    html_loader = loader.get_template('get_page1.html')

    #第二步:构造我们要动态加载的数据

    a =100

    b =[1,2,3,4,5]

    c ={'name':'yuange','age':30}

    data ={'a':a,'b':b,'c':c}

    #第三步:构造我们的请求上下文

    context = RequestContext(request,data)

    #第四步:使用加载器将上下文渲染成标准的html代码

    content = html_loader.render(context)

    return HttpResponse(content)

    # returnrender(request,'get_page1.html',context)

 

 

 

模板

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

    <p>我是一个动态的网页</p>

    {{ a }}<br>

    {{ b }}<br>

    {{ c }}<br>

{#    循环遍历列表#}

    {%for num in b %}

        {{ num }}

    {% endfor %}

    <br>

{#遍历字典#}

    {%for key,value in c.items %}

        {{ key }}---{{ value }}

    {% endfor %}

</body>

</html>

 

 

1.2 简写函数render

  • render(request, template_name[, context])
  • 结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象
  • request:该request用于生成response
  • template_name:要使用的模板的完整名称
  • context:添加到模板上下文的一个字典,视图将在渲染模板之前调用它

    defget_page1(request):

        a =100

        b =[1,2,3,4,5]

        c ={'name':'yuange','age':30}

        context={'a':a,'b':b,'c':c}

        return render(request,'get_page1.html',context)

 

2. 属性和方法

2.1 属性

  • content:表示返回的内容,字符串类型
  • charset:表示response采用的编码字符集,字符串类型,例如utf-8
  • status_code:响应的HTTP响应状态码,例如404,500,302
  • content-type:指定输出的MIME类型

例如:text/html,application/xml;q=0.9,image/webp,image/apng

2.2 方法

1)init :使用页内容实例化HttpResponse对象

2)write(content):以文件的方式写

3)flush():以文件的方式输出缓存区

4)cookie是服务器设置存储在浏览器的一段文本信息,例如用户登录的时候不用输入密码了。

set_cookie(key,value='', max_age=None, expires=None):设置Cookie

    • key、value都是字符串类型
    • max_age是一个整数,表示在指定秒数后过期
    • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化
    • max_age与expires二选一
    • 如果不指定过期时间,则关闭浏览器过期

 

3. 关于cookie的操作

1)Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行session 跟踪而储存在用户本地终端上的数据(通常经过加密)。定义于 RFC2109 和 2965 中的都已废弃,最新取代的规范是 RFC6265 [1]  。(可以叫做浏览器缓存)

2)cookie是服务器设置存储在浏览器的一段文本信息,例如用户登录的时候不用输入密码了。

 

 

4. 子类HttpResponseRedirect(重定向)

  • 重定向,服务器端跳转
  • 构造函数的第一个参数用来指定重定向的地址

 

5. 子类JsonResponse

1)返回json数据,一般用于异步请求

2)_init _(data)

3)帮助用户创建JSON编码的响应

4)参数data是字典对象

5)JsonResponse的默认Content-Type为application/json

 

六、状态保持

1)http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态,也就是说上次请求的得到的相关信息于新的请求无关。

2)客户端与服务器端的一次通信,就是一次会话

3)实现状态保持的方式:在客户端或服务器端存储与会话有关的数据

4)存储方式包括cookie、session,会话一般指session对象

5)使用cookie,所有数据存储在客户端,注意不要存储敏感信息,容易泄露。

6)推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id

7)状态保持的目的:是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据。

8)同一个浏览器共享session,换浏览器就不共享了

9)注意:不同的请求者之间不会共享这个数据,与请求者一一对应

 

1. 启用session

1)使用django-adminstartproject创建的项目默认启用

2)在settings.py文件中

INSTALLED_APPS列表中添加:
'django.contrib.sessions',

MIDDLEWARE_CLASSES列表中添加:
'django.contrib.sessions.middleware.SessionMiddleware',

3)禁用会话:删除上面指定的两个值,禁用会话将节省一些性能消耗

2. 使用session

1)启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象

2)get(key,default=None):根据键获取会话的值

3)clear():清除所有会话,不会删除数据库中的session记录

3)flush():删除当前的会话数据并删除会话的Cookie,会删除数据库中的session记录

4)delrequest.session['member_id']:删除会话,不删除mysql的记录

5)request.session[member_id]= None:删除会话,不删除mysql的记录

3. session的基本操作

4. 会话过期时间

  • set_expiry(value):设置会话的超时时间
  • 如果没有指定,则两个星期后过期,和cookie时间一样
  • 如果value是一个整数,会话将在values秒没有活动后过期
  • 若果value是一个timedelta对象,会话将在当前时间加上这个指定的日期/时间过期
  • 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
  • 如果value为None,那么会话永不过期
  • 修改视图中login_handle函数,查看效果

5. 存储session的五种方式(了解)

使用存储会话的方式,可以使用settings.py的SESSION_ENGINE项指定

5.1 基于数据库的会话

1)基于数据库的会话:这是django默认的会话存储方式

需要添加django.contrib.sessions到的INSTALLED_APPS设置中,

运行manage.py migrate在数据库中安装会话表,可显示指定为

SESSION_ENGINE='django.contrib.sessions.backends.db'

5.2 基于缓存的会话

基于缓存的会话:只存在本地内在中,如果丢失则不能找回,比数据库的方式读写更快。

SESSION_ENGINE='django.contrib.sessions.backends.cache'

5.3 可以将缓存和数据库同时使用

可以将缓存和数据库同时使用:优先从本地缓存中获取,如果没有则从数据库中获取,这种性能更好

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

5.4 将Session存储在文件系统中

将Session存储在文件系统中:最后一种方式是将Session存储在文件系统中。

需要设置SESSION_ENGINE='django.contrib.sessions.backends.file'

这时你还需要同时设置SESSION_FILE_PATH 变量,它代表Session文件保存的位置,缺省的设置一般是tempfile.gettempdir(),表示系统的临时目录。这里要确保应用程序对那个目录有读写的权限。

 

5.5 使用Redis缓存session

会话还支持文件、纯cookie、Memcached、Redis等方式存储,下面演示使用redis存储

 

5.5.1 安装django-redis-sessions包

注意要在虚拟环境中安装,不在虚拟环境中会报错

命令:pip3 install django-redis-sessions
注意要在虚拟环境中安装

如果用下面的安装不行,会报错

报错信息

 

 

 

5.5.2 修改settings中的配置,增加如下项
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_HOST = 'localhost'
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DB = 0
SESSION_REDIS_PASSWORD = ''
SESSION_REDIS_PREFIX = 'session'
5.5.3管理redis的命令
启动:sudo redis-server /etc/redis/redis.conf
停止:sudo redis-server stop
重启:sudo redis-server restart
redis-cli:使用客户端连接服务器
keys *:查看所有的键
get name:获取指定键的值
del name:删除指定名称的键

 

session存储的是base64编码过的

http://www1.tc711.com/tool/BASE64.htm,在该网站解析,得到我们存储的session

5.5.4 COOKIE和SESSION有什么区别

1,session 在服务器端,cookie 在客户端(浏览器)
2,session 默认被存在在服务器的一个文件里(不是内存)
3,session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)
4,session 可以放在文件、数据库、或内存中都可以。
5,用户验证这种场合一般会用 session

因此,维持一个会话的核心就是客户端的唯一标识,即 session id

5.5.5 注意

注意如果同时设置了保存到mysql和redis,那么只能保存到redis中


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值