Total Pageviews

Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

2021/01/08

[Spring Boot] Cannot insert data in h2 database

 Environment

  • JDK: 1.8
  • Spring Boot: 2.4.1
  • Database: H2
  • yaml configuration
spring:
  datasource:
    url: jdbc:h2:file:./database/test;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
    username: sa
    password: password
    schema: classpath:/sql/schema.sql
    data: classpath:/sql/data/*.sql
    hikari:
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        show_sql: false
        use_sql_comments: true
        format_sql: true
  h2:
    console:
      enabled: true
      path: /console
      settings:
        trace: false
        web-allow-others: false


Problem

As I startup Spring Boot, it created table successfully, but fail to insert data.


How-To

Set initialization-mode to always in yaml, then this problem will be solved.

spring:
  datasource:
    initialization-mode: always
    url: jdbc:h2:file:./database/test;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
    username: sa
    password: password
    schema: classpath:/sql/schema.sql
    data: classpath:/sql/data/*.sql
    hikari:
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        show_sql: false
        use_sql_comments: true
        format_sql: true
  h2:
    console:
      enabled: true
      path: /console
      settings:
        trace: false
        web-allow-others: false





2021/01/01

[Spring] [Swagger] How to apply Basic Authentication in swagger?

Configuration Steps

 1. added dependency in pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>


2. created SecurityConfiguration class as following:

package com.xxx.tool.filegenerator.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    // add all the swagger url pattern behind basic authentication
    private static final String[] AUTH_LIST = {"/v2/api-docs", "/configuration/ui",
            "/swagger-resources", "/configuration/security",
            "/swagger-ui.html", "/webjars/**"};

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("password")).roles("USER").and()
                .withUser("admin").password(passwordEncoder().encode("iamadmin")).roles("ADMIN", "USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers(AUTH_LIST).authenticated().and().httpBasic();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}





2020/12/01

[Java] [JUnit] [SpringBoot] How to assign active profile in unit test?

Requirement
If I have multiple profiles in Spring Boot project, how to assign specific profile in my unit test program?


How-To
Added @ActiveProfiles onto your unit test class:
package com.test.tool.filegenerator.ftl.cp937;

import com.test.tool.filegenerator.util.Cp973FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("office")
public class TS0110_050110_70118_R01FileTest {

    @Autowired
    private Cp973FileUtils cp973FileUtils;

    @ParameterizedTest
    @ValueSource(strings = {"delivery/test data/LN3112P2.LN3112P2"})
    public void testReadTS0110_050110_70118_R01(String file) {
        Assertions.assertThatCode(
                () -> cp973FileUtils.readAndPrintContent(file)).doesNotThrowAnyException();
    }

}


2020/11/10

[Java] [Spring] How to configure Spring profile?

Problem
I am using jsoup to download excel file from google drive via Java.

I need to connect to google drive via http proxy in office, and can connect to google drive without proxy at home.

How to use Spring profile to configure to fit my different working environment?


How-To
1. Create a DownloadService Interface
package com.cht.tool.filegenerator.service;

import java.io.IOException;

public interface DownloadService {

    void downloadExcel() throws IOException;

}

2. Create a JSoupDefaultService serivce and mark with default profile
package com.cht.tool.filegenerator.service;

import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

@Slf4j
@Service
@Profile({"default"})
public class JSoupDefaultService implements DownloadService {

    @Value("${jsoup.from}")
    private String from;

    @Value("${jsoup.to}")
    private String to;

    public void downloadExcel() throws IOException {
        log.debug("default profile");
        Connection.Response response = null;
        try {
            response = Jsoup.connect(from)
                    .ignoreContentType(true)
                    .execute();
        } catch (IOException e) {
            throw new IOException("fail to connect to google drive, error : " + e.getMessage(), e);
        }
        log.debug("status code = {}", response.statusCode());

        Files.write(Paths.get(to), response.bodyAsBytes());
        log.debug("excel file downloaded.");
    }

}

3. Create a JSoupService service and mark with office profile
package com.cht.tool.filegenerator.service;

import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

@Slf4j
@Service
@Profile("office")
public class JSoupService implements DownloadService {

    @Value("${jsoup.from}")
    private String from;

    @Value("${jsoup.to}")
    private String to;

    @Value("${jsoup.proxy}")
    private String proxy;

    @Value("${jsoup.port}")
    private int port;

    public void downloadExcel() throws IOException {
        log.debug("office profile");
        Connection.Response response = null;
        try {
            response = Jsoup.connect(from)
                    .proxy(proxy, port)
                    .ignoreContentType(true)
                    .execute();
        } catch (IOException e) {
            throw new IOException("fail to connect to google drive, error : " + e.getMessage(), e);
        }
        log.debug("status code = {}", response.statusCode());

        Files.write(Paths.get(to), response.bodyAsBytes());
        log.debug("excel file downloaded.");
    }

}


4. Create a default profile in yaml
spring:
  profiles:
    active: default


5. Write Test code in Spring Application
package com.cht.tool.filegenerator;

import com.cht.tool.filegenerator.service.DownloadService;
import com.cht.tool.filegenerator.service.FileGeneratorService;
import com.cht.tool.filegenerator.service.JSoupService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;

import java.nio.file.Files;
import java.nio.file.Paths;

@Slf4j
@SpringBootApplication
public class FileGeneratorApplication {

    @Value("${jsoup.to}")
    private String to;

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

    @Bean
    CommandLineRunner run(FileGeneratorService fileGeneratorService, DownloadService downloadService) {
        return args -> {
            if (Files.exists(Paths.get(to))) {
                Files.delete(Paths.get(to));
            }
            downloadService.downloadExcel();

            fileGeneratorService.writePropertyFile();
            fileGeneratorService.writeFtpPropertyFile();
            fileGeneratorService.writeFtlFile();
            fileGeneratorService.writeSqlFile();
        };
    }
}

6. Do test
2020-07-24 11:18:50.529 DEBUG 6628 --- [           main] c.c.t.f.FileGeneratorApplication         : Running with Spring Boot v2.3.1.RELEASE, Spring v5.2.7.RELEASE
2020-07-24 11:18:50.529  INFO 6628 --- [           main] c.c.t.f.FileGeneratorApplication         : The following profiles are active: default
2020-07-24 11:18:51.328  INFO 6628 --- [           main] c.c.t.f.FileGeneratorApplication         : Started FileGeneratorApplication in 1.355 seconds (JVM running for 2.489)
2020-07-24 11:18:51.343 DEBUG 6628 --- [           main] c.c.t.f.service.JSoupDefaultService      : default profile
2020-07-24 11:18:53.501 DEBUG 6628 --- [           main] c.c.t.f.service.JSoupDefaultService      : status code = 200
2020-07-24 11:18:53.732 DEBUG 6628 --- [           main] c.c.t.f.service.JSoupDefaultService      : excel file downloaded.





2020/11/09

[Java] [IntelliJ] How to set Spring profile in IntelliJ

Requirement
Assume I have two Spring profile, default and office, how to set office profile in IntelliJ?


How-To
Step 1. Run ➡️ Edit Configuration

 
Step 2. Fill in office to Activate profiles ➡️ Click OK



2020/03/09

[Java] [Spring] [JDBC] [Oracle] How to call stored procedure - example 2

Assume I have a stored procedure as bellows:
create or replace PACKAGE PACKAGE1 AS 
     PROCEDURE TEST_EMPLOYEE 
    (
      I_GENDER IN VARCHAR2 DEFAULT 'M',
      O_RESULT OUT SYS_REFCURSOR,
      o_return_code OUT INT
    );
END PACKAGE1;

create or replace PACKAGE BODY PACKAGE1
AS
   PROCEDURE TEST_EMPLOYEE 
    (
      I_GENDER IN VARCHAR2 DEFAULT 'M',
      O_RESULT OUT SYS_REFCURSOR,
      o_return_code OUT INT 
    ) AS 
    BEGIN
      OPEN O_RESULT FOR 
      SELECT ID, NAME, PHONE, ADDRESS, GENDER
      FROM EMPLOYEE 
      WHERE GENDER = I_GENDER;
      o_return_code := 0;
    END TEST_EMPLOYEE;
END PACKAGE1;


Step1. Create a custom repository interface:
package com.example.jpa.repository.custom;

import java.util.Map;

public interface EmployeeRepositoryCustom {

    Map<String, Object> findEmployee(String gender);

}


Step2. Create a custom implementation class:
package com.example.jpa.repository.impl;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;

import java.util.Map;

@Slf4j
public class EmployeeRepositoryImpl implements EmployeeRepositoryCustom {

    @Autowired
    private NamedParameterJdbcTemplate jdbcTemplate;

    @Override
    public Map<String, Object> findEmployee(String gender) {
        SimpleJdbcCall jdbcCall
                = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate().getDataSource())
                .withCatalogName("PACKAGE1")
                .withProcedureName("TEST_EMPLOYEE")
                .returningResultSet("O_RESULT", 
                                    BeanPropertyRowMapper.newInstance(Employee.class));

        SqlParameterSource input = new MapSqlParameterSource().addValue("I_GENDER", gender);

        Map<String, Object> output = jdbcCall.execute(input);
        output.entrySet().forEach(entry -> 
            log.debug("key = {}, value = {}", entry.getKey(), entry.getValue()));

        return output;
    }
}



Step3. Create an repository interface
package com.example.jpa.repository;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, String>, EmployeeRepositoryCustom {
}


Step4. Create a test case:

package com.example.jpa;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.EmployeeRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@SpringBootTest
@Slf4j
public class TestEmployeeRepository {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Test
    public void testFindEmployee() {
        Map<String, Object> output = employeeRepository.findEmployee("F");

        List<Employee> employees = (List<Employee>) output.get("O_RESULT");
        for (int i = 0; i < employees.size(); i++) {
            log.debug("employee = {}", ToStringBuilder.reflectionToString(employees.get(i)));
        }

        int returnCode = ((BigDecimal) output.get("O_RETURN_CODE")).intValue();
        log.debug("returnCode = {}", returnCode);
    }

}


Step5. Check result:
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = O_RESULT, value = [com.example.jpa.entity.Employee@2adbd899, com.example.jpa.entity.Employee@d6831df]
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = O_RETURN_CODE, value = 0
[           main] com.example.jpa.TestEmployeeRepository   : employee = com.example.jpa.entity.Employee@77ccded4[id=2,name=Mandy,phone=0911111111,address=Taipei,gender=F]
[           main] com.example.jpa.TestEmployeeRepository   : employee = com.example.jpa.entity.Employee@2bb717d7[id=3,name=Gina,phone=0911111111,address=ChiaYi,gender=F]
[           main] com.example.jpa.TestEmployeeRepository   : returnCode = 0