【Spring學習】SpringMVC demo搭建


前言:今天會通過IDEA建立一個SpringMVC的demo項目,在其中會涉及到一些基礎模塊和相關知識,然后結合這個具體的知識點,理解清楚SpringMVC的框架原理(以圖的形式展示),順藤摸瓜分析源碼

一、新建項目

通過File-New-Project,在下方頁面勾選:Spring MVC + Web Application

 

點擊Next填上:ProjectName和Project Location,之后會進入下載依賴包的過程:

 

完成之后,在窗口中打開的工程目錄如下:其中lib中所放的是依賴的jar包,src中根據自己的需求添加package+class,其中IDEA已經自動幫助在WEB-INF中默認配置了applicationContext.xml、dispatcher-servlet.xml、web.xml

 

至此,基礎工程也包含IDEA自動配置的都已經建好

 

二、確認配置文件內容

梳理清楚WEB-INF下的三個xml文件的作用和其中所配置內容的具體含義

 

直接通過官網介紹:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html 查看

具體介紹如下: 

1、web.xml

作用:用來對DispatcherServlet進行注冊和初始化(web.xml configuration registers and initializes the DispatcherServlet)

內容示例:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 5  version="3.1">
 6     <context-param>
 7         <param-name>contextConfigLocation</param-name>
 8         <param-value>/WEB-INF/applicationContext.xml</param-value>
 9     </context-param>
10     <listener>
11         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
12     </listener>
13     <servlet>
14         <servlet-name>dispatcher</servlet-name>
15         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
16         <load-on-startup>1</load-on-startup>
17     </servlet>
18     <servlet-mapping>
19         <servlet-name>dispatcher</servlet-name>
20         <url-pattern>*.form</url-pattern>
21     </servlet-mapping>
22 </web-app>

重點關注的內容,如圖中黃色底色的<context-param>的<param-value>部分,這個是WebApplicationContext的配置文件,如上所示就代表只配置了一個WebApplicationContext,一般情況下是足夠的,也可以有Context的層次結構:其中一個根WebApplicationContext在多個DispatcherServlet(或其他servlet)實例之間共享,每個實例都有自己的子WebApplicationContext配置:(注:如下圖為從官網截圖內容)

 

2、applicationContext.xml

作用:這里的名字就是上面黃色底色標注出的xml文件的路徑,這個WebApplicationContext具有指向ServletContext及其關聯的Servlet的鏈接;

內容:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <beans xmlns="http://www.springframework.org/schema/beans"
 4 
 5  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 6 
 7  xmlns:context="http://www.springframework.org/schema/context"
 8 
 9  xmlns:mvc="http://www.springframework.org/schema/mvc"
10 
11  xsi:schemaLocation="http://www.springframework.org/schema/beans 12 
13  http://www.springframework.org/schema/beans/spring-beans.xsd 14 
15  http://www.springframework.org/schema/context 16 
17  http://www.springframework.org/schema/context/spring-context.xsd 18 
19  http://www.springframework.org/schema/mvc 20 
21  http://www.springframework.org/schema/cache/spring-mvc.xsd">
22 
23 
24 
25     <context:component-scan base-package="cn.lx.controller" />
26 
27     <mvc:annotation-driven />
28 
29 
30 
31     <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
32 
33         <property name="prefix" value="/WEB-INF/"/>
34 
35         <property name="suffix" value=".jsp"/>
36 
37     </bean>
38 
39 </beans>
備注:其中<context:component-scan base-package="cn.lx.controller" />
    <mvc:annotation-driven />以及下面的bean都是自己添加的
其中,context添加之后,上面的beans中的xmlns和xsi中都會添加上對應的項,mvc的也一樣;但是IDEA在自動補齊mvc的內容時會出現cache字樣,如下所示,導致出現bug,具體問題及bug解決方案在(三)中

 

3、dispatcher-servlet.xml:

作用:dispatcher-servlet.xml與applicationContext.xml是孩子與父親的上下文的關系,在applicationContext.xml中可以定義全局的Spring的特性,dispatcher-servlet.xml就是在Context Hierarchy中定義的子WebapplicationContext.xml的內容,在其中具體定義屬於當前Servlet的處理分發邏輯等

 

三、xml配置問題解決 && 模塊功能實現

在applicationContext.xml中添加<mvc:annotation-driven>出現了問題,一共兩個問題:

第一次是:輸入<mvc:annotation-driven/>的時候,IDEA會自動生成xmlns:mvc=”http://www.spingframework.org/schema/cache”,下面的xsi:schemaLocation=的內容也會增加:http://www.spingframework.org/schema/cache   http://www.spingframework.org/schema/cache/spring-cache.xsd

在自動生成這樣之后,運行的時候會出現錯誤提示:

21-Feb-2019 14:50:30.345 嚴重 [RMI TCP Connection(3)-127.0.0.1] org.springframework.web.context.ContextLoader.initWebApplicationContext Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.cache.interceptor.CacheInterceptor#0': Cannot resolve reference to bean 'cacheManager' while setting bean property 'cacheManager'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cacheManager' available at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1537) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1284) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4668) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5136) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:713) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:695) at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1729) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) [2019-02-21 02:50:30,383] Artifact demo:war exploded: Error during artifact deployment. See server log for details. at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:289) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:457) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:406) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:289) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468) at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:324) at sun.rmi.transport.Transport$1.run(Transport.java:200) at sun.rmi.transport.Transport$1.run(Transport.java:197) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:196) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cacheManager' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1213) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351) ... 60 more

以上錯誤中的cacheManager,我並沒有用到,但是很奇怪,為什么會拋出這個錯誤,搜索全局找跟cache相關的內容,發現在xml文件中出現了xmlns和schemaLocation中有cache的內容出現,基於此繼續追查(后面會補一篇xml解析和schema的內容),發現可能是這里配置的問題,而且因為實際上還沒有走到具體邏輯中,是在啟動過程中就已經拋出錯誤,出現cache的xmlns的內容如下:xmlns:mvc=http://www.springframework.org/schema/cache

然后找到這個mvc是在下面定義的:<mvc:annotation-driven />相匹配,重新輸入內容自動聯想發現:紅色框線內基本都是annotation-driven,只是來源不同,默認點擊enter會自動選擇cache的路徑,導致出現這個錯誤

接下來,對這個異常進行初步分析的過程(這里不包含CacheManager運行原理和源碼解析,后面會有一篇文章進行介紹),查官網資料,https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/integration.html#cache-plug

8.5章節中有如下內容描述:

The cache abstraction provides several storage integration options. To use them, you need to declare an appropriate CacheManager (an entity that controls and manages Cache instances and that can be used to retrieve these for storage).

之后官網詳細的基於不同方式的cache需要配置的xml內容做了demo樣例,也查詢了一些其他文檔,本地添加bean的聲明之后,異常消失:

 

至此,這個基於自動補齊的<annotation-driven>的問題解決,但實際上,我需要的是:mvc的namespace和對應的xsd,修改程序將:namespace和schemaLocations中的cache都改成mvc:

 

在applicationContext.xml中繼續添加bean配置:

<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
    <property name="prefix" value="/WEB-INF/"/>
    <property name="suffix" value=".jsp"/>
</bean>
在src下建包名/類,testController.java的實現,如下:
@Controller public class TestController { @RequestMapping("/test.form") public void execute(){ return ; } }

 

test.jsp的內容如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>

<head>

    <title>test</title>

</head>

<body> Hello Spring MVC Test </body>

</html>
 
        
四、運行
點擊run之后會提示進行Edit Configurations,進入頁面,將相應內容填入(需要啟動TomcatServer並設置路徑)

設置Demployment:

 

之后點擊run按鈕,運行提示ClassNotFound:

嚴重 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.StandardContext.listenerStart Error configuring application listener of class [org.springframework.web.context.ContextLoaderListener] java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1363) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1186) at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:540) at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:521) at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:150) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4590)
 
        
但工程的lib目錄下的jar都引入了,那就是Tomcat運行的時候加載不到這個jar包的原因,通過File-Project Structure打開進入到工程設置頁面,如下圖所示,將右側點擊之后選擇Put into output Root,

 之后查看左側output root的按鈕,可以看到:WEB-INF下有SpringMVC的jar包:

以上問題都解決以后,就能夠運行成功整個項目了~
備注:在運行過程中,下方窗口中出現運行日志會有中文亂碼的情況:可以參考該篇文章:https://blog.csdn.net/qq_41264674/article/details/80945140


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM