NumberFormat не работает с ModelAndView и HandlerInterceptorAdapter - PullRequest
2 голосов
/ 05 декабря 2011

Я создал пользовательский HandlerInterceptorAdapter для переопределения postHandle метода:

public class AcmeInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);

        AcmeController controller = (AcmeController) handler;

        controller.finalize(modelAndView);
    }
}

В AcmeModel я определяю поле, помеченное NumberFormat:

public class AcmeModel {
    private BigDecimal cost = BigDecimal.valueOf(67890.6789);

    @NumberFormat(style = Style.CURRENCY)
    public BigDecimal getCost() {
        return cost;
    }
}

В acme.jsp я использую <spring:bind> для вывода отформатированного значения:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<spring:bind path="acmeModel.cost">
    Cost: <c:out value="${status.value}" />
</spring:bind>

Теперь сначала я попробую контроллер следующим образом:

@Controller
public class AcmeController {

    @RequestMapping("/")
    public ModelAndView index() {
        ModelAndView modelAndView = new ModelAndView("WEB-INF/views/acme.jsp");
        modelAndView.addObject(new AcmeModel());
        return modelAndView;
    }

    public void finalize(ModelAndView modelAndView) {
    }
}

И вот что я получаю:

Стоимость: $ 67 890,68

Вот загадочная часть. Если я переместу вызов на addObject в тело finalize:

@Controller
public class AcmeController {

    @RequestMapping("/")
    public ModelAndView index() {
        ModelAndView modelAndView = new ModelAndView("WEB-INF/views/acme.jsp");
        //modelAndView.addObject(new AcmeModel());
        return modelAndView;
    }

    public void finalize(ModelAndView modelAndView) {
        modelAndView.addObject(new AcmeModel());
    }
}

Тогда вывод будет:

Стоимость: 67890,6789

В чем разница между добавлением объекта к ModelAndView в методе обработчика по сравнению с обычным методом контроллера, который влияет на <spring:bind>?

Редактировать : Вот определение бина для сервлета.

<beans ...>     
    <mvc:annotation-driven />       
    <context:component-scan base-package="com.example" />       
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean id="acmeInterceptor" class="com.example.numberformat.AcmeInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

1 Ответ

1 голос
/ 12 декабря 2011

Spring обрабатывает форматирование с помощью объекта BindingResult.Когда вы добавляете значения в модель в контроллере, Spring проверяет их, создает BindingResult и добавляет его в модель.Этот механизм работает только для контроллеров, а не для перехватчиков, может быть он намеренный или нет, я не уверен, но он определенно работает так.Если вы хотите, чтобы привязка выполнялась для значений, установленных в перехватчике, тогда вам нужно выполнить привязку yourslef.Измените ваш перехватчик следующим образом:

public class AcmeInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {      

        AcmeController controller = (AcmeController) handler;

        AcmeModel acmeModel = controller.getAcmeModel();
        String key = "acmeModel";

        BeanPropertyBindingResult bpb = new BeanPropertyBindingResult(
                acmeModel, key);

        bpb.initConversion(controller.getBinder().getConversionService());

        modelAndView.addObject(key, acmeModel);
        modelAndView.addObject(BindingResult.MODEL_KEY_PREFIX + key, bpb);

    }

}

, поскольку вы можете видеть, что этот фрагмент кода добавляет дополнительный объект BindingResult к модели.Он должен получить ConversionService.На данный момент это делается путем получения его от контроллера.Контроллер может получить к нему доступ с помощью аннотации @InitBinder, подобной этой

public class AcmeController {

    private WebDataBinder binder;

    @InitBinder
    protected void initBinder(WebDataBinder binder) {

        this.binder = binder;

    }

Другой вариант заключается в реализации метода preHandle в перехватчике вместо postHandle.PreHandle не может получить доступ к модели, но он может получить доступ к запросу, поэтому в preHandle вы можете добавить AcmeModel к требованию в качестве атрибута, затем в вашем контроллере вы можете получить значение, добавить его в модель, тогда оно будет привязано.к весне, как и остальные атрибуты модели.

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