簡介
三層架構(gòu)是什么
三層架構(gòu)分別是表現(xiàn)層、業(yè)務(wù)層和持久層。
表現(xiàn)層也就是我們常說的web層,負(fù)責(zé)接收客戶端的請(qǐng)求,向客戶端相應(yīng)數(shù)據(jù)。業(yè)務(wù)層也就是service層,負(fù)責(zé)業(yè)務(wù)邏輯處理。持久層也就是dao層,負(fù)責(zé)數(shù)據(jù)持久化,與數(shù)據(jù)庫打交道,對(duì)數(shù)據(jù)庫表進(jìn)行增刪改查等操作。
MVC是什么
MVC是Model View Controller的縮寫,Model就是數(shù)據(jù)模型,用于封裝數(shù)據(jù),也可以理解為就是JavaBean; View是視圖,一般用來展示數(shù)據(jù),通常指jsp或html等;Controller是控制器,處理程序邏輯。
SpringMVC是什么
1.表現(xiàn)層框架,負(fù)責(zé)接收客戶端請(qǐng)求,并向客戶端相應(yīng)結(jié)果。
2.它通過一套注解,讓一個(gè)簡單的Java類成為可以處理請(qǐng)求的控制器,并且還支持RESTful編程風(fēng)格。
3.與Spring無縫集成,這點(diǎn)是其他框架不可比的。
入門案例
創(chuàng)建一個(gè)web項(xiàng)目


添加依賴
<dependencies>
<!--springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!--jsp-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
配置
在web.xml中配置前置控制器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--前置控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--可以不配置, 默認(rèn)會(huì)找WEB-INF/*-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
1. 是否在啟動(dòng)的時(shí)候就加載這個(gè)servlet(實(shí)例化并調(diào)用其init()方法)
2. 它的值必須是一個(gè)整數(shù),表示servlet應(yīng)該被載入的順序
3. 當(dāng)值為0或者大于0時(shí),表示容器在應(yīng)用啟動(dòng)時(shí)就加載并初始化這個(gè)servlet
4. 當(dāng)值小于0或者沒有指定時(shí),則表示容器在該servlet被選擇時(shí)才會(huì)去加載
5. 正數(shù)的值越小,該servlet的優(yōu)先級(jí)越高,應(yīng)用啟動(dòng)時(shí)就越先加載
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
創(chuàng)建src/main/resources/springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 開啟注解掃描 -->
<context:component-scan base-package="com._54programer"/>
<!-- 視圖解析器對(duì)象 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 開啟SpringMVC框架注解的支持 -->
<mvc:annotation-driven/>
</beans>
創(chuàng)建控制器
package com.sn511.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping(path = "/hello")
public String hello(){
System.out.println("hello springmvc");
return "hello";
}
}
創(chuàng)建jsp
/webapp/WEB-INF/pages/hello.jsp
<%--
Created by IntelliJ IDEA.
User: SN
Date: 2019/9/21
Time: 10:33
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Helo</title>
</head>
<body>
<h3>Hello SpringMVC</h3>
</body>
</html>
訪問: http://localhost:8080/springmvc_war/hello

執(zhí)行流程分析
第一階段
Tomcat啟動(dòng),加載web.xml文件,實(shí)例并初始化DispatchServlet,DispatchServlet加載springmvc.xml并創(chuàng)建Spring容器,根據(jù)配置初始化對(duì)象。
第二階段
客戶端訪問,發(fā)送hello請(qǐng)求,請(qǐng)求先到達(dá)前端控制器DispatchServlet,然后DispatchServlet根據(jù)請(qǐng)求動(dòng)作名稱轉(zhuǎn)發(fā)請(qǐng)求到HelloController,然后HelloController根據(jù)方法返回值通過InternalResourceViewResolver找到相應(yīng)的結(jié)果視圖并響應(yīng)給客戶端。

DispatcherServlet,前端控制器,dispatcherServlet 是整個(gè)流程控制的中心,由它調(diào)用其它組件處理用戶的請(qǐng)求,dispatcherServlet 的存在降低了組件之間的耦合性。
常用注解
RequestMapping
用于建立請(qǐng)求URL和處理請(qǐng)求方法之間的對(duì)應(yīng)關(guān)系
位置: 類、方法上
屬性:
value: 用于指定請(qǐng)求的 URL
method: 用于指定請(qǐng)求的 方式
params: 用于指定限制請(qǐng)求參數(shù)的條件,要求請(qǐng)求參數(shù)的 key 和 value 必須和配置的一模一樣
headers: 用于指定限制請(qǐng)求消息頭的條件
//get請(qǐng)求, 必須有name參數(shù), 否則報(bào)錯(cuò)
@RequestMapping(value = "/hello", method = RequestMethod.GET, params = {"name"})
public String hello(){
System.out.println("hello springmvc");
return "hello";
}
參數(shù)綁定
把請(qǐng)求參數(shù)和控制器方法參數(shù)進(jìn)行綁定
支持基本類型、實(shí)體類和集合類型。
基本類型
要求參數(shù)名稱必須和控制器方法的名稱保持一致,嚴(yán)格區(qū)分大小寫
http://localhost:8080/springmvc_war/hello?name=lisi&age=11
@RequestMapping(value = "/hello")
public String hello(String name, Integer age){
System.out.println("hello "+ name + ", age is "+ age);
return "hello";
}
實(shí)體類類型
要求表單中的參數(shù)和實(shí)體類的屬性名稱保持一致
public class Address implements Serializable {
private String provinceName; //省份
private String cityName;//城市
省略getter、setter方法
}
public class Person implements Serializable {
private String name;
private Integer age;
private Address address;
省略getter、setter方法
}
@Controller
public class PersonController {
@RequestMapping("/person")
public void person(Person person){
}
}
# 表單
<form action="/person" method="get">
<input type="text" name="name">
<input type="text" name="age">
<input type="text" name="address.provinceName">
<input type="text" name="address.cityName">
</form>
集合類型
兩種方式,第一種要求集合類型的請(qǐng)求參數(shù)必須在實(shí)體類中;第二種接收的請(qǐng)求參數(shù)是json格式數(shù)據(jù),需要借助一個(gè)注解實(shí)現(xiàn)。
public class Company {
private String name;
private List<Person> persons;
private Map<String, Person> personMap;
}
<form action="/user" method="get">
<input type="text" name="name">
<input type="text" name="persons[0].name">
<input type="text" name="persons[1].name">
<input type="text" name="personMap['first'].name">
<input type="text" name="personMap['seconed'].name">
</form>
SpringMVC支持使用原始 ServletAPI 對(duì)象作為控制器方法的參數(shù)
支持原始 ServletAPI 對(duì)象有:
HttpServletRequest,HttpServletResponse,HttpSession
InputStream,OutputStream
Reader,Writer
java.security.Principal
Locale
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request,HttpServletResponse response,HttpSession session) {
}
RequestParam
把請(qǐng)求中指定名稱的參數(shù)給控制器中的形參賦值
屬性
value: 請(qǐng)求參數(shù)中的名稱
required: 請(qǐng)求參數(shù)中是否必須提供此參數(shù)。默認(rèn)值:true
@RequestMapping("/person")
public void person(@RequestParam("name") String username, @RequestParam(value = "age", required = false) Integer age){
}
RequestBody
用于獲取請(qǐng)求體內(nèi)容。直接使用得到是 key=value&key=value...結(jié)構(gòu)的數(shù)據(jù),get 請(qǐng)求方式不適用
屬性
required: 是否必須有請(qǐng)求體。默認(rèn)值是:true
@RequestMapping("/person")
public void person(@RequestBody(required = false) String body){
System.out.println(body); //name=lisi&age=11
}
ResponseBody
該注解用于將 Controller 的方法返回的對(duì)象,通過 HttpMessageConverter 接口轉(zhuǎn)換為指定格式的數(shù)據(jù)如:json,xml 等,通過 Response 響應(yīng)給客戶端
PathVaribale
用于綁定 url 中的占位符。
例如:請(qǐng)求 url 中 /delete/{id},這個(gè){id}就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 風(fēng)格 URL 的一個(gè)重要標(biāo)志。
屬性:
value:用于指定 url 中占位符名稱。
required:是否必須提供占位符。
# /person/20
@RequestMapping("/person/{id}")
public void person(@PathVariable("id") Integer id){
}
RequestHeader
用于獲取請(qǐng)求消息頭,在實(shí)際開發(fā)中一般不怎么用。
屬性:
value:提供消息頭名稱
required:是否必須有此消息頭
@RequestMapping("/person")
public void person(@RequestHeader(value = "Accept-Language", required = false) String requestHeader){
}
CookieValue
用于把指定 cookie 名稱的值傳入控制器方法參數(shù)
屬性:
value:指定 cookie 的名稱。
required:是否必須有此 cookie。
@RequestMapping("/useCookieValue")
public vode person(@CookieValue(value="JSESSIONID",required=false) String cookieValue){
}
ModelAttribute
用于修飾方法和參數(shù),出現(xiàn)在方法上,表示當(dāng)前方法會(huì)在控制器的方法執(zhí)行之前,先執(zhí)行
屬性
value:用于獲取數(shù)據(jù)的 key。key 可以是 POJO 的屬性名稱,也可以是 map 結(jié)構(gòu)的 key。應(yīng)用場景:
當(dāng)表單提交數(shù)據(jù)不是完整的實(shí)體類數(shù)據(jù)時(shí),保證沒有提交數(shù)據(jù)的字段使用數(shù)據(jù)庫對(duì)象原來的數(shù)據(jù)
SessionAttribute
用于多次執(zhí)行控制器方法間的參數(shù)共享。
屬性:
value:用于指定存入的屬性名稱
type:用于指定存入的數(shù)據(jù)類型。
響應(yīng)數(shù)據(jù)和結(jié)果視圖
返回值
字符串
返回字符串可以指定邏輯視圖名,通過視圖解析器解析為物理視圖地址。
@RequestMapping("/hello")
public String hello(){
return "success";
}
void
返回值為void,可以在代碼中指定邏輯邏輯視圖路徑。
@RequestMapping("/person")
public void person(HttpServletRequest request, HttpServletResponse response) throws Exception{
//1. 使用request跳轉(zhuǎn)頁面
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
//2. 使用response重定向
response.sendRedirect("");
//3. 使用response指定相應(yīng)結(jié)果
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=urf-8");
response.getWriter().write("hello");
}
ModelAndView
@RequestMapping("/person")
public ModelAndView person() throws Exception{
ModelAndView modelAndView = new ModelAndView();
//這里添加的數(shù)據(jù), 在也面上可以通過el表達(dá)式直接獲取
modelAndView.addObject("name", "lisi");
//設(shè)置視圖名稱,視圖解析器會(huì)根據(jù)名稱前往指定的視圖
modelAndView.setViewName("success");
return modelAndView;
}
forward轉(zhuǎn)發(fā)和Redireac重定向
@RequestMapping("/person")
public String person() throws Exception{
//等價(jià)于request.getRequestDispatcher("url").forward(request, response)
return "forward:/WEB-INF/pages/success.jsp";
}
@RequestMapping("/person")
public String person() throws Exception{
//等價(jià)于response.sendRedirect(url);
return "redireac:url";
}
亂碼問題
web.xml
<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>