代码之家  ›  专栏  ›  技术社区  ›  Brian Hsu

这是在提升框架中处理类似RESTful的URL的正确方法吗?

  •  3
  • Brian Hsu  · 技术社区  · 14 年前

    如果我有这样的网址 http://localhost/Test/edit/ id和我希望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")) -> ()
    
        })
    })
    
    5 回复  |  直到 14 年前
        1
  •  3
  •   Jim Barrows    14 年前

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

    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))
    }
    
        2
  •  2
  •   Brian Hsu    14 年前

    谢谢你的回复。

    我最想要的是这些重写的东西与菜单紧密结合在一起,这样我就可以在我的模型类中设置它们,比如粗糙特性。

    最后,我自己创建了一个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) -> ()
            }
        })
    }
    
        3
  •  2
  •   bkuder    14 年前

    我偶然发现了这篇文章,因为我有同样的问题。吉姆·巴罗斯的回答是正确的(也是最简单的),但是没有任何解释,我很难摸索出代码在做什么。有关Jim解决方案为何有效的详细解释,请参见在线电梯手册。( http://groups.google.com/group/the-lift-book )查看第3.12节,标题为“URL重写”,它将指导您逐步了解如何构建一个RESTful URL。

    无论如何,不需要编写自定义loc来实现所需的效果。

    祝你好运!

        4
  •  1
  •   Brian Hsu    14 年前

    抱歉,上面的评论很混乱。

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

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

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

    它只匹配URL http://localhost/Test/edit 不是什么 http://localhost/Test/edit/1

        5
  •  0
  •   manuel aldana    14 年前

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

    在我的视图中,id属于URI路径,它标识一个唯一的资源,我喜欢将此信息保存在路径中。URI可以是任何类型的字符串(因此查询参数也可以工作),但我将尽可能地为URI建模,使其与资源ID保持一致。