Spring Boot를 사용한 웹 MVC 애플리케이션 예제.

 

먼저, Spring Boot에서는 템플릿 엔진으로 Thymeleaf를 사용하고 있다.

 

본 예제는 DB에서 메뉴 정보를 조회하여 메뉴 정보를 가지고 메뉴 페이지로 이동하는 URL을 가정한 예제이다.

 

DB는 상황마다 다를 수 있으므로 DB에 관한 내용은 포함되어 있지 않다.

 

애플리케이션의 동작 순서

 

1. /menu URL을 입력하게 되면, MenuController의 goToMenu함수가 실행된다.

2. Spring Framework에 의해 생성된 MenuService의 getMenu함수가 실행된다.

3. 메뉴 정보를 조회한다.(현재는 하드코딩되어 있으며, DB 조회하는 내용으로 변경이 필요하다.)

4. 메뉴정보를 Model에 담는다.

5. Html에서 Thymeleaf을 사용하여 Object를 화면에 표시한다.

 

<!-- pom.xml의 dependencies -->
<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- spring-boot와 함께 thymeleaf도 포함 되어 있어야 한다. -->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
</dependencies>
//DemoMvcApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoMvcApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoMvcApplication.class, args);
	}
}
//MenuController.java
package com.example.demo.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.demo.dto.MenuDTO;
import com.example.demo.service.MenuService;

@Controller
public class MenuController {

	@Autowired
	private MenuService menuService;
	
	@RequestMapping("/menu")
	public String goToMenu(Model model) {
		List<MenuDTO> menuList = menuService.getMenu();
		model.addAttribute("menuList", menuList);
		return "menu";
	}
}
//MenuService.java
package com.example.demo.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.example.demo.dto.MenuDTO;

@Service
public class MenuService {
	public List<MenuDTO> getMenu() {
		//DB에서 메뉴 데이터를 조회하는 내용으로 변경이 필요한 소스 시작
		List<MenuDTO> menuList = new ArrayList<MenuDTO>();
		MenuDTO menuDto = new MenuDTO();
		menuDto.setMenuId(1);
		menuDto.setParentMenuId(0);
		menuDto.setMenuName("Top");
		menuList.add(menuDto);
		menuDto = new MenuDTO();
		menuDto.setMenuId(2);
		menuDto.setParentMenuId(1);
		menuDto.setMenuName("First Menu");
		menuList.add(menuDto);
		menuDto = new MenuDTO();
		menuDto.setMenuId(3);
		menuDto.setParentMenuId(1);
		menuDto.setMenuName("Second Menu");
		menuList.add(menuDto);
		//DB에서 메뉴 데이터를 조회하는 내용으로 변경이 필요한 소스 끝
		return menuList;
	}
}
//MenuDTO.java
package com.example.demo.dto;

import java.util.Date;

import lombok.Data;

@Data
public class MenuDTO {
	private int menuId;
	private int parentMenuId;
	private String menuName;
	private Date regDate;
	private String regId;
	private Date modDate;
	private String modId;
}
<!-- /src/main/resources/templates/menu.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Menu</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div>Menu Page</div>
<ul th:each="menu: ${menuList}">
      <li th:text="${menu.menuName}"></li>
</ul>
</body>
</html>

 


먼저, AOP나 CGLIB 내용은 고려하지 않고 기본 @Transactional을 사용 할 경우를 다룬 내용입니다.


우선, Spring boot에서 @Transactional 위한 기본 설정 사항


@Configuration

@EnableTransactionManagement

public class DataSourceConfig{

..

    @Bean

    public DataSourceTransactionManager txManager() {

        return new DataSourceTransactionManager(getDataSource());

    }

...

}


 위와 같이 설정을 하고 사용하게 되면 @Transactional 이용하여 트랜잭션을 사용 할 있다.

 


유의점

1. Dynamics proxy 사용하기 때문에 인터페이스 구현이 필요하다.


따라서, 아래와 같은 구조를 가져야 한다.

public interface AService {

}


public class AServiceImp implements AService {

@Transactional

public void biz() {

}

}



2. 내부 호출, 재귀 호출 로서 사용하면 안된다.


예를 들면

public class AServiceImp implements AService {


@Transactional

public void biz() {

//insert 호출

mapper.insertBiz();

//내부호출

bizUpdate();

}


@Transactional

public void bizUpdate() {

mapper.updateBiz();

mapper.deleteBiz();

}

}


위와 같이 @Transactional을 사용한 함수여도 내부적으로 호출을 사용하게 되면

트랙잭션이 동작하지 않게 된다.


따라서, 2가지 유의점을 고려하여 @Transactional을 사용하여야 한다.