Spring REST配置指南与问题总结

下一版本的rapid-framework需要集成spring RESTful URL。最近JavaEye的badqiu对于如何搭建spring RESTful URL进行了研究,并总结问题如下。

springmvc 3.0 中增加 RESTful URL功能,构造出类似javaeye现在的URL。比如如下URL

 
 
  1. /blog/ 1   HTTP GET =>    得到id =  1 的blog  
  2. /blog/ 1   HTTP DELETE => 删除 id =  1 的blog  
  3. /blog/ 1   HTTP PUT  =>   更新id =  1 的blog  
  4. /blog     HTTP POST =>   新增BLOG 

以下详细解一下spring rest使用.

首先,我们带着如下两个问题查看本文。

1. 如何在java构造没有扩展名的RESTful url,如 /forms/1,而不是 /forms/1.do

2. 浏览器的form标签不支持提交delete,put请求,如何曲线解决

springmvc rest 实现

springmvc的resturl是通过@RequestMapping 及@PathVariable annotation提供的,通过如@RequestMapping(value="/blog /{id}",method=RequestMethod.DELETE)即可处理/blog/1 的delete请求.

 
 
  1. @RequestMapping (value= "/blog/{id}" ,method=RequestMethod.DELETE)  
  2. public  ModelAndView delete( @PathVariable  Long id,HttpServletRequest request,HttpServletResponse response) {  
  3.  blogManager.removeById(id);  
  4.   return   new  ModelAndView(LIST_ACTION);  
  5. }  
  6.   

@RequestMapping @PathVariable如果URL中带参数,则配合使用,如

 
 
  1. @RequestMapping (value= "/blog/{blogId}/message/{msgId}" ,method=RequestMethod.DELETE)  
  2. public  ModelAndView delete( @PathVariable ( "blogId" ) Long blogId, @PathVariable ( "msgId" ) Long msgId,HttpServletRequest request,HttpServletResponse response) {  
  3. }  
  4.   

spring rest配置指南

1. springmvc web.xml配置

 
 
  1. <  !-- 该servlet为tomcat,jetty等容器提供,将静态资源映射从/改为/static/目录,如原来访问 http://localhost/foo.css ,现在http://localhost/static/foo.css -- >  
  2. <   servlet-mapping >  
  3.   <   servlet-name > default <  /servlet-name >  
  4.   <   url-pattern > /static/* <  /url-pattern >  
  5. <  /servlet-mapping >  
  6. <   servlet >  
  7.      <   servlet-name > springmvc <  /servlet-name >  
  8.      <   servlet-class > org.springframework.web.servlet.DispatcherServlet <  /servlet-class >  
  9.      <   load-on-startup > 1 <  /load-on-startup >  
  10. <  /servlet >  
  11.  
  12. <  !-- URL重写filter,用于将访问静态资源http://localhost/foo.css 转为http://localhost/static/foo.css -- >  
  13. <   filter >  
  14.   <   filter-name > UrlRewriteFilter <  /filter-name >  
  15.   <   filter-class > org.tuckey.web.filters.urlrewrite.UrlRewriteFilter <  /filter-class >  
  16.   <   init-param >  
  17.        <   param-name > confReloadCheckInterval <  /param-name >  
  18.        <   param-value > 60 <  /param-value >  
  19.       <  /init-param >  
  20.   <   init-param >  
  21.               <   param-name > logLevel <  /param-name >  
  22.               <   param-value > DEBUG <  /param-value >  
  23.          <  /init-param >        
  24. <  /filter >  
  25. <   filter-mapping >  
  26.   <   filter-name > UrlRewriteFilter <  /filter-name >  
  27.   <   url-pattern > /* <  /url-pattern >  
  28. <  /filter-mapping >  
  29.  
  30. <  !-- 覆盖default servlet的/, springmvc servlet将处理原来处理静态资源的映射 -- >  
  31. <   servlet-mapping >  
  32.      <   servlet-name > springmvc <  /servlet-name >  
  33.      <   url-pattern > / <  /url-pattern >  
  34. <  /servlet-mapping >  
  35.  
  36. <  !-- 浏览器不支持put,delete等method,由该filter将/blog? _method = delete 转换为标准的http delete方法 -- >  
  37. <   filter >  
  38.   <   filter-name > HiddenHttpMethodFilter <  /filter-name >  
  39.   <   filter-class > org.springframework.web.filter.HiddenHttpMethodFilter <  /filter-class >  
  40. <  /filter >  
  41.  
  42. <   filter-mapping >  
  43.   <   filter-name > HiddenHttpMethodFilter <  /filter-name >  
  44.   <   servlet-name > springmvc <  /servlet-name >  
  45. <  /filter-mapping >  

2. webapp/WEB-INF/springmvc-servlet.xml配置,使用如下两个class激活@RequestMapping annotation

 
 
  1. <   bean   class = "org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />  
  2. <   bean   class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />  

完整配置

 
 
  1. <   beans   default-autowire = "byName"     >  
  2.  
  3.   <  !-- 自动搜索@Controller标注的类 -- >  
  4.   <   context:component-scan   base-package = "com.**.controller" />  
  5.    
  6.      <   bean   class = "org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />  
  7.  
  8.      <   bean   class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />  
  9.  
  10.      <  !-- Default ViewResolver -- >  
  11.      <   bean   id = "viewResolver"   class = "org.springframework.web.servlet.view.InternalResourceViewResolver" >  
  12.          <   property   name = "viewClass"   value = "org.springframework.web.servlet.view.JstlView" />  
  13.          <   property   name = "prefix"   value = "/pages" />  
  14.          <   property   name = "suffix"   value = ".jsp" > <  /property >  
  15.      <  /bean >  
  16.       
  17.      <   bean   id = "messageSource"   class = "org.springframework.context.support.ResourceBundleMessageSource"   p:basename = "i18n/messages" />  
  18.  
  19.      <  !-- Mapping exception to the handler view -- >  
  20.      <   bean   id = "exceptionResolver"   class = "org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" >  
  21.       <  !-- to /commons/error.jsp -- >  
  22.          <   property   name = "defaultErrorView"   value = "/commons/error" />  
  23.          <   property   name = "exceptionMappings" >  
  24.              <   props >  
  25.              <  /props >  
  26.          <  /property >  
  27.      <  /bean >  
  28.           
  29. <  /beans >  
  30.    

3. Controller编写

 
 
  1. /**  
  2.  * @RequestMapping("/userinfo") 具有层次关系,方法级的将在类一级@RequestMapping之一,  
  3.  * 如下面示例, 访问方法级别的@RequestMapping("/new"),则URL为 /userinfo/new  
  4.  */  
  5. @Controller  
  6. @RequestMapping ( "/userinfo" )  
  7. public   class  UserInfoController  extends  BaseSpringController{  
  8.   //默认多列排序,example: username desc,createTime asc  
  9.   protected   static   final  String DEFAULT_SORT_COLUMNS =  null ;   
  10.    
  11.   private  UserInfoManager userInfoManager;  
  12.    
  13.   private   final  String LIST_ACTION =  "redirect:/userinfo" ;  
  14.    
  15.   /**   
  16.   * 通过spring自动注入  
  17.   **/  
  18.   public   void  setUserInfoManager(UserInfoManager manager) {  
  19.    this .userInfoManager = manager;  
  20.  }  
  21.    
  22.   /** 列表 */  
  23.   @RequestMapping  
  24.   public  ModelAndView index(HttpServletRequest request,HttpServletResponse response,UserInfo userInfo) {  
  25.   PageRequest< Map> pageRequest = newPageRequest(request,DEFAULT_SORT_COLUMNS);  
  26.    //pageRequest.getFilters(); //add custom filters  
  27.     
  28.   Page page =  this .userInfoManager.findByPageRequest(pageRequest);  
  29.   savePage(page,pageRequest,request);  
  30.    return   new  ModelAndView( "/userinfo/list" , "userInfo" ,userInfo);  
  31.  }  
  32.    
  33.   /** 进入新增 */  
  34.   @RequestMapping (value= "/new" )  
  35.   public  ModelAndView _new(HttpServletRequest request,HttpServletResponse response,UserInfo userInfo)  throws  Exception {  
  36.    return   new  ModelAndView( "/userinfo/new" , "userInfo" ,userInfo);  
  37.  }  
  38.    
  39.   /** 显示 */  
  40.   @RequestMapping (value= "/{id}" )  
  41.   public  ModelAndView show( @PathVariable  Long id,HttpServletRequest request,HttpServletResponse response)  throws  Exception {  
  42.   UserInfo userInfo = (UserInfo)userInfoManager.getById(id);  
  43.    return   new  ModelAndView( "/userinfo/show" , "userInfo" ,userInfo);  
  44.  }  
  45.    
  46.   /** 编辑 */  
  47.   @RequestMapping (value= "/{id}/edit" )  
  48.   public  ModelAndView edit( @PathVariable  Long id,HttpServletRequest request,HttpServletResponse response)  throws  Exception {  
  49.   UserInfo userInfo = (UserInfo)userInfoManager.getById(id);  
  50.    return   new  ModelAndView( "/userinfo/edit" , "userInfo" ,userInfo);  
  51.  }  
  52.    
  53.   /** 保存新增 */  
  54.   @RequestMapping (method=RequestMethod.POST)  
  55.   public  ModelAndView create(HttpServletRequest request,HttpServletResponse response,UserInfo userInfo)  throws  Exception {  
  56.   userInfoManager.save(userInfo);  
  57.    return   new  ModelAndView(LIST_ACTION);  
  58.  }  
  59.    
  60.   /** 保存更新 */  
  61.   @RequestMapping (value= "/{id}" ,method=RequestMethod.PUT)  
  62.   public  ModelAndView update( @PathVariable  Long id,HttpServletRequest request,HttpServletResponse response)  throws  Exception {  
  63.   UserInfo userInfo = (UserInfo)userInfoManager.getById(id);  
  64.   bind(request,userInfo);  
  65.   userInfoManager.update(userInfo);  
  66.    return   new  ModelAndView(LIST_ACTION);  
  67.  }  
  68.    
  69.   /** 删除 */  
  70.   @RequestMapping (value= "/{id}" ,method=RequestMethod.DELETE)  
  71.   public  ModelAndView delete( @PathVariable  Long id,HttpServletRequest request,HttpServletResponse response) {  
  72.   userInfoManager.removeById(id);  
  73.    return   new  ModelAndView(LIST_ACTION);  
  74.  }  
  75.  
  76.   /** 批量删除 */  
  77.   @RequestMapping (method=RequestMethod.DELETE)  
  78.   public  ModelAndView batchDelete(HttpServletRequest request,HttpServletResponse response) {  
  79.   String[] items = request.getParameterValues( "items" );  
  80.    for ( int  i =  0 ; i <  items.length; i++) {  
  81.    java.lang.Long id =  new  java.lang.Long(items[i]);  
  82.    userInfoManager.removeById(id);  
  83.   }  
  84.    return   new  ModelAndView(LIST_ACTION);  
  85.  }  
  86.    
  87. }  
  88.    

上面是rapid-framework 新版本生成器生成的代码,以后也将应用此规则,rest url中增删改查等基本方法与Controller的方法映射规则

 
 
  1. /userinfo    => index()  
  2. /userinfo/new  => _new()  
  3. /userinfo/{id}  =>  show ()  
  4. /userinfo/{id}/edit   => edit()  
  5. /userinfo  POST  => create()  
  6. /userinfo/{id}  PUT => update()  
  7. /userinfo/{id}  DELETE => delete()  
  8. /userinfo  DELETE  => batchDelete()  

注(不使用 /userinfo/add  => add() 方法是由于add这个方法会被maxthon浏览器当做广告链接过滤掉,因为包含ad字符)

4. jsp 编写

 
 
  1. <   form:form   action = "${ctx}/userinfo/${userInfo.userId}"   method = "put" >  
  2. <  /form:form >  
  3.  将生成一个hidden的 _method = put ,并于web.xml中的HiddenHttpMethodFilter配合使用,在服务端将post请求改为put请求  
  4.  
  5. <   form   id = "userInfo"   action = "/springmvc_rest_demo/userinfo/2"   method = "post" >  
  6.   <   input   type = "hidden"   name = "_method"   value = "put" />  
  7. <  /form >  
  8.    

另外一种方法是你可以使用ajax发送put,delete请求.

5. 静态资源的URL重写

如上我们描述,现因为将default servlet映射至/static/的子目录,现我们访问静态资源将会带一个/static/前缀.

如 /foo.gif, 现在访问该文件将是 /static/foo.gif.

那如何避免这个前缀呢,那就是应用URL rewrite,现我们使用 http://tuckey.org/urlrewrite/ , 重写规则如下

 
 
  1. <   urlrewrite >  
  2.      <  !-- 访问jsp及jspx将不rewrite url,其它.js,.css,.gif等将重写,如 / foo.gif  = >  /static/foo.gif -- >  
  3.      <   rule >  
  4.       <   condition   operator = "notequal"   next = "and"   type = "request-uri" > .*.jsp <  /condition >  
  5.       <   condition   operator = "notequal"   next = "and"   type = "request-uri" > .*.jspx <  /condition >  
  6.          <   from > ^(/.*/..*)$ <  /from >  
  7.          <   to > /static$1 <  /to >  
  8.      <  /rule >  
  9. <  /urlrewrite >  
  10.     

另笔者专门写了一个 RestUrlRewriteFilter来做同样的事件,以后会随着rapid-framework一周发布. 比这个更加轻量级.

并且该代码已经贡献给spring,不知会不会在下一版本发布。

 

http://developer.51cto.com/art/200909/153054.htm

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值