Spring mvc 构造RESTful URL 详细讲解(spring 3.0 应用)

详细讲解spring rest使用,简单例子如下:

  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    

首先,我们带着如下三 个问题 查看本文。
1. 如何在java构造没有扩展名的RESTful url,如 /forms/1,而不是 /forms/1.do

2. 由于我们要构造没有扩展名的url本来是处理静态资源的容器映射的,现在被我们的spring占用了,冲突怎么解决?

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

 

spring mvc rest 实现

spring mvc的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. }  

@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. }  

 

 spring rest配置指南

1. spring mvc 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>  

 

 

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( @RequestParam ( "items" ) Long[] items,HttpServletRequest request,HttpServletResponse response) {  
  79.           
  80.         for ( int  i =  0 ; i < items.length; i++) {  
  81.               
  82.             userInfoManager.removeById(items[i]);  
  83.         }  
  84.         return   new  ModelAndView(LIST_ACTION);  
  85.     }  
  86.       
  87. }  

 

 

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

Java代码
  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 编写

Html代码
  1. < form:form   action = "${ctx}/userinfo/${userInfo.userId}"   method = "put" >   
  2. </ form:form >   

 生成的html内容如下, 生成一个hidden的_method=put,并于web.xml中的HiddenHttpMethodFilter配合使用,在服务端将post请求改为put请求

Java代码
  1. <form id= "userInfo"  action= "/springmvc_rest_demo/userinfo/2"  method= "post" >  
  2.     <input type="hidden"  name= "_method"  value= "put" />  
  3. </form>  

 

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

 

5. 静态资源的URL重写

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

   如 /foo.gif, 现在访问该文件将是 /static/foo.gif.
   那如何避免这个前缀呢,那就是应用URL rewrite,现我们使用 http://tuckey.org/urlrewrite/ , 重写规则如下

 

Xml代码
  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 >

你可能感兴趣的:(spring,spring,mvc,Restful,应用)