9주차 회고
스프링을 이용해 드디어 그럴듯한 웹페이지를 조작할 수 있게 됐다.
자바를 이렇게 쓸 수 있다는게 신기하기도하고.. 감회가 새롭기도하고... '드디어 첫발을 떼는구나!' 이런 느낌이 든다.
오프라인 수업도 집중해서 듣고 있지만 역시 온라인 강의로 보충 내용을 더 듣는게 좋을 것 같다.
스프링은 실습+온라인 강의를 들으면서 개인 공부시간을 활용해야겠다.
9주차 학습 내용
웹 : 리소스 파일을 전달받는 것. 웹 브라우저를 통해 리소스 파일 볼 수 있음.
인터넷: 웹 컨텐츠를 공유하는 인프라
쿠키: 클라이언트 식별기술(<HTTP의 stateless특성 때문에 등장)
세션: 여러 Tx(요청+응답)을 하나로 묶은 것
URL 인코딩과 Base64 인코딩
URL 인코딩: nonAscii 텍스트 -> Ascii 텍스트로 변환 (Ascii: 네트워크계 공용어 느낌) by자동처리-브라우저
Base64 인코딩: 바이너리 데이터 -> 텍스트로 변환 by수동처리-코드넣어야함
=> 이미지를 링크를 통해 외부에서 불러오는 것이 아니라 URL에 직접 넣어버리는 것임
^^) 공유가 쉽다-서버 안거치구, 그냥 URL코드만 있으면 OK
응용) 개인 컨텐츠를 다른 사람과 공유, 다른 사람에게 전달하기.(주식차트, 바둑판, 행운의 편지...)
▷ 행운의 편지 페이지 챗gpt랑 같이 만들어봄 (https://github.com/Seowon-Park/LuckyChainLetter.git)
?왜 바이너리 데이터는 URL인코딩 방식을 안써?
URL길이는 제한이 있기 때문에 간결하게 표현 가능한 Base64인코딩 사용.
URL인코딩은 1byte(0xFF) => %FF(12byte) 방식으로 표현.
-> 순수 바이너리 데이터와 비교하면, 최대 300%의 용량 증가(데이터 1byte 당 3byte를 꼭 차지함)
Base64인코딩은 1byte => 6bit씩 쪼개서 표현 URL인코딩 방식 보다 텍스트 표현 훨씬 간결.
-> 순수 바이너리 데이터와 비교하면, 대략 33%의 용량 증가(데이터 1byte 당 2bit값(과 마지막엔 패딩)이 생기기 때문)
redirect와 forward
?loginController.java에서 return "/home"; 했는데 왜 URL이 /home으로 바뀌지 않았을까?
forward방식으로 처리됐기 때문.
사용자가 보낸 원래 요청(/login)을 유지한 채, 서버 안에서 home.jsp으로 이동 -> 새로 고침할 경우 다시 login화면으로..(반복)
∴ redirect방식으로 처리 필요 => return " redirect: / ";
@RequestMapping(value="/", method=RequestMethod.GET)을 가진 homeController.java에게 작업 맡겨짐.
homeController.java의 메서드 반환이 return "home";이라면 /home으로 URL변경됨
*GET: 갖다 줘.
*POST: 이 데이터 처리해줘.
*2XX:성공 / 3XX:리다이랙션 / 4XX: 너 책임이야(클라이언트) / 5XX: 내 책임이야(서버)
(스프링&DB 관련) 디자인패턴
-스프링 동작 방식-
1. 빈 설정 파일/클래스(@Configuration 등) 을 기반으로 스프링이 시작
2. ApplicationContext 혹은 BeanFactory가 초기화 ← 이때, 설정된 빈(Bean)들을 생성(+의존성 주입)
3. 생성된 빈은 싱글톤(Sigleton)으로 관리&빈 저장소(Map구조)에 객체 캐싱(for 객체 재사용)
4. 사용자는 @Autowired 혹은 생성자등을 통해 빈을 받아서 사용
디자인 패턴 1. 싱글톤 : 객체 1개를 재사용
- 스프링은 기본적으르 빈을 싱글톤으로 관리, 하나의 인스턴스를 여러 곳에서 공유
ex) 서비스 호출, 리포지토리, 상태유지가 필요없을 때
디자인 패턴 2. 플라이웨이트 : 객체 n개를 재사용_(캐싱 사용)
- 객체 공유 방식이 플라이웨이트 패턴과 유사하다고 볼 수 ㅇ
- Map을 통해 객체를 재사용
- 메모리 절약에 도움b
디자인 패턴 3. 프로토타입 : 객체를 복제 clone()
- 객체를 직접 생성x, 기존 객체를 복제해서 새로운 객체를 얻음. 개별 소유
- 동시성 충돌 방지
ex) 폼 객체, 계산용 인스턴스, 사용자 상태 추적용
디자인 패턴 4. Proxy : 같은 옷입히기(같은 인터페이스 구현)
- 인터페이스를 구현하고, 전/후처리를 추가(or 제어) => 메서드 실행 전/후에 코드(Advice)를 삽입
- 실제 객체를 직접 사용x, 프록시를 통해 간접적으로 접근
public class Main {
public static void main(String[] args) {
Service rs = new RealServiceWork1(); //실제 작업1 객체 생성 & 인터페이스 참조변수
Service ps = new ProxyService(rs); //프록시 객체 생성 & 실제 작업1과 연결
ps.doSomething();
}
}
interface Service {
void doSomething();
}
class RealServiceWork1 implements Service { //실제 작업
public void doSomething() {
System.out.println("실제 작업 실행");
}
}
class ProxyService implements Service { //프록시
private final Service realService;
public ProxyService(Service realService) {
this.Service = Service;
}
public void doSomething() {
System.out.println("[Before] 로깅 시작");
realService.doSomething();
System.out.println("[After] 로깅 끝");
}
}
- 스프링의 AOP: 프록시 패턴을 기반으로 동작
ex) 트랜젝션, 로깅
-아래와 같이 서비스를 호출했을때
@Service
public class MyService {
public void doSomething() {
System.out.println("업무 로직 실행 중");
}
}
-스프링에서 내부적으로 자동처리
[Client] → [Proxy(MyService)] → [LoggingAspect의 before()] → doSomething() → [LoggingAspect의 after()]
디자인 패턴 5. 전략 : 가변을 주입(포함). 변경이 필요한 부분은 밖에서 빼서 처리하고 다시 넣는다.
≒ 스테이트 패턴(if문을 밖으로 뺀다!(전략패턴도 비슷함!))
- 알고리즘을 인터페이스로 추상화, 실행 시점에 구체 전략을 선택
ex) 상황에 따라 다른 정책(전략)을 적용해야 할 때, 유저 유형에 따라 다른 동작
public class Main {
public static void main(String[] args) {
MessageService service = new MessageService();
service.setSender(new KakaoSender());
service.sendMessage("안녕! 카카오톡!"); // 카카오톡으로 보냄
service.setSender(new EmailSender());
service.sendMessage("메일입니다!"); // 이메일로 보냄
}
}
public interface MessageSender {//전략 인터페이스(메신저 플랫폼)
void send(String message);
}
public class KakaoSender implements MessageSender {//전략 구현체1. 카카오톡
public void send(String message) {
System.out.println("카카오톡으로 보냄: " + message);
}
}
public class EmailSender implements MessageSender {//전략 구현체2. 이메일
public void send(String message) {
System.out.println("이메일로 보냄: " + message);
}
}
public class MessageService {//전략 서비스
private MessageSender sender; // 전략을 담을 필드
public void setSender(MessageSender sender) { // 전략을 선택하는 메서드
this.sender = sender;
}
public void sendMessage(String message) {
sender.send(message); // 선택된 전략을 실행
}
}
디자인 패턴 6. 커맨드 : 타입을 command로 추상화해서 모든 타입의 객체를 가리킬 수 o. -> 명렬을 묶는다
≒ 컴포짓 패턴 -> 대상을 묶는다
- 다형성 이용한 패턴
- 준비물
명령(Command) 추상화-(구현)-> 기능 동작(ConcreteCommand)
실행을 위임하는 호출자(Invoker)-리모컨/
수신자(Receiver)-전등
- 작동 원리
1) Command 인터페이스를 기능 동작 클래스들이 구현
2) 기능 동작을 Command로 다룸
3) 리모콘은 command를 받고 excute()를 진행할 뿐(기능이 command를 구현했나만 고려)
import static java.lang.System.out;
public class CommandPatern {
public static void main(String[] args) {
RemoteControl remote = new RemoteControl();//리모컨 생성
Light light = new Light(); // Light 객체 생성
Command lightOn = new LightOnCommand(light);//lightOn 동작과 light 객체 연결
Command lightOff = new LightOffCommand(light);//lightOff 동작과 light 객체 연결
remote.setCommand(lightOn);//리모컨 객체와 lightOn 동작 연결
remote.pressButton(); //리모컨: 버튼누름 -> Command excute()를 구현한 lightOn의 excute()실행 -> light의 on()실행
remote.setCommand(lightOff);// 리모컨 객체와 lightOff 동작 연결
remote.pressButton();//리모컨: 버튼누름 -> Command excute()를 구현한 lightOff의 excute()실행 -> light의 off()실행
}
}
//receiver: 실제 명령 수행
class Light{
public void on(){
out.println("불을 켭니다");
}
public void off(){
out.println("불을 끕니다.");
}
}
//Command 인터페이스 -- 구현 명령의 상위격
interface Command{
void execute();
}
//ConcreteCommand: 실제 명령 구현
class LightOnCommand implements Command{
private Light light; //수신자
public LightOnCommand(Light light){
this.light = light;
}
public void execute(){
light.on(); //수신자한테 실제 행동 위임
}
}
class LightOffCommand implements Command{
private Light light;
public LightOffCommand(Light light){
this.light = light ;
}
public void execute(){
light.off();
}
}
//Invoker: 명령 받으면 execute()호출만함 - 그 명령이 무슨 명령인지는 몰라
class RemoteControl{
private Command command;
public void setCommand(Command command){
this.command = command;
}
public void pressButton(){
command.execute();
}
}
- 배열(같은 타입의 객체)과 사용하는 경우 多
=> [DB] undo(롤백), redo(복구)에서 쓰임)
?전략패턴과 커맨드패턴 같은거 아냐?
둘 다 인터페이스 + 구현체 + 실행 클래스 구조. 다형성 활용. 객체를 통해 행동(메서드 실행)을 캡슐화.
-차이점-
▶전략패턴 "메시지를 어떤 방식으로 보낼까?"
전략을 사용하는 컨텍스트 객체가 직접 메서드를 호출. 전략에 따라 동작이 바뀜 (플러그 교체 느낌)
▶커맨패턴 "명령 객체 연결하고, 그냥 버튼 누르면 기능이 작동해~"
Invoker(명령 호출자)가 execute()만 호출하고 내부는 모름. 명령을 객체로 만들어 저장, 재사용 가능
'개발 일지 > 주차별 학습일지' 카테고리의 다른 글
| [커널아카데미] 백엔드 12기 15주차 - 주변을 객체 모델링 해보자! (0) | 2025.07.05 |
|---|---|
| [커널아카데미] 백엔드 12기 13주차 - 쇼핑몰 웹페이지 구상 & 초안 (0) | 2025.06.17 |
| [커널아카데미] 백엔드 12기 8주차 - SQL모델링_영화관 예약 시스템 (0) | 2025.05.16 |
| [커널아카데미] 백엔드 12기 7주차 - 데이터 모델링/SQL튜닝 (1) | 2025.05.09 |
| [커널아카데미] 백엔드 12기 6주차 - SQL / 데이터 모델링 시작 (1) | 2025.05.02 |