首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Spring MVC 實戰(二):流程控制——攔截器、映射解析器與多型控制器

     編輯:關於C語言

核心組件總覽

Spring MVC 的流程控制三大支柱:

  1. HandlerMapping:URL → Controller 映射解析
  2. HandlerInterceptor:預處理/後處理/完成後橫切邏輯
  3. Controller:業務邏輯入口,支援多種實現風格

一、HandlerMapping 兩大主流實現

1. BeanNameUrlHandlerMapping(慣例優於配置)

<bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/hello.html" class="com.example.HelloController"/>
  • Bean `name` 直接作為 URL 模式,簡單直接。
  • 缺點:URL 與類名耦合,重構時需同步修改 XML 與類。

2. SimpleUrlHandlerMapping(彈性映射,推薦生產)

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="urlMap">
        <map>
            <entry key="/hello*.html" value-ref="helloController"/>
            <entry key="/api/**" value-ref="apiController"/>
        </map>
    </property>
    <property name="interceptors">
        <list><ref bean="timeInterceptor"/></list>
    </property>
</bean>

<bean id="helloController" class="com.example.HelloController"/>
  • 支援 Ant 風格通配符(`*`、`**`、`?`)。
  • 可掛載攔截器鏈,實現橫切關注點。
  • URL 與 Controller ID 解耦,利於維護。

二、HandlerInterceptor 實戰

1. 自訂攔截器

public class TimeInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        long start = System.nanoTime();
        req.setAttribute("startTime", start);
        System.out.println("preHandle " + new Date());
        return true;  // false 終止後續流程
    }

    @Override
    public void postHandle(HttpServletRequest req, HttpServletResponse res,
                           Object handler, ModelAndView mv) {
        System.out.println("postHandle " + new Date());
    }

    @Override
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res,
                                Object handler, Exception ex) {
        long start = (Long) req.getAttribute("startTime");
        System.out.printf("afterCompletion %s 耗時 %d ms%n", new Date(), (System.nanoTime()-start)/1_000_000);
    }
}

2. 掛載到 Mapping

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="interceptors">
        <list><ref bean="timeInterceptor"/></list>
    </property>
    <property name="urlMap"> ... </property>
</bean>

同一 Mapping 下的所有 Controller 共享攔截器鏈;不同 Mapping 可配置不同鏈。

三、Controller 多態實現指南

繼承類別適用場景關鍵方法
AbstractController 單一請求處理,最基礎 `handleRequestInternal(req, res)`
MultiActionController 單類別聚合多個相關動作(CRUD) 自訂方法 `insert(req,res)`、`delete(req,res)` + `MethodNameResolver`
AbstractCommandController 表單綁定,自動將請求參數填充 Command 物件 `handle(req, res, command, errors)` + `setCommandClass(User.class)`
SimpleFormController 完整表單流程(顯示→驗證→提交→成功視圖) `formBackingObject`、`onSubmit`、`referenceData`

MultiActionController 範例

public class UserController extends MultiActionController {
    public ModelAndView list(HttpServletRequest req, HttpServletResponse res) {
        return new ModelAndView("userList", "users", userService.findAll());
    }
    public ModelAndView create(HttpServletRequest req, HttpServletResponse res) {
        // 手動綁定或用 ServletRequestDataBinder
        return new ModelAndView("redirect:/user/list.html");
    }
}
<bean id="userController" class="com.example.UserController"/>
<bean id="multiMapping" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
    <property name="delegate" ref="userController"/>
    <property name="methodNameResolver">
        <bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
            <property name="mappings">
                <props>
                    <prop key="/user/list.html">list</prop>
                    <prop key="/user/create.html">create</prop>
                </props>
            </property>
        </bean>
    </property>
</bean>

AbstractCommandController 表單綁定

public class LoginController extends AbstractCommandController {
    public LoginController() { setCommandClass(LoginForm.class); }

    @Override
    protected ModelAndView handle(HttpServletRequest req, HttpServletResponse res,
                                  Object cmd, BindException errors) {
        LoginForm form = (LoginForm) cmd;
        if (errors.hasErrors()) return new ModelAndView("loginForm");
        if (authService.login(form.getUsername(), form.getPassword())) {
            return new ModelAndView("redirect:/home.html");
        }
        errors.reject("invalid.credentials");
        return new ModelAndView("loginForm");
    }
}

框架自動:實例化 `LoginForm` → 依名稱綁定請求參數 → 驗證(若有 `Validator`)→ 傳入 `handle`。

四、最佳實踐清單

  1. 優先用 SimpleUrlHandlerMapping + 註解式 Controller(@Controller + @RequestMapping),XML 映射僅維護舊專案。
  2. 攔截器粒度:通用日誌/計時/權限 → 全域攔截器;業務專用 → 針對性 Mapping 掛載。
  3. Command 物件建議使用不可變 DTO + Bean Validation(JSR-303),避免 `setCommandClass` 緊耦合實體。
  4. 棄用 `MultiActionController`/`SimpleFormController`(Spring 3.0+ 已標記棄用),改用註解式多方法 Controller。

Spring MVC 的流程控制核心是「映射解耦、攔截橫切、Controller 多態」。掌握 XML 時代的三大組件演進脈絡,能更深刻理解現代註解式實現的設計初衷。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved