diff --git a/src/main/java/iams/nlib/user/service/QRCodeService.java b/src/main/java/iams/nlib/user/service/QRCodeService.java new file mode 100644 index 00000000..52782d3c --- /dev/null +++ b/src/main/java/iams/nlib/user/service/QRCodeService.java @@ -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; + +/** + *
+ * @Class Name : QRCodeService.java + * + * @Description : QR 코드 생성 처리 + * + * + * @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021) + * + *+ * + * -------------------------------------------------------- + * ※ 참고 : 바코드 정보 + * -------------------------------------------------------- + * [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; + } + +} diff --git a/src/main/java/iams/nlib/user/web/BarcodeController.java b/src/main/java/iams/nlib/user/web/BarcodeController.java new file mode 100644 index 00000000..b15987f0 --- /dev/null +++ b/src/main/java/iams/nlib/user/web/BarcodeController.java @@ -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"; + } +} diff --git a/src/main/resources/egovframework/egovProps/globals.properties b/src/main/resources/egovframework/egovProps/globals.properties index 299e74cd..c3cd9277 100644 --- a/src/main/resources/egovframework/egovProps/globals.properties +++ b/src/main/resources/egovframework/egovProps/globals.properties @@ -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 + + diff --git a/src/main/webapp/WEB-INF/jsp/iams/nlib/common/Left.jsp b/src/main/webapp/WEB-INF/jsp/iams/nlib/common/Left.jsp index f74fc947..ff8a76ec 100644 --- a/src/main/webapp/WEB-INF/jsp/iams/nlib/common/Left.jsp +++ b/src/main/webapp/WEB-INF/jsp/iams/nlib/common/Left.jsp @@ -19,6 +19,9 @@ link:hover { color: #000000; text-decoration: none; }
+ * @Class Name : getSampleInfo.jsp + * + * @Description : RESTful API 호출 샘플 + * + * + * @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021) + * + *+ * + * @ ------------ -------- --------------------------- + * @ 수정일 수정자 수정내용 + * @ ------------ -------- --------------------------- + * @ 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" %> +