'JAVA의 정석'의 저자 남궁성의 Spring 강의를 듣고 정리하였습니다.
source: https://github.com/castello/spring_basic/tree/main
Spring으로 개발하기 위해 필요한 도구들 🦎
자바 개발도구: JAVA11 (Oracle JDK - 유료, Open JDK - 오픈소스로 만들어짐:IBM, RedHat, Amazon)
MAC - SDKMAN을 이용해서 openJDK설치( sdk install java 11.0.12.7.2-amzn )
통합 개발 환경(IDE) : STS, IntelliJ
실무에서 STS도 사용한다고 하니 STS를 이용하여 프로젝트를 만들다가, IntelliJ로 넘어갈 것이다.
웹 서버: Tomcat 9
tomcat 설치 후 bin 폴더의 ./startup.sh 실행하여 시작시키기
접속방법 : http://localhost:8080/
종료방법: ./shutdown.sh
웹 브라우저:chrome
데이터베이스: MYSQL 5.7
기타: VS code, Git, AWS, Maven
설치 참고 자료: https://github.com/castello/spring_basic
java version : SE(Standard, 일반), EE(Enterprise, 서버, 대기업), ME(Micro 소형기기)
VSC(Version Control System): SVN(무료, 단순), Git(복잡, 강력)
VS Code Extension
korean, prettier, open in browser(alt+b 사용시 html 화면 바로 띄워짐), indent-rainbow(들여쓰기 레벨 색깔로 보여줌)
auto rename tag(html 앞 태그 고치면 뒤 태그도 고쳐짐)
MAC M1에서 STS 설치 문제 해결방법
arm64 jdk 문제로 인해 발생한다. x86-64 bit jdk를 설치하여 사용하면 된다.
https://limecats0331.github.io/blog/m1_STS/
Spring project 만들기
Spring Starter Project - Spring Boot Project
Spring Legacy Project - Spring Project
우리는 스프링 프로젝트를 만들 예정이므로 Legacy Project를 선택한다.
template은 Spring MVC Project를 선택한다.
패키지 이름 작성하기
Tomcat 연결하기
설치한 톰캣 버전으로 선택
톰캣 설치 경로 지정
외부 브라우저 사용하기
preferences 선택
Use external web browser - Chrome으로 추가하기
Application 실행하기
Chrome으로 웹이 열리는 것을 볼 수 있다.
MAC STS 실행 안되는 문제
잘 되다가 갑자기 STS가 실행이 안된다면 프로그램의 인증 문제 일 수 있다.
위 명령어를 터미널에 쳤을때 checksum did not verify 오류가 떴다면 강제 인증을 실행하자.
그 후에는 정상 실행이 되는 것을 확인할 수 있다.
아래 블로그를 참고했다.
https://happy-jjang-a.tistory.com/104
AWS 서버 구축하기
원격 서버에 톰캣을 설치해서 접근하기
AWS
Amazon이 제공하는 cloud service
AWS 가입하기 - 최초 가입시 12개월 동안 프리티어 계정 사용가능
무료 사용량을 초과하면 과금될 수 있음
Amazon EC2
크기 조정이 가능한 컴퓨팅 용량을 클라우드에서 제공하는 웹 서비스
- Amazon S3: 확장성, 가용성, 내구성을 가진 데이터 저장 공간을 제공
- Amazon RDS: 관계형 DB 관리 서비스, 관계형 DB(MySQL, Oracle)등을 모니터링, 주기적 백업
관련 용어
- on-Premise : 서버를 직접 운영하는 방식
- Serverless : 서버 작업을 서버 내부가 아닌 클라우드 서비스로 처리
- Region : 데이터 센터가 물리적으로 존재하는 곳
- CDN(Content Delivery Network) : 정적 리소스를 빠르게 제공할 수 있게 전세계의 캐시서버에 복제해주는 서비스.
AWS 계정을 만들어 프리티어(Free-Tier)를 사용한다.
instance 만들기
EC2 - region:Seoul- instance 시작
key pair 생성
키 페어를 생성하고 다운로드한다.
인스턴스 생성하기 버튼 누르기
인스턴스 연결하기
연결 버튼 누르기
RDP Client 버튼 누르기
원격 데스크톱 파일 다운로드하기
(Mac은 App Store에서 Microsoft Remote Desktop 설치까지 하기)
다운로드 받은 rdp 파일을 RDP로 열어보면 로그인하라고 뜬다.
RDP Client 아래에 암호 가져오기 누르면 된다.
아까 key pair download하여 저장한 pem파일을 업로드하여 암호를 얻는다.
암호를 입력하여 접속하면 서버 화면이 잘 뜬다 🐯
깃허브 참고해서 서버에 jdk11과 톰캣 설치하기(이전과 과정 같음)
https://github.com/castello/spring_basic
jdk11과 톰캣을 설치해서 C 드라이브로 이동한다.
제어판의 환경 변수 설정 부분에서 Path-edit에서 new 버튼을 눌러 jdk11의 빈 폴더 경로를 추가한다.
jdk11\bin을 move up하여 맨 위로 올려주면 우선순위가 높아진다.
new - JAVA_HOME 추가하기
Powershell에서 JDK 설치 확인
톰캣 폴더의 startup을 클릭한후 localhost:8080이 잘 실행되는지 확인한다.
localhost:8080 접속이 잘 된다.
이제 이 서버의 톰캣을 내 컴퓨터에서 접속하여 사용해야한다.
방화벽 열기
firewall - advanced settings
inbound rules: 바깥 컴퓨터에서 이 컴퓨터의 방화벽 안으로 들어올때의 규칙
outbound rules: 이 컴퓨터에서 바깥 컴퓨터에 접속하기 위해 방화벽 밖으로 나갈때의 규칙
바깥 컴퓨터(내 컴퓨터)에서 이 서버의 컴퓨터(aws 인스턴스)로 접속하여 톰캣을 사용할 것이므로
inbound rules - new rule 클릭
톰캣의 8080포트 열어주기
이름 적고 finish
추가적으로 aws의 보안 그룹도 설정해주어야한다.
EC2 대시보드 - 보안 그룹 - default 말고 이번에 새로 생긴거(launch-wizard-1) 선택
inbound 규칙 편집
유형을 모든 TCP로 바꾸고 규칙 저장
내 컴퓨터에서 aws 인스턴스로 접속
1. aws 인스턴스의 네트워킹 - 퍼블릭 IPv4 주소로 접속하기
접속 링크 : 퍼블릭 IPv4:8080
환경 설정 끝 !! (DB는 나중에 설치)
Spring MVC
원격 프로그램 실행 방식
브라우저 (외부 컴퓨터) - WAS (서버 컴퓨터)
1. 외부 컴퓨터의 브라우저에서 URL 입력하기
2. WAS는 외부 컴퓨터의 ip주소의 요청을 받으면 프로그램을 실행한다.
웹 서버 vs WAS (Web Service Architecture)
웹 서버 : 웹 브라우저 클라이언트로부터 HTTP 요청을 받아들이고 HTML 문서와 같은 웹페이지를 반환하는 컴퓨터 프로그램 (정적 컨텐츠 제공)
WAS : 인터넷 상에서 HTTP 프로토콜을 통해 사용자 컴퓨터나 장치에 웹 애플리케이션을 수행해주는 middleware (동적 컨텐츠 제공)
-> 주로 db 서버와 같이 수행
출처 : https://codechasseur.tistory.com/25
원격 프로그램 실행 방법
1. 프로그램 등록
2. URL과 프로그램을 연결
@Contoller //1. 프로그램 등록
public class Hello {
@RequestMapping("/hello") //2. URL과 main()을 연결
public void main(){
System.out.println("Hello");
}
}
/hello 링크로 들어가면 main 메서드가 호출된다.
실행할 프로그램 만들기
스프링 프로젝트 만들기
file - new - spring legacy project
프로젝트 실행하기
run as - run on server
프로젝트 명을 루트로 하는 링크로 실행된다.
프로그램 만들기
Contoller에 등록한 후 URL과 실행시킬 메서드를 매핑한다.
프로그램 실행
프로그램 실행시 Hello가 출력된다.
✅ main 메서드는 static이 아님에도 호출 가능한 이유
-> 호출시 톰캣이 Hello 인스턴스를 생성하기때문에 main 메서드를 호출할 수 있다.
인스턴스 메서드와 static 메서드의 차이
인스턴스 메서드는 클래스 내 모든 필드를 사용할 수 있지만 static 메서드는 static 필드만 사용 가능하다.
? main 메서드를 private으로 선언해도 호출이 가능할까?
실제 private 메서드는 외부에서 호출할 수 없다.
하지만 Reflection API를 사용하여 호출하면 private 메서드도 호출할 수 있다.
Reflection API 예제
✅ 클래스 파일이 메모리에 올라갈때, 클래스 파일마다 Class 객체가 하나씩 생성된다.
✅ forName은 그 Class 객체를 얻어올 수 있다. Class 객체는 어떤 필드와 메서드를 가지고있는지 설명하는 설계도이다.
AWS 배포하기
1. project - export - .war file 만들기
👀 war 파일은 zip파일로 파일 format을 바꾸어도 실행된다.
2. aws 접속해서 인스턴스 재시작
✅ 인스턴스를 사용하지 않을때는 중지해 두는 것이 좋다. (종료와는 다르다. 종료는 instance 날아감)
✅ 재시작하면 IP 주소도 바뀌기 때문에 원격 데스크톱 파일을 다시 다운로드 받아야한다.
✅ 암호는 변하지않는다
3. war 파일 옮기기
command+c, v 하여 tomcat의 webapps에 붙여넣기
✨ webapps : 톰캣 실행시 실행되는 application
tomcat 실행하면 ch2 폴더가 생기고 그 안에 java 프로젝트 파일이 들어있는 것을 확인할 수 있다. = 설치 성공함
4. war 파일이 잘 옮겨졌는지 확인
aws의 퍼블릭 주소에 hello로 접속하면
aws 서버에서 hello 메서드를 실행한 후 정상적으로 출력되는 것을 볼 수 있다.
HTTP 요청과 응답
프로그램 만들기
년월일을 입력하면 요일을 알려주는 프로그램
터미널에서 클래스 실행 방법
workspace로 가서 target/classes에서 실행한다
java 클래스명 인자
HttpServletRequest
브라우저 요청시 tomcat은 요청 정보를 HttpServletRequest 객체에 담아 인자로 전달한다.
얻을 수 있는 정보
getParameter는 문자열로 값을 리턴한다.
getParameterNames() : 파라미터 이름들만 반환한다. 리턴타입 Iterator
getParameterMap() : map 형태로 파라미터 가져온다.
getParameterValues("파라미터이름") : 파라미터 이름이 중복될때 그 파라미터의 값들을 String 배열로 리턴
함수 예시
package com.fastcampus.ch2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class RequestInfo {
@RequestMapping("/requestInfo")
// public static void main(String[] args) {
public void main(HttpServletRequest request) {
System.out.println("request.getCharacterEncoding()="+request.getCharacterEncoding()); // 요청 내용의 인코딩
System.out.println("request.getContentLength()="+request.getContentLength()); // 요청 내용의 길이. 알수 없을 때는 -1
System.out.println("request.getContentType()="+request.getContentType()); // 요청 내용의 타입. 알 수 없을 때는 null
System.out.println("request.getMethod()="+request.getMethod()); // 요청 방법
System.out.println("request.getProtocol()="+request.getProtocol()); // 프로토콜의 종류와 버젼 HTTP/1.1
System.out.println("request.getScheme()="+request.getScheme()); // 프로토콜
System.out.println("request.getServerName()="+request.getServerName()); // 서버 이름 또는 ip주소
System.out.println("request.getServerPort()="+request.getServerPort()); // 서버 포트
System.out.println("request.getRequestURL()="+request.getRequestURL()); // 요청 URL
System.out.println("request.getRequestURI()="+request.getRequestURI()); // 요청 URI
System.out.println("request.getContextPath()="+request.getContextPath()); // context path
System.out.println("request.getServletPath()="+request.getServletPath()); // servlet path
System.out.println("request.getQueryString()="+request.getQueryString()); // 쿼리 스트링
System.out.println("request.getLocalName()="+request.getLocalName()); // 로컬 이름
System.out.println("request.getLocalPort()="+request.getLocalPort()); // 로컬 포트
System.out.println("request.getRemoteAddr()="+request.getRemoteAddr()); // 원격 ip주소
System.out.println("request.getRemoteHost()="+request.getRemoteHost()); // 원격 호스트 또는 ip주소
System.out.println("request.getRemotePort()="+request.getRemotePort()); // 원격 포트
}
}
//
//[실행결과] http://localhost:8080/ch2/requestInfo?year=2021&month=10&day=1
//request.getCharacterEncoding()=UTF-8
//request.getContentLength()=-1
//request.getContentType()=null
//request.getMethod()=GET
//request.getProtocol()=HTTP/1.1
//request.getScheme()=http
//request.getServerName()=localhost
//request.getServerPort()=8080
//request.getRequestURI()=http://localhost:8080/ch2/requestInfo
//request.getRequestURI()=/ch2/requestInfo
//request.getContextPath()=/ch2
//request.getServletPath()=/requestInfo
//request.getQueryString()=year=2021&month=10&day=1
//request.getLocalName()=localhost
//request.getLocalPort()=8080
//request.getRemoteAddr()=0:0:0:0:0:0:0:1 <--- AWS에 배포(deploy)한 다음에 실행하면, 실제 ip주소를 확인할 수 있음.
//request.getRemoteHost()=0:0:0:0:0:0:0:1 <--- AWS에 배포(deploy)한 다음에 실행하면, 실제 ip주소를 확인할 수 있음.
//request.getRemotePort()=54855
HttpServletRequest을 이용한 YoilTeller 프로그램
package com.fastcampus.ch2;
import java.util.Calendar;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class YoilTeller {
// public static void main(String[] args) {
@RequestMapping("/getYoil")
public void main(HttpServletRequest request) {
// 1. 입력
String year = request.getParameter("year");
String month = request.getParameter("month");
String day = request.getParameter("day");
// int로 변환
int yyyy = Integer.parseInt(year);
int mm = Integer.parseInt(month);
int dd = Integer.parseInt(day);
// 2. 처리
Calendar cal = Calendar.getInstance();
cal.set(yyyy, mm - 1, dd);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
char yoil = " 일월화수목금토".charAt(dayOfWeek); // 일요일:1, 월요일:2, ...
// 3. 출력
System.out.println(year + "년 " + month + "월 " + day + "일은 ");
System.out.println(yoil + "요일입니다.");
}
}
파라미터와 함께 링크로 접속하면,
http://localhost:8080/ch2/getYoil?year=2021&month=10&day=1
출력 결과
터미널이 아닌 웹사이트에 출력 결과를 띄우고 싶을때
=> HttpServletResponse의 getWriter() 메서드 사용
✅ setContentType을 "text/html"로, setCharacterType을 "utf-8"으로 지정(한글이 깨지지않도록)한다.
접속 화면
화면에 띄우기 2
이미지 경로 : src - webapp - resources안에 img 폴더 만들기
✅ ctrl+shift+o : 자동 import
프로그램
화면
서버가 제공하는 리소스
정적 리소스
파일형태, 바뀌지 않음 ex).img, .css, .html
동적 리소스
요청할때마다 바뀐다. ex) 프로그램, 스트리밍
랜덤으로 주사위 이미지 6개중 2개가 띄워진다.
클라이언트와 서버
클라이언트와 서버 - 역할에 따른 구분
클라이언트 : 서비스를 요청하는 애플리케이션
서버 : 서비스를 제공하는 애플리케이션
서버의 종류 - 제공하는 서비스에 따른 구분
Email Server, File Server, Web server
✅ 한 대의 PC에 여러개의 서버가 운영될 수 있다. => 서버마다 다른 포트를 할당하여 각각 접근 가능
WAS : 웹 애플리케이션을 서비스 하는 서버
클라이언트와 서버 - 역할에 따른 구분
✅ Thread (그림에서 사람처럼 보이는 것)
✅ Context : 프로그램(java 프로젝트)
✅ Servlet : 작은 서버 프로그램
host/context/servlet
Tomcat 설정 파일 - server.xml, web.xml
톰캣설치경로/conf/server.xml : Tomcat 서버 설정 파일
톰캣설치경로/conf/web.xml : Tomcat의 모든 web app의 공통 설정
웹앱이름/WEB-INF/web.xml : web app의 개별 설정 - 프로젝트마다 존재
Tomcat 설정 파일
위 파일들은 Tomcat의 conf 폴더에 있는 설정 파일의 복사본이다. 하나의 Tomcat 프로그램을 공유하면서
설정만 다른 여러 서버를 등록할 수 있다.
WebApp 설정 파일
아래의 web.xml은 모든 Webapp 공통 설정 파일이고, firstSpring/src/main/webapp/WEB-INF/web.xml은 개별 설정 파일이다.
공통 설정 후 => 개별 설정한다.
최근에는 프로그램 만들때마다 web.xml을 수정하지않고 애노테이션을 이용한다.
Protocol(프로토콜)
- 서로 간의 통신을 위한 약속, 규칙
- 주고 받을 데이터에 대한 형식을 정의한 것
HTTP(Hyper Text Transfer Protocol)이란?
- 텍스트 기반의 프로토콜, 단순하고 읽기 쉽다.
- stateless ( 상태 유지하지않음) : 클라이언트 정보를 저장 X
- 쿠키와 세션으로 보완
- 확장 가능하다. : 커스텀 헤더(header) 추가 가능
요청 - 응답
- URL을 검색하면 브라우저는 요청 메세지를 만들어 서버에 전달한다.
- 서버는 응답 메세지를 만들어 브라우저에 전송한다.
요청 method
GET : 리소스 얻어오기 - body 없음 (쿼리로 소용량의 데이터 전달 - 약 7000자)
POST : 서버에 전송할 data를 body에 보냄 (대용량 전달 가능)
Postman - chrome 확장 프로그램 설치하기
Postman을 이용하면 훨씬 쉽게 요청을 보낼 수 있다.
GET 요청
쿼리로 데이터를 보내지 않고 POST 요청으로 데이터를 보낼 수도 있다.
POST 요청
body로 데이터를 보내도 응답은 같은 것을 알 수 있다.
텍스트와 바이너리, MIME, Base64
텍스트 파일 vs 바이너리 파일
텍스트 파일: 문자만 저장되어 있는 파일
바이너리 파일: 문자와 숫자가 저장되어 있는 파일
✅ 메모장은 Text Editor => 파일을 메모장으로 열 때 깨지면 바이너리 파일, 안깨지고 문자가 존재하면 텍스트 파일
바이너리는 문자와 숫자 각각 쓰고 읽는다.
텍스트는 문자와 숫자 모두 문자로 쓰고, 문자로 읽는다.
텍스트 파일에서 12는 '1' '2' 로 저장된다. (4 byte -> 2 byte)
텍스트 파일에서 12.625f는 '1' '2' '.' '6' '2' '5' 로 저장된다. (4 byte -> 6 byte)
바이너리 데이터를 텍스트 기반 HTTP로 전달하는 방법
1. MIME
2. Base64
MIME(Multipurpose Internet Mail Extensions)
텍스트 기반 프로토콜(ex) HTTP)에 바이너리 데이터를 전송하기 위해 고안되었다.
HTTP의 Content-Type 헤더를 사용하여 데이터의 타입을 명시한다.
response.setContentType("image/jpeg")로 지정하면 보낸 텍스트를 이미지(바이너리)로 인식한다.
이미지(바이너리 파일) 보내기
form-data의 file 형식으로 보낸다.
postman이 만든 메세지
---WebKitFormBoundary는 key를 구분하는 경계선이다.
Request Header 정보 출력하는 프로그램
package com.fastcampus.ch2;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RequestHeader {
@RequestMapping("/requestHeader")
public void main(HttpServletRequest request) {
Enumeration<String> e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = e.nextElement();
System.out.println(name + ":" + request.getHeader(name));
}
}
}
출력 화면
Request Message 출력하는 프로그램
package com.fastcampus.ch2;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RequestMessage {
@RequestMapping("/requestMessage")
public void main(HttpServletRequest request) throws Exception {
// 1. request line
String requestLine = request.getMethod(); // GET 또는 POST
requestLine += " " + request.getRequestURI(); // /ch2/requestMessage
String queryString = request.getQueryString(); // year=2021&month=10&day=1
requestLine += queryString == null ? "" : "?"+queryString;
requestLine += " " + request.getProtocol(); // HTTP/1.1
System.out.println(requestLine);
// 2. request headers
Enumeration<String> e = request.getHeaderNames();
while (e.hasMoreElements()) {
String name = e.nextElement();
System.out.println(name + ":" + request.getHeader(name));
}
// 3. request body - POST일 때만 해당, GET은 body가 없음(CONTENT_LENGTH=0)
final int CONTENT_LENGTH = request.getContentLength();
// System.out.println("content length="+CONTENT_LENGTH);
if(CONTENT_LENGTH > 0) {
byte[] content = new byte[CONTENT_LENGTH];
InputStream in = request.getInputStream();
in.read(content, 0, CONTENT_LENGTH);
System.out.println(); // empty line
System.out.println(new String(content, "utf-8")); // year=2021&month=10&day=1
} // if
} // main
}
출력화면
BASE 64
바이너리 데이터를 텍스트 데이터로 변환할때 사용
64진법은 '0'~'9' (10개), 'A'~'Z' (26개), 'a'~'z' (26개), '+', '/' : 모두 64개(6 bit)의 문자로 구성
Base64 예시
Ma라는 텍스트를 2진수로 표현하여 6 bit씩 자르면 010011 010110 000100 이다.
(자리가 남으면 padding 0으로 채운다.)
‼️ 단점 : size가 커진다.
Ma(16비트) -> 010011 010110 000100(24비트)로 데이터가 늘어난다.
base64 encoder (image to Base64)
https://www.base64encode.net/base64-image-encoder
이미지 변환 예제
1. 이미지 업로드하여 Base64로 변환하기
2. visual studio code 열어서 html 안에 이미지 파일 저장하기
img src에 data:image/jpeg; base64, 를 적고 그 뒤에 base64 값을 붙여넣는다.
3. 브라우저 화면에서 html 보기
이미지를 잘 볼 수 있다.
'Spring > 카테캠 - TIL' 카테고리의 다른 글
TIL [0521] Spring MVC 3 (0) | 2023.05.21 |
---|---|
TIL [0519-0520] Spring MVC 2 (2) | 2023.05.21 |
TIL [0504-0505] : 객체지향 프로그래밍(예외처리, 로그, IO 스트림, 직렬화) (0) | 2023.05.06 |
TIL [0503-0504] : 객체지향 프로그래밍(내부클래스, 람다식, 스트림) (0) | 2023.05.05 |
TIL (0424 - 0429) : 객체지향 프로그래밍 (0) | 2023.04.29 |