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

版权声明:本文为博主原创文章,如需转载请声明作者信息,谢谢。 https://blog.csdn.net/itCatface/article/details/78903304

一直用OkHttp感觉也没什么毛病,空闲时间看看Retrofit怎么使用
本篇仅介绍最基本的Retrofit用法,如有错误请提出,我会虚心请教并改正,谢谢

一、接口

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

  1. 开门见山贴代码

    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)
  2. 做个解释

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

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

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

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

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

二、具体的请求

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

  1. 代码贴上

    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
            }
        }
    }
  2. 做个解释

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

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

三、服务端

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

  1. 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);
        }
    }
  2. 做个解释

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

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

    3. 如有关于Retrofit和服务端的问题,请留下回复,一起交流

猜你喜欢

转载自blog.csdn.net/itCatface/article/details/78903304