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());
    }
}
生成的文件及其內(nèi)容.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();
        }
    }

}

啟動項(xiàng)目孝冒,在瀏覽器中訪問:localhost:8060/file/1524895173355

三洋幻、與前端并行工作

1.使用swagger自動生成html文檔

通過該文檔可以把寫的RESTfulAPI向前端描述清楚
根據(jù)代碼自動生成文檔;
改過代碼之后队秩,也可以自動更新文檔笑旺,而不用手動再去修改文檔

第一步:添加依賴:

Springfox Swagger2:掃描文件,生成文檔數(shù)據(jù)

<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";
    }

}

啟動項(xiàng)目馍资,訪問localhost:8060/swagger-ui.html
頁面列出了系統(tǒng)所有的Controller和endpoint

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

點(diǎn)擊try it out真正分發(fā)出請求:

tryitout.png

但是對于每個字段筒主,文檔中并沒能給出具體的含義,可以通過注解來達(dá)到此要求:

①描述方法:@ApiOperation(value="用戶查詢服務(wù)")

該value會默認(rèn)替換成方法名

②參數(shù)描述:

第一種情況:當(dāng)參數(shù)為一個對象時:在對象相應(yīng)的屬性上添加注解@ApiModelProperty(value=""):

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

第二種情況:參數(shù)直接是基本數(shù)據(jù)類型鸟蟹,沒有封裝對象乌妙,使用@ApiParam(""):

@GetMapping("/{id:\\d+}")
@JsonView(User.UserDetailView.class)
public User getInfo(@ApiParam("用戶id") @PathVariable String id) {
    //throw new UserNotExistException(id);
    System.out.println("進(jìn)入getInfo服務(wù)");
    User user = new User();
    user.setUsername("tom");
    return user;
}
通過使用注解描述方法和參數(shù).png

2.使用WireMock快速偽造RESTful服務(wù)

WireMock實(shí)際上是一個獨(dú)立的服務(wù)器,通過他的客戶端寫一些代碼來編輯該服務(wù)器建钥,告訴服務(wù)器收到什么請求返回什么響應(yīng)藤韵;可以隨時通過客戶端代碼和api改變服務(wù)器的行為,服務(wù)器一直運(yùn)行熊经,不需要重啟泽艘,不需要反復(fù)部署欲险。

使用wiremock服務(wù)器.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;

//該類是一個客戶端匹涮,要連接后臺啟動的服務(wù)器
public class MockServer {

    public static void main(String[] args) {
        //告訴服務(wù)器天试,如何處理外界的請求
        //指明服務(wù)器的位置
        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可以得到對應(yīng)的結(jié)果:

{"id":1}

對代碼進(jìn)行重構(gòu):

把json單獨(dú)拿出去:

把json單獨(dú)寫進(jìn)一個文件里.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;

//該類是一個客戶端然低,要連接后臺啟動的服務(wù)器
public class MockServer {

    public static void main(String[] args) throws Exception{
        //告訴服務(wù)器喜每,如何處理外界的請求
        //指明服務(wù)器的位置
        WireMock.configureFor(8062);//此處在本地,所以不需要再指定ip了
        WireMock.removeAllMappings();//把之前的配置都清空
        
        mock("/order/1","01");
        //加其服務(wù)
        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"

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脚翘,一起剝皮案震驚了整個濱河市灼卢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌来农,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件崇堰,死亡現(xiàn)場離奇詭異沃于,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)海诲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門繁莹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人特幔,你說我怎么就攤上這事咨演。” “怎么了蚯斯?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵薄风,是天一觀的道長。 經(jīng)常有香客問我拍嵌,道長遭赂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任横辆,我火速辦了婚禮撇他,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狈蚤。我一直安慰自己困肩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布脆侮。 她就那樣靜靜地躺著锌畸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪他嚷。 梳的紋絲不亂的頭發(fā)上蹋绽,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天芭毙,我揣著相機(jī)與錄音,去河邊找鬼卸耘。 笑死退敦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚣抗。 我是一名探鬼主播侈百,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼翰铡!你這毒婦竟也來了钝域?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锭魔,失蹤者是張志新(化名)和其女友劉穎例证,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迷捧,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡织咧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了漠秋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笙蒙。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖庆锦,靈堂內(nèi)的尸體忽然破棺而出捅位,到底是詐尸還是另有隱情,我是刑警寧澤搂抒,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布艇搀,位于F島的核電站,受9級特大地震影響燕耿,放射性物質(zhì)發(fā)生泄漏中符。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一誉帅、第九天 我趴在偏房一處隱蔽的房頂上張望淀散。 院中可真熱鬧,春花似錦蚜锨、人聲如沸档插。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郭膛。三九已至,卻和暖如春氛悬,著一層夾襖步出監(jiān)牢的瞬間则剃,已是汗流浹背耘柱。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棍现,地道東北人调煎。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像己肮,于是被迫代替她去往敵國和親士袄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理谎僻,服務(wù)發(fā)現(xiàn)娄柳,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,815評論 6 342
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,144評論 25 707
  • 記憶…… 我和同齡的千萬個人一起在世界上存在了20年艘绍, 如果我沒有一份屬于自己的記憶赤拒, 那么我和別人有什么不同? ...
    纖羽若麟小亭子閱讀 223評論 0 0
  • 我是一個普普通通的人鞍盗,接觸的也是普通人需了,普通事兒。 我家附近有個嫂子般甲,長的白白胖胖,眼睛不大鹅颊,個子不高敷存,嗓音特別亮...
    溫暖鞍山閱讀 278評論 0 0