Spring Boot JDBC projekt

Nový projekt si necháme vygenerovat na adrese start.spring.io. Budeme chtít závislosti JDBC a PostgreSQL. Více k vytváření projektů pomocí spring initializeru naleznete v tomto příspěvku.

spring_boot_jdbc_generate_project

Stažený projekt (.zip soubor) rozbalíme a naimportujeme do STS (Eclipse): File -> Import -> Maven -> Existing Maven Projects -> Next -> Root Directory (vybrat rozbalený projekt) -> Finish.
Pokud se nyní pokusíte projekt spustit (pravým na projekt -> Run As -> Spring Boot App) dostanete následující chybu:

***************************
APPLICATION FAILED TO START
***************************

Description:

Cannot determine embedded database driver class for database type NONE

Action:

If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).

Je třeba do souboru application.properties přidat data pro připojení k databázi. Více k tomuto tématu si můžete přečíst v tomto příspěvku.

#Spring DataSource
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=password

Pokud máte nainstalovánu databázi (RDMS) PostgreSQL, v ní vytvořenou databázi postgres (ta tam bývá vytvořena defaultně), uživatele s názvem postgres (taky bývá vytvořen defaultně) a heslo ‚password‘, měl by se vám nyní projekt spustit a ukončit bez chyby.

V databázi vytvoříme tabulku article.

DROP TABLE IF EXISTS article;

CREATE TABLE article (
    id serial NOT NULL,
    header varchar(100) NOT NULL,
    text varchar(10000) NOT NULL,
    created timestamp with time zone NOT NULL,
    modified timestamp with time zone,
    CONSTRAINT article_pk PRIMARY KEY (id)
);

Z naší aplikace budeme do této tabulky ukládat a načítat záznamy. Nejdříve si vytvoříme DTO (Data Transfer Object) Article. DTO se definuje jako objekt, který se používá pro přenos dat v aplikaci.

Article.java

import java.util.Date;

public class Article {

	private int id;
	private String header;
	private String text;
	private Date created;

	public int getId() {
		return id;
	}

	public String getHeader() {
		return header;
	}

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

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}
}

Field id nemá setter. Je to proto, že id je generováno databází (v PostgreSQL datový typ serial). Není tedy důvod tady setter mít.

Pro mapování výsledků vracených dotazem z databáze do objektů se používají mappery. V našem případě budeme mít jeden mapper.

ArticleMapper.java

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import cz.vitfo.model.Article;

public class ArticleMapper implements RowMapper<Article> {

	@Override
	public Article mapRow(ResultSet rs, int rowNum) throws SQLException {
		Article article = new Article();
		article.setHeader(rs.getString("header"));
		article.setText(rs.getString("text"));
		article.setCreated(rs.getTimestamp("created"));
		return article;
	}
}

Nyní vytvoříme rozhraní, které bude definovat metody pro práci s tabulkou article a také implementaci tohoto rozhraní. Rozhraní si nazveme ArticleDao a implementaci ArticleDaoImpl. DAO je další zkratka a znamená Data Access Object. Každá tabulka by měla mít své DAO a potom DAO představuje rozhraní mezi aplikací a databází (aplikace přistupuje k databázi přes jednotlivá DAO).

ArticleDao.java

import cz.vitfo.model.Article;

public interface ArticleDao {
	
	int insert(Article article);
	
	Article getById(int id);
	
	void delete(int id);
}

Naše DAO definuje tři metody. Metodu pro uložení článku, která vrátí id uloženého článku. Metodu, která článek načte dle id a metodu, která článek smaže.

ArticleDaoImpl.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import cz.vitfo.dao.ArticleDao;
import cz.vitfo.dao.impl.mappers.ArticleMapper;
import cz.vitfo.model.Article;

@Repository
public class ArticleDaoImpl implements ArticleDao {

	@Autowired
	JdbcTemplate jdbcTemplate;
	
	@Override
	public int insert(Article article) {
		return jdbcTemplate.queryForObject(
				"insert into article (header, text, created) values (?, ?, ?) returning id", 
				new Object[] {
						article.getHeader(),
						article.getText(),
						article.getCreated()
				}, Integer.class);
	}
	
	@Override
	public void delete(int id) {
		jdbcTemplate.update("delete from article where id = ?", id);
	}

	@Override
	public Article getById(int id) {
		return jdbcTemplate.queryForObject("select * from article where id = ?", new ArticleMapper(), id);
	}
}

Všimněte si, že bez jakéhokoliv dalšího nastavování, máme k dispozici objekt JdbcTemplate. Díky němu můžeme jednoduše pracovat s databází. Tento objekt si necháme pomocí Spring frameworku vytvořit a zpřístupnit ve třídě pomocí anotace @Autowired. Také si všimněte anotace @Repository na této třídě. Ta zjednodušeně říká, že pro vytváření instancí ArticleDao, se má použít tato implementace.

SpringjdbcApplication.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import cz.vitfo.dao.ArticleDao;
import cz.vitfo.model.Article;

@SpringBootApplication
public class SpringjdbcApplication {
	private static final Logger logger = LoggerFactory.getLogger(SpringjdbcApplication.class);
	
	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(SpringjdbcApplication.class, args);
		
		ArticleDao articleDao = context.getBean(ArticleDao.class);
		
		Article article = new Article();
		article.setHeader("My header");
		article.setText("This is text");
		article.setCreated(new Date());
		
		int articleId = articleDao.insert(article);
		
		Article articleById = articleDao.getById(articleId);
		logger.info(articleById.getHeader());
		logger.info(articleById.getText());
		logger.info(articleById.getCreated().toString());
		
		articleDao.delete(articleId);
	}
}

Jedná se o vstupní bod naší aplikace. Nejdříve si vytvoříme kontext, načteme z něj naše dao, vytvoříme článek, uložíme jej, zobrazíme a smažeme z databáze.

Zde je ještě struktura projektu.

│   pom.xml
│
└───src
    ├───main
    │   ├───java
    │   │   └───cz
    │   │       └───vitfo
    │   │           │   SpringjdbcApplication.java
    │   │           │
    │   │           ├───dao
    │   │           │   │   ArticleDao.java
    │   │           │   │
    │   │           │   └───impl
    │   │           │       │   ArticleDaoImpl.java
    │   │           │       │
    │   │           │       └───mappers
    │   │           │           │   ArticleMapper.java
    │   │           │           │
    │   │           │           └───copy
    │   │           │                   ArticleMapper.java
    │   │           │
    │   │           └───model
    │   │                   Article.java
    │   │
    │   └───resources
    │           application.properties
    │
    └───test
        └───java
            └───cz
                └───vitfo
                        SpringjdbcApplicationTests.java



Balíčky src.main.java.cz.vitfo, src.main.resources a src.test jsme již měly vygenerovány tak jako soubory SpringjdbcApplication.java, application.properties a SpringjdbcApplicationTests.java. Námi vytvoření Article.java jsem umístil do balíčku model, ArticleDao.java do dao, ArticleDaoImpl.java do dao.impl a ArticleMapper.java do dao.impl.mappers.

Napsat komentář