Разработка веб-приложений с помощью 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.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; } } |
Резюме
Spring Data — очень мощное оружие, оно помогает вам быстрее разрабатывать приложения и избегать сотен шаблонных строк кода. Использование Spring Data — это наиболее удобный способ создания слоя DAO в приложении, поэтому не игнорируйте его в своих проектах.