Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Двойное нажатие кнопки Submit


Автор: Zamuta 28.11.2006, 17:45
Всем привет.

Моё приложение регистрирует пользователей, заносит полученные данные в таблицу, а затем работает с этими данными из таблицы.

Приходилось ли кому-нибудь сталкиваться с проблемой двойного нажатия кнопки отправки данных? Ведь если нажать кнопку дважды, то получатся две одинаковые записи в таблице. Есть ли готовые решения в NetBeans или Eclips'e или где-нибудь ещё? 


На сколько критично стоит относиться к этому вопросу?

Автор: powerOn 28.11.2006, 17:52
Цитата(Zamuta @  28.11.2006,  17:45 Найти цитируемый пост)
Ведь если нажать кнопку дважды, то получатся две одинаковые записи в таблице. 

Двух одинаковых записей быть не должно. Нужно перед каждой записью проверку делать. Если запись есть - то вторую не добавлять.

Автор: Zamuta 28.11.2006, 18:18
А если получится так, что у юзера медленный инет.  Он нажимает кнопку отправки данных, код проверяет есть ли такие же записи в бд, видит что нет и сохраняет данные, на всё это уходит некоторое время, а юзер после первого нажатия тут же нажал второй раз, ну нервный юзер, например, началась проверка на такие же записи в бд, логин, например, а первые данные ещё не сохранились и получается, что такого логина ещё нет и приложение ставит эти данные в очередь на запись в бд. Т.е. проверка прошла успешно, а данные записались дважды. Что тогда?

У меня на локалхосте так и получается, но это без проверки совпадения на уже существующие данные....

Это мои соображения, сомневаюсь, поэтому спрашиваю......

Автор: Sherst 28.11.2006, 18:29
Что мешает сделать поле уникальным и ловить exception?

Автор: chief39 28.11.2006, 18:33
База данных должна поддерживать транзакционность и некторорые уровни изоляции на которые следует обратить внимание ;)
Поэтому если ты в одной транзакции будешь проверять есть ли запись и вставлять - вторая вставка просто не пройдёт. 

Цитата(Zamuta @  28.11.2006,  18:18 Найти цитируемый пост)
У меня на локалхосте так и получается, но это без проверки совпадения на уже существующие данные....

Логично smile

А если хотя бы поставить уникальный индекс на необходимую совокупность полей -СУБД сама не допустит такого, но будет ругаться некрасиво - лучше самому сделать проверку.

А выносить контроль целостности данных на клиентскую часть - не очень хорошо... :-/
Можно дополнить и продублировать, но это уже так.. фича, необходимая в определённых случаях

Автор: Sherst 28.11.2006, 18:33
Можно еще как-то попробовать сообщать юзеру что идет процесс записи данных...
Например сделать кнопку Добавить невидимой после окончания записи - показать.

Автор: chief39 28.11.2006, 18:47
Цитата(Sherst @  28.11.2006,  18:33 Найти цитируемый пост)
Можно еще как-то попробовать сообщать юзеру что идет процесс записи данных...
Например сделать кнопку Добавить невидимой после окончания записи - показать. 

Но это, опять-таки, лучше делать дополнительной фичей. Если важна целостность данных, а не красота(а как ещё может быть) -  то надёжнее, вернее и правильнее делать это ближе к данным. Поскольку никто не мешает открыть ещё один браузер на другой машине. И уж ему-то точно будет плевать с высокой горы на видимость/невидимость/цвет/форму кнопки соседа

Автор: Sherst 28.11.2006, 18:49
У SQLException юзай метод getErrorCode() 

Добавлено @ 18:50 
chief39 согласен smile

Автор: Zamuta 28.11.2006, 21:34
Спасибо всем за ответы....

Вообще, проверку на совпадение логинов нужно сделать, ведь нужно както-же юзеров различать.... 

А для предотвращения двойного нажатия кнопки мне больше понравилась идея Sherst 

Цитата
Например сделать кнопку Добавить невидимой после окончания записи - показать. 


Как такое можно сделать? У меня в NetBeans я вижу такие параметры для кнопки как disabled  и immediate. Это не то случайно что нужно? 

Как Вы считаете?

Автор: Sherst 29.11.2006, 01:34
Zamuta для начала скажите какой web-фрейморк используете: JSF, struts и т.д.
А дальше будем думать что можно сделать ...

Автор: chief39 29.11.2006, 11:45
Цитата(Zamuta @  28.11.2006,  21:34 Найти цитируемый пост)
Вообще, проверку на совпадение логинов нужно сделать, ведь нужно както-же юзеров различать.... 

Не понял... проверку уникальности логинов при создании? Или что?

Цитата(Zamuta @  28.11.2006,  21:34 Найти цитируемый пост)
А для предотвращения двойного нажатия кнопки мне больше понравилась идея Sherst 

Тебе нужна функциональность или опыт работы с кнопками?

Цитата(Zamuta @  28.11.2006,  21:34 Найти цитируемый пост)
Как такое можно сделать? У меня в NetBeans я вижу такие параметры для кнопки как disabled  и immediate. Это не то случайно что нужно? 

Насколько помню, в джаваскрипте можно устанавливать кнопке свойство 
Цитата(Zamuta @  28.11.2006,  21:34 Найти цитируемый пост)
disabled
 в true - кнопка задизаблится.



Цитата(Zamuta @  28.11.2006,  21:34 Найти цитируемый пост)
Как Вы считаете? 

У меня вознил один вопрос(для начала) - это курсовая для преподавателя(самостоятельные разборки с технологиями) или коммерческое/промышленное приложение?
Если второе - тогда порекомендую пересмотреть подход BTD(button driven development) и начать с продумывания архитектуры. Принцип "нарисовать кнопку, а потом придумать что она будет вызывать" может натворить много бед

Автор: Zamuta 29.11.2006, 14:03
Sherst, 

Цитата
Zamuta для начала скажите какой web-фрейморк используете: JSF, struts и т.д.
А дальше будем думать что можно сделать ... 

Использую JSF.

chief39, 
Цитата
Не понял... проверку уникальности логинов при создании? Или что?

Да. Т.е.  перед каждой записью делать проверку. Если запись есть - то вторую не добавлять. 
Цитата
Тебе нужна функциональность или опыт работы с кнопками?

Мне нужна функциональность. Но существуют такие решения, как шаблоны проектирования, т.е. готовые решения, скажем валидаторы или конвертеры, если не ошибаюсь. Так вот, чтобы не изобретать велосипед, возможно уже есть методы решения этой проблемы, т.к. до меня, думаю, люди с этим сталкивались.  

Цитата
У меня вознил один вопрос(для начала) - это курсовая для преподавателя(самостоятельные разборки с технологиями) или коммерческое/промышленное приложение?
Если второе - тогда порекомендую пересмотреть подход BTD(button driven development) и начать с продумывания архитектуры. Принцип "нарисовать кнопку, а потом придумать что она будет вызывать" может натворить много бед


Это коммерческое/промышленное приложение. 

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

Примерно понял, делаем поле для сохранения логина в бд уникальным и используем getErrorCode() у SQLException, таким образом решаем сразу две проблемы, т.е. сохраняем все логины уникальными, и предотвращаем многократное нажатие кнопки..... 

Всем спасибо за ответы....

Автор: Sherst 29.11.2006, 14:50
Цитата(Zamuta @  29.11.2006,  14:03 Найти цитируемый пост)
Да. Т.е.  перед каждой записью делать проверку. Если запись есть - то вторую не добавлять. 


БД сама все проверит лишь бы уникальное поле было smile

Для jsf компонент можно использовать свойства rendered - видно/скрыто, disabled - доступно / недоступно
Но в коммерческом приложении это будет лишним, а Exception можно всегда обработать.
Я обычно делаю страничку Error и при возникновении exception направляю юзера на эту страничку на которой вывожу также текст ошибки .

Автор: alexsmirnov 29.11.2006, 15:10
Ловля Exception и проверка уникальности в базе не поможет - после первого нажатия пользователь занес свои данные. По второму возникла ошибка - и в результате юзер видит что зарегистрироваться он не смог, хотя все в порядке.
Лучше либо действительно сразу на странице запрещать кнопку через JavaScript, либо ставить в форму скрытое поле с уникальным id и проверять повтор.

Автор: Zamuta 29.11.2006, 15:44
Кажется нашёл. smile 

Какой способ предпочли бы Вы?

1) http://www.javable.com/javaworld/tips/136_tt/
2) http://www.netmechanic.com/news/vol5/html_no16.htm

Автор: y3u 30.11.2006, 00:45
стандартный, принятый повсеместно способ, после нажатия на submit кнопка просто тупо дизейблится прямо сразу, и все... после того как форма отправится на сервак, страничка все равно перезагрузится, т.е. кнопка без доролнительных телодвижений будет раздизейблена... 

Автор: chief39 30.11.2006, 15:49
Предисловие:
Цитата(Zamuta @  29.11.2006,  14:03 Найти цитируемый пост)
готовые решения, скажем валидаторы или конвертеры
 - они сделают только косметические дейсвия без завязки на огромный запас данных, которые в БД. А мы говорим как раз о данных...



Цитата(Zamuta @  29.11.2006,  14:03 Найти цитируемый пост)
Это коммерческое/промышленное приложение. 

Цитата(Zamuta @  29.11.2006,  14:03 Найти цитируемый пост)

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


Фффух... ну тогда я просто не понимаю упорного тяготения к красоте скрытия кнопочки.....

Задизабленная кнопка решает только двойной клик на машине, клик на соседней машине она не решит в принципе.


Цитата(y3u @  30.11.2006,  00:45 Найти цитируемый пост)
стандартный, принятый повсеместно способ, после нажатия на submit кнопка просто тупо дизейблится прямо сразу, и все... после того как форма отправится на сервак, страничка все равно перезагрузится, т.е. кнопка без доролнительных телодвижений будет раздизейблена... 

Это весьма полезно и стоит это применить(способ действительно полезный и проверенный). Но это скорее доп. защита от шаловливых ручек ("НУ НЕ ТЫКАЙ ТЫ ТУДА! - ВИДИШЬ? - ГРУЗИТСЯ!!! СИДИ ЖДИ!!"). Напишу ещё.


Но если это промышленное приложение и у него есть критичные условия(что естественно) - тогда стоит поглядеть на него не со стороны браузера, а со стороны функциональности и логики работы.

Гораздо важнее чтобы Пользователь не обнаружил Своего двойника в один прекрасный момент чем красота и чуть ли анимация при создании себя любимого в базе.

Машины тоже отличаются цветом и фомой шильдиков. Но сначала проектируется ходовая, движок, трансмиссия, несущие и аэтодинамические характеристики кузова, и только потом уже приделываются ручки, зеркальца.

Ярко выделяются два направления(не учитывая остальных):
Те, кто пересел с ПХП на джаву как инструмент написания вэб-движков. И мыслит категориями динамических страничек. Как правило, первый путь: хэлло-ворд -> сервлет хелловорд. Далее идёт спуск в глубь джавы "ух ты... так тут ещё и не только странички...".
И те, кто пересел с сипипи и близких к нему. Тут человек поглядывает немного искоса на вэб и пишет десятки програмулек, радуется как ребёнок обилию коллекций, полезных библиотечек и пакетиков , а потом с подозрением встречает развесёлую компанию сервлетов и джсп.
Потом различия нивелируются, многие идут совершенно своим путём, но моя подсознательная имха такова.

Кажется, автор принадлежит первой школе. Это не в обиду, везде свои плюсы и минусы. Просто отталкиваясь от этого буду говорить.


Вобщем, поехали:

У нас есть несколько уровней где мы можем противостоять хаосу:
  • Есть наша любимая кнопка на страничке. Дизаблим. Отлично
  • Есть логика на сервере(в сервлете), которая проверит есть ли уже такая запись в БД
  • Есть уникальный констрэйнт в БД и ДиБиЭррор при вставке.
1) Пощупаем базу - констрэйнт нужен? - ДА! Как бы мы не напортачили в коде, наша верная старушка-БД не позволит в бедлама в своём домике. Хоть сто тыщщ ксепшнов посыпется на её голову, она не позволит испортить безвозвратно важные данные банальной перезаписью.
Главное - попросить её приглядеть за данными, создав уникальный констрэйнт
Итак, это - нужно

Но тут сидит ещё один нюанс... чтобы работать, опираясь только на один констрэйнт - надо отлавливать ошибку и обрабатывать её сверху как обсуждалось выше...
Нюансов становится два:
  • Надо опираться на специфические эксепшны БД. Что будет, если сменится версия БД или сама БД?  Вдруг она перестанет бросать ТАКОЕ, или будет что-то невнятное Бросать? Когда мы поймём в чём у нас нестыковка? Сколько пройдёт времени? Доволен ли юзер будет красивым УИ при том, что он битый час пропотеет над созданием себя и просмотром непонятных сообщений о непонятных проблемах в системе?
  •  УПРАВЛЕНИЕ ПРОГРАММОЙ С ПОМОЩЬЮ ЭКСЕПШНОВ - ПЛОХОЙ СТИЛЬ Это не означает что эксепшн - зло. Это как боль в человеческом организме - сообщает что что-то не так, как надо. Там, где происходит что-то непредвиденное(ПРОПАЛ СЕРВЕР БД!!  smile ) - впору орать трёхэтажными эксепшнами. Но кто сказал что что совпадение - это неправильно? 
    Пришёл правильный человек, сел за правильную систему, ввёл желаемый логин, такой логин уже есть - что тут неправильного?
    Мы не догадывались что это будет нормальная рабочая ситуация? 
    Враки!!! Вё мы прекрасно знали. Мы знали что тысячи КОль и каждый захочет своё имя сделать логином. 
    Если мне прищемили дверью руку - да, я заору. А если дверь просто закрыта - чему болеть? закрыта и закрыта, её право. 

    Не стоит писать код по принципу "сейчас я разгоняюсь, влетаю в коридор, поворачиваю налево и на полном ходу влетаю в двери!! (дальше по Задорнову) А если... вдруг... никаких дверей... там нет.... вот тогда уже(зал понимает в чём дело)... наш человек(зал плачет) с матом и своей головой пробивает новое окно!(зал пацтульями)".
    Зашёл, поглядел есть ли двери(!), открыты ли(!), открыл(!) - зашёл. Зачем головой вперёд лететь в бетонную стенку и орать "мать вашу, двери-то, двери где?!?!" ?

    Исключать этого не стоит, перехватывать можно(лишняя инфа о crash'e никогда не лишняя), но стоит всегда помнить что это нестандартная ситуация.
2) Далее... можно определить метод проверки... оооо.. кажется оно...
Перед тем как ломиться в дверь - давайте проверять - а есть ли дверь? Нет двери - сообщите корректным нормальным сообщением юзеру что "двери нет", "пива нет", "туалет занят", "Маня вышла" etc. Зачем кричать что-то похожее на kernel panic??
Пусть внемлет ситуации и войдёт в другую дверь(выпьет водочки, пойдёт к Тане).

Тут логика не страдает - мы просто переносим наши логичные поступки из реального мира в мир абстракций и цифр.


3) Поднимаясь к самой верхушке айсберга....
Дизаблить кнопочку... вроде бы и не надо уже... но почему же не надо? Надо!

Главное не перепутать тёплое с мягким. Дизабл спасёт от нескольких вещей.
Во-первых, не позволит человеку по глупости/спешке исскуственно создавать глупые ситуации: Три раза кликнул - три раза попросил создать юзера(а нафея тебе столько? - спросит добрая фея). Пресечём такую попытку ещё в зародыше.
Во-вторых, такая вещица полезна при неких сложных сессионных работах. Создали мы временную запись в одной таблице, во второй, в третьей, что-то сложное посчитали на их основе, добавили ещё одну - а вот тут уже два раза клацать не надо!!!
Может человек добавляет платежи, и добавить платёж с суммой 20 он может хоть сто раз. Но клиент заплатил всего 20. Поэтому, пощёлкав по кнопке, он надобавляет 80, 120, 240 на счёт клиенту. Даже не подозревая ни о чём(Я просто разместил объяву!!! - ну, то есть, просто давил на кнопку!!!  smile ). Проверять на уникальность тут нечего... Ведь клиент мог и в самом деле 2 раза по 20 заплатить. Это только юзер знает. Похожую ситуацию разруливали как-то. Без вариантов. Полезно. Под сим подпишусь.


Итого, теперь я бы внимательно подумал...
В том числе и над фразой
Цитата(Zamuta @  28.11.2006,  21:34 Найти цитируемый пост)
Вообще, проверку на совпадение логинов нужно сделать, ведь нужно както-же юзеров различать.... 

(Как-то, вроде-бы, неплохо бы...)

И всё-таки начал бы с тщательного проектирования организации данных,
потом полной структуры базы данных,
потом бизнес-ограничений и процессов,
и уж потом - реализация, тем более, интерфейса.


Вот такая здоровая вышла оффтопина....  smile 

Автор: Zamuta 10.12.2006, 01:34
Привет всем.

Сделал поле для хранения имени пользователя в бд уникальным. Ну и само собой теперь вылетает ошибка при попытке записать такое же значение.  


Код

error 
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry 'hfghfgjfg' for key 2
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)
        at com.mysql.jdbc.Connection.execSQL(Connection.java:3170)
        at com.mysql.jdbc.Connection.execSQL(Connection.java:3099)
        at com.mysql.jdbc.Statement.execute(Statement.java:695)
        at gear.RegBean.saveToDatabase(RegBean.java:143)
        at gear.RegBean.onClick(RegBean.java:92)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at com.sun.faces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:146)
        at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:92)
        at com.sun.rave.web.ui.appbase.faces.ActionListenerImpl.processAction(ActionListenerImpl.java:57)
        at javax.faces.component.UICommand.broadcast(UICommand.java:332)
        at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:287)
        at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:401)
        at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:95)
        at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:245)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:110)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:213)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at com.sun.rave.web.ui.util.UploadFilter.doFilter(UploadFilter.java:195)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:368)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
        at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
        at java.lang.Thread.run(Thread.java:595)



Код

private boolean saveToDatabase() throws SQLException {
        
        try {
            Class.forName(DRIVER_CLASS).newInstance();
            Connection con = DriverManager.getConnection(DB_HOST, DB_USER, DB_PASSWORD);
            Statement statement = con.createStatement();
            statement.execute("INSERT INTO reg (username, email, pass) VALUES ('"+name+"', '"+mail+"', '"+pass+"');");
        } catch(Exception e) {
            System.err.println(" error ");
            e.printStackTrace(System.err);
            return false;
        }         
        name = "";
        mail = "";
        pass = "";        
        return true;
    }   


И теперь, при попытке создания 

Код

catch(SQLException ex) {
        if (ex != null){
                 duplUserError = "Nickname already exist";
                 name = "";
                 result = false;
              } 
        }     


Пишет, что exception java.sql.sqlexception has already been caught, но до этого места я нигде больше не ловлю sqlexception.
Смысл в том, чтобы при появлении значения в SQLException ex выводилась ошибка о существовании уже существующей записи.
И кстати везде обыскал, но у SQLException метода getErrorCode() так и не нашёл, как сказал Sherst



Автор: batigoal 10.12.2006, 11:49
Цитата(Zamuta @  10.12.2006,  02:34 Найти цитируемый пост)
И кстати везде обыскал, но у SQLException метода getErrorCode() так и не нашёл,

Хм. http://java.sun.com/j2se/1.4.2/docs/api/java/sql/SQLException.html#getErrorCode()
Должон быть.

Я немного не понял твой вопрос. Ты в коде делаешь обработку ЛЮБОГО исключения (catch(Exception e)). Поэтому, разумеется, SQLException в твоем коде уже никогда не будет выброшен наружу. Убери try/catch, и тогда в случае ошибки SQLException будет выброшен из saveToDatabase().

Автор: Sherst 11.12.2006, 01:59
Код

private boolean saveToDatabase() {
        
        try {
            Class.forName(DRIVER_CLASS).newInstance();
            Connection con = DriverManager.getConnection(DB_HOST, DB_USER, DB_PASSWORD);
            Statement statement = con.createStatement();
            statement.execute("INSERT INTO reg (username, email, pass) VALUES ('"+name+"', '"+mail+"', '"+pass+"');");
        } catch(SQLException ex) {
            int errorCode = ex.getErrorCode();
            System.out.println(errorCode);
            // Смотришь чему равно errorCode когда добавляются одинаковые записи и дальше 
            //  анализируешь это значение
            //   if  errorCode == ....   System.out.println("Такой пользователь уже существует!");
        }         
           catch (Exception e) {
            }
    }   

Автор: Zamuta 11.12.2006, 22:39
Sherst, 

По определению  public int getErrorCode()  это int тип, поэтому я не могу сравнить его значение с логическим значением и сделать 

Код

catch(SQLException ex) {
            int errorCode = ex.getErrorCode();
            System.out.println(errorCode);
            if(errorCode != null){
                 duplUserError = "Nickname already exist";
                 name = "";
                 result = false;

}
        }         



Но так как errorCode возвращает the vendor's error code, то думаю, что его можно сравнить с нулём вот так

Код

catch(SQLException ex) {
            int errorCode = ex.getErrorCode();
            System.out.println(errorCode);
            if(errorCode != 0){
                 duplUserError = "Nickname already exist";
                 name = "";
                 result = false;

}
        }  



Так всё ловит, но это не есть гуд. Суть такова, что на странице регистрации сообщения об ошибке ввода данных выводятся на этой же странице, но только не сообщение о дублировании имени, т.к. приложение об этом узнает только когда попытается записать данные в бд. Сейчас сообщение "Nickname already exist" выводится на странице о неудачной записи данных, т.е. после попытки записи в бд, а мне нужно чтобы небыло перехода на другую страницу. Как сделать с переходом на другую страницу я само собой уже понял.

Код

public String onClick() {
        if(!validate())
            return "";
        
        boolean result = saveToDatabase();
        if(result)
            return "success";
        else
            return "failure";
    }
    
    private boolean validate() {
        boolean result = true;
        
        Pattern namep = Pattern.compile("^[a-zA-Z0-9]{3,20}");
        Matcher namem = namep.matcher(name);
        if(!namem.matches()) {
            nameError = "Enter your name correct please";
            name = "";
            result = false;
        }
        
        Pattern mailp = Pattern.compile("^[a-zA-Z0-9]+[@][a-z]+[.][a-z]{2,3}");
        Matcher mailm = mailp.matcher(mail);
        if(!mailm.matches()) {
            mailError = "Enter your e-mail correct please";
            mail = "";
            result = false;
        }
        
        Pattern passp = Pattern.compile("^[a-zA-Z0-9]{8,20}");
        Matcher passm = passp.matcher(pass);
        if(!passm.matches()) {
            passError = "Enter your password correct please";
            pass = "";
            result = false;
        }
        
        if (!pass.equals("") && (passconfirm.equals("") ||
                !pass.equals(passconfirm))) {
            passconfirmError = "Enter your password confirm correct please";
            passconfirm = "";
            result = false;
        }
        
        return result;
    }
    
    private boolean saveToDatabase() {
         boolean result = true;
        
        try {
            Class.forName(DRIVER_CLASS).newInstance();
            Connection con = DriverManager.getConnection(DB_HOST, DB_USER, DB_PASSWORD);
            Statement statement = con.createStatement();
            statement.execute("INSERT INTO reg (username, email, pass) VALUES ('"+name+"', '"+mail+"', '"+pass+"');");
        }catch(SQLException ex) {
            int errorCode = ex.getErrorCode();
            System.err.println("SQL error");
            ex.printStackTrace(System.err);            
            if(errorCode != 0){
                duplUserError = "Nickname already exist";
                name = "";
                result = false;
            }
          return result;
        }catch(Exception e) {
            System.err.println(" error ");
            e.printStackTrace(System.err);
              if (e != null){
                  duplUserError = "Nickname already exist";
                  name = "";
                  result = false;
              }
            return result;
        }
        
        name = "";
        mail = "";
        pass = "";
        
        return true;
        
    }
 

Автор: Sherst 12.12.2006, 01:02
Цитата(Zamuta @  11.12.2006,  22:39 Найти цитируемый пост)
Но так как errorCode возвращает the vendor's error code, то думаю, что его можно сравнить с нулём 

Зачем ?
Смоделируй ситуацию когда происходит добавление 2-ух идентичных записей и посмотри чему равно значение errorCode. А дальше используй это значение для определения того что у тебя произошла ошибка связанная с дублированием записи.

Дальше, как я понял, есть общая страница ошибок,  но ты хочешь что бы в случае неправильной регистрации не было перехода на эту страницу, а все выводилось на странице регистрации или я не правильно понял? 

Автор: Zamuta 12.12.2006, 01:30
Цитата

Смоделируй ситуацию когда происходит добавление 2-ух идентичных записей и посмотри чему равно значение errorCode. А дальше используй это значение для определения того что у тебя произошла ошибка связанная с дублированием записи.


Согласен, щас попробую.

Цитата

Дальше, как я понял, есть общая страница ошибок,  но ты хочешь что бы в случае неправильной регистрации не было перехода на эту страницу, а все выводилось на странице регистрации или я не правильно понял? 


Да, ты правильно понял. У меня так и работает проверка корректного ввода данных имени, майла, пароля и проверки повтора ввода пароля (см. выше validate() ). Хотелось бы и на совпадение имён сделать вывод ошибки здесь же. Но логику пока так и не продумал. Т.е нужно подключиться к бд не перезагружая страницу и вывести на ней ошибку. 

Автор: Sherst 12.12.2006, 12:38
Цитата(Zamuta @  12.12.2006,  01:30 Найти цитируемый пост)
Т.е нужно подключиться к бд не перезагружая страницу и вывести на ней ошибку.

Что бы что-то вывести нужно эту страницу перегрузить иначе ничего не получится.

Как бы сделал я 

метод класса по работе с БД:

Код

public void getReg(String name, String mail, String pass)
   throws ClassNotFoundException, SQLException, Exception {
       Class.forName(DRIVER_CLASS).newInstance();
       Connection con = DriverManager.getConnection(DB_HOST, DB_USER, DB_PASSWORD);
       Statement statement = con.createStatement();
       statement.execute("INSERT INTO reg (username, email, pass) VALUES ('"+name+"', '"+mail+"','"+pass+"');");                
}



Далее класс контроллер (UserHandler.java):
В нем делаешь переменную которая будет содержать текст ошибки: String errorDescription, пишешь get set методы для нее. Метод нажатия на кнопку:
Код

public String onClick() {
        // ...................
        try {
            getReg(username, email, pass);
        }
        catch (ClassNotFoundException cnfe) {
            return "Exception";
        }
        catch (SQLException sqle) {
            errorCode = sqle.getErrorCode();
            if (errorCode == X)  {// X - это число которое выпадет когда происходит дублирование записей 
               errorDescription = "Такой пользователь уже существует!";
               return "Duplicate";
            }
        }
        catch (Exception e) {
           retrun "Exception";
        }
         //......................
}



Оформляем faces-config.xml 

Код

  <managed-bean>
    <managed-bean-name>usHandler</managed-bean-name>
    <managed-bean-class>UserHandler</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>


  <navigation-rule>
    <from-view-id>/UserServiceActions.jsp</from-view-id>
    <navigation-case>
      <from-outcome>Duplicate</from-outcome>
      <to-view-id>/UserServiceActions.jsp</to-view-id>
    </navigation-case>
    <navigation-case>
      <from-outcome>Exception</from-outcome>
      <to-view-id>/ErrorPage.jsp</to-view-id>
    </navigation-case>
  </navigation-rule>


Все это выводишь на jsp страничке. Описание ошибки будет такое 
Код
#{usHandler.errorDescription}


Автор: Wowa 26.2.2007, 15:54
В ПХП эта проблема решается ОЧЕНЬ легко. После вставки данных в базу нужно лишь послать заголовок браузеру о переадресации. Делается это так:
header("Location: http://site.com/thanks.html&quot;);

Этот метод работает просто замечательно. Разве нельзя нечто подобное на Java сделать?? Ведь нужно:
1. Послать заголовок
2. Отобразить след. страницу

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)