Spring (스프링)
유용한 명령어
# 8080 포트를 사용하는 프로세스 찾기
netstat -ano | findstr 8080
# 특정 PID 프로세스 강제 종료
taskkill /f /pid [프로세스번호]
스프링이란?
스프링(Spring)은 Java 기반의 엔터프라이즈 애플리케이션 개발을 위한 오픈소스 경량급 프레임워크입니다.
학습 관점
- 처음 배우는 사람: 복잡한 환경설정에 압도당할 수 있음
- “스프링의 절반은 환경설정”이라는 말이 있을 정도
- JSP를 충분히 경험한 사람: 간결함에 감탄하게 됨
- 복잡한 JSP 코드를 간단한 설정으로 대체할 수 있다는 것을 깨닫게 됨
- 💡 스프링의 진정한 위력은 JSP 프로젝트를 충분히 경험한 후에야 이해할 수 있다
이름의 유래
기존의 EJB(Enterprise Java Bean)로 대표되는 무겁고 복잡한 Enterprise Framework의 시대를 “겨울”로 정의하고,
이제 가볍고 유연한 “봄(Spring)”이 왔다는 의미를 담고 있다.
스프링의 역사
탄생 (2002-2004)
- 2002년: 로드 존슨(Rod Johnson)이 저서 『Expert One-on-One J2EE Design and Development』를 출판
- 책에는 약 3만 줄의 예제 코드가 포함됨
- EJB의 복잡성을 비판하고 더 나은 접근 방식을 제시
- 개발자들이 열광하며 “데모로 끝내기에는 너무 아깝다”는 반응
- 오픈소스 프로젝트로 발전하여 여러 개발자들이 참여
- 2004년: Spring Framework 1.0 정식 릴리즈
성장
- 2004년: SpringSource 회사 창업
- 2009년: VMware에 인수
- 2013년: Pivotal Software로 분사
- 2019년: VMware가 Pivotal 재인수
- 현재: 전 세계에서 가장 많이 사용되는 Java 프레임워크
스프링의 본질
Why가 중요하다
“How”가 아니라 “Why”를 이해하는 것이 핵심이다.
- 스프링 API를 잘 사용하는 것보다
- 왜 스프링을 만들었는가? 핵심 컨셉이 무엇인가를 이해하는 것이 훨씬 중요하다
핵심 철학
스프링은 Java의 객체지향 프로그래밍(OOP)의 특징과 장점을 최대한 살려내는 프레임워크다.
즉, 객체지향적 프로그래밍을 하도록 도와주는 프레임워크다.
핵심 키워드:
- POJO (Plain Old Java Object)
- IoC/DI (Inversion of Control / Dependency Injection)
- AOP (Aspect Oriented Programming)
- PSA (Portable Service Abstraction)
왜 스프링을 배워야 하는가?
참고: 왜 스프링인가?
산업 표준이기 때문
- 기업의 채용 조건
- Java 백엔드 개발자 채용 시 거의 필수 요구사항
- 국내 기업 대부분이 Spring 기반 시스템 운영
- 전자정부 프레임워크
- 공공기관, 지방자치단체에서 표준으로 사용
- Spring Framework를 기반으로 구축됨
기업이 스프링을 선택하는 이유
한 줄 요약:
제한된 자원(개발자, 시간, 돈)으로 엔터프라이즈급 애플리케이션을 여러 명이 협업하여 개발하기에 가장 적합한 프레임워크
상세 이유:
- 경량급이면서 강력함
- Java 엔터프라이즈 개발을 편하게 해주는 오픈소스 프레임워크
- 필요한 기능만 선택적으로 사용 가능
- 성숙한 생태계
- 이미 검증된 수많은 라이브러리와 솔루션
- 인력 구하기 용이 (네트워크 효과)
- 풍부한 문서와 커뮤니티
- 근본적 문제 해결
- 단순히 도구나 기능을 제공하는 차원이 아님
- 엔터프라이즈 애플리케이션 개발의 근본적인 문제점에 도전하여 해결책 제시
장단점
✅ 장점
- 코드 간결화
- XML, 어노테이션을 통한 설정으로 보일러플레이트 코드 감소
- 핵심 비즈니스 로직에 집중 가능
- 반복 작업 최소화
- 데이터베이스 연결, 트랜잭션 관리 등 자동화
- 공통 관심사(Cross-cutting concerns)를 AOP로 처리
- 효율적인 프로젝트 관리
- 명확한 계층 구조와 역할 분리
- 표준화된 개발 방식
- 협업 용이성
- 여러 개발자가 동시에 작업하기 좋은 구조
- 모듈화된 설계로 의존성 관리 용이
⚠️ 단점
- 높은 초기 학습 곡선
- 프로젝트 세팅이 다소 복잡
- 충분한 연습과 경험이 필요
- 개념 이해 필수
- IoC, DI, AOP 등 핵심 개념을 제대로 이해하지 못하면
- 코드 분석조차 어려울 수 있음
- 과도한 추상화 가능성
- 잘못 사용하면 오히려 복잡도 증가
- 적절한 수준의 설계가 중요
JSP/Servlet vs Spring
이해의 핵심
- 프레임워크를 쓰면 무엇이 좋은지
- 여러 프레임워크 중 스프링이 무엇이 좋은지
이 두 가지를 이해하면 된다.
비유로 이해하기
- JSP: 자연에서 재료를 구해 직접 집을 짓는 것
- Spring: 현대식 건축 기법과 공구를 활용해 집을 짓는 것
또는
- JSP: 도시를 구축하는 것
- Spring: 국가 전체를 체계적으로 구축하는 것
핵심 차이
스프링의 완전함:
- 엔터프라이즈급 개발에 필요한 도구가 거의 다 갖춰져 있음
- JSP로 개발한다면 이러한 도구들을 직접 만들어야 함
Spring이 제공하는 주요 기능들
1. Framework로서의 장점
- 코드 품질 보장
- 프레임워크의 규칙을 따라야 하므로 나쁜 코드가 되기 어렵다
- 코드가 자연스럽게 객체지향 설계 원칙을 따르도록 강제
- 표준화
- 표준화로 인한 품질 향상
- 의사소통 원활: 정해진 위치, 정해진 이름
- 다른 사람이 만든 코드 분석이 쉬워짐
- 구인/구직 용이
2. MVC 패턴 지원
관심사의 분리:
- View (JSP): 화면 담당
- Controller (Java): 요청 처리
- Model (Java): 비즈니스 로직
- Static 리소스: CSS, JS 분리
JSP의 문제점 해결:
// ❌ JSP에서의 HTML 출력 (가독성 최악)
out.print("<tr><td>" + id + "</td><td>");
// ✅ Spring에서는 View와 완전 분리
return "userList"; // View 이름만 반환
- PrintWriter 생성 등의 중복 코드 제거
- HTML과 Java 코드의 명확한 분리
3. Maven/Gradle – 의존성 관리
라이브러리 관리 혁신:
- 라이브러리 파일 자체를 프로젝트에 포함하지 않음
pom.xml(Maven) 또는build.gradle(Gradle)만 공유- 필요한 라이브러리를 자동으로 다운로드 및 관리
4. Spring Security
인증/인가 자동화:
- 회원가입, 로그인 화면 제공
- 세션 체크 자동화
- 권한 체크 (Role-based Access Control)
- 비밀번호 암호화 (BCrypt 등)
- CSRF, XSS 등 보안 취약점 방어
5. MyBatis (Persistence Framework)
데이터베이스 연동 간소화:
- 소스 코드 양 약 62% 감소
- 복잡한 JDBC 코드 제거
- SQL 변경 시 재컴파일 불필요
- 쿼리와 Java 코드 분리 → 역할 분리, 유지보수성 향상
- Connection 관리 자동화
MyBatis 사용 예시:
<!-- ❌ JSP/Servlet: JDBC 코드 -->
<!-- Connection, PreparedStatement, ResultSet 관리 등 수십 줄 -->
<!-- ✅ MyBatis: XML로 쿼리만 작성 -->
<select id="getUserById" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
6. AOP (Aspect Oriented Programming)
횡단 관심사 분리:
- 주된 비즈니스 로직이 아닌 부가 기능을 분리
- 코드 중복 제거
사용 예시:
- 모든 Service 메서드의 실행 시간 측정
- 모든 Controller의 요청/응답 로깅
- 트랜잭션 관리
- 보안, 캐싱 등
// AOP 없이: 모든 메서드에 시간 측정 코드 추가 필요
public void saveUser(User user) {
long start = System.currentTimeMillis();
// 실제 비즈니스 로직
long end = System.currentTimeMillis();
log.info("실행 시간: " + (end - start) + "ms");
}
// AOP 사용: 어노테이션 하나로 해결
@LogExecutionTime
public void saveUser(User user) {
// 실제 비즈니스 로직만 작성
}
7. Transaction Management
트랜잭션 자동 관리:
- 설정(또는 어노테이션)만으로 트랜잭션 처리
- JSP에서는 commit, rollback 등을 수동으로 작성
트랜잭션 예시: 계좌 이체
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
// 1. 출금 계좌에서 차감
accountRepository.withdraw(fromId, amount);
// 2. 입금 계좌에 추가
accountRepository.deposit(toId, amount);
// 둘 중 하나라도 실패하면 자동 rollback
}
8. Interceptor
요청/응답 전처리:
- Controller 호출 전후에 요청과 응답을 가공
- 로그인 체크, 권한 체크 자동화
- 로깅, 인코딩 처리 등
JSP와의 차이:
- JSP: 각 화면마다 절차적으로 체크 코드 작성
- Spring: 객체지향적으로 Interceptor 한 곳에서 관리
9. ORM (Object-Relational Mapping)
- JPA/Hibernate: 쿼리 없이 객체로 DB 제어
- SQL을 Java 코드로 추상화
- 데이터베이스 벤더 독립적
10. 기타 엔터프라이즈 기능
- Batch Processing: 대용량 데이터 처리
- WebSocket: 실시간 양방향 통신
- Task Scheduling: 스케줄링 작업
- Email: 메일 발송
- File Upload/Download: 파일 처리
💎 Spring의 핵심: DI/IoC
가장 핵심은 DI/IoC를 통한 제어의 역전이다.
자동차 비유로 이해하기
전통적인 방식 (IoC 없이):
- 자동차를 만들 때 그 안에서 바퀴를 만들고, 핸들을 만들고, 엔진을 만든다
- 자동차가 어떤 바퀴를 쓸지, 어떻게 만들지 모두 알고 있어야 함
- 바퀴를 교체하려면 자동차 전체를 수정해야 함
Spring 방식 (IoC 사용):
- 이미 만들어진 바퀴, 핸들, 엔진을 자동차에 조립
- 자동차는 “바퀴가 필요해”라고만 말하면 됨
- Spring Container가 적합한 바퀴를 찾아서 주입(inject)해줌
- 바퀴 교체가 필요하면 설정만 바꾸면 됨
Spring이 제공하는 것:
- 부품들을 담아둘 수 있는 컨테이너 (ApplicationContext)
- 컨테이너에 쉽게 올리는 방법 (@Component, @Bean 등)
- 컨테이너에서 쉽게 가져다 쓰는 방법 (@Autowired, 생성자 주입 등)
레고 비유로 이해하기
🔴 DI/IoC 미사용: 내가 직접 레고 찾기
상황:
- 레고 성을 만들려면 성벽, 성문, 깃발 블록이 필요
- 내 가방(코드) 안에서 직접 블록들을 찾아서 가져와 조립해야 함
문제점:
- 성문 블록을 강화 성문으로 바꾸고 싶다면?
→ 가방을 뒤져서 직접 교체하고, 연결 부위도 다시 맞춰야 함 - 매우 번거롭고 실수하기 쉬움
🟢 DI/IoC 사용: 레고 장인이 가져다주기
상황:
- 레고 장인(Spring IoC Container)에게 “성을 만들고 싶으니 성벽, 성문, 깃발 좀 주세요” 요청
- 장인이 부품 통에서 가장 좋은 블록들을 가져와 건네줌(주입)
장점:
- 강화 성문이 필요하면?
→ 장인에게 “이제부터 성문은 강화 성문으로 만들어 주세요”라고 말만 하면 됨 - 다음부터 자동으로 강화 성문을 가져다줌
- 매우 편리!
핵심 개념 정리
IoC (Inversion of Control, 제어의 역전)
내가 필요한 부품(객체)을 직접 만들고 관리하던 제어권이 Spring Container에게 넘어감
DI (Dependency Injection, 의존성 주입)
Spring Container가 내가 필요로 하는 부품(의존성)을 알아서 넣어줌
코드 예시: 자동차 경주 게임
자동차 경주 게임에서 Game 클래스가 Car를 이용해 경주하는 상황을 가정해 보겠습니다.
👎 DI/IoC를 사용하지 않았을 때
Game 클래스가 어떤 Car를 사용할지 직접 결정하고 생성해야 합니다.
// 1. 자동차 인터페이스와 구현체들
interface Car {
void drive();
}
class SportsCar implements Car {
@Override
public void drive() {
System.out.println("스포츠카가 엄청난 속도로 달립니다!");
}
}
class Truck implements Car {
@Override
public void drive() {
System.out.println("트럭이 묵직하게 달립니다!");
}
}
// 2. 게임 클래스
public class Game {
private Car car;
public Game() {
// 문제점 1: Game 클래스가 '어떤 차'를 쓸지 직접 결정하고 생성한다.
// 'SportsCar'라는 구체적인 클래스에 의존하고 있다.
this.car = new SportsCar();
}
public void run() {
System.out.println("경주를 시작합니다!");
car.drive();
}
public static void main(String[] args) {
Game game = new Game();
game.run();
}
}
실행 결과:
경주를 시작합니다!
스포츠카가 엄청난 속도로 달립니다!
이 코드의 문제점 (얼마나 고생할까?):
- 높은 결합도: Game 클래스는 SportsCar라는 특정 클래스와 강하게 묶여있습니다.
- 유연성 부족: 만약 경주에 Truck을 사용하고 싶다면? Game 클래스의 생성자 코드를 this.car = new Truck();으로 직접 수정하고 다시 컴파일해야 합니다. 게임에 새로운 종류의 차가 100개 추가된다면, Game 클래스는 100번 수정되어야 할 수도 있습니다.
- 테스트의 어려움: Game 클래스를 테스트하려면 항상 실제 SportsCar 객체가 필요합니다. 만약 SportsCar가 데이터베이스 연결 같은 복잡한 로직을 포함한다면, 간단한 run() 메소드 하나 테스트하기가 매우 까다로워집니다.
👍 DI/IoC를 사용했을 때 (레고 장인이 가져다주기)
이제 “레고 장인”, 즉 스프링의 IoC 컨테이너를 도입해 보겠습니다.
- 설정 파일 (레고 장인에게 부품 만드는 법 알려주기)
먼저 스프링에게 어떤 부품(객체, Bean)들을 만들고 관리해야 할지 알려줍니다.// Spring 설정 클래스 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration // “이 클래스는 스프링의 설정 파일(레고 조립 설명서)입니다.”
public class AppConfig {
@Bean // "이 메소드가 반환하는 객체를 스프링이 관리해주세요(부품 통에 넣어주세요)."
public Car car() {
// 여기서 어떤 차를 경주에 내보낼지 결정!
return new SportsCar();
// return new Truck(); // 트럭으로 바꾸고 싶으면 이 부분만 수정하면 끝!
}
@Bean
public Game game() {
// "Game 객체를 만들 때, 위에서 만든 car() 부품을 '주입'해주세요."
return new Game(car());
}
}
2. 수정된 게임 클래스
Game 클래스는 더 이상 자동차를 직접 만들지 않습니다. 그저 외부에서 만들어진 것을 받기만 합니다.
```Java
// 수정된 Game 클래스
public class Game {
private final Car car; // 이제 final로 선언 가능 (불변성 확보)
// 생성자를 통해 외부에서 Car 객체를 '주입' 받는다!
public Game(Car car) {
this.car = car;
}
public void run() {
System.out.println("경주를 시작합니다!");
car.drive();
}
}
- 실행 클래스 (스프링 컨테이너 사용)
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
// 1. 스프링 IoC 컨테이너(레고 장인)를 생성한다. 설정 정보(AppConfig)를 알려준다.
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 2. 컨테이너에게 "game"이라는 이름의 객체(Bean)를 달라고 요청한다.
Game game = context.getBean("game", Game.class);
// 3. 게임 실행
game.run();
}
}
실행 결과:
```Plain Text
경주를 시작합니다!
스포츠카가 엄청난 속도로 달립니다!
이 코드의 장점 (얼마나 편리해졌나?):
- 낮은 결합도: Game 클래스는 SportsCar나 Truck의 존재를 전혀 모릅니다. 오직 Car라는 인터페이스(규칙)에만 의존합니다.
- 엄청난 유연성: 경주에 Truck을 내보내고 싶다면? AppConfig 파일의 car() 메소드만 return new Truck();으로 바꾸면 됩니다. Game 클래스 코드는 단 한 줄도 건드릴 필요가 없습니다. 부품을 교체하기가 매우 쉬워졌습니다.
- 쉬운 테스트: Game 클래스를 테스트할 때, 실제 Car 객체 대신 가짜 Car 객체(Mock Object)를 생성자에 쉽게 주입하여 테스트할 수 있습니다.
결론
- DI/IoC가 없으면: 객체들이 서로를 직접 생성하고 의존하여, 마치 접착제로 붙인 레고처럼 단단하게 굳어버립니다. 변경이 어렵고 재사용이 힘들어집니다.
- DI/IoC가 있으면: 외부의 조립자(Spring IoC 컨테이너) 가 부품(객체)들을 관리하고, 필요할 때마다 끼워 넣어(주입) 줍니다. 덕분에 각 부품은 독립적으로 존재할 수 있고, 언제든지 쉽게 교체할 수 있는 유연한 구조가 됩니다.
이것이 바로 스프링이 DI/IoC를 통해 개발자에게 느슨한 결합(Loose Coupling) 과 높은 유연성이라는 강력한 무기를 제공하는 방법입니다.
- 이 예시를 보면 의문이 들어야 한다. 아니 이것도 어쟀든 AppConfig.java를 수정하고 다시 컴파일 해야하는것 아닌가? 맞다. 이건 사실 제대로된 예제가 아니라 application.properties 같은 자바코드가 아닌 외부에서 결정하게 하여야 제대뢴 코드다.
이렇게 보듯이 개발자가 신경써야 할 비지니스 ‘본질’에 집중할 수 있게 해주고
나머지는 스프링이 알아서 처리해준다.
이러고도 피부에 와닿지 않는다면 이때까지 한것이 본질만 만들었고 본질을 하기위한 부수적인 것들을 안만들어서, 그리고 규모있는 프로젝트를 협업으로 안해봐서 그렇다.
계속된 간접경험과 상상을 해야한다.
3개만 만들던것을 300개를 만들어야 하면 어떨까 이런식으로.
5명이 팀원이였는데 50명이 팀원이 되면 어떨까
따라하기 좋은 사이트
김밤파
공부하기 좋은 사이트 캣츠비
sts실행시 에러뜨면 .ini파일의 -vm 설정.
- 환경설정 따라하기
- 스프링을 왜쓰는지
- 이클립스, STS3, STS4 의 차이는?
- STS3 설치 에러나는사람은 환경변수세팅잘못(사용자변수에 했다든지), 경로가 너무 길든지, -vm 문제
- ojdbc란 무엇인지, 어떤버전의 ojdbc를 쓸건지 어떻게 판단하는지
- 스프링환경세팅을 한다는것은 무엇을 세팅한다는것인지
- maven은 무엇인지. 빌드툴. 빌드란 무엇인지.
- pom.xml에 라이브러리 설정을 해놓으면 그 라이브러리가 어떻게 내 프로젝트에 추가되는지
- 커넥션풀(hikariCP)이 뭔지
- 로거(log4j같은 라이브러리)를 왜쓰는지
- mybatis를 왜쓰는지
- 그 각각을 junit테스트 가능
-
따라하면서 유의해야될점
- log4jdbclog4jdbc.log4j2.properties 파일 이름 잘못됨. 중복된 앞의 log4jdbc 빼주기
- 오라클 11로 실습할때는 시퀀스 사용, vo부분에서 롬복 사용, mybatis 플러그인 설치해서 xml생성
- com.sql.date(일까지) 와 java.util.date(더 디테일) 다르다.
블로그는 java.util.date선택 - log4j import할때 slf4j꺼 선택.
- list.jsp의 결과 alert할때 return오타있음
- list.jsp에서 제목 클릭했을때 url에 bno만 호출되는 경우는 그 위의 자바스크립트 코드가 잘못됐을 확률이 매우 높음
- db에서는 잘되는데 mybatis 테스트에서 안나온다면 commit 확인
- get(상세보기)에서 목록버튼 안누르고 뒤로가기 누르면 bno가 누적되고 첫번째 bno로 먹힘.
=> .move 클릭했을때 실행하는 본문에 추가.
let nameEle = $(“input[name=bno]”);
nameEle.remove(); //제이쿼리로 dom삭제 - 페이징
Index로 실행계획볼때 오히려 cost가 많은건 현재데이터가 너무 작기 때문. 색인 설명
Criteria에서 기준을 설정하고 기준과 화면에서 넘어온 데이터로 페이징을 계산해서 PageMakerDTO에 저장.
컨트롤러에서 int total = bservice.getTotal(); 를 보면 알겠지만 한번 db에 접속해서 총 글의 갯수를 가져온다.
그리고 PageMakerDTO pageMaker = new PageMakerDTO(cri, total); 를 통해서 현재페이지, 한페이지당 보여줄글의갯수, 총 글의수 3개의 데이터를 가지고 어떻게 페이지를 보여줄지 계산하는 역할
페이지 계산부분알고리즘은은 몇개 대입해보면 수능 수리 3등급정도면 이해할수있다.
그정도 수학사고력이 안추어져있으면 이해보다 주입식이 효율적이다.
직접 연습장끄적거려가면서 계산식을 해봐야 깨닫는다. - 페이징에서 수정완료후 그페이지 유지되는 설명과 구현이 없어서 알아서 함.
modify.jsp에서 input hidden으로 pageNum, amount2개 넣고
컨트롤러 post modify에서 rttr.addFlashAttribute(“cri”, cri);
return “redirect:/board/list?pageNum=”+cri.getPageNum();
역사와 배경
- 스프링 공식 사이트의 한줄 소개
Spring makes it easy to create Java enterprise applications.
It provieds everything you need to embrace the Java language in an enterprise environment.
자바 엔터프라이즈 애플리케이션 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크- 엔터프라이즈 애플리케이션은 뭔가?
서버에서 동작하며 기업과 조직의 업무를 처리해주는 시스템. - 대규모의 복잡한 데이터를 관리하고, 이러한 데이터를 이용해 비지니스 프로세스의 지원 및 자동화를 제공한다.
- 비지니스의 근간으로 보안과 안정성, 확장성이 뛰어나야 한다.
- 다수의 사용자가 접근하며 기업내 분산된 다른 엔터프라이즈 애플리케이션과 통합된다.
- 데이터 입출력을 위한 다양한 사용자 인터페이스가 제공된다.
- 엔터프라이즈 앱의 예: 고객서비스, 공급망, 인사, 회계, 보험, 외환거래, 환자기록, 배송추적
- 엔터프라이즈가 아닌 앱의 예 : 운영체제, 게임, 워드프로세서, 공장자동화, 승강기제어
- 경량급이라는건 뭔가?
스프링 자체가 가볍다는 말이 아니다. 스프링은 20여개가 넘는 모듈로 세분화되고 수십만 라인에 달하는 코드를 가진 매우 복잡한 프레임워크다. 그럼에도 가볍다고 하는 이유는 불필요하게 무겁지 않다는 말이다. - 엔터프라이즈 에디션 자바 (Java EE)
- 엔터프라이즈 애플리케이션에 필요한 확장성, 신뢰성, 보안성 등을 제공하는 자바 플랫폼이자 프레임워크
- 대규모, 네트워크, 다계층 애플리케이션을 더 쉽고 안전하고 탄탄하게 구축할 수 있도록 설계됨
- 웹을 통한 UI, 시스템통합을 위한 리모팅, 선언적 트랜잭션 처리 등 전체 애플리케이션 스택을 제공한다.
- 다양한 자바 명세 요청서를 바탕으로 작성된 표준 API 모음이다.
- 자바 EE서버는 2가지로 나뉜다.
- 웹 모듈만 배포가능한 경량급 WAS를 서블릿 컨테이너라고 부른다.
- 자바EE의 모든 표준을 지원하고 다양한 모듈로 배포가 가능한 완전한 WAS
- ※2018년 JavaEE는 오라클에서 이클립스 재단으로 이관된 후 Javarta EE 라는 새 이름을 받았다.
- 엔터프라이즈 애플리케이션은 뭔가?
- 기본 흐름이나 구조가 정해져있기 때문에 개발자들의 실력의 차이를 좁힐수있고 의사소통이 효율적이다. 반쯤 완성한 상태에서 필요한 부분을 조립하는 형태의 개발. 개발자가 다루기 어려운 저수준의 기술에 많은 신경쓰지 않도록 해줌
- 스프링이 살아남은 이유
- 기존 EJB로 대표되는 복잡한 프레임워크에 반기를 들며 등장한 경량화된 프레임워크
- 특정 한 분야가 아니라 전체 구조를 다루는 프레임워크이므로 다른 프레임워크를 포용하여 혼용사용 가능
- 개발 생산성과 개발도구의 지원
- 스프링 공부
- 스프링컨테이너(애플리케이션 컨텍스트)를 다루는 방법과 설정정보를 작성하는 방법을 익혀야한다.
- 기본구조가 만들어져있는것을 사용하는것이기 때문에 설정이 반이다.
- 스프링을 사용한다는것은 다음3가지를 적극적으로 사용해서 애플리케이션을 개발한다는 뜻이다.
- 애플리케이션의 기본틀(스프링 컨테이너)
- 공통 프로그래밍 모델 (IoC/DI, 서비스추상화, AOP)
- 기술 API
-
개발환경 설치
- JDK //windows 64bit installer
- IntelliJ 또는 STS (무료버전에서는 스프링 연동 안된다)
- tomcat
-
개발할때 지향해야할 방향
- 느슨한 결합(약한 의존성) 나를 바꿀때 다른놈을 안바꿔도 되도록. 인터페이스의 사용.
- 높은 응집도. 관심사들끼리 묶이도록.
-
스프링강의
- T아카데미
- T아카데미 Honeymon
- 뉴렉처
- Kenu Heo
- 김지헌님. 특히 스프링부트
- 토비
- 김영한님(배민 개발팀장) 스프링 입문 – 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
- 백기선
-
스프링
-
스프링의 핵심철학
back to basic. 객체지향 프로그래밍이 제공하는 폭넓은 혜택을 누릴 수 있도록 기본으로 돌아가자. 그래서 가장 관심을 많이 두는 대상이 ‘오브젝트(객체)’다.
오브젝트의 생성, 다른오브젝트와 관계, 사용, 소멸 까지의 전과정을 진지하게 생각해볼필요가 있다. 나아가 어떻게 설계되어야 하는지.
그래서 재활용 가능한 설계방법인 디자인패턴, 리팩토링, 단위테스트 같은 여러가지 응용기술지식이 요구된다. - 2004년 3월 1차버전 출시 이후 20여년동안 자바 엔터프라이즈 어플리케이션 개발 부동의 1위 프레임워크
- 20여가지의 모듈이 있고 필요한것만 선택하여 사용가능. (부트, 클라우드, 데이터, 배치, 시큐리티가 주요한 모듈)
- 스프링의 탄생배경 : 테스트 용이성, 느슨한 결합
-
복잡성을 다루기 위한 스프링의 전략
- 비지니스 핵심코드와 엔터프라이즈 기술을 처리하는 코드를 분리
- POJO와 함께 스프링3대 핵심기술을 사용
- 이 전략이 효과적으로 적용되려면 반드시 좋은 객체지향 설계가 바탕이 되어야한다.
- 스프링 프레임워크는 수십개의 모듈로 나뉘어져 있다.
예) Sporing JDBC, Sporing MVC, Sporing AOP, Sporing ORM, Sporing Test, Sporing Security
-
-
POJO
- Plain Old Java Object. 순수자바 오브젝트. 2000년 마틴파울러가 컨터런스 준비과정에서 만든 용어
- 객체지향적 원리에 충실하고 특정 환경에 종속되지 않게 재활용될수있는 방식으로 설계된 객체
- ‘객체’에 애플리케이션의 핵심 로직을 담아 설계, 개발하는 방법을 POJO 프로그래밍이라 한다.
- 특정 라이브러리나 컨테이너의 기술에 종속적이지 않도록 순수 자바만 사용하여.
- 자동화된 테스트에 유리하며 유지보수성이 높다.
- EJB를 많이 사용하던 시절에서는 EJB에 종속적이게 개발이 진행되었다. 그로인해 모듈의 교체나 시스템 업그레이드시 종속성대문에 불편함이 발생하였다.
그래서 다시 기본 자바로 돌아가자는 움직임이 나타났다. - 특정 규약이나 환경에 종속되지 않는다. HTTP, SESSION등을 사용하는것도 POJO를 위반하는것이다. 순수 자바로만 할수있는것이 POJO다.
설정
.xml과 java파일 2개로 설정을 할 수 있다. xml로 설정하는것은 구식방법
자바코드로 하던것을 스프링에서는 설정파일이 많이 갖고간다. 스프링은 설정이 반.
xml에서 문자열은 “도 되고 ‘도 된다.
pom.xml
maven이 의존성관리하는 설정파일. mvnrepository 사이트에서 갖고오면 된다.
<properties> 안에 <org.springframework-version>4.3.25.RELEASE</org.springframework-version> 이런식으로 쓰면 다른 라이브러리에서 ${} 달러 중괄호로 변수처럼 사용할 수 있다. <version> ${<org.springframework-version>} </version>
자바에서 xml파일 로딩하는법, xml로 빈 관리하는 깨달음. ioc컨테이너의 이해
- 설정파일 만들기
<bean id='hello' class='풀패키지명' /> - 설정파일 자바로 가져오기
- 설정파일이 패키지 내부에 있을 경우
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("풀패키지경로"); ctx.close();했을때 아무메세지가 없으면 잘 로딩된 것. 에러가 뜨면 잘못된 것
<설정파일이 패키지 외부에 있을 경우>
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(“경로”);
- 설정파일이 패키지 내부에 있을 경우
- 설정파일안에있는 빈 객체 사용하기
클래스명 인스턴스명 = (형변환)ctx.게터메서드("빈아이디"); 또는 클래스명 인스턴스명 = ctx.게터메서드("빈아이디", 클래스명.class);
본인 스타일에 맞게 편한거 쓰면된다.
- 객체를 변경할때 인터페이스를 썼다면 설정파일하나만 건드리면 자바코드 하나도 건드릴거없이 다 바뀐다.
slf4j, logback
이 2개 넣어서 로그부터 빨리 세팅하고 개발하자.
scope가 runtime이면 실행 중에 로그를 볼 수 있다.
스프링 vs 스프링부트
- 스프링부트
- 스프링의 최대 단점인 프로젝트를 세팅하는데 너무 많은 시간이 걸리는 것을 해결하고자하는 스프링의 확장판. 버전과 호환성을 스프링이 직접 관리하여 그 문제를 해결했다.
- 스프링과의 차이점
- 내장 톰캣 사용
- starter를 통한 dependency자동화
- xml설정 안해도됨
- jar를 이용한 손쉬운 배포
- 스프링부트는 어노테이션 기반으로 작동. @SpringBootApplication이 스프링부트의 마법이 시작되는 곳.
- 스프링 버전
2014.04.01 스프링부트1.0 출시
2018.03.01 스프링부트2.0 출시
스프링2.5 : 어노테이션 도입
스프링3.0 : 별도설정없이 자바클래스만으로 설정 파일 대신
스프링4.0 : 모바일환경과 REST방식의 컨트롤러 지원
스프링5.0 : 리엑트 스타일의 개발 환경 지원
pivotal이 스프링부트의 개발을 주도하는 업체 - 스프링부트의 특징
- 단독실행 가능한 스프링 애플리케이션 생성
- 간단하게 실행할수 있으며 프로덕션(상용) 제품수준의 애플리케이션을 쉽게 만들 수 있다.
- 내장 컨테이너로 톰캣, 제티, 언더토우 중에서 선택가능
- 스타터를 통해 간결한 의존성 구성 지원. – 스프링에 대한 자동구성 제공. – 더이상 xml구성이 필요없음
- 제품출시후 운영에 필요한 다양한 기능을 제공
- 스프링부트의 구성요소
- 빌드툴(gradle vs maven)
- 스프링 프레임워크(4점대 vs 5점대)
- 스프링부트(1.5 vs 2.0) 2019년 8월부터 1.5업그레이드 중지
- 스프링부트 스타터(의존성 구성이 매우 쉬워진다.)
컨트롤러, 서비스, DTO, DAO


- 컨트롤러
사용자의 요청을 누가(어떤 서비스가) 처리할지 결정하는 파트 - 서비스
요청을 어떻게 처리를 할지 결정하는 파트 - DTO
Data Transfer Object
계층간의 데이터 교환을 위한 Java Bean (프로세스와 데이터베이스간의 데이터를 운반하는 객체) - DAO
Data Access Object
DB에 접근하기 위한 객체
스프링의 구동과정(프로세스)
- 웹어플리케이션이 실행되면 WAS에 의해 web.xml이 로딩된다.
- web.xml에 등록되어있는 ContextLoaderListener가 생성된다.
ContextLoaderListener는 ServletContextListener의 구현체이며 ApplicationContext를 생성한다. - 생성된 ApplicationContext는 applicationContext.xml을 로딩한다.
- DispatcherServlet(Servlet이며 프론트컨트롤러 역할) 이 생성되고 컨테이너를 구동하여 컨트롤러객체를 스프링에 빈으로 등록한다.
HttpServletRequest, HttpServletResponse 객체 등을 만든다. - DispatcherServlet이 요청을 핸들링하여 web.xml에 등록된 요청을 가로챈다.
servlet-context.xml 또는 root-context.xml로 가서 등록된 컨트롤러중에 해당요청을 처리한 컨트롤러를 검색(HandlerMapping)하여 요청을 넘긴다. - 필터, 인터셉터 등을 지나서 해당 Controller의 메서드로 이동한다.
참고 - 요청을 받은 컨트롤러는 서비스로 요청을 처리(Service -> DAO -> DB 다시 빽)하고 결과를 출력할 뷰의 이름을 알려준다.
- viewResolver는 컨트롤러가 준 뷰이름이 있는지 확인하여 View에게 View를 준다.
- View는 처리 결과 데이터가 포함된 뷰를 디스패처서블릿에게 준다.
- 디스패처서블릿은 클라이언트에게 결과를 반환한다.
- 뷰를 렌더링한다.
프로젝트 실행 구조(설정파일)
프로젝트 구동시 관여하는 4개의 설정파일.
- pom.xml
메이븐 의존성 관리하는 곳 - web.xml
프로젝트가 구동할때 제일 처음 참조하는 설정파일. 이 설정파일을 읽어 웹(WAS) 관련 설정들을 구성한다.
//root-context.xml의 경로 설정contextConfigLocation/WEB-INF/spring/root-context.xml
//서블릿, 디스패쳐서블릿 관련 설정
appServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation /WEB-INF/spring/appServlet/servlet-context.xml
1appServlet
/위에서 sppServlet이라는 이름으로 서블릿을 등록해줬고 바로밑에서 /(맨 첫페이지)에 들어왔을때 처리할 서블릿을 설정해줬다.
url패턴을 .do로 하는건 고전시대(스트럭트) 방식, /로 하면 web.xml의 .jsp를 처리하는 설정파일대로 적용이 안되기 때문에 / 가 정석이다.
요청을 톰캣(was)이 받아서 서블릿에 패턴을 요청해서 처리하게 된다. 패턴에 해당하는 컨트롤러가 요청을 받아서 처리하게 된다. 이 매커니즘을 반드시 알아야 한다. - root-context.xml
스프링이 관리해야할 객체(빈)들에 대한 설정(스프링의 영역안에서 라이프사이클을 가지고 의존성이 처리된다)
여기있는 모든 bean들은 context에서 사용되어 (싱글톤 형태니까) 공유가 가능하다.
어플리케이션 영역을 설정하는 것이다.
기본적으로 특별한 내용이 없다. 공통적으로 사용하려는 Bean. 예를들어서 db관련 설정 등을 써주면된다. - servlet-context.xml
내부적으로 웹 관련 처리의 준비작업을 진행
web.xml안에서 DipatcherServlet 등록시 설정한 파일이다. 스프링 컨테이너를 초기화 시키는 역할을 한다.
여기있는 bean들은 servlet-container에서만 사용된다.
그래서 @Controller는 servlet-context에 등록하고 @Service, @Repository등은 root-context에 등록한다.
– 해당패키지를 스캔해서 어토네이션이 명시된 클래스들을 빈으로 등록해준다. base-package는 패키지를 어디부터 스캔할지 지정하는 부분. 여러개로 지정해줄수 있다.
component-scan은 커스텀으로 만들어서 쓸수도있고 커스덤을 사용안하면 @Component, @Controller, @Service, @Repository로 등록된 빈은 디폴트로 스캔해준다.
– 은 어노테이션을 활용할때 디폴트 방식을 설정하는 곳.
–<beans:property name="suffix" value=".jsp" /></beans:bean>
응답 view를 렌더링 하는 viewResolver의 앞, 뒤에 문자열 붙이기
작은 프로젝트일 경우 root와 servlet 설정을 나누지 않아도 상관이 없다. 규모가 커질때 나누는 이유는 jsp의 scope와 관계가 있다.
예를들어 jsp의 어떤 자원은 a에게 차단하고, 어떤자원은 a,b,c에게 공유된다고 치자. 그럼 root-context에 공용으로 사용하는 자원. 예를들면 db를 설정하는 것이다. - dispatcher-servlet.xml
spring xml설정 파일에 대한 이해
- 빈등록과 설정을 모두 xml에 할경우 다음 포맷을 사용
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd“> - 빈등록은 xml, 빈설정은 자바 어노테이션으로 할경우 다음 포맷을 사용
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:context=”http://www.springframework.org/schema/context”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd“> - 그리고 만든 빈을 주입받기 위해서는 사용하는 측에서 아래와 같이 등록
다른속성으로 lazy-init, scope, primary, init-method, destroy-method 속성이 있는데 보니까 거의 안쓰일것 같다.
id와는 상관없다. class가 autowired될수있는 객체라면 자동으로 바인딩 해준다.
class가 같을때 id가 다르다면 id로 매핑된다. -
스프링 특징3가지. (스프링 트라이앵글)
-
IoC/DI (생성과 제어)
-
IoC. Inversion of Control. 제어의 역전
스프링에서는 일반적으로 객체를 new로 생성하지 않고 컨테이너에게 맡긴다. 싱글톤의 형태로 관리된다.
그럼 어떻게 사용하지? 주입받는다. 그래서 IoC와 DI 둘은 묶음이다.
즉, 개발자가 하던 객체의 관리(제어)를 프레임워크(엄밀하게는 컨테이너)가 대신 해주는것. 이것이 바로 IoC컨테이너.
개발자는 객체생성에 관련된 설정만 컨테이너에게 넘겨준다.

- 우리가 조립컴퓨터를 맞출때 스프링을 배우기전에는 A객체 안에서 B객체를 사용한다. A는 B에 의존한다. B가 있어야 A가 돌아가기 때문에. A가 메인보드의 개념, B가 CPU, 램, HDD 같은 부품의 개념
우리가 A를 만들려고 할때 어떤 B를 만들지 A의 개발당시에 이미 알고있어야 한다. 삼성램을 쓰다가 하이닉스램으로 바꾸게되면 램이 바꼈는데 메인보드인 A의 코드를 바꿔야한다. - cpu는 어디꺼 어느제품, 그래픽카드는 어디꺼 어디제품 다 정해서 명세서를 넘겨주면 조립업체에서 주문해서 조립해주듯이 명세서를 넘기면 객체를 생성해서 조립해서 컨테이너에 담아준다.
작은부품이 먼저 만들어야지 큰부품을 만들때 끼워넣을수있다. - 일반적인 개발
main()메소드와 같이 프로그램이 시작되는 지점에서 사용할 오브젝트를 결정하고,
결정한 오브젝트를 생성하고
만들어진 오브젝트에 있는 메소드를 호출하고
그 메소드안에서 다음에 사용할것을 결정하고 호출하는 식의 작업이 반복된다.
그러나 제어의 역전이란 이 흐름의 반대.
부모오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않는다. 당연히 생성하지도 않는다.
또 자신도 어떻게 만들어지고 어디서 사용되는지 알 수 없다.
모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문이다.
그것이 바로 역전이다. 조립까지 된다는것을 표현하고싶어서 IoC라는 말이 되었다.
스프링은 IoC를 기반기술로 삼아 극한까지 적용하고있는 프레임워크다.
사실 프레임워크라는것이 자체가 제어의 역전 개념이 적용된 대표적인 기술이다.
프레임워크는 단지 미리 만들어둔 반제품이나 확장해서 사용할 수 있도록 준비된 추상 라이브러리의 집합이 아니다.
라이브러리는 우리 코드가 라이브러리를 제어하고,
프레임워크는 프레임워크가 우리 코드를 제어한다.
각 객체마다 자기의 역할과 책임을 분리하고, 서로 협력하여 변경에 유연한 프로그래밍을 할 수 있는 기법이다.IoC를 적용하면 설계가 깔끔해지고 유연성이 증가하며 확장성이 좋아진다.
제어권이 컨테이너에 있기 때문에 DI, AOP 가 가능하다. - 우리가 조립컴퓨터를 맞출때 스프링을 배우기전에는 A객체 안에서 B객체를 사용한다. A는 B에 의존한다. B가 있어야 A가 돌아가기 때문에. A가 메인보드의 개념, B가 CPU, 램, HDD 같은 부품의 개념
-
DI. Dependency Injection. 의존관계 주입.
- IoC컨테이너에서 빈(bean) 객체를 생성하는 방식. ★★IoC를 구현하는 대표적인 원리★★
A라는 객체가 의존하는 객체B를 직접 만들어서 사용하는 것이 아니라, 주입받아 사용하는 방법. - 2개파라미터를 받는 사용자정의 생성자를 어떻게 스프링컨테이너가 만들까? 그 부품들 각각이 미리 생성되어있기 때문에. 이런식으로 제일 작은부품부터 먼저 만든다.
- (고급)@RequiredArgsConstructor
너가 생성자를 만들때 초기화되어야 하는놈 중에 초기화되지 않은 놈이 있으면 초기화해줘. 부품앞에는 final을 붙여주고 - DI라는 말은 마틴파울러와 아이들이 IoC의 의미를 명확하게 만든 용어다.
- 예)어떤 장난감은 배터리에 의존하고 있다.
배터리 일체형 이라면 배터리가 떨어지면 장난감을 새로 구입해야 한다.
배터리 분리형 이라면 배터리만 교체하면된다. - 쉽게 설명1
자기가 생성되기 위해서 꼭 필요한 부품이 있을 때 자기는 ‘부품에 의존한다.’ 라고 표현한다.
스프링은 부품을, 일체형이 아니라 조립형으로 만든 것이 큰 특징.
느슨한 결합으로 부품만 갈아 끼울 수 있도록. 부품객체를 디펜던시(의존)라고 하고, 꽂아주는것을 주입이라고 하는 것이다.
내가 사용할 부품을 나의 외부에서 주입 받도록 하는 것을 DI라고 한다.
예를 들어 Teacher 의존하는 Student (Strudent입장에서는 Teacher가 부품이다.)
B객체 없이는 A객체는 동작할 수 없다 = A(Strudent)가 B(Teacher)에 의존한다 = 의존 대상인 B(Teacher)가 바뀌면 그것이 A(Strudent)에 영향을 미친다.
학생이 선생님에 의존한다 = 선생님이 바뀌면 그것이 학생에게 영향을 미친다.
의존한다… 의 의미를 알겠나요?그러나 학생이 바뀌더라도 선생님은 영향을 받지 않는다.
public class Student{ private Teacher myTeacher; public Student(){ myTeacher = new Teacher("이고잉"); } }위와 같은 방식이 아니라 아래와 같은 방식으로 만든것. 어려운 개념이 아니다.
개발자가 코드로 넣어줬던 의존성을 주입 받도록 한 것
즉, 학생 클래스의 생성자안에서 담임 선생님을 만드는 것이 아니고
이미 만들어져 있는 담임선생님을 학생에게 주입한다.public class Student{ private Teacher myTeacher; public Student(Teacher myTeacher){ this.myTeacher = myTeacher; } }즉 선생님을 학생이 결정하는것이 아니라 학생 외부에서 결정하도록 하는것.
학생에서 선생님을 결정하게 하게될때 생기는 문제의 근본적인 원인은 가져오는 클래스에 대해 너무 많이 알고있기 때문이다.
만드는 방법에 종속되어 버린다. 외부에서 주입받으면 선생님이 어떤식으로 만들어지든지 상관이 없다.- 쉽게설명3 (가장좋은 예)
음식점에서 직접 식재료를 사지않고 대행업체에서 배송해주는것을 사용하는 경우에 얻는 장점이 무엇인가?를 생각해보면 편리하다, 장사에만 집중할 수 있다. 즉 주입을 받는 입장에서는 타입만 맞으면 어떤 객체인지 신경 쓸 필요가 없다, 자신의 역할은 변하지 않는다. - 직접주문
당근을 어디에서 얼마에 알아야돼. 수많은 업체에서 그걸 비교해야돼. 직접 전화를 걸어 주문을 해야됨. 이런작업을 내가필요한 부품마다 다해줘야돼. 결제도 업체마다 각각 해줘야돼.
주문을 하는시점에 판매자에 대한 정보를 알고있어야 한다. - 배송업체
어떤 식자재가 필요한지 목록만 전달해주면 자기가 알아서 최적의 조건으로 주문해서 배달까지 해줌. 나는 그 배송업체에 결제한번만 해주면됨. 엄청 편리해지면서 각 식자재 판매자들에 대해서 몰라도됨.
배송업체가 마음에 안들면 배송업체를 바꾸면됨.
그 당근이 어떻게 만들어지고 어떤 경로를 통해 만들어지는지 나는 상관안함. 당근을 받기만 한다면.
단점 : 배송업체에 추가 비용이 발생함. 하지만 내가 그일을 직접하게 되면 더 큰 비용이 발생함. - 어려운 예제
- DI없을때
@restcontroller public class mycontroller { private myservice service = new myservice(); @requestmapping("/welcome") public string welcome() { return service.retrievewelcomemessage(); } } - DI 있을때
@component public class myservice { public string retrievewelcomemessage(){ return "welcome to innovationm"; } }
@restcontroller
public class mycontroller {@autowired private myservice service; @requestmapping("/welcome") public string welcome() { return service.retrievewelcomemessage(); }}
- 다시 개념정리 : 자기가 필요한 부품을 얻기 위해 주체가 능동적이냐 주동적이냐에 대한 문제. DI라는것은 **주입을 받음으로써 어떤 객체에 의존하든지 신경쓰지 않고 자신의 역할은 변하지 않게 하는 원리** 스프링에서는 ApplicationContext가 필요한 객체를 생성하고, 주입하고 하는 역할을 해준다. ApplicationContext가 관리하는 객체들을 빈 이라고 한다. - 장점 : 부품을 쉽게 바꿀수 있음, 의존성이 제거되어 테스트에 용이, 재사용성 증가, 가독성 증가(기능별로 분리되기 때문), 코드의 변경시 영향을 최소화. 순환참조를 막을수있다. - 단점 : 부품을 조립해야하는 불편함 조립해주는 서비스를 이용하면 편하겠지. 그것이 바로 스프링 어떤 부품이 필요하고 어떻게 결합하기를 원하는지 설정만 해주면 알아서 조립해준다. - 방법3가지 - 수정자 주입 : Setter - 생성자 주입 : final사용가능. 레퍼런스 변경되지 않음 - 필드 주입 : - **의존성**이 사라짐 : 추상화, 코드 테스트에 용이, 순환참조 방지 - **생성자**로 주입해주나? - IoC컨테이너에서 빈(bean) 객체를 생성하는 방식. ★★IoC를 구현하는 대표적인 원리★★
-
-
AOP
Aspect Oriented Programming. 관점 지향 프로그래밍
스프링 어플리케이션은 대부분 MVC모델을 사용하기 때문에 WEB, Business, Data 3개의 레이어로 정의된다.
‘횡단 관심’ 공통적인 기능
AOP의 예제 : 니가만든 함수의 실행시간을 로그로 찍어달라. 스프링의 AOP기능이 지원안됐더라면 내가 만든 모든 함수의 앞뒤마다 시간을 체크해서 로그출력코드를 넣어줘야한다. 그것을 함수를 호출하면 되지 않냐? 마찬가지로 함수호출부를 다 넣어줘야되잖아. - 주요 어노테이션
- @Aspect : AOP를 정의하는 Class에 할당
- @Pointcut : 기능을 어디에 적용시킬지.
- @Before : 메소드 실행하기 이전
- @After : 메소드가 성공적으로 실행후 예외가 발생되더라도 실행
- @AfterReturning : 메소드 호출 성공 실행시
- @AfterThrowing : 메소드 호출 실패 예외 발생
- @Around : before / after 모두 제어
- 글로보면 이해하기 어렵지만 소스를 보면 쉽게 이해한다.
- dependency 추가해줘야한다.
-
PSA. 스프링을 제대로 공부했는지 5분만에 확인하는 방법
- 다른사람이 만든 connect함수를 호출해야될때 단위테스트에서는 이런 의존성을 제거해야한다.
- Portable Service Abstraction = 잘만든 인터페이스
다른 기술스택으로 간편하게 바꿀수있는 확장성을 갖고 있는 추상화 - 즉, 하나의 추상화로 여러 서비스를 묶어둔 것
- 잘 만든 인터페이스 하나가 열 클래스 부럽지 않다.
환경의 변화와 관계없이 일관된 방식의 기술 접근 환경을 제공하려는 추상화 구조 - 예)
원래 톰캣으로 실행되던 프로젝트를 Spring Web MVC 추상화 계층을 사용하면 netty기반으로 간단하게 바꿀수있다. - 원리
추상화와 DI주입 - 테스트하기 힘든 코드를 테스트하기 편리한 구조로 바꾸기 위해 추상화를 해야할때 이 관점을 제대로 이해해야한다. 서비스 추상화라는것은 서비스 내용을 모르더라도 해당 서비스를 이용할 수 있다는 것을 의미한다. 이런 기능이 가능한 것은 추상화 계층이 존재하기 때문이다.
=> (중요)해당부분을 추상화하여 DI를 통해 런타임시 결정하게 하는것이 답 - 코드
클래스 내부에서 인터페이스를 하나 정의하고 의존되는 함수 껍데기 만든다.
그놈의 구현체 클래스를 하나 만들고 의존하는 함수 껍데기만든다.
테스트하는놈은 그놈을 주입받아서 그놈을 통해서 connect연결
노하우, 팁
- 빈설정할때 property 값들을 세팅해놓으면 만들때 그설정대로 만들어진다.
ApplicationContext
- 스프링 애플리케이션 전반에 걸쳐 모든 구성요소의 제어를 담당하는 IoC엔진
- 스프링은 기본적으로 별다른 설정을 하지않으면 내부에서 생성하는 빈 오브젝트를 모두 싱글톤으로 만든다.
Annotation ( 어노테이션 )
- 프로그램에게 추가정보를 제공해주는 메타데이터
- 컴파일 타임과 런타임에서 코드를 어떻게 컴파일하고 처리할 것인지 알려주는 정보를 전달해준다.
- java1.5부터 지원
- 역할
- 컴파일러에게 문법 에러 체크
- 빌드나 배치시 코드를 자동 생성
- 런타임에 특정 기능을 실행
- 사용하는이유
- 간편한 설정
- 추가적으로 필요한 처리를 비지니스 로직에 영향을 주지않고 처리할 수 있기때문
- 종류
-
@ComponentScan (중요)
- @Component, @Service, @Repository, @Controller, @Configuration이 붙은 클래스 Bean들을 찾아서 Context에 bean등록.
- 해당 애노테이션을 갖는 클래스가 무엇을 하는지 단 번에 알 수 있다

-
@Component (중요)
- 개발자가 직접 작성한 클래스를 빈으로 등록.
- 스프링에서 관리되는 객체임을 표시하기 위해 사용
-
@Bean (중요)
- 개발자가 직접 제어가 불가능한 외부 라이브러리등을 Bean으로 만들때 사용
- 오브젝트를 만들어주는 메소드에서는 이 어노테이션을 붙여준다.
-
@Configuration (중요)
- xml대신 자바 클래스를 설정파일로 사용할때 붙여줌
-
@Autowired (중요)
- 속성(field), Setter, constructor(생성자)에서 사용할수있다.
- 주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입해준다.
- Controller 클래스에서 DAO나 Service에 관한 객체들을 주입 시킬 때 많이 사용. 즉 DI가 목적
- Type을 먼저 확인후 못찾으면 Name에 따라서 주입
- 스프링 의존적이라 나중에 프레임워크를 바꿀 계획이 있다면 @Resource나 @Inject를 사용하는것이 좋다.
-
@Inject (중요)
- Autowired와 유사하게 주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입한다.
-
@Controller (중요)
- 해당클래스가 스프링의 컨트롤러임을 나타냄. 뷰를 제공한다.
-
@RestController (중요)
- View로 응답하지 않고 Rest API를 제공하는 컨트롤러로 설정
- 해당 컨트롤러의 모든 메소드는 자동으로 @ResponseBody가 적용된다.
- method의 반환 결과를 JSON 형태로 반환
- View로 응답하지 않고 Rest API를 제공하는 컨트롤러로 설정
-
@ResponseBody (중요)
- 리턴값에 자동으로 @ResponseBody가 붙게되어 응답데이터(body)에 자동으로 자바객체가 매핑되어 전달됨.
- 웹에서 화면전환(새로고침) 없이 이루어지는 동작들은 대부분 비동기 통신으로 이루어진다.
비동기통신을 하기위해서는 클라이언트에서 서버로 요청 메세지를 보낼 때, 본문에 데이터를 담아서 보내야 하고, 서버에서 클라이언트로 응답을 보낼때에도 본문에 데이터를 담아서 보내야 한다. 이 본문이 바로 body다. - 이 어노테이션이 있는 메소드의 리턴값은 View를 통해출력되는 것이 아니라 Http Response Body에 직접 쓰이게 된다.
- return을 화면이 아니라 문자열 그 자체를 반환하게 된다.
- 자바객체를 HTTP요청의 바디로 매핑하여 클라이언트로 전송한다. HTTP 요청 본문에 담긴 값을 자바 객체로 Conversion해준다.
- 예
{"firstName" : "Michale", "lastName" : "Jordan"} @PostMapping("/users") public void printData(@RequestBody User user){}
-
@RequestBody (중요)
- Http의 요청본문 Body를 통째로!! 자바객체로 변환 전달받는다.(Parsing)
- 즉 JSON형태의 데이터를 JAVA객체에 매핑할때 사용한다.
- 이때 HttpMessageConverter를 사용한다. dispatcher-servlet.xml의 에서 확인
- Json이나 Xml로 전송된 파라미터를 매핑할 때 사용한다.
- 보내주는측에서 contentType: “application/json; UTF-8;” 을 해주어야 한다.
- 화면에서 ajax로 전달할때는 JSON.stringify(객체)를 통해 json으로 데이터를 변환해서 data에 넣어준다.
- public String age(@RequestBody Person person) 식으로 사용했다면 Person객체를 자동으로 생성하고 getter로 명명법 규칙을 따른 변수를 알아서 받아온다.
- 일반적인 get/post요청 파라미터라면 사용할일이 없으나 xml, json 기반의 메세지를 사용하는 요청의 경우 이 방법이 유용하다.
- Http의 요청본문 Body를 통째로!! 자바객체로 변환 전달받는다.(Parsing)
-
@RequestMapping (중요)
- 해당요청(URL)을 어떤 컨트롤러나 메서드가 처리할지 매핑해줌
-
@GetMapping (중요)
- Http GetMothod Url을 받아 화면 반환.
-
@PostMapping (중요)
- Http PostMothod Url을 받아화면 반환.
-
@RequestParam (중요)
- 컨트롤러 메소드의 파라미터와 웹요청 파라미터를 매핑해줌
(단일HTTP요청 파라미터를 메소드 파라미터에 넣어줌) - 정의와 호출의 파라미터명이 다른 경우 유용하게 사용된다.
- 해당파라미터가 반드시 있어야 하고 없으면 400에러. 선택적으로 받게 하려면 required를 false로 설정해야함.
- 화면에서 ajax로 전달할때는 “text”로 받는다. “Json”은 받을 수 없다.
- GET방식에서만 사용할수있다고 잘못설명된곳이 많은데 POST방식일 경우 Body를 통해 전달받을수 있다.
public String requestParam(@RequestParam(required = false, value = “id”) Integer memberId, 블라블라 이런식으로 받는데
모든파라미터를 한번에 받으려면 @RequestParam Map<String, Object> allParameters 이런식의 Map을 이용하면 된다.
- 컨트롤러 메소드의 파라미터와 웹요청 파라미터를 매핑해줌
-
@ModelAttribute (중요)
- 요청파라미터를 메서드 파라미터에서 1:1로 받으면 @RequestParam이고 오브젝트형태로 한번에 받으면 이걸 쓴다.
- 컨트롤러 메소드의 파라미터나 리턴값을 Model객체와 바인딩해줌
- 문자열을 자동으로 객체로 변환해주는 아름다움의 결정체
- 실질적으로 ModelMap.addAttribute와 같은 기능.
- 메소드에 선언하면 해당메소드의 리턴데이터가 ModelMap객체에 저장된다.
- 파라미터에 선언하면 해당객체에 .get(“속성이름”) 값이 바인딩된다.
- 즉, model.addAttribute를 안해도 되게 해준다.
-
@SessionAttributes
- Model객체를 세션에 저장해줌
-
@PathVariable(중요)
- URI에 파라미터로 전달할 변수를 지정할 수 있다. {템플릿변수} 와 동일한 이름을 갖는 파라미터를 추가해주면 된다
- REST 방식에서 리소스를 표현하는 데 사용
- 일치하지 않는 타입의 값이 들어오면 400에러
- 예
@RequestMapping(value = “/user/email/{email}”, method=RequestMethod.GET)
이런 형식일때 아래와 같이 바꿔주면 제대로 들어옵니다.
@RequestMapping(value = “user/email/{email:.+}”, method = RequestMethod.GET)
public ModelAndView getUserByEmail(@PathVariable(“email”) String email) {
-
@SpringBootApplication (중요)
- 스프링부트어플리케이션으로 설정
-
@Repository
- 해당클래스를 루트컨테이너에 Bean 객체로 생성해준다.
@Service 와 역할은 같으나 명시적으로 구분해주기 위해서 분리해서 사용한다.
마찬가지로 부모 어노테이션인 @Component를 붙여줘도 똑같이 동작은 한다.
- 해당클래스를 루트컨테이너에 Bean 객체로 생성해준다.
-
@Service
- 서비스 역할을 하도록 한다.
- (중요) 본질적으로는 인터페이스가 아니라 serviceimpl에 필요하다.
-
@Qualifier
- 오토와이어드 사용시 같은 bean이 2개이상일때 스프링이 무엇을 선택할지 명시적으로 알려주기 위해 사용
-
@Resource
- @Autowired + @Qualifier의 개념
- 주입하려고 하는 객체의 이름이 일치하는 객체를 자동으로 주입한다.
- 필드, Setter에만 붙일수있고 생성자에는 붙일수 없다.
-
@Runwith
- 스프링부트에서 삭제되었고 이미 내재되었기 때문에 안써도됨
https://www.whiteship.me/springboot-no-more-runwith/
- 스프링부트에서 삭제되었고 이미 내재되었기 때문에 안써도됨
-
- 스테레오타입 어노테이션이란
@Repository, @Service, @Controller, @Configuration, @Component등
스프링이 관리하는 컴포넌트임을 식별하게 해주는 마커를 말한다. - 어노테이션 직접 만들어보기
@Target(TYPE, ANNOTATION_TYPE, FIELD, CONSTRUCTOR, METHOD 중 적용가능한 대상) @Retention(SOURCE, CLASS, RUNTIME 3가지중 유지되는기간) public @interface 이름{ } 예) 1. 어노테이션 정의 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface JoelAnnotation { String value(); String[] produces(); } 2. 어노테이션 적용 public class TestController { @JoelAnnotation(value = "/joel-test", produces = "jsonType") public void testMethod() { System.out.println("Testing Method"); } } 3. 어노테이션이 적용된 객체 생성 public class Main { public static void main(String[] args) throws NoSuchMethodException { final TestController testController = new TestController(); final Method testMethod = testController.getClass().getMethod("testMethod"); final JoelAnnotation annotation = testMethod.getAnnotation(JoelAnnotation.class); final String value = annotation.value(); final String[] produces = annotation.produces(); System.out.println("value = " + value); System.out.println("produces = " + produces[0]); } }@autowired 는 특히 중요하기 때문에 한번 더 설명
예전에
<bean id="자식" class="풀패키지명" 키=값 키=값 /> <bean id="부모" class="풀패키지명"> <property name="자식" ref="자식id" /> </bean>이렇게 쓰던것을
부모 클래스에서 @Autowired public void set자식(자식 a){ this.자식 = a; }
1. ## Bean( ### 빈 ### 자바빈)
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=heartflow89&logNo=221006593791
- 스프링 IoC컨테이너가 관리하는 객체
- 자바빈이라고 하면 JAVA EE에서 데이터를 표현하기 위한 Java클래스를 만들때의 규약을 말한다.
여기저기 객체들의 속성들을 하나의 객체에 담기 위한 용도로 쓴다.
모든 필드는 private하며 getter, setter메서드로 제어한다.
생성자는 디폴트 생성자만 있어야 한다.
Serializable 인터페이스를 상속받아야 한다. 네트워크를 통해 전송되거나 파일에 저장되는 일이 잦기 때문
자바빈은 POJO이지만 POJO라고 자바빈은 아니다.
- 스프링에서 빈이라고 하면 스프링이 제어권을 가지고 생성하고 의존관계를 부여하는 오브젝트를 말한다.
- 역할 : DTO. 데이터를 읽어오거나 저장하는 역할을 반복적으로 수행하기 위해서
- (**중요**) 객체내에서 데이터변경작업이 있는 DTO객체같은것은 동기화문제로 인해 Bean객체로 사용하지 않는다.
Bean객체는 항상 데이터변경이 없는 객체에 한해 사용하는 점에 유의해야 한다.
- (**중요**)@Controller, @Service, @Repository 이 어노테이션들은 같은 빈(Bean) 객체에서만 작동하는 것이기 때문에 Bean으로 만들지 않은 일반 클래스에서 사용해봤자 아무 소용 없습니다.
- 등록법
1. 어노테이션
@Component, @Repository, @Service, @Controller, @Configuration,
1. 직접 또는 xml같은설정파일component-scan
@Configuration안에서 @Bean
- 사용법
1. 어노테이션
@Autowired, @Inject
1. 직접
ApplicationContext에서 getBean()으로
- 빈태그의 기본 속성
- class : 필수. 객체를 생성하기 위해 사용할 클래스를 지정
- id : Bean객체를 가져오기 위해 사용하는 이름 지정
IoC컨테이너가 가지고있는 객체의 주소값을 받으려면 id가 필요. getBean으로 가져올수 있다.
자동주입을 받게되면 id속성값 없이도 객체를 불러올 수 있다.
- lazy-init : 싱글톤인 경우 xml을 로딩할때 객체생성여부를 결정.
true면 xml로딩시가 아니라 객체를 가져올때(getBean() 할때) 생성
디폴트는 false . 게으른 초기화 안쓰는것이 기본이기 때문에 xml로딩시 프레임워크가 객체 생성
- scope : 객체의 범위를 설정
singleton : 객체를 하나만 생성해서 사용. 디폴트
prototype : 객체를 가져올 때 마다 객체를 생성
#### 스프링 시큐리티에 사용자정의 권한부여
https://offbyone.tistory.com/93
#### 스프링시큐리티로 로그인, 로그아웃처리
블라블라.permitAll().anyRequest().authenticated().
and().formLogin().loginPage("/login").permitAll();
and().logout().logoutUrl("/logout").logoutSuccessUrl("/logoutProc").permitAll();
에 대한 설명 :
- logoutUrl이 포스트요청으로 /logout으로 오면 get으로 리다이렉트 /logoutProc
successurl은 자동으로 시큐리티의 예외 url로 등록됨
- .permitAll은 어떤 권한의 유저든지 접근가능
#### 스프링부트 세션 시간 늘리기
https://sdragoon.tistory.com/entry/SpringBoot-%EC%84%B8%EC%85%98%ED%83%80%EC%9E%84-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95
## 프론트에서 백엔드 사이 데이터 주고받기
### ★★★★화면에서 백엔드로 데이터 넘기기 (컨트롤러에서 데이터 받기)★★★★
1. 주소창에 쿼리스트링으로 ?키=값&키=값 넣고 컨트롤러에서는 @RequestParam String 넘어온키1, @RequestParam String ("넘어온키2") String 백에서쓸변수명'
user?id="ggoomter"&name="배성원"
```java
@GetMapping("/getUser")
public void userGET(@RequestParam ("name") String name) {
//요청 파라미터에 name이라는 이름으로 넘어온값을 이 함수에서 name이라는 이름으로 쓰겠다.
//이런 노가다 작업을 안하기 위해서 객체에 변수들을 묶어서 넣었고,
//getName이라는 함수(카멜케이스 명명규칙)가 만들어져있으면 이런 작업을 안해줘도 자동으로 매칭되도록 스프링이 구현해놨다.
example?ids=12&ids=34&ids=18 이런식으로 같은 이름으로 여러 파라미터가 넘어오면 컨트롤러에서 String[] 로 받으면된다.
- map으로 받기.
컨트롤러에서 (@RequestParam Map<String, Object> paramMap, Model model) - class로 받기. (클래스명 인스턴스명)
//@RequestParam 안쓴다. @PostMapping(value = "/board/register.do") public String registerBoard(final BoardDTO params) { - PathVariable로 받기
@GetMapping("/example4/{id}") public void example3(@PathVariable String id, Model model){ model.addAttribute("id", id); } - json 받는 방법
@PostMapping("/example6") @ResponseBody public String example6(@RequestBody Map<String, Object> requestBody){ Map<String, Object> resultMap = new HashMap<String, Object>(); resultMap.put("result", true); } - Form의 Action받는것을 Controller url매핑해주면 된다.redirectredirect
화면의 name이 파라미터 이름이 되고 자동으로 파라미터변수에 넣어져서 온다.
파라미터에 객체를 넣어줘도 자동으로 값이 들어온다.
이게 무슨말이냐면 화면에서<input type = "text" name="userName"> <input type = "text", name="userId">이렇게 2개를 넘기고 아래와같이 컨트롤러에서 받으면
public void memberRegist(String userName, MemberDto dto){ System.out.println(userName); System.out.println(dto.getUserName()); System.out.println(dto.getUserId()); }3개가 다 찍힌다. dto에는 getter와 setter함수가 반드시 선언되어 있어야 한다.
- 컨트롤러에서 자바반 규칙에 맞는 DTO나 VO를 매개변수로 써주면 자동으로 카멜케이스 변환규칙에 따라 화면에서 넘겨준 name과 매핑해서 값을 가져온다.
예) / 게시판등록 처리 /
@PostMapping(“/enroll”)
public String boardEnrollPOST(BoardVO board, RedirectAttribuexpectedtes rttr) { - 체크박스에 체크된 순수 자바스크립트 변수에 있는 데이터 백단으로 넘기기
$(“.chkclass :checked”)
https://lopty.tistory.com/4
- 컨트롤러에서 자바반 규칙에 맞는 DTO나 VO를 매개변수로 써주면 자동으로 카멜케이스 변환규칙에 따라 화면에서 넘겨준 name과 매핑해서 값을 가져온다.
백엔드에서 화면으로 데이터 넘기기
- Model을 이용 (주로 mvc 패턴에서 이용)
- 컨트롤러에서는 model.addAttribute(“화면에서사용할 객체명또는 변수명”, 넘길데이터);
- f3 눌러서 확인해보면 알겠지만 object로 받느다. 즉, string이든 int든 dto든 뭐든 넘길수있다는것이다.
- 화면에서는 ${변수명 또는 객체명.속성} 으로 사용
Model
Model객체는 컨트롤러에서 생성된 데이터를 View에 전달하는 역할을 한다.
이전의 request.setAttribute()와 유사한 역할을 수행한다.
HashMap형태를 갖고있다.(key, value)
(중요) MVC에서의 Model이 아니다. 그때의 모델은 서비스 모델을 말한다.
데이터분석 모델에서 모델같이, input이 들어오면 비지니스 로직을 처리후 output을 내는 그 서비스단을 모델이라고 한다.
그 서비스모델의 input이든 output이든 Model객체를 통해서 주고받기 때문에 같다고 생각할수 있지만 엄밀히 말하면 다른것이다. - Redirect를 이용
예) return “redirect:index.do?test=test”; - ResponseBody를 이용 (주로 리액트나 뷰에서 이용)
- RedirectAttributes
RedirectAttributes 타입의 객체는 ‘일회성’으로 데이터를 전달 할 수 있다.
response.sendRedirect()와 동일한 용도로 사용이 가능한 객체이다.
addFlashAttribute() 메서드는 (이름, 값)을 파라미터로 이용하여 화면에 딱 한번만 사용하고 증발(?)해버리는 데이터를 전달한다. 새로고침을 하면 날라감
addAttribute() 리다이렉트할 주소 뒤에 쿼리스트링으로 데이터를 전달해준다.
MODEL에 넘겨주는것과 SESSION에 넘겨주는것의 차이는?
세션은 WAS에 속한 변수. MODEL은 APP에 속한 변수
유효범위가 다르다. MODEL은 한번만 전달된다. 파라미터처럼.
model.addAttribute하면 Model에 저장되는 것이 아니라 Request객체에 저정하는 것이다.
세션은 WAS가 브라우저에 담겨 유지된다.
- 매우중요
Model에다가 담으면 jstl에서 바로 객체를 쓸수있고
jsp의 <% 변수에 담은건 또 <% 안에서만 쓸수있지 jstl에서 쓰지 못한다.!!!!!!! - (중요)인터페이스를 autowired 해서 사용하는 이유와 원리
=> 구현체인 ServiceImpl쪽에 autowired하면 그 서비스임플이라는 클래스에 제한되기 때문. - 자바스프링이 대세가 된 과정(https://okky.kr/article/861238)
service 와 serviceImpl
실질적으로는 거의 1:1로 구현되게 사용하면서 왜 이런식으로 구성해서 사용하지?
- 한국에서 잘못된 객체지향적 코딩을 해왔고 그렇게 배웠기 때문.
원래라면 Controller에서 넘어온 매개변수로 서비스는 순수 자바로만 구성되고, veiw에 종속적인 코드가 없기 때문에 그대로 재사용할 수 있어야 한다. 추가 요청사항이 들어오면 기존소스를 수정하는 것이 아니라 서비스 인터페이스를 구현한 다른 클래스를 구현해 그 객체를 사용하게끔 해서 변화에는 닫혀있고 확장에는 열려있는 구조로 만들어야 한다. - 즉 어디서 잘못된것은 모르겠지만 한국식 MVC모델은 서비스를 인터페이스로 만드는 관례는 그대로 따르면서, 개발은 transaction script형식으로 진행하다보니 본질은 사라지고 형식만 남게 되었다.
- 원래라면 인터페이스에 함수의 형식을 약속하고 구현코드는(실제 작동 본문) 달라질수있는것이다.
즉 OCP(Open Clesed Principle). 개방에는 열려있고 수정에는 닫혀있어야 한다는 프로그래밍 원칙을 지키는 것.
인터페이스를 만들지말자는 결론을 내기보다는 애초에 왜 인터페이스를 만드는것이 정석으로 자리잡았을까를 공부하고 이유를 잘 살리는것이 바람직하다.
더군다나 네이밍까지 Impl을 붙이니 도대체 왜 Service인터페이스가 필요하지가 더욱 의문스럽게 느껴진다. ㅋㅋ
//같은 인터페이스의 2가지 구현체가 있다.
@Service
public class MainServiceImplA implements MainService {
@Override
public ResponseEntity<?> doAction() {
System.out.println("do Action A");
}
}
@Service
public class MainServiceImplB implements MainService {
@Override
public ResponseEntity<?> doAction() {
System.out.println("do Action B");
}
}
프로젝트 진행
- JDK와 ojdbc버전 호환
- https://www.oracle.com/database/technologies/faq-jdbc.html
oracle21.1 ojdbc8.jar(jdk8, 11, 12, 13, 14, 15), ojdbc11.jar(jdk11, 12, 13, 14, 15)
oracle 19c ojdbc10.jar(jdk10, 11), ojdbc8.jar(jdk8, 9, 11)
oracle 18.3 ojdbc8.jar(jdk8, 9, 10, 11)
oracle12.2 ojdbc8.jar(jdk8)
oracle 12.1 ojdbc6(jdk6), ojdbc7.jar(jdk7, 8)
나는 오라클 21에 jdk12니까 ojdbc8이나 11
mysql버전 확인 select version(); 나는 8.0.26 - https://mvnrepository.com/
- 유저경로에 .m2
- “jdbc:oracle:thin:@localhost:1521:시드명”
1521은 오라클 기본 포트 번호.
Oracle 11g인 경우 시드명 XE
Oralce 19인 경우 시드명 orcl
로그인 회원가입
HttpSession객체를 이용하여 처리. web.xml에서 HttpSession의 timeout을 지정할 수 있다.
session에 보관된 객체는 el표기법을 이용해서 자동으로 추적하는 방식을 사용하면 page, request, session, application순서대로 검색하기 때문에 jsp쪽의 개발자는 자신이 사용하는변수가 어디에 존재하는것인지 고민하지 않아도 된다.
알림기능
소켓통신
https://stothey0804.github.io/project/WebSocketExam/
FCM(Firebase Cloud Messaging) https://cmelcmel.tistory.com/104
페이징
총 글의 갯수가 123개
현재페이지 : 3페이지, 페이지당 10개
3페이지의 첫번째로 보여줄글번호 : 1,2,3,4,5,6,7,8,9,10 1페이지
11~20 2페이지
21~30 3페이지
21 (현재페이지-1)x페이지당갯수+1
마지막으로 보여줄글 : 30 현재페이지 x 페이지당갯수
/* 마지막 페이지 */
this.endPage = (int)(Math.ceil(cri.getPageNum()/10.0))*10;
(현재페이지/10.0)올림적용후 10곱하기
현재페이지가 3이면?
0.3 올림적용후 1 10곱하면 10
10
1 2 '3' 4 5 6 7 8 9 10
현재페이지가 5라면?
0.5 올림적용하면 1 10곱하면 10
1 2 '3' 4 5 6 7 8 9 10
현재페이지가 13이라면?
1.3 에 올림적용하면 2 10곱하면 20
11 12 '13' 14 15 16 17 18 19 20
/* 시작 페이지 */
this.startPage = this.endPage - (한페이지에표현할갯수-1);
/* 전체 마지막 페이지 */
총글의갯수가 123개일때
총글의갯수를 한페이지에 표현할갯수(=10)로 나눈후 몫 = 12
1페이지 : 1~ 10
10페이지 : 91~100
12페이지 : 111~120
13페이지 : 121~130
글의 갯수가 121이 되는순간 13페이지가 된다.
그말은 나눠서 나머지가 있으면 1을 더한다의 패턴.
/* 총 글의 갯수를 한페이지에 표현할 갯수(=10)으로 나눠서 나머지가 있으면 몫+1
나머지가 없으면 몫
*/
/* 전체 마지막 페이지 */
int realEnd = (int)(Math.ceil(total * 1.0/cri.getAmount()));
(총글의갯수*1.0)/한페이지에보여줄갯수
### 정적파일 경로
servlet-context.xml에 보면 아래와 같은 설정이 있다.
<resources mapping="/resources/**" location="/resources/" />
src/main/webapp/resources = js, css, image등의 기본경로
src/main/webapp = 웹페이지의 루트폴더
또 다른 방법으로는 WebMvcConfigurer 인터페이스 구현체를 통해서 하는 방법이 있다.
```java
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
jsp 모듈화
개발자는 반복을 극혐해야한다. 화면을 모듈화시켜서 중복을 방지해보자.
a에서 b를 인클루드 했을때 방법의 차이 //include방법의 차이
- //액션태그
내부적 파일의 흐름이 끝나면 결과를 a.jsp로 가져옴
화면의 구조를 분리해서 가져오는데 주로 사용 - <%@ include file=”jsp경로”> //디렉티브
서블릿으로 변환되기전에 합침.
그러므로 a.jsp에 있던 변수를 b.jsp에서 쓸수있음. 반대도 가능
여러 jsp에서 쓰는 공통변수, 중복로직을 제거하는데 사용
<body>
<jsp:include page="views/menu/top.jsp"></jsp:include>
<jsp:include page="views/menu/main.jsp"></jsp:include>
<jsp:include page="views/menu/footer.jsp"></jsp:include>
</body>
이런식으로 jsp파일을 짜집기만 하는식으로 화면구성하는것이 좋다.
출력버퍼를 플러시하려면 flush=”true” 속성 넣어주면 된다.
레이아웃 잡기가 어렵다면 아래같이 갖고오는쪽에서 레이아웃 잡자.
<table width="400" border="1" cellpadding="0" cellspacing="0">
<tr>
<td>
<jsp:include page="top.jsp" flush="false"/>
</td>
</tr>
스프링 화면에서 ajax로 댓글 수정 정석
고급
오브젝트 매퍼
Jackson같은놈들
mvnrepository에서 Jackson Databind
objectMapper.writeValueAsString(객체); //json 문자열로 변환
@jsonproperty 로 json으로 변환될때 이름 지정 가능
objectMapper.readTree(객체)는 JsonNode 타입으로 받을수 있다. 이걸 쓰려면 미리 JSON이 어떻게 생겼는지 알고 있어야 한다.
그 안에서 아래와같이 하나씩 꺼내올수 있다. String _name = jsonNode.get(“name”).asText();
배열은 ArrayNode arrayNode = (ArrayNode)cars;
List _cars = objectMapper.convertValue(arrayNode, new TypeReference<List>(){});
Reflection
- 자바는 정적언어로써 컴파일 시점에 타입을 결정하게 된다.
따라서 프레임워크나 라이브러리는 개발자가 만든 클래스의 정보를 컴파일 시점까지 알 수 없다.
이는 런타임 시점에서 동적으로 타입을 처리해야하는 경우에 대해 어려움이 있을 수 있는데 리플렉션을 통해 해결이 가능하다. - 리플렉션 = 런타임에 메서드, 클래스, 인터페이스의 동작을 검사하거나 수정하는데 사용되는 API
@Autowired의 심층 이해
스프링프레임워크에서 IoC컨테이너가 빈을 생성하고 관리하는 일을 담당하며
각종 설정파일에서 빈을 로딩해서 읽어들이고, 이를 바탕으로 Final Bean Definition을 생성한다.
그래서 의존성 주입은 Bean으로 등록된 클래스에서만 가능하다.
오토와이어링 되는 객체들은 일반적으로 private으로 선언된 경우가 많은데 그럼에도 불구하고 객체가 주입될 수 있는것은 리플렉션 때문이다.