剛學java不久,我有個疑問,為何用到的各種java開源jar包許多都是阿里巴巴的開源項目,為何幾乎很少見百度和騰訊?不是說好的BAT嗎?
Spring Boot 的配置文件及多環境配置
Spring Boot 使用一個全局的配置文件 application.properties 或 application.yml,放置在 src/main/resources 目錄或者類路徑的 /config 下。
Spring Boot 的全局配置文件的作用是對一些默認配置的配置值進行修改。
例如將 Tomcat 的默認端口號 8080 修改為 8082,並將默認的訪問路徑 “/” 修改為 “/boot”。可以在 application.yml 中添加:
server:
port: 8082
context-path: /boot
如果我們需要在不同的環境下面有不同的配置怎么辦?比如生產、開發、測試三個不同的環境,我們的配置肯定不一樣。這時,我們需要用到Profile。
Profile 是 Spring 用來針對不同的環境對不同的配置提供支持的,全局 Profile 配置使用 application-{profile}. yml(如 application-prod.yml)。通過在 application.yml 中設置 spring.profiles.active = prod 來指定活動的 Profile。
依次再目錄下面新建三個配置文件,application-dev.yml、application-test.yml、application-prod.yml。它們分別代表開發環境、測試環境、生產環境的配置文件。
application-dev.yml:
server:
port: 8083
context-path: /boot
application-test.yml:
server:
port: 8085
context-path: /boot
application-prod.yml:
server:
port: 8084
context-path: /boot
接下來修改application.yml:表示,將采用application-dev.yml這個配置文件。
spring:
profiles:
active: dev
我們在IDEA中運行項目,然后看下運行結果:
我們看到啟用了8083端口,而我們的配置文件application-dev.yml中正是配置的8083端口。
假設我們在application.yml中已經配置了端口8082,看下會怎么樣
運行結果:
Tomcat started on port(s): 8083 (http)
還是使用的dev中8083端口,那么我們再來換下位置,把
server:
port: 8082
context-path: /boot
放到配置文件的最后面,再看下結果,結果還是啟用的8083端口。
那么說明,配置文件會優先獲取Profile中的配置,如果Profile中沒有的配置項, 那么會直接取application.yml中的配置。
Spring Boot實現RestFul
回到之前AreaController類的代碼:
@Autowired private AreaService areaService; @RequestMapping(value = "/get", produces = {"application/json;charset=UTF-8"}) public Map<String,Object> getArea(@PathParam("areaId") Integer areaId){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("area",areaService.getArea(areaId)); return modelMap; }
我們的通過URL訪問的方式是這樣的:通過?號傳遞參數,而且要求問號后面的參數名稱必須和@PathParam("areaId")中的參數名稱保持一致,顯然這樣是不符合RestFul風格的。
@PathParam注解接收的是傳統的URL界面傳參的方式
接下來,我們稍微修改一下:
@RequestMapping(value = "/get/{areaId}", produces = {"application/json;charset=UTF-8"}) public Map<String,Object> getAreaApi(@PathVariable Integer areaId){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("area",areaService.getArea(areaId)); return modelMap; }
再看下允許結果:
我們再來修改一下代碼看下:
@RequestMapping(value = "/get/{Id}", produces = {"application/json;charset=UTF-8"}) public Map<String,Object> getAreaApi(@PathVariable("Id") Integer areaId){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("area",areaService.getArea(areaId)); return modelMap; }
運行結果還是一樣的。那么這說明,當@PathVariable中不指定參數名稱的時候,默認就是把后面的areaId當成是接收參數了,如果@PathVariable中指定了接收參數的名稱(這個名稱必須和{Id}一致),那么后面的Integer areaId可以隨意命名。
@PathVariable注解接收的就是符合RestFull風格的參數。此外還有一個@RequestParam注解。
@RequestParam 和 @PathVariable 注解是用於從request中接收請求的,兩個都可以接收參數,關鍵點不同的是@RequestParam 是從request里面拿取值,而 @PathVariable 是從一個URI模板里面來填充。
SpringBoot整合Swagger2自動生成API文檔
手寫Api文檔的幾個痛點:
文檔需要更新的時候,需要再次發送一份給前端,也就是文檔更新交流不及時。
接口返回結果不明確
不能直接在線測試接口,通常需要使用工具,比如postman
接口文檔太多,不好管理
Swagger也就是為了解決這個問題,當然也不能說Swagger就一定是完美的,當然也有缺點,最明顯的就是代碼移入性比較強。asp.net web api也有api文檔自動生成功能,最終效果和這個差不多。
(1)添加Swagger依賴
修改我們的pom.xml文件,添加變量 <springfox.version>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <springfox.version>2.7.0</springfox.version> </properties>
引入依賴
<!--swagger2--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${springfox.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${springfox.version}</version> </dependency>
(2)添加Swagger2的配置文件Swagger2Config
在config包下面新建類Swagger2Config
@Configuration @EnableSwagger2 public class Swagger2Config { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.yujie.controller")) //需要注意的是這里要寫入控制器所在的包 .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("springboot利用swagger構建api文檔") .description("簡單優雅的restfun風格,https://www.cnblogs.com/jiekzou/") .termsOfServiceUrl("https://www.cnblogs.com/jiekzou/") .version("1.0") .build(); } }
注意:用@Configuration注解該類,等價於XML中配置beans;用@Bean標注方法等價於XML中配置bean。
如上代碼所示,通過@Configuration注解,讓Spring來加載該類配置。再通過@EnableSwagger2注解來啟用Swagger2。
createRestApi函數創建Docket的Bean之后,apiInfo()用來創建該Api的基本信息(這些基本信息會展現在文檔頁面中)。select()函數返回一個ApiSelectorBuilder實例用來控制哪些接口暴露給Swagger來展現,本例采用指定掃描的包路徑來定義,Swagger會掃描該包下所有Controller定義的API,並產生文檔內容(除了被@ApiIgnore指定的請求)。
添加文檔內容
在完成了上述配置后,其實已經可以生產文檔內容,但是這樣的文檔主要針對請求本身,而描述主要來源於函數等命名產生,對用戶並不友好,我們通常需要自己增加一些說明來豐富文檔內容。如下所示,我們通過@ApiOperation注解來給API增加說明、通過@ApiImplicitParams、@ApiImplicitParam注解來給參數增加說明。
查看我們AreaController類的代碼如下:
@Api(value = "區域操作controller", description = "區域相關的操作", tags = {"區域模塊校驗接口"}) @RestController //@RequestMapping("/area") public class AreaController { @Autowired private AreaService areaService; /* @RequestMapping(value = "/get", produces = {"application/json;charset=UTF-8"}) public Map<String,Object> getArea(@PathParam("areaId") Integer areaId){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("area",areaService.getArea(areaId)); return modelMap; }*/ @ApiOperation(value="獲取區域詳細信息", notes="根據url的id來獲取區域詳細信息") @ApiImplicitParam(name = "Id", value = "區域ID", required = true, dataType = "Integer", paramType = "path") @RequestMapping(value = "/get/{Id}",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"}) public Map<String,Object> getAreaApi(@PathVariable("Id") Integer areaId){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("area",areaService.getArea(areaId)); return modelMap; } @ApiOperation(value="創建區域", notes="根據Area對象創建區域") @ApiImplicitParam(name = "area", value = "區域詳細實體area", required = true, dataType = "Area") @RequestMapping(value = "/add",method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) public Map<String,Object> addArea(Area area){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("success",areaService.addArea(area)); return modelMap; } @ApiOperation(value="修改區域", notes="根據Area對象修改區域") @ApiImplicitParam(name = "area", value = "區域詳細實體area", required = true, dataType = "Area") @RequestMapping(value = "/edit",method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) public Map<String,Object> editArea(Area area){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("success",areaService.addArea(area)); return modelMap; } @ApiOperation(value="獲取區域列表", notes="獲取區域列表") @ApiImplicitParams ({ @ApiImplicitParam(name = "pageNum", value = "第多少頁", required = true, dataType = "Integer", paramType = "path"), @ApiImplicitParam(name = "pageSize", value = "每頁取多少條記錄", required = true, dataType = "Integer", paramType = "path") }) @RequestMapping(value = "/all/{pageNum}/{pageSize}",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"}) public Object findAllArea(@PathVariable("pageNum") int pageNum, @PathVariable("pageSize") int pageSize){ return areaService.findAllArea(pageNum,pageSize); } @GetMapping(value="/del/{areaId}") public Map<String,Object> deleteArea(@PathVariable Integer areaId){ Map<String,Object> modelMap= new HashMap<String,Object>() ; modelMap.put("success",areaService.deleteArea(areaId)); return modelMap; } @GetMapping("/test") @ApiIgnore//使用該注解忽略這個API public String Test(){ return "test"; } }
swagger的相關注解
swagger通過注解表明該接口會生成文檔,包括接口名、請求方法、參數、返回信息的等等。
- @Api:修飾整個類,描述Controller的作用
- @ApiOperation:描述一個類的一個方法,或者說一個接口
- @ApiParam:單個參數描述
- @ApiModel:用對象來接收參數
- @ApiProperty:用對象接收參數時,描述對象的一個字段
- @ApiResponse:HTTP響應其中1個描述
- @ApiResponses:HTTP響應整體描述
- @ApiIgnore:使用該注解忽略這個API
- @ApiError :發生錯誤返回的信息
- @ApiImplicitParam:一個請求參數
- @ApiImplicitParams:多個請求參數
啟動Spring Boot程序,訪問:http://localhost:8083/boot/swagger-ui.html,最終運行效果如下: