본문 바로가기

반응형
반응형

이번 시간에는 버튼 제어와 히스토리 영역을 구현하도록 하겠습니다. 

업로드 시 히스토리 생성 > 체크박스 구현 > 버튼 제어 > 히스토리 영역

버튼 제어 요구조건

  • 등록자 : 임시 저장, 결재 버튼 노출
  • 결재자 : 반려, 결재 버튼 노출

우리가 저번 시간에 만든 appPage.jsp의 구조는 다음과 같습니다.

등록자의 요구조건은 글쓰기 화면, 결재자의 요구조건은 글읽기 화면에서 구현이 될 것입니다. 이 때 여러 상황에 따라 다양한 추가 기능을 구현해줘야 합니다. ¹내가 쓴 글을 읽을 때, 내가 반려, 결재 처리한 글을 읽을 때는 두 버튼(결재,반려)이 모두 없어야 하며, ²반려당한 내 글을 수정할 수 있어야 합니다.

이와 같은 참고사항까지 모두 고려해서 구현하도록 하겠습니다.

1-1. appPage.jsp

<!-- 수정 전 코드 -->
<button onclick="appCreateBtn(event)">등록</button>
<button id="subCreate-Btn">임시 저장</button>

<!-- ...... -->

<input type="hidden" id="appStatus"  name="appStatus" value="${appInfo.appStatus }">

<!-- 수정 후 코드 -->
<input type="hidden" id="appStatus"  name="appStatus">
<button onclick="appCreateBtn(event, 0)">등록</button>
<button onclick="appCreateBtn(event, 1)">임시 저장</button>

<!-- ...... -->

<input type="hidden" id="appStatusU"  name="appStatus" value="${appInfo.appStatus }">

수정 후 코드를 보면 하시겠지만 type이 hidden인 id값 appStatus인 <input>태그를 추가해줬습니다. 그런데 id값 appStatus인 항목은 이미 있으므로 코드의 통일성을 유지시켜주기 위해 기존에 있던 appStatus를 appStatusU로 바꿔줬습니다. 그러니 JQeury도 당연히 바꿔주도록 하겠습니다.

1-2. JQeury

function appCreateBtn(event, status){  // status 추가
    event.preventDefault();

    var titleLength = $("#title").val().length;
    var contentLength = $("#content").val().length;

    if(status == 1){	// status 값이 1인 경우 appStatus의 value를 'sub'로 바꿔준 뒤 서버로 보내줍니다.
        $("#appStatus").val('sub');
    }

    if(titleLength == 0 && contentLength > 0){
        alert("제목을 입력하세요.");
        $("#title").focus();
    } else if (titleLength > 0 && contentLength == 0){
        alert("내용을 입력하세요.");
        $("#content").focus();
    } else if(titleLength == 0 && contentLength == 0){
        alert("글을 작성하지 않았습니다.");
        $("#title").focus();
    } else {
        $("#appCreate-form").attr({
            'action' : '/create',
            'method' : 'post'
        }).submit();
    }
}

// ......

var sttVal = $("#appStatusU").val(); // 이전 코드 var sttVal = $("#appStatus").val();

 

 

임시 저장을 구현하면서 새로운 function을 만들까 했지만 status값 하나만 달라졌을 뿐이니 그 값만 정의해주면 되겠다고 생각했습니다. 그래서 매게 변수값과 그를 확인하는 if문을 추가해줬습니다.

1-3. Service

@Override
public void createApp(Map<String, Object> param) {
    int appSeq = Integer.parseInt(param.get("appSeq").toString());
    String appTitle = param.get("appTitle").toString();
    String appContent = param.get("appContent").toString();
    String appStatus = param.get("appStatus").toString(); // View에서 넘겨준 appStatus값

    Map<String, Object> appMap = new HashMap<String, Object>();
    appMap.put("appSeq", appSeq);
    appMap.put("appTitle", appTitle);
    appMap.put("appContent", appContent);

    Map<String, Object> memInfo = memDao.getMemInfo(param);
    int writerSeq = Integer.parseInt(memInfo.get("memSeq").toString());
    String writerPst = memInfo.get("memPosition").toString();

    appMap.put("writerSeq", writerSeq);


    if("sub".equals(appStatus)) {
        appMap.put("appStatus", "W"); // sub이 맞다면 임시저장으로 저장
        // 임시 저장은 결재할 수가 없으므로 결재자의 정보는 넣지 않습니다.
    } else {
        if("부장".equals(writerPst)) {
            appMap.put("apperSeq", writerSeq);
            appMap.put("appStatus", "C");
        } else if("과장".equals(writerPst)){
            appMap.put("apperSeq", writerSeq);
            appMap.put("appStatus", "B");
        } else {
            appMap.put("appStatus", "A");
        }
    }

    appDao.createApp(appMap);
    hisDao.createHis(appMap);
}

기존에 있던 글쓴이의 직급을 확인하는 코드는 else 코드에 넣어서 임시 저장이 아닌 경우에만 작동하게 해줍니다.

1-4. 결과물

일부러 사원부터 부장까지 차례로 글을 써봤습니다. 임시저장 상태로 저장됨과 동시에 결재 정보가 없고, 각 리스트에 다른 사람의 임시저장 글은 보이지 않는 것도 함께 확인했습니다!

이를 테스트 하기 위해서 사원으로 로그인을 해보니 대리라고 출력이 되고 있었습니다. 그래서 회원 테이블부터 확인해보니 DB는 아무 이상이 없었고 Mapper(MyBatis)에서 잘못 변환을 해주고 있음을 확인할 수 있었습니다. 

오른쪽 그림의 decode 부분을 보면 'dd','대리' 라고 되어있었습니다. 이를 'dd,'사원'으로 바꿔줬습니다.

 

1-5. appPage.jsp

<!-- 수정 전 코드 -->
<button id="replyBtn">반려</button>
<button id="appBtn">결재</button>

<!-- 수정 후 코드 -->
<button id="returnBtn">반려</button>
<button id="appBtn">결재</button>
<input type="hidden" name="id" value="${sessionId }">

 

1-6. JQuery

$(function(){

	/* 
    	이전 코드
	*/

    $("#returnBtn").on('click', function(event){
        event.preventDefault();

        $("#appStatusU").val('return');

        $("#appPrcForm").attr({
            'action' : '/changeApp',
            'method' : 'post'
        }).submit();
    });

    $("#appBtn").on('click', function(event){
        event.preventDefault();

        $("#appPrcForm").attr({
            'action' : '/changeApp',
            'method' : 'post'
        }).submit();
    });

})

 

1-7. Controller

@RequestMapping(value="/changeApp", method = RequestMethod.POST)
public String app(@RequestParam Map<String, Object> param) {
    appSer.changeApp(param);
    return "redirect:/list";
}

 

1-8. Service, Dao

// App Service Impl
@Override
public void changeApp(Map<String, Object> param) {
    int appSeq = Integer.parseInt(param.get("appSeq").toString()); // 2

    Map<String, Object> appInfo = appDao.getAppInfo(appSeq);
    int writerSeq = Integer.parseInt(appInfo.get("writerSeq").toString());

    Map<String, Object> appMap = new HashMap<String, Object>();
    appMap.put("appSeq", appSeq);
    appMap.put("writerSeq", writerSeq); // 5

    Map<String, Object> apperInfo = memDao.getMemInfo(param);
    int apperSeq = Integer.parseInt(apperInfo.get("memSeq").toString()); // 1
    String apperPst = apperInfo.get("memPosition").toString();

    String appStatusU = param.get("appStatus").toString(); // 3

    appMap.put("apperSeq", apperSeq);

    // 4
    if("return".equals(appStatusU)) {
        appMap.put("appStatus", "X");
    } else {
        if("부장".equals(apperPst)) {
            appMap.put("appStatus","C");
        } else if("과장".equals(apperPst)) {
            appMap.put("appStatus","B");
        }
    }

    appDao.changeApp(appMap);
    hisDao.createHis(appMap);
}

// App Dao Impl
@Override
public void changeApp(Map<String, Object> param) {
    sqlSession.update("AppMapper.changeApp", param);
}

Service에 대해서 설명 드리겠습니다. 결재처리에는 총 바뀌는 것이 결재자와 결재일, 결재상태입니다.

  1. 결재자를 View에서 받은 SessionId를 이용해서 회원 조회해서 PK값을 가져옵니다. ( // 1 )
  2. 결재 상태를 바꾸기 위해서 결재글의 PK값을 param에서 가져옵니다. ( // 2 )
  3. View에서 받은 appStatus를 가져와서( // 3 ) 반려인지 아닌지를 체크한 후에 반려라면 appStatus를 반려의 코드로, 반려가 아니라면 계급을 체크한 후에 알맞는 상태의 코드로 put 해줍니다. ( // 4 )
  4. History에도 넣어줘야 하기 때문에 글을 조회한 뒤 글쓴이의 PK를 넣어줍니다. ( // 5 )

1-9. Mapper

<update id="changeApp">
    update e_approval_app
        set
            apper_seq = #{apperSeq},
            app_date = sysdate,
            app_status = #{appStatus}
        where app_seq = #{appSeq}
</update>

결재일은 서버의 시간을 넣어줫습니다.

1-10. 결과물

반려 테스트
결재 테스트

결재자도 잘 바뀌고 반려, 결재코드로 저장 되는 것도 확인했습니다!

다음은 결재 상태에 따른 버튼 노출을 구현하겠습니다. 그 전에 각 직급별로 어떤 상황에 어느 버튼이 보여야 하는지 체크해 보도록 하겠습니다.

  • 사원, 대리 : 반려, 결재버튼 노출 금지
  • 과장 : 결재 대기인 글만 반려, 결재버튼 노출
  • 부장 : 결재 중인 글만 반려, 결재버튼 노출

위 사항을 보면 계급과 결재 상태를 보고 노출 여부를 결정짓고 있음을 알 수 있습니다! 하지만 내 임시 저장한 글에서는 결재 버튼이 보여야 겠죠? 잊지 말고 참고해 주도록 합니다.

1-11. Mapper

-- 수정 전 쿼리
<select id="getAppInfo" resultMap="App">
    select
        eaa.app_seq,
        eaa.app_title,
        eaa.app_content,
        eaa.reg_date,
        decode(eaa.app_status,'A','결재 대기','B','결재 중','C','결재 완료','W','임시 저장','X','반려') app_status,
        eamw.mem_name writer_name,
        eama.mem_name apper_name,
        eaa.writer_seq
    from e_approval_app eaa
    left join e_approval_member eamw on eaa.writer_seq = eamw.mem_seq
    left join e_approval_member eama on eaa.apper_seq = eama.mem_seq
    where eaa.app_seq = #{seq}
</select>

-- 수정 후 코드
<result column="WRITER_ID" property="writerId" />
-- ...
<select id="getAppInfo" resultMap="App">
    select
        eaa.app_seq,
        eaa.app_title,
        eaa.app_content,
        eaa.reg_date,
        decode(eaa.app_status,'A','결재 대기','B','결재 중','C','결재 완료','W','임시 저장','X','반려') app_status,
        eamw.mem_name writer_name,
        eama.mem_name apper_name,
        eaa.writer_seq,
        eamw.id writer_id -- 추가
    from e_approval_app eaa
    left join e_approval_member eamw on eaa.writer_seq = eamw.mem_seq
    left join e_approval_member eama on eaa.apper_seq = eama.mem_seq
    where eaa.app_seq = #{seq}
</select>

글쓴이의 ID를 출력 목록에 추가해주도록 합니다.

1-12. appPage.jsp

<form id="appPrcForm">
    <label for='seqU'>번호: </label>
    <input type="text" id="seqU" name="appSeq" value="${appInfo.appSeq }" readonly>
    <label for="writerU">작성자 : </label>
    <input type="text" id="writerU" name="writer" value="${appInfo.writerName }" readonly>
    <label for="appTitleU">제목 : </label>
    <input type="text" id="appTitleU" name="appTitle" value="${appInfo.appTitle }" readonly>
    <label for="contentU">내용</label>
    <textarea id="contentU" name="appContent" readonly>${appInfo.appContent }</textarea>
    <button id="returnBtn">반려</button>
    <button id="appBtn">결재</button>
    <button id="uptBtn" style="display:none;">수정</button>
    <input type="hidden" id="appStatusU"  name="appStatus" value="${appInfo.appStatus }">
    <!-- 추가 -->
    <input type="hidden" id="apperPstU" value="${sessionPst }">
    <input type="hidden" id="writerIdU" value="${appInfo.writerId }">
    <input type="hidden" id="apperIdU" name="id" value="${sessionId }">
</form>

 

1-13. JQuery

$(function(){

    var sttVal = $("#appStatusU").val();
    var apperPst = $("#apperPstU").val();
    var writerId = $("#writerIdU").val();
    var apperId = $("#apperIdU").val();

    // 체크박스 코드

    if(writerId == apperId && sttVal == '임시 저장'){
        $("#returnBtn").hide();
        $("#appBtn").show();
    } else if(writerId == apperId && sttVal == '반려'){
        $("#returnBtn").hide();
        $("#appBtn").show();
        $("#uptBtn").show();
    } else if(apperPst == '과장' && sttVal == '결재 대기'){
        $("#returnBtn").show();
        $("#appBtn").show();
    } else if(apperPst == '부장' && sttVal == '결재 중'){
        $("#returnBtn").show();
        $("#appBtn").show();
    } else {
        $("#returnBtn").hide();
        $("#appBtn").hide();
    }
    
    // 버튼 제어 코드

})

코드를 설명하겠습니다. jsp에서 추가해준 접속자의 직급(#apperPstU), 접속자의 ID(#apperIdU), 글쓴이의 ID(#writerIdU)의 value를 var 변수에 할당해준 뒤, 각각을 비교해도록 합니다. 본인의 임시저장 글은 두 ID가 같은지, 결재 상태가 임시 저장인지 체크하고, 본인의 반려당한 글은 두 ID가 같은지, 결재 상태가 반려인지 체크하고, 나머지는 각 직급에 맞게 결재 상태를 같이 비교합니다. 그리고 그 외에는 두 버튼 모두 숨겨주도록 합니다.

1-14. 결과물

부장
과장
대리

단계별로 설명하다보니 내용이 길어져서 히스토리 부분은 다음 시간에 구현하도록 하겠습니다. 빠잇~!

 

후기

정말 이해가 안 가는 부분에서 시간을 많이 잡아 먹었습니다 ㅠㅠ. 등록과 임시저장처럼 <button onclick="함수()"> 를 이용해서 반려와 결재 버튼 기능을 수행하려고 했는데 자꾸 post 방식이 아니라 get 방식으로 작동이 돼서 방식을 바꿀 수밖에 없었습니다.... 개인적으로 function 함수() ▶ <button onclick="함수()"> 방식을 선호하기에 최대한 게시글과 같이 바꾸지 않고 그와 같은 방법으로 하려고 했습니다만.. 해결을 하지 못하고 다른 방안그로 구현하게 됐습니다...

구현하면 할 수록 중간중간 빠진 기능들이 보여서 그 때마다 구현하려고 노력하고 있습니다. 대신 포스팅 속도는 느려졌지만 완성도 있는 결과물을 향해 가고 있다고 믿고 있습니다. 

항상 응원해주고 지켜봐주셔서 감사합니다. 다음 시간에도 힘내서 코딩&포스팅 하겠습니다!
반응형
댓글