✅ 지금까지의 빌드업 정리

#️⃣ 설정값

pom.xml
(**키워드: dependency)
maven설정(빌드역할)  tomcat, mybatis, jstl, spring dependency 꽂기
(maven project생성 후 필요한것 꽂기)
web.xml
(**키워드: mapping)
(webapp - WEB-INF 내부)
톰캣설정
외부에서 접근하는 url 패턴 & app 이름 mapping
(프로젝트-buildPath에 서버환경 만들어주고 web.xml설정)
여기 있는 app 이름을 기반으로 나중에 app-servlet.xml을 만들어준다 
(app-servlet.xml은 dispatcher servlet의 지시서역할이며 스프링 MVC 도입 이후에는 스프링의 지시서인 config.xml가 된다) 
config.xml
(**키워드 : bean)
(webapp - WEB-INF 내부)
스프링설정
url과 컨트롤러( 혹은 dao) bean 조립 (annotation으로도 설정가능)
ClassPathXmlApplicationContext나 AnnotationConfigApplicationContext로 xml 읽어들이기

 

 

#️⃣ 홈디렉토리

webapp -- 홈디렉토리
ㄴ WEB-INF -- 클라이언트로부터 jsp를 숨기는 곳. jsp를 컨트롤러와 소통할 수 있도록 한다
------------------ 이 단계에서 @WebServlet("url")로 경로를 연결하지 않는다. controller와 jsp 둘만을 연결시킴!

 

 

#️⃣ 서블릿 역할의 발전 ▶ 스프링 MVC의 도입

서블릿역할: dispatcher 를 가지고 jsp에게 forwarding해주기
 컨트롤러를 다시 프론트 컨트롤러(라우터역할의 dispatcher servlet)와 POJO컨트롤러로 나누기

프론트 컨트롤러 형태가 비슷해서 라이브러리가 제공됨 == 스프링 mvc

 

POJO 컨트롤러 : MVC의 MV만 가지고 있음.

public class ListController implements Controller{
    @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception{
            return mv;}
}

 

 

#️⃣ 스프링 MVC 도입

: 프론트 컨트롤러의 역할이 비슷하므로 도입된 스프링 MVC

  1. 서비스+다오를 합쳐서 내가 원하는 객체를 만들어줘
  2. 객체를 저장해서 가지고 있다가 내가 원할떄 넘겨줘 (IoC가 곧 DI)

 


 

✅ annotation으로 설정하기

xml을 쓰지 않는 대신 자바클래스에 설정코드를 만들어준다 (업무로직 코드가 아님)

annotation을 붙일때는 1. 클래스에 붙여서 해당 클래스 자체를 인식시킬수도 있고 (@Component) 2. 메서드에 붙여서 해당 메서드를 인식시킬 수도 있다.(@Autowired) 

 

 

#️⃣ 객체 생성법

  • @Bean으로 해당 객체 생성하기 (이름필요없음. 어떤 객체를 new할지 지정 가능)
  • @ComponentScan으로 해당 패키지 스캔해서 객체 생성하기
//방법2. 패키지 내부의 컴포넌트를 스캔하도록 만들기
@ComponentScan("com.newlecture.spring")
public class SpringConfig {

	
	//방법1. Bean으로 해당 객체 생성하기 -- 이름 따로 지정할 필요 없음
//	@Bean
//	public MenuDao dao() {
//		return new Dm2MenuDao();
//	}

}

👉 스캔하는 범위가 넓어지면 성능이 떨어질 수 있으므로 디테일하게 설정해주는게 좋다. 이를 위해 패키지를 여러개 만들게 된다면 배열을 통해 여러 페이지를 설정할 수 있다. (@ComponentsScans("패키지주소"))

👉 보통은 기본패키지를 설정해서 뒤지게 한다 (service, dao등은 기본패키지 이름 하위로 붙으므로 한번에 찾게 됨)

 

 

 

#️⃣ 객체 생성뒤 Dao와 연결하는 @Autowired (== setter injection)

@Autowired

: 객체와 setter를 연결하는 방법

@Component를 뒤져서 그 안에있는 @Autowired의 setter와 조립해준다.

👉 constructor나 setter에 붙여놓으면 초기화를 함께 진행할 수 있다 (constructor나 setter가 품고있는 프로시져를 함께 실행함)

 

 

 

오류발생 - The virtual machine was unable to remove all stack frames running old code from the call stack. 

더보기

메인함수 내에서 스프링 연결을 이것저것 교차해서 연결해보다가 난 오류...

 

#️⃣ 이클립스에서 저장할때 뜨는 오류 - The virtual machine was unable to remove all stack frames running old code from the call stack. 


"가상 머신은 호출 스택에서 이전 코드를 실행하는 모든 스택 프레임을 제거하지 못했습니다."
이 오류 메시지는 Java 또는 기타 가상 머신에서 실행되는 프로그램에서 발생하는 것으로, 프로그램의 함수 호출을 추적하는 호출 스택(call stack)을 관리하는 데 문제가 있음을 나타냅니다.
이 오류가 발생하는 일반적인 이유와 해결 방법은 다음과 같습니다:
  1. 무한 재귀 함수: 재귀 함수가 종료 조건을 갖추지 않은 경우 호출 스택이 무한정 쌓이면서 이 오류가 발생할 수 있습니다. 재귀 함수가 올바른 종료 조건을 가지고 있는지 확인하세요.
  2. 스택 오버플로우: 호출 스택이 깊거나 무한한 재귀로 인해 오버플로우하는 경우 이 오류가 발생할 수 있습니다. 재귀 깊이를 줄이거나 반복문을 사용하여 재귀를 대체하여 문제를 해결할 수 있습니다.
  3. 메모리 한계: 가상 머신이 호출 스택을 처리하는 데 충분한 메모리를 할당하지 않은 경우에도 이 오류가 발생할 수 있습니다. JVM 플래그인 사용하여 메모리 할당량을 늘릴 수 있습니다. 예를 들어 -Xmx512m와 같은 JVM 플래그를 사용하여 최대 힙 크기를 512MB로 설정할 수 있습니다.
  4. 스레드 관련 문제: 프로그램이 여러 스레드를 사용하는 경우, 스레드 관련 문제가 종종 이 오류를 발생시킬 수 있습니다. 스레드 안전성을 유지하고 공유 리소스에 대한 동시 액세스를 올바르게 처리하는지 확인하세요.
  5. 오래된 또는 잘못된 JVM: 가상 머신의 오래된 버전 또는 호환되지 않는 버전을 사용하는 경우 이 문제가 발생할 수 있습니다. JVM을 최신 버전으로 업데이트하면 이와 관련된 문제를 해결할 수 있습니다.
  6. 디버깅: 프로그램 실행을 디버깅하여 코드의 실행을 추적하고 구체적인 원인을 식별하는 데 도움이 되는 디버깅 도구를 사용하는 것도 고려해 보세요.
이 오류의 구체적인 원인을 파악하려면 스택 트레이스(stack trace) 및 코드 검토를 통해 문제를 식별하고 해결하는 것이 중요합니다.

 

 

 

 

 

#️⃣ 생성자에 주입하기 (==constructor injection)

: 생성하면서 초기화 할 일이 있을때 사용

@Autowired //--constructor injection
public MenuServiceImp(MenuDao dao) {
    System.out.println("constructor");
    this.dao = dao;
}

콘솔이 먼저 출력된다

 

#️⃣ 필드에 연결하기 (==field injection)

: 필드에 있는 자료형명의 이름은 아무 의미가없음. 따라서 캡슐이 깨지진않으며 private도 @autowired도 설정할 수 있다.

 

//어노테이션을 가지고 클래스 자체에 설정을 붙인다.
@Component()
public class MenuServiceImp implements MenuService {

//	private DmMenuDao dao;
	@Autowired // --field injection
	private MenuDao dao;

//안에서 생성을 하지않고 생성된 객체 자체를 꽂도록 하기
	public MenuServiceImp() {
//		dao = new Dm2MenuDao();
	}

//	@Autowired //--constructor injection
	public MenuServiceImp(MenuDao dao) {
		this.dao = dao;
	}

	// @Autowired //--setter Injection
	public void setDao(MenuDao dao) {
		this.dao = dao;
	}

	@Override
	public List<Menu> getList() {
		return dao.findAll();
	}

}

 

 

 

#️⃣ @Component 세분화하기

👉 MVC는 controller, service, dao로 계층이 나누어져있는데 그에 맞게 component를 설정해주는게 좋음

 

 

 

✅ XML과 annotation을 섞어서 설정하기

👉 기본은 xml이고 annotation을 얹어서 쓴다. XML과 annotation 각각이 어느범위까지 커버하는지를 체크하는것이 관건.

 

 

#️⃣ 1. @Component는 xml로 읽고 객체 내에 있는 annotation만 읽도록 설정하기

클래스 밖의 service, repository는 읽지 않고 생성한 객체 내에 있는 annotaton만 읽는다

👉 config.xml에 context 설정(annotation을 읽겠다는 설정)을 넣어준다. 

 

 

 

#️⃣ 2. @Component와 @Autowired의 등 annotation을 모두 읽겠다는 설정을 xml에 하고 싶다면? (config.xml은 읽히는 상태)

 

 

 

#️⃣ annotation을 붙일 수 없는 상황은? -- xml을 활용한다

우리가 만든 코드는 소스코드가 있어서 annotation을 붙일 수 있지만 타인이 만든, 보따리에 이미 들어가있는 소스코드는 annotation을 붙일 수 없다.

//소스코드가 없는 놈을 한보따리에 담아달라고 해야함
//@Component
@Configuration // -- Bean 전용 component
public class BeanConfig {
	
	//list라는 이름으로 해당 객체를 담아달라. -- 이럴땐 함수로 동작하는게 아니며 함수 명이 담을 이름이 된다.
	@Bean
	public List list() {
		return new ArrayList();
	}
}

객체를 사용할때는 해당 클래스 객체를 getBean()으로 가져와 형변환해서 사용한다 (기본형이 Object이기 때문)

 

 


 

 

✅ 프로젝트의 app-servlet.xml(==config.xml) 에 설정한 url-controller 구조를 annotation으로 변경하기

: url당 클래스를 맵핑하면 클래스가 그만큼 만들어짐 (url이 100개면 클래스가 100개가 됨)

👉 따라서 annotation을 사용해서 클래스단위가 아닌 함수단위로 변경시키는게 좋음

 

 

#️⃣ 1. app-servlet.xml에서 context (혹은 mvc)추가

 

 

 

#️⃣ 2. 사용자 요청시 HomeController가 실행되도록 mapping하기

<!-- <bean id="/menu/list" class="kr.co.rland.web.controller.menu.ListController"> 
    </bean> <bean id="/menu/detail" class="kr.co.rland.web.controller.menu.DetailController"> 
    </bean> -->

(▲app-servlet.xml에서 설정하던 위 내용을 대신하는 컨트롤러를 만드는 것)

 

 

 

▼ mapping하는 방법을 알아보자

 

#️⃣ POJO 컨트롤러 없이 자체적으로 뷰 반환하는 법

👉 annotation이 함수에 붙는데 함수이름은 마음대로 해도 되고 여러 함수를 넣을 수도 있음

 

 

 

#️⃣ 경로별로 클래스 나누기

❓ 클래스는 언제 만들어야할까?

👉 경로에 해당하는건 모두 클래스로 만들어짐

 

예) root 경로는 HomeController 클래스/ menu에 해당하는건 메뉴클래스

 

 

package kr.co.rland.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller //-- 얘도 컨트롤러이므로 어노테이션 잊지말기
@RequestMapping("/menu") //상위 경로를 나눌 수 있음
public class MenuController {
	
	@ResponseBody
	@RequestMapping("/list")
	public String menuList() { // --- 여기서 메서드 이름은 아무거나 넣어도 됨
		return "list in the menu";
	}
	
	@ResponseBody
	@RequestMapping("/detail")
	public String menuDetail() {
		return "detail in the menu";
	}

}

 

 

 

#️⃣ 입력값 체크

위에서 설정한 경로별 맵핑은 일반 컨트롤러에 해당하고 아직 프론트컨트롤러는 만들지 않았음!

//컨트롤러에서 jsp로 forwarding하기 (front controller아니고 POJO 임!)
@Controller
public class HomeController {

//	@ResponseBody
	@RequestMapping("/index")
	public String index(String s) {
		System.out.println(s);
		
		//forwarding
		return "/WEB-INF/view/index.jsp";
	}
}

 

 

+ Recent posts