当前位置: 首页 > news >正文

使用 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)

相关文章:

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

Spring Framework 是一个功能强大、功能丰富且设计精良的 Java 平台框架。它提供了一系列编程和配置模型&#xff0c;旨在简化和精简 Java 中健壮且可测试的应用程序的开发过程。 人们常说 Java 太复杂了&#xff0c;构建简单的应用程序需要很长时间。尽管如此&#xff0c;Jav…...

集成Spring Security详解

集成Spring Security详解 一、Spring Security简介 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架&#xff0c;它专注于为Java应用程序提供全面的安全解决方案。作为Spring项目的一部分&#xff0c;Spring Security继承了Spring框架的灵活性和可扩展性…...

Kettle9.4支持Clickhouse数据源插件开发以及性能测试

前言 最近业务这边有个指标需要用到大数据这边的列式数据库进行处理&#xff0c;由于kettle不支持clickhouse数据源驱动&#xff0c;这里查了一下网上的相关资料&#xff0c;发现了一些别人开发好的驱动包&#xff0c;下载下来后使用效果不尽人意。总结下来有以下几个问题&…...

微信支付V3 yansongda/pay 踩坑记录

Pay - 让支付开发更简单 | Pay 使用laravel 8框架 2.1 报错 Parse [mch_public_cert_path] Serial Number Error 是mch_secret_cert&#xff0c;mch_public_cert_path配置错误 2.2 报错 Get Wechat Public Cert Error 是mch_secret_key配置错误 #正确 Pay::config(config(w…...

AndroidStudio实验报告——实验一、二

目录 实验一&#xff1a; AS安装与安卓环境搭建 一、实验目标 二、实验内容 &#xff08;一&#xff09;Android Studio安装 &#xff08;二&#xff09;JDK安装与配置 &#xff08;三&#xff09;Android SDK安装与配置 三、实验结果&#xff1a;&#xff08;实…...

Nginx超简洁知识:负载均衡-反向代理,动静分离,配置文件

首先介绍一下为什么需要nginx&#xff1f; 在低并发场景下&#xff08;也就是用户量特别少的情况下&#xff09;&#xff0c;我们只需要部署一台服务器就能满足用户数量少的需求。 但是如果用户量逐渐增多&#xff0c;只有一台服务器是不够的。于是我们需要部署多台服务器。 …...

云手机:社交平台运营的热门工具

随着互联网的飞速发展&#xff0c;社交平台已经成为企业推广和营销的核心渠道。传统的运营方式已经无法满足高效运营的需求&#xff0c;而云手机作为新兴工具&#xff0c;逐渐成为社交平台运营的前沿趋势。本文将深入分析云手机如何优化社交平台的运营流程&#xff0c;助力企业…...

iptables限速规则

环境&#xff1a; iptables服务器&#xff1a;172.16.12.33 client&#xff1a;192.168.1.2 1、在防火墙上配置客户端的下载速度是1M/s &#xff08;1个包是1.3KB&#xff09; #限速客户端每秒的下载速度是1024KB&#xff0c;超出限制的流量就丢弃 [rootiptables-172-16-12-…...

易泊车牌识别:海外车牌快速定制,开启智能识别新时代

在当今数字化快速发展的时代&#xff0c;车牌识别技术已经成为了智能交通系统中不可或缺的一部分。而在众多车牌识别解决方案中&#xff0c;易泊车牌识别系统以其卓越的性能和独特的优势脱颖而出&#xff0c;尤其是在海外车牌快速定制方面&#xff0c;更是展现出了强大的实力。…...

同一个交换机不同vlan的设备为什么不能通信

在同一个交换机上&#xff0c;不同 VLAN 的设备不能直接通信&#xff0c;这是因为 VLAN&#xff08;虚拟局域网&#xff09;通过在数据链路层&#xff08;OSI 第2层&#xff09;对设备进行逻辑隔离&#xff0c;将不同 VLAN 的设备视为属于不同的网络。具体原因如下&#xff1a;…...

《业务三板斧:定目标、抓过程、拿结果》读书笔记4

管理者抓技能的第二个动作是构地图 管理者如何构建能力地图&#xff1f; 梳流程 构建能力地图的关键是梳理业务流程&#xff0c;明确“要做什么”及“怎么 做”。管理者只有明晰每一项业务流程对应的策略、关键举措、风 险、工具、话术、案例等&#xff0c;才能将方法复制给每一…...

PRCV 2024 - Day2

主会场 —— 主旨报告 报告题目&#xff1a;大模型背景下的数字内容取证 讲者&#xff1a;谭铁牛(中科院自动化所&#xff0c;中国科学院院士) 图1 大模型背景下的数字内容取证 在数字化时代&#xff0c;随着人工智能技术的迅猛发展&#xff0c;尤其是深度学习的广泛应用&…...

大厂面试真题-了解云原生吗,简单说一下docker和k8s

K8s&#xff08;Kubernetes&#xff09;和Docker都是容器化技术中的关键组件&#xff0c;但它们各自扮演着不同的角色。以下是对这两者的详细解析&#xff1a; 一、Docker Docker是一个开源的容器化平台&#xff0c;它允许开发人员将应用程序及其依赖项打包为一个独立的镜像&…...

Python基础入门

目录 1. 简介 2. 安装与设置 2.1 检查是否已安装Python 2.2 使用Python解释器 2.3 使用代码编辑器 3. Python基础语法 3.1 注释 3.2 变量和数据类型 3.3 输入输出 3.4 基本运算 4. 条件语句与循环 4.1 条件判断 4.2 循环 while循环 for循环 break与continue 5.…...

深入了解路由

目录 1. 什么是路由&#xff1f;2. 路由与网关的关系3. 路由表4. 静态路由与动态路由5. 下一跳6. 动态路由及常用路由协议7. 路由算法解析 1. 什么是路由&#xff1f; 路由 是网络中将数据包从源地址传送到目标地址的过程。它涉及网络设备&#xff08;如路由器&#xff09;根据…...

三大编程思想(POP、OOP、AOP、FOP)及oop 五大设计原则

概述 POP&#xff1a;面向过程编程&#xff08;Procedure Oriented Programming&#xff09; OOP&#xff1a;面向对象编程&#xff08;Object Oriented Programming&#xff09; AOP&#xff1a;面向切面编程&#xff08;Aspect Oriented Programming&#xff09; FOP&#x…...

JavaWeb开发4

JS对象 Array Array对象用于定义数组 var 变量名new Array(元素列表)&#xff1b; var 变量名[元素列表] 访问 arr[索引]值&#xff1b; 注意&#xff1a;JS中数组相对于Java中集合&#xff0c;数组的长度是可变的&#xff0c;JS是弱类型&#xff0c;所以可以存储任意类型…...

Git中Update和Pull的区别

在本文中&#xff0c;我们将介绍Git中的两个操作——”Update”和”Pull”&#xff0c;并解释它们之间的区别。 1、“Update”的含义和用法 “Update”是Git中用于更新本地仓库和工作区的操作。它的作用是将远程仓库中的最新变更同步到本地。当我们执行”Update”操作时&…...

物理安全概述

目录 物理安全概念物理安全威胁物理安全威胁物理安全保护物理安全分析与防护 物理安全概念 我不需要通过高深的网络技术来攻击你&#xff0c;直接在物理层面把你干倒&#xff0c;不要小瞧&#xff0c;其实这种攻击是最致命的&#xff0c;你把我的电脑给入侵了&#xff0c;可能…...

引领智慧文旅新纪元,开启未来旅游新境界

融合创新科技&#xff0c;重塑旅游体验&#xff0c;智慧文旅项目定义旅游新未来 在全球化的浪潮中&#xff0c;旅游已成为连接世界的重要纽带。智慧文旅项目&#xff0c;不仅仅是一次技术的革新&#xff0c;更是对旅游行业未来发展的一次深刻思考。信鸥科技通过运用云计算、大数…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...