Spring Framework ile MVC Uygulaması Oluşturma: Yeni Başlayanlar İçin Eğitimi
Yayınlanan: 2022-03-11Java'nın genellikle çok karmaşık olduğu ve basit uygulamalar oluşturmanın çok uzun sürdüğü söylenir. Bununla birlikte, Java, çevresinde oldukça olgun bir ekosisteme sahip istikrarlı bir platform sağlar ve bu da onu sağlam yazılımlar geliştirmek için harika bir seçenek haline getirir.
Java ekosistemindeki birçok güçlü çerçeveden biri olan Spring Framework, Java'da performanslı ve test edilebilir uygulamaların geliştirilmesini basitleştirmeyi amaçlayan bir dizi programlama ve yapılandırma modeliyle birlikte gelir.
Bu öğreticide, Spring Framework ve Java Persistence API'sini (JPA) kullanan yazılım geliştiricilerin veritabanı görevi görecek basit bir uygulama oluşturmanın zorluğunu ele alacağız.
Uygulama standart bir MVC mimarisini takip eder. Bir denetleyiciye (ContractsController sınıfı), görünümlere (Thymeleaf şablonlarına dayalı olarak) ve bir modele (bir Java harita nesnesi) sahip olacaktır. Basitlik adına, uygulama çalışırken verileri kalıcı kılmak için JPA'nın arkasında bir bellek içi veritabanı kullanacağız.
Spring Framework Eğitimine Başlarken
Spring tabanlı bir uygulama oluşturmak için aşağıdaki derleme araçlarından birini kullanmamız gerekecek:
- Uzman
- kepçe
Bu dersimizde Maven kullanacağız. Bu araçlardan herhangi birine aşina değilseniz, başlamanın kolay bir yolu Spring Tool Suite'i indirmektir. Paket, Spring Framework için ayrılmıştır ve kendi Eclipse tabanlı IDE'si ile birlikte gelir.
Spring Tool Suite'te File > New menüsünden Spring Starter Project seçerek yeni bir proje oluşturuyoruz.
Yeni bir proje oluşturulduktan sonra, Maven yapılandırma dosyası “ pom.xml ” i düzenlememiz ve aşağıdaki bağımlılıkları eklememiz gerekecek:
<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>
Listelenen bu bağımlılıklar Spring Boot Web, Thymeleaf, JPA ve H2'yi (bellek içi veritabanımız olarak hizmet edecek) yükleyecektir. Gerekli tüm kütüphaneler otomatik olarak çekilecektir.
Varlık Sınıfları
Geliştiriciler ve becerileri hakkında bilgi depolayabilmek için iki varlık sınıfı tanımlamamız gerekecek: “ Geliştirici ” ve “ Beceri ”.
Bunların her ikisi de bazı açıklamalar içeren düz Java sınıfları olarak tanımlanır. Sınıfların önüne “@Entity” ekleyerek, örneklerini JPA için kullanılabilir hale getiriyoruz. Bu, gerektiğinde kalıcı veri deposundan örnekleri depolamayı ve almayı kolaylaştıracaktır. Ek olarak, “@Id” ve “@GeneratedValue” ek açıklamaları, varlık için benzersiz kimlik alanını belirtmemize ve veri tabanında depolandığında değerinin otomatik olarak oluşturulmasına olanak tanır.
Bir geliştirici birçok yeteneğe sahip olabileceğinden, “@ManyToMany” ek açıklamasını kullanarak basit bir çoktan çoğa ilişki tanımlayabiliriz.
geliştirici
@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; } }
Beceri
@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; } }
depolar
JPA ile, kolay CRUD işlemlerine izin veren çok kullanışlı bir DeveloperRepository arayüzü ve SkillRepository arayüzü tanımlayabiliriz. Bu arabirimler, aşağıdakiler gibi basit yöntem çağrıları aracılığıyla depolanan geliştiricilere ve becerilere erişmemize olanak tanır:
- “respository.findAll()”: tüm geliştiricileri döndürür
- “repository.findOne(id)”: verilen kimliğe sahip geliştiriciyi döndürür
Bu arayüzleri oluşturmak için tek yapmamız gereken CrudRepository arayüzünü genişletmek.
Geliştirici Deposu
public interface DeveloperRepository extends CrudRepository<Developer, Long> { }
Beceri Deposu
public interface SkillRepository extends CrudRepository<Skill, Long> { public List<Skill> findByLabel(String label); }
Burada açıklanan ek yöntem “ findByLabel “ için işlevsellik JPA tarafından otomatik olarak sağlanacaktır.
kontrolör
Ardından, bu uygulama için kontrolör üzerinde çalışabiliriz. Denetleyici, şablonları görüntülemek ve aralarında gerekli tüm işlemleri gerçekleştirmek için istek URI'lerini eşler.
@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"; } }
URI'lerin yöntemlerle eşlenmesi, basit "@RequestMapping" ek açıklamaları aracılığıyla yapılır. Bu durumda, denetleyicinin her yöntemi bir URI ile eşlenir.

Bu yöntemlerin model parametresi, verilerin görünüme geçirilmesine izin verir. Özünde, bunlar değerlerin basit anahtar haritalarıdır.
Her denetleyici yöntemi, görünüm olarak kullanılacak Thymeleaf şablonunun adını veya belirli bir kalıptaki bir URL'yi döndürür (“yönlendirme:
Denetleyici içinde, "@Autowired" ek açıklamaları, ilgili alanda tanımlı havuzumuzun geçerli bir örneğini otomatik olarak atar. Bu, çok sayıda ortak kod ile uğraşmak zorunda kalmadan kontrolör içinden ilgili verilere erişim sağlar.
Görüntüleme
Son olarak, oluşturulacak görünümler için bazı şablonlar tanımlamamız gerekiyor. Bunun için basit bir şablonlama motoru olan Thymeleaf kullanıyoruz. Controller yöntemlerinde kullandığımız model direkt olarak şablonlar içerisinde mevcuttur yani bir modelde “ sözleşme ” anahtarına bir sözleşme girdiğimizde şablon içinden “contract.name” olarak name alanına ulaşabileceğiz.
Thymeleaf, HTML üretimini kontrol eden bazı özel öğeler ve nitelikler içerir. Çok sezgisel ve anlaşılırlar. Örneğin, bir span öğesinin içeriğini bir beceri adıyla doldurmak için tek yapmanız gereken aşağıdaki özniteliği tanımlamaktır (" beceri " anahtarının modelde tanımlandığını varsayarak):
<span th:text="${skill.label}"></span>
Bir bağlantı elemanının “ href ” niteliğini ayarlamak için benzer şekilde, “ th:href ” özel niteliği kullanılabilir.
Uygulamamızda iki basit şablona ihtiyacımız olacak. Anlaşılır olması için, burada gömülü şablon kodunda tüm stil ve sınıf özniteliklerini (yani Bootstrap özniteliklerini) atlayacağız.
Geliştirici Listesi
<!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>
Geliştirici Ayrıntıları
<!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/> <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>
Sunucuyu Çalıştırmak
Spring, bir önyükleme modülü içerir. Bu, sunucuyu komut satırı Java uygulaması olarak komut satırından kolayca başlatmamızı sağlar:
@SpringBootApplication public class Application implements CommandLineRunner { @Autowired DeveloperRepository developerRepository; @Autowired SkillRepository skillRepository; public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Bir bellek içi veritabanı kullandığımız için, başlatma sırasında veritabanını önceden tanımlanmış bazı verilerle önyüklemek mantıklıdır. Bu şekilde, sunucu çalışır durumdayken veritabanında en azından bir miktar veriye sahip olacağız.
@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); }
Çözüm
Spring, MVC uygulamaları oluşturmaya izin veren çok yönlü bir çerçevedir. Spring ile basit bir uygulama oluşturmak hızlı ve şeffaftır. Uygulama ayrıca JPA kullanılarak kolayca bir veritabanı ile entegre edilebilir.
Tüm bu projenin kaynak kodu GitHub'da mevcuttur.