Работа с ошибками
От: fellow.sufferer Россия  
Дата: 30.06.05 07:55
Оценка:
Хотелось бы обсудить тему работы с ошибками в веб-приложении на основе стратса.
Ловить на каждом экшине рантайм-ошибки и выбрасывать собственное исключение не здОрово...
Что посоветуете использовать или почитать?
Re: Работа с ошибками
От: L.C.R. Россия lj://_lcr_
Дата: 03.07.05 23:57
Оценка:
fellow.sufferer,

FS>Хотелось бы обсудить тему работы с ошибками в веб-приложении на основе стратса.

FS>Ловить на каждом экшине рантайм-ошибки и выбрасывать собственное исключение не здОрово...
FS>Что посоветуете использовать или почитать?

errorpage?
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re: Работа с ошибками
От: mihhon  
Дата: 06.07.05 18:14
Оценка: 5 (2)
errorpage — коряво, годится только для fatal errors, типа упавшей базы и невозможности работы приложения

далее код, который использовался/прогрессировал примерно с 2002 года на 5 проектах размером от 30 до 400 экранов

Struts, errors handling

1. ошибки делятся на бизнес и технические. при возникновении бизнес-ошибки делается редирект на input page action-а , при технической — на errorpage с сообщением "приходите завтра"

2. классы Action занимаются интерпретацией параметров http-запросов и вызовом методов бизнес-объектов (сервисов и т.п.). Бизнес-методы могут выкидовать exception-ы, которые наследуют AppException. AppException определяет атрибут code — код ошибки

3. все классы Action приложения наследуют BaseAction, который занимается обработкой ошибок, все остальные классы Action не содержат код обработки ошибок. BaseAction перекрывает execute и определяет executeImpl и addError (помимо прочего)

BaseAction
    ...

    public ActionForward execute(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
        try {
            long time = System.currentTimeMillis();
            ActionForward actionForward = null;
            ActionErrors errors = new ActionErrors();

            // security checks here

            // errors handling
            try {
                actionForward = executeImpl(mapping, form, request, response);
            }
            catch (AppException e) {
                addError(e, errors, request);
                actionForward = mapping.getInputForward();
            }
            catch (ParseException e) {
                errors.add(Const.RESOURCE_KEY_ERROR_DATE_PARSE,
                    new ActionError(
                        Const.RESOURCE_KEY_ERROR_DATE_PARSE));
                saveErrors(request, errors);
                actionForward = mapping.getInputForward();
            }
            return actionForward;
        }
        
        // unexpected error, also can be handled by <error-page> in web.xml
        catch (Throwable throwable) {
            request.setAttribute("javax.servlet.error.exception", throwable);
            request.setAttribute("javax.servlet.error.request_uri",
                request.getRequestURI());

            // forward to error page
            return mapping.findForward(Const.FORWARD_ERROR);
        }
    }

    public ActionForward executeImpl(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException, AppException, ParseException {
        throw new ServletException(
                "BaseAction.executeImpl is not implemented");
    }

    /**
     * processes an error
     *
     * @param e exception
     * @param errors errors
     * @param request request we are processing
     */
    protected void addError(AppException e, ActionErrors errors, HttpServletRequest request) {
        String key = Const.RESOURCE_KEY_ERROR_PREFIX + e.getCode();
        errors.add(key, new ActionError(key, e.getMessage()));
        saveErrors(request, errors);
    }


типичный код Action — только вызов бизнес-логики
public class CreationAction extends BaseAction {
    public ActionForward executeImpl(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException, TopadException, ParseException {
        HttpSession session = request.getSession(false);

        // get process
        CreationProcess proc = 
            (CreationProcessus) ProcessManager.get(CreationProcess.class);
        
        // get value object from session
        CompositeValue value =
            (CompositeValue )session.getAttribute(
                    Const.SESSION_KEY_UA_VALUE);

        User user = getUser(session);
        
        // cancel
        if (isCancelled(request)) {
            proc.cancel(value, user);
            clear(request, mapping);
            return mapping.findForward(Const.FORWARD_CANCEL);
        }

        // get form
        DetailForm dForm = (DetailForm) form;
        String action = dForm.getAction();

        // CONFIRM action
        if (Const.ACTION_CONFIRM.equals(action)) {
            // check transactional control token
            // token was set by this action 
            ActionForward tokenCheckResult = checkToken(request, mapping);
            if (tokenCheckResult != null) {
                return tokenCheckResult;
            }
            
            // copy form into action
            dForm.copyTo(value);

            // cofirm, this method can throw business or technical exception
            proc.confirm(value, user);

            // clean
            clear(request, mapping);
            return mapping.findForward(Const.FORWARD_SUCCESS);
        }

        else if (...) {

            ...
        }
    }
}



4. ApplicationResources.properties содержит такстовые сообщения для кодов ошибок, ключ начинается с префикса RESOURCE_KEY_ERROR_PREFIX

ApplicationResources.properties
# Validation errors block header and footer
errors.header=alert(''
errors.footer=);
...

# Error messages
error.prefix.=not defined, programmer's error !!!
error.prefix.null=invalid code, programmer's error !!!
...
error.prefix.S002=S002 Message 1.
error.prefix.S004=S004 Message 2.
...

error.parse.date=Date invalide


5. страница template приложения содержит следующий код, который отображает сообщения, если они есть, в javascript popup-окошке. таким образом пользователь одинаково информируется об clientside javascript validation ошибках, serverside validation ошибках и business logic ошибках

    <script language="Javascript">
            function showErrors () {
                <logic:messagesPresent>
                    <bean:message key="errors.header"/>
                        <html:messages id="error">
                          + '<%= StringUtils.filterForJavaScript((String) pageContext.getAttribute("error")) %>\n'
                        </html:messages>
                   <bean:message key="errors.footer"/>
                </logic:messagesPresent>
             }

...
    </script>
   </head>
    <body onload="showErrors();void(0);">
...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.