Что вам не хватает, так это то, что hash.update()
не заменяет хешированные данные. Вы постоянно обновляете хэш-объект, так что вы получаете хэш из конкатенированных строк . Из документации hashlib.hash.update()
:
Обновите хэш-объект со строкой arg . Повторные вызовы эквивалентны одному вызову с конкатенацией всех аргументов:
blockquote>m.update(a)
;m.update(b)
эквивалентенm.update(a+b)
.Смелый акцент мой.
Итак, вы не получаете хеш одной строки
'stackoverflow'
, вы получаете хэш сначала из'stackoverflow'
, затем из'stackoverflowstackoverflow'
, затем'stackoverflowstackoverflowstackoverflow'
и т. д., каждый раз, когда добавляет другой'stackoverflow'
, создавая более длинную и длинную строку. Ни одна из этих более длинных строк не равна исходной короткой строке, поэтому их хэши вряд ли будут одинаковыми.Создайте новый объект new для новых строк:
>>> import hashlib >>> m = hashlib.md5() >>> m.update('stack' + 'overflow') >>> m.hexdigest() '73868cb1848a216984dca1b6b0ee37bc' >>> m = hashlib.md5() # **new** hash object >>> m.update('stackoverflow') >>> m.hexdigest() '73868cb1848a216984dca1b6b0ee37bc' >>> m = hashlib.md5() # new object again >>> m.update('stack') # add the string in pieces, part 1 >>> m.update('overflow') # and part 2 >>> m.hexdigest() '73868cb1848a216984dca1b6b0ee37bc'
Вы можете легко создать свои «неправильные» хэши, отправив в конкатенированные данные:
>>> m = hashlib.md5() >>> m.update('stackoverflowstackoverflow') >>> m.hexdigest() '458b7358b9e0c3f561957b96e543c5a8' >>> m = hashlib.md5() >>> m.update('stackoverflowstackoverflowstackoverflow') >>> m.hexdigest() '65b0e62d4ff2d91e111ecc8f27f0e8f5' >>> m = hashlib.md5() >>> m.update('stackoverflow' * 4) >>> m.hexdigest() '60c3ae3dd9a2095340b2e024194bad3c'
Обратите внимание, что вы также можете передать первую строку в функцию
md5()
:>>> hashlib.md5('stackoverflow').hexdigest() '73868cb1848a216984dca1b6b0ee37bc'
Обычно вы используете метод
hash.update()
, только если вы обрабатываете данные в кусках (например, чтение строки по строке или чтение блоков данных из сокета) и не хотите, чтобы для одновременного хранения всех этих данных в памяти.
Как указано BalusC, actionListener
по умолчанию использует исключение, но в JSF 2.0 есть немного больше. А именно, он не просто проглатывает и записывает журналы, а фактически публикует исключение.
Это происходит с помощью такого вызова:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
Слушателем по умолчанию для этого события является ExceptionHandler
, который для Моджары установлен на com.sun.faces.context.ExceptionHandlerImpl
. Эта реализация в основном отменяет любое исключение, за исключением случаев, когда это относится к исключению AbortProcessingException, которое регистрируется. ActionListeners обертывают исключение, которое генерируется клиентским кодом в таком AbortProcessingException, которое объясняет, почему они всегда регистрируются.
Этот ExceptionHandler
может быть заменен, однако, в faces-config.xml с пользовательской реализацией:
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
Вместо того, чтобы слушать глобально, один компонент может также слушать эти события. Ниже приведено доказательство этой концепции:
@ManagedBean
@RequestScoped
public class MyBean {
public void actionMethod(ActionEvent event) {
FacesContext.getCurrentInstance().getApplication().subscribeToEvent(ExceptionQueuedEvent.class, new SystemEventListener() {
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
ExceptionQueuedEventContext content = (ExceptionQueuedEventContext)event.getSource();
throw new RuntimeException(content.getException());
}
@Override
public boolean isListenerForSource(Object source) {
return true;
}
});
throw new RuntimeException("test");
}
}
(обратите внимание: это не то, как обычно нужно кодировать слушателей, это только для демонстрационных целей!) [/ G0]
Вызов этого из Facelet следующим образом:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h:form>
<h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
</h:form>
</h:body>
</html>
Будет отображаться страница с ошибкой.
Сначала запускается ActionListener с возможностью изменения ответа, прежде чем действие вызывается и определяет местоположение следующей страницы.
Если у вас несколько кнопок на одной странице, которые должны перейти в в том же месте, но делайте несколько разные вещи, вы можете использовать одно и то же действие для каждой кнопки, но использовать другой ActionListener для обработки немного разных функций.
Вот ссылка, которая описывает взаимосвязь: