逐步理解SpringMVC

1.MVC(Model-View-Controller)css

用慕課網上的一個圖來看看MVChtml

Front Controller(前端控制器):把客戶的請求分發給不一樣的控制器去生成業務數據,將生成的業務數據分發給恰當的視圖模板生成咱們最終的圖形界面前端

Controller(控制層):實現業務數據的抽取,Controller-->Service-->dao-->ORM-->數據持久化java

Model(模型層):我認爲像是一箇中間件,若是須要數據持久化的時候,model將會成爲PO(persistant object),和dao層進行數據持久化;若是須要給View層展現的話,model將會成爲VO(value object),不必定和數據庫中的表對應,將View須要的數據封裝傳過去;有時候一個VO可能知足不了View層的需求,因此BO(business objec)就出來了;最後就是Pojo了,VO和PO應該都屬於它。 java的幾種對象(PO,VO,DAO,BO,POJO)解釋web

View(視圖層):顯示唄spring

2.SpringMVC數據庫

a.DispatcherServletexpress

SpringMVC很好的體現了MVC的核心風格:業務數據抽取同業務數據呈現相分離,只不過DispatcherServlet成了咱們(1)中提出的前端控制器。DispatcherServlet攔截了咱們的請求,將請求分發給不一樣的Controller,但他是怎麼知道不一樣的Controller的呢?因此有一個東西出現了apache

b.HandlerAdapterjson

 

HandlerAdapter是一個接口,有5個實現類,咱們在springMVC中大多數用的是@Controller,因此咱們看看它的實現類SimpleControllerHandlerAdapter,在Dispatcher中咱們看一下這個:

/**
     * Initialize the HandlerAdapters used by this class.
     * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
     * we default to SimpleControllerHandlerAdapter.(若是工廠中沒有這個handlerAdapter這個命名空間的話,咱們就默認使用SimpleControllerHandlerAdapter)
     */
    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;

        if (this.detectAllHandlerAdapters) {
            // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerAdapter> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
                // We keep HandlerAdapters in sorted order.
                OrderComparator.sort(this.handlerAdapters);
            }
        }
        else {
            try {
                HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerAdapter later.
            }
        }

        // Ensure we have at least some HandlerAdapters, by registering
        // default HandlerAdapters if no other adapters are found.
        if (this.handlerAdapters == null) {
            this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
            }
        }
    }

就這樣知道了咱們寫的Controller,本人小白,理解有誤,請大神指點!

c.HandlerInterceptor

接口,在調用Controller以前或者以後乾點什麼,相似AOP的思想。

d.HandlerMapping

既然用HandlerAdapter知道了那個對應的那個Controller,這個HandlerMapping就是分發請求的啦

e.HandlerExecutionChain

 

這個就是controller處理完與HandlerInterceptor生成handler傳給DispatcherServlet

f.ModeAndView

Model的具體表現,咱們在controller中使用map或者model,這個東西的做用就是將全部的東西轉換成modelandview

g.ViewResolver

視圖解析器,決定要用那個對象,如jstl,json

來,咱們上個圖理解一下:

 

總結一下:當請求傳到DispatcherServlet上的時候,由HandlerMapping分發請求到Controller,Controller處理完相應的操做,如業務邏輯,數據的持久化啊等等,而後和HandlerInterceptor把結果生成ModelandView返還給DispatcherServlet,而後DispatcherServlet決定用那個Resolver來解析數據,如jstl,xml,json啊等等,最後讓view層顯示就好了。

3.SpringMVC中的過程具體實操

a.先看看demo結構

b.上碼

a.web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 若是爲2.4版本的,就會默認支持EL -->
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>Archetype Created Web Application</display-name>
  
  <!-- Spring的應用上下文,理解層次化的ApplicationContext -->
  <!-- 定時任務都建議放在全局監聽的<context-param>中,而不建議放在<servlet>的<init-param>中. -->
  <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/configs/spring/applicationContext*.xml</param-value>
  </context-param>
  
  <listener>
  <listener-class>
  org.springframework.web.context.ContextLoaderListener
  </listener-class>
  </listener>
  
  
  
  <!-- DispatcherServlet,Spring MVC的核心 -->
  <servlet>
  <servlet-name>mvc-dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!-- DispatcherServlet對應的上下文配置,若是不配置下面的<init-param>,默認爲/WEB-INF/${servlet-name}-servlet.xml -->
  <init-param>
  <!-- contextConfigLocation爲固定的寫法 -->
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/configs/spring/mvc-dispatcher-servlet.xml</param-value>
  
  </init-param>
   <!-- 1)load-on-startup元素標記容器是否在啓動的時候就加載這個servlet(實例化並調用其init()方法)。
        2)它的值必須是一個整數,表示servlet應該被載入的順序
        2)當值爲0或者大於0時,表示容器在應用啓動時就加載並初始化這個servlet;
        3)當值小於0或者沒有指定時,則表示容器在該servlet被選擇時纔會去加載。
        4)正數的值越小,該servlet的優先級越高,應用啓動時就越先加載。
        5)當值相同時,容器就會本身選擇順序來加載。 -->
  <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
  <servlet-name>mvc-dispatcher</servlet-name>
  <!-- 表示攔截全部請求 -->
  <url-pattern>/</url-pattern>
  </servlet-mapping>
  
  
</web-app>

b.mvc-dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 本配置文件是工名爲mvc-dispatcher的DispatcherServlet使用,提供與其相關的Spring MVC的配置 -->

    <!--標籤支持,生命週期的管理 ,激活了咱們spring關於annotation的DI,當自動掃描啓動後,該配置能夠去掉-->
    <context:annotation-config />

    <!-- 自動掃描,只搜索@Controller標註的類,不搜索其餘標註的類 -->
    <context:component-scan base-package="com.huhu.spring">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>



    <!--HandlerMapping,會自動註冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter兩個bean,
                是spring MVC爲@Controllers分發請求所必須的,無需配置,spring MVC能夠默認啓動
      RequestMappingHandlerMapping   處理@RequestMapping註解的
      RequestMappingHandlerAdapter   處理@Controller註解的控制器類-->
    <!-- 擴充了註解驅動,能夠將請求參數綁定到控制器參數 (也就是說,URL查詢參數的某一個變量能夠直接映射到@Controller的某個方法的輸入參數)-->
    <mvc:annotation-driven />
    
   <!-- 靜態資源處理,css,js,images -->
   <!-- 
   <mvc:resources mapping="/resources/**" location="/resources/"/>
    -->
    
    <!--配置ViewResolver,可使用多個ViewResolver,使用order排序,可是InternalResourceViewResolver放在最後-->
    <!-- ViewResolver用那個viewresolver來獲取bean -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
    <property name="prefix" value="/WEB-INF/jsps/"></property>
    <property name="suffix" value=".jsp"></property>
    </bean>
    
    
    <!-- 文件上傳 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/> <!-- 10m -->
        <property name="maxInMemorySize" value="4096" />
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>
    
    <!-- viewResolver -->
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">    
    <property name="mediaTypes">    
      <map>    
        <entry key="html" value="text/html"/>    
        <entry key="xml" value="application/xml"/>  
        <entry key="json" value="application/json"/>    
      </map>    
    </property> 
    <!-- ViewResolver 負責怎麼去解析, 而View只表明一種 視圖層的技術 --> 
    <!--<property name="viewResolvers"> <list>   </list>  </property>-->
    <property name="defaultViews">  
        <list>  
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>  
        </list>  
    </property>  
</bean>  
    
</beans>

c.applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
    xmlns:cache="http://www.springframework.org/schema/cache"  
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/mvc  
    http://www.springframework.org/schema/mvc/spring-mvc.xsd" default-autowire="byName">  
  
    <!--
                    自動掃描web包 ,將帶有註解的類 歸入spring容器管理 
                    默認執行<context:annotation-config /> 
    -->  
    <context:component-scan base-package="com.huhu" >
    <!-- 不把@Controller歸入到spring容器中 -->
    <context:exclude-filter type="annotation" 
    expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
     
    
    

</beans> 

具體的xml語句的含義在文件註釋中已經標註,我想談談xml語句的運行流程:

web.xml的運行流程(context-param >> listener  >> fileter  >> servlet):

  1. 在啓動Web項目時,容器(好比Tomcat)會讀web.xml配置文件中的兩個節點<listener>和<contex-param>。
  2. 接着容器會建立一個ServletContext(上下文),應用範圍內即整個WEB項目都能使用這個上下文。
  3. 接着容器會將讀取到<context-param>轉化爲鍵值對,並交給ServletContext。
  4. 容器建立<listener></listener>中的類實例,即建立監聽(備註:listener定義的類能夠是自定義的類但必須須要繼承ServletContextListener)。
  5. 在監聽的類中會有一個contextInitialized(ServletContextEvent event)初始化方法,在這個方法中能夠通event.getServletContext().getInitParameter("contextConfigLocation"來獲得context-param 設定的值。在這個類中還必須有一個contextDestroyed(ServletContextEvent event) 銷燬方法.用於關閉應用前釋放資源,好比說數據庫鏈接的關閉。
  6. 獲得這個context-param的值以後,你就能夠作一些操做了.注意,這個時候你的WEB項目尚未徹底啓動完成.這個動做會比全部的Servlet都要早

web.xml中的bean加載(ContextLoaderListener,ContextLoaderServlet,servlet.DispatcherServlet):

  1. ContextLoaderListener 和 ContextLoaderServlet : 本質上是等同的,都是調用ContextLoader來加載web程序的上下文,加載完成之後,都是在ServletContext中,只不過listener須要Servlet2.3及以上支持。
  2. ContextLoaderListene與DispatcherServlet : 用DispatcherServlet載入的Bean是隸屬於此Servlet的(因此spring能夠配置多個分別擁有各自環境的DispatcherServlet),所以其餘servlet沒法獲取到該Context。

d.TestController.java

@Controller
@RequestMapping("/test")
public class TestController {
    
    private static Logger logger =LoggerFactory.getLogger(TestController.class);
    @Autowired
    private TestService testService;
    
   @RequestMapping("/{s}")
   @ResponseBody
   public String test(@PathVariable("s") String s) {
       logger.info(s);
       String str1 = testService.test(s);
       return str1;
   }
   
   //用於文件上傳,須要在pom.xml中添加依賴commons-fileupload
   
   @RequestMapping("/upload")
   public String upLoad(@RequestParam("file") MultipartFile file) throws IOException {
       if(!file.isEmpty()) {
           FileUtils.copyInputStreamToFile(file.getInputStream(), new File("D:\\demo\\image",System.currentTimeMillis()+".jpg"));   
       }
       return "success";
       
   }
   
   //json測試,須要在pom.xml中添加依賴jackson-databind
   @RequestMapping(value="/json/{id}",method=RequestMethod.GET)
   @ResponseBody
   public Map<String,String> json(@PathVariable("id") String id ) {
       
    Map<String, String> map=testService.jsonTest();

        return map;

   }
    
}

e.TestService.java

public interface TestService {
    public String test(String s);
    Map<String, String>  jsonTest();
}

f.TestServiceImpl.java

@Service("testService")
public class TestServiceImpl implements TestService{

    public String test(String s) {
        
        return "hello"+s;
    }
    
    public Map<String, String>  jsonTest(){
        Map<String, String> map=new HashMap();
        map.put("id", "1");
        map.put("name", "huhu");
        map.put("age", "23");
        return map;
    }
    
    
}

g.pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>huhu</groupId>
    <artifactId>test</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>test Maven Webapp</name>
  <url>http://maven.apache.org</url>
  
  <!-- 變量,來替代一些工程版本 -->
  <properties>
  <commons-lang.version>2.6</commons-lang.version>
  <slf4j.version>1.7.6</slf4j.version>
  <spring.version>4.1.3.RELEASE</spring.version>
  </properties>
  
  <!-- 統一管理jar包的版本 -->
  <dependencyManagement>
  <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>${spring.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
     </dependencies>
  </dependencyManagement>

  <dependencies>
  <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
   <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
   </dependency>
  
  <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    </dependency>
  
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>${commons-lang.version}</version>
    </dependency>
    
    <dependency>    
   <groupId>javax.servlet</groupId>    
   <artifactId>jstl</artifactId>    
   <version>1.2</version>    
   <scope>runtime</scope>    
    </dependency> 
    
    <!-- 文件上傳須要依賴的包-->
    <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
    </dependency>
    
    <!-- viewResolver中所須要的json -->
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.5</version>
    </dependency>

  </dependencies>
  
  <!-- 運行項目的插件  如mvn jetty:run -->
  <build>
  <!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-maven-plugin -->
    <plugins>
      <plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.2.2.v20140723</version>
      </plugin>
     </plugins>
  </build>

</project>

文件都上傳了,練練手吧!

4.SpringMVC中的數據綁定

a.什麼是數據綁定?
將界面用戶所填的屬性和程序內部設定的類型綁定
b.基本類型和包裝類型
1.基本類型
key是必須傳的,只能是int類型
2.包裝類型
能夠不傳key,能夠經過註解@RequestParam()能夠指定默認值
@RequestParam():
value() 對傳入參數指定名稱例如ecif
required() @RequestParam配置的傳入參數是否必定要傳
required=false表示能夠不傳,默認給參數賦值爲null注意(參數爲基本的數據類型int時不能使用 由於null不能賦值給int )
required=true 就是必需要有傳入參數,不傳會報400參數錯誤
value與required配合使用如沒有配置任何信息爲默認值 必須輸入對應參數名
3.數組
頁面能夠傳相同屬性的多個值,如name=qw&name=er
c.簡單對象,多層級對象,同屬性對象
簡單對象綁定:地址欄傳對象的屬性就行了
多層級對象(對象中含有一個屬性是另一種對象)綁定:只須要地址欄中輸入對象的屬性.屬性就能夠了
同屬性對象(擁有相同屬性的對象,地址欄該怎麼輸入呢):使用@InitBinder("")
函數體爲:
@InitBinder("user")
public void initUser(WebDataBinder binder){
binder.setFieldDefaultPrefix("user.");
}
ps:若是沒有使用@InitBinder(""),那麼同屬性對象該怎麼賦值呢

d.list,set,map的數據綁定
1.list
能夠經過索引下標進行綁定,地址欄直接寫對象的屬性,如users[0].name=qw&users[1].name=er
若是前臺請求,users[0].name=qw&users[20].name=er的時候,中間會出現一些空的對象,浪費資源空間,因此當咱們請求的時候注意索引下標
2.set
ps:set須要在運行的時候進行初始化,主要做用是在實際運用中進行對象的重複判斷,以及排除重複
直接請求會出現500錯誤,說set of size 0,建立對象的時候給他申請空間
set須要重寫equals()和hashcode()方法,無序,不重複,hashcode是惟一的,可是不符合實際,因此重寫object的hashcode()方法,重寫的話會出現相同屬性的對象產生相同的hashcode(),因此還要經過equals()方法來判斷是不是同一個對象。
3.map
經過鍵值對來存儲值
場景:一個班級,不須要重名的
URL請求:map.do?users['X'].name=qw&users['X'].age=23

 

------------------------------------------------------------------------------------------------補充-----------------------------------------------------------------------------

1.是誰關聯了****Mapper.xml和****.java的?

固然是經過xml關聯的,下面放一個mybatis.xml的配置文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 讀入properties配置文件 -->
    <properties resource="init.properties">

    </properties>
    <!-- 對象別名 -->
    <typeAliases>
        <typeAlias type="com.huhu.pojo.Person" alias="Person"/>
    </typeAliases>
    <!-- 數據源配置 -->
    <environments default="development">
        <environment id="development">
            <!-- 事務類型 -->
            <transactionManager type="JDBC"/>
            <!-- 數據源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 註冊xml文件 -->
    <mappers>
        <!-- 註冊PersonMapper.xml文件,PersonMapper.xml位於com.huhu.dao.mapper這個包下,
            因此resource寫成com/huhu/dao/mapper/PersonMapper.xml-->
        <mapper resource="com/huhu/dao/mapper/PersonMapper.xml"/>
        <!-- 將map下的*.java和*.xml都註冊到SqlSession實例中 -->
        <package name="com.huhu.dao.PersonMapper"/>
    </mappers>
</configuration>

2.那是誰注入了mybatis.xml呢?

web.xml中注入的

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
    classpath:spring/applicationContext.xml,
    classpath:mybatis/mybatis.xml
  </param-value>
</context-param>

真正的加載順序爲:context-param -> listener -> filter -> servlet

 

參考資料:

慕課網-Spring MVC起步

pring3.0中返回Json

spring web.xml 難點配置總結【轉】

解析mediaTypes+viewResolvers+viewResolvers

謝謝你們的閱讀,博客不易,請轉載註明地址:http://www.cnblogs.com/huhu1203/p/7633060.html

相關文章
相關標籤/搜索