我创建了一个自定义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>
的普通控制器方法有什么区别?
编辑:这是servlet的bean定义。
<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>
答案 0 :(得分:1)
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。现在,它是通过从控制器获取它来完成的。 Controller可以使用像这样的@InitBinder注释来访问它
public class AcmeController {
private WebDataBinder binder;
@InitBinder
protected void initBinder(WebDataBinder binder) {
this.binder = binder;
}
另一种选择是在拦截器中实现preHandle方法而不是postHandle。 PreHandle无法访问模型,但它可以访问请求,因此在preHandle中你可以将AcmeModel作为属性添加到reqiest然后在你的控制器中你可以得到值,将它添加到模型中,然后它将是Bound就像Spring的其他模型属性一样。