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.