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

本文概述

人们通常认为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中, 我们通过从”文件>新建”菜单下选择” Spring Starter项目”来创建一个新项目。

Spring框架教程

创建新项目后, 我们将需要编辑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(将用作我们的内存数据库)。所有必需的库将被自动拉出。

实体类别

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

这两个都被定义为带有某些注释的普通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);
}

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

控制者

接下来, 我们可以为该应用程序开发控制器。控制器将映射请求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";
	}

}

通过简单的” @RequestMapping”注释将URI映射到方法。在这种情况下, 控制器的每个方法都映射到URI。

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

每个控制器方法要么返回将用作视图的Thymeleaf模板的名称, 要么以特定模式(” redirect:”)的URL重定向到。例如, 方法” developer”和” _developersList_”返回模板的名称, 而” developersAdd”和” developersAddSkill”则返回要重定向到的URL。

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

观看次数

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

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

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

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

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

开发者名单

使用Spring框架构建MVC应用程序:初学者教程3
<!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>

开发人员详细信息

使用Spring框架构建MVC应用程序:初学者教程4
<!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包含一个启动模块。这使我们可以从命令行轻松启动服务器作为命令行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上获得。

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?