这是在 Lift Framework 中处理 RESTful(如 URL)的正确方法吗?

发布于 2024-08-18 01:41:46 字数 856 浏览 5 评论 0原文

如果我有一个像 http://localhost/Test/edit/{id} 这样的 URL,我想要{id} 转换为参数而不是 URL 路径部分。

使用 RewriteRequest 创建菜单是最好的方法吗?因为如果我有很多像这样的 URL 模式,我发现它有点样板。

val menu = Menu(new Loc[Unit] {

    override def name = "Test"
    override def text = "Test"
    override def link = (List ("Test"), true)
    override def params = Nil
    override def defaultValue = Full(())


    def isTarget (path: ParsePath) = path match {
        case ParsePath (List("Test", "edit", id), _, _, _) => true

        case _ => false
    }

    override def rewrite = Full ( NamedPF("Test") {
        case RewriteRequest (path, _, _) if isTarget(path) => 
             RewriteResponse(List("Test", "edit"),  
                             Map("id" -> "1024")) -> ()

    })
})

If I have a URL like http://localhost/Test/edit/{id} and I would like the {id} transform to a parameter instead of URL path part.

Is it best way to do it by create a menu with RewriteRequest? Because I found it a little boilerplate if I have lot URL pattern like this.

val menu = Menu(new Loc[Unit] {

    override def name = "Test"
    override def text = "Test"
    override def link = (List ("Test"), true)
    override def params = Nil
    override def defaultValue = Full(())


    def isTarget (path: ParsePath) = path match {
        case ParsePath (List("Test", "edit", id), _, _, _) => true

        case _ => false
    }

    override def rewrite = Full ( NamedPF("Test") {
        case RewriteRequest (path, _, _) if isTarget(path) => 
             RewriteResponse(List("Test", "edit"),  
                             Map("id" -> "1024")) -> ()

    })
})

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

下雨或天晴 2024-08-25 01:41:46

在 boot.scala 中,您需要以下内容(来自实际工作代码!)请注意,每个 RewriteResponse 路径必须位于您的站点地图中。

LiftRules.rewrite.append {
  case RewriteRequest(ParsePath(List("shopInfo", "view", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "view" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "orders", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "orders" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "sync", id), _, _, _), _, _) => RewriteResponse("shopInfo" ::  "sync" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "delete", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "delete" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "edit", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "edit" :: Nil, Map("id" -> id))
}

In your boot.scala you need the following (from actual working code!) Note that each RewriteResponse path must be in your sitemap.

LiftRules.rewrite.append {
  case RewriteRequest(ParsePath(List("shopInfo", "view", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "view" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "orders", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "orders" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "sync", id), _, _, _), _, _) => RewriteResponse("shopInfo" ::  "sync" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "delete", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "delete" :: Nil, Map("id" -> id))
  case RewriteRequest(ParsePath(List("shopInfo", "edit", id), _, _, _), _, _) => RewriteResponse("shopInfo" :: "edit" :: Nil, Map("id" -> id))
}
梦忆晨望 2024-08-25 01:41:46

感谢您的所有回复。

我最想要的是这些重写的东西与 Menu 紧密结合,这样我就可以在我的 Model 类中设置它们,比如 CRUDify 特征。

最后,我自己创建了一个 Loc 的子类来处理这些重写规则,我发现它工作得很好并且使事情变得更简单(至少对我来说),所以我在这里发布代码。

如果有人需要,请随意复制

/**
 *  A RESTful-like URL handling Loc
 *
 *  If you have the following templates:
 *
 *    * webapps/item/edit.html
 *    * webapps/item/view.html
 *  
 *  You want the following URL map to corresponding template with 
 *  last path component as a S parameter.
 *
 *    http://localhost/item/edit/1  to  http://localhost/item/edit
 *    http://localhost/item/view/1  to  http://localhost/item/view
 *
 *  You could create a Menu with this Loc class in your Model object.
 *
 *  <code>
 *  object Item extends Item with LongKeyedMetaMapper[Item] 
 *  {
 *      // Other methods here...
 *
 *      def menu () {  
 *
 *          // What methods do we have?
 *          val methods = List ("view", "edit")
 *
 *          val parameterName = "itemID"
 *          val itemLoc = new RESTfulLoc("Item", List("item"), "Item", 
 *                                       methods, parameterName)
 *
 *          Menu (itemLoc)
 *      }
 *  }
 *  </code>
 *
 *  Now add the menu to SiteMap in Boot.boot
 *
 *  <code>
 *  class Boot {
 *      def boot () {
 *          
 *          val entries = Item.menu ::  Nil
 *
 *          LiftRules.setSiteMap(SiteMap(entries:_*))
 *      }
 *  }
 *  </code>
 *
 *
 *  Finally, You could access the parameter in your snippet with 
 *  S.param("itemID")
 *
 */
class RESTfulLoc (val name: String, val path: List[String],
                  val text: LinkText[Unit], val methods: List[String],
                  val parameterName: String,
                  val locParams: LocParam[Unit]*) extends Loc[Unit] 
{
    override val defaultValue = Full(())
    override val params = locParams.toList
    override val link: Link[Unit] = (List(path.first), true)

    def this (name: String, path: List[String], text: LinkText[Unit], 
              methods: List[String], locParams: LocParam[Unit]*) = 
    {
        this (name, path, text, methods, "id", locParams:_*)
    }

    private def isTarget (path: ParsePath) = 
    {
        path.partPath -- this.path match {
            case List (action, id) => {
                (methods contains action) && id != "index"
            }
            case _ => false
        }
    }

    override def rewrite = Full (NamedPF("RESTfulLoc") 
    {
        case RewriteRequest (path, _, _) if isTarget(path) => {
             val parameter = path.partPath.last
             val action    = path.partPath.init
             val data      = Map (parameterName -> parameter)

             RewriteResponse(action, data) -> ()
        }
    })
}

Thanks for all of your replies.

What I want most is that these rewrite things combined tightly with Menu, so I could setup them just in my Model class, like CRUDify trait.

In the end, I created a subclass of Loc myself to handle these rewrite rules, and I found it works pretty well and make things much simpler (at least for me), so I post the code here.

Feel free to copy this if anyone need it

/**
 *  A RESTful-like URL handling Loc
 *
 *  If you have the following templates:
 *
 *    * webapps/item/edit.html
 *    * webapps/item/view.html
 *  
 *  You want the following URL map to corresponding template with 
 *  last path component as a S parameter.
 *
 *    http://localhost/item/edit/1  to  http://localhost/item/edit
 *    http://localhost/item/view/1  to  http://localhost/item/view
 *
 *  You could create a Menu with this Loc class in your Model object.
 *
 *  <code>
 *  object Item extends Item with LongKeyedMetaMapper[Item] 
 *  {
 *      // Other methods here...
 *
 *      def menu () {  
 *
 *          // What methods do we have?
 *          val methods = List ("view", "edit")
 *
 *          val parameterName = "itemID"
 *          val itemLoc = new RESTfulLoc("Item", List("item"), "Item", 
 *                                       methods, parameterName)
 *
 *          Menu (itemLoc)
 *      }
 *  }
 *  </code>
 *
 *  Now add the menu to SiteMap in Boot.boot
 *
 *  <code>
 *  class Boot {
 *      def boot () {
 *          
 *          val entries = Item.menu ::  Nil
 *
 *          LiftRules.setSiteMap(SiteMap(entries:_*))
 *      }
 *  }
 *  </code>
 *
 *
 *  Finally, You could access the parameter in your snippet with 
 *  S.param("itemID")
 *
 */
class RESTfulLoc (val name: String, val path: List[String],
                  val text: LinkText[Unit], val methods: List[String],
                  val parameterName: String,
                  val locParams: LocParam[Unit]*) extends Loc[Unit] 
{
    override val defaultValue = Full(())
    override val params = locParams.toList
    override val link: Link[Unit] = (List(path.first), true)

    def this (name: String, path: List[String], text: LinkText[Unit], 
              methods: List[String], locParams: LocParam[Unit]*) = 
    {
        this (name, path, text, methods, "id", locParams:_*)
    }

    private def isTarget (path: ParsePath) = 
    {
        path.partPath -- this.path match {
            case List (action, id) => {
                (methods contains action) && id != "index"
            }
            case _ => false
        }
    }

    override def rewrite = Full (NamedPF("RESTfulLoc") 
    {
        case RewriteRequest (path, _, _) if isTarget(path) => {
             val parameter = path.partPath.last
             val action    = path.partPath.init
             val data      = Map (parameterName -> parameter)

             RewriteResponse(action, data) -> ()
        }
    })
}
等待圉鍢 2024-08-25 01:41:46

我偶然发现这篇文章是因为我有同样的问题。 Jim Barrows 的答案是正确的(也是最简单的),但如果没有任何解释,我很难理解该代码的作用。有关 Jim 的解决方案为何有效的详细说明,请参阅在线 Lift 书籍 (http://groups.google.com/group/the-lift-book" rel="nofollow noreferrer">http://groups.google.com/group/the-lift-book" /groups.google.com/group/the-lift-book)。请查看第 3.12 节,标题为“URL 重写”,它将引导您逐步了解如何构建 RESTful URL。

无论如何,应该不需要编写自定义 Loc 来达到所需的效果。

祝你好运!

I stumbled on this post because I had the same question. The answer from Jim Barrows is correct (and the easiest), but without any explanation it was hard for me to grok what that code is doing. A detailed explanation of why Jim's solution works can be found in the Lift book online (http://groups.google.com/group/the-lift-book). Check out section 3.12, entitled "URL Rewriting" which walks you through step-by-step on how to build a RESTful URL.

At any rate, there should be no need to write a custom Loc to achieve the desired effect.

Best of luck!

终难愈 2024-08-25 01:41:46

抱歉,上面的评论有点乱。

问题是,如果我在 webapp/Test 下有一个名为 edit.html 的模板,这是我用来编辑项目的模板。

我有一个如下所示的菜单实例:

Menu (Loc("Test", List("Test") -> true, "Test"))

它只会匹配像 http://localhost/Test/edit,不是类似 http://localhost/Test/edit/1

Sorry, the comment above is a liitle messy.

The problem is that if I have a template named edit.html under webapp/Test, which is the template I use to edit an item.

And I have a Menu instance like the following:

Menu (Loc("Test", List("Test") -> true, "Test"))

It would only match URL like http://localhost/Test/edit, not anything like http://localhost/Test/edit/1

獨角戲 2024-08-25 01:41:46

为什么要更改为查询参数?是出于技术或框架原因吗?

在我看来,{id}​​ 属于 URI 路径,它标识唯一的资源,我喜欢将此信息保留在路径中。 URI 可以是任何类型的字符串(因此查询参数也可以工作),但我会将 URI 建模为尽可能接近资源 ID 一致。

Why do you want to change it to query param? Is it for technical or framework reasons?

The {id} belongs in my view to the URI path, it identifies a unique resource and I like to keep this information inside the path. The URIs can be any kind of character string (so query parameter would also work), but I would model the URIs as close resource-id conformant as possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文