SSM學習之SpringMVC架構基礎
- SpringMVC架構
-
- 1. 基本配置
-
- 1.1 pom.xml 依賴坐标
- 1.2 web.xml
- 1.3 SpringMVC.xml 配置檔案
- 1.4 請求亂碼配置過濾器
- 2. 運作流程
- 3 注解開發
-
- 3.1 常用注解
-
- @RequestMapping
- 3.2 請求處理
-
-
- Spring MVC 支援使用原生的ServletAPI,可以直接寫在參數中擷取
- @RequestParam @RequestHeader @CookieValue
- @PathVariable(“id”)
- @ModelAttribute
- @SessionAttribute
- @SessionAttributes({“msg”})
-
- 3.3 響應處理
-
- 3.3.1 輸出資料
- 3.4 互動 json 資料
-
- @RequestBody
- @ResponseBody
- @RestController
- 需要的jar包
- 4. Restful
- 5. 視圖解析器
-
- 5.1 重定向與轉發
- 5.2 通過配置檔案指定映射視圖解析
- 5.3 自定義視圖和視圖解析器
- 6. 資料轉換
-
- 6.1 自定義轉換器
- 7. 檔案上傳
- 8. 攔截器
SpringMVC架構
1. 基本配置
1.1 pom.xml 依賴坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
1.2 web.xml
<!-- 配置 spring mvc 的核心前端控制器 -->
<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>
<!-- 配置 servlet 的對象的建立時間點:應用加載時建立。
取值隻能是非 0 正整數,表示啟動順序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- /和/*都是攔截所有請求,但/*還會攔截到*.jsp頁面 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
1.3 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">
<!-- 配置建立 spring 容器要掃描的包 -->
<context:component-scan base-package="xyz.fishman"></context:component-scan>
<!-- 配置視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 在 springmvc.xml 的配置檔案中可以配置,靜态資源不過濾:
location 表示路徑, mapping 表示檔案, **表示該目錄下的檔案以及子目錄的檔案 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/scripts/" mapping="/javascript/**"/>
<!--放行靜态資源
<mvc:default-servlet-handler/> -->
<!-- 開啟注解驅動 -->
<mvc:annotation-driven/>
</beans>
1.4 請求亂碼配置過濾器
web.xml
<!-- 配置 springMVC 編碼過濾器
注意:字元編碼過濾器通常都在其他過濾器之前-->
<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>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 過濾所有請求 -->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 運作流程
- 用戶端點選連結發送http://localhost/hello
- 浏覽器與伺服器建立連接配接,請求到達tomcat
- SpringMVC的前端控制器(DispatcherServlet)收到所有請求,調用doDispatcher進行處理
- 根據HandlerMapping中儲存的請求映射資訊找到目前請求的處理器執行鍊(包含攔截器)與@RequestMapping标注的類比對(擴充卡),找到用哪個擴充卡中的目标方法
- 執行攔截器方法,擴充卡執行目标方法
- 得到目标方法的傳回值
- 執行攔截器的postHandle方法
- 視圖解析器處理結果
- 拿到頁面位址,前端控制器帶着資料轉發到該頁面(渲染頁面)
- 執行攔截器afterCompletion方法
3 注解開發
3.1 常用注解
@RequestMapping
作用:
用于建立請求 URL 和處理請求方法之間的對應關系。
出現位置:
類上:
請求 URL 的第一級通路目錄。此處不寫的話,就相當于應用的根目錄。 寫的話需要以/開頭。
它出現的目的是為了使我們的 URL 可以按照子產品化管理:
方法上:
請求 URL 對應的通路目錄,可以确定所調用的方法。
屬性:
- value:用于指定請求的 URL。 它和 path 屬性的作用是一樣的。
- method:用于指定請求的方式。
-
params:用于指定限制請求參數的條件。 它支援簡單的表達式。 要求請求參數的 key 和 value 必須和
配置的一模一樣。
- consumes:隻接收類型是某種的請求,規定請求頭的Content-Type
- produces:告訴浏覽器傳回的内容類型,設定響應頭的Context-Type
例如:
- params = {“accountName”},表示請求參數必須有 accountName
- params = {“moeny!100”},表示請求參數中 money 不能是 100。
- headers:用于指定限制請求消息頭的條件
3.2 請求處理
預設方式擷取請求參數:直接給方法入參上寫一個與請求參數名稱相同的變量。
Spring MVC 支援使用原生的ServletAPI,可以直接寫在參數中擷取
- HttpServletRequest
- HttpServletResponse
- HttpSession
- java.security.Principal
- Locale InputStream
- OutputStream
- Reader
- Writer
@RequestParam @RequestHeader @CookieValue
出現位置:
參數前
作用:
把請求/請求頭/cookie中指定名稱的參數給控制器中的形參指派。
屬性:
- value: 請求參數中的名稱。
- required:請求參數中是否必須提供此參數。預設值: true。表示必須提供,如果不提供将報錯。
@PathVariable(“id”)
作用:
擷取請求
路徑
中某個占位符的值。 {id}
@ModelAttribute
spring學習之@ModelAttribute運用詳解
作用:
該注解是 SpringMVC4.3 版本以後新加入的。它可以用于修飾方法和參數。(不常用)
出現位置:
方法上:
表示目前方法會在控制器的方法執行之前,先執行。它可以修飾沒有傳回值的方法,也可
以修飾有具體傳回值的方法。
參數上:
擷取指定的資料給參數指派。
屬性:
- value:用于擷取資料的 key。 key 可以是 POJO 的屬性名稱,也可以是 map 結構的 key。
@SessionAttribute
作用:
用于多次執行控制器方法間的參數共享。
屬性:
- value:用于指定存入的屬性名稱
- type:用于指定存入的資料類型。
public String SessionAttr(@SessionAttribute(value = "sessionStr") String sessionStr, Model model)
{
System.out.println("--> sessionStr : " + sessionStr);
model.addAttribute("sth", sessionStr);
return "test";
}
@SessionAttributes({“msg”})
出現位置:
類上:
給BindingAwareModelMap中儲存的msg資料也在Session中儲存一份。(不推薦,推薦使用原生API)
屬性:
- value:要在Session中儲存的資料名稱。
- types:隻要是指定類型的資料,都儲存一份到Session中。
3.3 響應處理
3.3.1 輸出資料
- 從參數中拿到一個Map<K,V>(接口)/Model(接口)/ModelMap,最終都是用同一個BindingAwareModelMap對象将資料放入,資料将傳入request域中。
- 傳回值可以是ModelAndView對象,并為其設定模型資料和視圖資訊,資料将傳入request域
- @SessionAttributes
3.4 互動 json 資料
@RequestBody
作用:
用于擷取請求體内容。 直接使用得到是 key=value&key=value…結構的資料。
get 請求方式不适用。
屬性:
required:是否必須有請求體。預設值是:true。當取值為 true 時,get 請求方式會報錯。如果取值
為 false, get 請求得到是 null。
@ResponseBody
作用:
該注解用于将 Controller 的方法傳回的對象,通過 HttpMessageConverter 接口轉換為指定格式的
資料如: json,xml 等,通過 Response 響應給用戶端。加在方法傳回類型前。
@RestController
相當于@[email protected]兩個注解的結合,傳回json資料不需要在方法前面加@ResponseBody注解了,但使用@RestController這個注解,就不能傳回jsp,html頁面,視圖解析器無法解析jsp,html頁面
需要的jar包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
4. Restful
需要在web.xml中配置一個filter,以支援put\delete等請求
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
修改表單送出(以delete請求為例)
<form action="/test/1"method="post">
<input type="hidden" value="delete" name="_method">
<input type="submit" value="delete">
</form>
對應控制器
@RequestMapping(value = "/test/{id}", method = RequestMethod.DELETE)
public String delete(@PathVariable int id) {
System.out.println("delete" + id);
return "success";
}
注意:使用Tomcat8.0以上時可能會報錯: HTTP Status 405 - JSPs only permit GET POST or HEAD
出錯原因:
發起的請求是個RESTFul風格的請求,調用了RESTFul風格的PUT方法。但是controller裡testRestPUT傳回的success字元串被映射到success.jsp。是以spring認為這應該是個JSP接口,且JSP接口僅僅支援GET方法和POST方法。是以系統提示提示了這個錯誤。
解決方法:
隻需要在jsp頁面中設定 isErrorPage=“true”即可正常顯示頁面。
5. 視圖解析器
5.1 重定向與轉發
//轉發需要寫從根目錄開始的全路徑,是伺服器處理路徑
"forward:/WEB-INF/pages/success.jsp"
//重定向是浏覽器處理路徑,不能直接通路到WEB-INF中的内容
"redirect:/index.jsp"
//兩者都與視圖解析器無關,故不會拼接路徑
5.2 通過配置檔案指定映射視圖解析
<mvc:view-controller path="/login" view-name="success"/>
<!--必須開啟MVC注解驅動模式,否則其他視圖解析器映射将無效
且需要配置在context:component-scan之前-->
<mvc:annotation-driven/>
<!-- 若加了<mvc:default-servlet-handler/>也需要啟動注解驅動模式 -->
5.3 自定義視圖和視圖解析器
分别建立實作ViewResolver和Ordered接口的視圖解析器類和實作View接口的視圖類,加入IOC容器中。
6. 資料轉換
MVC封裝自定義類型參數發生類型轉換時,可能需要用自定義轉換器。
6.1 自定義轉換器
public class StringToDateConverter implements Converter<String, Date> {
/**
* 用于把 String 類型轉成日期類型
*/
@Override
public Date convert(String source) {
DateFormat format = null;
try {
if(StringUtils.isEmpty(source)) {
throw new NullPointerException("請輸入要轉換的日期");
}
format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse(source);
return date;
} catch (Exception e) {
throw new RuntimeException("輸入日期有誤");
}
}
}
public class StringToInfoConverter implements Converter<String, Info> {
//fisman-22-19970104
@Override
public Info convert(String s) {
String[] args = s.split("-");
Info info = new Info();
DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
try {
info.setName(args[0]);
info.setAge(Integer.valueOf(args[1]));
Date date = dateFormat.parse(args[2]);
info.setDate(date);
return info;
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
}
<!-- 配置類型轉換器工廠 -->
<bean id="converterService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 給工廠注入一個新的類型轉換器 -->
<property name="converters">
<array>
<!-- 配置自定義類型轉換器 -->
<bean class="xyz.fishman.web.converter.StringToDateConverter"></bean>
</array>
</property>
</bean>
<!-- 引用自定義類型轉換器 -->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
7. 檔案上傳
必要前提
-
form 表單的 enctype 取值必須是: multipart/form-data
(預設值是:application/x-www-form-urlencoded) enctype:是表單請求正文的類型
- method 屬性取值必須是 Post
- 提供一個檔案選擇域
jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency
頁面
<form action="/fileUpload" method="post" enctype="multipart/form-data">
名稱: <input type="text" name="picname"/><br/>
圖檔: <input type="file" name="uploadFile"/><br/>
<input type="submit" value="上傳"/>
</form>
控制器
@Controller
public class FileUploadController {
/**
* 檔案上傳
*/
@RequestMapping("/fileUpload")
public String testResponseJson(String picname,MultipartFile
uploadFile,HttpServletRequest request) throws Exception{
//定義檔案名
String fileName = "";
//1.擷取原始檔案名
String uploadFileName = uploadFile.getOriginalFilename();
//2.截取檔案擴充名
String extendName =
uploadFileName.substring(uploadFileName.lastIndexOf(".")+1,
uploadFileName.length());
//3.把檔案加上随機數,防止檔案重複
String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase();
//4.判斷是否輸入了檔案名
if(!StringUtils.isEmpty(picname)) {
fileName = uuid+"_"+picname+"."+extendName;
}else {
fileName = uuid+"_"+uploadFileName;
}
System.out.println(fileName);
//2.擷取檔案路徑
ServletContext context = request.getServletContext();
String basePath = context.getRealPath("/uploads");
//3.解決同一檔案夾中檔案過多問題
String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
//4.判斷路徑是否存在
File file = new File(basePath+"/"+datePath);
if(!file.exists()) {
file.mkdirs();
}
//5.使用 MulitpartFile 接口中方法,把上傳的檔案寫到指定位置
uploadFile.transferTo(new File(file,fileName));
return "success";
}
}
檔案解析器
<!-- 配置檔案上傳解析器 -->
<!-- id的值不可改變 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 設定上傳檔案的最大尺寸為 5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
<!-- 注意:
檔案上傳的解析器 id 是固定的,不能起别的名稱,否則無法實作請求參數的綁定。(不光是檔案,其他
字段也将無法綁定) -->
8. 攔截器
- 實作HandlerInterceptor接口
- 重寫preHandle/postHandle/afterCompletion方法
- 在配置檔案中注冊攔截器的工作
<mvc:interceptors>
<!-- 攔截所有請求
<bean class="xyz.fishman.interceptor.MyInterceptor"></bean> -->
<mvc:interceptor>
<mvc:mapping path="/test"/>
<bean class="xyz.fishman.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
如果需要與其他元件配合,就用攔截器;若功能簡單就用filter。