一, 文件上传
单元测试:
- // 模拟上传文件
- @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"
- }
来源: http://www.jianshu.com/p/6288d49796d2