Перейти к содержанию

Spring Framework

Материал из Викиучебника — открытых книг для открытого мира

Простой проект с использованием Spring MVC

[править]

Для первого знакомства создадим проект по управлению пользователями. Пользователей можно смотреть, добавлять, удалять и изменять. Все очень просто. Разделим проект на две части - одна часть будет реализацией бизнес логики, а вторая для ее управления и отображения. Сделано это для того, чтобы реализовать слабую связанность компонентов в проекте и облегчения тестирования.

Для работы нужно:

  • Apache Tomcat 7.0.22
  • Java SDK 7
  • Ant 1.7
  • Spring Framework 3.1.1
  • NetBeans IDE 7.1

Создание проекта ModelService

[править]

Создадим проект в NetBeans для бизнес логики под именем ModelService:


Посмотрим на проект UserService.

Сервис-слой приложения(Содержит интерфейсы, в которых описано ЧТО ДЕЛАТЬ С ДАННЫМИ или, другими словами, бизнес логика приложения . Также содержит практические реализации этих интерфейсов.). Добавим в проект файлы IUserService.java, UserService.java и User.java.

Аннотации

Интерфейс сервиса org.app.service.IUserService

package org.app.service;

import java.util.List;
import org.app.domain.User;

public interface IUserService {
    List<User> getAll();
    void updateUser(User user);
    void deleteUser(Long id);
    void addUser(User user);
    
}

... и его реализация

package org.app.service;

import java.util.ArrayList;
import java.util.List;
import org.app.domain.User;
import org.springframework.stereotype.Service;

@Service
public class UserService implements IUserService{

    List<User> users = new ArrayList<User>();
    
    public UserService() {
        init();
    }

    private void init(){
        users.add(new User(Long.valueOf(1), "alec"));
    }
    
    @Override
    public List<User> getAll() {
        return users;
    }

    @Override
    public void updateUser(User user) {
        for (User us : users) {
            if (us.getId().longValue() == user.getId().longValue()) {
                int index = users.indexOf(us);
                users.set(index, user);
                break;
            }
        }
    }

    @Override
    public void deleteUser(Long id) {
        for(User u : users){
            if(u.getId().longValue() == id.longValue()) {
                users.remove(u);
                break;
            }
        }
    }

    @Override
    public void addUser(User user) {
        Long l = Long.MAX_VALUE;
        for (User u : users) {
            l = u.getId();
        }
        user.setId(l + 1);
        users.add(user);
    }    
}

Доменный слой (Здесь находятся POJO-классы, такие как User - это то, ЧЕМ приложение оперирует в бизнес логике). Сущность пользователя с которой мы работаем - User.java:

package org.app.domain;

public class User {
    
    private Long id;   
    private String name;
	
    public User() {
    }
    
    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }
    
    public Long getId() {
	return id;
    }

    public void setId(Long id) {
	this.id = id;
    }

    public String getName() {
	return name;
    }

    public void setName(String name) {
	this.name = name;
    }   	
}

Создание проекта UserProject

[править]

Создадим новый Web проект в NetBeans под именем UserProject:

Посмотрим на проект UserProject.

В дескрипторе развертывания приложения, web.xml, мы определяем, что все, что в запросе соответствует паттерну *.htm, должно обрабатываться DispatcherServlet из Spring-а. Также установим страницу по умолчанию в redirect.jsp:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Файл applicationContext.xml оставим как есть. Потом туда можно будет добавлять настройки для Hibernate, JPA и т.д.

Файл dispatcher-servlet.xml содержит описания бинов (Java-файлов), которые будет использовать DispatcherServlet и является контекстом сервлета (WebApplicationContext).

<context:component-scan base-package="org.app" /> - указывает Spring где в CLASSPATH нужно искать бины контроллеров и сервисов(которые помечены аннотациями @Controller и @Service).

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.app" />

    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />   
    
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />
</beans>

Веб-слой приложения (классы-контроллеры, описывающие КАК и КОГДА приложение взаимодействует с пользователем через веб.). Добавим в проект контроллер UserController.java

Аннотации

package org.app.controller;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.app.domain.User;
import org.app.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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;

@Controller
@Scope("singleton")
public class UserController {
    
    @Autowired
    private IUserService userService;  
   
    @PostConstruct
    public void post(){
        System.out.println("post construct");
    }
    @PreDestroy
    public void pre(){
        System.out.println("pre destroy");
    }
    
    @RequestMapping(value="/index.htm", method=RequestMethod.GET)
    public String index(Model model) {
        
	model.addAttribute("accounts", userService.getAll());
	return "index"; // показываем страницу index.jsp
    }
    
    @RequestMapping(value="/user/create.htm", method=RequestMethod.GET)
    public String createUser(@ModelAttribute("userAttribute") User account, Model model) {
        
	return "usercreate"; // показываем страницу usercreate.jsp
    }
    
    @RequestMapping(value="/user/update/{id}.htm", method=RequestMethod.GET)
    public String updateUser(@PathVariable Long id, @ModelAttribute("userAttribute") User account, Model model){
        for(User us : userService.getAll()){
            if(us.getId().longValue() == id.longValue()){
                account.setId(us.getId());
                account.setName(us.getName());
                model.addAttribute("userAttribute", account); 
                break;
            }
        }
        
        return "userupdate";
    }
    
    @RequestMapping(value="/user/delete/{id}.htm", method=RequestMethod.GET)
    public String deleteUser(@PathVariable Long id, Model model){  
        userService.deleteUser(id);        
        return "redirect:/index.htm"; // делаем редирект на index.htm
    }
   	
	@RequestMapping(value="/user/save.htm", method=RequestMethod.POST)
	public String saveUser(@ModelAttribute("userAttribute") User account, Model model) {
		if(account.getId() == null){
            this.userService.addUser(account);
        } else {
            this.userService.updateUser(account);
        }
		return "redirect:/index.htm";
	}
	
}

Для проверки работы приложения можно создать файл org.app.controller.Main:

package org.app.controller;

import org.app.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext(new String[] {"/web/WEB-INF/dispatcher-servlet.xml"});
        IUserService iuser =  (IUserService)context.getBean("userService"); // имя бина должно быть с маленькой буквы
        System.out.println("count of users:"+iuser.getAll().size());
    }
}


Слой представления (Описывает ЧТО пользователь увидит при взаимодействии с приложением). Слой состоит из 4 файлов JSP: redirect, index, usercreate и userupdate:

redirect.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<% response.sendRedirect("index.htm"); %>

index.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>User catalog</title>
    </head>

    <body>
        <a href="user/create.htm">create</a><br/>
        
        <c:forEach items="${accounts}" var="car">
            username: ${car.name} <a href="user/update/${car.id}.htm">update</a> <a href="user/delete/${car.id}.htm">delete</a>
		<br />
	</c:forEach>
    </body>
</html>

usercreate.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>Create user</h1>
        <c:url var="saveUrl" value="/user/save.htm" />
        <form:form modelAttribute="userAttribute" method="POST" action="${saveUrl}">
            User:
            <form:input path="name"></form:input>
<input type="submit" value="Save" />
        </form:form>
    </body>
</html>

userupdate.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>        
    </head>
    <body>
        <h1>Update user</h1>
        <c:url var="saveUrl" value="/user/save.htm" />
        <form:form modelAttribute="userAttribute" method="POST" action="${saveUrl}">
            
            <form:hidden path="id" />
            User:
            <form:input path="name"></form:input>
<input type="submit" value="Save" />
        </form:form>
    </body>
</html>

Это все. Можно запускать проект и смотреть что получилось.

Средний проект с использованием Spring MVC, Hibernate, AJAX и валидации

[править]

Создадим проект для хранения данных пользователей в организации. И снова разделим проект на две части. Будем использовать jQuery для отправки ajax запросов. И так же будем проверять входящие данные на валидность с помощью валидаторов.

Для работы нужно:

  • Apache Tomcat 7.0.22
  • Java SDK 7
  • Ant 1.7
  • Spring Framework 3.1.1
  • NetBeans IDE 7.1
  • Hibernate 3.2.5
  • jQuery 1.7.2

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

[править]

Создаем базу данных organization и соединение в NetBeans.

use organization;

CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255),
    position_id INT,
    group_id INT
) ENGINE = InnoDB;

CREATE TABLE positions (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255)
)ENGINE = InnoDB;

CREATE TABLE groups (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255)
)ENGINE = InnoDB;

CREATE TABLE languages (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255)
)ENGINE = InnoDB;

CREATE TABLE language_user (
    user_id INT UNSIGNED ,
    language_id INT UNSIGNED
)ENGINE = InnoDB;

INSERT INTO positions (title) VALUES ('junior developer');
INSERT INTO positions (title) VALUES ('middle developer');
INSERT INTO positions (title) VALUES ('senior developer');

INSERT INTO groups (title) VALUES ('group a');
INSERT INTO groups (title) VALUES ('group b');
INSERT INTO groups (title) VALUES ('group c');

INSERT INTO languages (title) VALUES ('java');
INSERT INTO languages (title) VALUES ('c#');
INSERT INTO languages (title) VALUES ('php');

INSERT INTO users (username, position_id, group_id) VALUES ('user 1', 1, 1);
INSERT INTO users (username, position_id, group_id) VALUES ('user 2', 2, 2);
INSERT INTO users (username, position_id, group_id) VALUES ('user 3', 3, 3);
INSERT INTO users (username, position_id, group_id) VALUES ('user 4', 2, 2);
INSERT INTO users (username, position_id, group_id) VALUES ('user 5', 3, 3);

INSERT INTO language_user (user_id, language_id) VALUES (1,1);
INSERT INTO language_user (user_id, language_id) VALUES (2,1);
INSERT INTO language_user (user_id, language_id) VALUES (3,1);
INSERT INTO language_user (user_id, language_id) VALUES (3,3);
INSERT INTO language_user (user_id, language_id) VALUES (4,2);
INSERT INTO language_user (user_id, language_id) VALUES (5,2);
INSERT INTO language_user (user_id, language_id) VALUES (4,1);
INSERT INTO language_user (user_id, language_id) VALUES (5,3);

Создание проекта OrganizationProject

[править]

Создадим новый Web проект в NetBeans под именем OrganizationProject:

Подключаемые библиотеки:

  • logback-classic-1.0.4.jar
  • logback-core-1.0.4.jar
  • slf4j-api.1.6.4.jar
  • OrgService.jar
  • mysql-connector-java-5.1.7-bin.jar
  • Hibernate
  • Persistence

Файл web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
    
</web-app>

В файле applicationContext.xml определим бин messageSource с помощью которого будем использовать в валидаторе локализованные сообщения.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
 <property name="basename">
     <value>messages</value>
 </property>
 </bean>
</beans>

Файл dispatcher-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.app" />
    
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />      

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />    

</beans>

Веб слой приложения.

Файл org.app.controller.UsersController:

package org.app.controller;

import org.app.config.UserSettings;
import org.app.service.IGroupsService;
import org.app.service.IUserService;
import org.app.service.PositionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Controller
@RequestMapping(value="/user")
public class UsersController {
    @Autowired
    private PositionService positionService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IGroupsService groupsService;    
    @Autowired
    private UserSettings userSettings;
    
    Logger log = LoggerFactory.getLogger(UsersController.class);    
    
    @RequestMapping(value="/index.htm", method=RequestMethod.GET)
    public String index(Model model) {
        model.addAttribute("groups", groupsService.getAll());
        model.addAttribute("positions", positionService.getAll());
        model.addAttribute("users", userService.getAll());
        log.debug("xxx debug");
        userSettings.loadSettings();
        log.debug("user settings :{}, {}", userSettings.getCountry(), userSettings.getLanguage());
        return "user/list";
    }
     
    @RequestMapping(value="addajax.htm",method=RequestMethod.POST)
    public @ResponseBody String add(@RequestParam(value = "username", required = true) String username, 
    @RequestParam(value = "positionid", required = true) Integer positionid, 
    @RequestParam(value = "groupid", required = true) Integer groupid ){
        String returnText;
        
        if(!username.isEmpty()){
            userService.addEntity(username, groupid, positionid);            
            returnText = "User has been added to the list. Total number of users are: " +username+";posid = "+positionid+";grid="+groupid;
        }else{
            returnText = "Sorry, an error has occur. User has not been added to list.";
        }
        return returnText;
    }
    
    @RequestMapping(value="/deleteajax.htm",method=RequestMethod.POST)
    public @ResponseBody String delete(@RequestParam(value = "userid", required = true) Integer userid ){
        String returnText;
        if(userid.intValue() != 0){
            userService.deleteEntity(userid);            
            returnText = "deleted: " +userid;
        }else{
            returnText = "Sorry, an error has occur. User has not been added to list.";
        }
        return returnText;
    }
    
}

Файл org.app.controller.GroupController:

package org.app.controller;

import org.app.domain.entities.Groups;
import org.app.service.IGroupsService;
import org.app.utils.GroupValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

@Controller
public class GroupController {
    
    @Autowired
    private IGroupsService groupsService;
    
    Logger log = LoggerFactory.getLogger(GroupController.class);
    
    GroupValidator groupValidator = new GroupValidator();
    
    @RequestMapping(value="/group/list.htm", method=RequestMethod.GET)
    public String list(Model model){
        model.addAttribute("groups", groupsService.getAll());
        log.debug("group list");
        return "group/list";
    }
    
    @RequestMapping(value="/group/add.htm",method=RequestMethod.GET)
    public String add(@ModelAttribute("groupAttribute") Groups group){
        
        return "group/add";
    }

    @RequestMapping(value = "/group/save.htm", method = RequestMethod.POST)
    public String save(@ModelAttribute("groupAttribute") Groups group, BindingResult result) {
        groupValidator.validate(group, result);
        if (!result.hasErrors()) {
            if (group.getId() == null) {
                log.debug("group save");
                this.groupsService.addEntity(group);
            }
        }        
        return "redirect:/group/list.htm";
    }
}

Файл org.app.controller.Main для проверки работы:

package org.app.controller;

import java.util.Locale;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {
    
    public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext(new String[] {"/web/WEB-INF/dispatcher-servlet.xml", "/web/WEB-INF/applicationContext.xml"});
        
        String message = context.getMessage("title.required", null, Locale.getDefault());
        System.out.println("mess:"+message);
    }
}

Файл org.app.utils.GroupValidator:

package org.app.utils;

import org.app.domain.entities.Groups;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

public class GroupValidator implements Validator{

    @Override
    public boolean supports(Class<?> type) {
        return Groups.class.equals(type);
    }

    @Override
    public void validate(Object o, Errors errors) {
        Groups group = (Groups) o;
        if(group.getTitle().trim().equals("")){
            errors.rejectValue("title", "title.required");
        }
    }    
}

Файл org.app.config.UserSettings для сохранения информации пользователя:

package org.app.config;

import java.util.Locale;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("userSettings")
public class UserSettings {    
    
    @Value("#{countryBean}") //inject bean
    private Country country;

    public UserSettings() {        
    }
    
    public void loadSettings(){
        country.loadSettings();
    }
    
    public String getLanguage(){        
        return country.getLanguage();
    }
    
    public String getCountry(){
        return country.getCountry();
    }    
}

@Component("countryBean")
class Country {
    
    @Value("RU") //inject string directly
    private String country;
    
    @Value("ru")
    private String language;
    
    public Country() {        
    }

    public String getCountry() {
        return country;
    }

    public String getLanguage() {
        return language;
    }
    
    void loadSettings(){
        this.country = Locale.getDefault().getCountry();
        this.language = Locale.getDefault().getLanguage();
    }    
}

Слой представления приложения.

Чтобы в каждом файле не использовать одни и те же строки воспользуемся файлом include.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>

Файл user/list.jsp:

<%@ include file="../include.jsp" %>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
        <script type="text/javascript" src="<c:url value="/resources/js/jquery-1.7.2.min.js" />"></script>
        
        <script type="text/javascript">
            function addUser() {
                
                var name = $('#name').val();
                var positionid = $("#positions option:selected").val();
                var groupid = $("#groups option:selected").val();
                
                $.ajax({
                    type: "POST",
                    url: "${pageContext.request.contextPath}/user/addajax.htm",
                    data: "username=" + name+"&positionid="+positionid+"&groupid="+groupid,
                    success: function(response){
                        $('#info').html(response);
                        $('#name').val('');
                        
                    },
                    error: function(e){
                        alert('Error: ' + e);
                    }
                });
            }
            function deleteUser(id){
                
                $.ajax({
                    type: "POST",
                    url: "${pageContext.request.contextPath}/user/deleteajax.htm",
                    data: "userid=" + id,
                    success: function(response){
                        $('#info').html(response);                        
                        
                    },
                    error: function(e){
                        alert('Error: ' + e);
                    }
                });
            }
        </script>
    </head>
    <body>
        <a href="${pageContext.request.contextPath}/group/list.htm">groups</a><br/>
        <h1>List users</h1>
        <ul>
            <c:forEach items="${users}" var="user">
                <li>Name : <c:out value="${user.username}" />;<input type="button" value="Delete" onclick="deleteUser(${user.id})">
            </c:forEach>
        </ul>
        
        <table>
            <tr><td>Enter your name : </td><td> <input type="text" id="name"></td><td>
                    <select id="positions">
                    <c:forEach items="${positions}" var="pos">
                        <option value="${pos.id}"><c:out value="${pos.title}" /></option>
            </c:forEach>
                    </select>
                </td><td>
                    <select id="groups">
                    <c:forEach items="${groups}" var="group">
                        <option value="${group.id}"><c:out value="${group.title}" /></option>
            </c:forEach>
                    </select>
                </td></tr>            
            <tr><td colspan="2"><input type="button" value="Add Users" onclick="addUser()"><br/></td></tr>
            <tr><td colspan="2"><div id="info" style="color: green;"></div></td></tr>
        </table>
    </body>
</html>

Файл group/add.jsp:

<%@ include file="../include.jsp" %>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
        <style>
.error {
color: #ff0000;
font-style: italic;
}
</style>
    </head>
    <body>
        <h1>Add group</h1>
        <c:url var="indexUrl" value="/user/index.htm" />
        <c:url var="saveUrl" value="/group/save.htm" />
        <form:form modelAttribute="groupAttribute" method="POST" action="${saveUrl}">
            Title:
            <form:input path="title"></form:input><form:errors path="title" cssClass="error" />
<input type="submit" value="Save" />
        </form:form>
<p>Return to <a href="${indexUrl}">Index Page</a></p>
    </body>
</html>

Файл group/list.jsp:

<%@ include file="../include.jsp" %>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>List groups</h1>
        <c:url var="indexUrl" value="/user/index.htm" />
        <a href="add.htm">create</a><br/>
        <c:if test="${empty groups}">
        List is empty.<br/>
        </c:if>
        <ul>
            <c:forEach items="${groups}" var="group">
                <li>Title : <c:out value="${group.title}" />;
            </c:forEach>
        </ul>
        <p>Return to <a href="${indexUrl}">Index Page</a></p>
        
    </body>
</html>

Файл logback.xml для логгирования с использованием SLF4J и его реализацией Logback:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %5p | %-55logger{55} | %m %n</pattern>
        </encoder>
    </appender>

    <logger name="org.app.service">
        <level value="DEBUG" />
    </logger>

    <logger name="org.springframework">
        <level value="DEBUG" />
    </logger>

    <root>
        <level value="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

Файл messages.properties:

title.required = Title is required

Создание проекта OrgService

[править]

Создадим проект в NetBeans для бизнес логики под именем OrgService и подключим созданный OrgService.jar в проект OrganizationProject:

Подключаемые библиотеки:

  • org.springframework.context-3.0.0.M3.jar
  • org.springframework.transaction-3.0.0.M3.jar
  • mysql-connector-java-5.1.7-bin.jar
  • Hibernate
  • Persistence

Доменный слой приложения.

HibernateUtil:

package org.utils;

import org.hibernate.Session;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

public class HibernateUtil {

    private static final SessionFactory sessionFactory;
    private static final Session session;
    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml) 
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
            session = sessionFactory.openSession();
        } catch (Throwable ex) {
            // Log the exception. 
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    
    public static Session getSession(){
        return session;
    }
}

Файл org.app.service.IUserService:

package org.app.service;

import java.util.List;
import org.app.domain.entities.Users;

public interface IUserService {
    List<Users> getAll();
    
    void addEntity(String username, Integer groupid, Integer positionid);
    
    void deleteEntity(Integer id);
}

Файл org.app.service.IGroupsService:

package org.app.service;

import java.util.List;
import org.app.domain.entities.Groups;

public interface IGroupsService {
    List<Groups> getAll();
    
    void addEntity(Groups group);
    
    void deleteEntity(Integer id);
}

Файл org.app.service.IPositionService:

package org.app.service;

import java.util.List;
import org.app.domain.entities.Positions;

public interface IPositionService {
    List<Positions> getAll();
}

Файл org.app.service.UsersService:

package org.app.service;

import java.util.ArrayList;
import java.util.List;
import org.app.domain.entities.Users;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;

import org.springframework.stereotype.Service;
import org.utils.HibernateUtil;

@Service
public class UsersService implements IUserService{
    
    Session session;
    public UsersService() {
        this.session = HibernateUtil.getSession();        
    }
    
    @Override
    public List<Users> getAll(){
        List <Users>resultList = new ArrayList<Users>();
        String hql = "from Users u";
        session.beginTransaction();
        Query q = session.createQuery(hql);
        resultList.addAll(q.list());
        session.getTransaction().commit();
        return resultList;
    }
    
    public static void main(String[] args) {
        try {
            
            String hql = "from Users u where id = 1";
            Session session = HibernateUtil.getSessionFactory().openSession();
            
        
            session.beginTransaction();
            Query q = session.createQuery(hql);
            List <Users>resultList = q.list();
            for(Users u : resultList){
                System.out.println("user:"+u.getUsername());
            }
            System.out.println("size:" + resultList.toString());
            session.getTransaction().commit();
            
            SQLQuery sq = session.createSQLQuery("select u.* from users as u, languages as l, language_user as lu where l.id = lu.language_id and u.id = lu.user_id and l.title = ? and u.position_id = ?");
            sq.setParameter(0, "c#");
            sq.setParameter(1, 3);
            List founded = sq.list();
            System.out.println("res:"+founded.size());
        } catch (HibernateException he) {
            he.printStackTrace();
        }
    }

    @Override
    public void addEntity(String username, Integer groupid, Integer positionid) {
        
        session.beginTransaction();
        //Query q = session.createQuery(hql);
        Users u = new Users(username, positionid, groupid);
        session.save(u);
        session.getTransaction().commit();
        
    }

    @Override
    public void deleteEntity(Integer id) {
        
        Users user = (Users) session.get(Users.class, id);
        if(user != null) {
            session.beginTransaction();
            session.delete(user);
            session.getTransaction().commit();
        }
        
    }
}

Файл org.app.service.GroupsService:

package org.app.service;

import java.util.ArrayList;
import java.util.List;
import org.app.domain.entities.Groups;
import org.hibernate.Query;
import org.hibernate.Session;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.utils.HibernateUtil;

@Service
@Transactional
public class GroupsService implements IGroupsService{
    
    Session session;
    
    public GroupsService() {
        this.session = HibernateUtil.getSession(); 
    }
    
    @Override
    public List<Groups> getAll(){
        List <Groups>resultList = new ArrayList<Groups>();
        String hql = "from Groups g"; 
        Query q = session.createQuery(hql);
        resultList.addAll(q.list());
        return resultList;
    }

    @Override
    public void addEntity(Groups group) {  
        session.save(group);
    }

    @Override
    public void deleteEntity(Integer id) {
        
        Groups g = (Groups) session.get(Groups.class, id);
        if(g != null) {
            session.delete(g);
        }
        
    }
}

Файл org.app.service.PositionService:

package org.app.service;

import java.util.ArrayList;
import java.util.List;
import org.app.domain.entities.Positions;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.stereotype.Service;
import org.utils.HibernateUtil;

@Service
public class PositionService implements IPositionService{

    Session session;
    
    public PositionService() {
        this.session = HibernateUtil.getSession();
    }

    
    @Override
    public List<Positions> getAll() {
        List <Positions>resultList = new ArrayList<Positions>();
        String hql = "from Positions u";
        session.beginTransaction();
        Query q = session.createQuery(hql);
        resultList.addAll(q.list());
        session.getTransaction().commit();
        return resultList;
    }
    
}

Файл org.app.domain.entities.Users:

package org.app.domain.entities;

public class Users  implements java.io.Serializable {

     private Integer id;
     private String username;
     private Integer positionId;
     private Integer groupId;

    public Users() {
    }

    public Users(String username, Integer positionId, Integer groupId) {
       this.username = username;
       this.positionId = positionId;
       this.groupId = groupId;
    }
   
    public Integer getId() {
        return this.id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return this.username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    public Integer getPositionId() {
        return this.positionId;
    }
    
    public void setPositionId(Integer positionId) {
        this.positionId = positionId;
    }
    public Integer getGroupId() {
        return this.groupId;
    }
    
    public void setGroupId(Integer groupId) {
        this.groupId = groupId;
    }
}

Файл org.app.domain.entities.Groups:

package org.app.domain.entities;

public class Groups  implements java.io.Serializable {

     private Integer id;
     private String title;

    public Groups() {
    }

    public Groups(String title) {
       this.title = title;
    }
   
    public Integer getId() {
        return this.id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return this.title;
    }
    
    public void setTitle(String title) {
        this.title = title;
    }
}

Настройки Hibernate

[править]

Файл hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/organization</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root</property>
    <mapping resource="org/app/domain/entities/Positions.hbm.xml"/>
    <mapping resource="org/app/domain/entities/Languages.hbm.xml"/>
    <mapping resource="org/app/domain/entities/Groups.hbm.xml"/>
    <mapping resource="org/app/domain/entities/Users.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

Файл hibernate.reveng.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
  <schema-selection match-catalog="organization"/>
  <table-filter match-name="languages"/>
  <table-filter match-name="positions"/>
  <table-filter match-name="groups"/>
  <table-filter match-name="users"/>
</hibernate-reverse-engineering>

Это все. Можно запускать проект и смотреть что получилось.

Простой проект с использованием Spring Framework и JSON

[править]

Создадим проект который будет использовать REST подход с использованием формата JSON и Spring Framework. Как обычно создаем Web проект и подключаем Spring Framework.

Для работы нужно:

  • Apache Tomcat 7.0.22
  • Java SDK 7
  • Ant 1.7
  • Spring Framework 3.1.1
  • NetBeans IDE 7.1
  • Jackson 1.9.7


Подключаемые библиотеки:



Затем редактируем файлы и в итоге получаем следующие изменения.

Файл dispatcher-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
    <context:component-scan base-package="app.controller" />
    
    <mvc:annotation-driven />
    
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<property name="order" value="1" />
        
		<property name="mediaTypes">
			<map>
				<entry key="json" value="application/json" />
			</map>
		</property>

		<property name="defaultViews">
			<list>
				<!-- JSON View -->
				<bean
					class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
				</bean>				
			</list>
		</property>
		<property name="ignoreAcceptHeader" value="true" />
	</bean>
	
	<bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />
</beans>

Файл web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/service/*</url-pattern>
        
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

Файл app.controller.IndexController:

package app.controller;

import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping(value="/index")
public class IndexController {
    
    @RequestMapping(value="/list", method=RequestMethod.GET)
    @ResponseBody
    public final List<UserObject> list(){
        List<UserObject> list = new ArrayList<UserObject>();
        list.add(new UserObject(Long.valueOf(1), "one"));
        list.add(new UserObject(Long.valueOf(2), "two"));
        return list;
    }
    
    @RequestMapping(value="/", method=RequestMethod.GET)
    public String help(){
        return "help";
    }
    
    @RequestMapping(value="create", method=RequestMethod.POST)
    @ResponseBody
    @ResponseStatus(HttpStatus.CREATED)
    public UserObject create(@RequestBody final UserObject entity){
        entity.setId(new Long(1));
        // add to somewhere
        System.out.println("create");
        return entity;
    }
    
    @RequestMapping(value="update", method=RequestMethod.PUT)
    @ResponseStatus(HttpStatus.OK)
    public final void update(@RequestBody final UserObject entity){
        // update to somewhere
        System.out.println("update");
    }
    
    @RequestMapping(value="delete/{id}", method=RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.OK)
    public final void delete(@PathVariable final Long id){
        // delete to somewhere
        System.out.println("delete");
    }
    
    @RequestMapping(value="findbyid/{id}", method=RequestMethod.GET)
    @ResponseBody
    public UserObject findByID(@PathVariable final Long id){
        return new UserObject(id, "three");
    }    
}

Файл app.controller.UserObject:

package app.controller;

public class UserObject {
    private Long id;
    private String name;

    public UserObject()
    {
    }

    public UserObject(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }    

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }
}


Файл jsp/index.jsp:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>User Service</title>
    </head>

    <body>
        <a href="list">list</a>
    </body>
</html>

Файл jsp/help.jsp:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>User Service</title>
    </head>
    <body>
        <h1>Help</h1>
        <a href="list">list</a>
        <a href="delete/5">delete id = 5</a>
        <a href="findbyid/5">find by id = 5</a>
    </body>
</html>

Компилируем проект и запускаем.

См. также

[править]

Ссылки

[править]