gpt4 book ai didi

java - Spring MVC Controller 设计

转载 作者:太空狗 更新时间:2023-10-29 22:47:47 24 4
gpt4 key购买 nike

我们正在将一个 struts 应用程序迁移到 Spring MVC 并利用 @Controller 注释将页面定向到各种方法调用。

不过,我在确定重用的好策略时遇到了麻烦。

我们在许多页面中基本上都做同样的事情:

prepareView(..., ...); //Various params -- could likely be standardized

if (!allowedToView()) {
mav.setViewName(injectedErrorPage);
}

performBusinessLogic(..., ...); //Various params -- not seeing how to standardize

persistEntities();
finalizeView(..., ...); // Various params -- could likely be standardized

使用什么策略来创建 final方法,使开发人员可以“忘记”这些过程?我曾考虑过创建一个抽象类,但由于每种方法所采用的方法不同,我确实没有办法将其“标准化”。

例如,我们有以下内容:
@RequestMapping("params="assign", method=RequestMethod.Post)
public ModelAndView assign(@SessionAttribute(value="sessionAttr") Pojo pojo,
@ModelAttribute("command") CommandPojo commandPojo,
BindingResult result) {
//Follows pattern above
}

@RequestMapping()
public ModelAndView filterResults(@SessionAttribute(value="sessionAttr") Pojo pojo,
@RequestAttribute("requestAttr") String requestAttr,
@ModelAttribute("command") CommandPojo2 commandPojo2,
BindingResult result) {

//Follows pattern above
}

拥有 final方法需要将其分解为两个 POJO(然后调用描述性函数)。我最关心的是我们如何处理进入这个 final方法的不同参数?我看不出有什么办法可以处理这种情况。

如果我们仍然可以拥有带有 protected 功能的“最终”方法,我们可以在需要时覆盖这些功能,那就太好了。

最佳答案

我和你有同样的问题。我还没有一个干净的解决方案,但我相信我取得了一些进展,所以我想我会与你分享我到目前为止的发现。

我按照three_cups_of_java 的建议探索了拦截器的使用,但遇到了各种问题(如下所述)。目前我正在尝试使用自定义 AnnotationMethodHandlerAdapter,但我还没有完成这项工作。

拦截器

由于拦截器无权访问它们拦截的 Controller 对象( 更正: 他们确实可以访问它,但对执行流程的控制有限), Controller 和拦截器必须通过以下方式进行通信 session 中的对象。

这是我的意思的一个稍微简化的例子:

在我们的旧架构中,我们有自己的基本 Controller ,每个人都可以扩展它。它本身扩展了 MultiActionController,并添加了一些自定义行为 - 就像在您的示例中一样,在调用处理程序方法之前,在发布请求之后更新服务器端 View 。这是有效的,因为所有 Controller 都提供了模板方法的实现(例如 getViewKeyInSession() )。

因此,基本 Controller 中的自定义代码大致如下所示:

// inside handleRequestInternal method
if (request.getMethod().equals("POST") {
updateViewAfterPost (session.get(getViewKeyInSession());
}
return super.handleRequestInternal();

现在,当我们将此代码移至拦截器时,我们遇到了几个问题:
  • 拦截器不能调用 getViewKeyInSession(),迫使我们对所有 Controller 使用相同的 session key (不好),或者遵守一些约定,即 View 的 session key 基于 url 或请求的参数(到目前为止,这也不好)。
  • 单个 Controller 不能再覆盖 updateModelAfterPost 的行为.这通常不是必需的,但不幸的是,对于某些 Controller 来说这是必需的。
  • 如果 Controller 提供了 updateModelAfterPost 的实现,并且想要向拦截器发出信号表示它对拦截器的帮助不感兴趣,则需要通过在 session 中放置一个标记对象供拦截器查看来实现,并且需要这样做它在之前的 GET 请求期间(也不好且不灵活)。

  • 使用自定义 AnnotationMethodHandlerAdapter

    目前我正在考虑指定 DefaultAnnotationHandlerMapping直接在我的 xml(而不是 mvc:annotation-driven )中,然后为它提供自定义 AnnotationMethodHandlerAdapter .

    正如我之前所说,我还没有取得足够的进展来呈现完整的结果,但是我的目标是这样的:

    我认为 AnnotationMethodHandlerAdapter 是 Spring 提供的 MultiActionController,但用于 pojo Controller 。例如,我已经知道如何将我自己的方法解析器(参见此 question)和其他 Spring 好东西插入它。

    这个适配器有几个你可以覆盖的方法,比如 invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) ,
    有可能 handle(HttpServletRequest request, HttpServletResponse response, Object handler)以及。

    在您的自定义代码中,您可以检查处理程序类,然后采取相应的行动。继续我前面的例子,如果处理程序类有一个方法 updateViewAfterPost或者如果它实现了某个接口(interface),那么你可以调用那个方法,然后调用 super让 spring 继续进行常规调用。因此,代码大致如下所示:
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    // inspect handler object, look for marker interface, methods and/or annotations
    // perform pre-processing on the handler object
    // e.g. handler.updateViewAfterPost(request, response)
    ModelAndView mav = super.handle (request, response, handler);
    // post-processing on the handler object
    return mav;
    }

    (当然,这只是一个玩具示例。在实际代码中,您需要更好的异常处理)

    更新:

    我用自定义 AnnotationMethodHandlerAdapter 尝试了上述策略,它确实有效。我在我的 pojo Controller 上使用了一个标记接口(interface),并且只引入了一个名为 updateModelAfterPost 的新方法。到生命周期,它按预期工作。

    我遇到了几个小的警告,主要是因为我在相同的 mvc 上下文中将旧方法与新方法相结合。下面你可以看到我对 xml 上下文所做的更改,然后是我认为值得强调的问题列表。
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="order" value="2" />
    </bean>

    <bean class="com.sample.MyAnnotationMethodHandlerAdapter">
    <property name="order" value="2" />
    </bean>

    <bean class="com.sample.MySimpleControllerHandlerAdapter" >
    <property name="order" value="1" />
    </bean>

    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="order" value="1" />
    <property name="mappings">
    <props>
    ...
    </props>
    </property>
    </bean>
  • 正如评论中提到的,我展开了 简写。我必须明确定义两个处理程序映射,并定义两个处理程序适配器。
  • 不幸的是,在我的遗留代码中,一些 Controller 是事务性的并且由 cglib 代理。 AnnotationMethodHandlerAdapter不能很好地处理这种情况,因此我设置了元素的顺序,使得遗留处理程序映射和处理程序适配器首先起作用,然后基于注释的处理程序映射和处理程序适配器起作用。
  • 我必须明确定义 Spring 的 SimpleControllerHandlerAdapter ,但我也不得不用我自己的类来扩展它,因为它没有实现 Ordered界面。
  • 我在定义 validator 时遇到了问题,因为我没有 jsr-303 的 jar。因此我放弃了 validator 和转换服务的声明。上面的 xml 片段正是我使用的,它不是为了答案而简化的精简版本。

  • 最后,这是相关类的代码:
    package com.sample;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;

    public class MyAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter {

    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    if (handler instanceof MyMarkerInterface) {
    MyMarkerInterface handler2 = (MyMarkerInterface) handler;
    handler2.updateModelAfterPost(request);
    }
    return super.invokeHandlerMethod(request, response, handler);
    }

    }


    package com.sample;

    import org.springframework.core.Ordered;
    import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;

    public class MySimpleControllerHandlerAdapter extends SimpleControllerHandlerAdapter implements Ordered {

    private int order = 0;

    public int getOrder() {
    return order;
    }

    public void setOrder(int order) {
    this.order = order;
    }


    }

    关于java - Spring MVC Controller 设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5265751/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com