使用 Spring 框架构建 MVC 应用程序:初学者教程

Spring Framework 是一个功能强大、功能丰富且设计精良的 Java 平台框架。它提供了一系列编程和配置模型,旨在简化和精简 Java 中健壮且可测试的应用程序的开发过程。

人们常说 Java 太复杂了,构建简单的应用程序需要很长时间。尽管如此,Java 提供了一个稳定的平台,周围有一个非常成熟的生态系统,这使其成为开发强大软件的绝佳选择。

Spring Framework 是 Java 生态系统中众多强大的框架之一,它附带了一系列编程和配置模型,旨在简化 Java 中高性能和可测试应用程序的开发。

在这里插入图片描述

在本教程中,我们将接受构建一个简单的应用程序的挑战,该应用程序将SpringMVC轻松掌握。

Spring Framework 教程入门

要构建基于 Spring 的应用程序,我们需要使用以下构建工具之一:

  • Maven 相关
  • Gradle 相关

在 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 WebThymeleafJPA H2(将用作我们的内存数据库)。所有必要的库都将自动拉取。

实体类

了能够存储有关开发人员及其技能的信息,我们需要定义两个实体类:“Developer”和“Skill”。

这两个类都被定义为带有一些注解的普通 Java 类。通过在类之前添加@Entity,我们可以将它们的实例提供给 JPA。这将使在需要时从持久性数据存储中存储和检索实例变得更加容易。此外,@Id@GeneratedValue注释允许我们指示实体的唯一 ID 字段,并在存储在数据库中时自动生成其值。

由于开发人员可以拥有许多技能,因此我们可以使用 “@ManyToMany” 注解定义一个简单的多对多关系。

Developer 开发 人员
@Entity
public class Developer {@Id@GeneratedValue(strategy=GenerationType.AUTO)private long id;private String firstName;private String lastName;private String email;@ManyToManyprivate 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;}}
Skill 技能
@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;}}

Repositories 存储库

用 JPA,我们可以定义一个非常有用的 Developer Repository 接口和 SkillRepository 接口,它们允许简单的 CRUD 操作。这些接口将允许我们通过简单的方法调用访问存储的开发人员和技能,例如:

  • respository.findAll():返回所有开发人员
  • repository.findOne(id):返回具有给定 ID 的开发人员

要创建这些接口,我们需要做的就是扩展 CrudRepository 接口。

Developer Repository 开发人员存储库
public interface DeveloperRepository extends CrudRepository<Developer, Long> {}
Skill Repository 技能仓库
public interface SkillRepository extends CrudRepository<Skill, Long> {public List<Skill> findByLabel(String label);
}

此处声明的附加方法 findByLabel 的功能将由 JPA 自动提供。

Controller 控制器

接下来,我们可以为这个应用程序开发控制器。控制器将映射请求 URI 以查看模板,并在两者之间执行所有必要的处理。

@Controller
public class DevelopersController {@AutowiredDeveloperRepository repository;@AutowiredSkillRepository 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。

这些方法的 model 参数允许将数据传递到视图。从本质上讲,这些是键到值的简单映射。

每个控制器方法要么返回要用作视图的 Thymeleaf 模板的名称,要么返回要重定向到的特定模式(redirect:)的 URL。例如,方法 developer_developersList_ 返回模板的名称,而 developersAdddevelopersAddSkill 返回要重定向到的 URL。

在控制器中,@Autowired注释会自动在相应字段中分配我们定义的存储库的有效实例。这允许从控制器内部访问相关数据,而无需处理大量样板代码。

Views 视图

最后,我们需要为要生成的视图定义一些模板。为此,我们使用了 Thymeleaf,一个简单的模板引擎。我们在控制器方法中使用的模型可以直接在模板中使用,即当我们在模型的 contract” 键中输入合约时,我们将能够从模板中以 “contract.name” 的形式访问 name 字段。

Thymeleaf 包含一些控制 HTML 生成的特殊元素和属性。他们非常直观和直接。例如,要使用技能名称填充 span 元素的内容,您只需定义以下属性(假设在模型中定义了键“skill”):

<span th:text="${skill.label}"></span>

与设置锚点元素的 href 属性类似,可以使用特殊属性 *th:href

在我们的应用程序中,我们需要两个简单的模板。为清楚起见,我们将在嵌入式模板代码中跳过所有 style 和 class 属性(即 Bootstrap 属性)。

Developer List 开发者名单

在这里插入图片描述

<!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>
Developer Details 开发者详情

在这里插入图片描述

<!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/>&nbsp;&nbsp;<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 包含一个 boot 模块。这允许我们轻松地从命令行作为命令行 Java 应用程序启动服务器:

@SpringBootApplication
public class Application implements CommandLineRunner {@AutowiredDeveloperRepository developerRepository;@AutowiredSkillRepository 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", "john.smith@example.com", Arrays.asList(new Skill[] { javascript, ruby })));developers.add(new Developer("Mark", "Johnson", "mjohnson@example.com", Arrays.asList(new Skill[] { emberjs, ruby })));developers.add(new Developer("Michael", "Williams", "michael.williams@example.com", Arrays.asList(new Skill[] { angularjs, ruby })));developers.add(new Developer("Fred", "Miller", "f.miller@example.com", Arrays.asList(new Skill[] { emberjs, angularjs, javascript })));developers.add(new Developer("Bob", "Brown", "brown@example.com", Arrays.asList(new Skill[] { emberjs })));developerRepository.save(developers);
}

总结

Spring 是一个多功能框架,允许构建 MVC 应用程序。使用 Spring 构建一个简单的应用程序既快速又透明。该应用程序还可以使用 JPA 轻松与数据库集成。

GitHub 该篇文章中使用到Demo源码整个项目的源代码。

推荐阅读

1、在 Spring 中使用 @EhCache 注解作为缓存
2、有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
3、如何理解应用 Java 多线程与并发编程?
4、Java Spring 中常用的 @PostConstruct 注解使用总结
5、线程 vs 虚拟线程:深入理解及区别
6、深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
7、10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
8、“打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”
9、Java 中消除 If-else 技巧总结
10、线程池的核心参数配置(仅供参考)
11【人工智能】聊聊Transformer,深度学习的一股清流(13)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/57352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity/C#使用EPPlus读取和写入Excel

简介&#xff1a;本篇使用EPPlus来将数据写入Excel&#xff0c;如果需要使用NPOI那可以阅读我之前文档使用NPOI创建及写入数据_npoi 模板 写数据-CSDN博客 一、安装EPPlus 这里使用 .unitypackage 文件形式安装 1.1下载NuGetForUnity.unitypackage github进行搜索下载 下载…

vscode设置特定扩展名文件的打开编码格式

用vscode 编辑c语言或者Verilog代码, 由于其它开发工具的文件编码格式无法修改,默认只能是gb2312, 与我们国内奉行的统一 utf8 不一致. 所以只能是更改特殊文件的打开方式. 配置方式如下. 关键配置如下: {"git.openRepositoryInParentFolders": "never",…

【办公类-57-01】美工室材料报销EXCEL表批量插入截图(图片)

背景需求&#xff1a; 我们班分到美工室&#xff0c;需要准备大量材料&#xff0c;根据原始的报销单EXCLE&#xff0c;里面有商品名称、图片、链接、单位、数量等信息 今天我和搭档一起填写新表&#xff0c;发现手机截图的图片插入EXCEL后非常大&#xff0c; 需要手动调整图片…

4 -《本地部署开源大模型》在Ubuntu 22.04系统下部署运行ChatGLM3-6B模型

在Ubuntu 22.04系统下部署运行ChatGLM3-6B模型 大模型部署整体来看并不复杂&#xff0c;且官方一般都会提供标准的模型部署流程&#xff0c;但很多人在部署过程中会遇到各种各样的问题&#xff0c;很难成功部署&#xff0c;主要是因为这个过程会涉及非常多依赖库的安装和更新及…

【AI】人工智能的应用与前景

目录 人工智能的应用与前景1. 人工智能的当前应用1.1 医疗领域1.1.1 医疗影像中的AI应用1.1.2 药物研发中的AI潜力 1.2 企业与商业领域1.2.1 数据驱动的智能决策1.2.2 自动化业务流程 1.3 智能生活领域1.3.1 自动驾驶技术的崛起1.3.2 智能家居中的AI应用 2. 人工智能的未来前景…

Golang | Leetcode Golang题解之第485题最大连续1的个数

题目&#xff1a; 题解&#xff1a; func findMaxConsecutiveOnes(nums []int) (maxCnt int) {cnt : 0for _, v : range nums {if v 1 {cnt} else {maxCnt max(maxCnt, cnt)cnt 0}}maxCnt max(maxCnt, cnt)return }func max(a, b int) int {if a > b {return a}return …

区块链技术在网络安全中的应用研究

摘要&#xff1a; 随着网络技术的快速发展&#xff0c;网络安全问题日益凸显。区块链技术以其去中心化、不可篡改、可追溯等特性&#xff0c;为网络安全提供了新的解决方案。本文深入探讨了区块链技术在网络安全多个领域的应用&#xff0c;包括数据加密与存储、身份认证、网络攻…

Golang | Leetcode Golang题解之第494题目标和

题目&#xff1a; 题解&#xff1a; func findTargetSumWays(nums []int, target int) int {sum : 0for _, v : range nums {sum v}diff : sum - targetif diff < 0 || diff%2 1 {return 0}neg : diff / 2dp : make([]int, neg1)dp[0] 1for _, num : range nums {for j …

HICP--2

在area 0的路由器只生成 area 0 的数据库&#xff0c;只在area 1 的一样。但是既在又在的生成两个 area的 LSDB 一、区域间三类LSA 在OSPF&#xff08;Open Shortest Path First&#xff09;协议中&#xff0c;区域间三类LSA&#xff08;Link-State Advertisement&#xff09…

基于Java+jsp的CRM客户关系管理系统的实现

系统的详细设计和实现 根据上文的功能分析和数据库的分析&#xff0c;在系统的实现阶段上采用当今开源的SSH&#xff08;StrutsHibernateSpring&#xff09;整合框架实现。其目的是降低个模块间的耦合度&#xff0c;使各个模块之间的功能相互独立、模块内部结构清晰。 系统架…

听泉鉴宝在三个月前已布局商标注册!

近日“听泉鉴宝”以幽默的风格和节目效果迅速涨粉至2500多万&#xff0c;连线出现“馆藏文物”和“盗墓现场”等内容&#xff0c;听泉鉴宝早在几个月前已布局商标注册。 据普推知产商标老杨在商标局网站检索发现&#xff0c;“听泉鉴宝”的主人丁某所持股的江苏灵匠申请了三十…

视图库对接系列(GA-T 1400)十六-二、视图库对接系列(本级)查询订阅

说明 之前我们在本级中少写了一个查询订阅的接口,这里的话 我们给本级中补充一个功能,实现查询订阅功能。文档 这面我们是向下级发送查询订阅的功能,我们目前测试的话需要手动触发下这个功能, 我们就写一个接口就叫/custom/VIID/Subscribes ,和1400接口的区别是增加了一个…

ffmpeg视频滤镜:双边滤波-bilateral

滤镜简述 bilateral 官网链接 > FFmpeg Filters Documentation 双边滤波是一种图片去噪的方法&#xff0c;它会综合考虑像素的空间和像素值来优化图片&#xff0c;可以看一下如下效果&#xff1a; 左边是 原图&#xff0c;右边是优化后的&#xff0c;相当于磨皮了。 要…

打造高性能在线电子表格:WebGL 渲染引擎 Kola2d 自研之路

导读&#xff1a;本文主要阐述了 Docs 在线表格为打造极致渲染性能所做的关键优化和过程思考&#xff0c;作为首个在在线电子表格领域自研基于WebGL渲染引擎的「吃螃蟹」者&#xff0c;整个过程面临诸多不确定性与挑战&#xff0c;Kola2d 的整体设计在此期间也经历了几轮推倒重…

linux之网络子系统- 地址解析协议arp 源码分析和邻居通用框架

一、arp 的作用 ARP&#xff08;Address Resolution Protocol&#xff0c;地址解析协议&#xff09;是将IP地址解析为以太网MAC地址&#xff08;物理地址&#xff09;的协议。在局域网中&#xff0c;当主机或其他网络设备有数据要发送给另一个主机或设备时&#xff0c;它必须知…

酒店预订订房小程序源码系统 多酒店入驻+打造类似美团的酒店模式 带完整的安装代码包以及搭建部署教程

系统概述 随着移动互联网的普及&#xff0c;小程序因其轻量级、无需下载安装、即用即走的特点&#xff0c;迅速成为各行业的标配。对于酒店预订行业而言&#xff0c;小程序不仅能够有效提升用户体验&#xff0c;还能降低运营成本&#xff0c;提高转化率。本源码系统正是基于这…

企业数字化转型的理论指南:构建未来企业的关键策略与实践路径

数字化转型已经成为当今企业发展和市场竞争的核心驱动力&#xff0c;而在这一过程中&#xff0c;企业架构&#xff08;EA&#xff09;发挥着至关重要的作用。这本白皮书《世界级企业架构&#xff1a;建立和发展EA能力的领导者方法》提供了深入的理论指导&#xff0c;为企业如何…

ToolBox没有进行配置 Failed to initialize Toolboxlibrary

solidworks打开右侧提示 ToolBox没有进行配置跟Failed to initialize Toolboxlibrary 解决方法如下 使用xxclean的扩展功能 SW右侧栏是英文 toolbox配置无效 这个按钮

开源大模型项目,助你效率提高 10 倍

随着 AI 的普及&#xff0c;大家使用 AI 工具的时间越来越长了&#xff0c;尤其因为有了像 GPT-4o 和 Claude 这样强大的 LLM。 今天&#xff0c;我将介绍 21 个开源 LLM 项目&#xff0c;它们可以帮助你构建令人兴奋的内容&#xff0c;并将人工智能集成到你的项目中。 Vanna…

【华为HCIP实战课程十七】OSPF的4类及5类LSA详解,网络工程师

一、5类LSA详解 由ASBR产生,描述到AS外部的路由,通告到所有的区域(除了STUB区域和NSSA区域)。 我们在R6设备配置引入直连路由,R6的lo10 属于区域2 interface LoopBack10 ip address 6.6.6.6 255.255.255.255 ospf enable 1 area 0.0.0.2 [R6-ospf-1]import-route dire…