您的位置:首页 > 其它

Retrofit入门[简单使用方式介绍哦]

2017-12-26 16:04 519 查看
一直用OkHttp感觉也没什么毛病,空闲时间看看Retrofit怎么使用

本篇仅介绍最基本的Retrofit用法,如有错误请提出,我会虚心请教并改正,谢谢

一、接口

想必有所了解的同学都知道Retrofit是基于接口来进行请求,如下

开门见山贴代码

interface RetrofitApi {

/* 1. 仅请求服务器数据 */
@GET(".")
fun register(): Call<String>

/* 2. 上传参数 */
@GET("hi/register")
fun register(@QueryMap map: Map<String, String>): Call<String>

/* 3. ???上传json[暂时处于僵硬状态...] */
@POST("postJson")
fun postJson(@Body user: User): Call<String>

/* 4. 上传单个文件 */
@Multipart
@POST(".")
fun uploadFile(@Part("description") description: RequestBody, @Part file: MultipartBody.Part): Call<String>

/* 5. 上传多个文件 & 多个参数 */
@JvmSuppressWildcards   // [IllegalArgumentException: Parameter type must not include a type variable or wildcard]
@Multipart
@POST(".")
fun uploadFiles(@PartMap fileMap: Map<String, RequestBody>, @QueryMap map: Map<String, String>): Call<String>

/* 6. 下载文件 */
@Streaming  // 避免下载大文件被Retrofit整个读进内存
@GET("downloadFile")
fun download(): Call<ResponseBody>
}


javabean数据类User如下

data class User(val password: String, val username: String)


做个解释

上面的第三个上传json(或者有需求是上传xml的,这里没有成功实现,如有需要的同学联系我,然后我会尽快待补)

注意事项代码里都加注释了,再次说明几点

有@Part的地方基本都要加@Multipart

有@PartMap的地方最好加@JvmSuppressWildcards,否则会出错(注释有)

下载文件时Retrofit会将文件流整个读进内存,避免OOM需添加@Streaming

二、具体的请求

刚开始,多写几遍最基本的请求步骤,加强记忆,不急着封装啥的

代码贴上

object RetrofitRequest {

@JvmStatic
fun main(args: Array<String>) {
//        register()
//        registerWithParams()
//        postJson()
//        uploadFile()
//        uploadFiles()
download()
}

private fun register() {
// 先来个模子 -> 给模子加花 -> 通过模子刻个实例出来
val retrofit = Retrofit.Builder()   // 创建客户端建造器
.baseUrl("http://127.0.0.1:8080/hi/register/")   // 添加主机地址
.addConverterFactory(ScalarsConverterFactory.create()) // 制定数据解析器[可用gson、jackson等或自定制]
.build()    // 创建客户端实例

val api = retrofit.create(RetrofitApi::class.java)  // 获取Api实例

val call = api.register()   // 通过Api实例获取一个Call对象

call.enqueue(object : Callback<String> {  // 开始请求[enqueue(异步) | execute(同步)]
override fun onFailure(call: Call<String>?, t: Throwable?) {
println("请求失败: ${t.toString()}")
}

override fun onResponse(call: Call<String>?, response: Response<String>?) {
println("请求成功: ${response?.body()}")
}
})
}

private fun registerWithParams() {
val retrofit = Retrofit.Builder()
.baseUrl("http://127.0.0.1:8080/")
.addConverterFactory(ScalarsConverterFactory.create())
.build()

val api = retrofit.create(RetrofitApi::class.java)

val call = api.register(mapOf("username" to "catface", "password" to "root"))   // 添加请求参数map

call.enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>?, response: Response<String>?) {
println("请求成功: ${response?.body()}")
}

override fun onFailure(call: Call<String>?, t: Throwable?) {
println("请求失败: ${t.toString()}")
}

})
}

// 僵硬中...
private fun postJson() {
val retrofit = Retrofit.Builder()
.baseUrl("http://127.0.0.1:8080/")
.addConverterFactory(GsonConverterFactory.create())
.build()

val api = retrofit.create(RetrofitApi::class.java)

val call = api.postJson(User("root", "catface"))

call.enqueue(object : Callback<String> {
override fun onFailure(call: Call<String>?, t: Throwable?) {
println("请求失败: ${t.toString()}")
}

override fun onResponse(call: Call<String>?, response: Response<String>?) {
println("请求成功: ${response?.body()}")
}
})
}

private fun uploadFile() {
val retrofit = Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.baseUrl("http://127.0.0.1:8080/hi/uploadFileByJava/")
.build()

val api = retrofit.create(RetrofitApi::class.java)

val file = File("D:/下载/图片/ic_launcher.png")
val requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file)
val fileBody = MultipartBody.Part.createFormData("file", file.name, requestBody)

val description = RequestBody.create(MediaType.parse("multipart/form-data"), "This is a description")

val call = api.uploadFile(description, fileBody)

call.enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>, response: Response<String>) {
println("请求成功: ${response.body().toString()}")
}

override fun onFailure(call: Call<String>, t: Throwable) {
println("请求失败: ${t.toString()}")
}
})
}

private fun uploadFiles() {
val retrofit = Retrofit.Builder()
.baseUrl("http://127.0.0.1:8080/hi/uploadFileBySpringAndFileName/")
.addConverterFactory(ScalarsConverterFactory.create())
.build()

val api = retrofit.create(RetrofitApi::class.java)

/* 文件 */
val fileMap = HashMap<String, RequestBody>()
val file1 = File("D:/下载/图片/ic_launcher.png")
val file2 = File("D:/下载/图片/girl01.jpg")
fileMap.put("file1\"; filename=\"" + file1.name, RequestBody.create(MediaType.parse("multipart/form-data"), file1))
fileMap.put("file2\"; filename=\"" + file2.name, RequestBody.create(MediaType.parse("multipart/form-data"), file2))

/* 参数 */
val map = HashMap<String, String>()
map.put("username", "catface")
map.put("password", "root")

val call = api.uploadFiles(fileMap, map)

call.enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>?, response: Response<String>?) {
println("请求成功: ${response?.body()}")
}

override fun onFailure(call: Call<String>?, t: Throwable?) {
println("请求失败: ${t.toString()}")
}

})
}

private fun download() {
val retrofit = Retrofit.Builder()
.baseUrl("http://127.0.0.1:8080/hi/")
.addConverterFactory(ScalarsConverterFactory.create())
.build()

val api = retrofit.create(RetrofitApi::class.java)

val call = api.download()

call.enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>?) {
println("请求成功")
if (response!!.isSuccessful) {
writeResponseBodyToDisk(response.body()!!)
}
}

override fun onFailure(call: Call<ResponseBody>?, t: Throwable?) {
println("请求失败: ${t.toString()}")
}

})
}

/* 将流写到本地的工具 */
fun writeResponseBodyToDisk(body: ResponseBody): Boolean {
try {
val futureStudioIconFile = File("d:/a_test_dir/Future Studio Icon.jpg")

var inputStream: InputStream? = null
var outputStream: OutputStream? = null

try {
val fileReader = ByteArray(4096)

val fileSize = body.contentLength()
var fileSizeDownloaded: Long = 0

inputStream = body.byteStream()
outputStream = FileOutputStream(futureStudioIconFile)

while (true) {
val read = inputStream!!.read(fileReader)

if (read == -1) {
break
}

outputStream.write(fileReader, 0, read)

fileSizeDownloaded += read.toLong()

println("file download: $fileSizeDownloaded of $fileSize")
}

outputStream.flush()

return true
} catch (e: IOException) {
return false
} finally {
if (inputStream != null) {
inputStream.close()
}

if (outputStream != null) {
outputStream.close()
}
}
} catch (e: IOException) {
return false
}
}
}


做个解释

在数据解析器方面,我觉得直接返回json串后自己使用gson或者fastjson解析,又清楚也不麻烦,不太喜欢在构造Retrofit实例的时候就固定了解析方式,当然如果为了方便项目需求需要加也没问题

步骤大致就是:创建Retrofit实例,然后通过接口定义的请求得到Api实例,通过这个实例得到对应的Call对象,最后进行具体的请求

三、服务端

为了方便同学们了解服务端是怎么接收文件和参数的,在此贴出我写的完整的服务端小demo,可做大家入门案例,灰常简单,且功能很全,能接收客户端传来的各种参数、文件,而且能返回给客户端字符串、json串、还能提供文件给客户端进行下载,直接看,不用害怕

Controller代码贴上

@Controller
@RequestMapping("hi")
public class HiController {

/******************************************** 与客户端进行入参出参联系 ********************************************/
/**
* 1. 接收参数 --> 返回字符串
*/
@RequestMapping(value = "/register", produces = "application/json; charset=utf-8")
@ResponseBody
public String register(HttpServletRequest request) {
System.out.println("接口开始执行-->register");

Map<String, String[]> map = request.getParameterMap();

if (null == map || map.size() < 1) return "本次请求未上传任何参数";

String result = "";
for (String key : map.keySet()) {
System.out.println(key + "-" + map.get(key)[0]);

result += "\r\n" + key + "-" + map.get(key)[0];
}

return result;
}

/**
* 接收json串
*/
@RequestMapping(value = "/postJson", method = RequestMethod.POST, produces = "application/json; charset=utf-8")
@ResponseBody
public String postJson(@RequestBody Map<String, String> map) throws IOException {
System.out.println("接口开始执行-->postJson");

if (null == map || map.size() < 1) return "本次请求未上传任何参数";

String result = "";
for (String key : map.keySet()) {
System.out.println(key + "-" + map.get(key));

result += "\r\n" + key + "-" + map.get(key);
}

return result;
}

/**
* 2. 接收参数 --> 返回json
*/
@RequestMapping(value = "/login", produces = "application/json; charset=utf-8")
@ResponseBody
public String login(@RequestParam("username") String username, @RequestParam("password") String password) throws IOException {
System.out.println("接口开始执行-->login");

/* 接收入参 */
System.out.println(username + " || " + password);

/* 提供出参[json格式] */
Map<String, String> map = new HashMap<String, String>();
map.put("username", "测试中文 your username is: " + username);
map.put("password", "测试中文 your password is: " + password);

/* 返回json给客户端 */
return JSON.toJSONString(map);
}

@RequestMapping(value = "/receiveArr")
public void receiveArr(@RequestParam("ids[]") String[] ids) {
System.out.println("接口开始执行-->receiveArr");

for (String id : ids) {
System.out.println(id);
}
}

/******************************************** 客户端上传文件 ********************************************/
/**
* ↓通过流保存上传的文件(耗时较长)
*
* @param file 将文件封装成CommonsMultipartFile
*/
@RequestMapping("/uploadFileByStream")
@ResponseBody
public String uploadFileByStream(@RequestParam("file") CommonsMultipartFile file) throws IOException {
System.out.println("接口开始执行-->uploadFileByStream");

OutputStream os = new FileOutputStream("d:/" + file.getOriginalFilename());

InputStream is = file.getInputStream();

int temp;
while ((temp = is.read()) != -1) {
os.write(temp);
}

os.flush();
os.close();
is.close();

return "uploadFileByStream suc...";
}

/**
* ↓通过Java API: file.transferTo()保存上传的单个文件
*/
@RequestMapping("/uploadFileByJava")
@ResponseBody
public String uploadFileByJava(@RequestParam("file") CommonsMultipartFile file) throws IOException {
System.out.println("接口开始执行-->uploadFileByJava");

file.transferTo(new File("d:/" + file.getOriginalFilename()));

return "uploadFileByJava suc... ";
}

/**
* ↓通过Spring API保存上传的多个文件
*/
@RequestMapping("/uploadFilesBySpring")
@ResponseBody
public String uploadFilesBySpring(HttpServletRequest request) throws IOException {
System.out.println("接口开始执行-->uploadFilesBySpring");

String desPath;

CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
if (multipartResolver.isMultipart(request)) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;

Iterator<String> iterator = multiRequest.getFileNames();

while (iterator.hasNext()) {
MultipartFile file = multiRequest.getFile(iterator.next());

if (null != file) {
desPath = "d:/tt/" + file.getOriginalFilename();
file.transferTo(new File(desPath));
}
}
}

return "uploadFilesBySpring suc...";
}

/**
* →接收文件map & 请求参数map←
*/
@RequestMapping(value = "/uploadFileBySpringAndFileName", method = RequestMethod.POST, produces = "application/json; charset=utf-8")
@ResponseBody
public String uploadFileBySpringAndFileName(HttpServletRequest request) throws IOException {
System.out.println("接口开始执行-->uploadFileBySpringAndFileName");

/* 1. 获取所有参数 */
Map<String, String[]> parameterMap = request.getParameterMap();

System.out.println("参数数量: " + parameterMap.size()); // 入参数量

for (String key : parameterMap.keySet()) {
System.out.println(key + ":" + parameterMap.get(key)[0]);
}

/* 2. 获取所有文件 */
CommonsMultipartResolver multiResolver = new CommonsMultipartResolver(request.getSession().getServletContext());

if (multiResolver.isMultipart(request)) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;

MultiValueMap<String, MultipartFile> multiFileMap = multiRequest.getMultiFileMap();
System.out.println("文件数量: " + multiFileMap.size()); // 入参数量
for (String key : multiFileMap.keySet()) {
System.out.println(key + " : " + multiFileMap.get(key).get(0).getOriginalFilename());
multiFileMap.get(key).get(0).transferTo(new File("d:/a_test_dir/" + multiFileMap.get(key).get(0).getOriginalFilename()));
}

/*Iterator<String> iterator = multiRequest.getFileNames();

while (iterator.hasNext()) {
Map<String, MultipartFile> fileMap = multiRequest.getFileMap();

MultipartFile file = fileMap.get("file");

System.out.println(file.getOriginalFilename());
}*/
}

return "uploadFileBySpringAndFileName suc...";
}

/* 添加一个网上的小demo,没啥用,随便看看 */
@RequestMapping("/uploadFiles")
@ResponseBody
public String uploadFiles(HttpServletRequest request) throws IOException {
System.out.println("接口开始执行-->uploadFiles");

//创建一个通用的多部分解析器
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
//判断 request 是否有文件上传,即多部分请求
if (multipartResolver.isMultipart(request)) {
//转换成多部分request
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
//取得request中的所有文件名
Iterator<String> iter = multiRequest.getFileNames();
while (iter.hasNext()) {
//记录上传过程起始时的时间,用来计算上传时间
int pre = (int) System.currentTimeMillis();
//取得上传文件
MultipartFile file = multiRequest.getFile(iter.next());
if (file != null) {
//取得当前上传文件的文件名称
String myFileName = file.getOriginalFilename();
//如果名称不"",说明该文件存在,否则说明该文件不存在
if (myFileName.trim() != "") {
System.out.println(myFileName);
//重命名上传后的文件名
String fileName = "demoUpload" + file.getOriginalFilename();
//定义上传路径
String path = "D:/a_test_dir/" + fileName;
File localFile = new File(path);
file.transferTo(localFile);
}
}
//记录上传该文件后的时间
int finaltime = (int) System.currentTimeMillis();
System.out.println(finaltime - pre);
}
}

return "/success";
}

/******************************************* 向页面输出验证码png ********************************************/
@RequestMapping("/verificationCode")
public void verificationCode(HttpServletResponse response, HttpSession session) throws IOException {
System.out.println("接口开始执行-->verificationCode");

Object[] objs = ImageUtil.createImage();
session.setAttribute("imgCode", objs[0]);

BufferedImage img = (BufferedImage) objs[1];
response.setContentType("image/png");
OutputStream os = response.getOutputStream();
ImageIO.write(img, "png", os);
}

/******************************************* 向客户端提供文件下载 ********************************************/
@RequestMapping("/downloadFile")
public ResponseEntity<byte[]> downloadFile() throws IOException {
System.out.println("接口开始执行-->downloadFile");

File file = new File("C:\\Users\\Administrator\\Desktop\\temp.jpg");

HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", "temp.jpg");
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentLength(file.length());

System.out.println(file.length() + " is length,..");

return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
}
}


做个解释

服务器就基于SSM(SpringMVC+Spring+Mybatis)

新手学习中,本篇未涉及难点和概念部分,即看完能够在项目中使用

如有关于Retrofit和服务端的问题,请留下回复,一起交流
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: