※ Keep in mind
본 내용은 웹개발과정의 강의 중 내용을 복습을 위해서 메모한 것에 불과한 것입니다. 이러한 연유로 강의내용을 오인한 나머지 오기재 및 불기재가 있을 수 있으니 '참고'만 해주시길 바랍니다. 저의 경우에도 본 내용을 단순하 읽은 것이 결코 저의 것이라고 생각하지 않습니다. 본 내용은 복습를 위한 초기 내지 중간 과정에 불과한 것이고, 이후에 내용을 보충 후 인출 및 설명하기 과정이 있어야 비로소 복습의 단추가 어느정도 마무리 되어간다고 볼 수 있습니다.
따라서 당초에 본 내용은 비공개였습니다. 그럼에도 불구하고 본 내용을 공개한 점은 함께 공부하는 동료들과 나눔을 바탕으로 배움과 성장의 공진화라는 소기의 목적을 달성에 어느정도 도움이 될수 있기 때문이라고 생각합니다.
I. 들어가며
1. 지난시간과 오늘의 목표
1) 지난시간
타임리프로 처음으로 데이터가져왔는데 이를 활용할수있어야해
2) 오늘의 목표
id=3 으로 해서 가능해
최근 들어 나오는 사이트들을 보면 /(슬러시)해서 데이터를 넘버링 하는 경우가 있어 이거를 보아야하고
메뉴의 내용을 심을 때에도 문제가 돼! 심으면서 목록 할때 어떻게 데이터를 가져와야할지 생각해야해
II. 타임리프
1. 사이트와 더 연동시켜보기
(1) descriptrion 데이터넣어주기
1)
메뉴 테이블에다가 description이라는 컬럼을 만들자 (각 음료마다 설명을 넣어주어야하기 때문이다)
그런데 이 경우 뷰는 이전 것 기준이기 때문에 drop해서 지우고 다시 만들자
그러면 디스크립션이 들어갔어!
// 엔티티란 DB에서 담을녀석이다 .
public class Menu {
private long id;
private String name;
private Integer price;
private String img;
//새로 추가한 부분
private String description;
(2) 링크사용하기
1)
때로는 @이 붙여서 리소스있는 위치부터 찾아라고 가능하고,
?가 없으니 소괄호 안에서 데이터를 심어야해!
데이터 심을 때는 반드시 중괄호나 골뱅이를 꼭 활용해야해!
불편해보이더라도 이렇게 해야해
전에도 말했던거 처럼 이전 href는 손댈필요없이 추가적으로 만들면 되는 것이고, 절대경로를 쓸 필요가없어
<section class="menu">
<form class="">
<h1><span th:text="${menu.name}">알랜드 커피</span><span style="font-size: 8px">(커피음료)</span></h1>
<div class="menu-img-box">
<a href="detail"
th:href="@{detail(id=${menu.id})}">
<img class="menu-img" src="/image/product/12.png">
</a>
</div>
<div class="menu-price">4500 원</div>
<div class="menu-option-list">
<span class="menu-option">
<input class="menu-option-input" type="checkbox">
<label>ICED</label>
</span>
<span class="menu-option ml-2">
<input class="menu-option-input" type="checkbox">
<label>Large</label>
</span>
</div>
<div class="menu-button-list">
<input class="btn btn-fill btn-size-1 btn-size-1-lg" type="submit" value="담기">
<input class="btn btn-line btn-size-1 btn-size-1-lg ml-1" type="submit" value="주문하기">
</div>
</form>
</section>
<a href="detail" th:href="@{detail(id=${menu.id})}">
실제로 하면 이렇게 해서 href를 변경안하고 가능해!
(2) controller 부류 세팅하기
controller로 가자
controller에서 id값을 얻어야하는데 어떻게 얻을까?
http://localhost:8080/menu/detail?id=713
위 주소에 맞춰어서 인수를 만들어주자!
@RequestMapping("detail") //주소와 같게 해주면
public String detail(int id, Model model) {
Menu menu = service.getById(id);
model.addAttribute("menu", menu);
return "menu/detail";
}
컨트롤러에 맞추어준다
package kr.co.rland.web.service;
import java.util.List;
import kr.co.rland.web.entity.Menu;
import kr.co.rland.web.entity.MenuView;
public interface MenuService {
List<Menu> getList();
List<Menu> getList(int page);
List<Menu> getList(int page, String query);
List<Menu> getList(int page, int categoryId);
List<Menu> getList(int page, int categoryId, String query);
// 서비스는 업무적인 단위로 이름을 지어주어야해
// 그래서 update보다는 다른거하자
void pointUp();
List<MenuView> getViewList();
List<MenuView> getViewList(int page);
List<MenuView> getViewList(int page, String query);
List<MenuView> getViewList(int page, int categoryId);
List<MenuView> getViewList(int page, int categoryId, String query);
Menu getById(long id);
}
interface를 해주고나서
package kr.co.rland.web.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import kr.co.rland.web.entity.Menu;
import kr.co.rland.web.entity.MenuView;
import kr.co.rland.web.repository.MenuRepository;
@Service
public class DefaultMenuService implements MenuService {
@Autowired
private MenuRepository repository;
public void setRepository(MenuRepository repository) {
this.repository = repository;
}
// @Transactional(propagation = )
@Override
public void pointUp() {
}
@Override
public List<Menu> getList() {
// return repository.findAll(0,10,"",1,3000,"regDate","desc");
return repository.findAll(0,10,"",null,null,null,null);
}
@Override
public List<MenuView> getViewList() {
// TODO Auto-generated method stub
return repository.findviewAll(0,10,"",null,null,null,null);
}
@Override
public Menu getById(long id) {
// TODO Auto-generated method stub
Menu menu = repository.findById(id);
return menu;
}
}
repository 에 있는 findById 메소드에다가 id 매개변수 값을 넣어주고
그 결과값을 return 해주는것으로 구현한다.
3)
@SpringBootTest
class DefaultMenuServiceTest {
@Autowired
private MenuService service;
@Test
void test() {
// service.pointUp();
// List<MenuView> list = service.getViewList(1,1);
// System.out.println(list);
Menu menu =service.getById(617L);
System.out.println(menu);
System.out.println("작업완료");
}
}
이렇게 해서 unit 테스트가 충분하게 가능해!
이렇게 service에서 데이터를 가지고오는 것이 성공적으로 되었다.
이제 controller에서 view로 데이터를 보내주는 것을 하면된다!
(3) detatil.htm 세팅하기
1)
detail.html을 해보자
그런데 '원' 은 어떻게 유지할까? "" 안에 ''이 감싼 문자열이야!
<article>
<header>
<h1 class="text-title2" th:text="${menu.name}">딸기청</h1>
<!-- 원의 경우 어떻게 해야할까? -->
<span class="text-normal" th:text="${menu.price}">4,500원</span>
</header>
<p class="text-normal" th:text=${menu.description}>신선한 과일로 만들고 알랜드만의 비법으로 직접 만들어서
다른 곳에서는 느낄 수 없는 상큼함과 새콤함을 자랑합니다.
</p>
</article>
여기에다가 + 를 하면 간단하게 가능해
<header>
<h1 class="text-title2" th:text="${menu.name}">딸기청</h1>
<!-- 원의 경우 어떻게 해야할까? -->
<span class="text-normal" th:text="${menu.price} + ' 원' ">4,500원</span>
</header>
2)
포맷팅관련해서는 유틸리티가 있어
공식문서를 보면 숫자를 구분해서 포인트를 넣는방법에 차이가있어
<header>
<h1 class="text-title2" th:text="${menu.name}">딸기청</h1>
<!-- 원의 경우 어떻게 해야할까? -->
<span class="text-normal" th:text="${#numbers.formatInteger(menu.price, 3,'COMMA')} + ' 원' ">4,500원</span>
</header>
여기 POINT는 점(.)이야, COMMA로 하면 우리가 원하는 쉼표(,) 를 볼 수있어!
${#numbers.formatInteger( )} 괄호 안에다가 인수에 ${}을 쓸 필요없이 그대로 넣어주면돼!
3)
이번에는 이미지를 넣어보자! 넣어줄 이미지를 정리해서 static에 넣어주자
4)
골뱅이(@) 사용되는경우와 틸드(~)가 사용되는경우가 있어
변수 사용할 때는 달라
위에서 보이는것 처럼
- fragment 는 ~(틸드)
- url가져오는 등 static한거는 @
src는 @ 를 이용해서 static한 것 들고와!
상수를 쓰는데, 변수를 포함한다는 것은
header>
<h1 class="d-none">수제청</h1>
<div class="img-div">
<img alt="" th:src="'/image/menu/'+${menu.img}" src="https://images.unsplash.com/photo-1515442261605-65987783cb6a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80">
</div>
</header>
이렇게 하면 정상적으로 나와
골뱅이를 붙여서 하는방법이 있어
이게 생소할수도있는데
덧셈을 안하고 골뱅이 하는게 더 쉬울수도있어!
아래와 같이 중간부분을 쉽게 바꿀수 있기 때문이야
<a th:href="@{/menus/{id}/edit(id=${menu.id})}">test</a>
5) 정리
이미지 와 가격
<!-- 이미지 가격 바꾸자! -->
<h1><span th:text="${menu.name}">알랜드 커피</span><span style="font-size: 8px">(커피음료)</span></h1>
<div class="menu-img-box">
<a href="detail" th:href="@{detail(id=${menu.id})}"><img class="menu-img" th:src="@{/image/menu/{img}(img=${menu.img})}" src="/image/product/12.png"></a>
</div>
<div class="menu-price" th:text="${#numbers.formatInteger(menu.price,3,'COMMA')}+' 원'">4500 원</div>
앞서 한것 처럼 @ 이용해서 이미지를 연결해주고
가격도 number formating 을 이용해서 해준다.
(3) detail.html 나머지 정리
1)
menu 에 보면 category 따라서 무엇이 들어갈지 결정하는것이야
<ul>
<li class="menu-selected">
<a href="/menu/list">전체</a>
</li>
<li>
<a href="?c=1">커피음료</a>
</li>
<li>
<a href="?c=2">수제청</a>
</li>
<li>
<a href="?c=3">샌드위치</a>
</li>
<li>
<a href="?c=4">쿠키</a>
</li>
</ul>
이렇게 할래? 반복문을할래?
3)
데이터를가지고 만드는게 나아!
그 이전에 카테고리 틀이 있어야해 entity를 만들자
그런데,,, 매번 다 알면서 getter, setter 하는게 피곤해 library를쓰자
lombok을 다운받자
model 부분에 생성자 직접 추가를 이전에는 해야했는데 어노테이션이면 알아서 다 돼!
package kr.co.rland.web.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Builder
public class Category {
private int id;
private String name;
}
새로운속성 추가변경에 많은 불편함이있는데 얘가 알아서 다 만들어줘
lombok library면 유용해!
그런데 어노테이션 다 하기 번거로우면 단한줄 @data 면돼!
package kr.co.rland.web.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
//@Getter
//@Setter
//@NoArgsConstructor
//@AllArgsConstructor
//@ToString
@Data
@Builder
public class Category {
private int id;
private String name;
}
이걸로 한줄로 가능해! 이거를 이용하면 멤버만 생각하면돼서 유용해!
우리는 mybatis로 데이터 query를해야하는데 서비스는 곧잇다가 하자
일단 repository 부터!
4)
package kr.co.rland.web.repository;
import java.util.List;
//ibatis가 원래 이름이야!
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import kr.co.rland.web.entity.Category;
import kr.co.rland.web.entity.Menu;
import kr.co.rland.web.entity.MenuView;
//이것을 구현한 구현체를 알아서 repo에 보내주는거야!
@Mapper
public interface CategoryRepository {
List<Category> findAll();
Category findById(long id);
int insert(Category category);
int update(Category category);
void delete(long id);
}
Category 전용 interface를 마련해주자
이렇게 해주면 각각의 메소드는 mapper에서 자동으로 연결이 돼어서 이용이 가능하다!
interface에 대한 구현체인 mapper를 추가해주고, 설정해주자!
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.co.rland.web.repository.CategoryRepository">
<!-- 아까는 한줄에 구현해야했는데, 이제 내려쓰기도 해도 되고부담이 없어! 주석도 돼! -->
<!-- resultType 대신에 resultMap을 이용해-->
<select id="findAll" resultType ="Category">
<!-- resultType이 무엇이냐 modle을 넣어주자 -->
select *
From category
</select>
<select id="findById" resultType ="Category">
<!-- resultType이 무엇이냐 modle을 넣어주자 -->
select *
From category
where id=#{id}
</select>
<insert id="insert" parameterType="Category">
insert into category(name)
value(#{name})
</insert>
<update id="update" parameterType="Category">
update category
<trim prefix="SET" suffixOverrides=",">
<if test="name != null">name=#{name},</if>
<if test="price != null">price=#{price},</if>
<if test="img != null">img=#{img}</if>
</trim>
where id=#{id}
</update>
<!-- 이렇게 이제 쿼리문 만드는게 repo 구현이야! -->
<delete id="delete">
delete from category where id =${id}
</delete>
</mapper>
MenuRepositoryMapper에서 몇가지를 제외하고
resultType과 parameterType을 바꿔주자
그리고 대상 테이블명도 category로 바꿔주자
그리고 findById도 만들어주자
다만 우리는 출력은 모든 카테고리를 해야한다
그렇기 때문에 findById는 필요가없다 (그냥 개인적으로 만듬)
5)
이제 테스트를 해보자!!
package kr.co.rland.web.repository;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import kr.co.rland.web.entity.Category;
import kr.co.rland.web.entity.Menu;
@AutoConfigureTestDatabase(replace = Replace.NONE)
@MybatisTest
class CategoryRepositoryTest {
@Autowired
private CategoryRepository repository;
@Test
void testFindAll() {
List<Category> list = repository.findAll();
System.out.println("작업완료");
System.out.println(list);
}
}
이렇게 하면 카테고리 목록들이 모두 나오게된다.
이러한 결과들을 볼 수있다. (다만 현재 lombok 문제로 올바르게 출력된 것은 아니다)
getter seter 가 올바르게 된경우 다음과 같이 출력이 된다.
1. 보충
2. 회고
1) 오늘 문제를 해결하는 과정에서 태그가 문제일 때 마다 나오는게 500에러였다. 사실 크로스체킹을 해본 결과 header라던지 쓸대없이 중복되는 태그가 문제였다. 500이문제면 html을 잘 살펴보자
'배움 __IL > TIL 1기' 카테고리의 다른 글
TIL : 74번째- 230322 [3-3-수] (0) | 2023.03.22 |
---|---|
TIL : 73번째- 230321 [3-3-화] (0) | 2023.03.21 |
TIL : 71번째- 230317 [3-2-금] (0) | 2023.03.17 |
TIL : 70번째- 230316 [3-2-목] (0) | 2023.03.16 |
TIL : 69번째- 230315 [3-2-수] (0) | 2023.03.15 |