MVC 기능 수행 과정
웹 -> DispatcherServlet -> HandlerMapping -> Controller -> ModelAndView
-> DispatcheerServlet -> ViewResolver -> View -> DispatcheerServlet -> 웹
web.xml - ContextLoaderListener를 사용해서 빈 설정 XML 파일 읽어들이기
action-servlet.xml - 스프링에서 필요한 여러가지 빈 설정
action-dataSource.xml - 스프링 JDBC 설정에 필요한 정보 설정
jdbc.properties - 데이터베이스 연결 정보 저장
action-service.xml - 서비스 빈 생성 설정
//web.xml
//여러 설정 읽기위해 ContexetLoaderListener 설정
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
//ContexetLoaderListener로 해당위치의 설정 파일 읽어들이기
/WEB-INF/config/action-service.xml
/WEB-INF/config/action-dataSource.xml
</param-value>
</context-param>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
//action-servlet
...
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="memberController" class="com.spring.member.controller.MemberControllerImpl">
<property name="methodNameResolver">
<ref local="methodResolver" />
</property>
<property name="memberService" ref="memberService" />
</bean>
<bean id="methodResolver"
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/member/listMembers.do">listMembers</prop>
<prop key="/member/addMember.do">addMember</prop>
<prop key="/member/memberForm.do">memberForm</prop>
<prop key="/member/memberDetail.do">memberDetail</prop>
</props>
</property>
</bean>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/member/*.do">memberController</prop>
</props>
</property>
</bean>
</beans>
//action-service.xml
...
<bean id="memberService" class="com.spring.member.service.MemberServiceImpl">
<!--memberService bean memberDAO 속성에 memberDAO 빈을 주입시킨다 -->
<property name="memberDAO" ref="memberDAO" />
</bean>
//action-dataSource.xml
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- jdbc.properties에서 설정정보를 가지고온다 -->
<value>/WEB-INF/config/jdbc.properties</value>
</list>
</property>
</bean>
<!-- jdbc.properties 4가지 설정정보로 SimpleDriverDataSource 빈 생성시에 DB에 연결한다 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- memberDAO에 주입해준다 -->
<bean id="memberDAO" class="com.spring.member.dao.MemberDAOImpl">
<property name="dataSource" ref="dataSource" />
</bean>
//jdbc.properties
jdbc.driverClassName = oracle.jdbc.driver.OracleDriver
jdbc.url = jdbc:oracle:thin:@localhost:1521:orcl
jdbc.username = ''
jdbc.password = ''
XML파일에 의한 주입되는 과정
1. memberController <- 2. memberService <- 3.memberDAO <- 4.dataSource
4 -> 3 : action-dataSource.xml
3 -> 2 : action-service.xml
2 -> 1 : action-servlet.xml
주의해야할점!!!
xml에서 대입을 해줄때 설정파일에서 생성된 빈을 주입하기 위해서 반드시 setter을 구현해야한다
DAO에서 jdbcTemplate를 사용하여 SQL을 사용해도된다
//MemberDAOImpl.java
public List selectAllMembers() throws DataAccessException {
String query = "select id,pwd,name,email,joinDate"
+ " from t_member "
+ " order by joinDate desc";
List membersList = new ArrayList();
membersList = this.jdbcTemplate.query(query, new RowMapper(){
public Object mapRow(ResultSet rs, int rowNum) throws SQLException{
MemberVO memberVO = new MemberVO();
memberVO.setId(rs.getString(("id")));
memberVO.setPwd(rs.getString(("pwd")));
memberVO.setName(rs.getString(("name")));
memberVO.setEmail(rs.getString(("email")));
memberVO.setJoinDate(rs.getString(("joinDate")));
return memberVO;
}
});
return membersList;
}
위의 것들은 Spring JDBC의 기능인데, 실제 개발을 진행할때는
MyBatis나 Hibernate를 사용하여서 데이터베이스 연동을 하게된다.
하지만 위의 내용들을 알아두면 도움이 된다.
참고 : pro22
애플리케이션의 규모가 작을때는 기존의 JDBC를 이용해서 충분히 할수있었지만,
규모가 커졌을때에는 기존의 JDBC의 한계가 있다.
그래서 나온것이 MyBatis같은 데이터베이스 연동프레임워크가 나오게되었다.
기존 JDBC 연동
connection -> Statement 객체 생성 -> SQL문 전송 -> 결과 반환 -> close
이 방식의 단점은 SQL문이 기본 프로그래밍 코드에 섞인다는것.
MyBatis 특징
1. SQL을 소스코드가 아닌 XML로 분리
2. SQL과 프로그래밍 코드를 분리해서 구현
3. 데이터소스기능 트랜잭션 처리 기능
MyBatis 설정 파일
SqlMapConfig.xml : 데이터베이스 연동시 반환되는 값을 저장할 빈,트랜잭션,데이터소스 등 마이바티스 관련 정보 설정(데이터 연동 기능)
ex)member.xml : 원하는 sql문을 태그별로 정리해서 지정해둠
List selectList(query_id) : id에 대한 select 문을 실행후 여러 레코드 List로 반환
List selectList(query,id, 조건) : 위와 동일하나 조건도 전달
int insert(query,id Object obj) : id에 대한 insert문 및 obj 객체의 값 추가
int update(query,id Object obj) : obj 객체의 값으로 id에 대한 update문 실행
int delete(query,id Object obj) : obj 객체의 값으로 id에 대한 delete문 실행
//SqlMapConfig.xml
<configuration>
<typeAliases>
<typeAlias type="com.spring.ex01.MemberVO" alias="memberVO"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--DB 연결 설정 -->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="JDBC:oracle:thin:@localhost:1521:orcl" />
<property name="username" value=" " />
<property name="password" value=" " />
</dataSource>
</environment>
</environments>
<mappers>
<!-- member.xml을 읽어들이기 -->
<mapper resource="mybatis/mappers/member.xml"/>
</mappers>
</configuration>
//member.xml
//select, insert, update, delete태그로 나타내고
//각각의 원하는 id, parameterType을 적어준뒤
//dao에서 namespace를 통하여 접근하여서 원하는 sql의 id를 통해 sql 가져오기
<mapper namespace="mapper.member">
<!-- memberVO에 저장 -->
<resultMap id="memResult" type="memberVO">
<result property="id" column="id" />
<result property="pwd" column="pwd" />
<result property="name" column="name" />
<result property="email" column="email" />
<result property="joinDate" column="joinDate" />
</resultMap>
<!--id를 가지고 DAO에서 호출하고, 반환되는 값들을 resultMap에 넣어준다-->
select id="selectMemberByPwd" resultMap="memResult" parameterType="int" >
<![CDATA[
select * from t_member
where
pwd = #{pwd}
]]>
</select>
<insert id="insertMember" parameterType="memberVO">
<![CDATA[
insert into t_member(id, pwd, name, email)
values(#{id}, #{pwd}, #{name}, #{email})
]]>
</insert>
<insert id="insertMember2" parameterType="java.util.HashMap">
<![CDATA[
insert into t_member (id, pwd, name, email)
values(#{id}, #{pwd}, #{name}, #{email})
]]>
</insert>
<update id="updateMember" parameterType="memberVO">
<![CDATA[
update t_member
set pwd=#{pwd}, name=#{name}, email=#{email}
where id=#{id}
]]>
</update>
<delete id="deleteMember" parameterType="String">
<![CDATA[
delete from t_member
where
id=#{id}
]]>
</delete>
</mapper>
//MemberDAO.java
...
public class MemberDAO {
private static SqlSessionFactory sqlMapper=null;
public static SqlSessionFactory getInstance(){
if(sqlMapper==null){
try{
String resource = "mybatis/SqlMapConfig.xml";
Reader reader = Resources.getResourceAsReader(resource);
//myBatis를 이용하는 sqlMapper 객체 가져오기
sqlMapper = new SqlSessionFactoryBuilder().build(reader);
reader.close();
}catch(Exception e){
e.printStackTrace();
}
}
return sqlMapper;
}
public List<MemberVO> selectMemberByPwd(int pwd) {
//sql의 instance를 가져와서 session을 open
sqlMapper = getInstance();
SqlSession session = sqlMapper.openSession();
List<MemberVO> membersList = null;
//session의 selectList 메소드를 사용(여러개가 있을수 있으므로 List로 받아온다)
membersList = session.selectList("mapper.member.selectMemberByPwd", pwd);
return membersList;
}
public int insertMember(MemberVO memberVO) {
sqlMapper = getInstance();
SqlSession session = sqlMapper.openSession();
int result = 0;
result = session.insert("mapper.member.insertMember", memberVO);
session.commit();
return result;
}
public int insertMember2(Map<String, String> memberMap) {
sqlMapper = getInstance();
SqlSession session = sqlMapper.openSession();
int result = session.insert("mapper.member.insertMember2", memberMap);
session.commit();
return result;
}
public int updateMember(MemberVO memberVO) {
sqlMapper = getInstance();
SqlSession session = sqlMapper.openSession();
int result = session.update("mapper.member.updateMember", memberVO);
session.commit();
return result;
}
public int deleteMember(String id) {
sqlMapper = getInstance();
SqlSession session = sqlMapper.openSession();
int result = 0;
result = session.delete("mapper.member.deleteMember", id );
session.commit();
return result;
}
}
동적 SQL문을 구성하는 요소들
1. if
2. choose(when, otherwise)
3. trim(where, set)
4. foreach
<where>
<if test="조건식">
</if>
</where>
<where>
<if test="name != '' and name != null">
name = #{name}
</if>
<if test="email != '' and email != null ">
and email = #{email}
</if>
</where>
<choose>
<when test="">
</when>
<otherwise>
구문 n+1;
</otherwise>
</choose>
<where>
<choose>
<when test="name != '' and name != null and email != '' and email != null">
name=#{name} and email=#{email}
</when>
<when test="name != '' and name != null">
name=#{name}
</when>
<when test="email != '' and email != null">
email=#{email}
</when>
</choose>
</where>
<foreach item="item" collection="list" index="index" open="(" close=")" separator=",">
#{item}
</foreach>
where name in
<foreach item="item" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
order by joinDate desc
<sql id="a">
<![CDATA[
select * from t_member
]]>
</sql>
<select id="foreachSelect" resultMap="memResult" parameterType="java.util.Map">
<include refid="a" />
<!--include 부분으로 sql문을 넣어줄수있다. -->
<!--<![CDATA[
select * from t_member
]]>-->
where name in
<foreach item="item" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
order by joinDate desc
</select>
Mybatis tip **
마이바티스에서 오라클의 like를 검색할때는 '%' 기호와 조건값사이에 반드시 ||기호를
사용해서 연결해주어야한다.
//아래와 같이하면 에러
<![CDATA[
select * from t_member
where name like '%'#{name}'%'
]]>
//아래와 같이
<![CDATA[
select * from t_member
where name like '%' || #{name} || '%'
]]>
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>/WEB-INF/config/jdbc.properties</value>
</property>
</bean>
//jdbc.property 읽어들이기
<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
//datasource 속성에 datasource 빈 생성
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
//modelconfig 설정
<property name="configLocation"
value="classpath:mybatis/model/modelConfig.xml" />
//mapper안에 모든 .xml파일들 들여와 설정
<property name="mapperLocations" value="classpath:mybatis/mappers/*.xml" />
</bean>
// sqlsessionTemplate 클래스 사용하여 sqlsession 빈 생성
<bean id="sqlSession"
class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
// sqlsession 빈을 memberDAO 빈 속성에 주입
<bean id="memberDAO"
class="com.spring.member.dao.MemberDAOImpl">
<property name="sqlSession" ref="sqlSession"></property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/member/" />
<property name="suffix" value=".jsp"/>
</bean>
<bean id="memberController"
class="com.spring.member.controller.MemberControllerImpl">
<property name="methodNameResolver">
<ref local="memberMethodResolver"/>
</property>
<property name="memberService" ref="memberService"/>
</bean>
<bean id="memberMethodResolver"
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver" >
<property name="mappings" >
<props>
<prop key="/member/listMembers.do" >listMembers</prop>
<prop key="/member/addMember.do" >addMember</prop>
<prop key="/member/removeMember.do">removeMember</prop>
<prop key="/member/memberForm.do" >form</prop>
</props>
</property>
</bean>
<bean id="memberUrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/member/*.do">memberController</prop>
</props>
</property>
</bean>