๊ด€๋ฆฌ ๋ฉ”๋‰ด

๐Ÿ’ป๐Ÿ’ญ๐ŸŽง๐ŸŒ

[์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ] 8. ์Šคํ”„๋ง Spring QR ์ฝ”๋“œ๋กœ ์ถœ์„ ์ฒดํฌ ๊ธฐ๋Šฅ ๋ณธ๋ฌธ

์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ

[์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ] 8. ์Šคํ”„๋ง Spring QR ์ฝ”๋“œ๋กœ ์ถœ์„ ์ฒดํฌ ๊ธฐ๋Šฅ

adorableco 2024. 1. 27. 17:25
๋ฐ˜์‘ํ˜•

์š”๊ตฌ์‚ฌํ•ญ

  • ๊ฒฝ๊ธฐ ์‹œ์ž‘ 30๋ถ„ ์ „๋ถ€ํ„ฐ ๊ฒฝ๊ธฐ ๋ฆฌ๋” ํ™”๋ฉด์—์„œ QR ์ฝ”๋“œ๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ๋‹ค.
  • ์ฐธ๊ฐ€ ์ธ์›๋“ค์€ ์ด QR ์ฝ”๋“œ๋ฅผ ์ดฌ์˜ํ•˜์—ฌ ์ถœ์„ ์ฒดํฌ๋ฅผ ํ•œ๋‹ค.

 

์˜คํ”ˆ ์†Œ์Šค์ธ zxing ์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค. ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์› ๋‹ค!
build.gradle ํŒŒ์ผ์— ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

    implementation group: 'com.google.zxing', name: 'javase', version: '3.5.0'
    implementation group: 'com.google.zxing', name: 'core', version: '3.5.0'

 

createQr(User user, Long matchId)

QR ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ”์ดํŠธ ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ

    public ResponseEntity<byte[]> createQr(User user, Long matchId) throws Exception {

        Match match = matchRepository.findById(matchId).get();

        int width = 200;
        int height = 200;

        long time = differenceTime(match);

        if (match.getUser().getUserId() != user.getUserId()){
            return ResponseEntity.badRequest()
                    .body("๊ฒฝ๊ธฐ ๋ฆฌ๋”๊ฐ€ ์•„๋‹˜".getBytes(StandardCharsets.UTF_8));
        }
        else if (time > 30 * 60000 || time < -10 * 60000) {
            return ResponseEntity.badRequest().body("์ถœ์„ ์ฒดํฌ ๊ฐ€๋Šฅ ์‹œ๊ฐ„์ด ์•„๋‹˜".getBytes(StandardCharsets.UTF_8));
        }

        String url = "http://localhost:8080/api/attendance/"+matchId;

        BitMatrix encode = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height);

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        MatrixToImageWriter.writeToStream(encode, "PNG", out);

        return ResponseEntity.ok()
                .contentType(MediaType.IMAGE_PNG)
                .body(out.toByteArray());

    }
  • if๋ฌธ๋ถ€ํ„ฐ ๋จผ์ € ๋ณด๋ฉด match ๋ฅผ ๋“ฑ๋กํ•œ ์œ ์ €, ์ฆ‰ ๊ฒฝ๊ธฐ ๋ฆฌ๋”์ธ์ง€๋ฅผ ๋จผ์ € ํ™•์ธํ•œ ํ›„ ์•„๋‹ˆ๋ฉด badRequest๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    โ“ ๊ทผ๋ฐ ๋ฐ˜ํ™˜ํƒ€์ž…์ด ResponseEntity<byte[]> ์ผ ๋•Œ ์˜ค๋ฅ˜๋ฅผ String ์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์‹ถ์œผ๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋ ค๋‚˜.. ์ €๋ฒˆ๋ถ€ํ„ฐ ๊ถ๊ธˆํ–ˆ๋Š”๋ฐ ๊ท€์ฐฎ์•„์„œ ๋‚˜์ค‘์— ์ฐพ์•„๋ณผ ์˜ˆ์ • ...^^
  • ๋‹ค์Œ ์ œ์•ฝ์กฐ๊ฑด์€ ์ถœ์„์ฒดํฌ ๊ฐ€๋Šฅ ์‹œ๊ฐ„์— ๊ด€ํ•œ ๊ฒƒ์ธ๋ฐ if๋ฌธ ์œ„์—์„œ ํ˜„์žฌ ์‹œ๊ฐ„๊ณผ ๊ฒฝ๊ธฐ ์˜ˆ์ • ์‹œ๊ฐ„์„ ๋น„๊ตํ•ด์„œ ์ฐจ์ด๊ฐ’์„ ์ดˆ ๋‹จ์œ„๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” differenceTime ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ time ๋ณ€์ˆ˜์— ๋‹ด์•„๋‘์—ˆ๋‹ค. ๊ฒฝ๊ธฐ ์‹œ์ž‘ ์‹œ๊ฐ„ 30๋ถ„ ์ „์—์„œ ๊ฒฝ๊ธฐ ์‹œ์ž‘ ํ›„ 10๋ถ„ ์‚ฌ์ด๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์ถœ์„์ฒดํฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ badRequest๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

 

โœ… differenceTime() ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    private long differenceTime(Match match) throws ParseException {
        String now= LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toString();
        String matchTime= match.getStartTime().toString();

        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        Date d1 = format.parse(now);
        Date d2 = format.parse(matchTime);
        long sec = (d2.getTime() - d1.getTime()) / 1000;
        long min = (d2.getTime() - d1.getTime()) / 60000;
        long hour = (d2.getTime() - d1.getTime()) / 3600000;
        long days = sec / (24*60*60);

        return sec + min + hour + days;
    }

์ด์ œ ๋ชจ๋‘ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด qr์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค!

  • String url ์—๋Š” QR์ฝ”๋“œ ์Šค์บ”์„ ํ†ตํ•ด ์ด๋™ํ•  url์„ ๋‹ด์•„์ค€๋‹ค.
    • ์‚ฌ์‹ค ๋‚ด๊ฐ€ ์›ํ–ˆ๋˜ ์ด์ƒ์ ์ธ ๋ฐฉ๋ฒ•์€ QR์ฝ”๋“œ๋ฅผ ์Šค์บ”ํ•ด์„œ ์ด๋™ํ•˜๊ฒŒ๋  url์ด ๋ฐ”๋กœ ์ถœ์„ ์ฒดํฌ api๋กœ ์—ฐ๊ฒฐ๋˜์–ด์„œ ์ถœ์„ ์ฒดํฌ๊ฐ€ ์™„๋ฃŒ๋˜๋Š” ๊ฒƒ์ธ๋ฐ BitMatrix ๊ฐ์ฒด์—์„œ ๊ตฌํ˜„ํ•  ์ˆ˜๋Š” ์žˆ๋Š”๊ฑด์ง€ ๊ฐ์ด ๋„ํ†ต ์•ˆ์™€์„œ.. ์ผ๋‹จ ํ”„๋ก ํŠธ์ชฝ์—์„œ ๋‹ค์‹œ POST๋กœ ์š”์ฒญ์„ ์ค„ url์„ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ–ˆ๊ณ  ํ”„๋ก ํŠธ์—์„  response๋กœ ๋ฐ›์€๊ฑธ ๋‹ค์‹œ api ์š”์ฒญ์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ์กฐ๊ธˆ.. ๋ฒˆ๊ฑฐ๋กœ์šด ๊ฒƒ ๊ฐ™๋‹ค
  • BitMatrix ๊ฐ์ฒด๋Š” width, height, ๋ฐ”์ฝ”๋“œ ํฌ๋งท ์ค‘ QR_CODE, ๊ทธ๋ฆฌ๊ณ  ์œ„์—์„œ ์ง€์ •ํ•œ url ์„ ๋‹ด์•„ ์ƒ์„ฑํ•œ๋‹ค.

 

qrToAttendance(Long matchId, String userEmail)

๊ฒฝ๊ธฐ ์ฐธ๊ฐ€ ์ธ์›์ด ์ƒ์„ฑ๋œ qr ์ฝ”๋“œ๋ฅผ ์Šค์บ”ํ•œ ํ›„์— ์ถœ์„์ฒดํฌ๋ฅผ ์ฒ˜๋ฆฌ๊ฐ€ ๋˜๋Š” ๋ฉ”์„œ๋“œ

    public ResponseEntity<String> qrToAttendance(Long matchId, String userEmail) throws Exception {
        Match match = matchRepository.findById(matchId).get();
        Optional<Participation> participation = participationService.findByMatchAndUser(matchId, userEmail);

        long time = differenceTime(match);


        if (time > 30 * 40 || time < -10 * 40) {
            return ResponseEntity.badRequest().body("์ถœ์„ ์ฒดํฌ ๊ฐ€๋Šฅ ์‹œ๊ฐ„์ด ์•„๋‹˜");

        }
         else if (participation.get().isAttendance()) {
            return ResponseEntity.badRequest().body("์ด๋ฏธ ์ถœ์„ ์ฒดํฌ ์™„๋ฃŒ");
        } else {
            return participationService.checkAttendance(matchId, userEmail);
        }
    }
  • ์—ฌ๊ธฐ์„œ๋„ qr์ƒ์„ฑ ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์ด ์‹œ๊ฐ„ ์ œ์•ฝ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์–ด์ฐจํ”ผ qr์ฝ”๋“œ ์ƒ์„ฑ ์ž์ฒด๊ฐ€ ์•ˆ๋˜๋ฉด ์ถœ์„ ์ฒดํฌ ์‹œ๋„๋„ ํ•  ์ˆ˜ ์—†์ง€๋งŒ?.. ์‹œ๊ฐ„ ๋‚ด์— ์ƒ์„ฑํ•œ qr์ฝ”๋“œ๋ฅผ ์บก์ฒ˜ํ•œ ํ›„์— ๋‚˜์ค‘์— ์Šค์บ”ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์„œ๋„ ์‹œ๊ฐ„ ์ œ์•ฝ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•˜๊ธดํ•˜๋‹ค.
  • ๋˜ํ•œ ์ด๋ฏธ ์ถœ์„ ์ฒดํฌ๊ฐ€ ์™„๋ฃŒ๋œ ๊ฒฝ์šฐ์—๋„ badRequest ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • ๋ชจ๋“  ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด participationService์˜ checkAttendance ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ถœ์„์ฒดํฌ๋ฅผ ํ•ด์ค€๋‹ค.

 

checkAttendance(Long matchId, String userEmail)

    @Transactional
    public ResponseEntity<String> checkAttendance(Long matchId, String userEmail) {
        try {
            Match match = matchRepository.findById(matchId).get();
            User user = userRepository.findByEmail(userEmail).get();
            Participation participation = participationRespository.findByMatchAndUser(match, user).get();
            participation.setAttendance(true);
            int attendanceCount = match.getAttendanceCnt();
            match.setAttendanceCnt(attendanceCount + 1);
            return ResponseEntity.ok().body("์ถœ์„ ์ฒดํฌ ์™„๋ฃŒ");
        }catch (Exception e){
            return ResponseEntity.badRequest().body("์ถœ์„ ์ฒดํฌ ์‹คํŒจ");
        }
    }

 

 

participation.setAttendance(true);

โžก๏ธ ์œ ์ €์˜ participation (๊ฐœ์ธ ๊ฒฝ๊ธฐ ์ฐธ๊ฐ€ ์ •๋ณด) ์˜ ์ถœ์„ ์—ฌ๋ถ€๋ฅผ true ๋กœ ์„ธํŒ…ํ•ด์ฃผ๊ณ 

 

 

 int attendanceCount = match.getAttendanceCnt();
 match.setAttendanceCnt(attendanceCount + 1);

โžก๏ธ match (๊ฒฝ๊ธฐ ์ฐธ๊ฐ€ ๊ณตํ†ต ์ •๋ณด)์˜ ์ถœ์„์ธ์› ์ˆ˜๋ฅผ 1 ์ฆ๊ฐ€์‹œ์ผœ์ค€๋‹ค.

 

 

 

 

๊ฑฑ์ •ํ–ˆ๋˜ ๊ธฐ๋Šฅ์ด์—ˆ๋Š”๋ฐ ์ƒ๊ฐํ•ด๋ณด๋‹ค ์ˆœํƒ„ํ•˜๊ฒŒ ์ž˜ ๋๋ƒˆ๋‹ค! ๐Ÿ‘


์‹คํ–‰๊ฒฐ๊ณผ

  • ์„ฑ๊ณต!

 

  • ๊ฒฝ๊ธฐ๋ฆฌ๋”๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ

 

 

  • ์ถœ์„ ๊ฐ€๋Šฅ ์‹œ๊ฐ„์ด ์•„๋‹ ๊ฒฝ์šฐ

 

๋‹ค์Œ ํ•  ์ผ

  • ์ถœ์„๋ฅ , ์Šน๋ฅ  ๋“ฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํšŒ์› ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉํ•  api๋ฅผ ๊ตฌํ˜„
๋ฐ˜์‘ํ˜•