開(kāi)發(fā)過(guò)程中的效率提升工具
為了更愉快的寫(xiě)代碼,開(kāi)發(fā)過(guò)程中常常需要一些功能類來(lái)提高工作效率,記錄一下用到過(guò)的比較好的開(kāi)發(fā)效率工具
1、java StopWatch統(tǒng)計(jì)時(shí)間
? ? ? ?有時(shí)候記錄一段代碼的執(zhí)行時(shí)間,最常見(jiàn)的方法是打印當(dāng)前的時(shí)間與執(zhí)行后的差值,確定是使用很麻煩并且很不直觀。spring-framework提供了一個(gè)stopWatch類可以做類似任務(wù)的執(zhí)行時(shí)間控制。StopWath是apache commons lang3包下的一個(gè)任務(wù)執(zhí)行時(shí)間監(jiān)視器。
主要方法:
start();?????//開(kāi)始計(jì)時(shí)
split();?????//設(shè)置split點(diǎn)
getSplitTime(); ?//獲取從start 到 最后一次split的時(shí)間
reset();?????//重置計(jì)時(shí)
suspend();? ? ?//暫停計(jì)時(shí), 直到調(diào)用resume()后才恢復(fù)計(jì)時(shí)
resume();? ? ? //恢復(fù)計(jì)時(shí)
stop();????? //停止計(jì)時(shí)
getTime();????//統(tǒng)計(jì)從start到現(xiàn)在的計(jì)時(shí)
例子:
package com.example.stopwatch;
import org.springframework.util.StopWatch;
public class StopWatchTest {
? ? private void test() throws InterruptedException {
? ? ? ? StopWatch sw = new StopWatch();
? ? ? ? sw.start("起床");
? ? ? ? Thread.sleep(1000);
? ? ? ? sw.stop();
? ? ? ? sw.start("洗漱");
? ? ? ? Thread.sleep(2000);
? ? ? ? sw.stop();
? ? ? ? sw.start("鎖門(mén)");
? ? ? ? Thread.sleep(500);
? ? ? ? sw.stop();
? ? ? ? System.out.println(sw.prettyPrint());
? ? ? ? System.out.println(sw.getTotalTimeMillis());
? ? ? ? System.out.println(sw.getLastTaskName());
? ? ? ? System.out.println(sw.getLastTaskInfo());
? ? ? ? System.out.println(sw.getTaskCount());
? ? }
? ? public static void main(String []argv) throws InterruptedException {
? ? ? ? TestStopWatch testStopWatch = new TestStopWatch();
? ? ? ? testStopWatch.test();
? ? }
}
結(jié)果如下

2、Swagger Api
可以無(wú)需手寫(xiě),自動(dòng)生成接口的API文檔的工具
1、Maven依賴
<dependency>
????<groupId>io.springfox</groupId>
??? <artifactId>springfox-swagger2</artifactId>
??? <version>2.2.2</version>
</dependency>
<dependency>
??? <groupId>io.springfox</groupId>
??? <artifactId>springfox-swagger-ui</artifactId>
??? <version>2.2.2</version>
</dependency>
2、配置類
/**
* Swagger2配置類
* 在與spring boot集成時(shí),放在與Application.java同級(jí)的目錄下。
* 通過(guò)@Configuration注解,讓Spring來(lái)加載該類配置。
* 再通過(guò)@EnableSwagger2注解來(lái)啟用Swagger2。
*/
@Configuration
@EnableSwagger2
publicclass Swagger2 {
/**
? ? * 創(chuàng)建API應(yīng)用
? ? * apiInfo() 增加API相關(guān)信息
? ? * 通過(guò)select()函數(shù)返回一個(gè)ApiSelectorBuilder實(shí)例,用來(lái)控制哪些接口暴露給Swagger來(lái)展現(xiàn),
? ? * 本例采用指定掃描的包路徑來(lái)定義指定要建立API的目錄。
? ? *
? ? * @return
? ? */
@Bean
public Docket createRestApi() {
returnnewDocket(DocumentationType.SWAGGER_2)
? ? ? ? ? ? ? ? .apiInfo(apiInfo())
? ? ? ? ? ? ? ? .select()
.apis(RequestHandlerSelectors.basePackage("com.swaggerTest.controller"))
? ? ? ? ? ? ? ? .paths(PathSelectors.any())
? ? ? ? ? ? ? ? .build();
? ? }
/**
? ? * 創(chuàng)建該API的基本信息(這些基本信息會(huì)展現(xiàn)在文檔頁(yè)面中)
? ? * 訪問(wèn)地址:http://項(xiàng)目實(shí)際地址/swagger-ui.html
? ? * @return
? ? */
private ApiInfo apiInfo() {
returnnewApiInfoBuilder()
.title("Spring Boot中使用Swagger2構(gòu)建RESTful APIs")
.description("更多請(qǐng)關(guān)注http://www.baidu.com")
.termsOfServiceUrl("http://www.baidu.com")
.contact("sunf")
.version("1.0")
? ? ? ? ? ? ? ? .build();
? ? }
如上代碼所示,通過(guò)createRestApi函數(shù)創(chuàng)建Docket的Bean之后,apiInfo()用來(lái)創(chuàng)建該Api的基本信息(這些基本信息會(huì)展現(xiàn)在文檔頁(yè)面中)。
3、使用方法介紹
Swagger使用的注解及其說(shuō)明:
@Api:用在類上,說(shuō)明該類的作用。
@ApiOperation:注解來(lái)給API增加方法說(shuō)明。
@ApiImplicitParams?: 用在方法上包含一組參數(shù)說(shuō)明。
@ApiImplicitParam:用來(lái)注解來(lái)給方法入?yún)⒃黾诱f(shuō)明。
@ApiResponses:用于表示一組響應(yīng)
@ApiResponse:用在@ApiResponses中,一般用于表達(dá)一個(gè)錯(cuò)誤的響應(yīng)信息
l?code:數(shù)字,例如400
l?message:信息,例如"請(qǐng)求參數(shù)沒(méi)填好"
l?response:拋出異常的類
@ApiModel:描述一個(gè)Model的信息(一般用在請(qǐng)求參數(shù)無(wú)法使用@ApiImplicitParam注解進(jìn)行描述的時(shí)候)
l?@ApiModelProperty:描述一個(gè)model的屬性

/**
* 一個(gè)用來(lái)測(cè)試swagger注解的控制器
* 注意@ApiImplicitParam的使用會(huì)影響程序運(yùn)行,如果使用不當(dāng)可能造成控制器收不到消息
*
*@authorSUNF
*/
@Controller
@RequestMapping("/say")
@Api(value ="SayController|一個(gè)用來(lái)測(cè)試swagger注解的控制器")
publicclass SayController {
@ResponseBody
@RequestMapping(value ="/getUserName", method= RequestMethod.GET)
@ApiOperation(value="根據(jù)用戶編號(hào)獲取用戶姓名", notes="test: 僅1和2有正確返回")
@ApiImplicitParam(paramType="query", name ="userNumber", value ="用戶編號(hào)", required =true, dataType ="Integer")
public String getUserName(@RequestParam Integer userNumber){
if(userNumber ==1){
return"張三豐";
? ? ? ? }
elseif(userNumber ==2){
return"慕容復(fù)";
? ? ? ? }
else{
return"未知";
? ? ? ? }
? ? }
@ResponseBody
@RequestMapping("/updatePassword")
@ApiOperation(value="修改用戶密碼", notes="根據(jù)用戶id修改密碼")
@ApiImplicitParams({
@ApiImplicitParam(paramType="query", name ="userId", value ="用戶ID", required =true, dataType ="Integer"),
@ApiImplicitParam(paramType="query", name ="password", value ="舊密碼", required =true, dataType ="String"),
@ApiImplicitParam(paramType="query", name ="newPassword", value ="新密碼", required =true, dataType ="String")
? ? })
public String updatePassword(@RequestParam(value="userId") Integer userId, @RequestParam(value="password") String password,
@RequestParam(value="newPassword") String newPassword){
if(userId <=0|| userId >2){
return"未知的用戶";
? ? ? }
if(StringUtils.isEmpty(password) || StringUtils.isEmpty(newPassword)){
return"密碼不能為空";
? ? ? }
if(password.equals(newPassword)){
return"新舊密碼不能相同";
? ? ? }
return"密碼修改成功!";
? ? }
完成上述代碼添加上,啟動(dòng)Spring Boot程序,訪問(wèn):http://localhost:8080/swagger-ui.html
其他注意事項(xiàng):
1、paramType會(huì)直接影響程序的運(yùn)行期,如果paramType與方法參數(shù)獲取使用的注解不一致,會(huì)直接影響到參數(shù)的接收。
2、Conntroller中定義的方法必須在@RequestMapper中顯示的指定RequestMethod類型,否則SawggerUi會(huì)默認(rèn)為全類型皆可訪問(wèn), API列表中會(huì)生成多條項(xiàng)目。
工具類
所有的工具類,優(yōu)先采用?apache commons?系列;
apache commons未提供的工具可以自行擴(kuò)展,也應(yīng)該是在其基礎(chǔ)之上進(jìn)行擴(kuò)展,而不是另外實(shí)現(xiàn)

編碼及加解密方法規(guī)范
應(yīng)用中資源統(tǒng)一采用?UTF-8?編碼,統(tǒng)一采用Spring提供的CharacterEncodingFilter來(lái)實(shí)現(xiàn)。
常見(jiàn)的加解密統(tǒng)一采用?apache commons-codec?庫(kù)所提供的方法,具體 API 及文檔參見(jiàn):https://commons.apache.org/proper/commons-codec
關(guān)于金額類型的說(shuō)明
應(yīng)用中涉及到金額時(shí),在系統(tǒng)、數(shù)據(jù)庫(kù)設(shè)計(jì)的時(shí)候通常有兩種做法:
1.?Decimal?格式:(也是較通用的格式),數(shù)據(jù)庫(kù)和Java中都有對(duì)應(yīng)的類型支持;
優(yōu)點(diǎn):直觀,在使用的過(guò)程中也無(wú)需轉(zhuǎn)換。精度方面也支持得非常好,可以隨時(shí)動(dòng)態(tài)調(diào)整;
缺點(diǎn):API 使用相對(duì)復(fù)雜一點(diǎn),對(duì)應(yīng)的 Java 對(duì)象為?BigDecimal?,做四則運(yùn)算的時(shí)候都是對(duì)象方法調(diào)用;
2.?Int?格式:通常按照一定的小數(shù)點(diǎn)留存數(shù)量乘以相應(yīng)的倍數(shù),將金額轉(zhuǎn)換成分(美分);
比如:?1.88?元 =?188?分
優(yōu)點(diǎn):數(shù)據(jù)類型簡(jiǎn)單,做四則運(yùn)算時(shí)也比較快捷方便;
缺點(diǎn):精度無(wú)法動(dòng)態(tài)變換,在用戶輸入/展示與數(shù)據(jù)存儲(chǔ)之間需要進(jìn)行數(shù)據(jù)轉(zhuǎn)換;
注:由于真正做運(yùn)算的場(chǎng)景不多, 相關(guān) API 也不會(huì)頻繁的調(diào)用,所以根據(jù)以上的比較,規(guī)定本中心所有金額相關(guān)的數(shù)據(jù)類型,如無(wú)特殊原因需要說(shuō)明外,統(tǒng)一采用?Decimal?數(shù)據(jù)格式;