본문 바로가기

programming/Gukbi

국비 교육 77일차 - spring Autowired, web 연결

728x90
반응형

럭키 77

 

오늘도 역시 이어서 spring 기본 문법을 배웠다. 사실 꼭 필수적인 부분인데 문법만 배우는건 쉽게 지루해진다..

그래도 정신차리고 열심히 정리를 해야지

 

기본 개념 다시 정리

 

1. 스프링: 여러 클래스들을 모아서 관리해주는 컨테이너.

객체의 생성부터 객체의 소멸까지 다운다. 스프링은 이미 만들어져 있는 라이브러리이기 때문에 자바소스코딩을 할 수 없다. 

 

스프링으로 클래스를 관리하는 방법에는 두 가지가 있다. 

1) XML

2) Annotation

 

먼저 XML은 <bean> 태그를 이용해서 메모리를 할당해준다. id는 해당 객체를 찾을 수 있게 해주는 명칭같은 것이다. 

app.xml 파일에서 필요한 클래스들을 모아주고 시작하면 된다. 

 

<?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="movieDao" class="com.sist.main.MovieDAO"
	p:sqlSessionFactory-ref="ssf"
/>
</beans>

  위의 코드를 보면 DAO 클래스의 메모리 생성을 해주고 있다. app.xml 파일에서 해주고 있다. 

 

package com.sist.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.*;
public class MainClass {

	public static void main(String[] args) {
		String[] xml={"datasource.xml", "muisc_app.xml", "movie_app.xml"};
		ApplicationContext app=
				new ClassPathXmlApplicationContext(xml);
		MusicDAO musicdao=(MusicDAO)app.getBean("musicDao");
		MovieDAO moviedao=(MovieDAO)app.getBean("movieDao");
		
		// 스프링에서 생성된 객체를 얻어오면 => 객체에서 필요한 메소드 호출
		List<MovieVO> mList=moviedao.movieListData();
		List<MusicVO> nList=musicdao.musicAllData();
	}

}

 그리고 MainClass에서 이렇게 메모리를 생성한 객체를 getBean을 통해서 얻어오고, 객체에서 필요한 메소드를 호출할 수 있게 된다. 

 

2) Annotation

어노테이션으로 클래스 메모리를 할당하는 방법도 있다. 사용방법은 사용할 클래스 위에 @(Annotaion)을 올려주는 것이다. 

<?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:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<context:component-scan base-package="com.sist.main2"/>
	<!-- 패키지 단위로 메모리 할당 -->
</beans>

 

어노테이션을 사용한 패키지의 app.xml 파일

위의 xml을 이용한 방법과는 다르게, 클래스 단위가 아닌 패키지 단위로 메모리를 할당한다. 

package com.sist.main2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

@Component("mc")
public class MainClass {
	// 스프링에서 같은 클래스명을 가지고 있는 저장된 객체주소를 자동으로 찾아서 대입 (자동주입)
	// 스프링에서 Sawon 객체를 자동으로 찾아주는 것 
	@Autowired
	private Sawon sa;
	
	
	public static void main(String[] args) {
		ApplicationContext app=
				new ClassPathXmlApplicationContext("app2.xml");
		MainClass m=(MainClass)app.getBean("mc");
		m.sa.print();
	}
}

 MainClass 맨 위에 올려준 저 @Component 어노테이션으로 클래스 메모리를 할당해줄 수 있다. 

그리고 Sawon 클래스 역시 만들어 뒀기 때문에, @Autowired를 통해서 Sawon 클래스를 자동으로 찾아와서 값을 대입해줄 수 있다. 

 

package com.sist.main2;

import org.springframework.stereotype.Component;
/*
 * 	<bean id="ds" class="com.sist.main.Sawon">
 * 		=> 필요한 데이터를 첨부 (DI)
 * 	어노테이션은 DI를 할 수 없다/ 메모리만 할당 
 */

@Component("sa")
public class Sawon {
	private String name; 
	private String sex;
	public Sawon ()
	{
		name="황런쥔";
		sex="공주";
	}
	public void print()
	{
		System.out.println("이름:"+name);
		System.out.println("성별:"+sex);
	}
}

 이게 Sawon 클래스이다. 이렇게 @Component에 id "sa"를 주면 다른 클래스에서 아이디를 주고 값을 주입해줄 수 있다. 

 

그러면 어노테이션의 종류에 대해서 간단히 정리해보겠다. 

 

1. @Component : 일반클래스에 사용

2. @Repository : 저장소 (DAO)에 사용

3. @Service : 통합된 저장소 (BI), DAO를 통합할 경우에 사용

4. @Controller : Model 클래스, 파일명을 전송할때 사용 (사이트 이동시, 주로 웹에서 사용함)

5. @RestController : 화면 이동이 아니라 필요한 문자열 전송할때 사용 ex) Ajax, VueJS, React 등등

 

bean에서는 id를 주고 생성된 객체를 찾아왔듯이, 어노테이션에서도 @Component("sa")/ 괄호안에 있는 값으로 객체를 찾아 올 수 있다. 

 

 

스프링에서 객체를 생성하기 전에, 개발자는 반드시 필요한 데이터를 설정(주입)해주어야 한다. 

이 과정을 DI라고 부른다. 

 

그리고 이 과정이 Map방식으로 진행이 된다. 

id를 주면 주소값(ref)를 읽어오는 방식이다. 즉, id==key | 메모리주소==value 이다. 

 

 

스프링을 사용할때 가장 큰 장점은, 클래스들을 모아주지만 각자 독립적으로 움직이기 때문에 결합성이 낮지만 응집력이 높은 프로그램을 만들 수 있기 때문이다. 

 

여기에 이제 오라클을 연결해주는 라이브러리로 Mybatis를 사용하면 좀더 간략하게 프로그램을 만들 수 있다는 장점을 갖게 된다. 

 

오늘 수업을 들으면서 필기를 한 부분.

config.xml -> music-mapper.xml -> app.xml -> MusicDAO -> MainClass

 

이 순서대로 파일을 만들고 작성해줬다. 

 

db를 연결해주는 config.xml 파일을 먼저보면, 

<?xml version="1.0" encoding="UTF-8"?>
<!-- mapper전체, VO 전체를 모아준다 -->
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
 <configuration>
 <!-- VO를 모아서 관리 -->
 	<typeAliases>
 		<typeAlias type="com.sist.main.MusicVO" alias="MusicVO"/>
 	</typeAliases>
 <!-- SQL문장을 모아서 관리 -->
 	<mappers>
 		<mapper resource="com/sist/main/music-mapper.xml"/>
 	</mappers>
 </configuration>

 VO를 모아주고, SQL문장을 모아서 관리할 mapper class의 주소를 저장한다. 여기에 저장을 해두면 알아서 mapper.xml의 코드를 읽어가게 된다. 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sist.main.music-mapper">
  <!-- 프로그램에서 사용하는 SQL문장을 저장 
       CURD => Create , Update , Read , Delete 
               ======(Insert)    ====(Select)
       1) Insert => <insert>
       2) Update => <update>
       3) Select => <select>
       4) Delete => <delete>
       ==> 1. id부여(Map에서 저장되는 키명 : 중복이 없이 만든다)
           2. 결과값을 받는 경우 : resultType(SELECT문장에만 존재)
                          결과값이 1개인 경우 => 일반데이터형 
                 SELECT pwd FROM table_name  ==> String
                 SELECT COUNT(*) FROM table_name ==> int
                          결과값이 2개인 경우 => VO,Map
                      VO로 먼저 처리 (VO에 없는 변수는 Map)
                 SELECT MAX(hit),Min(hit) FROM table_name
                        ======== ========= Map => 스칼라 서브쿼리
                 SELECT no,title FROM table_name
                        ========
                          VO
           3. 데이터베이스에 값을 추가 (?) : parameterType
                SELECT * FROM table_name 
                WHERE no=? => ?대신 #{no} => getNo()
       => 동적 퀴리 <if> : 다중 검색  in(<forEach> , <where>)  
   -->
   <!-- 데이터 읽기 : 페이지 나누기 -->
   <!-- id의 시작은 알파벳으로 한다 , 대소문자 구분 -->
   <!-- start , end  
        데이터 두개이상 => VO,Map
        
        Map map=new HashMap();
        map.put("start",1)
        map.put("end",10)
        
        #{start} => map에서 start는 키명
        #{end}   => map에서 end는 키명
   -->
   <select id="musicListData" resultType="MusicVO" parameterType="hashmap">
     SELECT no,title,singer,album,num 
     FROM (SELECT no,title,singer,album,rownum as num 
     FROM (SELECT no,title,singer,album 
     FROM genie_music ORDER BY no ASC))
     WHERE num BETWEEN #{start} AND #{end}
   </select>
   <!-- 총페이지 구하기 -->
   <select id="musicTotalPage" resultType="int">
     SELECT CEIL(COUNT(*)/10.0) FROM genie_music
   </select>
   <select id="musicCount" resultType="int">
     SELECT COUNT(*) FROM genie_music
   </select>
   <!-- 찾기
        1) 제목 ==> title LIKE
        2) 가수명 ==> singer LIKE
        
        #{} => 일반데이터 
        ${} => table_name,column명을 설정
    -->
   <select id="musicFindData" resultType="MusicVO" parameterType="hashmap">
     SELECT no,title,singer,album
     FROM genie_music
     WHERE ${column} LIKE '%'||#{finddata}||'%'
   </select>
   <!-- 상세보기 -->
   <select id="musicDetailData" resultType="MusicVO" parameterType="int">
     SELECT * FROM genie_music
     WHERE no=#{no}
   </select>
</mapper>

 수업시간 예제로 만든 music-mapper.xml 파일

 

여기에 사용할 SQL문장을 적어준다. 어제 정리해둔 것 처럼 resultType, parameterType을 잘 생각해서 지정해둔다. 

 

<?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:c="http://www.springframework.org/schema/c"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<!-- 오라클 정보를 모아서 마이바티스로 전송 -->
<util:properties id="db" location="classpath:db.properties"/>
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
	p:driverClassName="#{db['driver']}"
	p:url="#{db['url']}"
	p:username="#{db['username']}"
	p:password="#{db['password']}"
/>
<!-- MyBatis로 전송 -->
<bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean"
	p:dataSource-ref="ds"
	p:configLocation="classpath:config.xml"	
/>
<!-- 사용자 정의 DAO에 전송 -->
<bean id="dao" class="com.sist.main.MusicDAO"
	p:sqlSessionFactory-ref="ssf"
/>
</beans>

 그리고 메모리를 할당할 클래스의 정보를 모아주는 app.xml 파일

오라클의 정보를 모아주는 클래스, MyBatis로 전송하는 클래스, 사용자 DAO에 전송할 클래스를 하나로 모아준다. 

 

package com.sist.main;

import org.mybatis.spring.support.SqlSessionDaoSupport;
/*
 * 	=> SqlSessionDaoSupport
 * 		데이터 베이스 정보 (DataSource)
 * 		SqlSessionFactory : getConnection, disConnection
 * 		=================
 * 		SqlSession => sql문장 전송, 결과값을 받는 역할 
 */
import java.util.*;
public class MusicDAO extends SqlSessionDaoSupport{
	public List<MusicVO> musicListData(Map map)
	{
		return getSqlSession().selectList("musicListData", map);
	}
	public int musicTotalPage()
	{
		return getSqlSession().selectOne("musicTotalPage");
	}
	// 총갯수 읽기
	public int musicCount()
	{
		return getSqlSession().selectOne("musicCount");
	}
	public MusicVO musicDetailData(int no)
	{
		return getSqlSession().selectOne("musicDetailData", no);
	}
	public List<MusicVO> musicFindData(Map map)
	{
		return getSqlSession().selectList("musicFindData", map);
	}
}

 

그리고 DAO 파일에서 메소드들을 실제로 만들어 준다. 그리고 MainClass로 가면

 

ApplicationContext app=
				new ClassPathXmlApplicationContext("app.xml");
		// 스프링에 저장된 DAO를 가지고 온다 
		MusicDAO dao=(MusicDAO)app.getBean("dao");
		// 사용
		int totalpage=dao.musicTotalPage();
		Scanner scan=new Scanner(System.in);
		System.out.print("페이지 입력:(1~"+totalpage+")=>");
		int curpage=scan.nextInt();
		Map map=new HashMap();
		int rowSize=10;
		int start=(rowSize*curpage)-(rowSize-1);
		int end=(rowSize*curpage);
		// WHERE num BETWEEN #{start} AND #{end}
		map.put("start", start);
		map.put("end", end);
		
		// 결과값 받기
		List<MusicVO> list=dao.musicListData(map);

 이렇게 스프링에 저장한 dao 클래스를 가지고와서 메소드를 사용해서 원하는 결과값을 확인해 볼 수 있다. 

 

그리고 @Autowired 사용법

자동으로 메모리를 할당해준 클래스를 찾아와 주는 것인데, 만약에 같은 @Component로 메모리를 할당해준 클래스가 여러개였다면 

 

package com.sist.main3;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MainClass {
	@Autowired
	//@Qualifier("mySQL")
	//@Resource(name="mySQL")
	DB db;
	
	public static void main(String[] args) {
		ApplicationContext app=
				new ClassPathXmlApplicationContext("app3.xml");
		MainClass mc=(MainClass)app.getBean("mainClass");
		
		mc.db.select();
		mc.db.insert();
		mc.db.update();
		mc.db.delete();
	}
}

 위와 같은 경우 오류가 나는 코드를 만날 수 있다. 

 오류 메세지를 보면 매칭되는 bean이 한개가 아니라 2개이기 때문에 실행할 수 없다고 나온다. 

 

인터페이스 파일인 DB에 아래와 같이 4개의 메소드가 있는데, 

package com.sist.main3;

public interface DB {
	public void select();
	public void insert();
	public void delete();
	public void update();
	
}

 이것을 상속받은 클래스가 Oracle, MySQL 두개 이기 때문이다. 

 

 이런 경우에 @Autowired를 사용해도 자동으로 클래스 정보를 읽어올 수 없다. 

 

	@Autowired
	@Qualifier("mySQL")
	DB db;

 그래서 이렇게 클래스 정보를 읽어와야 딱 지정한 정보를 읽어올 수 있게 된다. 

 

 

그리고 앞으로 다루게될 웹을 연결하는 프로젝트

MVC 구조

 

 

 이것만 봐도 벌써 좀 복잡하고 머리속이 아찔해진다. (그정돈 아님)

 

일단 그냥 자바로만 해본 것과는 다른 점이 WEB-INF 폴더 아래에 config.xml 파일과 applicationContext.xml 파일을 저장한다는 점이다. 

 

사실 아직 엄청 제대로 웹 연동을 배운것은 아니기 때문에 구조정도만 잘 이해하고 있어도 성공일것 같다. 

 

한가지 추가된 것은 web.xml 파일에 dispatcherServlet을 등록해야한다는것, controller와 연동에 필요한 모델 클래스들이 필요하다는 것이 있다. 

 

 

package com.sist.main;
// Model => Controller
/*
 * 	DispatcherServlet : Front Controller => 요청 제어
 * 	Model : Controller = 요청처리한 결과를 제어
 */
import java.util.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.sist.dao.*;
public class MusicController {
	@Autowired
	private MusicDAO dao;
	
	@RequestMapping("music/list.do")
	public String music_list(Model model)
	{
		List<MusicVO> list=dao.musicAllData();
		model.addAttribute("list", list); // => JSP로 넘어갈때 변환 request.setAttribute()
		// Model => JSP로 데이터 전송하는 역할
		return "music/list";
	}
}

 

 

일단 오늘은 여기까지만 정리하고

내일 어차피 더 제대로 웹 연동을 배우게 되기 때문에 더 배우고 나서 다시 정리해보겠다. 

 

728x90
반응형