Spring Framework로 MVC 애플리케이션 빌드하기: 초심자를 위한 튜토리얼
게시 됨: 2022-03-11Java는 종종 너무 복잡하고 간단한 애플리케이션을 빌드하는 데 너무 오래 걸린다고 합니다. 그럼에도 불구하고 Java는 주변에 매우 성숙한 생태계가 있는 안정적인 플랫폼을 제공하므로 강력한 소프트웨어를 개발하기 위한 훌륭한 옵션이 됩니다.
Java 에코시스템의 많은 강력한 프레임워크 중 하나인 Spring Framework는 Java에서 성능이 좋고 테스트 가능한 애플리케이션의 개발을 단순화하는 것을 목표로 하는 프로그래밍 및 구성 모델 모음과 함께 제공됩니다.
이 튜토리얼에서는 Spring Framework와 JPA(Java Persistence API)를 사용하여 소프트웨어 개발자의 데이터베이스 역할을 할 간단한 애플리케이션을 구축하는 데 도전할 것입니다.
애플리케이션은 표준 MVC 아키텍처를 따릅니다. 컨트롤러(ContractsController 클래스), 보기(Thymeleaf 템플릿 기반) 및 모델(Java 맵 개체)이 있습니다. 단순화를 위해 JPA 뒤의 메모리 내 데이터베이스를 사용하여 애플리케이션이 실행되는 동안 데이터를 유지합니다.
스프링 프레임워크 튜토리얼 시작하기
Spring 기반 애플리케이션을 빌드하려면 다음 빌드 도구 중 하나를 사용해야 합니다.
- 메이븐
- 그라들
이 튜토리얼에서는 Maven을 사용할 것입니다. 이러한 도구에 익숙하지 않은 경우 시작하는 쉬운 방법은 Spring Tool Suite를 다운로드하는 것입니다. 이 제품군은 Spring Framework 전용이며 자체 Eclipse 기반 IDE와 함께 제공됩니다.
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 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를 사용하면 손쉬운 CRUD 작업을 허용하는 매우 유용한 DeveloperRepository 인터페이스와 SkillRepository 인터페이스를 정의할 수 있습니다. 이러한 인터페이스를 통해 다음과 같은 간단한 메서드 호출을 통해 저장된 개발자와 기술에 액세스할 수 있습니다.
- "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); }
여기에 선언된 추가 메소드 " findByLabel "에 대한 기능은 JPA에서 자동으로 제공됩니다.
제어 장치
다음으로 이 애플리케이션의 컨트롤러에서 작업할 수 있습니다. 컨트롤러는 요청 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"; } }
메서드에 대한 URI 매핑은 간단한 "@RequestMapping" 주석을 통해 수행됩니다. 이 경우 컨트롤러의 모든 메서드는 URI에 매핑됩니다.

이러한 메서드의 모델 매개변수를 사용하면 데이터를 뷰에 전달할 수 있습니다. 본질적으로 이것은 키와 값의 단순한 맵입니다.
각 컨트롤러 메서드는 보기로 사용할 Thymeleaf 템플릿의 이름이나 특정 패턴의 URL("리디렉션:
컨트롤러 내에서 "@Autowired" 주석은 해당 필드에 정의된 저장소의 유효한 인스턴스를 자동으로 할당합니다. 이를 통해 많은 상용구 코드를 처리할 필요 없이 컨트롤러 내에서 관련 데이터에 액세스할 수 있습니다.
견해
마지막으로 생성할 보기에 대한 몇 가지 템플릿을 정의해야 합니다. 이를 위해 간단한 템플릿 엔진인 Thymeleaf를 사용하고 있습니다. 컨트롤러 메서드에서 사용한 모델은 템플릿 내에서 직접 사용할 수 있습니다. 즉, 모델의 " contract " 키에 계약을 입력하면 템플릿 내에서 "contract.name"으로 이름 필드에 액세스할 수 있습니다.
Thymeleaf에는 HTML 생성을 제어하는 몇 가지 특수 요소와 속성이 포함되어 있습니다. 그들은 매우 직관적이고 간단합니다. 예를 들어, span 요소의 내용을 기술 이름으로 채우려면 다음 속성을 정의하기만 하면 됩니다(키 " 기술 "이 모델에 정의되어 있다고 가정).
<span th:text="${skill.label}"></span>
앵커 요소의 " href " 속성을 설정하는 것과 유사하게 특수 속성 " th:href "를 사용할 수 있습니다.
우리 응용 프로그램에는 두 개의 간단한 템플릿이 필요합니다. 명확성을 기하기 위해 여기 포함된 템플릿 코드에서 모든 스타일 및 클래스 속성(즉, 부트스트랩 속성)을 건너뜁니다.
개발자 목록
<!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>
개발자 세부 정보
<!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>
서버 실행
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에서 사용할 수 있습니다.