QR코드 생성 및 사용자 정보 추출 공통 모듈 추가
This commit is contained in:
parent
917d8d46f2
commit
8ec6f8a489
192
src/main/java/iams/nlib/user/service/QRCodeService.java
Normal file
192
src/main/java/iams/nlib/user/service/QRCodeService.java
Normal file
@ -0,0 +1,192 @@
|
||||
package iams.nlib.user.service;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.hsqldb.lib.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.qrcode.QRCodeWriter;
|
||||
|
||||
import egovframework.com.cmm.LoginVO;
|
||||
import egovframework.com.utl.sim.service.EgovFileScrty;
|
||||
import iams.nlib.dataapi.service.DataApi;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* @Class Name : QRCodeService.java
|
||||
*
|
||||
* @Description : QR 코드 생성 처리
|
||||
*
|
||||
*
|
||||
* @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* --------------------------------------------------------
|
||||
* ※ 참고 : 바코드 정보
|
||||
* --------------------------------------------------------
|
||||
* [Universal Product Code : UPC] : 1D 바코드
|
||||
* - UPC-A : 12자리 (6자리 제조사ID번호 + 5자리품목번호 + 1자리 체크 숫자)
|
||||
* - UPC-E : 8자리 (주로 작은 패키지용으로 사용)
|
||||
*
|
||||
* [European Article Number : EAN Codes]
|
||||
* - EAN-13(Most commonly), EAN-8, JAN-13, ISBN
|
||||
* - EAN-13 : UPC 코드와 유사, "o" + UPC-A코드
|
||||
*
|
||||
* [Code 128]
|
||||
* - 함축 고밀도 선형 코드로, 물류/배송에서 주문/유통 목적으로 주로 사용
|
||||
* - 아스키 128자 인코딩 가능
|
||||
*
|
||||
* [PDF417]
|
||||
* - 다중 1D 바코드가 다른 1D 바코드위에 쌓여서 구성되는 선형 바코드
|
||||
* - 일반적인 선형 바코드기기 사용 가능
|
||||
* - 여행 승차권,ID카드,물품목록 관리용으로 사용
|
||||
* - 체크숫자 대신 Reed-Solomon 오류 교정 방식 사용
|
||||
*
|
||||
* [QR Codes : Quick Response Code]
|
||||
* - 바코드 매트릭스 즉,2D 바코드로 가장 많이 쓰여지고 있는 바코드
|
||||
* - 제한된 공간에 많은 양의 정보를 담을 수 있음
|
||||
*
|
||||
* 라이브러리
|
||||
* - Barbecue : 오픈소스 자바 라이브러리, 1D바코드, PNG/GIF/JPEG/SVG 생성 기능
|
||||
* - Barcode4j : 오픈소스 라이브러리, 2D바코드 포멧 지원, DataMarix, PDF417
|
||||
* - ZXing(Zebra Crossing) : 오픈소스, 자바로 구현된 멀티포멧 1D/2D바코드 이미지 처리 라이브러리, QR코드 지원하는 주 자바 라이브러리 (본시스템에서 사용하는 LIB)
|
||||
* - QRGen : ZXing을 사용한 간단한 자바 QR코드 생성 API
|
||||
*
|
||||
*
|
||||
* @ ------------ -------- ---------------------------
|
||||
* @ 수정일 수정자 수정내용
|
||||
* @ ------------ -------- ---------------------------
|
||||
* @ 2021. 6. 25. KNKIM 최초 생성
|
||||
*
|
||||
*
|
||||
* @author 이씨플라자 * DIGITALSHIP KNKIM
|
||||
* @since 2021. 6. 25.
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
@Service("qrCodeService")
|
||||
public class QRCodeService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(QRCodeService.class);
|
||||
|
||||
/**
|
||||
* QR코드로 생성할 수 있는 최대문자열 바이트 길이
|
||||
*
|
||||
* QR코드로 생성할 수 있는 코드값은 다음과 같으나, 본 시스템 용도에 충분한 크기인 "2000"자로 크기를 제한한다.
|
||||
*
|
||||
* - Numeric only Max. 7,089 characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
|
||||
* - Alphanumeric Max. 4,296 characters (0–9, A–Z [upper-case only], space, $, %, *, +, -, ., /, :)
|
||||
* - Binary/byte Max. 2,953 characters (8-bit bytes) (23624 bits)
|
||||
*/
|
||||
public static final int MAX_QRTEXT_BYTES = 2000;
|
||||
|
||||
/**
|
||||
* 입력된 문자열에 대한 QR 2D 바코드를 BufferedImage 로 생성하여 리턴한다.
|
||||
*
|
||||
*
|
||||
* @param barcodeText
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static BufferedImage generateQRCodeImageByZxing(String barcodeText) throws Exception {
|
||||
|
||||
if(StringUtil.isEmpty(barcodeText)) {
|
||||
throw new Exception("QR 2D바코드로 생성할 문자 정보가 없습니다.");
|
||||
}
|
||||
|
||||
if(barcodeText.getBytes().length > MAX_QRTEXT_BYTES) {
|
||||
throw new Exception(String.format("QR 2D바코드로 생성할 문자의 길이는 %d 바이트를 초과할 수 없습니다.", MAX_QRTEXT_BYTES));
|
||||
}
|
||||
|
||||
QRCodeWriter barcodeWriter = new QRCodeWriter();
|
||||
BitMatrix bitMatrix = barcodeWriter.encode(barcodeText, BarcodeFormat.QR_CODE, 200, 200);
|
||||
|
||||
return MatrixToImageWriter.toBufferedImage(bitMatrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자정보를 가지고, QRCode 바코드를 BufferedImage 로 생성하여 리턴한다.
|
||||
*
|
||||
* (1) "사용자고유번호;이메일;이름;" 형식으로 문자열을 구성
|
||||
* (2) 앞의 (1)의 문자열을 암호화 처리
|
||||
* (3) 앞의 (2) 암호화 문자열로 QRCode 생성하여 BufferedImage형식으로 리턴
|
||||
*
|
||||
* @param loginVO
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static BufferedImage generateMemberQRCodeImage(LoginVO loginVO) throws Exception {
|
||||
|
||||
if(loginVO == null) {
|
||||
throw new Exception("QR 2D바코드로 생성할 사용자 정보가 없습니다.");
|
||||
}
|
||||
|
||||
if(StringUtil.isEmpty(loginVO.getUniqId())) {
|
||||
throw new Exception("QR 2D바코드로 생성에 필요한 사용자고유번호 정보가 없습니다.");
|
||||
}
|
||||
|
||||
if(StringUtil.isEmpty(loginVO.getEmail())) {
|
||||
throw new Exception("QR 2D바코드로 생성에 필요한 이메일 정보가 없습니다.");
|
||||
}
|
||||
|
||||
if(StringUtil.isEmpty(loginVO.getName())) {
|
||||
throw new Exception("QR 2D바코드로 생성에 필요한 이름 정보가 없습니다.");
|
||||
}
|
||||
|
||||
// (1) "사용자고유번호;이메일;이름;" 형식으로 문자열을 구성
|
||||
String barcodeText = String.format("%s;%s;%s;"
|
||||
, loginVO.getUniqId()
|
||||
, loginVO.getEmail()
|
||||
, loginVO.getName());
|
||||
log.debug("generateMemberQRCodeImage : barcodeText=" + barcodeText);
|
||||
|
||||
// (2) 앞의 (1)의 문자열을 암호화 처리
|
||||
String cryptedBarcodeText = EgovFileScrty.encodeBinary(barcodeText.getBytes());
|
||||
log.debug("generateMemberQRCodeImage : cryptedBarcodeText=" + cryptedBarcodeText);
|
||||
loginVO.setDn(cryptedBarcodeText);
|
||||
|
||||
// (3) 앞의 (2) 암호화 문자열로 QRCode 생성하여 BufferedImage형식으로 리턴
|
||||
return generateQRCodeImageByZxing(cryptedBarcodeText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 QR코드 추출 정보를 통해 사용자정보VO를 생성하여 리턴한다.
|
||||
*
|
||||
* @param encodedBarcodeText
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static LoginVO getMemberInfoFromQRCode(String encodedBarcodeText) throws Exception {
|
||||
|
||||
if(StringUtil.isEmpty(encodedBarcodeText)) {
|
||||
throw new Exception("사용자 QR코드 추출 정보가 정보가 없습니다.");
|
||||
}
|
||||
|
||||
log.debug("getMemberInfoFromQRCode : encodedBarcodeText=" + encodedBarcodeText);
|
||||
|
||||
String barcodeText = new String(EgovFileScrty.decodeBinary(encodedBarcodeText));
|
||||
log.debug("getMemberInfoFromQRCode : decodedBarcodeText=" + barcodeText);
|
||||
|
||||
String[] split = barcodeText.split(";");
|
||||
|
||||
if(split.length < 3) {
|
||||
throw new Exception("사용자 QR코드 추출 정보가 적합하지 않습니다.");
|
||||
}
|
||||
|
||||
LoginVO info = new LoginVO();
|
||||
|
||||
info.setUniqId(split[0]);
|
||||
info.setEmail(split[1]);
|
||||
info.setName(split[2]);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
101
src/main/java/iams/nlib/user/web/BarcodeController.java
Normal file
101
src/main/java/iams/nlib/user/web/BarcodeController.java
Normal file
@ -0,0 +1,101 @@
|
||||
package iams.nlib.user.web;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import egovframework.com.cmm.LoginVO;
|
||||
import iams.nlib.user.service.QRCodeService;
|
||||
import iams.nlib.util.StringUtil;
|
||||
|
||||
@Controller
|
||||
public class BarcodeController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BarcodeController.class);
|
||||
|
||||
/** QRCodeService */
|
||||
@Resource(name = "qrCodeService")
|
||||
private QRCodeService qrCodeService;
|
||||
|
||||
/**
|
||||
* 샘플 : 회원정보를 입력받을 수 있는 폼을 구성하여 표출한다.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value="/sample/barcode/getMemberQRCodeForm.do", produces=MediaType.IMAGE_JPEG_VALUE)
|
||||
public String getMemberQRCodeForm(@ModelAttribute("loginVO") LoginVO loginVO, ModelMap model) throws Exception {
|
||||
|
||||
log.debug("getMemberQRCodeForm : loginVO=" + loginVO.toString());
|
||||
|
||||
if(StringUtil.isEmpty(loginVO.getUniqId())) loginVO.setUniqId("USER0001-000001");
|
||||
if(StringUtil.isEmpty(loginVO.getEmail())) loginVO.setEmail("myid@digitalship.co.kr");
|
||||
if(StringUtil.isEmpty(loginVO.getName())) loginVO.setName("홍길동");
|
||||
|
||||
model.addAttribute("loginVO", loginVO);
|
||||
|
||||
return "iams/nlib/sample/getMemberInfoFromQRCode";
|
||||
}
|
||||
|
||||
/**
|
||||
* 샘플 : 입력받은 회원정보를 가지고 QR 2D 바코드를 생성하는 예를 보여준다.
|
||||
* 결과값은 JPG 바코드 이미지 이다. (Zxing Lib 사용)
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value="/sample/barcode/getMemberQRCode.do", produces=MediaType.IMAGE_JPEG_VALUE)
|
||||
public @ResponseBody byte[] getMemberQRCode(@ModelAttribute("loginVO") LoginVO loginVO, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
||||
log.debug("getMemberQRCode : loginVO=" + loginVO.toString());
|
||||
|
||||
BufferedImage bufferedImage = qrCodeService.generateMemberQRCodeImage(loginVO);
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ImageIO.write( bufferedImage , "jpg", byteArrayOutputStream);
|
||||
byte[] bs = byteArrayOutputStream.toByteArray();
|
||||
response.setContentLength(bs.length);
|
||||
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 샘플 : 회원정보 QR 2D 바코드 내용을 입력받아 사용자VO 정보를 추출하는 예를 보여준다.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value="/sample/barcode/getMemberInfoFromQRCode.do")
|
||||
public String getMemberInfoFromQRCode(@RequestParam String barcodeText, ModelMap model) throws Exception {
|
||||
|
||||
log.debug("getMemberInfoFromQRCode : barcodeText=" + barcodeText);
|
||||
|
||||
LoginVO loginVO = qrCodeService.getMemberInfoFromQRCode(barcodeText);
|
||||
log.debug("getMemberInfoFromQRCode : loginVO=" + loginVO.toString());
|
||||
|
||||
model.addAttribute("loginVO", loginVO);
|
||||
|
||||
return "iams/nlib/sample/getMemberInfoFromQRCode";
|
||||
}
|
||||
}
|
||||
@ -142,3 +142,16 @@ ldap.password =secret
|
||||
|
||||
#\uc57d\ub3c4\uad00\ub9ac Kakao \uac1c\ubc1c\uc790 appkey \ubc1c\uae09 \ubc1b\uc544 \ub4f1\ub85d\ud574\uc11c \uae30\uc785 (\uce74\uce74\uc624\uac1c\ubc1c Dev \uc571\uad00\ub9ac \ub0b4\uc5d0\uc11c \ub3c4\uba54\uc778 \ub4f1\ub85d \ud544\uc694)
|
||||
roughMap.appkey =b0fdac4f718d71a02d796f8fe3e12987
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# \uc554\ud638\ud654 \ucc98\ub9ac (DIGITALSHIP 2021.06.28)
|
||||
#-----------------------------------------------------------------------
|
||||
# \ube44\ubc00\ubc88\ud638 \ub2e8\ubc29\ud5a5 \uc554\ud638\ud654 \ucc98\ub9ac \uc54c\uace0\ub9ac\uc998
|
||||
crypto.password.algorithm=SHA-256
|
||||
crypto.password.hashed=gdyYs/IZqY86VcWhT8emCYfqY1ahw2vtLG+/FzNqtrQ=
|
||||
|
||||
# \uac1c\uc778\uc815\ubcf4 \uc591\ubc29\ud5a5 \uc554\ud638\ud654 \ucc98\ub9ac \uc54c\uace0\ub9ac\uc998
|
||||
|
||||
crypto.algorithm=Aria
|
||||
|
||||
|
||||
|
||||
@ -19,6 +19,9 @@ link:hover { color: #000000; text-decoration: none; }
|
||||
<li><strong class="left_title_strong"><strong class="top_title_strong"><a href="${pageContext.request.contextPath}/sample/getSampleInfoForm.do" target="_content">통신API</a></strong></strong></li>
|
||||
|
||||
<li><strong class="left_title_strong"><strong class="top_title_strong"><a href="#" onclick="javascript:alert('준비중입니다.');return false;" target="_content">로그인</a></strong></strong></li>
|
||||
|
||||
<li><strong class="left_title_strong"><strong class="top_title_strong"><a href="${pageContext.request.contextPath}/sample/barcode/getMemberQRCodeForm.do" target="_content">바코드생성</a></strong></strong></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@ -0,0 +1,104 @@
|
||||
<%
|
||||
/**
|
||||
* <pre>
|
||||
* @Class Name : getSampleInfo.jsp
|
||||
*
|
||||
* @Description : RESTful API 호출 샘플
|
||||
*
|
||||
*
|
||||
* @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @ ------------ -------- ---------------------------
|
||||
* @ 수정일 수정자 수정내용
|
||||
* @ ------------ -------- ---------------------------
|
||||
* @ 2021. 6. 15. KNKIM 최초 생성
|
||||
*
|
||||
*
|
||||
* @author 이씨플라자 * DIGITALSHIP KNKIM
|
||||
* @since 2021. 6. 15.
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
%>
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
|
||||
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
|
||||
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
|
||||
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
|
||||
<c:set var="pageTitle">QRCode 회원정보</c:set>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${pageTitle}</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<!-- <link type="text/css" rel="stylesheet" href="<c:url value='/css/egovframework/com/com.css' />"> -->
|
||||
|
||||
<script type="text/javascript" src="<c:url value="/validator.do"/>"></script>
|
||||
<validator:javascript formName="authorManage" staticJavascript="false" xhtml="true" cdata="false"/>
|
||||
<script type="text/javaScript" language="javascript">
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- javascript warning tag -->
|
||||
<noscript class="noScriptTitle"><spring:message code="common.noScriptTitle.msg" /></noscript>
|
||||
<form:form commandName="reqInfo"
|
||||
action="${pageContext.request.contextPath}/sample/barcode/getMemberQRCode.do" method="post"
|
||||
target="_blank"
|
||||
onSubmit="fncAuthorInsert(document.forms[0]); return false;">
|
||||
<div class="wTableFrm">
|
||||
<!-- 타이틀 -->
|
||||
<h2>${pageTitle} - QR코드 생성 </h2>
|
||||
uniqId : <input name="uniqId" id="uniqId" value="${loginVO.uniqId}" /> <br />
|
||||
email : <input name="email" id="email" value="${loginVO.email}" /> <br />
|
||||
name : <input name="name" id="name" value="${loginVO.name}" /> <br />
|
||||
|
||||
<div style="clear:both;"> </div>
|
||||
|
||||
<!-- 하단 버튼 -->
|
||||
<div class="btn">
|
||||
<input type="submit" class="s_submit" value="바코드생성" /> <!-- 조회 -->
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
|
||||
<br />
|
||||
|
||||
<div style="clear:both;"></div>
|
||||
|
||||
</div>
|
||||
</form:form>
|
||||
|
||||
<hr>
|
||||
<div style="clear:both;"></div>
|
||||
|
||||
<form:form commandName="reqInfo"
|
||||
action="${pageContext.request.contextPath}/sample/barcode/getMemberInfoFromQRCode.do" method="post"
|
||||
onSubmit="fncAuthorInsert(document.forms[0]); return false;">
|
||||
<div class="wTableFrm">
|
||||
<!-- 타이틀 -->
|
||||
<h2>${pageTitle} - QR코드로부터 사용자정보추출</h2>
|
||||
|
||||
QR코드 생성 로그의 DEBUG [iams.nlib.user.service.QRCodeService] generateMemberQRCodeImage : cryptedBarcodeText 의 값을 넣는다.
|
||||
<div style="clear:both;"> </div>
|
||||
|
||||
barcodeText : <input name="barcodeText" id="barcodeText" value="VVNFUjAwMDEtMDAwMDAxO215aWRAZGlnaXRhbHNoaXAuY28ua3I77ZmN6ri464+ZOw==" /> <br />
|
||||
<div style="clear:both;"> </div>
|
||||
|
||||
<!-- 하단 버튼 -->
|
||||
<div class="btn">
|
||||
<input type="submit" class="s_submit" value="<spring:message code="button.inquire" />" title="<spring:message code="button.inquire" /> <spring:message code="button.inquire" />" /><!-- 조회 -->
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
|
||||
</div>
|
||||
</form:form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user