Разработка

веб-приложений

на Jav 

Трехуровневая архитектура

Веб-клиент

Веб-приложение

База данных

Веб-приложение

WAR-файл

Java

классы

Java

библиотеки

Ресурсы

Конфигурационные файлы

Пример web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<display-name>Documentation portal</display-name>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	<servlet>
		<servlet-name>app-servlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/app-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>app-servlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

Сервер приложений

  • Tomcat
  • GlassFish
  • WildFly
  • WebSphere

 Java Servlets –спецификация сервера приложений

В дальнейшем в качестве сервера приложений будет использоваться Tomcat

Spring

Spring Framework – проект, предоставляющий множество инструментов для быстрой и удобной Enterprise-разработки

Центральная возможность – контейнер бинов

Объявление бинов

Xml-конфигурация

Аннотации

<bean id="imageService" class="pro.sisit.learningdesk.services.ImageServiceImpl">
	<property name="imageDAO" ref="imageDAO" />
	<property name="fileStorage" ref="fileStorage" />
</bean>
@Service
public class ImageServiceImpl implements ImageService {

	@Autowired
	private ImageDAO imageDAO;

	@Autowired
	private FileStorage fileStorage;

	// Методы
}

Аннотации бинов

Базовая аннотация – @Component

Равносильные аннотации – @Service,                                                                           @Repository,                                                                     @Controller

Аннотация с дополнительным поведением –                                                            @RestController

Dependency Injection

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDAO userDAO;

	@Autowired
	private UserRoleDAO userRoleDAO;

	@Autowired
	private PasswordEncoder encoder;

}

Каждый бин декларативно объявляет свои зависимости, и контейнер при создании бина внедряет подходящие реализации

Всё вместе

Tomcat

Приложение

Spring

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Бин

Архитектура веб-приложения

  • Внешнее API
  • Сервисы
  • Слой доступа к данным

Слой доступа к данным

Сущность – отображение таблиц БД в Java-классы.

DAO (Data Access Object) – специальный объект для формирования запросов к БД

Слой доступа к данным состоит из сущностей и DAO.

Спецификация работы с хранимыми данными – JPA, Java Persistence API.

Java Persistence API

JPA описывает работу с хранимыми данными, по сути – спецификация ORM.

JPA включает в себя:

  • Entity
  • Criteria API
  • JPQL
  • и многое другое

 

В Spring используется популярная реализация JPA – Hibernate.

Hibernate

Основные элементы:

  • Session
  • SessionFactory
  • Criteria
  • Query

Session представляет текущую сессию по работе с базой данных, позволяет проводить простейшие операции с БД, а также создавать запросы.

SessionFactory позволяет создавать сессии, но можно настроить автоматическое создание

Criteria

Criteria – удобный инструмент для программного построения Select-запросов

@Override
public ArticleNode getFirstArticle(CategoryNode parent) {
	Criteria criteria = getSession().createCriteria(ArticleNode.class);
	criteria.add(Restrictions.eq("parent", parent));
	criteria.addOrder(Order.asc("orderNumber"));
	criteria.setMaxResults(1);
	return ArticleNode.class.cast(criteria.uniqueResult());
}

HQL и Query

@Override
public List<OrganisationAuthentications> getOrgAuths(Date startDate, Date endDate) {
	Query query = getSession().createQuery("select authUser.contract.id, "
                        + "count(*) from " + type.getCanonicalName()
			+ " auth left join auth.user authUser "
			+ "where timestamp < :end and timestamp >= :start"
                        + " and authUser.contract is not null "
			+ "group by authUser.contract.id");
	query.setDate("start", startDate);
	query.setDate("end", endDate);
	return getAuthentications(query.list());
}

HQL – SQL-подобный объектно-ориентированный язык запросов, реализация JPQL

Объявление сущностей и DAO

@Entity
@Table(name = "user_roles")
public class UserRole {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@ManyToOne(fetch = FetchType.LAZY)
	private User user;

	@Enumerated(EnumType.STRING)
	private Role role;

        // Геттеры/сеттеры
}

DAO – @Repository

Пример объявления сущности:

Сервисы

Сервис – место обитания бизнес-логики

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDAO userDAO;

	@Autowired
	private UserRoleDAO userRoleDAO;

	@Override
	public User findByLogin(String login) {
		if (login == null || login.isEmpty()) {
			throw new IllegalArgumentException();
		}
		return userDAO.findByLogin(login);
	}

}

Внешнее API

Внешнее API состоит из компонентов, обрабатывающих HTTP и другие запросы.

SOAP-сервисы – JAX-WS (Java API for Xml Web Services)

HTTP-запросы – Spring MVC

REST-сервисы – Spring REST

Контроллеры

Задача – обработка простых HTTP-запросов

@Controller
public class AdminController {
	
	@RequestMapping("/admin/**")
	public String getIndex() {
		return "admin/index";
	}
}

REST-контроллеры

Особенность – ответ автоматически сериализуется в заданный клиентом формат

@RestController
@RequestMapping("system")
public class SystemInfoRestService {

	@Autowired
	private SystemService systemService;

	@RequestMapping(path = "version", method = RequestMethod.GET)
	public String getVersion() {
		return systemService.getVersion();
	}

}

Вспомогательные инструменты

  • Миграции схемы БД
  • Сборка
  • Управление зависимостями
  • Тестирование
  • Логирование

Liquibase

Инструмент миграции данных.

Наборы изменений описываются в xml-конфигурации.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog>
    <changeSet id="create table articles" author="a.petrov">
        <createTable tableName="articles">
            <column name="id" type="bigint" autoIncrement="true">
                <constraints primaryKey="true" primaryKeyName="articles_pk" />
            </column>
            <column name="text" type="text">
                <constraints nullable="false" />
            </column>
            <column name="parent_id" type="bigint">
                <constraints foreignKeyName="articles_parent_id_fk" deleteCascade="true"
                             references="articles(id)" />
            </column>
        </createTable>
    </changeSet>
</databaseChangeLog>

Gradle

Gradle – система сборки проекта, которая также управляет зависимостями.

Взял лучшее из Maven'а, добавил много хорошего.

Конфигурационные файлы пишутся на скриптовом JVM-языке Groovy. Всё становится лучше с Groovy!

build.gradle

apply plugin: 'war'

sourceCompatibility=1.8
targetCompatibility=1.8

tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

war {
    from ('../learningdesk-client/build') { into 'resources'}
    manifest {
        attributes  'Version' : version
    }
    archiveName = project.parent.name + '##' + project.version + '.war'
}

dependencies {
    def springVersion = '4.2.2.RELEASE'
    compile group: 'org.springframework', name: 'spring-beans', version: springVersion
    compile group: 'org.springframework', name: 'spring-orm', version: springVersion
    compile group: 'org.springframework', name: 'spring-context', version: springVersion
    compile group: 'org.springframework', name: 'spring-test', version: springVersion
    compile group: 'org.springframework', name: 'spring-web', version: springVersion
    testCompile group: 'org.testng', name: 'testng', version:'6.9.+'
    testCompile group: 'org.mockito', name: 'mockito-all', version:'1.10.19'
}

Автотесты

TestNG – мощная библиотека 

автотестирования, многое взявшая из JUnit.

Отличительные особенности:

  • Data-driven тестирование
  • Параллельное выполнение тестов
  • Конфигурирование наборов тестов

Mockito – удобная библиотека для создания объектов-заглушек.

Пример автотеста

@DataProvider(name = "findByLoginData")
public Object[][] getFindByLoginData() {
	User user = new User();
	return new Object[][] { new Object[] { "login", user, user }, 
                                new Object[] { "", user, null },
			        new Object[] { null, user, null } };
}

@Test(dataProvider = "findByLoginData")
public void testFindByLogin(String login, User daoUser, User expected) {
	UserServiceImpl service = new UserServiceImpl();
	UserDAO dao = mock(UserDAO.class);
	inject(service, dao, UserDAO.class);
	when(dao.findByLogin(login)).thenReturn(daoUser);
	Assert.assertEquals(service.findByLogin(login), expected);
}

Логирование

SLF4J – универсальный и удобный фасад для логирования данных.

Log4J – гибкая и мощная библиотека для логирования данных.

private final Logger logger = LoggerFactory.getLogger(getClass().getCanonicalName());
	
// В далеком-далеком методе
logger.error("Happened error in REST controller");
<log4j:configuration>
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<layout class="org.apache.log4j.PatternLayout" />
	</appender>
	<root>
		<level value="INFO" />
		<appender-ref ref="console" />
	</root>
</log4j:configuration>

Спасибо за внимание.

Презентация доступна по адресу: 

https://slides.com/walkingdev/javax-base/

Логирование: https://habrahabr.ru/post/113145/

Основы Hibernate: https://habrahabr.ru/post/132385/

Liquibase: https://habrahabr.ru/post/178665/

Gradle: https://habrahabr.ru/post/107085/

javax-base

By walkingdev

javax-base

  • 833