真不是我吹,Spring里这款牛逼的网络工具库我估计你都没用过!(下)

简介: 现如今的 IT 项目,由服务端向外发起网络请求的场景,基本上处处可见! 传统情况下,在服务端代码里访问 http 服务时,我们一般会使用 JDK 的 HttpURLConnection 或者 Apache 的 HttpClient,不过这种方法使用起来太过繁琐,而且 api 使用起来非常的复杂,还得操心资源回收。

使用ResponseEntity<T> responseEntity来接收响应结果。用responseEntity.getBody()获取响应体。

/**
 * 单元测试
 */
@Test
public void testAllGet(){
    //请求地址
    String url = "http://localhost:8080/testGet";
    //发起请求,返回全部信息
    ResponseEntity<ResponseBean> response = restTemplate.getForEntity(url, ResponseBean.class);
    // 获取响应体
    System.out.println("HTTP 响应body:" + response.getBody().toString());
    // 以下是getForEntity比getForObject多出来的内容
    HttpStatus statusCode = response.getStatusCode();
    int statusCodeValue = response.getStatusCodeValue();
    HttpHeaders headers = response.getHeaders();
    System.out.println("HTTP 响应状态:" + statusCode);
    System.out.println("HTTP 响应状态码:" + statusCodeValue);
    System.out.println("HTTP Headers信息:" + headers);
}

3.2、POST 请求

其实POST请求方法和GET请求方法上大同小异,RestTemplatePOST请求也包含两个主要方法:

  • postForObject()
  • postForEntity()

postForEntity()返回全部的信息,postForObject()方法返回body对象,具体使用方法如下!

  • 模拟表单请求,post方法测试
@RestController
public class TestController {
    /**
     * 模拟表单请求,post方法测试
     * @return
     */
    @RequestMapping(value = "testPostByForm", method = RequestMethod.POST)
    public ResponseBean testPostByForm(@RequestParam("userName") String userName,
                                        @RequestParam("userPwd") String userPwd){
        ResponseBean result = new ResponseBean();
        result.setCode("200");
        result.setMsg("请求成功,方法:testPostByForm,请求参数userName:" + userName + ",userPwd:" + userPwd);
        return result;
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 模拟表单提交,post请求
 */
@Test
public void testPostByForm(){
    //请求地址
    String url = "http://localhost:8080/testPostByForm";
    // 请求头设置,x-www-form-urlencoded格式的数据
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    //提交参数设置
    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
    map.add("userName", "唐三藏");
    map.add("userPwd", "123456");
    // 组装请求体
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
    //发起请求
    ResponseBean responseBean = restTemplate.postForObject(url, request, ResponseBean.class);
    System.out.println(responseBean.toString());
}
  • 模拟表单请求,post方法测试(对象接受)
@RestController
public class TestController {
    /**
     * 模拟表单请求,post方法测试
     * @param request
     * @return
     */
    @RequestMapping(value = "testPostByFormAndObj", method = RequestMethod.POST)
    public ResponseBean testPostByForm(RequestBean request){
        ResponseBean result = new ResponseBean();
        result.setCode("200");
        result.setMsg("请求成功,方法:testPostByFormAndObj,请求参数:" + JSON.toJSONString(request));
        return result;
    }
}
public class RequestBean {
    private String userName;
    private String userPwd;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserPwd() {
        return userPwd;
    }
    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 模拟表单提交,post请求
 */
@Test
public void testPostByForm(){
    //请求地址
    String url = "http://localhost:8080/testPostByFormAndObj";
    // 请求头设置,x-www-form-urlencoded格式的数据
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    //提交参数设置
    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
    map.add("userName", "唐三藏");
    map.add("userPwd", "123456");
    // 组装请求体
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
    //发起请求
    ResponseBean responseBean = restTemplate.postForObject(url, request, ResponseBean.class);
    System.out.println(responseBean.toString());
}
  • 模拟 JSON 请求,post 方法测试
@RestController
public class TestController {
    /**
     * 模拟JSON请求,post方法测试
     * @param request
     * @return
     */
    @RequestMapping(value = "testPostByJson", method = RequestMethod.POST)
    public ResponseBean testPostByJson(@RequestBody RequestBean request){
        ResponseBean result = new ResponseBean();
        result.setCode("200");
        result.setMsg("请求成功,方法:testPostByJson,请求参数:" + JSON.toJSONString(request));
        return result;
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 模拟JSON提交,post请求
 */
@Test
public void testPostByJson(){
    //请求地址
    String url = "http://localhost:8080/testPostByJson";
    //入参
    RequestBean request = new RequestBean();
    request.setUserName("唐三藏");
    request.setUserPwd("123456789");
    //发送post请求,并打印结果,以String类型接收响应结果JSON字符串
    ResponseBean responseBean = restTemplate.postForObject(url, request, ResponseBean.class);
    System.out.println(responseBean.toString());
}
  • 模拟页面重定向,post请求
@Controller
public class LoginController {
    /**
     * 重定向
     * @param request
     * @return
     */
    @RequestMapping(value = "testPostByLocation", method = RequestMethod.POST)
    public String testPostByLocation(@RequestBody RequestBean request){
        return "redirect:index.html";
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 重定向,post请求
 */
@Test
public void testPostByLocation(){
    //请求地址
    String url = "http://localhost:8080/testPostByLocation";
    //入参
    RequestBean request = new RequestBean();
    request.setUserName("唐三藏");
    request.setUserPwd("123456789");
    //用于提交完成数据之后的页面跳转,返回跳转url
    URI uri = restTemplate.postForLocation(url, request);
    System.out.println(uri.toString());
}

输出结果如下:

http://localhost:8080/index.html

3.3、PUT 请求

put请求方法,可能很多人都没用过,它指的是修改一个已经存在的资源或者插入资源,该方法会向URL代表的资源发送一个HTTP PUT方法请求,示例如下!

@RestController
public class TestController {
    /**
     * 模拟JSON请求,put方法测试
     * @param request
     * @return
     */
    @RequestMapping(value = "testPutByJson", method = RequestMethod.PUT)
    public void testPutByJson(@RequestBody RequestBean request){
        System.out.println("请求成功,方法:testPutByJson,请求参数:" + JSON.toJSONString(request));
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 模拟JSON提交,put请求
 */
@Test
public void testPutByJson(){
    //请求地址
    String url = "http://localhost:8080/testPutByJson";
    //入参
    RequestBean request = new RequestBean();
    request.setUserName("唐三藏");
    request.setUserPwd("123456789");
    //模拟JSON提交,put请求
    restTemplate.put(url, request);
}

3.4、DELETE 请求

与之对应的还有delete方法协议,表示删除一个已经存在的资源,该方法会向URL代表的资源发送一个HTTP DELETE方法请求。

@RestController
public class TestController {
    /**
     * 模拟JSON请求,delete方法测试
     * @return
     */
    @RequestMapping(value = "testDeleteByJson", method = RequestMethod.DELETE)
    public void testDeleteByJson(){
        System.out.println("请求成功,方法:testDeleteByJson");
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 模拟JSON提交,delete请求
 */
@Test
public void testDeleteByJson(){
    //请求地址
    String url = "http://localhost:8080/testDeleteByJson";
    //模拟JSON提交,delete请求
    restTemplate.delete(url);
}

3.5、通用请求方法 exchange 方法

如果以上方法还不满足你的要求。在RestTemplate工具类里面,还有一个exchange通用协议请求方法,它可以发送GETPOSTDELETEPUTOPTIONSPATCH等等HTTP方法请求。

打开源码,我们可以很清晰的看到这一点。

4.jpg5.jpg

采用exchange方法,可以满足各种场景下的请求操作!

3.6、文件上传与下载

除了经常用到的getpost请求以外,还有一个我们经常会碰到的场景,那就是文件的上传与下载,如果采用RestTemplate,该怎么使用呢?

案例如下,具体实现细节参考代码注释!

  • 文件上传
@RestController
public class FileUploadController {
    private static final String UPLOAD_PATH = "/springboot-frame-example/springboot-example-resttemplate/";
    /**
     * 文件上传
     * @param uploadFile
     * @return
     */
    @RequestMapping(value = "upload", method = RequestMethod.POST)
    public ResponseBean upload(@RequestParam("uploadFile") MultipartFile uploadFile,
                               @RequestParam("userName") String userName) {
        // 在 uploadPath 文件夹中通过用户名对上传的文件归类保存
        File folder = new File(UPLOAD_PATH + userName);
        if (!folder.isDirectory()) {
            folder.mkdirs();
        }
        // 对上传的文件重命名,避免文件重名
        String oldName = uploadFile.getOriginalFilename();
        String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
        //定义返回视图
        ResponseBean result = new ResponseBean();
        try {
            // 文件保存
            uploadFile.transferTo(new File(folder, newName));
            result.setCode("200");
            result.setMsg("文件上传成功,方法:upload,文件名:" + newName);
        } catch (IOException e) {
            e.printStackTrace();
            result.setCode("500");
            result.setMsg("文件上传失败,方法:upload,请求文件:" + oldName);
        }
        return result;
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 文件上传,post请求
 */
@Test
public void upload(){
    //需要上传的文件
    String filePath = "/Users/panzhi/Desktop/Jietu20220205-194655.jpg";
    //请求地址
    String url = "http://localhost:8080/upload";
    // 请求头设置,multipart/form-data格式的数据
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
    //提交参数设置
    MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
    param.add("uploadFile", new FileSystemResource(new File(filePath)));
    //服务端如果接受额外参数,可以传递
    param.add("userName", "张三");
    // 组装请求体
    HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(param, headers);
    //发起请求
    ResponseBean responseBean = restTemplate.postForObject(url, request, ResponseBean.class);
    System.out.println(responseBean.toString());
}
  • 文件下载
@RestController
public class FileUploadController {
    private static final String UPLOAD_PATH = "springboot-frame-example/springboot-example-resttemplate/";
    /**
     * 带参的get请求(restful风格)
     * @return
     */
    @RequestMapping(value = "downloadFile/{userName}/{fileName}", method = RequestMethod.GET)
    public void downloadFile(@PathVariable(value = "userName") String userName,
                             @PathVariable(value = "fileName") String fileName,
                             HttpServletRequest request,
                             HttpServletResponse response) throws Exception {
        File file = new File(UPLOAD_PATH + userName + File.separator + fileName);
        if (file.exists()) {
            //获取文件流
            FileInputStream fis = new FileInputStream(file);
            //获取文件后缀(.png)
            String extendFileName = fileName.substring(fileName.lastIndexOf('.'));
            //动态设置响应类型,根据前台传递文件类型设置响应类型
            response.setContentType(request.getSession().getServletContext().getMimeType(extendFileName));
            //设置响应头,attachment表示以附件的形式下载,inline表示在线打开
            response.setHeader("content-disposition","attachment;fileName=" + URLEncoder.encode(fileName,"UTF-8"));
            //获取输出流对象(用于写文件)
            OutputStream os = response.getOutputStream();
            //下载文件,使用spring框架中的FileCopyUtils工具
            FileCopyUtils.copy(fis,os);
        }
    }
}
@Autowired
private RestTemplate restTemplate;
/**
 * 小文件下载
 * @throws IOException
 */
@Test
public void downloadFile() throws IOException {
    String userName = "张三";
    String fileName = "c98b677c-0948-46ef-84d2-3742a2b821b0.jpg";
    //请求地址
    String url = "http://localhost:8080/downloadFile/{1}/{2}";
    //发起请求,直接返回对象(restful风格)
    ResponseEntity<byte[]> rsp = restTemplate.getForEntity(url, byte[].class, userName,fileName);
    System.out.println("文件下载请求结果状态码:" + rsp.getStatusCode());
    // 将下载下来的文件内容保存到本地
    String targetPath = "/Users/panzhi/Desktop/"  + fileName;
    Files.write(Paths.get(targetPath), Objects.requireNonNull(rsp.getBody(), "未获取到下载文件"));
}

这种下载方法实际上是将下载文件一次性加载到客户端本地内存,然后从内存将文件写入磁盘。这种方式对于小文件的下载还比较适合,如果文件比较大或者文件下载并发量比较大,容易造成内存的大量占用,从而降低应用的运行效率。

  • 大文件下载
@Autowired
private RestTemplate restTemplate;
/**
 * 大文件下载
 * @throws IOException
 */
@Test
public void downloadBigFile() throws IOException {
    String userName = "张三";
    String fileName = "c98b677c-0948-46ef-84d2-3742a2b821b0.jpg";
    //请求地址
    String url = "http://localhost:8080/downloadFile/{1}/{2}";
    //定义请求头的接收类型
    RequestCallback requestCallback = request -> request.getHeaders()
            .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
    //对响应进行流式处理而不是将其全部加载到内存中
    String targetPath = "/Users/panzhi/Desktop/"  + fileName;
    restTemplate.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
        Files.copy(clientHttpResponse.getBody(), Paths.get(targetPath));
        return null;
    }, userName, fileName);
}

这种下载方式的区别在于:

  • 设置了请求头APPLICATION_OCTET_STREAM,表示以流的形式进行数据加载
  • RequestCallback结合File.copy保证了接收到一部分文件内容,就向磁盘写入一部分内容。而不是全部加载到内存,最后再写入磁盘文件。

在下载大文件时,例如excelpdfzip等等文件,特别管用,

四、小结

通过本章的讲解,想必读者初步的了解了如何使用RestTemplate方便快捷的访问restful接口。其实RestTemplate的功能非常强大,作者也仅仅学了点皮毛。如果大家觉得本文有什么地方没写清楚的或者有其他什么想要了解的可以在下方留言,我后续会尽量在文中进行补充完善!

相关文章
|
5天前
|
安全 Linux 网络安全
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息。本文分三部分介绍 nmap:基本原理、使用方法及技巧、实际应用及案例分析。通过学习 nmap,您可以更好地了解网络拓扑和安全状况,提升网络安全管理和渗透测试能力。
30 5
|
2月前
|
JavaScript 前端开发 API
网络请求库 – axios库
网络请求库 – axios库
197 60
|
25天前
|
网络协议 安全 Linux
网络工具ping的使用方式
【10月更文挑战第19天】网络工具ping的使用方式
45 6
|
1月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
413 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
1月前
|
监控 Java 对象存储
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
43 1
|
2月前
|
Java 应用服务中间件 Spring
IDEA 工具 启动 spring boot 的 main 方法报错。已解决
IDEA 工具 启动 spring boot 的 main 方法报错。已解决
|
2月前
|
数据采集 JSON API
🎓Python网络请求新手指南:requests库带你轻松玩转HTTP协议
本文介绍Python网络编程中不可或缺的HTTP协议基础,并以requests库为例,详细讲解如何执行GET与POST请求、处理响应及自定义请求头等操作。通过简洁易懂的代码示例,帮助初学者快速掌握网络爬虫与API开发所需的关键技能。无论是安装配置还是会话管理,requests库均提供了强大而直观的接口,助力读者轻松应对各类网络编程任务。
116 3
|
2月前
|
机器学习/深度学习 JSON API
HTTP协议实战演练场:Python requests库助你成为网络数据抓取大师
在数据驱动的时代,网络数据抓取对于数据分析、机器学习等至关重要。HTTP协议作为互联网通信的基石,其重要性不言而喻。Python的`requests`库凭借简洁的API和强大的功能,成为网络数据抓取的利器。本文将通过实战演练展示如何使用`requests`库进行数据抓取,包括发送GET/POST请求、处理JSON响应及添加自定义请求头等。首先,请确保已安装`requests`库,可通过`pip install requests`进行安装。接下来,我们将逐一介绍如何利用`requests`库探索网络世界,助你成为数据抓取大师。在实践过程中,务必遵守相关法律法规和网站使用条款,做到技术与道德并重。
52 2
|
2月前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
在网络数据的海洋中,网络爬虫遵循HTTP协议,穿梭于互联网各处,收集宝贵信息。本文将从零开始,使用Python的requests库,深入解析HTTP协议,助你构建自己的网络爬虫帝国。首先介绍HTTP协议基础,包括请求与响应结构;然后详细介绍requests库的安装与使用,演示如何发送GET和POST请求并处理响应;最后概述爬虫构建流程及挑战,帮助你逐步掌握核心技术,畅游数据海洋。
67 3
|
2月前
|
数据采集 网络协议 API
HTTP协议大揭秘!Python requests库实战,让网络请求变得简单高效
【9月更文挑战第13天】在数字化时代,互联网成为信息传输的核心平台,HTTP协议作为基石,定义了客户端与服务器间的数据传输规则。直接处理HTTP请求复杂繁琐,但Python的`requests`库提供了一个简洁强大的接口,简化了这一过程。HTTP协议采用请求与响应模式,无状态且结构化设计,使其能灵活处理各种数据交换。
79 8