Зміст
У цій частині статті розглянемо безпосереднє створення класів і веб-сторінок для взаємодії з користувачем. У першій частині статті згадувався файл настройок Hibernate під назвою hibernate.cfg.xml, в якому знаходиться маппінг класів, пов'язаних з базою даних. В нашому випадку, це класи Country і User. Файл hibernate.cfg.xml представлений нижче
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="com.seostella.spring.domain.user.User" />
<mapping class="com.seostella.spring.domain.Country" />
</session-factory>
</hibernate-configuration>
Почнемо розгляд з більш простого класу Country. Нижче лістинг:
package com.seostella.spring.domain;
import javax.persistence.*;
/**
*
* @author seostella.com
*/
@Entity
public class Country {
@Id
@GeneratedValue
private long id;
@Column(name = "name", unique = true, nullable=false)
private String name;
public Country() {
}
public Country(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
Докладно зупинятися на цьому класі не будемо - основні моменти описані в статті Основи Hibernate 3 на прикладі роботи з MySQL
Далі створимо DAO для роботи з цим класом. Почнемо з інтерфейсу CountryDAO:
package com.seostella.spring.dao;
import com.seostella.spring.domain.Country;
import java.util.List;
/**
*
* @author seostella.com
*/
public interface CountryDAO {
public void saveCountry(Country user);
public List<Country> countryList();
public void removeCountry(Long id);
public Country retriveCountry(Long id);
}
За допомогою CountryDAO будемо виконувати найпростіші операції: збереження країни, отримання списку країн, видалення країни і отримання об'єкта за ідентифікатором.
Реалізація інтерфейсу CountryDAO представлена нижче:
package com.seostella.spring.dao;
import com.seostella.spring.domain.Country;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
*
* @author seostella.com
*/
@Repository
public class CountryDAOImpl implements CountryDAO {
@Autowired
private SessionFactory sessionFactory;
public void saveCountry(Country user) {
sessionFactory.getCurrentSession().saveOrUpdate(user);
}
@SuppressWarnings("unchecked")
public List<Country> countryList() {
return sessionFactory.getCurrentSession().createQuery("from Country").list();
}
public void removeCountry(Long id) {
Country country = (Country) sessionFactory.getCurrentSession().load(
Country.class, id);
if (null != country) {
sessionFactory.getCurrentSession().delete(country);
}
}
public Country retriveCountry(Long id){
Query q = sessionFactory.getCurrentSession().createQuery("from Country where id = :id");
q.setLong("id", id);
return (Country) q.uniqueResult();
}
}
Розглянемо детально цей клас:
@Autowired
private SessionFactory sessionFactory;
- bean з конфігураційного файлу db-config.xml:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>/WEB-INF/db/hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">${jdbc.show_sql}</prop>
</props>
</property>
</bean>
- він є по суті "коннектором" до бази даних. За допомогою його виконуються всі звернення до бази.
public void saveCountry(Country user) {
sessionFactory.getCurrentSession().saveOrUpdate(user);
}
- метод для збереження і оновлення об'єкта Country в базі даних. Для визначення наявності об'єкта в базі використовується первинний ключ (в нашому випадку id). Тому, якщо методу передається об'єкт Country, в якому не встановлено значення властивості id, то об'єкт буде додано в базу, а не оновлено. Тобто, при виконанні цього методу виконується два запити до бази. Перший - "select * from country where id =: countryId", другий - або "insert into country ...", або "update country ..." в залежності від того, повернув перший запит якийсь запис в таблиці чи ні.
@SuppressWarnings("unchecked")
public List<Country> countryList() {
return sessionFactory.getCurrentSession().createQuery("from Country").list();
}
- метод для отримання списку країн. sessionFactory.getCurrentSession().createQuery("from Country") - створення об'єкта Query, який повертає записи з бази даних. "from Country" - формат "внутрішнього SQL для Hibernate", названого HQL. В цій статті розглянуто 3 типи створення запитів: за допомогою @NamedQueries, @NamedNativeQueries і без їх використання.
У методах removeCountry() і retriveCountry() немає нічого специфічного, тому вони розглядатися не будуть.
Класи сервісу CountryService і CountryServiceImpl повторюють логіку CountryDAO так як в цьому прикладі немає необхідності в додатковій обробці даних, отриманих від CountryDAO.
package com.seostella.spring.service;
import java.util.List;
import com.seostella.spring.domain.Country;
/**
*
* @author seostella.com
*/
public interface CountryService {
public void saveCountry(Country user);
public List<Country> countryList();
public void removeCountry(Long id);
public Country retriveCountry(Long id);
}
package com.seostella.spring.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.seostella.spring.dao.CountryDAO;
import com.seostella.spring.domain.Country;
/**
*
* @author seostella.com
*/
@Service
public class CountryServiceImpl implements CountryService {
@Autowired
private CountryDAO countryDAO;
@Transactional
public void saveCountry(Country country) {
countryDAO.saveCountry(country);
}
@Transactional
public List<Country> countryList() {
return countryDAO.countryList();
}
@Transactional
public void removeCountry(Long id) {
countryDAO.removeCountry(id);
}
@Transactional
public Country retriveCountry(Long id) {
return countryDAO.retriveCountry(id);
}
}
Контролер, який обробляє дані від користувача представлений нижче:
package com.seostella.spring.controller;
import com.seostella.spring.domain.Country;
import com.seostella.spring.service.CountryService;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* @author seostella.com
*/
@Controller
public class CountryController {
@Autowired
private CountryService countryService;
@RequestMapping("/country/index")
public String listContacts(Map<String, Object> map) {
map.put("country", new Country());
map.put("countryList", countryService.countryList());
return "country_list";
}
@RequestMapping(value = "/country/add", method = RequestMethod.POST)
public String addContact(@ModelAttribute("country") Country country, BindingResult result) {
countryService.saveCountry(country);
return "redirect:/country/index";
}
@RequestMapping("/country/delete/{countryId}")
public String deleteContact(@PathVariable("countryId") Long countryId) {
countryService.removeCountry(countryId);
return "redirect:/country/index";
}
@RequestMapping("/country/save")
public String saveContact(@ModelAttribute("country") Country country, BindingResult result) {
countryService.saveCountry(country);
return "redirect:/country/edit/" + country.getId();
}
@RequestMapping("/country/edit/{countryId}")
public String editContact(@PathVariable("countryId") Long countryId, Map<String, Object> map) {
Country country = countryService.retriveCountry(countryId);
map.put("country", country);
return "country_edit";
}
}
Контролери та jsp-відображення виходять за рамки цієї статті і тому розглядатися не будуть. Нижче наведені jsp-файли, відповідальні за відображення об'єктів Country:
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Spring Hibernate Example</title>
</head>
<body>
<jsp:include flush="false" page="menu.jsp" />
<h2>Edit '${country.name}'</h2>
<form:form method="post"
action="${pageContext.request.contextPath}/country/save"
commandName="country">
<form:hidden path="id" />
<jsp:include flush="true" page="country_form.jsp" />
</form:form>
<a href="${pageContext.request.contextPath}/country/index"
title="Country List">Country List</a>
</body>
</html>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<table>
<tr>
<td><form:label path="name"><spring:message code="label.name"/></form:label></td>
<td><form:input path="name" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="<spring:message code="label.savecountry"/>"/>
</td>
</tr>
</table>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Spring Hibernate Example</title>
</head>
<body>
<jsp:include flush="false" page="menu.jsp" />
<h2>Country List</h2>
<form:form method="post"
action="${pageContext.request.contextPath}/country/add"
commandName="country">
<jsp:include flush="true" page="country_form.jsp">
<jsp:param name="adduser" value="true" />
</jsp:include>
</form:form>
<h3>
<spring:message code="label.countries" />
</h3>
<c:if test="${!empty countryList}">
<table class="data">
<tr>
<th><spring:message code="label.name" /></th>
<th> </th>
</tr>
<c:forEach items="${countryList}" var="country">
<tr>
<td>${country.name}</td>
<td><a
href="${pageContext.request.contextPath}/country/edit/${country.id}"><spring:message
code="label.edit" /></a></td>
<td><a
href="${pageContext.request.contextPath}/country/delete/${country.id}"><spring:message
code="label.delete" /></a></td>
</tr>
</c:forEach>
</table>
</c:if>
</body>
</html>
Перейдемо до класу User:
package com.seostella.spring.domain.user;
import javax.persistence.*;
import com.seostella.spring.domain.Country;
/**
*
* @author seostella.com
*/
@NamedQueries({
@NamedQuery(name = User.NamedQuery.USER_FIND_ALL, query = "from User"),
@NamedQuery(name = User.NamedQuery.USER_FIND_BY_ID, query = "from User where id = :id") })
@NamedNativeQueries({
@NamedNativeQuery(name = User.NamedQuery.USER_FIND_BY_NAME, query = "select * from hb_user where name like :name", resultClass = User.class) })
@Entity
@Table(name = "hb_user")
public class User {
@Id
@GeneratedValue
private long id;
@Column(name = "name", unique = true, nullable = false)
private String name;
@Column(nullable = false)
private String password;
@Column(columnDefinition = "enum('male','female')")
@Enumerated(EnumType.STRING)
private Gender gender = Gender.male;
@ManyToOne
@JoinColumn(name = "country_id")
private Country country;
private Boolean subscribed;
public User() {
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Country getCountry() {
return country;
}
public Gender getGender() {
return gender;
}
public void setCountry(Country country) {
this.country = country;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public Boolean getSubscribed() {
return subscribed;
}
public void setSubscribed(Boolean subscribed) {
this.subscribed = subscribed;
}
public static class NamedQuery {
public static final String USER_FIND_ALL = "User.findAll";
public static final String USER_FIND_BY_ID = "User.findById";
public static final String USER_FIND_BY_NAME = "User.findByName";
}
}
@NamedQueries({
@NamedQuery(name = User.NamedQuery.USER_FIND_ALL, query = "from User"),
@NamedQuery(name = User.NamedQuery.USER_FIND_BY_ID, query = "from User where id = :id") })
@NamedNativeQueries({
@NamedNativeQuery(name = User.NamedQuery.USER_FIND_BY_NAME, query = "select * from hb_user where name like :name", resultClass = User.class) })
- іменовані запити, один з яких, USER_FIND_BY_NAME, є "сирим" запитом. Об'єкти Query для подібних запитів формуються наступним способом:
Query q = sessionFactory.getCurrentSession().getNamedQuery( User.NamedQuery.USER_FIND_BY_ID );
Інші елементи цього класу розглядалися у статті Основи Hibernate 3 на прикладі роботи з MySQL.
Класи UserDAO і UserDAOImpl:
package com.seostella.spring.dao;
import com.seostella.spring.domain.user.User;
import java.util.List;
/**
*
* @author seostella.com
*/
public interface UserDAO {
public void saveUser(User user);
public List<User> userList();
public void removeUser(Long id);
public User retriveUser(Long id);
public List<User> findUsersByName(String name);
}
package com.seostella.spring.dao;
import com.seostella.spring.domain.Country;
import com.seostella.spring.domain.user.User;
import com.seostella.spring.service.CountryService;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
*
* @author seostella.com
*/
@Repository
public class UserDAOImpl implements UserDAO {
@Autowired
CountryService countryService;
@Autowired
private SessionFactory sessionFactory;
public void saveUser(User user) {
Country country = countryService.retriveCountry( user.getCountry().getId() );
user.setCountry(country);
sessionFactory.getCurrentSession().saveOrUpdate(user);
}
@SuppressWarnings("unchecked")
public List<User> userList() {
return sessionFactory.getCurrentSession().getNamedQuery( User.NamedQuery.USER_FIND_ALL ).list();
}
public void removeUser(Long id) {
User user = (User) sessionFactory.getCurrentSession().load(
User.class, id);
if (null != user) {
sessionFactory.getCurrentSession().delete(user);
}
}
public User retriveUser(Long id){
Query q = sessionFactory.getCurrentSession().getNamedQuery( User.NamedQuery.USER_FIND_BY_ID );
q.setLong("id", id);
return (User) q.uniqueResult();
}
@SuppressWarnings("unchecked")
public List<User> findUsersByName(String name){
Query q = sessionFactory.getCurrentSession().getNamedQuery( User.NamedQuery.USER_FIND_BY_NAME );
q.setString("name", "%" + name + "%");
return (List<User>) q.list();
}
}
Класи UserService і UserServiceImpl:
package com.seostella.spring.service;
import com.seostella.spring.domain.user.User;
import java.util.List;
/**
*
* @author seostella.com
*/
public interface UserService {
public void saveUser(User user);
public List<User> userList();
public void removeUser(Long id);
public User retriveUser(Long id);
public List<User> findUsersByName(String name);
}
package com.seostella.spring.service;
import com.seostella.spring.dao.UserDAO;
import com.seostella.spring.domain.user.User;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
*
* @author seostella.com
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Transactional
public void saveUser(User user) {
userDAO.saveUser(user);
}
@Transactional
public List<User> userList() {
return userDAO.userList();
}
@Transactional
public void removeUser(Long id) {
userDAO.removeUser(id);
}
@Transactional
public User retriveUser(Long id){
return userDAO.retriveUser(id);
}
@Transactional
public List<User> findUsersByName(String name){
return userDAO.findUsersByName( name );
}
}
UserController і jsp-файли:
package com.seostella.spring.controller;
import com.seostella.spring.domain.user.User;
import com.seostella.spring.service.CountryService;
import com.seostella.spring.service.UserService;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* @author seostella.com
*/
@Controller
public class UserController {
@Autowired
private UserService userService;
@Autowired
private CountryService countryService;
@RequestMapping("/user/index")
public String listUsers(Map<String, Object> map) {
map.put("user", new User());
map.put("findUser", new User());
map.put("userList", userService.userList());
map.put("countryList", countryService.countryList());
return "user_list";
}
@RequestMapping(value = "/user/add", method = RequestMethod.POST)
public String addUser(@ModelAttribute("user") User user, BindingResult result) {
userService.saveUser(user);
return "redirect:/user/index";
}
@RequestMapping("/user/delete/{userId}")
public String deleteUser(@PathVariable("userId") Long userId) {
userService.removeUser(userId);
return "redirect:/user/index";
}
@RequestMapping("/user/save")
public String saveUser(@ModelAttribute("user") User user, BindingResult result) {
userService.saveUser(user);
return "redirect:/user/edit/" + user.getId();
}
@RequestMapping("/user/edit/{userId}")
public String editUser(@PathVariable("userId") Long userId, Map<String, Object> map) {
User user = userService.retriveUser(userId);
map.put("user", user);
map.put("countryList", countryService.countryList());
return "user_edit";
}
@RequestMapping("/user/find")
public String findUsers(@ModelAttribute("findUser") User user, BindingResult result, Map<String, Object> map) {
map.put("userList", userService.findUsersByName( user.getName() ) );
map.put("user", new User());
return "user_list";
}
}
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Spring Hibernate Example</title>
</head>
<body>
<jsp:include flush="false" page="menu.jsp" />
<h2>Edit '${user.name}' from ${user.country.name}</h2>
<form:form method="post"
action="${pageContext.request.contextPath}/user/save"
commandName="user">
<form:hidden path="id" />
<jsp:include flush="true" page="user_form.jsp" />
</form:form>
<a href="${pageContext.request.contextPath}/user/index"
title="User List">User List</a>
</body>
</html>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<table>
<tr>
<td><form:label path="name"><spring:message code="label.name"/></form:label></td>
<td><form:input path="name" /></td>
</tr>
<tr>
<td><form:label path="password"><spring:message code="label.password"/></form:label></td>
<td><form:input path="password" /></td>
</tr>
<tr>
<td><form:label path="gender"><spring:message code="label.gender"/></form:label></td>
<td>
<form:radiobutton path="gender" value="male" /><spring:message code="label.male"/>
<form:radiobutton path="gender" value="female" /><spring:message code="label.female"/>
</td>
</tr>
<tr>
<td><form:label path="country"><spring:message code="label.country"/></form:label></td>
<td>
<form:select path="country.id">
<form:option value="0" label="Select" />
<form:options items="${countryList}" itemValue="id" itemLabel="name" />
</form:select>
</td>
</tr>
<tr>
<td><form:label path="subscribed"><spring:message code="label.subscribed"/></form:label></td>
<td><form:checkbox path="subscribed" label="Would you like to join our mailinglist?" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="<spring:message code="label.saveuser"/>"/>
</td>
</tr>
</table>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Spring Hibernate Example</title>
</head>
<body>
<jsp:include flush="false" page="menu.jsp" />
<h2>User List</h2>
<form:form method="post"
action="${pageContext.request.contextPath}/user/add"
commandName="user">
<jsp:include flush="true" page="user_form.jsp">
<jsp:param name="adduser" value="true" />
</jsp:include>
</form:form>
<h3>Find user: </h3>
<form:form method="post"
action="${pageContext.request.contextPath}/user/find"
commandName="findUser">
<form:label path="name"><spring:message code="label.name"/></form:label>
<form:input path="name" />
<input type="submit" value="<spring:message code="label.go"/>"/>
</form:form>
<h3>
<spring:message code="label.users" />
</h3>
<c:if test="${!empty userList}">
<table class="data">
<tr>
<th><spring:message code="label.name" /></th>
<th><spring:message code="label.password" /></th>
<th><spring:message code="label.gender" /></th>
<th><spring:message code="label.country" /></th>
<th><spring:message code="label.subscribed" /></th>
<th> </th>
</tr>
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.name}</td>
<td>${user.password}</td>
<td>${user.gender}</td>
<td>${user.country.name}</td>
<td>${user.subscribed}</td>
<td><a
href="${pageContext.request.contextPath}/user/edit/${user.id}"><spring:message
code="label.edit" /></a></td>
<td><a
href="${pageContext.request.contextPath}/user/delete/${user.id}"><spring:message
code="label.delete" /></a></td>
</tr>
</c:forEach>
</table>
</c:if>
</body>
</html>
Також представимо допоміжний клас HomeController і jsp-файли: home.jsp і menu.jsp:
package com.seostella.spring.controller;
import java.util.Locale;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* @author seostella.com
*/
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
return "home";
}
}
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page session="false"%>
<html>
<head>
<title>Home</title>
</head>
<body>
<jsp:include flush="false" page="menu.jsp" />
<h2>Home page ${user.name}</h2>
</body>
</html>
<a href="${pageContext.request.contextPath}/" title="Home">Home</a>
<a href="${pageContext.request.contextPath}/user/index" title="User List">User List</a>
<a href="${pageContext.request.contextPath}/country/index" title="Country List">Country List</a>
<hr>
Завантажити код програми можна за наступним посиланням - Завантажити spring-hibernate.zip
< | Spring 3 і Hibernate 3. Частина 1 |
29 листопада 2012 р. 02:38
|
Добавлять надо либы какие ещё? Не запускается ни в 6 томкате, ни в 7. Также в родном STS. 100500 ошибок. 10 часов жизни убил на этот пример.
|