commit 4d239e430d2512edde86e39cd6f4f97a35f423f3 Author: Terry Chang Date: Fri Aug 31 17:02:59 2018 +0900 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f2f14a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,87 @@ +# Created by https://www.gitignore.io/api/maven,eclipse,java-web + +### Eclipse ### + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### Eclipse Patch ### +# Eclipse Core +.project + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Annotation Processing +.apt_generated + +### Java-Web ### +## ignoring target file +target/ + +### Maven ### +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + + +# End of https://www.gitignore.io/api/maven,eclipse,java-web \ No newline at end of file diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..167b4db --- /dev/null +++ b/lombok.config @@ -0,0 +1 @@ +lombok.log.fieldName = logger \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..18be6d5 --- /dev/null +++ b/pom.xml @@ -0,0 +1,244 @@ + + + 4.0.0 + com.terry + xplatform + xplatform + war + 1.0.0-BUILD-SNAPSHOT + + 1.8 + UTF-8 + UTF-8 + + + 2.2 + 1.2 + 2.5 + + + 4.3.18.RELEASE + + + 1.8.13 + + + 1.4.197 + 11.2.0 + + + 3.4.6 + 1.3.2 + + + 1.2.3 + 1.7.25 + 1.16 + + + 2.5.1 + + + + + + org.springframework + spring-context + ${spring-framework.version} + + + + commons-logging + commons-logging + + + + + + + org.springframework + spring-jdbc + ${spring-framework.version} + + + + + org.springframework + spring-tx + ${spring-framework.version} + + + + + org.springframework + spring-webmvc + ${spring-framework.version} + + + + + org.aspectj + aspectjrt + ${aspectj.version} + + + org.aspectj + aspectjweaver + ${aspectj.version} + + + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + compile + + + ch.qos.logback + logback-classic + ${logback.version} + runtime + + + + + javax.servlet + servlet-api + ${servlet.version} + provided + + + javax.servlet.jsp + jsp-api + ${jsp.version} + provided + + + javax.servlet + jstl + ${jstl.version} + + + + org.projectlombok + lombok + 1.18.2 + true + + + + com.h2database + h2 + ${h2db.version} + compile + + + + + org.mybatis + mybatis + ${mybatis.version} + + + + org.mybatis + mybatis-spring + ${mybatis-spring.version} + + + + org.bgee.log4jdbc-log4j2 + log4jdbc-log4j2-jdbc4.1 + ${log4jdbc.version} + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + + javax.validation + validation-api + 2.0.1.Final + + + + org.hibernate.validator + hibernate-validator + 6.0.12.Final + + + + com.tobesoft + xplatform + 1.0 + system + ${basedir}/src/main/webapp/WEB-INF/lib/xplatform-xapi-1.0.jar + + + + com.tobesoft + miplatform + 3.2 + system + ${basedir}/src/main/webapp/WEB-INF/lib/miplatform-3.2.jar + + + + + + + + maven-eclipse-plugin + 2.9 + + + org.springframework.ide.eclipse.core.springnature + + + org.springframework.ide.eclipse.core.springbuilder + + true + true + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.5.1 + + 1.8 + 1.8 + -Xlint:all + true + true + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + org.test.int1.Main + + + + + diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..a3aae09 --- /dev/null +++ b/readme.txt @@ -0,0 +1,146 @@ +살펴봐야 할 내용을 정리한겁니다.. +여기 문서에 적힌 대로 셋팅해보시고 테스트 꼭 진행하세요.. +크게는 2가지 내용에 대해 설명할껍니다.. +먼저 첫번째로 Mapper 인터페이스로 DAO를 대체하는 방법은.. + +1. 먼저 mybatis mapper 파일을 보세요.. +제가 드린 소스를 기준으로 설명드리면 src/main/resources/com/terry/xplatform/resources/mybatis/mapper 디렉토리에 있는 sample.xml 입니다.. +그 파일을 열어보세요.. +그 파일을 보면 요렇게 있을겁니다.. +즉 이 파일은 com.terry.xplatform.dao 패키지에 있는 SampleDAO 인터페이스와 매핑되는거에요.. +그리고 현재 열어놓은 xml 파일을 보시면 insert, update 태그들이 보이실겁니다..이때 보셔야 할 것이 id 부분이에요.. +왜냐면 이 아이디와 동일한 이름의 메소드를 만들어야 합니다.. +일단 이렇게만 기억해두시고 com.terry.xplatform.dao 패키지에 있는 SampleDAO 인터페이스 파일을 열어보세요.. +인터페이스이기 때문에 구체적으로 코딩된 내용은 없고 메소드의 정의만 있습니다.. + +@Mapper +public interface SampleDAO { + + public void insertSample(SampleVO sampleVO); + public void updateSample(SampleVO sampleVO); + public void deleteSample(@Param("id") int id); + public SampleVO selectSample(@Param("id") int id); + public List selectSampleList(SampleDefaultVO sampleDefaultVO); + public long selectSampleListTotCnt(SampleDefaultVO sampleDefaultVO); + public Map dataType(); + +} + +여기서 보셔야 할 것은 @Mapper 인터페이스에요..이걸 적어줘야 합니다.. +그리고 메소드 이름들을 보세요..위에서 언급했던 sample.xml 에 있는 각 태그들의 id와 일치되죠? +즉 해당 태그의 id에 대한 부분을 같은 이름의 메소드가 처리한다고 보시면 됩니다.. +query 가 있는 xml을 저는 VO로 하기 때문에 메소드의 파라미터들을 VO로 받았지만 SQL 작업을 하면 VO로 받지 않고 int 값 같은 단일 타입으로 받아야 할 때도 있습니다.. +그때 사용되는게 @Param 어노테이션입니다.. + +public void deleteSample(@Param("id") int id); 이걸 기준으로 설명드리면 얘와 매핑되는 것은 + + + + + +이것과 매핑되겠죠? 여기서 보시면 parameterType 속성을 vo의 alias가 아닌 int 타입으로 줬습니다.. +그렇기땜에 #{id}는 특정 VO의 id란 이름의 멤버변수가 아니에요.. +이럴때 사용되는게 @Param 어노테이션입니다.. +@Param("id")로 해서 query 문에서 사용되는 변수명을 적어주는거에요.. +그러면 그게 해당 query문의 변수와 매핑이 됩니다.. + +그러면 이렇게 만든 Mapper 인터페이스를 어떻게 사용하냐면.. +src/main/java/com/terry/xplatform/service/impl 패키지에 있는 SampleServiceImpl 클래스를 열어보세요.. +그러면 다음과 같은 부분이 있을 겁니다.. + +@Autowired +private SqlSession sqlSession; + +SampleDAO sampleDAO; + +@PostConstruct +public void init() { + sampleDAO = sqlSession.getMapper(SampleDAO.class); +} + +이렇게 SqlSession 타입 멤버변수를 하나 설정하고 +@PostConstruct 어노테이션을 통해 SampleServiceImpl이 초기화될때 sampleDAO 변수를 sqlSession.getMapper 메소드를 통해 설정해주는거에요.. +여기서 SampleDAO는 위에서 언급했던 @Mapper 어노테이션이 붙은 SampleDAO 인터페이스입니다.. +그 다음엔 Service에서 우리가 DAO 사용하듯 그냥 하시면 되요.. +기존에 SqlSession.select 메소드나 insert 메소드를 DAO 클래스에서 일일이 작성할 필요가 없습니다.. + +이렇게 크게 2가지 설명한다는 내용중 하나 설명했고 또 하나는 VO 클래스의 alias 등록하는 방법이에요.. +일전에 저랑 스터디 카페에서 이 부분에 대해 얘기할때 일일이 mubatis config 파일에 등록한다고 했는데.. +좀더 찾아보니 스캔해서 등록해주는 기능이 있더군요.. + +/src/main/resources/com/terry/xplatform/resources/mybatis/config 에 가시면 mybatis-config.xml 파일이 있습니다.. +그 내용도 얼마 안되니 여기다가 쓸께요.. + + + + + + + + + + + + +여기서 봐야 할것은 태그의 하위 태그로 있는 태그 입니다.. +여기에 VO가 들어있는 패키지를 써주는거에요..그러나 패키지를 써준다고 끝나는게 아닙니다.. +왜냐면 패키지 안에 있는것들중 mybatis vo로 등록할 것도 있고 그렇지 않은 것도 있기 때문에.. +VO에 별도 기술해줘야 할 것이 있어요.. +com.terry.xplatform.vo 패키지에 있는 SampleVO 클래스를 열어보세요.. +소스도 얼마안되니 여기다가 바로 써드릴께요.. + +@Data +@AllArgsConstructor +@Alias("SampleVO") +public class SampleVO extends XplatformVO { + + /** + * + */ + private static final long serialVersionUID = -4891478433457788136L; + + /** 아이디 */ + private String id; + + /** 이름 */ + private String name; + + /** 내용 */ + private String description; + + /** 사용여부 */ + private String useYn; + + /** 등록자 */ + private String regUser; +} + +여기서 봐야 할 부분중 @Alias가 있습니다.. +@Alias 어노테이션에 mybatis 에서 사용할 VO의 이름을 써주는거에요.. +그러면 위에서 태그에 설정되어 있는 패키지 안의 클래스들에서 @Alias 어노테이션이 있는 것만 Mybatis의 VO로 등록해서 사용하게 됩니다.. +@Alias("SampleVO") 로 했기 때문에 query 문이 있는 sample.xml 문에서 다음과 같이 이 클래스를 사용할 수 있는거에요.. + + + + + +parameterType 속성에 있는 SampleVO를 @Alias 어노테이션에 붙인 이름으로 찾아서 매핑하는거죠.. + +그리고 제가 보내드린 query xml 파일을 보시면 거기에 동적 sql 하는 부분이 있습니다.. +그 부분이 ibatis하고는 다른 부분이 있으니까 꼭 보세요.. +문서 보시고 모르는 부분은 전화주세요.. diff --git a/src/main/java/com/terry/xplatform/config/handler/GlobalExceptionHandler.java b/src/main/java/com/terry/xplatform/config/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..76b8056 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/handler/GlobalExceptionHandler.java @@ -0,0 +1,28 @@ +package com.terry.xplatform.config.handler; + +import org.springframework.dao.DataAccessException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.servlet.ModelAndView; + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(value={DataAccessException.class}) + public ModelAndView processDataAccessException(DataAccessException ex){ + ModelAndView modelAndView = new ModelAndView(); + modelAndView.addObject("ErrorCode", "-1"); + modelAndView.addObject("ErrorMsg", ex.getMessage()); + modelAndView.setViewName("errorView"); + return modelAndView; + } + + @ExceptionHandler(value={Exception.class}) + public ModelAndView processException(Exception ex){ + ModelAndView modelAndView = new ModelAndView(); + modelAndView.addObject("ErrorCode", "-1"); + modelAndView.addObject("ErrorMsg", ex.getMessage()); + modelAndView.setViewName("errorView"); + return modelAndView; + } +} diff --git a/src/main/java/com/terry/xplatform/config/utils/XplatformReflectionUtils.java b/src/main/java/com/terry/xplatform/config/utils/XplatformReflectionUtils.java new file mode 100644 index 0000000..50fcbed --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/utils/XplatformReflectionUtils.java @@ -0,0 +1,386 @@ +package com.terry.xplatform.config.utils; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.core.MethodParameter; +import org.springframework.util.ReflectionUtils; + +import com.tobesoft.xplatform.data.ColumnHeader; +import com.tobesoft.xplatform.data.DataSet; +import com.tobesoft.xplatform.data.DataTypes; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class XplatformReflectionUtils { + + /** + * Xplatform의 DataSet에 있는 특정 컬럼의 값을 VO와 매핑하는 메소드 + * @param field + * @param columnHeader + * @param obj + * @param columnValue + */ + public static void setField(Field field, ColumnHeader columnHeader, Object obj, String columnValue) { + + ReflectionUtils.makeAccessible(field); //Field가 private 등의 접근할 수 없는 상황일때도 접근할 수 있게 한다 + + Class fieldType = field.getType(); + + if(fieldType == String.class) { + ReflectionUtils.setField(field, obj, columnValue); + } else if(fieldType == char.class || fieldType == Character.class) { + ReflectionUtils.setField(field, obj, columnValue.charAt(0)); + } else if(fieldType == short.class || fieldType == Short.class) { + ReflectionUtils.setField(field, obj, Short.parseShort(columnValue, 10)); + } else if(fieldType == int.class || fieldType == Integer.class) { + ReflectionUtils.setField(field, obj, Integer.parseInt(columnValue, 10)); + } else if(fieldType == long.class || fieldType == Long.class) { + ReflectionUtils.setField(field, obj, Long.parseLong(columnValue, 10)); + } else if(fieldType == float.class || fieldType == Float.class) { + ReflectionUtils.setField(field, obj, Float.parseFloat(columnValue)); + } else if(fieldType == double.class || fieldType == Double.class) { + ReflectionUtils.setField(field, obj, Double.parseDouble(columnValue)); + } else if(fieldType == Date.class) { + int dataType = columnHeader.getDataType(); + Calendar calendar = Calendar.getInstance(); + if(dataType == DataTypes.DATE) { + if(columnValue.length() == 8) { // yyyyMMdd + String year = columnValue.substring(0, 4); + String month = columnValue.substring(4, 6); + String day = columnValue.substring(6, 8); + + calendar.set(Calendar.YEAR, Integer.parseInt(year, 10)); + calendar.set(Calendar.MONTH, Integer.parseInt(month, 10) - 1); + calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day, 10)); + + } else { // DataTypes.DATE 타입에 8자리 숫자가 들어와야 하는데 그러지 않은 것이므로 예외처리 대상이다 + + } + } else if(dataType == DataTypes.TIME) { + if(columnValue.length() > 6) { + String hour = columnValue.substring(0, 2); + String minute = columnValue.substring(2, 4); + String second = columnValue.substring(4, 6); + String milisecond = columnValue.substring(6, 9); + + calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour, 10)); + calendar.set(Calendar.MINUTE, Integer.parseInt(minute, 10)); + calendar.set(Calendar.SECOND, Integer.parseInt(second, 10)); + calendar.set(Calendar.MILLISECOND, Integer.parseInt(milisecond, 10)); + } else { // DataTypes.DATE 타입에 6자리 이상의 숫자가 들어와야 하는데 그러지 않은 것이므로 예외처리 대상이다 + + } + } else if(dataType == DataTypes.DATE_TIME) { + if(columnValue.length() == 17) { + String year = columnValue.substring(0, 4); + String month = columnValue.substring(4, 6); + String day = columnValue.substring(6, 8); + String hour = columnValue.substring(8, 10); + String minute = columnValue.substring(10, 12); + String second = columnValue.substring(12, 14); + String milisecond = columnValue.substring(14); + + calendar.set(Calendar.YEAR, Integer.parseInt(year, 10)); + calendar.set(Calendar.MONTH, Integer.parseInt(month, 10) - 1); + calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day, 10)); + calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour, 10)); + calendar.set(Calendar.MINUTE, Integer.parseInt(minute, 10)); + calendar.set(Calendar.SECOND, Integer.parseInt(second, 10)); + calendar.set(Calendar.MILLISECOND, Integer.parseInt(milisecond, 10)); + + } else { // DataTypes.DATE 타입에 14자리 이상의 숫자가 들어와야 하는데 그러지 않은 것이므로 예외처리 대상이다 + + } + } + + ReflectionUtils.setField(field, obj, calendar.getTime()); + } + + } + + /* + public static Collection getCollection(Class clazz) { + Collection result = null; + if(clazz == ArrayList.class) { + result = new ArrayList(); + } else if(clazz == HashSet.class) { + result = new HashSet(); + } + + return result; + } + */ + + /** + * Java Reflection에서 Field 객체를 가져올때 해당 객체의 Super 클래스들에 대한 Field를 같이 가져오는 것이 없어서 별도로 제작했다 + * @param t + * @return 해당 객체가 가지고 있는 Field 객체들 및 해당 객체의 Super 클래스들이 가지고 있는 Field 객체들이 들어있는 List 객체 + */ + public static List getFields(T t) { + List fields = new ArrayList<>(); + Class clazz = t.getClass(); + while (clazz != Object.class) { + fields.addAll(Arrays.asList(clazz.getDeclaredFields())); + clazz = clazz.getSuperclass(); + } + return fields; + } + + /** + * DataSet 클래스 객체를 Collection 인터페이스 계열의 클래스 객체로 변환하는 메소드 + * @param dataSet 변환대상이 되는 DataSet + * @param collectionType 변환되는 Collection 계열 인터페이스 및 클래스 타입 + * @param genericClass 변환되는 Collection 계열 인터페이스 및 클래스의 내부에 들어사는 클래스 타입 + * @return + * @throws InstantiationException + * @throws IllegalAccessException + */ + public static Object convertDataSetToCollection(DataSet dataSet, Class collectionType, Class genericClass) throws InstantiationException, IllegalAccessException { + Object result = null; + int insertUpdateRowCount = dataSet.getRowCount(); + int removeRowCount = dataSet.getRemovedRowCount(); + int columnCount = dataSet.getColumnCount(); // 데이터셋에서 삭제된 데이터행(DataRow)는 별도 공간에 저장되기 때문에 이에 대한 처리를 위해 별도 변수를 잡고 이에 대한 작업을 진행한다 + + if(collectionType.isInterface()) { // Colleciton 계열 인터페이스로 선언한 경우 + if(collectionType.equals(List.class)) { // List 타입으로 받을 경우(ArrayList를 생성해서 return 해준다) + List listResult = new ArrayList(); + + // 저장(insert, update)되어야 할 DataSet의 row들에 대한 처리 + for(int i=0; i < insertUpdateRowCount; i++) { + if(Map.class.isAssignableFrom(genericClass)) { + Map obj = makeDataAsMap(genericClass, dataSet, columnCount, i); + listResult.add(obj); + } else { + Object obj = makeDataAsObject(genericClass, dataSet, columnCount, i); + listResult.add(obj); + } + } + + // 삭제(delete)되어야 할 DataSet의 row들에 대한 처리 + for(int i = 0; i < removeRowCount; i++) { + if(Map.class.isAssignableFrom(genericClass)) { + Map obj = makeRemovedDataAsMap(genericClass, dataSet, columnCount, i); + listResult.add(obj); + } else { + Object obj = makeRemovedDataAsObject(genericClass, dataSet, columnCount, i); + listResult.add(obj); + } + } + + result = listResult; + } else if(collectionType.equals(Set.class)) { // Set 타입으로 받을 경우(HashSet을 생성해서 return 해준다) + Set setResult = new HashSet(); + + // 저장(insert, update)되어야 할 DataSet의 row들에 대한 처리 + for(int i=0; i < insertUpdateRowCount; i++) { + if(Map.class.isAssignableFrom(genericClass)) { + Map obj = makeDataAsMap(genericClass, dataSet, columnCount, i); + setResult.add(obj); + } else { + Object obj = makeDataAsObject(genericClass, dataSet, columnCount, i); + setResult.add(obj); + } + } + + // 삭제(delete)되어야 할 DataSet의 row들에 대한 처리 + for(int i = 0; i < removeRowCount; i++) { + if(Map.class.isAssignableFrom(genericClass)) { + Map obj = makeRemovedDataAsMap(genericClass, dataSet, columnCount, i); + setResult.add(obj); + } else { + Object obj = makeRemovedDataAsObject(genericClass, dataSet, columnCount, i); + setResult.add(obj); + } + } + + result = setResult; + } + } else { // List, Set 같은 인터페이스가 아니라 ArrayList, HashSet 같은 Collection 인터페이스 구현 클래스로 받은 경우 + Object checkObject = collectionType.newInstance(); + Class checkType = checkObject.getClass(); + if(Collection.class.isAssignableFrom(checkType)) { + + // 저장(insert, update)되어야 할 DataSet의 row들에 대한 처리 + for(int i=0; i < insertUpdateRowCount; i++) { + if(Map.class.isAssignableFrom(genericClass)) { + Map obj = makeDataAsMap(genericClass, dataSet, columnCount, i); + ((Collection)(checkObject)).add(obj); + } else { + Object obj = makeDataAsObject(genericClass, dataSet, columnCount, i); + ((Collection)(checkObject)).add(obj); + } + } + + // 삭제(delete)되어야 할 DataSet의 row들에 대한 처리 + for(int i = 0; i < removeRowCount; i++) { + if(Map.class.isAssignableFrom(genericClass)) { + Map obj = makeRemovedDataAsMap(genericClass, dataSet, columnCount, i); + ((Collection)(checkObject)).add(obj); + } else { + Object obj = makeRemovedDataAsObject(genericClass, dataSet, columnCount, i); + ((Collection)(checkObject)).add(obj); + } + } + } + + result = checkObject; + } + + + + return result; + } + + /** + * DataSet 객체에서 특정 row에 해당되는 객체를 Map 형태로 변환한다 + * 변환된 Map에서 key는 해당 DataSet의 column 이름이다. + * @param dataSet DataSet 객체 + * @param colCount DataSet 객체의 컬럼 갯수 + * @param rowIdx DataSet 객체에서 읽고자 하는 row의 인덱스 + * @return + * @throws IllegalAccessException + * @throws InstantiationException + */ + private static Map makeDataAsMap(Class mapType, DataSet dataSet, int colCount, int rowIdx) throws InstantiationException, IllegalAccessException { + Map result = null; + if(mapType.isInterface()) { + result = new HashMap(); + } else { + result = (Map) mapType.newInstance(); + } + + result.put("rowType", dataSet.getRowType(rowIdx)); + result.put("storeDataChanges", dataSet.isStoreDataChanges()); + for(int j=0; j < colCount; j++) { + Object columnValue = dataSet.getObject(rowIdx, j); // 데이터셋에서 해당 row에 대한 column 값을 Object로 가져온다 + + ColumnHeader columnHeader = dataSet.getColumn(j); + String columnName = columnHeader.getName(); + result.put(columnName, columnValue); + } + + return result; + } + + /** + * DataSet 객체에 저장되어 있는 삭제된 데이터에서 특정 row에 해당되는 객체를 Map 형태로 변환한다 + * 변환된 Map에서 key는 해당 DataSet의 column 이름이다. + * @param dataSet DataSet 객체 + * @param colCount DataSet 객체의 컬럼 갯수 + * @param rowIdx DataSet 객체에서 읽고자 하는 row의 인덱스 + * @return + * @throws IllegalAccessException + * @throws InstantiationException + */ + private static Map makeRemovedDataAsMap(Class mapType, DataSet dataSet, int colCount, int rowIdx) throws InstantiationException, IllegalAccessException { + Map result = null; + if(mapType.isInterface()) { + result = new HashMap(); + } else { + result = (Map) mapType.newInstance(); + } + + result.put("rowType", DataSet.ROW_TYPE_DELETED); + result.put("storeDataChanges", dataSet.isStoreDataChanges()); + for(int j=0; j < colCount; j++) { + Object columnValue = dataSet.getRemovedData(rowIdx, j); // 데이터셋에서 해당 row에 대한 column 값을 Object로 가져온다 + + ColumnHeader columnHeader = dataSet.getColumn(j); + String columnName = columnHeader.getName(); + result.put(columnName, columnValue); + } + + return result; + } + + /** + * DataSet 객체에서 특정 row에 해당되는 객체를 특정 클래스의 객체로 변환한다 + * @param innerClass 특정 클래스타입 + * @param dataSet DataSet 객체 + * @param colCount DataSet 객체의 컬럼 갯수 + * @param rowIdx DataSet 객체에서 읽고자 하는 row의 인덱스 + * @return + * @throws InstantiationException + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + private static Object makeDataAsObject(Class innerClass, DataSet dataSet, int colCount, int rowIdx) throws InstantiationException, IllegalArgumentException, IllegalAccessException { + Object obj = innerClass.newInstance(); + Field rowTypeField = ReflectionUtils.findField(innerClass, "rowType"); + Field storeDataChangesField = ReflectionUtils.findField(innerClass, "storeDataChanges"); + ReflectionUtils.makeAccessible(rowTypeField); + ReflectionUtils.makeAccessible(storeDataChangesField); + rowTypeField.setInt(obj, dataSet.getRowType(rowIdx)); + storeDataChangesField.setBoolean(obj, dataSet.isStoreDataChanges()); + + for(int j=0; j < colCount; j++) { + String columnValue = dataSet.getString(rowIdx, j); // 데이터셋에서 해당 row에 대한 column 값을 String으로 가져온다 + + ColumnHeader columnHeader = dataSet.getColumn(j); + String columnName = columnHeader.getName(); + + Field field = ReflectionUtils.findField(innerClass, columnName); + + if(field == null) { // 컬럼이름으로 된 멤버변수를 찾지 못한 경우 + continue; + } else { + XplatformReflectionUtils.setField(field, columnHeader, obj, columnValue); + } + } + + return obj; + } + + /** + * DataSet 객체에서 특정 row에 해당되는 객체를 특정 클래스의 객체로 변환한다 + * @param innerClass 특정 클래스타입 + * @param dataSet DataSet 객체 + * @param colCount DataSet 객체의 컬럼 갯수 + * @param rowIdx DataSet 객체에서 읽고자 하는 row의 인덱스 + * @return + * @throws InstantiationException + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + private static Object makeRemovedDataAsObject(Class innerClass, DataSet dataSet, int colCount, int rowIdx) throws InstantiationException, IllegalArgumentException, IllegalAccessException { + Object obj = innerClass.newInstance(); + Field rowTypeField = ReflectionUtils.findField(innerClass, "rowType"); + Field storeDataChangesField = ReflectionUtils.findField(innerClass, "storeDataChanges"); + ReflectionUtils.makeAccessible(rowTypeField); + ReflectionUtils.makeAccessible(storeDataChangesField); + + // 삭제된 행의 rowType을 읽어오는 메소드는 없기 때문에(DataSet 클래스의 getRowType 메소드는 저장이나 변경된 데이터셋에 대한 rowType 을 읽어오는 것이지 삭제된 행에 대한 rowType을 읽는 것이 아니다) + // 이렇게 된 원인은 삭제된 행을 별도로 저장하는 상황때문에 그리 된거지만 어차피 삭제된 행은 rowType이 DataSet.ROW_TYPE_DELETED로 설정되기 때문에 이것으로 강제 설정을 해준다 + rowTypeField.setInt(obj, DataSet.ROW_TYPE_DELETED); + storeDataChangesField.setBoolean(obj, dataSet.isStoreDataChanges()); + + for(int j=0; j < colCount; j++) { + String columnValue = dataSet.getRemovedStringData(rowIdx, j); // 삭제된 데이터의 해당 row에 대한 column 값을 String으로 가져온다 + + ColumnHeader columnHeader = dataSet.getColumn(j); + String columnName = columnHeader.getName(); + + Field field = ReflectionUtils.findField(innerClass, columnName); + + if(field == null) { // 컬럼이름으로 된 멤버변수를 찾지 못한 경우 + continue; + } else { + XplatformReflectionUtils.setField(field, columnHeader, obj, columnValue); + } + } + + return obj; + } +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/XplatformConstants.java b/src/main/java/com/terry/xplatform/config/xplatform/XplatformConstants.java new file mode 100644 index 0000000..3180b8f --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/XplatformConstants.java @@ -0,0 +1,7 @@ +package com.terry.xplatform.config.xplatform; + +import com.tobesoft.xplatform.tx.PlatformType; + +public class XplatformConstants implements PlatformType { + public static final String CONTENT_TYPE_CSV = "csv"; +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestDataSet.java b/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestDataSet.java new file mode 100644 index 0000000..6d3a348 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestDataSet.java @@ -0,0 +1,13 @@ +package com.terry.xplatform.config.xplatform.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequestDataSet { + + String name() default ""; // 읽고자하는 데이터셋 이름을 받아들이는 부분 +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestDataSetList.java b/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestDataSetList.java new file mode 100644 index 0000000..2455ed3 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestDataSetList.java @@ -0,0 +1,13 @@ +package com.terry.xplatform.config.xplatform.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequestDataSetList { + + String name() default ""; // 읽고자하는 데이터셋 리스트 이름을 받아들이는 부분 +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestVariable.java b/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestVariable.java new file mode 100644 index 0000000..25989ff --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/annotation/RequestVariable.java @@ -0,0 +1,13 @@ +package com.terry.xplatform.config.xplatform.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequestVariable { + + String name() default ""; // 읽고자하는 변수명 이름을 받아들이는 부분 +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/data/XplatformVO.java b/src/main/java/com/terry/xplatform/config/xplatform/data/XplatformVO.java new file mode 100644 index 0000000..91285a5 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/data/XplatformVO.java @@ -0,0 +1,20 @@ +package com.terry.xplatform.config.xplatform.data; + +import com.terry.xplatform.vo.SampleDefaultVO; + +import lombok.Getter; +import lombok.Setter; + +/** + * XPlatform의 DataSet에서 변환되는 VO는 이 클래스를 반드시 상속받아야 한다 + * @author Terry Chang + * + */ +@Getter +@Setter +public abstract class XplatformVO extends SampleDefaultVO { + + private int rowType; + private boolean storeDataChanges; + +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/support/HttpRequestWrapper.java b/src/main/java/com/terry/xplatform/config/xplatform/support/HttpRequestWrapper.java new file mode 100644 index 0000000..9811be5 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/support/HttpRequestWrapper.java @@ -0,0 +1,49 @@ +package com.terry.xplatform.config.xplatform.support; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.springframework.util.StreamUtils; + +public class HttpRequestWrapper extends HttpServletRequestWrapper { + + private byte[] bodyData; + + public HttpRequestWrapper(HttpServletRequest request) throws IOException { + super(request); + // TODO Auto-generated constructor stub + InputStream is = request.getInputStream(); + bodyData = StreamUtils.copyToByteArray(is); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + // TODO Auto-generated method stub + final ByteArrayInputStream bis = new ByteArrayInputStream(bodyData); + return new ServletImpl(bis); + } +} + +class ServletImpl extends ServletInputStream { + + private InputStream is; + + public ServletImpl(InputStream bis) { + is = bis; + } + + @Override + public int read() throws IOException { + return is.read(); + } + + @Override + public int read(byte[] b) throws IOException { + return is.read(b); + } +} \ No newline at end of file diff --git a/src/main/java/com/terry/xplatform/config/xplatform/support/HttpServletRequestWrapperFilter.java b/src/main/java/com/terry/xplatform/config/xplatform/support/HttpServletRequestWrapperFilter.java new file mode 100644 index 0000000..01bca9c --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/support/HttpServletRequestWrapperFilter.java @@ -0,0 +1,54 @@ +package com.terry.xplatform.config.xplatform.support; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Service; + +/** + * HttpServletRequest 객체를 한번 감싸주어서 request로 전달해주는 Filter이다. + * 일반적으로 HttpServletRequest 객체의 request body를 읽었을 경우 Stream으로 읽어나가기 때문에 + * 한번 읽게 되면 다시 읽을수가 없는 상황이 된다. + * 그래서 HttpServletRequest 객체를 한번 감싸는 Wrapper 클래스를 만든뒤에 그 클래스에 원래 request의 InputStream을 배열로 보관한뒤 + * 이 Wrapper 클래스 객체를 전달함으로써 이걸 이용하는 클래스는 Wrapper 클래스 객체의 배열을 읽게 함으로써 여러번 읽을수 있게끔 해준다 + * + * 이 클래스를 Spring Bean으로 등록할땐 Servlet Context가 아닌 Root Context에 등록해야 한다 + * 그래야 web.xml에서 Spring의 DelegatingFilterProxy 클래스를 통해 이 Filter 클래스를 사용할 수 있다(Spring의 Bean Injection 기능 사용이 가능) + * Spring Security에서 설정 xml이 Root Context에 등록되는 것과 같은 의미이다 + * + * @author Terry Chang + * + */ +@Service +public class HttpServletRequestWrapperFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // TODO Auto-generated method stub + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + // TODO Auto-generated method stub + HttpServletRequest httpServletRequest = (HttpServletRequest)request; + HttpRequestWrapper httpRequestWrapper = new HttpRequestWrapper(httpServletRequest); + chain.doFilter(httpRequestWrapper, response); + + } + + @Override + public void destroy() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/support/XplatformArgumentResolver.java b/src/main/java/com/terry/xplatform/config/xplatform/support/XplatformArgumentResolver.java new file mode 100644 index 0000000..ae7ae07 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/support/XplatformArgumentResolver.java @@ -0,0 +1,264 @@ +package com.terry.xplatform.config.xplatform.support; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.core.MethodParameter; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.support.WebArgumentResolver; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import com.terry.xplatform.config.utils.XplatformReflectionUtils; +import com.terry.xplatform.config.xplatform.annotation.RequestDataSet; +import com.terry.xplatform.config.xplatform.annotation.RequestDataSetList; +import com.terry.xplatform.config.xplatform.annotation.RequestVariable; +import com.tobesoft.xplatform.data.DataSet; +import com.tobesoft.xplatform.data.DataSetList; +import com.tobesoft.xplatform.data.PlatformData; +import com.tobesoft.xplatform.data.Variable; +import com.tobesoft.xplatform.data.VariableList; +import com.tobesoft.xplatform.tx.HttpPlatformRequest; +import com.tobesoft.xplatform.tx.PlatformRequest; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class XplatformArgumentResolver implements HandlerMethodArgumentResolver { + + /** + * DataSetList 객체를 HttpServletRequest의 setAttribute 메소드를 이용해서 저장할 때 사용되는 이름 + */ + private final String DATASETLIST_NAME; + + /** + * VariableList 객체를 HttpServletRequest의 setAttribute 메소드를 이용해서 저장할 때 사용되는 이름 + */ + private final String VARIABLELIST_NAME; + + public XplatformArgumentResolver() { + this.DATASETLIST_NAME = "dataSetList"; + this.VARIABLELIST_NAME = "variableList"; + } + + public XplatformArgumentResolver(String dataSetListName, String variableListName) { + this.DATASETLIST_NAME = dataSetListName; + this.VARIABLELIST_NAME = variableListName; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + // TODO Auto-generated method stub + boolean result = false; + + if(parameter.hasParameterAnnotation(RequestDataSet.class)){ + result = true; + }else if(parameter.hasParameterAnnotation(RequestVariable.class)){ + result = true; + } + + return result; + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + // TODO Auto-generated method stub + + Class type = parameter.getParameterType(); + Annotation[] annotations = parameter.getParameterAnnotations(); + HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest(); + // HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + // PlatformRequest platformRequest = new HttpPlatformRequest(request, "utf-8"); + + DataSetList dataSetList = null; + VariableList variableList = null; + + // 관련 처리를 할때마다 매번 Request의 Body에 있는 DataSetList와 VariableList를 만들면 오버헤드 소지가 있어서 + // 처음에 한번만 읽고 DataSetList와 VariableList를 HttpServletRequest에 setAttribute를 통해 저장을 한 뒤에 + // 다시 읽을때는 Request의 Body를 읽는게 아니라 저장되어 있는 것을 다시 읽어서 재활용한다 + if(request.getAttribute(DATASETLIST_NAME) == null || request.getAttribute(VARIABLELIST_NAME) == null) { + PlatformRequest platformRequest = new HttpPlatformRequest(request.getInputStream()); + platformRequest.receiveData(); + PlatformData platformData = platformRequest.getData(); + dataSetList = platformData.getDataSetList(); + variableList = platformData.getVariableList(); + + request.setAttribute(DATASETLIST_NAME, dataSetList); + request.setAttribute(VARIABLELIST_NAME, variableList); + } else { + dataSetList = (DataSetList)request.getAttribute(DATASETLIST_NAME); + variableList = (VariableList)request.getAttribute(VARIABLELIST_NAME); + } + + Object result = null; + + + for(Annotation annotation : annotations){ + Class annotationClass = annotation.annotationType(); + + if(annotationClass.equals(RequestDataSetList.class)){ // @RequestDataSetList 어노테이션에 대한 처리(이 어노테이션은 DataSetList 클래스객체만 파라미터 타입으로 받을 수 있다) + if(type.equals(DataSetList.class)) { + result = dataSetList; + }else{ + result = WebArgumentResolver.UNRESOLVED; + } + } else if(annotationClass.equals(RequestDataSet.class)){ // @RequestDataSet 어노테이션에 대한 처리 + RequestDataSet requestDataSet = (RequestDataSet)annotation; + String dataSetName = requestDataSet.name(); + if(!StringUtils.hasText(dataSetName)) { // DataSet 이름이 빠진것이므로 이거는 예외처리 진행하자 + result = WebArgumentResolver.UNRESOLVED; + } else { + DataSet dataSet = dataSetList.get(dataSetName); + if(type.equals(DataSet.class)) { // DataSet 파라미터 타입으로 받을 경우는 해당 이름으로 DataSet을 찾아서 이를 return 해주면 된다 + result = dataSet; + } else { // DataSet 클래스 객체는 Collection 인터페이스 계열 클래스들만 변환이 가능하기 때문에 이에 대한 체크 + if(Collection.class.isAssignableFrom(type)) { + // Type[] typeArray = ((ParameterizedType)parameter.getGenericParameterType()).getActualTypeArguments(); + // Class genericClassType = (Class) ((ParameterizedType)parameter.getGenericParameterType()).getActualTypeArguments()[0]; + + Type genericType = ((ParameterizedType)parameter.getGenericParameterType()).getActualTypeArguments()[0]; + Class genericClass = null; + if(genericType instanceof Class) { + genericClass = (Class)genericType; + } else { + Type rawType = ((ParameterizedType)genericType).getRawType(); + genericClass = (Class)rawType; + } + + result = XplatformReflectionUtils.convertDataSetToCollection(dataSet, type, genericClass); + } else { + result = WebArgumentResolver.UNRESOLVED; + } + } + } + + // XplatformReflectionUtils.convertDataSetToCollection 메소드로 변환할 수 없는 타입일 경우 null이 return 되기 때문에 이에 대한 처리 + if(result == null) { + result = WebArgumentResolver.UNRESOLVED; + } + } else if(annotationClass.equals(RequestVariable.class)) { // @RequestVariable 어노테이션에 대한 처리 + RequestVariable requestVariable = (RequestVariable)annotation; + String variableName = requestVariable.name(); + Variable variable = variableList.get(variableName); + if(StringUtils.hasText(variableName)) { // 특정 변수 이름이 있기 때문에 해당 이름에 대한 값을 낸다 + if(type.equals(int.class)) { + result = variable.getInt(); + } else if(type.equals(Integer.class)) { + result = new Integer(variable.getInt()); + } else if(type.equals(long.class)) { + result = variable.getLong(); + } else if(type.equals(Long.class)) { + result = new Long(variable.getLong()); + } else if(type.equals(float.class)) { + result = variable.getFloat(); + } else if(type.equals(Float.class)) { + result = new Float(variable.getFloat()); + } else if(type.equals(double.class)) { + result = variable.getDouble(); + } else if(type.equals(Double.class)) { + result = new Double(variable.getDouble()); + } else if(type.equals(Date.class)) { + result = variable.getDateTime(); + } else if(type.equals(String.class)) { + result = variable.getString(); + } else { + result = variable.getObject(); + } + } else { // 특정 변수 이름이 없으면 VO로 매핑하는 것이기 때문에 오히려 이런 경우 자바의 데이터타입과는 매핑을 할 수 없다 + List keyList = variableList.keyList(); + + if(Collection.class.isAssignableFrom(type)) { + Collection collectionResult = null; + if(type.isInterface()) { + if(type == List.class) { + collectionResult = new ArrayList(); + } else if(type == Set.class) { + collectionResult = new HashSet(); + } + } else { + collectionResult = (Collection)type.newInstance(); + } + + for(String key : keyList) { + collectionResult.add(variableList.getObject(key)); + } + + result = collectionResult; + } else if(Map.class.isAssignableFrom(type)) { + Map mapResult = null; + if(type.isInterface()) { + mapResult = new HashMap(); + } else { + mapResult = (Map)type.newInstance(); + } + + for(String key : keyList) { + mapResult.put(key, variableList.getObject(key)); + } + + result = mapResult; + } else { + // 객체로 변환하는 과정에서 예외가 발생하면 지원하지 않는 타입이기 때문에 그에 대한 처리를 한다 + try { + + Object obj = type.newInstance(); + + for(String key : keyList) { + Field keyField = ReflectionUtils.findField(type, key); + ReflectionUtils.makeAccessible(keyField); + + Class keyFieldType = keyField.getType(); + + if(keyFieldType == int.class) { + keyField.setInt(obj, variableList.getInt(key)); + } else if(keyFieldType == Integer.class) { + keyField.set(obj, new Integer(variableList.getInt(key))); + } else if(keyFieldType == long.class) { + keyField.setLong(obj, variableList.getLong(key)); + } else if(keyFieldType == Long.class) { + keyField.set(obj, new Long(variableList.getLong(key))); + } else if(keyFieldType == float.class) { + keyField.setFloat(obj, variableList.getFloat(key)); + } else if(keyFieldType == Float.class) { + keyField.set(obj, new Float(variableList.getFloat(key))); + } else if(keyFieldType == double.class) { + keyField.setDouble(obj, variableList.getDouble(key)); + } else if(keyFieldType == Double.class) { + keyField.set(obj, new Double(variableList.getFloat(key))); + } else if(keyFieldType == Date.class) { + keyField.set(obj, variableList.getDateTime(key)); + } else if(keyFieldType == String.class) { + keyField.set(obj, variableList.getString(key)); + } else { + keyField.set(obj, variableList.getObject(key)); + } + } + + result = obj; + } catch(Exception e) { + result = WebArgumentResolver.UNRESOLVED; + } + } + } + } + + } + + return result; + } +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/web/XplatformView.java b/src/main/java/com/terry/xplatform/config/xplatform/web/XplatformView.java new file mode 100644 index 0000000..f4dba58 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/web/XplatformView.java @@ -0,0 +1,317 @@ +package com.terry.xplatform.config.xplatform.web; + +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.util.StringUtils; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.web.servlet.support.RequestContext; +import org.springframework.web.servlet.view.AbstractTemplateView; + +import com.terry.xplatform.config.utils.XplatformReflectionUtils; +import com.terry.xplatform.config.xplatform.XplatformConstants; +import com.tobesoft.xplatform.data.DataSet; +import com.tobesoft.xplatform.data.DataSetList; +import com.tobesoft.xplatform.data.DataTypes; +import com.tobesoft.xplatform.data.PlatformData; +import com.tobesoft.xplatform.data.Variable; +import com.tobesoft.xplatform.data.VariableList; +import com.tobesoft.xplatform.data.datatype.PlatformDataType; +import com.tobesoft.xplatform.tx.HttpPlatformResponse; + +public class XplatformView extends AbstractTemplateView { + + /** + * Xplatform의 작업결과가 성공적이었을때의 ErrorCode 값을 설정한다 + */ + private final String ERROR_CODE_VALUE; + + /** + * Xplatform의 작업결과가 성공적이었을때의 ErrorMsg 값을 설정한다 + */ + private final String ERROR_MSG_VALUE; + + public XplatformView() { + this.ERROR_CODE_VALUE = "0"; + this.ERROR_MSG_VALUE = ""; + } + + public XplatformView(String errorCodeValue, String errorMsgValue) { + this.ERROR_CODE_VALUE = errorCodeValue; + this.ERROR_MSG_VALUE = errorMsgValue; + } + + @Override + protected void renderMergedTemplateModel(Map model, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { + // TODO Auto-generated method stub + String contentType = StringUtils.hasText((String)model.get("contentType")) ? (String)model.get("contentType") : XplatformConstants.CONTENT_TYPE_XML; + model.remove("contentType"); + + if(contentType == XplatformConstants.CONTENT_TYPE_XML) { + VariableList variableList = new VariableList(); + DataSetList dataSetList = new DataSetList(); + HttpPlatformResponse httpPlatformResponse = new HttpPlatformResponse(httpServletResponse, XplatformConstants.CONTENT_TYPE_XML); + + for(Entry entry : model.entrySet()) { + String key = entry.getKey(); + Object object = entry.getValue(); + if(object instanceof Collection) { + @SuppressWarnings("unchecked") + DataSet dataSet = makeDataSet(key, (Collection)object); + dataSetList.add(dataSet); + } else { + Variable variable = null; + if(object instanceof Integer) { + variable = new Variable(key, PlatformDataType.INT, (Integer)object); + } else if(object instanceof Long) { + variable = new Variable(key, PlatformDataType.LONG, (Long)object); + } else if(object instanceof Float) { + variable = new Variable(key, PlatformDataType.FLOAT, (Float)object); + } else if(object instanceof Double) { + variable = new Variable(key, PlatformDataType.DOUBLE, (Double)object); + } else if(object instanceof Date) { + variable = new Variable(key, PlatformDataType.DATE, (Date)object); + } else if(object instanceof String){ + variable = new Variable(key, PlatformDataType.STRING, (String)object); + } else if(object instanceof Variable) { + variable = (Variable)object; + } else { + // model에 들어있는 클래스 객체중에 DataSet으로 변환할 수 없는 클래스 객체가 들어있는것은 bypass 하게끔 한다 + + if(skipDataSet(object)) { + continue; + } + + // 객체의 멤버변수들 값을 읽어서 한 행짜리 데이터셋으로 return 하는 방법을 고민해보자 + DataSet dataSet = makeDataSet(key, object); + dataSetList.add(dataSet); + } + if(variable != null) { + variableList.add(variable); + } + } + } + + // XplatformView를 만든다는 것은 그 이전단계까지는 예외없이 진행되었다는 뜻이기 때문에 Xplatform에서 읽어들일변수인 ErrorCode 와 ErrorMsg 변수에 작업이 성공했다는 내용을 설정한다 + // Controller에서 ErrorCode와 ErrorMsg를 설정한 것이 없으면 XplatformView에서 설정하도록 한다 + if(!model.containsKey("ErrorCode")) { + variableList.add("ErrorCode", ERROR_CODE_VALUE); + } + + if(!model.containsKey("ErrorMsg")) { + variableList.add("ErrorMsg", ERROR_MSG_VALUE); + } + + PlatformData platformData = new PlatformData(); + platformData.setVariableList(variableList); + platformData.setDataSetList(dataSetList); + httpPlatformResponse.setData(platformData); + httpPlatformResponse.sendData(); + + } else if(contentType == XplatformConstants.CONTENT_TYPE_CSV) { + + } + + + } + + /** + * Collection 객체와 DataSet 이름을 파라미터로 받아 해당 객체가 들어있는 DataSet을 return 한다 + * @param dataSetName + * @param collection + * @return + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + private DataSet makeDataSet(String dataSetName, Collection collection) throws IllegalArgumentException, IllegalAccessException { + DataSet dataSet = new DataSet(dataSetName); + Object objColumn = null; + if(collection != null && collection.size() != 0) { + objColumn = collection.iterator().next(); + setColumnHeader(dataSet, objColumn); + addCollectionToDataSet(dataSet, collection); + } + return dataSet; + } + + /** + * Object 객체와 DataSet 이름을 파라미터로 받아 해당 객체가 들어있는 DataSet을 return 한다 + * @param dataSetName + * @param object + * @return + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + private DataSet makeDataSet(String dataSetName, Object object) throws IllegalArgumentException, IllegalAccessException { + DataSet dataSet = new DataSet(dataSetName); + setColumnHeader(dataSet, object); + addObjectToDataSet(dataSet, object); + return dataSet; + } + + /** + * DataSet 객체와 DataSet에 들어갈 객체를 파라미터로 받아 DataSet 객체에 ColumnHeader 정보를 설정한다 + * @param dataSet + * @param object + */ + private void setColumnHeader(DataSet dataSet, Object object) { + if(object instanceof Map) { + @SuppressWarnings("unchecked") + Map map = (Map) object; + for(Map.Entry entry : map.entrySet()) { + Object value = entry.getValue(); + + if(value instanceof Integer) { + dataSet.addColumn(entry.getKey(), DataTypes.INT); + } else if(value instanceof Long) { + dataSet.addColumn(entry.getKey(), DataTypes.LONG); + } else if(value instanceof Float) { + dataSet.addColumn(entry.getKey(), DataTypes.FLOAT); + } else if(value instanceof Double) { + dataSet.addColumn(entry.getKey(), DataTypes.DOUBLE); + } else if(value instanceof Date) { + dataSet.addColumn(entry.getKey(), DataTypes.DATE); + } else { + dataSet.addColumn(entry.getKey(), DataTypes.STRING); + } + } + } else { + List fieldList = XplatformReflectionUtils.getFields(object); + for(Field field : fieldList) { + field.setAccessible(true); + String fieldName = field.getName(); + Class classType = field.getType(); + if(classType == int.class || classType == Integer.class) { + dataSet.addColumn(fieldName, DataTypes.INT); + } else if(classType == long.class || classType == Long.class) { + dataSet.addColumn(fieldName, DataTypes.LONG); + } else if(classType == float.class || classType == Float.class) { + dataSet.addColumn(fieldName, DataTypes.FLOAT); + } else if(classType == double.class || classType == Double.class) { + dataSet.addColumn(fieldName, DataTypes.DOUBLE); + } else if(classType == Date.class) { + dataSet.addColumn(fieldName, DataTypes.DATE); + } else { + dataSet.addColumn(fieldName, DataTypes.STRING); + } + } + } + } + + /** + * Collection 객체를 받아 Collection 객체 안에 있는 객체들을 묶어서 하나의 DataSet으로 만들어서 추가한다 + * @param dataSet + * @param collection + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + private void addCollectionToDataSet(DataSet dataSet, Collection collection) throws IllegalArgumentException, IllegalAccessException { + Iterator iterator = collection.iterator(); + // Object value = collection.iterator().next(); + + while(iterator.hasNext()) { + Object value = iterator.next(); + addObjectToDataSet(dataSet, value); + } + } + + /** + * Object 객체를 받아 DataSet에 추가한다 + * @param dataSet 대상이 되는 DataSet + * @param object 추가되는 Object 객체 + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + private void addObjectToDataSet(DataSet dataSet, Object object) throws IllegalArgumentException, IllegalAccessException { + int rowIdx = dataSet.newRow(); + + if(object instanceof Map) { + @SuppressWarnings("unchecked") + Map map = (Map)object; + for(Map.Entry entry : map.entrySet()) { + String columnName = entry.getKey(); + Object mapValue = entry.getValue(); + + if(mapValue instanceof Integer) { + dataSet.set(rowIdx, columnName, (int)mapValue); + } else if(mapValue instanceof Long) { + dataSet.set(rowIdx, columnName, (long)mapValue); + } else if(mapValue instanceof Float) { + dataSet.set(rowIdx, columnName, (float)mapValue); + } else if(mapValue instanceof Double) { + dataSet.set(rowIdx, columnName, (double)mapValue); + } else if(mapValue instanceof Date) { + dataSet.set(rowIdx, columnName, (Date)mapValue); + } else if(mapValue instanceof Boolean) { // boolean 계열은 String의 valueOf 메소드로 값을 설정한다 + dataSet.set(rowIdx, columnName, String.valueOf((Boolean)mapValue)); + } else { + dataSet.set(rowIdx, columnName, (String)mapValue); + } + } + } else { + List fieldList = XplatformReflectionUtils.getFields(object); + + for(Field field : fieldList) { + field.setAccessible(true); + String columnName = field.getName(); + Class classType = field.getType(); + + if(classType == int.class ) { + dataSet.set(rowIdx, columnName, field.getInt(object)); + } else if(classType == Integer.class) { + dataSet.set(rowIdx, columnName, field.get(object) == null ? null : ((Integer)field.get(object)).intValue()); + } else if(classType == long.class) { + dataSet.set(rowIdx, columnName, field.getLong(object)); + } else if(classType == Long.class) { + dataSet.set(rowIdx, columnName, field.get(object) == null ? null : ((Long)field.get(object)).longValue()); + } else if(classType == float.class) { + dataSet.set(rowIdx, columnName, field.getFloat(object)); + } else if(classType == Float.class) { + dataSet.set(rowIdx, columnName, field.get(object) == null ? null : ((Float)field.get(object)).floatValue()); + } else if(classType == double.class) { + dataSet.set(rowIdx, columnName, field.getDouble(object)); + } else if(classType == Double.class) { + dataSet.set(rowIdx, columnName, field.get(object) == null ? null : ((Double)field.get(object)).doubleValue()); + } else if(classType == Date.class) { + dataSet.set(rowIdx, columnName, (Date)(field.get(object))); + } else if(classType == boolean.class || classType == Boolean.class) { // boolean 계열은 String의 valueOf 메소드로 값을 설정한다 + dataSet.set(rowIdx, columnName, String.valueOf((field.get(object)))); + } else { + dataSet.set(rowIdx, columnName, (String)(field.get(object))); + } + } + } + } + + /** + * renderMergedTemplateModel 메소드의 model 파라미터에 있는 객체들 중에 DataSet으로 표현할 수 없는 클래스들이 있다(주로 Spring이 자체적으로 넣어놓은 property bind 등의 클래스) + * model에 있는 객체중 이런 클래스 객체는 DataSet으로의 변환을 제외시킬 목적으로 만든 메소드이며 개발하는 도중에 이런 성격의 클래스가 있으면 classArray 배열에 클래스를 객체에 있는 것중ㅇ + * @param object + * @return + */ + private boolean skipDataSet(Object object) { + Class [] classArray = new Class[] {BeanPropertyBindingResult.class, RequestContext.class}; + + boolean result = false; + Class objectClass = object.getClass(); + + for(Class clazz : classArray) { + if(clazz == objectClass) { + result = true; + break; + } + } + + return result; + } + + +} diff --git a/src/main/java/com/terry/xplatform/config/xplatform/web/XplatformViewResolver.java b/src/main/java/com/terry/xplatform/config/xplatform/web/XplatformViewResolver.java new file mode 100644 index 0000000..0c3a9d4 --- /dev/null +++ b/src/main/java/com/terry/xplatform/config/xplatform/web/XplatformViewResolver.java @@ -0,0 +1,23 @@ +package com.terry.xplatform.config.xplatform.web; + +import org.springframework.web.servlet.view.AbstractTemplateViewResolver; +import org.springframework.web.servlet.view.AbstractUrlBasedView; + +public class XplatformViewResolver extends AbstractTemplateViewResolver { + + @Override + protected Class getViewClass() { + // TODO Auto-generated method stub + return XplatformView.class; + } + + @Override + protected AbstractUrlBasedView buildView(String viewName) throws Exception { + // TODO Auto-generated method stub + XplatformView view = (XplatformView)super.buildView(viewName); + return view; + } + + + +} diff --git a/src/main/java/com/terry/xplatform/dao/SampleDAO.java b/src/main/java/com/terry/xplatform/dao/SampleDAO.java new file mode 100644 index 0000000..96e7bbc --- /dev/null +++ b/src/main/java/com/terry/xplatform/dao/SampleDAO.java @@ -0,0 +1,23 @@ +package com.terry.xplatform.dao; + +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import com.terry.xplatform.vo.SampleDefaultVO; +import com.terry.xplatform.vo.SampleVO; + +@Mapper +public interface SampleDAO { + + public void insertSample(SampleVO sampleVO); + public void updateSample(SampleVO sampleVO); + public void deleteSample(@Param("id") int id); + public SampleVO selectSample(@Param("id") int id); + public List selectSampleList(SampleDefaultVO sampleDefaultVO); + public long selectSampleListTotCnt(SampleDefaultVO sampleDefaultVO); + public Map dataType(); + +} diff --git a/src/main/java/com/terry/xplatform/service/SampleService.java b/src/main/java/com/terry/xplatform/service/SampleService.java new file mode 100644 index 0000000..9c5afdf --- /dev/null +++ b/src/main/java/com/terry/xplatform/service/SampleService.java @@ -0,0 +1,14 @@ +package com.terry.xplatform.service; + +import java.util.List; + +import org.springframework.dao.DataAccessException; + +import com.terry.xplatform.vo.SampleDefaultVO; +import com.terry.xplatform.vo.SampleVO; + +public interface SampleService { + + public void modify(List dataSet) throws DataAccessException; + public List list(SampleDefaultVO sampleDefaultVO) throws DataAccessException; +} diff --git a/src/main/java/com/terry/xplatform/service/impl/SampleServiceImpl.java b/src/main/java/com/terry/xplatform/service/impl/SampleServiceImpl.java new file mode 100644 index 0000000..987d036 --- /dev/null +++ b/src/main/java/com/terry/xplatform/service/impl/SampleServiceImpl.java @@ -0,0 +1,73 @@ +package com.terry.xplatform.service.impl; + +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.ibatis.session.SqlSession; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.stereotype.Service; + +import com.terry.xplatform.dao.SampleDAO; +import com.terry.xplatform.service.SampleService; +import com.terry.xplatform.vo.SampleDefaultVO; +import com.terry.xplatform.vo.SampleVO; +import com.tobesoft.xplatform.data.DataSet; + +@Service +public class SampleServiceImpl implements SampleService { + + @Autowired + private SqlSession sqlSession; + + SampleDAO sampleDAO; + + @PostConstruct + public void init() { + sampleDAO = sqlSession.getMapper(SampleDAO.class); + } + + @Override + public List list(SampleDefaultVO sampleDefaultVO) throws DataAccessException { + // TODO Auto-generated method stub + List result = sampleDAO.selectSampleList(sampleDefaultVO); + return result; + } + + @Override + public void modify(List dataSet) throws DataAccessException { + // TODO Auto-generated method stub + for(SampleVO sampleVO : dataSet) { + if(sampleVO.isStoreDataChanges()) { + int rowType = sampleVO.getRowType(); + switch(rowType) { + case DataSet.ROW_TYPE_INSERTED : + sampleDAO.insertSample(sampleVO); + break; + case DataSet.ROW_TYPE_UPDATED : + sampleDAO.updateSample(sampleVO); + break; + case DataSet.ROW_TYPE_DELETED : + sampleDAO.deleteSample(sampleVO.getId()); + break; + } + } else { + int rowType = sampleVO.getRowType(); + switch(rowType) { + case DataSet.ROW_TYPE_NORMAL : // ROW_TYPE_NORMAL로 받을 경우 현재 행이 insert 상태인지 update 상태인지를 알 수 없기 때문에 delete, insert 작업을 통해서 두 가지 상황을 모두 만족시키도록 한다 + sampleDAO.deleteSample(sampleVO.getId()); + sampleDAO.insertSample(sampleVO); + break; + case DataSet.ROW_TYPE_DELETED : + sampleDAO.deleteSample(sampleVO.getId()); + break; + } + } + + } + } + + + +} diff --git a/src/main/java/com/terry/xplatform/vo/SampleDefaultVO.java b/src/main/java/com/terry/xplatform/vo/SampleDefaultVO.java new file mode 100644 index 0000000..5e2964f --- /dev/null +++ b/src/main/java/com/terry/xplatform/vo/SampleDefaultVO.java @@ -0,0 +1,39 @@ +package com.terry.xplatform.vo; + +import java.io.Serializable; + +import org.apache.ibatis.type.Alias; + +import lombok.Data; + +@Data +@Alias("SampleDefaultVO") +public class SampleDefaultVO implements Serializable { + + /** 검색조건 */ + private String searchCondition = ""; + + /** 검색Keyword */ + private String searchKeyword = ""; + + /** 검색사용여부 */ + private String searchUseYn = ""; + + /** 현재페이지 */ + private int pageIndex = 1; + + /** 페이지갯수 */ + private int pageUnit = 10; + + /** 페이지사이즈 */ + private int pageSize = 10; + + /** firstIndex */ + private int firstIndex = 1; + + /** lastIndex */ + private int lastIndex = 1; + + /** recordCountPerPage */ + private int recordCountPerPage = 10; +} diff --git a/src/main/java/com/terry/xplatform/vo/SampleVO.java b/src/main/java/com/terry/xplatform/vo/SampleVO.java new file mode 100644 index 0000000..7eded1e --- /dev/null +++ b/src/main/java/com/terry/xplatform/vo/SampleVO.java @@ -0,0 +1,36 @@ +package com.terry.xplatform.vo; + +import org.apache.ibatis.type.Alias; + +import com.terry.xplatform.config.xplatform.data.XplatformVO; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Alias("SampleVO") +public class SampleVO extends XplatformVO { + + /** + * + */ + private static final long serialVersionUID = -4891478433457788136L; + + /** 아이디 */ + private Integer id; + + /** 이름 */ + private String name; + + /** 내용 */ + private String description; + + /** 사용여부 */ + private String useYn; + + /** 등록자 */ + private String regUser; +} diff --git a/src/main/java/com/terry/xplatform/web/SampleController.java b/src/main/java/com/terry/xplatform/web/SampleController.java new file mode 100644 index 0000000..ea5d3d7 --- /dev/null +++ b/src/main/java/com/terry/xplatform/web/SampleController.java @@ -0,0 +1,57 @@ +package com.terry.xplatform.web; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.terry.xplatform.config.xplatform.annotation.RequestDataSet; +import com.terry.xplatform.config.xplatform.annotation.RequestVariable; +import com.terry.xplatform.service.SampleService; +import com.terry.xplatform.vo.SampleVO; + +import lombok.extern.slf4j.Slf4j; + +@Controller +@Slf4j +public class SampleController { + + @Autowired + SampleService sampleService; + + @RequestMapping("/egovSampleSelect") + public void list(Model model + , SampleVO sampleVO + , @RequestVariable SampleVO requestVariableSampleVO + , @RequestVariable Map requestVariableMap + , @RequestVariable(name="firstIndex") int firstIndex + , @RequestVariable(name="recordCountPerPage") String recordCountPerPage + , HttpServletRequest httpServletRequest) { + // public void list(Model model, SampleVO sampleVO, @RequestVariable SampleVO requestVariableSampleVO) { + List sampleList = sampleService.list(sampleVO); + model.addAttribute("ds_output", sampleList); + } + + /* + @RequestMapping("/egovSampleSelect") + public void list(HttpServletRequest httpServletRequest) { + String firstIndex = httpServletRequest.getParameter("firstIndex"); + String recordCountPerPage = httpServletRequest.getParameter("recordCountPerPage"); + } + */ + + @RequestMapping("/egovSampleModify") + public void modify(@RequestDataSet(name="ds_input")ArrayList dataSet + , @RequestDataSet(name="ds_input")List> dataSetMap + , @RequestDataSet(name="ds_input")Set dataHashSet) { + sampleService.modify(dataSet); + } + +} diff --git a/src/main/resources/XPLATFORM_Server_License.xml b/src/main/resources/XPLATFORM_Server_License.xml new file mode 100644 index 0000000..b820849 --- /dev/null +++ b/src/main/resources/XPLATFORM_Server_License.xml @@ -0,0 +1,19 @@ + + + + XPLATFORM + 9 + Runtime, Widget, AJAX + + + TOBESOFT + 0 + 0.0.0.0 + Windows,CE,Linux + + + 2018-08-01 + 2 + + RDUTZJQZYZVS42PMV7NP4WGXE53J4VWM9 + \ No newline at end of file diff --git a/src/main/resources/com/terry/xplatform/resources/mybatis/config/mybatis-config.xml b/src/main/resources/com/terry/xplatform/resources/mybatis/config/mybatis-config.xml new file mode 100644 index 0000000..20aaa1e --- /dev/null +++ b/src/main/resources/com/terry/xplatform/resources/mybatis/config/mybatis-config.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/com/terry/xplatform/resources/mybatis/mapper/sample.xml b/src/main/resources/com/terry/xplatform/resources/mybatis/mapper/sample.xml new file mode 100644 index 0000000..e39e369 --- /dev/null +++ b/src/main/resources/com/terry/xplatform/resources/mybatis/mapper/sample.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/com/terry/xplatform/resources/spring/context-aspect.xml b/src/main/resources/com/terry/xplatform/resources/spring/context-aspect.xml new file mode 100644 index 0000000..f8d042d --- /dev/null +++ b/src/main/resources/com/terry/xplatform/resources/spring/context-aspect.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/com/terry/xplatform/resources/spring/context-common.xml b/src/main/resources/com/terry/xplatform/resources/spring/context-common.xml new file mode 100644 index 0000000..265b17e --- /dev/null +++ b/src/main/resources/com/terry/xplatform/resources/spring/context-common.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/src/main/resources/com/terry/xplatform/resources/spring/context-datasource.xml b/src/main/resources/com/terry/xplatform/resources/spring/context-datasource.xml new file mode 100644 index 0000000..5b256e2 --- /dev/null +++ b/src/main/resources/com/terry/xplatform/resources/spring/context-datasource.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/src/main/resources/com/terry/xplatform/resources/spring/context-sqlMap.xml b/src/main/resources/com/terry/xplatform/resources/spring/context-sqlMap.xml new file mode 100644 index 0000000..b50575e --- /dev/null +++ b/src/main/resources/com/terry/xplatform/resources/spring/context-sqlMap.xml @@ -0,0 +1,34 @@ + + + + + + + + + + classpath:com/terry/xplatform/resources/mybatis/mapper/*.xml + + + + + + + + + + + + + + + + diff --git a/src/main/resources/com/terry/xplatform/resources/spring/context-transaction.xml b/src/main/resources/com/terry/xplatform/resources/spring/context-transaction.xml new file mode 100644 index 0000000..88d346e --- /dev/null +++ b/src/main/resources/com/terry/xplatform/resources/spring/context-transaction.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/createdata.sql b/src/main/resources/createdata.sql new file mode 100644 index 0000000..9224aa7 --- /dev/null +++ b/src/main/resources/createdata.sql @@ -0,0 +1,4 @@ +INSERT INTO SAMPLE(ID, NAME, DESCRIPTION, USE_YN, REG_USER) VALUES('1','카테고리명1','설명1','1','등록자1'); +INSERT INTO SAMPLE(ID, NAME, DESCRIPTION, USE_YN, REG_USER) VALUES('2','카테고리명2','설명2','2','등록자2'); +INSERT INTO SAMPLE(ID, NAME, DESCRIPTION, USE_YN, REG_USER) VALUES('3','카테고리명3','설명3','1','등록자3'); +INSERT INTO IDS VALUES('SAMPLE',175); \ No newline at end of file diff --git a/src/main/resources/log4jdbc.log4j2.properties b/src/main/resources/log4jdbc.log4j2.properties new file mode 100644 index 0000000..379cdcf --- /dev/null +++ b/src/main/resources/log4jdbc.log4j2.properties @@ -0,0 +1,3 @@ +log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator +# log4jdbc.spylogdelegator.name=com.terry.springboard.common.log.CustomSlf4jSpyLogDelegator +log4jdbc.dump.sql.maxlinelength=0 \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..c592dd1 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,51 @@ + + + + + + true + + + + + + + + %-5level %logger{50} - %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..b579161 --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE SAMPLE ( + ID VARCHAR(16) NOT NULL PRIMARY KEY, + NAME VARCHAR(50), + DESCRIPTION VARCHAR(100), + USE_YN CHAR(1), + REG_USER VARCHAR(10), + REG_DATE DATE NOT NULL DEFAULT CURRENT_DATE() +); + +CREATE TABLE IDS ( + TABLE_NAME VARCHAR(16) NOT NULL PRIMARY KEY + ,NEXT_ID DECIMAL(30) NOT NULL +); \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/config/spring/servlet-context.xml b/src/main/webapp/WEB-INF/config/spring/servlet-context.xml new file mode 100644 index 0000000..1199cca --- /dev/null +++ b/src/main/webapp/WEB-INF/config/spring/servlet-context.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/lib/miplatform-3.2.jar b/src/main/webapp/WEB-INF/lib/miplatform-3.2.jar new file mode 100644 index 0000000..2b014d0 Binary files /dev/null and b/src/main/webapp/WEB-INF/lib/miplatform-3.2.jar differ diff --git a/src/main/webapp/WEB-INF/lib/xplatform-xapi-1.0.jar b/src/main/webapp/WEB-INF/lib/xplatform-xapi-1.0.jar new file mode 100644 index 0000000..9c4bf4b Binary files /dev/null and b/src/main/webapp/WEB-INF/lib/xplatform-xapi-1.0.jar differ diff --git a/src/main/webapp/WEB-INF/views/home.jsp b/src/main/webapp/WEB-INF/views/home.jsp new file mode 100644 index 0000000..4783383 --- /dev/null +++ b/src/main/webapp/WEB-INF/views/home.jsp @@ -0,0 +1,14 @@ +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ page session="false" %> + + + Home + + +

+ Hello world! +

+ +

The time on the server is ${serverTime}.

+ + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..2ef6f3e --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,44 @@ + + + + + + contextConfigLocation + + classpath*:com/terry/xplatform/resources/spring/context-*.xml + + + + + org.springframework.web.context.ContextLoaderListener + + + + + appServlet + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + + /WEB-INF/config/spring/servlet-context.xml + + 1 + + + + appServlet + *.do + + + + httpServletRequestWrapperFilter + org.springframework.web.filter.DelegatingFilterProxy + + + + httpServletRequestWrapperFilter + *.do + + diff --git a/src/main/webapp/xui/DefaultTheme.xadl b/src/main/webapp/xui/DefaultTheme.xadl new file mode 100644 index 0000000..613f646 --- /dev/null +++ b/src/main/webapp/xui/DefaultTheme.xadl @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/webapp/xui/DefaultTheme.xprj b/src/main/webapp/xui/DefaultTheme.xprj new file mode 100644 index 0000000..db82dd5 --- /dev/null +++ b/src/main/webapp/xui/DefaultTheme.xprj @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/webapp/xui/DefaultTheme.xtheme b/src/main/webapp/xui/DefaultTheme.xtheme new file mode 100644 index 0000000..66a07be Binary files /dev/null and b/src/main/webapp/xui/DefaultTheme.xtheme differ diff --git a/src/main/webapp/xui/body.html b/src/main/webapp/xui/body.html new file mode 100644 index 0000000..fc0be0f --- /dev/null +++ b/src/main/webapp/xui/body.html @@ -0,0 +1,98 @@ + + +XPlatform Run Page + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/xui/css/Template.css b/src/main/webapp/xui/css/Template.css new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/src/main/webapp/xui/css/Template.css @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/webapp/xui/default_typedef.xml b/src/main/webapp/xui/default_typedef.xml new file mode 100644 index 0000000..5c76800 --- /dev/null +++ b/src/main/webapp/xui/default_typedef.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/webapp/xui/frame/commFrame.xfdl b/src/main/webapp/xui/frame/commFrame.xfdl new file mode 100644 index 0000000..02fc2a9 --- /dev/null +++ b/src/main/webapp/xui/frame/commFrame.xfdl @@ -0,0 +1,30 @@ + + + +
+ + + + +
+
diff --git a/src/main/webapp/xui/frame/leftFrame.xfdl b/src/main/webapp/xui/frame/leftFrame.xfdl new file mode 100644 index 0000000..986ba66 --- /dev/null +++ b/src/main/webapp/xui/frame/leftFrame.xfdl @@ -0,0 +1,911 @@ + + + +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + +