Spring — Hibernate: ассоциация один ко многим

Продолжаем цикл статей — переводов по Spring и Hibernate, от krams.Предыдущая статья: «Spring MVC 3, Аннотации Hibernate, MySQL. Туториал по интеграции».

Введение.В этом уроке мы познакомимся с использованием отношения один ко многим, используя аннотации Hibernate и Spring MVC 3. Мы будем использовать аннотоцию @OneToMany для указания отношений между нашими объектами. Мы не будем использовать каскадные типы или fetch-стратегии, вместо этого мы воспользуемся стандартными настройками @OneToMany.

Что такое ассоциация один-ко-многим? Ассоциация один-ко-многим возникает тогда, когда каждой записи в таблице А, соответствует множество записей в таблице Б, но каждая запись в таблице Б имеет лишь одну соответствующую запись в таблице А.

Спецификация нашего приложения.

Приложение является простой CRUD системой управления списком записей. Каждая запись соответствует одному лицу, она содержит персональные данные и данные о кредитной карте. Каждое лицо может владеть несколькими кредитками. Так же мы добавим систему редактирования лиц и кредиток.

Ниже приведены скриншоты из будущего приложения:

7562d2e6e5ca47ac9d0f01357900a40f.pngbefff878de3443a58221aa5c8cfa293d.png

4e9cbd3e6c504775a51755dd998d0893.png

Доменные объекты

Основываясь на спецификации, мы имеем два доменных объекта: персона (Person) и кредитка (Credit Card).

У объекта персоны должны быть следующие поля: — id— first name (имя)— last name (фамилия)— money (деньги)— credit cards (кредитки)

У объекта кредитка поля следующие: — id— type (тип)— number (номер)

Обратите внимание, что каждой персоне соответствует множество кредитных карт, а следственно мы используем ассоциацию один-ко-многим. Конечно мы можем посмотреть на эту ситуацию и с другой стороны и использовать ассоциацию многие-к-одному, но это будет темой другого урока.

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

Начнем с доменного слоя.Как говорилось ранее, у нас есть два доменных объекта: Person и CreditCard. Следовательно мы объявим два POJO объекта, представляющих наш доменный слой. У каждого из них будет аннотация Entity для хранения в базе данных.

Person.java package org.krams.tutorial.domain; import java.io.Serializable; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; /** * Represents a person entity * * @author Krams at {@link http://krams915@blogspot.com} */ @Entity @Table (name = «PERSON») public class Person implements Serializable { private static final long serialVersionUID = -5527566248002296042L; @Id @Column (name = «ID») @GeneratedValue private Integer id; @Column (name = «FIRST_NAME») private String firstName; @Column (name = «LAST_NAME») private String lastName; @Column (name = «MONEY») private Double money; @OneToMany private Set creditCards; public Integer getId () { return id; } public void setId (Integer id) { this.id = id; } public String getFirstName () { return firstName; } public void setFirstName (String firstName) { this.firstName = firstName; } public String getLastName () { return lastName; } public void setLastName (String lastName) { this.lastName = lastName; } public Double getMoney () { return money; } public void setMoney (Double money) { this.money = money; } public Set getCreditCards () { return creditCards; } public void setCreditCards (Set creditCards) { this.creditCards = creditCards; } } Класс Person отображен в таблице PERSON. И выглядит следующим образом:

b75581a5f1f748769ea292604b1e640f.png

Обратите внимание на аннотацию @OneToMany для переменной creditCards, мы не указали ни каскадный тип, ни fetch-стратегию, полагаясь на настройки по умолчанию. Позже мы узнаем некоторые проблемы, связанные с этим.

Person.java @Entity @Table (name = «PERSON») public class Person implements Serializable { … @OneToMany private Set creditCards; … } CreditCard.java package org.krams.tutorial.domain; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; /** * Represents a credit card entity * * @author Krams at {@link http://krams915@blogspot.com} */ @Entity @Table (name = «CREDIT_CARD») public class CreditCard implements Serializable { private static final long serialVersionUID = 5924361831551833717L; @Id @Column (name = «ID») @GeneratedValue private Integer id; @Column (name = «TYPE») private String type; @Column (name = «NUMBER») private String number; public Integer getId () { return id; } public void setId (Integer id) { this.id = id; } public String getType () { return type; } public void setType (String type) { this.type = type; } public String getNumber () { return number; } public void setNumber (String number) { this.number = number; } } Класс CreditCard отображен в таблице CREDIT_CARD и выглядит: 4ee8621673ab422182ed47cdaad708ee.png

Используя phpmyadmin db designer посмотрим на отношения между Person и CreditCard:

542fd2f7736a4f0ca4683519cd8f71ca.png

Взглянем на сгенерированные таблицы:

a9c248ba20cf45a0a7927efafd2ae8c3.png

Мы указывали только две сущности: CreditCard и Person, и ожидали увидеть только две таблицы в базе данных. Так почему же их три? Так как в настройке по умолчанию создается третья связующая таблица.

Цитата из Hibernate Annotations Reference Guide: Без описания отображения, для соотношения один-ко-многим используется связующая таблица. Именем таблицы является конкатенация имени первой таблицы, символа »_» и имени второй таблицы. Для обеспечения соотношения один ко многим колонке с id первой таблицы присваивается модификатор UNIQUE.Позже мы обсудим другие недостатки установок по умолчанию.

Сервисный слой.После объявления доменных объектов, нам необходимо создать сервисный слой, который содержит два сервиса: PersonService и CreditCardService.

PersonService отвечает за обработку CRUD операций над сущностью Person. Каждый метод в конечном итоге передает объект Hibernate сессии.

PersonService.java package org.krams.tutorial.service; import java.util.List; import java.util.Set; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.krams.tutorial.domain.CreditCard; import org.krams.tutorial.domain.Person; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Service for processing Persons * * @author Krams at {@link http://krams915@blogspot.com */ @Service («personService») @Transactional public class PersonService { protected static Logger logger = Logger.getLogger («service»); @Resource (name=«sessionFactory») private SessionFactory sessionFactory; /** * Retrieves all persons * * @return a list of persons */ public List getAll () { logger.debug («Retrieving all persons»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Create a Hibernate query (HQL) Query query = session.createQuery («FROM Person»); // Retrieve all return query.list (); } /** * Retrieves a single person */ public Person get (Integer id) { // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Retrieve existing person // Create a Hibernate query (HQL) Query query = session.createQuery («FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id=»+id); return (Person) query.uniqueResult (); } /** * Adds a new person */ public void add (Person person) { logger.debug («Adding new person»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Persists to db session.save (person); } /** * Deletes an existing person * @param id the id of the existing person */ public void delete (Integer id) { logger.debug («Deleting existing person»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Create a Hibernate query (HQL) Query query = session.createQuery («FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id=»+id); // Retrieve record Person person = (Person) query.uniqueResult (); Set creditCards =person.getCreditCards (); // Delete person session.delete (person); // Delete associated credit cards for (CreditCard creditCard: creditCards) { session.delete (creditCard); } } /** * Edits an existing person */ public void edit (Person person) { logger.debug («Editing existing person»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Retrieve existing person via id Person existingPerson = (Person) session.get (Person.class, person.getId ()); // Assign updated values to this person existingPerson.setFirstName (person.getFirstName ()); existingPerson.setLastName (person.getLastName ()); existingPerson.setMoney (person.getMoney ()); // Save updates session.save (existingPerson); } } PersonService обманчиво выглядит простым, он решает две основные проблемы, которые заслуживают особого внимания:

Проблема 1. Fetch стратегииПолучение записи лица не подгружает связанные с ним записи кредиток.

Следующий запрос получает персону по id.Query query = session.createQuery («FROM Person WHERE p.id=»+id);

Проблема происходит потому, что мы не указали fetch-стратегию когда описывали аннотацию @OneToMany, для того, что бы это исправить — изменим запрос: Query query = session.createQuery («FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id=»+id);

Проблема 2. Каскадные типы.Удаление персоны не приводит к удалению соответствуещих ему кредитных карт.Следующая запись удаляет запись о лице: session.delete (person);

Проблема возникает потому, что мы не указали каскадные типы в аннотации @OneToMany. Это значит, что мы должны реализовать свою стратегию удаления записей о кредитках.

Вначале необходимо создать запрос для получения кредитных карт, которые мы размещаем на временное хранение в коллекцию. Затем мы удаляем запись о персоне. После всего извлекая из коллекции, мы удаляем кретки одну за другой.

Исправленный запрос // Create a Hibernate query (HQL) Query query = session.createQuery («FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id=»+id); // Retrieve record Person person = (Person) query.uniqueResult (); Set creditCards =person.getCreditCards (); // Delete person session.delete (person); // Delete associated credit cards for (CreditCard creditCard: creditCards) { session.delete (creditCard); } CreditCardServiceCreditCardService отвечает за обработку CRUD операций над сущностью CreditCard. Каждый метод в конечном итоге передает объект Hibernate сессии.

CreditCardService.java package org.krams.tutorial.service; import java.util.ArrayList; import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.krams.tutorial.domain.CreditCard; import org.krams.tutorial.domain.Person; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Service for processing Credit Cards * * @author Krams at {@link http://krams915@blogspot.com */ @Service («creditCardService») @Transactional public class CreditCardService { protected static Logger logger = Logger.getLogger («service»); @Resource (name=«sessionFactory») private SessionFactory sessionFactory; /** * Retrieves all credit cards */ public List getAll (Integer personId) { logger.debug («Retrieving all credit cards»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Create a Hibernate query (HQL) Query query = session.createQuery («FROM Person as p LEFT JOIN FETCH p.creditCards WHERE p.id=»+personId); Person person = (Person) query.uniqueResult (); // Retrieve all return new ArrayList(person.getCreditCards ()); } /** * Retrieves all credit cards */ public List getAll () { logger.debug («Retrieving all credit cards»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Create a Hibernate query (HQL) Query query = session.createQuery («FROM CreditCard»); // Retrieve all return query.list (); } /** * Retrieves a single credit card */ public CreditCard get (Integer id) { // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Retrieve existing credit card CreditCard creditCard = (CreditCard) session.get (CreditCard.class, id); // Persists to db return creditCard; } /** * Adds a new credit card */ public void add (Integer personId, CreditCard creditCard) { logger.debug («Adding new credit card»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Persists to db session.save (creditCard); // Add to person as well // Retrieve existing person via id Person existingPerson = (Person) session.get (Person.class, personId); // Assign updated values to this person existingPerson.getCreditCards ().add (creditCard); // Save updates session.save (existingPerson); } /** * Deletes an existing credit card */ public void delete (Integer id) { logger.debug («Deleting existing credit card»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Delete reference to foreign key credit card first // We need a SQL query instead of HQL query here to access the third table Query query = session.createSQLQuery («DELETE FROM PERSON_CREDIT_CARD » + «WHERE creditCards_ID=»+id); query.executeUpdate (); // Retrieve existing credit card CreditCard creditCard = (CreditCard) session.get (CreditCard.class, id); // Delete session.delete (creditCard); } /** * Edits an existing credit card */ public void edit (CreditCard creditCard) { logger.debug («Editing existing creditCard»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Retrieve existing credit card via id CreditCard existingCreditCard = (CreditCard) session.get (CreditCard.class, creditCard.getId ()); // Assign updated values to this credit card existingCreditCard.setNumber (creditCard.getNumber ()); existingCreditCard.setType (creditCard.getType ()); // Save updates session.save (existingCreditCard); } } Обратим особое внимание на метод delete (): delete () public void delete (Integer id) { logger.debug («Deleting existing credit card»); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession (); // Delete reference to foreign key credit card first // We need a SQL query instead of HQL query here to access the third table Query query = session.createSQLQuery («DELETE FROM PERSON_CREDIT_CARD » + «WHERE creditCards_ID=»+id); query.executeUpdate (); // Retrieve existing credit card CreditCard creditCard = (CreditCard) session.get (CreditCard.class, id); // Delete session.delete (creditCard); } Для удаления кредтки, вначале необходимо удалить ее из связующей таблицы, следующим запросом: Query query = session.createSQLQuery («DELETE FROM PERSON_CREDIT_CARD » +«WHERE creditCards_ID=»+id);

Обратите внимание, что связующая таблица создана Hibernate и запрос SQL, а не HQL.После удаления данных из связующей таблицы, удаляем информацию из таблицы CREDIT_CARD.session.delete (creditCard)

Слой контроллера.После создания сервисного и доменного слоев, необходимо создать слой контроллер. Мы создадим два контроллера: MainController и CreditCardController.

MainController

MainController отвечает за обработку запросов к записям лиц. Каждый CRUD запрос в конечном счете передается на PersonService, а затем возвращает соответствующую JSP страницу.

MainController.java package org.krams.tutorial.controller; import java.util.ArrayList; import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.krams.tutorial.domain.Person; import org.krams.tutorial.dto.PersonDTO; import org.krams.tutorial.service.CreditCardService; import org.krams.tutorial.service.PersonService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; /** * Handles person request * * @author Krams at {@link http://krams915@blogspot.com */ @Controller @RequestMapping (»/main/record») public class MainController { protected static Logger logger = Logger.getLogger («controller»); @Resource (name=«personService») private PersonService personService; @Resource (name=«creditCardService») private CreditCardService creditCardService; /** * Retrieves the «Records» page */ @RequestMapping (value = »/list», method = RequestMethod.GET) public String getRecords (Model model) { logger.debug («Received request to show records page»); // Retrieve all persons List persons = personService.getAll (); // Prepare model object List personsDTO = new ArrayList(); for (Person person: persons) { // Create new data transfer object PersonDTO dto = new PersonDTO (); dto.setId (person.getId ()); dto.setFirstName (person.getFirstName ()); dto.setLastName (person.getLastName ()); dto.setMoney (person.getMoney ()); dto.setCreditCards (creditCardService.getAll (person.getId ())); // Add to model list personsDTO.add (dto); } // Add to model model.addAttribute («persons», personsDTO); // This will resolve to /WEB-INF/jsp/records.jsp return «records»; } /** * Retrieves the «Add New Record» page */ @RequestMapping (value = »/add», method = RequestMethod.GET) public String getAdd (Model model) { logger.debug («Received request to show add page»); // Create new Person and add to model model.addAttribute («personAttribute», new Person ()); // This will resolve to /WEB-INF/jsp/add-record.jsp return «add-record»; } /** * Adds a new record */ @RequestMapping (value = »/add», method = RequestMethod.POST) public String postAdd (@ModelAttribute («personAttribute») Person person) { logger.debug («Received request to add new record»); // Delegate to service personService.add (person); // Redirect to url return «redirect:/krams/main/record/list»; } /** * Deletes a record including all the associated credit cards */ @RequestMapping (value = »/delete», method = RequestMethod.GET) public String getDelete (@RequestParam («id») Integer personId) { logger.debug («Received request to delete record»); // Delete person personService.delete (personId); // Redirect to url return «redirect:/krams/main/record/list»; } /** * Retrieves the «Edit Existing Record» page */ @RequestMapping (value = »/edit», method = RequestMethod.GET) public String getEdit (@RequestParam («id») Integer personId, Model model) { logger.debug («Received request to show edit page»); // Retrieve person by id Person existingPerson = personService.get (personId); // Add to model model.addAttribute («personAttribute», existingPerson); // This will resolve to /WEB-INF/jsp/edit-record.jsp return «edit-record»; } /** * Edits an existing record */ @RequestMapping (value = »/edit», method = RequestMethod.POST) public String postEdit (@RequestParam («id») Integer personId, @ModelAttribute («personAttribute») Person person) { logger.debug («Received request to edit existing person»); // Assign id person.setId (personId); // Delegate to service personService.edit (person); // Redirect to url return «redirect:/krams/main/record/list»; } } Обратите внимание, что метод getRecords () метод отображает Person и CreditCard как объект передачи данных: PersonDTO.

getRecords () /** * Retrieves the «Records» page */ @RequestMapping (value = »/list», method = RequestMethod.GET) public String getRecords (Model model) { logger.debug («Received request to show records page»); // Retrieve all persons List persons = personService.getAll (); // Prepare model object List personsDTO = new ArrayList(); for (Person person: persons) { // Create new data transfer object PersonDTO dto = new PersonDTO (); dto.setId (person.getId ()); dto.setFirstName (person.getFirstName ()); dto.setLastName (person.getLastName ()); dto.setMoney (person.getMoney ()); dto.setCreditCards (creditCardService.getAll (person.getId ())); // Add to model list personsDTO.add (dto); } // Add to model model.addAttribute («persons», personsDTO); // This will resolve to /WEB-INF/jsp/records.jsp return «records»; } PersonDTO выступает в роли модели данных для records.jsp.

PersonDTO.java package org.krams.tutorial.dto; import java.util.List; import org.krams.tutorial.domain.CreditCard; /** * Data Transfer Object for displaying purposes */ public class PersonDTO { private Integer id; private String firstName; private String lastName; private Double money; private List creditCards; public Integer getId () { return id; } public void setId (Integer id) { this.id = id; } public String getFirstName () { return firstName; } public void setFirstName (String firstName) { this.firstName = firstName; } public String getLastName () { return lastName; } public void setLastName (String lastName) { this.lastName = lastName; } public Double getMoney () { return money; } public void setMoney (Double money) { this.money = money; } public List getCreditCards () { return creditCards; } public void setCreditCards (List creditCards) { this.creditCards = creditCards; } } CreditCardControllerCreditCardController отвечает за обработку запросов для кредиток. Мы не будем использовать все имеющиеся в этом контроллере методы, они были добавлены для полноты.

CreditCardController.java package org.krams.tutorial.controller; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.krams.tutorial.domain.CreditCard; import org.krams.tutorial.service.CreditCardService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; /** * Handles credit card requests * * @author Krams at {@link http://krams915@blogspot.com */ @Controller @RequestMapping (»/main/creditcard») public class CreditCardController { protected static Logger logger = Logger.getLogger («controller»); @Resource (name=«creditCardService») private CreditCardService creditCardService; /** * Retrieves the «Add New Credit Card» page */ @RequestMapping (value = »/add», method = RequestMethod.GET) public String getAdd (@RequestParam («id») Integer personId, Model model) { logger.debug («Received request to show add page»); // Prepare model object CreditCard creditCard = new CreditCard (); // Add to model model.addAttribute («personId», personId); model.addAttribute («creditCardAttribute», creditCard); // This will resolve to /WEB-INF/jsp/add-credit-card.jsp return «add-credit-card»; } /** * Adds a new credit card */ @RequestMapping (value = »/add», method = RequestMethod.POST) public String postAdd (@RequestParam («id») Integer personId, @ModelAttribute («creditCardAttribute») CreditCard creditCard) { logger.debug («Received request to add new credit card»); // Delegate to service creditCardService.add (personId, creditCard); // Redirect to url return «redirect:/krams/main/record/list»; } /** * Deletes a credit card */ @RequestMapping (value = »/delete», method = RequestMethod.GET) public String getDelete (@RequestParam («id») Integer creditCardId) { logger.debug («Received request to delete credit card»); // Delegate to service creditCardService.delete (creditCardId); // Redirect to url return «redirect:/krams/main/record/list»; } /** * Retrieves the «Edit Existing Credit Card» page */ @RequestMapping (value = »/edit», method = RequestMethod.GET) public String getEdit (@RequestParam («pid») Integer personId, @RequestParam («cid») Integer creditCardId, Model model) { logger.debug («Received request to show edit page»); // Retrieve credit card by id CreditCard existingCreditCard = creditCardService.get (creditCardId); // Add to model model.addAttribute («personId», personId); model.addAttribute («creditCardAttribute», existingCreditCard); // This will resolve to /WEB-INF/jsp/edit-credit-card.jsp return «edit-credit-card»; } /** * Edits an existing credit card */ @RequestMapping (value = »/edit», method = RequestMethod.POST) public String postEdit (@RequestParam («id») Integer creditCardId, @ModelAttribute («creditCardAttribute») CreditCard creditCard) { logger.debug («Received request to add new credit card»); // Assign id creditCard.setId (creditCardId); // Delegate to service creditCardService.edit (creditCard); // Redirect to url return «redirect:/krams/main/record/list»; } } VIEW слой.

После обсуждения доменного, сервисного и слоя контроллера, создадим слой VIEW. Он состоит в основном из JSP страниц. Вот они:

3158278c51ab4924a3ee6c7492abb365.png

records.jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> Insert title here

Records

Id First Name Last Name Money CC Type CC Number
+
N/A N/A +
No records found.

Create new record

Добавить новую запись48fdf4ee7ddb4585847860067d0bf0cd.png

add-record.jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> Insert title here

Create New Record

First Name:
Last Name
Money
Правка существующей записи: befff878de3443a58221aa5c8cfa293d.png

edit-record.jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> Insert title here

Edit Existing Record

Id:
First Name:
Last Name
Money
Добавить новую кредитку: 27567d16722643e6a474aa4220e1e9a4.png

add-credit-card.jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> Insert title here

Add New Credit Card

Person Id:
Type:
Number:
Править существующую кредитку: 4e9cbd3e6c504775a51755dd998d0893.png

edit-credit-card.jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> Insert title here

Edit Existing Credit Card

Person Id:
Type:
Number:
Конфигурация.Мы создали все необходимые Java классы. Следующий шаг — создать необходимые файлы конфигурации.

web.xml spring org.springframework.web.servlet.DispatcherServlet 1 spring /krams/* org.springframework.web.context.ContextLoaderListener spring-servlet.xml applicationContext.xml hibernate-context.xml hibernate.cfg.xml org.hibernate.dialect.MySQL5InnoDBDialect true create spring.properties # database properties app.jdbc.driverClassName=com.mysql.jdbc.Driver app.jdbc.url=jdbc: mysql://localhost/mydatabase app.jdbc.username=root app.jdbc.password= #hibernate properties hibernate.config=/WEB-INF/hibernate.cfg.xml Запуск приложения.Устанавливаем базу данных.Наше приложение использует MySQL в качестве базы данных. Для запуска приложения убедитесь, что вы создали базу данных.

Для ее создания следуйте шагам:1. Откройте phpmyadmin (или любую другую программу для работы с БД, которую вы предпочитаете)2. Создаем новую базу данных mydatabase3. Запускаем наше приложение, схему БД оно создаст автоматически.

Для проверки используете файл mydatabase.sql, расположенный в каталоге WEB_INF нашего приложения.

Для доступа к приложению используйте URL: localhost:8080/spring-hibernate-one-to-many-default/krams/main/record/list

ЗаключениеМы создали приложения Spring MVC используя отношение один-ко-многим и аннотации Hibernate. Так же мы обсудили проблемы связанные с установками по умолчанию для аннотации @OneToMany.

GIT: github.com/sa4ek/spring-hibernate-one-to-many-default

© Habrahabr.ru