有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java NumberFormat不适用于ModelAndView和HandlerInterceptorAdapter

我创建了一个自定义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;
    }
}

在极致。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) {
    }
}

这是我得到的结果:

Cost: $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());
    }
}

然后输出变成:

Cost: 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>

共 (1) 个答案

  1. # 1 楼答案

    Spring通过BindingResult对象处理格式化。当您在控制器中向模型添加值时,spring会验证这些值,创建BindingResult并将其添加到模型中。这种机制只适用于控制器,不适用于拦截器,可能是有意的,也可能不是,我不确定,但它肯定是这样工作的。如果您希望对拦截器中设置的值进行绑定,则需要自行进行绑定。修改拦截器如下:

    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对象添加到模型中。它需要获得转换服务。目前,它是通过从控制器获取数据来完成的。控制器可以使用@InitBinder注释访问它,如下所示

    public class AcmeController {
    
        private WebDataBinder binder;
    
        @InitBinder
        protected void initBinder(WebDataBinder binder) {
    
            this.binder = binder;
    
        }
    

    另一种选择是在拦截器中实现preHandle方法,而不是postHandle。PreHandle无法访问模型,但它可以访问请求,因此在PreHandle中,您可以将AcmeModel作为属性添加到Requiest中,然后在控制器中,您可以获取值,将其添加到模型中,然后它将像其他模型属性一样由Spring绑定