跳到主要內容

Spring boot v1.5 (四) swagger,properties and structing your code

上一章有稍微讓大家看一下swagger怎麼跟spring boot無縫接軌,本章就深入一點來介紹swagger,把它定位在 API似乎有點薄弱,當作工具(Tools)我覺得倒很個很好的解釋,它主要提供的工具分別為 swagger core、swagger codegen、swagger editor、swagger ui等,以下是各自的說明:

  • swagger core:這是swagger的核心,使用Java撰寫出來的。
  • swagger codegen:可以依據swagger(yaml格式)產生出來的api json或是url,可產生客戶端(client)相對應的程式碼。
  • swagger editor:透過這個工具可以產生yaml,有點像是Eclipse IDE一樣,撰寫相對應的yaml,透過yaml可以產服務端(server)及客戶端(client)的程式碼,透過這裡可以玩玩看。
  • swagger ui:將這工具與你的程式結合,如上章的方式,程式啟動後就會自動生成 api 前端頁面提供使用。

調整一下原本的程式碼,增加客製化的功能,並修改原本Ex3Controller、User增加REST註解,你就會發現swagger的好用。
  • SwaggerConfiguration.java
package louisz.springboot.example3;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import static springfox.documentation.builders.PathSelectors.regex;

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
 @Bean
 public Docket usersApi() {
  return new Docket(DocumentationType.SWAGGER_2).select()
    .apis(RequestHandlerSelectors.basePackage("louisz.springboot.example3")).paths(regex("/user.*")).build()
    .apiInfo(metaData());

 }

 private ApiInfo metaData() {
  ApiInfo apiInfo = new ApiInfo("Louisz User RESTful API", "Louisz User RESTful API for blog", "1.0",
    "Terms of service", new Contact("Louisz Cheng", "#", "louisz6ster@gmail.com"),
    "Apache License Version 2.0", "https://www.apache.org/licenses/LICENSE-2.0");
  return apiInfo;
 }
}
  • Ex3Controller.java
package louisz.springboot.example3;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@RestController
@RequestMapping(value = "/user") // 上層路徑配置
@Api(value = "User Function", description = "操作User的RESTful 線上文件說明") // 最上層的說明                 
public class Ex3Controller {
 // 單一儲存庫
 static Map users = Collections.synchronizedMap(new HashMap());

 /**
  * 取得所有User清單
  * 
  * @return
  */
 @ApiOperation(value = "取得所有User清單", response = User.class)
 @ApiResponses(value = { @ApiResponse(code = 200, message = "正常回覆"), @ApiResponse(code = 401, message = "你尚未驗證通過"),
   @ApiResponse(code = 403, message = "你沒有權限可以使用該功能"), @ApiResponse(code = 404, message = "URL錯誤") })
 @RequestMapping(value = "/all", method = RequestMethod.POST)
 public List getUserList() {
  // 取得所有User List
  return new ArrayList(users.values());
 }

 /**
  * 新增User資料,傳入User JSON資料進行新增,成功回傳success
  * 
  * @param user
  * @return
  */
 @ApiOperation(value = "新增一筆User的資料", response = Iterable.class)
 @ApiResponses(value = { @ApiResponse(code = 200, message = "正常回覆"), @ApiResponse(code = 401, message = "你尚未驗證通過"),
   @ApiResponse(code = 403, message = "你沒有權限可以使用該功能"), @ApiResponse(code = 404, message = "URL錯誤") })
 @RequestMapping(value = "/add", method = RequestMethod.POST)
 public String addUser(@ModelAttribute User user) {
  // 傳入Input JSON會自動轉換為User物件
  users.put(user.getId(), user);
  return "add success";
 }

 /**
  * 傳入id進行查詢,回傳User JSON
  * 
  * @param id
  * @return
  */
 @ApiOperation(value = "透過ID查詢User資料", response = User.class)
 @ApiResponses(value = { @ApiResponse(code = 200, message = "正常回覆"), @ApiResponse(code = 401, message = "你尚未驗證通過"),
   @ApiResponse(code = 403, message = "你沒有權限可以使用該功能"), @ApiResponse(code = 404, message = "URL錯誤") })
 @RequestMapping(value = "/find/{id}", method = RequestMethod.POST)
 public User findUser(@PathVariable Long id) {
  // Output User會自動轉換為JSON物件
  return users.get(id);
 }

 /**
  * 傳入id及JSON User進行資料更新
  * 
  * @param id
  * @param user
  * @return
  */
 @ApiOperation(value = "更新特定User資料", response = String.class)
 @ApiResponses(value = { @ApiResponse(code = 200, message = "正常回覆"), @ApiResponse(code = 401, message = "你尚未驗證通過"),
   @ApiResponse(code = 403, message = "你沒有權限可以使用該功能"), @ApiResponse(code = 404, message = "URL錯誤") })
 @RequestMapping(value = "/update/{id}", method = RequestMethod.POST)
 public String updateUser(@PathVariable Long id, @ModelAttribute User user) {
  // 更新User資料
  User u = users.get(id);
  // System.out.println(u.getName()+"=>"+user.getMobileNumber());
  // 使用了BeanUtils
  BeanUtils.copyProperties(user, u);
  users.put(id, u);
  return "update success";
 }

 /**
  * 傳入id進行資料刪除,回傳success
  * 
  * @param id
  * @return
  */
 @ApiOperation(value = "刪除特定User資料", response = String.class)
 @ApiResponses(value = { @ApiResponse(code = 200, message = "正常回覆"), @ApiResponse(code = 401, message = "你尚未驗證通過"),
   @ApiResponse(code = 403, message = "你沒有權限可以使用該功能"), @ApiResponse(code = 404, message = "URL錯誤") })
 @RequestMapping(value = "/remove/{id}", method = RequestMethod.DELETE)
 public String removeUser(@PathVariable Long id) {
  // 刪除user資料
  users.remove(id);
  return "delete success";
 }

}
  • User.java
package louisz.springboot.example3;

import io.swagger.annotations.ApiModelProperty;

public class User {
 @ApiModelProperty(notes = "ID", required = true)
 private Long id;
 @ApiModelProperty(notes = "使用者姓名", required = true)
 private String name;
 @ApiModelProperty(notes = "使用者emai", required = true)
 private String email;
 @ApiModelProperty(notes = "使用者手機號碼")
 private String mobileNumber;

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 public String getMobileNumber() {
  return mobileNumber;
 }

 public void setMobileNumber(String mobileNumber) {
  this.mobileNumber = mobileNumber;
 }

}

執行並連結到http://localhost:8090/swagger-ui.html,結果如圖


    補充完swagger,進入本章的兩個主題,自訂屬性(application.properties)及專案結構定義,之前有提到application.properties(這裡),spring boot似乎一些主要的設定資訊都是透過這裡,一 般來說大部分專案都會使用到自己所需的設定資訊都會放在檔案中,可以透過File或是Apache Common Configuration或是其他方式進行,在spring boot當中已經把這機制放進去了,所以可以將所需的資訊放在application.properties或是resources下的其他自訂檔案中。
    在專案的開發中,分類一向都是很難決定的,因為伴隨著越來越多code,系統或專案結構就變得很重要,以下的分類方式提供給大家參考,當然有些情形是依據當下或是特定的規定進行,不過大致上這樣的分類應該可以應付大部分的專案才是,主要以Layer的概念去切割,如view、controller、model等,然後再細分下去如model.entities、model.facade、controller.service、controller.integrate等,當然也有些基本的如commons、utils,參考結構如下:

company(公司名稱).system(系統別).layer.patterns(design pattern)
company.project(專案).layer.functions(功能)
company.commons(通用)
company.utils(工具)
company.system.commons
company.system.utils


學習目的:使用自訂屬性設定檔、屬性一些進階的使用。
學習時數:1.5 hr
教學影片:




  • ExampleProperties.java
package louisz.springboot.example4;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component // DI之後介紹
@PropertySource("classpath:example4.properties") //設定自訂的設定檔檔名及路徑
@ConfigurationProperties("app") //prefix
public class ExampleProperties {
 //@Value("${app.name}") 也可以採用這種方式,這樣name可以不用相同,但是不建議
 //,因為後續不好維護
 private String name;
 
 private String version;
 
 private String nameversion;
 
 private String stringvalue;
 private int intvalue;
 private long longvalue;
 private int tenvalue;
 private int twentyvalue;
 
 
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getVersion() {
  return version;
 }
 public void setVersion(String version) {
  this.version = version;
 }
 public String getNameversion() {
  return nameversion;
 }
 public void setNameversion(String nameversion) {
  this.nameversion = nameversion;
 }
 public String getStringvalue() {
  return stringvalue;
 }
 public void setStringvalue(String stringvalue) {
  this.stringvalue = stringvalue;
 }
 public int getIntvalue() {
  return intvalue;
 }
 public void setIntvalue(int intvalue) {
  this.intvalue = intvalue;
 }
 public long getLongvalue() {
  return longvalue;
 }
 public void setLongvalue(long longvalue) {
  this.longvalue = longvalue;
 }
 public int getTenvalue() {
  return tenvalue;
 }
 public void setTenvalue(int tenvalue) {
  this.tenvalue = tenvalue;
 }
 public int getTwentyvalue() {
  return twentyvalue;
 }
 public void setTwentyvalue(int twentyvalue) {
  this.twentyvalue = twentyvalue;
 }

 
}

  • TestExampleProperties.java
package louisz.springboot.example4;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;


//spring boot 1.4以後的方式
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class TestExampleProperties {
 @Autowired
 private ExampleProperties exampleProperties;//注入
 
 @Test
 public void getHello() throws Exception {
  //驗證是否符合預期
  Assert.assertEquals(exampleProperties.getName(), "example4");
  Assert.assertEquals(exampleProperties.getVersion(), "1");
  Assert.assertEquals(exampleProperties.getNameversion(), "example4_1");
  System.out.println(exampleProperties.getIntvalue());
  System.out.println(exampleProperties.getTwentyvalue());
 }
 
}

Github code(louisz.springboot.example4)

參考連結:
http://blog.didispace.com/springbootproperties/

留言

這個網誌中的熱門文章

使用Apache Http Server進行Proxy和LoadB alance

環境概述 OS:Linux Apache Http Server:2.2.21 安裝可以使用rpm或是抓source下來compile,建議前者 rpm –ivh apache-http-xxx.rpm 這裡請注意一下安裝的版本 http.conf 參數設定 Proxy < VirtualHost *:80>      ProxyPass targetPath fromPath | fromUrl < VirtualHost/>  範例如下 < VirtualHost *:80>      ProxyPass /app http://DomainName或IP:8888/app      ProxyPassReverse /app http://DomainName或IP:8888/app < VirtualHost/> 上述的參數設定為,將某主機的http通訊協定下的Web application(app),對應到本台Web Server的app下。這樣的Proxy架構的設定對企業內的Web應用程式相當有用處,若是遇到Web Application Server掛點只需要修改Proxy對應,不需要動到dns等等,是個滿便宜的Proxy架構設定喔。﹝不過要注意Web Application要注意redirectc和forward等的撰寫,盡量不要有絕對IP的出現﹞

IBM MQ Server To Server的簡易設定

IBM MQ 的STS建置方式,IBM Red Book已經說明的滿完整的,這裡稍微整理一下,步驟如下 在 MQ-A Server MQ QMGR(MQA) 上需要建立的物件定義如下: • 遠端佇列定義 PAYROLL.QUERY • 傳輸佇列定義 MQB(預設 = 遠端佇列管理程式名稱) • 程序定義 MQA.TO.MQB.PROCESS(對於 WebSphere MQ for AIX、HP-UX、Solaris 與 Windows,及 MQSeries for Compaq Tru64 UNIX 與 OS/2 Warp,並非必要) • 傳送端通道定義 MQA.TO.MQB • 接收端通道定義 MQB.TO.MQA • 本端佇列定義 MQ2 以下是必須建立在 MQ-B Server MQ QMGR(MQB) 中的物件定義: • 遠端佇列定義 PAYROLL.RESPONE • 傳輸佇列定義 MQA(預設值=遠端佇列管理程式名稱) • 程序定義 MQB.TO.MQA.PROCESS(對於 WebSphere MQ for AIX、HP-UX、Solaris 與 Windows,及 MQSeries for Compaq Tru64 UNIX 與 OS/2 Warp,並非必要) • 傳送端通道定義 MQB.TO.MQA • 接收端通道定義 MQA.TO.MQB • 本端佇列定義 MQ4 1.先啟動MQ-A Server上的QMGR(MQA),並使用Runmqsc進入。 2.在佇列管理程式 MQA 上執行下列指令。 遠端佇列定義 DEFINE QREMOTE(PAYROLL.QUERY) DESCR('MQA 的遠端佇列') REPLACE + PUT(ENABLED) XMITQ(MQB) RNAME(MQ4) RQMNAME(MQB) 註: 遠端佇列定義並非實體的佇列,但卻是引導訊息至傳輸佇列 (MQB) 的一種方式,以便能將訊息送至佇列管理程式 MQB。 傳輸佇列定義 DEFINE QLOCAL(MQB) DESCR('對 MQB 的傳輸佇列') REPLACE + USAGE(XMITQ) PUT(ENABLED) GET(ENABLED) TRIGGER TRIGTYPE(FIRST) + INITQ(SYSTEM.CHANN

IReport字型下拉選單中文亂碼

這個問題其實也不是很大啦,不過當你有很多的中文字型檔的時候可能就不知道要選哪一個,啟動IReport後,開啟報表後會發現左邊下拉選單中,最下面的字型清單中有出現方框,顯示不出該字型的名稱,這幾個字型應該是判斷新細明體,標楷體及細明體,如下圖 下載IReport的Source Code來檢查一下,it.businesslogic.ireport.gui.MainFrame發現這個JComboBox有特別設定Arial字型,當然只要是中文的都顯示不出來ㄚ,所以點掉這一行後重新編譯,嘿嘿就可以了。 jComboBoxFont.setFont(new java.awt.Font("Arial", 0, 11)); 我目前使用的版本為 IReport-3.0.0-src