Разработка
веб-приложений
на 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