Backend/๐ŸŒฑ Spring

[Spring] Mapping

HS0601 2025. 7. 23. 22:55

 

 

ํ•˜... ์Šคํ”„๋ง์„ ํ•˜๋ฉด์„œ ํž˜๋“  ๊ฒŒ ํ•œ ๋‘๊ฐœ๊ฐ€ ์•„๋‹ˆ๋‹ค.

์ผ๋‹จ ํ”„๋ก ํŠธ์—”๋“œ ๊ณต๋ถ€ํ•ด ๋ณด๋ฉด์„œ, ์ˆ˜ํผ๋ฒ ์ด์Šค ์—ฐ๋™ํ•˜์—ฌ DB์—์„œ CRUD๋ฅผ ๊ฒฝํ—˜ํ•œ ๋ฐ” ์žˆ๋‹ค. 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋ก ํŠธ๋„ ๋‹ค ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๋ฐฑ์—”๋“œ์™€์˜ ์ฐจ์ด๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ์•ˆ๋ณด์—ฌ์„œ ํž˜๋“ค์—ˆ๋‹ค.

 

ํ”„์—” ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์•ˆ ๋ณด์˜€๋˜ ์ ์€, ์Šˆํผ๋ฒ ์ด์Šค๊ฐ€ ๋ฐฑ์—”๋“œ ์—ญํ• ์„ ๋Œ€์‹  ๋งก์•„์ค€ ์…ˆ.

=> DB ํŠธ๋žœ์žญ์…˜, ๊ถŒํ•œ ์ •์ฑ…, ๋กœ๊น…, ๊ฐ์‚ฌ ๋“ฑ์˜ ์ง„์งœ ์‹คํ–‰ ์ฃผ์ฒด๋Š” ์„œ๋ฒ„ ์ชฝ์ด ํ•„์š”ํ•จ

 

์•ˆ์ผํ–ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. ๋ญ”๊ฐ€ ๊ธฐ์–ต ์ €ํŽธ ๋„ˆ๋จธ์— ์žˆ๋Š” ๊ฒƒ ๊ฐ™๊ธฐ๋„ ํ•˜๊ณ .

๊ฐ™์€ ๊ธฐ๋Šฅ(์˜ˆ: “์œ ์ € ์‚ญ์ œ”)์„ React(ํ”„๋ก ํŠธ) vs Spring(๋ฐฑ์—”๋“œ)๋กœ ๋‚˜๋ˆ ์„œ ๋ณด๋ฉด ์ฐจ์ด๊ฐ€ ํ™• ์„ ๋‹ค.
// React ์˜ˆ์‹œ
function UserItem({ id }) {
  const handleDelete = async () => {
    await fetch(`/api/users/${id}`, { method: 'DELETE' });
    // ํ™”๋ฉด์—์„œ ์ œ๊ฑฐ(๋ฆฌ์ŠคํŠธ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ค๊ฑฐ๋‚˜, ๋กœ์ปฌ ์ƒํƒœ์—์„œ ๋นผ๊ธฐ)
  };

  return <button onClick={handleDelete}>์‚ญ์ œ</button>;
}

 

๋ฒ„ํŠผ ํด๋ฆญ ์‹œ HTTP ์š”์ฒญ ์ „์†กํ•˜๋Š” ์ฝ”๋“œ

๋ถˆ๊ฐ€๋Šฅํ•œ ์ : DB์—์„œ ์ง„์งœ๋กœ ์ง€์šฐ๊ธฐ, ๊ถŒํ•œ ์ฒดํฌ, ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ, ๋กœ๊ทธ ๊ธฐ๋ก ๋“ฑ 

(๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž๋„๊ตฌ๋กœ ๋ˆ„๊ตฌ๋‚˜ ์ง์ ‘ ์š”์ฒญ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, “์ง„์งœ ์‚ญ์ œ”๋Š” ์„œ๋ฒ„๊ฐ€ ํŒ๋‹จ/์‹คํ–‰ํ•ด์•ผ ํ•จ)

@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService service;

    public UserController(UserService service) {
        this.service = service;
    }

    @DeleteMapping("/{id}")        // ← ๋งคํ•‘: DELETE /api/users/3
    public void delete(@PathVariable Long id,
                       @AuthenticationPrincipal UserPrincipal me) {

        // 1) ์ธ์ฆ/๊ถŒํ•œ ์ฒดํฌ
        if (!me.isAdmin()) throw new ForbiddenException();

        // 2) ๋น„์ฆˆ๋‹ˆ์Šค ๋ฃฐ(๊ด€๋ จ ๋ฐ์ดํ„ฐ ์ •๋ฆฌ ๋“ฑ)
        service.deleteUser(id);

        // 3) ํŠธ๋žœ์žญ์…˜์œผ๋กœ DB ๋ณ€๊ฒฝ
        // 4) ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ธฐ๋ก
    }
}

 

  • ์–ด๋–ค URL + HTTP ๋ฉ”์„œ๋“œ(DELETE) → ์–ด๋–ค ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ›์„์ง€ ๋งคํ•‘
  • ์š”์ฒญ๊ฐ’์„ ๊ฒ€์ฆ/๊ถŒํ•œ์ฒดํฌ
  • DB ์กฐ์ž‘, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ
  • ์ •ํ™•ํ•œ ์‘๋‹ต ์ฝ”๋“œ/๋ฐ”๋”” ๋ฐ˜ํ™˜
  • ๋กœ๊ทธ, ๋ชจ๋‹ˆํ„ฐ๋ง, ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋“ฑ ์šด์˜ ์ฑ…์ž„

 


๋งคํ•‘

 

 

๋งคํ•‘์ด๋ž€?
- HTTP ์š”์ฒญ(์ฃผ์†Œ+๋ฉ”์„œ๋“œ+๊ธฐํƒ€ ์ •๋ณด)์„ ์–ด๋–ค ๋ฉ”์„œ๋“œ๋กœ ๋ณด๋‚ผ์ง€ ์—ฐ๊ฒฐํ•ด ๋‘๋Š” ๊ทœ์น™.
- ์‰ฝ๊ฒŒ ๋งํ•ด ๋ผ์šฐํŒ…, ๊ธธ์ฐพ๊ธฐ ํ‘œ์ง€ํŒ ์—ญํ• 

 

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋งคํ•‘์ด ์žˆ๋‹ค.

  • @RequestMapping
  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉฐ ์ดํ•ด๋ฅผ ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

//๋‚ด๋ถ€์ ์œผ๋กœ @Controller + @ResponseBody๊ฐ€ ํ•ฉ์ณ์ง„ ์• ๋„ˆํ…Œ์ด์…˜.
//์ด ํด๋ž˜์Šค๋Š” ์›น ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ + ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฆฌํ„ดํ•œ ๊ฑธ ๊ทธ๋Œ€๋กœ HTTP ์‘๋‹ต ๋ฐ”๋””์— ๋„ฃ์Œ
@RestController 

//์ด ํด๋ž˜์Šค ์•ˆ์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ URL ์•ž์— /users๋ฅผ ๋ถ™์—ฌ๋ผ๋Š” ๊ณตํ†ต ๊ฒฝ๋กœ(prefix)์ง€์ •.
@RequestMapping("/users")


// ํด๋ž˜์Šค์— @RequestMapping("/users")
// ๋ฉ”์„œ๋“œ์— @GetMapping("/{id}")  
// ⇒ ์‹ค์ œ URL: GET http://localhost:8080/users/10


// ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ฒฐ๊ตญ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•จ.(๋ฉ”์„œ๋“œ๋ฅผ ๋‹ด์„ ๊ทธ๋ฆ‡์ด ํ•„์š”)
public class UserController{ 

	//1) ์กฐํšŒ: GET
	@GetMapping("{/id}") //GET/user/10
	public UserDto getUser(@PathVariable Long id){
	// @PathVariable ๋กœ URL์˜ {id} ๊ฐ’์„ ๋งคํ•‘
		return service.findById(id);	
	}

	//2) ์ƒ์„ฑ: POST
	@PostMapping( // POST /users
    		// ์š”์ฒญ ๋ฐ”๋”” ํƒ€์ž… ์ œํ•œ(์„ ํƒ)
		consumes = "application/json",
      	 	 // ์‘๋‹ต ํƒ€์ž… ์ œํ•œ(์„ ํƒ)
		produces = "application/json" 
	)

	//3) PUT: ์ „์ฒด ์ˆ˜์ •(์น˜ํ™˜)
	@PutMapping("/{id}") //PUT/users/10
	public UserDto replace(@PathVariable Long id, @RequestBody UpdateUserReq req
	){
		return service.replace(id, req);
	}

	//4) PATCH: ๋ถ€๋ถ„์ˆ˜์ •
	@PathMapping("/{id}") //PATCH/users/10
	public UserDto patch(@PathVariable Long id, @RequestBody Map<String, Object> fields){
		return service.prtialUpdate(id, fields);
	}

	//5) DELETE: ์‚ญ์ œ
	@DeleteMapping("/{id}") //DELETE/users/10
	public void delete(@PathVariable Long id){
		service.delete(id);
	}

}

 

์‹ค์ œ ์ฃผ์†Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค

์‹ค์ œ URL = ์„œ๋ฒ„์ฃผ์†Œ(http://localhost:8080) + ํด๋ž˜์Šค prefix(/users) + ๋ฉ”์„œ๋“œ ๊ฒฝ๋กœ("/{id}" ๊ฐ™์€ ๊ฒƒ)

 

 

๋ฌธ๋ฒ•๋งŒ ๋†“๊ณ  ๋ณด๋ฉด

@RestController
@RequestMapping("/users")  // ๊ณตํ†ต prefix
public class UserController {

    // 1) ์กฐํšŒ(Read, ๋‹จ๊ฑด)
    @GetMapping("/{id}")                     // GET /users/{id}
    public UserDto getUser(@PathVariable Long id) { ... }

    // 2) ์ƒ์„ฑ(Create)
    @PostMapping(                            // POST /users
        consumes = "application/json",
        produces = "application/json"
    )
    public UserDto create(@RequestBody CreateUserReq req) { ... }

    // 3) ์ „์ฒด ์ˆ˜์ •(Replace)
    @PutMapping("/{id}")                     // PUT /users/{id}
    public UserDto replace(@PathVariable Long id,
                           @RequestBody UpdateUserReq req) { ... }

    // 4) ๋ถ€๋ถ„ ์ˆ˜์ •(Patch)
    @PatchMapping("/{id}")                   // PATCH /users/{id}
    public UserDto patch(@PathVariable Long id,
                         @RequestBody Map<String, Object> fields) { ... }

    // 5) ์‚ญ์ œ(Delete)
    @DeleteMapping("/{id}")                  // DELETE /users/{id}
    public void delete(@PathVariable Long id) { ... }
}

 

 

*์ปจํŠธ๋กค๋Ÿฌ = ํด๋ž˜์Šค(๊ทธ๋ฆ‡).
์†”์งํžˆ *์ปจํŠธ๋กค๋Ÿฌ๋งŒ ์žˆ์–ด๋„ ๋Œ์•„๊ฐ€๊ธด ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค๋ฌด์—์„œ๋Š” ๋ณดํ†ต

Controller → Service → Repository(DB)๋กœ ๋‚˜๋ˆ„๊ณ  DTO ๋กœ ์š”์ฒญ/์‘๋‹ต ํ˜•์‹์„ ๋ถ„๋ฆฌํ•œ๋‹ค.

 

๊ตณ์ด ๋‚˜๋ˆ„๋Š” ์ด์œ ๋Š”

 

  • Controller: HTTP์ฒ˜๋ฆฌ(๋งคํ•‘, ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ, ์ƒํƒœ์ฝ”๋“œ ๋“ฑ)๋งŒ 
  • Service: ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง(๊ณ„์‚ฐ, ์ •์ฑ…, ํŠธ๋žœ์žญ์…˜)
  • Repository: DB์ ‘๊ทผ
  • DTO: HTTP์šฉ ๋ฐ์ดํ„ฐ ํฌ๋งท(ํ•„๋“œ๋ช…, ๊ฒ€์ฆ)๊ณผ ๋‚ด๋ถ€ ๋„๋ฉ”์ธ์„ ๋ถ„๋ฆฌ

=> ์•ˆ ๋‚˜๋ˆ„๋ฉด ์ปจํŠธ๋กค๋Ÿฌ ์•ˆ์— ๋กœ์ง/DB์ฝ”๋“œ ๋‹ค ๋•Œ๋ ค๋„ฃ์–ด์„œ ๊ธˆ๋ฐฉ ์ง€์˜ฅ ๋จ

 

๋‚˜๋จธ์ง€ ์˜ˆ์‹œ์ฝ”๋“œ๋„ ๊ฐ™์ด ๋‹ค๋ค„๋ณด๊ฒ ๋‹ค

Service
// src/main/java/com/example/demo/user/UserService.java
package com.example.demo.user;

import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

@Service
public class UserService {
 // ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ„์ด DB์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ Map (key: id, value: UserDto)
    private final Map<Long, UserDto> store = new HashMap<>();
    // ID๋ฅผ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๋ฉฐ ๋ฐœ๊ธ‰ํ•˜๊ธฐ ์œ„ํ•œ ์“ฐ๋ ˆ๋“œ ์•ˆ์ „ํ•œ ์นด์šดํ„ฐ
    private final AtomicLong seq = new AtomicLong(1);

  	// ๋‹จ๊ฑด ์กฐํšŒ: id๋กœ store์—์„œ ์ฐพ์•„ ๋ฐ˜ํ™˜
    public UserDto findById(Long id) {
        return store.get(id);
    }

	// ์ „์ฒด ์กฐํšŒ: store์˜ ๊ฐ’๋“ค๋งŒ ๋ฝ‘์•„์„œ List๋กœ ๋ฐ˜ํ™˜
    public List<UserDto> findAll() {
        return new ArrayList<>(store.values());
    }

    // ์ƒ์„ฑ: ์ƒˆ ID ๋ฐœ๊ธ‰ → DTO ๋งŒ๋“ค๊ณ  → store์— ์ €์žฅ → ์ €์žฅ๋œ DTO ๋ฐ˜ํ™˜
    public UserDto create(CreateUserReq req) {
        Long id = seq.getAndIncrement();// ํ˜„์žฌ ๊ฐ’ ๋ฐ˜ํ™˜ ํ›„ +1
         // ์š”์ฒญ ๋ฐ”๋””๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ DTO ์ƒ์„ฑ
        UserDto dto = new UserDto(id, req.name(), req.email());
        store.put(id, dto);// ๋ฉ”๋ชจ๋ฆฌ ์ €์žฅ
        return dto;
    }

    // ์ „์ฒด ์ˆ˜์ •(์น˜ํ™˜): ๋“ค์–ด์˜จ ๊ฐ’์œผ๋กœ ํ†ต์งธ๋กœ ๋ฎ์–ด์“ฐ๊ธฐ
    public UserDto replace(Long id, UpdateUserReq req) {
        UserDto dto = new UserDto(id, req.name(), req.email());
        store.put(id, dto);// ํ•ด๋‹น id์— ๋ฎ์–ด์”€(์—†์œผ๋ฉด ์ƒˆ๋กœ ๋“ค์–ด๊ฐ)
        return dto;
    }

    // ๋ถ€๋ถ„ ์ˆ˜์ •: ์ „๋‹ฌ๋œ fields(Map)์— ์žˆ๋Š” ๊ฐ’๋งŒ ๊ธฐ์กด ๊ฐ’์—์„œ ๋ฐ”๊ฟ”์น˜๊ธฐ
    public UserDto partialUpdate(Long id, Map<String, Object> fields) {
        UserDto old = store.get(id);// ๊ธฐ์กด ๋ฐ์ดํ„ฐ ์กฐํšŒ
        if (old == null) return null;// ์—†์œผ๋ฉด null (์‹ค๋ฌด์—์„  ์˜ˆ์™ธ ๋˜์ง)

        // ์ƒˆ ๊ฐ’ ์žˆ์œผ๋ฉด ์ƒˆ ๊ฐ’, ์—†์œผ๋ฉด ๊ธฐ์กด ๊ฐ’
        String name  = (String) fields.getOrDefault("name",  old.name());
        String email = (String) fields.getOrDefault("email", old.email());

        UserDto updated = new UserDto(id, name, email);// ์ˆ˜์ •๋œ DTO ์ƒ์„ฑ
        store.put(id, updated); // ์ €์žฅ์†Œ์— ๊ฐฑ์‹ 
        return updated;
    }

    // ์‚ญ์ œ: id๋กœ store์—์„œ ์ œ๊ฑฐ
    public void delete(Long id) {
        store.remove(id);
    }
}

 

dto

 

// src/main/java/com/example/demo/user/dto๋“ค.java
package com.example.demo.user;

// Java 17 record ์˜ˆ์‹œ (๊ฐ„๋‹จ DTO)
public record UserDto(Long id, String name, String email) {}

public record CreateUserReq(String name, String email) {}

public record UpdateUserReq(String name, String email) {}

 

 

ํฌ์ŠคํŠธ๋งจ์œผ๋กœ ํ™•์ธ ์‹œ

 

GET http://localhost:8080/users

POST http://localhost:8080/users (JSON ๋ฐ”๋””)

GET http://localhost:8080/users/1

PUT http://localhost:8080/users/1

PATCH http://localhost:8080/users/1

DELETE http://localhost:8080/users/1
HTTP ํ•œ ๋ฐฉ์— ์ฒ˜๋ฆฌ ํ๋ฆ„
[๋ธŒ๋ผ์šฐ์ €/React] โ”€โ”€HTTP์š”์ฒญโ”€โ”€>[Controller]โ”€>[Service]โ”€>[Repository/DB]
                                   โ”‚          โ”‚                โ”‚
                          (์š”์ฒญ/์‘๋‹ต ์ฒ˜๋ฆฌ) (๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง)(๋ฐ์ดํ„ฐ ์ €์žฅ/์กฐํšŒ)
                                   โ”‚
                               [DTO ๋ณ€ํ™˜]
                                   โ”‚
                             HTTP ์‘๋‹ต(JSON ๋“ฑ)

 

 

 

 

 

 

๋‹ค ํ•„์š” ์—†๊ณ  ์ผ๋‹จ ์•„๋ž˜ ์ฝ”๋“œ๋งŒ ๊ธฐ์–ตํ•ด์•ผ๊ฒ ๋‹ค

@RestController
@RequestMapping("/๋ฆฌ์†Œ์Šค")
public class FooController {

    private final FooService service;
    public FooController(FooService service){ this.service = service; }

    @GetMapping("/{id}")
    public FooDto get(@PathVariable Long id){ return service.get(id); }

    @PostMapping // ์ƒˆ๋กœ๋งŒ๋“ค๊ธฐ๋ผ id๊ฐ€ ์—†์Œ
    public FooDto create(@RequestBody CreateFooReq req){ return service.create(req); }

    @PutMapping("/{id}")
    public FooDto replace(@PathVariable Long id, @RequestBody UpdateFooReq req){ return service.replace(id, req); }

    @PatchMapping("/{id}")
    public FooDto patch(@PathVariable Long id, @RequestBody Map<String,Object> fields){ return service.patch(id, fields); }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id){ service.delete(id); }
}

 

'Backend > ๐ŸŒฑ Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Spring]์˜์กด๊ด€๊ณ„ ์ฃผ์ž…(DI)  (2) 2025.07.28
[Spring]Spring Bean  (2) 2025.07.28
[Spring] Layered Architecture  (3) 2025.07.26
[Spring]MVC  (4) 2025.07.23
[Spring] Spring!  (1) 2025.07.22