package nlib.cmm.qrcode; import java.awt.image.BufferedImage; 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.utl.sim.service.EgovFileScrty; import nlib.cmm.crypto.NlibPasswordEncoder; import nlib.user.service.NlibLoginVO; import nlib.util.StringUtil; /** *
 * @Class Name : QRCodeUtil.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 QRCodeUtil { private static final Logger log = LoggerFactory.getLogger(QRCodeUtil.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(NlibLoginVO 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 NlibLoginVO 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코드 추출 정보가 적합하지 않습니다."); } NlibLoginVO info = new NlibLoginVO(); info.setUniqId(split[0]); info.setEmail(split[1]); info.setName(split[2]); return info; } }