
๐ ๊ธฐ๋ณธ ์
ํ
๐ applicaiton.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
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.1.1</version>
</dependency>
๐ BeanConfiguration
@Configuration
public class BeanConfiguration {
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
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;
int defaultButtonCount = 10;
int startPage;
int endPage;
startPage = (int) (Math.ceil((double) currentPage / defaultButtonCount) - 1) * defaultButtonCount + 1;
endPage = startPage + defaultButtonCount - 1;
if(page.getTotalPages() < endPage)
endPage = page.getTotalPages();
if(page.getTotalPages() == 0 && endPage == 0)
endPage = startPage;
return new PagingButtonInfo(currentPage, startPage, endPage);
}
}
๐ Templates (views)
๐ main.html
<h1 align="center">๐ญ๐ค WELCOME TO 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/querymethod'">์ฟผ๋ฆฌ๋ฉ์๋ ํ
์คํธ</button>
<button onclick="location.href='/menu/regist'">๋ฉ๋ด ๋ฑ๋กํ๊ธฐ</button>
<button onclick="location.href='/menu/modify'">๋ฉ๋ด ์์ ํ๊ธฐ</button>
<button onclick="location.href='/menu/delete'">๋ฉ๋ด ์ญ์ ํ๊ธฐ</button>
</div>
๐ 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>
if(window.location.hash === '#menu-modify'){
alert('[[${message}]]');
}
</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>
<div align="center" id="paging" >
<button th:onclick="'location.href=\'/menu/list?page=' + @{${paging.startPage}} + '\''">โโ</button>
<button th:onclick="'location.href=\'/menu/list?page=' + @{${paging.currentPage - 1}} + '\''"
th:disabled="${ menuList.first }">โ</button>
<th:block th:each="page : ${ #numbers.sequence(paging.startPage, paging.endPage)}">
<button th:onclick="'location.href=\'/menu/list?page=' + @{${page}} + '\''"
th:text="${ page }"
th:disabled="${ paging.currentPage eq page }">
</button>
</th:block>
<button th:onclick="'location.href=\'/menu/list?page=' + @{${paging.currentPage + 1}} + '\''"
th:disabled="${ menuList.last }">โถ</button>
<button th:onclick="'location.href=\'/menu/list?page=' + @{${paging.endPage}} + '\''">โถโถ</button>
</div>
<script>
if(window.location.hash === '#menu-regist' || window.location.hash === '#menu-remove'){
alert('[[${message}]]');
}
</script>
๐ list2.html
<h1 align="center">โจ <span th:text="${ #numbers.formatInteger(menuPrice, 3, 'COMMA') }"></span>์ ์ด๊ณผ์ธ ๋ฉ๋ด๋ค โจ</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>
๐ querymethod.html
<h3>์
๋ ฅ ๊ฐ๊ฒฉ์ ์ด๊ณผํ๋ ๋ฉ๋ด์ ๋ชฉ๋ก ์กฐํ</h3>
<form action="/menu/test1">
<input type="number" name="menuPrice">์ ์ด๊ณผ์ ๋ฉ๋ด ๋ชฉ๋ก ์กฐํ<br>
<input type="submit" value="์กฐํ">
</form>
๐ 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">
</select><br>
<label>ํ๋งค ์ํ : </label>
<select name="orderableStatus">
<option value="Y">ํ๋งค๊ฐ๋ฅ</option>
<option value="N">ํ๋งค๋ถ๊ฐ</option>
</select><br>
<input type="submit" value="์ ์ก">
</form>
<script>
$(function(){
$.ajax({
url : '/menu/category',
success : function(data) {
console.log(data);
let html = '';
for(let index in data) {
html += `<option value='${data[index].categoryCode}'>${data[index].categoryName}</option>`;
}
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>
$(function(){
$.ajax({
url : '/menu/category',
success : function(data) {
console.log(data);
let html = '';
for(let index in data) {
html += `<option value='${data[index].categoryCode}'>${data[index].categoryName}</option>`;
}
document.querySelector("#categoryCode").insertAdjacentHTML('beforeend', html);
},
error : function(xhr) {
console.log(xhr);
}
});
})
$(function(){
$.ajax({
url : '/menu/menu',
success : function(data) {
console.log(data);
let html = '';
for(let index in data) {
html += `<option value='${data[index].menuCode}'>[${data[index].menuCode}] ${data[index].menuName}</option>`;
}
document.querySelector("#menuCode").insertAdjacentHTML('beforeend', html);
},
error : function(xhr) {
console.log(xhr);
}
});
})
</script>
๐ delete.html
<h3 align="center">๋ฉ๋ด ์ญ์ </h3>
<form action="/menu/delete" method="post">
<label>์ญ์ ํ ๋ฉ๋ด์ ๋ฒํธ : </label>
<input type="number" name="menuCode"><br>
<input type="submit" value="์ ์ก">
</form>
๐ 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;
}
@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;
}
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";
}
}
@Controller
@RequestMapping("/menu")
@Slf4j
public class MenuController {
private final MenuService menuService;
public MenuController(MenuService menuService) {
this.menuService = menuService;
}
@GetMapping("/{menuCode}")
public String findMenuByCode(@PathVariable int menuCode, Model model) {
MenuDTO menu = menuService.findMenuByCode(menuCode);
model.addAttribute("menu", menu);
return "menu/one";
}
@GetMapping("list")
public String findMenuList(@PageableDefault Pageable pageable, Model model) {
log.info("pageable : {}", pageable);
Page<MenuDTO> menuList = menuService.findMenuList(pageable);
log.info("์กฐํํ ๋ด์ฉ ๋ชฉ๋ก : {}", menuList.getContent());
log.info("์ด ํ์ด์ง ์ : {}", menuList.getTotalPages());
log.info("์ด ๋ฉ๋ด ์ : {}", menuList.getTotalElements());
log.info("ํด๋น ํ์ด์ง์ ํ์ ๋ ์์ ์ : {}", menuList.getSize());
log.info("ํด๋น ํ์ด์ง์ ์ค์ ์์ ์ : {}", menuList.getNumberOfElements());
log.info("์ฒซ ํ์ด์ง ์ฌ๋ถ : {}", menuList.isFirst());
log.info("๋ง์ง๋ง ํ์ด์ง ์ฌ๋ถ : {}", menuList.isLast());
log.info("์ ๋ ฌ ๋ฐฉ์ : {}", menuList.getSort());
log.info("์ฌ๋ฌ ํ์ด์ง ์ค ํ์ฌ ์ธ๋ฑ์ค : {}", menuList.getNumber());
PagingButtonInfo paging = Pagenation.getPagingButtonInfo(menuList);
model.addAttribute("paging", paging);
model.addAttribute("menuList", menuList);
return "menu/list";
}
@GetMapping("/querymethod")
public void queryMethodPage() {}
@GetMapping("/test1")
public String menuTest1(@RequestParam Integer menuPrice, Model model) {
List<MenuDTO> menuList = menuService.menuTest1(menuPrice);
model.addAttribute("menuList", menuList);
model.addAttribute("menuPrice", menuPrice);
return "menu/list2";
}
@GetMapping("/regist")
public void registPage() {}
@GetMapping(value="category", produces="application/json; charset=UTF-8")
@ResponseBody
public List<CategoryDTO> findCategoryList() {
return menuService.findAllCategory();
}
@PostMapping("/regist")
public String registNewMenu(MenuDTO newMenu, RedirectAttributes rttr) {
menuService.registNewMenu(newMenu);
rttr.addFlashAttribute("message", "๋ฉ๋ด ๋ฑ๋ก ์ฑ๊ณต! ๋ฑ๋ก๋ ๋ฉ๋ด๋ฅผ ํ์ธํ์ธ์ ๐ฅณ");
return "redirect:/menu/list#menu-regist";
}
@GetMapping("/modify")
public void modifyPage() {}
@GetMapping(value="menu", produces="application/json; charset=UTF-8")
@ResponseBody
public List<MenuDTO> findMenuList() {
return menuService.findMenuList();
}
@PostMapping("/modify")
public String menuModify(@ModelAttribute MenuDTO menu, RedirectAttributes rttr) {
menuService.modifyMenu(menu);
rttr.addFlashAttribute("message", "๋ฉ๋ด ์์ ์ฑ๊ณต! ์์ ๋ ๋ฉ๋ด๋ฅผ ํ์ธํ์ธ์ ๐");
return "redirect:/menu/" + menu.getMenuCode() + "#menu-modify";
}
@GetMapping("/delete")
public void deletePage() {}
@PostMapping("/delete")
public String deleteMenu(@RequestParam Integer menuCode, RedirectAttributes rttr) {
menuService.deleteMenu(menuCode);
rttr.addFlashAttribute("message", "๋ฉ๋ด ์ญ์ ์ฑ๊ณต! ๐");
return "redirect:/menu/list#menu-remove";
}
}
๐ Service
@Service
public class MenuService {
private final CategoryRepository categoryRepository;
private final MenuRepository menuRepository;
private final ModelMapper modelMapper;
public MenuService(CategoryRepository categoryRepository, MenuRepository menuRepository, ModelMapper modelMapper) {
this.categoryRepository = categoryRepository;
this.menuRepository = menuRepository;
this.modelMapper = modelMapper;
}
public MenuDTO findMenuByCode(int menuCode) {
Menu menu = menuRepository.findById(menuCode).orElseThrow(IllegalArgumentException::new);
return modelMapper.map(menu, MenuDTO.class);
}
public List<MenuDTO> findMenuList() {
List<Menu> menuList = menuRepository.findAll(Sort.by("menuCode").descending());
return menuList.stream().map(menu -> modelMapper.map(menu, MenuDTO.class)).collect(Collectors.toList());
}
public Page<MenuDTO> findMenuList(Pageable pageable) {
pageable = PageRequest.of(pageable.getPageNumber() <= 0 ? 0 : pageable.getPageNumber() -1,
pageable.getPageSize(),
Sort.by("menuCode").descending());
Page<Menu> menuList = menuRepository.findAll(pageable);
return menuList.map(menu -> modelMapper.map(menu, MenuDTO.class));
}
public List<MenuDTO> menuTest1(Integer menuPrice) {
List<Menu> menuList = menuRepository.findByMenuPriceGreaterThan(menuPrice, Sort.by("menuPrice"));
return menuList.stream().map(menu -> modelMapper.map(menu, MenuDTO.class)).collect(Collectors.toList());
}
public List<CategoryDTO> findAllCategory() {
List<Category> categoryList = categoryRepository.findAllCategory();
return categoryList.stream().map(category -> modelMapper.map(category, CategoryDTO.class)).collect(Collectors.toList());
}
@Transactional
public void registNewMenu(MenuDTO newMenu) {
menuRepository.save(modelMapper.map(newMenu, Menu.class));
}
@Transactional
public void modifyMenu(MenuDTO menu) {
Menu foundMenu = menuRepository.findById(menu.getMenuCode()).orElseThrow(IllegalArgumentException::new);
foundMenu.setMenuName(menu.getMenuName());
foundMenu.setMenuPrice(menu.getMenuPrice());
foundMenu.setCategoryCode(menu.getCategoryCode());
foundMenu.setOrderableStatus(menu.getOrderableStatus());
}
@Transactional
public void deleteMenu(Integer menuCode) {
menuRepository.deleteById(menuCode);
}
}
๐ Repository
public interface CategoryRepository extends JpaRepository<Category, Integer> {
@Query(value="SELECT CATEGORY_CODE, CATEGORY_NAME, REF_CATEGORY_CODE FROM TBL_CATEGORY ORDER BY CATEGORY_CODE ASC"
, nativeQuery=true)
public List<Category> findAllCategory();
}
๐ CategoryRepository
public interface MenuRepository extends JpaRepository<Menu, Integer> {
List<Menu> findByMenuPriceGreaterThan(Integer menuPrice);
List<Menu> findByMenuPriceGreaterThanOrderByMenuPrice(Integer menuPrice);
List<Menu> findByMenuPriceGreaterThan(Integer menuPrice, Sort sort);
}