0.1 시작 전 Gradle 설정 내용 확인

https://minaminaworld.tistory.com/218

 

[SpringBoot] 멀티 데이터베이스 설정하기 - 설정편

1. Gradle 설정 dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'junit:junit..

minaminaworld.tistory.com

0.2 JPA 설정편 확인: JPA에서 생성한 데이터를 읽어오는 테스트 코드 작성함

https://minaminaworld.tistory.com/219

 

[SpringBoot] 멀티 데이터베이스(DB) 설정하기 JPA 편

0. 시작 전 Gradle 설정 내용 확인 https://minaminaworld.tistory.com/218 [SpringBoot] 멀티 데이터베이스 설정하기 - 설정편 1. Gradle 설정 dependencies { implementation 'org.springframework.boot:spring-..

minaminaworld.tistory.com


1. 테스트 DB, 스키마, 테이블 정보

 - 테스트 DB명: db1

 - 테스트 스키마: jpa

 - 테스트 테이블: userjpa (Jpa Option: create를 통한 자동 생성함)

 

 


2. application.yml 과 application-local.yml

 - application.yml

spring:
  profiles:
    active: local

- application-local.yml

spring:
  config:
    activate:
      on-profile: local
  datasource:
    jpa:
      #     jdbc-url: jdbc:postgresql://localhost:5432/db1
      url: jdbc:postgresql://localhost:5432/db1
      username: postgres
      password: postgres
      driver-class-name: org.postgresql.Driver
    mybatis:
      #      jdbcUrl: jdbc:postgresql://localhost:5432/db1
      url: jdbc:postgresql://localhost:5432/db1
      username: postgres
      password: postgres
      driver-class-name: org.postgresql.Driver
server:
  port: 8090 # 서버 포트 변경

2. MybatisDbProperties.java

package com.example.multidb.database.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "spring.datasource.mybatis") // application-local.yml 참고
@Getter
@Setter
public class MybatisDbProperties {
    String url;
    String username;
    String password;
    String driverClassName;
}

3. mybatis-config.xml 작성 (* resources 폴더 생성)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="cacheEnabled" value="true" />
        <setting name="useColumnLabel" value="true" />
        <setting name="useGeneratedKeys" value="false" />
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <setting name="defaultStatementTimeout" value="25000" />
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <setting name="jdbcTypeForNull" value="NULL"/>
    </settings>
    <typeAliases>
        <!-- 오탈자 조심 -->
        <package name="com.example.multidb.domain.mybatis"/>
    </typeAliases>
</configuration>

4. UserMybatis.java: 테이블 읽어올 항목 작성(VO 생성)

package com.example.multidb.domain.mybatis;

import javax.persistence.Column;

public class UserMybatis {
    private Long id;
    private String name;
    private String email;
    private int age;

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

5. UserMybatisMapper.java와 UserMybatisMapper.xml 작성

- UserMybatisMapper.java

package com.example.multidb.persistence.mybatis.mapper;

import com.example.multidb.domain.mybatis.UserMybatis;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.Map;

@Repository
public interface UserMybatisMapper {
    public ArrayList<UserMybatis> getUsers() throws Exception;
}

- UserMybatisMapper.xml : namespace 부분 확인하시면서 하세요. 오탈자 조심

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.multidb.persistence.mybatis.mapper.UserMybatisMapper">

    <select id="getUsers" resultType="com.example.multidb.domain.mybatis.UserMybatis">
            SELECT * FROM jpa.userjpa;
    </select>

</mapper>

6. MybatisDb.java

package com.example.multidb.database.config;

import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
@RequiredArgsConstructor
@MapperScan(
        basePackages = {"com.example.multidb.persistence.mybatis.mapper"}
)
public class MybatisDb {

    private final MybatisDbProperties mybatisDbProperties;

    @Bean(name = "mybatisDataSource")
    public DataSource dataSource() {
        // 빌더 dataSource 생성
        // 프로퍼티 정보
        System.out.println("------------------------------------------");
        String url = mybatisDbProperties.getUrl();
        String username = mybatisDbProperties.getUsername();
        String password = mybatisDbProperties.getPassword();
        String driverClassName = mybatisDbProperties.getDriverClassName();

        System.out.println("url = " + url);
        System.out.println("username = " + username);
        System.out.println("password = " + password);
        System.out.println("driverClassName = " + driverClassName);
        System.out.println("------------------------------------------");

        return  DataSourceBuilder.create()
                .url(mybatisDbProperties.getUrl())
                .username(mybatisDbProperties.getUsername())
                .password(mybatisDbProperties.getPassword())
                .driverClassName(mybatisDbProperties.getDriverClassName())
                .build();
    }

    @Bean(name = "mybatisSessionFactory")
//    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("mybatisDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setTypeAliasesPackage("com.example.multidb.domain.jpa");
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
        sessionFactoryBean.setMapperLocations(resolver.getResources("classpath*:mybatis/mapper/**/*.xml"));
        return sessionFactoryBean.getObject();
    }

    @Bean(name = "mybatisSqlSessionTemplate")
    public SqlSessionTemplate firstSqlSessionTemplate(@Qualifier("mybatisSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

6. MybatisService.java 및 테스트 코드 작성

- MybatisService.java

package com.example.multidb.service;

import com.example.multidb.domain.jpa.UserJpa;
import com.example.multidb.domain.mybatis.UserMybatis;
import com.example.multidb.persistence.jpa.repository.UserJpaRepository;
import com.example.multidb.persistence.mybatis.mapper.UserMybatisMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;

@Service
@RequiredArgsConstructor
public class MybatisService {
    private final UserMybatisMapper userMybatisMapper;

    @Transactional(readOnly = true)
    public void readUser() {
        try {
            ArrayList<UserMybatis> users = userMybatisMapper.getUsers();
            for (UserMybatis user : users) {
                System.out.println("user = " + user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

- MybatisServiceTest.java

package com.example.multidb.service;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class mybatisServiceTest {

    @Autowired
    private MybatisService mybatisService;

    @Test
    @DisplayName("JPA에서 생성한 유저 읽어오기")
    void readUser() {
        mybatisService.readUser();
    }
}

7.  결과화면

 

블로그 이미지

미나미나미

,

0. 시작 전 Gradle 설정 내용 확인

https://minaminaworld.tistory.com/218

 

[SpringBoot] 멀티 데이터베이스 설정하기 - 설정편

1. Gradle 설정 dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'junit:junit..

minaminaworld.tistory.com


1. 테스트 DB, 스키마, 테이블 정보

 - 테스트 DB명: db1

 - 테스트 스키마: jpa

 - 테스트 테이블: userjpa (Jpa Option: create를 통한 자동 생성함)

 

 


2. application.yml 과 application-local.yml

 - application.yml

spring:
  profiles:
    active: local

- application-local.yml

spring:
  config:
    activate:
      on-profile: local
  datasource:
    jpa:
      #     jdbc-url: jdbc:postgresql://localhost:5432/db1
      url: jdbc:postgresql://localhost:5432/db1
      username: postgres
      password: postgres
      driver-class-name: org.postgresql.Driver
    mybatis:
      #      jdbcUrl: jdbc:postgresql://localhost:5432/db1
      url: jdbc:postgresql://localhost:5432/db1
      username: postgres
      password: postgres
      driver-class-name: org.postgresql.Driver
server:
  port: 8090 # 서버 포트 변경

3. JpaDbProperties.java : 데이터베이스 설정 정보 세팅(yml 참고)

package com.example.multidb.database.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "spring.datasource.jpa") // application-local.yml 참고
@Getter
@Setter
public class JpaDbProperties {
    String url;
    String username;
    String password;
    String driverClassName;
}

4. UserJpa.java와 UserJpaRepository.java

- UserJpa.java

package com.example.multidb.domain.jpa;

import lombok.*;
import javax.persistence.*;

@Entity
@SequenceGenerator(
        name = "USER_SEQ_GEN", // 시퀀스 제너레이터 이름
        sequenceName = "USER_SEQ", // 시퀀스 이름
        initialValue = 1,
        allocationSize = 1 // 메모리를 통해 할당할 범위 사이즈
)
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(schema = "jpa")
public class UserJpa {

    @Id
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "USER_SEQ_GEN"
    )
    private Long id;

    private String name;

    @Column(unique = true, nullable = false)
    private String email;

    private int age;

    public UserJpa(String name, String email, int age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }

}

- UserJpaRepository.java

package com.example.multidb.persistence.jpa.repository;

import com.example.multidb.domain.jpa.UserJpa;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserJpaRepository extends JpaRepository<UserJpa, Long> {

}

4. JpaDb.java: DB 설정하기

 - 1번과 2번 방식 동일하게 DataSouce를 생성할 수 있음으로 참고하시길 바랍니다.

 

package com.example.multidb.database.config;

import com.google.common.collect.ImmutableMap;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef = "jpaEntityManagerFactory",
        transactionManagerRef = "jpaTransactionManager",
        basePackages = {"com.example.multidb.persistence.jpa.repository"} // Repository 위치
)
@RequiredArgsConstructor
public class JpaDb {
//// 1번 방식 ----------------------------------------------------------------------------
//    @Bean
//    @ConfigurationProperties(prefix = "spring.datasource.jpa")
//    public DataSourceProperties jpaDataSourceProperties() {
//        DataSourceProperties dataSourceProperties = new DataSourceProperties();
//        return dataSourceProperties;
//    }
//
//    @Bean(name = "jpaDataSource")
//    public DataSource dataSource(@Qualifier("jpaDataSourceProperties") DataSourceProperties dataSourceProperties) {
//        // 프로퍼티 정보
//        String url = dataSourceProperties.getUrl();
//        String username = dataSourceProperties.getUsername();
//        String password = dataSourceProperties.getPassword();
//        String driverClassName = dataSourceProperties.getDriverClassName();
//
//        System.out.println("------------------------------------------");
//        System.out.println("url = " + url);
//        System.out.println("username = " + username);
//        System.out.println("password = " + password);
//        System.out.println("driverClassName = " + driverClassName);
//        System.out.println("------------------------------------------");
//
//        return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
//    }
//// ---------------------------------------------------------------------------- 1번 방식

    // 2번 방식 ----------------------------------------------------------------------------
    private final JpaDbProperties jpaDbProperties;

    @Primary
    @Bean(name = "jpaDataSource")
    public DataSource dataSource() {
        // 빌더 dataSource 생성

        // 프로퍼티 정보
        System.out.println("------------------------------------------");
        String url = jpaDbProperties.getUrl();
        String username = jpaDbProperties.getUsername();
        String password = jpaDbProperties.getPassword();
        String driverClassName = jpaDbProperties.getDriverClassName();

        System.out.println("url = " + url);
        System.out.println("username = " + username);
        System.out.println("password = " + password);
        System.out.println("driverClassName = " + driverClassName);
        System.out.println("------------------------------------------");

        return  DataSourceBuilder.create()
                .url(jpaDbProperties.getUrl())
                .username(jpaDbProperties.getUsername())
                .password(jpaDbProperties.getPassword())
                .driverClassName(jpaDbProperties.getDriverClassName())
                .build();
    }
    // ---------------------------------------------------------------------------- 2번 방식

    @Bean(name = "jpaEntityManagerFactory")
    @Primary
    public EntityManagerFactory entityManagerFactory(
            @Qualifier("jpaDataSource") DataSource dataSource
    ) {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(dataSource);
        factory.setPackagesToScan(new String[]{"com.example.multidb.domain.jpa"}); //Entity 위치
        factory.setPersistenceUnitName("jpa");

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setJpaPropertyMap(ImmutableMap.of(
                "hibernate.hbm2ddl.auto", "create",
//                "hibernate.hbm2ddl.auto", "create-drop",
                "hibernate.dialect", "org.hibernate.dialect.PostgreSQL10Dialect",
                "hibernate.show_sql", "true",
                "hibernate.format_sql", "true",
                "hibernate.open-in-view", "false"
        ));
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    @Bean(name = "jpaTransactionManager")
    @Primary
    public PlatformTransactionManager transactionManager(@Qualifier("jpaEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(entityManagerFactory);
        return tm;
    }

}

5. JpaService.java와 JpaServiceTest.java: UserJpa 생성 서비스 코드와 테스트 작성

- JpaService.java

package com.example.multidb.service;

import com.example.multidb.domain.jpa.UserJpa;
import com.example.multidb.persistence.jpa.repository.UserJpaRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class JpaService {

    private final UserJpaRepository userJpaRepository;

    @Transactional
    public void createUser(String name, String email, int age) {
//        UserJpa userJpa = new UserJpa("A", "a@email.com", 20);
        userJpaRepository.save(new UserJpa(name, email, age));
    }
}

- JpaServiceTest.java

package com.example.multidb.service;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class JpaServiceTest {

    @Autowired
    private JpaService jpaService;

    @Test
    @DisplayName("JPA 유저 생성")
    void createUser() {
        //        UserJpa userJpa = new UserJpa("A", "a@email.com", 20);
        for (int i = 0; i < 10; i++) {
            jpaService.createUser("A" + i, "a" + i + "@email.com", 20 + i);
        }
    }
}

6. 테스트 결과


 

블로그 이미지

미나미나미

,

1. Gradle 설정

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    testImplementation 'junit:junit:4.13.1'

    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    // postgresql
    // https://mvnrepository.com/artifact/org.postgresql/postgresql
    implementation group: 'org.postgresql', name: 'postgresql'

    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"

    // mybatis -----
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc:2.6.7'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'
    // ----- mybatis

    // lombok -----
    annotationProcessor 'org.projectlombok:lombok'
    // ----- lombok

    // 다중 DB JPA 속성 관련
    implementation group: 'com.google.guava', name: 'guava', version: '31.1-jre'
}

 

블로그 이미지

미나미나미

,

# 사전준비: OpenAPI Key를 발급받습니다.

https://www.data.go.kr/data/15057210/openapi.do


1.  공공데이터포털 API Response 데이터를 활용 받은 JSON 정보를 받을 DTO 생성

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

public class WthrHourDto {

    @JsonProperty("response")
    private Response response;

    public Response getResponse() {
        return response;
    }

    public void setResponse(Response response) {
        this.response = response;
    }

    public static class Response {
        @JsonProperty("body")
        private Body body;
        @JsonProperty("header")
        private Header header;

        public Body getBody() {
            return body;
        }

        public void setBody(Body body) {
            this.body = body;
        }

        public Header getHeader() {
            return header;
        }

        public void setHeader(Header header) {
            this.header = header;
        }
    }

    public static class Body {
        @JsonProperty("totalCount")
        private int totalCount; // 데이터 총 개수
        @JsonProperty("numOfRows")
        private int numOfRows; // 한 페이지당 표출 수
        @JsonProperty("pageNo")
        private int pageNo; // 페이지 수
        @JsonProperty("items")
        private Items items; //
        @JsonProperty("dataType")
        private String dataType; // 응답 자료 형식

        public int getTotalCount() {
            return totalCount;
        }

        public void setTotalCount(int totalCount) {
            this.totalCount = totalCount;
        }

        public int getNumOfRows() {
            return numOfRows;
        }

        public void setNumOfRows(int numOfRows) {
            this.numOfRows = numOfRows;
        }

        public int getPageNo() {
            return pageNo;
        }

        public void setPageNo(int pageNo) {
            this.pageNo = pageNo;
        }

        public Items getItems() {
            return items;
        }

        public void setItems(Items items) {
            this.items = items;
        }

        public String getDataType() {
            return dataType;
        }

        public void setDataType(String dataType) {
            this.dataType = dataType;
        }
    }

    public static class Items {
        @JsonProperty("item")
        private List<Item> item;

        public List<Item> getItem() {
            return item;
        }

        public void setItem(List<Item> item) {
            this.item = item;
        }
    }

    public static class Item {
        @JsonProperty("m03Te")
        private String m03Te; // 30cm 지중 온도(섭씨)
        @JsonProperty("m02Te")
        private String m02Te; // 20cm 지중 온도(섭씨)
        @JsonProperty("m01Te")
        private String m01Te; // 10cm 지중 온도(섭씨)
        @JsonProperty("m005Te")
        private String m005Te; // 5cm 지중 온도(섭씨)
        @JsonProperty("tsQcflg")
        private String tsQcflg; // 지면 온도 품질 검사 플래그
        @JsonProperty("ts")
        private String ts; // 지면 온도(섭씨)
        @JsonProperty("dmstMtphNo")
        private String dmstMtphNo; // 현상번호(국내식)
        @JsonProperty("gndSttCd")
        private String gndSttCd; // 지면상태 => 종료 16.7.1.00 시
        @JsonProperty("vs")
        private String vs; // 시정(10m)
        @JsonProperty("lcsCh")
        private String lcsCh; // 최저운고(100m)
        @JsonProperty("clfmAbbrCd")
        private String clfmAbbrCd; // 운형(운형약어)
        @JsonProperty("dc10LmcsCa")
        private String dc10LmcsCa; // 중하층운량(10분위)
        @JsonProperty("dc10Tca")
        private String dc10Tca; // 전운량(10분위)
        @JsonProperty("hr3Fhsc")
        private String hr3Fhsc; // 3시간 신적설(cm)
        @JsonProperty("dsnw")
        private String dsnw; // 적설(cm)
        @JsonProperty("icsr")
        private String icsr; // 일사(MJ/m2): 지표면에 도달한 태양복사에너지. 태양복사(단파복사)를 말하지만 여러 요인들로 인해 태양상수보다 작게 나온다.
        @JsonProperty("ssQcflg")
        private String ssQcflg; // 일조 품질검사 플래그
        @JsonProperty("ss")
        private String ss; // 일조(hr): 태양 광선이 구름이나 안개로 가려지지 않고 땅 위를 비치는 것
        @JsonProperty("psQcflg")
        private String psQcflg; // 일조 품질검사 플래그
        @JsonProperty("ps")
        private String ps; // 해면기압
        @JsonProperty("paQcflg")
        private String paQcflg; // 해면기압 품질검사 플래그
        @JsonProperty("pa")
        private String pa; // 현지기압(hPa)
        @JsonProperty("td")
        private String td; // 이슬점온도(섭씨)
        @JsonProperty("pv")
        private String pv; // 증기압(hPa)
        @JsonProperty("hmQcflg")
        private String hmQcflg; // 습도 품질검사 플래그
        @JsonProperty("hm")
        private String hm; // 습도(%)
        @JsonProperty("wdQcflg")
        private String wdQcflg; // 풍향 품질검사 플래그
        @JsonProperty("wd")
        private String wd; // 풍향(16방위)
        @JsonProperty("wsQcflg")
        private String wsQcflg; // 풍향 품질검사 플래그
        @JsonProperty("ws")
        private String ws; // 풍속(m/s)
        @JsonProperty("rnQcflg")
        private String rnQcflg; // 강수량 품질검사 플래그
        @JsonProperty("rn")
        private String rn; // 강수량(mm)
        @JsonProperty("taQcflg")
        private String taQcflg; // 기온 품질검사 플래그
        @JsonProperty("ta")
        private String ta; // 기온(섭씨)
        @JsonProperty("stnNm")
        private String stnNm; // 종관기상관측 지점명
        @JsonProperty("stnId")
        private String stnId; // 지점 번호
        @JsonProperty("rnum")
        private String rnum; // 목록 순서
        @JsonProperty("tm")
        private String tm; // 시간

        public String getM03Te() {
            return m03Te;
        }

        public void setM03Te(String m03Te) {
            this.m03Te = m03Te;
        }

        public String getM02Te() {
            return m02Te;
        }

        public void setM02Te(String m02Te) {
            this.m02Te = m02Te;
        }

        public String getM01Te() {
            return m01Te;
        }

        public void setM01Te(String m01Te) {
            this.m01Te = m01Te;
        }

        public String getM005Te() {
            return m005Te;
        }

        public void setM005Te(String m005Te) {
            this.m005Te = m005Te;
        }

        public String getTsQcflg() {
            return tsQcflg;
        }

        public void setTsQcflg(String tsQcflg) {
            this.tsQcflg = tsQcflg;
        }

        public String getTs() {
            return ts;
        }

        public void setTs(String ts) {
            this.ts = ts;
        }

        public String getDmstMtphNo() {
            return dmstMtphNo;
        }

        public void setDmstMtphNo(String dmstMtphNo) {
            this.dmstMtphNo = dmstMtphNo;
        }

        public String getGndSttCd() {
            return gndSttCd;
        }

        public void setGndSttCd(String gndSttCd) {
            this.gndSttCd = gndSttCd;
        }

        public String getVs() {
            return vs;
        }

        public void setVs(String vs) {
            this.vs = vs;
        }

        public String getLcsCh() {
            return lcsCh;
        }

        public void setLcsCh(String lcsCh) {
            this.lcsCh = lcsCh;
        }

        public String getClfmAbbrCd() {
            return clfmAbbrCd;
        }

        public void setClfmAbbrCd(String clfmAbbrCd) {
            this.clfmAbbrCd = clfmAbbrCd;
        }

        public String getDc10LmcsCa() {
            return dc10LmcsCa;
        }

        public void setDc10LmcsCa(String dc10LmcsCa) {
            this.dc10LmcsCa = dc10LmcsCa;
        }

        public String getDc10Tca() {
            return dc10Tca;
        }

        public void setDc10Tca(String dc10Tca) {
            this.dc10Tca = dc10Tca;
        }

        public String getHr3Fhsc() {
            return hr3Fhsc;
        }

        public void setHr3Fhsc(String hr3Fhsc) {
            this.hr3Fhsc = hr3Fhsc;
        }

        public String getDsnw() {
            return dsnw;
        }

        public void setDsnw(String dsnw) {
            this.dsnw = dsnw;
        }

        public String getIcsr() {
            return icsr;
        }

        public void setIcsr(String icsr) {
            this.icsr = icsr;
        }

        public String getSsQcflg() {
            return ssQcflg;
        }

        public void setSsQcflg(String ssQcflg) {
            this.ssQcflg = ssQcflg;
        }

        public String getSs() {
            return ss;
        }

        public void setSs(String ss) {
            this.ss = ss;
        }

        public String getPsQcflg() {
            return psQcflg;
        }

        public void setPsQcflg(String psQcflg) {
            this.psQcflg = psQcflg;
        }

        public String getPs() {
            return ps;
        }

        public void setPs(String ps) {
            this.ps = ps;
        }

        public String getPaQcflg() {
            return paQcflg;
        }

        public void setPaQcflg(String paQcflg) {
            this.paQcflg = paQcflg;
        }

        public String getPa() {
            return pa;
        }

        public void setPa(String pa) {
            this.pa = pa;
        }

        public String getTd() {
            return td;
        }

        public void setTd(String td) {
            this.td = td;
        }

        public String getPv() {
            return pv;
        }

        public void setPv(String pv) {
            this.pv = pv;
        }

        public String getHmQcflg() {
            return hmQcflg;
        }

        public void setHmQcflg(String hmQcflg) {
            this.hmQcflg = hmQcflg;
        }

        public String getHm() {
            return hm;
        }

        public void setHm(String hm) {
            this.hm = hm;
        }

        public String getWdQcflg() {
            return wdQcflg;
        }

        public void setWdQcflg(String wdQcflg) {
            this.wdQcflg = wdQcflg;
        }

        public String getWd() {
            return wd;
        }

        public void setWd(String wd) {
            this.wd = wd;
        }

        public String getWsQcflg() {
            return wsQcflg;
        }

        public void setWsQcflg(String wsQcflg) {
            this.wsQcflg = wsQcflg;
        }

        public String getWs() {
            return ws;
        }

        public void setWs(String ws) {
            this.ws = ws;
        }

        public String getRnQcflg() {
            return rnQcflg;
        }

        public void setRnQcflg(String rnQcflg) {
            this.rnQcflg = rnQcflg;
        }

        public String getRn() {
            return rn;
        }

        public void setRn(String rn) {
            this.rn = rn;
        }

        public String getTaQcflg() {
            return taQcflg;
        }

        public void setTaQcflg(String taQcflg) {
            this.taQcflg = taQcflg;
        }

        public String getTa() {
            return ta;
        }

        public void setTa(String ta) {
            this.ta = ta;
        }

        public String getStnNm() {
            return stnNm;
        }

        public void setStnNm(String stnNm) {
            this.stnNm = stnNm;
        }

        public String getStnId() {
            return stnId;
        }

        public void setStnId(String stnId) {
            this.stnId = stnId;
        }

        public String getRnum() {
            return rnum;
        }

        public void setRnum(String rnum) {
            this.rnum = rnum;
        }

        public String getTm() {
            return tm;
        }

        public void setTm(String tm) {
            this.tm = tm;
        }

        @Override
        public String toString() {
            return "Item{" +
                    "  m03Te='" + m03Te + '\'' +
                    ", m02Te='" + m02Te + '\'' +
                    ", m01Te='" + m01Te + '\'' +
                    ", m005Te='" + m005Te + '\'' +
                    ", tsQcflg='" + tsQcflg + '\'' +
                    ", ts='" + ts + '\'' +
                    ", dmstMtphNo='" + dmstMtphNo + '\'' +
                    ", gndSttCd='" + gndSttCd + '\'' +
                    ", vs='" + vs + '\'' +
                    ", lcsCh='" + lcsCh + '\'' +
                    ", clfmAbbrCd='" + clfmAbbrCd + '\'' +
                    ", dc10LmcsCa='" + dc10LmcsCa + '\'' +
                    ", dc10Tca='" + dc10Tca + '\'' +
                    ", hr3Fhsc='" + hr3Fhsc + '\'' +
                    ", dsnw='" + dsnw + '\'' +
                    ", icsr='" + icsr + '\'' +
                    ", ssQcflg='" + ssQcflg + '\'' +
                    ", ss='" + ss + '\'' +
                    ", psQcflg='" + psQcflg + '\'' +
                    ", ps='" + ps + '\'' +
                    ", paQcflg='" + paQcflg + '\'' +
                    ", pa='" + pa + '\'' +
                    ", td='" + td + '\'' +
                    ", pv='" + pv + '\'' +
                    ", hmQcflg='" + hmQcflg + '\'' +
                    ", hm='" + hm + '\'' +
                    ", wdQcflg='" + wdQcflg + '\'' +
                    ", wd='" + wd + '\'' +
                    ", wsQcflg='" + wsQcflg + '\'' +
                    ", ws='" + ws + '\'' +
                    ", rnQcflg='" + rnQcflg + '\'' +
                    ", rn='" + rn + '\'' +
                    ", taQcflg='" + taQcflg + '\'' +
                    ", ta='" + ta + '\'' +
                    ", stnNm='" + stnNm + '\'' +
                    ", stnId='" + stnId + '\'' +
                    ", rnum='" + rnum + '\'' +
                    ", tm='" + tm + '\'' +
                    '}';
        }
    }

    public static class Header {
        @JsonProperty("resultMsg")
        private String resultMsg;
        @JsonProperty("resultCode")
        private String resultCode;

        public String getResultMsg() {
            return resultMsg;
        }

        public void setResultMsg(String resultMsg) {
            this.resultMsg = resultMsg;
        }

        public String getResultCode() {
            return resultCode;
        }

        public void setResultCode(String resultCode) {
            this.resultCode = resultCode;
        }
    }
}

2.  데이터 받을 서비스 코드 작성

* 여기서 URLEncoder 부분 'dataCd, dateCd ,startDt ,startHh ,endDt, endHh'를 활용하여 데이터 기간을 변경할 수 있습니다. 이 글에서는 하루씩 받기 위해서 소스코드가 작성되어 있으니, 필요에 따라 변형해서 사용하시면 될거 같습니다.

@Service
public class WeatherService {
    public String serviceKey = "서비스키 입력";
    /**
     *
     * @param year 시작 년도
     * @param month 시작 달
     * @param day 시작 일
     * @return
     * @throws IOException
     */
    public List<WthrHourDto.Item> getWthrDataListHour(String year, String month, String day) throws IOException {
        LocalDate startDt = LocalDate.of(Integer.parseInt(year), Integer.parseInt(month), Integer.parseInt(day)); // 시작일
        String strStartDt = startDt.format(DateTimeFormatter.ofPattern("yyyyMMdd")); // ex) 20220410
        LocalDate endDt = startDt.plusDays(1);
        String strEndDt = endDt.format(DateTimeFormatter.ofPattern("yyyyMMdd"));// ex) 20220411

        StringBuilder urlBuilder = new StringBuilder("http://apis.data.go.kr/1360000/AsosHourlyInfoService/getWthrDataList"); /*URL*/
        urlBuilder.append("?" + URLEncoder.encode("serviceKey", "UTF-8") + "=" + serviceKey); /*Service Key*/
        urlBuilder.append("&" + URLEncoder.encode("pageNo", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8")); /*페이지번호 Default : 10*/
        urlBuilder.append("&" + URLEncoder.encode("numOfRows", "UTF-8") + "=" + URLEncoder.encode("24", "UTF-8")); /*한 페이지 결과 수 Default : 1*/
        urlBuilder.append("&" + URLEncoder.encode("dataType", "UTF-8") + "=" + URLEncoder.encode("json", "UTF-8")); /*요청자료형식(XML/JSON) Default : XML*/
        urlBuilder.append("&" + URLEncoder.encode("dataCd", "UTF-8") + "=" + URLEncoder.encode("ASOS", "UTF-8")); /*자료 분류 코드(ASOS)*/
        urlBuilder.append("&" + URLEncoder.encode("dateCd", "UTF-8") + "=" + URLEncoder.encode("HR", "UTF-8")); /*날짜 분류 코드(HR)*/
        urlBuilder.append("&" + URLEncoder.encode("startDt", "UTF-8") + "=" + URLEncoder.encode(strStartDt, "UTF-8")); /*조회 기간 시작일(YYYYMMDD)*/
        urlBuilder.append("&" + URLEncoder.encode("startHh", "UTF-8") + "=" + URLEncoder.encode("00", "UTF-8")); /*조회 기간 시작시(HH)*/
        urlBuilder.append("&" + URLEncoder.encode("endDt", "UTF-8") + "=" + URLEncoder.encode(strEndDt, "UTF-8")); /*조회 기간 종료일(YYYYMMDD) (전일(D-1) 까지 제공)*/
        urlBuilder.append("&" + URLEncoder.encode("endHh", "UTF-8") + "=" + URLEncoder.encode("00", "UTF-8")); /*조회 기간 종료시(HH)*/
        urlBuilder.append("&" + URLEncoder.encode("stnIds", "UTF-8") + "=" + URLEncoder.encode("108", "UTF-8")); /*종관기상관측 지점 번호 (활용가이드 하단 첨부 참조)*/
        URL url = new URL(urlBuilder.toString());
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-type", "application/json");
        System.out.println("Response code: " + conn.getResponseCode());
        BufferedReader rd;
        if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        } else {
            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
        }
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = rd.readLine()) != null) {
            sb.append(line);
        }
        rd.close();
        conn.disconnect();

        String json = sb.toString();
        WthrHourDto wthrHourDto = new ObjectMapper().readValue(json, WthrHourDto.class);
//        System.out.println("wthrHourDto.getResponse().getBody().getNumOfRows() = " + wthrHourDto.getResponse().getBody().getNumOfRows());
//        System.out.println("wthrHourDto.getResponse().getBody().getTotalCount() = " + wthrHourDto.getResponse().getBody().getTotalCount());
        List<WthrHourDto.Item> items = wthrHourDto.getResponse().getBody().getItems().getItem();
        System.out.println("wthrHourDto.getResponse().getBody().getItems().getItem() = " + items);
        for (WthrHourDto.Item item : items) {
            System.out.println("item = " + item);
        }
        return items;
    }
}

3.  Controller 작성

@RestController
public class WeatherAPIController {

    private final WeatherService weatherService;

    public WeatherAPIController(WeatherService weatherService) {
        this.weatherService = weatherService;
    }

    @GetMapping("wthrhour")
    public ResponseEntity wthrhour(
            @PathParam("year") String year,
            @PathParam("month") String month,
            @PathParam("day") String day
    ) {
        List<WthrHourDto.Item> wthrDataListHour = null;
        try {
            wthrDataListHour = weatherService.getWthrDataListHour(year,month,day);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResponseEntity.ok().body(wthrDataListHour);
    }
}

4. 결과화면

 

블로그 이미지

미나미나미

,

# OpenAPI 키 발행: https://www.data.go.kr/data/15012690/openapi.do 

# 서비스 키를 발급 받아야합니다.


# 프로젝트 구조

- ApiController.java

- RequestUtils.java 

 

1. 공공데이터에서 제공해주는 Java 버전의 API를 살짝 각색합니다.

  Year과 Month를 넣는 부분과 Json 형식으로 요청합니다.

2. Json으로 받은 데이터를 Hashmap으로 변환합니다.

# 1번과 2번 소스코드

private static String secretKey = "서비스키";
    
    public static Map<String, Object> holidayInfoAPI(String year, String month) throws IOException {
        StringBuilder urlBuilder = new StringBuilder("http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getHoliDeInfo"); /*URL*/
        urlBuilder.append("?" + URLEncoder.encode("serviceKey", "UTF-8") + "=" + secretKey); /*Service Key*/
        urlBuilder.append("&" + URLEncoder.encode("pageNo", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8")); /*페이지번호*/
        urlBuilder.append("&" + URLEncoder.encode("numOfRows", "UTF-8") + "=" + URLEncoder.encode("10", "UTF-8")); /*한 페이지 결과 수*/
        urlBuilder.append("&" + URLEncoder.encode("solYear", "UTF-8") + "=" + URLEncoder.encode(year, "UTF-8")); /*연 */
        urlBuilder.append("&" + URLEncoder.encode("solMonth", "UTF-8") + "=" + URLEncoder.encode(month.length() == 1 ? "0" + month : month, "UTF-8")); /*월*/
        urlBuilder.append("&" + URLEncoder.encode("_type", "UTF-8") + "=" + URLEncoder.encode("json", "UTF-8")); /* json으로 요청 */

        URL url = new URL(urlBuilder.toString());
        System.out.println("요청URL = " + urlBuilder);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-type", "application/json");
        System.out.println("Response code: " + conn.getResponseCode());

        BufferedReader rd;
        if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        } else {
            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
        }
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = rd.readLine()) != null) {
            sb.append(line);
        }
        rd.close();
        conn.disconnect();
        // System.out.println(sb.toString());

        return string2Map(sb.toString());
    }

    /**
     * Json String을 Hashmap으로 반환
     *
     * @param json
     * @return
     */
    public static Map<String, Object> string2Map(String json) {
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> map = null;

        try {
            map = mapper.readValue(json, Map.class);
            System.out.println(map);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return map;
    }

3. Controller 구성

* 공휴일 요청 후, 세 가지의 응답을 받게 됩니다.

  1. 공휴일이 없는 경우 

  2. 공휴일 하루 있는 경우

  3. 공휴일 이틀 이상인 경우

 

 

   @GetMapping("holidayInfoAPI")
    public ResponseEntity holidayInfoAPI(
            @PathParam("year") String year,
            @PathParam("month") String month
    ) {

        System.out.println("year = " + year);
        System.out.println("month = " + month);

        ArrayList<HashMap> responseHolidayArr = new ArrayList<>();

        try {
            Map<String, Object> holidayMap = RequestUtils.holidayInfoAPI(year, month);
            Map<String, Object> response = (Map<String, Object>) holidayMap.get("response");
            Map<String, Object> body = (Map<String, Object>) response.get("body");
            System.out.println("body = " + body);

            int totalCount = (int) body.get("totalCount");
            if (totalCount <= 0) {
                System.out.println("공휴일 없음");
            }
            if (totalCount == 1) {
                HashMap<String, Object> items = (HashMap<String, Object>) body.get("items");
                HashMap<String, Object> item = (HashMap<String, Object>) items.get("item");
                responseHolidayArr.add(item);
                System.out.println("item = " + item);
            }
            if (totalCount > 1) {
                HashMap<String, Object> items = (HashMap<String, Object>) body.get("items");
                ArrayList<HashMap<String, Object>> item = (ArrayList<HashMap<String, Object>>) items.get("item");
                for (HashMap<String, Object> itemMap : item) {
                    System.out.println("itemMap = " + itemMap);
                    responseHolidayArr.add(itemMap);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResponseEntity.ok().body(responseHolidayArr);
    }

4. 결과 화면

 

 

 

 

블로그 이미지

미나미나미

,

 

2022.02.24 - [[Spring]/springboot] - [SpringBoot] RestAPI 파일업로드 - 1

 

[SpringBoot] RestAPI 파일업로드 - 1

1. start.spring.io에서 스프링 프로젝트 생성하기 2. 파일 업로드 관련 properties 생성 spring: servlet: multipart: max-request-size: 500MB # request 요청 제한(defalut 10mb) max-file-size: 500MB # 파..

minaminaworld.tistory.com


1. 프로젝트 메인에서 업로드 폴더 생성 

   @Value("${uploadFolder}")
    private String uploadFolder;

    public static void main(String[] args) {
        SpringApplication.run(TistoryFileDownloadApplication.class, args);
    }

    @PostConstruct
    public void createUploadFolder() {
        Path upload = Paths.get(uploadFolder);
        try {
            if (!Files.exists(upload)) {
                Files.createDirectory(upload);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2. 파일 저장 서비스 코드 작성

@Service
public class FileService {

    @Value("${uploadFolder}")
    private String uploadFolder;

    public void save(MultipartFile file) {
        Path upload = Paths.get(uploadFolder);
        try {
            Files.copy(file.getInputStream(), upload.resolve(file.getOriginalFilename()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. Postman 테스트 결과 

 

블로그 이미지

미나미나미

,

1. start.spring.io에서 스프링 프로젝트 생성하기


 

2. 파일 업로드 관련 properties 생성

spring:
  servlet:
    multipart:
      max-request-size: 500MB # request 요청 제한(defalut 10mb)
      max-file-size: 500MB # 파일 크기 업로드 데한 (defalut 10mb)

uploadFoloder: upload

3. 파일 RestController 생성 

@PostMapping("/upload")
public ResponseEntity upload(
	@RequestParam("files") MultipartFile[] files // 파일 받기
) {
	// 1. response 객체 생성
    HashMap<String, Object> resultMap = new HashMap<>();
    HashMap<String, Object> responseData = new HashMap<>();
    
    // 2. 받은 파일 데이터 확인
    List<HashMap<String, Object>> fileNames = new ArrayList<>();
    	Arrays.stream(files).forEach(f -> {
    	HashMap<String, Object> map = new HashMap<>();
	    System.out.println("f.getOriginalFilename() = " + f.getOriginalFilename());
    	map.put("fileName", f.getOriginalFilename());
    	map.put("fileSize", f.getSize());
    
        fileNames.add(map);
    });
    
    // 3. response 하기
    responseData.put("files", fileNames);
    resultMap.put("response", responseData);
    return ResponseEntity.ok().body(resultMap);
}

4. Postman으로 테스트 하기  

   파일을 서버에서 전달 테스트

블로그 이미지

미나미나미

,

 

# RegBean.java

package com.example.demo;

public class RegBean {

    private String beanName;
    private int beanInt;

    public void setBeanInt(int beanInt) {
        this.beanInt = beanInt;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public int getBeanInt() {
        return beanInt;
    }

    public String getBeanName() {
        return beanName;
    }

    @Override
    public String toString() {
        return "RegBean{" +
                "beanName='" + beanName + '\'' +
                ", beanInt=" + beanInt +
                '}';
    }
}

# RegBeanConfiguration.java

@Configuration
@EnableConfigurationProperties(RegBeanProperties.class)
public class RegBeanConfiguration {

    @Bean
    @ConditionalOnMissingBean // 이 타입에 Bean 없을 때만 등록
    public RegBean regBean(RegBeanProperties properties) {
        RegBean regBean = new RegBean();
        regBean.setBeanInt(properties.getBeanInt());
        regBean.setBeanName(properties.getBeanName());
        return regBean;
    }
}

# RegBeanProperties.java

pom.xml에 등록해야함.

 

// 소문자 가능함.
@ConfigurationProperties("reg-bean")
public class RegBeanProperties {

    private String beanName;
    private int beanInt;

    public void setBeanInt(int beanInt) {
        this.beanInt = beanInt;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public int getBeanInt() {
        return beanInt;
    }

    public String getBeanName() {
        return beanName;
    }

}

# Maven Install


 

1. pom.xml 특정 jar 가져오기

        <dependency>
            <groupId>com.example</groupId>
            <artifactId>AutoconfigurationSub</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

 

2.  가져온 Bean 값 활용하기 

@Component
public class RegBeanRunner implements ApplicationRunner {

    private static final Logger logger = LoggerFactory.getLogger(RegBeanRunner.class);

    @Autowired
    RegBean regBean;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        logger.info("regBean=" + regBean.toString());
    }
}

 

3. application.properties에서 프로퍼티즈 등록하기 

logging.level.root=debug
reg-bean.beanInt=10
reg-bean.beanName=RegBeanTest

 

4. 결과 

 

 

블로그 이미지

미나미나미

,