更强大的功能!Spring MVC用ResponseEntity返回可实现

更强大的功能!Spring MVC用ResponseEntity返回可实现

今天有粉丝询问胖哥开源微信支付V3开发包Payment Spring Boot下载对账单接口的一些细节,并问我为什么要返回ResponseEntity对象而不是直接返回一个业务实体对象。今天就来统一解答一下并科普一下它的用途。

ResponseEntity

ResponseEntity对象是Spring对请求响应的封装。它继承了HttpEntity对象,包含了Http的响应码(httpstatus)、响应头(header)、响应体(body)三个部分。一个获取用户信息的Spring MVC接口通常我们直接返回实体即可(配合@RestController):

@GetMapping("/user")public User userinfo() {    User user = new User();    user.setUsername("felord.cn");    return user;}

等同于使用ResponseEntity作为控制器接口的返回值:

    @GetMapping("/userinfo")    public ResponseEntity<User> user() {        User user = new User();        user.setUsername("felord.cn");        return ResponseEntity.ok(user);    }

但是使用ResponseEntity时我们可以做更多事情。

自定义响应码

上面的ResponseEntity.ok已经包含了返回200Http响应码,我们还可以通过ResponseEntity.status(HttpStatus|int)来自定义返回的响应码。

自定义响应体

放置响应的响应体,通常就是我们接口的数据,这里是一个例子:

ResponseEntity.status(HttpStatus.OK)               .body(Object)

响应头

通常我们指定Spring MVC接口的响应头是通过@RequestMapping和其Restful系列注解中的header()consumesproduces()这几个属性设置。如果你使用了ResponseEntity,可以通过链式调用来设置:

ResponseEntity.status(HttpStatus.OK)               .allow(HttpMethod.GET)               .contentType(MediaType.APPLICATION_JSON)               .contentLength(1048576)               .header("My-Header","felord.cn")               .build();

所有的标准请求头都有对应的设置方法,你也可以通过header(String headerName, String... headerValues)设置自定义请求头。

大致原理

我们来看一个用来处理Spring MVC控制器接口返回值的抽象接口HandlerMethodReturnValueHandler

public interface HandlerMethodReturnValueHandler { /**  * 支持的返回值类型  */ boolean supportsReturnType(MethodParameter returnType); /**  *  将数据绑定到视图,并设置处理标志以指示已直接处理响应,后续的其它方法就不处理了,优先级非常高  */ void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,   ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;}

它的一个重要实现HttpEntityMethodProcessor就是处理返回类型为HttpEntity的控制器方法的处理器。它会把ResponseEntity携带的三种信息交给ServletServerHttpResponse对象渲染视图,并设置处理标志以指示已直接处理响应,后续的其它方法就不处理了,优先级非常高。

实战运用

通常让你写个下载文件接口都是拿到HttpServletResponse对象,然后配置好Content-Type往里面写流。如果用ResponseEntity会更加简单优雅。

@GetMapping("/download")public ResponseEntity<Resource> load() {    ClassPathResource classPathResource = new ClassPathResource("application.yml");    String filename = classPathResource.getFilename();    HttpHeaders httpHeaders = new HttpHeaders();    httpHeaders.setContentDisposition(ContentDisposition.inline().filename(filename, StandardCharsets.UTF_8).build());    return ResponseEntity.ok()            .headers(httpHeaders)            .body(classPathResource);}

上面是一个把Spring Boot配置文件 application.yml下载下来的例子。主要分为三步:

  • 将要下载的文件封装成org.springframework.core.io.Resource对象,它有很多实现。这里用了ClassPathResource,其它InputStreamResourcePathResource都是常用的实现。
  • 然后配置下载文件请求头Content-Disposition。针对下载它有两种模式: inline表示在浏览器直接展示文件内容;attachment表示下载为文件。另外下载后的文件名也在这里指定,请不要忘记文件扩展名,例如这里application.yml。如果不指定Content-Disposition,你需要根据文件扩展名设置对应的Content-Type,会麻烦一些。
  • 最后是组装ResponseEntity<Resource>返回。

原理参见org.springframework.http.converter.ResourceHttpMessageConverter

inline模式下载文件对应的效果:

总结

今天对Spring 中的ResponseEntity作用和机制进行了分享,同时贴近实战分享了下载文件的另一种办法。在胖哥的微信支付开发包Payment Spring BootResponseEntity得到了大量的运用,有兴趣可以去看一下源码实现。

转载于公众号-程序猿DD


北京云中融信网络科技有限公司(简称融云),是安全、可靠的全球互联网通信云服务商,向开发者和企业提供即时通讯和实时音视频通信云服务。iResearch 艾瑞权威数据报告显示,融云即时通讯云市场份额连续多年稳居头位。

融云构建了一张覆盖全球所有国家及地区(共 233 个)的通信云网络,在全球各地设立多个数据中心及数千个加速节点。基于客户业务需求,融云可提供多种部署模式——公有云、私有云、混合云,为全球企业提供稳定的互联网通信云服务。针对企业级用户,融云将业务垂直到各个行业,为社交、直播、金融、交通运输、教育、电商、医疗等多个行业领域推出了针对性解决方案。

融云基于海量业务的技术锤炼,从基础架构到精细化运营,充分体现平台实力;凭借卓越的产品和优质的服务,在开发者规模、行业覆盖率、平台日活跃用户数、日均消息量等方面超越全行业。目前,已有数十万互联网用户及上千家企业级用户通过融云实现了场景化沟通,并从中获益,包括工商银行、中国移动、四川航空、CCTV 微视、中联重科、58 赶集、大河报业、新东方、陆金所、融创地产、IDG、华兴资本、易车网、猪八戒、得到 APP、荔枝、汽车之家、哈啰出行、百姓网、StarMaker、Opera、Elelive。

       

标签: