首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

精通 Grails:自訂 URI 與 Codec 優化部落格永久連結

     編輯:Java 相關知識

URI 是 Web 應用的命脈。Grails 預設 /controller/action/id 雖唯一但缺乏語意。本文示範如何透過 Controller 邏輯、UrlMappings、自訂 Codec 打造可讀、可記、有利 SEO 的友善 URI。

現狀與痛點

預設 URI:https://localhost:9090/blogito/entry/show/1

  • 洩露資料庫主鍵(內部實作細節)
  • 無語意,難以記憶與分享
  • 部落格永久連結應具描述性:/blog/jsmith/grails-codecs

建立 User 領域與關聯

class User {
    static constraints = {
        login(unique: true)
        password(password: true)
        name()
    }
    static hasMany = [entries: Entry]
    String login, password, name
    String toString() { name }
}
class Entry {
    static belongsTo = [author: User]
    String title, summary
    Date dateCreated, lastUpdated
}

BootStrap.groovy 建立種子資料:

def jdoe = new User(login: 'jdoe', password: 'password', name: 'John Doe')
def e1 = new Entry(title: 'Grails 1.1 beta is out', summary: 'Check out the new features')
jdoe.addToEntries(e1); jdoe.save()

顯示作者的條目列表

Controller 依登入名過濾

class EntryController {
    def list = {
        if (!params.max) params.max = 10
        flash.id = params.id
        if (!params.id) params.id = "No User Supplied"
        def author = User.findByLogin(params.id)
        def entryList, entryCount
        if (author) {
            def query = { eq('author', author) }
            entryList = Entry.createCriteria().list(params, query)
            entryCount = Entry.createCriteria().count(query)
        } else {
            entryList = Entry.list(params)
            entryCount = Entry.count()
        }
        [entryInstanceList: entryList, entryCount: entryCount]
    }
}

關鍵點:

  • params.id 對應 URL 最後一段(預設映射行為)
  • 用 User.findByLogin 而非 get
  • Hibernate Criteria Builder 建構動態查詢
  • flash.id 傳遞分頁參數

分頁調整

<g:paginate total="${entryCount}" params="${flash}"/>

依作者過濾列表

分頁測試

UrlMappings 客製化路由

class UrlMappings {
    static mappings = {
        "/$controller/$action?/$id?" { constraints {} }
        "/"(controller: "entry")
        "/blog/$id"(controller: "entry", action: "list")
        "/blog/$id/$title?"(controller: "entry", action: "list")
        "/entry/$action?/$id?/$title?"(controller: "entry")
        "500"(view: '/error')
    }
}

現在支援:

  • /blog/jsmith → 作者列表
  • /blog/jsmith/grails-codecs → 標題模糊比對

自訂 UnderscoreCodec:空白轉底線

class UnderscoreCodec {
    static encode = { target -> target.replaceAll(" ", "_") }
    static decode = { target -> target.replaceAll("_", " ") }
}

所有 String 自動獲得 encodeAsUnderscore()、decodeUnderscore()。

測試 Codec

class UnderscoreCodecTests extends GroovyTestCase {
    void testEncode() { assertEquals "this_is_a_test", "this is a test".encodeAsUnderscore() }
    void testDecode() { assertEquals "this is a test", "this_is_a_test".decodeUnderscore() }
}

依用戶與標題查看條目

Controller 整合 Codec 解碼

def list = {
    // ...
    flash.title = params.title
    if (!params.title) params.title = ""
    def author = User.findByLogin(params.id)
    if (author) {
        def query = {
            and {
                eq('author', author)
                like("title", params.title.decodeUnderscore() + '%')
            }
        }
        entryList = Entry.createCriteria().list(params, query)
        entryCount = Entry.createCriteria().count(query)
    }
    // ...
}

使用 like 支援前綴比對,decodeUnderscore() 還原標題關鍵字。

內建 Codec 快覽

  • HtmlCodec:encodeAsHTML()/decodeHTML() 防 XSS
  • URLCodec:encodeAsURL() 查詢字串編碼
  • Base64Codec、JavaScriptCodec

置於 grails-app/utils/*Codec.groovy 即自動註冊。

結語

友善 URI 三步走:Controller 語意查詢、UrlMappings 路由重寫、Codec 格式轉換。Blogito 現具備語意化永久連結,下一篇將實作登入驗證與檔案上傳,讓使用者發布富媒體部落格內容。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved