使用springMVC创建REST风格的服务器

来源:互联网 发布:最好玩的网络手机游戏 编辑:程序博客网 时间:2024/05/21 10:25

越来越多的企业级应用都在由SOAP过渡到REST,REST API 客户端和服务器的交互由“行为”变成了“状态”(或表述),这样的风格对于客户端乃至整个系统的横向拓展都非常友好,REST API 的关注点在于资源而不在于行为,服务器端通过转换资源的各种表述形式来提供对更多客户端的支持,而不是仅限于现在或未来的某一种资源(json,html/text,xml,rss等等)。

非常幸运的是spring MVC对于REST有着很好的支持,有多种方法可以帮助我们构建REST风格的服务器。

首先,对于资源表述点,springMVC通常有两种方式来实现。

一、协商资源表述

这么来说很抽象。通俗来讲就是,服务器端和客户端根据事先的约定来规定资源的表述形式,如json,jstl。然后通过配置相应的视图解析器来渲染对应的形式的视图。

springMVC 提供了ContentNegotiatingViewResolver来协调这一过程。ContentNegotiatingViewResolver会根据1.url的后缀名(如请求后缀为/application.json)2.请求的头部里定义的contentType,来依次确定本次请求的资源表述形式。如果还没有确定,则意味着客户端可以接受任何数据,将默认调用设定的默认视图解析器。

在确定了资源的表述形式之后,ContentNegotiatingViewResolver会依次让其他视图解析器按照逻辑视图名渲染视图,将返回的view放入列表中,并根据客户端请求的资源形式,查找对应的视图,找到的第一个视图,会进行渲染模型操作。(注意,这里的视图解析器的执行顺序还是会根据order值来确定)。

而要使用ContentNegotiatingViewResolver,需要配置它对应的ContentNegotiationManager来配置一些默认的内容(如默认的资源表述形式,是否忽略请求头信息等等)。下面给出一份简单的配置代码:
XML:

<bean id="contentNegotiationManager" class="org.springframework.http.ContentNegotiationManagerFactoryBean  p:defaultContentType="application/json"">
这里使用了p命名空间,你也可以用property来代替。


javaConfig:

在你的springMVC配置类里(继承了WebMvcConfigurerAdapter的类),重写configureContentNegotiation方法即可:

@Override    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {        configurer.defaultContentType(MediaType.APPLICATION_JSON);    }
配置好ContentNegotiationManager后,在ContentNegotiatingViewResolver中配置好这个依赖即可。


二、使用HTTP信息转换器

消息转换(message conversion)提供了资源表述一种更为直接的形式。dispatcherServlet不需要再将模型数据填充到视图中,实际上,根本就不存在模型和视图了,这里只有控制器产生的数据,消息转换器会把数据转换为对应的资源表述形式。这种方式是不是听起来挺靠谱的?

其实这种方式配置起来更简单,因为啥都不用做,spring已经自带了各种各样的转换器,且已经实现了相应的接口。所以你只需将对应转换器的依赖包引入到你的项目就行了。具体的消息转换器的种类 可自行百度,太多了这里就不一一罗列了。

当然,不用配置就意味着需要调整代码结构。

首先,使用消息转换功能就意味着 我们要跳过模式视图渲染流程,直接返回数据。能够达到目的的方式有很多种,最简单的一种就是使用@ResponseBody注解,

将这个注解加入到方法上,则方法返回的对象会自动转换为请求对应的响应体,@ResponseBody注解会告诉spring,我们要将返回的对象作为资源发送给客户端,并将其转换为客户端可接受的表述形式。具体来说,DispatcherServlet会考虑到请求中Accept头部信息,并查找能够为客户端提供所需表述形式的消息转换器。

例如,我们经常会使用jquery ajax发起资源形式为json的请求。请求头部会包含ContentType=application/json的信息。则dispatcherServlet会选择MappingJacksonHttpMessage-Converter作为消息转换器,前提是你有引入jackson json的相关依赖包。

这样方法所返回的java对象会转换为对应的json对象,并被写入到响应体中返回给客户端。

同理,若请求内的参数需要进行此类转换,只需使用@RequestBody注解即可,它能告诉spring查找一个消息转换器,将来自客户端的资源表述转换为对象。@RequestMapping注解可以加入consumes参数用来限定只处理那种类型的请求,例如:

@RequestMapping(value = {"/getuser"},method = RequestMethod.POST, consumes = "application/json")    public @ResponseBody BaseFile getFile(@RequestBody BaseFile file) {        return null;    }


上面代码表示只处理请求类型为"application/json"的post请求,且请求后缀为“/getuser”,另外该方法表示会返回类型为“application/json”的内容。

这里@RequestBody会根据请求的Content-Type,查找相应的转换器(任意实现了该类型的MessageConverter),将消息体转换为参数对象“BaseFile”。

这里需要说明一下@RequestMapping中 consumes和produces的区别:

consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

produces::指定返回的内容类型,且仅当request请求头中的(Accept)类型中包含该指定类型才返回。

上述内容基本就是一个简单的rest端点的实现,但是每个方法都需要注解处理未免有些太麻烦。

因此在spring4.0之后引入了@RestController注解,该注解在基于@Controller注解之上为每个方法都加入了消息转换功能,就不必再添加@ResponseBody和@RequestBody。

接下来,让我们来构建一些更复杂的Controller

比如,我们需要为每个controller提供一套错误处理机制,首先,我们需要为controller中的方法返回体附加一些其他信息,例如状态码,错误信息等。

在controller中新建一个控制器方法,在并在方法上添加@ExceptionHandler(YourException.class),这个控制器方法将处理在其他控制器中抛出的YourException异常,譬如我们可以在这个方法中返回一些错误码和错误信息

而ResponseEntity类可以让我们在返回体中包含更多信息,例如如下代码:

 @ExceptionHandler({BizException.class})    public String exception(BizException e, HttpServletRequest request, HttpServletResponse response) {        return new ResponseEntity<Error>{new Error(e,request,response),HttpStatus.OK};    }


也可以不用这么麻烦,如果附加信息只有状态码,那么可以使用@ResponseStatus来代替ResponseEntity,具体状态可以自行查看HttpStatus类里的定义。

 @RequestMapping(value = "/{id}", method = RequestMethod.GET)    public    @ResponseBody    BaseFile getFile(@PathVariable long id) {        BaseFile file = DAOHelper.findFile(id);        if (file == null) throw new BizException(id);        return file;    }

如果使用了@RestController,则上面的@ResponseBody注解可以去掉。

三、REST客户端

既然前面说了,REST是可以代替SOAP的东西,REST客户端可以直接通过http服务来调用远程端接口。



上面的代码就是一个简单的客户端调用。

 其实也有更加简洁的方式,即使用RestTemplate类来辅助客户端调用,具体使用可以百度,这里不再赘述。

原创粉丝点击