Retrofit简介
Retrofit是Java和Android的REST客户端。 它使通过基于REST的webService和JSON(或其他结构化数据)变得相对容易。 在Retrofit中,您可以配置用于数据序列化的转换器。 通常对于JSON使用GSon,但您可以添加自定义转换器来处理XML或其他协议。 Retrofit使用OkHttp库进行HTTP请求。
-
retrofit 更类似于 spring 的restTemplate 对已有网络请求libary 再次封装,更像是一种增强类似lombok
-
retrofit 基于okHttp ,这两个libary 都是Square Open Source 维护,对于已经使用okHttp的项目可以平滑迁移
-
retrofit 诞生的意义:把Url 和 http请求解耦、打散,针对接口编程、简化代码、增加易读性
为什么使用retrofit
-
基于接口编程,解耦,各个http请求之间无关联。修改影响小、容易扩展
-
基于目前平台的现状:都使用不同的http网络请求封装,可读性一般、不方便后期维护
-
基于注解
-
提供JSON to POJO,POJO to JSON,网络请求(POST,GET,PUT,DELETE等)封装
1、为了做测试,建立了一个新的Spring Boot项目"restful",项目结构如下:
1.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kongliand</groupId>
<artifactId>springboot-retrofit</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-retrofit</name>
<description>springboot-retrofit</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2 Application.java
package com.zzg.resultful;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1.3 Hotel.java
package com.zzg.resultful.domain;
public class Hotel {
private int id;
private String hotelname;
public Hotel() {
}
public Hotel(int id, String hotelname) {
this.id = id;
this.hotelname = hotelname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getHotelname() {
return hotelname;
}
public void setHotelname(String hotelname) {
this.hotelname = hotelname;
}
}
1.4 HotelController.java
package com.zzg.resultful.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.zzg.resultful.domain.Hotel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@RestController
@RequestMapping("/hotel")
@Api("HotelController相关api")
public class HotelController {
@ApiOperation("获取酒店Hotel信息:getHotelWithQueryParameter")
@RequestMapping(value="/getHotelWithQueryParameter",method=RequestMethod.GET)
public Hotel getHotelWithQueryParameter(@RequestParam("hotelname") String hotelname) {
if(hotelname.equals("nana")){
return new Hotel(777, "假日酒店");
}
return new Hotel(1314, "玫瑰酒店");
}
@ApiOperation("获取酒店Hotel信息:getHotelList")
@RequestMapping(value="/getHotelList",method=RequestMethod.POST)
public List<Hotel> getHotelList() {
List<Hotel> hotelList = new ArrayList<Hotel>();
hotelList.add(new Hotel(1314, "玫瑰酒店"));
hotelList.add(new Hotel(2046, "2046酒店"));
return hotelList;
}
@ApiOperation("获取酒店Hotel信息:getHotelListWithBody")
@RequestMapping(value="/getHotelListWithBody",method=RequestMethod.POST)
public List<Hotel> getHotelListWithBody(@RequestBody Hotel hotel) {
List<Hotel> hotelList = new ArrayList<Hotel>();
if(hotel.getHotelname().equals("武林酒店")){
hotelList.add(new Hotel(13141, "玫瑰酒店1"));
hotelList.add(new Hotel(20461, "2046酒店1"));
return hotelList;
}
hotelList.add(new Hotel(1314, "玫瑰酒店"));
hotelList.add(new Hotel(2046, "2046酒店"));
return hotelList;
}
}
说明:该类提供了三个方法,也是将来customerresultful服务远程调用的三个方法。
2、新建另一个springboot 项目“customerresultful”,项目结构如下:
2.1 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zzg</groupId> <artifactId>customerrestful</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>customerrestful</name> <url>http://maven.apache.org</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.3.RELEASE</version> </parent> <dependencies> <dependency>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency><!-- 引入retrofit --> <dependency> <groupId>com.squareup.retrofit</groupId> <artifactId>retrofit</artifactId> <version>1.9.0</version> </dependency> </dependencies> </project>
说明:引入retrofit1.9.0依赖,与2.0的差别很大。
2.2 RestAdapterConfig.java
package com.zzg.customerrestful.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import retrofit.RestAdapter;
@Configuration
public class RestAdapterConfig {
/**
* 获取RestAdapter单例Bean
* @return
*/
@Bean
public RestAdapter getRestAdapter(){
/**
* setEndpoint("http://localhost:8081"):指定基本的URL,
* API接口中的URL是相对于该URL的路径的,
* 不能少了协议名,例如写成:localhost:8081就不行
*/
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint("http://localhost:8081")
.build();
return adapter;
}
}
说明:
- 使用 @Configuration+@Bean 构建RestAdapter单例。
- 在构建的过程中,一定要有setEndpoint("http://localhost:8081")方法,该方法指定了基本的URL(即:指定协议+IP+port)
2.3 HotelAPI.java
package com.zzg.customerrestful.api;
import java.util.List;
import com.zzg.customerrestful.domain.Hotel;
import retrofit.http.Body;
import retrofit.http.GET;
import retrofit.http.POST;
import retrofit.http.Query;
public interface HotelAPI {
/**
* GET请求带查询参数
*/
@GET("/hotel/getHotelWithQueryParameter")
public Hotel getHotelWithQueryParameter(@Query("hotelname") String hotelname);
/**
* POST请求
*/
@POST("/hotel/getHotelList")
public List<Hotel> getHotelList();
/**
* POST请求,带参数JavaBean
*/
@POST("/hotel/getHotelListWithBody")
public List<Hotel> getHotelListWithBody(@Body Hotel hotel);
}
说明:
- 该接口指定了调用远程服务的方法的基本路径与参数以及返回值等
- 路径都是相对路径,相对于setEndpoint("http://localhost:8081")指定的路径
- 方式有@GET/@POST/@PUT/@DELETE等
- 传递参数在get方式中可以直接将参数连到URL上去
- 传递参数使用@Query(服务被调用方使用@RequestParam接收),路径中的传递参数使用@Path(Restful风格),还可以直接传递一个对象@Body(服务被调用方使用@RequestBody接收),参数在请求头中@Header(服务被调用方使用@RequestHeader接收)
- 依旧要建一个Hotel类,最好与resultful中的相同,不同也没关系
2.4 HotelAPIConfig.java
package com.zzg.customerrestful.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import retrofit.RestAdapter;
@Configuration
public class HotelAPIConfig {
@Autowired
private RestAdapter adapter;
@Bean
public HotelAPI getHotelAPI(){
return adapter.create(HotelAPI.class);
}
}
说明:
- 使用 @Configuration+@Bean 构建HotelAPI单例。
- HotelAPI接口实例是由RestAdapter来构建的,所以需要注入了RestAdapter
经过以上步骤后,之后就可以直接在其他类中注入HotelAPI实例来像普通的bean进行操作了。
2.5 UserService.java
package com.zzg.customerrestful.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zzg.customerrestful.api.HotelAPI;
import com.zzg.customerrestful.domain.Hotel;
@Service
public class UserService {
@Autowired
private HotelAPI hotelApi;
public Hotel getHotelFromMyboot2WithQueryParameter(String hotelname){
return hotelApi.getHotelWithQueryParameter(hotelname);
}
public List<Hotel> getHotelFromMyboot2List(){
return hotelApi.getHotelList();//测试post请求
}
public List<Hotel> getHotelFromMyboot2ListWithBody(Hotel hotel){
return hotelApi.getHotelListWithBody(hotel);//测试post请求
}
}
说明:
- service中注入了HotelAPI实例,使用该实例调用接口方法
- 其实,retrofit的接口的注入和使用与mybatis的注解方式的mapper接口的使用相似
2.6、UserController.java
package com.zzg.customerrestful.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.zzg.customerrestful.domain.Hotel;
import com.zzg.customerrestful.service.UserService;
import io.swagger.annotations.ApiOperation;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@ApiOperation("获取酒店信息,测试GETWithQueryParameter")
@RequestMapping(value="/getHotelWithQueryParameter",method=RequestMethod.GET)
public Hotel getHotel(@RequestParam("hotelname") String hotelname) {
return userService.getHotelFromMyboot2WithQueryParameter(hotelname);
}
@ApiOperation("获取酒店信息,测试POST")
@RequestMapping(value="/getHotelList",method=RequestMethod.GET)
public List<Hotel> getHotelList() {
return userService.getHotelFromMyboot2List();
}
@ApiOperation("获取酒店信息,测试POST")
@RequestMapping(value="/getHotelListWithBody",method=RequestMethod.GET)
public List<Hotel> getHotelListWithBody() {
return userService.getHotelFromMyboot2ListWithBody(new Hotel(888, "武林酒店"));
}
}
测试:
首先,启动服务resultful,浏览器输入"localhost:8081/swagger-ui.html"可以查看服务是否启动成功。
其次,启动服务customerresultful,浏览器输入"localhost:8080/swagger-ui.html",再进行相应接口的测试即可。