SpringMVC 入門


MVC 簡介

1、MVC 是一種架構模式
程序分層,分工合作,既相互獨立,又協同工作,分為三層:模型層、視圖層和控制層

2、MVC 是一種思考方式
View:視圖層,為用戶提供UI,重點關注數據的呈現,為用戶提供界面
Model:模型層,業務數據的信息表示,關注支撐業務的信息構成,通常是多個業務實體的組合
Controller:控制層,調用業務邏輯產生合適的數據(Model),傳遞數據給視圖用於呈現

MVC 設計模式在 B/S 下的應用:
MVC設計模式在B/S下的應用

①:瀏覽器發送請求到控制器(這里要知道控制器的作用)
②:控制器不能處理請求必須交給模型層來處理接着去訪問數據庫
③:模型層將處理好的結果返回給控制層
④:控制層將邏輯視圖響應給瀏覽器(瀏覽器顯示的是渲染過的視圖)

MVC 本質:MVC 的核心思想是業務數據抽取同業務數據呈現相分離;分離有利於程序簡化,方便編程

前端控制器模式

前端控制器模式(Front Controller Pattern)是用來提供一個集中的請求處理機制,所有的請求都將由一個單一的處理程序處理。該處理程序可以做認證/授權/記錄日志,或者跟蹤請求,然后把請求傳給相應的處理程序。

  • 前端控制器(Front Controller)- 處理應用程序所有類型請求的單個處理程序,應用程序可以是基於 web 的應用程序,也可以是基於桌面的應用程序。
  • 調度器(Dispatcher) - 前端控制器可能使用一個調度器對象來調度請求到相應的具體處理程序。
  • 視圖(View) - 視圖是為請求而創建的對象。

前端控制器的主要作用:

  • 指前端控制器將我們的請求分發給我們的控制器去生成業務數據
  • 將生成的業務數據分發給恰當的視圖模版來生成最終的視圖界面

Front Controller(MVC)

SpringMVC 基本概念

SpringMVC 基本概念

對組件說明:
1、DispatherServlet:前端控制器 用戶請求到達前端控制器,相當於 MVC 中的 C,而 DispatherServlet 是整個流程的核心,它來調用其他組件來處理用戶的請求,前端控制器的存在降低了其他組件之間的耦合度。
2、HandlerMapping:處理器映射器 它的作用就好比去看電影要拿着電影票根據電影票上面的座位號找到座位其中座位就是 Handler,電影票以及上面的座位號就是 URL HandlerMapping 負責根據用戶請求找到 Handler 即處理器,SpringMVC 提供了不同的映射器實現不同的映射方式,例如:配置文件方式,實現接口方式,注解方式等。
3、Handler:處理器 Handler 是后端控制器,在前端控制器的控制下后端控制器對具體的用戶請求進行處理,Handler 涉及到具體的用戶業務請求,所以一般情況下需要程序員根據業務需求開發。
4、HandlerAdapter:處理器適配器 通過 HandlerAdapter 對處理器進行執行,這是適配器模式的應用,通過適配器可以對更多類型的處理器進行執行。播放的電影是 3D 的你看不清楚,因此電影院跟你說你要想看清電影就必須戴 3D 眼鏡。也就是說 Handler 滿足一定的要求才可以被執行。
5、ViewResolver:視圖解析器 ViewResolver 負責將處理結果生成 View 視圖,ViewResolver 首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成View視圖對象,最后對View進行渲染將處理結果通過頁面展示給用戶。

SpringMVC 基本概念

工作原理解釋說明:
1、用戶發送請求到 SpringMVC 框架提供的 DispatcherServlet 這個前端控制器(了解 struts2 的朋友也都知道其實 struts2也有一個前端控制器 web.xml 中的 filter 標簽就是)。
2、前端控制器會去找處理器映射器(HandlerMapping),處理器映射器根據請求 url 找到具體的處理器,生成處理器對象及處理器攔截器(如果有則生成)一並返回給 DispatcherServlet 。
3、根據處理器映射器返回的處理器,DispatcherServlet 會找“合適”的處理器適配器(HandlerAdapter)
4、處理器適配器 HandlerAdpater 會去執行處理器(Handler 開發的時候會被叫成 Controller 也叫后端控制器在 struts2 中action 也是一個后端控制器)執行之前會有轉換器、數據綁定、校驗器等等完成上面這些才會去正在執行 Handler
5、后端控制器 Handler 執行完成之后返回一個 ModelAndView 對象 。
6、處理器適配器 HandlerAdpater 會將這個 ModelAndView 返回前端控制器 DispatcherServlet。前端控制器會將ModelAndView 對象交給視圖解析器 ViewResolver。
7、視圖解析器 ViewResolver 解析 ModelAndView 對象之后返回邏輯視圖。
8、前端控制器 DispatcherServlet 對邏輯視圖進行渲染(數據填充)之后返回真正的物理 View 並響應給瀏覽器。

SpringMVC 基本概念

SpringMVC 配置

1、前端控制器需要在 web.xml 中配置

<!-- 配置前端控制器 -->
<servlet>
	<servlet-name>web-dispatcher</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!--加載前端控制器配置文件 上下文配置位置-->
	<init-param>
		<!-- 備注:
            contextConfigLocation:指定 SpringMVC 配置的加載位置,如果不指定則默認加載
            WEB-INF/[DispatcherServlet 的 Servlet 名字]-servlet.xml
         -->
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/spring-*.xml</param-value>
	</init-param>
	<!-- 表示隨WEB服務器啟動 -->
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>web-dispatcher</servlet-name>
	<!-- 備注:可以攔截三種請求
        第一種:攔截固定后綴的url,比如設置為 *.do、*.action, 例如:/user/add.action 此方法最簡單,不會導致靜態資源(jpg,js,css)被攔截
        第二種:攔截所有,設置為/,例如:/user/add  /user/add.action此方法可以實現REST風格的url,
        很多互聯網類型的應用使用這種方式.但是此方法會導致靜態文件(jpg,js,css)被攔截后不能正常顯示.需要特殊處理
        第三種:攔截所有,設置為/*,此設置方法錯誤,因為請求到Action,當action轉到jsp時再次被攔截,提示不能根據jsp路徑mapping成功
    -->
	<!-- 默認匹配所有的請求 -->
	<url-pattern>/</url-pattern>
</servlet-mapping>

2、在 spring/spring-web.xml 配置視圖解析器

<!-- 配置視圖解析器 -->
<!-- InternalResourceViewResolver:支持JSP視圖解析 -->
<!-- viewClass:JstlView 表示JSP模板頁面需要使用JSTL標簽庫,所以classpath中必須包含jstl的相關jar包; -->
<!-- prefix 和 suffix:查找視圖頁面的前綴和后綴,最終視圖的址為: -->
<!-- 前綴+邏輯視圖名+后綴,邏輯視圖名需要在controller中返回ModelAndView指定,比如邏輯視圖名為hello,-->
<!-- 則最終返回的jsp視圖地址 "WEB-INF/jsp/hello.jsp" -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<!-- 決定視圖類型,如果添加了jstl支持(即有jstl.jar),那么默認就是解析為jstl視圖 -->
	<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
	<!-- 視圖前綴 -->
	<property name="prefix" value="/WEB-INF/jsp/" />
	<!-- 視圖后綴 -->
	<property name="suffix" value=".jsp" />
</bean>

3、在 spring/spring-web.xml 配置 注解模式

<!-- 自動加載RequestMappingHandlerMapping和RequestMappingHandlerAdapter, -->
<!-- 可用在xml配置文件中使用<mvc:annotation-driven>替代注解處理器和適配器的配置。 -->
<mvc:annotation-driven/>

4、在 spring/spring-web.xml 配置 掃描web 相關的 bean

<!-- 組件掃描器:可以掃描 @Controller、@Service、@Repository 等等 -->
<context:component-scan base-package="com.controller" />

SpringMVC 中的注解

@Controller

@Controller 注解,用於標識這個類是一個后端控制器(類似struts中的action),主要作用就是接受頁面的參數,轉發頁面。
@Controller 源碼:

@Target({ElementType.TYPE}) // 表明只能定義在類上面
@Retention(RetentionPolicy.RUNTIME) //保留策略是RUNTIME,在JVM加載類時,會把注解加載到JVM內存中(它是唯一可以用反射來讀取注解的策略)
@Documented //@Documented用於描述其它類型的annotation應該被作為被標注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個標記注解,沒有成員。
@Component //spring框架規定當一個類不好歸類(service、dao、controller)的時候可以使用這個注解,由此可見即便好歸類內部還是使用的@Component注解
public @interface Controller {
	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any
	 */
	String value() default "";
}

@RequestMapping

這個注解的作用目標就跟@Controller不一樣了,這個注解可以定義在類上面也可以定義在方法上面。

/**
* 1.@RequestMapping:除了修飾方法,還可以修飾類
* 2.類定義處:提供初步的請求信息映射.相對於WEB應用的根目錄(窄化請求)
* 3.方法處:提供進一步的細分映射信息。相對於類定義處的URL。
*      若類定義處為標注@RequestMapping,則方法出的URL相對於WEB應用的根目錄
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
	String[] value() default {};
	RequestMethod[] method() default {}; //限制請求方式
	String[] params() default {}; //要求請求的URL包含指定的參數
}

代碼實例

@Controller
@RequestMapping("/demo")
public class IndexController {
	@RequestMapping(value = "/test", method = RequestMethod.GET)
	public String index(Model model, HttpServletRequest request) {
		// 在游覽器訪問 http://localhost:8080/demo/test 將進入這里
		model.addAttribute("originURL", "");
		model.addAttribute("controllerName", "index");
		return "index";
	}
}

@RequestMapping 還支持 Ant 方格的請求

?:匹配文件中的一個字符
*:匹配文件中任意字符
**:**匹配多層路徑

/user/*/createUser : 匹配 -/user/aa/createUser 或者 -/user/aa/createUser
/user/**/createUser : 匹配 -/user/aa/createUser 或者 -/user/createUser 或者 -/user/aa/cc/createUser
/user/createUser?? : 匹配 -/user/aa/createUseraa

@PathVariable

@PathVariable 這個注解支持現在當下較為流行的 Restful 風格的 URL。 先說說這個注解的作用,支持將 url 中的占位符參數綁定到目標方法的參數上, 該功能也是 SpringMVC 實現 Restful 風格 url 的重要措施。

代碼實例

// http://localhost:8080/demo/sss
@RequestMapping(value = "/{slug:.+}", method = RequestMethod.GET)
	public String index2(@PathVariable("slug") String slug, Model model) {
	LOG.info("DemoController index2 slug  " + slug);
	// common
	model.addAttribute("originURL", "demo/");
	model.addAttribute("controllerName", "demo");
	model.addAttribute("controllerMethod", "index2");
	model.addAttribute("slug", slug);
	return "demo";
}

//slug = sss

我們熟悉的請求應該是 POST 和 GET 請求,這兩個請求也是最常用的而實際上 HTTP1.1 請求還有 PUT、DELETE 等8種來表名請求的動作。

在 SpringMVC 中要實現 PUT 和 DELETE 請求需要在 web.xml 額外配置一個過濾器,這個過濾器的作用就是把 POST 請求變為 PUT 和 DELETE 請求。
關於 Restful 的內容計划單獨寫。

@RequestParam

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
	String value() default "";//值即為請求參數的參數名
	boolean required() default true;//該參數是否是必須。默認值為true
	String defaultValue() default ValueConstants.DEFAULT_NONE;//請求參數的默認值
}
// http://localhost:8080/demo/para?slug=google
@RequestMapping(value = "/para", method = RequestMethod.GET)
public String index3(@RequestParam(value = "slug", defaultValue = "") String slug, Model model) {
	model.addAttribute("originURL", "demo/");
	model.addAttribute("controllerName", "demo");
	model.addAttribute("controllerMethod", "index3");
	model.addAttribute("slug", slug);
	return "demo";
}
slug = google

另外還有一點要提示一下,參數沒有加這個注解也能映射成功,這是應為 SpringMVC 框架支持請求參數和目標方法參數一致的時候可以省略這個注解。

@ResponseBody

/**
 * Annotation that indicates a method return value should be bound to the web
 * response body. Supported for annotated handler methods in Servlet environments.
 * 
 * 這個注解指明一個方法的返回值應該綁定在 web response body 中,在 Servlet 環境中支持注解處理方法
 * 
 * <p>As of version 4.0 this annotation can also be added on the type level in
 * which case it is inherited and does not need to be added on the method level.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}

代碼

// http://localhost:8080/demo/json
@RequestMapping(value = "/json", method = RequestMethod.POST)
public @ResponseBody Domain index7(HttpServletRequest request, Model model) {

	LOG.info("DemoController demo index7");
	model.addAttribute("originURL", "demo/");
	model.addAttribute("controllerName", "demo");
	model.addAttribute("controllerMethod", "index7");

	Domain domain = new Domain();
	domain.setDomain("gggoogle.com");
	domain.setId(100);
	return domain;
}

/* response body
{
	"id": 100,
	"domain": "gggoogle.com"
}
*/

SpringMVC 數據綁定

簡單說一下場景:
對於一個注冊頁面有很多信息譬如:用戶名、密碼、確認密碼、郵箱、手機、興趣等等。這時候就會想能不能將這些個參數包裝在一個對象中(POJO),用這個POJO來做目標方法的形參上面。可以說的是 SpringMVC 是支持將 POJO 作為目標參數的。當然也是要遵循一些規則的,就是表單的 name 屬性值要和 POJO 的屬性值要一致。當然了,這樣又會有一個新的疑問支不支持級聯屬性答案是支持的。

public class Address {
	private String city;
	...
}
public class Persion {
	private String name;
	private Address address;
	...
}
<form action="/demo/pojo">
	NAME:<input type="text" name="name" />
	CITY:<input type="text" name="address.city" />
</form>
@RequestMapping(value = "/pojo", method = RequestMethod.POST)
public String index4(Persion persion, Model model) {
	model.addAttribute("originURL", "demo/");
	model.addAttribute("controllerName", "demo");
	model.addAttribute("controllerMethod", "index4");
	model.addAttribute("persion", persion);
	return "demo";
}

SpringMVC 使用 Servlet API

可以使用 Servlet 原生的API作為目標方法的參數。具體支持以下類型:HttpServletRequest、HttpServletResponse、HttpSession、java.security.Principal、Locale、InputStream、OutputStream、Reader、Writer

// http://localhost:8080/demo/req?slug=facebook
@RequestMapping(value = "/req", method = RequestMethod.GET)
public String index5(HttpServletRequest request, Model model) {
	String slug = request.getParameter("slug");
	model.addAttribute("originURL", "demo/");
	model.addAttribute("controllerName", "demo");
	model.addAttribute("controllerMethod", "index5");
	model.addAttribute("slug", slug);
	return "demo";
}

Reference:


免責聲明!

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



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