간단! Spring Boot에서 WebAPI를 두드려 JSON 형식의 응답을 java 객체로 변환

개요



spring boot를 사용하여 세상에 공개된 webAPI를 두드리자!
이번은 일례로서 일본 우편이 공개하고 있는 「우편 번호 검색 API」를 사용해 보겠습니다. 양식에 입력한 우편번호를 요청 URL에 GET 매개변수로 전달하고 json 형식의 응답을 얻은 후 java로 변환하여 응답 내용을 화면에 표시합니다.

개발 환경
  • macOS Sierra 10.12
  • java version 1.8.0_65
  • Spring-Boot 1.3.5
  • Thymeleaf
  • Gradle


  • 참고 자료
  • 5.17. REST 클라이언트(HTTP 클라이언트)
  • Jackson 사용법 노트
  • 우편 번호 검색 API - zipcloud

  • 완성도




    입력 양식






    송신 결과





    컨트롤러



    /zipcode에 액세스하면 입력 양식의 화면을 표시합니다.
    보내기 버튼을 누르면/zipcode/confirm에 액세스하고 POST 매개 변수로 전달 된 우편 번호를 @RequestParam에서 가져옵니다.
    가져온 우편 번호를 인수로 API를 호출하는 서비스 클래스를 호출합니다. 마지막으로 API 응답을 모델에 넣습니다.
    여기에서는 리스트를 model에 넣어 thymeleaf로 리스트의 정보를 표시하고 있습니다만, controller로 하나씩 model에 넣어도 OK.

    ZipCodeController.java
    @Controller
    public class ZipCodeController {
    
        @Autowired
        ZipCodeService zpcService;
    
        /**
         * 郵便番号入力フォーム
         * @return "zipcode"
         */
        @RequestMapping("/zipcode")
        public String zipcodeForm(HttpSession session, Model model) {
            return "zipcode";
        }
    
        /**
         * 郵便番号情報表示 
         * @return "zipcode-confirm"
         */
        @RequestMapping(value="/zipcode/confirm", method=RequestMethod.POST)
        public String zipcodeConfirm(HttpSession session, Model model, 
                                     @RequestParam("zipcode") String zipcode){
    
            // 一応必須チェックのみ 数字・桁数チェックは省略
            // nullまたは空文字の場合、入力フォームにエラーメッセージを表示
            if (zipcode == null || zipcode.equals("")) {
                model.addAttribute("errorMessage", "郵便番号を入力してください。");
                return zipcodeForm(session, model);
            }
    
            // 郵便番号検索APIサービス呼び出し
            ZipCodeDto zipCodeDto = zpcService.service(zipcode);
            // thymeleafでリストを展開して表示する
            model.addAttribute("zipcodeList", zipCodeDto.getResults());
            return "zipcode-confirm";   
        }
    }
    
    

    서비스



    Controller에서 전달된 우편 번호를 API의 요청 URL과 결합하여 RestTemplate의 postForEntity 메서드의 첫 번째 인수에 전달합니다.

    RestTemplate이란?
    RestTemplate은 REST API(Web API)를 호출하기 위한 메서드를 제공하는 클래스이며 Spring Framework에서 제공하는 HTTP 클라이언트입니다.
    ※자세한 것은 여기 를 참조해 주세요

    response.getBody()로 JSON 문자열을 가져옵니다.


    JSON 문자열





    JSON 문자열을 구문 분석하려면 json 파서 라이브러리의 Jackson을 설치합니다.

    build.gradle
    dependencies {
    compile("com.fasterxml.jackson.core:jackson-databind")
    }
    

    restTemplate의 getForObject 메소드를 제1 인수에 API의 URL, 제2 인수에 받는 DTO, 제3 인수에 API 파라미터를 지정해 호출합니다.

    ZipCodeService.java
    
    @Service
    public class ZipCodeService {
    
        @Autowired
        @Qualifier("zipCodeSearchRestTemplate")
        RestTemplate restTemplate;
    
        /** 郵便番号検索API リクエストURL */
        private static final String URL = "http://zipcloud.ibsnet.co.jp/api/search?zipcode={zipcode}";
    
        public ZipCodeDto service(String zipcode) {
            return restTemplate.getForObject(URL, ZipCodeDto.class, zipcode);
        }
    
    }
    
    

    RestTemplateResolver



    추가
    코멘트에 이하의 지적 받아, RestTemplateResolver 클래스를 작성합니다.

    RestTemplate은 내부에서 HttpMessageConverter를 사용하여 HTTP의 BODY와 Java 객체를 변환하고 있지만 Jackson 용 HttpMessageConverter의 구현 클래스 (MappingJackson2HttpMessageConverter)는 content-type이 application/json이 아닙니다. 요네···.

    RestTemplateResolver.java
    @Component
    public class RestTemplateResolver {
    
        @Bean
        public RestTemplate zipCodeSearchRestTemplate() {
            RestTemplate restTemplate = new RestTemplate();
            MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
            List<MediaType> supportedMediaTypes = new ArrayList<>(messageConverter.getSupportedMediaTypes());
            supportedMediaTypes.add(MediaType.TEXT_PLAIN); // text/plainのJacksonの処理対象にくわえる
            messageConverter.setSupportedMediaTypes(supportedMediaTypes);
            restTemplate.setMessageConverters(Collections.singletonList(messageConverter)); // カスタムしたHttpMessageConverterを適用
            return restTemplate;
        }
    }
    
    

    Dto



    ZipCodeDto.java
        /** ステータス */
        int status;
    
        /** メッセージ */
        String message;
    
        /** 郵便番号情報リスト */
        List<ZipCodeDataDto> results = new ArrayList<>();
    

    ZipCodeDataDto.java
       /** 郵便番号 */
        String zipcode;
    
        /** 都道府県コード */
        String prefcode;
    
        /** 都道府県名 */
        String address1;
    
        /** 市区町村名 */
        String address2;
    
        /** 町域名 */
        String address3;
    
        /** 都道府県名カナ */
        String kana1;
    
        /** 市区町村名カナ */
        String kana2;
    
        /** 町域名カナ */
        String kana3;
    

    ※setter, getter는 생략

    Template



    템플릿 엔진은 thymeleaf를 사용.
    리스트내의 요소를 하나씩 꺼내고 싶은 경우는 th:each="변수 : ${콜렉션}"로 기술할 수 있다. th:object를 정의해 두면 *{변수}로 객체 안의 요소를 얻을 수 있다. 다른 thymeleaf의 기법에 대해서는 여기에서는 할애한다.

    zipcode-confirm.html
    th:each="item : ${zipcodeList}" th:object="${item}"
    th:text="*{zipcode}"
    th:text="*{prefcode}"
    th:text="*{address1}"
    ・
    ・(省略)
    ・
    th:text="*{kana3}"
    

    사용한 코드

    좋은 웹페이지 즐겨찾기