[Из песочницы] Пишем простое веб-приложение используя Spring MVC, Spring Data JPA и Hibernate

Привет, Хабр! Представляю Вашему вниманию перевод руководства «Spring MVC + Spring Data JPA + Hibernate — CRUD Example» автора Nam Ha Minh.

В этом руководстве по Java Spring вы узнаете, как настроить Spring MVC приложение для работы с Spring Data JPA, разработав простое веб-приложение, которое позволяет управлять информацией о клиентах.
По завершению этого руководства, вы сможете создать веб-приложение Java основанное на технологиях Spring MVC и Spring Data JPA, которое выглядит следующим образом:

image


Программы и технологии используемые в этом руководстве: Java 8, Apache Tomcat 9, MySQL Server 5.7, Eclipse IDE 4.7 (Oxygen), Spring Framework 5.1, Hibernate 5.4, Spring Data JPA 2.1.5 и Servlet 3.1.

Начнём с создания базы данных.

1. Создание базы данных


Мы будем использовать MySQL. В нашем пример мы будем работать с данными в таблице customer, которая находится в схеме с именем sales. Таблица customer имеет 4 поля: id, name, email и address:

image


Вы можете запустить следующий MySQL скрипт для создания схемы и таблицы:

CREATE DATABASE `sales`;
CREATE TABLE `customer` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `email` varchar(45) NOT NULL,
  `address` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


2. Создание проекта в Eclipse


Создайте Dynamic Web Project в Eclipse, и конвертируйте его в проект Maven: для этого нажмите ПКМ по проекту, выберете Configure > Convert to Maven Project. В открывшемся диалоговом окне Create new POM введите следующую информацию:

— Group Id: net.codejava
— Artifact Id: CustomerManager

Также убедитесь, что версия JRE для проекта Java 8 или новее.

Затем, откройте pom.xml (файл Maven), чтобы настроить зависимости для этого проекта. Объявите свойства версий для Spring и Hibernate Frameworks:


    5.1.5.RELEASE
    5.4.1.Final


Укажите зависимость для Spring Framework:


    org.springframework
    spring-context
    ${spring.version}


Для создания веб-приложений Spring MVC:


    org.springframework
    spring-webmvc
    ${spring.version}


Для использования Spring Data JPA:


    org.springframework
    spring-orm
    ${spring.version}


    org.springframework.data
    spring-data-jpa
    2.1.5.RELEASE


Мы используем Hibernate в качестве реализации JPA, поэтому добавим следующую зависимость:


    org.hibernate
    hibernate-core
    ${hibernate.version}


Для того, чтобы приложение работало с MySQL, нам нужна зависимость для драйвера MySQL JDBC:


    mysql
    mysql-connector-java
    8.0.14
    runtime


И теперь зависимости для Java Servlet, JSP и JSTL:


    javax.servlet
    javax.servlet-api
    3.1.0
    provided


    javax.servlet.jsp
    javax.servlet.jsp-api
    2.3.1
    provided


    jstl
    jstl
    1.2


Создайте два Java пакета в корне проекта:
net.codejava.config: для классов конфигурации.
net.codejava.customer: для классов приложения.

3. Создание файла настройки JPA


Поскольку мы используем JPA, нам нужно определить свойства для подключения к базе данных в файле persistence.xml, а не в hibernate.cfg.xml. Создайте новый каталог с именем META-INF в исходной папке проекта, чтобы поместить в него файл persistence.xml:

image


И впишите в этот файл код представленный ниже:



     
    
        
            
            
            
            
            
            
        
    
     


Как вы можете видеть, мы указываем свойства для соединения с базой данных, такие как URL, user, password и класс JDBC драйвера. Так же обратите внимание, что имя SalesDB будет использоваться нами в коде конфигурации.

4. Создание Model Class


Создайте класс Customer, который сопоставляется с таблицей customer в базе данных следующим образом:

package net.codejava.customer;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
 
@Entity
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
 
    private String name;
    private String email;
    private String address;
 
    protected Customer() {
    }
 
    protected Customer(String name, String email, String address) {
        this.name = name;
        this.email = email;
        this.address = address;
    }
 
    // геттеры и сеттеры не показаны для краткости. Создайте их с помощью средств своей IDE, или вручную.
 
}


Как вы могли увидеть, мы используем аннотацию @Entity для сопоставления этого класса с таблицей customer (имя класса совпадает с именем таблицы). Все имена полей класса идентичны именам полей в таблице. Поле id имеет аннотации @Id и @GeneratedValue, чтобы указать, что это поле является первичным ключом и его значение генерируется автоматически.

5. Конфигурация Spring MVC и Spring Data JPA


Далее, напишем Java код для настройки Spring MVC и Spring Data JPA. Мы будем использовать конфигурацию на основе Java, так как она проще, чем XML.

Настройка Spring Dispatcher Servlet


Для использования Spring MVC в нашем приложении, нам надо зарегистрировать Spring Dispatcher Servlet при запуске приложения, написав следующий класс:

package net.codejava.config;
 
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
 
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
 
public class WebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(WebMvcConfig.class);
          
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
                "SpringDispatcher", new DispatcherServlet(appContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
          
    }
}


Метод onStartup() этого класса будет автоматически вызываться сервлетом при загрузке приложения. Spring Dispatcher Servlet обарабатывает все запросы cопоставляя URL »/» и ищет конфигурацию в классе WebMvcConfig, которй описан ниже.

Настройка Spring MVC


Создайте класс WebMvcConfig в пакете net.codejava.config, содержащий следующий код:

package net.codejava.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
 
@Configuration
@ComponentScan("net.codejava ")
public class WebMvcConfig {
    @Bean(name = "viewResolver")
    public InternalResourceViewResolver getViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}


Этот класс помечен аннотацией @Configuration, сообщающей Spring, что это файл конфигурации. Аннотация @ComponentScan говорит Spring искать классы конфигурации в пакете net.codejava.

В этом классе мы создаём bean-компонент, который распознаёт представления (View), с помощью указания префикса и суффикса для этих представлений. Поэтому создайте каталог views внутри каталога WebContent/WEB-INF для хранения JSP файлов.

Здесь вы можете добавить и другие конфигурации Spring MVC.

Настройка Spring Data JPA


Для работы с Spring Data JPA нам надо создать два beans-компонента: EntityManagerFactory и JpaTransactionManager. Поэтому создадим другой конфигурационный класс JpaConfig:

package net.codejava.config;
 
import javax.persistence.EntityManagerFactory;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
@Configuration
@EnableJpaRepositories(basePackages = {"net.codejava.customer"})
@EnableTransactionManagement
public class JpaConfig {
    @Bean
    public LocalEntityManagerFactoryBean entityManagerFactory() {
        LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
        factoryBean.setPersistenceUnitName("SalesDB");
          
        return factoryBean;
    }
      
    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
          
        return transactionManager;
    } 
}


Здесь мы используем две важные аннотации:

  • @EnableJpaRepositories: сообщает Spring Data JPA, что нужно искать классы репозитория в указанном пакете (net.codejava) для внедрения соответсвующего кода во время выполнения.
  • @EnableTransactionManagement: сообщает Spring Data JPA, чтобы тот генерировал код для управления транзакциями во время выполнения.


В этом классе первый метод создаёт экземпляр EntityManagerFactory для управления Persistence Unit нашей SalesDB (это имя указано выше в persistence.xml).

Последний метод создаёт экземпляр JpaTransactionManager для EntityManagerFactory, созданный методом ранее.

Это минимальная необходимая конфигурация для использования Spring Data JPA.

Создание Repository Interface


Создайте интерфейс CustomerRepository, который расширяет определенный в Spring Data JPA интерфейс CrudRepository:

package net.codejava.customer;
 
import java.util.List;
 
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
 
public interface CustomerRepository extends CrudRepository {
     
}


Это почти весь код, который нам нужен для доступа к данным. Просто, согласитесь? С Spring Data JPA нам не нужно писать DAO (Java Data Acces Object) код. Просто объявите интерфейс, расширяющий интерфейс CrudRepository, в котором определены такие методы CRUD как: save(), findAll(), findById(), deleteById() и т.д. Во время выполнения Spring Data JPA автоматически сгенерирует код.

Обратите внимание, что мы должны указать тип класса модели и тип поля первичного ключа при расширении CrudRepository: CrudRepository.

7. Создание Service Class


Затем, создайте класс CustomerService:

package net.codejava.customer;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
@Service
@Transactional
public class CustomerService {
    @Autowired CustomerRepository repo;
     
    public void save(Customer customer) {
        repo.save(customer);
    }
     
    public List listAll() {
        return (List) repo.findAll();
    }
     
    public Customer get(Long id) {
        return repo.findById(id).get();
    }
     
    public void delete(Long id) {
        repo.deleteById(id);
    }
     
}


Обратите внимание на аннотацию @Transactional, которой помечен наш класс. Это означает, что все методы этого класса будут перехвачены Spring Data JPA для управления транзакциями. И экземпляр интерфейса CustomerRepository будет внедрён в этот класс:

@Autowired CustomerRepository repo;


Это похоже на магию, поскольку мы не пишем DAO код, но Spring Data JPA автоматически создаст реализацию во время выполнения.

Как вы можете видеть, все методы в данном классе предназначены для операций CRUD. Он просто делегирует весь вызов объекту CustomerRepository. Вам может показаться этот класс избыточным, но он необходим, для отделения уровня business/service от уровня repository/DAO.

8. Создание контроллера Spring MVC


Создайте класс CustomerContoroller для обработки всех запросов от клиентов:

package net.codejava.customer;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
 
 
@Controller
public class CustomerController {
 
    @Autowired
    private CustomerService customerService;
 
    // здесь будут методы обработки
}


Это типичный класс Spring MVC Controller, который аннотирован с помощью @Controller. Вы можете увидеть, что экземпляр CustomerService внедряется в этот объект с помощью аннотации @Autowired.

Мы напишем методы обработки в следующих секциях.

9. Добавление списка клиентов


На домашней странице нашего приложения будут отображаться все клиенты, для этого добавьте соответствующий обрабатывающий метод в наш CustomerController класс:

@RequestMapping("/")
public ModelAndView home() {
    List listCustomer = customerService.listAll();
    ModelAndView mav = new ModelAndView("index");
    mav.addObject("listCustomer", listCustomer);
    return mav;
}


Домашняя страница просмотра (index.jsp) должна выглядеть следующим образом:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   




Customer Manager


Customer Manager

 

New Customer

ID Name E-mail Address Action
${customer.id} ${customer.name} ${customer.email} ${customer.address} Edit     Delete


Теперь вы можете запустить веб-приложение. Добавьте несколько строк в таблицу customer и перейдите по адресу http://localhost:8080/CustomerManager/, и вы увидите что-то похожее:

image


10. Добавление нового пользователя


Для того, чтобы реализовать функцию создания нового клиента, нам нужно написать два метода-обработчика. И первый из них будет отображать новую форму для добавления клиента:

@RequestMapping("/new")
public String newCustomerForm(Map model) {
    Customer customer = new Customer();
    model.put("customer", customer);
    return "new_customer";
}


Напишем саму JSP форму с именем new_customer.jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>      




New Customer


    
        

New Customer

                                                                                                                                                                                                                                                                                                                                                     
Name:
Email:
Address:
        
    


Теперь на главной странице у вас появится ссылка New Customer, при нажатии на которую вы увидите новую форму:

image


Второй метод-обработчик будет обрабатывать кнопку Save в этой форме:

@RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveCustomer(@ModelAttribute("customer") Customer customer) {
    customerService.save(customer);
    return "redirect:/";
}


Как вы можете видеть, она перенаправляет клиента на домашнюю страницу, после успешного сохранения пользователя.

11. Изменение данных пользователя


Чтобы реализовать функцию редактирования клиента, добавим следующий метод-обработчик в класс CustomerController:

@RequestMapping("/edit")
public ModelAndView editCustomerForm(@RequestParam long id) {
    ModelAndView mav = new ModelAndView("edit_customer");
    Customer customer = customerService.get(id);
    mav.addObject("customer", customer);
 
    return mav;
}


Напишем форму edit_customer.jsp, которая вызывается этим методом:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>      




Edit Customer


    

Edit Customer

ID: ${customer.id}
Name:
Email:
Address:


Нажмите на гиперссылку Edit рядом с клиентом на домашней странице, вызовется форма редактирования клиента, которая будет выглядеть примерно вот так:

-i_f4slbfwi4ijh89y8kkurrgos.png

Метод-обработчик по-прежнему обрабатывает кнопку Save.

12. Удаление клиента


Для реализации функции удаления, напишите следующий метод-обработчик в классе CustomerController:

@RequestMapping("/delete")
public String deleteCustomerForm(@RequestParam long id) {
    customerService.delete(id);
    return "redirect:/";       
}


Нажмите на гиперссылку Delete рядом с клиентом на главной странице. Клиент удалится, а список обновится.

13. Поиск по клиентам


Наконец, давайте реализуем функцию поиска, которая позволяет пользователю искать клиентов, вводя ключевое слово. Функция поиска ищет ключевые слова в трёх полях: имя, email и адрес, для чего нам потребуется написать собственный метод в интерфейсе CustomerRepository:

package net.codejava.customer;
 
import java.util.List;
 
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
 
public interface CustomerRepository extends CrudRepository {
     
    @Query(value = "SELECT c FROM Customer c WHERE c.name LIKE '%' || :keyword || '%'"
            + " OR c.email LIKE '%' || :keyword || '%'"
            + " OR c.address LIKE '%' || :keyword || '%'")
    public List search(@Param("keyword") String keyword);
}


Метод search() — это просто абстрактный метод, аннотированный с помощью @Query. Поисковый запрос является запросом JPA.

Затем добавьте метод в класс CustomerService:

public List search(String keyword) {
    return repo.search(keyword);
}


Теперь добавьте метод-обработчик в класс CustomerController:

@RequestMapping("/search")
public ModelAndView search(@RequestParam String keyword) {
    List result = customerService.search(keyword);
    ModelAndView mav = new ModelAndView("search");
    mav.addObject("result", result);
 
    return mav;    
}


И создайте страницу результата поиска search.jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   




Search Result


Search Result

ID Name E-mail Address
${customer.id} ${customer.name} ${customer.email} ${customer.address}


Для тестирования функции поиска, введите ключевое слово в поле поиска на домашней странице, и нажмите Enter. Вы увидите страницу результата поиска:

5gat9cau3uhaaokqe55_lgnonne.png


Выводы


В данном руководстве вы узнали как можно разработать веб-приложение Spring MVC, используя Spring Data JPA для доступа к данным. Как вы могли видеть, Spring Data JPA значительно уменьшает и упрощает код, который нам нужно писать.

Для сравнения, вот структура проекта в Eclipse IDE:

x06-u2yeydhoc81hf056lylv3gw.png


Благодарю за прочтение!

© Habrahabr.ru