Membangun Aplikasi MVC dengan Kerangka Musim Semi: Tutorial Pemula

Diterbitkan: 2022-03-11

Java sering dikatakan terlalu rumit dan memakan waktu terlalu lama untuk membangun aplikasi sederhana. Meskipun demikian, Java menyediakan platform yang stabil dengan ekosistem yang sangat matang di sekitarnya, yang menjadikannya pilihan yang bagus untuk mengembangkan perangkat lunak yang kuat.

Spring Framework, salah satu dari banyak kerangka kuat di ekosistem Java, hadir dengan kumpulan model pemrograman dan konfigurasi dengan tujuan untuk menyederhanakan pengembangan aplikasi berkinerja dan dapat diuji di Java.

Kerangka Musim Semi

Dalam tutorial ini, kita akan mengambil tantangan untuk membangun aplikasi sederhana yang akan bertindak sebagai database pengembang perangkat lunak menggunakan Spring Framework dan Java Persistence API (JPA).

Aplikasi mengikuti arsitektur MVC standar. Ini akan memiliki pengontrol (kelas ContractsController), tampilan (berdasarkan template Thymeleaf), dan model (objek peta Java). Demi kesederhanaan, kami akan menggunakan database dalam memori di belakang JPA untuk menyimpan data saat aplikasi sedang berjalan.

Memulai dengan Tutorial Kerangka Musim Semi

Untuk membangun aplikasi berbasis Spring, kita perlu menggunakan salah satu alat build berikut:

  • Maven
  • Gradle

Dalam tutorial ini, kita akan menggunakan Maven. Jika Anda tidak terbiasa dengan salah satu alat ini, cara mudah untuk memulai adalah mengunduh Spring Tool Suite. Suite ini didedikasikan untuk Spring Framework, dan dilengkapi dengan IDE berbasis Eclipse sendiri.

Di Spring Tool Suite, kami membuat proyek baru dengan memilih "Proyek Pemula Musim Semi" dari menu "File > Baru".

Tutorial Kerangka Musim Semi

Setelah proyek baru dibuat, kita perlu mengedit file konfigurasi Maven, “ pom.xml ”, dan menambahkan dependensi berikut:

 <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>

Dependensi yang terdaftar ini akan memuat Spring Boot Web, Thymeleaf, JPA, dan H2 (yang akan berfungsi sebagai database dalam memori kami). Semua perpustakaan yang diperlukan akan ditarik secara otomatis.

Kelas Entitas

Untuk dapat menyimpan informasi tentang pengembang dan keterampilan mereka, kita perlu mendefinisikan dua kelas entitas: " Pengembang " dan " Keterampilan ".

Keduanya didefinisikan sebagai kelas Java biasa dengan beberapa anotasi. Dengan menambahkan “@Entity” sebelum kelas, kami membuat instance mereka tersedia untuk JPA. Ini akan mempermudah penyimpanan dan pengambilan instans dari penyimpanan data persisten bila diperlukan. Selain itu, anotasi “@Id” dan “@GeneratedValue” memungkinkan kami menunjukkan bidang ID unik untuk entitas dan nilainya dihasilkan secara otomatis saat disimpan dalam database.

Karena pengembang dapat memiliki banyak keterampilan, kita dapat mendefinisikan hubungan banyak-ke-banyak yang sederhana menggunakan anotasi “@ManyToMany”.

Pengembang

 @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; } }

Keahlian

 @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; } }

Repositori

Dengan JPA kita dapat mendefinisikan antarmuka DeveloperRepository dan antarmuka SkillRepository yang sangat berguna, yang memungkinkan pengoperasian CRUD dengan mudah. Antarmuka ini akan memungkinkan kita untuk mengakses pengembang dan keterampilan yang tersimpan melalui pemanggilan metode sederhana, seperti:

  • "respository.findAll()": mengembalikan semua pengembang
  • "repository.findOne(id)": mengembalikan pengembang dengan ID yang diberikan

Untuk membuat antarmuka ini, yang perlu kita lakukan adalah memperluas antarmuka CrudRepository.

Gudang Pengembang

 public interface DeveloperRepository extends CrudRepository<Developer, Long> { }

Gudang Keterampilan

 public interface SkillRepository extends CrudRepository<Skill, Long> { public List<Skill> findByLabel(String label); }

Fungsionalitas untuk metode tambahan " findByLabel " yang dideklarasikan di sini akan disediakan secara otomatis oleh JPA.

Pengontrol

Selanjutnya kita bisa mengerjakan controller untuk aplikasi ini. Pengontrol akan memetakan URI permintaan untuk melihat templat dan melakukan semua pemrosesan yang diperlukan di antaranya.

 @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"; } }

Pemetaan URI ke metode dilakukan melalui anotasi sederhana “@RequestMapping”. Dalam hal ini, setiap metode pengontrol dipetakan ke URI.

Parameter model dari metode ini memungkinkan data diteruskan ke tampilan. Intinya, ini adalah peta sederhana dari kunci nilai.

Setiap metode pengontrol mengembalikan nama templat Thymeleaf untuk digunakan sebagai tampilan, atau URL dalam pola tertentu (“pengalihan: ”) untuk mengalihkan ke. Misalnya, metode “developer” dan “_developersList_” mengembalikan nama template, sedangkan “developersAdd” dan “developersAddSkill” mengembalikan URL tujuan pengalihan.

Di dalam pengontrol, anotasi “@Autowired” secara otomatis menetapkan instance valid dari repositori yang kami tentukan di bidang yang sesuai. Ini memungkinkan akses ke data yang relevan dari dalam pengontrol tanpa harus berurusan dengan banyak kode boilerplate.

Tampilan

Terakhir, kita perlu mendefinisikan beberapa template untuk tampilan yang akan dihasilkan. Untuk ini kami menggunakan Thymeleaf, mesin templating sederhana. Model yang kami gunakan dalam metode pengontrol tersedia langsung di dalam templat, yaitu ketika kami memasukkan kontrak ke dalam kunci " kontrak " dalam sebuah model, kami akan dapat mengakses bidang nama sebagai "nama kontrak" dari dalam templat.

Thymeleaf berisi beberapa elemen dan atribut khusus yang mengontrol pembuatan HTML. Mereka sangat intuitif dan lugas. Misalnya, untuk mengisi konten elemen span dengan nama keterampilan, yang perlu Anda lakukan hanyalah menentukan atribut berikut (dengan asumsi bahwa kunci " keterampilan " didefinisikan dalam model):

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

Demikian pula untuk mengatur atribut “ href ” dari elemen jangkar, atribut khusus “ th:href ” dapat digunakan.

Dalam aplikasi kita, kita akan membutuhkan dua template sederhana. Untuk kejelasan, kami akan melewatkan semua atribut gaya dan kelas (yaitu yang Bootstrap) di sini dalam kode templat yang disematkan.

Daftar Pengembang

 <!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>

Detail Pengembang

 <!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>

Menjalankan Server

Musim semi berisi modul boot. Ini memungkinkan kita untuk memulai server dengan mudah dari baris perintah sebagai aplikasi Java baris perintah:

 @SpringBootApplication public class Application implements CommandLineRunner { @Autowired DeveloperRepository developerRepository; @Autowired SkillRepository skillRepository; public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

Karena kita menggunakan database dalam memori, masuk akal untuk mem-bootstrap database dengan beberapa data yang telah ditentukan saat peluncuran. Dengan begitu kita akan memiliki setidaknya beberapa data dalam database saat server aktif dan berjalan.

 @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); }

Kesimpulan

Spring adalah kerangka kerja serbaguna yang memungkinkan pembuatan aplikasi MVC. Membangun aplikasi sederhana dengan Spring cepat dan transparan. Aplikasi ini juga dapat diintegrasikan dengan database dengan mudah menggunakan JPA.

Kode sumber dari seluruh proyek ini tersedia di GitHub.