Статьи

Spring JPA Data + Hibernate + MySQL + Maven

Разработка веб-приложений с помощью Spring MVC предполагает создание нескольких логических уровней архитектуры. Одним из уровней является слой DAO (Repository). Он отвечает за связь с базой данных. Если вы разработали слой DAO хотя бы один раз, вы должны знать, что он содержит много стандартного кода. Spring Data берет на себя часть рутинной работы, связанной с DAO.

В этой статье я приведу пример приложения, которое будет демонстрировать Spring Data (JPA) в сочетании с Spring MVC, MySQL и Maven . Hibernate будет использоваться в качестве реализации JPA. Как вы, наверное, знаете, я большой поклонник конфигураций на основе Java, поэтому я буду использовать этот подход для настройки Spring Data. В конце урока вы можете найти ссылку на пример проекта на GitHub.

подготовка

В этой статье я хочу сосредоточиться на Spring Data, поэтому все, что выходит за рамки, я опущу. Но в начале я хочу предоставить большую часть ссылок, которые могут быть полезны для вас в контексте этого урока.

Эти ссылки должны дать ответы на 90% вопросов, которые могут возникнуть во время чтения поста. Давайте начнем с создания таблицы в MySQL:

1
2
3
4
5
6
CREATE TABLE `shops` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `name` varchar(60) NOT NULL,
  `employees_number` int(6) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

Теперь мы можем продолжить с Java-кодом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Entity
@Table(name = "shops")
public class Shop {
 
    @Id
    @GeneratedValue
    private Integer id;
 
    private String name;
 
    @Column(name = "employees_number")
    private Integer emplNumber;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Integer getEmplNumber() {
        return emplNumber;
    }
 
    public void setEmplNumber(Integer emplNumber) {
        this.emplNumber = emplNumber;
    }
}

Конфигурация данных Spring

Я считаю, что скриншот проекта поможет вам понять, что происходит.

весна-данные JPA-проект-структура

В файле свойств сосредоточены все данные конфигурации:

01
02
03
04
05
06
07
08
09
10
#DB properties:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/hibnatedb
db.username=hibuser
db.password=root
 
#Hibernate Configuration:
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql=true
entitymanager.packages.to.scan=com.spr.model

Класс WebAppConfig содержит все конфигурации на основе Java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.spr")
@PropertySource("classpath:application.properties")
@EnableJpaRepositories("com.spr.repository")
public class WebAppConfig {
 
    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
 
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
 
    @Resource
    private Environment env;
 
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
 
        dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
        dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
 
        return dataSource;
    }
 
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
        entityManagerFactoryBean.setPackagesToScan(env.
getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
 
        entityManagerFactoryBean.setJpaProperties(hibProperties());
 
        return entityManagerFactoryBean;
    }
 
    private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
        return properties;
    }
 
    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }
 
    @Bean
    public UrlBasedViewResolver setupViewResolver() {
        UrlBasedViewResolver resolver = new UrlBasedViewResolver();
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        return resolver;
    }
 
}

Обратите внимание на аннотацию @EnableJpaRepositories . Это позволяет использовать репозитории JPA. Пакет com.spr.repository будет сканироваться для обнаружения репозиториев. В бине entityManagerFactory я определил, что Hibernate будет использоваться как реализация JPA.

Класс Initializer будет опущен.

Уровни DAO & Service

Хранилище для сущности магазина:

1
2
3
4
5
6
7
8
9
package com.spr.repository;
 
import org.springframework.data.jpa.repository.JpaRepository;
 
import com.spr.model.Shop;
 
public interface ShopRepository extends JpaRepository<shop, integer=""> {
 
}

Определенно, это самый простой фрагмент кода в руководстве. Но это требует самого высокого внимания. Интерфейс JpaRepository содержит основные операции, которые можно выполнять с любым объектом (операции CRUD). Более подробную информацию вы можете найти на официальной странице документации .

Вот код интерфейса ShopService:

1
2
3
4
5
6
7
8
9
public interface ShopService {
 
    public Shop create(Shop shop);
    public Shop delete(int id) throws ShopNotFound;
    public List findAll();
    public Shop update(Shop shop) throws ShopNotFound;
    public Shop findById(int id);
 
}

И реализация интерфейса сервиса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.util.List;
 
import javax.annotation.Resource;
 
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import com.spr.exception.ShopNotFound;
import com.spr.model.Shop;
import com.spr.repository.ShopRepository;
 
@Service
public class ShopServiceImpl implements ShopService {
 
    @Resource
    private ShopRepository shopRepository;
 
    @Override
    @Transactional
    public Shop create(Shop shop) {
        Shop createdShop = shop;
        return shopRepository.save(createdShop);
    }
 
    @Override
    @Transactional
    public Shop findById(int id) {
        return shopRepository.findOne(id);
    }
 
    @Override
    @Transactional(rollbackFor=ShopNotFound.class)
    public Shop delete(int id) throws ShopNotFound {
        Shop deletedShop = shopRepository.findOne(id);
 
        if (deletedShop == null)
            throw new ShopNotFound();
 
        shopRepository.delete(deletedShop);
        return deletedShop;
    }
 
    @Override
    @Transactional
    public List findAll() {
        return shopRepository.findAll();
    }
 
    @Override
    @Transactional(rollbackFor=ShopNotFound.class)
    public Shop update(Shop shop) throws ShopNotFound {
        Shop updatedShop = shopRepository.findOne(shop.getId());
 
        if (updatedShop == null)
            throw new ShopNotFound();
 
        updatedShop.setName(shop.getName());
        updatedShop.setEmplNumber(shop.getEmplNumber());
        return updatedShop;
    }
 
}

Таким образом, ShopRepository используется.

контроллер

Наконец, я могу использовать класс ShopSrviceImpl в контроллере. Все страницы JSP будут опущены, поэтому вы можете найти их исходный код на GitHub .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
@Controller
@RequestMapping(value="/shop")
public class ShopController {
 
    @Autowired
    private ShopService shopService;
 
    @RequestMapping(value="/create", method=RequestMethod.GET)
    public ModelAndView newShopPage() {
        ModelAndView mav = new ModelAndView("shop-new", "shop", new Shop());
        return mav;
    }
 
    @RequestMapping(value="/create", method=RequestMethod.POST)
    public ModelAndView createNewShop(@ModelAttribute Shop shop,
            final RedirectAttributes redirectAttributes) {
 
        ModelAndView mav = new ModelAndView();
        String message = "New shop "+shop.getName()+" was successfully created.";
 
        shopService.create(shop);
        mav.setViewName("redirect:/index.html");
 
        redirectAttributes.addFlashAttribute("message", message);  
        return mav;    
    }
 
    @RequestMapping(value="/list", method=RequestMethod.GET)
    public ModelAndView shopListPage() {
        ModelAndView mav = new ModelAndView("shop-list");
        List shopList = shopService.findAll();
        mav.addObject("shopList", shopList);
        return mav;
    }
 
    @RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
    public ModelAndView editShopPage(@PathVariable Integer id) {
        ModelAndView mav = new ModelAndView("shop-edit");
        Shop shop = shopService.findById(id);
        mav.addObject("shop", shop);
        return mav;
    }
 
    @RequestMapping(value="/edit/{id}", method=RequestMethod.POST)
    public ModelAndView editShop(@ModelAttribute Shop shop,
            @PathVariable Integer id,
            final RedirectAttributes redirectAttributes) throws ShopNotFound {
 
        ModelAndView mav = new ModelAndView("redirect:/index.html");
        String message = "Shop was successfully updated.";
 
        shopService.update(shop);
 
        redirectAttributes.addFlashAttribute("message", message);  
        return mav;
    }
 
    @RequestMapping(value="/delete/{id}", method=RequestMethod.GET)
    public ModelAndView deleteShop(@PathVariable Integer id,
            final RedirectAttributes redirectAttributes) throws ShopNotFound {
 
        ModelAndView mav = new ModelAndView("redirect:/index.html");       
 
        Shop shop = shopService.delete(id);
        String message = "The shop "+shop.getName()+" was successfully deleted.";
 
        redirectAttributes.addFlashAttribute("message", message);
        return mav;
    }
 
}

весна-данные JPA-приложения

Резюме

Spring Data — очень мощное оружие, оно помогает вам быстрее разрабатывать приложения и избегать сотен шаблонных строк кода. Использование Spring Data — это наиболее удобный способ создания слоя DAO в приложении, поэтому не игнорируйте его в своих проектах.

Ссылка: Spring JPA Data + Hibernate + MySQL + Maven от нашего партнера по JCG Алексея Зволинского в блоге заметок Фрузенштейна .