完成gpage分页包开发以及示例代码测试

This commit is contained in:
John 2018-04-22 22:17:20 +08:00
parent 82f456adc5
commit 654bfe44a3
11 changed files with 304 additions and 157 deletions

10
g/g.go
View File

@ -6,8 +6,18 @@
package g
import (
"html/template"
)
// 常用map数据结构
type Map map[string]interface{}
// 常用list数据结构
type List []Map
// 输出到模板页面时保留HTML标签原意不做自动escape处理
func HTML(content string) template.HTML {
return template.HTML(content)
}

View File

@ -27,6 +27,7 @@ type Request struct {
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
Session *Session // 与当前请求绑定的Session对象(并发安全)
Response *Response // 对应请求的返回数据操作对象
Router *Router // 匹配到的路由对象
}
// 创建一个Request对象

View File

@ -65,15 +65,20 @@ type Server struct {
// 域名、URI与回调函数的绑定记录表
type HandlerMap map[string]*HandlerItem
// 路由对象
type Router struct {
Uri string // 注册时的pattern - uri
Method string // 注册时的pattern - method
Domain string // 注册时的pattern - domain
Priority int // 优先级,用于链表排序,值越大优先级越高
}
// http回调函数注册信息
type HandlerItem struct {
ctype reflect.Type // 控制器类型
fname string // 回调方法名称
faddr HandlerFunc // 准确的执行方法内存地址(与以上两个参数二选一)
uri string // 注册时的pattern - uri
method string // 注册时的pattern - method
domain string // 注册时的pattern - domain
priority int // 优先级,用于链表排序,值越大优先级越高
router *Router // 注册时绑定的路由对象
}
// http注册函数

View File

@ -27,9 +27,11 @@ func (s *Server) setHookHandler(pattern string, hook string, item *HandlerItem)
if err != nil {
return errors.New("invalid pattern")
}
item.uri = uri
item.domain = domain
item.method = method
item.router = &Router {
Uri : uri,
Domain : domain,
Method : method,
}
s.hhmu.Lock()
defer s.hhmu.Unlock()
@ -44,8 +46,8 @@ func (s *Server) setHookHandler(pattern string, hook string, item *HandlerItem)
}
p = p.(map[string]interface{})[hook]
array := strings.Split(uri[1:], "/")
item.priority = len(array)
array := strings.Split(uri[1:], "/")
item.router.Priority = len(array)
for _, v := range array {
if len(v) == 0 {
continue
@ -164,8 +166,8 @@ func (s *Server) searchHookHandler(r *Request, hook string) []*hookCacheItem {
for i := len(lists) - 1; i >= 0; i-- {
for e := lists[i].Front(); e != nil; e = e.Next() {
item := e.Value.(*HandlerItem)
if strings.EqualFold(item.method, gDEFAULT_METHOD) || strings.EqualFold(item.method, r.Method) {
regrule, names := s.patternToRegRule(item.uri)
if strings.EqualFold(item.router.Method, gDEFAULT_METHOD) || strings.EqualFold(item.router.Method, r.Method) {
regrule, names := s.patternToRegRule(item.router.Uri)
if gregx.IsMatchString(regrule, r.URL.Path) {
hookItem := &hookCacheItem {item.faddr, nil}
// 如果需要query匹配那么需要重新解析URL

View File

@ -40,6 +40,7 @@ func (s *Server) getHandler(r *Request) *HandlerItem {
for k, v := range handlerItem.values {
r.values[k] = v
}
r.Router = handlerItem.item.router
return handlerItem.item
}
return nil
@ -74,10 +75,11 @@ func (s *Server) setHandler(pattern string, item *HandlerItem) error {
if err != nil {
return errors.New("invalid pattern")
}
item.uri = uri
item.domain = domain
item.method = method
item.router = &Router {
Uri : uri,
Domain : domain,
Method : method,
}
s.hmmu.Lock()
defer s.hmmu.Unlock()
defer s.clearHandlerCache()
@ -88,10 +90,10 @@ func (s *Server) setHandler(pattern string, item *HandlerItem) error {
if _, ok := s.handlerTree[domain]; !ok {
s.handlerTree[domain] = make(map[string]interface{})
}
p := s.handlerTree[domain]
lists := make([]*list.List, 0)
array := strings.Split(uri[1:], "/")
item.priority = len(array)
p := s.handlerTree[domain]
lists := make([]*list.List, 0)
array := strings.Split(uri[1:], "/")
item.router.Priority = len(array)
for k, v := range array {
if len(v) == 0 {
continue
@ -149,13 +151,13 @@ func (s *Server) setHandler(pattern string, item *HandlerItem) error {
// 对比两个HandlerItem的优先级需要非常注意的是注意新老对比项的参数先后顺序
func (s *Server) compareHandlerItemPriority(newItem, oldItem *HandlerItem) bool {
if newItem.priority > oldItem.priority {
if newItem.router.Priority > oldItem.router.Priority {
return true
}
if newItem.priority < oldItem.priority {
if newItem.router.Priority < oldItem.router.Priority {
return false
}
if strings.Count(newItem.uri, "/:") > strings.Count(oldItem.uri, "/:") {
if strings.Count(newItem.router.Uri, "/:") > strings.Count(oldItem.router.Uri, "/:") {
return true
}
return false
@ -224,8 +226,8 @@ func (s *Server) searchHandlerDynamic(r *Request) *handlerCacheItem {
for i := len(lists) - 1; i >= 0; i-- {
for e := lists[i].Front(); e != nil; e = e.Next() {
item := e.Value.(*HandlerItem)
if strings.EqualFold(item.method, gDEFAULT_METHOD) || strings.EqualFold(item.method, r.Method) {
regrule, names := s.patternToRegRule(item.uri)
if strings.EqualFold(item.router.Method, gDEFAULT_METHOD) || strings.EqualFold(item.router.Method, r.Method) {
regrule, names := s.patternToRegRule(item.router.Uri)
if gregx.IsMatchString(regrule, r.URL.Path) {
handlerItem := &handlerCacheItem{item, nil}
// 如果需要query匹配那么需要重新解析URL

View File

@ -32,6 +32,19 @@ type View struct {
// 视图表
var viewMap = gmap.NewStringInterfaceMap()
// 默认的视图对象
var viewObj = Get(".")
// 输出到模板页面时保留HTML标签原意不做自动escape处理
func HTML(content string) template.HTML {
return template.HTML(content)
}
// 直接解析模板内容,返回解析后的内容
func ParseContent(content string, params map[string]interface{}) ([]byte, error) {
return viewObj.ParseContent(content, params)
}
// 获取或者创建一个视图对象
func Get(path string) *View {
if r := viewMap.Get(path); r != nil {

View File

@ -17,55 +17,53 @@ import (
// 分页对象
type Page struct {
pageName string // 分页参数名称
nextPageTag string // 下一页标签
prevPageTag string // 上一页标签
firstPageTag string // 首页标签
lastPageTag string // 尾页标签
prevBar string // 上一分页条
nextBar string // 下一分页条
totalSize int // 总共条数
pageBarNum int // 控制记录条的个数
totalPage int // 总页数
currentPage int // 当前页
offset int // 分页的offset条数
url *url2.URL // URL对象
route string // 路由规则
ajaxActionName string // AJAX动作名当该属性有值时表示使用AJAX分页
Url *url2.URL // 当前页面的URL对象
Route string // 当前页面的路由规则(在静态分页下有效)
TotalSize int // 总共数据条数
TotalPage int // 总页数
CurrentPage int // 当前页码
PageName string // 分页参数名称(GET参数)
NextPageTag string // 下一页标签
PrevPageTag string // 上一页标签
FirstPageTag string // 首页标签
LastPageTag string // 尾页标签
PrevBar string // 上一分页条
NextBar string // 下一分页条
PageBarNum int // 控制分页条的数量
AjaxActionName string // AJAX方法名当该属性有值时表示使用AJAX分页
}
// 创建一个分页对象,输入参数分别为:
// 总数量、每页数量、当前页码、当前的URL(可以只是URI+QUERY)、(可选)路由规则(例如: /user/list/:page、/order/list/*page)
func New(totalSize, perPage, currentPage int, url string, route...string) *Page {
func New(TotalSize, perPage int, CurrentPage interface{}, url string, route...string) *Page {
u, _ := url2.Parse(url)
page := &Page {
pageName : "page",
prevPageTag : "<",
nextPageTag : ">",
firstPageTag : "|<",
lastPageTag : ">|",
prevBar : "<<",
nextBar : ">>",
totalSize : totalSize,
totalPage : int(math.Ceil(float64(totalSize/perPage))),
currentPage : currentPage,
offset : (currentPage - 1)*perPage,
pageBarNum : 10,
url : u,
PageName : "page",
PrevPageTag : "<",
NextPageTag : ">",
FirstPageTag : "|<",
LastPageTag : ">|",
PrevBar : "<<",
NextBar : ">>",
TotalSize : TotalSize,
TotalPage : int(math.Ceil(float64(TotalSize/perPage))),
CurrentPage : gconv.Int(CurrentPage),
PageBarNum : 10,
Url : u,
}
if len(route) > 0 {
page.route = route[0]
page.Route = route[0]
}
return page
}
// 启用AJAX分页
func (page *Page)EnableAjax(actionName string) {
page.ajaxActionName = actionName
func (page *Page) EnableAjax(actionName string) {
page.AjaxActionName = actionName
}
// 获取显示"下一页"的内容.
func (page *Page) nextPage(styles ... string) string {
func (page *Page) NextPage(styles ... string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
@ -73,14 +71,14 @@ func (page *Page) nextPage(styles ... string) string {
if len(styles) > 1 {
style = styles[0]
}
if page.currentPage < page.totalPage {
return page.getLink(page.getUrl(page.currentPage + 1), page.nextPageTag, "下一页", style)
if page.CurrentPage < page.TotalPage {
return page.GetLink(page.GetUrl(page.CurrentPage + 1), page.NextPageTag, "下一页", style)
}
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.nextPageTag)
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.NextPageTag)
}
/// 获取显示“上一页”的内容
func (page *Page) prevPage(styles ... string) string {
func (page *Page) PrevPage(styles ... string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
@ -88,10 +86,10 @@ func (page *Page) prevPage(styles ... string) string {
if len(styles) > 1 {
style = styles[0]
}
if page.currentPage > 1 {
return page.getLink(page.getUrl(page.currentPage - 1), page.prevPageTag, "上一页", style)
if page.CurrentPage > 1 {
return page.GetLink(page.GetUrl(page.CurrentPage - 1), page.PrevPageTag, "上一页", style)
}
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.prevPageTag)
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.PrevPageTag)
}
/**
@ -99,7 +97,7 @@ func (page *Page) prevPage(styles ... string) string {
*
* @return string
*/
func (page *Page)firstPage(styles ... string) string {
func (page *Page) FirstPage(styles ... string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
@ -107,14 +105,14 @@ func (page *Page)firstPage(styles ... string) string {
if len(styles) > 1 {
style = styles[0]
}
if page.currentPage == 1 {
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.firstPageTag)
if page.CurrentPage == 1 {
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.FirstPageTag)
}
return page.getLink(page.getUrl(1), page.firstPageTag, "第一页", style)
return page.GetLink(page.GetUrl(1), page.FirstPageTag, "第一页", style)
}
// 获取显示“尾页”的内容
func (page *Page)lastPage(styles ... string) string {
func (page *Page) LastPage(styles ... string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
@ -122,14 +120,14 @@ func (page *Page)lastPage(styles ... string) string {
if len(styles) > 1 {
style = styles[0]
}
if page.currentPage == page.totalPage {
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.lastPageTag)
if page.CurrentPage == page.TotalPage {
return fmt.Sprintf(`<span class="%s">%s</span>`, curStyle, page.LastPageTag)
}
return page.getLink(page.getUrl(page.totalPage), page.lastPageTag, "最后页", style)
return page.GetLink(page.GetUrl(page.TotalPage), page.LastPageTag, "最后页", style)
}
// 获得分页条
func (page *Page) nowBar(styles ... string) string {
// 获得分页条列表内容
func (page *Page) PageBar(styles ... string) string {
var curStyle, style string
if len(styles) > 0 {
curStyle = styles[0]
@ -137,43 +135,36 @@ func (page *Page) nowBar(styles ... string) string {
if len(styles) > 1 {
style = styles[0]
}
plus := int(math.Ceil(float64(page.pageBarNum / 2)))
if page.pageBarNum - plus + page.currentPage > page.totalPage {
plus = page.pageBarNum - page.totalPage + page.currentPage
plus := int(math.Ceil(float64(page.PageBarNum / 2)))
if page.PageBarNum - plus + page.CurrentPage > page.TotalPage {
plus = page.PageBarNum - page.TotalPage + page.CurrentPage
}
begin := page.currentPage - plus + 1
begin := page.CurrentPage - plus + 1
if begin < 1 {
begin = 1
}
ret := ""
for i := begin; i < begin + page.pageBarNum; i++ {
if i <= page.totalPage {
if i != page.currentPage {
ret += page.getLink(page.getUrl(i), gconv.String(i), style, "")
for i := begin; i < begin + page.PageBarNum; i++ {
if i <= page.TotalPage {
if i != page.CurrentPage {
ret += page.GetLink(page.GetUrl(i), gconv.String(i), style, "")
} else {
ret += fmt.Sprintf(`<span class="%s">%d</span>`, curStyle, i)
}
} else {
break
}
if i != begin + page.pageBarNum - 1 {
ret += "\n"
}
}
return ret
}
/**
* 获取显示跳转按钮的代码
*
* @return string
*/
func (page *Page) selectBar() string {
ret := fmt.Sprintf(`<select name="gpage_select" onchange="window.location.href='%sthis.value'">`, page.url)
for i := 1; i <= page.totalPage; i++ {
if (i == page.currentPage) {
ret += fmt.Sprintf(`<option value="%d" selected>%d</option>`, i, i)
// 获取基于select标签的显示跳转按钮的代码
func (page *Page) SelectBar() string {
ret := `<select name="gpage_select" onchange="window.location.href=this.value">`
for i := 1; i <= page.TotalPage; i++ {
if i == page.CurrentPage {
ret += fmt.Sprintf(`<option value="%s" selected>%d</option>`, page.GetUrl(i), i)
} else {
ret += fmt.Sprintf(`<option value="%d">%d</option>`, i, i)
ret += fmt.Sprintf(`<option value="%s">%d</option>`, page.GetUrl(i), i)
}
}
ret += "</select>"
@ -182,85 +173,99 @@ func (page *Page) selectBar() string {
// 预定义的分页显示风格内容
func (page *Page) GetContent(mode int) string {
switch (mode) {
switch mode {
case 1:
page.nextPageTag = "下一页"
page.prevPageTag = "上一页"
return fmt.Sprintf(`%s <span class="current">%d</span> %s`, page.prevPage(), page.currentPage, page.nextPage())
page.NextPageTag = "下一页"
page.PrevPageTag = "上一页"
return fmt.Sprintf(
`%s <span class="current">%d</span> %s`,
page.PrevPage(),
page.CurrentPage,
page.NextPage(),
)
case 2:
page.nextPageTag = "下一页>>"
page.prevPageTag = "<<上一页"
page.firstPageTag = "首页"
page.lastPageTag = "尾页"
return fmt.Sprintf(`%s%s <span class="current">[第%d页]</span> %s%s 第%s页`,
page.firstPage(), page.prevPage(), page.currentPage, page.nextPage(), page.lastPage(), page.selectBar())
page.NextPageTag = "下一页>>"
page.PrevPageTag = "<<上一页"
page.FirstPageTag = "首页"
page.LastPageTag = "尾页"
return fmt.Sprintf(
`%s%s<span class="current">[第%d页]</span>%s%s第%s页`,
page.FirstPage(),
page.PrevPage(),
page.CurrentPage,
page.NextPage(),
page.LastPage(),
page.SelectBar(),
)
case 3:
page.nextPageTag = "下一页"
page.prevPageTag = "上一页"
page.firstPageTag = "首页"
page.lastPageTag = "尾页"
pageStr := page.firstPage() + "\n"
pageStr += page.prevPage() + "\n"
pageStr += page.nowBar("current") + "\n"
pageStr += page.nextPage() + "\n"
pageStr += page.lastPage() + "\n"
pageStr += fmt.Sprintf(`<span>当前页%d/%d</span> <span>共%d条</span>`, page.currentPage, page.totalPage, page.totalSize)
page.NextPageTag = "下一页"
page.PrevPageTag = "上一页"
page.FirstPageTag = "首页"
page.LastPageTag = "尾页"
pageStr := page.FirstPage()
pageStr += page.PrevPage()
pageStr += page.PageBar("current")
pageStr += page.NextPage()
pageStr += page.LastPage()
pageStr += fmt.Sprintf(
`<span>当前页%d/%d</span> <span>共%d条</span>`,
page.CurrentPage,
page.TotalPage,
page.TotalSize,
)
return pageStr
case 4:
page.nextPageTag = "下一页"
page.prevPageTag = "上一页"
page.firstPageTag = "首页"
page.lastPageTag = "尾页"
pageStr := page.firstPage() + "\n"
pageStr += page.prevPage() + "\n"
pageStr += page.nowBar("current") + "\n"
pageStr += page.nextPage() + "\n"
pageStr += page.lastPage() + "\n"
page.NextPageTag = "下一页"
page.PrevPageTag = "上一页"
page.FirstPageTag = "首页"
page.LastPageTag = "尾页"
pageStr := page.FirstPage()
pageStr += page.PrevPage()
pageStr += page.PageBar("current")
pageStr += page.NextPage()
pageStr += page.LastPage()
return pageStr
}
return ""
}
// 为指定的页面返回地址值
func (page *Page) getUrl(pageNo int) string {
url := *page.url
if len(page.url.RawQuery) > 0 && len(page.url.Query().Get(page.pageName)) > 0 {
values := page.url.Query()
values.Set(page.pageName, gconv.String(pageNo))
url.RawQuery = values.Encode()
} else {
func (page *Page) GetUrl(pageNo int) string {
url := *page.Url
if len(page.Route) > 0 {
// 这里基于路由匹配的URL页码替换比较简单但能满足绝大多数场景
index := -1
array := strings.Split(page.route, "/")
array := strings.Split(page.Route, "/")
for k, v := range array {
if strings.EqualFold(v, ":" + page.pageName) || strings.EqualFold(v, "*" + page.pageName) {
if strings.EqualFold(v, ":" + page.PageName) || strings.EqualFold(v, "*" + page.PageName) {
index = k
break
}
}
// 替换url.Path中的分页码
if index != -1 {
array := strings.Split(page.url.Path, "/")
array := strings.Split(page.Url.Path, "/")
array[index] = gconv.String(pageNo)
url.Path = strings.Join(array, "/")
return url.String()
}
}
values := page.Url.Query()
values.Set(page.PageName, gconv.String(pageNo))
url.RawQuery = values.Encode()
return url.String()
}
// 获取链接地址
func (page *Page) getLink(url, text, title, style string) string {
func (page *Page) GetLink(url, text, title, style string) string {
if len(style) > 0 {
style = fmt.Sprintf(`class="%s" `, style)
}
if len(page.ajaxActionName) > 0 {
return fmt.Sprintf(`<a %shref='#' onclick="%s('%s')">%s</a>`, style, page.ajaxActionName, url, text)
if len(page.AjaxActionName) > 0 {
return fmt.Sprintf(`<a %shref='#' onclick="%s('%s')">%s</a>`, style, page.AjaxActionName, url, text)
} else {
return fmt.Sprintf(`<a %shref="%s" title="%s">%s</a>`, style, url, title, text)
}

View File

@ -1,16 +0,0 @@
package main
import (
"fmt"
"gitee.com/johng/gf/g/util/gpage"
)
func main() {
// 基本分页示例
page1 := gpage.New(100, 10, 1, "http://xxx.xxx.xxx/user/list?page=1&type=10#anchor")
fmt.Println(page1.GetContent(3))
// 基于静态链接的分页示例
page2 := gpage.New(100, 10, 1, "http://xxx.xxx.xxx/user/list/1?type=10#anchor", "/user/list/:page")
fmt.Println(page2.GetContent(3))
}

39
geg/util/gpage/gpage.go Normal file
View File

@ -0,0 +1,39 @@
package main
import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/os/gview"
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g/util/gpage"
)
func main() {
s := ghttp.GetServer()
s.BindHandler("/page/demo", func(r *ghttp.Request){
page := gpage.New(100, 10, r.Get("page"), r.URL.String())
buffer, _ := gview.ParseContent(`
<html>
<head>
<style>
a,span {padding:8px; font-size:16px;}
div{margin:5px 5px 20px 5px}
</style>
</head>
<body>
<div>{{.page1}}</div>
<div>{{.page2}}</div>
<div>{{.page3}}</div>
<div>{{.page4}}</div>
</body>
</html>
`, g.Map{
"page1" : gview.HTML(page.GetContent(1)),
"page2" : gview.HTML(page.GetContent(2)),
"page3" : gview.HTML(page.GetContent(3)),
"page4" : gview.HTML(page.GetContent(4)),
})
r.Response.Write(buffer)
})
s.SetPort(8199)
s.Run()
}

View File

@ -0,0 +1,47 @@
package main
import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/os/gview"
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g/util/gpage"
)
// 自定义分页内容
func pageContent(page *gpage.Page) string {
page.NextPageTag = "NextPage"
page.PrevPageTag = "PrevPage"
page.FirstPageTag = "HomePage"
page.LastPageTag = "LastPage"
pageStr := page.FirstPage()
pageStr += page.PrevPage()
pageStr += page.PageBar("current-page")
pageStr += page.NextPage()
pageStr += page.LastPage()
return pageStr
}
func main() {
s := ghttp.GetServer()
s.BindHandler("/page/custom/*page", func(r *ghttp.Request){
page := gpage.New(100, 10, r.Get("page"), r.URL.String(), r.Router.Uri)
buffer, _ := gview.ParseContent(`
<html>
<head>
<style>
a,span {padding:8px; font-size:16px;}
div{margin:5px 5px 20px 5px}
</style>
</head>
<body>
<div>{{.page}}</div>
</body>
</html>
`, g.Map{
"page" : gview.HTML(pageContent(page)),
})
r.Response.Write(buffer)
})
s.SetPort(8199)
s.Run()
}

View File

@ -0,0 +1,39 @@
package main
import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/os/gview"
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g/util/gpage"
)
func main() {
s := ghttp.GetServer()
s.BindHandler("/page/static/*page", func(r *ghttp.Request){
page := gpage.New(100, 10, r.Get("page"), r.URL.String(), r.Router.Uri)
buffer, _ := gview.ParseContent(`
<html>
<head>
<style>
a,span {padding:8px; font-size:16px;}
div{margin:5px 5px 20px 5px}
</style>
</head>
<body>
<div>{{.page1}}</div>
<div>{{.page2}}</div>
<div>{{.page3}}</div>
<div>{{.page4}}</div>
</body>
</html>
`, g.Map{
"page1" : gview.HTML(page.GetContent(1)),
"page2" : gview.HTML(page.GetContent(2)),
"page3" : gview.HTML(page.GetContent(3)),
"page4" : gview.HTML(page.GetContent(4)),
})
r.Response.Write(buffer)
})
s.SetPort(8199)
s.Run()
}