# Getting Started ## Configuration ### Logging ``` JpaAndRequestLoggingConfig.java : JPA / Web P6spySqlFormatConfiguration.java - decorator.datasource.p6spy.enable-logging: true CustomCommonsRequestLoggingFilter.java - org.springframework.web.filter: debug 필수 decorator.datasource.p6spy Security 비활성 @SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class}) SecurityJavaConfig.java - 예외 등록 - h2, swagger Swagger 설정 : SwaggerConfig resources 설정 WebAndFluxCommonConfig.java - MVC / Flux 공통 사용 MVC / Flux 동시 사용 설정 @EnableWebMvc 만 설정 - @EnableWebFlux는 미사용(사용시 충돌) MVC application - @EnableWebMvc - @SpringBootApplication : exclude에 WebMvcAutoConfiguration.class ``` ### swagger ```java //파라메터 값을 모두 String으로 취급 //String이 아닌 경우 example 값을 부여해야 compile시 WARN 발생 안함 @ApiImplicitParam(name="cmmUserId", value="사용자ID-PK", example = "1") ``` ### Reference Documentation For further reference, please consider the following sections: * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.5.0/maven-plugin/reference/html/) * [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.5.0/maven-plugin/reference/html/#build-image) # **Tailwind CSS** - [Tailwind CSS](https://tailwindcss.com/): 경량의 **CSS** 프레임워크이다. 덩치가 큰 **Bootstrap**과 달리 **CSS**로만 작동하면서 사용자에게 **UI** 구현을 맡기는 컨셉이다. 구현이 직관적이고 자유도가 높아 최근 급속도로 생태계가 확장되고 있다. - [Tailwind Cheat Sheet](https://nerdcave.com/tailwind-cheat-sheet): **Tailwind CSS**의 모든 클래스를 한 눈에 조회 검색 가능한 사이트이다. 사용이 편리하여 레퍼런스 사이트보다 더 찾게 된다. - [Tailwind Toolbox](https://www.tailwindtoolbox.com/): **Tailwind CSS** 기반으로 **UI** 구현에 참고할만한 여러 완성 템플릿을 제공한다. - [Tailwind Components](https://tailwindcomponents.com/): **Tailwind CSS** 기반으로 **UI** 구현에 참고할만한 여러 완성 컴포넌트를 제공한다. - [Awesome Tailwind CSS](https://github.com/aniftyco/awesome-tailwindcss): **Tailwind CSS** 관련 유용한 유용한 정보들을 소개한다. - [We build a login using TailwindCSS](https://stefanbauer.me/building-pingping/we-build-a-login-using-tailwindcss): **Tailwind CSS**을 이용한 로그인 폼 제작 과정을 설명한다. # **Webflux 지원 Database** 1. Postgres (io.r2dbc:r2dbc-postgresql) 2. H2 (io.r2dbc:r2dbc-h2) 3. Microsoft SQL Server (io.r2dbc:r2dbc-mssql) 4. MySQL (com.github.mirromutth:r2dbc-mysql) 5. jasync-sql MySQL (com.github.jasync-sql:jasync-r2dbc-mysql) ### mysql 사용시 ```xml io.r2dbc r2dbc-pool 0.8.0.RELEASE io.r2dbc r2dbc-pool 0.8.0.BUILD-SNAPSHOT dev.miku r2dbc-mysql 0.8.1.RELEASE ``` ### sample ```java import java.time.Duration; import java.time.LocalDateTime; import java.util.HashMap; import javax.annotation.PostConstruct; import org.springframework.stereotype.Repository; import io.r2dbc.pool.ConnectionPool; import io.r2dbc.pool.ConnectionPoolConfiguration; import io.r2dbc.spi.ConnectionFactories; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.Result; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @Repository public class DatabaseConfig { private ConnectionFactory factory; private ConnectionPool pool; //연결 @PostConstruct public void init() { factory = ConnectionFactories.get("r2dbcs:pool:mysql://비번:아이디@주소:포트/db명"); ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder(factory) .maxIdleTime(Duration.ofMillis(1000)) .maxSize(20) .build(); pool = new ConnectionPool(configuration); } //단일 셀렉트, 조회할 테이블 데이터가 n개이면 이런식으로 쓰면 안된다. public Mono> selectSingle() { Mono> mono = Mono.from(pool.create()).map(connection -> //커넥션 가공 Flux.from(connection.createStatement("select name, desc, date from test where id_=?ids").bind("ids", "2").execute()) .concatMap( result-> //1차 변환 result.map((row, rowMetadata)-> { //결과 재 조립 후 리턴 HashMap item = new HashMap<>(); item.put("names", row.get("name",String.class)); item.put("desc", row.get("desc",String.class)); item.put("date", row.get("date",Object.class)); return item; }) ).doFinally( (st)->{connection.close();}) ).flatMap( ccc -> Mono.from(ccc)); //2차 변환 return mono; } //단순 셀렉트 예제 public Flux> selectMany() { Flux> flux = Flux.from(pool.create()).concatMap(connection -> //커넥션 가공 및 1차 변환 Flux.from(connection.createStatement("select name, desc, date from test where id_=?ids").bind("ids", "2").execute()) .concatMap( result-> //2차 변환 result.map((row, rowMetadata)-> { //결과 재 조립 후 리턴 HashMap item = new HashMap<>(); item.put("names", row.get("name",String.class)); item.put("desc", row.get("desc",String.class)); item.put("date", row.get("date",Object.class)); return item; }) ).doFinally( (st)->{connection.close();}) ); return flux; } //저장 예제 public Mono insertTest() { return Mono.from(pool.create()).map( con -> Mono.from( con.createStatement(" insert into test(name, desc, date) values (?name, ?desc, ?date) ") .bind("name", "abcd").bind("desc", "desc").bind("date", LocalDateTime.now()).execute() ).doFinally( st-> con.close()).map( result -> result) ).flatMap( c-> Mono.from(c)); } } ```