1. 옆에 메뉴바에 탄력적IP를 찾을수 있다.

2. 할당을 클릭하면 성공적으로 할당을 받은것을 확인할 수 있다.

3.  탄력적 IP가 성공적으로 할당된것을 확인할 수 있다.

4. 주소연결을 눌러준다. 그러면 이러한 페이지를 볼 수 있다. 인스턴스와 프라이빗IP를 설정해주면 된다.

5. 탄력적 IP 와 인스턴스를 성공적으로 연결한것을 확인할 수 있다.

'SpringBoot' 카테고리의 다른 글

파일 서버에 복사하여 올리기  (0) 2019.07.25
Instance에 접속하기, JDK설치  (1) 2019.07.25
AWS & AWS EC2 Instance생성  (0) 2019.07.25
.jar 파일 만들기 및 실행  (0) 2019.07.23
Homebrew 설치 및 gradle설치  (0) 2019.07.23

Amazon Webservice는 아마존닷컴이 제공하는 각종 원격 컴퓨팅 서비스 즉, 클라우드를 의미한다. 대부분의 서비스는 최종 사용자에게 직접적으로 공개되는것이 아니고 다른 개발자가 사용 가능한 기능을 제공하는 플랫폼을 제공하는 Paas(Plaform As a Service)이다. 아마존 웹 서비스의 각종 서비스는 REST 프로토콜 및 SOAP 프로토콜을 통해 접근, 이용 및 관리가 가능하다. 서비스를 이용하는데 과금이 부여되는 방식이다.

 

Amazon EC2

 

Amazon Elastic Compute Cloud(Amazon EC2)  AWS 클라우드에서 확장식 컴퓨팅을 제공을 한다. 

Amazon EC2 사용하면 하드위어에 투자할 필요가 없어 더빠르게 애플리케이션 개발 배포가 가능하다.

또한 Amazon EC2 요구사항이나 갑작스로운 인기 증대 변동 사항에 따라 신속하게 규모를 확장하거나 축소할 있어 서버 트래픽 예측 필요성이 줄어든다. 

(위의 말을 쉽게 정리하자면 독립된 컴퓨터를 임대해주는 서비스 라고 이야기 할 수 있다.)

 

Amazon EC2 여러 기능이 존재한다.

  • 인스턴스: 가상 컴퓨팅 환경
  • Amazon 머신 이미지(AMI): 서버에 필요한 운영체제와 여러 소프트웨어들이 적절히 구성된 상태로 제공되는 템플릿으로 인스턴스를 쉽게 만들 있습니다.
  • 인스턴스 유형: 인스턴스를 위한 CPU, 메모리, 스토리지, 네트워킹 용량의 여러 가지 구성 제공
  • 페어를 사용하여 인스턴스 로그인 정보 보호(AWS 퍼블릭 키를 저장하고 사용자는 개인 키를 안전한 장소에 보관하는 방식)
  • 인스턴스 스토어 볼륨: 임시 데이터를 저장하는 스토리지 볼륨으로 인스턴스 종료 삭제됨
  • Amazon Elastic Block Store(Amazon EBS),  Amazon EBS 볼륨을 사용해 영구 스토리지 볼륨에 데이터 저장
  • 인스턴스와 Amazon EBS 볼륨 등의 리소스를 다른 물리적 장소에서 액세스할 있는 리전  가용 영역
  • 보안 그룹을 사용해 인스턴스에 연결할 있는 프로토콜, 포트, 소스 IP 범위를 지정하는 방화벽 기능
  • 탄력적 IP 주소(EIP): 동적 클라우드 컴퓨팅을 위한 고정 IPv4 주소
  • 태그: 사용자가 생성하여 Amazon EC2 리소스에 할당할 있는 메타데이터
  • AWS 클라우드에서는 논리적으로 격리되어 있지만, 원할 마다 고객의 네트워크와 간편히 연결할 있는 가상 네트워크Virtual Private Clouds(VPC)

https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/concepts.html

 

Amazon EC2란 무엇입니까? - Amazon Elastic Compute Cloud

Amazon EC2란 무엇입니까? Amazon Elastic Compute Cloud(Amazon EC2)는 Amazon Web Services(AWS) 클라우드에서 확장식 컴퓨팅을 제공합니다. Amazon EC2를 사용하면 하드웨어에 선투자할 필요가 없어 더 빠르게 애플리케이션을 개발하고 배포할 수 있습니다. Amazon EC2를 통해 원하는 만큼 가상 서버를 구축하고 보안 및 네트워크 구성과 스토리지 관리가 가능합니다. 또한 Amazon EC2는 요구

docs.aws.amazon.com

인스턴스

Amazon 머심 이미지(AMI)는 필요한 소프트웨어가 이미 구성되어 있는 템플릿이다. 

AMI에서 인스턴스를 바로 시작할 수 있는데 이 인스턴스는 AMI의 사본으로 클라우드에서 실행되는 가상 서버이다.

 

인스턴스 생성하기

 

1. AWS 회원가입하고 로그인하기 (회원가입시 카드 정보 입력하라고 하니 준비해야함!, 지원옆에 Region을 서울로 해야함)

 

2. 로그인후 아래의 그림과 같이 서비스 찾기에서 EC2를 검색한다.

 

3. 인스턴스를 생성한다. (인스턴스 시작을 클릭한다.)

 

4. 그림에서 보이는 항목중 Ubuntu server를 선택하여 준다.

 

5. 설정값을 바꾸지 말고 다음:인스턴스 세부 정보 구성을 눌러준다.

 

6. 이부분도 설정값 변경없이 다음으로 넘어가준다.

7. 스토리지 추가 부분도 크기값을 변경할 필요가 없다.

8. 키와 값을 설정해 준다.

9. 보안그룹 구성에서 유형을 3가지를 추가해주고 SSH는 내 IP를 설정해야한다. 

10. 시작을 클릭한다.

11. pem키를 다운 받은뒤 인스턴스 시작을 누그면 된다. 초기에는 무조건 키를 받아야한다.

11. 정상적으로 완료가 되면 이러한 페이지를 볼 수 있다.

12. 인스턴스 보기에서 정상적으로 Running되고 있는것을 확인할 수 있다.

'SpringBoot' 카테고리의 다른 글

Instance에 접속하기, JDK설치  (1) 2019.07.25
탄력적 IP 설정하기  (0) 2019.07.25
.jar 파일 만들기 및 실행  (0) 2019.07.23
Homebrew 설치 및 gradle설치  (0) 2019.07.23
사용중인 포트 찾아서 Kill하기  (0) 2019.07.23

(이전의 Homebrew 설치해서 Gradle을 설치해야만 한다!!)

1. 정의 

JAR(Java archive)는 여러개의 자바 클래스 파일과, 클래스들이 이용하는 관련 리소스 및 메타데이터를 하나의 파일로 모아서 자바 플랫폼에 응용 소프트웨어나 라이브러리를 배포하기 위한 소프트웨어 패키지 파일 포맷이다. 실제로 ZIP 파일 포맷으로 이루어진 압출파일로서, 파일 확장자는 .jar이다.

 

2. 파일만들기

Intellij 하단 부분을 보면 이러한것을 발견할 수가 있다. 여기에서 터미널을 클릭을 한다.

이후 gradle assemble 명령어를 치면 다음과 같은 메세지 화면을 볼 수 가 있다.

.jar 파일이 잘 만들어 졌는지 확인!! Spotlight에서 .jar라고 검색하면 바로 나온다.

music-0.0.1-SNAPSHOT.jar이 만들어 진것을 볼 수있다. 여기서 궁금한것은 과연 저 0.0.1이 뜻하는것이 무엇인가?

 

0.0.1 의 index를 각각 1 ,2 3이라고 명칭하자

index 1은 메이저 변경사항이 생길때 버전이 올라간다 예를 들어 어떠한 website를 구축하였을때 모든것이 바뀌었다면 index 1의 값이 올라간다.

index 2은 기능업데이트이다 예를 들어 어떠한 홈페이지에서 기능을 추가될 때 버전을 올린다.

index 3은 버그수정 및 자잘한 업데이트를 행할 때 버전이 올라간다.

 

이렇게 .jar파일을 만든후 우리는 .jar파일을 실행시킬 수 있다. 

Terminal에서 .jar파일이 있는 곳으로 이동하여 java -jar ".jar파일 이름"을 적어주면 다음과 같이 실행이 된다.

이 다음으로는 AWS EC2를 사용하여 만들었던 .jar파일을 복사하여 그곳에서 실행을 시킬것이다.

'SpringBoot' 카테고리의 다른 글

탄력적 IP 설정하기  (0) 2019.07.25
AWS & AWS EC2 Instance생성  (0) 2019.07.25
Homebrew 설치 및 gradle설치  (0) 2019.07.23
사용중인 포트 찾아서 Kill하기  (0) 2019.07.23
Spring으로 만드는 간단한 게시판(2)  (0) 2019.07.22

1. Homebrew는 무엇인가?

Homebrew는 macOS용 패키지 관리자이다. Terminal에서 명령어를 작성하여 자신이 필요한 프로그램을 설치, 삭제, 업데이트를 쉽게 관리할 수 있다.

 

2. Homebrew는 왜 사용한는가?

원하지 않는 프로그램이 설치 될 수도 있고 프로그램을 재설치, 삭제, 업데이트를 할때 기존에 데이터가 남아있는 경우가 많은데 Homebrew를 사용할 경우 이러한 문제를 손쉽게 해결할 수있다. 

 

3. Homebrew설치 방법

https://brew.sh/index_ko

 

Homebrew

The missing package manager for macOS (or Linux).

brew.sh

Homebrew사이트에 접속을 한 다음 아래 사진에서 터미널에 붙여넣기 하세요 부분을 복사한다음 터미널에 입력을 해준다.

붙여넣기를 하였으면 터미널에 이러한것이 나타난다.

Homebrew의 설치가 끝났으면 Gradle을 설치하여 준다.

 

Gradle이 잘 설치되었는지 확인한다.

잘 설치가 되었음을 알 수 있다.

Spring을 이용한 개발을 하면서 프로젝트를 running상태에서 종료시키지 않고 Intellij를 종료하면 해당 포트는 계속 할당이 되어있는 상태로 남아있다. 이때 특정 포트를 사용중인 프로세스를 점검하고 kill명령어로 종료를 시켜야 한다.

1
2
3
 
sudo lsof -i :"포트 번호"
sudo kill -9 "프로세스 번호" 

lsof -i :포트번호를 하였을때 나오는 결과값

위와 같은 명령어를 입력한다면 해당 포트번호에 현재 사용중인 프로세스가 등장한다.

만약 이 프로세스를 제거하고 싶다면 sudo kill -9 82937(PID)를 입력한다면 해당 포트의 프로세스는 삭제된다.

'SpringBoot' 카테고리의 다른 글

.jar 파일 만들기 및 실행  (0) 2019.07.23
Homebrew 설치 및 gradle설치  (0) 2019.07.23
Spring으로 만드는 간단한 게시판(2)  (0) 2019.07.22
Spring으로 만드는 간단한 게시판(1)  (0) 2019.07.22
Get & Post  (0) 2019.07.08

앞서 작성한 Spring으로 만드는 간단한 게시판 만들기(1) (로그인)을 만들고 실제로 게시판을 구현할것이다.

게시판의 세부 기능은 C(Create),R(Read),U(Update),D(Delete)로 나눌수 있다.

기능을 구현하기에 앞서 일전에 언급했었던 것을 생성해야한다.

Board

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
import javax.persistence.*;
 
@Entity
@Table(name = "board")
public class Board {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
 
    private Long id;
    private String content;
    private String title;
    private String writer;
    private Date date;
 
    public Long getId() {
        return id;
    }
 
    public String getContent() {
        return content;
    }
 
    public String getTitle() {
        return title;
    }
 
    public String getWriter() {
        return writer;
    }
 
    public Date getDate() {
        return date;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public void setWriter(String writer) {
        this.writer = writer;
    }
 
    public void setContent(String content) {
        this.content = content;
    }
 
    public void setDate(Date date) {
        this.date = date;
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

BoardRepository

1
2
3
4
5
6
7
8
9
 
import org.springframework.stereotype.Repository;
 
@Repository
public interface BoardRepository extends JpaRepository<Board,Long> {
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

BoardController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
 
 
import org.springframework.stereotype.Controller;
 
 
@Controller
public class BoardController {
 
    private final BoardListService listService;
    private final BoardWriteService boardWriteService;
    private final BoardInfoService boardInfoService;
    private final BoardDeleteService boardDeleteService;
    private final BoardUpdateService boardUpdateService;
 
    public BoardController(BoardListService listService, BoardWriteService boardWriteService,BoardInfoService boardInfoService,BoardDeleteService boardDeleteService,BoardUpdateService boardUpdateService)
    {
        this.listService=listService;
        this.boardWriteService=boardWriteService;
        this.boardInfoService=boardInfoService;
        this.boardDeleteService=boardDeleteService;
        this.boardUpdateService=boardUpdateService;
    }
 
    @GetMapping(value="/board")
    public String listShow(@RequestParam(value="pageNum",defaultValue = "1")int pageNum){
        listService.boardList(pageNum);
        return "board";
    }
    @PostMapping(value = "/boardWriteRequest")
    public String writeRequest(@RequestParam Map<String,String> paraMap)
    {
        String title=paraMap.get("title");
        String content = paraMap.get("content");
        String writer = paraMap.get("writer");
 
        return "redirect:/board"//board로 바로가서 출력값 보여준다
    }
    @GetMapping(value="/Info")
    public String getInfo(@RequestParam(value = "freeId")long freeId)
    {
        boardInfoService.InfoService(freeId);
        return "boardInfo";
    }
    @GetMapping(value="/boardDelete")
    public String getDelete(@RequestParam(value = "freeId"long freeId)
    {
        boardDeleteService.deleteService(freeId);
        return "redirect:/board";
    }
    @GetMapping(value="/boardUpdate")
    public String getUpdate(@RequestParam(value="freeId"long freeId)
    {
        boardInfoService.InfoService(freeId);
        return "boardUpdate";
    }
    @PostMapping(value="/update")
    public String update(@RequestParam Map<String,String> paraMap)
    {
        String id=paraMap.get("freeId");
        String title=paraMap.get("title");
        String content = paraMap.get("content");
 
 
        return "boardInfo";
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

PageMaker --> 게시판의 페이지 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
 
public class PageMaker {
    private int totalCount;// 전체 게시물 개수
    private int pageNum=1;// 현재 페이지 번호
    private int contentNum = 10;// 한 페이지에 몇 개 표시할지
    private int startPage = 1;// 현재 페이지 블록의 시작페이지
    private int endPage = 5;// 현재 페이지 블록의 마지막 페이지
    private boolean prev = false;// 이전 페이지로 가는 화살표
    private boolean next;// 다음 페이지로 가는 화살표
    private int currentBlock;// 현재 페이지 블록
    private int lastblock;// 마지막 페이지 블록
 
    public void prevNext(int pageNum) {
        if (pageNum > 0 && pageNum < 6) {
            setPrev(false);
            setNext(true);
        }
        else if (getLastblock() == getCurrentBlock()) {
            setPrev(true);
            setNext(false);
        }
        else {
            setPrev(true);
            setNext(true);
        }
    }
 
    public int calcpage(int totalCount , int contentNum) {
        int totalPage = totalCount / contentNum;
        if (totalCount % contentNum > 0) {
            totalPage++;
        }
        return totalPage;
    }
 
    public int getTotalCount() {
        return totalCount;
    }
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }
 
    public int getPageNum() {
        return pageNum;
    }
 
    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }
 
    public int getContentNum() {
        return contentNum;
    }
 
    public void setContentNum(int contentNum) {
        this.contentNum = contentNum;
    }
 
    public int getStartPage() {
        return startPage;
    }
    public void setStartPage(int currentBlock) {
        this.startPage = (currentBlock * 5- 4;
        //1 2 3 4 5
        //6 7 8 9 10
        //11 12 13
    }
    public int getEndPage() {
        return endPage;
    }
    public void setEndPage(int getLastBlock, int getCurrentBlock) {
        if (getLastBlock == getCurrentBlock) { // 현재 페이지 블록이 마지막 블록이면
            this.endPage = calcpage(getTotalCount(), getContentNum()); // 페이지 개수를 끝페이지로 지정
        }
        else {
            this.endPage = getStartPage() + 4// 시작 페이지 + 4를 끝페이지로 지정
        }
    }
    public boolean isPrev() {
        return prev;
    }
    public void setPrev(boolean prev) {
        this.prev = prev;
    }
    public boolean isNext() {
        return next;
    }
    public void setNext(boolean next) {
        this.next = next;
    }
    public int getCurrentBlock() {
        return currentBlock;
    }
    public void setCurrentBlock(int pageNum) { // 페이지 번호 5 들어옴
        //페이지 번호를 통해서 구한다.
        //페이지 번호 / 페이지 그룹 안의 개수
        //1p 1 / 5 => 0.2
        //5p 5 / 5 = > 1 -> 나머지는 0
        this.currentBlock = pageNum / <span style="

다음으로는 C,R,U,D Service이다.

첫번째로는 ListService이다 게시글을 저장하면 데이터베이스에서 게시글 리스틀을 전부 가져오는 역활을 한다. 하지만 여기서 주의해야 할점은 첫번째 만들었을 때 게시글의 갯수가 0이니깐 분류를 해야한다. 나는 if(freeboardPage.getsize()==0)일때와 그렇지 않을때 2가지로 나누었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 
import org.springframework.stereotype.Service;
 
 
@Service
public class BoardListService {
    public final HttpSession session;
    public final BoardRepository boardRepository;
    public final PageMakerService pageMakerService;
 
    public BoardListService(HttpSession session,BoardRepository boardRepository, PageMakerService pageMakerService)
    {
        this.session=session;
        this.boardRepository=boardRepository;
        this.pageMakerService=pageMakerService;
    }
 
    public String boardList(int pageNum)
    {
        PageMaker pageMaker = pageMakerService.generatePageMaker(pageNum,10,boardRepository);
        PageRequest pageRequest = PageRequest.of(pageNum-1,10);
        Page<Board> freeboardPage = boardRepository.findAll(pageRequest);
 
        if(freeboardPage.getSize()==0)
        {
            session.setAttribute("boardList",new ArrayList<Board>());
            session.setAttribute("pageMaker",pageMaker);
            return "board";
        }
 
        List<Board> freeboardList = freeboardPage.getContent();
        session.setAttribute("boardList",freeboardList);
        session.setAttribute("pageMaker",pageMaker);
 
        return "board";
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

두번째로는 Create부분이다.

Front에서 받아온 값을 객체 생성 및 값을 set해주고 해당되는 객체를  Repository에 save()를 해주고 session set을 해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
 
import org.springframework.stereotype.Service;
 
 
@Service
public class BoardWriteService {
 
    private final BoardRepository boardRepository;
    private final HttpSession httpSession;
 
    public BoardWriteService(BoardRepository boardRepository,HttpSession httpSession)
    {
        this.boardRepository=boardRepository;
        this.httpSession=httpSession;
    }
 
    public void write(String title, String content, String writer)
    {
        Board board = new Board();
        board.setTitle(title);
        board.setContent(content);
        board.setWriter(writer);
        httpSession.setAttribute("board",board);
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

세번째로는 Read부분이다.

나는 게시글에서 게시글의 재목을 클릭을 하였을 때 제목, 작성자, 내용 이렇게 3가지를 보이게 하였다.

해당되는 Id값을 가지고 Reposiroty에서 검색한다음 이것을 객체로 받아 session을 set해주면 front에서 session.board.getTitle()이렇게 하면 우리가 작성한 제목을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
 
import org.springframework.stereotype.Service;
 
 
@Service
public class BoardInfoService {
    private final BoardRepository boardRepository;
    private final HttpSession session;
 
    public BoardInfoService(BoardRepository boardRepository, HttpSession session)
    {
        this.boardRepository=boardRepository;
        this.session= session;
    }
 
    public void InfoService(long freeId)
    {
        Board board = boardRepository.findById(freeId).get();
 
        session.setAttribute("board",board);
 
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

네번째로는 Delete부분이다. 해당되는 Id를 가지고 Repository에서 deleteById를 해주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
 
import org.springframework.stereotype.Service;
 
@Service
public class BoardDeleteService {
    private final BoardRepository boardRepository;
 
    public BoardDeleteService(BoardRepository boardRepository)
    {
        this.boardRepository=boardRepository;
    }
    public void deleteService(long freeId)
    {
        boardRepository.deleteById(freeId);
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

마지막으로 Update부분이다. update는 처음에 생각하기 어려웠으나 Read+Create라는것을 알 수있었다. 이유는 게시글을 수정하기 위해서는 이전에 값을 알아야하고 또 이값을 다시 create하는것이기 때문이다.(그렇다고 코드상에 객체를 따로 생성하지는 않았다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
 
import org.springframework.stereotype.Service;
 
 
@Service
public class BoardUpdateService {
 
    private final HttpSession session;
    private final BoardRepository boardRepository;
 
    public BoardUpdateService(HttpSession session, BoardRepository boardRepository)
    {
        this.session=session;
        this.boardRepository= boardRepository;
    }
    public void Update(long id,String title,String content)
    {
        Board board= boardRepository.findById(id).get();//여기에서 findById가 optional이기 때문에 .get()을 사용해야 한다.
        board.setTitle(title);
        board.setContent(content);
 
        session.setAttribute("board",board);
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

 

 

Front

 

Board.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      th:with="lang=${#locale.language}" th:lang="${lang}">
<head>
    <title>Bootstrap Example</title>
    <meta charset="utf-8">
    <link href="ballad.css" rel="stylesheet" type="text/css">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        table{
            width: 100%;
            border-top: 1px solid #444444;
            border-collapse: collapse;
        }
        th, td{
            border-bottom: 1px solid #444444;
            padding: 10px;
        }
    </style>
    <script>
        function page(pageNum){
            location.href="/board?pageNum="+pageNum;
        }
        function getPost(freeid) {
            location.href="/Info?freeId="+freeid;
        }
    </script>
</head>
<body>
<div class="container">
    <h3> Board</h3>
    <h4><span th:text="${session.user.getUserId()}" ></span>님 환영합니다!</h4>
    <div class="col-sm-8 text-left">
        <table>
            <thead>
            <tr>
                <th>&nbsp;&nbsp;글 번호&nbsp;&nbsp;</th>
                <th>&nbsp;&nbsp;글 제목&nbsp;&nbsp;</th>
                <th>&nbsp;&nbsp;작성자&nbsp;&nbsp;</th>
            </tr>
            <th:block th:if="${session.boardList!=null}">
                <th:block th:each="board:${session.boardList}">
                    <tr>
                        <td><span th:text="${board.getId()}"></span></td>
                        <td><a th:onclick="|javascript:getPost('${board.getId()}')|" th:text="${board.getTitle()}"></a></td>
                        <td><span th:text="${board.getWriter()}"></span></td>
                    </tr>
                </th:block>
            </th:block>
            </thead>
            </table>
<!--        <a th:if="${session.pageMaker.isPrev()}" style="text-decoration: none;" th:onclick="|javascript:page('${session.pageMaker.getStartPage()}')|">&laquo;</a>-->
<!--        <th:block th:each="pageNum:${#numbers.sequence(session.pageMaker.getStartPage(),session.pageMaker.getEndPage())}">-->
<!--            &nbsp;<a th:text="${pageNum}" th:onclick="|javascript:page('${pageNum}')|"></a>&nbsp;-->
<!--        </th:block>-->
<!--        <a th:if="${session.pageMaker.isNext()}" style="text-decoration: none;" th:onclick="|javascript:page('${session.pageMaker.getEndPage()}')|">&raquo;</a>-->
    </div>
</div>
<div class="col-sm-8 text-right">
    <button type="button" style="color: white; background-color: gray; border-radius: 0.5em" onclick="location.href='/boardWrite'">글쓰기</button>
</div>
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

BoardInfo.html(상세보기)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      th:with="lang=${#locale.language}" th:lang="${lang}">
<head>
    <title>Bootstrap Example</title>
    <meta charset="utf-8">
    <link href="ballad.css" rel="stylesheet" type="text/css">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        th,td{
            padding:50px;
        }
    </style>
    <script>
        function page(pageNum){
            location.href="/board?pageNum="+pageNum;
        }
        function getDelete(freeid) {
            location.href = "/boardDelete?freeId=" + freeid;
        }
        function getUpdate(freeid){
            location.href = "/boardUpdate?freeId=" +freeid;
        }
    </script>
</head>
<body>
<div class ="container-fluid text-center">
    <span style="font-size: 20px">제목</span>&nbsp;&nbsp;&nbsp;<textarea style="height: 20px;" th:text="${session.board.getTitle()}"  readonly="readonly"></textarea>
    <br>
    <span style="font-size: 20px">작성자</span>&nbsp;&nbsp;&nbsp; <textarea style="height: 20px" th:text="${session.board.getWriter()}" readonly="readonly"></textarea>
    <br><br>
    <textarea style="height: 100px;width: 100px;" th:text="${session.board.getContent()}"  readonly="readonly"></textarea>
</div>
<div class="col-sm-8 text-right">
    <button type="button" style="color: white; background-color: gray; border-radius: 0.5em" th:onclick="|javascript:getUpdate('${session.board.getId()}')|">수정</button>
</div>
<div class="col-sm-8 text-right">
    <button type="button" style="color: white; background-color: gray; border-radius: 0.5em" th:onclick="|javascript:getDelete('${session.board.getId()}')|">삭제</button>
</div>
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

BoardWrite.html (Create 부분)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      th:with="lang=${#locale.language}" th:lang="${lang}">
<title>W3.CSS</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link href="board.css" rel="stylesheet" type="text/css">
<body>
 
<div class="w3-container">
    <h3>주의!</h3>
    <div class="w3-panel w3-red">
        <p style="">욕, 심한말, 법적신고가능함!</p>
    </div>
</div>
 
<form action="/boardWriteRequest" method="post">
    <input type="text" placeholder="글 제목" name="title">
    <br><br>
    <textarea placeholder="글 내용" name="content"></textarea>
    <br><br>
    <input type="hidden" th:value="${session.user.getUserName()}" name="writer">
    <div class="button">
        <button type="submit">Submit</button>
    </div>
</form>
 
</body>
</html>
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

BoardUpdate.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      th:with="lang=${#locale.language}" th:lang="${lang}">
<title>글 수정페이지</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link href="board.css" rel="stylesheet" type="text/css">
<body>
 
<div class="w3-container">
    <h3>주의!</h3>
    <div class="w3-panel w3-red">
        <p style="">욕, 심한말, 법적신고가능함!</p>
    </div>
</div>
 
<form action="/update" method="post">
    <input type="text"  th:value="${session.board.getTitle()}" name="title">
    <br><br>
    <input style="height:300px;width: 300px "  th:value="${session.board.getContent()}" name="content"></input>
    <br><br>
    <input type="hidden" th:value="${session.board.getId()}" name="freeId">
    <div class="button">
        <button type="submit">Submit</button>
    </div>
</form>
 
</body>
</html>
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

처음 Spring을 배우는데 많은 어려움이 있었지만 하나하나 해결해 나가는데 매우 재미있었던것 같다. 

이번주 부터는 이 게시판과는 별개로 따로 만든 게시판을 서버에 올렸는데 그 과정을 Posting할 예정이고 그 게시판을 Refactoring 및 Restful하게 만들 계획이다. (이 게시판은 Service Flow를 확실히 이해하기 위해 다시 처음부터 만들었던 코드이다,)

 

Service Flow를 이해하기 위한 나의 그림

 

'SpringBoot' 카테고리의 다른 글

Homebrew 설치 및 gradle설치  (0) 2019.07.23
사용중인 포트 찾아서 Kill하기  (0) 2019.07.23
Spring으로 만드는 간단한 게시판(1)  (0) 2019.07.22
Get & Post  (0) 2019.07.08
해시(Hash) 와 암호화(Encryption)  (0) 2019.07.08

Spring을 공부시작을 3주정도 지난것 같다. 

처음에 시작했을때  많이 어렵다고 생각하였으나 Service flow를 그림으로 그리면서 공부하니 훨씬 이해하기 쉽고 특정부분에서 어떠한 것이 필요한가 이해하기 쉬웠다. 이 코드는 이전에 진행했던 게시판에서 한 Section만 작성한 코드이다.(이전 게시판은 음악리뷰 게시판)

(디자인 부분은 신경쓰지 않았습니다. 기능만 구현하였습니다.)

1. 로그인하기 

어떠한 하나의 패키지를 만들때 가장 기본적으로 들어가야하는것은 다음과 같다.

예를 들어 지금 로그인 부분에서 User라는 Package가 있다면 그 안에 필수 요소는 User, UserRepository, UserController 이렇게 3개의 요소가 가장 기본이다. 

기능은 1. 기존의 사용자가 로그인을하는 경우 2.회원가입을 하는 경우 라고 생각한다.

User --> 값에 _ 가 들어가면 안된다 나중에 Repository에서 찾을때 _가 있으면 찾지 못한다!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
 
 
import javax.persistence.*;
 
 
@Entity
@Table(name="users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String userId;
    private String userName;
    private String userPassword;
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public void setUserId(String userId) {
        this.userId = userId;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }
 
    public Long getId() {
        return id;
    }
 
    public String getUserId() {
        return userId;
    }
 
    public String getUserName() {
        return userName;
    }
 
    public String getUserPassword() {
        return userPassword;
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

UserRepository --> 사용자를 찾기 위한 Query 부분

1
2
3
4
5
6
7
8
9
10
 
import org.springframework.stereotype.Repository;
 
@Repository
public interface UserRepository extends JpaRepository <User,Long> {
    User findByUserIdAndUserPassword(String userId,String userPassword); //Query부분
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

UserController -->여기를 이해하는것이 가장 중요!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
 
import org.springframework.stereotype.Controller;
 
 
@Controller
public class UserController {
 
    private final UserJoinService userJoinService;
    private final UserLoginService userLoginService;
 
    public UserController(UserJoinService userJoinService, UserLoginService userLoginService)
    {
        this.userJoinService=userJoinService;
        this.userLoginService=userLoginService;
    }
 
    @PostMapping(value = "/joinRequest")
    public String joinRequest(HttpServletRequest request)
    {
        userJoinService.JoinService(request);
        return "login";
    }
 
    @PostMapping(value = "/loginRequest")
    public String loginRequest(HttpServletRequest request)
    {
        User user = userLoginService.loginService(request);
        if(user==null)
        {
            return "login";
        }
        else
        {
            return "board";
        }
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

PasswordHash --> String으로 받은 사용자의 비밀번호를 SHA를 사용부분  이부분이 궁금하면 따로 정리 해놓은 Posting 참조!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 
import org.springframework.stereotype.Service;
import java.security.MessageDigest;
@Service
public class PasswordHash {
    public String getSHA256(String plainText) {
        String shaString = "";
        if(plainText == null){
            return "";
        }
        try {
            MessageDigest sh = MessageDigest.getInstance("SHA-256");
            sh.update(plainText.getBytes());
            byte byteData[] = sh.digest();
            StringBuffer stringBuffer = new StringBuffer();
            int byteSize = byteData.length;
 
            for (int i = 0; i < byteSize; i++) {
                stringBuffer.append(Integer.toString((byteData[i] & 0xff+ 0x100 , 16).substring(1));
            }
            shaString = stringBuffer.toString();
        }
 
        catch (Exception e) {
            e.printStackTrace();
            shaString = null;
        }
        return shaString;
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

 

Service부분은 사용자를 로그인 Part의 UserLoginService, 회원가입 Part의 UserJoinService가 필요하다,

 

UserJoinService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 
import org.springframework.stereotype.Service;
 
 
@Service
public class UserJoinService {
 
    private final UserRepository userRepository;
    private final PasswordHash passwordHash;
 
    public UserJoinService(UserRepository userRepository,PasswordHash passwordHash)
    {
        this.userRepository=userRepository;
        this.passwordHash=passwordHash;
    }
    public void JoinService(HttpServletRequest request)
    {
        String name=request.getParameter("userName"); //이름
        String id=request.getParameter("userId");//아이디
        String password = request.getParameter("userPassword");//비밀번호
 
 
        User user = new User();//객체생성
        user.setUserName(name);
        user.setUserId(id);
        String HashPassword =passwordHash.getSHA256(password);
        user.setUserPassword(HashPassword);
 
        userRepository.save(user);//사용자 객체 저장
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

회원가입의 Service Flow는 다음과 같다.

회원가입 버튼을 눌렀을때 Post형식으로 /joinRequest를 UserController로 간다. UserController에서 /joiinRequest를 @PostMapping을하여 UserJoinService를 사용한다.

이 Service부분을 살표보면 HttpServletRequest를 사용하여 Front쪽에서 "userName", "userId", "userPassword" 값을 전달받아 객체를 생성하여 값을 Setting하여 Repository에 저장을 한다. 그다음 다시 로그인 창이 다시 뜨게 return을 해준다.

( 여기에서 비밀번호는 그냥 저장하면 안되기 때문에 PasswordHash를 써서 변경후 저장해야한다.)

 

 

위의 생성자는 @Autowired를 대신하여 생성자를 작성하였다. 이렇게 한 이유는 Spring Framework가 종속적이기 때문이다.

생성자의 인자가 많아지는 경우에 final을 받는 파라미터를 생성자로 만들어주는 @RequiredArgsConstructor을 사용가능함 . 다만 이때는 인자의 추가나 순서 변경시 생성자 클래스가 변경되는 점에 주의해야한다. --출처 우아한형제들 기술블로그 

http://woowabros.github.io/experience/2019/02/28/pilot-project-settle.html

 

코드리뷰 적응기(feat. 파일럿 프로젝트) - 우아한형제들 기술 블로그

안녕하세요. 결제정산개발팀의 권세희입니다.저는 정산업무를 맡게 되었는데, 정산은 데이터 정합성과 트랜잭션, 도메인 주도 개발, Entity 간의 연관 관계, 대용량 데이터 처리가 핵심인 시스템입니다.정산 도메인과 기술셋에 대한 경험이 없어 들어가기에 앞서 파일럿 프로젝트를 먼...

woowabros.github.io

UserLoginService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 
 
import org.springframework.stereotype.Service;
 
 
@Service
public class UserLoginService {
 
    private final UserRepository userRepository;
    private final PasswordHash passwordHash;
    private final HttpSession session;
 
    public UserLoginService(UserRepository userRepository, PasswordHash passwordHash, HttpSession session){
        this.userRepository=userRepository;
        this.passwordHash=passwordHash;
        this.session=session;
    }
 
    public  User loginService(HttpServletRequest request){
        String id=request.getParameter("userId");
        String password=request.getParameter("userPassword");
        String hashPassword=passwordHash.getSHA256(password);
 
        User user=userRepository.findByUserIdAndUserPassword(id,hashPassword);
 
        session.setAttribute("user",user);
        return user;
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

위의 UserJoinService를 이해하였다면 이 파트도 쉽게 이해할 수 있다 다만, 다른점이 있다면 Repository에 잇는 findByUserAndUserPassword를 사용하여 사용자를 찾아주고 찾아준 객체를 user객체에 저장 및 반환하여 Controller /loginRequest에서 반환한 값이 null일 경우에는 계속 로그인 페이지에 남고 로그인 성공시 다음 페이지로 넘어간다.

 

Front Part

Join.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>회원가입페이지</title>
<body>
<div class="login-box">
    <h1>Create Account</h1>
 
    <form action="/joinRequest" method="post">
        <div class="textbox">
            <input type="text" value ="이름을 입력해주세요" placeholder="Username" name="userName">
        </div>
 
        <div class="textbox">
            <input type="text" value="아이디를 입력해주세요" placeholder="UserId" name="userId">
        </div>
 
        <div class="textbox">
            <input type="password" value="비밀번호를 입력해주세요" placeholder="Password" name="userPassword">
        </div>
        <input class="btn" type="submit" value="Sign In">
    </form>
 
</div>
</body>
</head>
<body>
<form>
 
</form>
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>로그인</title>
    <script src="https://kit.fontawesome.com/15f814a076.js"></script>
<body>
<div class="login-box">
    <h1>Longin</h1>
 
    <form action="/loginRequest" method="post">
        <div class="textbox">
            <i class="far fa-user"></i>
            <input type="text" placeholder="UserId" name="userId">
        </div>
 
        <div class="textbox">
            <i class="fas fa-lock"></i>
            <input type="password" placeholder="Password" name="userPassword">
        </div>
 
        <input class="btn" type="submit" name="" value="Sign In">
    </form>
    <br>
    <br>
    <input class="btn" type="button" name="" value="Create Account" onclick="location.href='/join'">
</div>
</body>
</head>
<body>
<form>
 
</form>
</body>
</html>
 
 
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

'SpringBoot' 카테고리의 다른 글

사용중인 포트 찾아서 Kill하기  (0) 2019.07.23
Spring으로 만드는 간단한 게시판(2)  (0) 2019.07.22
Get & Post  (0) 2019.07.08
해시(Hash) 와 암호화(Encryption)  (0) 2019.07.08
쿠키(Cookie)와 세션(Session)  (0) 2019.07.08

Spring을 공부하면서 @GetMapping, @PostMapping을 보았다. 대학교 시절 네트워크수업에서 Get, Post 방식을 배웠지면 누군가 물어봤을때 딱 자신있게 대답을 할 수 없어 두 방식이 어떠한 방법이고 차이점이 무엇인지 정리하기 위해 게시글을 작성하였다.

 

클라이언트가 서버로 요청을 보내는 방법은  1. Get  2.Post 이렇게 두가지 방법이 있다.

 

Get 방식

Get방식은 어떠한 정보를 가져와서 조회하기 위해 사용되는 방식이다. Get 방식에는 여러가지의 특징이 있다.

1. URL에 변수를 포함시켜 요청한다.

2. 데이터를 header를 포함하여 전송한다.

3. URL에 데이터가 노출되어 보안에 취약하다.

4. 캐싱이 가능하다. (캐싱: 한번 접근후, 똑같은 요청을 할 시 빠르게 접근하기 위해 레지스터에 데이터를 저장시키는것)

 

처음에 Spring을 공부하였을때 Get방식 즉, @GetMapping을 사용하여 loginRequest, joinRequest를 사용하였더니 URL에 아이디, 비밀번호 혹은 아이디, 비밀번호, 이름이 노출되는것을 확인하였다. 이것에 대한 해결방안으로 Get방식(@GetMapping)이 아닌 Post(@PostMapping)방법을 사용하였다.

 

Post 방식 

Post방식은 데이터를 서버로 제출하여 추가 또는 수정하기 위해서 데이터를 전송하는 방식이다 Post방식 또한 여러 특징이 있다.

1. URL에 변수에 변수를 노출하지 않고 요청을 한다.

2. 데이터를 Body에 포함시킨다.

3. URL에 데이터가 노툴되지 않아서 기본 보안이 설정되어 있다.

4. 전송하는데 길이 제한이 없다.

5. 캐싱을 불가능하다.

 

아래의 사진은 Controller에서 로그인시 , 회원가입시 보내는 @PostMapping 방식의 코드다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
import org.springframework.stereotype.Controller;
 
 
@Controller
public class UsersController {
 
    private final ListService listService;
//    private final UsersRepository userRepository;//final 재할당 안되게
    private final JoinService joinService;
    private final LonginService longinService;
 
    public UsersController(JoinService joinService,ListService listService, LonginService longinService) {
        this.joinService = joinService;
        this.listService = listService;
        this.longinService=longinService;
    }
    @PostMapping(value = "/joinRequest")
    public String joinRequest(HttpServletRequest request){
       joinService.joinUser(request);
       return "join";
   }
 
   @PostMapping(value="/loginRequest")
   public String loginRequest(HttpServletRequest request){
        return "index";
   }
 
   @GetMapping(value="/find")
    public String find(){
        System.out.println(listService.find());
        return "index";
   }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

'SpringBoot' 카테고리의 다른 글

Spring으로 만드는 간단한 게시판(2)  (0) 2019.07.22
Spring으로 만드는 간단한 게시판(1)  (0) 2019.07.22
해시(Hash) 와 암호화(Encryption)  (0) 2019.07.08
쿠키(Cookie)와 세션(Session)  (0) 2019.07.08
Docker  (0) 2019.06.27

+ Recent posts