본문 바로가기

일경험

[국민취업지원제도 일경험프로그램 27일차] 게시판 이미지 다운로드 기능 완료, 넥사크로(NEXACRO) 시작

반응형

27일 차 특이사항

1. mapper에는 ;를 쓰면 안 된다. 오류남. 

2. https://kimfk567.tistory.com/39?category=1007471 이곳을 참고하여 첨부파일 다운로드 코드를 짜고 있다. 

3. 파일첨부 2개 하면 오류가 난다. 1개만 가능하다. pk 오류라는데 뭐가 문제일까? 

4. pk로 설정되어 있는 file_Seq가 반복문을 돌면서 중복으로 삽입되기 때문이다. 코드를 고쳐줬다. 

private static final String SAVE_PATH = "C:/Users/tmdgh/Desktop/img/";
	// 글쓰기 
	@RequestMapping("insert")
	public String insert(@RequestParam Map<String, Object> map, HttpServletRequest request, 
			MultipartHttpServletRequest mReq) throws IllegalStateException, IOException {
		
		int listSeq = sqlSession.selectOne("mapper.listSeq"); //  게시글 최신 번호를 가져온다.
		map.put("seq", listSeq);	// seq 값을 최신화 한다.
		int insert = service.insert(map); // 게시글을 저장한다. 

		int fileSeq = sqlSession.selectOne("mapper.fileSeq"); // 초기 값
		int currentFileSeq = fileSeq;
		
		Iterator<String> itr = mReq.getFileNames(); // 단일 여러개
		while (itr.hasNext()) {
		    MultipartFile mFile = mReq.getFile(itr.next());
		    
		    String realName = mFile.getOriginalFilename();
		    String saveName = System.currentTimeMillis() + "_" + realName;
		    
		    mFile.transferTo(new File(SAVE_PATH + saveName));
		    
		    Map<String, Object> fileMap = new HashMap<String, Object>();
		    fileMap.put("fileSeq", currentFileSeq); // 각 파일에 대해 동일한 값을 사용
		    fileMap.put("realName", realName);
		    fileMap.put("saveName", saveName);
		    fileMap.put("SAVE_PATH", SAVE_PATH);
		    fileMap.put("listSeq", listSeq);
		    
		    int fileinsert = service.fileinsert(fileMap); 
		    
		    // file_Seq 값을 다음 번호로 업데이트
		    currentFileSeq++;
		}	
		return "redirect:list";
	}

currentFileSeq++ : 첨부파일이 2개면 예를 들어 1번 파일은 1050, 2번 파일은 1051로 테이블에 삽입된다. 

 

게시판 첨부파일 다운로드

1. 컨트롤러 

//파일 다운로드 
	@RequestMapping("fileDown")
	public void fileDown(@RequestParam Map<String, Object> map, HttpServletResponse response) throws Exception{
		Map<String, Object> resultMap = service.selectFileInfo(map);
		String storedFileName = (String) resultMap.get("SAVE_NAME");
		String originalFileName = (String) resultMap.get("REAL_NAME");
		
		// 파일을 저장했던 위치에서 첨부파일을 읽어 byte[]형식으로 변환한다.
		byte fileByte[] = org.apache.commons.io.FileUtils.readFileToByteArray(new File("C:/Users/tmdgh/Desktop/img/"+storedFileName));
		
		response.setContentType("application/octet-stream");
		response.setContentLength(fileByte.length); 
		response.setHeader("Content-Disposition",  "attachment; fileName=\""+URLEncoder.encode(originalFileName, "UTF-8")+"\";");
		response.getOutputStream().write(fileByte); 
		response.getOutputStream().flush();
		response.getOutputStream().close();
	}

 

2. 매퍼  

<!-- 게시판 seq 가져오기 -->
	<select id="listSeq" resultType="int">
	 select nvl(max(seq), 0)+1 
	 from board_study
	</select>
	
	<!-- 이미지 게시판 fileSeq 가져오기 -->
	<select id="fileSeq" resultType="int">
	 select nvl(max(file_seq), 0)+1 
	 from file_study_table
	 order by file_seq
	</select>
	
	<!-- 파일 조회 -->
	<select id="selectFileList" parameterType="int" resultType="hashMap">
		SELECT 
			FILE_SEQ,
			REAL_NAME,
			SAVE_NAME
		FROM file_study_table
		WHERE LIST_SEQ = #{listSeq}
	</select>
	
	<!-- 파일 정보 조회 -->
	<select id="selectFileInfo" parameterType="hashMap" resultType="hashMap">
		SELECT 
			SAVE_NAME,
			REAL_NAME
		FROM file_study_table
		WHERE FILE_SEQ = #{fileSeq}
	</select>

 

3. 상세페이지 jsp  

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri = "http://java.sun.com/jsp/jstl/core" %>


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script>
	$(function(){
		
		$("#regBtn").click(function(){
			$("#frm").attr("action","insert").attr("method","post").submit();
		})
		
		$("#uptBtn").click(function(){
			$("#frm").attr("action","update").attr("method","post").submit();
		})
		
		var tmp=0;
		$("#fileAdd").click(function(){
			var file = "<input type=file name=file"+tmp+" id=file"+tmp+" onchange=checkFile(this)><input type=button id=delBtn"+tmp+" value='X' onclick=fncDelete(this)><br>";
			$("#fileDv").append(file);

			tmp++;
		})

	})
	// 삭제 버튼 클릭시 이전, 후 태그 삭제 
	function fncDelete(delBtn){
		$(delBtn).prev().remove();
		$(delBtn).next().remove();
		$(delBtn).remove();
	}
	
	// 이미지 픽셀(500*500) 체크 
	function checkFile(el) {
		
	    var file = el.files;
	    var reader = new FileReader();
	
	    // 파일 읽기가 완료되면 실행되는 이벤트 핸들러
	    reader.onload = function (e) {
	        var img = new Image();
	        img.src = e.target.result;
	
	        img.onload = function () {
	            // 이미지의 가로와 세로 차원을 검사
	            var maxWidth = 500;
	            var maxHeight = 500;
	
	            if (img.width > maxWidth || img.height > maxHeight) {
	                // 차원 초과시 경고후 해당 이미지의 차원도 보여줌
	                alert('이미지 차원은 500x500 픽셀 이하여야 합니다.\n\n' + '현재 이미지 차원: ' + img.width + 'x' + img.height + ' 픽셀');
	                el.value = ''; // 파일 입력 필드 초기화
	            }
	        };
	    };
	
	    if (file.length > 0) {
	        // 파일 읽기 시작
	        reader.readAsDataURL(file[0]);
	    }
	}
//onclick함수와 input hidden 태그 사용해서 다운로드 실행 
function fn_fileDown(fileSeq){
	var formObj = $("form[name='frm']");
	$("#fileSeq").attr("value", fileSeq);
	formObj.attr("action", "/board/fileDown");
	formObj.submit();
}
</script>
<style>
   	 body {
       display: flex;
       justify-content: center;
       align-items: center;
       height: 100vh;
       margin: 0;
   			}
</style>
</head>
<body>
	<form name = "frm" id = "frm" enctype="multipart/form-data"> 
		<input type = "hidden" name = "seq" id = "seq" value = "${detail.seq}"><br>
		<input type = "hidden" name = "fileSeq" id = "fileSeq" value = ""><br>
		작성자 : <input type = "text" name = "name" id = "name" value = "${detail.name}"><br> 
		아이디 : <input type = "text" name = "id" id = "id" value = "${detail.id}"><br>
		제목 : <input type = "text" name = "subject" id = "subject" value = "${detail.subject}"><br>
		내용 : <br>
		<textarea rows="10" cols="40" name = "content" id = "content">${detail.content}</textarea>
		<br>
		
		<c:if test="${empty detail }">
			<div id = "fileDv">
				<input type = "button" name = "fileAdd" id = "fileAdd" value = "파일추가"><br>
			</div>
			<input type = "button" name = "regBtn" id = "regBtn" value = "등록">
			
		</c:if>
		<c:if test="${not empty detail }">
			<input type = "button" name = "uptBtn" id = "uptBtn" value = "수정">
		</c:if><br>
		<span>첨부 파일</span>
		<div class="form-group" style="border: 1px solid #dbdbdb;">
			<c:forEach var="file" items="${file}">
				<a href="#" onclick="fn_fileDown('${file.FILE_SEQ}'); return false;">${file.REAL_NAME}</a><br>
			</c:forEach>
		</div>
	</form>
</body>
</html>

 

넥사크로 시작

1. http://support.tobesoft.co.kr/Support/?menu=home 회원가입하기 

2. developer x64 다운

3. 넥사크로 메뉴얼을 보면서 기능 조작해 보기

- http://docs.tobesoft.com/getting_started_nexacro_17_ko/c2d3c9d6024ea862

4. 넥사크로플랫폼 앱을 만드는 기본적인 방법은 프로젝트와 폼을 만들고 폼 안에 필요한 컴포넌트를 배치하는 것 

5. 컴포넌트가 뭐지? 재사용 가능한 코드 (버튼, 텍스트 상자, 그래프, 테이블)

6. 넥사크로 가이드라인을 따라서 Customer List Search를 만들었다. search 버튼을 누르면 데이터가 삽입된다. 스크립트는 직접 작성해야 된다. 컴포넌트를 이용하여 객체를 원하는 대로 그리는 것이 편리한 것 같다. 그런데 찾아보니 아주 쓰레기라고 하는데 왜 인지는 아직 잘 모르겠다. 오늘 처음 써봐서 뭐가 좋은지 나쁜지 모르겠다. 

느낀 점

게시판 이미지 첨부 유효성 검사, 이미지 업로드, 이미지 다운로드 기능을 구현했다. 수많은 방법들 중에서 이해가 잘되는 코드를 찾았다. 사람들은 여러 가지 코드로 문제를 해결하는데 그중에서도 이해하기 쉽고 좋은 코드가 따로 있다. 아무리 봐도 이해되지 않는 코드들이 많았다. 아마 내 코드도 그런 코드가 아닐까 싶다. 단순하지만 작동이 정확히 되는 코드가 가장 좋다고 한다. 좋은 코드를 많이 읽어봐야겠다. 넥사크로를 spring에 연결하는 것을 다음 주에 할 것 같다. 굉장히 불친절한 프로그램이다. 설명서가 따로 없다. 구글링을 해봐도 나오는 자료가 별로 없다. 정부전자시스템 중에 넥사크로로 개발된 것들이 많다고 한다. 사람들이 욕을 할 만큼 좋지 않은 프로그램이지만 프로젝트를 나가게 됐을 때 사용하는 경우가 있으니 알아두면 나쁠 것은 없다. 그러나 가장 중요한 프로그래밍 언어는 Java, javascirpt다. 넥사크로를 한번 경험해 본다고 생각하자. 

 

반응형