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());
}
}
二哎甲、文件下載
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
點(diǎn)擊try it out真正分發(fā)出請求:
但是對于每個字段筒主,文檔中并沒能給出具體的含義,可以通過注解來達(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;
}
2.使用WireMock快速偽造RESTful服務(wù)
WireMock實(shí)際上是一個獨(dú)立的服務(wù)器,通過他的客戶端寫一些代碼來編輯該服務(wù)器建钥,告訴服務(wù)器收到什么請求返回什么響應(yīng)藤韵;可以隨時通過客戶端代碼和api改變服務(wù)器的行為,服務(wù)器一直運(yùn)行熊经,不需要重啟泽艘,不需要反復(fù)部署欲险。
①下載wiremock:http://wiremock.org/docs/running-standalone/
②啟動wiremock:使用命令$ java -jar wiremock-standalone-2.17.0.jar
注:在Windows上是不需要$這個的,直接是java -jar wiremock-standalone-2.17.0.jar
③添加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ú)拿出去:
修改代碼:
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"
}