[Web_3] Spring 3 ๐Ÿ‹

08627ยท2022๋…„ 9์›” 19์ผ
1

Spring

๋ชฉ๋ก ๋ณด๊ธฐ
3/13
post-thumbnail

๐Ÿ“Œ REST API
๐Ÿ“Œ RestController
๐Ÿ“Œ PathVariable
๐Ÿ“Œ DTO
๐Ÿ“Œ ResponseEntity
๐Ÿ“Œ @Autowired / @Qualifier


๐Ÿ’ก REST API

REST๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” API (Application Programming Interface)

๐ŸฆŽ REST (Representational State Transfer)

HTTP ์‚ฌ์šฉ ํ‘œ์ค€๋ฒ•์œผ๋กœ ์ œ์‹œ๋œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„ํ‚คํ…์ฒ˜. ์ž์›์„ ํ‘œํ˜„์œผ๋กœ์จ(์ž์›์„ URI๋กœ ํ‘œํ˜„ํ•˜๋Š” ํ˜•ํƒœ๋กœ ์š”์ฒญํ•˜์—ฌ) ๊ทธ ์ž์›์˜ ์ƒํƒœ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š”๋‹ค.

๐Ÿฆ– REST์˜ ๊ตฌ์„ฑ

  • ์ž์›(RESOURCE)
    ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฃจ๋Š” ๋ฐ์ดํ„ฐ, ๊ฐ์ฒด ๋“ฑ์˜ ๊ฒƒ
    ๋‹ค๋ฅธ ์ž์›๊ณผ ๊ตฌ๋ณ„๋˜๋Š” ๊ณ ์œ ํ•œ HTTP URI๋ฅผ ๊ฐ€์ง„๋‹ค.

  • ํ‘œํ˜„(Representations)
    ์ž์›์˜ ์ƒํƒœ ์š”์ฒญ์— ๋Œ€ํ•œ ์„œ๋ฒ„์˜ ์‘๋‹ต
    ๋ฐ์ดํ„ฐ ์ž์ฒด๋ฅผ ์‘๋‹ต์œผ๋กœ ์ œ๊ณตํ•จ (JSON, XML, TEXT ... ๋“ฑ์˜ ํ˜•ํƒœ)

  • ํ–‰์œ„(Verb)
    HTTP METHOD (CRUD : GET / POST / PUT / DELETE)

์ฆ‰, ๋ฐ์ดํ„ฐ๊ฐ€ (CRUD) ์š”์ฒญ๋  ๋•Œ ๊ณ ์œ ํ•œ HTTP URI๋ฅผ ๊ฐ€์ง„ ๋ฆฌ์†Œ์Šค๊ฐ€ ์ฒ˜๋ฆฌ๋˜์–ด ์‘๋‹ต์œผ๋กœ ์ œ๊ณต๋˜๋ฉฐ ์ž์›์˜ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•จ

๐Ÿฆ– REST์˜ ํŠน์ง•

  • Server-Client(์„œ๋ฒ„-ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ)
    : ์„œ๋ฒ„๋Š” API(๊ธฐ๋Šฅ)๋งŒ์„ ์ œ๊ณตํ•˜๊ฒŒ ๋จ. ํด๋ผ์ด์–ธํŠธ์™€์˜ ์—ญํ• ์ด ๋‚˜๋ˆ„์–ด์ง„๋‹ค.
  • Stateless(๋ฌด์ƒํƒœ์„ฑ)
    : ๋“ค์–ด์˜จ ์š”์ฒญ๋งŒ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์Œ.
  • Cacheable(์บ์‹œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ)
    : HTTP ํ”„๋กœํ† ์ฝœ ํ‘œ์ค€์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ผ ์บ์‹œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•จ.
  • Layered System(๊ณ„์ธตํ™”)
    : ๋‹ค์ค‘ ๊ณ„์ธต
  • Uniform Interface(์ธํ„ฐํŽ˜์ด์Šค ์ผ๊ด€์„ฑ)
    : ์ž์› ์ฒ˜๋ฆฌ๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ผ๊ด€์„ฑ์„ ๊ฐ–์ถค.
  • Self-descriptiveness(์ž์ฒด ํ‘œํ˜„์„ฑ)
    : REST API ๋งŒ ๋ณด์•„๋„ ์ดํ•ด ๊ฐ€๋Šฅํ•ด์•ผ ํ•จ.
    - URI๊ฐ€ ๋ฆฌ์†Œ์Šค๋ฅผ ๋ช…์‹œํ•จ. (๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉ, ํ–‰์œ„๋ฅผ ํ‘œํ˜„ํ•˜์ง€ ์•Š๋Š”๋‹ค.)
    - ํ–‰์œ„๋Š” HTTP Method(GET, POST, PUT, DELETE)๋กœ ํ‘œํ˜„ํ•จ.

๐ŸฆŽ RestController

REST๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ URI๋ฅผ ํ†ตํ•ด ๋ฆฌ์†Œ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋˜๋Š” Controller


๐Ÿ’ก PathVariable @pathvariable

RestController ์—์„œ๋Š” URI๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ํ‘œํ˜„ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋จ.
โžก๏ธ URI ๋ฅผ ๋ณ€์ˆ˜๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒŒ @pathvariable ์–ด๋…ธํ…Œ์ด์…˜

๋งคํ•‘ ์ฃผ์†Œ์— {๋ณ€์ˆ˜๋ช…}์„ ํฌํ•จํ•˜์—ฌ URI๋ฅผ ์ง€์ •ํ•ด์ฃผ๊ณ ,
๋งคํ•‘ ์ฃผ์†Œ์— ๋„ฃ์„ ๋ฉ”์†Œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ์— @pathvariable์„ ์ž‘์„ฑํ•ด์ค€๋‹ค.


๐Ÿ’ก DTO (Data Transfer Object)

๊ณ„์ธต ๊ฐ„(Controller, View, Business Layer)์— ๋ฐ์ดํ„ฐ ๊ตํ™˜์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด

Controller๋Š” Model์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„ View๋กœ ์ „๋‹ฌํ•œ๋‹ค.
Model์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์„ ๋•Œ, DTO๋กœ์„œ ์ „๋‹ฌํ•˜์—ฌ Model๊ณผ View ์‚ฌ์ด์˜ ์˜์กด์„ฑ์„ ํ•ด์ฒดํ•ด ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

RestController์—์„œ๋Š” DTO๋ฅผ ์ด์šฉํ•ด GET, POST, UPDATE, DELETE ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.


๐Ÿ’ก ResponseEntity

ddd

RequestEntity<T>์™€ ResponseEntity<T>๋Š” ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•˜๋Š” HttpEnityt<T> ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•œ๋‹ค.

โ€ป HttpEnityt<T> ํด๋ž˜์Šค๋Š” ์š”์ฒญ / ์‘๋‹ต์˜ HttpHeader์™€ HttpBody๋ฅผ ๊ฐ€์ง.

์‚ฌ์ง„์ฒ˜๋Ÿผ RequestEntity๋กœ ์š”์ฒญ์„ ๋ฐ›์•„์™€์„œ ์Šคํ”„๋ง RestApi๋ฅผ ํ†ตํ•ด ์š”์ฒญ ์ฒ˜๋ฆฌ ํ›„ ResponseEntity ๋กœ ์‘๋‹ตํ•ด์ฃผ๋Š” ์‹


๐Ÿฆ– ResponseEntity<T>
ํด๋ผ์ด์–ธํŠธ์˜ HttpRequest ์š”์ฒญ ์‹œ
HttpStatus(์ƒํƒœ ์ฝ”๋“œ), HttpHeaders, HttpBody ์‘๋‹ต ๋ฐ์ดํ„ฐ ๋ฅผ ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค.

@ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด Body๋ฅผ ๋ณด๋ƒˆ๋˜ ๊ฒƒ์— ์ถ”๊ฐ€์ ์œผ๋กœ ์ƒํƒœ ์ฝ”๋“œ์™€ ํ—ค๋” ์ •๋ณด๋ฅผ ์‘๋‹ตํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ‘พ EX. ResponseEntity

@RestController
public class ResponseEntityController {

	@GetMapping("/api/v1/entity/data1")
    public ResponseEntity<?> getData() { // โžก๏ธbody , status ๋งŒ ์‘๋‹ต
        return new ResponseEntity<String>("ResponseEntity ์‘๋‹ต", HttpStatus.OK);
    }

    @GetMapping("/api/v1/entity/data2")
    public ResponseEntity<?> getData2() { // โžก๏ธheader , status๋งŒ ์‘๋‹ต
    
        MultiValueMap<String, String> headers = new HttpHeaders();

        headers.add("test-token1", UUID.randomUUID().toString());
        headers.add("test-token2", UUID.randomUUID().toString());
        headers.add("test-token3", UUID.randomUUID().toString());

        return new ResponseEntity<String>(headers, HttpStatus.OK);
    }

    @GetMapping("/api/v1/entity/data3")
    public ResponseEntity<?> getData3() { // โžก๏ธbody, header , status ์‘๋‹ต
        MultiValueMap<String, String> headers = new HttpHeaders();

        headers.add("test-token1", UUID.randomUUID().toString());
        headers.add("test-token2", UUID.randomUUID().toString());
        headers.add("test-token3", UUID.randomUUID().toString());

        return new ResponseEntity<String>("test", headers, HttpStatus.OK);
    }

    @GetMapping("/api/v1/entity/data4")
    public ResponseEntity<?> getData4() { // โžก๏ธbody ์— DTO๋กœ์จ ์‘๋‹ตํ•จ
        MultiValueMap<String, String> headers = new HttpHeaders();

        headers.add("test-token1", UUID.randomUUID().toString());
        headers.add("test-token2", UUID.randomUUID().toString());
        headers.add("test-token3", UUID.randomUUID().toString());

        return new ResponseEntity<>( // โญ Constructor ์‚ฌ์šฉ
                new CMRespDto<>(1, "์ „์†ก ์„ฑ๊ณต", "ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ"),
                headers,
                HttpStatus.OK);
    }

    @GetMapping("/api/v1/entity/data5")
    public ResponseEntity<?> getData5() { 
        โ—HttpHeaders headers = new HttpHeaders();
        headers.add("token1", "aaaa1111");

        return ResponseEntity // โญ Builder ์‚ฌ์šฉ (๊ถŒ์žฅ)
                .ok()
                .headers(headers)
                .body(new CMRespDto<>(1, "๋ฉ”์„ธ์ง€", "test"));
    }
@AllArgsConstructor
โญ@Getter 
public class CMRespDto<T> {
    private int code; // 1 : ์„ฑ๊ณต, -1 : ์‹คํŒจ
    private String msg; // commit ๋ฉ”์„ธ์ง€
    private T data; // ์‘๋‹ต ๋ฐ์ดํ„ฐ
}

Response
์Šคํ”„๋ง์—์„œ๋Š” ์‘๋‹ตํ•  MediaType์„ ์‹๋ณ„ํ•˜๊ณ , ํ•ด๋‹น MediaType์œผ๋กœ ์‘๋‹ต์„ ๋งŒ๋“ค์–ด์ค„ ๋•Œ DTO์˜ Getter๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค.
๋”ฐ๋ผ์„œ ResponseEntity์˜ Body์— ๋„ฃ์–ด์ค„ DTO ๊ฐ์ฒด์—๋Š” @Getter ์–ด๋…ธํ…Œ์ด์…˜์„ ๊ผญ ๋‹ฌ์•„์ค€๋‹ค !

โž• Request ์ผ ๋•Œ๋„ ..
Ajax๋ฅผ ํ†ตํ•ด formData ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋ฉด, ์Šคํ”„๋ง์ด HTML ํŒŒ์ผ ์ƒ์˜ formData ํ˜•ํƒœ์—์„œ DTO ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ฒฝ์šฐ์—๋„ DTO ๊ฐ์ฒด์— @Getter ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
์ด๊ฑธ ๊นŒ๋จน๊ณ  ์™œ ์•ˆ๋Œ€๋‚˜ ํ–ˆ์Œ ์ง„์งœ (ฮฆ็šฟฮฆ)


๐Ÿ’ก @Autowired

์Šคํ”„๋ง ์—์„œ๋Š” ์Šคํ”„๋ง IoC ์ปจํ…Œ์ด๋„ˆ์— ์‚ฌ์šฉํ•˜๋Š” ๋นˆ(์˜์กด์„ฑ์„ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด)๋“ค์„ ์ฃผ์ž…ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

application.xml ์— bean ๋“ฑ๋ก์„ ํ•ด์ฃผ์–ด์•ผ ํ•จ.
ํ˜น์€ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•  ๋นˆ ํด๋ž˜์Šค์— โญ@Component ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€ํ•˜๋ฉด ์Šคํ”„๋ง์—์„œ ์ž๋™์œผ๋กœ ๋นˆ ๋“ฑ๋ก์„ ํ•ด์ค€๋‹ค.

<@Component ๋ฅผ ์ƒ์†ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜ : ์ž๋™์œผ๋กœ ๋นˆ ๋“ฑ๋ก ๋จ>

   @Service				โžก๏ธ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค์— ๋‹ฌ์•„์ค€๋‹ค. 
    
   @Repository			โžก๏ธ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๊ฒฐํ•˜๋Š” DAO ํด๋ž˜์Šค์— ๋‹ฌ์•„์ค€๋‹ค. 
    
   @Controller			โžก๏ธ  ์‚ฌ์šฉ์ž ์š”์ฒญ์„ ์ œ์–ดํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค์— ๋‹ฌ์•„์ค€๋‹ค. 

โžก๏ธ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๋Š”(์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ๊ฐ€์ ธ์˜ฌ) ๋ถ€๋ถ„์— @Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ๋‹ฌ์•„์„œ ์ž๋™์œผ๋กœ ์˜์กด์„ฑ ์ฃผ์ž…๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ’ก @Qualifier

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๊ฐ™์€ ํƒ€์ž…์˜ ๋นˆ์„ 2๊ฐœ ์ด์ƒ ๋“ฑ๋กํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด ๋นˆ์— ์ด๋ฆ„ ๊ฐ’(์‹๋ณ„์ž)์„ ์ฃผ๊ณ  @Qualifier ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์˜์กด ๊ฐ์ฒด๋ฅผ ์„ ํƒํ•ด์•ผ ํ•œ๋‹ค.


๐Ÿ‘พ EX. @Autowired / @Qualifier

โ—ฝ UserRestController.java

@Slf4j
@RestController
@RequestMapping("/api/v1")
public class UserRestController {

    @Autowired
    @Qualifier("a") // โญ a๋กœ ์ง€์ •๋œ Repository๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” ๋œป
    private UserRepository userRepository;

    @GetMapping("/users/{userCode}") //  path variable
    public ResponseEntity<?> getUser(@PathVariable int userCode) {
    
        User user = userRepository.findUserByUserCode(userCode);
        return ResponseEntity
        			.ok()
                    .body(user);
        // โญ ๋นŒ๋” ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ResponseEntity์˜         
        // 	Status์— OK ์ƒํƒœ ์ฝ”๋“œ, Body์— user ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„ ๋ฆฌํ„ดํ•จ.  
    }

    @PostMapping("/user")
    public ResponseEntity<?> addUser(UserAddReqDto userAddReqDto) {
    
        int result = userRepository.save(userAddReqDto.toEntity());
        
        if(result == 0) { // save() ๋ฆฌํ„ด๊ฐ’์ด 0์ด๋ฉด ์‹คํŒจ
            return ResponseEntity
            			.internalServerError()
                        .body("๋ฐ์ดํ„ฐ ์˜ค๋ฅ˜(Server)");
        }
        return ResponseEntity
        				.ok()
                        .body("์‚ฌ์šฉ์ž ์ถ”๊ฐ€ ์™„๋ฃŒ");
    }
}

ํด๋ž˜์Šค์— @RequestMapping ์— ์„ค์ •ํ•œ URI๋ž‘ ๋ฉ”์†Œ๋“œ์— @Get โ€ข Post Mapping ์— ์ค€ URI๊ฐ€ ํ•ฉ์ณ์ง„๋‹ค.
@GetMapping ๋งคํ•‘ ์ฃผ์†Œ โžก๏ธ http://localhost:8000/api/v1/users/1 ์ด ๋˜๋Š” ๊ฒƒ์ž„.

โ—ฝ UserAddReqDto.java

@Data
public class UserAddReqDto { 
    private String userId;
    private String userPassword;
    private String userName;
    private String userEmail;

    public User toEntity() { 	// Dto๋กœ ์ •๋ณด๋ฅผ ๋ฐ›์•„์„œ User๋กœ ๋ฐ”๊พธ์–ด์ค„ ๊ฒƒ์ž„. 
        return User.builder() 	// User ; user_code, ... ์„ ๊ฐ€์ง
                .user_id(userId)
                .user_password(userPassword)
                .user_name(userName)
                .user_email(userEmail)
                .build();
    }
}

โ—ฝ UserRepositoryImpl.java

@Repository("a") // โญ ์ด ํด๋ž˜์Šค๊ฐ€ ์ด๋ฆ„(์‹๋ณ„์ž) a๋กœ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋จ. 
public class UserRepositoryImpl implements UserRepository{

    private final List<User> userData;

    public UserRepositoryImpl() { // ์ƒ์„ฑ์ž
        userData = new ArrayList<User>();

        for(int i = 0; i < 5; i++) { // DB ์ƒ์„ฑ ์‹œ user1 ~ user5 ๊นŒ์ง€ ๋งŒ๋“ค์–ด ๋‘ . 
            int index = i + 1;

            User user = User.builder()
                    .user_code(index)
                    .user_id("user" + index)
                    .user_name("1111")
                    .user_password("user" + index)
                    .user_email("user" + index + "@")
                    .build();

            userData.add(user);
        }
    }

	/* ๐Ÿ’ซ save(user)
     * userData ๋ฅผ ๋๊นŒ์ง€ ๋ฐ˜๋ณตํ•˜์—ฌ
     * ๋” ํฐ userCode๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๋งˆ๋‹ค maxCode๋ฅผ ๊ฐฑ์‹ ํ•œ๋‹ค. 
     * ๊ฐ€์žฅ ํฐ maxCode ๊ฐ’์— 1์„ ๋”ํ•ด์„œ
     * ์ €์žฅํ•  user ์ •๋ณด์˜ userCode ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด์ค„ ๊ฒƒ     
     */
    @Override
    public int save(User user) {
        try {
            int maxCode = 0;
            for(User userObj : userData){
                if(userObj.getUser_code() > maxCode) { 
                    maxCode = userObj.getUser_code();
                }
            }
            maxCode++; 
            
            user.setUser_code(maxCode); 
            userData.add(user); // userData์— user ์ถ”๊ฐ€ํ•จ. 
            
        }catch (Exception e) {
            return 0; // ์‹คํŒจ
        }
        return 1; // ์„ฑ๊ณต
    }

	
    @Override
    public User findUserByUserCode(int userCode) {
        User user = null;

        for(User userObj: userData) {
            if(userObj.getUser_code() == userCode) {
                user = userObj;
            }
        }
        return user;
    }
}



- ์ฐธ๊ณ  ๐Ÿง™
REST API ์ œ๋Œ€๋กœ ์•Œ๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ
REST API๋ž€? REST, RESTful์ด๋ž€?
์˜ค๋Š˜์€ @pathvariable ์–ด๋…ธํ…Œ์ด์…˜!
ResponseEntity, HttpEntity๋ž€?
@ResponseBody ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ์ฒด์— getter๊ฐ€ ์—†์„ ๊ฒฝ์šฐ
@Autowired ๋ถ„์„!
@Qualifier ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ๋ฒ•
Java Bean VS Spring Bean
Using ResponseEntity in Spring




๐Ÿ“ข ์†Œ๊ฐ ๐Ÿ‹
์ƒˆ๋ฒฝ์ด๋‹ค. ๋ฐฐ๊ฐ€ ๊ณ ํ”„๋‹ค๐Ÿฅบ

0๊ฐœ์˜ ๋Œ“๊ธ€