• web框架详解之tornado 三 url和分页


    一、代码目录构建

    controllers  :处理业务逻辑的

    account:处理账户相关的

    上面目录作用和内容

    controllers 包 :处理业务逻辑的

             account:处理账户相关的

             home是主页内容文件

    settings   包:内容设置等

             Setting:配置文件

    statics    包: 静态文件的下相关目录

    views     包: HTML文件包

    内容分别为:

    #/usr/bin/env python
    #-*-coding:utf-8 -*-
    import tornado.web
    
    class LoginHandler(tornado.web.RequestHandler):
        def get(self,*args,**kwargs):
            self.write("ok")
    class LogoutHandler(tornado.web.RequestHandler):
        def get(self, *args, **kwargs):
            self.write("ok")
    class RegisterHandler(tornado.web.RedirectHandler):
        def get(self,*args,**kwargs):
            self.write("ok")
    account文件
    #/usr/bin/env python
    #-*-coding:utf-8-*-
    import tornado.web
    
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self, *args, **kwargs):
            # self.write("index.html")
            self.render("index.html")
    home文件
    #/usr/bin/env python
    #-*-coding:utf-8-*-
    
    settings={
        "template_path":"views",#模板路径的配置
        "static_path":"statics" #静态文件
    }
    Setting文件
    #/bin/usr/env python
    #-*- coding:utf-8 -*-
    import tornado.ioloop
    import tornado.web
    from controllers import home
    from settings import Setting
    
    #路由映射,路由系统
    application=tornado.web.Application(
        [(r"/index",home.IndexHandler),],
        **Setting.settings
    )
    
    if __name__=="__main__":
        application.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
    start文件

    其实就是把tornado拆解了

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    # 首先导入模块
    import tornado.ioloop
    import tornado.web
    # 让这个类继承   执行
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.render("s1.html")
    # 路由映射,也可以叫做路由系统
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ])
    if __name__ == "__main__":
        application.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
    View Code

    二、基于正则的动态路由

    设置分页:在路由系统中,用正则匹配数字,并且让第一个明明为num,第二个为nid

    #路由映射,路由系统
    application=tornado.web.Application(
        [(r"/index/(?P<num>d*)/(?P<nid>d*)",home.IndexHandler),],
        **Setting.settings
    )
    #/usr/bin/env python
    #-*-coding:utf-8-*-
    import tornado.web
    
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self,nid,num):
            # self.write("index.html")
            print(nid,num)
            self.render("index.html")
    在home文件中设置

    在网页url中输入http://127.0.0.1:8000/index/12321/151

    在后台中输出 151 和12321

     三、路由系统之二级域名

    application.add_handlers("www.cnblogs.com",[
        (r"/index/(?P<page>d*)",这里是自己定义的类)
    ])
    View Code

    二级路由就是:首先匹配域名,然后再匹配域名下的各个页面

    一级路由是直接匹配各个页面

    四、自定义分页:

    redirect_to实现的是action方法的跳转,向浏览器发起一个新的请求,具体使用方法如下
    
    注意点:用户连接tornado的时候,这个框架会用get方法给服务端发送页面信息,然后客户端向服务端发送消息,这里是用post方式,从客户端发送消息到服务端
    View Code
    #/bin/usr/env python
    #-*- coding:utf-8 -*-
    import tornado.ioloop
    import tornado.web
    from controllers import home
    from settings import Setting
    
    #路由映射,路由系统
    application=tornado.web.Application(
        [(r"/index/(?P<page>d*)",home.IndexHandler),],
        **Setting.settings
    )
    
    if __name__=="__main__":
        application.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
    start代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <h1>提交数据</h1>
    <form method="post" action="/index/1">
        <input name="username" type="text"/>
        <input name="email" type="text"/>
        <input type="submit" value="提交"/>
    </form>
    <h1>显示数据</h1>
        <table border="1">
            <thead>
            <tr>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
            </thead>
            <tbody>
            {% for line in list_info %}
                <tr>
                    <td>{{line['username']}}</td>
                    <td>{{line['email']}}</td>
                </tr>
            {% end %}
            </tbody>
        </table>
    </body>
    </html>
    HTML代码
    #/usr/bin/env python
    #-*-coding:utf-8-*-
    import tornado.web
    
    LIST_INFO=[
        {"username":"aa","email":"pyrene3110436742@162.com"}
    ]
    class IndexHandler(tornado.web.RequestHandler):
        def get(self,page):
            #假如每页显示5条数据
            # page是当前页
            # 第一页:05   LIST_INFO[0:5]
            #第二页:5:10    LIST_INFO[5:10]
            try:
                page=int(page)
            except Exception:
                page=1
            if page<1:
                page=1
            start=(page-1)*5
            end=page*5
            current_list=LIST_INFO[start:end]
    
            # print(nid,num)
            self.render("home/index.html" ,list_info=current_list)
        def post(self, *args, **kwargs):
            user=self.get_argument("username")
            email=self.get_argument("email")
            temp={"username":user,"email":email}
            LIST_INFO.append(temp)
            self.redirect("/index/1")
    home代码

    分析:

    这里有两种内容

    1、用户通过表格form提交数据,通过post方法,把输入的内容添加到LIST_INFO列表中,并且通过redirect方法跳转到get方法中返回给客户端

    2、内部做了页面判断,并且让页面只显示5条数据,用户通过路由系统输入url来访问每一页

    自定义分页优化

    通过传值来记住当前页

    三中的bug问题点在于:页面输入的时候,会跳转到首页,要解决

    #/usr/bin/env python
    #-*-coding:utf-8-*-
    import tornado.web
    
    LIST_INFO=[
        {"username":"aa","email":"pyrene3110436742@162.com"}
    ]
    class IndexHandler(tornado.web.RequestHandler):
        def get(self,page):
            #假如每页显示5条数据
            # page是当前页
            # 第一页:05   LIST_INFO[0:5]
            #第二页:5:10    LIST_INFO[5:10]
            try:
                page=int(page)
            except Exception:
                page=1
            if page<1:
                page=1
            start=(page-1)*5
            end=page*5
            current_list=LIST_INFO[start:end]
    
            # print(nid,num)
            self.render("home/index.html" ,list_info=current_list,current_page=page)
        def post(self,page):
            user=self.get_argument("username")
            email=self.get_argument("email")
            temp={"username":user,"email":email}
            LIST_INFO.append(temp)
            self.redirect("/index/"+page)
    home代码:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <h1>提交数据</h1>
    <form method="post" action="/index/{{current_page}}">
        <input name="username" type="text"/>
        <input name="email" type="text"/>
        <input type="submit" value="提交"/>
    </form>
    <h1>显示数据</h1>
        <table border="1">
            <thead>
            <tr>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
            </thead>
            <tbody>
            {% for line in list_info %}
                <tr>
                    <td>{{line['username']}}</td>
                    <td>{{line['email']}}</td>
                </tr>
            {% end %}
            </tbody>
        </table>
    </body>
    </html>
    index代码

    后台get方法中自定义页码变量,传入到html中,之后用户输入触发post方法,然后在post方法中跳转到当前页面

    自定义分页二:实现下图中的分页

     

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .pager a{
                display: inline-block;
                padding: 5px;
                margin: 3px;
                background-color: cadetblue;
            }
            .pager a.active{
                background-color:brown ;
                color: white;
            }
        </style>
    </head>
    <body>
    <h1>提交数据</h1>
    <form method="post" action="/index/{{current_page}}">
        <input name="username" type="text"/>
        <input name="email" type="text"/>
        <input type="submit" value="提交"/>
    </form>
    <h1>显示数据</h1>
        <table border="1">
            <thead>
            <tr>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
            </thead>
            <tbody>
            {% for line in list_info %}
                <tr>
                    <!--<td>{{line['username']}}</td>-->
                    <td>{% raw line['username']%}</td>
                    <td>{{line['email']}}</td>
                </tr>
            {% end %}
            </tbody>
        </table>
    <div class="pager">
            {% raw str_page %}
    </div>
    </body>
    </html>
    HTML代码
    #/usr/bin/env python
    #-*-coding:utf-8-*-
    import tornado.web
    
    LIST_INFO=[
        {"username":"aa","email":"pyrene3110436742@162.com"}
    ]
    for i in range(99):
        temp={"username":"bb"+str(i),"email":str(i)+"123"}
        LIST_INFO.append(temp)
    class IndexHandler(tornado.web.RequestHandler):
        def get(self,page):
            #假如每页显示5条数据
            # page是当前页
            # 第一页:05   LIST_INFO[0:5]
            #第二页:5:10    LIST_INFO[5:10]
            try:
                page=int(page)
            except Exception:
                page=1
            if page<1:
                page=1
            start=(page-1)*5
            end=page*5
            current_list=LIST_INFO[start:end]
    
            all_pager,c=divmod(len(LIST_INFO),5)
            if c>0:
                all_pager+=1
    
            list_page=[]
    
            for p in range(all_pager):
                # 设置当前页的样式
                if p+1 ==page:
                    temp='<a class="active" href="/index/%s">%s</a>' %(p+1,p+1)
                else:
                    temp='<a href="/index/%s">%s</a>'%(p+1,p+1)
                list_page.append(temp)
    
            str_page="".join(list_page)
    
            # print(nid,num)
            self.render("home/index.html" ,list_info=current_list,current_page=page,str_page=str_page)
    python代码
     1 实现步骤:
     2 首先在后台计算出数据的总页数,用divemode的方法 
     3 all_pager,c=divmod(len(LIST_INFO),5)
     4 if c>0:
     5     all_pager+=1
     6 all_pager为整数,c为小数,这里判断,如果c为小数的时候让整数加上1,也就是需要显示的页数
     7 2、创建一个空列表,并且遍历计算出来的页数,返回给前端页面
     8 list_page=[]
     9 
    10 for p in range(all_pager):
    11     # 设置当前页的样式
    12     if p+1 ==page:
    13         temp='<a class="active" href="/index/%s">%s</a>' %(p+1,p+1)
    14     else:
    15         temp='<a href="/index/%s">%s</a>'%(p+1,p+1)
    16     list_page.append(temp)
    17 
    18 str_page="".join(list_page)
    19 
    20 # print(nid,num)
    21 self.render("home/index.html" ,list_info=current_list,current_page=page,str_page=str_page)
    22 注意点:
    23 1、这里要设置点击到那一页的时候就显示那一页的样式,用于区分
    24 2、由于要传给前台的是字符串,所以这里要用join方法分割成字符串
    25 3、pag参数为当前页码
    26 
    27 前台代码:
    28 <div class="pager">
    29         {% raw str_page %}
    30 </div>
    31 由于后台传过来的数据,要按照后台的样式展示给用户,所以这里要用原声的js显示
    32 这里注意,后台要显示的原生的js必须是指定范围的,不然会被攻击

    自定义分页优化

     优化如下:

    具体思想如下:
    
    all_pager:总页数
    current_pager:当前页
    # range(当前页-5,当前页+5+1)
    当  总页数<11的时候
    1、    显示总页数
    当  总页数>11的时候
     如果当前页<=6:
        显示前11页
      如果当前页>6:
    如果:当前页+5 >总页数:
        总页数 -11  , 总页数
    else:
        当前页-5, 当前页+5
    View Code
    #s t 分页逻辑,这里让其显示11条信息
            if all_pager<11:
                s=1
                t=all_pager
            else:
                if page<=6:
                    s=1
                    t=11
                else:
                    if(page+5)>all_pager:
                        s=all_pager-10
                        t=all_pager
                    else:
                        s=page-5
                        t=page+5
    
            #注意这里的p代表的是s和t+1之间的页码
            for p in range(s,t+1):
                # 设置当前页的样式
                if p ==page:
                    temp='<a class="active" href="/index/%s">%s</a>' %(p,p)
                else:
                    temp='<a href="/index/%s">%s</a>'%(p,p)
                list_page.append(temp)
    
            str_page="".join(list_page)
    python代码实现

    如何做成插件?

    把各个方法分别封装到类中,然后如果以后想用这个插件,直接导入这个插件中的类就可以
    
    
    如果要封装页码:需要思考需求和产出什么
    需求:总页数、当前页
    产出:start  end  str_page
    
    把方法封装到类中,类中分别对应方法
    #/usr/bin/env python
    #-*-coding:utf-8-*-
    import tornado.web
    
    LIST_INFO=[
        {"username":"aa","email":"pyrene3110436742@162.com"}
    ]
    for i in range(99):
        temp={"username":"bb"+str(i),"email":str(i)+"123"}
        LIST_INFO.append(temp)
    
    class Pagination:
        #下面封装的参数分别为,当前页数,和总的数据
        def __init__(self,current_page,all_item):   #初始化当前页和总页数
            all_pager,c=divmod(all_item,5)   #all_pager为计算的到的总页数,要经过下面的判断
            if c>0:
                all_pager+=1
            self.all_pager=all_pager
    
            try:                                    #为当前页处理异常
                current_page=int(current_page)
            except Exception:
                current_page=1
            if current_page<1:
                current_page=1
            self.current_page=current_page
    
    
        # 加上这样的装饰器,会使下面调用这个方法的时候以访问字段的形式来访问,也就是不用加上括号
        @property
        def start(self):                        #当前页的起始数据
            return (self.current_page-1)*5
        @property
        def end(self):                          #当前页的结尾数据
            return self.current_page*5
    
        def page_str(self,base_url):            # 生成页码逻辑
            list_page=[]
            if self.all_pager<11:
                s=1
                t=self.all_pager
            else:
                if self.current_page<=6:
                    s=1
                    t=11
                else:
                    if( self.current_page+5)>self.all_pager:
                        s=self. current_page-10
                        t=self. current_page
                    else:
                        s= self.current_page-5
                        t= self.current_page+5
            for p in range(s,t+1):
                if p == self.current_page:
                    temp='<a class="active" href="%s%s">%s</a>' %(base_url,p,p) #这里设置自定义url
                else:
                    temp='<a href="%s%s">%s</a>'%(base_url,p,p)
                list_page.append(temp)
    
            return "".join(list_page)                       #直接返回值
    
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self,page):
    
            page_obj=Pagination(page,len(LIST_INFO))                    #传入当前页和总页数生成对象
            current_list=LIST_INFO[page_obj.start:page_obj.end]        #以字段的方式来应用类中的方法
            str_page=page_obj.page_str("/index/")                       #传入自己自定义的url
    
            # 传入参数,当前页的参数和页码数的参数
            self.render("home/index.html" ,list_info=current_list,current_page=page_obj.current_page,str_page=str_page)
    
    
        def post(self,page):
            user=self.get_argument("username")
            email=self.get_argument("email")
            temp={"username":user,"email":email}
            LIST_INFO.append(temp)
            self.redirect("/index/"+page)
    python代码

    跳转页面

    1 location.href=”url”
    2 首页:尾页:上一页:下一页都不难
    3 
    4 搜索跳转的代码形式:
    5 只要执行上面的就会自动跳转到指定的url
    6 所以这里用了js的事件方法,只不过把js变成字符串的形式传递给前台,然后转化为js代码的形式
    #首页
    first_page='<a  href="%s1">首页</a>'%(base_url,)
    list_page.append(first_page)
    
    #上一页 current_page-1 在javascript中加上javascript:void(0)表示什么也不做
    if self.current_page==1:
        pre_page='<a href="javascript:void(0)">上一页</a>'
    else:
        pre_page='<a  href="%s%s">上一页</a>'%(base_url,self.current_page-1)
    list_page.append(pre_page)
    
        #中间页数
    for p in range(s,t+1):
        if p == self.current_page:
            temp='<a class="active" href="%s%s">%s</a>' %(base_url,p,p) #这里设置自定义url
        else:
            temp='<a class-"active" href="%s%s">%s</a>'%(base_url,p,p)
        list_page.append(temp)
    #尾页
    last_page='<a  href=%s%s>尾页</a>'%(base_url,self.all_pager)
    list_page.append(last_page)
    
    #下一页 current_page+1 在javascript中加上javascript:void(0)表示什么也不做
    if self.current_page>=self.all_pager:
        next_page='<a href="javascript:void(0)">下一页</a>'
    else:
        next_page='<a  href="%s%s">下一页</a>'%(base_url,self.current_page+1)
    list_page.append(next_page)
    
    #跳转页面
    jump='''<input type="text" /><a  onclick="jump('%s',this);">GO</a>'''%(base_url,)
    script='''<script>
    function jump(baseUrl,ths){
        var val=ths.previousElementSibling.value;
        if(val.trim().length>0){
            location.href=baseUrl+val
        }
    }
    </script>'''
    list_page.append(jump)
    list_page.append(script)
    return "".join(list_page) 
    View Code

    五、安全XSS攻击

    xss跨站脚本攻击

     1 <h1>显示数据</h1>
     2     <table border="1">
     3         <thead>
     4         <tr>
     5             <th>用户名</th>
     6             <th>邮箱</th>
     7         </tr>
     8         </thead>
     9         <tbody>
    10         {% for line in list_info %}
    11             <tr>
    12                 <!--<td>{{line['username']}}</td>-->
    13                 <td>{% raw line['username']%}</td>
    14                 <td>{{line['email']}}</td>
    15             </tr>
    16         {% end %}
    17         </tbody>
    18     </table>

    上面13行的就是以原始方式展示,没做处理,那么无论用户还是后台输入的js代码都会以js形式展示给用户

    这种就是xss跨站脚本攻击模式

  • 相关阅读:
    ssh框架中文保存数据库MySQL乱码
    SSH ERROR com.opensymphony.xwork2.interceptor.ParametersInterceptor
    SSH(六)hibernate持久层模板于事务管理
    SSH(五)spring整合hibernate
    javaweb string
    spring加载配置文件
    order by 与 group by 区别
    PowerDesigner从SqlServer数据库中导入实体模型
    方向
    关于Hibernate 的数据库配置
  • 原文地址:https://www.cnblogs.com/pyrene/p/6676344.html
Copyright © 2020-2023  润新知