'Back-End/Spring'에 해당되는 글 102건

  1. 2019.07.02 게시판 만들기 (기본구조, 테이블 생성)
  2. 2019.07.02 Spring Editor (CKEditor, SummerNote) 사용 1
  3. 2019.07.01 Spring 이메일 보내기 1
  4. 2019.07.01 Spring xml bean property 정리
  5. 2019.06.30 jQuery 이벤트 바인딩
  6. 2019.06.28 드래그앤드롭, ajax 방식의 파일 업로드
  7. 2019.06.28 Spring 자바 코드 난독화 (Java Code Obfuscation)
  8. 2019.06.28 Spring 자바스크립트 난독화

게시판 만들기 (기본구조, 테이블 생성)

Back-End/Spring 2019. 7. 2. 12:24

-게시판의 주요 기능-


1. 기본 기능


ㄱ. 로그인 후 게시물 등록, 수정이 가능하도록 처리


ㄴ. 글쓰기 (스마트 에디터 적용, 태그 문자 처리, 공백 처리, 줄바꿈 처리)


ㄷ. 게시물 상세정보, 조회수 증가 처리


ㄹ. 게시물 수정


ㅁ. 게시물 삭제 (delete 방식)


ㅂ. 게시물 삭제 (update 방식)


ㅅ. 검색 기능


ㅇ. 페이지 나누기



2. 파일업로드 (ajax)


ㄱ. 게시판에 파일 첨부


ㄴ. 첨부파일 목록, 다운로드, 삭제


ㄷ. 수정화면에서 새로운 파일 올리기



3. 댓글 기능


ㄱ. 일반적인 방식으로 댓글쓰기 (RestController, REST 방식)

$.ajax( ) 함수 호출하여 insert

컨트롤러에서 뷰로 포워딩한 responseText를 html 태그에 출력


ㄴ. 컨트롤러에서 ArrayList json 형식으로 리턴받아 댓글 목록 출력 (list_json.do)


ㄷ. 목록에 댓글 갯수 표시


ㄹ. 댓글 페이지 나누기 (댓글 목록은 일반적인 방식으로 처리)


ㅁ. 비밀댓글 쓰기, 표시


ㅂ. REST 방식으로 댓글 쓰기 (insert_rest.do)

크롬 확장 프로그램을 이용한 입력 처리

{ "replytext" : "댓글", "replyer" : "kim", "bno" : "1", "secret_reply" : "n" }


ㅅ. REST 방식으로 댓글 목록 출력


ㅇ. REST 방식으로 댓글 상세 화면, 수정, 삭제 기능 구현



4. 페이지 나누기


- 페이지당 게시물수 : 10개


- 전체 게시물수 : 991개


- 몇 페이지? : 100


991 / 10 => 99.1 올림 => 100



- 페이지의 시작번호, 끝번호 계산


where rn between 1 and 10


1페이지 => 1 ~ 10

2페이지 => 11 ~ 20

.....

11페이지 => 101 ~ 110

57페이지 => 561 ~ 570

99페이지 => 981 ~ 990

100페이지 => 991 ~ 1000


시작번호 = (현재페이지 - 1) * 페이지당 게시물수 + 1


1페이지 => (1-1) * 10 + 1 => 1

2페이지 => (2-1) * 10 + 1 => 11

7페이지 => (7-1) * 10 + 1 => 61


끝번호 = 시작번호 + 페이지당 게시물수 - 1


1페이지 => 1 + 10 - 1 => 10

2페이지 => 11 + 10 -1 => 20


* 전체 페이지 블록수

전체 페이지 갯수 / 10

91 / 10 => 9.1 => 10개


 

예시 )


1    2    3    4    5    6    7    8    9    10    [다음]

[이전]    11    12    13    14    15    16    17    18    19    20    [다음]



현재 페이지가 속한 블록


(현재 페이지 - 1) / 페이지 블록 단위 + 1


1페이지 => 몇번째 블록? 1

(1-1) / 10 + 1 => 1


9페이지 => 1블록

(9-1) / 10 + 1 => 1


11페이지 => 2블록

(11-1) / 10 + 1 => 2


57페이지

(57-1) / 10 + 1 => 6


* 페이지 블록의 시작번호

(현재블록 - 1) * 블록단위 + 1

1블록 => (1-1) * 10 + 1 => 1

2블록 => (2-1) * 10 + 1 => 11

6블록 => (6-1) * 10 + 1 => 51


* 페이지 블록의 끝번호

블록 시작번호 + 블록단위 - 1;

1블록 => 1 + 10 - 1 => 10

2블록 => 11 + 10 - 1 => 20

6블록 => 51 + 10 - 1 => 60



-데이터베이스 게시판 테이블 만들기-



1
drop table board cascade constraints; //기존의 테이블과 중복되지 않도록 제약조건까지 모두 삭제
cs


1
2
3
4
5
6
7
8
9
create table board ( //테이블 생성
bno number not null, // 게시물 번호
title varchar2(200not null, // 제목
content varchar2(4000), // 내용
writer varchar2(50not null, // 작성자 아이디 (member테이블과 join할 예정)
regdate date default sysdate, // 작성 날짜 (기본값으로 현재 시간이 들어가게됨)
viewcnt number default 0, // 조회수 (기본값이 0이기 때문에 0부터 시작)
primary key(bno) //기본키는 게시물 번호로 설정함
);
cs



1
2
insert into board (bno,title,content,writer) values
((select nvl(max(bno)+1,1)from board),'제목','내용','pard');
//게시물의 번호를 시퀀스를 이용해도 되지만 객체를 따로 관리해야 하기때문에
//서브쿼리를 작성하여서 관리
기본적으로 board에서 가장 큰 게시글 번호에서 1을 더하거나, 값이 없을때 (초기값) 은 1을 준다는 쿼리이다.
cs


1
commit; //작업을 완료시키는 쿼리
cs


'Back-End > Spring' 카테고리의 다른 글

게시판 만들기 (게시글 쓰기)  (0) 2019.07.02
게시판 만들기 (게시글 목록)  (0) 2019.07.02
Spring Editor (CKEditor, SummerNote) 사용  (1) 2019.07.02
Spring 이메일 보내기  (1) 2019.07.01
Spring xml bean property 정리  (0) 2019.07.01
:

Spring Editor (CKEditor, SummerNote) 사용

Back-End/Spring 2019. 7. 2. 11:29

Smart Editor

 

WYSIWYG Editor (위지윅 에디터, whar you see is what you ger)

 

- 사용자가 현재 화면에서 보고 있는 내용과 동일한 html code를 생성하는 에디터

 

- 네이버, 다음 에디터, CKEditor, SummerNote 등

 

 



  CKEditor과 SummerNote의 차이점


  CKEditor : 이미지 파일은 디렉토리에 저장, 테이블에는 링크만 저장


  Summernote : 이미지를 테이블에 저장 (이미지를 테이블에 저장하면 DB가 과부하가 걸릴 수 있다.)

 

 

가. CKEditor

 

- http://ckeditor.com

 

- 자바스크립트 기반 위지윅 웹에디터, 쉬운 이식, 웹사이트 구축언어가 asp든, php든 관계없이 도입하기가 용이하다.

 

- 현재 CKEditor5 버전이 최신 버전이지만 여기서는 안정화된 버전인 CKEditor 4.11.2 버전으로 실습함

 

- 이미지 업로드를 위해서는 별도의 작업이 필요함 (컨트롤러를 미리 호출하는 등의 작업이 필요..)

 

 

 

-다운로드 방법-

 

1. https://ckeditor.com/ckeditor-4/download/ 접속

 

 

2. Standard Package 다운로드

 

 

 

3. 다운로드 후 압축을 풀고 ckeditor 디렉토리를 views에 붙인다.

 

 

 

 

 

- ckeditor 실습 예제 -

 

  
  view 하위의 디렉토리들은 기본적으로 selvlet으로 인식이 된다.


  그렇기 때문에 리소스로 등록을 하지 않으면 링크가 되지 않고 404에러가 발생을 하게 된다.


  그렇기 때문에 servlet-context.xml에 리소스 매핑을 해주어야 한다.

 

1. servlet-context.xml에 리소스 매핑을 추가

1
<resources location="/WEB-INF/views/ckeditor/" mapping="/ckeditor/**"></resources>
cs

 

 

2. ckeditor.js 참조 (ckeditor을 붙이고 싶은 파일로 이동해서 태그를 넣으면 된다)

1
<script src = "${path}/ckeditor/ckeditor.js"></script>
cs

 

 

3. ckeditor를 적용할 태그에 작성

(WEB-INF/views/shop/product_write.jsp 와 product_edit.jsp 에 적용해보기)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<div style = "width:800px;">
내용
<textarea id = "description" name = "description" rows = "5" cols = "80"
placeholder = "상품설명을 입력하세요"></textarea> //이런 textarea가 있을때 주로 스마트에디터를 많이 사용
<!--textarea를 스마트에디터로 변경함--!>
<script>
//CKEDITOR.replace("description"); //태그의 id
//이미지 업로드를 할 경우
CKEDITOR.replace("description",{
 
//CKEDITOR.replace와 id("description")를 잘 적어주면 그 태그가 smart editor 스타일로 바뀌게 된다.
 
    filebrowserUploadUrl : "${path}/imageUpload.do"
 
//파일을 업로드 해야하기 때문에 filebrowserUploadUrl을 사용하고, 서버쪽에 코드를 완성해주어야 한다.
 
});
</script>
</div>    
cs

 

 

4. product_write.jsp 에 ckeditor을 적용하기 위한 코드를 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- views/shop/product_write.jsp -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
 
<!-- ckeditor 사용을 위해 js 파일 연결 -->
<script src="${path}/ckeditor/ckeditor.js"></script>
 
</head>
<body>
<%@ include file="../include/admin_menu.jsp" %>
 
============중간생략==========================
 
<tr>
        <td>상품설명</td>
        <td><textarea rows="5" cols="60" 
            name="description" id="description"></textarea>
 
<script>
//id가 description인 태그에 ckeditor를 적용시킴
//이미지 업로드 안됨
CKEDITOR.replace("description",{
    filebrowserUploadUrl : "${path}/imageUpload.do"
}); //이미지 업로드 기능을 추가하기위한 코드
</script>
            
        </td>
    </tr>
    <tr>
        <td>상품이미지</td>
        <td>
            <input type="file" name="file1" id="file1"
        </td>
    </tr>
cs

 

 

 

5. ImageUploadController.java (컨트롤러)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.example.spring02.controller.upload;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
 
@Controller // 컨트롤러 어노테이션
public class ImageUploadController {
 
    // 컨트롤러클래스의 로그를 출력
    private static final Logger logger = LoggerFactory.getLogger(ImageUploadController.class);
 
    // 이미지 업로드
    // product_edit페이지에서 맵핑되는 메소드
    @RequestMapping("imageUpload.do")
 
    // 이미지를 저장하고, 불러오고, 업로드하기위해 매개변수를 선언
    public void imageUpload(HttpServletRequest request, HttpServletResponse response, @RequestParam MultipartFile upload)
//MultipartFile 타입은 ckedit에서 upload란 이름으로 저장하게 된다
            throws Exception {
 
        // 한글깨짐을 방지하기위해 문자셋 설정
        response.setCharacterEncoding("utf-8");
 
        // 마찬가지로 파라미터로 전달되는 response 객체의 한글 설정
        response.setContentType("text/html; charset=utf-8");
 
        // 업로드한 파일 이름
        String fileName = upload.getOriginalFilename();
 
        // 파일을 바이트 배열로 변환
        byte[] bytes = upload.getBytes();
 
        // 이미지를 업로드할 디렉토리(배포 디렉토리로 설정)
        String uploadPath = "D:\\work\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp1\\wtpwebapps\\spring02\\WEB-INF\\views\\images\\";
 
  프로젝트는 개발 디렉토리에 저장이 되는데 이미지를 업로드할 디렉토리를 개발 디렉토리로 설정하면 일일이 새로고침을 해주어야되서
 
불편하기 때문에 이미지를 업로드할 디렉토리를 배포 디렉토리로 설정한다.
        
OutputStream out = new FileOutputStream(new File(uploadPath + fileName));
 
        // 서버로 업로드
        // write메소드의 매개값으로 파일의 총 바이트를 매개값으로 준다.
        // 지정된 바이트를 출력 스트립에 쓴다 (출력하기 위해서)
        out.write(bytes);
 
        // 클라이언트에 결과 표시
        String callback = request.getParameter("CKEditorFuncNum");
 
        // 서버=>클라이언트로 텍스트 전송(자바스크립트 실행)
        PrintWriter printWriter = response.getWriter();
        String fileUrl = request.getContextPath() + "/images/" + fileName;
        printWriter.println("<script>window.parent.CKEDITOR.tools.callFunction(" + callback + ",'" + fileUrl
                + "','이미지가 업로드되었습니다.')" + "</script>");
        printWriter.flush();
    }
}
cs

 

 

만약에 에러가 발생할 경우

 

ckeditor / config.js 파일을 열고 마지막 라인에 추가

 

 config.filebrowserUploadMethod = 'form';

 

 

 

ckeditor 적용 화면

 

 

 

나. SummerNote

 

- http://summernote.org (우리나라 개발자들이 만듦)

 

- 이미지를 텍스트 형식으로 저장함

 

- 적용 예시

 

 

1. http://summernote.org 접속해서 SummerNote 다운로드

 

 

 

 

2. 압축을 풀고 dist 디렉토리를 views에 붙이고 이름을 summernote로 변경한다.

 

 

 

3. servlet-context.xml에 리소스 매핑 추가

(location이 실제 경로이고, mapping가 url 상의 경로를 의미한다)

1
<resources location="/WEB-INF/views/summernote/" mapping="/summernote/**"></resources>
cs
 
4. product_write.jsp (상품정보 쓰기 페이지)에 summernote를 적용
 
 
4-1 적용시킬 코드를 찾기 위해 summernote 홈페이지로 이동하고,  Getting started를 클릭

 

 
4-2 스크롤바를 밑으로 내려서 Include js/css 안에 있는 코드를 복사한다. (summernote 라이브러리를 사용하기 위한 코드)

 

 
5. product_write.jsp (상품정보 쓰기 페이지)에 summernote를 적용 시키는 코드를 추가
(복사한 코드를 붙여넣기)
product_write.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- views/shop/product_write.jsp -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
 
<!-- include libraries(jQuery, bootstrap) -->
<!-- summernote홈페이지에서 받은 summernote를 사용하기 위한 코드를 추가 -->
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script> 
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script> 
 
<!-- include summernote css/js -->
<!-- 이 css와 js는 로컬에 있는 것들을 링크시킨 것이다. -->
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.js"></script>
 
 
 
<%-- <!-- ckeditor 사용을 위해 js 파일 연결 -->
같은 페이지에 스마트에디터를 동시에 2개를 사용할 수 없으므로 ckeditor은 주석처리 한다.
<script src="${path}/ckeditor/ckeditor.js"></script> --%>
 
</head>
<body>
<%@ include file="../include/admin_menu.jsp" %>
 
<script>
//id가 description인 것을 summernote 방식으로 적용하라는 의미이다.
//높이와 넓이를 설정하지 않으면 화면이 작게 나오기때문에 설정해주어야 한다.
$(function(){
    $("#description").summernote({
        height : 300,
        width : 800
    });
});
 
 
function product_write(){
    // 태그를 name으로 조회할 경우
    //var product_name=document.form1.product_name.value;
    // 태그를 id로 조회할 경우
    var product_name=$("#product_name").val();
    var price=$("#price").val();
    var description=$("#description").val();
    if(product_name==""){ //빈값이면
        alert("상품이름을 입력하세요"); 
        $("#product_name").focus(); //입력포커스 이동
        return//함수 종료, 폼 데이터를 제출하지 않음
    }
    if(price==""){
        alert("가격을 입력하세요");
        $("#price").focus();
        return;
    }
/*     if(description==""){
        alert("상품 설명을 입력하세요");
        $("#description").focus();
        return;
    } */
    //폼 데이터를 받을 주소
    document.form1.action="${path}/shop/product/insert.do";
    //폼 데이터를 서버에 전송
    document.form1.submit();
}
</script>
 
 
<h2>상품 등록</h2>
<form name="form1" method="post"
    enctype="multipart/form-data">
<table>
    <tr>
        <td>상품명</td>
        <td><input name="product_name" id="product_name"></td>
    </tr>
    <tr>
        <td>가격</td>
        <td><input name="price" id="price"></td>
    </tr>
    <tr>
        <td>상품설명</td>
        <td><textarea rows="5" cols="60" 
            name="description" id="description"></textarea>
<script>
//위쪽과 마찬가지로 같은페이지에서 스마트에디터를 동시에 2개를 사용할 수 없으므로 주석처리 한다.
//id가 description인 태그에 ckeditor를 적용시킴
//CKEDITOR.replace("description"); //이미지 업로드 안됨
/* CKEDITOR.replace("description",{
    filebrowserUploadUrl : "${path}/imageUpload.do"
}); */
</script>            
        </td>
    </tr>
    <tr>
        <td>상품이미지</td>
        <td>
            <input type="file" name="file1" id="file1"
        </td>
    </tr>
    <tr>
        <td colspan="2" align="center">
            <input type="button" value="등록" 
                onclick="javascript:product_write()">
            <input type="button" value="목록"
onclick="location.href='${path}/shop/product/list.do'">
        </td>
    </tr>
</table>    
</form>
 
</body>
</html>
cs

 

 

 

summernote 적용 화면

 

 

아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

'Back-End > Spring' 카테고리의 다른 글

게시판 만들기 (게시글 목록)  (0) 2019.07.02
게시판 만들기 (기본구조, 테이블 생성)  (0) 2019.07.02
Spring 이메일 보내기  (1) 2019.07.01
Spring xml bean property 정리  (0) 2019.07.01
jQuery 이벤트 바인딩  (0) 2019.06.30
:

Spring 이메일 보내기

Back-End/Spring 2019. 7. 1. 15:54

-이메일 서비스 구축 방법-

 

이메일 발송을 위해서는 메일 서버가 필요

 

 

 
  * 서버 구축 방법 *


  - 자체 구축


  - 포털사이트에서 제공하는 smtp(Simple Mail Transfer Protocol) server 활용


  - gmail의 경우 : 내 계정 - 로그인 및 보안 - 기기 활동 및 보안관련 활동 - 보안 수준이 낮은 앱 허용 옵션을 사용으로 설정해야 함


  - 여기에서는 gmail을 활용할 예정

 

 

 

-실습 예제-

 

1) pom.xml에 라이브러리 추가

 

빌드가 잘 안될 경우 스프링의 버전을 조정할 필요가 있음

비슷한 이름의 라이브러리가 있으므로 artifactld (버전 정보를 생략한 jar파일의 이름)를 정확히 확인하고 추가해야 함

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- 이메일 발송 관련 라이브러리 -->
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>vax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
cs

 

 

 

2) root-context.xml 에 메일 발송을 위한 bean을 등록

(계정이 등록되어 있어야 하기 때문)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 이메일 발송 bean 설정 -->
    <bean id="mailSender" 
class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="smtp.gmail.com" /<!-- gmail을 사용 -->
        <property name="port" value="587" />
        <property name="username" value="이메일주소" />
        <property name="password" value="비밀번호" />
        <property name="javaMailProperties">
            <props>
                <prop key="mail.transport.protocol">smtp</prop>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.debug">true</prop>
            </props>
        </property>
    </bean>
</beans>
cs

 

 

 

3) EmailDTO.java 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.example.spring02.model.email;
 
public class EmailDTO {
    private String senderName;    //발신자 이름
    private String senderMail;    //발신자 이메일 주소
    private String receiveMail;    //수신자 이메일 주소
    private String subject;            //제목
    private String message;            //본문
    
    //getter,setter,toString
    public String getSenderName() {
        return senderName;
    }
    public void setSenderName(String senderName) {
        this.senderName = senderName;
    }
    public String getSenderMail() {
        return senderMail;
    }
    public void setSenderMail(String senderMail) {
        this.senderMail = senderMail;
    }
    public String getReceiveMail() {
        return receiveMail;
    }
    public void setReceiveMail(String receiveMail) {
        this.receiveMail = receiveMail;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    @Override
    public String toString() {
        return "EmailDTO [senderName=" + senderName + ", senderMail=" + senderMail + ", receiveMail=" + receiveMail
                + ", subject=" + subject + ", message=" + message + "]";
    }
    
}
 
cs

 

 

 

4) EmailService.java 만들기

1
2
3
4
5
6
7
package com.example.spring02.service.email;
 
import com.example.spring02.model.email.EmailDTO;
 
public interface EmailService {
    public void sendMail(EmailDTO dto);
}
cs

 

 

 

5)EmailServiceImpl.java 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.example.spring02.service.email;
 
import javax.inject.Inject;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
 
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
 
import com.example.spring02.model.email.EmailDTO;
 
@Service // 서비스 빈으로 등록
public class EmailServiceImpl implements EmailService {
 
    @Inject
    JavaMailSender mailSender; // root-context.xml에 설정한 bean, 의존성을 주입
 
    @Override
    public void sendMail(EmailDTO dto) {
        try {
            // 이메일 객체
            MimeMessage msg = mailSender.createMimeMessage();
 
            // 받는 사람을 설정 (수신자, 받는사람의 이메일 주소 객체를 생성해서 수신자 이메일주소를 담음)
            msg.addRecipient(RecipientType.TO, new InternetAddress(dto.getReceiveMail()));
 
            /*
             * createMimeMessage() : MimeMessage객체를 생성시킴 (이것을 이용해서 메시지를 구성한 뒤 메일 발송)
             * addRecipient() : 메시지의 발신자를 설정 InternetAddress() : 이메일 주소 getReceiveMail() :
             * 수신자 이메일 주소
             */
 
            // 보내는 사람(이메일주소+이름)
            // (발신자, 보내는 사람의 이메일 주소와 이름을 담음)
            // 이메일 발신자
            msg.addFrom(new InternetAddress[] { new InternetAddress(dto.getSenderMail(), dto.getSenderName()) });
 
            // 이메일 제목 (인코딩을 해야 한글이 깨지지 않음)
            msg.setSubject(dto.getSubject(), "utf-8");
            // 이메일 본문 (인코딩을 해야 한글이 깨지지 않음)
            msg.setText(dto.getMessage(), "utf-8");
 
//            html로 보낼 경우            
//            MimeMessage message = mailSender.createMimeMessage();
//            MimeMessageHelper helper 
//            = new MimeMessageHelper(message, true);
//            helper.setTo("test@host.com");
//            helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
 
            // 이메일 보내기
            mailSender.send(msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
cs

 

 

 

6) admin_menu.jsp 에 이메일 발송 하이퍼링크를 추가

1
<a href="${path}/email/write.do">이메일 발송</a> | 
cs

 

 

 

7) EmailController.java 만들기 (컨트롤러)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.example.spring02.controller.email;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
 
import com.example.spring02.model.email.EmailDTO;
import com.example.spring02.service.email.EmailService;
 
@Controller // 컨트롤러 어노테이션 선언
@RequestMapping("email/*"// 공통적인 매핑 주소
public class EmailController {
 
    @Inject
    EmailService emailService; // 서비스를 호출하기위한 의존성 주입
 
    @RequestMapping("write.do"// 이메일 쓰기를 누르면 이 메소드로 맵핑되어서
    public String write() {
        return "/email/write"// 다시 write jsp 페이지로 이동하고 jsp페이지에서 내용을 다 채운 뒤에 확인 버튼을 누르면 send.do로 넘어감
    }
 
    @RequestMapping("send.do"// 확인 (메일발송) 버튼을 누르면 맵핑되는 메소드
    public String send(@ModelAttribute EmailDTO dto, Model model) {
        try {
 
            emailService.sendMail(dto); // dto (메일관련 정보)를 sendMail에 저장함
            model.addAttribute("message""이메일이 발송되었습니다."); // 이메일이 발송되었다는 메시지를 출력시킨다.
 
        } catch (Exception e) {
            e.printStackTrace();
            model.addAttribute("message""이메일 발송 실패..."); // 이메일 발송이 실패되었다는 메시지를 출력
        }
        return "/email/write"// 실패했으므로 다시 write jsp 페이지로 이동함
    }
}
cs

 

 

 

8) write.jsp 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
</head>
<body>
<%@ include file="../include/admin_menu.jsp" %>
<h2>이메일 보내기</h2>
<form method="post" action="${path}/email/send.do"
<!-- post방식으로 자료를 컨트롤러로 보냄 -->
 
발신자 이름 : <input name="senderName"><br>
발신자 이메일 : <input name="senderMail"><br>
수신자 이메일 : <input name="receiveMail"><br>
제목 : <input name="subject"><br>
내용 : <textarea rows="5" cols="80" name="message"></textarea>
<br>
<input type="submit" value="전송">
</form>
<span style="color:red;">${message}</span>
 
</body>
</html>
cs

 

 

 

아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

:

Spring xml bean property 정리

Back-End/Spring 2019. 7. 1. 15:16

일반적인 bean 선언


<bean id = "testBean" class = "com.ljw.TestBean" />




id : spring container 에서 유일하게 식별할 수 있는 이름


class : 해당하는 bean의 full path (경로)




id대신 name 속성을 사용할 수 있음


<bean name = "testBean" class = "com.ljw.TestBean" />




facotry 클래스의 getInstace 를 통한 bean을 설정


<bean id = "testFactory" class = "com.ljw.TestFactory"

factory-method = "getInstance" />

factory-method : 해당 클래스의 객체를 반환해주는 메소드 (singleton 에서)




생성자를 통한 bean 설정


<bean id="testService" class="com.ljw.Service">
    <constructor-arg>
        <ref bean="testDao"/>
    </constructor-arg>
</bean>

<bean id="testDao" class="com.ljw.TestDao"/>
  
ref : reference, 즉 testDao id(혹은 name)를 갖는 bean을 생성자의 인자로 넘겨주겠다는 의미    

<bean id="testService" class="com.ljw.Service">
    <constructor-arg ref="testDao"/>
</bean>


이것 역시 위와 같은 의미

생성자에 특정 값을 넣어줄 때
<bean id="testService" class="com.ljw.Service">
    <constructor-arg>
        <value> 10  </value>
     </constructor-arg>
</bean>

혹은 다음과 같이 작성가능
<bean id="testService" class="com.ljw.Service">
    <constructor-arg value="10"/>
</bean>

<value type="long"> 3000 </value> 같이 value 값의 type을 지정해줄수도 있다(기본적으로 string으로 인식)
즉 생성자가 여러가지 유형이 있을경우 위와같이 type을 설정해주지 않으면 기본적으로 string type의 생성자를 먼저 고려하게됨


property bean 설정 방식(setXXX 함수 를 이용하여 bean 설정)

<bean id="testServcie" class="con.ljw.TestService" >
    <property name="testDao">
        <ref bean="implTestDao"/>
    </property>
</bean>

<bean id="implTestDao" class="con.ljw.ImplTestDao" />

property : TestService class의 setTestDao method를 의미

즉 위의 설정은 TestService class의 setTestDao 메소드를 호출하면서 인자 값으로 ImplTestDao 객체를 넘겨준다는 의미


<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/login/login.mw">loginController</prop>
            </props>
        </property>
    </bean>

props : java.util.properties 클래스로 key, value를 string type으로만 갖는다.
즉 위의 예는 SimpleUrlHandlerMapping 클스의  setMappings 메소드를통해 properties 객체를 생성하고
해당 properties 객체는 key="/login/login.mw", value = loginController를 갖고 있게된다.



Bean 객체 범위
<bean name="testDao" class="com.ljw.TestDao"/>

TestDao testDao1 = (TestDao)applicationContext.getBean("testDao");
TestDao testDao2 = (TestDao)applicationContext.getBean("testDao");
위 코드를 통해 생성된 testDao는 동일한 객체이다(스프링 컨테이너 내에서 빈 객체는 싱글턴)

bean scope를 명시하여 서로다른 객체로 생성이 가능한데 다음과 같다.

scope="singleon"  : 기본값이며 스프링 컨테이너당 하나의 빈 객체 생성
scope="prototype" : 빈은 사용할때마다 새로운 객체 생성
scope="request"    :  http 요청마다 새로운 객체 생성(WebApplicationContext에서 사용) 
scope="session"    :  세션마다 새로운 객체 생성(WebApplicationContext에서 사용)


<bean name="testDao" class="com.ljw.TestDao" scope="protytype" />
--> bean의 scope 속성값에 설정 하여 사용


list, map 등의 컬렉션 에대한 xml 태크가 있긴하지만 위에 정리된 부분만 봐도
spring xml에 대해 이해가 될거라 판단됨.



출처

http://jwlee1728.egloos.com/v/1805102

:

jQuery 이벤트 바인딩

Back-End/Spring 2019. 6. 30. 21:49

바인딩(Binding)이란?


서로 묶어서 연결해 준다는 의미이다. 예를 들어, 버튼이 하나 있는데 이 버튼을 클릭했을 때 click 이벤트가 발생한다고 가정했을때,


click이벤트를 함수 객체와 바인딩 (연결) 하면 이 click 이벤트가 발생했을 때 등록한 함수 객체가 실행된다.


즉, 사용자가 버튼을 클릭하면 이 함수가 실행된다.




특정 요소에서 발생하는 이벤트를 처리하기 위해서는 이벤트 핸들러(event handler) 함수를 작성해야만 한다.
이렇게 작성된 이벤트 핸들러를 특정 요소에 연결하는 것을 이벤트 바인딩(event binding)이라고 한다.

jQuery는 이벤트 바인딩을 위한 다양한 방법을 제공한다.

다음 예제는 id가 "btn"인 요소에 클릭(click) 이벤트 핸들러를 바인딩하는 다양한 방법이다.

$("#btn").click(function(event) { // 실행하고자 하는 jQuery 코드 });
$("#btn").bind("click", function(event) { // 실행하고자 하는 jQuery 코드 });
$("#btn").on("click", function(event) { // 실행하고자 하는 jQuery 코드 });
$("body").on({click: function(event) { // 실행하고자 하는 jQuery 코드 }}, "#btn");
$("body").on("click", "#btn", function(event) { // 실행하고자 하는 jQuery 코드 });

jQuery 1.7부터는 .bind()나 .click() 메소드를 사용해도, 내부적으로 .on() 메소드를 이용하여 이벤트 핸들러와 바인딩한다.

이벤트 처리의 발전

jQuery의 발전에 따라 이벤트를 처리하는 방법 역시 변해 왔다.
jQuery 1.0에서는 .bind() 메소드를 사용하여 이벤트 핸들러를 등록했다.
그 다음에는 .live() 메소드와 .delegate() 메소드를 거쳐, 현재는 .on() 메소드를 이용하여 이벤트를 처리하고 있다.

.on() 메소드

jQuery는 특정 요소에 이벤트 바인딩(event binding)하기 위해 .on() 메소드를 사용한다. jQuery 1.7부터 소개된 .on() 메소드는 다음과 같은 특징을 가진다.

  1. 선택한 요소에 어떤 타입의 이벤트라도 연결할 수 있다.
  2. 하나의 이벤트 핸들러에 여러 개의 이벤트를 동시에 연결할 수 있다.
  3. 선택한 요소에 여러 개의 이벤트 핸들러와 여러 개의 이벤트를 같이 연결할 수 있다.
  4. 사용자 지정 이벤트(custom event)를 위해 이벤트 핸들러로 데이터를 넘길 수 있다.
  5. 차후에 다루게 될 요소를 이벤트에 바인딩할 수 있다.

기본형

아래 예제는 요소를 클릭했을 때 알람창이 켜지는 예제이다.

$("p").on("click", function(){
 alert("문장이 클릭되었습니다.");
});


이벤트 핸들러 하나에 이벤트를 여러개 설정

.on() 메소드를 사용하면 하나의 이벤트 핸들러에 여러 개의 이벤트를 동시에 바인딩할 수 있다.

아래 예제는 <p> 요소에 mouseenter와 mouseleave 이벤트를 설정하였다.

$("p").on("mouseenter mouseleave", function() {
  $("div").append("마우스 커서가 문장 위로 들어오거나 빠져 나갔습니다.<br>");
});


또한, 하나의 요소에 여러 개의 이벤트 핸들러를 사용하여 여러 개의 이벤트를 같이 바인딩할 수도 있다.

$("p").on({ 
  click: function() {
    $("div").append("마우스가 문장을 클릭했습니다.<br>");
  },
  mouseenter: function() {
    $("div").append("마우스가 커서가 문장 위로 들어왔습니다.<br>");
  },
  mouseleave: function() {
    $("div").append("마우스가 커서가 문장을 빠져 나갔습니다.<br>");
  }
});


.off() 메소드

.off() 메소드는 더 이상 사용하지 않는 이벤트와의 바인딩(binding)을 제거한다.

$("#btn").on("click", function() {
  alert("버튼을 클릭했습니다.");
});
$("#btnBind").on("click", function() {
  $("#btn").on("click").text("버튼 클릭 가능");
});
$("#btnUnbind").on("click", function() {
  $("#btn").off("click").text("버튼 클릭 불가능");
});


.one() 메소드

.one() 메소드는 바인딩(binding)된 이벤트 핸들러가 한번만 실행되고 나서는, 더는 실행되지 않는다.

$("button").one("click", function() {
  $("div").append("이제 클릭이 되지 않습니다.<br>");
});


.one() 메소드는 on() 메소드와 같은 인수를 전달받는다.
따라서 여러 개의 이벤트 핸들러와 여러 개의 이벤트를 가질 수 있는 등 .on() 메소드와 같은 특징을 갖는다.


출처

http://www.devkuma.com/books/pages/232







:

드래그앤드롭, ajax 방식의 파일 업로드

Back-End/Spring 2019. 6. 28. 17:22

ajax (비동기적 방식)을 이용해서 드래그앤드롭을 이용해 파일업로드


이번에는 드래그해서 파일을 갖다놓으면 파일이 업로드되는 방식으로 할 예정



-실습 예제-


menu.jsp에 업로드 링크 코드를 추가

1
<a href="${path}/upload/uploadAjax">업로드(Ajax)</a> | 
cs


util 패키지를 추가하고, MediaUtils.java 파일을 만듦




MediaUtils.java


이미지와 이미지가 아닌 파일을 구분해서 업로드하고 섬네일을 만들예정


나머지 파일들은 업로드만 할 예정


그럼 구분을 해주어야 하는데 getMediaType( ) 메소드를 호출하게 되면 get( )안에 들어있는 이미지 형식이면 그림파일이고,


안들어있는 형식의 파일이면 일반파일로 생각해 구분할 예정.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.example.spring02.util;
 
import java.util.HashMap;
import java.util.Map;
 
import org.springframework.http.MediaType;
 
public class MediaUtils {
    private static Map<String,MediaType> mediaMap;
    
    //클래스를 로딩할 때 제일 먼저 실행되는 코드
    
    //파일을 업로드할때 해당되는 형식을 리턴하는 클래스
    
    //static로 만들어놓았기 때문에 이 부분은 처음부터 메모리에 올라가있는 상태이다.
    
    static {
        mediaMap = new HashMap<>(); //키와 값을 저장해야 하기 때문에 HashMap<>를 사용
        mediaMap.put("JPG",MediaType.IMAGE_JPEG); //JPG 값을 저장
        mediaMap.put("GIF",MediaType.IMAGE_GIF); //GIF 값을 저장
        mediaMap.put("PNG",MediaType.IMAGE_PNG); //PNG 값을 저장
    }
    
    public static MediaType getMediaType(String type) {
        // toUpperCase() 대문자로 변경
        return mediaMap.get(type.toUpperCase()); //mediaMap안에 저장되어 있는 형식 (jpg,gif,png)이면 그림파일, 아니면 일반파일로 구분함
    }    //toUpperCase() 메소드는 대문자로 바꿔주는 메소드
}
cs



util.UploadFileUtils.java


 - 파일 업로드를 할 때 파일의 이름이 중복되지 않도록 하기 위해 uuid를 사용했음


 - uuid는 16바이트 숫자로 구성되며 중복가능성이 없다고 보장할 수는 없으나 거의 중복이 없다고 본다.


 - uuid는 밀리세컨드 + db시퀀스로 구성되며 16바이트 (128비트), 32개의 십육진수로 표현, 총 36개 문자 (32개 문자와 4개의 하이픈)


   8 - 4 - 4 - 4 - 12


예) 550e8400-e29b-41d4-a716-446655440000

     340,282,366,920,938,463,463,374,607,431,768,211,456개의 사용 가능한 UUID를 만들 수 있다.



UploadFileUtils.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package com.example.spring02.util;
 
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
 
public class UploadFileUtils {
    //로깅을 위한 변수
    private static final Logger logger 
        = LoggerFactory.getLogger(UploadFileUtils.class);
 
    
    //업로드를 하면 이 메소드가 호출된다.
    //File name를 똑같이 쓰면 덮어쓰기가 될 수 있으므로
    //uuid를 생성해서 파일이름 앞쪽에 붙여주어서 파일이름이 서로 중복되지 않게끔 한다.
    
    public static String uploadFile(String uploadPath
            , String originalName, byte[] fileData) 
                    throws Exception {
        // uuid 발급, 랜덤한uuid를 만들어 uid에 저장
        UUID uid = UUID.randomUUID();
        
        //uuid를 추가한 파일 이름
        String savedName = uid.toString() + "_" + originalName;
        
        // 업로드할 디렉토리 생성 (월, 일 날짜별로 디렉토리를 만든다.)
        // calcPath는 년도, 월, 일이 출력되게하는 메소드이고, 밑에서 static으로 선언되었으므로 메모리에 제일 처음 올려져 있다.
        // calcpath에 업로드 경로를 매개값으로 줘서, 업로드한 날짜를 savedPath에 저장하고, target변수에 File
        
        String savedPath = calcPath(uploadPath);
        File target = new File(uploadPath 
                + savedPath, savedName);    //업로드경로와 저장경로에 저장한파일의 이름에 대한 File 객체를 생성한다.
        
        // 임시 디렉토리에 업로드된 파일을 지정된 디렉토리로 복사
        FileCopyUtils.copy(fileData, target); //target에 저장된 파일경로와 이름, 그리고 fileData(파일용량)을 복사
        
        // 파일의 확장자 검사
        // a.jpg / aaa.bbb.ccc.jpg
        String formatName = originalName.substring(
                originalName.lastIndexOf("."+ 1);
        //lastIndexOf() 메소드는 String오브젝트에서 "." 문자열부터 끝쪽 방향으로 문자열을 찾는다.
        //"."이 여러개 있을 수도 있으므로 마지막 "." 뒤쪽부터 확장자이다.
        //그러니까 파일의 확장자가 뭔지 찾기 위해서 "." 뒷부분의 문자를 검색한다는 뜻이다.
        
        String uploadedFileName = null//uploadedFileName의 초기값을 지정
        
        // 이미지 파일은 썸네일 사용
        // 타입을 집어넣으면 이미지인지 아닌지 확인이 가능하다.
        if (MediaUtils.getMediaType(formatName) != null) {
            // 만약 이미지 이면
            // 썸네일 생성 (해당 그림이 드래그하면 작게보임)
            uploadedFileName = makeThumbnail(uploadPath
                    , savedPath, savedName);
            
        } else {    //이미지 파일이 아니면 아이콘을 생성한다.
            uploadedFileName = makeIcon(uploadPath, savedPath
                    , savedName);
        }
        return uploadedFileName;
    }
    
    //아이콘 생성
    private static String makeIcon(String uploadPath
            , String path, String fileName) throws Exception {
        // 아이콘의 이름
        String iconName = uploadPath + path + File.separator 
                + fileName;
        // 아이콘 이름을 리턴
        // File.separatorChar : 디렉토리 구분자
        // 윈도우 \ , 유닉스(리눅스) /
        return iconName.substring(uploadPath.length())
                .replace(File.separatorChar, '/');
        //파일 이름이라고 생각하면 된다.
    }
    
    
    private static String makeThumbnail(String uploadPath
            , String path, String fileName) throws Exception {
        // 이미지를 읽기 위한 버퍼
        BufferedImage sourceImg = ImageIO.read(
                new File(uploadPath + path, fileName));
        // 100픽셀 단위의 썸네일 생성
        // 작은 썸네일이기 때문에 이미지의 크기를 줄여야 한다.
        // 높이가 100픽셀이면 가로 사이즈는 자동으로 지정된다.
        BufferedImage destImg = Scalr.resize(
                sourceImg, Scalr.Method.AUTOMATIC
                , Scalr.Mode.FIT_TO_HEIGHT, 100);
        
        
        // 썸네일의 이름
        // 썸네일에는 "s_" 를 붙인다.
        
        String thumbnailName = uploadPath + path 
        + File.separator + "s_" + fileName;
        
        File newFile = new File(thumbnailName); //섬네일의 경로를 newFile변수에 저장
        
        String formatName = fileName.substring
                fileName.lastIndexOf("."+ 1);
                //lastIndexOf() 메소드는 String오브젝트에서 "." 문자열부터 끝쪽 방향으로 문자열을 찾는다.
                //"."이 여러개 있을 수도 있으므로 마지막 "." 뒤쪽부터 확장자이다.
                //그러니까 파일의 확장자가 뭔지 찾기 위해서 "." 뒷부분의 문자를 검색한다는 뜻이다.
        
        
        // 썸네일 생성
        // 아까 사이즈를 조정한 이미지파일형식, 파일이름(대문자로바꿔서), 아까 섬네일의 경로를 저장한 newFile변수를 넣어 
        // write 메소드를 사용해 썸네일을 생성
        ImageIO.write(
                destImg, formatName.toUpperCase(), newFile);
        
        
        // 썸네일의 이름을 리턴함
        return thumbnailName.substring(
        uploadPath.length()).replace(File.separatorChar, '/');
        }
    
    
    private static String calcPath(String uploadPath) {
        Calendar cal = Calendar.getInstance();
        String yearPath = File.separator 
                + cal.get(Calendar.YEAR);
        
        // "월"이랑 "일"은 10보다 작을때가 있으므로 (1월,2월....은 01월, 02월 이런식으로 붙이기 위해)
        // 그러니까 자릿수를 맞춰주기 위해서 DecimalFormat를 사용
        
        String monthPath = yearPath + File.separator 
                + new DecimalFormat("00").format(
                        cal.get(Calendar.MONTH) + 1);
        String datePath = monthPath + File.separator 
                + new DecimalFormat("00").format(cal.get(
                        Calendar.DATE));
        
        //디렉토리를 생성
        makeDir(uploadPath, yearPath, monthPath, datePath);
        logger.info(datePath);
        return datePath;
    }
    
 
    private static void makeDir(
            
            // 위에서 makeDir을 호출할때는 매개변수가 4개 이지만, String뒤에 있는 ...이 가변사이즈 매개변수이기 
            // 때문에 호출시에 매개변수의 숫자가 많아도 호출시에 매개변수가 배열로 만들어져 paths로 다 들어가기 때문에 쌓일수 있다.
            // ex) paths 0번이 yearPath, 1번이 monthPath가 되고, 2번이 datePath가 된다.
            
            String uploadPath, String... paths) {
        //디렉토리가 존재하면 skip, (디렉토리가 기존에 존재하면 만들지 않는다는 뜻)
        if (new File(paths[paths.length - 1]).exists()) {
            return;
        }
        //디렉토리가 없을시에 디렉토리 생성 코드
        //paths 배열에 저장된 값들을 하나씩 path에 저장하고,
        //업로드
        for (String path : paths) {
            File dirPath = new File(uploadPath + path);
            if (!dirPath.exists()) {//디렉토리가 존재하지 않으면
                dirPath.mkdir(); // 디렉토리 생성, mkdir()메소드는 패스명이 나타내는 디렉토리를 생성하는 메소드.
            }
        }
    }
}
cs



pom.xml


이미지 썸네일을 만들어주는 라이브러리를 추가함

1
2
3
4
5
6
<!-- 이미지 썸네일을 만들어주는 라이브러리 -->
        <dependency>
            <groupId>org.imgscalr</groupId>
            <artifactId>imgscalr-lib</artifactId>
            <version>4.2</version>
        </dependency>
cs



menu.jsp (view)

1
<a href="${path}/upload/uploadAjax">업로드(Ajax)</a> | 
cs



AjaxUploadController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.example.spring02.controller.upload;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
 
import javax.annotation.Resource;
import javax.inject.Inject;
 
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
 
import com.example.spring02.service.board.BoardService;
import com.example.spring02.util.MediaUtils;
import com.example.spring02.util.UploadFileUtils;
 
@Controller
public class AjaxUploadController {
    // 로깅을 위한 변수
    private static final Logger logger = LoggerFactory.getLogger(AjaxUploadController.class);
    
    @Inject
    BoardService boardService;
 
    // 업로드 디렉토리 servlet-context.xml에 설정되어 있음
    @Resource(name = "uploadPath")
    String uploadPath;
 
    // 파일첨부 페이지로 이동
    @RequestMapping(value = "/upload/uploadAjax"
            method = RequestMethod.GET)
    public String uploadAjax() {
        return "/upload/uploadAjax";
    }
 
    // 업로드한 파일은 MultipartFile 변수에 저장됨
    @ResponseBody // json 형식으로 리턴
    @RequestMapping(value = "/upload/uploadAjax"
    method = RequestMethod.POST, produces = "text/plain;charset=utf-8")
    public ResponseEntity<String> uploadAjax(MultipartFile file) throws Exception {
        // 업로드한 파일 정보와 Http 상태 코드를 함께 리턴
        return new ResponseEntity<String>(
                UploadFileUtils.uploadFile(uploadPath, file.getOriginalFilename(), file.getBytes()), HttpStatus.OK);
    }
 
    // 이미지 표시 기능
    @ResponseBody // view가 아닌 data 리턴
    @RequestMapping("/upload/displayFile")
    public ResponseEntity<byte[]> displayFile(String fileName) 
            throws Exception {
        // 서버의 파일을 다운로드하기 위한 스트림
        InputStream in = null// java.io
        ResponseEntity<byte[]> entity = null;
        try {
            // 확장자 검사
            String formatName = fileName.substring(
                    fileName.lastIndexOf("."+ 1);
            MediaType mType = MediaUtils.getMediaType(formatName);
            // 헤더 구성 객체
            HttpHeaders headers = new HttpHeaders();
            // InputStream 생성
            in = new FileInputStream(uploadPath + fileName);
//            if (mType != null) { // 이미지 파일이면
//                headers.setContentType(mType);
//            } else { // 이미지가 아니면
                fileName = fileName.substring(
                        fileName.indexOf("_"+ 1);
                // 다운로드용 컨텐트 타입
                headers.setContentType(
                        MediaType.APPLICATION_OCTET_STREAM);
                // 큰 따옴표 내부에 " \" "
                // 바이트배열을 스트링으로
                // iso-8859-1 서유럽언어
                // new String(fileName.getBytes("utf-8"),"iso-8859-1")
                headers.add("Content-Disposition",
                        "attachment; filename=\"" 
                                + new String(
fileName.getBytes("utf-8"), "iso-8859-1"+ "\"");
                // headers.add("Content-Disposition"
                // ,"attachment; filename='"+fileName+"'");
//            }
            // 바이트배열, 헤더
            entity = new ResponseEntity<byte[]>(
                    IOUtils.toByteArray(in), headers, HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            entity = new ResponseEntity<byte[]>(
                    HttpStatus.BAD_REQUEST);
        } finally {
            if (in != null)
                in.close(); // 스트림 닫기
        }
        return entity;
    }
    
    @ResponseBody //뷰가 아닌 데이터를 리턴
    @RequestMapping(value="/upload/deleteFile"
        ,method=RequestMethod.POST)
    public ResponseEntity<String> deleteFile(String fileName){
        logger.info("fileName:"+fileName); 
        //확장자 검사
        String formatName=fileName.substring(
                fileName.lastIndexOf(".")+1);
        MediaType mType=MediaUtils.getMediaType(formatName);
        if(mType != null) { //이미지 파일이면 원본이미지 삭제
            String front=fileName.substring(012);
            String end=fileName.substring(14);
//         File.separatorChar : 유닉스 / 윈도우즈\    
            new File(uploadPath+(front+end).replace(
                    '/',File.separatorChar)).delete();
        }
        //원본 파일 삭제(이미지이면 썸네일 삭제)
        new File(uploadPath+fileName.replace(
                '/',File.separatorChar)).delete();
        //레코드 삭제
        boardService.deleteFile(fileName); 
        
        return new ResponseEntity<String>("deleted"
                ,HttpStatus.OK);
    }
}
cs



servlet-context.xml

1
2
3
4
5
    <!-- 파일업로드를 위한 디렉토리 설정 -->
    <!-- String uploadPath=new String("d:/upload"); -->
    <beans:bean id="uploadPath" class="java.lang.String">
        <beans:constructor-arg value="d:/upload" />
    </beans:bean>
cs

 


uploadAjax.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- views/upload/uploadAjax.jsp -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp" %>
<!-- ----------------------------------css파일 부분 ----------------------------------------------------------->
<style>
.fileDrop {
    width: 100%;
    height: 200px;
    border: 1px dotted blue;
}
small {
    margin-left:3px;
    font-weight: bold;
    color: gray;
}
</style>
<!-- ----------------------------------css파일 부분 ----------------------------------------------------------->
<script>
$(function(){
    //드래그 기본 효과를 막음
    $(".fileDrop").on("dragenter dragover"function(event){
        event.preventDefault(); //기본효과를 막는다.
    });
    //기본효과를 막지 않으면 파일 업로드를 할 시에 사진이 실행되어버리기 때문에 기본효과를 막아야 한다.
 
// event : jquery의 이벤트
// originalEvent : javascript의 이벤트
    $(".fileDrop").on("drop",function(event){
        //drop이 될 때 기본 효과를 막음
        event.preventDefault();
        //드래그된 파일의 정보
        
        //첨부파일 배열
        var files=event.originalEvent.dataTransfer.files; //드래그된 파일정보를 files변수에 저장
        var file=files[0]; //첫번째 첨부파일 (컨트롤을 누르고 파일을 여러개를 올릴수도 있기 때문에, 첫번째 첨부파일이라고 지정한다.)
        
        
    /*     -ajax란??-
        Asynchronous JavaScript and XML의 약자 입니다.
        javascript와 xml을 이용하여 비동기 통신을 하는 기능입니다.
        쉽게 말해서 새로고침 없이 새로 고침 효과를 볼 수 있는 기능 (실시간으로 변화하는 페이지..)
        ajax는 데이터를 갱신하는 곳에서 사용한다면 페이지 전환 없이 동적으로 변화하는 모습을 자연스럽게 구현할 수 있습니다.
        
        -동기식과 비동기식-
        
        동기식 방식 : 클라이언트가 서버에게 요청하고 응답이 올 때까지 기다리는 것.
        비동기식 방식 : 클라이언트가 서버에게 요청을 하고 응답이 오기 전까지 다른일을 할 수 있다. */
 
        //ajax로 전달할 폼 객체
        var formData=new FormData(); //폼 객체
        formData.append("file",file); //만들어진 폼 객체에 위에서 저장한 file를 ifle란 이름의 변수로 저장한다
        //서버에 파일 업로드(백그라운드에서 실행됨)
        
        //    processData : false => post 방식
        //    contentType : false => multipart/form-data로 처리됨
        
        
        //비동기적 방식으로 보낸다.
        $.ajax({
            type: "post"//post 방식으로 보냄
            url: "${path}/upload/uploadAjax"//보낼 url
            data: formData, //formData를 보냄
            dataType: "text",
            processData: false,
            contentType: false,
            success: function(data,status,req){
                //alert(data);
                console.log("data:"+data); //업로드된 파일 이름
                console.log("status:"+status); //성공,실패 여부
                console.log("req:"+req.status);//요청코드값
                var str="";
                if(checkImageType(data)){ //이미지 파일일 경우 밑에있는 checkImageType메소드에서 리턴한값으로 참, 거짓 판단
                    //이미지파일이 맞을 경우에 실행되는 구문
                    //파일이름으로 이미지링크를 거는 하이퍼링크를 건다.
 
str="<div><a href='${path}/upload/displayFile?fileName="
        +getImageLink(data)+"'>";
                            
str+="<img src='${path}/upload/displayFile?fileName="
        +data+"'></a>"//이미지 파일일때는 이미지 자체를 보여준다.
 
    }else//이미지가 아닌 경우 텍스트만 보여준다 (text파일이나 기타 응용파일같은 것들....)
    str="<div>";
    str+="<a href='${path}/upload/displayFile?fileName="
        +data+"'>"+getOriginalName(data)+"</a>";
        }
                str+="<span data-src="+data+">[삭제]</span></div>"//삭제링크를 클릭하면 파일이름을 보내게 된다.
                $(".uploadedList").append(str);
            }
        });
    });
    // 태그.on("이벤트","자손태그",이벤트핸들러)
    // data : "fileName="+$(this).attr("data-src")
    // 태그.attr("속성")
    // $("#userid").attr("type")
    
    
    //fileDrop 함수
    //첨부파일 삭제 함수
    $(".uploadedList").on("click","span",function(event){
        //현재 클릭한 태그
        //span태그를 click하면 deleteFile로 이동
        var that=$(this); //this는 클릭한 태그가 된다 (즉, span태그를 클릭핤 )
//data: "fileName="+$(this).attr("data-src"),        
        $.ajax({
            url: "${path}/upload/deleteFile",
            type: "post",
            data: {fileName: $(this).attr("data-src")},
            //deleteFile로 이동하면 data-src속성을 뽑아서
            //보낸다.
            dataType: "text",
            success: function(result){
                if(result=="deleted"){
            //클릭한 span 태그가 속한 div를 제거
                    that.parent("div").remove();
            //dete
                }
            }
        });
    });
    
    function getOriginalName(fileName){
        if(checkImageType(fileName)){ //이미지 파일이면 skip
            return;
        }
        
        var idx=fileName.indexOf("_")+1//uuid를 제외한 파일이름을 리턴함
        return fileName.substr(idx);
    }
    function getImageLink(fileName){
        if(!checkImageType(fileName)){//이미지 파일이 아니면 skip
            return//함수를 종료시킨다.
        }
        
        //    이미지 파일일 경우 연월일 경로와 s_를 제거해서 리턴시킨다.
        var front=fileName.substr(0,12);//연월일 경로
        var end=fileName.substr(14);// s_ 제거
        return front+end;
    }
    
    //이미지인지, 아닌지 체크해주는 메소드
    function checkImageType(fileName){
        // i : ignore case (대소문자 무관)
        var pattern = /jpg|png|jpeg/i; //정규표현식(i는 대소문자 무시하기 때문에 넣은것.) 
        return fileName.match(pattern); //규칙에 맞으면 true
        //그러니까 파일의 확장명을 검사해서 jpg,png,jpeg형식이 있으면 fileName과 매칭해서 true를 리턴한다.
    }
});
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>Ajax File Upload</h2>
<!-- 파일을 업로드할 영역 -->
<div class="fileDrop"></div>
<!-- 업로드된 파일 목록을 출력할 영역 -->
<div class="uploadedList"></div>
 
</body>
</html>
cs




'Back-End > Spring' 카테고리의 다른 글

Spring xml bean property 정리  (0) 2019.07.01
jQuery 이벤트 바인딩  (0) 2019.06.30
Spring 자바 코드 난독화 (Java Code Obfuscation)  (0) 2019.06.28
Spring 자바스크립트 난독화  (0) 2019.06.28
인터셉터 (Interceptor)  (0) 2019.06.27
:

Spring 자바 코드 난독화 (Java Code Obfuscation)

Back-End/Spring 2019. 6. 28. 14:25

-자바 코드 난독화 (Java Code Obfuscation)-

 

 



 
 - 자바 프로그램은 디컴파일 (decompile), 디스어셈블 (disassemble)이 가능하므로 코드 난독화가 필요함


 - 프로가드 (proguard) : 대표적인 바자 난독화 라이브러리


 - 변수명, method name을 읽기 어렵게 변환함


 - 난독화를 해도 근본적으로 디컴파일은 막기 어려움


 - Spring 프로젝트보다는 자바 프로젝트에 적합
   (war 파일보다는 jar 파일로 export 할 경우에 적합함, 어노테이션, xml 설정 등에는 난독화 적용이 어려움)


 - java 코드를 읽기 어렵게 변경하는 것.


 - 상용프로그램 같은 경우는 배포하기 전에 난독화를 한번 하고 배포를한다. (보안때문에)

 

 

자바 디컴파일러를 다운로드

http://mannaedu.com/bbs/board.php?bo_table=pds&wr_id=41&sfl=wr_subject&stx=%EC%9E%90%EB%B0%94&sop=and

 

 

jd-gui-0.3.6.windows.zip
다운로드

 

 

압축을 풀기 => jd-gui.exe 클릭 (클래스 파일을 주고 자바 소스파일을 얻어내는 프로그램)

 

 

프로그램을 실행하고 File => Open File를 클릭

 

 

 

디컴파일할 파일을 누른 후 열기 버튼을 누름 (마찬가지로 jar 파일도 확인가능)

 

 

 

 

class파일을 열면 그 class가 속해있는 프로젝트가 통째로 열리게 된다.

 

 

 

 

자바 코드 난독화 실습

 

-jad (자바 디컴파일러), 자바 실습소스

 

-자바 실습소스를 이클립스로 import 한 후 jar 파일로 export

 

-jad에서 export한 jar 파일을 열어서 디컴파일된 소스 코드 확인

 

-프로가드 사이트 : http://proguard.sourceforge.net

 

 

proguard 6.0.3 다운로드 주소 : https://sourceforge.net/projects/proguard/files/

 

 

jar 파일 준비 ( jsp 프로젝트보다는 java 프로젝트로 테스트하는 것이 더 좋음), jar 파일을 찾기 쉬운 경로에 미리 복사함

 

 

- 난독화 테스트할 java project 생성

 

- 프로젝트 이름 : java_test

 

 

-proguard 다운로드-

 

 

 

 

 

 

 

 

 

다운로드 받은 압축파일의 압축을 풀고, 압축을 푼 파일을 D드라이브로 이동시킨다.

 

 

 

 

-실습하기-

 

자바 프로젝트 생성 => Jumin.java 클래스 생성하고 아래 코드를 작성

 

Jumin.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package java_test2;
 
import java.util.Scanner;
 
public class Jumin {
 
    private String jumin; // 주민등록번호
    private int age; // 나이
    private char gender; // 성별
    private String strGender; // 성별저장
    private String nation; // 국가
 
    public Jumin() {
    }
 
    public void input() {
 
        Scanner scan = new Scanner(System.in); // 주민등록번호를 입력받기위해 Scanner객체 선언
        System.out.print("주민등록번호 : ");
        jumin = scan.nextLine(); // 입력받은 주민등록번호를 jumin변수에 저장
    }
 
    public void setAge() { // 나이를 저장하는 메소드
        int base = 0// 초기값을 0으로 선언
        gender = jumin.charAt(7); // index값은 항상 0부터 시작하므로 주민등록번호의 8번재값이 jumin에 저장
        switch (gender) {
 
        // gender에 저장된 숫자에 따라 다른 switch문이 실행됨
        case '1':
        case '2':
        case '5':
        case '6':
            base = 1900;
            break;
 
        case '3':
        case '4':
        case '7':
        case '8':
            base = 2000;
            break;
        }
 
        age = 2019 - (base + Integer.parseInt(jumin.substring(02)));
        // 나이를 계산하기 위해서 index의 0번째부터 4번째값까지를 리턴하고 base값과 더하고
        // 2019에서 그 값을 빼주면 현재 나이가 계산이된다.
        // ex) 나이가 28일때 2019-(1900+92)를 하면 27이된다. (만나이 이기 때문)
    }
 
    public void setNation() {
        // 주민등록 번호의 8번째 자리의 숫자의 값에따라 내국인과 내국인을 판별함.
 
        if (gender >= '1' && gender <= '4') {
            nation = "내국인";
        } else if (gender >= '5' && gender <= '8') {
            nation = "외국인";
        }
    }
 
    public void setStrGender() {
        // 주민등록 번호의 8번째 자리의 숫자의 값에따라 성별을 판별함.
        switch (gender) {
        case '1':
        case '3':
        case '5':
        case '7':
            strGender = "남";
            break;
        case '2':
        case '4':
        case '6':
        case '8':
            strGender = "여";
            break;
        }
    }
 
    public String toString() {
        // 입력한 주민등록번호로 판별된 데이터들을 취합해서 result에 저장하고,
        // result를 리턴.
        String result = "국적 :" + nation + "\n" + "나이:" + age + "\n" + "성별:" + strGender;
        return result;
    }
 
    public static void main(String arg[]) {
        Jumin ex = new Jumin(); // Jumin클래스를 사용하기 위해 ex변수에 Jumin 객체를 생성
        ex.input(); // 주민등록번호 입력 메소드 실행
        ex.setAge(); // 나이 저장 메소드 실행
        ex.setNation(); // 내, 외국 판별 메소드를 실행
        System.out.println(ex); // ex변수에 저장된 result를 출력함.
                                // 나머지 메소드들은 void이기 때문에 리턴값이 없음.
    }
}
 
cs

 

 

 

cmd창을 열고 d: => cd proguard6.0.3\lib => java -jar proguardgui.jar 을 입력

 

 

STS4로 돌아가서 아까 만든 프로젝트를 우클릭 => Export => Java => JAR file 실행

 

아래 그림과 같이 만듦

 

 

 

 

 

 

 

 

 

 

 

저장후 next => finsh 클릭,

 

 

 

 

바탕화면에 jar파일이 생성된것을 확인하고 아까 cmd로 실행한 ProGuard를 연다.

 

Input/Output => Add input... => jar파일 클릭 하고 ok를 클릭

 

 

 

 

input파일 추가를 완료했으므로 이 파일을 난독화 한 후에 출력할 output파일을 지정해야 한다.

 

Add output => 이름 output.jar로 한다. => OK 클릭

 

 

 

output.jar 파일이 지정되었으면 Next 버튼을 클릭하고 마지막에 Process! 버튼을 클릭함

 

클릭하면 난독화가 끝나고 패키징까지 되서 output.jar 파일이 만들어진다.

 

만들어진 output.jar 파일을 디컴파일러로 열어보면 변수이름과 메소드이름이 난독화가 되서 변수 이름이 a,b,c,d,e로 바뀐것을 확인할 수 있다.

 

실행은 정상적으로 된다.

 

Jumin.class (output.jar)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package java_test2;
 
import java.io.PrintStream;
import java.util.Scanner;
 
public class Jumin
{
  private String a; //변수 이름이 난독화되어서 a,b,c,d,e로 되었다.
  private int b;
  private char c;
  private String d;
  private String e;
  
  public String toString()
  {
    String str;
    return str = "국적 :" + this.e + "\n나이:" + this.b + "\n성별:" + this.d;
  }
  
  public static void main(String[] paramArrayOfString)
  {
    Object localObject = paramArrayOfString = new Jumin();
    Scanner localScanner = new Scanner(System.in);
    System.out.print("주민등록번호 : ");
    ((Jumin)localObject).a = localScanner.nextLine();
    localObject = paramArrayOfString;
    int i = 0;
    Object tmp42_41 = localObject;
    tmp42_41.c = tmp42_41.a.charAt(7);
    switch (((Jumin)localObject).c)
    {
    case '1'
    case '2'
    case '5'
    case '6'
      i = 1900;
      break;
    case '3'
    case '4'
    case '7'
    case '8'
      i = 2000;
    }
    ((Jumin)localObject).b = (2019 - (i + Integer.parseInt(((Jumin)localObject).a.substring(02))));
    localObject = paramArrayOfString;
    if ((paramArrayOfString.c >= '1'&& (((Jumin)localObject).c <= '4')) {
      ((Jumin)localObject).e = "내국인";
    } else if ((((Jumin)localObject).c >= '5'&& (((Jumin)localObject).c <= '8')) {
      ((Jumin)localObject).e = "외국인";
    }
    localObject = paramArrayOfString;
    switch (paramArrayOfString.c)
    {
    case '1'
    case '3'
    case '5'
    case '7'
      ((Jumin)localObject).d = "남";
      break;
    case '2'
    case '4'
    case '6'
    case '8'
      ((Jumin)localObject).d = "여";
    }
    System.out.println(paramArrayOfString);
  }
}
 
cs

 

아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

:

Spring 자바스크립트 난독화

Back-End/Spring 2019. 6. 28. 10:22

자바스크립트 난독화(Javascript Obfuscation)란?


자바스크립트는 클라이언트에서 실행되도록하는 언어인데, 사용자가 웹사이트에 접근하게 되면

해당 스크립트를 그대로 볼 수 있게 되는데, 이를 방지하고자 적용하는 기법.

변수명과 함수명 같은것들을 읽기 어렵게 바꾸는 기법. 암호화랑은 다르다. 읽기 어렵게만함

하지만 궂이 자바스크립트까지 난독화할 필요는 없다.


(그러니까 사용자가 자바스크립트 코드를 그대로 볼 수 없도록 하는 기법, 보안..문제 때문에 그런거 같음)



  자바스크립트 난독화 사이트


  http://dean.edwards.name/packer/





- 자바스크립트 난독화 방법 -


(이 난독화된 코드는 자바스크립트 코드이므로 실제 Spring에서 그대로 복사해서 사용할 수 있다.)


주의할점 : ${path} 처럼 경로가 설정된 것은 난독화사이트에서 어떤 경로가 설정된 것이지 제대로 알 수가 없기 때문에 제대로 실행이 안될 수도 있다.

              그렇기 때문에 ${path} 같은 것은 사용하지 않고, 원래 경로를 그대로 써준다.

              (또한, $코드는 EL 코드이지, 자바스크립트 코드가 아니기 때문에 에러가 발생한다.)


  - Base62 encode 방식 -


  Binary Data를 Text로 바꾸는 Encoding의 하나로써 Binary Data를 Character set에 영향을 받지 않는


  공통 ASCII 영역의 문자로만 이루어진 문자열로 바꾸는 Encoding이다.


  Base62를 글자 그대로 직역하면 62진법 이라는 뜻.





  - Shrink variables 방식 -


  변수를 알파벳처럼 단순 문자로 바꾸는 방식.





: