Spring์—์„œ์˜ JPA ๐Ÿ”ฅ

JOY๐ŸŒฑยท2023๋…„ 4์›” 12์ผ
0

๐Ÿธ JPA

๋ชฉ๋ก ๋ณด๊ธฐ
7/8
post-thumbnail

๐Ÿ™‹โ€ Spring์—์„œ JPA๋ฅผ ํ™œ์šฉํ•ด๋ณด์ž !

GitHub

๐Ÿ“Œ ๊ธฐ๋ณธ ์…‹ํŒ…

๐Ÿ‘‰ application.yml

# server port config
server:
  port: 8001
  
# DB config
spring:
  datasource:
    driver-class-name: oracle.jdbc.driver.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521:xe
    username: C##GREEDY
    password: GREEDY
    
# JPA config
  jpa:
    generate-ddl: false       # create table์„ ํ•  ๋•Œ๋งŒ true(๊ธฐ๋ณธ๊ฐ’)
    show-sql: true            # JPA๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” SQL๊ตฌ๋ฌธ์„ ์ฝ˜์†”์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ
    database: oracle
    properties:
      hibernate:
        '[format_sql]': true  # SQL์„ ๊ฐœํ–‰ํ•˜์—ฌ ๋ณด๊ธฐ์ข‹๊ฒŒ ์ถœ๋ ฅ

๐Ÿ‘‰ pom.xml

<!-- Menu(์˜์†์„ฑ ๊ฐ์ฒด) -> MenuDTO(๋น„์˜์†์„ฑ ๊ฐ์ฒด)๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ModelMapper ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ -->
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
  	<groupId>org.modelmapper</groupId>
	<artifactId>modelmapper</artifactId>
	<version>3.1.1</version>
</dependency>

๐Ÿ‘‰ BeanConfiguration

@Configuration
public class BeanConfiguration {

	/* ModelMapper๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ ํ›„, ModelMapper๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Bean ๋“ฑ๋ก */
	@Bean
	public ModelMapper modelMapper() {
		
		return new ModelMapper();
	}
}


๐Ÿ‘€ templates (views)

๐Ÿ‘‰ main.html

	<h1 align="center">๐Ÿ๐Ÿฉ GREEDY RESTAURANT์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹น! ๐Ÿฉ๐Ÿพ</h1>
	
	<div align="center">
	<button onclick="location.href='/menu/81'">81๋ฒˆ ๋ฉ”๋‰ด ๋ณด๊ธฐ</button>
	<button onclick="location.href='/menu/list'">๋ฉ”๋‰ดํŒ ๋ณด๊ธฐ</button>
	<button onclick="location.href='/menu/regist'">๋ฉ”๋‰ด ๋“ฑ๋กํ•˜๊ธฐ</button>
	<button onclick="location.href='/menu/modify'">๋ฉ”๋‰ด ์ˆ˜์ •ํ•˜๊ธฐ</button>
	<button onclick="location.href='/menu/remove'">๋ฉ”๋‰ด ์‚ญ์ œํ•˜๊ธฐ</button>
	<button onclick="searchMenu()">๋ฉ”๋‰ด ๊ฒ€์ƒ‰ํ•˜๊ธฐ</button>
	<button onclick="location.href='/menu/recommend'">์˜ค๋Š˜์˜ ๋ฉ”๋‰ด ์ถ”์ฒœ๋ฐ›๊ธฐ</button>
	</div>
	
	<script>
		/* ์ž…๋ ฅ๋œ ํ‚ค์›Œ๋“œ๋กœ ๊ฒ€์ƒ‰ํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ™”๋ฉด์— ์กฐํšŒ์‹œํ‚ค๊ธฐ */
		function searchMenu() {
			
			const keyword = prompt('ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” ๐Ÿฅณ')
			
			if(keyword !== null && keyword.trim().length !== 0) {
				console.log(keyword);
				window.location.href = "/menu/search?keyword=" + keyword;
			} else {
				alert('ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” ๐Ÿคฅ')
			}
		}
	</script>

๐Ÿ‘‰ one.html

	<h1 align="center">โœจ ๋ฉ”๋‰ด โœจ</h1>

	<table align="center" border="1">
		<tr>
			<th>๋ฉ”๋‰ด๋ฒˆํ˜ธ</th>
			<th>๋ฉ”๋‰ด๋ช…</th>
			<th>๋ฉ”๋‰ด๊ฐ€๊ฒฉ</th>
			<th>์นดํ…Œ๊ณ ๋ฆฌ์ฝ”๋“œ</th>
			<th>ํŒ๋งค์ƒํƒœ</th>
		</tr>
		<tr>
			<td th:text="${ menu.menuCode }"></td>
			<td th:text="${ menu.menuName }"></td>
			<td th:text="${ menu.menuPrice }"></td>
			<td th:text="${ menu.categoryCode }"></td>
			<td th:text="${ menu.orderableStatus }"></td>
		</tr>
	</table>
	
	<script>
	/* ๋ฉ”๋‰ด ์ˆ˜์ • ํ›„, ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ redirect ๋˜๊ธฐ ์ „ alert ๋„์šฐ๊ธฐ */
	if(window.location.hash === '#menu-modify'){
	    alert('[[${message}]]'); // message ๋ณ€์ˆ˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ „๋‹ฌํ•œ Flash Attribute
	}
	</script>

๐Ÿ‘‰ list.html

<h1 align="center">โœจ ๋ฉ”๋‰ดํŒ โœจ</h1>

	<table align="center" border="1">
		<tr>
			<th>๋ฉ”๋‰ด๋ฒˆํ˜ธ</th>
			<th>๋ฉ”๋‰ด๋ช…</th>
			<th>๋ฉ”๋‰ด๊ฐ€๊ฒฉ</th>
			<th>์นดํ…Œ๊ณ ๋ฆฌ์ฝ”๋“œ</th>
			<th>ํŒ๋งค์ƒํƒœ</th>
		</tr>
		<tr th:each="menu : ${ menuList }">
			<td th:text="${ menu.menuCode }"></td>
			<td th:text="${ menu.menuName }"></td>
			<td th:text="${ menu.menuPrice }"></td>
			<td th:text="${ menu.categoryCode }"></td>
			<td th:text="${ menu.orderableStatus }"></td>
		</tr>
	</table>
	
	<script>
	/* ์‹ ๊ทœ ๋ฉ”๋‰ด ๋“ฑ๋ก or ๋ฉ”๋‰ด ์‚ญ์ œ ํ›„, ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ redirect ๋˜๊ธฐ ์ „ alert ๋„์šฐ๊ธฐ */
	if(window.location.hash === '#menu-regist' || window.location.hash === '#menu-remove'){
	    alert('[[${message}]]'); // message ๋ณ€์ˆ˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ „๋‹ฌํ•œ Flash Attribute
	}
	</script>

๐Ÿ‘‰ regist.html

<h3 align="center">์‹ ๊ทœ ๋ฉ”๋‰ด ๋“ฑ๋ก</h3>
	
	<form align="center" action="/menu/regist" method="post">
		<label>๋ฉ”๋‰ด ์ด๋ฆ„ : </label><input type="text" name="menuName"><br>
		<label>๋ฉ”๋‰ด ๊ฐ€๊ฒฉ : </label><input type="number" name="menuPrice"><br>
		<label>์นดํ…Œ๊ณ ๋ฆฌ : </label>
		<select name="categoryCode" id="categoryCode">
			<!-- 
				์นดํ…Œ๊ณ ๋ฆฌ ๋‚ด์šฉ์ด ๋ณ€ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์กฐํšŒ ํ•ด์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋ฉฐ
				์—ฌ๊ธฐ์—์„œ๋Š” ajax๋กœ ์ฒ˜๋ฆฌ
			 -->
		</select><br>
		<label>ํŒ๋งค ์ƒํƒœ : </label>
		<select name="orderableStatus">
			<option value="Y">ํŒ๋งค๊ฐ€๋Šฅ</option>
			<option value="N">ํŒ๋งค๋ถˆ๊ฐ€</option>
		</select><br>
		<input type="submit" value="์ „์†ก">
	</form>

	<script>
		/* ๋น„๋™๊ธฐ ํ†ต์‹ (ajax)์„ ํ†ตํ•ด ๋ชจ๋“  ์นดํ…Œ๊ณ ๋ฆฌ ๋ฆฌ์ŠคํŠธ ์กฐํšŒ */
		$(function(){
			$.ajax({
				url : '/menu/category',
				success : function(data) {
					console.log(data);
					
					let html = '';
					/* data๋ผ๋Š” ์กฐํšŒ๋œ ๋ฐฐ์—ด์„ ๋ฐ˜๋ณตํ•˜์—ฌ ํ•ฉ์‚ฐ์‹œํ‚ค๊ธฐ */
					for(let index in data) {
						html += `<option value='${data[index].categoryCode}'>${data[index].categoryName}</option>`;
						// ์กฐํšŒ๋œ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ด๋ฆ„์„ ํ™”๋ฉด์— ๋…ธ์ถœ์‹œํ‚ค๊ณ  ๊ทธ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์„ ํƒ(<option>)๋˜๋ฉด value๋Š” ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ฝ”๋“œ
					}
					/* ๊ทธ ๊ฐ’์„ <select>์— insertํ•˜์—ฌ ํ™”๋ฉด์— ๋…ธ์ถœ๋˜๋„๋ก ํ•จ */
					document.querySelector("#categoryCode").insertAdjacentHTML('beforeend', html);
					
				},
				error : function(xhr) {
					console.log(xhr);
				}
			});
		})
	</script>

๐Ÿ‘‰ modify.html

<h3 align="center">๋ฉ”๋‰ด ์ˆ˜์ •</h3>
	
	<form align="center" action="/menu/modify" method="post">
		<label>์ˆ˜์ •ํ•  ๋ฉ”๋‰ด : </label>
		<select name="menuCode" id="menuCode"></select><br>
		<label>์ƒˆ๋กœ์šด ๋ฉ”๋‰ด ์ด๋ฆ„ : </label>
		<input type="text" name="menuName"><br>
		<label>์ƒˆ๋กœ์šด ๋ฉ”๋‰ด ๊ฐ€๊ฒฉ : </label>
		<input type="number" name="menuPrice"><br>
		<label>์ƒˆ๋กœ์šด ๋ฉ”๋‰ด์˜ ์นดํ…Œ๊ณ ๋ฆฌ : </label>
		<select name="categoryCode" id="categoryCode"></select><br>
		<label>ํŒ๋งค ์ƒํƒœ : </label>
		<select name="orderableStatus">
			<option value="Y">ํŒ๋งค๊ฐ€๋Šฅ</option>
			<option value="N">ํŒ๋งค๋ถˆ๊ฐ€</option>
		</select><br>
		<input type="submit" value="์ „์†ก">
	</form>
	
	<script>
		/* ๋น„๋™๊ธฐ ํ†ต์‹ (ajax)์„ ํ†ตํ•ด ๋ชจ๋“  ์นดํ…Œ๊ณ ๋ฆฌ ๋ฆฌ์ŠคํŠธ ์กฐํšŒ */
		$(function(){
			$.ajax({
				url : '/menu/category',
				success : function(data) {
					console.log(data);
					
					let html = '';
					/* data๋ผ๋Š” ์กฐํšŒ๋œ ๋ฐฐ์—ด์„ ๋ฐ˜๋ณตํ•˜์—ฌ ํ•ฉ์‚ฐ์‹œํ‚ค๊ธฐ */
					for(let index in data) {
						html += `<option value='${data[index].categoryCode}'>${data[index].categoryName}</option>`;
						// ์กฐํšŒ๋œ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ด๋ฆ„์„ ํ™”๋ฉด์— ๋…ธ์ถœ์‹œํ‚ค๊ณ  ๊ทธ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์„ ํƒ(<option>)๋˜๋ฉด value๋Š” ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ฝ”๋“œ
					}
					/* ๊ทธ ๊ฐ’์„ <select>์— insertํ•˜์—ฌ ํ™”๋ฉด์— ๋…ธ์ถœ๋˜๋„๋ก ํ•จ */
					document.querySelector("#categoryCode").insertAdjacentHTML('beforeend', html);
					
				},
				error : function(xhr) {
					console.log(xhr);
				}
			});
		})
		
		/* ๋น„๋™๊ธฐ ํ†ต์‹ (ajax)์„ ํ†ตํ•ด ๋ชจ๋“  ๋ฉ”๋‰ด ๋ฆฌ์ŠคํŠธ ์กฐํšŒ */
		$(function(){
			$.ajax({
				url : '/menu/menu',
				success : function(data) {
					console.log(data);
					
					let html = '';
					/* data๋ผ๋Š” ์กฐํšŒ๋œ ๋ฐฐ์—ด์„ ๋ฐ˜๋ณตํ•˜์—ฌ ํ•ฉ์‚ฐ์‹œํ‚ค๊ธฐ */
					for(let index in data) {
						html += `<option value='${data[index].menuCode}'>[${data[index].menuCode}] ${data[index].menuName}</option>`;
						// ์กฐํšŒ๋œ ๋ฉ”๋‰ด์ฝ”๋“œ์™€ ์ด๋ฆ„์„ ํ™”๋ฉด์— ๋…ธ์ถœ์‹œํ‚ค๊ณ  ๊ทธ ๋ฉ”๋‰ด๊ฐ€ ์„ ํƒ(<option>)๋˜๋ฉด value๋Š” ํ•ด๋‹น ๋ฉ”๋‰ด์˜ ์ฝ”๋“œ
					}
					/* ๊ทธ ๊ฐ’์„ <select>์— insertํ•˜์—ฌ ํ™”๋ฉด์— ๋…ธ์ถœ๋˜๋„๋ก ํ•จ */
					document.querySelector("#menuCode").insertAdjacentHTML('beforeend', html);
					
				},
				error : function(xhr) {
					console.log(xhr);
				}
			});
		})
	</script>

๐Ÿ‘‰ delete.html

<h3 align="center">๋ฉ”๋‰ด ์‚ญ์ œ</h3>
	
	<form align="center" action="/menu/remove" method="post">
		<label>์‚ญ์ œํ•  ๋ฉ”๋‰ด : </label>
		<select name="menuCode" id="menuCode"></select><br>
		<input type="submit" value="์ „์†ก">
	</form>

	<script>
		/* ๋น„๋™๊ธฐ ํ†ต์‹ (ajax)์„ ํ†ตํ•ด ๋ชจ๋“  ๋ฉ”๋‰ด ๋ฆฌ์ŠคํŠธ ์กฐํšŒ */
		$(function(){
			$.ajax({
				url : '/menu/menu',
				success : function(data) {
					console.log(data);
					
					let html = '';
					/* data๋ผ๋Š” ์กฐํšŒ๋œ ๋ฐฐ์—ด์„ ๋ฐ˜๋ณตํ•˜์—ฌ ํ•ฉ์‚ฐ์‹œํ‚ค๊ธฐ */
					for(let index in data) {
						html += `<option value='${data[index].menuCode}'>${data[index].menuName}</option>`;
						// ์กฐํšŒ๋œ ๋ฉ”๋‰ด์˜ ์ด๋ฆ„์„ ํ™”๋ฉด์— ๋…ธ์ถœ์‹œํ‚ค๊ณ  ๊ทธ ๋ฉ”๋‰ด๊ฐ€ ์„ ํƒ(<option>)๋˜๋ฉด value๋Š” ํ•ด๋‹น ๋ฉ”๋‰ด์˜ ์ฝ”๋“œ
					}
					/* ๊ทธ ๊ฐ’์„ <select>์— insertํ•˜์—ฌ ํ™”๋ฉด์— ๋…ธ์ถœ๋˜๋„๋ก ํ•จ */
					document.querySelector("#menuCode").insertAdjacentHTML('beforeend', html);
					
				},
				error : function(xhr) {
					console.log(xhr);
				}
			});
		})
	</script>

๐Ÿ‘€ Entity

๐Ÿ‘‰ Category

@Entity
@Table(name="TBL_CATEGORY")
public class Category {

	@Id
	@Column(name="CATEGORY_CODE")
	private int categoryCode;
	
	@Column(name="CATEGORY_NAME")
	private String categoryName;
	
	@Column(name="REF_CATEGORY_CODE")
	private Integer refCategoryCode;
    
    /* ๊ธฐ๋ณธ ์…‹ํŒ… */
    
}

๐Ÿ‘‰ Menu

@Entity
@Table(name="TBL_MENU")
@SequenceGenerator(						
		name="SEQ_MENU_CODE_GENERATOR",	
		sequenceName="SEQ_MENU_CODE",	
		initialValue=100,				
		allocationSize=1				
)
public class Menu {
	
	@Id							
	@Column(name="MENU_CODE")	
	@GeneratedValue(								
			strategy=GenerationType.SEQUENCE,		
			generator="SEQ_MENU_CODE_GENERATOR"		
	)
	private int menuCode;
	@Column(name="MENU_NAME")
	private String menuName;
	@Column(name="MENU_PRICE")
	private int menuPrice;
	@Column(name="CATEGORY_CODE")
	private int categoryCode;
	@Column(name="ORDERABLE_STATUS")
	private String orderableStatus;
    
    /* ๊ธฐ๋ณธ ์…‹ํŒ… */
}

๐Ÿ‘€ DTO

๐Ÿ‘‰ CategoryDTO

public class CategoryDTO {

	private int categoryCode;
	private String categoryName;
	private Integer refCategoryCode;
    
    /* ๊ธฐ๋ณธ ์…‹ํŒ… */
    
}

๐Ÿ‘‰ MenuDTO

public class MenuDTO {

	private int menuCode;
	private String menuName;
	private int menuPrice;
	private int categoryCode;
	private String orderableStatus;
    
    /* ๊ธฐ๋ณธ ์…‹ํŒ… */
    
}

๐Ÿ‘€ Controller

๐Ÿ‘‰ MainController

@Controller
public class MainController {

	@GetMapping(value = {"/", "/main"})
	public String main() {
		
		return "main/main";
	}
}

๐Ÿ‘‰ MenuController

@PathVariable @ResponseBody RedirectAttributes addFlashAttribute() shuffle() subList()

@Controller
@RequestMapping("/menu")
public class MenuController {

	private MenuService menuService;
	
	public MenuController(MenuService menuService) {
		this.menuService = menuService;
	}
	/* ๋ฉ”๋‰ด ์ฝ”๋“œ๋กœ ํ•ด๋‹น ๋ฉ”๋‰ด ์กฐํšŒํ•˜๊ธฐ */
	@GetMapping("/{menuCode}")
	public String findMenuByCode(@PathVariable int menuCode, Model model) {
		
		MenuDTO menu = menuService.findMenuByCode(menuCode);
//		System.out.println("menu : " + menu);
		
		model.addAttribute("menu", menu);
		
		return "menu/one";
	}
	/* ๋ชจ๋“  ๋ฉ”๋‰ด ๋ฆฌ์ŠคํŠธ ์กฐํšŒํ•˜๊ธฐ */
	@GetMapping("/list")
	public String findAllMenu(Model model) {
		
		List<MenuDTO> menuList = menuService.findAllMenu();
		
		model.addAttribute("menuList", menuList);
		
		return "menu/list";
	}
	/* '๋ฉ”๋‰ด ๋“ฑ๋กํ•˜๊ธฐ'๋ฅผ ์œ„ํ•œ ํ™”๋ฉด ์ „ํ™˜ */
	@GetMapping("/regist")
	public void registPage() {}
	
	/* ์นดํ…Œ๊ณ ๋ฆฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋น„๋™๊ธฐ ํ†ต์‹ (ajax) */
	@GetMapping(value="category", produces="application/json; charset=UTF-8")
	@ResponseBody /* ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์ด ๊ณง ์‘๋‹ต๋˜๋Š” ๊ฐ’์˜ ๋ฐ”๋”” */
	public List<CategoryDTO> findCategoryList() {
		
		return menuService.findAllCategory();
	}
	
	/* ๋ฉ”๋‰ด ๋“ฑ๋กํ•˜๊ธฐ */
	@PostMapping("/regist")
	public String registNewMenu(@ModelAttribute MenuDTO newMenu, RedirectAttributes rttr) { /* @ModelAttribute๋Š” ์ƒ๋žต๋˜์–ด๋„ ์ •์ƒ ๋™์ž‘ํ•˜์ง€๋งŒ ๋ช…์‹œ */
		
		menuService.registNewMenu(newMenu);
		
		rttr.addFlashAttribute("message", "๋ฉ”๋‰ด ๋“ฑ๋ก ์„ฑ๊ณต! ๋“ฑ๋ก๋œ ๋ฉ”๋‰ด๋ฅผ ํ™•์ธํ•˜์„ธ์š” ๐Ÿฅณ");
		
		return "redirect:/menu/list#menu-regist";
	}
	/* ๋ฉ”๋‰ด ์ˆ˜์ •ํ•˜๊ธฐ */
	@GetMapping("/modify")
	public void modifyPage() {}
	
	@PostMapping("/modify")
	public String menuModify(@ModelAttribute MenuDTO menu, RedirectAttributes rttr) {
		
		menuService.modifyMenu(menu);
		
		rttr.addFlashAttribute("message", "๋ฉ”๋‰ด ์ˆ˜์ • ์„ฑ๊ณต! ์ˆ˜์ •๋œ ๋ฉ”๋‰ด๋ฅผ ํ™•์ธํ•˜์„ธ์š” ๐Ÿ˜");
		
		/* ์ˆ˜์ •๋œ ๋ฉ”๋‰ด์˜ ์ƒ์„ธํŽ˜์ด์ง€๋กœ ์ด๋™ */
		return "redirect:/menu/" + menu.getMenuCode() + "#menu-modify";
	}
	/* ๋ฉ”๋‰ด ์‚ญ์ œํ•˜๊ธฐ */
	@GetMapping("/remove")
	public void removePage() {}
	
	/* ๋ฉ”๋‰ด ๋ฆฌ์ŠคํŠธ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋น„๋™๊ธฐ ํ†ต์‹ (ajax) */
	@GetMapping(value="menu", produces="application/json; charset=UTF-8")
	@ResponseBody /* ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์ด ๊ณง ์‘๋‹ต๋˜๋Š” ๊ฐ’์˜ ๋ฐ”๋”” */
	public List<MenuDTO> findMenuList() {
		
		return menuService.findAllMenu();
	}
	
	@PostMapping("/remove")
	public String menuRemove(@ModelAttribute MenuDTO menu, RedirectAttributes rttr) {
		
		menuService.removeMenu(menu);
		
		rttr.addFlashAttribute("message", "๋ฉ”๋‰ด ์‚ญ์ œ ์„ฑ๊ณต! ๐Ÿ‘‹");
		
		return "redirect:/menu/list#menu-remove";
	}
	/* ๋ฉ”๋‰ด ๊ฒ€์ƒ‰ํ•˜๊ธฐ */
	@GetMapping("/search")
	public String searchedPage(@RequestParam(value="keyword", required=false) String keyword, Model model) {
		
		List<MenuDTO> menuList = menuService.searchMenu(keyword);
		
		model.addAttribute("menuList", menuList);
		
		return "/menu/list";
	}
	/* ์˜ค๋Š˜์˜ ๋ฉ”๋‰ด ์ถ”์ฒœ๋ฐ›๊ธฐ */
	@GetMapping("/recommend")
	public String recommendPage(Model model) {
		
		List<MenuDTO> menuList = menuService.findAllMenu();
		
		Collections.shuffle(menuList); // shuffle() ๋ฉ”์†Œ๋“œ๋กœ menuList ์•ˆ์— ์žˆ๋Š” ๊ฐ’ ๋žœ๋ค์œผ๋กœ ์žฌ๋ฐฐ์น˜
		List<MenuDTO> recommendedMenulist = menuList.subList(0, 5); // subList() ๋ฉ”์†Œ๋“œ๋กœ 0๋ถ€ํ„ฐ 4๋ฒˆ ์ธ๋ฑ์Šค๊นŒ์ง€๋งŒ ์ถ”์ถœ
		
		model.addAttribute("menuList", recommendedMenulist);
		
		return "/menu/list";
	}
}

๐Ÿ‘€ Service

@PersistenceContext : ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
modelMapper.map() stream().map() collect(Collectors.toList())

๐Ÿ‘‰ MenuService

@Service
public class MenuService {

	private MenuRepository menuRepository;	// MenuRepository๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ ์œ„ํ•ด ํ•„๋“œ ์„ ์–ธ ๋ฐ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•œ ์˜์กด์„ฑ ์ฃผ์ž…
	private ModelMapper modelMapper;		// ModelMapper๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ ์œ„ํ•ด ํ•„๋“œ ์„ ์–ธ ๋ฐ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•œ ์˜์กด์„ฑ ์ฃผ์ž…
	
	@PersistenceContext // ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
	private EntityManager entityManager;
	
	public MenuService(MenuRepository menuRepository, ModelMapper modelMapper) {
		this.menuRepository = menuRepository;
		this.modelMapper = modelMapper;
	}
	/* ์˜์†์„ฑ ๊ฐ์ฒด(์—”ํ‹ฐํ‹ฐ)๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ํ›ผ์† ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ ๋น„์˜์† ๊ฐ์ฒด๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ฐ˜ํ™˜ */
	/* MenuDTO : ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์•„๋‹Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฌถ์–ด์„œ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด */
	/* ๋ฉ”๋‰ด ์ฝ”๋“œ๋กœ ํ•ด๋‹น ๋ฉ”๋‰ด ์กฐํšŒํ•˜๊ธฐ */
	public MenuDTO findMenuByCode(int menuCode) {
		
		/* Menu -> MenuDTO(๋น„์˜์† ๊ฐ์ฒด)๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ModelMapper ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ ์ถ”๊ฐ€ ํ›„ ์‚ฌ์šฉ */
		return modelMapper.map(menuRepository.findMenuByCode(entityManager, menuCode), MenuDTO.class);
		// modelMapper.map(๋ณ€ํ™˜ํ•˜๊ณ ์žํ•˜๋Š” ๋Œ€์ƒ์˜ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด, ๋ณ€ํ™˜ํ•˜๊ณ ์žํ•˜๋Š” ํƒ€์ž…);
	}
	/* ๋ชจ๋“  ๋ฉ”๋‰ด ๋ฆฌ์ŠคํŠธ ์กฐํšŒํ•˜๊ธฐ */
	public List<MenuDTO> findAllMenu() {
		
		/* List<Menu> Menu ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์œผ๋ฏ€๋กœ Streamํ™” ์‹œ์ผœ MenuDTO */
		List<Menu> menuList = menuRepository.findAllMenu(entityManager);
		
		return menuList.stream().map(menu -> modelMapper.map(menu, MenuDTO.class)).collect(Collectors.toList());
		/* menu : Menu ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋“ค
		 * stream์˜ map()์€ ๊ด„ํ˜ธ ์•ˆ์˜ ๋™์ž‘์„ ํ•˜๋‚˜ํ•˜๋‚˜ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋‚˜์„œ ๊ฐ€๊ณต๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ 
		 * collect(Collectors.toList() : ๋‹ค์‹œ stream์„ List ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ */
		
		/* 
		 * [์ฝ”๋“œ ํ•ด์„]
		 * 1. menuList๋ผ๋Š” List<Menu> ํƒ€์ž…์„ streamํ™” ํ•˜์—ฌ map() ์‚ฌ์šฉ
		 * 2. menu๋ผ๋Š” Menu ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋“ค์„ modelMapper์˜ map()๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด MenuDTO ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜
		 * 3. ๋‹ค์‹œ stream์„ Listํ˜•ํƒœ๋กœ ๋ณ€ํ™˜
		 */
	}
	/* ๋ชจ๋“  ์นดํ…Œ๊ณ ๋ฆฌ ๋ฆฌ์ŠคํŠธ ์กฐํšŒํ•˜๊ธฐ */
	public List<CategoryDTO> findAllCategory() {
		
		List<Category> categoryList = menuRepository.findAllCategory(entityManager);
		
		return categoryList.stream().map(category -> modelMapper.map(category, CategoryDTO.class)).collect(Collectors.toList());
	}
	/* ์Šคํ”„๋ง์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋ฅผ ์ง€์›
	 * ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ @Transactional์„ ์„ ์–ธํ•˜๋Š” ์„ ์–ธ์  ํŠธ๋žœ์žญ์…˜์ด ๋ณดํŽธ์ ์ธ ๋ฐฉ์‹
	 * ํด๋ž˜์Šค ๋ ˆ๋ฒจ๊ณผ ๋ฉ”์†Œ๋“œ ๋ ˆ๋ฒจ์— ์ž‘์„ฑ๋  ์ˆ˜ ์žˆ๊ณ  ํด๋ž˜์Šค ๋ ˆ๋ฒจ์— ์ž‘์„ฑ ์‹œ ํ•˜์œ„ ๋ชจ๋“  ๋ฉ”์†Œ๋“œ์— ์ ์šฉ
	 * ์–ด๋…ธํ…Œ์ด์…˜์ด ์„ ์–ธ๋˜๋ฉด ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์‹œ ์ž๋™์œผ๋กœ ํ”„๋ก์‹œ ๊ฐ์ฒด(๊ฐ€๋กœ์ฑ„๋Š” ๊ฐ์ฒด)๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ ํ•ด๋‹น ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์ •์ƒ ์ˆ˜ํ–‰ ์—ฌ๋ถ€์— ๋”ฐ๋ผ
	 * commit, rollback ์ฒ˜๋ฆฌ๋ฅผ ํ•จ */
	
	/* ๋ฉ”๋‰ด ๋“ฑ๋กํ•˜๊ธฐ */
	@Transactional
	public void registNewMenu(MenuDTO newMenu) {
		
		/* ์ด์ „ ๋ฐฉ์‹๊ณผ๋Š” ๋ฐ˜๋Œ€๋กœ MenuDTO๋ฅผ Menuํ˜•ํƒœ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ Menuํƒ€์ž…์œผ๋กœ ์ „๋‹ฌ */
		menuRepository.registNewMenu(entityManager, modelMapper.map(newMenu, Menu.class));
	}
	/* ๋ฉ”๋‰ด ์ˆ˜์ •ํ•˜๊ธฐ */
	@Transactional
	public void modifyMenu(MenuDTO menu) {
		
		menuRepository.modifyMenu(entityManager, modelMapper.map(menu, Menu.class));
	}
	/* ๋ฉ”๋‰ด ์‚ญ์ œํ•˜๊ธฐ */
	@Transactional
	public void removeMenu(MenuDTO menu) {
		
		menuRepository.removeMenu(entityManager, modelMapper.map(menu, Menu.class));
	}
	/* ๋ฉ”๋‰ด ๊ฒ€์ƒ‰ํ•˜๊ธฐ */
	public List<MenuDTO> searchMenu(String keyword) {
		
		List<Menu> menuList = menuRepository.searchMenu(entityManager, keyword);
		
		return menuList.stream().map(menu -> modelMapper.map(menu, MenuDTO.class)).collect(Collectors.toList());
	}
}

๐Ÿ‘€ Repository

find() persist() remove() createQuery() getResultList() setParameter()

๐Ÿ‘‰ MenuRepository

@Repository
public class MenuRepository {

	/* ๋ฉ”๋‰ด ์ฝ”๋“œ๋กœ ํ•ด๋‹น ๋ฉ”๋‰ด ์กฐํšŒํ•˜๊ธฐ */
	public Menu findMenuByCode(EntityManager entityManager, int menuCode) {
		
		/* find()๋Š” ํ…Œ์ด๋ธ”์˜ PK๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์†Œ๋“œ์ด๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋„ EntityManager๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฐ€์ ธ์˜ด */
		return entityManager.find(Menu.class, menuCode);
	}
	/* ๋ชจ๋“  ๋ฉ”๋‰ด ๋ฆฌ์ŠคํŠธ ์กฐํšŒํ•˜๊ธฐ */
	public List<Menu> findAllMenu(EntityManager entityManager) {
		
		String jpql = "SELECT m FROM Menu AS m ORDER BY m.menuCode ASC";
		
		return entityManager.createQuery(jpql, Menu.class).getResultList();
	}
	/* '๋ฉ”๋‰ด ๋“ฑ๋กํ•˜๊ธฐ'์—์„œ ํ•„์š”ํ•œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ฆฌ์ŠคํŠธ ์กฐํšŒํ•˜๊ธฐ(ajax) */
	public List<Category> findAllCategory(EntityManager entityManager) {
		
		String jpql = "SELECT c FROM Category AS c ORDER BY c.categoryCode ASC";
				
		return entityManager.createQuery(jpql, Category.class).getResultList();
	}
	
	/* ๋ฉ”๋‰ด ๋“ฑ๋กํ•˜๊ธฐ */
	public void registNewMenu(EntityManager entityManager, Menu menu) {
		
		/* entityManager์•ผ, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— menu๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•ด์ฃผ๋ ด! */
		entityManager.persist(menu);
	}
	/* ๋ฉ”๋‰ด ์ˆ˜์ •ํ•˜๊ธฐ */
	public void modifyMenu(EntityManager entityManager, Menu menu) {
		
		/* menu : ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ๋ฐ›์€ menuCode, menuName, menuPrice, categoryCode, orderableStatus๊ฐ€ ๋„˜์–ด์˜ด */
		System.out.println(menu);
		
		/* ์ „๋‹ฌ ๋ฐ›์€ ๋ฉ”๋‰ด ์ •๋ณด๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋จผ์ € ์กฐํšŒ */
		Menu selectedMenu = entityManager.find(Menu.class, menu.getMenuCode());
		
		/* ์กฐํšŒ๋œ ๋ฉ”๋‰ด ๊ฐ์ฒด๋ฅผ ์ˆ˜์ • */
		selectedMenu.setMenuName(menu.getMenuName());
		selectedMenu.setMenuPrice(menu.getMenuPrice());
		selectedMenu.setCategoryCode(menu.getCategoryCode());
		selectedMenu.setOrderableStatus(menu.getOrderableStatus());
	}
	/* ๋ฉ”๋‰ด ์‚ญ์ œํ•˜๊ธฐ */
	public void removeMenu(EntityManager entityManager, Menu menu) {
		
		/* ์ „๋‹ฌ ๋ฐ›์€ ๋ฉ”๋‰ด ์ •๋ณด๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋จผ์ € ์กฐํšŒ */
		Menu selectedMenu = entityManager.find(Menu.class, menu.getMenuCode());
		
		entityManager.remove(selectedMenu);
	}
	/* ๋ฉ”๋‰ด ๊ฒ€์ƒ‰ํ•˜๊ธฐ */
	public List<Menu> searchMenu(EntityManager entityManager, String keyword) {
		
		String jpql = "SELECT m FROM Menu AS m WHERE m.menuName LIKE :keyword ORDER BY m.menuCode ASC";
		
		return entityManager.createQuery(jpql, Menu.class).setParameter("keyword", "%"+keyword+"%").getResultList();
	}
}
profile
Tiny little habits make me

0๊ฐœ์˜ ๋Œ“๊ธ€