authors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.
Stefan is a qualified software developer with a computer science degree and nearly a decade of experience in the tech industry.
Java is often said to be too complicated and to take too long to build simple applications. Nonetheless, Java provides a stable platform with a very mature ecosystem around it, which makes it a wonderful option for developing robust software.
The Spring Framework, one of the many powerful frameworks in the Java ecosystem, comes with a collection of programming and configuration models with a goal to simplify the development of performant and testable applications in Java.
In this tutorial, we will take the challenge of building a simple application that will act as a database of software developers using Spring Framework and the Java Persistence API (JPA).
The application follows a standard MVC architecture. It will have a controller (ContractsController class), views (based on Thymeleaf templates), and a model (a Java map object). For the sake of simplicity, we will use an in-memory database behind JPA to persist data while the application is running.
To build a Spring based application, we will need to use one of the following build tools:
In this tutorial, we will use Maven. If you are not familiar with either of these tools, an easy way to get started is to download the Spring Tool Suite. The suite is dedicated for Spring Framework, and comes with its own Eclipse based IDE.
In Spring Tool Suite, we create a new project by selecting “Spring Starter Project” from under the “File > New” menu.
Once a new project has been created, we will need to edit the Maven configuration file, “pom.xml”, and add the following dependencies:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-data-jpa
com.h2database
h2
org.springframework.data
spring-data-commons
These listed dependencies will load Spring Boot Web, Thymeleaf, JPA, and H2 (which will serve as our in-memory database). All necessary libraries will be pulled automatically.
To be able to store information about developers and their skills, we will need to define two entity classes: “Developer” and “Skill”.
Both of these are defined as plain Java classes with some annotations. By adding “@Entity” before the classes, we are making their instances available to JPA. This will make it easier to store and retrieve instances from the persistent data store when needed. Additionally, the “@Id” and “@GeneratedValue” annotations allow us to indicate the unique ID field for the entity and have its value generated automatically when stored in the database.
As a developer can have many skills, we can define a simple many-to-many relationship using the “@ManyToMany” annotation.
@Entity
public class Developer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
private String email;
@ManyToMany
private List skills;
public Developer() {
super();
}
public Developer(String firstName, String lastName, String email,
List 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 getSkills() {
return skills;
}
public void setSkills(List 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;
}
}
With JPA we can define a very useful DeveloperRepository interface and SkillRepository interface, which allow for easy CRUD operations. These interfaces will allow us to access stored developers and skills through simple method calls, such as:
To create these interfaces, all we need to do is extend the CrudRepository interface.
public interface DeveloperRepository extends CrudRepository {
}
public interface SkillRepository extends CrudRepository {
public List findByLabel(String label);
}
Functionality for the the additional method “findByLabel “declared here will be provided automatically by JPA.
Next, we can work on the controller for this application. The controller will map request URIs to view templates and perform all necessary processing in between.
@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";
}
}
Mapping of URIs to methods is done via simple “@RequestMapping” annotations. In this case, every method of the controller is mapped to a URI.
The model parameter of these methods allows data to be passed to the view. In essence, these are simple maps of keys to values.
Each controller method either returns the name of the Thymeleaf template to be used as view, or a URL in a specific pattern (“redirect:
Within the controller, the “@Autowired” annotations automatically assigns a valid instance of our defined repository in the corresponding field. This allows access to relevant data from within the controller without having to deal with a lot of boilerplate code.
Finally, we need to define some templates for the views to be generated. For this we are using Thymeleaf, a simple templating engine. The model we used in controller methods is available directly within the templates, i.e. when we enter a contract into “contract” key in a model, we will be able to access the name field as “contract.name” from within the template.
Thymeleaf contains some special elements and attributes that control generation of HTML. They are very intuitive and straightforward. For example, to populate the contents of a span element with the name of a skill, all you need to do is define the following attribute (assuming that the key “skill” is defined in the model):
Similarly to set the “href” attribute of an anchor element, the special attribute “th:href” can be used.
In our application, we will need two simple templates. For clarity, we will skip all style and class attributes (namely Bootstrap ones) here in the embedded template code.
Developers database
Developers
Name
Skills
,
view
Buying-website-contact@lh-jb.com
Buying-website-contact@lh-jb.com
正规赌博平台
正规赌博平台
欧洲杯下注
买球app
买球平台
Buying-website-service@jxedt2016.net
tory burch 中国官网
中国纺织网资讯行情中心
澳门皇冠赌场
东岳机械
中国儿童中心
北京风云际拓展公司
奥特朗热水器官网
昆明国旅
浦城之窗
上海房产网
宇虹颜料
苏州美罗商城
珠海交警网上车管所
中国电力招标网
Developer
Developer
Name:
Email:
Skills:
-
Buying-website-contact@lh-jb.com
Buying-website-contact@lh-jb.com
正规赌博平台
正规赌博平台
欧洲杯下注
买球app
买球平台
Buying-website-service@jxedt2016.net
tory burch 中国官网
中国纺织网资讯行情中心
澳门皇冠赌场
东岳机械
中国儿童中心
北京风云际拓展公司
奥特朗热水器官网
昆明国旅
浦城之窗
上海房产网
宇虹颜料
苏州美罗商城
珠海交警网上车管所
中国电力招标网
Spring contains a boot module. This allows us to start the server easily from command line as a command line Java application:
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
DeveloperRepository developerRepository;
@Autowired
SkillRepository skillRepository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Since we are using an in-memory database, it makes sense to bootstrap the database with some predefined data at launch. That way we will have at least some data in the database when the server is up and running.
@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 developers = new LinkedList();
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 is a versatile framework that allows building MVC applications. Building a simple application with Spring is quick and transparent. The application can also be integrated with a database easily using JPA.
The source code of this entire project is available on GitHub.
Located in Bratislava, Bratislava Region, Slovakia
Member since March 5, 2015
Stefan is a qualified software developer with a computer science degree and nearly a decade of experience in the tech industry.
17
World-class articles, delivered weekly.
World-class articles, delivered weekly.
Join the Toptal® community.