Skip to content

Instantly share code, notes, and snippets.

@adityapatnaik
Last active May 15, 2024 03:52
Show Gist options
  • Save adityapatnaik/e0bc5d399e489224b874167780bd29d4 to your computer and use it in GitHub Desktop.
Save adityapatnaik/e0bc5d399e489224b874167780bd29d4 to your computer and use it in GitHub Desktop.
Spring Boot Select and Insert API using jdbc template with configurable columns, source and destination tables.

Data Transfer Service

This is a Spring Boot application that provides a REST API endpoint to transfer data from a source table to a destination table in a database. The source table, destination table, and columns to be transferred can be configured through a properties file.

Prerequisites

  • Java 11 or higher
  • Maven

Configuration

The application properties can be configured in the application.properties file. Here's an example:

# Server configuration
server.port=8080

# Datasource configuration
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# H2 console configuration
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# Application configuration
app.source.table=source_table
app.source.columns=column1,column2,column3
app.destination.table=destination_table

# Logging configuration
logging.level.root=INFO
logging.level.com.example.datatransfer=DEBUG
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
logging.file.name=logs/data-transfer.log
logging.file.max-size=10MB
logging.file.max-history=7
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>data-transfer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>data-transfer</name>
    <description>Data Transfer Service</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
@Component
@ConfigurationProperties(prefix = "app")
class DataTransferProperties {
    private String sourceTable;
    private List<String> sourceColumns;
    private String destinationTable;

    // Getters and setters

    public String getSourceTable() {
        return sourceTable;
    }

    public void setSourceTable(String sourceTable) {
        this.sourceTable = sourceTable;
    }

    public List<String> getSourceColumns() {
        return sourceColumns;
    }

    public void setSourceColumns(List<String> sourceColumns) {
        this.sourceColumns = sourceColumns;
    }

    public String getDestinationTable() {
        return destinationTable;
    }

    public void setDestinationTable(String destinationTable) {
        this.destinationTable = destinationTable;
    }
}
public class DataTransferException extends RuntimeException {
    public DataTransferException(String message) {
        super(message);
    }

    public DataTransferException(String message, Throwable cause) {
        super(message, cause);
    }
}
@Service
class DataTransferService {
    private final JdbcTemplate jdbcTemplate;
    private final DataTransferProperties properties;

    public DataTransferService(JdbcTemplate jdbcTemplate, DataTransferProperties properties) {
        this.jdbcTemplate = jdbcTemplate;
        this.properties = properties;
    }

    public void transferData() {
        deleteDataFromDestinationTable();
        List<Object[]> rows = selectDataFromSourceTable();
        insertDataIntoDestinationTable(rows);
    }

    private void deleteDataFromDestinationTable() {
        String destinationTable = properties.getDestinationTable();

        try {
            jdbcTemplate.update("DELETE FROM " + destinationTable);
        } catch (Exception e) {
            throw new DataTransferException("Failed to delete data from destination table", e);
        }
    }

    private List<Object[]> selectDataFromSourceTable() {
        String sourceTable = properties.getSourceTable();
        List<String> sourceColumns = properties.getSourceColumns();

        String selectQuery = "SELECT " + String.join(",", sourceColumns) + " FROM " + sourceTable;
        try {
            return jdbcTemplate.query(selectQuery, (rs, rowNum) -> {
                Object[] row = new Object[sourceColumns.size()];
                for (int i = 0; i < sourceColumns.size(); i++) {
                    row[i] = rs.getObject(i + 1);
                }
                return row;
            });
        } catch (Exception e) {
            throw new DataTransferException("Failed to fetch data from source table", e);
        }
    }

    private void insertDataIntoDestinationTable(List<Object[]> rows) {
        String destinationTable = properties.getDestinationTable();
        List<String> sourceColumns = properties.getSourceColumns();

        String columnList = sourceColumns.stream().collect(Collectors.joining(","));
        String insertQuery = "INSERT INTO " + destinationTable + "(" + columnList + ") VALUES (" + String.join(",", Collections.nCopies(sourceColumns.size(), "?")) + ")";
        try {
            jdbcTemplate.batchUpdate(insertQuery, new BatchPreparedStatementSetter() {
                @Override
                public void setValues(PreparedStatement ps, int i) throws SQLException {
                    Object[] row = rows.get(i);
                    for (int j = 0; j < row.length; j++) {
                        ps.setObject(j + 1, row[j]);
                    }
                }

                @Override
                public int getBatchSize() {
                    return rows.size();
                }
            });
        } catch (Exception e) {
            throw new DataTransferException("Failed to insert data into destination table", e);
        }
    }
}
@RestController
class DataTransferController {
    private final DataTransferService dataTransferService;

    public DataTransferController(DataTransferService dataTransferService) {
        this.dataTransferService = dataTransferService;
    }

    @GetMapping("/transfer-data")
    public ResponseEntity<String> transferData() {
        try {
            dataTransferService.transferData();
            return ResponseEntity.ok("Data transfer successful");
        } catch (DataTransferException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment