180 lines
6.3 KiB
Java
180 lines
6.3 KiB
Java
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;
|
||
|
||
/**
|
||
* <pre>
|
||
* @Class Name : QRCodeUtil.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 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.getMbInfoId())) {
|
||
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바코드로 생성에 필요한 이름 정보가 없습니다.");
|
||
}
|
||
|
||
String barcodeText = loginVO.getMbInfoId();
|
||
return generateQRCodeImageByZxing(barcodeText);
|
||
}
|
||
|
||
/**
|
||
* 사용자 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.setMbInfoId(split[0]);
|
||
info.setEmail(split[1]);
|
||
info.setName(split[2]);
|
||
|
||
return info;
|
||
}
|
||
|
||
}
|