簡單地聊一聊Spring Boot的構架

2023-11-14 12:02:09

本文由葡萄城技術團隊釋出。轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。

前言

本文小編將詳細解析Spring Boot框架,並通過程式碼舉例說明每個層的作用。我們將深入探討Spring Boot的整體架構,包括展示層、業務邏輯層和資料存取層。通過這些例子,讀者將更加清晰地瞭解每個層在應用程式中的具體作用。通過程式碼範例,我們將幫助讀者更好地理解和應用Spring Boot框架,從而提高應用程式的可維護性和可延伸性。

什麼是Spring Boot

在介紹Spring Boot框架的分層之前,小編先為大家介紹一下什麼是Spring Boot:

Spring Boot是一個基於Spring框架的開發框架,旨在簡化Spring應用程式的搭建和開發。Spring Boot提供了很多自動化設定的功能,可以快速地搭建一個基於Spring的Web應用程式,而不需要手動進行繁瑣的設定。

Spring Boot可以幫助開發人員快速構建各種型別的應用程式,包括Web應用程式、RESTful服務、批次處理應用程式和基於訊息的應用程式等。它採用Java程式語言,並且可以與各種其他技術整合,例如Thymeleaf、MongoDB、Redis等。

Spring Boot還提供了很多有用的工具和外掛,例如Spring Boot CLI(命令列介面),可以幫助開發人員更加便捷地建立、執行和測試Spring Boot應用程式。此外,Spring Boot還支援各種構建工具,例如Maven和Gradle,以及各種開發環境,例如Eclipse和IntelliJ IDEA。

Spring Boot分層:

Spring Boot主要分為4層:Controller層、Service層、Repository/DAO層和Model層。

1. Controller層

在SpringBoot中,Controller層是MVC(Model-View-Controller)模式中的控制器部分,負責處理來自使用者發起的HTTP請求,並返回相應的響應結果。Controller層接收到請求後,通常會呼叫Service層進行業務邏輯處理,最後再將處理結果封裝成響應物件並返回給前端。

一個Controller類通常包含多個方法,每個方法對應一個不同的HTTP請求路徑,並使用特定的註解來標識。例如,使用@GetMapping註解表示該方法處理GET請求,@PostMapping表示該方法處理POST請求。同時,通過@RequestParam註解可以獲取請求引數,@PathVariable註解可以獲取URL路徑引數,@RequestBody註解可以獲取請求體中的資料。

2. Service層

在Spring Boot中,Service層是應用程式的一部分,負責處理業務邏輯和協調不同的元件。它是控制器(Controller)和資料存取層(Repository)之間的中間層,用於將業務邏輯與資料操作解耦。

Service層的主要職責可以總結如下:

  1. 執行業務邏輯:Service層負責實現應用程式的業務邏輯。它包含了具體的業務規則和操作流程,以滿足需求和業務規定。例如,對於電子商務應用程式,Service層可能會包含建立訂單、處理支付、驗證庫存等業務邏輯的實現。
  2. 協調資料存取:Service層充當控制器和資料存取層之間的橋樑。它通過呼叫相應的Repository介面來執行資料操作,如查詢資料庫、儲存資料、更新資料等。Service層可以組織和協調多個Repository操作,以完成複雜的業務需求。
  3. 提供業務介面:Service層可以定義一些公共介面或方法,供其他元件(如控制器、其他Service等)使用。這樣可以封裝底層的業務邏輯實現,使其對外提供統一的介面。這種封裝有助於提高程式碼的可維護性和重用性。
  4. 處理事務管理:Service層通常涉及到資料庫的讀寫操作,需要保證資料的一致性和完整性。通過使用Spring框架提供的事務管理機制,Service層可以確保多個資料庫操作在一個事務中執行。它可以定義事務的邊界、隔離級別、回滾策略等,以確保資料操作的正確性和可靠性。
  5. 實現業務規則和驗證:Service層可以包含對傳入資料的驗證和處理邏輯。例如,對於使用者註冊操作,Service層可能會對輸入的使用者名稱進行唯一性檢查,對密碼進行加密等。這樣可以保證應用程式的安全性和資料的有效性。

3. Repository/DAO層

DAO全稱是Data Access Object,其主要目標是從資料庫高效獲取(查詢)資料,併為service層提供服務。

Repository/DAO層的主要職責可以總結如下:

  1. 定義資料存取介面:Repository或DAO層定義了存取資料庫的介面,它們通常包括各種讀、寫、更新、刪除等操作。這些操作通過方法呼叫來實現,使得業務邏輯可以輕鬆地使用這些操作。
  2. 提供資料對映:Repository或DAO層負責將資料庫中的資料對映到Java類或物件中。這種對映可以是簡單的一對一關係,也可以是複雜的關聯關係。通常情況下,開發人員會使用ORM框架(如Hibernate)來自動完成資料對映。
  3. 處理資料存取異常:Repository或DAO層負責處理與資料存取相關的異常情況,例如資料庫連線失敗、SQL語句執行錯誤等。它們可以捕獲這些異常並進行相應的處理,以保證應用程式的穩定性和可靠性。
  4. 支援資料來源設定:Repository或DAO層支援不同型別的資料來源設定,例如關係型資料庫、NoSQL資料庫、檔案系統等。它們可以根據不同的資料來源型別,提供相應的資料存取介面和資料對映策略。
  5. 提供資料快取:Repository或DAO層可以快取已經讀取的資料,以提高應用程式的效能。它們可以使用記憶體快取、分散式快取等不同型別的快取機制,根據業務需求進行選擇。

4. Model層

在Spring Boot中,Model層物件是用於封裝和傳遞資料的Java物件。它表示應用程式中的業務資料,並負責處理資料的獲取、儲存和修改等操作。Model層物件通常具有以下特點:

  1. 實體類(Entity Class):Model層物件通常是實體類或POJO(Plain Old Java Object),用於表示業務資料的結構。實體類的屬性對應資料庫表的欄位,通過ORM(Object-Relational Mapping)框架可以將實體類與資料庫進行對映。
  2. 資料傳輸物件(Data Transfer Object,DTO):在一些場景下,為了滿足特定的需求,可能需要使用DTO來封裝資料。DTO是一個簡單的Java物件,用於在不同的層之間傳輸資料。DTO通常只包含必要的屬性,以減少資料傳輸的大小和複雜性。
  3. 資料校驗(Data Validation):Model層物件可以用於資料校驗,確保傳入的資料符合特定的規則和要求。可以使用註解(如javax.validation.constraints)或其他驗證框架(如Hibernate Validator)對屬性進行校驗。
  4. 業務邏輯(Business Logic):Model層物件可以包含一些業務邏輯的方法,用於處理資料的計算、轉換和操作等。這些方法可以在Model層物件中定義,或者在服務層(Service Layer)中進行實現。

程式碼範例:

1.Controller層:

ProjectController.java

package com.example.Controller;
//import statements goes here
@RestController
public class UserController {
   
    //List all the available projects
    @GetMapping(path = "/projects", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Project>> getProjects() {
     
    // perform validation checks
    // return the services provided by service layer
    }
    //Apply for the project
    @PostMapping(path = "/apply-project", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<HttpStatus> applyProject(@RequestBody Map<String,String> json) {
    // perform validation checks
    // return the services provided by service layer
    }
    
    //Upload resume
    @PostMapping(path = "/upload-resume/{usn}")
    public ResponseEntity<List<Object>> uploadToDB(@RequestParam("file") MultipartFile[] file,@PathVariable String usn) {
    
    // perform validation checks
    // return the services provided by service layer
    }
    //Download resume
    @GetMapping("/files/download/{fileName:.+}")
    public ResponseEntity downloadFromDB(@PathVariable String fileName) {
    // perform validation checks
    // return the services provided by service layer
    }
}

上面例子使用了@GetMapping和@PostMapping:

@GetMapping註解用於將一個方法對映到指定的HTTP GET請求。它可以用於處理瀏覽器直接存取某個URL或者其他應用程式發起GET請求的情況。通過在方法上新增@GetMapping,我們可以定義一個處理該請求的方法,並在方法中編寫相應的業務邏輯。

@PostMapping註解用於將一個方法對映到指定的HTTP POST請求。它可以用於處理表單提交、使用者端資料上傳等操作。通過在方法上新增@PostMapping,我們可以定義一個處理該請求的方法,並在方法中編寫相應的業務邏輯。

2.Service層:

下面這段定義了專案相關的服務方法,並規定這些方法的輸入引數和返回值。

在程式碼範例中,ProjectService 介面宣告了三個方法:

  1. getProjects() 方法返回一個 List<Project> 物件作為響應體(ResponseEntity),用於獲取所有專案資訊。
  2. applyProject(String USN,int project_id) 方法返回 HttpStatus 列舉值,表示申請參與某個專案的狀態。
  3. uploadProjectDocument(MultipartFile[] files,int project_id) 方法返回 List<Object> 物件作為響應體,用於上傳專案檔案。

ProjectService.java

package com.example.Service;

// import statements

public interface ProjectService {

    ResponseEntity<List<Project>> getProjects();

    HttpStatus applyProject(String USN,int project_id);

    ResponseEntity<List<Object>> uploadProjectDocument(MultipartFile[] files,int project_id);

}

ProjectServiceImpl.java

package com.example.Service;

//import statements
@Service
public class ProjectServiceImpl implements ProjectService {
//dependency injection of DAO to be gone here (Autowire)
  
    @Override
    public ResponseEntity<List<Project>> getProjects() {
        try {
           //Business logic implementation using DAO services
        } catch (Exception e) {
            return new ResponseEntity<>(null,HttpStatus.INTERNAL_SERVER_ERROR) ;
        }
    }
   
    @Override
    public HttpStatus applyProject(String USN, int project_id) {
   
    //Business logic implementation using DAO services
    }
  
   //helper functions
    public ResponseEntity uploadToLocalFileSystem(MultipartFile file,int project_id) {
     
    }
    @Override
    public ResponseEntity<List<Object>> uploadProjectDocument(MultipartFile[] files,int project_id) {
       //Business logic implementation using DAO services
    }

}

3.Repository/DAO層:

下面的這段程式碼是一個介面類,屬於包名為"com.example.Dao"的專案資料存取物件(DAO)。它擴充套件了 JpaRepository<Project, Integer> 介面,該介面提供了基本的CRUD(建立、讀取、更新、刪除)操作方法,用於對資料庫中的 "Project" 實體進行操作。

ProjectDAO.java

package com.example.Dao;

//import statements

public interface ProjectDao extends JpaRepository<Project,Integer> {

//You can also include native queries on top of CRUD operations provided by JPA
// Add queries here using @Query annotations and corresponding functions

    @Query(value = "Your SQL query ",nativeQuery = true)
    public List<Project> getProjects();

}

}

4.Model層:

下面這段程式碼定義了一個名為 "Project" 的實體類,表示一個專案。它包含了專案的各個屬性(如專案ID、公司名稱、描述、要求等),並與其他實體類(如員工、學生、檔案、資金等)之間建立了關聯關係。通過使用 JPA 註解,該類可以方便地進行資料庫操作和查詢。

程式碼中的各個部分的含義如下:

  1. @Entity 註解表示該類是一個實體類,與資料庫中的表進行對映。
  2. @Table(name = "project") 註解指定了對應的資料庫表名為 "project"。
  3. @Id 註解表示該欄位是主鍵。
  4. @GeneratedValue(strategy = GenerationType.IDENTITY) 註解指定了主鍵的生成策略為自增長。
  5. @Column 註解用於指定該屬性與資料庫表中的列的對映關係,其中 nullable 屬性表示該列是否允許為空,name 屬性指定了對應的資料庫列名。
  6. @JsonIgnore 註解用於忽略該屬性在序列化和反序列化過程中的處理。
  7. @ManyToMany(mappedBy="funded_projects") 註解表示當前實體與另一個實體 Fund 之間存在多對多的關聯關係,通過 mappedBy 屬性指定了在 Fund 實體中維護關聯關係的屬性名為 "funded_projects"。
  8. Set<Staff>, Set<Student>, Set<Document>, Set<Fund> 表示與其他實體之間的關聯關係,通過集合型別的屬性來表示多對多關係或一對多關係。

Project.java

package com.example.Entity;

//import statements

@Entity
@Table(name = "project")
public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int project_id;
    @Column(nullable = false, name = "company_name")
    private String company_name;

    @Column(nullable = false, name = "description")
    private String description;

    @Column(nullable = false, name = "requirements")
    private String requirements;

    @Column(nullable = false, name = "manager")
    private String manager;
    @Column(nullable = false, name = "start_date")
    private Date start_date = new Date();

    @Column( name = "end_date")
    private Date end_date = new Date();
    @Column(nullable = false,name = "opening")
    private int opening;
    @Column(name = "resources")
    private String resources;
    public Set<Staff> getStaff_incharge() {
        return staff_incharge;
    }
    public void setStaff_incharge(Set<Staff> staff_incharge) {
        this.staff_incharge = staff_incharge;
    }
    public Set<Student> getApplied_students() {
        return applied_students;
    }
    public Set<Document> getDocuments() {
        return documents;
    }
    public void setDocuments(Set<Document> documents) {
        this.documents = documents;
    }
    @JsonIgnore
    @ManyToMany(mappedBy="funded_projects")
    private Set<Fund> funds;
    public Set<Fund> getFunds() {
        return funds;
    }
    public void setFunds(Set<Fund> funds) {
        this.funds = funds;
    }
    public void setApplied_students(Set<Student> applied_students) {
        this.applied_students = applied_students;
    }
    public Set<Student> getWorking_students() {
        return working_students;
    }
    public void setWorking_students(Set<Student> working_students) {
        this.working_students = working_students;
    }
//constructors
    public Project() {
        super();
    }
    public Project(int project_id, String company_name, String description, String requirements, String manager, Date start_date, Date end_date, int opening, String resources) {
        super();
        this.project_id = project_id;
        this.company_name = company_name;
        this.description = description;
        this.requirements = requirements;
        this.manager = manager;
        this.start_date = start_date;
        this.end_date = end_date;
        this.opening = opening;
        this.resources = resources;
    }
    public int getProject_id() {
        return project_id;
    }
    public void setProject_id(int project_id) {
        this.project_id = project_id;
    }
    public String getCompany_name() {
        return company_name;
    }
    public void setCompany_name(String company_name) {
        this.company_name = company_name;
    }

    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getRequirements() {
        return requirements;
    }
    public void setRequirements(String requirements) {
        this.requirements = requirements;
    }
    public String getManager() {
        return manager;
    }
    public void setManager(String manager) {
        this.manager = manager;
    }
    public Date getStart_date() {
        return start_date;
    }
    public void setStart_date(Date start_date) {
        this.start_date = start_date;
    }
    public Date getEnd_date() {
        return end_date;
    }
    public void setEnd_date(Date end_date) {
        this.end_date = end_date;
    }
    public int getOpening() {
        return opening;
    }
    public void setOpening(int opening) {
        this.opening = opening;
    }
    public String getResources() {
        return resources;
    }
    public void setResources(String resources) {
        this.resources = resources;
    }
    @Override
    public String toString() {
        return "Project{" +
                "project_id=" + project_id +
                ", company_name='" + company_name + '\'' +
                ", description='" + description + '\'' +
                ", requirements='" + requirements + '\'' +
                ", manager='" + manager + '\'' +
                ", start_date=" + start_date +
                ", end_date=" + end_date +
                ", opening=" + opening +
                ", resources='" + resources + '\'' +
                '}';
    }
}

總結

本文為讀者詳細介紹了Spring Boot框架的四層構架,以及如何使用各種技術和工具來進行開發。通過閱讀本文,希望可以幫助讀者可以更好地理解Spring Boot框架的工作原理和應用場景,並能夠利用所學知識來實現自己的專案。

參考資料:《Understanding Spring Boot Architecture》

擴充套件連結:

Redis從入門到實踐

一節課帶你搞懂資料庫事務!

Chrome開發者工具使用教學

從表單驅動到模型驅動,解讀低程式碼開發平臺的發展趨勢

低程式碼開發平臺是什麼?

基於分支的版本管理,幫助低程式碼從專案交付走向客製化化產品開發