Spring RESTful风格url示例

转:http://www.xdemo.org/spring-restful/


口水篇

REST是设计风格而不是标准

  • 资源是由URI来指定。

  • 对资源的操作包括获取、创建、修改和删除资源

    这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。

  • 通过操作资源的表现形式来操作资源。

常用操作

GET 获取
POST 提交
PUT 更新
Delete 删除

REST确实不是标准,只是设计风格,目的只是让url看起来更简洁实用,是资源状态的一种表达。

实战篇

Demo下载地址http://pan.baidu.com/s/1o6sJLZs

项目结构

Maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!-- Jar版本管理 -->
<properties>
    <springframework>4.0.2.RELEASE</springframework>
    <log4j>1.2.17</log4j>
    <jstl>1.2</jstl>
</properties>
<dependencies>
    <!-- Spring web mvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${springframework}</version>
    </dependency>
    <!-- JSTL -->
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>${jstl}</version>
    </dependency>
    <!-- log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j}</version>
    </dependency>
    <!-- 单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

web.xml配置

需要注意,HiddenHttpMethodFilter是针对浏览器表单不支持put和delete方法而设计的,通过在表单中设置隐藏域,来分发到相应的处理器上,如<input type="hidden" name="_method" value="put" />

开发后记:最近把RESTful风格融入到了项目中去了,在开发过程中发现一个问题,就是aJax提交的PUT请求,无法通过HiddenHttpMethodFilter这个过滤器拿到值,后来搜索一番,改用HttpPutFormContentFilter即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?xml version="1.0" encoding="UTF-8"?>
<!-- 通过http://java.sun.com/xml/ns/javaee/获取最新的schemaLocation -->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    <display-name>SpringActivemqServer</display-name>
    <!-- WebAppRootKey -->
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>example.SpringActivemqServer</param-value>
    </context-param>
    <!-- Log4J Start -->
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:log4j.properties</param-value>
    </context-param>
    <context-param>
        <param-name>log4jRefreshInterval</param-name>
        <param-value>6000</param-value>
    </context-param>
    <!-- Spring Log4J config -->
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
    <!-- Log4J End -->
    <!-- Spring 编码过滤器 start -->
    <filter>
        <filter-name>characterEncoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- Spring 编码过滤器 End -->
    <!-- Spring Application Context Listener Start -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- Spring Application Context Listener End -->
    <!-- Spring MVC Config Start -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <!-- Filter all resources -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- Spring MVC Config End -->
    <!-- 隐藏的HttpMethod方法过滤器,表单提交中需要携带一个name=_method的隐藏域,value=put或者delete -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <servlet-name>SpringMVC</servlet-name>
    </filter-mapping>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

spring-mvc.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="UTF-8"?>  
<!-- 查找最新的schemaLocation 访问 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:context="http://www.springframework.org/schema/context"  
       xmlns:mvc="http://www.springframework.org/schema/mvc" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.0.xsd   
        http://www.springframework.org/schema/mvc   
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">  
  <!-- 防止@ResponseBody中文乱码 -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean
                    class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <bean class="org.springframework.http.MediaType">
                                <constructor-arg index="0" value="text" />
                                <constructor-arg index="1" value="plain" />
                                <constructor-arg index="2" value="UTF-8" />
                            </bean>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
    </bean>
      <!-- 启用MVC注解 -->
    <mvc:annotation-driven />
 
    <!-- 静态资源文件,不会被Spring MVC拦截 -->
    <mvc:resources location="/resources/" mapping="/resources/**"/>
     
    <!-- 指定Sping组件扫描的基本包路径 -->
    <context:component-scan base-package="org.xdemo.example" >
        <!-- 这里只扫描Controller,不可重复加载Service -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
     
      <!-- JSP视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/WEB-INF/views/" />  
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    </bean>
</beans>

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!-- 查找最新的schemaLocation 访问 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.0.xsd">
     <!-- 配置扫描路径 -->
     <context:component-scan base-package="org.xdemo.example">
       <!-- 只扫描Service,也可以添加Repostory,但是要把Controller排除在外,Controller由spring-mvc.xml去加载 -->
       <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" /> -->
       <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" /> -->
       <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" /> -->
       <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
     </context:component-scan>
</beans>

User实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package org.xdemo.example.springrestful.entity;
/**
 * @作者 Goofy
 * @邮件 252878950@qq.com
 * @日期 2014-4-2下午1:40:32
 * @描述 用户实体类
 */
public class User {
    private String userId;
    private String userName;
    public User(){}
    public User(String userId,String userName){
        this.userId=userId;
        this.userName=userName;
    }
    /**
     * @return the userId
     */
    public String getUserId() {
        return userId;
    }
    /**
     * @param userId the userId to set
     */
    public void setUserId(String userId) {
        this.userId = userId;
    }
    /**
     * @return the userName
     */
    public String getUserName() {
        return userName;
    }
    /**
     * @param userName the userName to set
     */
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

UserController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package org.xdemo.example.springrestful.controller;
import java.util.ArrayList;
import java.util.List;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.xdemo.example.springrestful.entity.User;
/**
 * @作者 Goofy
 * @邮件 252878950@qq.com
 * @日期 2014-4-2下午1:28:07
 */
@Controller
@RequestMapping("/user")
public class UserController {
    public List<User> list=null;
    /**
     * user路径下默认显示用户列表
     * @return
     */
    @RequestMapping(method=RequestMethod.GET)
    public ModelAndView index(){
        if(list==null){
            list=getUserList();
        }
        ModelMap model=new ModelMap();
        model.addAttribute("list",list);
        return new ModelAndView("user/index",model);
    }
    /**
     * 跳转到添加用户页面,约定优于配置,默认匹配文件/WEB-INF/views/user/add.jsp
     */
    @RequestMapping("add")
    public void add(){}
    /**
     * 新增保存用户
     * @param user
     * @return ModelAndView
     */
    @RequestMapping(method=RequestMethod.POST)
    public ModelAndView addUser(User user){
        if(list==null){
            list=getUserList();
        }
        list.add(user);
        ModelMap model=new ModelMap();
        model.addAttribute("list",list);
        return new ModelAndView("user/index",model);
    }
    /**
     * 查看用户详细信息
     * @param id
     * @return ModelAndView
     */
    @RequestMapping(method=RequestMethod.GET,value="{id}")
    public ModelAndView viewUser(@PathVariable("id")String id){
        User user=findUserById(id);
        ModelMap model=new ModelMap();
        model.addAttribute("user",user);
        return new ModelAndView("user/view",model);
    }
     
    /**
     * 删除用户
     * @param id
     */
    @ResponseBody
    @RequestMapping(method=RequestMethod.DELETE,value="{id}")
    public String deleteUser(@PathVariable("id")String id){
        if(list==null){
            list=getUserList();
        }
        removeUserByUserId(id);
        return "suc";
    }
     
    /**
     * 跳转到编辑页面
     * @param id
     * @return ModelAndView
     */
    @RequestMapping("{id}/edit")
    public ModelAndView toEdit(@PathVariable("id")String id){
         
        User user=findUserById(id);
        ModelMap model=new ModelMap();
        model.addAttribute("user",user);
         
        return new ModelAndView("user/edit",model);
    }
     
    /**
     * 更新用户并跳转到用户列表页面
     * @param user
     * @return ModelAndView
     */
    @RequestMapping(method=RequestMethod.PUT)
    public ModelAndView edit(User user){
        updateUser(user);
        return new ModelAndView("redirect:/user/");
    }
     
/********************下面方法是操作数据的*********************/
    /**
     * 造10个用户
     * @return List<User>
     */
    private List<User> getUserList(){
        List<User> list=new ArrayList<User>();
        for(int i=0; i<10;i++){
            list.add(new User((i+1)+"","李四"+(i+1)));
        }
        return list;
    }
    /**
     * 删除用户
     * @param id
     * @return List<User>
     */
    private List<User> removeUserByUserId(String id){
        if(list==null)return null;
        for(User user:list){
            if(user.getUserId().equals(id)){
                list.remove(user);break;
            }
        }
        return list;
    }
    /**
     * 查找用户
     * @param id
     * @return User
     */
    private User findUserById(String id){
        User user=null;
        if(list==null)return null;
        for(User _user:list){
            if(_user.getUserId().equals(id)){
                user=_user;break;
            }
        }
        return user;
    }
    /**
     * 更新用户
     * @param user
     */
    private void updateUser(User user){
        for(User _user:list){
            if(_user.getUserId().equals(user.getUserId())){
                _user.setUserName(user.getUserName());break;