내가 보려고 정리하는/Spring

웹 : datasource-context : 0410

보동이용용 2023. 4. 10. 17:51
반응형

1. req가 들어오면 

2. 리스너가 작동 -> Root 컨텍스트 먼저 형성 -> ( P.L > B.L.L ): D.L 형태를 가지고 이동

==> Mybatis관련 bean들도 상위에 등록해야한다. >> 오늘할일!

3. D.S > C.L

어노테이션을 기반으로 정보를 수집하는 Handler Mapping

동적인 요청을 하는 컨트롤러였다. 정적인 요청도 가져왔다. 이것을 처리핸들러구조가 필요하다. 그래서 H.M이 하나가 아니고 RMHM , simpleUrlHandlerMapping이 하나 더 작동하고 있다.

HandlerAdapter를 통해서 컨트롤러를 실행한다.

spring의 가장 큰 전략은 POJO이다. << 정해진 규칙이 없다. (이름, 리턴타입, 파라미터 규칙이 없어.) 핸들러 어댑터입장에서는 실행할 메서드의 시그니쳐가 너무 다양해서 HMAR의 구현체를 통해서 판단하고 실행시킨다.

이 부분이  D.S.Container 하위 컨테이너

M/V를 넘긴다. 이것을 req에 핸들러 어댑터가 옮겨 담아준다.

view는 디스패쳐에게 넘기고 그것을 다시 ViewResolverSSSSSSS에게 전달한다. 

필터는 스프링컨테이너 밖에있고 서블릿 컨테이너인 톰캣 안에 있다.

1.encording 2. principal 3.multipart 

multipart 원본인지 확인하고 원본이면 WR로 보냄.

상위 컨테이너에 filterMultipartResolver로 넣어뒀다. 이 아이디가 바뀌면 multipartFilter는 이것을 찾지 못한다. 

왜 상위일까? web.xml에 등록된 순서를 보면 root > filter > servlet 그렇기 때문에 상위에다가 등록해야한다. 아직 하위는 생성도 되기 전이기 때문!!!!!!


복습끝!


🚩오늘할일 

- 마이바티스를 상위에 등록하여 사용해보기

- 뷰리졸버를 독립적으로 사용할 수 있는 타일즈를 추가하기 위해 뷰 리졸버를 하나 더 추가할 것이다. 

- H/V와 스프링의 연동구조 >> ValidateUtils 빠잉~


▶PropertyDAOImpl_FS

1.@Repository("propDao_Fs") 로 bean 등록

@PostConstruct //주입이 끝난 후 이 life cycle callback 이 실행된다.
public void loadData() {

2.init으로 수정

@Value("classpath:kr/or/ddit/props/DataStore.properties") // property editor 에 의해 값이 변환된 후 주입됨.
private File propFile;

 

▶PropertyServiceImpl1  : file system

PropertyServiceImpl3  : DB

각기 다른 인젝션

 

▶PropertyContollerServlet  : 1번받아야해

▶JdbcPropertiesControllerServlet:  : 3번받아야해

 

- serviceImple을 bean으로 등록한다.(id 설정 필요)

-controller도 bean등록하고 injection 주입한다.

- 라이프 사이클 콜백 등록하고 

-

 

Rest

(state 상태를 표현하는 방식 >> 주고받는 요청에는 데이터만 포함이지 UI는 포함시키지 않는다. 응답데이터 형식이 HTML이면 안된다. Rest로 교환될때는 대부분의 형식은 json or xml 이다.)

rest의 기본은 파라미터 존재하지 않는다.

// PostRedirectGet pattern
@PostMapping
protected String doPost(@RequestBody PropertyVO newProp) {
//		PropertyVO newProp = RequestBodyProcessor.getContentFromRequestBody(req, PropertyVO.class); //언마샬링
    service.createProperty(newProp);
//		resp.sendRedirect(req.getContextPath() + "/props");
    return "redirect:/props";
}

 

 


buyerList를 비동기로 바꾸기

1. buyerList.jsp를 본다.

본다.....또본다..... 보고 또 본다.... 모르겠다.....ㅎㅎ

다시 본다..

1. event.preventDefault(); 이벤트를 막는다.

2.ajax한테 보낼 정보들을 뽑는다.

url, method, dataType, contentType, data

>>consume 이랑 proce....를 설정한다. Header!! rest필요한지 판단한다.

3.결과를 받으면 done에서 설정한다.

이제 해보자 !!


▶BuyerListController

▶BuyerList.jsp

el이 상관없다. model을 가져오지 않으니

1페이지를 요청한 것이 첫화면

 

이 결과를 티바디에 넣기

<%--<c:set var="buyerList" value="${pagination.dataList }"/> --%>
<%--<c:if test="${not empty buyerList }"> --%>
<%--	<c:forEach items="${buyerList }" var="buyer"> --%>
<%--		<c:url value="/buyer/buyerView.do" var="viewURL"> --%>
<%--			<c:param name="what" value="${buyer.buyerId }"/> --%>
<%--		</c:url> --%>
<!-- 		<tr> -->
<%-- 			<td>${buyer.rnum }</td> --%>
<%-- 			<td><a href="${viewURL }">${buyer.buyerName }</a></td> --%>
<%-- 			<td>${buyer.lprodNm }</td> --%>
<%-- 			<td>${buyer.buyerAdd1 }</td> --%>
<%-- 			<td>${buyer.buyerCharger }</td> --%>
<%-- 			<td>${buyer.buyerMail }</td> --%>
<%-- 			<td>${buyer.buyerComtel }</td> --%>
<%-- 			<td>${buyer.prodCnt }</td> --%>
<!-- 		</tr> -->
<%-- 	</c:forEach> --%>
<%--</c:if> --%>
<%--<c:if test="${empty buyerList }"> --%>
<!--	<tr> -->
<!--		<td colspan="8">거래품목 없음</td> -->
<!--	</tr> -->
<%--</c:if> --%>

원래 티바디에 있던 것들은 지워진다.

 

searchForm.get(0).reset();

reset html소스 쓰기 위해서 get(0)으로 html 로 serchForm 만들어주기!!


이제 Mybatis를 spring과 연결해보자!

mybatis연결해보자. 

mybatis spring 이 더 필요하다.

 

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>3.0.1</version>
</dependency>

설치

▶datasource-context.xml (상위 컨텍스트 -context.xml형태로 만들어서 자동으로 등록된다.)

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

빈등록>> factorybean >> factory에서 생성되는 객체를 빈으로 등록하는것

sql session factory factory bean >> 이제 bulid따로 안해도 된다.

 

<!-- Mybatis + Spring 을 위한 추가 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

 

<context:property-placeholder location="classpath:kr/or/ddit/db/dbinfo.properties"/>
	
<bean class="org.apache.commons.dbcp2.BasicDataSource" 
    p:driverClassName="${driverClassName}"
    p:url="${url}"
    p:username="${user}"
    p:password="${password}"
    p:initialSize="${initialSize}"
    p:maxTotal="${maxTotal}"
    p:maxWaitMillis="${maxWait}"
/>

context propertyplaceholder로 등록하고 bean으로 값을 등록한다.

spring el은 사용할 수 없다. context에 id가 없어서 placeholder로 쓴다.

placeholder에는 연산자 쓸수 없다.그냥 구멍내놓은 것 뿐

 

maindb.driverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
maindb.url=jdbc:log4jdbc:oracle:thin:@localhost:1521:xe
maindb.user=LDY92
maindb.password=java

maindb.initialSize=2
maindb.maxTotal=2
maindb.maxWait=2000

 

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

사이트 소스 참고한 내용.

맵퍼프록시를 대신 생성해주고 클래스를 주면 인터페이스를 받는다. 프록시는 부하가 큰데 만들었다 지웠다를 반복하던 기존 방법과 달리 여기서 한번 생성해준다.

더좋은 방법이 있다.

@Configuration
public class MyBatisConfig {
  @Bean
  public UserMapper userMapper() throws Exception {
    SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory());
    return sqlSessionTemplate.getMapper(UserMapper.class);
  }
}

이 자바 컨피그 방식을 xml방식으로 등록해보자.

 

▶ buyerDAOImpl (첫번째 방법)

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" 
    c:sqlSessionFactory-ref="sqlSessionFactory"
/>

결국 필요한건 sqlsession이기 때문에 이걸 빈으로 등록하고 buyerdaoimpl에가서 injection을 추가하면 try블록이 사라질 수 있다.

 

 

 

▶prodImple은다른방식으로해보자(두번째 방법)

@Repository
public class ProdDAOImpl extends SqlSessionDaoSupport implements ProdDAO{ 

//SqlSessionDaoSupport

SqlSessionDaoSupport추상 클래스를 상속받았다. 이것이 무엇인지 살펴보면, 

▷SqlSessionDaoSupport >> 추상클래스이다.

public abstract class SqlSessionDaoSupport extends DaoSupport {

  private SqlSessionTemplate sqlSessionTemplate;

SqlSessionTemplate을 받고 있다.(SqlSessionTemplate에 들어가보면 SqlSession을 또 받아 쓰고 있다.)

부모의 것은 자식이 자유롭게 사용할 수 있다. 

@Override
public int insertProd(ProdVO prod) {
    ProdDAO mapperProxy = getSqlSessionTemplate().getMapper(ProdDAO.class);
    return mapperProxy.insertProd(prod);
}

ProdDAOImpl이 sqlSessionDaoSupport를 상속받음으로써 부모에 있는 SqlSessionTemplate을 사용할수 있으나 

sqlSessionTemplate이 private으로 접근제한되어있기 때문에 getter로 받아왔다.

그런데 지금은 자동으로 인젝션이 되지 않기 때문에 null이 뜬다.

내부모가 인젝션을 못받으니까 내가 대신 받는다.

@Inject
@Override
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    super.setSqlSessionTemplate(sqlSessionTemplate);
}

 부모를 setter로 받은후 inject한다.

 

▶datasource-context.xml, MemberDAOImpl (세번째방법)

<mybatis-spring:scan base-package="kr.or.ddit.member.dao"/>

 

스캔하다가 interface를 만나면 proxy를 자동으로 등록해준다. daoimpl필요 없음 삭제.

모든 인터페이스가 다 프록시가 생성된다.? 생성이 필요 없는 애들도 있을텐데?

<mybatis-spring:scan base-package="kr.or.ddit.member.dao"
    annotation="org.apache.ibatis.annotations.Mapper"
/>
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface Mapper {
  // Interface Mapper
}

이 맵퍼어노테이션을 가진 대상만 프록시를 생성한다.

@Mapper
public interface MemberDAO {

이 MemberDAO는 이제 @Mapper어노테이션에 의해 스캔되어 프록시가 생성될 것이다. 그러므로 이 interface를 구현하는 DAOImpl구현체는 더이상 필요하지 않다. 삭제!

 

▶propsdao도 추가시키고 싶어!!!(세번째 방법을 활용해보자.)

<mybatis-spring:scan base-package="kr.or.ddit.**.dao"

댑스구조를 와일드카드로 바꿔버려. 그러면 기본패키지 않에서 dao패키지로 끝나는 패키지는 모두 스캔대상으로 등록된다.

<mybatis-spring:scan base-package="kr.or.ddit.**.dao"
    annotation="org.apache.ibatis.annotations.Mapper"
    factory-ref="sqlSessionFactory" 
/>

아까 어노테이션 설정 걸었던 곳에 factory-ref="sqlSessionFactory" 맵퍼정보만 추가했다.

내부적으로 프록시가 생성되어야해서 그 구현체를 생성해주려는아이가 jdk내부적으로 있는 아이가 해주려는 것. 

다오에 일정부분 코드가 필요한 경우가 있다. 비지니스의 특수한 코드는 스프링이 만들어줄 수 없기에 1번이나 2번 방법을 쓴다. 그런데 그렇지 않은 경우에는 3번을 쓴다.


순서를 정리해보자.

마이바티스와 스프링을 연동하기 위해

1.필요한 의존성 

pom.xml  >> spring-orm  (Mybatis[JPA, iBatis, Hibernate])  >>mybatis-spring

2.configation.xml

프로퍼티스파일, 프로퍼티정보를 가져오기위한 인바이런먼트소스 들을 가지고 와서

그게 datasource-context.xml 로 보낸다.

3. datasource-context.xml

SqlSessionFactoryBean 에  datasource injection

와이드카드 이용해서 맵퍼 등록함.

 

최프하면 팀으로 공동으로 사용한다. 테스트하지 않고 커밋을 해버리면? 사용하고 있는 맵핑파일의 10개중 한개만 안되도 어플리케이션 자체가 실행이 안된다. 내가 만든 xml그냥 올리면 안된다. 단위테스트를 통해 확인된 것들만 커밋해야한다.

 


오전에 못했던 select 태그들 수정해보자.

select 태그 하드코딩 없애기! (ControllerAdvice)

 

lprod는 prod, buyer보다 더 상위개념

▶OthersDAO

buyerList

buyerInsert

buyerUpdate

prodList

prodInsert

상품 수정은 선택 안하니까 괜찮아

 

@ModelAttribute를 메서드에도 쓸 수 있다.

1. 모델을 req에 넣겠다.

2. 모델의 이름을 결정하겠다. 

 

@ModelAttribute("lprodList")
public List<Map<String, Object>> lprodList(){
    return othersDAO.selectLprodList()
}

set Attribute의 기능을 한다.

1.메서드가 핸들러어댑터에 의해 실행된다.

2. 모델을 req에 넣는다.

2. 이름 싱글밸류의 밸류로 

 

두개의 핸들러 메서드가 실행되기 전에 모델 어트리부트 어노테이션을 먼저 모델 어트리부트로 넣어준다.

관련된 곳 모두에 넣으려니 불편...!!

 

Advice로 해결해보자.

▶servlet-context.xml

<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>

<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>

저번에 궁금해했던 이코드 !!! 알아보자.

 

@ControllerAdvice(basePackages = { "kr.or.ddit.prod.controller", "kr.or.ddit.buyer.controller" })
public class OthersControllerAdvice { 

    @Inject private OthersDAO othersDAO; 
    @ModelAttribute("lprodList") 
    public List<Map<String, Object>> lprodList() { 
        System.err.println("============lprodList==========="); 
        return othersDAO.selectLprodList(); 
    } 

    @ModelAttribute("buyerList") 
    public List<BuyerVO> buyerList() { 
   		System.err.println("============buyerList==========="); 
        return othersDAO.selectBuyerList(); 
    } 
}

 

중복되고 있는 코드를 분리해서 책임을 분리하는 것.

위빙이 되고 있다.

위빙이란, 원본 로직에 부가 기능 로직 추가되는 것을 말한다

멤버는 이 구조가 필요가 없다. >> 선별적 어드바이스가 필요하다.

모든 컨트롤러에서 공통적으로 가져가야하는 모델이 있을때 사용할 수 있다.


controller 대상으로 spring과 연결된 junit테스트케이스를 해보자.

 

Mock 객체 (test용 가짜 객체)를 만들어준다.

서버를 돌리지 않으면 req, resp가 없고 그러면 controller를 실행할수없어서 못했었다. 

그런데 이것을 통해 가능하게 되었다.

easy moke 눈여겨보기

테스트 방법

 

반응형