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.
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.
