Swagger 是一個規范和完整的框架,用於生成、描述、調用和可視化 RESTful 風格的 Web 服務。總體目標是使客戶端和文件系統作為服務器以同樣的速度來更新。文件的方法,參數和模型緊密集成到服務器端的代碼,允許API來始終保持同步。Swagger 讓部署管理和使用功能強大的API從未如此簡單。
更多關於Swagger的作用,相信大家百度一下能了解的更全面,本文以SpringBoot中集成Swagger為例做介紹說明。
一、修改pom.xml,添加maven依賴
<!-- Swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.6.1</version> </dependency>
二、添加Swagger配置類
package com.example.swaggerdemo; import static com.google.common.base.Predicates.or; import static springfox.documentation.builders.PathSelectors.regex; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.async.DeferredResult; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * SwaggerConfig */ @Configuration @EnableSwagger2 public class SwaggerConfig { /** * SpringBoot默認已經將classpath:/META-INF/resources/和classpath:/META-INF/resources/webjars/映射 * 所以該方法不需要重寫,如果在SpringMVC中,可能需要重寫定義(我沒有嘗試) * 重寫該方法需要 extends WebMvcConfigurerAdapter * */ // @Override // public void addResourceHandlers(ResourceHandlerRegistry registry) { // registry.addResourceHandler("swagger-ui.html") // .addResourceLocations("classpath:/META-INF/resources/"); // // registry.addResourceHandler("/webjars/**") // .addResourceLocations("classpath:/META-INF/resources/webjars/"); // } /** * 可以定義多個組,比如本類中定義把test和demo區分開了 * (訪問頁面就可以看到效果了) * */ @Bean public Docket testApi() { return new Docket(DocumentationType.SWAGGER_2) .groupName("test") .genericModelSubstitutes(DeferredResult.class) // .genericModelSubstitutes(ResponseEntity.class) .useDefaultResponseMessages(false) .forCodeGeneration(true) .pathMapping("/")// base,最終調用接口后會和paths拼接在一起 .select() .paths(or(regex("/api/.*")))//過濾的接口 .build() .apiInfo(testApiInfo()); } @Bean public Docket demoApi() { return new Docket(DocumentationType.SWAGGER_2) .groupName("demo") .genericModelSubstitutes(DeferredResult.class) // .genericModelSubstitutes(ResponseEntity.class) .useDefaultResponseMessages(false) .forCodeGeneration(false) .pathMapping("/") .select() .paths(or(regex("/demo/.*")))//過濾的接口 .build() .apiInfo(demoApiInfo()); } private ApiInfo testApiInfo() { return new ApiInfoBuilder() .title("Electronic Health Record(EHR) Platform API")//大標題 .description("EHR Platform's REST API, all the applications could access the Object model data via JSON.")//詳細描述 .version("1.0")//版本 .termsOfServiceUrl("NO terms of service") .contact(new Contact("小單", "http://blog.csdn.net/catoop", "365384722@qq.com"))//作者 .license("The Apache License, Version 2.0") .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html") .build(); } private ApiInfo demoApiInfo() { return new ApiInfoBuilder() .title("Electronic Health Record(EHR) Platform API")//大標題 .description("EHR Platform's REST API, all the applications could access the Object model data via JSON.")//詳細描述 .version("1.0")//版本 .termsOfServiceUrl("NO terms of service") .contact(new Contact("小單", "http://blog.csdn.net/catoop", "365384722@qq.com"))//作者 .license("The Apache License, Version 2.0") .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html") .build(); return apiInfo; } }
經過這2步配置后,我們啟動服務后,訪問:http://localhost:8080/swagger-ui.html 就完成了集成。
Swagger會默認把所有Controller中的RequestMapping方法都生成API出來,實際上我們一般只需要標准接口的(像返回頁面的那種Controller方法我們並不需要),所有你可以按下面的方法來設定要生成API的方法的要求。
如下我針對RestController注解的類和ResponseBody注解的方法才生成Swaager的API,並且排除了特定的類,代碼如下:
@Configuration @EnableSwagger2 // 啟用 Swagger public class SwaggerConfig { @Bean public Docket createRestApi() { Predicate<RequestHandler> predicate = new Predicate<RequestHandler>() { @Override public boolean apply(RequestHandler input) { Class<?> declaringClass = input.declaringClass(); if (declaringClass == BasicErrorController.class)// 排除 return false; if(declaringClass.isAnnotationPresent(RestController.class)) // 被注解的類 return true; if(input.isAnnotatedWith(ResponseBody.class)) // 被注解的方法 return true; return false; } }; return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .useDefaultResponseMessages(false) .select() .apis(predicate) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("包含媒體、咨詢、搜索引擎關鍵字、廣告等類型接口的服務")//大標題 .version("1.0")//版本 .build(); }
三、常見swagger注解一覽與使用
最常用的5個注解
@Api:修飾整個類,描述Controller的作用 @ApiOperation:描述一個類的一個方法,或者說一個接口 @ApiParam:單個參數描述 @ApiModel:用對象來接收參數 @ApiProperty:用對象接收參數時,描述對象的一個字段
其它若干
@ApiResponse:HTTP響應其中1個描述 @ApiResponses:HTTP響應整體描述 @ApiIgnore:使用該注解忽略這個API @ApiClass @ApiError @ApiErrors @ApiParamImplicit @ApiParamsImplicit
下面創建2個Controller來測試:
1、TestController.java
@Controller @RequestMapping("/api/test") public class TestController { @ResponseBody @RequestMapping(value = "/show", method=RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)// 這里指定RequestMethod,如果不指定Swagger會把所有RequestMethod都輸出,在實際應用中,具體指定請求類型也使接口更為嚴謹。 @ApiOperation(value="測試接口", notes="測試接口詳細描述") public String show( @ApiParam(required=true, name="name", value="姓名") @RequestParam(name = "name", required=true) String stuName){ return "success"; } }
2、DemoController.java
/** * DemoController * */ @Controller @RequestMapping(value = "/demo") public class DemoController { private Logger logger = LoggerFactory.getLogger(DemoController.class); /** * 可以直接使用@ResponseBody響應JSON * * @param request * @param response * @return */ @ResponseBody @RequestMapping(value = "/getcount", method = RequestMethod.POST) @ApiOperation(value="測試-getCount", notes="getCount更多說明") public ModelMap getCount(HttpServletRequest request, HttpServletResponse response) { logger.info(">>>>>>>> begin getCount >>>>>>>>"); ModelMap map = new ModelMap(); map.addAttribute("count", 158); // 后台獲取的國際化信息 map.addAttribute("xstest", "測試"); return map; } /** * 可以直接使用@ResponseBody響應JSON * * @param request * @param response * @return */ @ApiIgnore//使用該注解忽略這個API @ResponseBody @RequestMapping(value = "/jsonTest1", method = RequestMethod.POST) public ModelMap jsonTest(HttpServletRequest request, HttpServletResponse response) { ModelMap map = new ModelMap(); map.addAttribute("hello", "你好"); map.addAttribute("veryGood", "很好"); return map; } /** * 可以直接使用@ResponseBody響應JSON * * @param request * @param response * @return */ @ResponseBody @RequestMapping(value = "/jsonTest3", method = RequestMethod.POST) public List<String> jsonTest3(HttpServletRequest request, HttpServletResponse response) { List<String> list = new ArrayList<String>(); list.add("hello"); list.add("你好"); return list; } /** * JSON請求一個對象<br/> * (Ajax Post Data:{"name":"名稱","content":"內容"}) * * @param version * @return */ @ResponseBody @RequestMapping(value = "/jsonTest2", method = RequestMethod.POST) public ModelMap jsonTest2(@RequestBody Demo demo) { logger.info("demoName:" + demo.getName()); logger.info("demoContent:" + demo.getContent()); ModelMap map = new ModelMap(); map.addAttribute("result", "ok"); return map; } /** * 直接讀取URL參數值<br/> * /demo/jsonTest6.do?name=Hello&content=World * * @param demoName * @param content * @return */ @ResponseBody @RequestMapping(value = "/jsonTest6", method = RequestMethod.POST) public ModelMap jsonTest6(@RequestParam("name") String demoName, @RequestParam String content) { logger.info("demoName:" + demoName); ModelMap map = new ModelMap(); map.addAttribute("name",demoName + "AAA"); map.addAttribute("content",content + "BBB"); map.addAttribute("date",new java.util.Date()); return map; } /** * JSON請求一個對象,將RequestBody自動轉換為JSONObject對象<br/> * (Ajax Post Data:{"name":"名稱","content":"內容"}) * * 使用JSONObject請添加依賴 * <dependency> * <groupId>net.sf.json-lib</groupId> * <artifactId>json-lib</artifactId> * <version>2.4</version> * <!--指定jdk版本 --> * <classifier>jdk15</classifier> * </dependency> * * @param version * @return */ @ResponseBody @RequestMapping(value = "/jsonTest5", method = RequestMethod.POST) public ModelMap jsonTest5(@RequestBody JSONObject jsonObject) { String name = jsonObject.getString("name"); logger.info("demoName:" + name); ModelMap map = new ModelMap(); map.addAttribute("demoName",name); return map; } /** * 輸入 和輸出為JSON格式的數據的方式 HttpEntity<?> ResponseEntity<?> * * @param u * @return */ @ResponseBody @RequestMapping(value = "/jsonTest4", method = RequestMethod.POST) public ResponseEntity<String> jsonTest4(HttpEntity<Demo> demo, HttpServletRequest request, HttpSession session) { //獲取Headers方法 HttpHeaders headers = demo.getHeaders(); // 獲取內容 String demoContent = demo.getBody().getContent(); // 這里直接new一個對象(HttpHeaders headers = new HttpHeaders();) HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add("MyHeaderName", "SHANHY"); ResponseEntity<String> responseResult = new ResponseEntity<String>( demoContent, responseHeaders, HttpStatus.OK); return responseResult; } }
Swagger2默認將所有的Controller中的RequestMapping方法都會暴露,然而在實際開發中,我們並不一定需要把所有API都提現在文檔中查看,這種情況下,使用注解@ApiIgnore來解決,如果應用在Controller范圍上,則當前Controller中的所有方法都會被忽略,如果應用在方法上,則對應用的方法忽略暴露API。
注解@ApiOperation和@ApiParam可以理解為API說明,多動手嘗試就很容易理解了。
如果我們不使用這樣注解進行說明,Swagger2也是有默認值的,沒什么可說的試試就知道了。
在 http://localhost:8080/swagger-ui.html 顯示頁面的右上角有api_key ,springfox-swagger 2.2.2 版本並沒有進行處理,我們可以自己添加攔截器攔截 /v2/api-docs 來處理我們API文檔的訪問權限,如果要更嚴格更靈活的控制,可能需要修改源碼來實現了。相信 springfox-swagger 的后期版本應該會支持更全面的應用需求的。
引自 http://blog.csdn.net/catoop/article/details/50668896