Рубрики
Без рубрики

Пример контроллера, службы и DAO с Spring Boot и JSF

Пример применения контроллера, службы и DAO с JSF и Spring Boot.

Автор оригинала: baeldung.

1. введение

JavaServer Faces-это платформа пользовательского интерфейса на основе компонентов на стороне сервера. Первоначально он был разработан как часть Jakarta EE. В этом уроке мы рассмотрим, как интегрировать JSF в приложение Spring Boot.

В качестве примера мы реализуем простое приложение для создания списка дел.

2. Зависимости Maven

Мы должны расширить наши pom.xml использовать технологии JSF:


    org.apache.tomcat.embed
    tomcat-embed-jasper



    org.glassfish
    javax.faces
    2.3.7

Артефакт javax.faces содержит API-интерфейсы JSF, а также реализации. Подробную информацию можно найти здесь .

3. Настройка сервлета JSF

Фреймворк JSF использует файлы XHTML для описания содержимого и структуры пользовательского интерфейса. Серверная сторона генерирует файлы JSF из описаний XHTML.

Давайте начнем с создания статической структуры в файле index.xhtml в каталоге src/main/webapp :


    
        
        
        TO-DO application
    
    
        

Welcome in the TO-DO application!

This is a static message rendered from xhtml.

Содержимое будет доступно по адресу /index.jsf . Хотя, если мы попытаемся добраться до содержимого на этом этапе, мы получим сообщение об ошибке на стороне клиента:

There was an unexpected error (type=Not Found, status=404).
No message available

Не будет никакого сообщения об ошибке бэкенда. Тем не менее, мы можем выяснить, нам нужен сервлет JSF для обработки запроса и сопоставление сервлета для сопоставления запроса с обработчиком.

Поскольку мы находимся в Spring Boot, мы можем легко расширить наш класс приложений для обработки требуемой конфигурации:

@SpringBootApplication
public class JsfApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(JsfApplication.class, args);
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        FacesServlet servlet = new FacesServlet();
        ServletRegistrationBean servletRegistrationBean = 
          new ServletRegistrationBean(servlet, "*.jsf");
        return servletRegistrationBean;
    }
}

Это выглядит великолепно и довольно разумно, но, к сожалению, все еще недостаточно хорошо. При попытке открыть /index.jsf теперь мы получим еще одну ошибку:

java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory.

К сожалению, нам нужен web.xml рядом с конфигурацией Java. Давайте создадим его в src/webapp/WEB-INF :


    Faces Servlet
    javax.faces.webapp.FacesServlet
    1


    Faces Servlet
    *.jsf

Теперь наша конфигурация готова к работе. Откройте /index.jsp :

Welcome in the TO-DO application!

This is a static message rendered from xhtml.

Прежде чем мы создадим наш пользовательский интерфейс, давайте создадим бэкэнд приложения.

4. Реализация шаблона DAO

DAO расшифровывается как объект доступа к данным. Обычно класс DAO отвечает за две концепции. Инкапсулирование деталей уровня сохраняемости и предоставление интерфейса CRUD для одного объекта. Вы можете найти подробное описание в этом руководстве.

Чтобы реализовать шаблон DAO, мы сначала определим общий интерфейс :

public interface Dao {

    Optional get(int id);
    Collection getAll();
    int save(T t);
    void update(T t);
    void delete(T t);
}

Теперь давайте создадим наш первый и единственный доменный класс в этом приложении для выполнения задач:

public class Todo {

    private int id;
    private String message;
    private int priority;

    // standard getters and setters

}

Следующим классом будет реализация Dao . Прелесть этого шаблона в том, что мы можем предоставить новую реализацию этого интерфейса в любое время.

Следовательно, мы можем изменить уровень сохраняемости, не касаясь остальной части кода.

В нашем примере мы будем использовать класс хранения в памяти :

@Component
public class TodoDao implements Dao {

    private List todoList = new ArrayList<>();
    
    @Override
    public Optional get(int id) {
        return Optional.ofNullable(todoList.get(id));
    }

    @Override
    public Collection getAll() {
        return todoList.stream()
          .filter(Objects::nonNull)
          .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
    }

    @Override
    public int save(Todo todo) {
        todoList.add(todo);
        int index = todoList.size() - 1;
        todo.setId(index);
        return index;
    }

    @Override
    public void update(Todo todo) {
        todoList.set(todo.getId(), todo);
    }

    @Override
    public void delete(Todo todo) {
        todoList.set(todo.getId(), null);
    }
}

5. Уровень Обслуживания

Основная цель уровня DAO-обработка деталей механизма сохранения. В то время как уровень обслуживания стоит поверх него для обработки бизнес-требований.

Обратите внимание, что на интерфейс DAO будут ссылаться из службы:

@Scope(value = "session")
@Component(value = "todoService")
public class TodoService {

    @Autowired
    private Dao todoDao;
    private Todo todo = new Todo();

    public void save() {
        todoDao.save(todo);
        todo = new Todo();
    }

    public Collection getAllTodo() {
        return todoDao.getAll();
    }

    public int saveTodo(Todo todo) {
        validate(todo);
        return todoDao.save(todo);
    }

    private void validate(Todo todo) {
        // Details omitted
    }

    public Todo getTodo() {
        return todo;
    }
}

Здесь служба является именованным компонентом. Мы будем использовать это имя для ссылки на компонент из контекста JSF.

Кроме того, этот класс имеет область сеанса, которая будет удовлетворительной для этого простого приложения.

Для получения дополнительной информации о весенних областях применения ознакомьтесь с этим учебником. Поскольку встроенные области Spring имеют другую модель, чем JSF, стоит рассмотреть возможность определения пользовательской области.

Дополнительные рекомендации по этому вопросу доступны в этом руководстве.

6. Контроллер

Как и в приложении JSP, контроллер будет обрабатывать навигацию между различными представлениями.

Далее мы реализуем минималистичный контроллер. Он будет перемещаться со страницы открытия на страницу списка дел:

@Scope(value = "session")
@Component(value = "jsfController")
public class JsfController {

    public String loadTodoPage() {
        checkPermission();
        return "/todo.xhtml";
    }

    private void checkPermission() {
        // Details omitted
    }
}

Навигация основана на возвращаемом имени. Следовательно, страница load To do отправит нас на страницу todo.xhtml , которую мы реализуем далее.

7. Подключение JSF и весенних бобов

Давайте посмотрим, как мы можем ссылаться на наши компоненты из контекста JSF. Во-первых, мы расширим index.xhtml :


    
       // same code as before
    
    
        
// same code as before

Здесь мы ввели CommandButton внутри элемента формы. Это важно, так как каждая команда UI элемент (например, кнопка command) должна быть помещена внутри элемента Uniform (например, из).

На этом этапе мы можем запустить наше приложение и изучить /index.jsf :

К сожалению, мы получим ошибку, когда нажмем на кнопку:

There was an unexpected error (type=Internal Server Error, status=500).
javax.el.PropertyNotFoundException:
/index.xhtml @11,104 action="#{jsfController.loadTodoPage}":
Target Unreachable, identifier [jsfController] resolved to null

В сообщении четко указывается проблема: контроллер jsf разрешен в null. Соответствующий компонент либо не создан, либо, по крайней мере, невидим из контекста JSF.

В данной ситуации верно последнее.

Нам нужно связать весенний контекст с JSF контекст в рамках webapp/WEB-INF/faces-config.xml :



    
        org.springframework.web.jsf.el.SpringBeanFacesELResolver
    

Теперь, когда наш контроллер готов к работе, нам понадобится todo.xhtml !

8. Взаимодействие Со Службой Из JSF

Наша страница todo.xhtml будет иметь две цели. Во-первых, в нем будут отображаться все элементы задач.

Во-вторых, предложите возможность добавлять новые элементы в список.

Для этого компонент пользовательского интерфейса будет напрямую взаимодействовать с объявленной ранее службой:


    
        
        
        TO-DO application
    
    
        
List of TO-DO items
Message #{item.message} Priority #{item.priority}
Add new to-do item:

Вышеупомянутые две цели реализуются в двух отдельных элементах div .

В первом случае мы использовали элемент таблица данных для представления всех значений из todoService.Все делать .

Второй div содержит форму, в которой мы можем изменить состояние объекта Todo в TodoService.

Мы используем элемент input Text для приема пользовательского ввода, где второй ввод автоматически преобразуется в int. С помощью кнопки command пользователь может сохранить (теперь в памяти) объект Todo с помощью todoService.save .

9. Заключение

Фреймворк JSF может быть интегрирован в фреймворк Spring. Вы должны выбрать, какая структура будет управлять бобами. В этом уроке мы использовали фреймворк Spring.

Однако модель области немного отличается от фреймворка JSF. Таким образом, вы можете рассмотреть возможность определения пользовательских областей в контексте Spring.

Как всегда, код доступен на GitHub .