클라우드공부 방향성에 대해 조언을 얻으러

클라우드과정을 듣기 전에 나는 클라우드 전문가 분을 만났다.

그래도 이쪽 분야에 대해서 어느 정도 알고 가야 공부에 대한 방향이 잡힐 것 같아서였다.

퍼블릭 클라우드, AWS를 공부를 하라고 권유를 해주셨고, 더불어 AWS자격증도 취득하는 것을 권유해주셨다.

일단 나는 기초적인 공부가 덜되어 있고, 국비과정을 통해서 엄청나게 공부한 후에 그 뒤에 고려를 해보기로 했다.

또한, 공부를 하려고 했지만, 학원에서 배우는 내용만으로도 벅찼기 때문에 다른 것을 공부할 여유가 되지 않았다.

 

네트워크 관련 서적 구매

그리고 나는 인프라를 공부한다면 기본적으로 전부 공부하는 후니책을 샀다.

 

책이 엄청 두꺼웠고, 과정 공부를 하면서 책을 들여다 보기란 쉽지 않았다.

어떻게 할까 고민하다가 학원에 가기전 집에서 딱 5분-10분 씩, 1-2페이지를 보고 가기로 결정했다.

그리고 공부하다 보니 학원과정에서 배우는 네트워크 과정하고 겹치게 되었고, 과정에서 배우는 네트워크는 내가 보는 내용보다 앞질러 갔다. 그래도 꾸준히 아침에 5분-10분씩 복습한다는 생각으로 조금씩 봤었다.

 

클라우드 서적 구매

그리고 과정시작전에 클라우드에서 공부를 해야겠다고 생각을 했고, 디테일하게 공부하기 어려우니

쉽고 개념을 익힐 수 있는 클라우드 서적을 사야겠다고 마음을 먹고 교보문고에 가서 골랐다.

학원에가서 담임교수님이 빠르게 개념을 훓는데 이 책이 좋다고 하셨다.. 역시나 나도 책을 보는 눈이 있는건가 ㅠㅠ

 

공부를 했지만 사실 이 단어의 의미가 이런의미이구나 하고 지나가는 정도 였다.

아키텍처나 등등 봐도 각인이 잘되지 않았다.

그리고 과정이 시작되고 내가 공부한 내용은 1주일을 가지 못했다..

가상머신 세팅

설정

Memory 4GB

processors 2

hard disk (SCSI) -20GB

hard disk (SCSI) -30GB

Network Adapter Bridged (Automatic)

Network Adapter 2 NAT

Standard Partition-LVM으로 설정이 아닌 standard partition으로 설정

 

싱글노드로 오픈스택을 구축할 예정

 

1. vi /etc/default/grub 편집

-vi /etc/default/ tab 해서 grub 타입 완성

-grub cmdline linux에서 quiet 뒤에 net.ifnames=0 biosdevname=0 이 추가

 

작업하는이유

인터페이스 카드 이름과 바이오스(하드웨어의 정보를 읽어서 부팅하는역할)에서 알려주는 이름을 사용하지 않겠다!!!

- 이렇게 커널의 기본값을 변경해줘야 커널이 업데이트 되었을때 값이 변경되지 않습니.

 

2. grub 파일 재생성

명령어

-> grub2-mkconfig o /boot/grub2/grub.cfg (위에 설정한대로 대로 생성해주는 역할 : 재생성 이유)

-> reboot 또는 shutdown r now (reboot 하고 systemctl resetart network를 해주기-수정할 경우)

 

3. 인터페이스 카드 이름 변경하러 가기

cd /etc/sysconfig/network:-scripts

mv - v ifcfg-ens33 ifcfg-eth0

mv - v ifcfg-ens34 ifcfg-eht1

 

(2.3.4.번 결과사진)

 

4. vi /etc/sysconfig/network-scripts/ifcfg-eth0 (외부) 그리고 eth1(내부)

설정 eth0

static

IPADDR =192.168.0.102

GATEWAY=192.168.0.1

NETMASK=255.255.255.0

DNS1 =8.8.8.8

#마주한 장애.

swp 파일이 있어 지워라는 내용이었음

지우려고 하다가, 실패했는데, 다시 vi /etc/sysconfig/network-scripts/ifcfg-eht1 로 하니 다시 들어가진다.

파일을 앞에서 이미 작업하다가 제대로 삭제를 안하거나 내용없이 종료를 하지 않으면 나오는 문제이다.

 

설정 eth1

static

yes

IPADDR =10.0.0.30

GATEWAY=10.0.0.2

NETMASK=255.255.255.0

DNS1 =8.8.8.8

 

->yum y update (새로 바뀐 내용 업데이트)

->reboot 실행

 

5. ping 테스트를 해주어 통신이 되는지 확인해줄 것

-네트워크 상에서 호스트간 통신을 확인하는 명령어

-ICMP프로토콜 프로그램,네트워크 연결을 점검하는 도구

 

*trace-route

-패킷이 라우터 까지 도달아는 구간의 정보를 기록

-ICMP를 이용하여 TTL값을 포함하고 있는 패킷을 전송하여 반환값을 출력

-IP주소나 URL로서 목적지를 입력,게이트웨이,컴퓨터이름,주소,걸리는시간을 표시

 

설치명령어

yum -y install traceroute

 

실행명령어

traceroute 10.0.0.2

 

*netstat

-라우팅과 관련된 정보를 얻기 위한 명령어. 라우팅 테이블을 화면에 표시.

 

설치명령어

#yum -y install net-tools

 

실행명령어

netstat

 

#yum –y update 가 안되고 gateway 및 8.8.8.8 ping이 안되길래 확인했던 방법

eth1 ping 가는데 eth0 외부 gateway 8.8.8.8 이 안되길래

bridge 설정을 밖에서 안해주어서 생긴 문제이었다.

 

 

메모리

슬롯

- 메인보드에 있는 메모리 삽입구, 메모리는 메인보드에 꽂는다.

 

채널

- 메모리를 구성할 수 있는 구역

 

랭크

- dram에서 데이터를 입출력하는 단위 (싱글랭크:1R 등등

 

DRAM 칩의 조합으로 구성

-싱글 랭크 메모리의 1개 메모리 : 64bit(ECC8bit 추가 72bit)DRAM 칩이 탑재

-듀얼랭크 사양 2

 

메모리 표기 방법

4GB(4GB메모리) 2Rx89(더블랭크 8bit 칩 사용) PC3L(DDR3 저전압)-10600(최대데이터전송속도가 약 10.67GB/)R(REGISTERED)-09

 

메모리 성능 확인방법

'DDR3 PC3-12800 4GB'라는 램이 있다면, 이는 4GB 용량의 DDR3 규격 램 중에서도 약 12,800MB/s의 최대 데이터 전송속도를 낼 수 있는 제품이다. 동작 속도는 해당 전송속도에서 8을 나누는 것으로 계산한다.

그러니까 DDR3 PC3-12800의 동작 속도는 1,600MHz가 된다.

 

디스크

디스크(가정용은 주로 SATA, SSD)

SATA 하드디스크(serial ata)

-SAS 보다 가격이 저렴

 

SAS 하드디스크(Serial Attached scsi)

-스타형 토폴로지

-고속으로 동작하고 신뢰성 좋은 24시간 365일 가동할 용도로 사용

 

FC(Fibre Channel) 하드디스크

-루프형/패브릭형 토폴로지

-하드디스크는 초고속으로 동작하고 신뢰성이 높다.

(SAN 스토리지등 엔터프라이즈 용도로 사용)

 

SSD(반도체 소자 메모리를 기억장치에 이용한 디스크)

-Solid State Drive

 

셀종류

-SLC single level cell : 1bit 데이터 기록

-MLC multi level cell :2bit 데이터 기록

 

비휘발성 메모리(NAND 플래시 메모리 Flash Memory)

-엔터프라이즈 용도, 초고속 저장 장치

 

서버요건을 결정하는 요소의 예

-CPU, 메모리, 디스크, RAID, NIC, PSU, 보증기간, 지원수준, 확장성, 물리적인 사이즈, 무게

비트와 메모리의 관계

32비트 232=4,294........ 으로 나온다.

->그래서 32비트는 최대 4기가 메모리까지 인식할 수 있다.

 

64비트 264=18,446 .......으로 나온다.

->6418기가 메모리까지 설치 및 인식이 가능하다.

 

단위개념

옥텟(octet) : 한데 묶여 쓰이는 2진 이진부호모음. 바이트가 8비트를 가리킬 때 서로 같은 뜻을 갖는다.

                 전기통신 분야에서는 바이트란 용어 대신 옥텟이란 표현을 사용한다. 팔중수라고도 부른다.

니블(nibble) : 1바이트의 절반으로 보통 4비트를 가리킨다. 이때 바이트 하나는 상위 니블(상위 4비트)과 하위 니블(하위

                  4비트)로 나눌 수 있다.

비트(bit) : 비트는 전산학과 정보 이론의 정보 단위

워드(word) : 전자통신 기기에 따라 2바이트 또는 4바이트를 묶어서 부르는 단위

킬로바이트(kbyte) : 1024 바이트는 1 킬로 바이트

바이트(byte) : 컴퓨터의 기억장치의 크기를 나타내는 단위로 자주 쓰인다.

 

CPU

-중앙연산능력장치

-연산을 대량으로 빠르게 처리하는 장치(두뇌)

-과거에는 동작 주파수를 올려서 연산능력을 높였지만,

최근에는 동작 주파수를 억제하고 멀티코어나 멀티스레드와 같은 방식을 이용해서

하나의 CPU로 동시에 처리할 수 있는 연산 개수를 늘려서 연산 능력 향상시킴

 

소켓수

-CPU 개수

 

코어수

-CPU의 주요 계산 부분, 복수의 코어가 있는 것을 멀티코어라고 함

 

스레드 수

-하나의 코어에서 처리할 수 있는 수(하이퍼스레딩 기능이 있으면 코어 수가 배가 된다)

 

동작 주파수

-1초당 클럭수. 동작 주파수가 높을수록 처리속도가 빨라지지만, 전력 효율이 나빠지고 발열도 증가

 

캐시

-cpu와 메인 메모리 사이에 캐시 메모리가 있음

-캐시 메모리는 빠른 속도의 메모리 임

-캐시 메모리에 자주 액세스하는 데이터를 저장해서 상대적으로 느린 메인 메모리로의 액 세스를 줄여 CPU의 처리 성능

 을 높임

 

하이퍼스레딩

-하나의 코어로 두 개의 처리를 실행할 수 있는 기술(인텔CPU에서 사용하는 용어)

 

터보부스트 기술

-CPU의 속도를 자동으로 기준 클럭보다 빠르게 동작시키는 기능

-전혀 일을 하지 않는 코어가 있을 때, 일을 하고 있는 코어를 클럭 업시키는 기술(인텔CPU용어)

 

CPU 스펙 보는법

인텔          코어i5-7세대(i5-7200U)     카비레이크       2.5GHz             듀얼코어

(제조사)       (CPU시리즈)                  CPU코드명       CPU속도            코어개수

주문목록검색 취소

1. OrderController 클래스에서

 

@GetMapping 작성

@PostMapping작성

사진

 

2. OrderList.html 파일 작성

 

 

3. 특정이름으로 검색이

마주한 에러 및 문제해결

-OrderRepositoryJPA Criteria 구문 작성

-OrderService 클래스에 findAllCriteria로 변경

 

실습

화면출력

정리

1.orderList.html파일

-검색조건 양식(form)이 있어야 한다.

 

회원명 구문

주문상태 구문

검색 구문

->검색 버튼을 누르면

 

위에 구문에서 작성하고 선택한 옵션값들을 보낸 값들이

OrderController 클래스에 OrderSearchmemberNameOrderStatus에 바인딩이 된다.

다시 OrderController에 와서 바인딩 된 상태로 return에 지정한 order/orderList로 넘어가게 된다.

 

enum typeorder,cancel을 둘다 값을 OrderStatus 루프를 통해 뿌리고 select를 해야 한다.

타임리프의 문법을 사용해서 값을 뿌릴 수 있다.

, enum에 잇는 values를 가져와서 값을 뿌리게 된다.

 

 

<tr th:each="item : ${orders}"> 구문 설명

<td th:text="${item.id}"></td>

<td th:text="${item.member.name}"></td>

<td th:text="${item.orderItems[0].item.name}"></td>

<td th:text="${item.orderItems[0].orderPrice}"></td>

<td th:text="${item.orderItems[0].count}"></td>

<td th:text="${item.status}"></td>

<td th:text="${item.orderDate}"></td>

<td>

 

-orders를 주문으로 돌려서 나오게 한다.

 

 

<a th:if="${item.status.name() == 'ORDER'}" 구문설명

href="#" th:href="'javascript:cancel('+${item.id}+')'"

class="btn btn-danger">CANCEL</a>

 

-상태가 order이면 cancel버튼이 나오도록 자바 스크립트로 작성을 했다.

cancel을 누를 시에 자바스크립트 캔슬이 호출되어 하기구문으로 넘어간다.

 

<script>

function cancel(id) {

var form = document.createElement("form");

form.setAttribute("method", "post");

form.setAttribute("action", "/orders/" + id + "/cancel");

document.body.appendChild(form);

form.submit();

}

</script>

 

- 구문에서 form 내에 해당하는 내용들을 위해 구문작성을 만들어야 한다.

 

-@PostMapping 방식으로 cancelOrder을 받아와서

redirect으로 화면에 cancel상태의 화면을 출력한다.

 

 

cancel버튼클릭시 화면 및 cancel상태의 목록검색

 

특정이름없이 전체목록출력

상품주문

1. OrderController 클래스 생성 및 세팅

 

사진

 

화면출력

 

*번외로 알아본것들

ordercontroller에서 memberid를 직접찾아서 보내면 되지 않을까에 대한 고민들

=>controller 로직도 지저분해진다.

 

커맨드성

외부에서 식별자만 넘기고

서비스에서 엔티티를 찾는 것부터 거기서 하면

엔티티의 값들도 엔티티를 조회해야 영속상태로 진행을 한다.

 

가급적이면 핵심비즈니스 로직이 있는 경우엔

밖에서 엔티티를 찾아서 넣는 것 보다 식별자만 넘겨주고

핵심비즈니스 로직을 안에서 찾게 되면 영속성 컨텍스트가 존재하는 상태에서 조회가 가능하다.

주문하면서 멤버가 바뀌게 되더라도 더티체킹이 되어 자연스럽게 적용이 된다.

밖에서 가지고 오게 되면 트랜잭션 없이 이루어지는 것이라 더티체킹이 되지 않는다.

 

마주한문제

상품주문버튼 클릭시 에러

코드수정

 

에러가 발생하지 않는다.

상품수정

 

등록이나 조회는 쉬운편이지만, 수정은 복잡하다.

jpa에서 어떠한 방법으로 수정하는 것이 좋을 것인지(정석적인지)에 대해

고민해서 선택해야 한다. 방법중엔 변경감지, 병합이라는 방법이 있다고 한다.

 

jpa의 가이드는 변경감지를 best practice라고 권한다.

 

사진(item controller 수정구문)

 

updateItemForm.html 파일

-createItemForm 파일과의 차이점은 기존에 있는 데이터를 보유하고 있다의 정도이다.

 

*form-control : formcontrol로 명시할 경우 form이 제대로 설정이 되지 않는다.

 

사진

 

사진(수정버튼)

사진(수정화면)

 

*itemId 취약점

-브라우저창에서 상품수정시에 format이 넘어올 때에 인위적으로 아이디를 조작해서 넘길 수 있다.

 서비스계층이든 뒷단이든 유저가 item에 대해 권한이 있는지 체크하는 로직이 있어야 한다.

 

 

2. 변경감지와 병합

JPA에서 변경감지를 모르면 시간을 많이 낭비할 수 있다.

 

JPA기본 메커니즘

a. JPA값 변경시 예제

 

@RunWith(SpringRunner.class)

@SpringBootTest

public class ItemUpdateTest {

 

@Autowired

EntityManager em;

 

@Test

public void updateTest() throws Exception{

Book book = em.find(Book.class, primarykey:1L); //1번 데이터베이스에 있다고 가정한다.

 

//트랜잭션(TX)

book.setName("asdfasdf");

->트랜잭션안에서 이름을 변경하고 트랜잭션 커밋할때에 JPA가 자동으로 변경된구문을 찾아서

업데이트 쿼리를 자동 생성해서 데이터베이스에 생성한다.

이것을 변경감지 == dirty checking이라고 한다.

이 매커니즘을 기본으로 jpa 의 엔티티를 바꿀 수 있다.

 

이것과 비슷한 예제가 했었던 실습구문에 있다.

setStatus의 상태만 바꾸고 jpa가 트랜잭션 커밋시점에 바뀐 것을 찾아서 업데이트 쿼리를 이용해 디비에 전달하여 커밋을 완료한다. 엔티티매니저 merge와 같은 행위를 따로 해주지 않아도 된다.

 

정리

-엔티티가 영속성상태로 관리 되면 값만 바꾸면 변경된 JPA가 트랜잭션 커밋시점에 변경된값을 알고,

 디비에 반영시킨다.

 

문제는 준영속 엔티티를 이해해야 한다.

-jpa 영속성 컨텍스트가 더 이상 관리하지 않는 엔티티를 말한다.

 

새로운 객체는 새로운 객체이지만 아이디는 세팅이 된 상태이다.

JPA에 작업을 한번 거친 식별자(itemId)가 있는 것은 준영속 엔티티라고 한다.

데이터베이스에 들어갔다 나온 데이터라 JPA가 식별할 수 있는 아이디를 가지고 있다.

여기에서 준영속 엔티티는 book이다.

포트폴리에서는 내가 직접 만든 new Book이고, JPA가 관리하지 않는 준영속 엔티티이다.

jpa 영속성 컨텍스트가 관리하는 엔티티는 변경된 것을 알지만 준영속 엔티티는 그렇지 않다.

아무리 준영속엔티티에 정보를 변경해도 변경이 되지 않는다.

 

어떻게 하면 준영속 엔티티를 수정할 수 있을까에 대해 알아보기로 한다.

 

준영속 엔티티를 수정하는 2가지 방법

-변경감지기능사용(dirty checking)

-병합(merge)사용

 

변경감지 기능 사용

@Transactional

void update(Item itemParam) { //itemParam: 파라미터로 넘어온 준영속 상태엔티티이다.

 

Item findItem = em.find(Item.class, itemParam.getId()); 다시 동일한 엔티티를 조회한다.

 

findItem.setPrice(itemParam.getPrice()); //데이터를 수정한다.

}

 

== 비슷한 예제

@Transactional

public void updateItem(Long itemId, Book param) {

 

private final ItemRepository itemRepository;

 

@Transactional

public void saveItem(Item item) {

itemRepository.save(item);

}

 

@Transactional

public void updateItem(Long itemId, Book param) {

//파라미터로 넘어온 준영속 상태엔티티이다.

 

Item findItem = itemRepository.findOne(itemId);

//다시 동일한 엔티티를 조회한다.

 

findItem.setPrice(param.getPrice());

findItem.setName(param.getName());

findItem.setStockQuantity(param.getStockQuantity());

//데이터를 수정한다.

}

 

 

설명

-@Transactional 안에서 파라미터로 넘어온 준영속 상태엔티티를 부른다.

-다시 동일한 엔티티를 조회한다.(findItem)

-넘어온 준영속상태의 엔티티의 값을 다시 재세팅(변경/수정)을 한다.

-트랜잭션이 커밋할 시에, flush를 보내어, 변경된 값을 찾아( 변경감지 : dirty checking)내어 감지한다.

-데이터베이스 update sql 실행하여 변경된 값이 전달 된다.(데이터를 조회 한다.)

 

->이것이 더 나은 수정방법이다.

 

 

2. 병합방법

-포트폴리오에 사용한 방법은 병합방법이다.

-준영속 상태 엔티티를 영속 상태로 변경해주고자 할 때 사용하는 기능 방법이다.

 

예제1)

@Transactional

vodi update(Item itemParam) { //itemParam : 파라미터로 넘어온 준영속 상태의 엔티티

Item mergeItem = em.merge(item);

}

 

병합 : 기존에 있는 엔티티

병합 동작 방식 정리

1. 준속 엔티티의 식별자 값으로 속 엔티티를 조회한다.

2. 속 엔티티의 값을 준속 엔티티의 값으로 모두 교체한다.(병합한다.)

3. 트랜잭션 커밋 시점에 변경 감지 기능이 동작해서 데이터베이스에 UPDATE SQL이 실행

 

주의

-변경 감지 기능을 사용하면 원하는 속성만 선택해서 변경할 수 있지만,

 병합을 사용하면 모든 속성이 변경된다. 병합시 값이 없으면 null로 업데이트 할 위험도 있다.

 (병합은 모든 필드를 교체한다.) -> 그래서 실무에서 병합기능은 위험하다.

 

예를들어

 

Book book = new Book();

book.setId(form.getId());

book.setName(form.getName());

book.setPrice(form.getPrice()); -> 이부분을 빠뜨리면 pricenull로 업데이트가 된다. book.setStockQuantity(form.getStockQuantity());

book.setAuthor(form.getAuthor());

book.setIsbn(form.getIsbn());

 

itemService.saveItem(book);

return "redirect:/items";

}

 

*자세한 원리는 매뉴얼에 보면 있다.

 

유지보수성 측면에서

@Transactional

public void updateItem(Long itemId, Book param) {

//파라미터로 넘어온 준영속 상태엔티티이다.

 

Item findItem = itemRepository.findOne(itemId);

//다시 동일한 엔티티를 조회한다.

//findItem.change(name, price, stockQuantity);

->이렇게 해주어야 change만 확인하면 어디가 변경된지 쉽게 추적할 수있다.

 

findItem.setPrice(param.getPrice());

findItem.setName(param.getName());

findItem.setStockQuantity(param.getStockQuantity());

//데이터를 수정한다.

}

 

가장 좋은 해결 방법

엔티티를 변경할 때는 항상 변경 감지를 사용할 것.

컨트롤러에서 어설프게 엔티티를 생성하지 마세요.

트랜잭션이 있는 서비스 계층에 식별자(id)와 변경할 데이터를 명확하게 전달할것.

상품목록

1. itemController 클래스에서 추가 작성

 

ItemController에서 권장사항

public String create(BookForm form) { ~구문에서

create book을 해서 파라미터를 넘기는 것이 좋은 설계이다.

set을 간소화할 수 있다.

static 생성자 메서드를 가지고 의도에 맞게 사용하는 것이 좋다.

 

사진

2.itemList.html 생성 및 작성

 

사진

 

에러해결과정

1.return의 경로가 “items/itemsList“로 되어 있었다.

items/itemList로 변경하니 상품목록이 나온다.

 

에러화면

수정

출력화면

상품등록

 

1.BookForm 클래스 생성

 

 

2.ItemController 클래스 생성

 

ItemController에서 권장사항 3

public String create(BookForm form) { ~구문에서

static 생성자 메서드를 가지고 의도에 맞게 사용하는 것이 좋다. set을 간소화할 수 있다.

create book을 해서 파라미터를 넘기는 것이 좋은 설계이다.

 

private final MemberService memberService

Controller가 서비스(MemberService)를 사용한다.

 

*Model model이란?

model.addAttribute(“정보”)

-> controller로 뷰로 넘어갈 때 데이터를 실어서 정보를 넘긴다.

return "items/createItemForm“ ->여기로 화면이 출력이 된다.

createItemForm을 위한 html을 만들어야 한다.

controller가 화면을 이동할 때 빈 BookForm을 가지고 간다,.

validation같은 역할을 해주기 때문에 빈 BookForm을 가지고 가도록 한다.

데이터가 넘어가니 데이터의 화면출력을 위한 createItemForm.html 생성이 필요하다.

 

*필드값도 추적이 가능하다.

model.addAttribute(“정보”) 가 데이터를 실어서 정보를 넘길 때

controller가 화면을 이동할 때 빈 BookForm을 넘겨주므로,

name, price 등의 필드값도 추적이 가능하다.

 

사진

 

 

3. createItemForm.html 생성

 

실습

 

마주한문제

에러화면사진

 

에러문제해결절차

1. ItemController에서 받아오는 modelattribute이름 확인

2. return 되는 경로 확인

3. createItemForm.html 코드확인

 

4. Book클래스 및 연관된 클래스들 한번씩 체크..

 

5. 경로재확인

-fragments 하위에 items디렉터리가 있어

members와 동일하게 items 디렉터리 위치 templates 하위에 디렉터리위치를 변경

상품등록화면 출력확인

 

데이터 입력확인

*싱글테이블 전략으로 인해 Artist 등 전부 null으로 된 것을 확인할 수 있다.

 

 

 

회원목록조회

 

1.MemberController클래스에서 멤버조회하도록 MemberList.html구문작성

 

사진

 

사진, *변수를 합쳐 단축시켜주는 refactor inline 기능 (ctrl + alt + n)

*타임리프의 장점

-html 태그를 그대로 가져다 사용한다.

-MemberController클래스에서 작성한 List<member>구문에 있는 model에서 members를 담아서 사용한 것을 그대로 

 memberList.html파일로 가져와서 binding이 된다. 그래서 그대로 출력하는 구문만 작성하면 된다.

 

타임리프에서 address?

-null이면 그대로 진행 안한다는 의미

 

마주한 문제(회원목록화면 출력이 안된다.)

에러메세지 발생

-에러메시지만 보았을 때는 이해가 안된다..

가설1

MemberControll클래스에서 return "user/userList"으로 해주어서 출력이 안되었을 것이다.

 

결과- 그대로

 

가설 2

회원이름 입력을 하지 않았을 때에 submit을 누르면

필수항목입니다 메시지가 나오는지 재확인 및 재작동됨을 확인했다.

 

이름을 우리나라말로 바꾸어 보았다. submit이 되고 처음화면으로 redirect가 된다.

처음엔 hello1 로 했었는데. 영어 또는 숫자 입력이 안되게 구문을 작성한 것으로 짐작했지만

h2.database에 들어가니 정보가 입력이 되어 있다.

 

가설 3

회원목록이 나오지 않는다는 것은 못받아 온다는 뜻이라고 가설을 세웠다.

GetMapping(“ members/”)에서 /members로 바꾸어 보았다...

 

결과-동일한 에러

 

가설 4

회원목록이 나오지 return 으로 memberList가 받아 오지 못한다고 가설을 세웠다.

확인해보니 return("members/memberList")로 괄호안에 설정 되어 있었다.

return "member/memberList"; 로 수정완료

 

그래도 에러가 나온다.

 

가설5

다시 회원목록조회 구문을 잠시 주석처리하니,

회원가입시 작성하였던 데이터가 Member 테이블에 잘 나오고 에러도 없다.

 

회원가입 항목을 작성하니 에러가 나오고

member_id를 처음 데이터 작성한 첫행으로 인식을 하여

현재 보유한 데이터가 7개이면 회원가입작성 및 submit후에 에러가 나오고 8번을 새로고침해야 작성한 내용이 데이터베이스에 들어가있음을 확인함.

 

현재 application.yml에서 ddl-auto(초기화옵션)은 create이고,

create는 엔티티자체를 전부 없애고 다시 새로 만들어주는 역할이니 그러한 현상이 발생하는 것으로 짐작하여 update로 변경해주었다.

 

결과-회원가입작성은 잘된다.

 

가설6

-회원목록을 클릭하면 회원가입작성페이지가 나온다.

-home.html 파일에 들어가서 확인을 했다.

<p class="lead">회원 기능</p>

<p>

<a class="btn btn-lg btn-secondary" href="/members/new">회원가입</a>

<a class="btn btn-lg btn-secondary" href="/members/new">회원목록</a>

</p>

로 회원가입과 동일하게 하이퍼텍스트 리퍼런스가 동일하게 되어 있다.

-<a class="btn btn-lg btn-secondary" href="/members">회원목록</a> 으로 수정

 

회원목록출력성공 완료

 

사진

 

권장사항

엔티티를 폼으로 사용하면 화면 종속적 기능이 되어버려서

엔티티가 지저분해지게 된다. 유지보수가 하기 어려워진다.

핵심 로직을 수정하니 화면이 나오지 않는다라는 상황이 발생한다.

엔티티는 순수하게 유지하라는 얘기가 있음.

 

jpa 사용할 때 조심해야 하는 것은 순수하게 간결하게 엔티티를 작성해야 한다.

핵심 비즈니스로직에만 디펜던시가 있도록 작성해야 한다.

그래야 어플리케이션을 만들어도 더 커지지 않는다. 유지보수하기가 좋아진다.

 

엔티티 대신 폼객체나 DTO(Data Transfer Object)권장을 한다.

회원등록할때에는 MemberForm객체를 사용했는데 데이터를 memberList로 보낼 때에는 Member로 보낸다.

 

권장사항2

api를 만들 때에는 엔티티를 절대 외부로 반환하면 안된다. api는 스펙이기 때문이다.

 

예를 들어 패스워드가 그대로 노출(private String userpassword;)될 수도 있고,

엔티티의 로직을 변경했는데 api스펙이 변하게 된다. 그래서 api를 만들 때에는 엔티티를 절대 외부로 반환하면 안된다.

 

사진

+ Recent posts