Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4b79a54
๋กœ๊ทธ์ธ/ํšŒ์› ๊ฐ€์ž…api + jwt์ด์šฉํ•œ api ๋ณด์•ˆ
diacond Sep 1, 2025
3a0c497
์ฑ„ํŒ…๋ฐฉ ํ…Œ์ŠคํŠธ ๋””๋ฒ„๊น…
diacond Sep 25, 2025
804fb31
์ฑ„ํŒ…๋ฐฉ ๊ฐœ์„ค&์ฑ„ํŒ… ๋ฉ”์‹œ์ง€ ํ…Œ์ŠคํŠธ ์™„๋ฃŒ
diacond Sep 30, 2025
f6d97e9
์นด์นด์˜ค์ง€๋„api + ์ฑ„ํŒ…๋ฐฉ
diacond Sep 30, 2025
b8fb0c3
์ฑ„ํŒ…๋ฐฉ+์ฑ„ํŒ… ๊ธฐ๋Šฅ ์™„์„ฑ
diacond Oct 9, 2025
bba4196
PR ๋ฆฌ๋ทฐ ๋ฐ˜์˜ - ๋ณด์•ˆ ๊ฐ•ํ™”, username ๋ณต๊ตฌ
diacond Oct 13, 2025
22c1cf8
testdb.mv.db ๋ฌด์‹œ
diacond Oct 13, 2025
bb68d4c
main๋ธŒ๋žœ์น˜&pr๋ฆฌ๋ทฐ ๋ฐ˜์˜
diacond Oct 13, 2025
cc716f3
๋ฉ”์ธ ๋ธŒ๋žœ์น˜๋ž‘ ์ถฉ๋Œ ํ•ด๊ฒฐ ํ›„ ํ•ฉ๋ณ‘
diacond Oct 20, 2025
1c52e17
fix-horim ์ถฉ๋Œ ์ž‘์—… ํ•ด๊ฒฐ ์ค‘
diacond Oct 25, 2025
a85d765
Merge remote-tracking branch 'origin/main' into fix-horim
diacond Oct 25, 2025
3c210c8
~
diacond Oct 26, 2025
b63d638
๋ชจ๋“  ํ…Œ์ŠคํŠธ ์˜ค๋ฅ˜ ํ•ด๊ฒฐ
diacond Oct 28, 2025
f25b15a
PR ์ค‘ java/CI ์˜ค๋ฅ˜ ํ•ด๊ฒฐ - MemberSignupTest
diacond Oct 28, 2025
efecb49
Role ์‚ญ์ œ
yuuuyeonho Oct 28, 2025
7c98787
์‹œํ๋ฆฌํ‹ฐ permitAll
yuuuyeonho Oct 29, 2025
982e538
renew
diacond Nov 9, 2025
457bf8e
Merge branch 'fix-horim' of http://github.com/Cagong-ReceiptPower/Recโ€ฆ
diacond Nov 9, 2025
25b7ce6
PR ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜/์ˆ˜์ •
diacond Nov 11, 2025
704ffa2
PR ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜ + ์˜ค๋ฅ˜ ์ˆ˜์ •
diacond Nov 11, 2025
726292b
์ฑ„ํŒ…๋ฐฉ ๊ฐœ์„ค ๋ฐฉ๋ฒ• ์ˆ˜์ •
diacond Nov 14, 2025
9e45231
๋งˆ์ผ๋ฆฌ์ง€ ํ…Œ์ŠคํŠธ ์ถฉ๋Œ ํ•ด๊ฒฐ
diacond Nov 14, 2025
bacc23f
fix: ์ž”๊ฐ€์ง€ ์ˆ˜์ •
yuuuyeonho Nov 14, 2025
f9daf41
fix: ๋„์ปคํŒŒ์ผ ์ˆ˜์ •
yuuuyeonho Nov 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ out/
.vscode/

mydb.db
testdb.mv.db
.env
github-actions-key
github-actions-key.pub
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM openjdk:21
FROM eclipse-temurin:21
COPY build/libs/*.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
18 changes: 14 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,45 @@ repositories {
}

dependencies {
// ๊ธฐ๋ณธ ์›น, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ, Lombok
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation' // ์ถ”๊ฐ€
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

// ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค (JPA, MySQL)
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.mysql:mysql-connector-j'
implementation 'org.hibernate.orm:hibernate-community-dialects'

// ๋ณด์•ˆ (Spring Security)
implementation 'org.springframework.boot:spring-boot-starter-security'

// JWT ๊ด€๋ จ ์˜์กด์„ฑ ์ถ”๊ฐ€
// JWT (ํ† ํฐ)
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'

// test
testImplementation 'io.rest-assured:rest-assured:5.5.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.5.0'
runtimeOnly 'com.h2database:h2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
implementation 'org.springframework.boot:spring-boot-starter-websocket'

// mqtt
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
implementation 'org.json:json:20240303'

// 1. .env ํŒŒ์ผ์„ ์ฝ๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
implementation 'io.github.cdimascio:java-dotenv:5.2.2'

// 2. @EnableJpaAuditing์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ Spring Data JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

tasks.named('test') {
useJUnitPlatform()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
// ReceiptPowerServerApplication.java

package com.cagong.receiptpowerserver;

import io.github.cdimascio.dotenv.Dotenv; // import ์ถ”๊ฐ€
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
public class ReceiptPowerServerApplication {

public static void main(String[] args) {
SpringApplication.run(ReceiptPowerServerApplication.class, args);
}

}
public static void main(String[] args) {
Dotenv.configure()
.ignoreIfMissing() // .env ํŒŒ์ผ์ด ์—†์–ด๋„(์˜ˆ: ๋ฐฐํฌ ํ™˜๊ฒฝ) ์˜ค๋ฅ˜ ์—†์ด ํ†ต๊ณผ
.systemProperties() // .env์˜ ๋ชจ๋“  ๋ณ€์ˆ˜๋ฅผ System.setProperty()๋กœ ์ž๋™ ๋“ฑ๋ก
.load();
SpringApplication.run(ReceiptPowerServerApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.cagong.receiptpowerserver.domain.cafe;

import com.cagong.receiptpowerserver.domain.cafe.dto.CafeRequest;
import com.cagong.receiptpowerserver.domain.cafe.dto.CafeUpdateRequest;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
Expand All @@ -16,6 +17,9 @@ public class Cafe {
@Column(name = "cafe_id")
private Long id;

// [์ถ”๊ฐ€] ์นด์นด์˜ค ์žฅ์†Œ ID๋ฅผ ์ €์žฅํ•  ํ•„๋“œ. ์นดํŽ˜๊ฐ€ ์ค‘๋ณต ์ €์žฅ๋˜๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค.
@Column(unique = true)

private String name;

private String address;
Expand All @@ -27,15 +31,15 @@ public class Cafe {
private String phoneNumber;

@Builder
public Cafe(String name, String address, double latitude, double longitude, String phoneNumber) {
public Cafe(String name, double latitude, double longitude, String address, String phoneNumber) {
this.name = name;
this.address = address;
this.latitude = latitude;
this. longitude = longitude;
this.longitude = longitude;
this.address = address;
this.phoneNumber = phoneNumber;
}

public void updateFrom(CafeRequest request) {
public void update(CafeUpdateRequest request) {
this.name = request.getCafeName();
this.address = request.getAddress();
this.latitude = request.getLatitude();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,66 @@

import com.cagong.receiptpowerserver.domain.cafe.dto.CafeRequest;
import com.cagong.receiptpowerserver.domain.cafe.dto.CafeResponse;
import com.cagong.receiptpowerserver.domain.cafe.dto.CafeUpdateRequest;
import com.cagong.receiptpowerserver.domain.cafe.dto.CafeWithChatRoomsResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/cafes")
@RequiredArgsConstructor
public class CafeController {

private final CafeService cafeService;
/**
* 1. ์นดํŽ˜ ์ƒ์„ฑ (POST /api/cafes)
*/
@PostMapping
public ResponseEntity<Long> createCafe(@RequestBody CafeRequest request) {
Long cafeId = cafeService.saveCafe(request);
return ResponseEntity.status(HttpStatus.CREATED).body(cafeId);
}

/**
* 2. ์นดํŽ˜ ์ „์ฒด ์กฐํšŒ (GET /api/cafes/all)
*/
@GetMapping("/all")
public ResponseEntity<List<CafeResponse>> getAllCafes(){
List<CafeResponse> responses = cafeService.getAllCafes();
return ResponseEntity.ok().body(responses);
public ResponseEntity<List<CafeResponse>> getAllCafes() {
List<CafeResponse> cafes = cafeService.findAllCafes();
return ResponseEntity.ok(cafes);
}

/**
* 3. ์นดํŽ˜ ID๋กœ 1๊ฑด ์กฐํšŒ (GET /api/cafes/{cafeId})
*/
@GetMapping("/{cafeId}")
public ResponseEntity<CafeResponse> getCafeById(@PathVariable Long cafeId){
try{
CafeResponse response = cafeService.getCafeById(cafeId);
return ResponseEntity.ok().body(response);
} catch (IllegalArgumentException e){
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
public ResponseEntity<CafeResponse> getCafeById(@PathVariable Long cafeId) {
CafeResponse cafe = cafeService.findCafeById(cafeId);
return ResponseEntity.ok(cafe);
}

@PostMapping
public ResponseEntity<Void> createCafe(@RequestBody CafeRequest request){
Long cafeId = cafeService.createCafe(request);
return ResponseEntity.created(URI.create("/cafes/" + cafeId)).build();
/**
* 4. ์นดํŽ˜ ์‚ญ์ œ (DELETE /api/cafes/{cafeId})
*/
@DeleteMapping("/{cafeId}")
public ResponseEntity<Void> deleteCafe(@PathVariable Long cafeId) {
cafeService.deleteCafeById(cafeId);
return ResponseEntity.noContent().build(); // 204 No Content
}

@PutMapping("/{cafeId}")
public ResponseEntity<Void> updateCafe (@PathVariable Long cafeId, @RequestBody CafeRequest request){
try {
cafeService.updateCafe(cafeId, request);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
@PatchMapping("/{cafeId}")
public ResponseEntity<CafeResponse> updateCafe(
@PathVariable Long cafeId,
@RequestBody CafeUpdateRequest request) {

// ์„œ๋น„์Šค์˜ updateCafe ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ
CafeResponse updatedCafe = cafeService.updateCafe(cafeId, request);

@DeleteMapping("{cafeId}")
public ResponseEntity<Void> deleteCafe(@PathVariable Long cafeId){
try {
cafeService.deleteCafe(cafeId);
return ResponseEntity.noContent().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
// ์ˆ˜์ •๋œ ์ •๋ณด(updatedCafe)๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ 200 OK์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜
return ResponseEntity.ok(updatedCafe);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@

import java.util.Optional;

public interface CafeRepository extends JpaRepository<Cafe, Long> {
}
public interface CafeRepository extends JpaRepository<Cafe, Long> { }
Original file line number Diff line number Diff line change
@@ -1,75 +1,87 @@
package com.cagong.receiptpowerserver.domain.cafe;

import com.cagong.receiptpowerserver.domain.cafe.dto.CafeRequest;
import com.cagong.receiptpowerserver.domain.cafe.dto.CafeUpdateRequest; // [์ˆ˜์ •] 1. CafeUpdateRequest import
import com.cagong.receiptpowerserver.domain.cafe.dto.CafeResponse;
// [์ˆ˜์ •] 2. Kakao API ๋ฐ ChatRoomService ๊ด€๋ จ ์˜์กด์„ฑ *๋ชจ๋‘ ์‚ญ์ œ*
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;


@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class CafeService {
private final CafeRepository cafeRepository;

public List<CafeResponse> getAllCafes(){
return cafeRepository.findAll().stream()
.map(cafe -> new CafeResponse(
cafe.getId(),
cafe.getName(),
cafe.getAddress(),
cafe.getLatitude(),
cafe.getLongitude(),
cafe.getPhoneNumber()
))
.collect(Collectors.toList());
}
private final CafeRepository cafeRepository;

public CafeResponse getCafeById(Long cafeId){
return cafeRepository.findById(cafeId)
.map(cafe -> new CafeResponse(
cafe.getId(),
cafe.getName(),
cafe.getAddress(),
cafe.getLatitude(),
cafe.getLongitude(),
cafe.getPhoneNumber()
))
.orElseThrow(() -> new IllegalArgumentException("ํ•ด๋‹น ID์˜ ์นดํŽ˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: " + cafeId));
}
// [์ˆ˜์ •] 3. ChatRoomService, RestTemplate, kakaoApiKey ์˜์กด์„ฑ *๋ชจ๋‘ ์‚ญ์ œ*

/**
* 1. ์นดํŽ˜ ์ƒ์„ฑ (POST /api/cafes)
*/
@Transactional
public Long createCafe(CafeRequest request){
public Long saveCafe(CafeRequest request) {
Cafe cafe = Cafe.builder()
.name(request.getCafeName())
.address(request.getAddress())
.latitude(request.getLatitude())
.longitude(request.getLongitude())
.phoneNumber(request.getPhoneNumber())
.build();
Cafe saved = cafeRepository.save(cafe);
return saved.getId();
}

@Transactional
public void updateCafe(Long cafeId, CafeRequest request){
Cafe cafe = cafeRepository.findById(cafeId)
.orElseThrow(() -> new IllegalArgumentException("ํ•ด๋‹น ID์˜ ์นดํŽ˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: " + cafeId));
Cafe savedCafe = cafeRepository.save(cafe);
return savedCafe.getId();
}

cafe.updateFrom(request);
/**
* 2. ์นดํŽ˜ ์ „์ฒด ์กฐํšŒ (GET /api/cafes/all)
*/
@Transactional(readOnly = true)
public List<CafeResponse> findAllCafes() {
return cafeRepository.findAll().stream()
.map(CafeResponse::new) // (CafeResponse(Cafe) ์ƒ์„ฑ์ž ์‚ฌ์šฉ)
.collect(Collectors.toList());
}

cafeRepository.save(cafe);
/**
* 3. ์นดํŽ˜ ID๋กœ 1๊ฑด ์กฐํšŒ (GET /api/cafes/{cafeId})
*/
@Transactional(readOnly = true)
public CafeResponse findCafeById(Long cafeId) {
Cafe cafe = cafeRepository.findById(cafeId)
.orElseThrow(() -> new RuntimeException("ํ•ด๋‹น ID์˜ ์นดํŽ˜๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค:" + cafeId));
return new CafeResponse(cafe); // (CafeResponse(Cafe) ์ƒ์„ฑ์ž ์‚ฌ์šฉ)
}

/**
* 4. ์นดํŽ˜ ์‚ญ์ œ (DELETE /api/cafes/{cafeId})
*/
@Transactional
public void deleteCafe(Long cafeId){
if(!cafeRepository.existsById(cafeId)){
throw new IllegalArgumentException("ํ•ด๋‹น ID์˜ ์นดํŽ˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: " + cafeId);
}
cafeRepository.deleteById(cafeId);
public void deleteCafeById(Long cafeId) {
Cafe cafe = cafeRepository.findById(cafeId)
.orElseThrow(() -> new RuntimeException("ํ•ด๋‹น ID์˜ ์นดํŽ˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: " + cafeId));
cafeRepository.delete(cafe);
}
}

/**
* 5. ์นดํŽ˜ ์ˆ˜์ •
* */
@Transactional
public CafeResponse updateCafe(Long cafeId, CafeUpdateRequest request) {
// [์ˆ˜์ •] 4. updateCafe ๋กœ์ง์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ˆ˜์ •

// 1. DB์—์„œ ์นดํŽ˜ Entity๋ฅผ ์กฐํšŒ
Cafe cafe = cafeRepository.findById(cafeId)
.orElseThrow(() -> new RuntimeException("ํ•ด๋‹น ID์˜ ์นดํŽ˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: " + cafeId));

// 2. Entity์˜ update ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ (JPA ๋ณ€๊ฒฝ ๊ฐ์ง€)
// (์ด ์ฝ”๋“œ๊ฐ€ ์ž‘๋™ํ•˜๋ ค๋ฉด Cafe.java์— update(CafeUpdateRequest request) ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค)
cafe.update(request);

// 3. ์ˆ˜์ •๋œ Entity๋ฅผ DTO๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜
return new CafeResponse(cafe);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
@Getter
@AllArgsConstructor
public class CafeRequest {
private String cafeName;
private String cafeName; // โ—๏ธ ํ•„๋“œ๋ช… ํ™•์ธ
private String address;
private double latitude;
private double longitude;
private String phoneNumber;
}
}
Loading
Loading