1.什么是mvc?
1.1原始比較初級的設計模式:
1.2 MVC設計模式
2MVC設計模式的優勢與核心在於其能解耦和:
傳統的設計模式相當於是一個串聯的設計,只要其中一個環節出了問題便會使下一環節中止
網上普遍的對於mvc設計模式的解讀為:
2.1.定義:MVC 設計模型是一種使用 Model View Controller( 模型-視圖-控制器)設計創建 Web 應用程序的模式。
由上主謂賓可以很容易看出,mvc模型是一種用來寫web應用程序的樣式,也就是說只能寫web不能寫其它?
2.2 既然使用了 Model View Controller( 模型-視圖-控制器),那么就很有必要來介紹一下該(模型-視圖-控制器)到底是怎樣的一個東西?
Model(模型):是應用程序中用於處理應用程序數據邏輯的部分。
通常模型對象負責在數據庫中存取數據。
通常視圖是依據模型數據創建的。
通常控制器負責從視圖讀取數據,控制用戶輸入,並向模型發送數據。
3 Springmvc和spring?
Springmvc是spring的部分。
4.Springmvc執行流程
根據mvc設計模式:用戶向服務器發送請求,前端控制器(web.xml)接受請求,前端控制器將請求分為如下幾步
1.向處理器映射器(HandlerMapping)請求獲取action類的url,處理器映射器(springmvc.xml)獲取到action類的url后便將帶有攔截器的chian返回給前端控制器
2.向處理器適配器(handlerAdapter)請求執行action,處理器適配器(springmvc.xml)執行action的方法,所以action需要調用業務層的方法,並將返回結果(mode and view)返回給處理器適配器,處理器適配器將得到的結果(mode and view)返回給前端控制器。
3.向視圖解析器(ViewResolver)請求視圖解析,視圖解析器(springmvc.xml)接受到請求后立即解析視圖,並將view返回給前端控制器。
4.前端控制器接收到view后向視圖層(view)發送視圖渲染請求,視圖層渲染完后將jstl返回給前端控制器,
5.最后前端控制器將得到的結果響應返回給用戶。
springmvc中mvc各自的職責
DispatcherServlet是前端控制器設計模式的實現,提供Spring Web MVC的集中訪問點,而且負責職責的分派,而且與Spring IoC容器無縫集成,從而可以獲得Spring的所有好處。
DispatcherServlet主要用作職責調度工作,本身主要用於控制流程,主要職責如下:
1、文件上傳解析,如果請求類型是multipart將通過MultipartResolver進行文件上傳解析;
2、通過HandlerMapping,將請求映射到處理器(返回一個HandlerExecutionChain,它包括一個處理器、多個HandlerInterceptor攔截器);
3、 通過HandlerAdapter支持多種類型的處理器(HandlerExecutionChain中的處理器);
4、通過ViewResolver解析邏輯視圖名到具體視圖實現;
5、本地化解析;
6、渲染具體的視圖等;
7、如果執行過程中遇到異常將交給HandlerExceptionResolver來解析。
視圖層:
視圖是用戶看到並與之交互的界面。對老式的Web應用程序來說,視圖就是由HTML元素組成的界面,在新式的Web應用程序中,HTML依舊在視圖中扮演着重要的角色,但一些新的技術已層出不窮,它們包括Macromedia Flash和像XHTML,XML/XSL,WML等一些標識語言和Web services. 如何處理應用程序的界面變得越來越有挑戰性。MVC一個大的好處是它能為你的應用程序處理很多不同的視圖。在視圖中其實沒有真正的處理發生,不管這些數據是聯機存儲的還是一個雇員列表,作為視圖來講,它只是作為一種輸出數據並允許用戶操縱的方式。
模型層:
模型表示企業數據和業務規則。在MVC的三個部件中,模型擁有最多的處理任務。例如它可能用像EJBs和ColdFusion Components這樣的構件對象來處理數據庫。被模型返回的數據是中立的,就是說模型與數據格式無關,這樣一個模型能為多個視圖提供數據。由於應用於模型的代碼只需寫一次就可以被多個視圖重用,所以減少了代碼的重復性。
mvc設計模式的優點
1、開發人員可以只關注整個結構中的其中某一層;
2、可以很容易的用新的實現來替換原有層次的實現;
3、可以降低層與層之間的依賴;
4、有利於標准化;
5、利於各層邏輯的復用。
spring具體流程回顧及相應代碼
具體流程:
(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)配置HttpRequestHandlerAdapter適配器
<!-- 配置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>
總結:
在面試中問到這個問題后,如果將mvc和springmvc的執行流程和整體結構講述清楚便可以了