1. Введение
Model View Controller (MVC) — это популярный шаблон проектирования для создания веб-приложений. В течение нескольких лет это был де-факто принцип разработки современных веб-приложений.
В этом руководстве мы узнаем о создании веб-приложения с использованием Jakarta EE MVC 2.0 с веб-страницей и REST API.
2. JSR-371
Jakarta MVC 2.0 (ранее JSR 371 MVC 1.0) — это основанная на действиях веб-инфраструктура, построенная на Jakarta RESTful Web Services или JAX-RS (ранее Java API для RESTful веб-служб ). JSR-371 дополняет JAX-RS дополнительными аннотациями, которые делают создание веб-приложений более удобным.
JSR 371 или Jakarta MVC стандартизирует то, как мы разрабатываем веб-приложения на Java. Кроме того, основной целью является использование существующих CDI (внедрение контекстов и зависимостей) и проверки компонентов, а также поддержка JSP и Facelets в качестве технологий просмотра.
В настоящее время идет работа над спецификацией Jakarta MVC 2.1, которая, вероятно, будет выпущена вместе с выпуском Jakarta EE 10.
3. Аннотации JSR-371
JSR-371 определяет еще несколько аннотаций помимо аннотаций JAX-RS. Все эти аннотации являются частью пакета jakarta.mvc.*
. **
**
3.1. jakarta.mvc.Контроллер
Аннотация @Controller
помечает ресурс как контроллер MVC. При использовании для класса все методы ресурсов в классе становятся контроллерами. Точно так же использование этой аннотации в методе ресурса делает этот метод контроллером. Как правило, определение @Controller
в методе полезно, если мы хотим определить контроллеры MVC и API REST в одном классе.
Например, давайте определим контроллер:
@Path("user")
public class UserController {
@GET
@Produces("text/html")
@Controller
public String showUserForm(){
return "user.jsp";
}
@GET
@Produces("application/json")
public String getUserDetails(){
return getUserDetails();
}
}
Этот класс имеет @Controller
, который отображает форму пользователя ( showUserForm
) и REST API, который возвращает сведения о пользователе в формате JSON ( getUserDetails
).
3.2. jakarta.mvc.View
Как и @Controller
, мы можем пометить класс ресурса или метод ресурса аннотацией @View
. Как правило, метод ресурса, возвращающий void
, должен иметь @View
. Класс с @View
представляет представление по умолчанию для контроллеров в классе с типом void
.
Например, давайте определим контроллер с помощью @View
:
@Controller
@Path("user")
@View("defaultModal.jsp")
public class UserController {
@GET
@Path("void")
@View("userForm.jsp")
@Produces("text/html")
public void showForm() {
getInitFormData();
}
@GET
@Path("string")
@Produces("text/html")
public void showModal() {
getModalData();
}
}
Здесь и класс ресурса, и метод ресурса имеют аннотацию @View
. Контроллер showForm
отображает представление userForm.jsp.
Точно так же контроллер showModal отображает
файл defaultModal.jsp,
определенный в классе ресурсов.
3.3. jakarta.mvc.binding.MvcBinding
Веб-службы Jakarta RESTful отклоняют запрос с ошибками привязки и проверки. Подобная настройка может не подойти для пользователей, взаимодействующих с веб-страницей. К счастью, Jakarta MVC вызывает контроллер даже при возникновении ошибок привязки и проверки. Как правило, пользователь должен быть хорошо информирован об ошибках привязки данных.
Контроллеры внедряют BindingResult
, чтобы предоставить пользователю удобочитаемые сообщения об ошибках проверки и привязки. Например, давайте определим контроллер с помощью @MvcBinding
:
@Controller
@Path("user")
public class UserController {
@MvcBinding
@FormParam("age")
@Min(18)
private int age;
@Inject
private BindingResult bindingResult;
@Inject
private Models models;
@POST
public String processForm() {
if (bindingResult.isFailed()) {
models.put("errors", bindingResult.getAllMessages());
return "user.jsp";
}
}
}
Здесь, если пользователь вводит возраст
менее 18 лет, он будет отправлен обратно на ту же страницу с ошибками привязки. Страница user.jsp
с помощью языка выражений (EL) может извлекать ошибки
атрибутов запроса и отображать их на странице.
3.4. jakarta.mvc.RedirectScoped
Рассмотрим форму, в которой пользователь заполняет и отправляет данные (HTTP POST). Сервер обрабатывает данные и перенаправляет пользователя на страницу успеха (HTTP GET). Этот шаблон широко известен как шаблон PRG (Post-Redirect-Get) . Есть несколько сценариев, в которых нам нравится хранить данные между POST и GET. В этих сценариях объем моделей/компонентов выходит за рамки одного запроса.
Когда bean-компонент аннотируется с помощью @RedirectScoped,
состояние bean-компонента выходит за рамки одного запроса. Тем не менее, состояние уничтожается после завершения POST, перенаправления и получения. Бин, разграниченный @RedirectScoped
, уничтожается после завершения POST, Redirect и GET.
Например, предположим, что пользователь
bean-компонента имеет аннотацию @RedirectScoped
:
@RedirectScoped
public class User
{
private String id;
private String name;
// getters and setters
}
Затем внедрите этот bean-компонент в контроллер:
@Controller
@Path("user")
public class UserController {
@Inject
private User user;
@POST
public String post() {
user.setName("John Doe");
return "redirect:/submit";
}
@GET
public String get() {
return "success.jsp";
}
}
Здесь пользователь
bean-компонента доступен для POST и последующего перенаправления и GET. Следовательно, success.jsp
может получить доступ к атрибуту имени компонента с помощью
EL.
3.5. jakarta.mvc.UriRef
Мы можем использовать аннотацию @UriRef
только для метода ресурса. @UriRef
позволяет нам указать имя методам ресурса. Вместо URI пути к контроллеру мы можем использовать эти имена для вызова наших контроллеров в представлениях.
Предположим, что есть пользовательская форма с href
:
<a href="/app/user">Clich Here</a>
Нажатие Click Here
вызывает контроллер, сопоставленный с GET /app/user
.
@GET
@UriRef("user-details")
public String getUserDetails(String userId) {
userService.getUserDetails(userId);
}
Здесь мы назвали наш контроллер user-details
. Теперь мы можем ссылаться на это имя в наших представлениях вместо URI:
<a href="${mvc.uri('user-details')}">Click Here</a>
3.6. jakarta.mvc.security.CsrfProtected
Эта аннотация предписывает, что проверка CSRF необходима для вызова метода ресурса. Если токен CSRF недействителен, клиент получает исключение ForbiddenException
(HTTP 403). Только метод ресурса может иметь эту аннотацию.
Рассмотрим контроллер:
@POST
@Path("user")
@CsrfProtected
public String saveUser(User user) {
service.saveUser(user);
}
Учитывая, что контроллер имеет аннотацию @CsrfProtected
, запрос достигает контроллера только в том случае, если он содержит допустимый токен CSRF.
4. Создание приложения MVC
Далее давайте создадим веб-приложение с REST API и контроллером. Наконец, давайте развернем наше веб-приложение в последней версии Eclipse Glassfish .
4.1. Создать проект
Во-первых, давайте воспользуемся архетипом Maven:generate
для создания проекта Jakarta MVC 2.0:
mvn archetype:generate
-DarchetypeGroupId=org.eclipse.krazo
-DarchetypeArtifactId=krazo-jakartaee9-archetype
-DarchetypeVersion=2.0.0 -DgroupId=com.foreach
-DartifactId=krazo -DkrazoImpl=jersey
Приведенный выше архетип создает проект maven с необходимыми артефактами, похожими на:
Также сгенерированный pom.xml
содержит зависимости jakarta.platform , jakarta.mvc
и org.eclipse.krazo
:
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>9.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.mvc</groupId>
<artifactId>jakarta.mvc-api</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.krazo</groupId>
<artifactId>krazo-jersey</artifactId>
<version>2.0.0</version>
</dependency>
4.2. Контроллеры
Далее давайте определим контроллеры для отображения формы, сохранения сведений о пользователе и API для получения сведений о пользователе. Но сначала давайте определим наш путь к приложению:
@ApplicationPath("/app")
public class UserApplication extends Application {
}
Путь к приложению определяется как /app
. Далее давайте определим наши контроллеры, которые перенаправляют пользователя в форму сведений о пользователе:
@Path("users")
public class UserController {
@GET
@Controller
public String showForm() {
return "user.jsp";
}
}
Затем в разделе WEB-INF/views
мы можем создать представление user.jsp,
а также собрать и развернуть приложение:
mvn clean install glassfish:deploy
Этот подключаемый модуль Glassfish Maven собирается, развертывается и работает на порту 8080. После успешного развертывания мы можем открыть браузер и перейти по URL-адресу:
http://локальный:8080/mvc-2.0/приложение/пользователи
: ``
Далее давайте определим HTTP POST, который обрабатывает действие отправки формы:
@POST
@Controller
public String saveUser(@Valid @BeanParam User user) {
return "redirect:users/success";
}
Теперь, когда пользователь нажимает кнопку « Создать
», контроллер обрабатывает запрос POST и перенаправляет пользователя на страницу успеха:
Давайте воспользуемся Jakarta Validations, CDI и @MvcBinding
для проверки формы:
@Named("user")
public class User implements Serializable {
@MvcBinding
@Null
private String id;
@MvcBinding
@NotNull
@Size(min = 1, message = "Name cannot be blank")
@FormParam("name")
private String name;
// other validations with getters and setters
}
После проверки формы давайте проверим наличие ошибок привязки. Если есть какие-либо ошибки привязки, мы должны предоставить пользователю сообщения проверки. Для этого давайте внедрим BindingResult
для обработки недопустимых параметров формы. Обновим наш метод saveUser
:
@Inject
private BindingResult bindingResult;
public String saveUser(@Valid @BeanParam User user) {
if (bindingResult.isFailed()) {
models.put("errors", bindingResult.getAllErrors());
return "user.jsp";
}
return "redirect:users/success";
}
При наличии проверок, если пользователь отправляет форму без обязательных параметров, мы отображаем ошибки проверки:
Далее давайте защитим наш метод POST от CSRF-атак с помощью @CsrfProtected
. Добавьте @CsrfProtected
в метод saveUser
:
@POST
@Controller
@CsrfProtected
public String saveUser(@Valid @BeanParam User user) {
}
Далее попробуем нажать кнопку « Создать
» :
Когда контроллер защищен от CSRF-атак, клиент всегда должен передавать токен CSRF. Итак, давайте добавим скрытое поле в user.jsp
, которое добавляет токен CSRF при каждом запросе:
<input type="hidden" name="${mvc.csrf.name}" value="${mvc.csrf.token}"/>
Точно так же давайте сейчас разработаем REST API :
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<User> getUsers() {
return users;
}
Этот HTTP GET API возвращает список пользователей.
5. Вывод
В этой статье мы узнали о Jakarta MVC 2.0 и о том, как разрабатывать веб-приложение и REST API с помощью Eclipse Krazo. Мы видели, как MVC 2.0 стандартизирует способ создания веб-приложений на основе MVC на Java.
Как всегда, полный исходный код доступен на GitHub .