1 環境版本說明
Jdk : 1.8
Maven : 3.5
IDEA : 專業版 2017.2
2 環境准備
2.1 Maven安裝及其配置
2.2 Tomcat安裝及其配置
3 詳細步驟
3.1 根據模板創建maven工程
file -> new -> project -> maven -> webapp
技巧01:根據模板創建web工程時,請選擇 maven-archetype-webapp
3.2 目錄結構調整
項目創建成功后的目錄結構如下:
跳坑01:新創建的項目中沒有存放源文件的java文件夾,也沒有存放測試文件的test文件夾,同樣沒有存放資源文件的resources文件夾
跳坑01:在main目錄下新建java、resources兩個文件夾,分別用來存放源文件和資源文件;在main的同級目錄中新建test目錄用來存放測試文件夾
技巧01:雖然我們創建了相關的文件夾,但是IDEA並不知道java文件夾是用來存放源文件,test用來存放測試文件,resources用來存放資源文件的;我們必須進行手動配置:
說明:是在main的統計目錄中創建一個文件夾名為test,再在test中創建一個java文件夾,並將這個java文件夾指定為存放測試文件的包(本博文是之間將test文件夾指定成了存放測試文件的地方)
file -> project structure -> modules
設置完后整個目錄結構如下:
3.3 配置tomcat
3.3.1 打開啟動配置頁面
3.3.2 添加tomcat啟動項
3.3.3 配置tomcat基本信息
3.3.4 添加web模塊
技巧01:為項目添加一個web模塊,file -> project structure -> module
跳坑01:利用IDEA創建項目時會在main目錄下創建一個webapp文件夾,該文件夾里面的內容就是需要被部署到tomcat容器的內容,但是我們為項目添加了web模塊后會自動在項目的根目錄下生成一個web文件夾【建議將這個web文件夾刪掉】,這個文件夾的作用和main目錄下的webapp文件夾的作用相同,而且添加web模塊時自動尋找的是新創建的web文件夾下面的web.xml文件;將web.xml改成webapp下面的web.xml,並將web的源文件文件夾改成webapp,修改后的效果如下:
3.3.5 添加artifacts
技巧01:添加一個web應用,這個web引用來源於modules【其實就是來源於我們創建的web工程】
3.3.6 配置發布頁面
將 artifacts 中配置為web應用添加到tomcat配置中的deployment
3.3.7 配置開發熱部署
就是修改前后台代碼后不用重啟tomcat,IDEA會自動進行【修改后台時自動重啟tomcat服務器,修改前台時刷新瀏覽器就可以啦】
3.3.8 啟動測試
直接通過IDEA啟動tomcat就可以啦
技巧01:應用啟動成功后,會自動訪問webapp里面的index.jsp頁面
4 添加框架支持
我們創建的Web應用知識一個架子,不過IDEA支持自動添加框架;這樣就不需要手動在pom.xml中添加相關框架的依賴配置了
右鍵項目 -> add framework stupport
技巧01:本博文主要添加spring框架的支持
技巧02:點擊確認后會自動將spring框架的依賴包下載到項目中去【PS: 是直接將依賴下載到項目中的lib目錄下】,整個過程有點花時間
跳坑01:如果下載依賴期間由於網絡原因失敗,這時候就需要重新添加框架;但是這時候發現已經沒有spring相關的選項了
填坑01:這是后就需要進入到項目結構中的modules配置中,將spring相關的模塊刪除,在重新進行框架添加
技巧03:添加完spring框架支持后會在webapp文件夾下自動生成相關的配置文件,並在webapp中的web.xml中對這些配置文件記性監聽配置
5 Bean相關
Bean相關的詳細內容請參見《精通spring4.x企業應用開發實戰》
5.1 配置bean
5.1.1 准備
在pom.xml文件中引入lombok依賴
創建Student類和Teacher類

package domain; import lombok.Data; /** * @author 王楊帥 * @create 2018-08-10 20:43 * @desc 學生實體類 **/ @Data public class Student { private String id; private String name; private Integer age; private String address; public void info() { System.out.println("我是學生,我在學習控制反轉相關知識點。"); } }

package domain; /** * @author 王楊帥 * @create 2018-08-10 20:45 * @desc 老師實體類 **/ public class Teacher { private String id; private String name; private Integer age; private String address; public void info() { System.out.println("我是老師,我在教授IOC相關知識點。"); } }
5.1.2 利用xml配置
技巧01:需要將配置文件放到resources文件夾下【之前通過添加spring框架支持時產生的配置文件位於webapp下面,移動后需要更改web.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="student" class="domain.Student"></bean> </beans>
5.1.3 利用類注解配置

package core.config; import domain.Teacher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 王楊帥 * @create 2018-08-10 20:59 * @desc bean配置類 **/ @Configuration public class Beans { @Bean(value = "teacher") public Teacher buildTeacher() { return new Teacher(); } }
5.2 獲取bean
5.2.1 利用BeanFactory獲取

/** * 利用BeanFactory獲取bean * @throws IOException */ @Test public void test01() throws IOException { System.out.println("Hello Boy"); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource resource = resolver.getResource("classpath:applicationContext.xml"); System.out.println(resource.getURL()); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(resource); System.out.println("初始化BeanFactory完畢"); Student student = factory.getBean("student", Student.class); System.out.println("student bean 獲取成功"); student.info(); }
5.2.2. 利用ApplicationContext獲取
技巧01:利用ApplicationContext獲取xml配置的bean和配置類配置的bean需要用不同的實現類

/** * 利用ApplicationContext獲取bean */ @Test public void test02() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Student student = applicationContext.getBean("student", Student.class); student.info(); } /** * 利用ApplicationContext獲取配置類配置的bean */ @Test public void test03() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Beans.class); Teacher teacher = applicationContext.getBean("teacher", Teacher.class); teacher.info(); }
5.2.3 獲取bean代碼匯總

package domain; import core.config.Beans; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; /** * @author 王楊帥 * @create 2018-08-10 20:47 * @desc 測試類 **/ public class TestDemo { @Before public void init() { System.out.println("初始化方法"); } /** * 利用BeanFactory獲取bean * @throws IOException */ @Test public void test01() throws IOException { System.out.println("Hello Boy"); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource resource = resolver.getResource("classpath:applicationContext.xml"); System.out.println(resource.getURL()); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(resource); System.out.println("初始化BeanFactory完畢"); Student student = factory.getBean("student", Student.class); System.out.println("student bean 獲取成功"); student.info(); } /** * 利用ApplicationContext獲取bean */ @Test public void test02() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Student student = applicationContext.getBean("student", Student.class); student.info(); } /** * 利用ApplicationContext獲取配置類配置的bean */ @Test public void test03() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Beans.class); Teacher teacher = applicationContext.getBean("teacher", Teacher.class); teacher.info(); } }
6 web.xml配置
6.1 當前項目出現的問題
由於我們在5.1.2的時候將bean相關的配置文件都移動到了resources目錄下,但是web.xml中還沒有做對應的修改;默認web.xml的配置文件是放在WEB-INF下面的,默認的web.xml配置文件信息如下
我們將配置文件移動到resources目錄下后,在不更改web.xml配置文件的情況下啟動taomcat運行項目的報錯信息如下(報錯原因就是web.xml的配置中還是在WEB-INF下面去尋找配置文件,但是我們已經將配置文件移動到了resources目錄下,所以會報IO異常):
6.2 修改web.xml中的配置文件路徑
技巧01:如果在web.xml中不寫任何參數配置信息,默認的路徑是"/WEB-INF/applicationContext.xml, 在WEB-INF目錄下創建的xml文件的名稱必須是applicationContext.xml
技巧02:可以同時配置多個配置文件路徑信息,它們之間用逗號隔開
6.3 再次啟動的效果
啟動結果:修改完web.xml中的配置文件路徑后,再次啟動容器時,雖然可以正常啟動,但是在啟動時會報一個錯誤,錯誤信息如下:
報錯原因:使用springMVC時需要配置DispatcherServlet,而 DispatcherServlet 需要一個配置文件,該配置文件的默認值時WEB-INF下面的dispatcher-servlet.xml,我們已經將其移動到了resouces目錄下,所以會報錯。
解決辦法:在配置DispatcherServlet 時利用 <init-param> 重新指定默認配置文件的位置【PS: 隨便指定一個即可,本案例指定的是一個空的配置文件dispatcher-servlet.xml】
6.4 web.xml配置詳情

<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <!-- 在Spring框架中是如何解決從頁面傳來的字符串的編碼問題的呢? 下面我們來看看Spring框架給我們提供過濾器CharacterEncodingFilter 這個過濾器就是針對於每次瀏覽器請求進行過濾的,然后再其之上添加了父類沒有的功能即處理字符編碼。 其中encoding用來設置編碼格式,forceEncoding用來設置是否理會 request.getCharacterEncoding()方法,設置為true則強制覆蓋之前的編碼格式。--> <filter> <filter-name>characterEncodingFilter</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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 項目中使用Spring 時,applicationContext.xml配置文件中並沒有BeanFactory,要想在業務層中的class 文件中直接引用Spring容器管理的bean可通過以下方式--> <!--1、在web.xml配置監聽器ContextLoaderListener--> <!--ContextLoaderListener的作用就是啟動Web容器時,自動裝配ApplicationContext的配置信息。因為它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啟動容器時,就會默認執行它實現的方法。 在ContextLoaderListener中關聯了ContextLoader這個類,所以整個加載配置過程由ContextLoader來完成。 它的API說明 第一段說明ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet生成。 如果查看ContextLoaderServlet的API,可以看到它也關聯了ContextLoader這個類而且它實現了HttpServlet這個接口 第二段,ContextLoader創建的是 XmlWebApplicationContext這樣一個類,它實現的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext-> BeanFactory這樣一來spring中的所有bean都由這個類來創建 IUploaddatafileManager uploadmanager = (IUploaddatafileManager) ContextLoaderListener.getCurrentWebApplicationContext().getBean("uploadManager"); --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--2、部署applicationContext的xml文件--> <!--如果在web.xml中不寫任何參數配置信息,默認的路徑是"/WEB-INF/applicationContext.xml, 在WEB-INF目錄下創建的xml文件的名稱必須是applicationContext.xml。 如果是要自定義文件名可以在web.xml里加入contextConfigLocation這個context參數: 在<param-value> </param-value>里指定相應的xml文件名,如果有多個xml文件,可以寫在一起並以“,”號分隔。 也可以這樣applicationContext-*.xml采用通配符,比如這那個目錄下有applicationContext-ibatis-base.xml, applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都會一同被載入。 在ContextLoaderListener中關聯了ContextLoader這個類,所以整個加載配置過程由ContextLoader來完成。--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext.xml</param-value> </context-param> <!--如果你的DispatcherServlet攔截"/",為了實現REST風格,攔截了所有的請求,那么同時對*.js,*.jpg等靜態文件的訪問也就被攔截了。--> <!--方案一:激活Tomcat的defaultServlet來處理靜態文件--> <!--要寫在DispatcherServlet的前面, 讓 defaultServlet先攔截請求,這樣請求就不會進入Spring了,我想性能是最好的吧。--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.swf</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.gif</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.png</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.xml</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.json</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.map</url-pattern> </servlet-mapping> <!--使用Spring MVC,配置DispatcherServlet是第一步。DispatcherServlet是一個Servlet,,所以可以配置多個DispatcherServlet--> <!--DispatcherServlet是前置控制器,配置在web.xml文件中的。攔截匹配的請求,Servlet攔截匹配規則要自已定義,把攔截下來的請求,依據某某規則分發到目標Controller(我們寫的Action)來處理。--> <servlet> <servlet-name>DispatcherServlet</servlet-name><!--在DispatcherServlet的初始化過程中,框架會在web應用的 WEB-INF文件夾下尋找名為[servlet-name]-servlet.xml 的配置文件,生成文件中定義的bean。--> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--指明了配置文件的文件名,不使用默認配置文件名,而使用dispatcher-servlet.xml配置文件。--> <init-param> <param-name>contextConfigLocation</param-name> <!--其中<param-value>**.xml</param-value> 這里可以使用多種寫法--> <!--1、不寫,使用默認值:/WEB-INF/<servlet-name>-servlet.xml--> <!--2、<param-value>/WEB-INF/classes/dispatcher-servlet.xml</param-value>--> <!--3、<param-value>classpath*:dispatcher-servlet.xml</param-value>--> <!--4、多個值用逗號分隔--> <param-value>classpath:spring/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup><!--是啟動順序,讓這個Servlet隨Servletp容器一起啟動。--> </servlet> <servlet-mapping> <!--這個Servlet的名字是dispatcher,可以有多個DispatcherServlet,是通過名字來區分的。每一個DispatcherServlet有自己的WebApplicationContext上下文對象。同時保存的ServletContext中和Request對象中.--> <!--ApplicationContext是Spring的核心,Context我們通常解釋為上下文環境,我想用“容器”來表述它更容易理解一些,ApplicationContext則是“應用的容器”了:P,Spring把Bean放在這個容器中,在需要的時候,用getBean方法取出--> <servlet-name>DispatcherServlet</servlet-name> <!--Servlet攔截匹配規則可以自已定義,當映射為@RequestMapping("/user/add")時,為例,攔截哪種URL合適?--> <!--1、攔截*.do、*.htm, 例如:/user/add.do,這是最傳統的方式,最簡單也最實用。不會導致靜態文件(jpg,js,css)被攔截。--> <!--2、攔截/,例如:/user/add,可以實現現在很流行的REST風格。很多互聯網類型的應用很喜歡這種風格的URL。弊端:會導致靜態文件(jpg,js,css)被攔截后不能正常顯示。 --> <url-pattern>/</url-pattern> <!--會攔截URL中帶“/”的請求。--> </servlet-mapping> <welcome-file-list><!--指定歡迎頁面--> <welcome-file>login.html</welcome-file> </welcome-file-list> <error-page> <!--當系統出現404錯誤,跳轉到頁面nopage.html--> <error-code>404</error-code> <location>/nopage.html</location> </error-page> <error-page> <!--當系統出現java.lang.NullPointerException,跳轉到頁面error.html--> <exception-type>java.lang.NullPointerException</exception-type> <location>/error.html</location> </error-page> <session-config><!--會話超時配置,單位分鍾--> <session-timeout>360</session-timeout> </session-config> </web-app>
7 利用注解配置Bean
利用XML或者java配置類來配置Bean都比較麻煩,從spring2.0開始就支持利用注解來配置Bean,常用的注解如下(詳情參見《精通Spring4.x企業應用開發實戰》P155):
@Repository
@Service
@Controller
@Component
7.1 注解配置Bean實戰
7.1.1 創建一個實例
技巧01:在該注解上添加@Component注解
技巧02:通過注解配置Bean時默認的Bean名稱是對應類的類名首字母小寫后的結果,當然也可以通過注解的value屬性進行指定

package domain; import lombok.Data; import org.springframework.stereotype.Component; /** * @author 王楊帥 * @create 2018-08-11 15:46 * @desc **/ @Data @Component public class Dog { private String id; private String name; public void info() { System.out.println("我是哮天犬"); } }
7.1.2 配置Bean配置注解掃描
技巧01:在配置文件中添加掃描類包來應用注解定義的Bean
技巧02:配置前掃描包前需要在配置文件中先進行命名空間的聲明(詳情參見《精通Spring4.x企業應用開發實戰》P117)
7.1.3 測試一下

@Test public void test01() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Dog dog = applicationContext.getBean("dog", Dog.class); dog.info(); }
跳坑01:直接利用@Autowired進行依賴注入配置好的Bean是總是失敗,錯誤信息如下
填坑01:參考博文
8 自動裝配Bean
傳統的注入方式有:構造器注入、set注入(屬性注入)、工廠方法注入(詳情參見《精通Spring4.x企業應用開發實戰》P121)
實現依賴注入的注解有(詳情參見《精通Spring4.x企業應用開發實戰》P157):
@Autowired -> 根據類型注入【推薦使用】
@Resource -> 根據Bean名稱注入
@Inject -> 根據類型注入
9 MVC配置
前后端分離的項目,后台根據不同的URL調用不同的類及其方法進行邏輯操作,操作完畢后后台需要向前台返回JSON的數據。
9.1 配置步驟
9.1.1 修改web.xml中DispatcherServlet配置
技巧01:DispacherServlet是用來攔截請求的,前后端分離項目中DispacherServlet會將攔截到的請求url分發到對應的類進行邏輯處理
技巧02:默認的DispacherServlet配置只是攔截 .form 結尾的請求url,本案例修改為攔截請求url中帶 / 的所有請求
9.1.2 利用注解編寫控制層
技巧01:控制層就是處理DispatcherServlet攔截到的請求url的類【就是進行邏輯處理的入口】
技巧02:lombok的日志使用logback實現的,所以需要導入logback依賴

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>

package cn.xiangxu.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author 王楊帥 * @create 2018-08-11 16:22 * @desc **/ @RestController @RequestMapping(value = "/test") @Slf4j public class TestConroller { @GetMapping public String test01() { String result = "前后台連接測試"; log.info(result); return result; } }
9.1.3 開啟MVC注解支持
10 本博文參考源代碼
11 參考博文