원본 본문으로 이동하기

SAP RFC JCO (java - sapjco3.jar)를 이용한 접근방법

박용서 - 우선 SAP 연계정보 제공사를 통해 sapjco3.jar 파일과 리눅스 .so 윈도우 .dll 을 다운받습니다. 라이브러리 파일 (.so, .dll)을 시스템 폴더에 넣습니다. 연동 예제 public static void main(String[] args) throws Exception { // SAP 연결 SapManager sap = SapManager.newSapManagerBinder() .set(DestinationDataProvider.JCO_ASHOST, "호스트") // AS 호스트 : 경우에 따라 MS 호스트[JCO_MSHOST] 등도 사용함. .set(DestinationDataProvider.JCO_MSSERV, "9999") // MS 포트 [AS, MS는 MS, GW는 JCO_GWSERV] .set(DestinationDataProvider.JCO_SYSNR, "01") // 시스템 번호 .set(DestinationDataProvider.JCO_GROUP, "Group Name") // 그룹 .set(DestinationDataProvider.JCO_LANG, "KO") // 언어 .set(DestinationDataProvider.JCO_CLIENT, "100") // 클라이언트 번호 .set(DestinationDataProvider.JCO_USER, "user") // 계정 .set(DestinationDataProvider.JCO_PASSWD, "password") // 암호 .bind(); // 접속 후 RFC 연결 SapRfcFunction rfc = sap.getRfcFunction("RFC 함수 이름"); // IMPORT rfc.imports().setValue("AAA", "A"); // AAA rfc.imports().setValue("BBB", "B"); // BBB rfc.imports().setValue("CCC", "C"); // CCC // 실행 rfc.execute(); // EXPORT System.out.println(rfc.exports().getValue("DDD")); System.out.println(rfc.exports().getValue("EEE")); System.out.println(rfc.exports().getValue("FFF")); // 테이블 조회 List<ZSPADEPT_NEW> table1 = rfc.getTable("TABLE_NAME", 클래스매핑.class); table1.stream().limit(10).forEach(System.out::println); // 10개만 조회 } 라이브러리 파일 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import com.sap.conn.jco.JCoDestination; import com.sap.conn.jco.JCoDestinationManager; import com.sap.conn.jco.JCoException; import com.sap.conn.jco.JCoFieldIterator; import com.sap.conn.jco.JCoFunction; import com.sap.conn.jco.JCoParameterList; import com.sap.conn.jco.JCoTable; /** * SAP RFC 유틸<br> * class로 테이블을 받을경우 언더스코어 -> 카멜로 변경함. * ABC_DDD -> abcDdd * @author 박용서 * @since 2018. 2. 20. */ public class SapManager { final static String CONN_FILE_NAME = "SAP"; // newSapManagerBinder 통해 부르세요. SapManager() { } /** 연결을 시도합니다. * @throws JCoException */ public SapRfcFunction getRfcFunction(String rfcFunctionName) throws JCoException { return new SapRfcFunction(CONN_FILE_NAME, rfcFunctionName); } /** * 함수를 선언합니다. * @author 박용서 * @since 2018. 2. 20. */ public static class SapRfcFunction { final JCoFunction function; final JCoDestination destination; final String functionName; JCoParameterList tables; JCoParameterList imports; JCoParameterList exports; long startTime = 0L; // 생성 private SapRfcFunction(String connectionFileName, String rfcFunctionName) throws JCoException { this.functionName = rfcFunctionName; destination = JCoDestinationManager.getDestination(connectionFileName); function = destination.getRepository().getFunction(rfcFunctionName); } /** * import 값을 입력합니다.<br> * execute() 이전에 불려야 합니다. * @return JCoParameterList */ public JCoParameterList imports() { if (imports == null) { imports = function.getImportParameterList(); } return imports; } /** * export 값을 출력합니다.<br> * execute() 이후 불려야합니다. * @return JCoParameterList */ public JCoParameterList exports() { if (exports == null) { exports = function.getExportParameterList(); } return exports; } /** * 실행 * @throws JCoException */ public String execute() throws JCoException { // 로그 부분은 임시로 이렇게 해둠.. 적당히 log4j나 logback등으로 찍도로 만들어쓰세요. startTime = System.currentTimeMillis(); final StringBuilder logs = new StringBuilder(1024).append("SAP RFC FUNCTION : ").append(functionName); // IMPORT logs.append("\n# IMPORT\n - "); imports().forEach(e -> logs.append(e.getName()).append(':').append(e.getValue().toString()).append(", ")); // 실행 function.execute(destination); // EXPORT logs.append("\n\n# EXPORT\n - "); exports().forEach(e -> logs.append(e.getName()).append(':').append(e.getValue().toString()).append(", ")); logs.append("\n\n"); // 테이블 목록 logs.append("\n\n# nTABLE [").append(getTableCount()).append("]"); tables.forEach(table -> logs.append("\n - ").append(table.getName()).append(" : ").append(table.getTable().getNumRows())); // 최종시간 logs.append("\n\nSAP RFC FUNCTION -- END TIME ").append(System.currentTimeMillis() - startTime); return logs.toString(); } /** * 테이블 갯수를 가져옵니다.<br> * execute() 이후에 불려야합니다. * @return */ public int getTableCount() { if (tables == null) { tables = function.getTableParameterList(); } return tables.getFieldCount(); } /** * 테이블을 가져옵니다.<br> * execute() 이후에 불려야합니다. * @param index * @return * @throws Exception */ public <T> List<T> getTable(int index, final Class<T> T) throws Exception { return getTable(index, null, T); } /** * 테이블을 가져옵니다.<br> * execute() 이후에 불려야합니다. * @param name * @param T * @return * @throws Exception */ public <T> List<T> getTable(String name, final Class<T> T) throws Exception { return getTable(0, name, T); } public <T> List<T> getTable(int tableIndex, String tableName, final Class<T> T) throws Exception { final SimpleDateFormat ymdhms = new SimpleDateFormat("yyyyMMddHHmmss"); return getTable(tableIndex, tableName, cols -> { Field[] cdo = new Field[cols.length]; for (int i = 0 ; i < cols.length ; i++) { try { Field field = T.getDeclaredField(underscoreToCamel(cols[i])); field.setAccessible(true); cdo[i] = field; } catch (NoSuchFieldException e) { // 필드가 없는것은 무시한다. } } return cdo; }, (fields, keys, values) -> { T t = T.newInstance(); for (int i = 0 ; i < fields.length ; i++) { Field field = fields[i]; if (field != null) { Object val = values[i]; if (val != null) { switch (val.getClass().getName()) { case "java.util.Date" : field.set(t, ymdhms.format((Date)val)); break; default : field.set(t, val.toString()); } } } } return t; }); } /** * 테이블을 가져옵니다.<br> * execute() 이후에 불려야합니다. * @param tableIndex tableName가 null 인경우 해당 인덱스의 테이블을 가져옵니다. * @param tableName 테이블을 이름으로 가져옵니다. (우선순위) * @param columnDefiner * @param rowMapper * @return * @throws Exception */ public <CDO, RC> List<RC> getTable(int tableIndex, String tableName, ColumnDefiner<CDO> columnDefiner, RowMapper<CDO, RC> rowMapper) throws Exception { // 체크 if (getTableCount() <= tableIndex) { throw new IllegalArgumentException("out of table index [" + tableIndex + "/" + getTableCount() + "]"); } // 선언 List<RC> list = new ArrayList<>(); JCoTable table = tableName != null ? tables.getTable(tableName) : tables.getTable(tableIndex); // 로우가 있는지 확인 if (table != null && table.isFirstRow()) { // 필드를 구합니다. List<String> columnList = new ArrayList<>(); JCoFieldIterator columnIterator = table.getFieldIterator(); while (columnIterator.hasNextField()) { columnList.add(columnIterator.nextField().getName()); } String[] columns = columnList.toArray(new String[columnList.size()]); int columnLength = columns.length; // 컬럼 디파이너를 부릅니다. Column Definer Object CDO cdo; if (columnDefiner != null) { cdo = columnDefiner.call(columns); } else { cdo = null; } do { int valueIndex = 0; Object[] values = new Object[columnLength]; JCoFieldIterator valueIterator = table.getFieldIterator(); while (valueIterator.hasNextField()) { values[valueIndex++] = valueIterator.nextField().getValue(); } list.add(rowMapper.call(cdo, columns, values)); } while (table.nextRow()); } return list; } // 언더스코어를 카멜로 바꿉니다. private String underscoreToCamel(String val) { char[] c = val.toLowerCase().toCharArray(); char[] d = new char[c.length]; int p = 0; for (int i = 0 ; i < c.length ; i++) { if (c[i] == '_') { c[i+1] = Character.toUpperCase(c[i+1]); continue; } d[p++] = c[i]; } return new String(d, 0, p); } /** * 테이블을 가져옵니다.<br> * execute() 이후에 불려야합니다. * @param index * @return * @throws Exception */ public List<Map<String, Object>> getTableMap(int index) throws Exception { return getTable(index, null, null, (cdo, keys, values) -> { Map<String, Object> map = new LinkedHashMap<>(); for (int i = 0 ; i < keys.length ; i++) { map.put(keys[i], values[i]); } return map; }); } /** * 모든 테이블을 맵으로 가져옵니다.<br> * execute() 이후에 불려야합니다. * @return * @throws Exception */ public List<List<Map<String, Object>>> getAllTableMapList() throws Exception { List<List<Map<String, Object>>> list = new ArrayList<>(); int tableCount = getTableCount(); for (int i = 0 ; i < tableCount ; i++) { list.add(getTableMap(i)); } return list; } } /** 연결을 시도합니다. */ public static SapManagerBinder newSapManagerBinder() { return new SapManagerBinder(new Properties()); } /** * 커넥터 연결 * @author 박용서 * @since 2018. 2. 20. */ public static class SapManagerBinder { // 환경 final Properties properties; // 내부함수 SapManagerBinder(Properties properties) { this.properties = properties; } /** 바인드 */ public synchronized SapManager bind() throws JCoException, IOException { File connectionFile = new File(CONN_FILE_NAME+".jcoDestination"); if (!connectionFile.exists()) { FileOutputStream fos = new FileOutputStream(connectionFile, false); properties.store(fos, "make connection file"); fos.close(); } return new SapManager(); } /** 값 세팅 */ public SapManagerBinder set(String key, String value) { properties.setProperty(key, value); return this; } } /** * 처음 생성된 Column을 보여주는 뷰입니다. * @author 박용서 * @since 2018. 2. 20. */ public static interface ColumnDefiner<CDO> { CDO call(String[] rows) throws Exception; } /** * 행 매핑 * @author 박용서 * @since 2018. 2. 20. */ public static interface RowMapper<CDO, RC> { RC call(CDO columnDefiner, String[] rows, Object[] values) throws Exception; } } - 자바