---
# System prepended metadata

title: DispatcherServlet與controller的概念
tags: [Java Web-mvc, Java Web-Servlet]

---

# DispatcherServlet與controller的概念
###### tags: `Java Web-Servlet`
###### tags: `Java Web-mvc`

### 事由：
當建立許多Servlet，每個Servlet都有各自的方法，若要調用方法，都要使用反射來調用？

### 解決思路：
![](https://i.imgur.com/uDkN7Tc.png)
### 使用核心控制器DispatcherServlet來解決
根據用戶的請求，將用戶轉發到對應的Servlet，再對應到裏頭的methods
### 好處：
可以把底下的Controller重複使用到的反射代碼，統整放到DispatcherServlet


```java=
//*.do：表示攔截所有.do的請求
@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
   
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码
        request.setCharacterEncoding("UTF-8");
        //假设url是：  http://localhost:8080/pro15/hello.do
        //那么servletPath是：    /hello.do
        // 我的思路是：
        // 第1步： /hello.do ->   hello   或者  /fruit.do  -> fruit
        // 第2步： hello -> HelloController 或者 fruit -> FruitController
        //在application.xml的配置文件中，描寫關鍵字與controller類的關係
        String servletPath = request.getServletPath();
        //去除/，剩下hello.do
        servletPath = servletPath.substring(1);
        //去除.do，剩下hello
        int lastDotIndex = servletPath.lastIndexOf(".do") ;
        
        servletPath = servletPath.substring(0,lastDotIndex);
        
        Object controllerBeanObj = beanMap.get(servletPath);

        String operate = request.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index" ;
        }
        //先找出要使用的servlet底下所有的方法
        //再利用反射來調用選擇的方法
        //如此一來，就能把每個controller都要重複寫的反射代碼，統整到dispatcherServlet
        try {
            Method method = controllerBeanObj.getClass().getDeclaredMethod(operate,HttpServletRequest.class,HttpServletResponse.class);
            if(method!=null){
                //将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
                //值为 false 则指示反射的对象应该实施 Java 语言访问检查
                //由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的 
                method.setAccessible(true);
                method.invoke(controllerBeanObj,request,response);
            }else{
                throw new RuntimeException("operate值非法!");
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

```
### 如何讓Dispatcher可以引導到其他Servlet
1.Controller在內存中形成容器beanMap，
```java=
private Map<String,Object> beanMap = new HashMap<>();
```
2.容器中有各種組件，並且與xxx.do對應
![](https://i.imgur.com/kgczAyr.png)
3.把XxxController與xxx的關係在xml配置文件中描述
```xml=
<beans>
<!--這個bean標籤的作用，是將來servletPath中涉及的名字對應的是fruit，那麼就要FruitController這個類來處理    -->
    <bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"/>
</beans>
```
4.Servlet類中的方法對應
![](https://i.imgur.com/WpAnYw3.png)
