SpringBoot開發單體應用(三)

單體開發進階

SpringBoot的Web開發之路

衆所周知,CRUD是每個程序員的必經之路。作爲一個初級程序員,只要能夠獨立開發出一個簡單的CRUD系統即可,例如OA系統、CRM管理系統、基於表單的CRUD系統等。
簡單來說,分佈式開發是後端提供接口,前端接收信息進行渲染;單體開發是後端提供數據,前端獲取數據進行渲染。
從開發流程來說,單體開發和分佈式開發本質上並沒有區別,只是用到的技術和思想上略有不同。
分佈式開發的本質:網絡是不可靠的,我們需要解決服務之間的通信問題,例如服務崩潰了的解決方案,客戶端如何去進行訪問,服務的註冊和發現等。

Swagger

什麼是Swagger?

在前後端分離的項目當中,開發人員的分工大概如下:

  • 前端主要專注於控制層和視圖層,由專業的前端團隊進行開發。
  • 後端主要專注於後端控制層、服務層和數據訪問層,由專業的後端團隊進行開發。

那麼問題來了,前後端的交互一般都是通過API來進行的,關於API的約定應該如何處理呢?
在早期的時候,一般由後端編寫協同文檔,前端根據文檔解析接口然後渲染視圖。但問題也很明顯,前端和後端之間無法做到及時協商,最終可能導致問題集中爆發或者項目延時。
爲了解決這些問題,Swagger應運而生。
什麼是Swagger?
Swagger是一個規範和完整的框架,用於生成、描述、調用和可視化 RESTful風格的Web服務。總體目標是使客戶端和文件系統作爲服務器以同樣的速度來更新。文件的方法,參數和模型緊密集成到服務器端的代碼,允許API來始終保持同步。
Swagger的作用主要有兩點:接口的文檔在線自動生成和功能測試。
現在的開源項目中,都會集成Swagger。
Swagger的主要特點

  • 號稱世界上最流行的API框架。
  • Restful API自動生成文檔,和代碼對應。
  • 直接運行測試接口,不需要下載postman了。
  • 支持多種語言,如Java、Php等。

Swagger官網地址::https://swagger.io/
Swagger官網

集成Swagger

基礎集成

1、導入Swagger2依賴。

<!--swaggger2依賴-->
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

2、編寫Swagger配置類,註冊Docket到Spring容器中,在主啓動類上添加@EnableSwagger2開啓配置使Swagger生效。

//Swagger配置類
@Configuration 
public class SwaggerConfig { 

	// 註冊bean Docket 
	@Bean 
	public Docket docket(){ 
		return new Docket(DocumentationType.SWAGGER_2); 
	} 
}

//主啓動類
@SpringBootApplication
@EnableSwagger2 //使swagger生效,默認不開啓
public class SpringbootPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootPlusApplication.class, args);
    }

}

3、啓動項目進行測試,Swagger API文檔默認訪問地址:http://localhost:8080/swagger-ui.html
Swagger API 文檔頁面
注意在Controller的方法請求路徑映射不要使用@RequestMapping來配置,應該直接使用具體請求方法的註解,如@GetMapping@PostMapping等。因爲使用@RequestMapping配置在API文檔上一個方法默認會生成七種請求的API文檔信息,如下圖所示。
一個方法的七種請求的API文檔信息

配置Swagger

1、在SwaggerConfig類中配置文檔信息,構造ApiInfo對象。

@Bean
public Docket docket(){
	return new Docket(DocumentationType.SWAGGER_2)
			.apiInfo(apiInfo())//配置文檔信息
}
	
//配置文檔信息apiInfo
private ApiInfo apiInfo(){

	Contact contact = new Contact("wunian", "https://www.jianshu.com/u/5e27029e243f", "[email protected]");

	return new ApiInfo(
			"SpringBoot-Plus接口文檔信息",//文檔標題
			"所有的測試請求地址",//文檔描述
			"v1.0",//文檔版本
			"https://www.jianshu.com/u/5e27029e243f",//組織鏈接
			contact,
			"Apache 2.0",
			"http://www.apache.org/licenses/LICENSE-2.0",
			new ArrayList<>());
}

2、配置哪些接口需要被掃描到文檔中。

@Bean
public Docket docket(){
	return new Docket(DocumentationType.SWAGGER_2)
			.apiInfo(apiInfo())
			.select()
			.apis(RequestHandlerSelectors.basePackage("com.wunian.controller"))//設置掃描指定包下的類
			.build();
}

RequestHandlerSelectors類的所有靜態方法說明:

  • any():掃描所有,項目的所有接口都會被掃描。
  • none():不掃描接口。
  • basePackage():根據包路徑掃描。
  • withMethodAnnotation(GetMapping.class):通過方法註解掃描。
  • withClassAnnotation(Controller.class):通過類上的註解掃描。

RequestHandlerSelectors類的所有靜態方法
3、設置哪些接口不被掃描。

@Bean
public Docket docket(){
	return new Docket(DocumentationType.SWAGGER_2)
			.apiInfo(apiInfo())
			.select()
			.apis(RequestHandlerSelectors.basePackage("com.wunian.controller"))//設置掃描指定包下的類
            //配置path過濾請求,只掃描以/kuang開頭的請求
            .paths(PathSelectors.ant("/kuang/**")) 
			.build();
}

PathSelectors類的所有靜態方法說明:

  • ant(String antPattern):只掃描指定的路徑下的請求。
  • any():任何請求都會被掃描。
  • none():不掃描請求。
  • regex(String pathRegex):通過正則表達式來匹配請求。

PathSelectors類的所有靜態方法.png

配置Swagger開關

如果我們要讓swagger-ui頁面只在test和dev環境下顯示,prod環境不顯示就需要配置enable(false)方法。

@Bean
public Docket docket(){
	return new Docket(DocumentationType.SWAGGER_2)
			.apiInfo(apiInfo())
            .enable(false)//如果是false就無法在瀏覽器中訪問swagger-ui.html
			.select()
			.apis(RequestHandlerSelectors.basePackage("com.wunian.controller"))//
            .paths(PathSelectors.ant("/kuang/**")) 
			.build();
}

swagger-ui.html頁面無法訪問
不過直接在enable方法中傳入false也不合適,它應該是一個變量,我們可以通過Profiles類來獲取限定的開發環境,並且調用Environment對象的acceptsProfiles方法來判斷當前環境是否是限定的開發環境。

@Bean
public Docket docket(Environment environment){
	//設置要顯示的swagger環境
	Profiles of = Profiles.of("dev", "test");
	//判斷是否處於該環境
	boolean isEnable=environment.acceptsProfiles(of);
	return new Docket(DocumentationType.SWAGGER_2)
			.apiInfo(apiInfo())
			.enable(isEnable) //如果是false,就無法在瀏覽器中訪問
			.select()
			.apis(RequestHandlerSelectors.basePackage("com.wunian.controller"))
			.paths(PathSelectors.ant("/kuang/**")) 
			
			.build();
}

配置API分組

這個配置只需要瞭解即可,以後可以使用MyBatis-Plus一鍵生成。

@Bean
public Docket docket1(){
	return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
}

@Bean
public Docket docket2(){
	return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
}

@Bean
public Docket docket3(){
	return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
}

API分組

實體配置

1、新建一個實體類,類上使用@ApiModel註解來添加該實體類的描述信息,此註解其實就是註釋,只不過它會被Swagger識別。

//和註釋差不多,但是會被swagger識別
@ApiModel("用戶實體")  //實體類的描述信息
public class User {//只有在controller中返回值用到,這個類纔會顯示在swagger中

    @ApiModelProperty("用戶名")
    private String username;
    @ApiModelProperty("密碼")
    private String password;
}

2、請求的接口配置,如果要在swagger-ui.html中看到實體類的配置,那麼這個實體類一定是在請求的返回值或者泛型中,只有這樣它纔會被映射。

//只有返回值用到纔會顯示
@GetMapping("/getUser")
public User getUser(){
	return new User();
}

實體類的配置

接口上的配置

在類上使用@Api註解來添加類的描述信息,在方法上使用@ApiOperation註解來添加方法的描述信息,在方法的形參上使用@ApiParam註解來添加參數的描述信息。

@Api(tags="Hello測試類")   //類的描述信息
@RestController
public class HelloController {

    @GetMapping("/kuang/hello")
    public String hello(){
        return "Hello Swagger";
    }

    //只有返回值用到纔會顯示
    @GetMapping("/getUser")
    public User getUser(){
        return new User();
    }
   // 後面我們自己開發項目的時候,主要是寫方法註釋和參數註釋!
    @ApiOperation("coding的接口") //方法和接口的描述信息
    @PutMapping("/coding")
    public String coding(@ApiParam("用戶名") String username){//參數的描述信息
        return username;
    }
}

Swagger接口文檔的皮膚包(擴展)

1、默認的皮膚包: http://localhost:8080/swagger-ui.html

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

默認皮膚包

2、bootstrap-ui: http://localhost:8080/doc.html

<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/swagger-bootstrap-ui --> 
<dependency> 
	<groupId>com.github.xiaoymin</groupId> 
	<artifactId>swagger-bootstrap-ui</artifactId> 
	<version>1.9.6</version> 
</dependency>

bootstrap-ui
3、ui-layer:http://localhost:8080/docs.html

<!-- https://mvnrepository.com/artifact/com.github.caspar-chen/swagger-ui-layer - ->
<dependency> 
	<groupId>com.github.caspar-chen</groupId> 
	<artifactId>swagger-ui-layer</artifactId> 
	<version>1.1.3</version> 
</dependency>

ui-layer

4、mg-ui: http://localhost:8080/document.html

<dependency> 
	<groupId>com.zyplayer</groupId> 
	<artifactId>swagger-mg-ui</artifactId> 
	<version>1.0.6</version> 
</dependency>

mg-ui

異步任務

我們可以來模擬一個延時的異步處理請求。
1、在業務方法中添加@Async註解,此註解相當於告訴Spring這是一個異步任務,默認使用線程池開啓異步任務,效率很高。

@Service
public class AsyncService {

    //模擬一個延時的後臺方法
    @Async //告訴spring這是一個異步方法,默認使用了線程池
    public void hello(){
        try{
            Thread.sleep(3000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("數據處理中......");
    }
}

2、在主啓動類上添加@EnableAsync開啓異步任務支持。

@SpringBootApplication
@EnableSwagger2 //使swagger生效,默認不開啓
@EnableAsync //開啓異步任務的支持
public class SpringbootPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootPlusApplication.class, args);
    }
}

3、啓動項目進行測試,頁面如果出現秒級刷新,說明測試成功。

定時任務

Cron表達式

計劃任務,是指任務在約定的時間執行已經計劃好的工作,這只是表面的意思。在Linux中,我們經常用到Cron服務器來完成這項工作。Cron服務器可以根據配置文件約定的時間來執行特定的任務。
Cron基本格式
實際上在分前面還有秒,範圍在0-59之間。
一些特殊符號的含義:

  • *表示任意時間。
  • -表示區間。
  • L表示最後。
  • ?用在日或星期上,表示不確定值、不限制值。
  • W表示工作日,這裏的工作日指的是朝九晚五,雙休和節假日。
  • #用於星期上,#後面的數字表示第幾周,如果不存在這個周的值,則不執行。

這些特殊符號其實不用刻意去記憶,我們想要編寫Cron表達式只需要去找在線生成Cron表達式的網站去生成就好了。
常用的Cron表達式:

(1)0/2 * * * * ? 表示每2秒 執行任務 
(1)0 0/2 * * * ? 表示每2分鐘 執行任務 
(1)0 0 2 1 * ? 表示在每月的1日的凌晨2點調整任務 
(2)0 15 10 ? * MON-FRI 表示週一到週五每天上午10:15執行作業 
(3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每個月的最後一個星期五上午10:15執行作 
(4)0 0 10,14,16 * * ? 每天上午10點,下午2點,4點 
(5)0 0/30 9-17 * * ? 朝九晚五工作時間內每半小時 
(6)0 0 12 ? * WED 表示每個星期三中午12點 
(7)0 0 12 * * ? 每天中午12點觸發 
(8)0 15 10 ? * * 每天上午10:15觸發 
(9)0 15 10 * * ? 每天上午10:15觸發 
(10)0 15 10 * * ? 每天上午10:15觸發 
(11)0 15 10 * * ? 2005 2005年的每天上午10:15觸發 
(12)0 * 14 * * ? 在每天下午2點到下午2:59期間的每1分鐘觸發 
(13)0 0/5 14 * * ? 在每天下午2點到下午2:55期間的每5分鐘觸發 
(14)0 0/5 14,18 * * ? 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發 
(15)0 0-5 14 * * ? 在每天下午2點到下午2:05期間的每1分鐘觸發 
(16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44觸發 
(17)0 15 10 ? * MON-FRI 週一至週五的上午10:15觸發 
(18)0 15 10 15 * ? 每月15日上午10:15觸發 
(19)0 15 10 L * ? 每月最後一日的上午10:15觸發 
(20)0 15 10 ? * 6L 每月的最後一個星期五上午10:15觸發 
(21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最後一個星期五上午10:15觸發 
(22)0 15 10 ? * 6#3 每月的第三個星期五上午10:15觸發

編寫定時任務

1、編寫Service,在定時方法上添加@Scheduled註解,該註解傳入一個cron參數,此參數傳入一個Cron表達式。

@Service //放到spring容器中
public class ScheduledService {

    //工作中的定時任務都可以使用這樣的方法
    //秒 分 時 日 月 周幾
    @Scheduled(cron = "0 * * * * 0-7")  //每天每時每分整點執行
    public void hello(){
        System.out.println("Hello  Scheduled");
    }
}

2、在主啓動類上添加@EnableScheduling註解開啓定時任務支持。

@SpringBootApplication
@EnableSwagger2 //使swagger生效,默認不開啓
@EnableAsync //開啓異步任務的支持
@EnableScheduling//開啓定時任務支持
public class SpringbootPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootPlusApplication.class, args);
    }
}

3、啓動項目進行測試,可以看到每一分鐘的整點都會輸出"Hello Scheduled"。

郵件任務

所有的網站,幾乎都有郵件收發功能。我們這裏以QQ郵箱爲例,基於SpringBoot來實現發送郵件功能。

郵箱的開發者權限獲取
相比於其他郵箱,QQ郵箱較爲複雜,因爲它有安全驗證。我們需要登錄QQ郵箱去開啓一下SMTP服務,具體操作步驟如下圖所示。
QQ郵箱開啓SMTP服務
然後我們就可以獲得一個授權碼了,它相當於我們的郵箱賬號的密碼,通過它可以登錄我們的郵箱。
獲得授權碼
對於不同的郵箱系統,網站服務器地址是不一樣的:

  • QQ郵箱:smtp.qq.com
  • 網易郵箱:smtp.163.com
  • 新浪郵箱:smtp.sina.com

SMTP服務器地址

測試

1、導入啓動器,java中發送郵件的包是javax.mail,但是SpringBoot啓動器中導入的包是jakarta.mail。

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-mail</artifactId> 
</dependency>

2、配置發件人信息,詳細的配置項可以查看MailProperties配置類。

#發件人的信息
[email protected]
spring.mail.password=mxhdobcadmkudacd
spring.mail.host=smtp.qq.com
#QQ比較特殊,需要配置ssl安全連接,其他郵箱不需要配置
spring.mail.properties.mail.smtp.ssl.enable=true

4、測試發送簡單郵件和複雜郵件。

@SpringBootTest
class SpringbootPlusApplicationTests {

    @Autowired
    JavaMailSender sender;

    @Test
    void sendMailTest(){//測試簡單的郵件發送
        //發送簡單的郵件
        SimpleMailMessage message = new SimpleMailMessage();//簡單的郵件消息
        message.setSubject("你收到了一份面試邀請");//郵件主題
        message.setText("纔怪,測試郵件哦!");

        message.setFrom("[email protected]");//發件人
        message.setTo("[email protected]","[email protected]");//收件人
        sender.send(message); //發送郵件
    }

    @Test
    void sendMimeMailTest() throws MessagingException {//測試複雜的郵件發送
        //複雜的郵件,通過一個輔助類來完成 MimeMessageHelper
        MimeMessage mimeMessage = sender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        //基本信息
        helper.setSubject("支付寶到賬提醒:尊敬的客戶,您3月份...");
        helper.setText("<h1 style='color:red'>支付寶到賬1,0000,000元,請注意查收!</h1>",true);
        //發送附件
        helper.addAttachment("1.jpg",new File("C:\\Users\\Administrator\\Desktop\\1.jpg"));

        helper.setFrom("[email protected]");
        helper.setTo(new String[]{"[email protected]","[email protected]"});
        sender.send(mimeMessage);  //發送郵件
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章