(자바스크립트/모바일,스마트폰카메라/웹캠/바코드스캔/손전등제어/FlashLight)QuaggsJS/JavaScript기반 Ba…

(자바스크립트/모바일카메라/웹캠/바코드스캔/손전등제어/FlashLight)QuaggsJS/JavaScript기반 Barcode Scan, SpringBoot, JSP 예제

 

- QuaggsJS를 이용하여 스프링부트, JSP에서 작성한 예제 입니다.

- 이전에 올려드린 바코드 스캔 기능에 휴대폰 손전등(FlashLight)을 제어하는 기능이 추가 되었습니다.

- 본 예제에서는 Code_93 바코드를 대상으로 하였습니다. (QuaggsJS에서는 추가로 다양한 형태의 바코드를 지원 합니다.)

- 바코드 스캔을 할때는 휴대폰 손전등이 켜지고 스캔이 끝나면 손전등이 꺼집니다.

- PC의 크롬 웹브라우저, 스마트폰/모바일폰 크롬에서 테스트 하였습니다.

 

1. JavaScript 기반 웹페이지에서 바코드를 인식하기 위한 quaggaJS 라이브러리를 다운받자.

 

https://serratus.github.io/quaggaJS/ 

 

ZIP 파일을 다운받아서 압축을 풀자.

 

 

2. 스프링부트로 demo 라는 이름의 플젝을 생성하고 패키지를 com.example.demp 라고 하자.

 

3. DemoApplication.java

package com.example.demo;

 

import org.apache.catalina.connector.Connector;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;

import org.springframework.boot.web.servlet.server.ServletWebServerFactory;

import org.springframework.context.annotation.Bean;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

 

@SpringBootApplication

public class DemoApplication {

 

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

}

@Bean

    public ServletWebServerFactory serveltContainer(){

        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();

        tomcat.addAdditionalTomcatConnectors(createStandardConnector());

        return tomcat;

    }

 

    private Connector createStandardConnector(){

        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");

        connector.setPort(8080);

        return connector;

    }

 

}



4. MainController.java

package com.example.demo;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class MainController {
 
    @RequestMapping("/")
    public String jsp() throws Exception {
        return "main";
    }
}


5. src/main 아래에 webapp/WEB-INF/jsp 폴더 생성

6. jsp폴더에 main.jsp 작성

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        /* In order to place the tracking correctly */
        canvas.drawing, canvas.drawingBuffer {
            position: absolute;
            left: 0;
            top: 0;
        }
    </style>
</head>

<body>
    <!-- Div to show the scanner -->
    <div id="scanner-container"></div>
    <input type="button" id="btn" value="Start/Stop the scanner" />

    <!-- Include the image-diff library -->
    <script src="/js/quagga.js"></script>

    <script>
        var _scannerIsRunning = false;

        function startScanner() {            
            Quagga.init({
                inputStream: {
                    name: "Live",
                    type: "LiveStream",
                    target: document.querySelector('#scanner-container'),
                    constraints: {
                        width: 640,
                        height: 480,
                        facingMode: "environment"                            
                    },
                },
                decoder: {
                    readers: [
                        "code_93_reader"
                    ],
                    debug: {
                        showCanvas: true,
                        showPatches: true,
                        showFoundPatches: true,
                        showSkeleton: true,
                        showLabels: true,
                        showPatchLabels: true,
                        showRemainingPatchLabels: true,
                        boxFromPatches: {
                            showTransformed: true,
                            showTransformedBox: true,
                            showBB: true
                        }
                    }
                },

            }, function (err) {
                if (err) {
                    console.log(err);
                    return
                }

                console.log("Initialization finished. Ready to start");
                Quagga.start();

                // Set flag to is running
                _scannerIsRunning = true;
            });
            
           
            Quagga.onProcessed(function (result) {

            var track = Quagga.CameraAccess.getActiveTrack();
                track.applyConstraints({advanced: [{torch:true}]}); //Torch is on
                
                var drawingCtx = Quagga.canvas.ctx.overlay,
                drawingCanvas = Quagga.canvas.dom.overlay;

                if (result) {
                    if (result.boxes) {
                        drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
                        result.boxes.filter(function (box) {
                            return box !== result.box;
                        }).forEach(function (box) {
                            Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 });
                        });
                    }

                    if (result.box) {
                        Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 });
                    }

                    if (result.codeResult && result.codeResult.code) {
                        Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
                    }
                }
            });


            Quagga.onDetected(function (result) {
                console.log("Barcode detected and processed : [" + result.codeResult.code + "]", result);
                alert("Barcode detected and processed : [" + result.codeResult.code + "]")
                var track = Quagga.CameraAccess.getActiveTrack();
                track.applyConstraints({advanced: [{torch:false}]}); //Torch is off
            });
        }


        // Start/stop scanner
        document.getElementById("btn").addEventListener("click", function () {
            if (_scannerIsRunning) {
            var track = Quagga.CameraAccess.getActiveTrack();
                track.applyConstraints({advanced: [{torch:false}]}); //Torch is off
                Quagga.stop();                
            } else {
                startScanner();
            }
        }, false);
    </script>
</body>

</html>

7. webapp 아래 js 폴더에 다운받은 quaggaJS dist 폴더의 quagga.js를 복사, src 폴더의 analytics, common, ,,,,, reader 모든 폴더를 js 아래로 복사

1f7ba28fb9535b4a5e06862a8b1d87e9_1595665
 

8. 자바스크립트기반 quagga 에서 바코드 스캔이 가능하려면 https 로 웹서비스가 기동되어야 하는데 스프링부트에서는 커맨드창에서 workspace아래 demo 프로젝트 폴더로 이동하여 다음명령을 실행하여 서버 인증서를 만들자.

 

C:\bpr\workspace\demo>keytool -genkey -alias springbootssl -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 4000

 

키 저장소 비밀번호 입력:

이름과 성을 입력하십시오.

  [Unknown]:  jclee

조직 단위 이름을 입력하십시오.

  [Unknown]:  jclee

조직 이름을 입력하십시오.

  [Unknown]:  jclee

구/군/시 이름을 입력하십시오?

  [Unknown]:  seoul

시/도 이름을 입력하십시오.

  [Unknown]:  seoul

이 조직의 두 자리 국가 코드를 입력하십시오.

  [Unknown]:  kr

CN=jclee, OU=jclee, O=jclee, L=seoul, ST=seoul, C=kr이(가) 맞습니까?

  [아니오]:  y

 

9. src/main/resource 아래의 application.properties 파일

 

spring.mvc.view.prefix=/WEB-INF/jsp/

spring.mvc.view.suffix=.jsp

server.ssl.key-store=keystore.p12

server.ssl.key-store-type=PKCS12

server.ssl.key-store-password=tatata01

server.ssl.key-alias=springbootssl

server.port=8443

 

10. DemoApplication.java에서 Ctrl + F11 로 스프링부트 프로젝트를 시작

 

 

  .   ____          _            __ _ _

 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )

  '  |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::        (v2.3.1.RELEASE)

 

2020-07-25 17:07:13.065  INFO 4888 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on DESKTOP-CMQ34NP with PID 4888 (C:\bpr\workspace\demo\target\classes started by user in C:\bpr\workspace\demo)

2020-07-25 17:07:13.068  INFO 4888 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default

2020-07-25 17:07:13.856  INFO 4888 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8443 (https) 8080 (http)

2020-07-25 17:07:13.873  INFO 4888 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]

2020-07-25 17:07:13.874  INFO 4888 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.36]

2020-07-25 17:07:14.097  INFO 4888 --- [           main] org.apache.jasper.servlet.TldScanner     : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

2020-07-25 17:07:14.102  INFO 4888 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext

2020-07-25 17:07:14.102  INFO 4888 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 994 ms

2020-07-25 17:07:14.260  INFO 4888 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'

2020-07-25 17:07:15.237  INFO 4888 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8443 (https) 8080 (http) with context path ''

2020-07-25 17:07:15.246  INFO 4888 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 2.518 seconds (JVM running for 3.308)

2020-07-25 17:07:23.626  INFO 4888 --- [nio-8443-exec-5] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'

2020-07-25 17:07:23.626  INFO 4888 --- [nio-8443-exec-5] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'

2020-07-25 17:07:23.631  INFO 4888 --- [nio-8443-exec-5] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms

 

11. localhost:8080 형태는 https가 아니더라도 실행이 되며 휴대폰/PDA IP형태의 접근은 https로 접근해야 한다.

 

웹브라우저에서 확인은 http://localhost:8080 으로 접근하여 확인하자.

(여러가지 바코드 종류중 code_93 바코드로 테스트 했구요, quggaJS에서는 여러가지 형태를 지원합니다.)

 

1f7ba28fb9535b4a5e06862a8b1d87e9_1595666
12. 스마트폰에서는 https://192.168.0.5:8443 으로 접근해서 확인하자. (제 웹서버 아이피가 192.168.0.5 입니다. 휴대폰설정, 사이트설정에서 카메라 접근 허용해야 하구요~)

 

1f7ba28fb9535b4a5e06862a8b1d87e9_1595666 

 

 

Comments