카테고리 없음

0303 오전수업

logloglog 2021. 3. 3. 12:48

 

서비스나 dao 는 순수 자바코드. 특정 프레임을 써서 만들지는 않음 첨가물이 없음 .. > 플레인요거트같은.. 포조!

포조를 조립만 할거임

 

조립하기 위한 클래스를 따로 만들거임

포조는 어떤 프레임워크를 가져오든지 포조를 그냥 가져와서 쓸수있게 만들어져있어야하는거임

 

needjarvis.tistory.com/585

 

포조(Plain Old Java Object, POJO) 이해하기

포조(Plain Old Java Object, POJO) 개념 스프링(Spring)을 공부 하거나, 자바를 공부하다보면 POJO(Plain Old Java Object)라는 용어를 자주 보게 될 것이다. 그때마다 뭔말이야? 하면서 넘어가는 경우가 많을텐..

needjarvis.tistory.com

POJO : 사용자가 작성하는 클래스들이 해당 프레임웍에 종속적이지 않으면 된다

 

스프링 프레임워크는 IoC(Inversion of Control, 제어의 역전) 컨테이너 안에서 POJO를 구성 및 관리하는 것이 가장 핵심으로 POJO를 매우 잘 다루는 프레임워크가 스프링 프레임워크이다.

 

스프링이 나오게 된 배경에 포조가있기때문에 잘 알아두면 좋다.

 

Java EE 등을 사용할 때에 비해서 특정 인터페이스를 구현하거나 상속 할 필요 없고 라이브러리를 지원하기에 용이하며 객체 또한 가벼운 것이 특징이다.


출처: https://needjarvis.tistory.com/585 [자비스가 필요해]

 

포조형태로 만드려면 dao단에 jdbc를써야함

(이래야 프레임웤의 영향을 받지않는다)

 

우리가쓰는 dao는 세션을 받아서스고잇음 트랜젝션을 구현하기위해서 서비스에서 세션을 받고 그 세션에 대한 트랜젝션을 수행하려고...

마이바티스는 알아서 롤백을 처리하기때문에 따로 롤백커밋이런거만들필요강벗음

서비스에서는 필드단에서 멤버변수로 나와잇는 세션을 할당받앗을거임

서비스에 팩토리를 인가하고 팩토리를 받은 서비스는 서비스할떄마다 오픈세션을 햇엇음

 

우리는 스프링에서 마이바티스 sql 세션을 쓰고잇지않음.

마이바티스-스프링의 sql 세션 (템플릿?)을 쓰고잇음 얘의 특징은 트랜젝션을 하지않는다

어떻게해야함? 결론: 서비스를 바꿔야함 (포조가 아니기 떄문에.. 마이바티스를 적용했기떄문에)

어떤식으로? 트랜젝션에 해당하는 부분은 이제 적용하지않음

트랜젝션은 어제따로만들어놧기떄문에 따로만들어놓은 트랜젝션을 인가할거임

 

서비스에서

팩토리를 가져와서 오픈세션하는건 바뀜.. 팩토리를 받아서 지가 오픈해서 세션 인스턴스를 만드는 형식이엇음..

어제 sqlsessiontemplate 가 줄거임 세션을 줄거라는 말임!

 

dao는

세션을 받아서썼었기떄문에 상관이없음

근데 이것도 마이바티스 적용할게아니라면 dao도 못쓰게됨 뒤집어엎어야함

 

서비스는 dao매서드호출하는거 뺴고 다 날릴거임

트랜젝션 매니저로 트랜젝션을 처리할거니까 세션필요없기떄문에

서비스는 dao 매서드 호출하면서 본 목적인 기능에대한 데이터처리에만 집중하면 된다

트랜젝션은 서비스가 진행될때 따로 감시하고 문제가 터지면 트랜젝션 매니저가 (서비스가아니라)롤백하는거임

즉 서비스가 세션을 dao에게 인가할 필요도 없어진다. 중복코드도 사라진다. 트라이캐치어쩌구 다 사라짐

>sql세션은 dao가 챙기면 되는거임

 

스프링을 쓰면 개발자의 역량 차이를 어느정도 해소할수있다

 


새로만들자

멤버단

 

dao는 해당 쿠ㅓ리 던지고 결과받아서 주는 역할만 할 뿐 데이터를 처리하는건 서비스

쿼리문 하나당 dao 하나임 그래야 조합이 바껴도 써먹을 수 있음

 

*잘라서 가져올경우에는 쿼리문에 조인이 다닥다닥붙음 (서버쪽에 부하.. 예전에 클라이언트보다 서버컴이 더 빠를떄 쓰던방법)

근데 요즘은 그게 아니니까 조인문도 안쓰고 가져와서 자른다 디비서버에 부하를 줄 필요가 없다. 쿼리문도 단촐해짐. 조인이없으니 이너뷰가 없으니까...

 

dao에서 하나씩 맵퍼 호출하게끔 만들어줘야 서비스에서 dao 호출해서 데이터 가공할수있게 한다

그리고 dao 에서는 서비스


 

인터페이스를 먼저 구성해야함

package kr.or.ddit.dao;

import java.sql.SQLException;
import java.util.List;

import kr.or.ddit.command.SearchCriteria;
import kr.or.ddit.dto.MemberVO;

public interface MemberDAO {
	//필요한 데이터를 가져오는 방식은 이렇게 하겠다.
	//브레인 스토밍으로 기능생각한것들
	//매퍼에잇는 각각의 sql 문들을 단독으로 실행할수있또록
	
		// 회원리스트
		List<MemberVO> selectMemberList(SearchCriteria cri) throws SQLException;

		// 검색 결과의 전체 리스트 개수
		int selectMemberListCount(SearchCriteria cri) throws SQLException;

		// 회원정보 조회
		MemberVO selectMemberById(String id) throws SQLException;

		// 회원정보 추가
		void insertMember(MemberVO member) throws SQLException;

		// 회원정보 수정
		void updateMember(MemberVO member) throws SQLException;

		// 회원정보 삭제
		void deleteMember(String id) throws SQLException;

		// 회원정지
		void disabledMember(String id) throws SQLException;

		// 회원 활성화
		void enabledMember(String id) throws SQLException;
}

 

리턴타입과 파라미터 등을 보고 서비스를 생각해야함
서비스의 기능은 이것들을 조합해서 만들수도 있고 1:1이면 같을수도있고,,

 

이제 포조를 만들어야함

 

스프링에 적용할 포조는

절대 싱글톤 패턴을 적용하면 안됨

싱글톤 패턴을 적용하면 외부에서 인스턴스를 못만든다 >> 의존주입을 못한다.

스프링컨테이너가 인스턴스을 외부에서 주입해야하는데 인스턴스 자체를 못만들기때문에 의존주입을 못하는것

 

*싱글톤으로 되어있는 클래스인데 여기에 어쨌든 스프링을 얹으려고 한다면? 인스턴스를 외부에서 만들수있어야하는데 (인스턴스를 못만들게 되어있는 상태에서) : 상속하면 됨.?? 상속할때 생성자 상속 안받음

근데 생성자가 private으로 잠겨잇어서 상속도안됨. 상속받아도 조상클래스의 생성자 호출할수없기떄문에 상속불가능

자식클래스에서 부모의 인스턴스를 갖고있으려고 상속하는건데... 암튼 상속도안됨

 

답은 래핑해야함 (수고스럽긴하지만)

그래서 애초에 싱글톤패턴을 사용하지않는게 현명하다

 

싱글톤과(인스턴스하나만만들어서쓰는게) 싱글톤 패턴(고정화시켜서 쓰는 패턴)은 다르다

 

스프링에서 컨테이너의 인스턴스들은 다 싱글톤임

주입할때마다 새로운 인스턴스를 할당하고싶다면?? <다음시간에

 

 

일단 임플

package kr.or.ddit.dao;

import java.sql.SQLException;
import java.util.List;

import org.apache.ibatis.session.SqlSession;

import kr.or.ddit.command.SearchCriteria;
import kr.or.ddit.dto.MemberVO;

public class MemberDAOImpl implements MemberDAO{
//클래스니까 인스턴스생성할수잇으니 빈등록할수잇고
	
	//제일먼저 해야할건 세션을 갖고있게 해야하므로
	private SqlSession sqlSession;
	
	//이 세션은 외부에서 주는거임
	public void setSqlSession(SqlSession sqlSession) {
		this.sqlSession = sqlSession;
	}

 

우리가 만든 클래스의 빈 등록은 application context에 (즉 데이터소스 (이미만들어진클래스의빈등록)와 구분을 하자)

 

application-context

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="memberDAO" class="kr.or.ddit.dao.MemberDAOImpl"
			p:sqlSession-ref="sqlSession"
			/>
</beans>


루트에 데이터소스가 임포트되어있고 어플리케이션도 루트에 임포트할꺼기때문에 어플리케이션에도 sqlsession잇는거랑 다름없다. 자동완성은 안되지만

멤버 dao가 sqlsession 주입받고있구나

 

 

11:26분경 rowbounds 설명...

 

	
	@Override
	public List<MemberVO> selectMemberList(SearchCriteria cri) throws SQLException {
		int offset = cri.getPageStartRowNum(); //시작행번호
		int limit = cri.getPerPageNum();//몇개씩가져올건지
		RowBounds rowBounds = new RowBounds(offset, limit);//잘라서 우리에게줌 (row 행 bounds 범위)
		
		List<MemberVO> memberList = null;
		
		memberList = sqlSession.selectList("Member-mapper.selectSearchMemberList",cri,rowBounds);
		
		return memberList;
	}

 

셀렉리스트는 오버로드되어있음 파라미터 1,2,3 개짜리 오버로딩되어있음 3개짜리는 로우바운즈는 짜르겟단 얘기임 몇행부터 몇개

 

디비에서 로우넘(지자체적으로 붙이는거)은 첫줄부터 0번지임 

1번페이지는 0번부터나옴 1페이지는 0~9번 2페이지는 10~19 번... 이런식

시작번지는 1을 뺀다음 10곱하면 시작번호가 나옴 pageStartRowNum을 그렇게 만들어놨음 페이지번호를 주면 시작행번호를 알수있도록

거기서부터 10개씩자른다 (PerpageNum)

그 offset이랑 limit을 rowbounds에게 주면 잘라서 가져온다

 

 

package kr.or.ddit.dao;

import java.sql.SQLException;
import java.util.List;

import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;

import kr.or.ddit.command.SearchCriteria;
import kr.or.ddit.dto.MemberVO;

public class MemberDAOImpl implements MemberDAO{
//클래스니까 인스턴스생성할수잇으니 빈등록할수잇고
	
	//제일먼저 해야할건 세션을 갖고있게 해야하므로
	private SqlSession sqlSession;
	
	//이 세션은 외부에서 주는거임
	public void setSqlSession(SqlSession sqlSession) {
		this.sqlSession = sqlSession;
	}
	
	@Override
	public List<MemberVO> selectMemberList(SearchCriteria cri) throws SQLException {
		int offset = cri.getPageStartRowNum(); //시작행번호
		int limit = cri.getPerPageNum();//몇개씩가져올건지
		RowBounds rowBounds = new RowBounds(offset, limit);//잘라서 우리에게줌 (row 행 bounds 범위)
		
		List<MemberVO> memberList = null;
		
		memberList = sqlSession.selectList("Member-mapper.selectSearchMemberList",cri,rowBounds);
		
		return memberList;
	}

	@Override
	public int selectMemberListCount(SearchCriteria cri) throws SQLException {
		int count=0;
		count = sqlSession.selectOne("Member-Mapper.selectSearchMemberListCount",cri);
		return count;
	}

	@Override
	public MemberVO selectMemberById(String id) throws SQLException {
		MemberVO member = sqlSession.selectOne("Member-Mapper.selectMemberById",id);
		return member;
	}

	@Override
	public void insertMember(MemberVO member) throws SQLException {
		sqlSession.update("Member-Mapper.insertMember",member);
	}

	@Override
	public void updateMember(MemberVO member) throws SQLException {
		sqlSession.update("Member-Mapper.updateMember",member);
	}

	@Override
	public void deleteMember(String id) throws SQLException {
		sqlSession.update("Member-Mapper.deleteMember",id);
	}

	@Override
	public void disabledMember(String id) throws SQLException {
		sqlSession.update("Member-Mapper.disabledMember",id);
	}

	@Override
	public void enabledMember(String id) throws SQLException {
		sqlSession.update("Member-Mapper.enabledMember",id);
	}

}

 

이제 테스트할거

 

package kr.or.ddit.dao;

import java.sql.SQLException;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import kr.or.ddit.dto.MemberVO;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:kr/or/ddit/context/root-context.xml")
public class TestMemberDAOImpl {
	
	@Autowired
	private MemberDAO memberDAO; 
	//root컨텍스트로 인해 만들어지는 스프링 컨테이너조회에서 멤버dao과 같은 타입의 인스턴스 가져다줄거임

	//미미라는 애들 검색했을떄 잘 가져오는가
	@Test
	public void testSelectMember() throws SQLException{
		String id = "mimi";
		MemberVO member = memberDAO.selectMemberById(id);
		Assert.assertEquals(id,member.getId());
	}
}

 

만약 인서트를 테스트하면 실제로 디비에 들어감 > 문제임!왜 ? 테스트는 한번하건 두번하건 같아야함 (재연성이있어야함) 근데 인서트로 테스트하면 그게불가능

처음은 성공할거임 두번째 하면 터짐 (unique 제약위반 익셉션) >> 재연성이없다.

그렇다고 인자를 바꾸는건 변인통제위반

 

일단 해보자

	@Test
	public void testInsertMember() throws SQLException{
		MemberVO testMember = new MemberVO();
		testMember.setId("kaka");
		testMember.setPwd("kaka");
		testMember.setName("kaka");
		testMember.setEmail("kaka@kaka.net");
		testMember.setPhone("000-0000-0000");
		testMember.setPicture("noImage.jpg");
		
		memberDAO.insertMember(testMember);
		MemberVO result = memberDAO.selectMemberById(testMember.getId());
		
		Assert.assertEquals(testMember.getId(), result.getId());
	}
    

첫번째
두번째

 

이거 해결?

인서트끝난후에 커밋을 해서 그런거임

 

어떻게해야댐

커밋하면안되고 롤백을 해야함

인서트가 되는지안되는지에 대한 실험이기때문임

 

우린 트랜젝션 매니저를 따로만들어놨기떄문에 얘한테 명령을 하면 됨 근데 만들어놧음

 

일단 디비가서 kaka 지우고

 

우리가 만들엇던 트랜젝션 매니저 호출한다.

이렇게만 해주면 알아서 찾아서 가져옴

 

가져왓으니 롤백이 필요한곳에 지정하면 됨

 

롤백이 필요한곳에 이것만 적어주면 됨

이제 몇번을 해도 ok

 

중요한건 멤버브이오를 만들어서 주는거임.. 받아올수없으니까


서비스가자

 

dao에게 넘겨줘야할건 서비스도 받아야한다는걸 생각하면서 만들면 됨

그리고 기능단위로 메서드 만들기

dao는 쿼리문 단위로 만들고, 서비슨느 기능의 단위로 만들면 됨

 

package kr.or.ddit.service;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import kr.or.ddit.command.SearchCriteria;
import kr.or.ddit.dto.MemberVO;
import kr.or.ddit.exception.InvalidPasswordException;
import kr.or.ddit.exception.NotFoundIDException;

public interface MemberService {
	// 로그인
	void login(String id, String pwd) throws SQLException, NotFoundIDException, 
													InvalidPasswordException;

	// 회원리스트조회
	List<MemberVO> getMemberList(SearchCriteria cri) throws SQLException;
	
	Map<String,Object> getSearchMemberList(SearchCriteria cri) throws SQLException;

	// 회원정보조회
	MemberVO getMember(String id) throws SQLException;

	// 회원등록
	void regist(MemberVO member) throws SQLException;

	// 회원수정
	void modify(MemberVO member) throws SQLException;

	// 회원삭제
	void remove(String id) throws SQLException;

	// 회원정지
	void disabled(String id) throws SQLException;

	// 회원활성
	void enabled(String id) throws SQLException;
}

익셉션도 만들고

 

구현체를 만들어야함

*기존과의 차이점 : 이번에 만드는 서비스는

1. dao를 셋메서드를 이용해서 인스턴스받아내도록 해야하고, 

2. sql세션팩토리를 받질않음. 그래서 오픈세션할필요없다.

 

 

가져오기

package kr.or.ddit.service;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.apache.ibatis.session.SqlSession;

import kr.or.ddit.command.PageMaker;
import kr.or.ddit.command.SearchCriteria;
import kr.or.ddit.dao.MemberDAO;
import kr.or.ddit.dto.MemberVO;
import kr.or.ddit.exception.InvalidPasswordException;
import kr.or.ddit.exception.NotFoundIDException;

public class MemberServiceImpl implements MemberService {
	
	//memberDAO를 멤버로 가지고잇고 인스턴스는 의존주입 되는형해
	private MemberDAO memberDAO;
	public void setMemberDAO(MemberDAO memberDAO) {
		this.memberDAO = memberDAO;
	}

	//sql세션팩토리는 받지않는다 (dao가 가지고잇다)
	//서비스는 어떤 dao를 호출해서 기능할것인가에대한 본래목적에만 충실하면 됨
	//트랜젝션 부분은 따로구현할거임 (관점지향적)

	@Override
	public void login(String id, String pwd, HttpSession session) throws SQLException, NotFoundIDException, InvalidPasswordException {
		//session은 컨트롤러가 줄거임
		MemberVO member = memberDAO.selectMemberById(id);
		if (member == null)
			throw new NotFoundIDException();
		if (!pwd.equals(member.getPwd()))
			throw new InvalidPasswordException();
		
		//유효시간은 6분
		session.setAttribute("loginUser", member);
		session.setMaxInactiveInterval(6*60);
		
	}

	@Override
	public List<MemberVO> getMemberList(SearchCriteria cri) throws SQLException {
		List<MemberVO> memberList = (List<MemberVO>)getSearchMemberList(cri).get("memberList");
		return memberList;
	}

	@Override
	public Map<String, Object> getSearchMemberList(SearchCriteria cri) throws SQLException {
		List<MemberVO> memberList = memberDAO.selectMemberList(cri);

		PageMaker pageMaker = new PageMaker();
		pageMaker.setCri(cri);
		pageMaker.setTotalCount(memberDAO.selectMemberListCount( cri));

		Map<String, Object> dataMap = new HashMap<String, Object>();
		dataMap.put("memberList", memberList);
		dataMap.put("pageMaker", pageMaker);

		return dataMap;
	}

	@Override
	public MemberVO getMember(String id) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void regist(MemberVO member) throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	public void modify(MemberVO member) throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	public void remove(String id) throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	public void disabled(String id) throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	public void enabled(String id) throws SQLException {
		// TODO Auto-generated method stub

	}

}