目錄
- <<回到導覽
- Spring boot
- 1. http協議
- 1.1.請求協議
- 1.2.響應協議
- 2.Tomcat
- 2.1.請求
- 2.1.1.apifox
- 2.1.2.簡單參數
- 2.1.3.實體參數
- 2.1.4.數組集合參數
- 2.1.5.日期參數
- 2.1.6.(重點)JSON參數
- 2.1.7.路徑參數
- 2.2.響應
- 2.3.綜合練習
- 3.三層架構
- 3.1.三層拆分
- 3.2.分層解耦
- 3.3.補充
<<回到導覽
Spring boot
Spring boot官網
簡介:Spring Boot 基于Spring,簡化了配置,降低的入門難度,可以幫助我們非常快速的構建應用程序、簡化開發、提高效率
需求:使用 SpringBoot 開發一個web應用,瀏覽器發起請求 /hello后,給瀏覽器返回字符串 “Hello World ~”
-
創建spring boot項目(保證網絡間接正常)
-
刪除一些暫時不用的文件
-
在包下創建文件
-
編寫這個文件
// 請求處理類 @RestController public class HelloController {// 表名這個請求處理類,處理的是“/hello”@RequestMapping("/hello")public String Hello() {System.out.println("Hello World");return "Hello World!!!";} }
運行啟動類(SpringDemoApplication)
-
訪問服務
訪問
http://localhost:8080/hello
或者http://127.0.0.1:8080/hello
每訪問一次這個服務,控制臺還會打印一次Hello World
1. http協議
概念:Hyper Text Transfer Protocol, 超文本傳輸協議,規定了瀏覽器和服務器之間數據傳輸的規則。
特點:
- 基于TCP協議:面向連接,安全
- 基于請求-響應模型的:一次請求對應一次響應
- HTTP協議是無狀態的協議:對于事務處理沒有記憶能力。每次請求-響應都是獨立的。
- 缺點:多次請求間不能共享數據。
- 優點:速度快
1.1.請求協議
請求方式 | 請求參數位置 | 請求大小 |
---|---|---|
GET | 在請求行(沒有請求體) | 有大小限制 |
POST | 在請求體 | 沒有大小限制 |
-
GET請求
-
POST請求
1.2.響應協議
響應協議和POST請求有些相似,分為響應行、響應頭、響應體,響應數據放在響應體里面
狀態碼 | 說明 |
---|---|
1xx | 臨時狀態碼,表示請求已經接收,應該繼續請求或者如果它已經完成則忽略它。 |
2xx | 成功接收,處理已完成。 |
3xx | 重定向到其他地方;讓客戶端再發起一次請求以完成整個處理。 |
4xx | 客戶端錯誤,責任在客戶端。(如:請求了不存在的資源、客戶端未被授權、禁止訪問等。) |
5xx | 服務器錯誤,責任在服務端。(如:程序拋出異常等)。 |
常用狀態碼 | 解釋 |
---|---|
200 | 處理成功 |
302/304 | location重定向/隱式重定向 |
400 | 客戶端語法錯誤 |
403 | 服務器拒絕提供服務(沒有權限) |
404 | 請求資源不存在(url錯誤) |
405 | 請求方式有誤 |
500 | 服務器發生不可預期的錯誤 |
503 | 服務器尚未準備好處理請求 |
2.Tomcat
Web服務器是一個軟件程序,對HTTP協議的操作進行封裝,簡化web服務器開發
作用:部署web項目,對外提供網上信息瀏覽服務
Tomcat:一個輕量級的web服務器,支持servlet、jsp等少量avaEE規范。也被稱為web容器、servlet容器。
起步依賴:利用maven中依賴傳遞的特性,把開發某一個功能常見的依賴整合在一起(如web)
在spring boot web開發環境中,已經集成了Tomcat
2.1.請求
2.1.1.apifox
apifox官網:https://app.apifox.com/
apifox使用教程:https://www.bilibili.com/video/BV1Jc41147xC
在使用apifox之前要安裝插件Apifox Browser Extension
:
嘗試用apifox測試接口
2.1.2.簡單參數
簡單參數:參數名和變量名相同,定義形參即可接收參數
@RestController
public class RequestController {@RequestMapping("/simpleParam")public String simpleParam(String name, int age) {System.out.println(name + ":" + age);return "OK";}
}
如果方法形參名稱與請求參數名稱不匹配,不能接收值,但是不會報錯
這時,可以使用@RequestParam
完成映射,但是該注解的required屬性默認是true,代表請求參數必須傳遞
@RestController
public class RequestController {@RequestMapping("/simpleParam")public String simpleParam(@RequestParam(name = "name") String username, int age) {System.out.println(username + ":" + age);return "OK";}
}
2.1.3.實體參數
實體參數:多個參數名和形參變量名相同,定義POJO接收即可
@RestController
public class RequestController {@RequestMapping("/simplePojo")public String simpleParam(User user) {System.out.println(user);return "OK";}
}
public class User{private String name;private int age;// Getter、Setter、toString
}
-
示例
為上面用戶添加地址信息(包含省份和城市)
@RestController public class RequestController {@RequestMapping("/complexPojo")public String complexPojo(User user) {System.out.println(user);return "OK";} }
public class User{private String name;private int age;private Address address;// Getter、Setter、toString }
public class Address {private String province;private String city;// Getter、Setter、toString }
2.1.4.數組集合參數
-
數組參數:請求參數名與形參數組名稱相同,定義數組類型形參即可接收參數
@RestController public class RequestController {@RequestMapping("/arrayParam")public String arrayParam(String[] hobby) {System.out.println(Arrays.toString(hobby));return "OK";} }
-
集合參數:請求參數名與形參集合名稱相同,通過
@RequestParam
綁定參數關系@RestController public class RequestController {@RequestMapping("/listParam")public String listParam(@RequestParam List<String> hobby) {System.out.println(hobby);return "OK";} }
2.1.5.日期參數
日期參數:使用@DateTimeFormat注解完成日期參數格式的轉換
@RestController
public class RequestController {@RequestMapping("/dateParam")public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")LocalDateTime updateTime) {System.out.println(updateTime);return "OK";}
}
2.1.6.(重點)JSON參數
JSON參數:JSON數據鍵名和形參屬性名相同,定義POJO類型形參即可接收參數,需要使用@RequestBody
標識
在上面的請求中,都是用的GET請求方式,請求參數在請求行,但利用json字符串傳參要用POST請求方式,請求參數在請求體
-
例如:
{"name":"Tom","age":18,"address":{"province":"四川","city":"成都"} }
-
json參數傳遞
@RestController public class RequestController {@RequestMapping("/jsonParam")public String jsonParam(@RequestBody User user) {System.out.println(user);return "OK";} }
2.1.7.路徑參數
路徑參數:通過URL直接傳遞參數,使用{}
來標識該路徑參數,需要使用@RequestMapping
獲取路徑參數
@RestController
public class RequestController {@RequestMapping("/pathParam/{id}")public String pathParam(@PathVariable Integer id) {System.out.println(id);return "OK";}
}
-
傳遞多個路徑參數
@RestController public class RequestController {@RequestMapping("/pathParam/{id}/{uid}")public String pathParam(@PathVariable Integer id, @PathVariable Integer uid) {System.out.println(id + "," + uid);return "OK";} }
2.2.響應
@RestController
注解包含了@ResponseBody注解@Controller注解
-
統一響應結果:
- 響應碼
- 提示信息
- 返回的數據
// Result public class Result {private Integer code ;//1 成功 , 0 失敗private String msg; //提示信息private Object data; //數據 datapublic Result() {}public Result(Integer code, String msg, Object data) {this.code = code;this.msg = msg;this.data = data;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public static Result success(Object data){return new Result(1, "success", data);}public static Result success(){return new Result(1, "success", null);}public static Result error(String msg){return new Result(0, msg, null);}@Overridepublic String toString() {return "Result{" +"code=" + code +", msg='" + msg + '\'' +", data=" + data +'}';} }
-
改寫請求
@RequestMapping("/simpleParam") public Result simpleParam(String name, int age) {System.out.println(name + ":" + age);return Result.success("Hello World"); }
2.3.綜合練習
獲取員工數據,返回統一響應結果,在頁面中渲染(相關資料可以在黑馬官方公眾號下載)
-
在pom.xml文件中引入dom4j的依賴,用于解析XML文件
<!-- 解析xml --> <dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version> </dependency>
-
引入資料中提供的解析XML的工具類XMLParserUtils、對應的實體類Emp、XML文件 emp.xml
-
引入資料中提供的靜態頁面文件,放在resources下的static目錄下
-
編寫Controller程序,處理請求,響應數據
@RestController public class EmpController {@RequestMapping("/listEmp")public Result list() {// 1. 加載解析xmlString file = "D:\\桌面\\Java\\Java(下)\\spring_demo\\src\\main\\resources\\emp.xml";List<Emp> empList = XmlParserUtils.parse(file, Emp.class);// 2. 對數據進行轉換處理empList.forEach(emp -> {String gender = emp.getGender();if("1".equals(gender)) {emp.setGender("男");}else if("2".equals(gender)) {emp.setGender("女");}String job = emp.getJob();if("1".equals(job)) {emp.setJob("教師");}else if("2".equals(job)) {emp.setGender("學生");}});// 3. 響應數據return Result.success(empList);} }
-
嘗試發送請求
-
通過瀏覽器訪問前端頁面
3.三層架構
在上一節的綜合練習中,代碼的不同的業務邏輯寫在了一起,導致代碼復用性差,難以維護
為此設計了三層架構來優化
功能分類 | 對應層 | 說明 |
---|---|---|
數據訪問 | controller(控制層) | 接收前端發送的請求,對請求進行處理,并響應數據 |
邏輯處理 | service(業務邏輯層) | 處理具體的業務邏輯 |
接收請求、響應數據 | dao(數據訪問層,Data Access Object) | 數據訪問操作(包括增、刪、改、查) |
controller => service => dao (=>表示調用關系)
3.1.三層拆分
我們將上面三部分的代碼分別寫到對應層,每個對應層有一個接口(要做的事情),每個接口可以有若干個實現方案(實現類)
-
數據訪問層(dao)
// 接口 public interface Empdao {// 獲取員工列表public List<Emp> empList(); }
// 實現類 public class EmpDaoA implements Empdao {@Overridepublic List<Emp> empList() {// 1. 加載解析xmlString file = "D:\\桌面\\Java\\Java(下)\\spring_demo\\src\\main\\resources\\emp.xml";List<Emp> empList = XmlParserUtils.parse(file, Emp.class);return empList;} }
-
業務邏輯層(service)
// 接口 public interface EmpService {public List<Emp> empList(); }
// 實現類 public class EmpServiceA implements EmpService {private Empdao empdao = new EmpDaoA();@Overridepublic List<Emp> empList() {// 調用dao層接口List<Emp> empList = empdao.empList();// 2. 對數據進行轉換處理empList.forEach(emp -> {String gender = emp.getGender();if("1".equals(gender)) {emp.setGender("男");}else if("2".equals(gender)) {emp.setGender("女");}String job = emp.getJob();if("1".equals(job)) {emp.setJob("教師");}else if("2".equals(job)) {emp.setGender("學生");}});return empList;} }
-
控制層(controller)
@RestController public class EmpController {private EmpService empService = new EmpServiceA();@RequestMapping("/listEmp")public Result list() {// 3. 響應數據return Result.success(empService.empList());} }
3.2.分層解耦
- 內聚:軟件中各個功能模塊內部的功能聯系。
- 耦合:衡量軟件中各個層/模塊之間的依賴、關聯的程度。
- 軟件設計原則:高內聚低耦合
在上節的三層拆分中,三個層級耦合性比較高,我們要降低耦合性
控制反轉(IOC):對象的創建控制器由程序自身轉移到外部(容器),通過
@Component
注解實現
依賴注入(DI):容器為應用程序提供運行時所依賴的資源,通過
@Autowired
注解實現
-
Service層、Dao層的實現類,交給IOC容器管理(控制反轉)
// Service層 @Component public class EmpServiceA implements EmpService {private Empdao empdao;// ... }
// Dao層 @Component public class EmpDaoA implements Empdao {// ... }
-
為Controller層、Service層注入運行時依賴的對象(依賴注入)
@RestController public class EmpController {@Autowiredprivate EmpService empService;// ... }
// Service層 @Component public class EmpServiceA implements EmpService {@Autowired // 程序在運行時,IOC容器會提供該類型的bean對象,并賦值給該變量private Empdao empdao;// ... }
3.3.補充
注解 | 聲明 | 位置 |
---|---|---|
@Component | bean的基礎注解 | 不屬于以下三類時,用此注解(eg:工具類) |
@Controller | @Component的衍生注解 | 標注在控制器類上(@RestController注解已包括,一般不寫) |
@Service | @Component的衍生注解 | 標注在業務邏輯類上 |
@Repository | @Component的衍生注解 | 標注在數據訪問類上(由于與mybatis整合,用的少) |
了解:
- 聲明bean的時候,可以通過value屬性指定bean的名字,如果沒有指定,默認為類名首字母小寫。
- 前面聲明bean的四大注解,要想生效,還需要被組件掃描注解@ComponentScan掃描。
- @ComponentScan注解雖然沒有顯式配置,但是實際上已經包含在了啟動類聲明注解 @SpringBootApplication 中,默認掃描的范圍是啟動類所在包及其子包。