관리 메뉴

LC Studio

JAVA & Spring 강의 (자바 인강 8주차) 웹 개발 개론, 스프링 입문 본문

Java/Java&Spring 기초 강의

JAVA & Spring 강의 (자바 인강 8주차) 웹 개발 개론, 스프링 입문

Leopard Cat 2022. 5. 11. 12:04

Web

(World Wide Web, WWW, W3)

Web Site, API, User Interface 등의 용도가 있다.

 

-URI (Uniform Resource Identifier)

-HTTP (Hypertext Transfer Protocol)

-HTML (Hyper Text Markup Language)

web의 기반이다.


REST

Representational State Transfer (자원의 상태 전달) 

-> 네트워크 아키텍처(네트워크의 근간이 되는 운영 구조)

 

1. Clint, Server : Clint와 Server와의 독립성

2. Stateless : 요청에 대해 클라이언트의 상태를 서버에 저장하지 않는다. (모든 요청은 새롭게)

3. Cache : 클라이언트는 서버의 응답을 임시저장 할 수 있어야 한다.

4. Layered System : 계층형태로 구축하여 확장이 가능해야 한다. (방화벽, 게이트웨이, Proxy 등)

5. 인터페이스의 일관성 : 작은 다위로 분리하여, 클라이언트, 서버가 독립적으로 개선될 수 있어야함

6. Code on Demand : 특정한 기능을 서버로부터 클라이언트가 전달받아 코드를 실행 할 수 있어야 한다.

 

1. 자원의 식별

웹 기반의 REST에서는 리소스를 접근을 할 때 URI 사용, URI 자원식별 정보가 담겨있어야 함

ex) https://foo.co.kr/user/100 -> 100번째 user

Resource : user

식별자 : 100

 

2. 메시지를 통한 리소스 조작

클라이언트와 서버는 일정 규약의 API 스팩을 가지고 통신을 해야함, 서버는 클라이언트에게 메시지를 통해 전달해야 함

네트워크 아키텍처 1. Clint, Server 와도 연결되는 부분, 메시지형태로 전달하지 않으면, 서버의 수정사항 때문에 클라이언트에서 에러가 날 수 있음 

 

3. 자기 서술적 메시지

요청하는 데이터가 어떻게 처리되어야 하는지 충분한 데이터를 포함해야 한다.

 

4. 애플리케이션 상태에 대한 엔진으로써 하이퍼미디어

REST API를 개발할 때 단순히 Client 요청에 대한 데이터만 응답 해주는 것이 아닌, 관련된 리소스에 대한 Link 정보까지 같이 포함 되어져야 한다.


URI 설계 패턴

1. URI (Uniform Resource Identifier)

인터넷에서 특정 자원을 나타내는 주소 값. 유일한 값

요청 : https://www.fastcampus.co.kr/resource/sample/1 

 

응답 : fastcampus.pdf, fastcampus.docx

 

2. URL (Uniform Resource Locator)

인터넷에서 자원, 특정 파일이 어디에 위치하는지 식별하는 주소

요청 : https://www.fastcampus.co.kr/fastcampus.pdf

 

URL은 URI의 하위개념...

 

URI 설계원칙

-슬래시 구분자는( / ) 계층 관계를 나타내는 데 사용한다.

-URI 마지막 문자로 ( / )는 포함하지 않는다.

-하이픈( - )은 URI 가독성을 높이는데 사용한다.

-밑줄( _ )은 사용하지 않는다.

-uri 경로에는 소문자가 적합하다.

-파일 확장자는 uri를 포함하지 않는다.

-언어에 의존적인 확장자를 사용하지 않는다.

-구현에 의존적인 경로(서버이름 등)를 사용하지 않는다.

-세션 ID를 사용하지 않는다.(특정 사용자의 경로)

-프로그래밍 언어의 Method명을 이용하지 않는다.

-명사에 단수형보다 복수형을 사용해야 한다. classX classesO

-컨트롤러 이름으로는 동사나 동사구를 사용한다.

-경로 부분 중 변하는 부분은 유일한 값으로 대체한다.

-CRUD의 기능을 나타내는 것은 URI에 사용하지 않는다.

-URI Query Parameter(쿼리 부분으로 컬렉션 결과해 대해 필터 가능하다)

-URI Query는 컬렉션의 결과를 페이지로 구분하여 나타내는데 사용한다.

-API에 있어 서브 도메인은 일관성있게 사용해야 한다.(api or api-)

-클라이언트 개발자 포탈 서브 도메인은 일관성있게 만든다(dev or developer)


HTTP Protocol

Hypertext Transfer Protocol / 웹에서 데이터를 주고 받는 프로토콜

TCP를 기반으로 한 REST의 특징을 모두 구현하고 있는 Web 기반의 프로토콜

HTTP는 메시지를 주고(Request) 받는(Response) 형태의 통신

 

HTTP요청 Method

HTTP Status Code

1xx 처리중

2xx 성공

3xx 리다이렉트

4xx 클라이언트 에러

5xx 서버에러

 

자주 사용되는 코드

200 성공

201 Put할 경우, 성공, 리소스를 생성 성공

301 리다이렉트, 리소스 다른 장소로 변경

303 리다이렉트, client에서 자동으로 새로운 리소스로 요청 처리

400 요청오류, 파라미터 에러

401 권한없음

404 리소스 없음

500 서버 내부 에러

503 서비스 정지


Spring Boot

-단순하게 실행되며, 프로덕션 제품 수준의 스프링 기반 어플리케이션을 쉡게 만들 수 있다.

-Spring Boot 어플리케이션에는 Spring 구성이 거의 필요하지 않다.

-Spring Boot java-jar로 실행하는 java 어플리케이션을 만들 수 있다.

 

주요목표

-Spring 개발에 대해 빠르고, 광범위하게 적용할 수 있는 환경

-기본값 설정이 있지만 설정을 바꿀 수 있다.

-대규모 프로젝트에 공통적인 비 기능 제공(보안기능, 모니터링 등 프로덕션에 필요한 기능 지원)

-XML 구성 요구사항이 전혀 없음

 

Build Tool

-Maven

-Gradle

 

Servlet Containers

-Tomcat

-Jetty

-Undertow

-Netty


package com.example.hello.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController // 해당 Class를 Rest API를 처리하는 Controller로 설정
@RequestMapping("/api") // RequestMapping URI를 지정해주는 Annotation
public class ApiController {

    @GetMapping("/hello") // http://localhost:8080/api/hello
    public String hello(){
        return "hello spring boot!";
    }
}

get 방식 실습, http://localhost:8080/api/hello

 

Get / Path Variable을 받는 방법

@RestController
@RequestMapping("/api/get")
public class GetApiController {

    //Path Variable
    @GetMapping(path="/hello") // http://localhost:8080/api/get/hello
    public String hello(){
        return "get Hello";
    }

    // @GetMapping("/hi") get / post/ put/ delete 다 됨.
    @RequestMapping(path = "/hi", method = RequestMethod.GET) // get 만 됨 http://localhost:8080/api/get/hi
    public String hi(){
        return "get hi";
    }

    @GetMapping("/path-variable/{name}") // http://localhost:8080/api/get/path/path-variable/{name}
    public String pathVariable(@PathVariable String name){ //변화하는 부분에 대한 것은 @PathVariable로 받음 /주소의 변수명과 @PathVariable의 변수명은 같아야 함
        System.out.println("PathVariable : "+name);
        return name;
    }

@GetMapping 통한 path 지정,

@RequestMapping을 통한  path 지정,

@GetMapping을 통한 변화하는 주소 지정

 

Get / Query Parameter을 받는 방법

//Query Parameter
    //검색할 때 여러가지 매개변수 인자
    //ex) 구글 intellij 검색
    //https://www.google.com/
    // search? q = intellij
    // &oq = intellij
    // &aqs = chrome..69i57j69i59l4j0i512l2j69i61.2600j0j7
    // &sourceid = chrome
    // &ie = UTF-8
    // ?로 시작해서 Key = Value 형태

    // http://localhost:8080/api/get/query-param?user=steve&email=steve@naver.com&age=30
    @GetMapping(path = "query-param")
    public String queryParam(@RequestParam Map<String, String> queryParam){

        StringBuilder sb = new StringBuilder();



        queryParam.entrySet().forEach(entry->{
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
            System.out.println("\n");

            sb.append(entry.getKey()+" = "+entry.getValue()+"\n");

        });

        return sb.toString();
    }

    @GetMapping("query-param02")
    public String queryParam02(
        @RequestParam String name,
        @RequestParam String email,
        @RequestParam int age
    ){
        System.out.println(name);
        System.out.println(email);
        System.out.println(age);

        return name+" "+email+" "+age;
    }

    @GetMapping("query-param03")
    public String queryParam03(UserRequest userRequest){
        System.out.println(userRequest.getName());
        System.out.println(userRequest.getEmail());
        System.out.println(userRequest.getAge());

        return userRequest.toString();
    }

Map으로 연결해서 받는 방법,

받은 값을 @RequestParam으로 지정해 받는 방법,

아래와같이 객체를 미리 정의하여 받는 방법이 있다.

package com.example.hello.dto;

public class UserRequest {

    private String name;
    private String email;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "UserRequest{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

PUT

package com.example.put;

import com.example.put.dto.PostRequestDto;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class PutApiController {

    @PutMapping("/put/{userId}")
    public PostRequestDto put(@RequestBody PostRequestDto requestDto, @PathVariable(name = "userId") Long id){
        System.out.println(requestDto);
        System.out.println(id);
        return requestDto;
    }
}

@putMapping을 통해 Put Resource 설정,

@RequestBody를 통해 Request Body부분 파싱

@PathVariable을 통해 URL Path Variable Parsing


DELETE

package com.example.delete.controller;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class DeleteApiController {
    
    @DeleteMapping("/delete/{userId}")
    public void delete(@PathVariable String userId, @RequestParam String account){
        
        System.out.println(userId);
        System.out.println(account);
    }
}

@DeleteMapping / Delete Resource 설정

@RequestParam / URL Query Param 파싱

@PathVariable / URL Path Variable 파싱

Object Query Param Object로 파싱


스프링에서 응답을 내려주는 방식

 

package com.example.response.controller;

import com.example.response.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class ApiController {

    //text
    @GetMapping("/text")
    public String text(@RequestParam String account){
        return account;
    }

    //json
    @PostMapping("/json")
    public User json(@RequestBody User user){
        return user;
    }

    //ResponseEntity
    @PutMapping("/put")
    public ResponseEntity<User> put(@RequestBody User user){
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }
}

text, json, responseEntity 예시

 

package com.example.response.controller;

import com.example.response.dto.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class PageController {

    @RequestMapping("/main")
    public String main(){
        return "main.html";
    }

    //ResponseBody
    @ResponseBody
    @GetMapping("/user")
    public User user(){
        var user = new User();
        user.setName("steve");
        user.setAddress("패스트캠퍼스");
        return user;
    }
}

위와같이 html로 반환하고, Json도 내려줄 수 있음, 하지만 이와같은 Json응답방식은 추천하지 않음

 

package com.example.response.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
@JsonInclude(JsonInclude.Include.NON_NULL) //null값은 안보여줌
public class User {

    private String Name;
    private int age;
    private String phoneNumber;
    private String address;

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "Name='" + Name + '\'' +
                ", age=" + age +
                ", phoneNumber='" + phoneNumber + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

위는 기본적인 User 클래스, 특이점,

@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) //클래스 이름 스네이크 케이스 변환
@JsonInclude(JsonInclude.Include.NON_NULL) //null값은 안보여줌

Object Mapper

var objectMapper = new ObjectMapper();

		//Object -> Text
		//Object mapper get method를 활용한다

		var user = new User("steve",100, "010-2134-4352");
		var text = objectMapper.writeValueAsString(user);
		System.out.println(text);

		// Text -> Object
		// Object mapper은 default 생성자를 필요로 한다

		var objectUser = objectMapper.readValue(text, User.class);
		System.out.println(objectUser);

// Object -> Text
아래처럼 Object mapper get method를 활용한다,

즉 get이 있어야하고 get으로 시작하는 다른 메서드가 존재하면 오류가 난다.

public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

// Text -> Object
아래처럼 Object mapper은 default 생성자를 필요로 한다

public User(){
        this.name = null;
        this.age = 0;
        this.phoneNumber = null;
    }

아래는 User Class 전체코드

package com.example.objectmapper;

import com.fasterxml.jackson.annotation.JsonProperty;

public class User {
    private String name;
    private int age;
    @JsonProperty("phone_number")
    private String phoneNumber;

    public User(){
        this.name = null;
        this.age = 0;
        this.phoneNumber = null;
    }

    public User(String name, int age, String phoneNumber){
        this.age = age;
        this.name = name;
        this.phoneNumber = phoneNumber;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", phoneNumber='" + phoneNumber + '\'' +
                '}';
    }
}

Object -> Text 결과

Text -> Object 결과

반응형