使用 Spring 框架構建 MVC 應用程序:初學者教程
已發表: 2022-03-11人們常說 Java 太複雜,而且構建簡單的應用程序花費的時間太長。 儘管如此,Java 提供了一個穩定的平台,周圍有一個非常成熟的生態系統,這使其成為開發健壯軟件的絕佳選擇。
Spring 框架是 Java 生態系統中眾多強大的框架之一,它帶有一組編程和配置模型,旨在簡化 Java 中高性能和可測試應用程序的開發。
在本教程中,我們將挑戰構建一個簡單的應用程序,該應用程序將充當使用 Spring Framework 和 Java Persistence API (JPA) 的軟件開發人員的數據庫。
該應用程序遵循標準的 MVC 架構。 它將有一個控制器(ContractsController 類)、視圖(基於 Thymeleaf 模板)和一個模型(一個 Java 地圖對象)。 為簡單起見,我們將使用 JPA 背後的內存數據庫在應用程序運行時持久保存數據。
Spring 框架教程入門
要構建基於 Spring 的應用程序,我們將需要使用以下構建工具之一:
- 馬文
- 搖籃
在本教程中,我們將使用 Maven。 如果您不熟悉這些工具中的任何一個,一個簡單的入門方法是下載 Spring Tool Suite。 該套件專用於 Spring Framework,並帶有自己的基於 Eclipse 的 IDE。
在 Spring Tool Suite 中,我們通過從“File > New”菜單下選擇“Spring Starter Project”來創建一個新項目。
創建新項目後,我們需要編輯 Maven 配置文件“ pom.xml ”,並添加以下依賴項:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons</artifactId> </dependency>
這些列出的依賴項將加載 Spring Boot Web、Thymeleaf、JPA 和 H2(將作為我們的內存數據庫)。 所有必要的庫將被自動拉取。
實體類
為了能夠存儲有關開發人員及其技能的信息,我們需要定義兩個實體類:“ Developer ”和“ Skill ”。
這兩者都被定義為帶有一些註釋的普通 Java 類。 通過在類前添加“@Entity”,我們將它們的實例提供給 JPA。 這將使在需要時從持久數據存儲中存儲和檢索實例變得更加容易。 此外,“@Id”和“@GeneratedValue”註釋允許我們指示實體的唯一 ID 字段,並在存儲在數據庫中時自動生成其值。
由於開發人員可以擁有許多技能,我們可以使用“@ManyToMany”註釋定義一個簡單的多對多關係。
開發商
@Entity public class Developer { @Id @GeneratedValue(strategy=GenerationType.AUTO) private long id; private String firstName; private String lastName; private String email; @ManyToMany private List<Skill> skills; public Developer() { super(); } public Developer(String firstName, String lastName, String email, List<Skill> skills) { super(); this.firstName = firstName; this.lastName = lastName; this.email = email; this.skills = skills; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public List<Skill> getSkills() { return skills; } public void setSkills(List<Skill> skills) { this.skills = skills; } public boolean hasSkill(Skill skill) { for (Skill containedSkill: getSkills()) { if (containedSkill.getId() == skill.getId()) { return true; } } return false; } }
技能
@Entity public class Skill { @Id @GeneratedValue(strategy=GenerationType.AUTO) private long id; private String label; private String description; public Skill() { super(); } public Skill(String label, String description) { super(); this.label = label; this.description = description; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
存儲庫
使用 JPA,我們可以定義一個非常有用的 DeveloperRepository 接口和 SkillRepository 接口,它們允許簡單的 CRUD 操作。 這些接口將允許我們通過簡單的方法調用來訪問存儲的開發人員和技能,例如:
- “respository.findAll()”:返回所有開發者
- “repository.findOne(id)”:返回給定 ID 的開發者
要創建這些接口,我們需要做的就是擴展 CrudRepository 接口。
開發者資料庫
public interface DeveloperRepository extends CrudRepository<Developer, Long> { }
技能庫
public interface SkillRepository extends CrudRepository<Skill, Long> { public List<Skill> findByLabel(String label); }
此處聲明的附加方法“ findByLabel ”的功能將由 JPA 自動提供。
控制器
接下來,我們可以在這個應用程序的控制器上工作。 控制器會將請求 URI 映射到查看模板並在兩者之間執行所有必要的處理。
@Controller public class DevelopersController { @Autowired DeveloperRepository repository; @Autowired SkillRepository skillRepository; @RequestMapping("/developer/{id}") public String developer(@PathVariable Long id, Model model) { model.addAttribute("developer", repository.findOne(id)); model.addAttribute("skills", skillRepository.findAll()); return "developer"; } @RequestMapping(value="/developers",method=RequestMethod.GET) public String developersList(Model model) { model.addAttribute("developers", repository.findAll()); return "developers"; } @RequestMapping(value="/developers",method=RequestMethod.POST) public String developersAdd(@RequestParam String email, @RequestParam String firstName, @RequestParam String lastName, Model model) { Developer newDeveloper = new Developer(); newDeveloper.setEmail(email); newDeveloper.setFirstName(firstName); newDeveloper.setLastName(lastName); repository.save(newDeveloper); model.addAttribute("developer", newDeveloper); model.addAttribute("skills", skillRepository.findAll()); return "redirect:/developer/" + newDeveloper.getId(); } @RequestMapping(value="/developer/{id}/skills", method=RequestMethod.POST) public String developersAddSkill(@PathVariable Long id, @RequestParam Long skillId, Model model) { Skill skill = skillRepository.findOne(skillId); Developer developer = repository.findOne(id); if (developer != null) { if (!developer.hasSkill(skill)) { developer.getSkills().add(skill); } repository.save(developer); model.addAttribute("developer", repository.findOne(id)); model.addAttribute("skills", skillRepository.findAll()); return "redirect:/developer/" + developer.getId(); } model.addAttribute("developers", repository.findAll()); return "redirect:/developers"; } }
URI 到方法的映射是通過簡單的“@RequestMapping”註釋完成的。 在這種情況下,控制器的每個方法都映射到一個 URI。

這些方法的模型參數允許將數據傳遞給視圖。 本質上,這些是鍵到值的簡單映射。
每個控制器方法要么返回要用作視圖的 Thymeleaf 模板的名稱,要么返回特定模式的 URL(“redirect:
在控制器中,“@Autowired”註釋會自動在相應字段中分配我們定義的存儲庫的有效實例。 這允許從控制器內部訪問相關數據,而無需處理大量樣板代碼。
意見
最後,我們需要為要生成的視圖定義一些模板。 為此,我們使用 Thymeleaf,一個簡單的模板引擎。 我們在控制器方法中使用的模型可以直接在模板中使用,即當我們在模型中的“ contract ”鍵中輸入合約時,我們將能夠從模板中以“contract.name”的形式訪問名稱字段。
Thymeleaf 包含一些控制 HTML 生成的特殊元素和屬性。 它們非常直觀和直接。 例如,要使用技能名稱填充 span 元素的內容,您需要做的就是定義以下屬性(假設在模型中定義了鍵“技能”):
<span th:text="${skill.label}"></span>
與設置錨元素的“ href ”屬性類似,可以使用特殊屬性“ th:href ”。
在我們的應用程序中,我們將需要兩個簡單的模板。 為清楚起見,我們將跳過嵌入模板代碼中的所有樣式和類屬性(即 Bootstrap 屬性)。
開發者列表
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Developers database</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <h1>Developers</h1> <table> <tr> <th>Name</th> <th>Skills</th> <th></th> </tr> <tr th:each="developer : ${developers}"> <td th:text="${developer.firstName + ' ' + developer.lastName}"></td> <td> <span th:each="skill,iterStat : ${developer.skills}"> <span th:text="${skill.label}"/><th:block th:if="${!iterStat.last}">,</th:block> </span> </td> <td> <a th:href="@{/developer/{id}(id=${developer.id})}">view</a> </td> </tr> </table> <hr/> <form th:action="@{/developers}" method="post" enctype="multipart/form-data"> <div> First name: <input name="firstName" /> </div> <div> Last name: <input name="lastName" /> </div> <div> Email: <input name="email" /> </div> <div> <input type="submit" value="Create developer" name="button"/> </div> </form> </body> </html>
開發者詳情
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Developer</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <h1>Developer</h1> Name: <b th:text="${developer.firstName}" /> <b th:text="${developer.lastName}" /><br/> Email: <span th:text="${developer.email}" /><br/> Skills: <span th:each="skill : ${developer.skills}"> <br/> <span th:text="${skill.label}" /> - <span th:text="${skill.description}" /> </span> <form th:action="@{/developer/{id}/skills(id=${developer.id})}" method="post" enctype="multipart/form-data" > <select name="skillId"> <option th:each="skill : ${skills}" th:value="${skill.id}" th:text="${skill.description}">Skill</option> </select> <input type="submit" value="Add skill"/> </form> </body> </html>
運行服務器
Spring 包含一個引導模塊。 這允許我們從命令行輕鬆地啟動服務器作為命令行 Java 應用程序:
@SpringBootApplication public class Application implements CommandLineRunner { @Autowired DeveloperRepository developerRepository; @Autowired SkillRepository skillRepository; public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
由於我們使用的是內存數據庫,因此在啟動時使用一些預定義的數據引導數據庫是有意義的。 這樣,當服務器啟動並運行時,我們將在數據庫中至少有一些數據。
@Override public void run(String... args) throws Exception { Skill javascript = new Skill("javascript", "Javascript language skill"); Skill ruby = new Skill("ruby", "Ruby language skill"); Skill emberjs = new Skill("emberjs", "Emberjs framework"); Skill angularjs = new Skill("angularjs", "Angularjs framework"); skillRepository.save(javascript); skillRepository.save(ruby); skillRepository.save(emberjs); skillRepository.save(angularjs); List<Developer> developers = new LinkedList<Developer>(); developers.add(new Developer("John", "Smith", "[email protected]", Arrays.asList(new Skill[] { javascript, ruby }))); developers.add(new Developer("Mark", "Johnson", "[email protected]", Arrays.asList(new Skill[] { emberjs, ruby }))); developers.add(new Developer("Michael", "Williams", "[email protected]", Arrays.asList(new Skill[] { angularjs, ruby }))); developers.add(new Developer("Fred", "Miller", "[email protected]", Arrays.asList(new Skill[] { emberjs, angularjs, javascript }))); developers.add(new Developer("Bob", "Brown", "[email protected]", Arrays.asList(new Skill[] { emberjs }))); developerRepository.save(developers); }
結論
Spring 是一個通用框架,允許構建 MVC 應用程序。 使用 Spring 構建一個簡單的應用程序既快速又透明。 該應用程序還可以使用 JPA 輕鬆地與數據庫集成。
整個項目的源代碼可在 GitHub 上找到。