spring mvc 提供的restful 服务怎么访问

发布网友 发布时间:2022-04-21 19:55

我来回答

1个回答

热心网友 时间:2022-04-26 11:47

Spring MVC本身对Restful支持非常好。它的@RequestMapping、@RequestParam、@PathVariable、@ResponseBody注解很好的支持了REST。18.2 Creating RESTful services
1. @RequestMapping
Spring uses the @RequestMapping method annotation to define the URI Template for the request. 类似于struts的action-mapping。 可以指定POST或者GET。
2. @PathVariable
The @PathVariable method parameter annotation is used to indicate that a method parameter should be bound to the value of a URI template variable. 用于抽取URL中的信息作为参数。(注意,不包括请求字符串,那是@RequestParam做的事情。)
@RequestMapping("/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
// ...
}

如果变量名与pathVariable名不一致,那么需要指定:
@RequestMapping("/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
// implementation omitted
}

Tip
method parameters that are decorated with the @PathVariable annotation can be of any simple type such as int, long, Date... Spring automatically converts to the appropriate type and throws a TypeMismatchException if the type is not correct.
3. @RequestParam
官方文档居然没有对这个注解进行说明,估计是遗漏了(真不应该啊)。这个注解跟@PathVariable功能差不多,只是参数值的来源不一样而已。它的取值来源是请求参数(querystring或者post表单字段)。
对了,因为它的来源可以是POST字段,所以它支持更丰富和复杂的类型信息。比如文件对象:
@RequestMapping("/imageUpload")
public String processImageUpload(@RequestParam("name") String name,
@RequestParam("description") String description,
@RequestParam("image") MultipartFile image) throws IOException {
this.imageDatabase.storeImage(name, image.getInputStream(),
(int) image.getSize(), description);
return "redirect:imageList";
}

还可以设置defaultValue:
@RequestMapping("/imageUpload")
public String processImageUpload(@RequestParam(value="name", defaultValue="arganzheng") String name,
@RequestParam("description") String description,
@RequestParam("image") MultipartFile image) throws IOException {
this.imageDatabase.storeImage(name, image.getInputStream(),
(int) image.getSize(), description);
return "redirect:imageList";
}

4. @RequestBody和@ResponseBody
这两个注解其实用到了Spring的一个非常灵活的设计——HttpMessageConverter 18.3.2 HTTP Message Conversion
与@RequestParam不同,@RequestBody和@ResponseBody是针对整个HTTP请求或者返回消息的。前者只是针对HTTP请求消息中的一个 name=value 键值对(名称很贴切)。
HtppMessageConverter负责将HTTP请求消息(HTTP request message)转化为对象,或者将对象转化为HTTP响应体(HTTP response body)。
public interface HttpMessageConverter<T> {

// Indicate whether the given class is supported by this converter.
boolean supports(Class<? extends T> clazz);

// Return the list of MediaType objects supported by this converter.
List<MediaType> getSupportedMediaTypes();

// Read an object of the given type form the given input message, and returns it.
T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException;

// Write an given object to the given output message.
void write(T t, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException;

}

Spring MVC对HttpMessageConverter有多种默认实现,基本上不需要自己再自定义HttpMessageConverter
StringHttpMessageConverter - converts strings
FormHttpMessageConverter - converts form data to/from a MultiValueMap<String, String>
ByteArrayMessageConverter - converts byte arrays
SourceHttpMessageConverter - convert to/from a javax.xml.transform.Source
RssChannelHttpMessageConverter - convert to/from RSS feeds
MappingJacksonHttpMessageConverter - convert to/from JSON using Jackson's ObjectMapper
etc...
然而对于RESTful应用,用的最多的当然是MappingJacksonHttpMessageConverter。
但是MappingJacksonHttpMessageConverter不是默认的HttpMessageConverter:
public class AnnotationMethodHandlerAdapter extends WebContentGenerator
implements HandlerAdapter, Ordered, BeanFactoryAware {

...

public AnnotationMethodHandlerAdapter() {
// no restriction of HTTP methods by default
super(false);

// See SPR-7316
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false);
this.messageConverters = new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), stringHttpMessageConverter,
new SourceHttpMessageConverter(), new XmlAwareFormHttpMessageConverter()};
}
}

如上:默认的HttpMessageConverter是ByteArrayHttpMessageConverter、stringHttpMessageConverter、SourceHttpMessageConverter和XmlAwareFormHttpMessageConverter转换器。所以需要配置一下:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=GBK</value>
</list>
</property>
</bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>

配置好了之后,就可以享受@Requestbody和@ResponseBody对JONS转换的便利之处了:
@RequestMapping(value = "api", method = RequestMethod.POST)
@ResponseBody
public boolean addApi(@RequestBody
Api api, @RequestParam(value = "afterApiId", required = false)
Integer afterApiId) {
Integer id = apiMetadataService.addApi(api);
return id > 0;
}

@RequestMapping(value = "api/{apiId}", method = RequestMethod.GET)
@ResponseBody
public Api getApi(@PathVariable("apiId")
int apiId) {
return apiMetadataService.getApi(apiId, Version.primary);
}

一般情况下我们是不需要自定义HttpMessageConverter,不过对于Restful应用,有时候我们需要返回jsonp数据:
package me.arganzheng.study.springmvc.util;

import java.io.IOException;
import java.io.PrintStream;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class MappingJsonpHttpMessageConverter extends MappingJacksonHttpMessageConverter {

public MappingJsonpHttpMessageConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationConfig(objectMapper.getSerializationConfig().withSerializationInclusion(Inclusion.NON_NULL));
setObjectMapper(objectMapper);
}

@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
String jsonpCallback = null;

RequestAttributes reqAttrs = RequestContextHolder.currentRequestAttributes();
if(reqAttrs instanceof ServletRequestAttributes){
jsonpCallback = ((ServletRequestAttributes)reqAttrs).getRequest().getParameter("jsonpCallback");
}

if(jsonpCallback != null){
new PrintStream(outputMessage.getBody()).print(jsonpCallback + "(");
}

super.writeInternal(o, outputMessage);

if(jsonpCallback != null){
new PrintStream(outputMessage.getBody()).println(");");
}
}
}

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com