Существует три основные причины.
FacesServlet
не вызывается. FacesServlet
mapping . URL-адрес ссылки (URL-адрес, который вы видите в адресной строке браузера) должен соответствовать
файла FacesServlet
, как определено в web.xml
чтобы все работы JSF выполнялись. FacesServlet
- это тот, который отвечает за разбор файла XHTML, сбор представленных значений формы, выполнение преобразования / проверки, обновление моделей, вызывание действий и создание выходных данных HTML. Если вы не вызываете FacesServlet
по URL-адресу, то все, что вы получили (и увидите через rightclick, View Source в браузере), действительно является исходным исходным кодом XHTML.
Если
, например, *.jsf
, ссылка должна указывать на /register.jsf
, а не на /register.xhtml
. Если это, например, /faces/*
, как и у вас, ссылка должна указывать на /faces/register.xhtml
, а не на /register.xhtml
. Один из способов избежать этой путаницы - просто изменить
с /faces/*
на *.xhtml
. Таким образом, нижестоящее является идеальным отображением:
facesServlet
javax.faces.webapp.FacesServlet
facesServlet
*.xhtml
Если вы по какой-то причине не можете поменять
на *.xhtml
, то вы, вероятно, также хотели бы, чтобы конечные пользователи не могли напрямую обращаться к источнику XHTML кодировать файлы по URL-адресу. В этом случае вы можете добавить
в
в *.xhtml
с пустым
в web.xml
, который предотвращает это:
Restrict direct access to XHTML files
XHTML files
*.xhtml
Предстоящий JSF 2.3 решит все из вышеперечисленного, автоматически регистрируя FacesServlet
в шаблоне URL-адреса *.xhtml
во время запуска webapp.
. С введением JSF 2.2 еще одна вероятная причина заключается в том, что пространства имен XML не соответствуют версии JSF. xmlns.jcp.org
, как показано ниже, является новым с JSF 2.2 и не работает в старых версиях JSF. Символы почти такие же, как если бы FacesServlet
не вызывался.
Если вы не можете перейти на JSF 2.2, вам нужно вместо этого использовать старые пространства имен java.sun.com
XML:
. Еще одна вероятная причина заключается в том, что несколько реализаций JSF были загружены вашим webapp, конфликтуя и разлагая друг друга. Например, когда ваш путь к классу среды выполнения Webapp загрязнен несколькими различными версиями JSF-библиотек или в конкретной комбинации Mojarra 2.x + Tomcat 8.x, когда в файле web.xml
веб-приложения есть ненужная запись ConfigureListener
, вызывающая ее загрузку дважды.
com.sun.faces.config.ConfigureListener
При использовании Maven убедитесь, что вы правильно определяете зависимости и понимаете области зависимостей. Важно: не связывайте зависимости в webapp, если они уже предоставлены целевым сервером.
JSF имеет очень крутую кривую обучения для тех, кто не знаком с базовыми HTTP , HTML и сервлетами . В Интернете много ресурсов низкого качества. Пожалуйста, игнорируйте фрагменты скриншотов кода, поддерживаемые любителями, в основном ориентированные на доход от рекламы, а не на обучение, такие как розы, учебник, javabeat и т. Д. Они легко узнаваемы, нарушая рекламные ссылки / баннеры. Также, пожалуйста, игнорируйте ресурсы, связанные с юрским JSF 1.x. Они легко узнаваемы с помощью JSP-файлов вместо файлов XHTML. JSP как технология просмотра устарела с тех пор, как JSF 2.0 уже в 2009 году.
Чтобы начать правильно, начните с нашей вики-страницы JSF и закажите авторитетную книгу .
Ответ Claudiu корректен, но можно также обмануть путем получения имени класса от self
аргумент. Это даст вводящие в заблуждение операторы журнала в случаях наследования, но скажет Вам класс объекта, метод которого называют. Например:
from functools import wraps # use this to preserve function signatures and docstrings
def logger(func):
@wraps(func)
def with_logging(*args, **kwargs):
print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
return func(*args, **kwargs)
return with_logging
class C(object):
@logger
def f(self):
pass
C().f()
, Поскольку я сказал, это не будет работать правильно в случаях, где Вы наследовали функцию от родительского класса; в этом случае Вы могли бы сказать
class B(C):
pass
b = B()
b.f()
и получить сообщение Entering B.f
, где Вы на самом деле хотите получить сообщение Entering C.f
, так как это - корректный класс. С другой стороны, это могло бы быть приемлемо, в этом случае я рекомендую этот подход по предложению Claudiu.
Функции только становятся методами во времени выполнения. Таким образом, когда Вы добираетесь C.f
, Вы получаете связанную функцию (и C.f.im_class is C
). В то время, когда Ваша функция определяется, это - просто простая функция, это не связывается ни с каким классом. Эта несвязанная и разъединенная функция - то, что украшено регистратором.
self.__class__.__name__
даст Вам название класса, но можно также использовать дескрипторы для выполнения этого несколько более общим способом. Этот шаблон описан в сообщении в блоге на Декораторах и Дескрипторах , и реализация Вашего декоратора регистратора в особенности была бы похожа:
class logger(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
return self.__class__(self.func.__get__(obj, type))
def __call__(self, *args, **kw):
print 'Entering %s' % self.func
return self.func(*args, **kw)
class C(object):
@logger
def f(self, x, y):
return x+y
C().f(1, 2)
# => Entering <bound method C.f of <__main__.C object at 0x...>>
, Очевидно, вывод может быть улучшен (при помощи, например, getattr(self.func, 'im_class', None)
), но этот общий шаблон будет работать и на методы и на функции. Однако это будет не работа для классов старого стиля (но просто не используйте тех;)
Кажется, что, в то время как класс создается, Python создает объекты регулярной функции. В них только превращаются несвязанные объекты метода впоследствии. Зная это, это - единственный способ, которым я мог найти, чтобы сделать то, что Вы хотите:
def logger(myFunc):
def new(*args, **keyargs):
print 'Entering %s.%s' % (myFunc.im_class.__name__, myFunc.__name__)
return myFunc(*args, **keyargs)
return new
class C(object):
def f(self):
pass
C.f = logger(C.f)
C().f()
Это производит желаемый результат.
, Если Вы хотите обернуть все методы в класс, тогда Вы, вероятно, хотите создать функцию wrapClass, которую Вы могли тогда использовать как это:
C = wrapClass(C)
Функции класса должны всегда брать сам в качестве своего первого аргумента, таким образом, можно использовать это вместо меня am_class.
def logger(myFunc):
def new(self, *args, **keyargs):
print 'Entering %s.%s' % (self.__class__.__name__, myFunc.__name__)
return myFunc(self, *args, **keyargs)
return new
class C(object):
@logger
def f(self):
pass
C().f()
сначала я хотел использовать self.__name__
, но это не работает, потому что экземпляр не имеет никакого имени. необходимо использовать self.__class__.__name__
для получения названия класса.
Можно также использовать new.instancemethod()
для создания метода экземпляра (или связанный или развязанный) от функции.
Я нашел другое решение очень похожей проблемы, используя библиотеку inspect
. Когда вызывается декоратор, даже если функция еще не привязана к классу, вы можете просмотреть стек и определить, какой класс вызывает декоратор. Вы можете, по крайней мере, получить строковое имя класса, если это все, что вам нужно (вероятно, вы еще не можете ссылаться на него, поскольку он находится в процессе создания). Тогда вам не нужно будет ничего вызывать после того, как класс будет создан.
import inspect
def logger(myFunc):
classname = inspect.getouterframes(inspect.currentframe())[1][3]
def new(*args, **keyargs):
print 'Entering %s.%s' % (classname, myFunc.__name__)
return myFunc(*args, **keyargs)
return new
class C(object):
@logger
def f(self):
pass
C().f()
Хотя этот способ не обязательно лучше, чем другие, это единственный способ, который я могу найти, чтобы узнать имя класса будущего метода во время вызова декоратора. Обратите внимание на то, что в документации по библиотеке inspect
нельзя оставлять ссылки на фреймы.
Идеи, предложенные здесь, превосходны, но имеют некоторые недостатки:
inspect.getouterframes
и args [0] .__ class __.__ name __
не подходят для простого функции и статические методы. __ get __
должен быть в классе, который отклонен @wraps
. @wraps
должен лучше скрывать следы. Итак, я объединил некоторые идеи с этой страницы, ссылки, документы и свою собственную голову,
и наконец нашли решение, в котором отсутствуют все три вышеупомянутых недостатка.
В результате method_decorator
:
functools.wraps ()
. Использование:
pip install method_decorator
from method_decorator import method_decorator
class my_decorator(method_decorator):
# ...
Подробнее об использовании см. полные юнит-тесты .
А вот только код класса method_decorator
:
class method_decorator(object):
def __init__(self, func, obj=None, cls=None, method_type='function'):
# These defaults are OK for plain functions
# and will be changed by __get__() for methods once a method is dot-referenced.
self.func, self.obj, self.cls, self.method_type = func, obj, cls, method_type
def __get__(self, obj=None, cls=None):
# It is executed when decorated func is referenced as a method: cls.func or obj.func.
if self.obj == obj and self.cls == cls:
return self # Use the same instance that is already processed by previous call to this __get__().
method_type = (
'staticmethod' if isinstance(self.func, staticmethod) else
'classmethod' if isinstance(self.func, classmethod) else
'instancemethod'
# No branch for plain function - correct method_type for it is already set in __init__() defaults.
)
return object.__getattribute__(self, '__class__')( # Use specialized method_decorator (or descendant) instance, don't change current instance attributes - it leads to conflicts.
self.func.__get__(obj, cls), obj, cls, method_type) # Use bound or unbound method with this underlying func.
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def __getattribute__(self, attr_name): # Hiding traces of decoration.
if attr_name in ('__init__', '__get__', '__call__', '__getattribute__', 'func', 'obj', 'cls', 'method_type'): # Our known names. '__class__' is not included because is used only with explicit object.__getattribute__().
return object.__getattribute__(self, attr_name) # Stopping recursion.
# All other attr_names, including auto-defined by system in self, are searched in decorated self.func, e.g.: __module__, __class__, __name__, __doc__, im_*, func_*, etc.
return getattr(self.func, attr_name) # Raises correct AttributeError if name is not found in decorated self.func.
def __repr__(self): # Special case: __repr__ ignores __getattribute__.
return self.func.__repr__()