单元测试:
//模拟上传文件
@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();
}
}
}
启动项目,在浏览器中访问:localhost:8060/file/1524895173355
通过该文档可以把写的RESTfulAPI向前端描述清楚
根据代码自动生成文档;
改过代码之后,也可以自动更新文档,而不用手动再去修改文档
第一步:添加依赖:
Springfox Swagger2:扫描文件,生成文档数据
io.springfox
springfox-swagger2
2.7.0
Springfox Swagger UI:生成最终看到的可视化界面
io.springfox
springfox-swagger-ui
2.7.0
第二步:在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
点击try it out真正分发出请求:
但是对于每个字段,文档中并没能给出具体的含义,可以通过注解来达到此要求:
①描述方法:@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;
}
WireMock实际上是一个独立的服务器,通过他的客户端写一些代码来编辑该服务器,告诉服务器收到什么请求返回什么响应;可以随时通过客户端代码和api改变服务器的行为,服务器一直运行,不需要重启,不需要反复部署。
①下载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依赖:
com.github.tomakehurst
wiremock
2.5.1
编写代码:
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单独拿出去:
修改代码:
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"
}