大家好!我是sum墨,一個一線的底層碼農,平時喜歡研究和思考一些技術相關的問題並整理成文,限於本人水平,如果文章和程式碼有表述不當之處,還請不吝賜教。
作為一名從業已達六年的老碼農,我的工作主要是開發後端Java業務系統,包括各種管理後臺和小程式等。在這些專案中,我設計過單/多租戶體系系統,對接過許多開放平臺,也搞過訊息中心這類較為複雜的應用,但幸運的是,我至今還沒有遇到過線上系統由於程式碼崩潰導致資損的情況。這其中的原因有三點:一是業務系統本身並不複雜;二是我一直遵循某大廠程式碼規約,在開發過程中儘可能按規約編寫程式碼;三是經過多年的開發經驗積累,我成為了一名熟練工,掌握了一些實用的技巧。
介面引數是導致很多BUG產生的始作俑者,原因在於介面引數有3多:介面引數的取值地方多,如查詢引數(Query Parameters)、路徑引數(Path Parameters)、請求體(Request Body)等;資料型別多,如數位、字元、日期、檔案等;判斷情況多,如空值判斷、格式判斷、大小判斷等;
範例程式碼如下:
@GetMapping("/testParams1")
public ResponseEntity<String> testParams1(String param1, Integer param2) {
return ResponseEntity.ok(MessageFormat.format("param1:[{0}];param2:[{1}]", param1, param2));
}
呼叫請求:http://localhost:8080/testParams1?param1=111¶m2=222
返回如下:
沒啥坑。
範例程式碼如下
@GetMapping("/testParams2")
public ResponseEntity<String> testParams2(ParamsReq paramsReq) {
return ResponseEntity.ok(MessageFormat.format("param1:[{0}];param2:[{1}]", paramsReq.getParam1(), paramsReq.getParam2()));
}
ParamsReq.java
public class ParamsReq {
private String param1;
private String param2;
public ParamsReq() {
}
public ParamsReq(String param1, String param2) {
this.param1 = param1;
this.param2 = param2;
}
public String getParam1() {
return param1;
}
public void setParam1(String param1) {
this.param1 = param1;
}
public String getParam2() {
return param2;
}
public void setParam2(String param2) {
this.param2 = param2;
}
@Override
public String toString() {
return "ParamsReq{" +
"param1='" + param1 + '\'' +
", param2='" + param2 + '\'' +
'}';
}
}
呼叫請求:http://localhost:8080/testParams2?param1=111¶m2=222
返回如下:
這種有一個坑,Spring預設使用無參建構函式來範例化物件,所以ParamsReq不能是介面、抽象類等特殊類。
範例程式碼如下:
@PostMapping("/testParams3")
public ResponseEntity<String> testParams3(ParamsReq paramsReq) {
return ResponseEntity.ok(MessageFormat.format("param1:[{0}];param2:[{1}]", paramsReq.getParam1(), paramsReq.getParam2()));
}
ParamsReq類程式碼同上
和GET請求類似,沒啥坑。
沒啥坑。
這裡有坑了,當content-type為application/json時,介面引數取值為空。這時就需要在引數前加上一個註解:
@RequestBody
,原因是通過@RequestBody
註解,Spring Boot可以自動地將請求體中的JSON資料轉換為Java物件,從而方便地進行資料的處理和轉換。如果不加@RequestBody
註解,Spring Boot預設會將請求體中的JSON資料作為普通的表單資料來處理,而不會自動轉換為Java物件。:
改成這樣就行:
public ResponseEntity<String> testParams3(@RequestBody ParamsReq paramsReq)
範例程式碼如下:
@GetMapping("/testParams4/{pathParam}")
public ResponseEntity<String> testParams4(@PathVariable("pathParam") String pathParam) {
return ResponseEntity.ok(MessageFormat.format("pathParam:[{0}];", pathParam));
}
引數使用
{
和}
框起來,然後使用@PathVariable
即可獲取到值,坑不多。
這兩種情況裡面的引數主要是標識類的引數如userToken,一般都是不變的,業務中很少使用到。
沒啥坑。
範例程式碼如下:
@GetMapping("/testParams5")
public ResponseEntity<String> testParams5(Date date) {
return ResponseEntity.ok(MessageFormat.format("pathParam:[{0}];", date));
}
這裡有個問題,這樣的介面前端怎麼傳這個
date
值,字串?時間戳?我已經替大家試過了,都不行,介面直接報400。
正確的做法是在日期引數前加上@DateTimeFormat註解,改成這樣就行了:
public ResponseEntity<String> testParams5(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date)
。
傳參的話傳字串:2023-09-14 00:00:00 即可
範例程式碼如下:
@GetMapping("/testParams6")
public ResponseEntity<String> testParams6(List<Integer> paramList) {
return ResponseEntity.ok(MessageFormat.format("paramList:[{0}];", paramList));
}
這串程式碼不用測試,它本身就是錯誤的,前面說過Spring預設使用無參建構函式來範例化物件,但是List是一個介面,沒有無參建構函式。
為了解決這個問題,可以使用Spring的@RequestParam
註解來指定引數名,並將多個引數值繫結到一個List物件中。
修改程式碼如下:
public String testParams6(@RequestParam("paramList") List<Integer> paramList)
即可
然後,通過使用逗號分隔的引數值來存取介面,如:http://localhost:8080/testParams6?paramList=1,2,3
這樣就可以成功傳遞參數列並存取介面了。
先寫一個簡單上傳介面
upload.html
<!DOCTYPE html>
<html>
<head>
<title>File Upload Demo</title>
</head>
<body>
<h1>File Upload Demo</h1>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<br/><br/>
<input type="submit" value="Upload" />
</form>
</body>
</html>
後端上傳程式碼
FileUploadController.java
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class FileUploadController {
@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
// Check if file is empty
if (file.isEmpty()) {
return new ResponseEntity<>("File is empty", HttpStatus.BAD_REQUEST);
}
// Save the file
try {
byte[] bytes = file.getBytes();
// Logic to save the file to a desired location
return new ResponseEntity<>("File uploaded successfully", HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>("Failed to upload file", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
上傳介面後端其實還好,主要是前端需要處理的內容多一些,由於MultipartFile類也是一個介面,所以這裡也需要加上
@RequestParam
註解。
前面提到的@RequestBody
、@RequestParam
註解都是SpringBoot自帶的,它們主要的功能是將請求引數轉換為我們介面定義的變數或者Java物件,而校驗引數值是否合法通常有下面幾種做法:
@NotNull
、@NotBlank
這裡主要講一下javax.validation如何使用!
<!-- 介面引數校驗 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
註解 | 說明 | 使用頻率 |
---|---|---|
@NotNull | 不能為null,常用於數位、日期 | 常用 |
@NotBlank | 不能為null也不能為空,常用於字串 | 常用 |
@NotEmpty | 集合不能為空,常用於List、Map、Set | 常用 |
註解 | 說明 | 使用頻率 |
---|---|---|
@Max | 被註釋的元素必須小於等於指定的值 | 常用 |
@Min | 被註釋的元素必須大於等於指定的值 | 常用 |
@Positive | 被註釋的元素必須是正數 | 不常用 |
@Negative | 被註釋的元素必須是負數 | 不常用 |
註解 | 說明 | 使用頻率 |
---|---|---|
@AssertFalse | 被註釋的元素必須是false | 常用 |
@AssertTrue | 被註釋的元素必須是true | 常用 |
註解 | 說明 | 使用頻率 |
---|---|---|
@Future | 被註釋的元素必須是將來的日期 | 不常用 |
@Past | 被註釋的元素必須是過去的日期 | 不常用 |
註解 | 說明 | 使用頻率 |
---|---|---|
被註釋的元素必須是電子郵箱地址 | 常用 | |
@Pattern | 被註釋的元素必須是符合正規表示式,我經常使用這個判斷手機號是否合法 | 常用 |
下面是一個經典的案例
@Data
public class StudentReq {
@NotBlank(message = "主鍵不能為空")
private String id;
@NotBlank(message = "名字不能為空")
@Size(min = 2, max = 4, message = "名字字元長度必須為 2~4個")
private String name;
@Pattern(regexp = "^1[3456789]\\d{9}$", message = "手機號格式錯誤")
private String phone;
@Email(message = "郵箱格式錯誤")
private String email;
@Past(message = "生日必須早於當前時間")
private Date birth;
@Min(value = 0, message = "年齡必須為 0~100")
@Max(value = 100, message = "年齡必須為 0~100")
private Integer age;
@PositiveOrZero
private Double score;
}
這些東西看看就行了,用的時候翻一下檔案就行,記也記不住。
這些物件可以直接在介面引數上使用,通過框架自動注入的方式獲取其範例。在使用時,需要保證框架已經正確設定和啟用了對應的註解和攔截器。用的最多的就是HttpServletRequest和HttpServletResponse了。
本文來自部落格園,作者:sum墨,轉載請註明原文連結:https://www.cnblogs.com/wlovet/p/17700353.html