@Controller : 定义一个类为控制器,这个与 @Repository 有点像
@RequestMapping : 定义Controller的URL映射以及请求方法
@PathVariable : 定义路径参数,Rest本身就是把资源进行唯一定义,那么URL中使用参数也是唯一定义的一种形式
@ResponseBody : 定义返回结果,这个在ajax请求的时候特别有用,因为不需要跳转到其他URL
@ResponseStatus : 定义返回状态
@RequestParam : 定义请求参数,如果是前台与后台同名参数,那么没必要使用它
........................
下面贴出Controller的代码
/**
* <p>项目名称:restful
* <p>Package名称:com.hnust.controller
* 文件名称:ResourceController.java
* 版本:1.00
* 创建日期:2014年10月26日
* Copyright©2014 HNUST .All Rights Reserved.
*/
package com.hnust.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
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 com.hnust.bean.Message;
import com.hnust.bean.Resource;
import com.hnust.service.ResourceService;
/**
*
*@author:Heweipo
*@version 1.00
*
*/
@Controller
@RequestMapping("/resource")
public class ResourceController {
@Autowired
private ResourceService service;
/**
*
* <p>通过id获取资源
* 在这里采用@PathVariable注解,同时返回一个String,让SpringMVC自动寻找最合适的视图解析器
* 优点是能够找到html视图解析器,但是缺点是,JavaBean转为XML格式,
* 需要在 org.springframework.oxm.jaxb.Jaxb2Marshaller绑定JavaBean
* 所以 这里Resource一定要进行绑定
* @param id
* @param model
* @return
* @return String
* author: Heweipo
*/
@RequestMapping(value="/get/{id}" , method=RequestMethod.GET)
public String get(@PathVariable("id") String id , ModelMap model){
model.put("resource", service.getResource(id));
return "resource";
}
/**
*
* <p>存储resource,另外,关于resource的number参数注入很值得注意,如果URL中携带的参数不能转为
* Integer类型,那么是无法继续访问这个方法的!!所以,对于JavaBean最好设置与数据库对应的数据类型
* 进行类型约束。
* 在这里采用@ResponseBody注解,那么返回的对象将会被对应的视图解析器解析,
* 但是不会有html解析器,但是有一个
* 优点:javaBean 如果转为 XML 是不需要在spring-servlet 中
* org.springframework.oxm.jaxb.Jaxb2Marshaller 绑定的
* @param resource
* @param model
* @return void
* author: Heweipo
*/
@RequestMapping(value="/put" , method=RequestMethod.PUT)
public @ResponseBody Message put(Resource resource , ModelMap model){
Message message = new Message();
if(StringUtils.isEmpty(resource.getId())
|| StringUtils.isEmpty(resource.getName())){
message.setMsg("请输入id 和 用户名");
message.setResult("faile");
return message;
}
service.insertResource(resource);
message.setMsg("数据已经存储");
message.setResult("success");
return message;
}
/**
*
* <p>通过id更新resource
* @param resource
* @param model
* @return
* @return Message
* author: Heweipo
*/
@RequestMapping(value="/post" , method=RequestMethod.POST)
public @ResponseBody Message post(Resource resource , ModelMap model){
Message message = new Message();
if(StringUtils.isEmpty(resource.getId())){
message.setMsg("id不能为空");
message.setResult("faile");
return message;
}
service.updateResource(resource);
message.setMsg("数据已经修改");
message.setResult("success");
return message;
}
/**
*
* <p>通过id删除资源
* @param id
* @param model
* @return
* @return Message
* author: Heweipo
*/
@RequestMapping(value="/delete/{id}" , method=RequestMethod.DELETE)
public @ResponseBody Message delete(@PathVariable("id")String id, ModelMap model){
Message message = new Message();
service.deleteResource(id);
message.setMsg("数据已删除");
message.setResult("success");
return message;
}
}
注意的几点说明:
1)关于请求参数自动封装问题,当我们在方法的形参中采用JavaBean时,SpringMVC会把请求的参数中与JavaBean对应的属性封装成JavaBean的一个实例返回,如果有些属性没有值,他就为空;如果属性值进行赋值是类型转换发生错误,则无法请求URL。封装好的JavaBean实例会存储在ModelMap中,并且以JavaBean的类名首字母小写的形式作为key值,所以,你可以 这样获取 model.get('resource');实际这也是很常用的,因为 XML解析的时候需要一个根元素,那么,如果我们的model中存储太多的元素XML是无法解析的。这个Controller不存在这种情况,原因是我是用了@ResponseBody
2)关于返回值的问题,@ResponseBody 是返回值的标识,尤其是对象解析的时候特别有用。而且,使用@ResponseBody后,对于XML解析的对象都可以不用在spring-servlet中进行绑定,然而,如果我们有些时候需要返回一个html,或者Json,或者XML的时候,我们就不会去使用@ResponseBody,而是采用String的形式,把返回的对象存储在model中。当返回值为null时效果与@ResponseBody 是一样的。
下面是修改后的代码:
/**
*
* <p>通过id更新resource
* Message 一定要在 org.springframework.oxm.jaxb.Jaxb2Marshaller 绑定
* @param resource
* @param model
* @return
* @return Message
* author: Heweipo
*/
@RequestMapping(value="/post" , method=RequestMethod.POST)
public String post(Resource resource , ModelMap model){
// 这里清除掉SpringMVC帮我们封装的JavaBean
model.remove("resource");
Message message = new Message();
// 这里存储我们需要解析的JavaBean
model.put("message", message);
if(StringUtils.isEmpty(resource.getId())){
message.setMsg("id不能为空");
message.setResult("faile");
return null;
}
service.updateResource(resource);
message.setMsg("数据已经修改");
message.setResult("success");
// 返回空的效果和使用@ResponseBody是一样的,但是原理不同,
// @ResponseBody 貌似采用了Servlet3.0 的异步特性
return null;
}
对应的spring-servlet.xml源代码:
<!-- XML 与 Java 数据转换 -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<!-- 需要在这里绑定,原因是controller里没有采用@ResponseBody进行返回 -->
<value>com.hnust.bean.Message</value>
</list>
</property>
</bean>
2 请求类型
在@RequestMapping中我们对method进行赋值,如果赋值了那么必须按照对应的请求方法进行访问,否者出现405.该项目中采用测试工具进行测试:
工具采用:Firefox 的RestClient 插件 https://addons.mozilla.org/zh-CN/firefox/addon/restclient/
1)新增资源:put http://localhost:8080/restful/resource/put?id=id_888&name=ireport&number=89
<message>
<msg>数据已经存储</msg>
<result>success</result>
</message>
2)更新资源 post http://localhost:8080/restful/resource/post?id=id_888&name=node.js&number=12
<message>
<msg>数据已经更新</msg>
<result>success</result>
</message>
3) 删除资源 delete http://localhost:8080/restful/resource/delete/id_888
<message>
<msg>数据已删除</msg>
<result>success</result>
</message>
3 关于返回内容格式
内容协商机制很简单,有两种方式,一种是该项目中使用的视图渲染进行内容协商,另外一种则是进行类型转换,本项目中源码如下:
<!-- 主要是进行Controller 和 URL 的一些注解绑定,这里可以进行转换器配置:只有配置好了转换器才能进行类与JSON和XML的转换,当然只是针对基于转换器协商资源表述 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<!-- XML 与 Java 数据转换 -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<!--common XML 映射 JavaBean 注册 -->
<value>com.hnust.bean.Resource</value>
<!-- 不需要在这里绑定,原因是controller里采用ResponseBody进行返回 -->
<!-- <value>com.hnust.bean.Message</value> -->
</list>
</property>
</bean>
<!-- 基于视图渲染进行协商资源表述 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<!-- restful 是否采用扩展名的方式确定内容格式,id.json 返回JSON格式 -->
<property name="favorPathExtension" value="true"></property>
<!-- restful 是否采用参数支持确定内容格式,id?format=json 返回JSON格式 -->
<property name="favorParameter" value="true"></property>
<!-- restful 是否忽略掉accept header,Accept:application/json -->
<property name="ignoreAcceptHeader" value="false"></property>
<!-- 基于视图按顺序解析 -->
<property name="order" value="1" />
<!-- 对采用扩展名,参数新式的 URL 进行获取对应的 accept -->
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
<entry key="html" value="text/html"/>
</map>
</property>
<!-- 如果扩展名,参数甚至header 信息都没有找到对应的accept时 -->
<property name="defaultContentType" value="text/html"/>
<!-- 采用对应的视图进行渲染 -->
<property name="defaultViews">
<list >
<!-- 转换Java对象为XML格式数据 -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg ref="jaxbMarshaller" />
</bean>
<!-- 转换Java对象为JSON 格式数据 -->
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
</list>
</property>
<!-- 采用对应的视图进行渲染 -->
<property name="viewResolvers">
<list >
<!-- 查找在上下文中定义了ID的Bean,并且定位该ID -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<!-- 对Controller中返回的视图实例进行解析,并且组装URL定位到对应的资源 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
</bean>
然而如果使用转换机制的话:
<!-- 输出字符串内容,非路径 -->
<bean id="stringConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- JSON -->
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller"/>
<property name="supportedMediaTypes" value="application/xml" />
</bean>
<!-- 基于转换器进行内容协商 -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<!-- XML转换器需要绑定需要转换的类 -->
<property name="classesToBeBound">
<list>
<value>com.hnust.bean.Resource</value>
</list>
</property>
</bean>
<!-- 注册对象转换器 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringConverter" />
<ref bean="jsonConverter" />
<ref bean="marshallingHttpMessageConverter"/>
</list>
</property>
</bean>
4 pom文件,获取jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
</dependency>
5 项目源码链接: