Skip to content

Commit

Permalink
Merge pull request #118 from HaegyeongKim01/week11-haegyeong
Browse files Browse the repository at this point in the history
refactor: qr 수정, shared/cards/{cardId/ 경로 변경
  • Loading branch information
HaegyeongKim01 authored Nov 15, 2024
2 parents 7a6a553 + e52ee06 commit 6517e9f
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
"/notice",
"/notice/**",
"/qna",
"/qna/**"
"/qna/**",
"/shared/**"
).permitAll();
// 그 외의 모든 요청은 인증 필요
auth.anyRequest().authenticated();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,11 @@ public String editCardView(@PathVariable("cardId") Long cardId, Model model) {
return "card-edit";
}

@GetMapping("/shared/cards/{cardId}")
public String sharedCardView(@PathVariable("cardId") Long cardId, Model model) {
CardResponseDto card = cardService.getCard(cardId);
model.addAttribute("card", card);
return "card-shared-view";
}

}
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
package com.devcard.devcard.card.controller.rest;

import com.devcard.devcard.card.dto.QrResponseDto;
import com.devcard.devcard.card.service.QrServiceImpl;
import com.google.zxing.WriterException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
public class QrController {

private final QrServiceImpl qrServiceImpl;

@Autowired
public QrController(QrServiceImpl qrServiceImpl) {
this.qrServiceImpl = qrServiceImpl;
}

@GetMapping("/cards/{card_id}/qrcode")
public ResponseEntity<QrResponseDto> createQR(@PathVariable (name = "card_id") Long cardId) throws IOException, WriterException {
String qrUrl = qrServiceImpl.createQr(cardId);

return ResponseEntity.ok()
.body(new QrResponseDto(qrUrl));
}
}
package com.devcard.devcard.card.controller.rest;

import com.devcard.devcard.card.service.QrServiceImpl;
import com.google.zxing.WriterException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@RestController
public class QrController {

private final QrServiceImpl qrServiceImpl;

@Autowired
public QrController(QrServiceImpl qrServiceImpl) {
this.qrServiceImpl = qrServiceImpl;
}

@GetMapping("/cards/{card_id}/qrcode-image")
public ResponseEntity<byte[]> generateQrImage(@PathVariable(name = "card_id") Long cardId) throws IOException, WriterException {
ByteArrayOutputStream qrImageStream = qrServiceImpl.generateQrImageStream(cardId);

return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"qrcode.png\"")
.contentType(MediaType.IMAGE_PNG)
.body(qrImageStream.toByteArray());
}
}
6 changes: 0 additions & 6 deletions src/main/java/com/devcard/devcard/card/dto/QrResponseDto.java

This file was deleted.

117 changes: 36 additions & 81 deletions src/main/java/com/devcard/devcard/card/service/QrServiceImpl.java
Original file line number Diff line number Diff line change
@@ -1,81 +1,36 @@
package com.devcard.devcard.card.service;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class QrServiceImpl implements QrService{

private static final int QR_SIZE_WIDTH = 200;
private static final int QR_SIZE_HEIGHT = 200;

@Value("${qr.domain.uri}")
private String domainUri;

@Value("${qr.code.directory}")
private String qrCodeDirectory;

/**
* @param cardId QR로 만들 명함 ID
* @return QR 코드 IMAGE 파일 이름만 반환
*/
@Override
public String createQr(Long cardId) throws WriterException, IOException {

// QR URL - QR 코드 정보 URL
String url = generateQrUrl(cardId);

// QR Code - BitMatrix: qr code 정보 생성
BitMatrix bitMatrix = generateQrCode(url);

// Setting QR Image File Name, Path
String qrFileName = generateQrFileName(cardId);
Path qrPath = generateQrFilePath(qrFileName);

// Save QR
saveQrCodeImage(bitMatrix, qrPath);

return domainUri + "qrcodes/" + qrFileName;
}

private String generateQrUrl(Long cardId) {
return domainUri + "cards/" + cardId + "/view";
}

private BitMatrix generateQrCode(String url) throws WriterException {
try {
return new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, QR_SIZE_WIDTH, QR_SIZE_HEIGHT);
} catch (WriterException e) {
throw e;
}
}

private String generateQrFileName(Long cardId) {
return "card_id_" + cardId + ".png";
}

private Path generateQrFilePath(String qrFileName) {
return Paths.get(qrCodeDirectory + qrFileName);
}

private void saveQrCodeImage(BitMatrix bitMatrix, Path qrPath) throws IOException {
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
MatrixToImageWriter.writeToStream(bitMatrix, "png", out);
Files.createDirectories(qrPath.getParent());
Files.write(qrPath, out.toByteArray());
} catch (IOException e) {
throw e;
}
}
}
package com.devcard.devcard.card.service;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@Service
public class QrServiceImpl {

private static final int QR_SIZE_WIDTH = 200;
private static final int QR_SIZE_HEIGHT = 200;

@Value("${qr.domain.uri}")
private String domainUri;

public ByteArrayOutputStream generateQrImageStream(Long cardId) throws WriterException, IOException {
// QR URL 생성
String url = domainUri + "shared/cards/" + cardId;

// QR Code 생성
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, QR_SIZE_WIDTH, QR_SIZE_HEIGHT);

// QR Code 이미지를 메모리 스트림에 저장
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, "PNG", outputStream);

return outputStream;
}
}
10 changes: 9 additions & 1 deletion src/main/resources/static/css/card/card-detail.css
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,12 @@

.delete-button.button:hover {
background-color: #16a085; /* Darker red */
}
}

#qr-image-container {
display: none;
text-align: center;
margin-top: 10px; /* 기존 20px에서 10px로 줄임 */
position: relative; /* 컨테이너의 위치를 세부 조정할 수 있도록 설정 */
top: -10px; /* 컨테이너를 위로 이동 */
}
48 changes: 22 additions & 26 deletions src/main/resources/static/js/card/card-share.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
// Kakao 공유 버튼
document.getElementById('kakao-share-btn').addEventListener('click', function () {
if (!cardId) {
console.error('Card ID가 제공되지 않았습니다.');
handleError('Card ID가 유효하지 않습니다.', 300);
return;
}

// 기본 content 설정
// Kakao 공유 설정
const content = {
title: `${cardName}님의 명함`,
imageUrl: 'https://developers.kakao.com/assets/img/about/logos/kakaolink/kakaolink_btn_medium.png',
link: {
mobileWebUrl: `http://3.34.144.148:8080/cards/${cardId}/view`,
webUrl: `http://3.34.144.148:8080/cards/${cardId}/view`
mobileWebUrl: `http://3.34.144.148:8080/shared/cards/${cardId}`,
webUrl: `http://3.34.144.148:8080/shared/cards/${cardId}`
}
};

// description이 있는 경우에만 추가
if (cardCompany || cardPosition) {
content.description = `회사: ${cardCompany || ''}${cardCompany && cardPosition ? ', ' : ''}직책: ${cardPosition || ''}`;
}
Expand All @@ -27,53 +27,49 @@ document.getElementById('kakao-share-btn').addEventListener('click', function ()
{
title: '명함 보기',
link: {
mobileWebUrl: `http://3.34.144.148:8080/cards/${cardId}/view`,
webUrl: `http://3.34.144.148:8080/cards/${cardId}/view`
mobileWebUrl: `http://3.34.144.148:8080/shared/cards/${cardId}`,
webUrl: `http://3.34.144.148:8080/shared/cards/${cardId}`
}
}
],
fail: function(error) {
fail: function (error) {
console.error(error);
handleError('카카오톡 공유에 실패했습니다.', 300);
}
});
});

// QR 생성 및 렌더링
document.getElementById('qr-share-btn').addEventListener('click', function () {
const cardId = this.getAttribute('data-card-id'); // QR 버튼에서 cardId 가져오기
const cardId = this.getAttribute('data-card-id'); // 버튼에서 cardId 가져오기

if (!cardId) {
console.error('Card ID가 제공되지 않았습니다.');
handleError('Card ID가 유효하지 않습니다.', 300);
return;
}

fetch(`/cards/${cardId}/qrcode`)
const qrContainer = document.getElementById('qr-image-container');
qrContainer.innerHTML = ''; // 이전 QR 코드 제거

// QR 코드 API 요청
fetch(`/cards/${cardId}/qrcode-image?t=${new Date().getTime()}`)
.then(response => {
if (!response.ok) {
console.error(`서버 응답 오류: ${response.status} ${response.statusText}`);
return response.text();
}
return response.json();
if (!response.ok) throw new Error('QR 코드 생성에 실패했습니다.');
return response.blob();
})
.then(data => {
console.log(data)
const qrUrl = `${data.qrcode_url}?t=${new Date().getTime()}`; // 타임스탬프 추가
.then(blob => {
const qrImage = document.createElement('img');
qrImage.src = qrUrl;
qrImage.src = URL.createObjectURL(blob);
qrImage.alt = 'QR Code';
qrImage.style.width = '200px';
qrImage.style.height = 'auto';

const qrContainer = document.getElementById('qr-image-container');
qrContainer.innerHTML = ''; // 기존 내용 지우기
qrContainer.appendChild(qrImage); // QR 코드 이미지 추가
qrImage.style.height = '200px';

qrContainer.style.display = 'block';
handleSuccess('QR 코드가 성공적으로 생성되었습니다.', 400);
qrContainer.appendChild(qrImage); // QR 이미지 추가
qrContainer.style.display = 'block'; // QR 컨테이너 표시
})
.catch(error => {
console.error('QR 코드 fetch 오류:', error);
console.error('QR 코드 생성 중 오류:', error);
handleError('QR 코드 생성에 실패했습니다.', 400);
});
});
2 changes: 2 additions & 0 deletions src/main/resources/templates/card-detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ <h3>그룹 선택</h3>
const cardCompany = /*[[${card.company}]]*/ ''; // 회사 이름
const cardPosition = /*[[${card.position}]]*/ ''; // 직책
</script>


</body>

<script th:src="@{/js/card/card-detail.js}"></script>
Expand Down
Loading

0 comments on commit 6517e9f

Please sign in to comment.