[목차]

9. Controller 처리, DB연동

① 요청 파라미터

② get/post 방식이 다른 동일 요청 처리

③ DB 연동 - DataSource

④ DB연동 - JdbcDaoSuport

⑤ DB연동 - Mybatis(xml), (root-servlet.xml사용)

⑥ DB연동 - mybatis(annotation), (root-servlet.xml사용)


[내용]

① 요청 파라미터

 = sprweb10_para_url
 - index.jsp

<body>
	<h2>* 요청 파라미터 연습</h2>
	<h3>get</h3>
	<a href="kbs/login?type=admin">관리자</a><br>
	<a href="kbs/login?type=user">일반 사용자</a><br>
	<a href="kbs/login">파라미터 없음</a><br>
	<h3>post</h3>
	<form action="kbs/login? method="post">
		data : <input type="text" name="type" value="user">
		<input type="submit" value="전송">
	</form>
	<hr>
	<h2>* 요청 URL로 정보전달</h2>
	<form action="mbc/korea" method="get">
		data : <input type="text" name="name" value="tom">
		<input type="submit" value="전송">
	</form>
	<br>
	<form action="mbc/usa" method="get">
		data : <input type="text" name="name" value="james">
		<input type="submit" value="전송">
	</form>
	<h2>* 요청 URL로 정보전달2</h2>
	<form action="ent/bighit/singer/bts" method="get">
		신곡 : <input type="text" name="title" value="다이너마이트">
		<input type="submit" value="전송">
	</form>
	<form action="ent/yg/singer/blackpink" method="get">
		신곡 : <input type="text" name="title" value="아이스크림">
		<input type="submit" value="전송">
	</form>
</body>

 => 요청 url ? 뒤의 key = value 값을 이용하여 정보 전달. (get/post)

 => 요청 url 중 mbc/ 뒤의 값으로 정보 전달.

 => 요청 url 중 ent/ ? /singer/? 각 ent/ singer 뒤의 값으로 정보 전달.

 

 

 - servlet-context.xml

<context:component-scan base-package="aa.bb.controller" />

 => <context:componet-scan> : controller pakage의 어노테이션 스캔.

 

 

 - LoginController

@Controller // controller 동작
public class LoginController {
	
	@RequestMapping(value="kbs/login", params = "type=admin")
	public ModelAndView aa() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg","관리자");
		return modelAndView;
	}
	
	@RequestMapping(value="kbs/login", params = "type=user")
	public ModelAndView bb() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg","일반고객");
		return modelAndView;
	}
	
	@RequestMapping(value="kbs/login", params = "!type") // parameter가 없는경우
	public ModelAndView cc() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg","인자가 없음.");
		return modelAndView;
	}

 => @RequestMapping(value="url", params = "key=name") : value는 요청 url에, params는 key, name값에 매핑되는

      요청이 들어올 경우 해당 메소드가 실행되도록 한다.

 => params 값에 따라 각각 다른 메소드가 실행되어 setViewName()의 show.jsp 파일에 addObject()로 [msg] key에

      value를 전달한다.

 

 

	// 요청 url의 일부를 변수로 받아 처리
	@RequestMapping(value="mbc/{url}")// url변수에 요청 mbc/의 값을 대입한다.
	public ModelAndView dd(
			@PathVariable String url,
			@RequestParam("name") String name) {
		System.out.println("url : "+url+" name : "+name);
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		
		if(url.equals("korea")) {
			modelAndView.addObject("msg", url+" "+name+"님 만세");
		}else if(url.equals("usa")) {
			modelAndView.addObject("msg", url+" "+name+"님 ㅇㅇ ");
		}else {
			modelAndView.addObject("msg","기타");
		}
		return modelAndView;
	}
	
	@RequestMapping(value="ent/{co}/singer/{singer}")
	public ModelAndView ee(
			@PathVariable String co,
			@PathVariable String singer,
			@RequestParam("title") String title) {
		
		String datas = "소속사 : "+co+", 가수 : "+singer+", 타이틀 곡 : "+title; 
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg", datas);
		
		return modelAndView;
	}
}

=> @RequestMapping(value="url/{변수명}") : mbc/korea로 요청url이 들어올 경우 변수에 korea가 들어간다.

     @PathVariable 타입 변수명 : 요청 url을 변수로 받도록 하는 어노테이션.

     @RequestParam("<form>의 name 속성") 타입 변수 : 변수 String name에 <form>의 value값이 전달된다.

 

 

 - show.jsp

<body>
	결과는 ${msg}
</body>

 => EL 사용 결과값 출력.

 

 


② get/post 방식이 다른 동일 요청 처리

 = sprweb11_getpost
 - index.jsp

<body>
	<h2>메인</h2>
	회원처리 게시판 <a href="login">로그인(get)</a> 
	<pre>본문
	</pre>	
</body>

 => url요청을 login 전달. (Get방식)

 

 

 - LoginController

@Controller
public class LoginController {
	private String formName = "loginform";
	
	@Autowired
	private LoginForm loginForm;
			
	@RequestMapping(value="login", method=RequestMethod.GET)
	public String form() {
		return formName;
	}
	
	@RequestMapping(value="login", method=RequestMethod.POST)
	public String submit(LoginForm loginForm) {
		
		if(loginForm.getUserid().equalsIgnoreCase("aa")&
				loginForm.getPasswd().equalsIgnoreCase("11")) {
			
			return "redirect:/list";//로그인 성공하면 목록보기
		}else {
			return formName; // 로그인 실패하면 로그인 화면으로 이동
		}
	}
}

 => index.jsp에서 전달한 url "login"(get 방식)으로 form()메소드가 실행된다.

 => @RequestMapping(value="url명", method=RequestMethod.GET) : 해당 url중 GET방식으로 전달할 경우만 해당

       메소드가 실행된다.

=> @Controller의 클래스에 String을 리턴값으로 가지는 form() 메소드가 실행될 경우 리턴값과 동일한 jsp파일을 실행

     한다. (loginform.jsp 실행)

 

 

 - loginform.jsp

<body>
	<h2>자료입력</h2>
	<form action="login" method="post"/>
		id : <input type="text" name="userid" id="userid"/><br>
		pwd: <input type="text" name="passwd" id="passwd"/><br>
		<input type="submit" value="전송(전통적)"/><br>
	</form>
</body>

 => LoginController class의 form() 메소드 실행으로 실행된다.

 => index.jsp의 동일한 url 요청명인 "login"으로 Post방식으로 값을 전달한다. 

 

 

 - LoginController

@Controller
public class LoginController {
	private String formName = "loginform";
	
	@Autowired
	private LoginForm loginForm;
			
	@RequestMapping(value="login", method=RequestMethod.GET)
	public String form() {
		return formName;
	}
	
	@RequestMapping(value="login", method=RequestMethod.POST)
	public String submit(LoginForm loginForm) {
		
		if(loginForm.getUserid().equalsIgnoreCase("aa")&
				loginForm.getPasswd().equalsIgnoreCase("11")) {
			
			return "redirect:/list";//로그인 성공하면 목록보기
		}else {
			return formName; // 로그인 실패하면 로그인 화면으로 이동
		}
	}
}

 => @RequestMapping(value="url명", method=RequestMethod.POST) : url중 Post방식으로 송부시에 실행된다.

 => String 메소드명(FormBean 변수명) : <form>태그의 name 속성값과 동일한 변수를 가지는 FormBean을 매개변수로

      가질 경우 FormBean객체에 각 값들이 대입된다.

      str1.equalsIngnorseCase(str2) : str1과 str2를 대소문자 구분하지않고 비교한다.

 => Login에 성공할 경우 redirect로 클라이언트에서 요청을 실행한 것과 같이 실행하여야한다. (forward를 사용하지

      않음). Redirect로 list.jsp를 실행한다.

 

 

-  LoginForm

@Component
public class LoginForm {
	private String userid; // <form>태그의 name속성값과 동일하게 변수를 가진다.
	private String passwd;
	
	public String getUserid() {
		return userid;
	}
	public void setUserid(String userid) {
		this.userid = userid;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
}

 => <form>태그의 name속성값과 동일하게 변수를 가지도록 작성한다. FormBean은 client의 요청을 처리할 때 사용

      한다. DTO는 DB 자료를 처리할 때 사용. (용도에 따라 관례적으로 FormBean과 DTO를 사용한다)

 

 

 - ListController

@Controller
public class ListController {
	@RequestMapping("list")
	public ModelAndView aaa() {
		ModelAndView view = new ModelAndView("list");
		view.addObject("msg", "로그인 성공으로 하고 뭔가를 출력함");
		
		return view;
	}
}

 => 성공시 실행할 내용을 구현한다. "msg" key에 값 전달.

 

 

 - list.jsp

<body>
	결과 : ${msg}
</body>

 => EL사용하여 msg값 출력

 


③ DB 연동 - DataSource

 = sprweb12_db_legacy
 - main.jsp

<body>
	<h2>메인</h2>
	<a href="testdb">상품보기</a>
</body>

 => "testdb" url 전달.(get 방식)

     <%response.sendRedirect("testdb"); %>로 동일한 기능 수행하도록 구현가능.

 

 

 - servlet-context.xml

<context:component-scan base-package="aa.bb.controller" />
<context:component-scan base-package="aa.bb.model" />

 => 어노테이션 scan.

 

 

- ListController

@Controller // 클라이언트로 부터  요청 받을 경우 동작
public class ListController {
	
	@Autowired
	private DataDao dataDao;
	
	@RequestMapping("testdb") // url mapping
	public ModelAndView listProcess() {
		ArrayList<SangpumDto> list = dataDao.getDataAll();
		
		return new ModelAndView("list", "datas", list); // list.jsp에 연결.
	}
}

 => @Controller : 클라이언트로 부터  요청 받을 경우 동작.

      @Autowired : setter injection 기능 수행.

      @RequestMapping("url명") : url명과 동일한 url을 받을 경우 실행.

      dataDao의 getDataAll()를 실행한 list값을 "datas" key에 넣어 실행한다.

 

 

- SangpumDto

public class SangpumDto {
	private String code, sang, su, dan;
	//getter/setter
}

 => DB 데이터를 담는 DTO 정의.

 

 

- DataDao

@Repository // DB 연결.
public class DataDao {
	private Connection conn;
	private PreparedStatement ptmt;
	private ResultSet rs;
	
	public DataDao() {
	}
	
	@Autowired
	private DataSourceMaria dataSourceMaria; 
	
	public ArrayList<SangpumDto> getDataAll(){
		ArrayList<SangpumDto> list = new ArrayList<SangpumDto>();
		
		try {
			String sql = "select * from sangdata";
			conn = dataSourceMaria.getConnection();
			ptmt=conn.prepareStatement(sql);
			rs = ptmt.executeQuery();
			while(rs.next()) {
				SangpumDto dto = new SangpumDto();
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getString("su"));
				dto.setDan(rs.getString("dan"));
				list.add(dto);
			}
		} catch (Exception e) {
			System.out.println("getDataAll err"+e);
		}finally {
			try {
				if(conn != null) conn.close();
				if(ptmt != null) ptmt.close();
				if(rs != null) rs.close();
			} catch (Exception e2) {
				System.out.println(e2);
			}
		}
		return list;
	}
}

 => @Repository : 객체 생성. DB 연결하는 클래스에 사용. 기능은 @Component와 동일.

      @Autowired : DriverManagerDataSource를 상속받은 클래스 객체를 setter injection한다.

      getConnection() : jdbc와 연결.

      prepareStatement(sql) : sql문을 get한다.

      executeQuery() : sql문을 실행한 결과를 리턴한다.

      rs.next() : sql 실행 결과를 한 행 단위로 읽는다.

      rs.getString("record명") : 읽고 있는 sql 실행결과 라인의 Record 값을 리턴한다.

 => sql문의 실행 결과를 dto에 담고 실행결과의 한 줄씩 list에 담는다.(list.add(dto))

 => sql문의 실행결과를 ArrayList로 반환한다.

 

 

- DataSourceMaria

@Repository() // DB연동
//@Repository("dataSource") 
public class DataSourceMaria extends DriverManagerDataSource{
	public DataSourceMaria() {
		setDriverClassName("org.mariadb.jdbc.Driver");
		setUrl("jdbc:mysql://127.0.0.1:3306/test");
		setUsername("root");
		setPassword("123");
	}
}

 => extends DriverManagerDataSource : 상속하여 DB와 연결하는 객체를 생성한다.

 => setDriverClassName() / setUrl() / setUsername() / setPassword() : JDBC연결을 위한 정보를 set한다.

 

 

- list.jsp

<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
<body>
	<h2>*상품자료(전통적)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>
		
		<c:forEach var="s" items="${datas}">
			<tr>
				<td>${s.code}</td>
				<td>${s.sang}</td>
				<td>${s.su}</td>
				<td>${s.dan}</td>
			</tr>
		</c:forEach>
	</table>
</body>

 => <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> : EL 액션태그로 core 메소드를 액션태그를 사용

      할 수 있게 library를 연결한다.

 => <c:forEach var="변수명" items="${리스트명}"> : var에 items의 list 값을 index 0 부터 null까지 반복 실행한다.

       (for-each문)

 => EL사용하여 결과값 출력.

 

 


④ DB연동 - JdbcDaoSuport

= sprweb13_db_jdbc_dao_support
-  index.jsp

<body>
	<a href="testdb">상품보기(JbdcDaoSupport)</a>
</body>

 => DataSource와 동일

 

 

- servlet-context.xml

<context:component-scan base-package="aa.bb.controller" />
<context:component-scan base-package="aa.bb.model" />

 => DataSource와 동일

 

 

- ListController

@Controller // 클라이언트로 부터  요청 받을 경우 동작
public class ListController {
	
	@Autowired
	private DataDao dataDao;
	
	@RequestMapping("testdb") // url mapping
	public ModelAndView listProcess() {
		ArrayList<SangpumDto> list = dataDao.getDataAll();
		
		return new ModelAndView("list", "datas", list); // list.jsp에 연결.
	}
}

 => DataSource와 동일

 

 

- SangpumDto

public class SangpumDto {
	private String code, sang, su, dan;
	//getter/setter
}

 => DataSource와 동일

 

 

- DataSourceMaria

@Repository() // DB연동
//@Repository("dataSource") 
public class DataSourceMaria extends DriverManagerDataSource{
	public DataSourceMaria() {
		setDriverClassName("org.mariadb.jdbc.Driver");
		setUrl("jdbc:mysql://127.0.0.1:3306/test");
		setUsername("root");
		setPassword("123");
	}
}

 => DataSource와 동일

 

 

- DataDao

@Repository // DB 연결.
public class DataDao extends JdbcDaoSupport{
	//@Autowired
	//private DataSourceMaria dataSourceMaria; // DataDao에 주입됨.
	//DataSource를 JdbcDaoSupport가 가지고 있으로 생성자를 이용한다.
	
	public DataDao(DriverManagerDataSource dataSource) {
		setDataSource(dataSource);
	}
	
	public List<SangpumDto> getDataAll(){
		String sql="select * from sangdata";
		return getJdbcTemplate().query(sql, new ItemRowMapper());
	}
	
	class ItemRowMapper implements RowMapper{
		@Override
		public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
			SangpumDto dto = new SangpumDto();
			dto.setCode(rs.getString("code"));
			dto.setSang(rs.getString("sang"));
			dto.setSu(rs.getString("su"));
			dto.setDan(rs.getString("dan"));
			return dto;
		}
	}
}

 => extends JdbcDaoSupport : JdbcDaoSupport 상속 받아 기능을 수행한다.

 => @Autowird를 사용하면 DataDao객체에 dataSource가 setter injection됨으로 해당 기능이 정상동작하지않는다.

       정상동작을 위해선 상속을 받고있는 JdbcDaoSupport객체에 setter injection을 하여야한다. 생성자를 이용하여

       DataDao객체가 생성되면 setDataSource()가 실행되도록 하여 JdbcDaoSupport객체에 dataSource를 setter

       injection한다.

 => getJdbcTemplate().query(sql, new ItemRowMapper()) : sql문이 ItemRowMapper클래스가 실행하여 한줄 씩 실행된

      결과를  List 리턴.

 => implemets RowMapper : RowMapper를 상속하여 mapRow() 메소드를 오버라이딩하여 sql문을 실행한다.

 

 

 

- list.jsp

<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
<body>
	<h2>*상품자료(전통적)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>
		
		<c:forEach var="s" items="${datas}">
			<tr>
				<td>${s.code}</td>
				<td>${s.sang}</td>
				<td>${s.su}</td>
				<td>${s.dan}</td>
			</tr>
		</c:forEach>
	</table>
</body>

 => DataSource와 동일

 


⑤ DB연동 - Mybatis(xml) (root-servlet.xml사용)

 = sprweb14_db_mybatis

 - pom.xml

<!-- MariaDB driver -->
<dependency>
	<groupId>org.mariadb.jdbc</groupId>
	<artifactId>mariadb-java-client</artifactId>
	<version>2.6.2</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

 => MariaDB, Mybatis lib 추가한다.

 

 

- main.jsp

<body>
	<a href="list">상품보기(@MVC-MyBatis)</a>
</body>

=> url 요청명 list 전달.(get방식)

 

 

 - servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

=> 어노테이션 사용을 위한 패키지 스캔.

 

 

- db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=123

 => 계정정보를 가진 자바 속성 파일. key=name 형식. (암호화 파일로 구현하는 것을 지향)

 

 

 - Configuration.xml

<configuration>
 <typeAliases>
 	<typeAlias type="pack.model.SangpumDto" alias="dto"/>
 	<typeAlias type="pack.controller.SangpumBean" alias="formBean"/>
 </typeAliases>
 <!--  DB 연결을 root-context.xml에서 하도록 수정.
 <properties resource="pack/mybatis/db.properties" />
 <environments default="dev">
  <environment id="dev">
   <transactionManager type="JDBC" />
   <dataSource type="POOLED">
    <property name="driver" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
   </dataSource>
  </environment>
 </environments>
 -->
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 => 공유자원을 관리하는 root-context.xml에서 DB연결을 하도록, Sql문 mapping하는 DataMapper.xml관련 설정을

      제외하고 삭제.

 => DataMapper파일과 alias를 정의한다.

 

 

 - DataMapper.xml

<mapper namespace="dev">
	<select id="selectAll" resultType="dto">
		select * from sangdata
	</select>
	<select id="selectSearch" parameterType="formBean" resultType="dto">
		select code, sang, su, dan from sangdata
		where sang like concat('%',#{searchValue},'%')
	</select>
</mapper>

 => sql문과 연결되는 Mapper 파일을 작성한다.(<mapper>태그 내부에 sql문을 형식에 맞춰 작성)

 => <select> : select문 작성 시 사용되는 태그. (id속성 - 외부에서 호출할 이름 / resultType - sql문을 실행한 결과

                    Type / parameterType속성 - 외부로 부터 받을 매개변수의 타입, #{변수명}에 매개변수가 대입된다.)

=> like concat('%', 검색어, '%') : 검색어가 포함된 결과 반환. ( like %검색어%)

 

 

- SqlMapConfig : 미사용 (root-context.xml에서 DB연결)

 

 

 - root-context.xml

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>

 => <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> : 외부 파일의 프로퍼티

       정보를 해당 설정파일에서 사용가능하도록 기능 제공.

 => locations 속성으로 db.properties를 read하도록 설정.
      db.properties의 프로퍼티를 ${프로퍼티값}으로 사용할 수 있다.

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
	<property name="driverClass" value="${driver}"/>
	<property name="url" value="${url}"/>
	<property name="username" value="${username}"/>
	<property name="password" value="${password}"/>
</bean>

<bean class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource"/>
	<property name="configLocation" value="classpath:pack/mybatis/Configuration.xml"></property>
</bean>

 => <bean class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> : db를 사용할 수 있도록 기능제공.

               drivaerClass, url, usernam, password를 setter 주입하여 db연결 객체 생성.

 => <bean class=org.mybatis.spring.SqlSessionFactoryBean"> : SqlSessionFatory 객체를 생성.

               Configuration.xml, dataSource를 setter 주입하여 factory 객체 생성.

               factory객체를 여러개 사용시에는 id속성을 사용한다.

 

 

- ListController

@Controller
//@ComponentScan("pack.model")
public class ListController {
	
	@Autowired // setter injection
	private SangpumInter sangpumInter; // 다형성 사용
	
	@RequestMapping("list")
	public Model process(Model model){
		model.addAttribute("data", sangpumInter.list());
		// Model객체는 addAttribe(key, value) 메소드를 사용하여 값을 전달.
		return model; // 받은 요청명 그대로 송부한다.
	}
}

 => @Controller : Controller 기능 수행 (servlet 동작)

 => "list" url 받을 경우 동작한다. list()메소드를 실행한 결과를 "data" key에 넣어 list.jsp에 리턴한다.

 

 

- SangpumDto

public class SangpumDto {
	private String code,sang, su, dan;
	//setter, getter
}

 => DB연동에 사용되는 데이터는 Dto로 작성.(select)

 

 

- SangpumBean

public class SangpumBean {
	// formBean : 수정, 삭제 등의 작업이 있다면 code, sang, su, dan도 처리
	// 검색용
	private String searchValue;

	public String getSearchValue() {
		return searchValue;
	}

	public void setSearchValue(String searchValue) {
		this.searchValue = searchValue;
	}
}

=> insert, delete의 작업을 진행할 경우 FormBean으로 작성.

=> select문에 매개변수로 들어가 조건을 추가할 searchValue 변수 정의.

 

 

- SangpumInter

public interface SangpumInter {
	List<SangpumDto> list() throws DataAccessException;
	List<SangpumDto> seach(SangpumBean bean) throws DataAccessException;
	//insert, update, delete ...
}

 => 테이블별로 interface로 관리한다.

 => db에서 select 전체 테이블 조회 기능을 갖출 list()메소드 선언.

 => db에서 select 특정 검색어가 들어간 데이터를 조회 기능을 갖출 search()메소드 선언.

 

 

- SangpumImpl

@Repository // DB연동
public class SangpumImpl extends SqlSessionDaoSupport implements SangpumInter{
	
	@Autowired // 타입에 의한 매핑
	// 복수개일 경우 @Quiyfied사용
	public SangpumImpl(SqlSessionFactory factory) {
		// root-context.xml에서 factory 객체 생성함.
		setSqlSessionFactory(factory); // SqlSessionDaoSupport에 factory 주입.
	}
	
	@Override
	public List<SangpumDto> list() throws DataAccessException {
		return getSqlSession().selectList("selectAll");
	}

	@Override
	public List<SangpumDto> seach(SangpumBean bean) throws DataAccessException {
		return getSqlSession().selectList("selectSearch", bean);
	}
}

 => @Repository : 객체생성(DB연동 기능을 갖출경우 관례적으로 @Repository사용)

 => extends SqlSessionDaoSupport : SqlSession을 제공하는 추상 클래스.(getSqlSession()메소드)

 => implements SangpumInter : 다형성을 통한 테이블별 관리를 하기 위해 interface사용

 => 생성자 setter 주입을 통해 SqlSessionFactory 객체를 sqlSessionDaoSupport에 set한다.(setSqlSessionFactory() 사용)

 => getSqlSession() : sqlSession객체의 메소드를 사용하여 sql문을 실행한 결과를 리턴한다.

=> selectList("매핑 id") : select문을 실행하여 복수의 data를 list로 리턴한다. DataMapper.xml의 id를 매개변수로

     가진다.

 

 

- SearchController

@Controller
public class SearchController {
	@Autowired
	private SangpumInter sangpumInter;
	
	@RequestMapping(value="search", method = RequestMethod.POST)
	public ModelAndView searchProcess(SangpumBean bean) {
		List<SangpumDto> list = sangpumInter.seach(bean);
		return new ModelAndView("list","data", list);
	}
}

 => "search" url 받을 경우 <form>태그의 name 속성들의 값을 formBean객체로 대입하여 받는다.

       formBean객체를 매개변수로 search()메소드를 실행하여 list결과를 "data" key에 리턴한다.

 

 

 - list.jsp

<body>
	<h2>* 상품정보(@MVC - MyBatis)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>	
		<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
		<c:forEach var="s" items="${data}">
		<tr>
			<td>${s.code}</td>
			<td>${s.sang}</td>
			<td>${s.su}</td>
			<td>${s.dan}</td>
		</tr>
		</c:forEach>
		<tr>
			<td colspan="4">
				<form action="search" method="post">
					이름 : <input type="text" name="searchValue">
					<input type="submit" value="검색">
				</form>
			</td>
		</tr>
	</table>
</body>

 => sql 결과를 테이블 형태로 출력.

 

 


⑥ DB연동 - mybatis(annotation), (root-servlet.xml사용)

 = sprweb14_db_mybatis_annotation

- main.jsp

<body>
	<a href="list">상품보기(@MVC-MyBatis)</a>
</body>

=> xml방식과 동일

 

 

 - servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

=> xml방식과 동일

 

 

 

- db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=123

=> xml방식과 동일

 

 

 

 - Configuration.xml : 미사용(어노테이션 사용)

 

 

 - DataMapper.xml : 미사용(어노테이션 사용)

 

- SqlMapConfig : 미사용 (root-context.xml에서 DB연결)

 

 

 - root-context.xml

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>

=> xml방식과 동일

 

 

- ListController

@Controller
//@ComponentScan("pack.model")
public class ListController {
	
	@Autowired // setter injection
	private SangpumInter sangpumInter; // 다형성 사용
	
	@RequestMapping("list")
	public Model process(Model model){
		model.addAttribute("data", sangpumInter.list());
		// Model객체는 addAttribe(key, value) 메소드를 사용하여 값을 전달.
		return model; // 받은 요청명 그대로 송부한다.
	}
}

=> xml방식과 동일

 

 

- SangpumDto

public class SangpumDto {
	private String code,sang, su, dan;
	//setter, getter
}

=> xml방식과 동일

 

 

 

- SangpumBean

public class SangpumBean {
	// formBean : 수정, 삭제 등의 작업이 있다면 code, sang, su, dan도 처리
	// 검색용
	private String searchValue;

	public String getSearchValue() {
		return searchValue;
	}

	public void setSearchValue(String searchValue) {
		this.searchValue = searchValue;
	}
}

=> xml방식과 동일

 

 

- SangpumInter

public interface SangpumInter {
	List<SangpumDto> list() throws DataAccessException;
	List<SangpumDto> seach(SangpumBean bean) throws DataAccessException;
	//insert, update, delete ...
}

=> xml방식과 동일

 

 

- SangpumAnnoInter

// MyBatis SQL mapping interface file
public interface SangpumAnnoInter {
	@Select("select * from sangdata")
	public List<SangpumDto> selectAllData();
	
	@Select(" select code, sang, su, dan from sangdata where sang like concat('%',#{searchValue},'%')")
	public List<SangpumDto> selectSearch(SangpumBean bean);
}

 => MyBatis SQL mapping interface파일 작성.

 => @Select("select sql문") : db에서 sql문 실행한 결과값을 리턴한다.

 

 

- SangpumImpl

@Repository // DB연동
public class SangpumImpl implements SangpumInter{
	
	@Autowired
	private SangpumAnnoInter sangpumAnnoInter;
	
	@Override
	public List<SangpumDto> list() throws DataAccessException {
		return sangpumAnnoInter.selectAllData();
	}

	@Override
	public List<SangpumDto> seach(SangpumBean bean) throws DataAccessException {
		return sangpumAnnoInter.selectSearch(bean);
	}
}

 => extends SqlSessionDaoSupport은 하지않는다.

 => @Autowired : sql mapping interface객체를 setter injection한다.

=> sql mapping interface객체의 메소드의 결과를 리턴받는다.

 

 

- SearchController

@Controller
public class SearchController {
	@Autowired
	private SangpumInter sangpumInter;
	
	@RequestMapping(value="search", method = RequestMethod.POST)
	public ModelAndView searchProcess(SangpumBean bean) {
		List<SangpumDto> list = sangpumInter.seach(bean);
		return new ModelAndView("list","data", list);
	}
}

=> xml방식과 동일

 

 

 - list.jsp

<body>
	<h2>* 상품정보(@MVC - MyBatis)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>	
		<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
		<c:forEach var="s" items="${data}">
		<tr>
			<td>${s.code}</td>
			<td>${s.sang}</td>
			<td>${s.su}</td>
			<td>${s.dan}</td>
		</tr>
		</c:forEach>
		<tr>
			<td colspan="4">
				<form action="search" method="post">
					이름 : <input type="text" name="searchValue">
					<input type="submit" value="검색">
				</form>
			</td>
		</tr>
	</table>
</body>

=> xml방식과 동일

 

 


 

[목차]

8. Controller 처리

    ① Client요청을 Controller로 연결하기
    공유 객체 사용
    패턴을 사용한 경로 매핑
    @annotation을 이용한 Controller호출
    Spring MVC Project를 사용
    @RequestParam 사용(get)
        * Controller 값 처리(기존) : getParameter()
        * Controller 값 처리(어노테이션 사용)
        * get 방식은 한글이 안깨지나 post 방식사용시 한글이 깨진다. Encording을 하여 한글 깨짐을 방지한다.
    FormBean, @ModelAttribute 사용(post)
        * Controller 값 처리(기존) : getParameter()
        * Controller 값 처리(FormBean 사용)
        * Controller 값 처리(@ModelAttribute 사용)

 


[내용]

1) Client요청을 Controller로 연결하기

 

    : implements Controller와 @Controller 사용

 

=sprweb3

 - start.html

<body>
	<a href="hello.do">클릭 1-1(get)</a>
	<form action="hello.do" method="post">
		<input type="submit" value="클릭 1-2(post)"/>
	</form>
	<hr>
	<a href="world.do">클릭 2-1</a>
	<a href="good.do">클릭 2-2</a>
	<a href="hi/nice.do">클릭 2-3</a>
	<form action="korea.do" method="get">
		<input type="submit" value="클릭 2-4(get)"/>
	</form>
	<form action="usa.do" method="post">
		<input type="submit" value="클릭 2-4(post)"/>
	</form>
</body>

 => 클릭 1-1 (요청 : hello.do / get)

      클릭 1-2 (요청 : hello.do / post)

      클릭 2-1 (요청 : world.do / get)

      클릭 2-2 (요청 : good.do / get)

      클릭 2-3 (요청 : hi/nice.do / get)

      클릭 2-4 (요청 : korea.do / get)

      클릭 2-4 (요청 : usa.do / post)

 

 

 - web.xml

<!-- DispatcherServlet는 test-servlet.xml의 설정을 불러온다. -->
<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!-- servlet-name이 아닌 다른  path로 연결할 경우 사용-->
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			<!-- 공백 구분 -->
			/WEB-INF/abc/hello-servlet.xml
			/WEB-INF/def/world-servlet.xml
		</param-value>
	</init-param>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

=> test-servlet.xml이 아닌 다른 patch로 연결할 경우, <init-param> 태그를 사용한다.

     hello-servlet, world-servlet으로 연결된다.

 

 

- hello-servlet.xml/ world-servlet.xml

 * Controller implemets(상속)을 사용할 경우

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->
<bean name="/hello.do" class="pack.HelloController"></bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => hello.do 요청이 올 경우 HelloController가 실행된다.

 

  * @Controller(어노테이션)을 사용할 경우

<!-- 어노테이션 사용시 삭제 -->
<!-- 2. Handler Mapping -->
<!-- 
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
 -->
<!-- 3. Controller -->
<!--  
<bean name="/hello.do" class="pack.HelloController"></bean>
-->
<!-- 어노테이션 사용시 추가 -->
<context:component-scan base-package="pack"/>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => 어노테이션 사용시 <context:component-scan>를 사용한다. pack package의 어노테이션이 동작하도록 한다.

 

 

 - HelloController
 * Controller implemets(상속)을 사용할 경우

public class HelloController implements Controller{
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
									throws Exception {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("veiw1"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hello"); // 모델에 다녀왔다 가정. // key-value 전달.
		
		return modelAndView;
	}
}

=> hello-servlet.xml/ world-servlet.xml에서 연결한 hello.do 요청 발생 시 실행된다.

=> handlerRequest() 메소드를 오버라이딩하여 request를 처리한다.

=> setVieName("파일명")으로 view1에 연결된다. .hello-servlet.xml 파일의 ViewResover 처리로 /views/view1.jsp파일이

     연결된다.

 => addObject(key, value)를 이용하여 값을 전달한다.

 

  * @Controller(어노테이션)을 사용할 경우

 

@Controller
@RequestMapping("hello.do") // 모든 메소드가 수행된다.
public class HelloController{
	@RequestMapping(method=RequestMethod.GET)
	//@RequestMapping("hello.do") // 해당 메소드만 실행된다.
	public ModelAndView aaa() {
		ModelAndView modelAndView =  new ModelAndView();
		modelAndView.setViewName("view1");
		modelAndView.addObject("message", "hello aaa");
		return modelAndView;
	}
	
	@RequestMapping(method=RequestMethod.POST)
	//@RequestMapping("hello.do")
	public ModelAndView bbb() {
		ModelAndView modelAndView =  new ModelAndView();
		modelAndView.setViewName("view1");
		modelAndView.addObject("message", "hello bbb");
		return modelAndView;
	}
}

 => hello-servlet.xml의 <context:component-scan>태그로 인해 @Controller가 동작한다.

      @Controller : 클라이언트 요청에 따라 해당 클래스가 Controller동작을 하게된다.

      @RequestMapping("요청명") : 요청명에 해당하는 요청이 들어올 경우 클래스가 실행된다.

      @RequestMapping(method=RequestMethod.GET) : Get방식의 요청이 들어올때만 실행하게 한다.

      @RequestMapping(method=RequestMethod.POST) : Post방식의 요청이 들어올때만 실행하게 한다.

 => ModelAndView객체를 리턴하도록 하여 값을 전달한다. 메소드명을 임의 지정 가능하다.

 

 

 -  WorldController
 * Controller implemets(상속)을 사용할 경우

public class WorldController implements Controller{
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
								throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world"); // 모델에 다녀왔다 가정. // key-value 전달.
		
		return modelAndView;
	}
}

 => HelloController와 동일

 

  * @Controller(어노테이션)을 사용할 경우

 

@Controller
public class WorldController{
	@RequestMapping({"/world.do","/good*.*","/hi/nice.do"}) // 여러개의 요청을 받을 수 있음.
	//@RequestMapping("world.do")
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world"); // 모델에 다녀왔다 가정. key-value 전달.
		
		return modelAndView;
	}
	
	@RequestMapping(value="/korea.do", method=RequestMethod.GET) // GET만 받을 수 있다.
	//@RequestMapping({"/korea.do"})// Get과 Post를 모두 받을 수 있다.
	public ModelAndView handleRequest2(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world korea"); // 모델에 다녀왔다 가정. key-value 전달.
		
		return modelAndView;
	}
    
	@RequestMapping(value="/usa.*", method=RequestMethod.POST) // POST만 받을 수 있다.
	//@RequestMapping(value="/usa.*", method=RequestMethod.GET) // GET만 받을 수 있다.
	//@RequestMapping({"/usa.*"})
	public ModelAndView handleRequest3(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world usa"); // 모델에 다녀왔다 가정. key-value 전달.
		
		return modelAndView;
	}
}

 => @RequestMapping({요청명1, 요청명2,..}) : 배열을 사용하여 여러개의 요청명을 받을 수 있다.

      @RequestMapping(value="요청명", method=RequestMethod.GET) : 요청과 method 방식을 설정할 수 있다.

      요청명에 * 를 사용하여 복수의 요청을 받을 수 있다.

 

 

 - view1.jsp / view2.jsp

<body>
	hello 결과 : ${requestScope.message}
</body>

 => Controller에서 addObject()메소드로 전달한 value를 key를 사용하여 받을 수 있다. (EL 사용 - ${key})

 

 


2) 공유 객체 사용

 = spr4_share

 - index.html

<body>
	클래스 간 자원 공유<br>
	<a href="hello.do">요청 1</a><br>
	<a href="world.kor">요청2</a><br>
</body>

 

 

 - web.xml

<!-- WebApplicationContext보다 먼저 수행 : 공유 자원 설정시 필요 -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

 => applicationContext.xml에 공유자원을 설정한다.

<!-- WebApplicationContext에 의해 자동 수행 -->
<servlet>
	<servlet-name>hello</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!-- <load-on-startup> init() 메소드 호출 순서 -->
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>hello</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

<servlet>
	<servlet-name>world</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>world</servlet-name>
	<url-pattern>*.kor</url-pattern>
	<!-- <url-pattern>/</url-pattern> 모든 요청사항 -->
</servlet-mapping>

 => *.do 요청과 hello-servlet.xml 연결

 => *.kor요청과 world-servlet.xml 연결

 

 

- applicationContext.xml

<!-- 공유 자원 객체 생성 -->
<bean id="sharedData" class="pack.SharedData">
	<property name = "shared" value="스프링 프로젝트 공유자원입니다."/>
</bean>

 => setter injection을 이용하여 공유자원 객체 shard에 value를 설정한다.

 

 

 - hello-servlet.xml, world-servlet.xml

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->  
<bean name="/hello.do" class="pack.HelloController">
	<property name="data" ref="sharedData"/>
</bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => hello.do과 HelloController 연결. HelloController에 공유객체를 setter injection한다.

 

 

 - SharedData

public class SharedData {
	private String shared;
	public void setShared(String shared) {
		this.shared = shared;
	}
	public String getShared() {
		return shared;
	}
}

 => getter, setter를 이용하여 공유객체를 사용한다.

 

 

 - HelloController

public class HelloController implements Controller{
	private SharedData data; // 공유객체 선언.
	// setter injection에 사용
	public void setData(SharedData data) {
		this.data = data;
	}
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		// 현재 클래스가 공유자원을 사용
		ModelAndView modelAndView = new ModelAndView("helloworld"); // ViewFile명
		modelAndView.addObject("msg", data.getShared() + "hello");
	
		return modelAndView;
	}
}

 => ModelAndView("ViewFile명") : ModelAndView 생성자에 매개변수로 ViewFile명을 전달하여 ViewFile에 연결.  (setViewName("ViewFile명")과 동일)
 => addObject()메소드 사용하여 공유 객체의 내용 전달.

 

 

 - helloworld.jsp

<body>
	결과 : ${msg}
</body>

 


3) 패턴을 사용한 경로 매핑

 

 =spr5_arrange

 - index.html

<body>
	@MVC 기본정리<p/>
	<a href="hello.do">인사하기 1</a>
</body>

 => hello.do 요청. (get)

 

 

 - web.xml

<!-- WebApplicationContext에 의해 자동 수행 -->
<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!-- <load-on-startup> init() 메소드 호출 순서 -->
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

 => test-servlet.xml과 *.do를 url mapping한다.

 => <servlet-mapping>이 여러개 일 경우 <load-on-startup>로 init() 메소드 호출 순서를 지정할 수 있다.

 

 

 - test-servlet.xml

 * mapping 방법1 : 요청 url과 동일한 이름을 bean과 매핑(basic)

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->
<bean name="/hello.do" class="pack.controller.HelloController">
	<property name="helloModel" ref="helloModel"></property>
</bean>

<bean id="helloModel" class="pack.model.HelloModel"></bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

=> HelloController에 helloModel를 setter injection하여 객체 생성.

=>  hello.do 요청과 HelloController을 mapping

 

* mapping 방법2 : 경로 매핑(패턴 : *, ?)

<!-- 2. Handler Mapping-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="alwaysUseFullPath" value="true"/>
	<property name="mappings">
		<props>
			<!-- <prop key="*.do">hi</prop> -->
			<!-- <prop key="h*.do">hi</prop> -->
			<!--<prop key="/**/*.do">hi</prop> -->
			<prop key="/**/?????.do">hi</prop>
		</props>
	</property>
</bean>

<!-- 3. Controller -->
<bean name="hi" class="pack.controller.HelloController">
	<property name="helloModel" ref="helloModel"></property>
</bean>

<bean id="helloModel" class="pack.model.HelloModel"></bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 =>SimSimpleUrlHandlerMapping사용하여 <prop>에 경로 매핑 가능하다.

 => ?는 글자 갯수. * 복수개의 문자를 나타냄.

 => HelloController mapping의 name을 <prop>의 값으로 받아 패턴을 연결한다.

 

 

 - HelloController

public class HelloController implements Controller{
	
	private HelloModel helloModel;
	
	//setter injection
	public void setHelloModel(HelloModel helloModel) {
		this.helloModel = helloModel;
	}
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
				throws Exception {
		// 모델 만들고 모델과 통신하기
		String result = helloModel.getGreeting();
        
		ModelAndView modelAndView = new ModelAndView();
		//ModelAndView modelAndView = new ModelAndView("hello"); // ViewFile명
		
		modelAndView.setViewName("hello");
		modelAndView.addObject("result",result); // forword 방식(default)
		
		//modelAndView.setViewName("redirect:/views/hello.jsp?result='d'"); // reditect 방식
	
		return modelAndView;
	}
}

 => Controller를 상속받고 handleRequest 오버라이딩하여 요청사항을 처리한다.
 => 기본 방식을 forward로 하여 /views/hello.jsp에 addObject(key, value)로 값을 전달한다.
 => setViewName("redirect:/views/hello.jsp")으로 redirect 가능하다.

 

 - HelloModel

public class HelloModel {
	public String getGreeting() {
		int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		if(hour >= 6 & hour <= 10) {
			return "좋은 아침입니다.";
		}else if(hour >= 12 & hour <= 15) {
			return "점심은 맛있게 드셨나요";
		}else if(hour >= 18 & hour <= 22) {
			return "좋은 저녁되세요";
		}else {
			return "안녕하세요";
		}
	}
}

 => 기능을 담당하는 model 클래스

 

 

 - hello.jsp

<body>
 인사말 : ${result}
</body>

 


4) @annotation을 이용한 Controller호출

 

 = sprwrb6_annotation

 - index.html

<body>
	@MVC 기본정리<p/>
	<a href="hello.do">인사하기 1 - annotation</a><br>
	<a href="abc/world.do">인사하기 2 - annotation</a><br>
	<a href="kbs.do">인사하기 3 - annotation</a><br>
	<a href="hello">인사하기 4 - annotation</a><br>
	<br>
	<a href="kakao.do">인사하기 5 - annotation</a><br>
	<a href="mbc">인사하기 6 - annotation</a><br>
	<a href="sbs">인사하기 7 - annotation</a><br>
</body>

 => 요청 url 설정.

 

 - web.xml

<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
    <!--  <url-pattern>*.do</url-pattern>  확장자가 do인 요청 -->
  	<!-- <url-pattern>/aa.jsp</url-pattern> 단일 파일일 경우 /를 붙인다.-->
	<url-pattern>/</url-pattern><!-- 모든요청 -->
</servlet-mapping>

 => <url-pattern>/</url-pattern> 모든요청.
 => test-servlet 실행.

 

 

 - test-servlet.xml

* web.xml의 <url-pattern>/</url-pattern>를 적용하려면 다음 코드를 test-servlet.xml에 추가한다.

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="alwaysMustRevalidate" value="true"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
	<property name="alwaysUseFullPath" value="true"/>
</bean>

<mvc:annotation-driven/>
<mvc:default-servlet-handler/>

 => 모든 요청 경로가 연결된다.

 => <mvc:annotation-driven/> : @annotation기반의 Controller호출

 => <mvc:default-servlet-handler/> : 처리하지 못한 요청을 DefaultSerlvet에게 넘겨준다.

<!-- annotation인 경우 -->
<context:component-scan base-package="pack.controller"/>
<context:component-scan base-package="pack.model"/>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => <context:component-scan> : 어노테이션 사용시 사용.

 


- HelloController

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	
	@Autowired // setter injection
	private HelloModel helloModel;
	
	@RequestMapping(method=RequestMethod.GET) // GET방식과 mapping 
	public ModelAndView abc() { // 모델 만들고 모델과 통신하기
		String result = helloModel.getGreeting();
		ModelAndView modelAndView = new ModelAndView();
		 
		modelAndView.setViewName("hello");
		modelAndView.addObject("result",result); // forword 방식(default)
		  
		//modelAndView.setViewName("redirect:/views/hello.jsp?result='d'"); // reditect 방식
		 
		return modelAndView; 
	}
}

 => @Controller : 어노테이션을 사용하여 Controller를 호출한다.

 => ModelAndView객체를 리턴값으로 값을 전달한다. result key에 result value를 전달한다.

 

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	
	@Autowired // setter injection
	private HelloModel helloModel;
    
	// Map을 이용할 경우 출력할 View의 ViewName을 명시하지않는다.
	// 요청명을 그대로 ViewName으로 가져간다.
	// 요청명 hello, view명 hello.jsp
	@RequestMapping(method = RequestMethod.GET) // GET방식과 mapping
	public Map<String, Object> abc() {
		String result = helloModel.getGreeting();
		
		HashMap<String, Object> map = new HashMap<String, Object>();
		
		map.put("result", result); // 요청명이 view 파일명이 된다.
		
		return map;
	}
}

 => Map을 이용할 경우 출력할 View의 ViewName을 명시하지않는다.
      요청명을 그대로 ViewName으로 가져간다. (spec에 약속된 사항)
      요청명 hello, view명 hello

=> HashMap를 이용하여 key, value를 전달.

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	
	@Autowired // setter injection
	private HelloModel helloModel;
    
	@RequestMapping(method = RequestMethod.GET) // GET방식과 mapping
	public Model abc(Model model) {
		String result = helloModel.getGreeting();
		
		model.addAttribute("result",result); // 요청명이 view 파일명이 된다.
		
		return model;
	}
}

 => Model 객체를 이용하여 addAttribute()메소드를 이용하여 값을 전달한다.

      요청명을 그대로 ViewName으로 가져간다. (spec에 약속된 사항)

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	@Autowired // setter injection
	private HelloModel helloModel;
	@RequestMapping(method = RequestMethod.GET) // GET방식과 mapping
	public String abc() {
		String result = helloModel.getGreeting();
		
		return "hello";
	}
}

 => String 리턴값을 가져간다.

      요청명을 그대로 ViewName으로 가져간다. (spec에 약속된 사항)

 

 

 - HelloModel

@Component
public class HelloModel {
	public String getGreeting() {
		int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		if(hour >= 6 & hour <= 10) {
			return "좋은 아침입니다.";
		}else if(hour >= 12 & hour <= 15) {
			return "점심은 맛있게 드셨나요";
		}else if(hour >= 18 & hour <= 22) {
			return "좋은 저녁되세요";
		}else {
			return "안녕하세요";
		}
	}
}

 

 - hello.jsp

<body>
 - annotation<br>
 인사말 : ${result}
</body>

 

 


5) Spring MVC Project를 사용

 

[New] - [Spring Legacy Project] - project명 입력 - [Spring MVC Project] 선택 - [Next] - aa.bb.cc입력 - [finish]

 

 - pom.xml

<properties>
	<java-version>1.8</java-version>
	<org.springframework-version>5.0.0.RELEASE</org.springframework-version>
	<org.aspectj-version>1.6.10</org.aspectj-version>
	<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>

 => 변경

 

 


6) @RequestParam 사용(get)

 = sprweb8_parameter

 - login.jsp

<form action="login" method="get">
	id : <input type="text" name="id"/><br>
	password : <input type="text" name="pwd"/><br>
	<input type="submit" value="전송(get)">
</form>

 => login url로 name이 id, pwd인 값 전달.(get)

 

 

 - LoginController

* Controller 값 처리(기존) : getParameter()

@Controller
public class LoginController {
	//@RequestMapping("login")
	@RequestMapping(value="login", method=RequestMethod.GET)
	public ModelAndView submit(HttpServletRequest request) {
		String id = request.getParameter("id");
		String pwd = request.getParameter("pwd");
		
		System.out.println("id:"+id);
		System.out.println("pwd:"+pwd);
		
		String data = "";
		if(id.equals("aa") && pwd.equals("11")) {
			data = "로그인 성공";
		}else {
			data = "로그인 실패";
		}
			
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data", data);
		
		return view;
	}
}

 => getParameter() 메소드를 사용하여 값을 가져온다.

 => 로직 동작 후 seyViewName()로 result.jsp에 addObject()메소드로 data값을 전달한다.

 

* Controller 값 처리(어노테이션 사용)

@Controller
@RequestMapping("login") // type level mapping
public class LoginController {
	
	@RequestMapping(method=RequestMethod.GET) // method level mapping
	public ModelAndView submit(
			@RequestParam("id") String id,
			@RequestParam("pwd") String pwd) {
		
		String data = "";
		if(id.equals("aa") && pwd.equals("11")) {
			data = "로그인 성공";
		}else {
			data = "로그인 실패";
		}
			
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data", data);
		
		return view;
	}
}

 => @RequestParam("name")을 사용하여 getParameter()의 기능을 수행한다.

 

 

 - result.jsp

<body>
	결과 : ${data}
</body>

 


* get 방식은 한글이 안깨지나 post 방식사용시 한글이 깨진다. Encording을 하여 한글 깨짐을 방지한다.

 

 - web.xml

<!-- 한글 깨짐 방지(post) -->
<filter>
	<filter-name>encodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter
	</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>encodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

 => web.xml에 위의 코드를 copy&paste한다.

 


7) FormBean, @ModelAttribute 사용(post)

 

 

 - input.jsp

<h2>* 자료입력</h2>
<form action="sangpum" method="post">
	품명 : <input type="text" name="sang"><br>
	수량 : <input type="text" name="su"><br>
	단가 : <input type="text" name="dan"><br>
	<input type="submit" valus="전송(post)"/>
</form>

 

 - SangpumController

* Controller 값 처리(기존) : getParameter()

@Controller
public class SangpumController {
	@RequestMapping(value="sangpum", method=RequestMethod.POST)
	public ModelAndView submit(HttpServletRequest request) {
		String sang = request.getParameter("sang");
		String su = request.getParameter("su");
		String dan = request.getParameter("dan");
		System.out.println(sang+" "+" "+su+" "+dan);
		
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data","good");
		
		return view;
	}
}

* Controller 값 처리(FormBean 사용)

@Controller
public class SangpumController {
	@RequestMapping(value="sangpum", method=RequestMethod.POST)
	public ModelAndView submit(SangpumBean bean) { // 지역 변수
		//클라이언트로 부터 들어오는 데이터 양이 많을 경우 사용(form bean)
		
		System.out.println(bean.getSang()+" "+" "+bean.getSu()+" "+bean.getDan());
		
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data","good");
		
		return view;
	}
}

 => 매개변수로 FormBean을 사용하여 값을 전달한다. bean의 범위는 {}안으로 지역변수로 사용된다.

 

* Controller 값 처리(@ModelAttribute 사용)

@Controller
public class SangpumController {
	@Autowired // setter injection
	private SangpumModel sanpumModel;
	
	@RequestMapping(value="sangpum", method=RequestMethod.POST)
	//public ModelAndView submit(SangpumBean bean) { // 지역 변수
	public ModelAndView submit(@ModelAttribute("bean") SangpumBean bean) { // 전역변수
		//클라이언트로 부터 들어오는 데이터 양이 많을 경우 사용(form bean)
		
		System.out.println(bean.getSang()+" "+" "+bean.getSu()+" "+bean.getDan());
		
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data",sanpumModel.computeSangpum(bean));
		
		return view;
	}
}

 => 매개변수로 @ModelAttribute을 사용시 bean의 범위는 전역변수로 사용되어 addObject() 메소드를 사용하지않아도

      다른 파일에서 접근이 가능하다.

 

 

 - SangpumBean

@Component
public class SangpumBean { // form bean
	private String sang; // 클라이언트로 부터 전달되어 오는 요청 Parameter값과 변수명을 동일하게 가져간다.
	private int su, dan;
	
	public String getSang() {
		return sang;
	}
	public void setSang(String sang) {
		this.sang = sang;
	}
	public int getSu() {
		return su;
	}
	public void setSu(int su) {
		this.su = su;
	}
	public int getDan() {
		return dan;
	}
	public void setDan(int dan) {
		this.dan = dan;
	}
}

 => Form Bean 정의. Form Bean의 멤버변수는 <form>태그 하위 태그 name의 값과 동일하게 가져간다.

 

 - SangpumModel

@Component // 객체생성
public class SangpumModel { // 비지니스 로직 처리를 하는 모델 영역의 클래스
	public String computeSangpum(SangpumBean bean) {
		int price = bean.getSu() * bean.getDan();
		String data = "품명" + bean.getSang() + " , 금액은 "+price;
		
		return data;
	}
}

 

 

- result.jsp

<body>
post 결과 : ${data}
<br>
${bean.sang}
</body>

 

12. MVC pattern

Client
(html)
----> Controller
(servlet,
interface, class)
----> Model
(DTO, DAO-sql)
----> DB
----> View
(FormBean, jsp)
   

 

1) Client : html의 <form>,<a>태그로 값을 전달한다.

<form action="path" method="get">
	<input type="text" name="name1" value="value1">
	<input type="submit">
</form>


<a href="sang.do?command=sang">상품</a><br> // Parameter로 값 전달
<a href="sang.do">상품</a> // 요청명으로 값 전달
<a href="buser.do">부서</a>

 

2) Controller

① servlet

@WebServlet("/hobby.do") : 단일
@WebServlet({"/hobby.do","/nicd.do"}) : 배열(복수)
@WebServlet({"*.do","*.kor"}) : 확장자(복수)

 => ( )안 설정한 url pattern을 사용하여 servlet 호출할 수 있다.

 

private HobbyModel model;
public void init() throws ServletException {
	model = new HobbyModel();
}

 => servlet의 service에 구현시 요청마다 new 객체 생성시 메모리를 많이 소모 함으로 init()에 작성한다.

 

protected void service(HttpServletRequest request, HttpServletResponse response)
						throws ServletException, IOException {

 => get/post방식에 상관없이 동작하도록 구현.

 

	try {
		name=request.getParameter("name");
	} catch (Exception e) {
		name=null;
	}  

 => 요청처리 방법 1 : parameter사용. request.getParameter()로 html의 value를 전달받는다.

 

	String str1 = request.getRequestURI();
	// 요청명 : /mvc_ex3_db/sang.do
	int idx = str1.lastIndexOf('/');
	// 11
	String str2 = str1.substring(idx+1); // idx+!부터 끝까지 자름
	// sang.do
	StringTokenizer str3 = new StringTokenizer(str2,"."); // str2를 .을 기준으로 토큰화
	// sang ,  do
	str4 = str3.nextToken();
	// sang
	String command = str4;

 => 요청처리 방법 2 : 요청명을 사용

      "/프로젝트명/uripattern.확장자"로 전달받는다.

 

	CommandInter inter = null;
	String viewName = "views/";
	try {
		if(command.equals("sang")) {
			inter = SangpumImpl.instance();
		}else if(command.equals("buser")) {
			inter = BuserImpl.instance();
		}else if(command.equals("jikwon")) {
			inter = JikwonImpl.instance();			
		}else {
			viewName += "error.html";
			response.sendRedirect(viewName);
            return;
		}
		viewName += inter.showData(request, response);
	} catch (Exception e) {
		System.out.println("service : "+e);
	}

 => interface를 상속받은 클래스의 singletone 객체를 받아온다.

 => 명령에 따른 다른 table의 객체를 받아오도록 오버라이딩을 진행한 메소드를 실행한다.

 

	//HobbyModel model = new HobbyModel();
	ArrayList<String> list = model.getHobby(hobby);
	request.setAttribute("datas", list);

 => 다음의 모델은 interface를 상속받은 클래스에 구현한다.(다형성을 사용)

 

	//response.sendRedirect(viewName+"?result="+result); // 컬렉션 류의 객체는 전달X
		
	request.setAttribute("result", result); // 객체 전달 가능.
	RequestDispatcher rd = request.getRequestDispatcher(viewName);
	rd.forward(request, response);
}

 => request setAttribute(), getAttribute()으로 값 전달.

 => sendRedirect의 경우 객체를 전달할 수 없어 forward로 요청 재지정하여 값 전달.

 

 

 * web.xml를 이용한 url pattern 등록 (경로 : Context/WEB_INF/web.xml)

<welcome-file-list>
	<welcome-file>index.html</welcome-file>
	<welcome-file>index.htm</welcome-file>
	<welcome-file>index.jsp</welcome-file>
	<welcome-file>default.html</welcome-file>
	<welcome-file>default.htm</welcome-file>
	<welcome-file>default.jsp</welcome-file>
</welcome-file-list>

 => <welcom-file>내 파일명을 입력하면, 도메인만 입력시에 해당 파일이 실행된다.

 => 위쪽 부터 우선순위를 가진다.

 

<servlet>
	<servlet-name>hobby</servlet-name>
	<servlet-class>pack.controller.HobbyController</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>hobby</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

=> url pattern 등록

 

 

② Interface

public interface CommandInter {
	String showData(HttpServletRequest request, HttpServletResponse response);
}

 

 

③ class

public class SangpumImpl implements CommandInter{
	//Singleton
	static SangpumImpl impl = new SangpumImpl();
	public static SangpumImpl instance() {
		return impl;
	}

	@Override
	public String showData(HttpServletRequest request, HttpServletResponse response) {
		SangpumModel model = new SangpumModel();//원래는 싱글으로 작성된 클래스를 읽어야함.
		ArrayList<SangpumDto> list = model.getDataAll();
		request.setAttribute("datas", list);
		return "sangpum.jsp";
	}

}

 => 모델에 있는 클래스와 통신을 하는 컨트롤러 영역내의 클래스를 선언한다.

 

* Singletone : 한클래스당 하나의 객체만 사용하도록 하는 인스턴스.

class 클래스명{
	private static 클래스명 singleton명 = new 클래스명();
	static 클래스명 getInstance(){
		return singleton;
	}
}

 

 

3) Model

① DTO

public class SangpumDto {
	private String code;
	private String sang;
	private String su;
	private int dan;
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
    ...
}

 => 필드, getter, setter 선언

 

 

② DAO (or Model)

 * JDBC Connection pooling

public class SangpumModel {
	private Connection conn;
	private PreparedStatement ptmt;
	private ResultSet rs;
	private DataSource ds;
	
	
	public SangpumModel() {
		try {
			Context context = new InitialContext();
			ds= (DataSource)context.lookup("java:comp/env/jdbc_maria");
		} catch (Exception e) {
			System.out.println("SangpumModel err"+e);
		}
	}
	
	public ArrayList<SangpumDto> getDataAll(){
		ArrayList<SangpumDto> list = new ArrayList<>();
		try {
			conn=ds.getConnection();
			String sql = "select * from sangdata";
			ptmt = conn.prepareStatement(sql);
			rs= ptmt.executeQuery();
			while(rs.next()) {
				SangpumDto dto = new SangpumDto();
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getString("su"));
				dto.setDan(rs.getInt("dan"));
				list.add(dto);
			}
		} catch (Exception e) {
			System.out.println("getDataAll err"+e);
		}finally {
			try {
				if(conn!=null) conn.close();
				if(ptmt!=null) ptmt.close();
				if(rs!=null) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
}

 

 * Mybatis (xml)

  - db.properties : 계정정보

  - Configuration.xml : <alias>, <mapper> 수정

  - DataMapper.xm : xml 형식 sql문 작성

  - SqlMapConfig : SqlSessionFactory 객체 생성

  - DAO(or model)

public class SangpumModel {
	private SqlSessionFactory factory = SqlMapConfig.getSqlSession();
	
	public ArrayList<SangpumDto> getDataAll(){
		ArrayList<SangpumDto> list = null;
		SqlSession sqlSession = factory.openSession();
		list = (ArrayList)sqlSession.selectList("selectDataAll");
		sqlSession.close();
		return list;
	}
}

 

* Mybatis (@어노테이션)

  - db.properties : 계정정보

  - Configuration.xml : <alias>, <mapper> 삭제

  - DataMapper.xm : 삭제

  - SqlMapperInter : 테이블수에 맞게 작성. sql문 작성

public interface SqlMapperInter_Jikwon {
	@Select("select jikwon_no, jikwon_name, buser_num, jikwon_jik from jikwon where buser_num = #{buser_no}")
	public List<JikwonDto> selectPartJikwon(String buser_no);
}

 

  - SqlMapConfig : SqlMapperInter의 class 배열에 연결.

Class[] mappers = {SqlMapperInter_Buser.class, SqlMapperInter_Jikwon.class, SqlMapperInter_Gogek.class};
for(int i=0; i<mappers.length;i++) {
	sqlSession.getConfiguration().addMapper(mappers[i]);
}

 

  - DAO(or model) : SqlSessionFactory객체사용하여 sql 메소드 호출.

public class JikwonDao {
	private SqlSessionFactory factory = SqlMapConfig.getSqlSession();
	
	public ArrayList<JikwonDto> selectPartJikwon(String buser_no){
		ArrayList<JikwonDto> list = new ArrayList<>(); 
		SqlSession sqlSession = factory.openSession();
		
		try {
			SqlMapperInter_Jikwon inter = sqlSession.getMapper(SqlMapperInter_Jikwon.class);
			list = (ArrayList)inter.selectPartJikwon(buser_no);
		} catch (Exception e) {
			System.out.println("selectPartJikwon err"+e);
		}finally {
			if(sqlSession != null) sqlSession.close();
		}
		return list;
	}
	
}

 

 

4) View

① jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
</head>
<body>
	*상품자료(MVC pattern)
	<table border="1">
		<tr>
			<td>코드</td><td>품명</td><td>수량</td><td>단가</td>
		</tr>
		<c:forEach var = "s" items="${datas}">
			<tr>
				<td>${s.code}</td>
				<td>${s.sang}</td>
				<td>${s.su}</td>
				<td>${s.dan}</td>
			</tr>
		</c:forEach>
	</table>
	
</body>
</html>

 

'BACK END > Servlet' 카테고리의 다른 글

[Servlet] Servlet 정리9 - Mybatis2  (0) 2021.01.06
[Servlet] Servlet 정리8 - Mybatis  (0) 2021.01.06
[Servlet] Servlet 정리7 - JDBC  (0) 2021.01.06
[Servlet] Servlet 정리6 - EL, JSTL  (0) 2021.01.04
[Servlet] Servlet 정리5 - Ajax  (0) 2021.01.03

+ Recent posts

1