Разработка веб-приложений с помощью Spring MVC предполагает создание нескольких логических уровней архитектуры. Одним из уровней является слой DAO (Repository). Он отвечает за связь с базой данных. Если вы разработали слой DAO хотя бы один раз, вы должны знать, что он содержит много стандартного кода. Spring Data берет на себя часть рутинной работы, связанной с DAO.
В этой статье я приведу пример приложения, которое будет демонстрировать Spring Data (JPA) в сочетании с Spring MVC, MySQL и Maven . Hibernate будет использоваться в качестве реализации JPA. Как вы, наверное, знаете, я большой поклонник конфигураций на основе Java, поэтому я буду использовать этот подход для настройки Spring Data. В конце урока вы можете найти ссылку на пример проекта на GitHub.
подготовка
В этой статье я хочу сосредоточиться на Spring Data, поэтому все, что выходит за рамки, я опущу. Но в начале я хочу предоставить большую часть ссылок, которые могут быть полезны для вас в контексте этого урока.
- Создание динамического веб-проекта в Eclipse с Maven.
- Простое приложение Spring MVC с конфигурацией на основе Java.
- Spring MVC + образец приложения Hibernate .
Эти ссылки должны дать ответы на 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
Я считаю, что скриншот проекта поможет вам понять, что происходит.
В файле свойств сосредоточены все данные конфигурации:
|
01
02
03
04
05
06
07
08
09
10
|
#DB properties:db.driver=com.mysql.jdbc.Driverdb.url=jdbc:mysql://localhost:3306/hibnatedbdb.username=hibuserdb.password=root#Hibernate Configuration:hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialecthibernate.show_sql=trueentitymanager.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;@Servicepublic 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; }} |
Резюме
Spring Data — очень мощное оружие, оно помогает вам быстрее разрабатывать приложения и избегать сотен шаблонных строк кода. Использование Spring Data — это наиболее удобный способ создания слоя DAO в приложении, поэтому не игнорируйте его в своих проектах.

