1. 程式人生 > >SpringMVC框架理解

SpringMVC框架理解

ola ans sub character XML toad this 轉發 org

JavaEE體系結構包括四層,從上到下分別是應用層、Web層、業務層、持久層。Struts和SpringMVC是Web層的框架,Spring是業務層的框架,Hibernate和MyBatis是持久層的框架。

為什麽要使用SpringMVC?

很多應用程序的問題在於處理業務數據的對象和顯示業務數據的視圖之間存在緊密耦合,通常,更新業務對象的命令都是從視圖本身發起的,使視圖對任何業務對象更改都有高度敏感性。而且,當多個視圖依賴於同一個業務對象時是沒有靈活性的。

SpringMVC是一種基於Java,實現了Web MVC設計模式,請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將Web層進行職責解耦。基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,SpringMVC也是要簡化我們日常Web開發。

MVC設計模式

技術分享圖片

SpringMVC的核心架構:

技術分享圖片

具體流程:

(1)首先用戶發送請求——>DispatcherServlet,前端控制器收到請求後自己不進行處理,而是委托給其他的解析器進行處理,作為統一訪問點,進行全局的流程控制;

(2)DispatcherServlet——>HandlerMapping,映射處理器將會把請求映射為HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象、多個HandlerInterceptor攔截器)對象;

(3)DispatcherServlet——>HandlerAdapter,處理器適配器將會把處理器包裝為適配器,從而支持多種類型的處理器,即適配器設計模式的應用,從而很容易支持很多類型的處理器;

(4)HandlerAdapter——>調用處理器相應功能處理方法,並返回一個ModelAndView對象(包含模型數據、邏輯視圖名);

(5)ModelAndView對象(Model部分是業務對象返回的模型數據,View部分為邏輯視圖名)——> ViewResolver, 視圖解析器將把邏輯視圖名解析為具體的View;

(6)View——>渲染,View會根據傳進來的Model模型數據進行渲染,此處的Model實際是一個Map數據結構;

(7)返回控制權給DispatcherServlet,由DispatcherServlet返回響應給用戶,到此一個流程結束。

SpringMVC入門程序:

(1)web.xml

<web-app>
  <servlet>
  <!-- 加載前端控制器 -->
  <servlet-name>springmvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!-- 
       加載配置文件
       默認加載規範:
       * 文件命名:servlet-name-servlet.xml====springmvc-servlet.xml
       * 路徑規範:必須在WEB-INF目錄下面
       修改加載路徑:
   -->
   <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>classpath:springmvc.xml</param-value>   
   </init-param>
  </servlet>

  <servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

(2)springmvc.xml

<beans>
    <!-- 配置映射處理器:根據bean(自定義Controler)的name屬性的url去尋找hanler;springmvc默認的映射處理器是
    BeanNameUrlHandlerMapping
     -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>


    <!-- 配置處理器適配器來執行Controlelr ,springmvc默認的是
    SimpleControllerHandlerAdapter
    -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

    <!-- 配置自定義Controler -->
    <bean id="myController" name="/hello.do" class="org.controller.MyController"></bean>

    <!-- 配置sprigmvc視圖解析器:解析邏輯視圖; 
        後臺返回邏輯視圖:index
        視圖解析器解析出真正物理視圖:前綴+邏輯試圖+後綴====/WEB-INF/jsps/index.jsp
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>        
    </bean>
</beans>

(3)自定義Controler

public class MyController implements Controller{

    public ModelAndView handleRequest(HttpServletRequest arg0,
            HttpServletResponse arg1) throws Exception {
        ModelAndView mv = new ModelAndView();
        //設置頁面回顯數據
        mv.addObject("hello", "歡迎學習springmvc!");

        //返回物理視圖
        //mv.setViewName("/WEB-INF/jsps/index.jsp");

        //返回邏輯視圖
        mv.setViewName("index");
        return mv;
    }
}

(4)index頁面

<html>
<body>
<h1>${hello}</h1>
</body>
</html>

(5)測試地址

http://localhost:8080/springmvc/hello.do

HandlerMapping

HandlerMapping 將會把請求映射為 HandlerExecutionChain 對象(包含一個 Handler 處理器(頁面控制器)對象、多個 HandlerInterceptor 攔截器)對象,通過這種策略模式,很容易添加新的映射策略。

映射處理器有三種,三種可以共存,相互不影響,分別是BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping和ControllerClassNameHandlerMapping;

BeanNameUrlHandlerMapping

//默認映射器,即使不配置,默認就使用這個來映射請求。
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
//映射器把請求映射到controller
<bean id="testController" name="/hello.do" class="org.controller.TestController"></bean>

SimpleUrlHandlerMapping

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/ss.do">testController</prop>
            <prop key="/abc.do">testController</prop>
        </props>
    </property>
</bean>
//那麽上面的這個映射配置:表示多個*.do文件可以訪問多個Controller或者一個Controller。 
//前提是:都必須依賴自定義的控制器bean
<bean id="testController" name="/hello.do" class="org.controller.TestController"></bean>

ControllerClassNameHandlerMapping

//這個Mapping一配置:我們就可以使用Contrller的 [類名.do]來訪問這個Controller.
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"></bean>

  HandlerMapping架構圖 :

技術分享圖片

HandlerAdapter

處理器適配器有兩種,可以共存,分別是SimpleControllerHandlerAdapter和HttpRequestHandlerAdapter。

SimpleControllerHandlerAdapter

SimpleControllerHandlerAdapter是默認的適配器,表示所有實現了org.springframework.web.servlet.mvc.Controller 接口的Bean 可以作為SpringMVC 中的處理器。

HttpRequestHandlerAdapter

HTTP請求處理器適配器將http請求封裝成HttpServletResquest 和HttpServletResponse對象,和servlet接口類似。

(1)配置HttpRequestHandlerAdapt

<!-- 配置HttpRequestHandlerAdapter適配器 -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>

(2)編寫Controller

public class HttpController implements HttpRequestHandler{

    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //給Request設置值,在頁面進行回顯
        request.setAttribute("hello", "這是HttpRequestHandler!");
        //跳轉頁面
        request.getRequestDispatcher("/WEB-INF/jsps/index.jsp").forward(request, response);
    }
}

(3)準備jsp頁面

<html>
<body>
<h1>${hello}</h1>
</body>
</html>

Adapter源碼分析

模擬場景:前端控制器(DispatcherServlet)接收到Handler對象後,傳遞給對應的處理器適配器(HandlerAdapter),處理器適配器調用相應的Handler方法。

(1)模擬Controller

//以下是Controller接口和它的是三種實現 
public interface Controller {
}

public class SimpleController implements Controller{
    public void doSimpleHandler() {
        System.out.println("Simple...");
    }
}

public class HttpController implements Controller{
    public void doHttpHandler() {
        System.out.println("Http...");
    }
}

public class AnnotationController implements Controller{
    public void doAnnotationHandler() {
        System.out.println("Annotation..");
    }
} 

(2)模擬HandlerAdapter

//以下是HandlerAdapter接口和它的三種實現
public interface HandlerAdapter {
    public boolean supports(Object handler);
    public void handle(Object handler);
}

public class SimpleHandlerAdapter implements HandlerAdapter{
    public boolean supports(Object handler) {
        return (handler instanceof SimpleController);
    }

    public void handle(Object handler) {
        ((SimpleController)handler).doSimpleHandler();
    }
}

public class HttpHandlerAdapter implements HandlerAdapter{
    public boolean supports(Object handler) {
        return (handler instanceof HttpController);
    }

    public void handle(Object handler) {
        ((HttpController)handler).doHttpHandler();
    }
}

public class AnnotationHandlerAdapter implements HandlerAdapter{
    public boolean supports(Object handler) {
        return (handler instanceof AnnotationController);
    }

    public void handle(Object handler) {
        ((AnnotationController)handler).doAnnotationHandler();
    }
}

(3)模擬DispatcherServlet

public class Dispatcher {
    public static List<HandlerAdapter> handlerAdapter = new ArrayList<HandlerAdapter>();

    public Dispatcher(){
        handlerAdapter.add(new SimpleHandlerAdapter());
        handlerAdapter.add(new HttpHandlerAdapter());
        handlerAdapter.add(new AnnotationHandlerAdapter());
    }

    //核心功能
    public void doDispatch() {
        //前端控制器(DispatcherServlet)接收到Handler對象後
        //SimpleController handler = new SimpleController();
        //HttpController handler = new HttpController();
        AnnotationController handler = new AnnotationController();

        //傳遞給對應的處理器適配器(HandlerAdapter)
        HandlerAdapter handlerAdapter = getHandlerAdapter(handler);

        //處理器適配器調用相應的Handler方法
        handlerAdapter.handle(handler);
    }

    //通過Handler找到對應的處理器適配器(HandlerAdapter)
    public HandlerAdapter getHandlerAdapter(Controller handler) {
        for(HandlerAdapter adapter : handlerAdapter){
            if(adapter.supports(handler)){
                return adapter;
            }
        }
        return null;
    }
}

(4)測試

public class Test {
    public static void main(String[] args) {
        Dispatcher dispather = new Dispatcher();
        dispather.doDispatch();
    }
}

====================================================================

控制器:

控制器架構圖

技術分享圖片

Controller 簡介

  • 收集、驗證請求參數並綁定到命令對象;
  • 將命令對象交給業務對象,由業務對象處理並返回模型數據;
  • 返回ModelAndView(Model部分是業務對象返回的模型數據,視圖部分為邏輯視圖名)。

ServletForwardingController(轉發控制器)

將接收到的請求轉發到一個命名的servlet,具體示例如下:當我們請求/forwardToServlet.do時,會被轉發到名字為“forwarding”的servlet處理,該sevlet的servlet-mapping標簽配置是可選的.

(1)控制器

public class ForwardingServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.getWriter().write("Controller forward to Servlet");
    }
}

(2)web.xml

<servlet>  
<servlet-name>forwarding</servlet-name>  
<servlet-class>org.controller.ForwardingServlet</servlet-class>  
</servlet> 

(3)spring.xml

<bean name="/forwardToServlet.do"   
class="org.springframework.web.servlet.mvc.ServletForwardingController">  
<property name="servletName" value="forwarding"></property>  

AbstractCommandController(命令控制器)

使用post請求進行表單提交

模擬提交用戶表信息。

(1)spring.xml配置文件:

<beans>
    <!-- 配置映射處理器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

    <!-- 配置處理器適配器-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

    <!-- 配置自定義Controler -->
    <bean name="/command.do" class="org.controller.CommandController"></bean>

    <bean name="/toAdd.do" class="org.controller.ToAddController"></bean>

    <!-- 配置sprigmvc視圖解析器:解析邏輯試圖 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>        
    </bean>
</beans>

(2)表單跳轉控制器:跳轉到表單頁面

public class ToAddController implements Controller{
    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView();
        //調轉到add添加頁面視圖
        mv.setViewName("add");
        return mv;
    }
}

(3)編輯頁面控制器:轉發表單信息

public class CommandController extends AbstractCommandController{

    //指定參數綁定到哪個javaBean
    public CommandController(){
        this.setCommandClass(User.class);
    }

    @Override
    protected ModelAndView handle(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {
        //把命令對象強轉成User對象
        User user = (User) command;
        ModelAndView mv = new ModelAndView();

        mv.addObject("user", user);
        mv.setViewName("MyJsp");

        return mv;
    }

    /*
     * 進行時間類型各種格式的覆蓋
     */
    @Override
    protected void initBinder(HttpServletRequest request,
            ServletRequestDataBinder binder) throws Exception {
        String str = request.getParameter("birthday");

        if(str.contains("/")){
            binder.registerCustomEditor(Date.class, 
                    new CustomDateEditor(new SimpleDateFormat("yyyy/MM/dd"), true));
        }else{
            binder.registerCustomEditor(Date.class, 
                    new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));    
        }
    }
}

(4)表單頁面:

<html>
<body>
<form action="${pageContext.request.contextPath }/command.do" method="post">
姓名:<input type="text" name="username" id="username"><p>
生日:<input type="text" name="birthday" id="birthday"><p>
性別:<input type="text" name="sex" id="sex"><p>
地址:<input type="text" name="address" id="address"><p>
<input type="submit" value="提交">
</form>
</body>
</html>

(5)表單信息呈現頁面:

<html>
<body>
${user.username } <br>
${user.birthday } <br>
${user.sex } <br>
${user.address } <br>
</body>
</html>

(6)進入表單頁面

http://localhost:8080/springmvc/toAdd.do 

使用get請求進行表單提交

在上面的代碼基礎上,直接輸入地址:

http://localhost:8080/springmvc/command.do?username=ltx&birthday=1996/11/01&sex=男&address=廣東

ParameterizableViewController(參數控制器)

使用參數控制器,不用自己定義Controller,可以直接使用toIndex進行訪問。

<bean name="/toIndex.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<!-- 配置你所要跳轉到視圖的名稱。跳轉到index頁面-->
<property name="viewName" value="index"></property>
</bean>

中文亂碼解決

Get請求亂碼

對於get請求中文參數出現亂碼解決方法有兩個:
修改tomcat配置文件添加編碼與工程編碼一致,如下:
<Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

另外一種方法對參數進行重新編碼:
String userName =new
String(request.getParamter("userName").getBytes("ISO8859-1"),"UTF-8")
ISO8859-1是Tomcat默認編碼,需要將Tomcat編碼後的內容按UTF-8編碼

Post請求亂碼

在web.xml中加入:

<filter>
    <filter-name>characterEncoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>characterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

版權聲明:轉載請註明出處! https://blog.csdn.net/litianxiang_kaola/article/details/79169148

SpringMVC框架理解