카테고리 없음

0303 오후수업

logloglog 2021. 3. 3. 15:41

daoimpl 이 완성이 되지않았는데 서비스 테스트하고싶다면?

dao를 목업형태로 만들어서 (디비를 거치지않ㅇ고) 테스트할수있따

만약 멤버리스트에 대한 기능이라면 dao를 호출하되 목업형태로 만들어서 그 목업형태에 따라서 서비스가 움직이면되는거니까 단위테스트 할수있따.

 

그래서 mokdao를 만들거임

 

memberVO에서 생산자만드는데

생성자 만들떄는 반드시**** 기본생성자 만들어주기***

디비를 거쳐오는게 아니고 내가 주는거임
디비에 잇는걸 가져오는건 dao의 몫이고 서비스는 dao가 준 데이터를 잘 담아서 넘겨주는것만이 목적이기떄문에
여기에잇는걸 서비스는 컨트롤러에게 잘 넘겨주기만 하면 된다.

import kr.or.ddit.dto.MemberVO;

public class MockMemberDAO implements MemberDAO{

	@Override
	public List<MemberVO> selectMemberList(SearchCriteria cri) throws SQLException {
		//디비를 거쳐오는게 아니고 내가 주는거임
		//디비에 잇는걸 가져오는건 dao의 몫이고 서비스는 dao가 준 데이터를 잘 담아서 넘겨주는것만이 목적이기떄문에
		//여기에잇는걸 서비스는 컨트롤러에게 잘 넘겨주기만 하면 된다.
		//cri받아서 데이터넘겨주는건 dao의 몫이니까
		List<MemberVO> memberList = new ArrayList<MemberVO>();
		
		MemberVO member1 = new MemberVO("mimi","mimi","mimi","000-0000-1234","mimi@mimi.com");
		MemberVO member2 = new MemberVO("mimi1","mimi1","mimi1","000-1111-1234","mimi1@mimi.com");
		
		memberList.add(member1);
		memberList.add(member2);
		
		return memberList;
	}

	@Override
	public int selectMemberListCount(SearchCriteria cri) throws SQLException {
		
		return 0;
	}

	@Override
	public MemberVO selectMemberById(String id) throws SQLException {
		MemberVO member = null;
		if(!id.equals("mimi"))return member;
		
		member=new MemberVO();
		member.setId(id);
		member.setPwd("1234");
		member.setEnabled(1);
		member.setPhone("010-1234-5678");
		member.setEmail(id+"@"+id+".com");
		member.setPicture("noImage.jpg");
		
		return member;
	}

 

이렇게 하면 dao가 다 만들어지지않았어도 테스트할수가있따


TestMemberService만들기

여기서 서비스를 가져오긴할건데 dao를 목dao 로 바꾸는 작업을 반드시 해줘야함

 

@Autowired
	private MemberServiceImpl service;
	
	@Before
	public void init() {
		service.setMemberDAO(new MockMemberDAO());
	}
@Test
	public void tesetGetList() throws SQLException{
		//criteria 는 형식만 맞춰준거임..컨트롤러라고 보면 됨
		SearchCriteria cri = new SearchCriteria();
		
		List<MemberVO> memberList = (List<MemberVO>)service.getSearchMemberList(cri).get("memberList");
		
		Assert.assertEquals(2, memberList.size());
	}

 

오류 빈등록안햇다고

 

<커맨드패턴>

 

커맨드 패턴으로 시작 함 시작은 커맨드가 중요한게아니고

원서블릿으로 한다는게 중요한거임

 

서블릿으로만 하게되면 서블릿으로 햇을때에 발생되는 익셉션처리나, 서블릿관리가 ㄷ굉장히힘듦

왜냐면 우리가 만들긴 하지만 리소스를 톰캣이주기때문에, 서블릿에대한 핸들링권이 우리에게없는거임

인스턴스를 마음대로 컨트롤할수없게됨

그래서 예외처리등 각종처리들이 어려워진거임

 

우리입맛에따라 핸들링할수있으려면

우리가만든 클래스에서 해당 리퀘스트가 처리되게해야한다  > 서블릿이 별로 할일이없어짐

 

서블릿 자체는 톰캣의 웹컨테이너에 들어있고 우리는 여기서서블렛을꺼내는권한이없다.

그래서 서블렛이만들어지고나서톰캣안의웹컨테이너안의서블릿인스턴스에대한관리가힘들엇음(접근이안되니까)

 

그래서 was 관할하의 웹컨테이너에서 처리하는게아니라 (결합도가 강함)

우리만의 영역을만들어서우리가언제든지 넣뺏할수잇는 우리만의 컨테이너에다가 인스턴스를 만들고 핸들링할수없을까?

고민끝에 만들어진게

서블릿의 역할을 최소한으로 하고 (req, res만 건내주고 뭔가 처리는 안하게)

 

HTtpserreq에서 url 알수잇으니까 우리가 만든 컨테이너에서 인스턴스빼서쓰면 되는거아닌가..

그럼 받는건 httpsereq가 받고 처리는 따로하니까

그걸 액셔너라고 만들자. 그래서 action이라고 인턴페이스를 만들게 됨

얘가 req, res를 처리하게됨

 

그럼 url에 따라 얘를 꺼내는 방법은?

그걸 핸들링할수잇는 핸들러 매퍼를 하나 주자.

 

기능화하는 단위 = 사용자가요청하는 url 단위

url 기준으로 액셔너를 매핑해서 두면 되지않으까?

(우리가 만들엇던 핸들러가 여기의 액셔너임)

 

서비스를 요청해서 실제로하는애들이 액셔너들임

기능들이 다 액셔너로 빠져나오니까 서블릿이 텅텅빔..원서블릿이 가능해지는ㄴ것

view = action.exe(req,res)만 해주면 됨

view 받아서 포워드나 리다이렉트만 해주면 됨

뷰는 있을수도없을수도 포워드, 리다이렉트할수도잇음.. 그래서 뷰를 리졸버로 만들어야함

 

 

컨테이너는 맵인거임

 

무튼 액셔너들은 이제 우리맘대로 컨트롤이가능

 

커맨드패턴으로 햇을때는 url이 index.do?command=sdfdsf 이런식으로 주게된다.

 

엠코드로 하는게 찐 커맨드인데, 알아먹기힘듦

어짜피 유알엘 넘어오는거니까 커맨드로 하지말고 그냥 유알엘 적자.. (메뉴에대해서만 커맨드패턴으로하고)

아이프레임을 따로 만들어서 아이프레임으로 받는거는 유알엘로 요청하도록 바꾼거임

 

처음에는 mcode로 넘어가지만, 아이프레임의 핸들러들은 다 유알엘로 규정한거임 그래야 우리가 뭔지 아니까

 

이게

jsp 서블릿의 컨트롤러아키텍쳐임

 

이상태에서 표준화할수있는 부분이잇고 표준화할수없는(매번 커스터마이징해야하는) 부분이 생김

좌측의 구조는 변하지않음

우측에 액셔너는 표준화할수없는 부분임

 

좌측은 한번만들어놓으면 끝남

우측은 액션이너무많아~ 그리고 클래스하나에 원매서드이기때문에 자원의 낭비가 발생(똑같은걸 너무많이만들게된다)

효율화시키고싶다

 

보드와 관련된 액션은 보드하나로,만들고싶다는 갈망이생긴거임

그래서 클래스단위의 원매서드 가 아니라 만드는걸멀티매서드로 만들고싶어짐

 

 

*수정 맵의 생성자에 프로퍼티 읽는거들어가있고, 서블릿의 이닛메서드에 매퍼잇음

이닛리스너없음

이닛리스너는 서비스랑 디에이오조립하려고 어플리케이션 컨텍스트떄문에 ㅁ만든거임!여기나올게아니라


< SPRING >

원서블릿체제 (front servlet)은 바뀌지 않는데 이름이 바뀜

총괄한다는 의미의 dispatcher servlet

 

클래스를 까서 메서드를 실행할때는 리플렉션이 필요하다. 리플렉션을 해서 invoke 해야됨

컨ㅌ트롤러 까서 메서드 실행(invoke) 해야하니까

 

서블렛과 컨트롤러를 정격으로 연결 > 서블렛이 컨트롤러를 실행할수있도록 맞춰주는  (리플렉션이용해서 ) 애가 어댑터 

 

컨트롤러 실행하려면 클래스까가지고 거기에 맞는 파라미터 줘야하는ㄷㅔ 서블릿은 그걸 못함 그래서 어댑터가 필요한거임

 

스프링MVC의 핵심 . 마음대로 메서드 작성해도 그걸 실행할수있게 해주는ㅇ ㅓ댑터!~!

 

이제 컨트롤러의 메서드를 입맛에맞게끔 만들수잇게 해주는게 어댑터임

그것의 이름 : 핸들러어댑터

 

매서드 실행시필요한 파라미터까지 어댑터가 챙겨줌

 

 

 

리퀘스트(어트리뷰트기떄문에 한꺼번에못넣음. 그래서 모델을 만들엇다. 리퀘스트 어트리뷰트에 셋하는걸 하나하나하지않고 한번에 할수잇게해주느것.. 마치 마이바티스의 파라미터타입정해주면 알아서 해주는것처럼..즉 모델은 안쓰면 그만이지만 쓰면 편리한것.. 셋어트리뷰투는 핸들러에서햇다. 핸들러는 액셔너고 액셔너가 컨트롤러니까 컨트롤러에서 모델쓴다.) 오면 매퍼에게 넘겨서 그유라엘일 실행해야할 서블릿을 알려줌 서블렛은 어댑터에게 넘겨줘서 그 컨트로러의 리플렉션을 취하면 파라미터 뽑아낼수잇을 파라미터를 핸들러어댑터가 만들어서 인보그(4번) 한다 그럼 해당 컨트롤러가 실행하고 컨트롤러는 메서드로 되어잇다. 매서드 실행한다

 

컨트롤러만 바뀐거임~~!~

 

 


 

1. 핸들러 매퍼에서 직접 프로퍼티읽음

 

>우리가 사용하는 MVC 패턴에서는 

해당 컨트롤러에서 매서드위에 각각 애너테이션을 달아서 매퍼에서 등록한다.

 

해당 매퍼를 등록하기위해서잇는거임

*Servlet Init Parameter(서블릿 초기화 매개변수)

서블릿을 생성하고 초기화할 때, 즉 init()을 호출할때 서블릿 컨테이너가 서블릿에 전달하는 데이터이다. 보통 DB 연결 정보와 같은 정적인 데이터를 전달할 때 사용한다. 다음의 방법으로 설정할 수 있다.

  1. DD파일(web.xml)의 서블릿 배치 정보에 설정
  2. 어노테이션을 사용해서 서블릿 소스 코드에 설정

가능한 1번의 방법으로 설정하는게 좋다. 소스 코드에서 분리해서 외부 파일에 두는게 더 관리하기 쉽기 때문이다.

출처:atoz-develop.tistory.com/entry/Servlet-Init-Parameter%EC%84%9C%EB%B8%94%EB%A6%BF-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98%EB%A1%9C-webxml%EC%97%90-DB-%EC%97%B0%EA%B2%B0-%EC%A0%95%EB%B3%B4-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0

 

디스패쳐서블렛은 어떤 핸들러어댑터.매퍼,리졸버를 쓸지 결정하게되는 명세서임

어떤 핸들러어댑터.매퍼,리졸버를 쓸지는 이미 되어잇고

 

컨트롤러가 어디잇냐, 어디서가져올건지에 대한 부분,

뷰리졸버 종류를 많이 만들엇으므로

어떤 리졸버를 어느상황에서쓸건지에대한 정보를 적어줘야함  

 

여기잇다
여기로옮기고

<param-value>classpath:kr/or/ddit/context/servlet-context.xml</param-value>

web.xml의 경로 바꿔주기

 

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="com.spring.mvc" />
	
	
	
</beans:beans>

ㅈ주석을 잘보기

 

빈등록하는방법

1. <bean>

2. annotation 

 

context:component 이놈은 뭐하는 녀석이냐면 xml로 빈등록하지않고 annotation으로 빈등록하게끔 해주는 녀석

base-package에 component-scan을 할 패키지 경로를 명시해주면 해당 경로를 포함한 모든 하위 경로에 적용되고, 애노테이션을 명시한 자바 파일들이 Bean으로 동록 되어 사용 가능해진다.

출처:jayviii.tistory.com/10

 

우리가 클래스를 만들떄

@componet라고 적어주면

annotation에 의한 빈 등록임.

 

주의해야할점 ! 컨테이너와 다르다.

뭐는 annotataion으로 하고 뭐는 xml로 할수있는게아니다

호환이안됨

 

xml로 등록을 하게되면 다 xml로 주입을 시켜줘야하고

annataion도 같은 이치

 

빈이 모이는 영역은 같은데 담는녀석들이 다름

 

Spring container에 빈들이 담기긴 함

근데 이 컨테이너에 등록을 시켜주는 사람이 다른 느낌임

 

xml읽어서 컨테이너에 빈 등록하는애가 제네릭xmlapplication어쩌구엿음 (저번시간에)

어플리테이션컨텍스트 자식들이 이렇게나 많다.

 

빈등록할떄 자바컨피그로 만들거냐 xml로 만들거냐 annotation 으로 만들거냐

다 따로따로잇음

그래서 GenericXml / Annotation /...

xml 상에서 등록한건 xml에서 주입해야하는거임

 

 

이렇게 할거면

 

이부분에서 패키지 등록해주면 됨

위에 이렇게 할거면 아까 xml로 빈으로 등록한거 다 지워야하는거임 

 

어노테이션 방식의 단점은 autowired 로 된거 다 클래스 까봐야 한다는 거임

반면에 빈은 빈그래프로 한눈에보기가 가능함

 

포조의 형태로 해주겟다고 스프링이 생각을해서

서비스 dao도 포조로 만들엇는데,,,,,

 

컨트롤러를 만들때 일반 클래스로 만들건데,

스프링 컨테이너에 잇는 빈들중 이 빈들이 일반 빈인지 컨트롤러인지 구분이 안된다...

컨트롤러용도로 만든건지 서비스용도로 만들건지 디스패쳐는 모르겟다

컨트롤러면 매퍼에 넘겨야하는데.....

어쩔? 어노테이션을 이용하자!!! < 선언자의 성격이잇으니까.. (이건 @before야 이건 @After야 ... 이런식으로 알려줄수잇으니가 @Controller 이렇게 하면 되지않으가 생각한거임)

 

그래서 컴포넌트만 잇어도 빈등록이되는데 이걸 갈라놓음

컨트롤러냐.서비스냐. dao냐

 

그래서 만든 어노테이션이 @Controller :MVC 의 Controller / @Service : Service layer / @Repository : DAO layer

이러는 목적 : mvc에서빈등록된 빈중에 컨트롤러에서 뽑아내려고

 

컨트롤러는 빈등록하지않고 어노테이션에 컨트롤러붙여주세요 하고 정함

그러면 이 @Controller를 찾아서 매퍼에 등록어야함 이걸 찾는건 context:componet-scan인거임

 

이게 컨트롤러를 매퍼에 등록하기위한 한 세트임
우리는 경로 이렇게...

@Controller로 어노테이션 줘야 컨트롤러로 등록된다.

 


어디서 많이봄... 어디?

js css 이미지 리소시스에 넣었엇음. 즉 url /resources/오면 /resources/에 넣겟다

web.xml에 서블릿 등록시 url 매핑 확인해보면

얘가 /이다... 다 받겠다는 소리임.. 그럼 css나 js 요청시마다 컨트롤러 다 만들어줘야하는 문제가 생김

우리가 커맨드패턴에서 .do로 받은 이유는? /로 잡아버리면 리소시스의 css. image js 다 서블렛에 걸림(화면내보내는애들인데)   그래서 그걸 피하려고 기능요청하는 애들은 .do 로 패터닝 시키고 나머지는 기본서블렛이 받도록 한거엿음

 

 

암튼 그래서

얘들은 뚫어주려고 만든거임.이렇게 설정해서

리소시스로 시작하는 유알엘들은 

여기다가 모으자

여기부터 시작하기로

 

 

이제 /로 잡은거에대한 영향이없고 .do로 따로 받을 필요도없다

 

기본적으로 스프링의 매퍼는 .패턴은 인정하지않는다.

핸들러매퍼를 지나면 login 이랑 login.do 는 같게 취급된다.

매퍼를 지나는 애들은 .do 건 ,do 가 없건 상관이없게된다

 

컨트롤러에 정의된 유알엘은 핸들러매퍼에 잡힘 그래야 그 유알엘왓을때 컨ㅌ트롤러 실행하니까

그럼 핸들러매퍼를 지나가지않는 유알엘은 .패턴 다 인정함

 

 

핸들러매퍼도 서블렛에서 요청을 해야하는거임

근데

여기있는 유알엘은 얘가 직접 처리하기때문에 핸들러매퍼에 안간다.

여하튼

servlet-context에 유알엘이 되어잇으면 핸들러매퍼지나지않는다 즉 .패턴 이 적용됨

 


컨트롤러 여기에 만들자

 

 

 

package kr.or.ddit.controller;

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

@Controller
public class MemberController {

	//지금까지 서블릿의 웹서블릿의 유알엘 규정, 핸들러에서의 유알엘프로퍼티.. 해왓지만
	//여기서는 메서드 위에 에노테이션으로 유알엘 규정
	
	@RequestMapping(value="/common/loginForm",method=RequestMethod.GET)
	public String loginForm() {
		String url = "";
		return url;
	}
}

 

우리가 커맨드패턴시 핸디캡이 겟과셋이 구분이안됏던거엿는데

여긴 .GET이고 /common/loginForm 이 유알엘 올때 안에 실행하라는 뜻임

 

초록읽으면서 파란까지 다읽어서 매퍼에 세팅 > 즉 프로퍼티 안만들고 여기다 적으면 됨

이게 로그로 다 찍히기때문에 어떤 

 

 

 

리퀘스트매핑은 컨트롤러밑에도붙일수가잇다

이컨트롤러의 액셔너는들의 유알엘은 /member로 시작한다는 뜻

 

 

이제 뷰 리졸버

 

다시 서블릿ㅅ컨텍스트

 

리졸버 의 결론 : 그다지특별할거없음 햇던거랑 같음 단지 프리픽스 서프픽스?를 밖으로빼놓은거뿐임

컨트롤러에서 리턴되는 화면에서 redirect: 붙이면 리다이렉트됨

결론 : 하던대로하면됨

 

지난번에햇던 리졸버와 비교

이걸 클래스필드로 올려서 셋메서드로 올리면??? 
이런식으로

 

 

 

이렇게 된다는 말임

 

그럼 이제 답 나옴

 

이렇게 하면 된다

 

jsp는 우리가 이미 잇다

확인
확인
.do 해도 마찬가지

 

 

이걸 다른 방법으로 열어보자

 

주석하자

 

서블릿에서 직접 jsp에 대한 핸들링해보자

 

서블릿컨텍스트

 

이 방법의 단점 : 리퀘스트에 뭔가를 심을수가없음. 그냥 화면 던지는 용

*잠깐 참고

그럼 

이렇게 index.jsp 죽이고 이렇게 할수잇다.

 

암튼 서버돌리기

 

얘가 잡는다.

이거 핸들러매퍼아님

이거 컨트롤러유알엘 등록해주는 핸들러매퍼가 아니고 서블릿이 내부적으로 가지고잇는 매퍼임

근데 이번엔 .do는 안됨

핸들러매퍼는 컨트롤러에 등록되는 유알엘 다루려고 외부에 만들어놓은거고

내부에는 심플유알엘핸들러가 잇다

 

이번엔 .do가 안되는 이유? .do가 자기한테 없으니까 핸들러에게 던짐

핸들러매퍼에도 .do 가 없음 그래서 404

 

핸들러에 .do 줘도 안됨 핸들러는 .패턴 인정 안하고 그냥 지워버리기떄문에

 

유알엘핸들러가 심플유알엘핸들러(서블릿내장 .패턴인정함) 핸들러매퍼(컨ㅌ트롤러의유알엘 챙기는녀석 .패턴인정안함) 두개라는거

 

즉 유알엘이 서블렛에정의되어잇는지 컨트롤러에정의되어잇는지에따라 다를수있따는점

 

앞으로 로그인체크필터를 안쓰고 시큐리티를 쓰게될텐데 기존방식대로 하면 문제가 생김 시큐리티는 핸들러매퍼가 아니기때문에..  필터는 핸들러매퍼같은거없음 디스퍁처서블렛 오기도전이기떄문에 .. 암튼그래서 .을 다 인식함

 

시큐리티필터를 만들거나 암튼 필터를 만들떄 기존에 하던대로 .패턴 다 인정임

그걸 가늠해서 만들어야함

 

 

*

index.jsp 가져오면 됨

 

로그인 만들어야댐

 

담당하는 멤버컨트롤러 살리고

여기다만들어야지 딴데만들면 인식안됨

package kr.or.ddit.controller;

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

@Controller
@RequestMapping(value="/member")
public class MemberController {

	//지금까지 서블릿의 웹서블릿의 유알엘 규정, 핸들러에서의 유알엘프로퍼티.. 해왓지만
	//여기서는 메서드 위에 에노테이션으로 유알엘 규정
	
	@RequestMapping(value="/regist",method=RequestMethod.GET)
	public String registForm() {
		String url = "member/regist";
		return url;
	}
}

 

url : localhost/mvc

 

 

 

 

내일오전에 타일즈하고 AOP (관점지향적?) 한다

 

 

컨트롤러에대한 이슈 : 

리턴타입이 스트링만 있는게 아니고

req,. res 아직 안받았는데 우리 입맛대로 할수가잇다

 

**깃허브 팁

지운파일들은 스테이지에 올려주고

.MF랑 pom.properties