테이블생성

CREATE TABLE ST_AS_REQUEST (

 [CONSULT_NO] [char](12) NOT NULL,
 [USER_PASSWORD] [char](4)  NULL,
 [CUST_SEQ] [char](12) NULL,
 [ITEM_CLASS2] [varchar](50) NULL,
    
      CONSTRAINT ST_AS_REQUEST_PK PRIMARY KEY (CONSULT_NO),
       CONSTRAINT ST_AS_REQUEST_FK FOREIGN KEY (CUST_SEQ) REFERENCES TableName(ColName)
); 

 

 

칼럼추가 

ALTER TABLE ST_MAGAZINE ADD TAG_NAME VARCHAR(50) NOT NULL DEFAULT 'N'

 

ALTER TABLE TCMOnBizConsultInfo ADD consultRequestTime VARCHAR(20) 
ALTER TABLE TCMOnBizConsultInfo ADD consultRequestTime VARCHAR(20) 

 

<JSP 다중파일업로드>

 

JSP에서는 여러개의 파일을 보낼수있는 폼이 필요하다.
여러개의 파일을 보낼려면 폼에서 반드시 2가지 처리를 해줘야한다.

 1) enctype="multipart/form-data"

 2) method="post" 

파일을 보내기위해서는 속성을 명시해줘야 전송이가능하다.

추가적인 설명을 붙이자면 multpart/form-data라는 속성은 문자가 아닌

파일 이미지등을 보낼때 주는 속성값이다.

그리고 이속성은 get방식으로는 전송할수없다.

get방식은 url에 담을수있는 정보를 보낼때 쓰는데. 이미지나 파일같은경우는 

데이터기 때문에 get방식으로는 송수신이 불가능하다. 

<form:form modelAttribute="item" method="post" enctype="multipart/form-data">
  <tr>
    <td class="label"><p>설명서 등록</p></td> <!-- 상품설명서 -->
    <td>
      <div>
        <button type="button" id="add_Instruction_file" style="display:none" class="table_btn"><
        span>파일찾기</span></button> 
        <p>
          <input type="file" name="itemInstructionFiles" multiple="multiple" />
          <form:input path="itemInstructionFileCode" value="0020" maxlength="10" style="display:none" />
        </p>
        <ul id="item_details_images">
          <c:forEach items="${item.itemFiles}" var="itemFile" varStatus="i">
            <c:if test="${itemFile.fileCode == 20}">
              <li id="item_file_id_${itemFile.fileId}">
                <span>${itemFile.fileOrgName}</span>
                <a href="javascript:deleteItemFiles('${itemFile.fileId}','${item.itemUserCode}');" 
                class="delete_item_image">
                  <button type="button" class="btn btn-gradient btn-xs"><span>선택삭제</span></button>
                </a>
              </li>
            </c:if>
          </c:forEach>
        </ul>
      </div>
    </td>
  </tr>
</form>

-하나의 아이템에 여러개의 설명서가 들어가는 1대다 구조의 파일업로드 JSP로직이다.

등록된 파일은 수정창에서 조회 가능하며 파일을 다운로드 하는 기능은 넣지 않았고 선택하여 삭제할수있게끔

코드를 짯다.

이렇게 자바단으로 데이터를 보내면 자바에서 처리하는 로직은 어떻게 짜야할까?

 

1)전송받은 컨트롤러에서 받는다

@RequestParam(value="itemInstructionFiles"required=falseMultipartFile[] itemInstructionFiles

 

2)여러개의 파일정보를 받을수있는 MultpartFile을 배열로 VO에 선언하여 준다. 

    private MultipartFile[] itemInstructionFiles;

 

3)뷰에서 받은 파일정보를 VO에 셋팅하여준다.

    item.setItemInstructionFiles(itemInstructionFiles);

 

4)자바의 파일 IO로직으로 파일을 실제 물리적으로 저장을 한다.

 

5)파일정보를 데이터베이스 테이블에 담는다.

 

여기서 파일 입출력을 다루지는 않을것이다.

MultipartFile로 넘어오는 정보는 파일이름,파일크기등이 넘어오는데

이때 자바에서는 확장자를 구분하여 저장시키기도 하고 제한두기도 하고 

파일크기로 제한을두는등 해당업무에 맞게 코딩을하여 사용한다. 

이부분은 프로젝트에서 공통으로 처리하는곳이 많다.

 

이렇게 파일을 뷰에서 받아온뒤

자바에서는 파일정보를 가공해서 

데이터베이스에 넣게되는데. 거의 프로젝트마다 공통된 부분이 많다.

파일명 같은경우 중복되면 안되서 UUID로 생성해서 저장시킨다.

프로젝트마다 파일을 DB에 저장시키는 방법이 다르지만

다중파일같은경우는 파일명이 중복되면 안되기때문에 실제파일명,중복처리한 파일명,파일경로 등은 

거의 필수적으로 들어간다. 

 

파일이 저장될때는 자바에서 처리되는과정

등록,수정이 다르게처리된다.

등록은 바로 파일저장을 시키면 되는데

수정같은경우는 조금복잡하다. 저장되는경우 / 저장안되는경우가 나눠지고 

등록된 파일을 삭제하는 로직도 들어가야 하기 때문이다.

그리고 파일을 뿌리는것도 동적으로 뿌려줘야하기때문에

리스트형태 private List<ItemFileitemFiles = new ArrayList<>()  로 받아와서 처리가 된다.

 

 

동적으로 처리되는과정[JSP]

<ul id="item_details_images">
  <c:forEach items="${item.itemFiles}" var="itemFile" varStatus="i">
    <c:if test="${itemFile.fileCode == 20}">
    <li id="item_file_id_${itemFile.fileId}">
      <span>${itemFile.fileOrgName}</span>
      <a href="javascript:deleteItemFiles('${itemFile.fileId}','${item.itemUserCode}');" 
      class="delete_item_image">
      	<button type="button" class="btn btn-gradient btn-xs">
        <span>선택삭제</span></button>
      </a>
    </li>
    </c:if>
  </c:forEach>
</ul>

-여기서 <li> 태그를 보면 동적처리된것을 알수있다.

해당파일의 고유한 키값을 아이디값으로 줌으로써 그파일의 아이디로 다운로드,업로드가 가능하게 되는것이다.

저기서 연결된 펑션은 해당파일을 실제로 삭제를 시키는 펑션이다

 

<연결된펑션>

function deleteItemFiles(id,code) {

  var message = '파일이 실제로 삭제됩니다. 계속 진행하시겠습니까?'; 
  if (!confirm(message)) {
  return;
  } 

  var param = {'itemFileId': id,'itemUserCode':code};
  $.post('${requestContext.managerUri}/item/delete-item-file', param, function(response){
    Common.responseHandler(response);
    $('#item_file_id_' + param.itemFileId).remove();
  });	

}

 여기서 파라미터값으로 id와 code를 보내게되는데.

이업무 같은경우에는 각 아이템마다 코드를 생성하여 폴더관리를 하고있다. 그렇기때문에 코드값을 따로 보내서

처리하게되지만 파일id값으로 폴더를 생성시킨다면 굳이 코드값을 보낼필요는 없다.

이렇게 뷰에서 정보를 전송해준다면 자바에서는 2가지 작업이 진행된다

  1.DB에서의 파일정보삭제

  2.물리적인 파일삭제

이루어지게 된다.

 

 

 

 

 

 

 

 

 

 

 

 

요즘 웬만한 기업 중에 ERP(전사적자원관리) 시스템을 이용하지 않는 기업은 없을 것이다. ERP는 기업 내의 모든 자원의 흐름을 한 눈에 살피고, 업무를 프로세스 기반으로 최적화 하기 위한 시스템으로, 기업 정보화의 핵심이라고 볼 수 있다.

ERP 소프트웨어 시장에서는 독일의 SAP가 전 세계 시장을 이끌고 있다. 국내에서도 삼성전자, 현대기아차, 한국전력, SK텔레콤, KT 등 많은 대기업이 SAP 소프트웨어를 기반으로 ERP 시스템을 운영하고 있다. 그런데 최근 SAP 소프트웨어 사용기업들은 큰 고민이 생겼다. 소위 “2025년 문제”라는 것이다.

SAP는 2025년부터 기존 제품(R3)의 유지관리 서비스를 중단할 방침이다. 구 제품 버그패치나 보안취약점 패치 등을 중단한다는 것이다. 2025년 이후에 SAP ERP를 계속 이용하고 싶으면 최신 제품인 SAP S/4 HANA로 마이그레이션 해야 한다. 윈도우XP의 지원이 중단된 이후에 윈도7으로 업그레이드 하는 것과 비교하면 이해하기 쉽다.

문제는 R3와 S/4 HANA가 완전히 다른 ERP 제품이라는 점이다. R3은 다양한 데이터베이스(DB)와 운영체제(OS)를 지원한다. 상당수의 SAP ERP 고객들은 SAP ERP용 DB로 ‘오라클 DB’를 이용한다.

반면 SAP S/4 HANA는 오직 리눅스 OS와 SAP HANA DB만 지원한다. 유닉스나 마이크로소프트 윈도우 OS, 오라클 DB는 지원하지 않는다. 리눅스 OS와 SAP의 DB 제품인 SAP HANA만 이용할 수 있다.

고객사 입장에서는 SAP ERP를 계속 이용하려면 DB를 오라클 DB에서 SAP HANA로 바꿔야 하는 상황이다. ERP를 마이그레이션 하는 것도 큰 변화인데, 여기에 더해 DB까지 마이그레이션 하는 것은 보통 큰 일이 아니다. SAP HANA DB는 인메모리 기반의 DB로, 빠른 성능을 자랑하지만 아직 시장에서 검증받기 시작한지 얼마되지 않았다. 30년 넘게 전세계적으로 애용된 오라클 DB와 비교하면 성숙도 면에서 떨어지는 것은 어쩔 수 없다. 여기에 서버 장비까지 리눅스용으로 바꿔야 한다. 기업 입장에서는 큰 부담이 아닐 수 없다.

 



그렇다면 SAP ERP 고객들은 어떤 선택을 해야할까? 선택지는 몇 개가 있다.

우선 SAP의 바람대로 SAP S/4 HANA로 마이그레이션하는 것이다. 물론 이 경우 DB도 오라클을 떠나서 SAP HANA로 바꿔야 한다. SAP에 대한 충성도가 높은 기업은 이를 택하는 것도 나쁘지 않을 것이다. SAP가 고객을 SAP S/4 HANA로 유인하기 위한 많은 인센티브를 제공할테니, 그것을 잘 이용하는 것도 좋을 것이다.

또 하나는 ERP를 이용해 자신들에게 락인(Lock-In)하려는 SAP의 유혹을 과감하게 떨쳐내고 다른 ERP로 바꾸는 방법이다. 시장에는 SAP ERP 외에도 대안은 있다. 가장 대표적인 것은 오라클 ERP다. 아마도 상당수의 SAP 고객사가 오라클 DB를 이용하고 있을테니, DB는 그대로 둔 채 ERP 소프트웨어만 오라클로 바꿔야 한다. 다만 이 경우 오라클 DB에 오라클 ERP의 조합이기 때문에 오라클에 락인되는 단점이 있다. 또 오라클은 최근 ERP를 클라우드화 하고 있기 때문에 클라우드에 대한 고민도 병행해야 한다. 오라클 ERP 이외에 마이크로소프트나 국내 업체들의 ERP 소프트웨어가 있지만 대기업 레퍼런스가 별로 없다는 단점이 있다.

 

 

 

 

이번 통합ERP시스템을 구축 하고있음으로써 SAP의 이유로 인해 많은 파장이 불고있는 현재

오라클 DB를 SAP S/4 HANA DB로 마이그레이션 에 대한 방법을 심층적으로 고민 하고있다.

고객사에서 SAP를 덜어낸다는 소식도 들리긴 하지만 아직 모르겠다.

 

프로젝트 개발을 진행하다 보면 상당히 많이 사용하고 있음에도 평소에 습관처럼 복붙 해서 쓰는 경우가 많아

정리할 겸 포스팅한다.  이내용을 이해하게 된다면 실무에서 적용하기에 크게 어렵지 않을 것이다. 

 

다오 또는 매퍼명을 적어주면 해당하는 메서드명으로 ID를 찾아서 실행해준다.

    <mapper namespace="test.master.extentionMapper">

 

 

쿼리 태그

<select>

<insert>

 <update>

쿼리 구문에 맞게 맞춰서 쓰면 된다.

 

insert 구문 앞에 오는 seletKey

<selectKey keyProperty="Sequence" resultType="Integer" order="BEFORE"> 
	SELECT IFNULL(MAX(PAYMENT_SEQUENCE), 0) + 1            
    FROM MENT            
    WHERE ORDER_CODE = #{Code}               
     AND ORDER_SEQUENCE = #{Sequence}       
  </selectKey>

시퀀스를 DB에서 만들어서 쓴다면 SeqNm.nextVal로 쓸 수 있지만 아직도 많은 프로젝트에서 

max+1을 적용해서 많이 사용하고 있다.

이때 서브 쿼리에 해당 쿼리를 써줘도 되지만 이 방법이 더 깔끔하고 간편하다. 

 

유의해서 사용해야 할 CDATA

CDATA 같은 경우   > <  등 부등호 처리 할 때 태그로 처리되는 부등호를

쿼리에서 인식하게 바꿔주는 역할을 한다. 

하지만 유의해야 할 점이 동적 태그를 CDATA로 감싸면 인식 안되기 때문에 이 부분 유의해서 써준다.

 

 

쿼리 내용 포함하는 include 태그

 <include refid="CommonMapper.paginationHeader" /> 

-쿼리를 불러서 포함시키는 태그인데 매퍼 Name.ID로 불러서 쓸 수 있다.

여러 가지 공통된 쿼리 내용을 포함시켜야 할 때 많이 쓴다.

 

 

결과을 담는 resultMap

  <resultMap id="masterResult" type="master.test.domain.masterVO">   
    	<result property="voName" column="colName" />     
        <result property="eventCode" column="EVENT_CODE" />   
        <collection property="attendanceConfigs" resultMap="AttendanceConfigResult" />  
  </resultMap>
  
  
  
	resultMap="masterResult"

resultMap으로 결과값을 VO에 매핑시킬 수 있다.

다른 테이블과 1대다 관계에 있고 다쪽 데이터를 매핑시킬 때는 List 형태로 받아서 매핑시켜야 하는데

이때는 collection형태로 담아야 한다.

리저트 맵으로 리저트타입을 넘길 때 resultTyㅃpe="masterResult"로 선언해주면 에러가 난다.

resultMap으로 선언된 결과값은  resultMap="masterResult"로 처리해야 에러 없이 실행될 것이다. 

 

 

쿼리 태그 옵션 값

 

-parameterType,

 

파라미터로 넘어 오는 변수를 자바 객체, 기본형을 써줄 수 있다

VO

int

String [한 칼럼의 경우 스트링 배열로 받을 수 있다.]

list

map

 

 

 

list 추가 설명

        INSERT MASG ( ID   
        	      ,STATUS         
                      ,PHONE       
                      ,CALLBACK          
                      ,REQDATE         
                      ,MSG           
                      ,TEMPLATE_CODE           
                      ,FAILED_TYPE            
                      ,FAILED_SUBJECT            
                      ,FAILED_MSG           
                      ,PROFILE_KEY         
                      ,BUTTON_JSON ) 
          VALUES      
      <foreach collection="list" item="masg" open="" close="" separator=",">      
              ( #{masg.id}
                ,'0'
                ,#{masg.phone}
                ,#{masg.callback}
                ,NOW()
                ,#{masg.msg}
                ,#{masg.templateCode},
                ,#{masg.failedType}
                ,#{masg.failedSubject}
                ,#{masg.failedMsg}
                ,#{masg.profileKey}
                ,#{masg.buttonJson} )  
        </foreach>

 

이런 식으로 루프 문을 돌려서 다량의 데이터를 추가시킬 수 있다.

 

 

 

-resultType

 

결과값은 map,list,VO,int,string, 등으로 넘길 수 있다

유의할 점은 VO의 경우 선언된 멤버 변수 기준으로 #{변수명}으로 적어야 하고

map은 키값 기준으로 int, string은 넘길 때 변수명 기준으로 

매퍼에서 받아와야 정상적으로 쓸 수 있다.

 

 

 

 

동적 태그

 

-IF태그

  <if test='displayFlag != null and displayFlag != ""'>
     AND DISPLAY_FLAG = #{displayFlag}
  </if>

 

 

 

-choose태그

                <choose>
                    <when test="orderCode != null and orderCode != ''">
                        AND ORDER_CODE = #{orderCode}
                    </when>
                    <when test="orderCode == "100" >
                        AND ORDER_CODE = '100'
                    </when>
                    <otherwise>
                        AND USER_ID = #{userId}
                    </otherwise>
                </choose>

 

when조건 둘 다 안 맞을 시 otherwise실행.

 

-foreach태그

            <foreach collection="list" item="item" index="i" open="(" separator="OR" close=")">
                        CODE = #{item.orderCode} 
                AND   QUENCE = #{item.orderSequence} 
                AND SEQUENCE = #{item.itemSequence}
                AND   STATUS = '01'
            </foreach>

            <foreach collection="status" item="status" index="i" open="(" separator="," close=")">
                 #{status}
            </foreach>

코드를 보면 대부분 알 것 같다.

item 결과값을 담는 변수

index는 값이 들어올 때마다 0부터 순차적으로 증가한다

open 구문 시작 시 들어가는 문자열

close 구문 끝날 시 들어가는 문자열

separator 한번 돌고 다음번에 오는 구분자

'JAVA' 카테고리의 다른 글

1대다 JSP 파일업로드  (0) 2020.06.28
2025년 SAP ERP 지원중단  (0) 2020.06.26
Orange For Oracle PL/SQL Guide  (1) 2020.06.16
어노테이션(Annotation )의 이해와 실무에서의 활용  (0) 2020.06.13
서블릿 정리  (0) 2020.02.16

테이블을 생성하는 명령어이다. 

 

신텍스

create table tableName(
            Col1     Type   primary key  comment 'PK Key'
           ,Col2    Type   
           ,Col3     Type   
           ,PK > 2  primary KEY(Col1,Col2,Col3)
           ,OptionName1 optionSet1
            OptionName2 optionSet2
           )

 

아래는 실제 생성명령어이다.

create table MASTER_FILE 
( 
    MASTER_ID       int default 0 not null comment '상품ID', 
    FILE_CODE    int       not null COMMENT '파일유형', 
    FILE_ID int  not null comment '상품파일ID', 
    FILE_NAME    varchar(255)     null comment '파일명', 
    FILE_ORG_NAME    varchar(255)  null comment '파일명', 
    CREATED_DATE  varchar(14)   null comment '등록일', 
    primary KEY (MASTER_ID,FILE_CODE,FILE_ID),
    constraint FK_MASTER_TO_MASTER_FILE
     foreign key (MASTER_ID) references MASTER (MASTER_ID) 
            on delete cascade 
) 
    comment '상품상세파일'; 

 

옵션별 기능

constraint  제약조건명을 설정하여 주는것이다.
이옵션을 사용하지 않으면 디폴트값으로 들어가는데 
그러면 가독성이 떨어지게 되고 제약조건 관리가 잘안될수
있다. 쓰는형식은 프로젝트 마다 정말 다다르다
테이블명_키값 , 외부테이블_생성테이블 
이렇게 하는 경우도 있다.

foreign key (ColName) referenences (MASTER) 해당구문은 참조하고있는 테이블(MASTER)의 외부키로 
엮어주는 구문이다. 
on delete cascade  이구문은 부모테이블을 참조하고있는 자식테이블
MASTER_FILE에 있는 데이터들이 부모테이블을 참조하고 
있고 그참조데이터가 지워지면 자식들도 함께 지울수있게
옵션값을 주는것이다. 이렇게 하면 데이터의 무결성을 지킬수 있을것이다.

 

PL/SQL 편집기 중 현재 사용 중인 Orange를 소개 간단하게 소개한다.

 

PL/SQL Developer 를 사용했지만 프로젝트에서

 

강제적으로 Orange For Oracle Version 5.0을 사용 중이다.

 

SQL 문장 은 다른 툴과 거의 비슷하기 때문에 정보제공 및 사용방법은 생략한다.

 

프리랜서로 개발 생활하면서 Procedure , Function, Trigger를 아주 많이 접하고 있음에

 

PL/SQL편집 debugger 방법을 소개한다.

 

서버상에 존재하는 Function, Procedure, Trigger 등 PL/SQL로 작성된 코드를 디버깅하기 위해서

 

PL/SQL Debugger는 Check Out 되어 있는 상태에서 실행할 수 없으며 반드시 Check In 상태

 

(Read Only Mode: 디버깅 중에 사용자의 실수로 코드가 변화하는 것을 방지하기 위함)에서만 가능하다.

 

디버깅을 시작하기 전에 [Debug Mode Compile] 버튼( )을 누를 것을 권장한다.

 

이는 서버상에서 변수 값을 추적하기 위한 디버깅 환경을 조성하기 위함이다.

 

또한 변수 값을 추적하기 위해서 [Watch] 탭을 클릭하고 해당 변수를 드래그해서 “Watch” 윈도로 드롭한다.

 

[start Debugger] 버튼 ( )을 누르면 Debug Execution 윈도가 뜨고 적절한 변수 값을 입력하고 [OK] 버튼을 누르면

 

디버깅이 시작된다.

 

[Step into] 버튼( )을 누르면 한 라인씩 디버그가 시작되며 현재 디버깅 라인이 좌측 화살표로 표시된다.

 

혹은 디버깅을 시작하기 전에 Break Point를 설정하고 설정한 지점까지 [Step over] 버튼( )을 눌러서 실행할 수 있다.

 

혹은 Break Point의 설정 없이 특정 라인까지 한 번에 진행되기를 원하는 경 우에는 그 라인에 커서를 두고

 

[Run to Cursor] 버튼( )을 누르면 된다.

 

물론 그 라인까지 진행하기 전에 Break Point가 존재하는 라인이 있으면 거기서 멈춘다.

 

간단한 Function이나 Procedure를 편집할 땐 별 사용의 의미가 없을지 언정

 

큰 단위의 Package 내부 중 몇만 라인 이상씩 되는 Procedure를 편집하기 위해선 너무나 유용하게 사용된다.

 

/* */

 

Oracle For Oracle Tool의 라이선스는 굉장히 비싸다.

'JAVA' 카테고리의 다른 글

1대다 JSP 파일업로드  (0) 2020.06.28
2025년 SAP ERP 지원중단  (0) 2020.06.26
마이바티스(MyBatis) 실무활용  (0) 2020.06.24
어노테이션(Annotation )의 이해와 실무에서의 활용  (0) 2020.06.13
서블릿 정리  (0) 2020.02.16

+ Recent posts