**Spring MVC Project를 위한 데이터베이스 테이블을 생성
=> Oracle과 MyBatis -> Hibernate로 변경 -> MySQL
1. Oracle에 작성
drop table item;
CREATE TABLE ITEM(
itemid number(5),
itemname VARCHAR2(20),
price number(6),
description VARCHAR2(50),
pictureurl VARCHAR2(20),
PRIMARY KEY (itemid)
);
insert into item values(1, 'Lemon', 500, 'Vitamin-A', 'lemon.jpg');
insert into item values(2, 'Orange', 1500, 'Vitamin-B', 'orange.jpg');
insert into item values(3, 'Kiwi', 2000, 'Vitamin-C', 'kiwi.jpg');
insert into item values(4, 'Grape', 1000, 'Vitamin-D', 'grape.jpg');
insert into item values(5, 'Strawberry', 2000, 'Vitamin-E', 'strawberry.jpg');
insert into item values(6, 'Mandarin', 300, 'Vitamin-F', 'mandarin.jpg');
commit;
select * from ITEM;
=> 오라클은 테이블이름과 컬럼명을 모두 대문자를 사용 : DTO를 만들지 않고 Map 이용시 중요
2. MySQL에 작성
drop table item;
-- 데이터 삽입, 삭제, 갱신이 빈번하면 innodb
-- 주 업무가 조회라면 MyISAM(Indexed Sequential Access Media)으로 설정
-- 한글이 있으면 인코딩 설정을 해주어야 함
CREATE TABLE ITEM(
itemid int,
itemname VARCHAR(20),
price int,
description VARCHAR(50),
pictureurl VARCHAR(20),
PRIMARY KEY (itemid)
)engine=innodb default charset=utf8;
insert into item values(1, 'Lemon', 500, 'Vitamin-A', 'lemon.jpg');
insert into item values(2, 'Orange', 1500, 'Vitamin-B', 'orange.jpg');
insert into item values(3, 'Kiwi', 2000, 'Vitamin-C', 'kiwi.jpg');
insert into item values(4, 'Grape', 1000, 'Vitamin-D', 'grape.jpg');
insert into item values(5, 'Strawberry', 2000, 'Vitamin-E', 'strawberry.jpg');
insert into item values(6, 'Mandarin', 300, 'Vitamin-F', 'mandarin.jpg');
commit;
select * from ITEM;
=> MySQL은 테이블 이름이나 컬럼 이름을 소문자로 사용
**Spring MVC Project 설정
1. Spring MVC Project를 생성
=> 기본 패키지 이름을 3 level 이상으로 설정
=> 3번째 패키지 이름이 application의 ContextPath(URL 기본경로) : Tomcat에서 수정 가능
- 실제 도메인 연결시는 없어짐, 포트번호 생략하려고 하면 http : 80번, https : 443번을 사용
2. 애플리케이션 실행
=> url - http://localhost:9000/pk/
3. 포트번호 생략
=> server.xml에서 tomcat의 port를 80번으로 변경
<!-- Servers/Tomcat.../server.xml에서 수정 -->
<Connector connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443"/>
4. ContextPath를 제거
=> ContextPath를 /로 변경
1) Tomcat 설정을 수정
=> [Servers] 탭에서 Tomcat을 더블 클릭
=> Modules탭에서 실행하고자 하는 프로젝트를 선택하고 [Edit]버튼을 누른 후 path를 /로 설정
2) 재실행
3) 다른 컴퓨터의 브라우저에서는 http://IP주소 만 입력하면 접속이 됨
5. Java, Spring, JUnit, Servlet, JSP 버전을 변경
=> pom.xml에서 수행
1) Java와 Spring버전 변경은 properties 태그에서 수행
<properties>
<java-version>1.8</java-version>
<org.springframework-version>5.0.7.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
=> java는 람다와 스트림을 사용한다면 1.8 이상
=> Spring은 4.0.0 이상을 사용
2) dependencies 태그 안에서 servlet과 jsp의 dependency를 수정
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.0</version>
<scope>provided</scope>
</dependency>
=> scope 태그를 남겨두어야 함
- scope가 있으면 현재 프로젝트의 라이브러리를 가져가지 않고 실행되는 곳의 라이브러리 사용
- servlet과 jsp는 java에 있는 것을 사용하지 않고 WAS의 것을 사용
3) JUnit - dependencies 안에서 수정(4.12로 변경, Spring 5.0이상은 4.12부터 테스트 가능
=> 단위(클래스나 메소드) 테스트 라이브러리
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
=> scope를 남겨두는데 이 scope는 테스트 할때 사용되고 배포를 할 때는 삭제가 되는 라이브러리 설정
4) servlet 버전을 변경한 경우 web.xml 파일의 DTD 수정
=> 이 작업없이도 실행에는 문제 X, 이 프로젝트를 다른 환경으로 가져가면 에러 발생
=> 구글에 web.xml 서블릿 버전으로 검색하면 DTD 검색됨
=> 기존 webapp 태그를 아래 내용으로 수정
<web-app version="3.1" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
6. 기본 설정이 끝나면 재실행
7. 여러명이 하는 프로젝트라면 여기까지는 일반적으로 project Manager가 결정
**오라클의 데이터를 MyBatis를 이용해서 읽어오기
=> MyBatis : SQL Mapper : SQL과 프로그래밍 언어의 코드를 분리
=> CRUD(Create, Read, Update, Delete)를 위한 프로젝트 구조
- Controller <- Service <- Repository <- MyBatis Session(xml, interface)
- DTO
- Interceptor, AOP Class
- Error Page 설정
1. pom.xml 파일에 필요한 의존성 설정
=> 필수 : oracle, spring-jdbc, mybatis, spring-mybatis : 필수
=> Spring-test : Test를 하고자 하면(거의 필수)
=> lombok : DTo 클래스를 편리하게 만들고자 하면(최근에 많이 사용)
=> log4jdbc : 데이터베이스 연동시 로그를 출력하고자 하면(개발시에만 사용)
1) Oracle의 Repository 설정 : Oracle의 경우 Maven 중앙저장소에 없어서 설정
<repositories>
<repository>
<id>oracle</id>
<name>ORACLE JDBC Repository</name>
<url>http://maven.jahia.org/maven2</url>
</repository>
</repositories>
2) dependencies 에 나머지 의존성 설정
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc7</artifactId>
<version>12.1.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4</artifactId>
<version>1.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework-version}</version>
</dependency>
3) pom.xml 수정후 저장하고 잠시 기다렸다가 재실행
=> 실행이 안되면 라이브러리를 다운받지 못한 것이나 설정 실패
2. 필요한 클래스를 생성
=> MyBatis를 xml로 사용
1) DTO 클래스 생성 : kr.co.pk.item.domain
=> 자료형과 이름을 정확하게 기재
2) DAO 클래스 생성 : kr.co.pk.item.
package kr.co.pk.item.dao;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class ItemDAO {
@Autowired
//MyBatis를 xml로 이용할 때 사용하는 클래스
private SqlSession sqlSession;
}
3) Service 인터페이스 생성 : kr.co.pk.item.service.ItemService
package kr.co.pk.item.service;
public interface ItemService {
}
4) Service 인터페이스의 내용을 구현할 ServiceImpl 클래스를 생성 : kr.co.pk.item.service.ItemServiceImpl
=> DAO를 주입받음
package kr.co.pk.item.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kr.co.pk.item.dao.ItemDAO;
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemDAO itemDao;
}
5) Controller 클래스를 생성 : kr.co.pk.item.controller.ItemController
=> Service를 주입받음
package kr.co.pk.item.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import kr.co.pk.item.service.ItemService;
@Controller
public class ItemController {
@Autowired
private ItemService itemService;
}
3. 데이터베이스 프레임워크 설정(Oracle + MyBatis)
1) 데이터베이스 접속 정보를 저장
=> root-context.xml 파일에 작성
=> 데이터베이스는 모든 서비스에 이용될 가능성이 높으므로 root-context.xml 파일에 작성
<!-- 모든곳에서 사용할 Bean을 생성 -->
<!-- 데이터 베이스 접속 정보를 저장하는 bean을 생성
데이터베이스 종류별로 설정 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@192.168.0.200:1521:xe</value>
</property>
<property name="username">
<value>system</value>
</property>
<property name="password">
<value>*******</value>
</property>
</bean>
2) Test 클래스를 만들어서 테스트
=> src/test/java 디렉토리에 생성
package kr.co.pk;
import javax.sql.DataSource;
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;
//설정 파일을 읽어오는 코드
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"file:src/main/webapp/WEB-INF/spring/root-context.xml"})
public class ItemTest {
//데이터베이스 접속 정보를 주입
@Autowired
private DataSource dataSource;
//데이터베이스 연결을 테스트
@Test
public void connectTest() {
try {
System.out.println(dataSource.getConnection());
}catch(Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
3) XML을 이용해서 MyBatis를 연동할 때 사용할 매퍼 파일을 생성
=>src/resources 디렉토리에 별도의 디렉토리(mappers)를 생성해서 만드는 것이 일반적
=> mappers/item.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="item">
</mapper>
4) root-context 파일에 xml을 이용해서 MyBatis를 사용할 수 있도록 해주는 Bean추가
<!-- XML을 이용한 MyBatis 사용 설정 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- mappers 디렉토리 안에 있는 모든 xml을 mapper 로 사용
다른 용도의 xml 파일이 있으면 에러 -->
<property name="mapperLocations"
value="classpath:mappers/**/*.xml" />
</bean>
<bean id="sqlSession"
class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
5) Test 클래스에 MyBatis 설정을 확인하기 위해 Test Source 추가
//MyBatis 사용 클래스를 주입
@Autowired
private SqlSession sqlSession;
//MyBatis 설정 정보를 테스트
@Test
public void mybatisTest() {
System.out.println(sqlSession);
}
=> mapper 파일에 sql이 하나도 없어서 에러 발생 (sql을 작성하고 다시 테스트)
4. 웹 애플리케이션이 시작할 때 Item 테이블의 전체 데이터를 가져와서 출력
1) sql 매퍼 파일에 필요한 SQL을 생성
<!-- Item 테이블의 데이터를 전부 가져오는 SQL -->
<select id="allitem"
resultType="kr.co.pk.item.domain.Item">
select itemid, itemname, price, description, pictureurl from item
</select>
2) ItemDAO 클래스에 전체 데이터를 가져오는 메소드를 생성
public List<Item> allitem(){
return sqlSession.selectList("item.allitem");
}
3) ItemService 인터페이스에 전체 데이터를 가져오는 메소드를 선언
//전체 데이터를 가져오는 메소드
public void allitem(
HttpServletRequest request,
HttpServletResponse response);
5) ItemController 클래스에 시작 요청을 처리하는 메소드를 수정
=> 단순한 웹 애플리케이션을 만들 때와 웹 서버를 만들 때는 Controeller가 조금씩 수정
=> 기존 homeController 내용은 삭제
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(HttpServletRequest request, HttpServletResponse response) {
//서비스의 메소드를 호출
itemService.allitem(request, response);
return "home";
}
6) 기존의 home.jsp 파일을 삭제하고 새로 생성한 후 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- jsp를 이용하여 데이터 출력시 이코드는 거의 필수 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ITEM</title>
</head>
<body>
<div align="center" class="body">
<h2>상품 목록</h2>
<table border="1">
<tr class="header">
<th width="80">상품 ID</th>
<th width="300">상품 이름</th>
<th width="100">상품 가격</th>
</tr>
<c:forEach var="item" items="${list}">
<tr class="recode">
<td width="80">${item.itemid}</td>
<td width="300">${item.itemname}</td>
<td width="100" align="right">${item.price}원</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
7) webapp 디렉토리에 css 디렉토리를 만들고 home.css 파일을 만들고 작성
div.body{
overflow-y:auto;
margin-top:50px;
margin-bottom:50px;
}
tr.header{
background:#C9BFED;
}
tr.record{
backgorund:#EDEDED;
}
8) home.jsp에 home.css를 적용
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/home.css">
9) servlet-context.xml 파일에 추가
<!-- Controller가 처리하지 못하는 URL은 WAS가 처리하도록 하는 설정 -->
<default-servlet-handler />
10) 다시 실행
5. 상세보기 구현
=> 목록보기에서 하나를 골라서 그 하나를 자세히 보는 기능
=> 목록보기에서 목록을 클릭하면 클릭한 목록을 자세히 보여주는 형태로 구현
- 클릭시 하나의 데이터를 찾아 올수 있도록 기본키 값을 어떻게 넘겨줄 것인지를 고려
- 웹에서는 url 뒤에 파라미터로 넘겨주던가 /값을 작성하는 형태를 이용
=> 최근에는 파라미터로 넘기기 보다는 URL에 변수를 추가하는 형태로 많이 구현
1) home.jsp 파일에 제목을 출력하는 부분을 수정
<a href="detail/${item.itemid}">${item.itemname}</a>
2) item.xml 파일에 상세보기를 위한 SQL 구현
<!-- Item 테이블에서 데이터 1개를 가져오는 SQL -->
<select id="detailitem"
parameterType="java.lang.Integer"
resultType="kr.co.pk.item.domain.Item">
select itemid, itemname, price, description, pictureurl
from item
where itemid = #{itemid}
</select>
3) mapper 테스트 : Test 클래스에 작성
@Test
public void detailitem() {
System.out.println(sqlSession.selectOne("item.detailitem",1));
}
4) ItemDAO에 상세보기를 위한 메소드를 작성
//Item 테이블에서 1개의 데이터를 가져오는 메소드
public Item detailitem(Integer itemid) {
return sqlSession.selectOne("item.detailitem", itemid);
}
5) itemService인터페이스에 상세보기를 위한 메소드 선언
//상세보기를 위한 메소드
public void detailitem(HttpServletRequest request, HttpServletResponse response);
6) itemServiceImpl 클래스에 상세보기를 위한 메소드를 구현
@Override
public void detailitem(HttpServletRequest request, HttpServletResponse response) {
//요청 주소의 마지막 부분 가져오기
//localhost/detail/itemid
String requestURI = request.getRequestURI();
String [] ar = requestURI.split("/");
String itemid = ar[ar.length-1];
//DAO의 메소드 호출
Item item = itemDao.detailitem(Integer.parseInt(itemid));
//결과를 저장
request.setAttribute("item", item);
}
7) ItemController 클래스에 상세보기를 위한 메소드를 구현
@RequestMapping(value = {"detail/{itemid}"}, method = RequestMethod.GET)
public String detail(HttpServletRequest request, HttpServletResponse response) {
//서비스의 메소드를 호출
itemService.detailitem(request, response);
return "detail";
}
8) 이미지를 프로젝트 내에 복사
=> webapp 디렉토리에 img 디렉토리 배치
9) detail.jsp 파일을 생성하고 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상세보기</title>
<link rel="stylesheet"
href="${pageContext.request.contextPath}/css/style.css">
</head>
<body>
<div align="center" class="body">
<h2>상품 상세 화면</h2>
<table border="1">
<tr class="header">
<td>
<img src="${pageContext.request.contextPath}/img/${item.pictureurl}"/>
<td>
<td>
<table>
<tr height="50">
<td width="80">상품명</td>
<td width="160">${item.itemname}</td>
</tr>
<tr height="50">
<td width="80">가격</td>
<td width="160">${item.price}원</td>
</tr>
<tr height="50">
<td width="80">비고</td>
<td width="160">${item.description}</td>
</tr>
<tr>
<td colspan="2" align="center"
width="240">
<a href="${pageContext.request.contextPath}/">
■목록으로 돌아가기
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</body>
</html>
6. MySQL로 변환
1) pom.xml 파일에 mysql 의존성을 추가
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
2) root-context.xml 파일에서 DataSource를 MySQL로 변경
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/myproject?
useUnicode=yes&characterEncoding=UTF-8 </value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>900826</value>
</property>
</bean>
7. Mapper 인터페이스를 이용한 MyBatis 사용
=> Mapper 인터페이스를 이용하면 xml파일을 만들 필요 없고, DAO도 만들 필요가 없음
1) Mapper로 사용할 인터페이스를 생성, 전체 데이터를 가져오는 메소드와 itemid를 이용하여 상세보기 메소드 생성
=> kr.co.pk.item.dao.ItemMapper
public interface ItemMapper {
@Select("select itemid, itemname, price, description, pictureurl from item")
public List<Item> allitem();
@Select("select itemid, itemname, price, description, pictureurl from item "
+ "where itemid = #{itemid}")
public List<Item> detailitem(Integer itemid);
}
2) root-context.xml 파일에 MapperFactoryBean을 생성
<!-- 인터페이스를 이용하여 MyBatis를 이용할 때 생성 -->
<bean id="ItemMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="mapperInterface" value="kr.co.pk.item.dao.ItemMapper" />
</bean>
3) ServiceImpl 클래스에서 ItemMapper를 주입받아서 사용하면 됨
@Autowired
//private ItemDAO itemDao;
private ItemMapper itemDao;
4) 전자정부 프레임워크나 기업에서 만든 프레임워크 들은 샘플 프로젝트에서 xml을 이용하는 방식 채택
8. hibernate로 변환
=> DTO 클래스를 확인 : 자료형을 확인
1) pom.xml 파일에 hibernate와 spring-orm의 의존성을 설정
<!-- hibernate 의존성 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.2.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework-version}</version>
</dependency>
2) Item 클래스와 테이블을 매핑하기 위한 하이버네이트 설정 파일 작성
=> kr.co.pk.item.dao 패키지에 item.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="kr.co.pk.item.domain">
<class name="Item" table="ITEM">
<id name="itemid" column="itemid" />
<property name="itemname" column="itemname"/>
<property name="price" column="price"/>
<property name="description" column="description"/>
<property name="pictureurl" column="pictureurl"/>
</class>
</hibernate-mapping>
3) root-context.xml 파일에 hibernate bean을 추가
=> 하이버네이트는 트랜잭션이 필수라서 tx네임스페이스를 추가
<!-- 하이버네이트 설정 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>kr/co/pk/item/dao/item.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>hibernate.dialect=org.hibernate.dialect.MySQLDialect</value>
</property>
</bean>
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
4) ItemDAO 클래스에 Hibernate 의 SessionFactory를 주입하고 메소드 코드를 수정
@Autowired
private SessionFactory sessionFactory;
//Item 테이블의 전체 데이터를 가져오는 메소드
public List<Item> allitem(){
//return sqlSession.selectList("item.allitem");
return sessionFactory.getCurrentSession().createCriteria(Item.class).list();
}
//Item 테이블에서 1개의 데이터를 가져오는 메소드
public Item detailitem(Integer itemid) {
//return sqlSession.selectOne("item.detailitem", itemid);
return sessionFactory.getCurrentSession().get(Item.class, itemid);
}
5) ItemServiceImpl의 메소드위에 @Transactional을 추가
=> 트랜잭션은 Service에 적용
**프로젝트에서 MyBatis를 XML로 사용하는 형태로 변환 - 데이터베이스는 오라클
=> 우리나라 공공기관이 대기업 SI에서는 아직까지 Oracle에 XML을 이용하는 MyBatis 방식을 많이 사용하기 때문
1. root-context.xml 파일에서 MySQL의 DataSource를 주석 처리하고 오라클의 DataSource를 주석해제
2. ItemDAO 클래스에서 하이버네이트 사용하는 부분을 주석처리하고 MyBatis 사용하는 부분으로 변경
3. ItemServiceImpl 클래스에서 MyBatis를 xml로 호출하는 형태로 변환
**다양한 View 출력
1. 파일 다운로드
=> 파일의 경로를 a 태그의 href에 설정하면 다운로드가 만들어짐
=> 링크에 설정된 파일이 브라우저가 사용가능한 파일이면 다운로드가 되지 않고 브라우저가 사용
- 텍스트 파일이나 이미지 파일의 경우 브라우저가 출력
- 음악, 동영상 파일은 재생
- 강제 다운로드는 파일링크에서 마우스 오른 쪽을 클릭해서 다른 이름으로 저장을 하면 됨
-> 무조건 다운로드가 되게 하려면 별도의 View를 만들어서 출력을 해야 함
2. Spring ViewResolver
=> Spring Controller는 View에 의존적이지 않음
- Spring Controller는 View의 이름을 만들어주는 것이지 실제 View를 결정하지 않음
- 실제 View를 결정하는 것은 ViewResolver
1) ViewResolver의 종류
=> InternalResourceViewResolver : 기본적으로 제공되는 ViewResolver로 JSTLView로 출력
=> BeanNameViewResolver : View의 이름을 가지고 직접 출력할 View를 지정
2) jsp 이외의 View로 출력하고자 하는 경우
=> BeanNameViewResolver 클래스의 bean을 생성해야 함
=> 그리고 난 후, <bean id="출력할 뷰 이름" class="출력할 뷰 클래스 이름"/>로 설정
3) jsp도 이용할 것라면 주의
=> InternalResourceViewResolver에 order 프로퍼티를 추가해서 BeanNameViewResolver의 order값보다 높게 설정
- BeanNameViewResolver가 처리하지 못하면 InternalResourceViewResolver가 처리하도록 해주어야 함
3. 오늘 출력 ( FileDownload View, CSV, Excel, PDF, JSON, XML 출력)
=> 공공기관 같은 곳에서 OpenAPI 서버를 만드는 경우에는 모두 중요
=> OpenAPI 서버가 아니라 자신의 App이나 기업을 위한 API를 만들경우 JSON과 XML이 중요
**프로젝트 내의 img 디렉토리의 파일 다운로드 링크 만들기
1. home.jsp 파일에 파일 다운로드 링크 만들기
<ul>
<li>
<a href="fileview" class="menu">파일 목록 보기</a>
</li>
</ul>
2. home.css 파일에 스타일 추가
.menu {
display: block;
width: 10em;
margin: 3px 5px;
padding: .5em 1em;
text-decoration: none;
text-align: center;
color: #fff;
background-color: rgb(190, 190, 190);
border: 2px solid rgb(175, 175, 175);
border-radius: 6px;
text-shadow: #666 .1em .1em .1em;
box-shadow: 0 5px 3px rgba(0, 0, 0, .5);
position: relative;
-webkit-transition: background-color 0.2s, border-color 0.2s, top .2s,
box-shadow 0.2s;
-moz-transition: background-color 0.2s, border-color 0.2s, top .2s,
box-shadow 0.2s;
-o-transition: background-color 0.2s, border-color 0.2s, top .2s,
box-shadow 0.2s;
-ms-transition: background-color 0.2s, border-color 0.2s, top .2s,
box-shadow 0.2s;
transition: background-color 0.2s, border-color 0.2s, top .2s,
box-shadow 0.2s;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
margin-bottom:3em;
}
/* a 태그에 포커스가 오거나 마우스가 올라오면 적용
: 다음에 나오는 것은 가상 선택자, 가상 클래스 */
a:hover, a:focus {
background-color: #fdca00;
border-color: #fda700;
}
a:active {
top: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .5);
}
3. ItemService 인터페이스에 img 디렉토리의 파일 목록을 보여주는 메소드를 선언
//img 디렉토리의 파일이름 목록을 가져오기 위한 메소드
public void fileview(
HttpServletRequest request,
HttpServletResponse response);
4. ItemServiceImpl 클래스에 파일 목록을 보여주는 메소드를 구현
@Override
public void fileview(HttpServletRequest request, HttpServletResponse response) {
//프로젝트 내의 디렉토리에 대한 절대 경로 가져오기
String imgPath =
request.getServletContext().getRealPath("/img");
//디렉토리 안의 모든 파일에 대한 이름을 가져오기 - File 클래스 이용
File f = new File(imgPath);
String [] fileList = f.list();
//파일이름을 List에 저장하고 List를 request에 저장
List<String> list = new ArrayList<String>();
for(String imsi : fileList) {
list.add(imsi);
}
request.setAttribute("list", list);
}
5. HomeController 클래스에 클라이언트의 요청이 오면 ServiceImpl 메소드를 호출하는 메소드를 작성
=> fileview를 GET방식으로 요청하면 ItemServiceImpl 클래스의 fileview()를 호출
@Controller
public class HomeController {
@Autowired
private ItemService itemService;
@RequestMapping(value = "fileview", method = RequestMethod.GET)
public String fileview(HttpServletRequest request, HttpServletResponse response) {
itemService.fileview(request, response);
return "fileview";
}
}
6. views 디렉토리에 fileview.jsp 파일을 만들고 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- if 나 forEach를 사용하기 위한 태그 라이브러리 설정 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일 목록</title>
</head>
<body>
<div align="center" class="body">
<h2>파일 목록</h2>
<table border="1">
<c:forEach var="item" items="${list}">
<tr>
<td><a href="${pageContext.request.contextPath}/img/${item}">${item}</a></td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
7. 디렉토리에 있는 파일이 이미지 파일이라 다운로드 되지 않고 브라우저에 출력
=> 파일이 텍스트를 제외한 문서, 이미지, 사운드, 비디오 파일이 아니라면 여기까지만 구현해도 다운로드 가능
**모든 파일이 다운로드 가능하도록 수정
1. fileview.jsp 파일에서 링크를 수정
<!--download 라는 요청에 filename 이라는 파라미터로 파일 이름을 넘겨주도록 요청을 생성 -->
<td><a href="download?filename=${item}">${item}</a></td>
2. HomeController 클래스에 download 요청을 처리할 메소드를 생성
//파일 다운로드 뷰를 출력하는 요청
@RequestMapping(value="download", method=RequestMethod.GET)
public String download(HttpServletRequest request, HttpServletResponse response, Model model) {
//아래 문장이 출력되지 않으면 View에서 요청과 Controller 처리 메소드의
//RequestMapping이 맞지 않는 것입니다.
//System.out.println("Controller");
//파라미터 읽기
String filename = request.getParameter("filename");
//이 줄에서 null 이 리턴되면 ? 뒤에 이름과 위의 이름이 안맞는 것입니다.
//System.out.println("파라미터:" + filename);
//데이터를 저장
model.addAttribute("filename", filename);
return "download";
}
3. 다운로드를 처리할 View 클래스 생성 : kr.co.pk.view.DownloadView
=> Controller에서 리턴하는 데이터를 읽어서 다운로드 받을 파일의 절대경로로 설정하는 부분만 수정하여 사용
package kr.co.pk.view;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.servlet.view.AbstractView;
public class DownloadView extends AbstractView{
public DownloadView() {
//형식을 설정
setContentType("application/download; charset=utf-8");
}
//출력할 뷰를 그리는 메소드
//model은 Controller에서 전달한 데이터
//request는 클라이언트의 요청 정보를 저장
//response는 클라이언트에게 응답할 정보를 저장
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response) throws Exception{
//파일의 절대 경로 만들기
//절대경로는 운영체제에 따라 디렉토리 표현방법이 다름
//windows는 \\ 그 외 운영체제는 /
//상대경로는 무조건 /
String filename = (String) model.get("filename");
String filePath = request.getServletContext().getRealPath("/img") + "/" + filename;
File file = new File(filePath);
//파일의 형식과 크기를 설정
response.setContentType(getContentType());
response.setContentLength((int)file.length());
//브라우저 종류를 판단
//파일명에 한글이 있을 경우 인코딩 방식 때문에 판단
String userAgent = request.getHeader("User-Agent");
//ie에서 접속시 userAgent에 rv라는 문자열이 포함되어 있음
boolean ie = userAgent.indexOf("rv") > -1;
//파일이름 설정
String fileName = null;
if(ie) {
filename = URLEncoder.encode(file.getName(), "utf-8");
}else {
filename = new String(file.getName().getBytes("utf-8"), "iso-8859-1");
}
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");
//파일 다운로드 받는 로직
response.setHeader("Content-Transfer-Encoding", "binary");
OutputStream out = response.getOutputStream();
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
FileCopyUtils.copy(fis, out);
}finally {
if(fis != null) {
try {
fis.close();
}catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
out.flush();
}
}
4. servlet-context.xml 파일의 ViewResolver 수정
=> jsp가 아닌 출력이 있으면 이 설정은 추가를 해 주어야 함
- 기존 ViewResolver의 order를 1로 설정하고 BeanNameViewResolver 빈을 추가하고 order를 0으로 설정
1) 기존 Viewresolver의 order를 추가
<!-- Controller에서 forwarding 하는 View 이름을 넘겨주었을 때 실제 사용할 View를 결정하는 설정 -->
<!-- Controller가 리턴판 뷰 이름을 가지고 실제 출력할 뷰를 설정하는 뷰 리졸버 jstlview(jsp)로 출력 -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
<beans:property name="order" value="1" />
</beans:bean>
2) 새로운 ViewResolver 추가
<!-- BeanNameViewResolver 설정 -->
<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<beans:property name="order" value="0" />
</beans:bean>
3) Controller에서 download 뷰를 리턴하면 추가한 View 클래스로 출력하도록 설정을 추가
<!-- download 출력설정 -->
<beans:bean id ="download" class="kr.co.pk.view.DownloadView" />
**Excel 출력
1. excel 출력을 위한 의존성 설정 - apache poi
<!-- Excel 출력을 위한 의존성 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.16</version>
</dependency>
2. home.jsp 파일에 엑셀 출력을 위한 요청을 생성
<li><a href="item.xls" class="menu">엑셀 출력</a></li>
3. HomeController 클래스에 item.xls 요청을 처리하는 메소드를 생성하여 작성
4. Excel로 출력할 수 있는 View 클래스를 생성
=> AbstractExcelView 로 부터 상속 받는 클래스 : kr.co.pk.view.excel
package kr.co.pk.view;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.servlet.view.document.AbstractXlsView;
import kr.co.pk.item.domain.Item;
public class ExcelView extends AbstractXlsView {
//workbook은 출력할 엑셀 파일
@Override
protected void buildExcelDocument(Map<String, Object> model, Workbook workbook,
HttpServletRequest request, HttpServletResponse response) throws Exception {
//출력할 데이터 가져오기
List<Item> list = (List<Item>)model.get("list");
//시트를 생성
Sheet sheet = workbook.createSheet("ITEM");
//열 너비 설정
sheet.setColumnWidth(1, 256*20);
sheet.setColumnWidth(2, 256*40);
sheet.setColumnWidth(3, 256*20);
//제목셀 생성
//0번행 생성
Row firstRow = sheet.createRow(0);
//셀 생성
Cell cell = firstRow.createCell(0);
cell.setCellValue("상품명");
cell = firstRow.createCell(1);
cell.setCellValue("상품설명");
cell = firstRow.createCell(2);
cell.setCellValue("가격");
//데이터 출력
//행번호를 저장할 변수
int rowNum = 1;
for(Item item : list) {
//행을 생성
Row row = sheet.createRow(rowNum++);
//셀을 생성하여 출력
Cell c = row.createCell(0);
c.setCellValue(item.getItemname());
c = row.createCell(1);
c.setCellValue(item.getDescription());
c = row.createCell(2);
c.setCellValue(item.getPrice() + "원");
}
}
}
5. servlet-context.xml 파일에 Controller에서 리턴한 뷰 이름과 Excel 뷰를 연결
<!-- Excel 출력설정 -->
<beans:bean id ="excel" class="kr.co.pk.view.ExcelView" />
**PDF 출력
1. 프로젝트 안에 한글을 춝\력할 수 있는 폰트를 복사
=> webapp/font/malgun.ttf
2. pom.xml 파일에 iText API 라이브러리의 의존성을 설정
<!-- PDF 출력을 위한 의존성 -->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
3. home.jsp 파일에 pdf 요청을 위한 링크를 생성
<li><a href="item.pdf" class="menu">PDF 출력</a></li>
4. homeController 클래스에 item.pdf 요청을 처리하는 메소드를 생성
//PDF로 출력하는 요청을 처리하는 메소드
@RequestMapping(value = "item.pdf", method = RequestMethod.GET)
public String pdf(
HttpServletRequest request, HttpServletResponse response, Model model) {
//ITEM 테이블의 데이터를 전부 읽어오는 서비스를 호출
itemService.allitem(request, response);
//Model에 데이터 저장
model.addAttribute("list", request.getAttribute("list"));
//출력할 뷰를 결정
return "pdf";
}
5. PDF로 출력할 View 클래스를 생성 - AbstractPdfView 클래스로부터 상속
=> kr.co.pk.view.PdfView
package kr.co.pk.view;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.document.AbstractPdfView;
import com.lowagie.text.Cell;
import com.lowagie.text.Document;
import com.lowagie.text.Font;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Table;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfWriter;
import kr.co.pk.item.domain.Item;
public class PdfView extends AbstractPdfView {
@Override
protected void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer,
HttpServletRequest request, HttpServletResponse response) throws Exception {
//데이터 가져오기
List<Item> list = (List<Item>)model.get("list");
//테이블을 생성 - 앞의 숫자는 열의 수, 뒤의 숫자는 행의 수
Table table = new Table(3, list.size()+1);
//패딩 설정
table.setPadding(5);
//폰트 생성 - 이 작업을 하지 않으면 한글 출력이 안됨
BaseFont bfKorean = BaseFont.createFont(request.getServletContext().getRealPath("/font")
+ "/malgun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font font = new Font(bfKorean);
Cell cell = new Cell(new Paragraph("상품명", font));
cell.setHeader(true);
table.addCell(cell);
cell = new Cell(new Paragraph("상품설명", font));
cell.setHeader(true);
table.addCell(cell);
cell = new Cell(new Paragraph("가격", font));
cell.setHeader(true);
table.addCell(cell);
table.endHeaders();
//데이터 출력
for(Item item : list) {
Cell imsi = new Cell(new Paragraph(item.getItemname(), font));
table.addCell(imsi);
imsi = new Cell(new Paragraph(item.getDescription(), font));
table.addCell(imsi);
imsi = new Cell(new Paragraph(item.getPrice() + "원", font));
table.addCell(imsi);
}
//테이블을 문서에 추가
document.add(table);
}
}
6. servlet-context.xml 파일에 Controller에서 리턴한 뷰 이름과 뷰 클래스를 매핑
<!-- PDF 출력설정 -->
<beans:bean id ="pdf" class="kr.co.pk.view.PdfView" />
**JSON 출력
1. pom.xml 파일에 jackson-databind 라이브러리의 의존성을 설정
<!-- JSON 출력을 위한 라이브러리 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
2. home.jsp 파일에 json 요청을 위한 링크를 생성
<li><a href="item.json" class="menu">ITEM JSON 출력</a></li>
3. HomeController 클래스에 item.json 요청을 처리하는 메소드 생성
// JSON로 출력을 위한 메소드
@RequestMapping(value = "item.json", method = RequestMethod.GET)
public String json(HttpServletRequest request, HttpServletResponse response, Model model) {
// ITEM 테이블의 데이터를 전부 읽어오는 서비스를 호출
itemService.allitem(request, response);
// Model에 데이터 저장
model.addAttribute("list", request.getAttribute("list"));
// 출력할 뷰를 결정
return "itemlist";
}
4. itemlist와 jsonview를 연결해주는 설정을 servlet-context.xml 파일에 추가
<!-- PDF 출력설정 -->
<beans:bean id ="itemlist"
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
============================================================================
20.07.09
**CSV 형식의 문자열을 출력
1. JSON 출력을 위한 Controller 클래스를 추가
=> kr.co.pk.controller.JSONController
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import kr.co.pk.item.service.ItemService;
@RestController
public class JSONController {
@Autowired
private ItemService itemService;
//문자열을 출력하는 요청 처리
@RequestMapping(value ="dataformat.csv", method = RequestMethod.GET)
public String csv() {
String result = "dataformat:csv,mxl,json";
return result;
}
}
2. home.jsp 파일에 위의 요청을 호출하는 LINK를 추가
<li><a href="dataformat.csv" class="menu">문자열 출력</a></li>
**json 출력
1. 앞에서 만든 Controller 클래스에 요청 처리 메소드를 추가
//JSON 출력을 위한 메소드
@RequestMapping(value ="dataformat.json", method = RequestMethod.GET)
public Map<String, Object> json() {
List<String> list = new ArrayList<String>();
list.add("csv: 구분자로 구분된 텍스트");
list.add("xml: 태그로 데이터를 표현");
list.add("json: 자바 스크립트의 데이터 표현법을 이용해서 데이터를 표현");
Map<String, Object> result = new HashedMap<String, Object>();
result.put("dataformat", list);
return result;
}
2. home.jsp 파일에 위의 요청을 호출하는 LINK를 추가
<li><a href="dataformat.csv" class="menu">문자열 출력</a></li>
**ajax를 이용한 json출력
1. 앞에서 만든 Controller 클래스에 요청 처리 메소드를 추가
//ajax 출력을 위한 메소드
@RequestMapping(value ="ajax.json", method = RequestMethod.GET)
public Map<String, Object> ajaxjson() {
//테이블 형식의 데이터 구조
//Map 대신에 DTO를 사용해도 됨
List<Map> list = new ArrayList<Map>();
Map<String, Object> map = new HashedMap<String, Object>();
map.put("Encapsulation",
"캡슐화 - 불필요한 부분은 숨기고 필요한 부분만 노출하여 사용하는 것으로 정보은닉");
list.add(map);
map = new HashedMap<String, Object>();
map.put("Inheritance",
"상속: 하위클래스가 상위클래스의 모든 것을 물려받는 ㄱ서으로 재사용성이 증가하고"
+ "유지보수가 편리해짐 직접 만든 클래스의 경우는 대부분의 경우 클래스를 여러개"
+ "만들다가 동일한 부분이 있어 상위클래스를 생성 - 이런 이유때문에 다이어그램"
+ "에서는 하위클래스에서 상위클래스로 화살표가 만들어짐 - is a 관계 또는 "
+ "generalization 이라고 함");
list.add(map);
map = new HashedMap<String, Object>();
map.put("Polymorphism",
"다형성: 동일한 메시지에 대하여 반응하는 성질로 프로그래밍에서는 동일한 코드가"
+ "어떤 인스턴스가 대입되었느냐에 따라 다른 클래스의 메소드를 호출하는 것"
+ "- 인터페이스나 추상 클래스에 메소드를 선언하고 다른 클래스들이 인터페이스나"
+ "추상 클래스를 상속받아서 메소드를 재정의 하는 방식으로 작성"
+ "- Inheritance 와 Method Overriding을 이용하여 구현");
list.add(map);
Map<String, Object> result = new HashedMap<String, Object>();
result.put("oop", list);
return result;
}
2. home.jsp 파일에 위의 요청을 ajax로 처리하는 코드 작성
=> Map(List(Map)) : 객체(배열(객체))
1) ajax 요청을 위한 DOM을 생성
<li><a href="#" class="menu" id="ajaxbtn">ajax 요청</a></li>
2) 스크립트 코드를 작성
<div id="disp"></div>
<script>
document.getElementById("ajaxbtn").addEventListener("click", function(event){
//ajax 객체를 생성
var request = new XMLHttpRequest();
//요청할 URL 생성
request.open('get', 'ajax.json');
//전송
request.send('');
//데이터를 가져오면 호출될 함수를 설정
request.addEventListener('load', function(data){
//데이터 확인 - 404와 관련된 HTML 에러가 발생하면 open에 작성한 URL과
//Controller의 RequestMapping에 작성한 URL을 비교
//alert(data.target.responseText) //xml이면 responseXML
//JSONParsing - 언어에 따라 파싱하는 방법이 다름
var result = JSON.parse(data.target.responseText);
var list = result.oop;
//alert(list);
document.getElementById("disp").innerHTML +=
list[0].Encapsulation + "<br/>";
document.getElementById("disp").innerHTML +=
list[1].Inheritance + "<br/>";
document.getElementById("disp").innerHTML +=
list[2].Polymorphism + "<br/>";
})
})
</script>
**ItemServiceImpl의 Allitem 메소드의 결과를 XML로 출력
1. XML 출력을 위한 의존성을 pom.xml에 작성
<!-- XML 출력을 위한 라이브러리 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
2. home.jsp 파일에 XML요청을 생성
<li><a href="item.xml" class="menu">XML 요청</a></li>
3. DTO 클래스를 수정 - Item
@XmlAccessorType(XmlAccessType.FIELD)
//출력할 속성과 순서를 설정
@XmlType(name = "", propOrder= {"itemid", "itemname", "price",
"description", "pictureurl"})
@Data
public class Item {
//숫자 데이터의 경우 null 이 될 가능성이 있는 경우는 Wrapper 클래스 사용
private Integer itemid;
private String itemname;
private Integer price;
private String description;
private String pictureurl;
}
4. DTO 클래스의 List를 속성으로 갖는 ItemReport.java 파일 생성
@XmlAccessorType(XmlAccessType.FIELD)
//전체 태그를 설정
@XmlRootElement(name="ITEMLIST")
public class ItemReport {
//DTO 1개만 출력될 태그 설정
@XmlElement(name="ITEM")
private List<Item> list;
private List<Item> getList(){
return list;
}
public void setList(List<Item> list) {
this.list = list;
}
}
5. HomeController에 xml 요청을 처리하는 메소드를 생성
// xml 출력을 위한 메소드
@RequestMapping(value = "item.xml", method = RequestMethod.GET)
public String xml(HttpServletRequest request, HttpServletResponse response, Model model) {
// ITEM 테이블의 데이터를 전부 읽어오는 서비스를 호출
itemService.allitem(request, response);
List<Item> list = (List<Item>)request.getAttribute("list");
ItemReport itemReport = new ItemReport();
itemReport.setList(list);
//Model에 데이터 저장
model.addAttribute("list", itemReport);
// 출력할 뷰를 결정
return "itemxml";
}
6. Servlet-context.xml 파일에 Controller에서 리턴한 뷰 이름을 XML로 출력하도록 설정
<!-- XML 출력설정 -->
<beans:bean id ="marshaller"
class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<beans:property name="classesToBeBound">
<beans:list>
<beans:value>kr.co.pk.item.domain.ItemReport</beans:value>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="itemxml"
class="org.springframework.web.servlet.view.xml.MarshallingView">
<beans:property name="marshaller" ref="marshaller" />
<beans:property name="modelKey" value="list" />
</beans:bean>
**예외 발생시키기
1. home.jsp 파일에 링크 추가
<li><a href="exception" class="menu">예외처리</a></li>
2. HomeController에 exception 요청이 왔을 때 처리할 메소드를 생성
// exception요청이 get방식으로 온경우 처리하기 위한 메소드
@RequestMapping(value = "exception", method = RequestMethod.GET)
public String exception(HttpServletRequest request, HttpServletResponse response, Model model) {
// 출력할 뷰를 결정
return "exception";
}
3. exception.jsp 파일을 만들고 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>예외처리</title>
</head>
<body>
<form method="post">
나누어지는 수<input type="text" name="num1" /><br/>
나누는 수 <input type="text" name="num2" /><br/>
<input type="submit" value="전송" />
</form>
</body>
</html>
4. HomeController에 위의 페이지에서 전송을 눌렀을 때 처리할 메소드를 생성
// exception요청이 post방식으로 온경우 처리하기 위한 메소드
@RequestMapping(value = "exception", method = RequestMethod.POST)
public String exceptionprocess(HttpServletRequest request, HttpServletResponse response, Model model) {
//파라미터 읽기
String num1 = request.getParameter("num1");
String num2 = request.getParameter("num2");
//파라미터 가지고 작업
int result = Integer.parseInt(num1) / Integer.parseInt(num2);
//결과 저장
model.addAttribute("result", result);
//결과 출력 페이지 설정
return "result";
}
5. 결과를 출력할 result.jsp 파일을 만들고 내용을 출력
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>결과 출력</title>
</head>
<body>
${result}
</body>
</html>
6. 숫자가 아닌 데이터나 두번째 입력란에 0을 대입하면 예외가 발생
=> 실제 프로젝트라면 전송을 누를때 유효성 검사를 하여 예외가 발생하지 않도록 해야 함
=> 예외가 발생했을 때 WAS는 예외 메시지와 printStackTrace를 출력하는데 유저는 이 메시지를 볼 필요가 없음
- 개발자는 이 메시지를 보고 예외를 수정, 사용자에게는 다른 형태의 예외 메시지 출력
**에러페이지 출력 설정
1. views 디렉토리에 error라는 디렉토리를 생성하고, exception.jsp 파일 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- exception 객체를 사용할 수 있는 페이지 -->
<%@ page isErrorPage = "true" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>예외 페이지</title>
</head>
<body>
ㅅㅂㅇ ㅈㅇㅄ<br/>
빠른 시일 내로 고칠게요<br/>
예외내용:${result }
</body>
</html>
2. HomeController 클래스에 예외가 발생하면 error/exception.jsp 파일을 출력하도록 하는 설정을 추가
//예외가 발생하면 처리하는 메소드
@ExceptionHandler(Exception.class)
public String handleException(Exception e, Model model) {
model.addAttribute("result", e.getMessage());
return "error/exception";
}
=> 별도의 클래스를 만들어서 클래스 이름 상단에 @ControllerAdvice("패키지명") 추가후 메소드를 만들면 패키지에서 발생한 예외를 처리
**Spring MVC View 설정
=> 단순한 페이지 이동은 Controller에 처리하는 메소드를 만들지 않고 servlet-context.xml 파일에 아래 태그를 추가
<view-controller path="요청경로" view-name="뷰이름" />
=> Controller URL패턴을 '/*', '/' 설정시 상대경로인 모든요청을 Controller가 처리, 처리하지 못하면 404에러 발생
- 위의 경우 404에러를 방지하려면 servlet-context.xml 파일에 <default-servlet-handler/>를 추가해야 함
- 해당 설정 추가시 Controller가 처리하지 못하는 요청은 WAS가 처리해달라고 요청
**Spring 메시지 출력
=> Spring에서 properties 파일의 내용을 출력하고자 할 때는 아래 설정을 추가
<bean class="org.springframework.context.support.ResourceBundleMessageSource"
id="messageSource">
<property name="basenames">
<list>
<value>메시지 파일 경로</value>
...
</list>
</property>
</bean>
=> 지역화(브라우저 언어 설정에 따라 다른 문자열 출력) 설정
- 메시지 파일이름_언어코드.properties로 만들면 됨
=> 프로퍼티 파일을 작성할 때는 key = value 형식으로 설정
=> value는 방드시 인코딩이 되어야 함
- IDE의 Workspace 설정에서 text file encoding을 UTF-8로 설정했으면 자동으로 인코딩 됨
=> jsp 파일에서 메시지 출력
<%@ taglib prefix="spring" uri= http://www.springframework.org/tags" %>를 추가하고
<spring:message code="key" var="변수명" />
=> key값을 출력하고 변수에 저장 - var는 생략 가능
**메시지 출력과 지역화
1. home.jsp 파일에 링크를 추가
<li><a href="validation" class="menu">유효성 검사</a></li>
2. 메시지를 저장할 파일을 src/main/resources 디렉토리에 message 디렉토리를 만들고 label.properties로 생성
email=email
password=password
loginform.help=email/password root/1234
loginform.title=Login Form
3. 프로퍼티 파일을 사용하기 위한 설정을 servlet-context.xml 파일에 추가
<!-- 메시지 파일의 경로 설정 -->
<beans:bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basenames">
<beans:list>
<beans:value>message/label</beans:value>
</beans:list>
</beans:property>
</beans:bean>
4. HomeController에 validation 요청이 get방식으로 오면 처리하는 메소드 생성
@RequestMapping(value = "validation", method = RequestMethod.GET)
public String validation() {
//결과 출력 페이지 설정
return "validation";
}
=> 위 메소드 대신에 servlet-context.xml 파일에 아래 설정을 추가해도 됨
<!-- validation 요청이 오면 view name을 validation로 설정 -->
<view-controller path="validation" view-name="validation"/>
5. 메시지를 출력할 validation.jsp 파일을 view 디렉토리에 생성하고 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- spring 태그를 사용하기 위한 설정 -->
<%@ taglib prefix="spring"
uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><spring:message code="loginform.title" /></title>
</head>
<body>
<form method="post">
<spring:message code="email" />
<input type="email" name="email" id="email"/><br/>
<spring:message code="password" />
<input type="password" name="password" id="password"/><br/>
<p><spring:message code="loginform.help"/></p>
<input type="submit" value="로그인"/>
</form>
</body>
</html>
6. 기존에 만든 프로퍼티 파일의 이름을 label_en.properties로 변경
7. label_ko.properties 파일을 만들고 동일한 이름의 key에 value를 변경
email=\uC774\uBA54\uC77C
password=\uD328\uC2A4\uC6CC\uB4DC
loginform.help=email/password root/1234
loginform.title=\uB85C\uADF8\uC778 \uD3FC
**Spring Form 관련 Custom Tag
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
=> 유효성 검사를 서버에서 한경우 이전 입력 값을 출력하는 부분이나 메시지 출력이 쉬워짐
1. <form:form>
=> action을 설정하지 않으면 이 페이지에 오게 만든 요청
=> method를 생략하면 post
=> id는 입력 폼의 값을 저장하는 Command 객체의 이름이 할당
2. <form:input> : input 객체 생성
3. <form:password> : password 객체 생성
4. <form:hidden> : hidden 객체 생성
=> path 속성에 DTO의 프로퍼티 명을 기재시 name과 id를 프로퍼티 명으로 설정
=> 데이터가 넘어왔다면 그 데이터를 value에 설정
<form:form commandName="member">
<form:input path="email" />
</form:form>
위처럼 작성시 아래처럼 변경됨
<form method="post">
<input type="text" name="email" id="email" value="${member.email}" />
</form>
5. <form:select>
=> item 속성에 List 타입의 속성을 대입하면 자동으로 option을 생성
6. <checkboxes>, <form:radiobuttons>
=> item 속성에 List 타입의 속성을 대입하면 자동으로 생성
7. <form:textarea>
=> path만 설정
8. <form:errors path="프로퍼티 이름">
=> 프로퍼티 명으로 만들어진 에러메시지를 출력
**Spring Form 관련 태그 사용 실습
1. email, password, logintype을 String으로 갖는 DTO 클래스 작성
package kr.co.pk.item.domain;
public class Member {
private String email;
private String password;
private String loginType;
public Member(String email, String password, String loginType) {
super();
this.email = email;
this.password = password;
this.loginType = loginType;
}
public Member() {
super();
// TODO Auto-generated constructor stub
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
@Override
public String toString() {
return "Member [email=" + email + ", password=" + password + ", loginType=" + loginType + "]";
}
}
2. HomeController에 loginType에 관련된 데이터를 만들어주는 메소드를 생성
@ModelAttribute("loginTypes")
public List<String> loginTypes(){
List<String> list = new ArrayList<String>();
list.add("개인회원");
list.add("기업회원");
list.add("비회원");
return list;
}
3. validation 요청을 처리하는 메소드를 수정
@RequestMapping(value = "validation", method = RequestMethod.GET)
public String validation(@ModelAttribute("member") Member member) {
//결과 출력 페이지 설정
return "validation";
}
4. validateion.jsp 파일을 수정
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- spring 태그를 사용하기 위한 설정 -->
<%@ taglib prefix="spring"
uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form"
uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><spring:message code="loginform.title" /></title>
</head>
<body>
<form:form modelAttribute="member">
<spring:message code="email" />
<form:input path="email"/><br/>
<spring:message code="password" />
<form:password path="password"/><br/>
<form:select path="loginType" items="${loginTypes}"/>
<p><spring:message code="loginform.help"/></p>
<input type="submit" value="로그인"/>
</form:form>
</body>
</html>
============================================================================
20.07.10
** 파일 업로드 실습
1. pom.xml 파일에 파일 업로드 라이브러리 의존성 작성
<!-- 파일 업로드 라이브러리 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
2. home.jsp 파일에 링크 추가
<li><a href="fileupload" class="menu">파일 업로드</a></li>
3.HomeController 클래스에 fileupload 요청이 GET방시긍로 전송되었을 때 처리하는 메소드를 작성
@RequestMapping(value = "fileupload", method = RequestMethod.GET)
public String fileupload() {
//결과 출력 페이지 설정
return "fileupload";
}
4. fileupload.jsp 파일을 views 디렉토리에 생성하고 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일 업로드</title>
</head>
<body>
<form action="requestupload" method="post" encrype="multipart/form-data">
이름<input type="text" name="number" /><br />
파일<input type="file" name="report" /><br />
<input type="submit" value="제출" />
</form>
<form action="requestparamupload" method="post" encrype="multipart/form-data">
이름<input type="text" name="number" /><br />
파일<input type="file" name="report" /><br />
<input type="submit" value="제출" />
</form>
<form action="commandupload" method="post" encrype="multipart/form-data">
이름<input type="text" name="number" /><br />
파일<input type="file" name="report" /><br />
<input type="submit" value="제출" />
</form>
</body>
</html>
5. web.xml 파일에 파라미터 인코딩 필터 설정을 확인하고 없으면 추가
<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>
6. Servlet-context.xml 파일에 MultipartResolver 클래스의 bean을 작성
<beans:bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</beans:bean>
7. HomeController 클래스에 첫번째 폼의 전송요청을 처리하는 메소드를 작성
@RequestMapping(value = "requestupload", method = RequestMethod.GET)
public String upload(MultipartHttpServletRequest request) {
//파라미터 읽어오기
String number = request.getParameter("number");
MultipartFile report = request.getFile("report");
//출력
System.out.println("number : " + number);
System.out.println("filename : " + report.getOriginalFilename());
return "fileupload";
}
9. Command 객체 이용
1) 파라미터를 저장할
package kr.co.pk.item.domain;
import org.springframework.web.multipart.MultipartFile;
public class Command {
private String number;
private MultipartFile Report;
public Command(String number, MultipartFile report) {
super();
this.number = number;
Report = report;
}
public Command() {
super();
// TODO Auto-generated constructor stub
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public MultipartFile getReport() {
return Report;
}
public void setReport(MultipartFile report) {
Report = report;
}
@Override
public String toString() {
return "Command [number=" + number + ", Report=" + Report + "]";
}
}
2) HomeController 클래스에 세번째 폼 처리 메소드를 생성
@RequestMapping(value = "commandupload", method = RequestMethod.POST)
public String upload(Command command) {
//출력
System.out.println("number : " + command.getNumber());
System.out.println("filename : " + command.getReport().getOriginalFilename());
return "redirect:/";
}
'수업 정리' 카테고리의 다른 글
66일차 수업정리(RestController, ajax) (0) | 2020.07.09 |
---|---|
63~65일차 수업 정리(Spring MVC Project 외 정리) (0) | 2020.07.08 |
63일차 수업 정리(Spring - MVC패턴) (0) | 2020.07.06 |
62일차 수업 정리(Spring - Transaction, Hibernate, MyBatis) (0) | 2020.07.03 |
61일차 수업정리(Spring - MyBatis) (0) | 2020.07.02 |