SpringBoot中文件上传与下载&swagger的使用

SpringBoot中文件上传与下载&swagger的使用

一、文件上传

单元测试:

//模拟上传文件
@Test
public void whenUploadSuccess() throws Exception {
    String result = mockMvc.perform(fileUpload("/file")
            .file(new MockMultipartFile("file","test.txt","multipart/form-data","hello upload".getBytes("UTF-8"))))
            .andExpect(status().isOk())
            .andReturn().getResponse().getContentAsString();
    System.out.println(result);
    //{"path":"D:\\WorkSpaces\\stsWS\\hcx-security-demo\\src\\main\\java\\com\\hcx\\web\\controller\\1524895173355.txt"}
}

Controller:

@RestController
@RequestMapping("/file")
public class FileController {
    
    @PostMapping
    public FileInfo upload(MultipartFile file) throws Exception{
        
        System.out.println(file.getName());//file
        System.out.println(file.getOriginalFilename());//test.txt
        System.out.println(file.getSize());//12
        String folder = "D:\\WorkSpaces\\stsWS\\hcx-security-demo\\src\\main\\java\\com\\hcx\\web\\controller";
        File localFile = new File(folder,new Date().getTime()+".txt");
        file.transferTo(localFile);
        return new FileInfo(localFile.getAbsolutePath());
    }
}
生成的文件及其内容.png

二、文件下载

package com.hcx.web.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.hcx.web.dto.FileInfo;

@RestController
@RequestMapping("/file")
public class FileController {
    
    private String folder = "D:\\\\WorkSpaces\\\\stsWS\\\\hcx-security-demo\\\\src\\\\main\\\\java\\\\com\\\\hcx\\\\web\\\\controller";
    
    @PostMapping
    public FileInfo upload(MultipartFile file) throws Exception{
        
        System.out.println(file.getName());//file
        System.out.println(file.getOriginalFilename());//test.txt
        System.out.println(file.getSize());//12
        String folder = "D:\\WorkSpaces\\stsWS\\hcx-security-demo\\src\\main\\java\\com\\hcx\\web\\controller";
        File localFile = new File(folder,new Date().getTime()+".txt");
        file.transferTo(localFile);
        return new FileInfo(localFile.getAbsolutePath());
        
    }
    
    @GetMapping("/{id}")
    public void download(@PathVariable String id,HttpServletRequest request,HttpServletResponse response) throws Exception{
        try(
        InputStream inputStream = new FileInputStream(new File(folder,id+".txt"));
        OutputStream outputStream = response.getOutputStream();){
            response.setContentType("application/x-download");
            response.addHeader("Content-Disposition", "attachment;filename=test.txt");
            
            IOUtils.copy(inputStream, outputStream);
            outputStream.flush();
        }
    }

}

启动项目,在浏览器中访问:localhost:8060/file/1524895173355

三、与前端并行工作

1.使用swagger自动生成html文档

通过该文档可以把写的RESTfulAPI向前端描述清楚
根据代码自动生成文档;
改过代码之后,也可以自动更新文档,而不用手动再去修改文档

第一步:添加依赖:

Springfox Swagger2:扫描文件,生成文档数据

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>

Springfox Swagger UI:生成最终看到的可视化界面

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

第二步:在DemoApplication启动类中添加注解:@EnableSwagger2

@SpringBootApplication
@RestController
@EnableSwagger2
public class DemoApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    
    @GetMapping("/hello")
    public String hello() {
        return "hello spring security";
    }

}

启动项目,访问localhost:8060/swagger-ui.html
页面列出了系统所有的Controller和endpoint

swagger-ui.png
swagger接口示例.png
swagger接口示例.png

点击try it out真正分发出请求:

tryitout.png

但是对于每个字段,文档中并没能给出具体的含义,可以通过注解来达到此要求:

①描述方法:@ApiOperation(value="用户查询服务")

该value会默认替换成方法名

②参数描述:

第一种情况:当参数为一个对象时:在对象相应的属性上添加注解@ApiModelProperty(value=""):

public class UserQueryCondition {
    private String username;
    @ApiModelProperty(value="用户年龄起始值")
    private int age;
    @ApiModelProperty(value="用户年龄终止值")
    private int ageTo;
    
    private String weight;
}

第二种情况:参数直接是基本数据类型,没有封装对象,使用@ApiParam(""):

@GetMapping("/{id:\\d+}")
@JsonView(User.UserDetailView.class)
public User getInfo(@ApiParam("用户id") @PathVariable String id) {
    //throw new UserNotExistException(id);
    System.out.println("进入getInfo服务");
    User user = new User();
    user.setUsername("tom");
    return user;
}
通过使用注解描述方法和参数.png

2.使用WireMock快速伪造RESTful服务

WireMock实际上是一个独立的服务器,通过他的客户端写一些代码来编辑该服务器,告诉服务器收到什么请求返回什么响应;可以随时通过客户端代码和api改变服务器的行为,服务器一直运行,不需要重启,不需要反复部署。

使用wiremock服务器.png

①下载wiremock:http://wiremock.org/docs/running-standalone/

下载wiremock.png

②启动wiremock:使用命令$ java -jar wiremock-standalone-2.17.0.jar

注:在Windows上是不需要$这个的,直接是java -jar wiremock-standalone-2.17.0.jar

wiremock启动界面.png

③添加wiremock依赖:

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock</artifactId>
    <version>2.5.1</version>
</dependency>

编写代码:

package com.hcx.web.wiremock;

import com.github.tomakehurst.wiremock.client.WireMock;

//该类是一个客户端,要连接后台启动的服务器
public class MockServer {

    public static void main(String[] args) {
        //告诉服务器,如何处理外界的请求
        //指明服务器的位置
        WireMock.configureFor(8062);//此处在本地,所以不需要再指定ip了
        WireMock.removeAllMappings();//把之前的配置都清空
        
        //伪造一个测试桩
        WireMock.stubFor(WireMock.get(WireMock.urlEqualTo("/order/1"))
                .willReturn(WireMock.aResponse().withBody("{\"id\":1}")
                        .withStatus(200)));
        
    }
}

此时访问浏览器localhost:8062/order/1可以得到对应的结果:

{"id":1}

对代码进行重构:

把json单独拿出去:

把json单独写进一个文件里.png

修改代码:

package com.hcx.web.wiremock;

import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.ClassPathResource;

import com.github.tomakehurst.wiremock.client.WireMock;

//该类是一个客户端,要连接后台启动的服务器
public class MockServer {

    public static void main(String[] args) throws Exception{
        //告诉服务器,如何处理外界的请求
        //指明服务器的位置
        WireMock.configureFor(8062);//此处在本地,所以不需要再指定ip了
        WireMock.removeAllMappings();//把之前的配置都清空
        
        mock("/order/1","01");
        //加其服务
        mock("/order/2","02");
        
    }
    
    public static void mock(String url,String file) throws IOException {
        ClassPathResource resource = new ClassPathResource("mock/response/"+file+".txt");
        String content = StringUtils.join(FileUtils.readLines(resource.getFile(),"UTF-8").toArray(),"\n");
//              FileUtils.readFileToString(resource.getFile());
        //伪造一个测试桩
        WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(url))
                .willReturn(WireMock.aResponse().withBody(content)
                        .withStatus(200)));
    }
}

01.txt:

{
    "id":1,
    "type":"A"

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,087评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,292评论 6 344
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • 记忆…… 我和同龄的千万个人一起在世界上存在了20年, 如果我没有一份属于自己的记忆, 那么我和别人有什么不同? ...
    纤羽若麟小亭子阅读 187评论 0 0
  • 我是一个普普通通的人,接触的也是普通人,普通事儿。 我家附近有个嫂子,长的白白胖胖,眼睛不大,个子不高,嗓音特别亮...
    温暖鞍山阅读 273评论 0 0