[Spring Data JPA] Exercise πŸ”₯

Joy🌱·2023λ…„ 4μ›” 15일
0

πŸ€– Exercise

λͺ©λ‘ 보기
6/6

πŸ“Œ κΈ°λ³Έ μ…‹νŒ…

πŸ‘‰ 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

<!-- μ˜μ†μ„± 객체 <=> λΉ„μ˜μ†μ„± 객체둜 λ³€ν™˜ν•  수 μžˆλŠ” 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();
	}
}

πŸ‘‰ PagingButtonInfo

public class PagingButtonInfo {
	
	private int currentPage;
	private int startPage;
	private int endPage;
    
    /* κΈ°λ³Έ μ…‹νŒ… */
    
}

πŸ‘‰ Pagenation

public class Pagenation {
	
	public static PagingButtonInfo getPagingButtonInfo(Page page) {
		
		int currentPage = page.getNumber() + 1;	 /* 인덱슀 κΈ°μ€€μ΄λ―€λ‘œ +1 */
		int defaultButtonCount = 10;
		int startPage;
		int endPage;
		
		startPage = (int) (Math.ceil((double) currentPage / defaultButtonCount) - 1) * defaultButtonCount + 1;
		endPage = startPage + defaultButtonCount - 1;
		
		/* λ‚΄κ°€ 가진 총 νŽ˜μ΄μ§€ μˆ˜κ°€ 4일 경우, endPage(10)보닀 μž‘μœΌλ―€λ‘œ endPageλ₯Ό 4둜 λ³€κ²½ν•˜λŠ” 둜직 */
		if(page.getTotalPages() < endPage)
			endPage = page.getTotalPages();
		
		if(page.getTotalPages() == 0 && endPage == 0)
			endPage = startPage;
		
		return new PagingButtonInfo(currentPage, startPage, endPage);
	}

}

πŸ‘€ Template (views)

πŸ‘‰ main.html

	<h1 align="center">🌱 λ–‘μžŽ 백화점 🌱</h1>
	
	<div align="center">
	<button onclick="location.href='/product/todays'">였늘의 μƒν’ˆ</button>
	<button onclick="location.href='/product/list'">전체 μƒν’ˆ</button>
	<button onclick="location.href='/product/regist'">μƒν’ˆ 등둝</button>
	<button onclick="location.href='/product/modify'">μƒν’ˆ μˆ˜μ •</button>
	<button onclick="location.href='/product/remove'">μƒν’ˆ μ‚­μ œ</button>
	</div>

πŸ‘‰ todays.html

	<h1 align="center">πŸ‘ 였늘의 μƒν’ˆ πŸ‘</h1>

    <table align="center" border="1">
		<tr>
			<th>μƒν’ˆλ²ˆν˜Έ</th>
			<th>μƒν’ˆλͺ…</th>
			<th>μƒν’ˆ νŒλ§€κ°€</th>
			<th>등둝일</th>
			<th>μ œμ‘°μ‚¬</th>
			<th>νŒλ§€μ—¬λΆ€</th>
		</tr>
		<tr th:each="product : ${ productList }">
			<td th:text="${ product.productNo }"></td>
			<td th:text="${ product.productName }"></td>
			<td th:text="${ #numbers.formatInteger(product.productPrice, 3, 'COMMA') } + 원"></td>
			<td th:text="${ product.date }"></td>
			<td th:text="${ product.supplierName }"></td>
			<td th:text="${ product.orderableStatus }"></td>
		</tr>
	</table>

πŸ‘‰ list.html

	<h1 align="center">🐀 All Product 🐀</h1>
	
	<div class="flex">
		<div align="left" class="searchBox">
		<form action="/product/search" method="get">
		    <input type="text" placeholder="μƒν’ˆλͺ… μž…λ ₯ :)" name="keyword">
		    <input type="submit" value="검색">
	    </form>
	    </div>
	    
	    <div align="right" class="dateBox">
		<form action="/product/after" method="get">
		    <input type="date" name="dateAfter">
		    <input type="submit" value="이후 μƒν’ˆ 쑰회">
	    </form>
		</div>
    </div>
    
    <table align="center" border="1">
		<tr>
			<th>μƒν’ˆλ²ˆν˜Έ</th>
			<th>μƒν’ˆλͺ…</th>
			<th>μƒν’ˆ νŒλ§€κ°€</th>
			<th>등둝일</th>
			<th>μ œμ‘°μ‚¬</th>
			<th>νŒλ§€μ—¬λΆ€</th>
		</tr>
		<tr th:each="product : ${ productList }">
			<td th:text="${ product.productNo }"></td>
			<td th:text="${ product.productName }"></td>
			<td th:text="${ #numbers.formatInteger(product.productPrice, 3, 'COMMA') } + 원"></td>
			<td th:text="${ product.date }"></td>
			<td th:text="${ product.supplierName }"></td>
			<td th:text="${ product.orderableStatus }"></td>
		</tr>
	</table>
	
	<div align="center" id="paging" >
		
		<!-- 맨 μ•žμœΌλ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/list?page=' + @{${paging.startPage}} + '\''">β—€β—€</button>
		
		<!-- 이전 νŽ˜μ΄μ§€λ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/list?page=' + @{${paging.currentPage - 1}} + '\''"
				th:disabled="${ productList.first }">β—€</button>
		
		<!-- 숫자 λ²„νŠΌ -->
		<th:block th:each="page : ${ #numbers.sequence(paging.startPage, paging.endPage)}">
			<button th:onclick="'location.href=\'/product/list?page=' + @{${page}} + '\''"
					th:text="${ page }"
					th:disabled="${ paging.currentPage eq page }">
			</button>
		</th:block>
		
		<!-- λ‹€μŒ νŽ˜μ΄μ§€λ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/list?page=' + @{${paging.currentPage + 1}} + '\''"
				th:disabled="${ productList.last }">β–Ά</button>
		
		<!-- 맨 끝으둜 이동 -->
		<button th:onclick="'location.href=\'/product/list?page=' + @{${paging.endPage}} + '\''">β–Άβ–Ά</button>
	</div>
	
	
	<script>
	/* μ‹ κ·œ μƒν’ˆ 등둝 or μƒν’ˆ μ‚­μ œ ν›„, ν•΄λ‹Ή νŽ˜μ΄μ§€λ‘œ redirect 되기 μ „ alert λ„μš°κΈ° */
	if(window.location.hash === '#success-regist' || window.location.hash === '#success-remove'){
	    alert('[[${message}]]'); // message λ³€μˆ˜λŠ” μ»¨νŠΈλ‘€λŸ¬μ—μ„œ μ „λ‹¬ν•œ Flash Attribute
	}
	</script>

πŸ‘‰ search.html

	<h1 align="center" th:text="'🐀 Products searched with ' + ${ keyword } + ' 🐀'"></h1>
	
	<div class="flex">
		<div align="left" class="searchBox">
		<form action="/product/search" method="get">
		    <input type="text" placeholder="μƒν’ˆλͺ… μž…λ ₯ :)" name="keyword">
		    <input type="submit" value="검색">
	    </form>
	    </div>
	    
	    <div align="right" class="dateBox">
		<form action="/product/after" method="get">
		    <input type="date" name="dateAfter">
		    <input type="submit" value="이후 μƒν’ˆ 쑰회">
	    </form>
		</div>
    </div>
	
	<table align="center" border="1">
		<tr>
			<th>μƒν’ˆλ²ˆν˜Έ</th>
			<th>μƒν’ˆλͺ…</th>
			<th>μƒν’ˆ νŒλ§€κ°€</th>
			<th>등둝일</th>
			<th>μ œμ‘°μ‚¬</th>
			<th>νŒλ§€μ—¬λΆ€</th>
		</tr>
		<tr th:each="product : ${ productList }">
			<td th:text="${ product.productNo }"></td>
			<td th:text="${ product.productName }"></td>
			<td th:text="${ #numbers.formatInteger(product.productPrice, 3, 'COMMA') } + 원"></td>
			<td th:text="${ product.date }"></td>
			<td th:text="${ product.supplierName }"></td>
			<td th:text="${ product.orderableStatus }"></td>
		</tr>
	</table>
	
	<div align="center" id="paging" >
		
		<!-- 맨 μ•žμœΌλ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/search?keyword=' + @{${ keyword }} + '&page=' + @{${paging.startPage}} + '\''">β—€β—€</button>
		
		<!-- 이전 νŽ˜μ΄μ§€λ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/search?keyword=' + @{${ keyword }} + '&page=' + @{${paging.currentPage - 1}} + '\''"
				th:disabled="${ productList.first }">β—€</button>
		
		<!-- 숫자 λ²„νŠΌ -->
		<th:block th:each="page : ${ #numbers.sequence(paging.startPage, paging.endPage)}">
			<button th:onclick="'location.href=\'/product/search?keyword=' + @{${ keyword }} + '&page=' + @{${page}} + '\''"
					th:text="${ page }"
					th:disabled="${ paging.currentPage eq page }">
			</button>
		</th:block>
		
		<!-- λ‹€μŒ νŽ˜μ΄μ§€λ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/search?keyword=' + @{${ keyword }} + '&page=' + @{${paging.currentPage + 1}} + '\''"
				th:disabled="${ productList.last }">β–Ά</button>
		
		<!-- 맨 끝으둜 이동 -->
		<button th:onclick="'location.href=\'/product/search?keyword=' + @{${ keyword }} + '&page=' + @{${paging.endPage}} + '\''">β–Άβ–Ά</button>
	</div>

πŸ‘‰ after.html

	<h1 align="center">🐀 <span th:text="${ dateAfter }"></span> 이후 λ“±λ‘λœ μƒν’ˆλ“€ 🐀</h1>
	
	<div class="flex">
		<div align="left" class="searchBox">
		<form action="/product/search" method="get">
		    <input type="text" placeholder="μƒν’ˆλͺ… μž…λ ₯ :)" name="keyword">
		    <input type="submit" value="검색">
	    </form>
	    </div>
	    
	    <div align="right" class="dateBox">
		<form action="/product/after" method="get">
		    <input type="date" name="dateAfter">
		    <input type="submit" value="이후 μƒν’ˆ 쑰회">
	    </form>
		</div>
    </div>
    
    <table align="center" border="1">
		<tr>
			<th>μƒν’ˆλ²ˆν˜Έ</th>
			<th>μƒν’ˆλͺ…</th>
			<th>μƒν’ˆ νŒλ§€κ°€</th>
			<th>등둝일</th>
			<th>μ œμ‘°μ‚¬</th>
			<th>νŒλ§€μ—¬λΆ€</th>
		</tr>
		<tr th:each="product : ${ productList }">
			<td th:text="${ product.productNo }"></td>
			<td th:text="${ product.productName }"></td>
			<td th:text="${ #numbers.formatInteger(product.productPrice, 3, 'COMMA') } + 원"></td>
			<td th:text="${ product.date }"></td>
			<td th:text="${ product.supplierName }"></td>
			<td th:text="${ product.orderableStatus }"></td>
		</tr>
	</table>
	
	<div align="center" id="paging" >
		
		<!-- 맨 μ•žμœΌλ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/after?dateAfter=' + @{${ dateAfter }} + '&page=' + @{${paging.startPage}} + '\''">β—€β—€</button>
		
		<!-- 이전 νŽ˜μ΄μ§€λ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/after?dateAfter=' + @{${ dateAfter }} + '&page=' + @{${paging.currentPage - 1}} + '\''"
				th:disabled="${ productList.first }">β—€</button>
		
		<!-- 숫자 λ²„νŠΌ -->
		<th:block th:each="page : ${ #numbers.sequence(paging.startPage, paging.endPage)}">
			<button th:onclick="'location.href=\'/product/after?dateAfter=' + @{${ dateAfter }} + '&page=' + @{${page}} + '\''"
					th:text="${ page }"
					th:disabled="${ paging.currentPage eq page }">
			</button>
		</th:block>
		
		<!-- λ‹€μŒ νŽ˜μ΄μ§€λ‘œ 이동 -->
		<button th:onclick="'location.href=\'/product/after?dateAfter=' + @{${ dateAfter }} + '&page=' + @{${paging.currentPage + 1}} + '\''"
				th:disabled="${ productList.last }">β–Ά</button>
		
		<!-- 맨 끝으둜 이동 -->
		<button th:onclick="'location.href=\'/product/after?dateAfter=' + @{${ dateAfter }} + '&page=' + @{${paging.endPage}} + '\''">β–Άβ–Ά</button>
	</div>

πŸ‘‰ regist.html

	<h3 align="center">μ‹ κ·œ μƒν’ˆ 등둝</h3>
	
	<form align="center" action="/product/regist" method="post">
		<label>μƒν’ˆλͺ… : </label><input type="text" name="productName"><br>
		<label>μƒν’ˆ 원가 : </label><input type="number" name="productPrice"><br>
		<label>μ œμ‘°μ‚¬ : </label>
		<select name="supplierName">
			<option value="SAMSUNG">μ‚Όμ„±</option>
			<option value="LG">LG</option>
			<option value="APPLE">Apple</option>
			<option value="PHILIPS">Philips</option>
			<option value="DYSON">Dyson</option>
			<option value="DAEWOO">λŒ€μš°</option>
			<option value="HYUNDAI">ν˜„λŒ€</option>
		</select><br>
		<label>판맀 μƒνƒœ : </label>
		<select name="orderableStatus">
			<option value="Y">νŒλ§€κ°€λŠ₯</option>
			<option value="N">νŒλ§€λΆˆκ°€</option>
		</select><br>
		<input type="submit" value="등둝">
	</form>

πŸ‘‰ modify.html

	<h3 align="center">μƒν’ˆ μˆ˜μ •</h3>
	
	<form align="center" action="/product/modify" method="post">
		<label>μˆ˜μ •ν•  μƒν’ˆ 선택 : </label>
		<select name="productNo" id="productNo"></select><br>
		<label>μƒν’ˆλͺ… : </label>
		<input type="text" name="productName"><br>
		<label>μƒν’ˆ 원가 : </label>
		<input type="number" name="productPrice"><br>
		<label>μ œμ‘°μ‚¬ : </label>
		<select name="supplierName">
			<option value="SAMSUNG">μ‚Όμ„±</option>
			<option value="LG">LG</option>
			<option value="APPLE">Apple</option>
			<option value="PHILIPS">Philips</option>
			<option value="DYSON">Dyson</option>
			<option value="DAEWOO">λŒ€μš°</option>
			<option value="HYUNDAI">ν˜„λŒ€</option>
		</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 : '/product/product',
			success : function(data) {
				console.log(data);
				
				let html = '';
				/* dataλΌλŠ” 쑰회된 배열을 λ°˜λ³΅ν•˜μ—¬ ν•©μ‚°μ‹œν‚€κΈ° */
				for(let index in data) {
					html += `<option value='${data[index].productNo}'>[${data[index].productNo}] ${data[index].productName}</option>`;
					// 쑰회된 μƒν’ˆλ²ˆν˜Έμ™€ μƒν’ˆλͺ…을 화면에 λ…ΈμΆœμ‹œν‚€κ³  κ·Έ μƒν’ˆμ΄ 선택(<option>)되면 valueλŠ” ν•΄λ‹Ή μƒν’ˆμ˜ μ½”λ“œ
				}
				/* κ·Έ 값을 <select>에 insertν•˜μ—¬ 화면에 λ…ΈμΆœλ˜λ„λ‘ 함 */
				document.querySelector("#productNo").insertAdjacentHTML('beforeend', html);
				
			},
			error : function(xhr) {
				console.log(xhr);
			}
		});
	})
	</script>

πŸ‘‰ modified.html

	<h1 align="center">🐀 μˆ˜μ •λœ μƒν’ˆ 확인 🐀</h1>

    <table align="center" border="1">
		<tr>
			<th>μƒν’ˆλ²ˆν˜Έ</th>
			<th>μƒν’ˆλͺ…</th>
			<th>μƒν’ˆ νŒλ§€κ°€</th>
			<th>등둝일</th>
			<th>μ œμ‘°μ‚¬</th>
			<th>νŒλ§€μ—¬λΆ€</th>
		</tr>
		<tr>
			<td th:text="${ product.productNo }"></td>
			<td th:text="${ product.productName }"></td>
			<td th:text="${ #numbers.formatInteger(product.productPrice, 3, 'COMMA') } + 원"></td>
			<td th:text="${ product.date }"></td>
			<td th:text="${ product.supplierName }"></td>
			<td th:text="${ product.orderableStatus }"></td>
		</tr>
	</table>


	<script>
	/* μƒν’ˆ μˆ˜μ • ν›„, ν•΄λ‹Ή νŽ˜μ΄μ§€λ‘œ redirect 되기 μ „ alert λ„μš°κΈ° */
	if(window.location.hash === '#success-modify'){
	    alert('[[${message}]]'); // message λ³€μˆ˜λŠ” μ»¨νŠΈλ‘€λŸ¬μ—μ„œ μ „λ‹¬ν•œ Flash Attribute
	}
	</script>

πŸ‘‰ remove.html

	<h3 align="center">μƒν’ˆ μ‚­μ œ</h3>
	
	<form align="center" action="/product/remove" method="post">
		<label>μ‚­μ œν•  μƒν’ˆ 선택 : </label>
		<select name="productNo" id="productNo"></select><br>
		<input type="submit" value="μ‚­μ œ">
	</form>

	<script>
		/* 비동기 톡신(ajax)을 톡해 λͺ¨λ“  μƒν’ˆ 리슀트 쑰회 */
		$(function(){
			$.ajax({
				url : '/product/product',
				success : function(data) {
					console.log(data);
					
					let html = '';
					/* dataλΌλŠ” 쑰회된 배열을 λ°˜λ³΅ν•˜μ—¬ ν•©μ‚°μ‹œν‚€κΈ° */
					for(let index in data) {
						html += `<option value='${data[index].productNo}'>${data[index].productName}</option>`;
						// 쑰회된 μƒν’ˆμ˜ 이름을 화면에 λ…ΈμΆœμ‹œν‚€κ³  κ·Έ μƒν’ˆμ΄ 선택(<option>)되면 valueλŠ” ν•΄λ‹Ή μƒν’ˆμ˜ μ½”λ“œ
					}
					/* κ·Έ 값을 <select>에 insertν•˜μ—¬ 화면에 λ…ΈμΆœλ˜λ„λ‘ 함 */
					document.querySelector("#productNo").insertAdjacentHTML('beforeend', html);
					
				},
				error : function(xhr) {
					console.log(xhr);
				}
			});
		})
	</script>

πŸ‘€ Entity

πŸ‘‰ Product

@Entity(name="product")
@Table(name="TBL_PRODUCT")
@SequenceGenerator(
		name="PRODUCT_SEQUENCE_GENERATOR", 	
		sequenceName="SEQ_PRODUCT_NO", 		
		initialValue=1,						
		allocationSize=1				
		)
public class Product {
	
	@Id
	@Column(name="PRODUCT_NO")
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="PRODUCT_SEQUENCE_GENERATOR")
	private int productNo;
	
	@Column(name="PRODUCT_NAME", nullable=false)
	private String productName;
	
	@Column(name="PRODUCT_PRICE", nullable=false)
	private int productPrice;
	
	@Column(name="RELEASE_DATE", nullable=false)
	private Date date;
	
	/* enum type을 ν™œμš©ν•œ ν•„λ“œ */
	@Column(name="SUPPLIER_NAME", nullable=false)
	@Enumerated(EnumType.STRING) // intκ°€ μ•„λ‹Œ String νƒ€μž…μœΌλ‘œ DB에 μ €μž₯ν•  것
	private SupplierType supplierName;
	
	@Column(name="ORDERABLE_STATUS", nullable=false)
	private String orderableStatus;
    
	/* κΈ°λ³Έ μ…‹νŒ… */    
    
}

πŸ‘‰ SupplierType

public enum SupplierType {

	SAMSUNG, LG, APPLE, PHILIPS, DYSON, DAEWOO, HYUNDAI
}

πŸ‘€ DTO

πŸ‘‰ ProductDTO

public class ProductDTO {
	
	private int productNo;
	private String productName;
	private int productPrice;
	private Date date;
	private SupplierType supplierName;
	private String orderableStatus;
    
    /* κΈ°λ³Έ μ…‹νŒ… */
    
}

πŸ‘€ Controller

πŸ‘‰ MainController

@Controller
public class MainController {

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

πŸ‘‰ ProductController

@Slf4j
@Controller
@RequestMapping("/product")
public class ProductController {

	private final ProductService productService;
	
	public ProductController (ProductService productService) {
		this.productService = productService;
	}
	
	/* 였늘의 μƒν’ˆ */
	@GetMapping("/todays")
	public String todaysPage(Model model) {
		
		List<ProductDTO> productList = productService.findProductList();
		
		Collections.shuffle(productList);
		List<ProductDTO> todaysProductlist = productList.subList(0, 3);
		log.info("todaysProductlist : {}", todaysProductlist);
		
		model.addAttribute("productList", todaysProductlist);
		
		return null;
	}
	
	/* 전체 μƒν’ˆ */
	@GetMapping("/list")
	public String listPage(@PageableDefault Pageable pageable, Model model) {
		
		/* νŽ˜μ΄μ§• 처리 */
		Page<ProductDTO> productList = productService.findProductList(pageable);
		PagingButtonInfo paging = Pagenation.getPagingButtonInfo(productList);
		
		model.addAttribute("paging", paging);
		model.addAttribute("productList", productList);
		
		return "product/list";
	}
	
	/* μƒν’ˆ 검색 */
	@GetMapping("/search")
	public String searchProduct(@PageableDefault Pageable pageable, @RequestParam(name="keyword") String keyword, Model model) {
		
		log.info(keyword);
		
		Page<ProductDTO> productList = productService.searchProductList(pageable, keyword);
		PagingButtonInfo paging = Pagenation.getPagingButtonInfo(productList);
		
		model.addAttribute("keyword", keyword);
		model.addAttribute("paging", paging);
		model.addAttribute("productList", productList);
		
		return "product/search";
	}
	
	/* 등둝일이 μž…λ ₯된 λ‚ μ§œ 이후인 μƒν’ˆ 쑰회 */
	@GetMapping("/after")
	public String searchDateAfterProduct(@PageableDefault Pageable pageable, @RequestParam(name="dateAfter") Date dateAfter, Model model) {
		
		Page<ProductDTO> productList = productService.searchDateAfterProductList(pageable, dateAfter);
		PagingButtonInfo paging = Pagenation.getPagingButtonInfo(productList);

		model.addAttribute("dateAfter", dateAfter);
		model.addAttribute("paging", paging);
		model.addAttribute("productList", productList);
		
		return "product/after";
	}
	
	/* μƒν’ˆ 등둝 */
	@GetMapping("/regist")
	public void registPage() {}
	
	@PostMapping("/regist")
	public String registNewProduct(ProductDTO newProduct, RedirectAttributes rttr) {
		
		productService.saveNewProduct(newProduct);
		
		rttr.addFlashAttribute("message", "μƒν’ˆ 등둝 성곡! λ“±λ‘λœ μƒν’ˆμ„ ν™•μΈν•΄λ³΄μ„Έμš” 🀩");
		
		return "redirect:/product/list#success-regist";
	}
	
	/* μƒν’ˆ μˆ˜μ • */
	@GetMapping("/modify")
	public void modifyPage() {}
	
	/* ν˜„μž¬ μƒν’ˆ 리슀트 쑰회(ajax) */
	@GetMapping(value="product", produces="application/json; charset=UTF-8")
	@ResponseBody
	public List<ProductDTO> findProductList() {
		
		return productService.findProductList();
	}
	
	@PostMapping("/modify")
	public String modifyProduct(ProductDTO product, RedirectAttributes rttr) {
		
		productService.modifyProduct(product);
		
		rttr.addFlashAttribute("message", "μƒν’ˆ μˆ˜μ • 성곡! μˆ˜μ •λœ μƒν’ˆμ„ ν™•μΈν•˜μ„Έμš” 😍");
		
		/* μˆ˜μ •λœ ν•˜λ‚˜μ˜ μƒν’ˆ νŽ˜μ΄μ§€λ‘œ 이동 */
		return "redirect:/product/" + product.getProductNo() + "#success-modify";
		
	}
	
	/* μˆ˜μ •λœ ν•˜λ‚˜μ˜ μƒν’ˆμ„ 쑰회 */
	@GetMapping("/{productNo}")
	public String modifiedPage(@PathVariable int productNo, Model model) {
		
		ProductDTO product = productService.findProductByCode(productNo);
		
		model.addAttribute("product", product);
		
		return "/product/modified";
	}
	
	/* μƒν’ˆ μ‚­μ œ */
	@GetMapping("/remove")
	public void removePage() {}
	
	@PostMapping("/remove")
	public String removeProduct(ProductDTO product, RedirectAttributes rttr) {
		
		productService.deleteProduct(product);
		
		rttr.addFlashAttribute("message", "μƒν’ˆ μ‚­μ œ 성곡! πŸ‘€");
		
		return "redirect:/product/list#success-remove";
	}
	
}

πŸ‘€ Service

πŸ‘‰ ProductService

@Slf4j
@Service
public class ProductService {

	private final ProductRepository productRepository;
	private final ModelMapper modelMapper;
	
	public ProductService(ProductRepository productRepository, ModelMapper modelMapper) {
		this.productRepository = productRepository;
		this.modelMapper = modelMapper;
	}
	
	/* 전체 μƒν’ˆ */
	public List<ProductDTO> findProductList() {
		
		List<Product> productList = productRepository.findAll(Sort.by("productNo"));
		
		return productList.stream().map(menu -> modelMapper.map(menu, ProductDTO.class)).collect(Collectors.toList());
	}
	
	/* 전체 μƒν’ˆ (Paging ver) */
	public Page<ProductDTO> findProductList(Pageable pageable) {
		
		pageable = PageRequest.of(pageable.getPageNumber() <= 0 ? 0 : pageable.getPageNumber() -1, 
				   pageable.getPageSize(),										
				   Sort.by("productNo").descending());
		
		Page<Product> productList = productRepository.findAll(pageable);
		
		return productList.map(product -> modelMapper.map(product, ProductDTO.class));
	}
	
	
	/* μƒν’ˆ 검색 */
	public Page<ProductDTO> searchProductList(Pageable pageable, String keyword) {
		
		pageable = PageRequest.of(pageable.getPageNumber() <= 0 ? 0 : pageable.getPageNumber() -1, 
				   pageable.getPageSize(),										
				   Sort.by("productNo").descending());
		
		Page<Product> productList = productRepository.findProductByContaining(pageable, keyword);
		log.info("productList : {}", productList);
		
		return productList.map(menu -> modelMapper.map(menu, ProductDTO.class));
	}
	
	/* 등둝일이 μž…λ ₯된 λ‚ μ§œ 이후인 μƒν’ˆ 쑰회 */
	public Page<ProductDTO> searchDateAfterProductList(Pageable pageable, Date dateAfter) {
		
		pageable = PageRequest.of(pageable.getPageNumber() <= 0 ? 0 : pageable.getPageNumber() -1, 
				   pageable.getPageSize(),										
				   Sort.by("date").descending());
		
		Page<Product> productList = productRepository.findByDateAfter(dateAfter, pageable);
		log.info("productList : {}", productList);
		
		return productList.map(menu -> modelMapper.map(menu, ProductDTO.class));
	}
	
	
	/* μƒν’ˆ 등둝 */
	@Transactional
	public void saveNewProduct(ProductDTO newProduct) {
		
		/* 등둝일 가곡 */
		newProduct.setDate(new java.sql.Date(System.currentTimeMillis()));
		
		/* μƒν’ˆμ›κ°€ 가곡 (μƒν’ˆ 수수료 & λΆ€κ°€μ„Έ) */
		int charge = (int) (newProduct.getProductPrice() * 0.1);
		int tax = (int) (newProduct.getProductPrice() * 0.05);
		newProduct.setProductPrice(newProduct.getProductPrice() + charge + tax);
		
		productRepository.save(modelMapper.map(newProduct, Product.class));
		
	}

	/* μƒν’ˆ μˆ˜μ • */
	@Transactional
	public void modifyProduct(ProductDTO product) {
		
		Product foundProduct = productRepository.findById(product.getProductNo()).orElseThrow(IllegalArgumentException::new);
		
		/* μƒν’ˆμ›κ°€ 가곡 (μƒν’ˆ 수수료 & λΆ€κ°€μ„Έ) */
		int charge = (int) (product.getProductPrice() * 0.1);
		int tax = (int) (product.getProductPrice() * 0.05);
		
		foundProduct.setProductName(product.getProductName());
		foundProduct.setProductPrice(product.getProductPrice() + charge + tax);
		foundProduct.setSupplierName(product.getSupplierName());
		foundProduct.setOrderableStatus(product.getOrderableStatus());
		
	}
	
	/* μˆ˜μ •λœ ν•˜λ‚˜μ˜ μƒν’ˆμ„ 쑰회 */
	public ProductDTO findProductByCode(int productNo) {
		
		Product product = productRepository.findById(productNo).orElseThrow(IllegalArgumentException::new);
		
		return modelMapper.map(product, ProductDTO.class);
	}

	/* μƒν’ˆ μ‚­μ œ */
	@Transactional
	public void deleteProduct(ProductDTO product) {
		
		productRepository.deleteById(product.getProductNo());
		
	}

}

πŸ‘€ Repository

πŸ‘‰ ProductRepository

public interface ProductRepository extends JpaRepository<Product, Integer> {

	/* 전달 받은 ν‚€μ›Œλ“œκ°€ ν¬ν•¨λœ μƒν’ˆμ„ μ‘°νšŒν•˜λŠ” λ©”μ†Œλ“œ */
	@Query("SELECT p FROM product p WHERE p.productName LIKE %:keyword%")
    public Page<Product> findProductByContaining(Pageable pageable, String keyword);

	/* 전달 받은 λ‚ μ§œ μ΄ν›„μ˜ μƒν’ˆμ„ μ‘°νšŒν•˜λŠ” λ©”μ†Œλ“œ */
	Page<Product> findByDateAfter(Date dateAfter, Pageable pageable);

}
profile
Tiny little habits make me

0개의 λŒ“κΈ€