GrabDuck

Java EE 6. Спецификация Servlet 3.0: что нового

:

С выходом Java EE 6 на ряду со значительными изменениями в JPA 2.0 спецификации сервлетов 3.0 также притерпела ряд улучшений: упростилась разработка и процедура развертывания, конфигурирование стало более удобным, появилась поддержка асинхронных запросов и улучшилась модель безопасности. Далее я попытаюсь осветить основные изменения в API.

Программирование и развертывание сервлетов упростилось главным образом за счет введения аннотаций для декларирования сервлет ( @WebServlet), фильтров ( @WebFilter), листнеров ( @WebListener) и ограничений безопасности ( @ServletSecurity). Таким образом, и дескриптор развертывания web.xml стал опциональным элементом. Обращаю внимание, что сами компоненты Servlet API не стали POJO, привычную иерархию интерфейсов и классов никто не отменял. Также добавилась аннотация для поддержки загрузки файлов @MultipartConfig и для установки параметров инициализации @WebInitParam.


Пример Hello World сервлета


package net.ismailov.tests;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name="hw", urlPatterns = "/hello_world")
public class HelloWorld extends HttpServlet{

  public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    PrintWriter writer = response.getWriter();
writer.println("<h1>Hello, World!</h1>");
}

}


Хорошей новостью стало появление возможности динамической регистрации сервлетов:
ServletRegistration.Dynamic dynamic =
servletContext.addServlet(“DynamicTestServlet”, “net.ismailov.DynamicTestServlet”)
dynamic.addMapping(“/dynamicServlet”);

Для поддержки длительных операций добавилась возможность асинхронной работы сервлета. Для включения данной возможности необходимо:

//Либо декларативно указать поддержку асинхронного режима
@WebServlet(asyncSupported=true)
//Либо установить при динамической инициализации сервлета
dynamic.setAsyncSupported(true);

* This source code was highlighted with Source Code Highlighter.


После этого responce не перестает существовать по завершении метода. Необходимо вызвать
AsyncContext ctx = ServletRequest.startAsync(req, res)

* This source code was highlighted with Source Code Highlighter.


Теперь экземляры request и responce будут сохранены, и, по завершении выполнения асинхронного метода, могут быть использованы для вывода пользователю одним из методов AsyncContext.dispatch(/*различные параметры*/)
  @WebServlet("/MyAsyncTestServlet" asyncSupported=true)
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) {
...
AsyncContext aCtx = request.startAsync(req, res);
ScheduledThreadPoolExecutor executor = new ThreadPoolExecutor(10);
executor.execute(new MyAsyncService(aCtx));
}
}

  public class MyAsyncService implements Runnable {
private AsyncContext ctx;
public MyAsyncService(AsyncContext ctx) {
this.ctx = ctx;
}
public void run() {
// Может быть вызвана долгая операция с последующим выводом
ctx.dispatch("/result.jsp");
}

Как уже упоминалось, с новым API стало возможно задавать ограничения доступа, например:

@WebServlet(name="hw", urlPatterns = "/hello_world")
@ServletSecurity(@HttpConstraint(rolesAllowed = {"admin"}))
public class HelloWorld extends HttpServlet{


Естественно, задача задания ролей/пользователей, равно как и аутентификация, являются vendor-specific. К примеру, glassfish выдает basic http auth формочку:

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

@ServletSecurity(httpMethodConstraints={ @HttpMethodConstraint("GET"),
@HttpMethodConstraint(value="POST", rolesAllowed={"user_group_1"})})

Основные нововведения в api 3.0 я постарался отразить, осталось лишь отметить, что с декабря прошлого года доступна "эталонная реализация" спецификации Java EE6: Glassfish 3.0, в которой можно поэкспериментировать с новым API.