軟件的總體架構有B/S(瀏覽器/服務器模式)和C/S(客戶端/服務器模式),ee開發主要就是B/S模式,從代碼開發的角度,代碼有層的概念.html
經典三層: web表現層(view+controller) +service業務層+dao(數據接入訪問層)前端
表現層(Web層)
整個表現層負責接收客戶端瀏覽器的請求並響應結果給客戶端瀏覽器顯示。(Http請求)java
具體說來,表現層=View視圖層+Controller控制層。Controller層負責接收請求、轉發請求給Service層、跳轉視圖頁面,servlet-->Struts(過濾器)-->SpringMVC程序員
業務層(Service層)
負責業務邏輯處理,和項目需求息息相關(好比轉帳業務)。web
Spring-->SpringBoot(全註解)ajax
主要涉及邏輯:異常處理參數處理聲明式事務AOPspring
持久層(Dao層)
和數據庫交互,對數據表進行增刪改查
JDBC-->JdbcTemplate --> DButils -->MyBatis->Spring Data JPA -->MyBatis Plus數據庫
主流:SSM-->潮流: Spring全家桶apache
SpringMVC是一個輕量級的eb表現層框架,用來寫Controller接收請求跳轉頁面的,它是Spring框架的一部分。SpringMVC是對Servlet的封裝和加強,簡化了servlet的操做。它已經超越了Struts,成爲目前最優秀的表現層框架。json
以前: request請求到servlet,一個項目中有不少servlet,不一樣serlvet處理不一樣的事情,比如不少年前裝修,業主須要直接抱需求告知水工、電工、木工等。如今咱們直接把需求告知包工頭,包工頭具體分發任務給下面的小弟(水工、電工、木工),咱們不須要直接和其餘人交涉。
前端控制器就相似於上面的包工頭,不幹具體的活,只負責接收請求,分發請求,反饋結果。
SpringMVC全局只須要一個servlet。
瀏覽器輸入url發起請求,該url請求被SpringMVC框架攔截處理,把後臺服務器的當前時間輸出到jsp頁面顯示。
目錄
maven jar包
<dependencies> <!--spring核心包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.8.RELEASE</version> </dependency> <!--springMVC的jar包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.8.RELEASE</version> </dependency> <!--Servlet--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--jsp--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> <!-- provided的做用是:當項目打成war包時,當前的jar包不會壓縮在當前的war包裏 只在當前代碼的編寫和編譯過程當中產生依賴的做用, 當程序部署在Tomcat中的工程在war包壓縮包中,經過加上provided否則jar包壓縮在war包中 運行的時候,用Tomcat自身帶的jar包 --> <scope>provided</scope> </dependency> </dependencies> <!-- 運行方式有兩種,一種是tomcat插件,而後在maven中找到對應的文件 打開tomcatjar包,右鍵run 另外一種tomcat運行 配置Tomcat插件 --> <!-- <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>9090</port> <path>/</path> </configuration> </plugin> </plugins> </build> -->
首頁
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首頁</title> </head> <body> SpringMVC框架的helloWorld </body> </html>
controller層也就是servelt
/** * 控制器(理解爲 至關於WEB階段的Servlet) * @author Lucky */ @Controller public class DefaultController { /** * 定義方法,至關於之前 Servlet 中 用於處理請求的方法 */ @RequestMapping("gotoResult") public ModelAndView gotoResult(ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()); // 指定頁面 modelAndView.setViewName("WEB-INF/jsp/result.jsp"); return modelAndView; } }
配置spring.xml 開啓註解掃描controller層的註解
<!-- 開啓SpringIOC註解掃描 --> <context:component-scan base-package="com.zhuxu.controller"></context:component-scan>
配置SpringMvc框架的前端控制器
<!-- 配置SpringMvc框架的前端控制器 --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 加載SpringMVC的配置文件 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 讓dispatcherServlet對象隨着Tomcat的啓動而建立 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
結果頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>結果頁面</title> </head> <body> ${nowDate} </body> </html>
爲何咱們寫了 @RequestMapping
就能夠找到相應的類或者方法呢?
爲何傳了參數就能夠自動進行封裝呢?
其實都依賴於 SpringMVC 的處理器映射器、處理器適配器、視圖解析器這三大組件來完成
總體流程描述:
url-pattern
會過濾出哪些請求能夠訪問、哪些不能訪問。而且會加載 springmvc.xml 配置文件。map<url,handler>
這樣的方式來存儲。dispatcherServlet 是整個流程的控制中心,由它調用其它組件處理用戶的請求。
dispatcherServlet 的存在下降了組件之間的耦合性。
HandlerMapping 負責根據用戶請求找到 Handler 即處理器
dispatcherServlet 接收到請求路徑以後,找 HandlerMapping ,根據請求路徑映射找到相應的方法或者類
SpringMVC 提供了不一樣的映射器實現不一樣的映射方式,例如:配置文件方式,實現接口方式,註解方式等。
它就是咱們開發中要編寫的具體業務控制器。
由 DispatcherServlet 把用戶請求轉發到 Handler。由 Handler 對具體的用戶請求進行處理。
經過 HandlerAdapter 對處理器進行執行,這是適配器模式的應用,經過擴展適配器能夠對更多類型的處理器進行執行。
ViewResolver 負責將處理結果生成 View 視圖。
ViewResolver 首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成 View 視圖對象,最後對 View 進行渲染將處理結果經過頁面展現給用戶。
SpringMVC 框架提供了不少的 View 視圖類型的支持,包括:jstlView、freemarkerView、pdfView 等。
咱們最經常使用的視圖就是 jsp,通常狀況下須要經過頁面標籤或頁面模版技術,將模型數據經過頁面展現給用戶,須要由程序員根據業務需求開發具體的頁面。
其實 springmvc 中的各個組件都是內置的,不用配置就能夠
ModelAndView 中設置視圖時,每次都要寫前綴和後綴,能夠不寫嗎?能夠,定製視圖解析器便可
在 springmvc.xml 中定製
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前綴 --> <property name="prefix" value="/WEB-INF/"/> <!-- 後綴 --> <property name="suffix" value=".jsp"/> </bean>
在 SpringMVC 的各個組件中,處理器映射器、處理器適配器、視圖解析器稱爲 SpringMVC 的三大組件。
使用 <mvc:annotation-driven>
會自動加載
可用在 SpringMVC.xml 配置文件中使用 <mvc:annotation-driven>
替代註解處理器映射器和適配器的配置。
它就至關於在 xml 中配置了:
<!-- HandlerMapping --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!-- HandlerAdapter --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!-- HadnlerExceptionResolvers --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean> <bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
注意: 通常開發中,咱們都須要寫上此標籤(雖然從入門案例中看,咱們不寫也行,隨着課程的深刻,該標籤還有具體的使用場景)
明確: 咱們只須要編寫處理具體業務的控制器以及視圖。
<mvc:annotation-driven />註解意義:提供 Controller請求轉發,json自動轉換等功能
<mvc:annotation-driven /> 是一種簡寫形式,徹底能夠手動配置替代這種簡寫形式,簡寫形式可讓初學都快速應用默認配置方案。配置一些 messageconverter。即解決了 @Controller 註解的使用前提配置 <context:annotation-config /> 是對包進行掃描,實現註釋驅動 Bean 定義,同時將 bean 自動注入容器中使用。即解決了 @Controller 標識的類的 bean 的注入和使用。
<mvc:annotation-driven /> 會自動註冊 RequestMappingHandlerMapping 與 RequestMappingHandlerAdapter 兩個 Bean,這是 Spring MVC 爲 @Controller 分發請求所必需的,而且提供了數據綁定支持,@NumberFormatannotation 支持,@DateTimeFormat 支持,@Valid 支持讀寫 XML 的支持(JAXB)和讀寫 JSON 的支持(默認Jackson)等功能。
咱們處理響應 ajax 請求時,就使用到了對 json 的支持。
對 action 寫 JUnit 單元測試時,要從 spring IOC 容器中取 DefaultAnnotationHandlerMapping 與 AnnotationMethodHandlerAdapter 兩個 bean,來完成測試,取的時候要知道是 <mvc:annotation-driven /> 這一句註冊的這兩個 bean。
多個URL路徑映射到同一個Handler(同一個方法)
Handler處理器
@RequestMapping註解用於映射請求與處理器
註解屬性value,能夠配置多個url
// 用法1:多個url路徑映射到同一個Handler(同一個方法) @RequestMapping(value = {"gotoResultURL","gotoResultURL2"}) public ModelAndView gotoResultURL(ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()+"========gotoResultURL"); // 指定頁面 modelAndView.setViewName("result"); return modelAndView;
@RequestMapping 註解做用在類上,實現對請求路徑的分類管理,限定類中方法訪問的前綴
@RequestMapping("default") public class DefaultController{}
<fieldset> <p>01_MVC入門測試用例</p> <a href = "${pageContext.request.contextPath}/default/gotoResultURL2.do">測試</a> </fieldset>
method屬性限定請求方法,請求的handler相同,請求方式不一樣進入不一樣方法處理
method屬性限定請求方法,請求的handler相同,請求方式不一樣進入不一樣方法處理,訪問的url是同樣的(handler名字是同樣的),可是根據不一樣的請求方式(get/post)進入不一樣的方法處理,請求的url同樣,可是請求方式不同(get/post)
/** * url相同,可是請求方式爲GET * @RequestMapping註解屬性method */ @RequestMapping(value = "gotoResultMethod",method = RequestMethod.GET) public ModelAndView gotoResultMethodGet(ModelAndView modelAndView){ modelAndView.addObject( "nowDate",new Date()+"Method=GET"); modelAndView.setViewName( "index" ); return modelAndView; /** * url相同,可是請求方式爲POST * @RequestMapping註解屬性method */ @RequestMapping(value = "gotoResultMethod" ,method = RequestMethod.POST) public ModelAndView gotoResultMethodPost(ModelAndView modelAndView){ modelAndView.addobject( "nowDate",new Date()+"Method=POST"); modelAndView.setViewName( "index" ); return modelAndView; }
params屬性限定請求參數:支持簡單的表達式語法,url同樣,根據攜帶參數的不一樣進入不一樣的方法處理
params屬性限定請求參數,支持簡單的表達式語法,url同樣,根據攜帶參數的不一樣進入不一樣的方法處理,url相同,請求方式相同,請求參數不一樣進入不一樣hanIder方法處理
<fieldset> <h4>用法4 params屬性限定請求參數︰支持簡單的表達式語法,url同樣,根據攜帶參數的不一樣進入不一樣的方法處理</h4> <a href="http://1ocalhost:8080/user/login. do?type=user">普通用戶</a> <a href="http://localhost:8080/user/login. do?type=admin">管理員</a> <a href="http://localhost:8080/user/login. do?type=vip">VIP</a> </fieldset> url相同,請求方式相同,請求參數不一樣 @RequestMapping註解屬性params id:表示請求必須包含名爲id的請求參數 演示:http://localhost:9090/user/gotoResultMethod.action?id=123 !id:表示請求不能包含名爲id的請求參數 演示: http://localhost:9090/user/gotoResultMethod.action?id=123 idl=100: 表示請求包含名爲param1的請求參數,但其值不能爲100 演示: http://localhost:9090/user/gotoResultMethod.action?id=1123213 id!=100」,"name」}:請求必須包含名爲id和name的兩個請求參數, 演示: http://localhost:9090/user/gotoResultMethod.action?id=112&name=zhang3
SpringMVC在方法中直接聲明HttpServletRequest,HttpServletResponse,HttpSession便可使用
控制器
@Controller @RequestMapping("params") public class DefaultController { // 功能一:默認支持ServletAPI @RequestMapping("gotoParams") public ModelAndView gotoResultURL(HttpServletRequest request, HttpServletResponse response, HttpSession session,ModelAndView modelAndView){ // 獲取請求參數 String id = request.getParameter("id"); String name = request.getParameter("name"); // 封裝數據 modelAndView.addObject("nowDate",new Date()+"==="+id+"===="+name); // 指定頁面 modelAndView.setViewName("result"); return modelAndView; } }
請求參數
<body> <h3>請求參數綁定</h3> <fieldset> <h4>功能一:默認支持ServletAPI</h4> <a href="${pageContext.request.contextPath}/params/gotoParams.do?id=123&name=list">測試路徑2</a> </fieldset> </body>
/** * 綁定基本數據類型參數 * 參數的名字,和請求參數的鍵相同 */ //功能2:綁定簡單數據類型 //http://localhost:9090/param/sendParamsBase.action?isVip=1 @RequestMapping(i"sendParamsBase"]) public ModelAndView sendParamsBase(Boolean isVip,ModelAndView modelAndView){ modelAndView.addobject("nowDate",new Date()+"===="+ isVip); modelAndView.setViewName("Result"); return mode1AndView; } // 功能二:綁定簡單數據類型 @RequestMapping("gotoParamsBase") public ModelAndView gotoParamsBase( Integer id,ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()+"==="+id); // 指定頁面 modelAndView.setViewName("result"); return modelAndView; }
jsp頁面
<fieldset> <h4>功能二:綁定簡單數據類型</h4> <a href="${pageContext.request.contextPath}/params/gotoParamsBase.do?id=123&name=list">測試路徑2</a> </fieldset>
當形參和傳遞的參數名稱不一致時使用RequestParam進行手動映射,相似於MyBatis中requestMap的做用
// 功能三:RequestParam @RequestMapping("gotoParamsParam") public ModelAndView gotoParamsParam(@RequestParam("id") Integer ids, ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()+"==="+ids); // 指定頁面 modelAndView.setViewName("result"); return modelAndView; }
<fieldset> <h4>功能三RequestParam</h4> <a href="${pageContext.request.contextPath}/params/gotoParamsBase.do?id=123">測試路徑2</a> </fieldset>
public class User { private Integer id; private String name; private String sex; } // get set tonstring 省略
// 功能四:綁定pojo @RequestMapping("gotoParamsPojo") public ModelAndView gotoParamsPojo(User user, ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()+"==="+user); // 指定頁面 modelAndView.setViewName("result"); return modelAndView; }
<fieldset> <h4>功能四:綁定pojo對象</h4> <a href="${pageContext.request.contextPath}/params/gotoParamsPojo.do?id=123&name=lisi">測試路徑2</a> </fieldset>
/** * 用於對 頁面提交的表單所對應的實體對象 * * entity---> 網頁中表單提交的數據,所對應的JavaBean對象 * pojo ---> 對應數據庫表的實體類 JavaBean對象 * @author Lucky */ public class QueryVo { private User user; @Override public String toString() { return "QueryVo{}"; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
<fieldset> <h4>功能五:綁定pojo對象的包裝類對象</h4> <a href="${pageContext.request.contextPath}/params/gotoParamsQueryVo.do?user.id=123&user.name=wangyi">測試路徑2</a> </fieldset>
// 功能五:綁定pojo對象的包裝類對象 @RequestMapping("gotoParamsQueryVo") public ModelAndView gotoParamsQueryVo(QueryVo queryVo, ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()+"==="+queryVo); // 指定頁面 modelAndView.setViewName("result"); return modelAndView; }
傳遞綁定集合類型(List/Map),做爲pojo的一個屬性來傳遞
<fieldset> <h4>功能六:綁定集合包裝pojo對象</h4> <form action="${pageContext.request.contextPath}/params/gotoParamsList.do" method="get"> <table> <tr> <th>id</th> <th>name</th> <th>sex</th> </tr> <tr> <td><input type="text" name="userList[0].id" placeholder="請輸入ID"></td> <td><input type="text" name="userList[0].name" placeholder="請輸入姓名"></td> <td><input type="text" name="userList[0].sex" placeholder="請輸入性別"></td> </tr> </table> <input type="submit" value="提交"> </form> </fieldset>
private List<User> userList;
// 功能六:綁定集合包裝pojo對象 @RequestMapping("gotoParamsList") public ModelAndView gotoParamsList(QueryVo queryVo, ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()+"==="+queryVo); // 指定頁面 modelAndView.setViewName("result"); return modelAndView; }
index.jsp
<fieldset> <h4>功能七:綁定Map集合包裝pojo對象</h4> <form action="${pageContext.request.contextPath}/params/gotoParamsList.do" method="get"> <table> <tr> <th>id</th> <th>name</th> <th>sex</th> </tr> <tr> <td><input type="text" name="userMap[user001].id" placeholder="請輸入ID"></td> <td><input type="text" name="userMap[user001].name" placeholder="請輸入姓名"></td> <td><input type="text" name="userMap[user001].sex" placeholder="請輸入性別"></td> </tr> </table> <input type="submit" value="提交"> </form> </fieldset>
ParamsController控制器中的方法
// 功能七:綁定Map集合包裝pojo對象 @RequestMapping("gotoParamsMap") public ModelAndView gotoParamsMap(QueryVo queryVo, ModelAndView modelAndView){ // 封裝數據 modelAndView.addObject("nowDate",new Date()+"==="+queryVo); // 指定頁面 modelAndView.setViewName("result"); return modelAndView; }
前邊的案例中你在輸入框,輸入一下中文試試,會發現控制檯是幾個 ????
隨便寫一個表單
<form action="encodingFilter" method="post"> <input type="text" name="name" /> <input type="submit" value="提交"> </form>
控制器
@RequestMapping(value = "encodingFilter",method = RequestMethod.POST) public String testEncodingFilter(String name){ System.out.println(name); return "success"; }
輸入中文,查看控制檯
在前端控制器 web.xml中寫
<!-- 配置編碼過濾器:過濾post請求 --> <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> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
可是此種方式只能攔截 POST 請求,攔截 GET 請求須要到 Tomcat 中配置
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
改成:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>
若是遇到 ajax 請求仍然亂碼,把: useBodyEncodingForURI="true"
改成 URIEncoding="UTF-8"
便可。
做用: 用於獲取請求消息頭。
屬性:
注: 在實際開發中通常不怎麼用。
使用示例 jsp中代碼:
<!-- RequestHeader註解 --> <a href="springmvc/useRequestHeader">獲取請求消息頭</a>
控制器中代碼:
/** * RequestHeader註解 * @param user * @return */ @RequestMapping("/useRequestHeader") public String useRequestHeader( @RequestHeader(value="Accept-Language", required=false) String requestHeader){ System.out.println(requestHeader); return "success"; }
做用: 用於把指定 cookie 名稱的值傳入控制器方法參數。
屬性:
<!-- CookieValue註解 --> <a href="springmvc/useCookieValue">綁定cookie的值</a>
控制器中的代碼:
/** * Cookie註解註解 * @param user * @return */ @RequestMapping("/useCookieValue") public String useCookieValue( @CookieValue(value="JSESSIONID",required=false) String cookieValue){ System.out.println(cookieValue); return "success"; }