■ 이번 페이지는 https://coding-mid-life.tistory.com/60?category=1287134  에서 작성된 Controller 예제의 개선을 진행한다

 

Spring MVC - Controller (MVC 개요/핸들러 메서드)

1. Controller 클래스 설계 및 구조 생성 API 계층을 Spring MVC 기반의 코드로 구현해 본다  1) 애플리케이션 경계 설정 커피 주문 애플리케이션으로 설정  2) 애플리케이션 기능 요구사항 수집 기능적

coding-mid-life.tistory.com

 

1. MemberComtroller 개선

  • ResponseEntity를 사용한다
    - ResponseEntity는 HttpEntity의 확장 클래스이다
    - HttpStatus 상태 코드를 추가한 전체 HTTP응답을 표현한다(상태코드, 헤더, 본문)
    - @Controller @RestController 애너테이션이 붙은 Controller 클래스의 핸들러 메서의 요청에 대한 응답을 표현한다
    - RestTemplate에서 외부 API통신에 대한 응답을 전달받아서 표현할 경우에 사용한다

  • Map 과 HashMap을 사용한다

 1) 기존 작성 코드

package com.dreamfactory.exam_controller.member;

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

import java.sql.SQLOutput;

@RestController

@RequestMapping(value ="v1/members", produces = MediaType.APPLICATION_JSON_VALUE)

public class MemberController {
    @PostMapping
    public String postMember(@RequestParam("email")String email,
                             @RequestParam("name")String name,
                             @RequestParam("phone")String phone) {        
        System.out.println("# email: " + email);
        System.out.println("# name: " + name);
        System.out.println("# phone: " + phone);
       
        //---> code change <---
        String reponse =
                "{\"" +
                    "email\":\""+email+"\"," +
                    "\"name\":\""+name+"\",\"" +
                    "phone\":\"" + phone+
                "\"}";
        return reponse;
    }

    @GetMapping("/{member-id}")    
    public String getMember(@PathVariable("member-id")long memberId) {
        
        System.out.println("# memberId: " + memberId);

        //not implementation
        return null;
    }

    @GetMapping 
    public String getMembers() {
        System.out.println("# get Members");

        //not implementation
        return null;
    }
}
  • 위의 코드에서 다음 부분이 개선이 우선된다
    - JSON 형식으로 응답을 받기 위해 작성된 코드이다
String reponse =
                "{\"" +
                    "email\":\""+email+"\"," +
                    "\"name\":\""+name+"\",\"" +
                    "phone\":\"" + phone+
                "\"}";
        return reponse;
  • 위의 수동 코드를 Map 메서드를 사용하여 개선하였다
//JSON문자열 응답 타입을 수작업 코드에서 Map객체로 변경->produce애트리뷰트를 삭제할 수 있다
//MAp 객체를 리턴하면 내부적으로 응답 데이터를 JSON데이터로 자동 변환해야 한다고 인식한다
Map<String, String> map = new HashMap<>();
map.put("email", email);
map.put("name", name);
map.put("phone", phone);
//리턴 값을 변경된 ResponseEntity로 대체
//ResponseEntity 객체를 생성하고 생성자 파라미터로 map과 HttpStatus.CREATED를 반환한다
//HttpStatus.CREATED 는 201, created를 의미한다
return new ResponseEntity<>(map, HttpStatus.CREATED)
  • 전체적으로 개선된 코드는 아래와 같다
  • getMember()와 getMembers() 핸들러 메서드도 ResponseEntity 객체를 리턴하고 HttpStatus.OK의 응답을 전송하는 것으로 수정되었다
package com.dreamfactory.exam_controller.member;

import ch.qos.logback.classic.util.LogbackMDCAdapter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.sql.SQLOutput;
//@애터테이션에 의해 자동으로 import 된다

import java.util.HashMap;
import java.util.Map;


@RestController
//Spring MVC에서는 특정 클래스에 @RestController 를 추가하면 해당 클래스가 REST API의 리소스(자원, Resource)를
  처리하기 위한 API 엔드포인트로 동작함을 정의한다
//@RestController가 추가된 클래스는 애플리케이션 로딩 시, Spring Bean 으로 등록 해 준다
//REST API란 REST 방식을 통해서 리소스에 접근하기 위한 서비스 API를 지칭한다
//REST(Representational State Transfer)는 HTTP 네트워크 상의 리소스(Resource, 자원)를 정의하고 
  해당 리소스를 URI라는 고유의 주소로 접근하는 접근 방식을 의미한다

@RequestMapping("v1/members"/*,produce=MediaType.APPLICATION_JSON_VALUE*/)
//produces애트리뷰트(Attribute)는 응답 데이터를 어떤 미디어 타입으로 클라이언트에게 전송할 지를 설정한다


public class MemberController {
    @PostMapping

    //postMember() 메서드는 회원 정보를 등록해주는 핸들러 메서드이다
    //클라이언트의 요청 데이터(request body)를 서버에 생성할 때 사용하는 애너테이션이다
    //클라이언트에서 요청 전송 시 HTTP Method 타입을 동일하게 맞춰 주어야 한다(POST)
    public /*String*/ResponseEntity postMember(@RequestParam("email")String email,
                                                  @RequestParam("name")String name,
                                                  @RequestParam("phone")String phone) {
        //@RequestParam() 핸들러 메서드의 파라미터 종류 중 하나이다
        /*클라이언트에서 전송하는 요청 데이터를 쿼리 파라미터(Query Parmeter 또는 Query String),
        폼 데이터(form-data), x-www-form-urlencoded 형식으로 전송하면 서버 쪽에서 전달 받을 때
        사용하는 애너테이션이다*/

//        System.out.println("# email: " + email);
//        System.out.println("# name: " + name);
//        System.out.println("# phone: " + phone);

//        JSON문자열 응답 타입을 수작업 코드에서 Map객체로 변경->produce애트리뷰트를 삭제할 수 있다
            //MAp 객체를 리턴하면 내부적으로 응답 데이터를 JSON데이터로 자동 변환해야 한다고 인식한다
            Map<String, String> map = new HashMap<>();
            map.put("email", email);
            map.put("name", name);
            map.put("phone", phone);
            //리턴 값을 변경된 ResponseEntity로 대체
            //ResponseEntity 객체를 생성하고 생성자 파라미터로 map과 HttpStatus.CREATED를 반환한다
            //HttpStatus.CREATED 는 201, created를 의미한다
            return new ResponseEntity<>(map, HttpStatus.CREATED);


        //클라이언트 쪽에서 JSON 형식의 데이터를 전송 받아야 하기 때문에
        //응답 문자열을 JSON 형식에 맞게 작성한다
//        String reponse =
//                "{\"" +
//                    "email\":\""+email+"\"," +
//                    "\"name\":\""+name+"\",\"" +
//                    "phone\":\"" + phone+
//                "\"}";
//        return reponse;
    }

    @GetMapping("/{member-id}")
    //@GetMapping은 클라이언트가 서버에 리소스를 조회할 때 사용하는 애너테이션이다
    //@GetMapping 애너테이션의 괄호 안에는 몇 가지 애트리뷰트(Attribute)를 사용할 수 있다
    //여기서는 전체 HTTP URI의 일부를 지정했다
    //클라이언트에서 getMember() 핸들러 메서드에 요청을 보낼 경우, 최종 URI는 형태는 아래와 같다
    // /v1/members/{member-id}
    //{member-id}는 회원 식별자를 의미한다
    //클라이언트가 요청을 보낼 때 URI로 어떤 값을 지정하느냐에 따라서 동적으로 바뀌는 값이다

    public /*String*/ResponseEntity getMember(@PathVariable("member-id")long memberId) {
        //getMember() 메서드는 특정 회원의 정보를 클라이언트 쪽에 제공하는 핸들러 메서드이다

        //@PathVariable역시 핸들러 메서드의 파라미터 종류 중 하나이다
        //@PathVariable의 괄호 안에 입력한 문자열 값은 @GetMapping("/{member-id}") 처럼 중괄호({ })
          안의 문자열과 동일해야 한다
        //여기서는 두 문자열 모두 “member-id” 로 동일하게 지정했다
        //두 문자열이 다르면 MissingPathVariableException이 발생한다

        System.out.println("# memberId: " + memberId);
        //리턴 값을 변경된 ResponseEntity로 대체
        //HttpStatus.OK 는 200, OK를 의미한다
        return new ResponseEntity<>(HttpStatus.OK);
        //not implementation
//        return null;
    }

    @GetMapping //별도의 URI를 지정해주지 않았기 때문에 클래스 레벨의 URI(“/v1/members”)에 매핑된다

    //getMembers() 메서드는 회원 목록을 클라이언트에게 제공하는 핸들러 메서드이다
    public /*String*/ResponseEntity getMembers() {
        System.out.println("# get Members");
        //리턴 값을 변경된 ResponseEntity로 대체
        //HttpStatus.OK 는 200, OK를 의미한다
        return new ResponseEntity<>(HttpStatus.OK);
        //not implementation
//        return null;
    }
}
  • 수정된 코드를 실행한 후 postman에서 post로 request한 결과는 아래와 같다
  • map에 의한 파라미터 값과 HttpStatus.CREATED의 결과값 201 Created가 반환된다
  • ResponseEntity를 사용하지 않았던 코드의 결과값 200 OK 가 변경된 결과이다

  • CoffeeController 와 OrderController 도 개선된 코드로 수정한다
  • CoffeeController 
package com.dreamfactory.exam_controller.coffee;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping(value="v1/coffees", produces = MediaType.APPLICATION_JSON_VALUE)
//v1은 버젼을 의미한다. coffees는 데이터 post, get 의 조회 위치를 의미한다

public class CoffeeController {
    @PostMapping

    //postCoffee() 메서드는 커피 정보를 등록해 준다
    public /*String*/ResponseEntity postCoffee(@RequestParam("coffee")String coffee,
                                                 @RequestParam("coffeeId")String coffeeId,
                                                 @RequestParam("korName")String korName,
                                                 @RequestParam("engName")String engName,
                                                 @RequestParam("price")int price) {
//        System.out.println("# coffee:" + coffee);
//        System.out.println("# coffeeId:" + coffeeId);
//        System.out.println("# korName:" + korName);
//        System.out.println("# engName:" + engName);
//        System.out.println("# price:" + price);

        //Map객체로 변경
            Map<String, String> map = new HashMap<>();
            map.put("coffee", coffee);
            map.put("coffeeId", coffeeId);
            map.put("korName", korName);
            map.put("engName", engName);
            map.put("price", String.valueOf(price));

            //return 값을 ResponseEntity로 변경
        return new ResponseEntity<>(map, HttpStatus.CREATED);

//        String reponse =
//                "{\"" +
//                    "coffee\":\""+coffee+"\"," +
//                    "\"coffeeId\":\""+coffeeId+"\"," +
//                    "\"korName\":\""+korName+"\"," +
//                    "\"engName\":\""+engName+"\"," +
//                    "\"price\":\""+price+
//                "\"}";
//        return reponse;
    }

    @GetMapping("/{coffee-id}")

    //getCoffee() 메서드는 커피 정보을 클라이언트에게 제공하는 핸들러 메서드이다
    public /*String*/ResponseEntity getCoffee(@PathVariable("coffee-id")long coffeeId) {
        System.out.println("# coffeeId: " + coffeeId);
        return new ResponseEntity<>(HttpStatus.OK);
        }

    @GetMapping //별도의 URI를 지정해주지 않았기 때문에 클래스 레벨의 URI(“/v1/coffees”)에 매핑된다

    //getCoffees() 메서드는 커피 목록을 클라이언트에게 제공하는 핸들러 메서드이다
    public /*String*/ResponseEntity getCoffees() {
        System.out.println("# get Coffees");
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

 

  • OrderController
package com.dreamfactory.exam_controller.order;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping(value="v1/orders"/*, produces = MediaType.APPLICATION_JSON_VALUE*/)

public class OrderController {
    @PostMapping

    //postOrder() 메서드는 커피 주문 정보를 등록한다
    public /*String*/ResponseEntity postOrder(@RequestParam("memberId") String memberId,
                                              @RequestParam("coffeeId") String coffeeId) {

        Map<String, String> map = new HashMap<>();
        map.put("memberId", memberId);
        map.put("coffeeId", coffeeId);

        return new ResponseEntity(map, HttpStatus.CREATED);
//        System.out.println("# memberId:" + memberId);
//        System.out.println("# coffeeId:" + coffeeId);
//
//        String reponse =
//                "{\"" +
//                        "memberId\":\"" + memberId + "\"," +
//                        "\"coffeeId\":\"" + coffeeId +
//                        "\"}";
//        return reponse;
    }

    @GetMapping("/{order-id}")
    public /*String*/ResponseEntity getOrder(@PathVariable("order-id") long orderId) {
        System.out.println("# orderId: " + orderId);
        return new ResponseEntity(HttpStatus.OK);
    }

    @GetMapping //별도의 URI를 지정해주지 않았기 때문에 클래스 레벨의 URI(“/v1/orders”)에 매핑된다

    //getOrders() 메서드는 주문 목록을 클라이언트에게 제공하는 핸들러 메서드이다
    public /*String*/ResponseEntity getOrders() {
        System.out.println("# get Orders");
        return new ResponseEntity(HttpStatus.OK);
    }
}

 

 

※ 참조 링크

▶ ResponseEntity : https://itvillage.tistory.com/44

 

ResponseEntity 알아보기

ResponseEntity란? ResponseEntity는 HttpEntity의 확장 클래스로써 HttpStatus 상태 코드를 추가한 전체 HTTP 응답(상태 코드, 헤더 및 본문)을 표현하는 클래스입니다. ResponseEntity를 어디에 사용할 수 있나..

itvillage.tistory.com

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html

 

ResponseEntity (Spring Framework 5.3.21 API)

Extension of HttpEntity that adds an HttpStatus status code. Used in RestTemplate as well as in @Controller methods. In RestTemplate, this class is returned by getForEntity() and exchange(): ResponseEntity entity = template.getForEntity("https://example.co

docs.spring.io

 

■ HashMap

1. 정의

  • HashMap은 key와 value 값으로 구성된다
    - HashMap(key, value)
    - key 값은 중복되면 않된다
    - value 값은 중복될 수 있다 
  • HashMap = Hash Table 에 저장 = 배열(Array) + 링크드리스트(LinkedList) 로 구성된다
  • HashMap은 순서를 유지하지 않아도 된다
     - 순서를 유지하고 싶다면 LikedHashMap을 사용하면 된다
  • HashMap은 Hashing 기법으로 만들어진다
HashMap map = new HasgMap();
map.put("key", "value");  //저장하기 위한 명령어로 put를 사용한다
  • key와 value 값 한쌍을 Entry라고 한다

2. Hashing

  • hash function은 key값을 받아서 해당되는 index 값(저장위치)을 반환하는 함수이다
  • 반환되는 index 값을 hash code라고 한다
  • hash 함수를 이용하여 hash 테이블에 데이터를 저장하고 반환하는 작업을 hashing이라고 한다
    - key값이 같으면 항상 같은 값을 반환한다
    - key값이 달라도 같은 값을 반환할 수 있다
  • hash table은 배열과 링크드 리스트의 조합이다
    - 배열의 접근성과 링크드리스트의 변경 용이성을 모두 가지고 있다

3. HashMap 메서드

 1) HashMap

  • HashMap()
  • HashMap(int initialCapacity)
  • HashMap(int initialCapacity, float loadFactor)
  • HashMap(Map m)

 

 2) Object Method

  • Object put(Object key, Object value)
    - 데이터를 저장할 때 사용한다
    - key와 value를 묶어서 저장한다(key=value)
  • void putAll(Map m)
    - 지정한 Map m의 값을 모두 저장할 때 사용한다
  • Object remove(Object key)
    - key 데이터를 삭제할 때 사용한다
  • Object replace(Object key, object value)
    - 지정한 key의 value를 변경할 때 사용한다
  • boolean replace(Object key, Object oldValue, Object newValue)
    - 지정한 key에 해당되는 value를 변경할 때 사용한다

 3) HashMap에 저장된 데이터를 읽어오는 Method

  • Set entrySet()
    - key와 value 쌍으로 구성된 데이터를 호출한다
  • Set keySet()
    - key 데이터만 호출한다
  • Collection value()
    - value 데이터만 호출한다

 4) HashMap에 저장된 데이터를 조회하는 Method

  • Object get(Object key)
    - 지정한 key에 해당하는 value를 반환한다
  • Object getOrDefault(Object key, Object defaultValue)
    - 주어진 key가 데이터에 없을 경우, 지정한 defaultValue 데이터를 반환한다
  • boolean containsKey(object key)
    - 주어진 key가 key 데이터에 있는지 여부를 확인한다
    - true / false 로 반환한다
  • boolean containsValue(Object vaalue)
    - 주어진 value가 value 데이터에 있는지 여부를 확인한다
    - true / false 로 반환한다

 5) 정량적 Method

  • int size()
    - 데이터의 크기를 확인한다
    boolean isEmpty()
    - 데이터가 비었는지 확인한다
  • void clear()
    - 데이터를 삭제한다
  • Object clone()
    - 데이터를 복제한다

 

4. 예제

import java.util.HashMap;
import java.util.Scanner;

public class HashMap_IdPw {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("Id1", "1111");
        map.put("Id2", "2222");
        map.put("Id3", "3333");
//        System.out.println(map);

        Scanner scanner = new Scanner(System.in);

        while (true) {  //반복문을 실행
            System.out.println("Id와 Pw를 입력하세요");
            System.out.println("Id : ");
            String id = scanner.nextLine().trim();  //trim 은 앞 뒤 공백을 없애준다
            System.out.println("Pw : ");
            String pw = scanner.nextLine().trim();

            System.out.println();  //줄바꿈 역활

            if (!map.containsKey(id)) {  //containsKey는 key 값 전체를 가리킨다
                System.out.println("일치하는 id가 없습니다" + "\n" + "다시 입력해 주시기 바랍니다");
                continue;  //다음 반복 while 문으로 이동
            }

            if (!map.get(id).equals(pw)) {  //get(id)는 key 값 중에 id와 일치하는 값이 있으면  value 값을 반환한다
                System.out.println("비밀번호가 일치하지 않습니다" + "\n" + "다시 입력해 주시기 바랍니다");
            } else {  //id와 pw가 일치하면 문장 출력 후 반복문 털출
                System.out.println("id와 비밀번호가 일치합니다");
                break;
            }
        }
    }
}
import java.util.*;

public class HashMap_SumAverage {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("kim", 90);
        map.put("lee", 50);
        map.put("cha", 80);
        map.put("park", 100);
        map.put("choi", 70);
//        System.out.println(map);

        //전체 map에 저장된 데이터에서 값을 호출,조회하는 코드

        Set set = map.entrySet();  //map에 저장된 데이터를 key,value 쌍으로 호출한다
        Iterator iter = set.iterator();  //set에 데이터가 남아 있는지 확인한다

        while(iter.hasNext()) {
            Map.Entry me = (Map.Entry)iter.next();  //Map 인터페이스 안의 Entry 인터페이스
            System.out.println("이름 : " + me.getKey() + ", 점수 : " + me.getValue());
        }

        //전체 map에서 key 데이터만을 호출하는 코드
        set = map.keySet();  //key에 저장된 값만 가져온다
        System.out.println("참가자 명단 : " + set);

        //전체 map에서 value 데이터만을 호출하는 코드
        Collection values = map.values();  //value 데이터를 가져온다
        iter = values.iterator();

        int total = 0;

        while(iter.hasNext()) {  //hasNext()는 읽어 올 요소가 남았는지 확인한다
            int i = (int)iter.next();  //next() 메소드는 읽어 올 요소가 남았는지 확인한다
            total = total +i;
        }

        System.out.println("총점 : " + total);
        System.out.println("평균 : " + (float)total/set.size());  //정수로 결과값이 나오므로 float로 형변환 해 준다
        System.out.println("최고점수 : "+ Collections.max(values));
        System.out.println("최저점수 : "+ Collections.min(values));
   }
}

 

 

 

'JAVA' 카테고리의 다른 글

Java - HashMap 활용 - 합계, 평균  (0) 2022.09.14
Java - 문자열 바꾸기 - replace  (0) 2022.09.13
Java - Static  (0) 2022.08.14
Java - 문자열 입력(Scanner, BufferReader)  (0) 2022.08.08
Java - 날짜(Date), 시간(Time)  (0) 2022.08.08

+ Recent posts