Существует ли универсальный RequestContext в API сервлетов Java?

(Я не уверен, как именно сформулировать заголовок здесь, и поэтому я не совсем уверен, как искать ответ.)

У меня есть движок сервлетов Java, который обрабатывает запросы. Скажем, у нас есть запрос doGet():

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //set up user data

    //do whatever the user requested
    SomeClass c = new SomeClass();
    c.doSomething();
}

Теперь в doSomething() я хочу получить доступ к тому, какой пользователь сделал запрос. Сейчас я делаю это, создавая Java-объект внутри метода и передавая его туда, где он мне нужен:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //set up user data
    MyUserObj userObj = new MyUserObj();
    userObj.setId('123');

    //do whatever the user requested
    SomeClass c = new SomeClass(userObj);
    c.doSomething();
}

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

Я знаю, что в ASP.NET MVC3 я могу добиться этого, сохраняя элементы/атрибуты для текущего потока, например: HttpContext.Current.Items.Add("myId", "123"). HttpContext затем становится доступным в других функциях без явного обхода объекта.

Есть ли способ в Java, чтобы установить некоторые переменные для запроса (или даже установить MyUserObject для доступа позже), не передавая объект в качестве параметра?

Ответ 1

В API сервлетов нет, но вы можете сделать свой собственный довольно легко. (Некоторые фреймворки, такие как spring -mvc, распорки обеспечивают такую ​​функциональность)

Просто используйте public static ThreadLocal для хранения и извлечения объекта. Вы даже можете сохранить HttpServletRequest себя в threadlocal и использовать его методы setAttribute()/getAttribute(), или вы можете сохранить threadlocal Map, чтобы быть агностиком API сервлета. Важно отметить, что вы должны очистить threadlocal после запроса (например, с помощью фильтра).

Также обратите внимание, что передача объекта как параметра считается лучшей практикой, потому что вы обычно передаете его с веб-уровня на сервисный уровень, который не должен зависеть от веб-объекта, например, HttpContext.

Если вы решите сохранить их в локальном потоке, а не передавать их:

public class RequestContext {
    private static ThreadLocal<Map<Object, Object>> attributes = new ThreadLocal<>();
    public static void initialize() {
        attributes.set(new HashMap<Map<Object, Object>>());
    }
    public static void cleanup() {
        attributes.set(null);
    }
    public static <T> T getAttribute(Object key) {
        return (T) attributes.get().get(key);
    }
    public static void setAttribute(Object key, Object value) {
        attributes.get().put(key, value);
    }
}

И необходимый фильтр:

@WebFilter(urlPatterns="/")
public class RequestContextFilter implements Filter {
     public void doFilter(..) {
         RequestContext.initialize();
         try {
             chain.doFilter(request, response);
         } finally {
             RequestContext.cleanup();
         }
     }
}

Ответ 2

Вы можете прикрепить объект к текущему запросу с помощью setAttribute. Этот API-интерфейс в основном используется для внутренней маршрутизации, но его можно безопасно использовать и в ваших собственных целях, если вы используете правильное пространство имен для имен ваших атрибутов.