关键字:springMVC有关RESTfull


Spring3中SpringMVC有关RESTfull URL的个人实现2010-07-22 00:10有关REST介绍、使用等的文章在网络上不计其数,REST好像又是一大热门,不过还好,已经有REST框架了,至少是个实质性的东西。

说实在的,有关REST这个四个英文字母我看得很多,但是一直都没有学习、研究过它到底是个什么东西,对我的学习和工作有什么影响。直到今天用Spring3的SpringMVC在做开发时才注意到它。

以前用的Struts1和Struts2做Web MVC框架,一般后缀都是.do, .jspx等,并且对于一些简单的CURD,后面还会加上?id=${id},类似其它。

所以我为了使URL更加的好看,也更想让Web爬虫光临,于是把URL用url rewrite做了个分发,例如:/user-view-1.htm 对应的是 /user/view.do?id=1

这样做后,Web站点的URL确实美观了许多。

现在公司都是用SpringMVC,其通过注释来指明URL,在两个月前第一次接触时,也确实感觉它的强大的威力。

比如:@RequestMapping(value = "/user-view-{id}"),它就可以接受一类URL,通过@PathVariable long id,就可以得到以前分发的效果了。

由于要拦截以'/'开头的URL,所以要改变原有的配置了,修改后的Web.xml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?> 

<web-app id="WebApp_ID" version="2.4" 

xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> 

<display-name>aboyprod</display-name> 


<context-param> 

<param-name>contextConfigLocation</param-name> 

<param-value>classpath:META-INF/spring/*.xml</param-value> 

</context-param> 


<!-- 过滤器 --> 

<filter> 

<filter-name>CharacterEncodingFilter</filter-name> 

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 

<init-param> 

<param-name>encoding</param-name> 

<param-value>GBK</param-value> 

</init-param> 

<init-param> 

<param-name>forceEncoding</param-name> 

<param-value>true</param-value> 

</init-param> 

</filter> 

<filter> 

<filter-name>SecurityControlFilter</filter-name> 

<filter-class>com.aboy.web.filter.SecurityControlFilter</filter-class> 

</filter> 

<!-- 

 <filter> <filter-name>HiddenHttpMethodFilter</filter-name> 

<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> 

</filter> 

--> 


<filter-mapping> 

<filter-name>CharacterEncodingFilter</filter-name> 

<url-pattern>/*</url-pattern> 

</filter-mapping> 

<filter-mapping> 

<filter-name>SecurityControlFilter</filter-name> 

<url-pattern>/*</url-pattern> 

</filter-mapping> 

 <!-- 

<filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> 

<servlet-name>dispatcher</servlet-name> </filter-mapping> 

--> 


<!-- Spring Starter --> 

<listener> 

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 

</listener> 

<listener> 

<listener-class>com.aboy.web.listener.JbpmContextListener</listener-class> 

</listener> 

<!--负责处理由JavaBeans Introspector的使用而引起的内存泄露。--> 

<listener> 

<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> 

</listener> 

<!-- 支持session scope的Spring bean --> 

<listener> 

<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> 

</listener> 


<!-- Servlet:Dispatcher --> 

<servlet> 

<servlet-name>dispatcher</servlet-name> 

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 

<load-on-startup>1</load-on-startup> 

</servlet> 

<!-- Servlet:CXFServlet --> 

<servlet> 

<servlet-name>CXFServlet</servlet-name> 

<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> 

<load-on-startup>1</load-on-startup> 

</servlet> 


<!-- Mapping:Default --> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.css</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.js</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.ico</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.gif</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.bmp</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.jpg</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.xml</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.txt</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.htm</url-pattern> 

</servlet-mapping> 

<servlet-mapping> 

<servlet-name>default</servlet-name> 

<url-pattern>*.html</url-pattern> 

</servlet-mapping> 


<!-- Mapping:Dispatcher --> 

 <servlet-mapping> 

<servlet-name>dispatcher</servlet-name> 

<url-pattern>/</url-pattern> 

</servlet-mapping> 


<!-- Mapping:CXFServlet --> 

<servlet-mapping> 

<servlet-name>CXFServlet</servlet-name> 

<url-pattern>/jws/*</url-pattern> 

</servlet-mapping> 


<session-config> 

<session-timeout>30</session-timeout> 

</session-config> 


<welcome-file-list> 

<welcome-file>index.html</welcome-file> 

</welcome-file-list> 


<login-config> 

<auth-method>BASIC</auth-method> 

</login-config> 

</web-app>



从上面的配置可以看出,显示指定了default的Servlet拦截一些静态资源。
说了这么多,好像跟RESTfull URL没有关系的,有关REST的介绍,

下面是我自己的一些RESTfull URL设计,以user为例,列出了CURD操作,第二列为HTTP操作,ALL代表GET、POST、PUT和DELETE都行:

/user-search ALL => search() 

/user-list ALL => list() 

/user-list-{page} ALL => list() 

/user-post ALL => post() 

/user-create ALL => create() 

/user-view-{id} ALL => view() 

/user-modify-{id} ALL => modify() 

/user-update-{id} ALL => update() 

/user-remove-{id} ALL => delete() 

/user-remove ALL => deleteBatch()



我们知道,HTTP的URL操作有4个:GET、POST、PUT和DELETE,一般场合中,我们只用了最常用的两个:GET和POST,我们当然完全可以充分利用全部四个。

做法就是去掉上面web.xml中有关HiddenHttpMethodFilter的注释,我们就可以这样了:

@RequestMapping(value="/user-{id}", method=RequestMethod.GET) 代表查看信息; 

@RequestMapping(value="/user-{id}", method=RequestMethod.PUT) 代表更新信息; 

@RequestMapping(value="/user-{id}", method=RequestMethod.DELETE) 代表删除信息;



但是除了GET之外,其它的两个操作都是提交表单操作,并且要增加一个隐藏域

<input type="hidden" name="_method" value="put"/> 或是 

<input type="hidden" name="_method" value="delete"/>



可以看出其弊端了:
1、URL一样,只是不同的HTTP操作,想发个链接给朋友,也许发出去的链接对方GET后,根本不是我想发的;
2、需要增加额外的配置(web.xml,Controller);
3、非常的死板,要删除一个用户或是更新信息,必须得通过表单才行。

于是,为了唯一标注一个URL,我的做法是:模块-操作-参数……,与具体的HTTP操作无关。
比如:/user-list-{page},代表查看第{page}页user列表,这个URL,不管在哪个HTTP操作(GET、POST、PUT和DELETE),其结果都是一样的。

===========================================