JavaRush /Java Blog /Random-TW /征服 Spring Boot
Surplus
等級 37
Москва

征服 Spring Boot

在 Random-TW 群組發布
美好的一天,親愛的讀者!很高興認識你,即使這個浮誇的名字是我們研究第一次接觸 Spring Boot 開發的樸素話題的主要原因。我想分享我在 JavaRush 入口網站上完成實習介紹性作業的經歷,從一個完全普通的技術大學生的角度來展示自己的概述,他想要測試自己所積累的知識的強度。 征服春季靴 - 1我絕不否認所附代碼或思維方法可能存在粗魯之處,我歡迎建設性的批評,因為正是有了“坎坷和碰傷”,才有可能向專業方向發展。而且,我根本不會假裝自己是解決給定條件的“萬能藥”,故意省略程式的各個片段,讓進入一個相對複雜的話題的關鍵重要性不至於對神經系統產生絲毫影響。確實,否認顯而易見的事實是魯莽的:這對我來說很難,直到某個時刻之前絕對沒有任何事情是清楚的。如果您在第一次執行任務時也有類似的感受,那麼“歡迎!” 讓我們在 Spring Boot 中編寫一個 Web 應用程序,使用實習入學考試的簡化類比,使用模板引擎Thymeleafquery查詢本地 MySQL 伺服器來過濾傳入的資訊數組。那麼就讓我們開始吧!

春季啟動。它是什麼動物以及如何烹飪?

簡而言之,它是Pivotel的一款優秀工具,可以在創建應用程式的過程中節省寶貴的時間,而無需直接連接第三方程式庫、編寫令人印象深刻的映射畫布和 servlet。使用Spring Initializr建構器就足夠了,它整合到IntelliJ IDEA Ultimate Edition中(檔案 - 新建 - 專案... - Spring Initializr)或位於start.spring.io Web 服務上,指定要包含的各種包優惠。
征服 Spring Boot - 2
按照提出的技術規範,我們將使用紳士設定的標準,並使用MySQL資料庫建立一個簡單的 Web 應用程式:
  • WEB是開發Web應用程式的主要元件,包括位於標準位址localhost:8080的本機Apache Tomcat伺服器和通用的Spring MVC框架。

  • DevTools - 當在編譯的程式碼或範本中偵測到變更時,用於在熱 JVM 中快速重新啟動應用程式;此外,如果專案中包含所選引擎,它可以使 Thymeleaf 免於清除快取。

  • JPA是一種使用資料庫所需的技術,它提供 Java 物件的物件關係映射,提供用於管理、保存和檢索實體的 API(在我們的例子中為Hibernate )。

  • Thymeleaf(Mustache、AngularJS、Vaadin 等) - 用於應用程式視覺化的模板引擎;由於我對 html 原理相對熟悉,我選擇了 Thymeleaf,它將該語言推向了世界的基石。

  • MySQL - 連接 Java 資料庫連接驅動程式以對資料庫執行 SQL 查詢。
在最終選擇元件並創建之後,我們得到了一個普通的 Web 應用程式架構,其中的目錄可供進一步填充。用於與視覺部分互動的片段,無論是 CSS 圖形樣式、標準 HTML 頁面或 JavaScript 功能,都應位於「resources」中,因此後端元件應放置在「java」中。我們還應該注意根範圍內的pom.xml文件,它儲存了專案結構和元件之間的依賴關係。如果你想用額外的套件進一步擴展功能或刪除不必要的東西,你應該<dependencies></dependencies>按照類似的方法在標籤之間進行操作。
征服 Spring Boot - 3

邁向美好未來的第一步

接下來,出現了一個相當有趣且非常合乎邏輯的問題:「現在該怎麼辦?這將如何運作?該程式建立在模型-視圖-控制器的原則之上:它組織從連接的資料庫(模型)中讀取實體,並透過控制項(視圖)顯示在使用者介面中;組件之間的通訊以及根據傳輸的請求執行操作是透過控制器進行的。關鍵要素的創建可作為持續發展的參考點。為了避免滑坡,維護工作領域戰友的尊重,應將元件放置在適當的目錄中(例如將Controller檔案放置在「java」分支的controllers資料夾中),並小心保存工作場所秩序。

本質是一個大機制中的一個小部分

或者換句話說,我們的模型是根據問題中設定的條件。離開討論的主題,回到介紹性項目,我們可以自信地斷言,任務之間的差異很小,並在進一步審查中遵循平均概念。比方說,筆記本中的筆記包括:
  • 用於確定在一般流程中的位置的識別號碼;
  • 一定字數的簡訊;
  • 用戶將其添加到常規列表的日期;
  • 用於確定“完成或未完成”(“讀取或未讀取”)的布林變數。
因此,讓我們在名為「entity」的目錄中建立一個 Note 類別並新增適當的欄位:
@Entity
public class Note {

   @Id
   @GeneratedValue
   private int id;
   private String message;
   private Date date;
   private boolean done;

   public Note() {
   }

   public Note(String message) {
       this.message = message;
       this.date = new Date();
       this.done = false;
   }
}
另一個偏離討論主題的問題是為了從理論立場更好地理解正在發生的事情。Spring中組件之間的連接是透過註解來指定的-物件前面的特殊指針,每個註解在機制中扮演特定的角色,並以「@」符號開頭。@Entity 註解向 Spring Boot 指示後續類別資料屬於“實體”,@Id 和 @GenerateValue 將選定的欄位指定為標識符,並在處理資訊數組時自動產生迭代器。我故意省略添加標準的 Getter 和 Setter 以增加視覺格式的緊湊性。接下來,考慮到使用資料庫來儲存記錄,我們進入應用程式開發的下一步:我們將在「repository」目錄中建立 NoteRepository 接口,作為交換鏈中的連接元素,並繼承最適合進一步工作的儲存庫,指示要存取的儲存實體和整數迭代器。
public interface NoteRepository extends JpaRepository<Note, Integer> {
}
事實上,僅此而已。簡潔明了。現在 Spring Boot 將使用已建立的元件來組織與資料庫的互動。遺留儲存庫的類型相對較多,具有不同的行動潛力。JpaRepository處於階梯的最頂端,最有潛力,包括下面的CrudRepository和PageAndSortingRepository。我們不會再進一步偏離主題,因為一些微妙之處可以在 Pivotel 網站的技術文件中找到。現在,在應用程式端實作資料鏡像並指定通訊方式後,您需要注意在適當的外部環境「MySQL Workbench」中建立MySQL資料庫,該資料庫在官方開發人員的程式集中預先安裝在桌面平台上使用於建立本機伺服器的附加套件:
征服 Spring Boot - 4
接下來,點擊主視窗中目前本機伺服器的圖示後,按照環境的指示,根據實體的欄位(註)建立表格圖,並填入適當的資料。有必要單獨釐清MySQL方言的微妙之處,迫切需要重視才能順利達到預期的結果:
  • 沒有單獨的布林類型本身。任何請求處理動作都會將「true」或「false」分別轉換為位元值「1」或「0」;
  • 日期完全儲存在 Timestamp 類型中。如果您使用核心熟悉的日期,您將不得不將自己限制在日曆中的位置。
征服 Spring Boot - 5
最終完成準備步驟後,我們點擊工具列上的「閃電」圖標,指示「MySQL Workbench」將資料傳送到本機伺服器。現在,如果新增資訊正確完成,我們可以透過將目前資料庫配置新增至 application.properties (通常位於「resources」目錄中),自信地回到本機 IDE 繼續開發:
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
最後使用註解將 Note 實體綁定到 MySQL。@Table 表示使用具有選定名稱和架構的表,@Column 表示變數屬於特定欄位。
@Entity
@Table(name = "test", schema = "test", catalog = "")
public class Note {

   @Id
   @GeneratedValue
   private int id;
   @Column(name = "message")
   private String message;
   @Column(name = "date")
   private Date date;
   @Column(name = "done")
   private boolean done;

   public Note() {
   }

   public Note(String message) {
       this.message = message;
       this.date = new Date();
       this.done = false;
   }
}

視圖或使用者介面

唉,我們可以有把握地說:“如果沒有絲毫理論或實踐知識,應用程式的可視化將成為主要的絆腳石。” 坦白說,前端部分佔據了總工作量的驚人部分,並且在很長一段時間內自信地磨損了我的神經。但由於 Thymeleaf 令人驚嘆的簡單性,在經歷了一系列令人著迷的失敗後,我們有可能找到合適的折衷方案。進一步的討論將涉及使用所選引擎的複雜性,儘管整體概念遵循類似的立場。主要技術是能夠使用最純粹的 HTML 並從各個片段組裝最終顯示,以避免相同部分的多次重複。我們假設UI 架構由一個主頁組成,該主頁由一個帶有控制項的導覽列(添加新條目、返回主頁)和一個動態表組成,該表用於顯示按添加註釋的時間以升序(ASC) 或遞減(ASC) 排序的實體( DESC) 方向、意義。讓我們以所有記錄按升序顯示為標準位置。根據所選模板引擎的分層策略,元件視覺化元素應位於「resources」目錄中的「templates」分支上。因此,對組件的進一步操作會考慮所提出的條件。讓我們在 html5 範本上建立一個名為「index」(或根據個人喜好的任何其他名稱)的主頁。例如:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/head :: head"></head>
<body>
<div class="container">
   <div th:replace="fragments/header :: header"></div>
   <div th:if="${not #lists.isEmpty(notes)}">
       <div th:replace="operations/list :: notebook"></div>
   </div>
   <div th:replace="fragments/footer :: footer"></div>
</div>
</body>
</html>
因此,讓我們分解最終應用程式的關鍵組件。Thymeleaf 使用單獨的語法來指示過程的使用,並以關鍵字「th:」開頭,庫的連結必須包含在開始的 <html> 標記中。
<div th:if="${not #lists.isEmpty(notes)}">
「if」操作與通常的處理方式完全沒有什麼不同,它會檢查傳入的「notes」屬性是否存在物件以供進一步顯示。值得一提的是,考慮到控制器用於組織模型和視覺化互動的用途,該主題與控制器的使用有重疊。許多模糊的時刻在未來成形,如果你願意就回去吧。
<head th:replace="operations/list :: notebook"></head>
「替換」操作表示以目前或單獨頁面中選定的片段取代「存根」或活動區塊 - 後一種情況在範例中清楚地觀察到。我們將「operations」目錄的「list.html」中名為「notebook」的片段複製到「index」檔案的 <div></div> 中,完全替換最終目標中的內容。傳出的內容如下:
<!DOCTYPE html>
<!--suppress ALL -->
<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:th="http://www.thymeleaf.org">

<div th:fragment="notebook">
   <table class="table table-bordered table-hover horizontal-align">
       <thead>
       <tr>
           <th style="width: 5%">#</th>
           <th style="width: 60%">Message</th>
           <th class="dropdown" style="width: 20%">Date
               <a th:href="@{'/sort/{sortDate}' (sortDate = 'ASC')}"><i class="fa fa-chevron-circle-up"></i></a>
               <a th:href="@{'/sort/{sortDate}' (sortDate = 'DESC')}"><i class="fa fa-chevron-circle-down"></i></a>
           </th>
           <th style="width: 5%">Done</th>
           <th style="width: 5%">Edit</th>
           <th style="width: 5%">Delete</th>
       </tr>
       </thead>
       <tbody>
       <tr th:each="note : ${notes}">
           <td th:text="${note.id}" style="text-align: center">#</td>
           <td th:text="${note.message}">Message</td>
           <td th:text="${#dates.format(note.date, 'EEE, d MMM yyyy HH:mm')}" style="text-align: center">Date</td>
           <td style="text-align: center">
               <i th:if="${note.done} == true" class="fa fa-plus-square-o" style="font-size:20px;color:#337ab7"></i>
               <i th:if="${note.done} == false" class="fa fa-minus-square-o" style="font-size:20px;color:#337ab7"></i>
           </td>
           <td style="text-align: center"><a th:href="@{'/edit/{id}'(id=${note.id})}"><i class="fa fa-edit" style="font-size:20px"></i></a></td>
           <td style="text-align: center"><a th:href="@{'/delete/{id}'(id=${note.id})}"><i class="fa fa-trash" style="font-size:20px"></i></a></td>
       </tr>
       </tbody>
   </table>
</div>
</html>
讓我們回到建設性概述並按順序瀏覽使用的 Thymeleaf 函數,省略使用的標準 HTML 語法或圖形樣式,並專門關注理解模板引擎機制。
<div th:fragment="notebook">
「片段」操作指定片段的名稱,並使得可以將區塊的內容用於「替換」命令。而且!絕不排除單一頁面內的多次使用,再次與程式語言中的過程或函數進行類比。
<a th:href="@{'/sort/{sortDate}' (sortDate = 'ASC')}">
在控制器中使用映射「/sort/{sortDate}」呼叫 @PostMapping 註釋,其中 {sortDate} 是傳出排序方向屬性。在下面的區塊中可以看到類似的東西,它根據迭代循環中使用者選擇的元素的位置添加動態變化:
<a th:href="@{'/edit/{id}'(id=${note.id})}">
<tr th:each="note : ${notes}">
枚舉值與 Java 語法中熟悉的 for 區塊的使用非常相似:變數「note」從輸入屬性數組 ${notes}(實體數組)中獲取當前元素,並用於更改值稍後。坦白說,我們可以專門寫一篇文章來列出 Thymeleaf 的廣泛功能和實際應用範例 - 模板引擎非常簡單,根本不需要學習額外語法的令人印象深刻的包袱。上述功能在開發者官網的技術文件中有概述,對於組織與後端的溝通起著關鍵作用。因此,您可以自信地繼續下一個也是最後一個部分。當然,可以將視覺化的其餘元件附加到文章末尾的已完成應用程式的連結中。

小公司的財務長、管理員

「Web 應用程式架構中的基石」—也許沒有辦法找到更準確的描述來描述 Controller 元件在組織程式工作中的重要性:大多數操作都是由控制器之間的連接元素精確執行的。模型和視圖。由於採用 S​​pring Boot 的操作機制,您可以毫無問題地放心使用映射和 GET/POST 請求方法,並自動連接資料儲存庫。讓我們在「controllers」目錄下的單獨檔案中建立 NoteController 類,再次參考對應註解的使用:
@Controller
public class NoteController {

   private NoteService service;

   @Autowired
   public void setNoteService(NoteService service) {
       this.service = service;
   }

   @GetMapping("/")
   public String list(Model model) {
       return "index";
   }
}
細心的人可能會注意到應用程式體系結構設計中的一個重要變化,該變化與添加服務以將業務邏輯與資料庫管理服務的工作隔離相關。完成的操作需要增加成品的多功能性,並為更改使用者介面的功能提供廣泛的範圍,而無需更改與資料庫的通訊方法。標準表示絕不會從眾多類似的表示中脫穎而出:該介面位於單獨的目錄中,並由帶有 @Service 註解的類別實現,用於 Spring Boot 檢測:
public interface NoteService {
   Note getNoteById(Integer id);
   void saveNote(Note note);
   void updateNote(Integer id, String message, boolean done);
   void deleteNote(Integer id);
   List<Note> findAll();
}

@Service
public class NoteServiceImpl implements NoteService{

   private NoteRepository repository;

   @Autowired
   public void setProductRepository(NoteRepository repository) {
       this.repository = repository;
   }

   @Override
   public Note getNoteById(Integer id) {
       return repository.findOne(id);
   }

   @Override
   public void saveNote(Note note) {
       repository.save(note);
   }

   @Override
   public void updateNote(Integer id, String message, boolean done) {
       Note updated = repository.findOne(id);
       updated.setDone(done);
       updated.setMessage(message);
       repository.save(updated);
   }

   @Override
   public void deleteNote(Integer id) {
       repository.delete(id);
   }

   @Override
   public List<Note> findAll() {
       return repository.findAll();
   }
}
讓我們回到回顧控制器並看看使用 Spring Boot 方法組織工作的複雜性。@Autowired 註解表示需要自動將服務綁定到適當類型的指定變數並與資料庫建立連線。應該更專注於視圖通訊的方式,由 @GetMapping("/") 註解指示,當收到 localhost:8080 的呼叫時,它會傳回一個名為「index」的頁面。您可以使用不同的方法,指定擴充功能描述 @RequestMapping(value = "/", method = RequestMethod.GET) 或以現成的 ModelAndView 取代傳回類型。然而,根據目前實際應用中的經驗狀態,我沒有註意到最終結果有任何根本差異,並使用通常的選項。讓我們透過使用附加選項卡新增元素來擴展控制器。使用者點擊導覽列元素後,呼叫@GetMapping("/new")並從「operations」目錄重新導向至「new」頁面,使用按鈕確認輸入資料時傳回名為「message」的參數並重新導向至主區塊。需要特別提及的是,輸入視窗中的變數名稱與傳輸值的名稱需要完全相符。
<input type="text" class="form-control" id="message" th:name="message" placeholder="Enter your note." maxlength="100"/>
@GetMapping("/new")
public String newNote() {
   return "operations/new";
}

@PostMapping("/save")
public String updateNote(@RequestParam String message) {
   service.saveNote(new Note(message));
   return "redirect:/";
}
類似的技術用於更新記錄。點擊控制項後,將呼叫 @GetMapping("/edit/{id}") 對應並傳輸 URL 字串中的標識符,並新增「note」屬性和條目以供進一步編輯。@RequestParam(value = "done", required = false) boolean done) 指定特定值在使用 Thymeleaf 模板引擎時在複選框的使用中起著關鍵作用,預設為“false”。
@GetMapping("/edit/{id}")
public String edit(@PathVariable Integer id, Model model) {
   Note note = service.getNoteById(id);
   model.addAttribute("note", note);
   return "operations/edit";
}

@PostMapping("/update")
public String saveNote(@RequestParam Integer id, @RequestParam String message,
                      @RequestParam(value = "done", required = false) boolean done) {
   service.updateNote(id, message, done);
   return "redirect:/";
}
從資料庫中刪除項目非常簡單,不需要透過使用傳遞的值來呼叫適當的服務函數進行任何重大操作:
@GetMapping("/delete/{id}")
public String delete(@PathVariable Integer id) {
   service.deleteNote(id);
   return "redirect:/";
}
現在,讓我們對完成的片段進行一些小調整,並繼續使用 Spring Data JPA 中的查詢查詢與 MySQL 進行令人興奮的通信,在關閉控制器之前單獨添加一個用於管理簡單過濾的功能。
@Controller
public class NoteController {

   private String sortDateMethod = "ASC";

   @GetMapping("/")
   public String list(Model model) {
       List<Note> notebook = filterAndSort();
       model.addAttribute("notes", notebook);
       model.addAttribute("sort", sortDateMethod);
       return "index";
   }

private List<Note> filterAndSort() {
   List<Note> notebook = null;
   switch (sortDateMethod) {
       case "ASC":
           notebook = service.findAllByOrderByDateAsc();
           break;
       case "DESC":
           notebook = service.findAllByOrderByDateDesc();
           break;
   }
   return notebook;
}

如此小,但如此重要的查詢。

令人尷尬的是,與預期相反,過濾值竟然成為完成技術任務的另一個絆腳石,自信地克服了分頁建立的複雜性閾值——將數據數組分成一定大小的單獨頁面以進一步顯示。最有可能的是,累積的疲勞正在造成損害,但是......靈感來自於一次完全偶然的查詢查詢。
public interface NoteRepository extends JpaRepository<Note, Integer> {
   List<Note> findAllByOrderByDateAsc();
   List<Note> findAllByOrderByDateDesc();
}
Spring Data JPA 提供了創建高度精細的資料庫查詢的能力,無需在收到資訊後對資訊進行排序,並且具有廣泛的應用潛力。例如:
List<Note> findAllByOrderByDateAsc();
此方法將轉換為 SQL 查詢並顯示所有按日期 (byDate) 升序 (Asc) 排序 (byOrder) 的記錄 (findAll)。此外,您可以透過單一需求創建複雜的組合併跨多個領域進行採樣。比方說,按日期值 (byDate) 遞減 (Decs) 順序 (byOrder) 選擇所有 (findAll) 已完成 (byDoneTrue) 記錄:
Page<Note> findAllByDoneTrueOrderByDateDesc(Pageable pageable);

結論或是一個新手程式設計師的另一個自白

全部!您可以使用 Shift+F10 組合或點擊對應的圖示安全地啟動 Web 應用程式。Spring Boot 將在 Apache Maven 上建置程序,並在 localhost:8080 安裝本機 Apache Tomcat 伺服器。現在您只需在任何瀏覽器中點擊該連結即可。
征服春季靴 - 6
當然,也要開發一種方法來滿足其他業務需求。應用程式的潛力受到開發人員的努力、足智多謀和想像力的限制。
征服 Spring Boot - 7
坦誠並關注走過的路,我一次又一次確信所選擇方向的正確性,並體會到在JavaRush教育門戶學習的好處。由於各種實際任務,我們有可能恢復對學習程式設計的誘人興趣,這種興趣在類似方向的高等教育機構的過時且令人驚訝的無聊課程中被完全壓抑。與整年參加講座和實驗室課程相比,四個月積極學習後端技術堆疊中的材料所投入的知識要多得多。信不信由你。我希望你不要屈服於輸入複雜材料的困難,因為只有透過克服障礙,我們才能變得更好,並在專業和個人方面得到發展。我希望這個小故事能幫助我發現一些使用 SpringBoot 這個神奇工具的新想法。PS GitHub .
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION