이것저것 붙이다가 다 때려치우고 그냥 처음부터 간단히 Emp DB 연결한거 정리.
기본의 기본의 기본부터 해본다.
목표는 "/empSearch.do" 로 호출하면 화면에 데이터가 조회되는 것!
HSQLDB를 임베디드 모드(메모리모드)로 실행할 것이고, MyBatis 사용.
1. 연결할 sql 파일 넣기
resources > db > 에 연결하려는 sql 파일 넣기
내용은 아래와 같다. 간단히 EMP 테이블과 DEPT 테이블을 넣자.
SET SCHEMA PUBLIC
SET DATABASE SQL SYNTAX ORA TRUE
--테이블 생성
CREATE MEMORY TABLE PUBLIC.EMP(EMPNO VARCHAR(4) NOT NULL PRIMARY KEY,ENAME VARCHAR(30),JOB VARCHAR(9),JOBSTATUS VARCHAR(9),MGR VARCHAR(4),HIREDATE VARCHAR(8),SAL DOUBLE,COMM DOUBLE,DEPTNO VARCHAR(2), LV INTEGER, ORDERNUM INTEGER)
CREATE MEMORY TABLE PUBLIC.DEPT(DEPTNO VARCHAR(2) NOT NULL PRIMARY KEY,DNAME VARCHAR(14),LOC VARCHAR(13))
SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC
--데이터 삽입
INSERT INTO EMP VALUES('3092','JOHN','CLERK','OD','7782','20160601',4300.0E0,100.0E0,'10', 3, 14)
INSERT INTO EMP VALUES('7499','ALLEN','SALESMAN','OD','7698','20130619',1600.0E0,300.0E0,'30', 3, 11)
INSERT INTO EMP VALUES('7521','WARD','SALESMAN','LV','7698','19810222',1250.0E0,500.0E0,'30', 3, 7)
INSERT INTO EMP VALUES('7566','JONES','MANAGER','OD','7839','19810402',2975.0E0,0.0E0,'20', 2, 2)
INSERT INTO EMP VALUES('7654','MARTIN','SALESMAN','OD','7698','19810928',1250.0E0,1400.0E0,'10', 3, 9)
INSERT INTO EMP VALUES('7698','BLAKE','MANAGER','LV','7839','19810501',2850.0E0,0.0E0,'30', 2, 6)
INSERT INTO EMP VALUES('7782','CLARK','MANAGER','OD','7839','19810609',2450.0E0,0.0E0,'10', 2, 12)
INSERT INTO EMP VALUES('7788','SCOTT','ANALYST','OD','7566','19870713',99999.0E0,0.0E0,'10', 3, 4)
INSERT INTO EMP VALUES('7839','KING','PRESIDENT','OD','','19811117',5000.0E0,0.0E0,'10', 1, 1)
INSERT INTO EMP VALUES('7844','TURNER','SALESMAN','OD','7698','19810908',1500.0E0,0.0E0,'30', 3, 8)
INSERT INTO EMP VALUES('7876','ADAMS','CLERK','RS','7788','19870713',1100.0E0,0.0E0,'20', 4, 5)
INSERT INTO EMP VALUES('7900','JAMES','CLERK','SB','7698','19811203',950.0E0,0.0E0,'30', 3, 10)
INSERT INTO EMP VALUES('7902','FORD','ANALYST','SB','7566','19811203',3000.0E0,100.0E0,'20', 3, 3)
INSERT INTO EMP VALUES('7934','MILLER','CLERK','LV','7782','19820123',1300.0E0,200.0E0,'10', 3, 13)
INSERT INTO DEPT VALUES('10','ACCOUNTING','NEWYORK')
INSERT INTO DEPT VALUES('20','RESEARCH','DALLAS')
INSERT INTO DEPT VALUES('30','SALES','CHICAGO')
INSERT INTO DEPT VALUES('40','OPERATIONS','BOSTON')
INSERT INTO DEPT VALUES('50','R&D','NEWYORK')
INSERT INTO DEPT VALUES('60','TECH SUPPORT','DALLAS')
INSERT INTO DEPT VALUES('70','MARKETING','CHICAGO')
INSERT INTO DEPT VALUES('80','DESIGN','BOSTON')
INSERT INTO DEPT VALUES('90','FACTORY1','NEWYORK')
INSERT INTO DEPT VALUES('91','FACTORY2','CHICAGO')
2. MyBatis 매퍼 파일 작성
EMP 테이블 전체 데이터를 조회하는 MyBatis 매퍼(xml) 파일을 만드는 작업.
resources > egovframework > mapper > let > ibsheetTemplate 경로에 empMapper.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="egovframework.mapper.let.ibsheetTemplate.empMapper">
<!-- EMP 전체 조회 -->
<select id="selectEmpList" resultType="egovMap">
<![CDATA[
SELECT * FROM EMP
]]>
</select>
</mapper>
데이터는 간단하게 전체를 조회해본다.
- namespace는 이 매퍼 파일을 참조할 때 사용할 이름이다.
- selectEmpList는 DAO에서 호출할 메서드명이다.
- resultType="egovMap"은 eGovFrame에서 자주 사용하는 결과 타입으로, key-value로 데이터를 받을 수 있다.
- <![CDATA[ ]]> 안에 SQL을 넣는 이유는, XML 특수 문자와 충돌하지 않게 하기 위함이다.
egovMap은 어디에 설정되어있냐면,
<!-- Type Aliases 설정-->
<typeAliases>
<typeAlias alias="egovMap" type="org.egovframe.rte.psl.dataaccess.util.EgovMap" />
<typeAlias alias="FileVO" type="egovframework.com.cmm.service.FileVO" />
<typeAlias alias="ComDefaultCodeVO" type="egovframework.com.cmm.ComDefaultCodeVO" />
<typeAlias alias="comDefaultVO" type="egovframework.com.cmm.ComDefaultVO" />
</typeAliases>
mapper-config.xml 파일에 Type Aliases 설정이 기본적으로 되어있다.
3. Service 인터페이스와 VO 생성
Service 인터페이스와 VO 객체를 만드는 작업.
java > egovframework > let > ibsheetTemplate > service 경로에 EmpService.java 파일 생성
java > egovframework > let > ibsheetTemplate > service 경로에 EmpVO.java 파일 생성
package egovframework.let.ibsheetTemplate.service;
import java.util.List;
import java.util.Map;
public interface EmpService {
List<Map<String, Object>> selectEmpList() throws Exception;
}
package egovframework.let.ibsheetTemplate.service;
import java.io.Serializable;
public class EmpVO implements Serializable {
private static final long serialVersionUID = 1L;
private String empno;
private String ename;
private String job;
private String jobstatus;
private String mgr;
private String hiredate;
private Double sal;
private Double comm;
private String deptno;
private Integer lv;
private Integer ordernum;
// getter/setter
public String getEmpno() { return empno; }
public void setEmpno(String empno) { this.empno = empno; }
public String getEname() { return ename; }
public void setEname(String ename) { this.ename = ename; }
public String getJob() { return job; }
public void setJob(String job) { this.job = job; }
public String getJobstatus() { return jobstatus; }
public void setJobstatus(String jobstatus) { this.jobstatus = jobstatus; }
public String getMgr() { return mgr; }
public void setMgr(String mgr) { this.mgr = mgr; }
public String getHiredate() { return hiredate; }
public void setHiredate(String hiredate) { this.hiredate = hiredate; }
public Double getSal() { return sal; }
public void setSal(Double sal) { this.sal = sal; }
public Double getComm() { return comm; }
public void setComm(Double comm) { this.comm = comm; }
public String getDeptno() { return deptno; }
public void setDeptno(String deptno) { this.deptno = deptno; }
public Integer getLv() { return lv; }
public void setLv(Integer lv) { this.lv = lv; }
public Integer getOrdernum() { return ordernum; }
public void setOrdernum(Integer ordernum) { this.ordernum = ordernum; }
}
- EmpService는 컨트롤러와 DAO를 연결해주는 중간 역할이다.
- EmpVO는 EMP 테이블의 데이터를 객체로 담는 용도이지만, 여기서는 egovMap을 사용해도 되기 때문에 선택 사항이다. (추후 확장성을 위해 만들어둠)
4. DAO 인터페이스 생성
DAO 인터페이스를 만드는 작업.
java > egovframework > let > ibsheetTemplate > service > impl경로에 EmpDAO.java 파일 생성
package egovframework.let.ibsheetTemplate.service.impl;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;
import org.egovframe.rte.psl.dataaccess.EgovAbstractMapper;
@Repository("empDAO")
public class EmpDAO extends EgovAbstractMapper {
public List<Map<String, Object>> selectEmpList() {
return selectList("egovframework.mapper.let.ibsheetTemplate.empMapper.selectEmpList");
}
}
- EgovAbstractMapper는 MyBatis의 SqlSession을 상속해서 selectList, selectOne 등을 바로 사용할 수 있도록 도와준다.
- EgovAbstractMapper는 egovframework.rte.psl.dataaccess 모듈에 포함되어 있으므로, Maven 또는 Gradle에 아래 의존성을 추가해야함.
- egov 4점대부터는 egovframework -> org.egovframe 이렇게 바뀌었으니 잘 보기!
<dependency>
<groupId>org.egovframe.rte</groupId>
<artifactId>org.egovframe.rte.psl.dataaccess</artifactId>
<version>4.2.0</version> <!-- 사용 중인 버전 확인 후 적절히 설정 -->
</dependency>
- selectList("네임스페이스.아이디") 형식으로 매퍼의 SQL을 호출한다.
- empMapper.xml에서 namespace="egovframework.mapper.let.ibsheetTemplate.empMapper"로 지정했기 때문에 해당 네임스페이스를 그대로 사용한다.
5. Service 구현 클래스 생성
DAO를 실제로 호출할 Service 구현체를 만드는 작업.
java > egovframework > let > ibsheetTemplate > service > impl경로에 EmpServiceImpl.java 파일 생성
package egovframework.let.ibsheetTemplate.service.impl;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import egovframework.let.ibsheetTemplate.service.EmpService;
@Service("empService")
public class EmpServiceImpl implements EmpService {
@Resource(name = "empDAO")
private EmpDAO empDAO;
@Override
public List<Map<String, Object>> selectEmpList() throws Exception {
return empDAO.selectEmpList();
}
}
- @Service("empService")는 Spring이 이 클래스를 서비스 계층으로 인식하게 해준다.
- @Resource(name = "empDAO")로 DAO를 주입받는다.
- Service 인터페이스에 정의한 selectEmpList를 구현하고, 내부적으로 DAO의 같은 이름 메서드를 호출한다.
6. Controller 클래스 생성
Controller 클래스를 만들어서,
empSearch.do라는 URL로 요청이 들어오면 EMP 테이블의 모든 데이터를 조회해서 반환하는 기능을 구현.
java > egovframework > let > ibsheetTemplate > web 경로에 EmpController.java 파일 생성
package egovframework.let.ibsheetTemplate.web;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import egovframework.let.ibsheetTemplate.service.EmpService;
@Controller
public class EmpController {
@Resource(name = "empService")
private EmpService empService;
@RequestMapping(value = "/empSearch.do")
@ResponseBody
public List<Map<String, Object>> selectEmpList(ModelMap model) throws Exception {
return empService.selectEmpList();
}
}
7. 설정파일 설정
몇가지 추가설정을 해줘야 한다.
1) context-datasource.xml
DB 연결 설정 (DataSource), MyBatis Mapper 파일 위치 지정, SQL 스크립트 초기 실행
<jdbc:embedded-database> 부분에 아래 내용 추가.
HSQLDB 같은 내장 DB를 사용할 경우 초기화 SQL을 실행하는 부분이다.
<!-- hsql -->
<jdbc:embedded-database id="dataSource-hsql" type="HSQL">
<jdbc:script location= "classpath:/db/shtdb.sql"/>
<jdbc:script location="classpath:/db/ibsheetTpdb.sql"/> <!-- 추가된 SQL 파일 -->
</jdbc:embedded-database>
이 설정은 HSQLDB가 초기 실행 시 ibsheetTpdb.sql 파일을 읽어서 EMP 테이블 등 필요한 테이블을 생성한다.
메모리 모드일 경우 매번 새로 실행되므로 필수!
2) context-mapper.xml
MyBatis 관련 설정, Mapper XML 파일 등록, SQL 실행 환경 구성
<property name="mapperLocations"> 아래 mapper 경로 추가.
<!-- Mybatis setup for Mybatis Database Layer -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:/egovframework/mapper/config/mapper-config.xml" />
<property name="mapperLocations">
<list>
<value>classpath:/egovframework/mapper/let/**/*_${Globals.DbType}.xml</value>
<value>classpath:/egovframework/mapper/let/ibsheetTemplate/*.xml</value> <!-- xml 파일 경로 추가 -->
</list>
</property>
</bean>
직접 XML 파일 경로를 명시해서 매퍼 파일을 등록한다.
3) egov-com-servlet.xml
Spring MVC 설정, 뷰(View) 관련 설정, 컨트롤러 컴포넌트 스캔 등
Spring MVC에서 JSON 데이터를 반환할 수 있도록 구성한다.
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ArrayList] with preset Content-Type 'null']
현재 이런 오류가 나는데,
컨트롤러에서 List<Map<String, Object>> 형태의 데이터를 반환하고 있으며,
@ResponseBody와 produces = "application/json" 도 사용하고 있으므로, 정상적으로 JSON 형태로 응답이 나가야 함.
이 에러는 Spring MVC에서 JSON 변환에 필요한 HttpMessageConverter를 찾을 수 없어서 발생하는 문제이다.
즉, ArrayList<Map<String, Object>>를 JSON으로 변환할 수 있는 변환기가 누락되어 있다는 뜻.
pom.xml 에서 jackson-databind 이 있는지 확인하거나,
spring 설정파일인 dispacher-servlet.xml(여기서는 egov-com-servlet.xml) 에서 mvc:annotation-driven 태그가 있는지 확인.
GPT에게 물어보니 아래와 같이 대답했다.
당신의 dispatcher-servlet.xml에 다음 두 가지 설정이 동시에 존재합니다:
![]() Jackson 변환기를 수동 설정에 추가하거나, 아래처럼 주석처리하는 방법이 있다. ![]() |
난 메시지 컨버터를 추가해줬다.
<!-- 화면처리용 JSP 파일명의 prefix, suffix 처리에 대한 mvc 설정 -->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" p:order="1"
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="egovframework.com.cmm.web.EgovBindingInitializer"/>
</property>
<property name="messageConverters">
<list>
<!-- JSON 변환을 위한 메시지 컨버터 추가 -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>
</property>
</bean>
+++ ModelAndView를 쓰는 경우 아래처럼 사용
<!-- json 관련 설정 @@@ -->
<!-- View 이름이 Bean 이름과 같을 때 그 Bean을 뷰로 사용함 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="0">
</bean>
<!-- 실제 JSON 출력을 담당하는 View 객체 -->
<bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" p:contentType="application/json;charset=UTF-8">
</bean>
<!-- json 관련 설정 끝-->
viewResolver : 컨트롤러에서 반환하는 뷰 이름을 실제 JSP 경로로 매핑
jsonView : @ResponseBody 없이도 JSON 응답을 보낼 수 있게 하는 뷰 설정
위 Controller랑은 관련이 없긴한데.... 아래와 같이 ModelAndView를 쓰는 경우에는 아래처럼 jsonView를 지정해야한다.
아래는 예시!
@RequestMapping("/empList.do")
public ModelAndView selectEmpList(@RequestParam Map<String, String> paramMap) throws Exception {
List<?> empList = empService.selectEmpList(paramMap);
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("empList", empList);
return mav;
}
- 컨트롤러에서 ModelAndView("jsonView")를 리턴하면,
- Spring은 "jsonView"라는 이름의 Bean을 찾고,
- 그 Bean은 MappingJackson2JsonView니까,
- 내부적으로 Java 객체를 JSON으로 변환해서 응답함.
- 따라서 클라이언트(브라우저 등)에는 JSON이 출력.
4) pom.xml
jsonView를 쓰려면 jackson 라이브러리가 필수임
<!-- jsonView 관련 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-core-asl -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
8. 결과
데이터가 화면에 잘 출력된다.
네트워크 탭에서도 보면 200으로 잘 가져오고, json 형태로 이쁘게 가져옴.
'[ 전자정부프레임워크 ]' 카테고리의 다른 글
배포용 homepage 만들기(2) - 조회/저장하기 (1) | 2025.04.16 |
---|---|
배포용 homepage 만들기(1) - egovFramework resources 구조 확인하기 (0) | 2025.04.04 |
eGov 호환성 인증 및 고객 샘플 제작 프로젝트 후기 (1) | 2024.09.11 |
전자정부프레임워크 spring boot로 환경 세팅하기 (0) | 2024.07.04 |
전자정부프레임워크 3.10에서 4.2로 마이그레이션 (0) | 2024.07.04 |