天天看點

SSM學習之SpringMVC架構基礎SpringMVC架構

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. 運作流程

  1. 用戶端點選連結發送http://localhost/hello
  2. 浏覽器與伺服器建立連接配接,請求到達tomcat
  3. SpringMVC的前端控制器(DispatcherServlet)收到所有請求,調用doDispatcher進行處理
  4. 根據HandlerMapping中儲存的請求映射資訊找到目前請求的處理器執行鍊(包含攔截器)與@RequestMapping标注的類比對(擴充卡),找到用哪個擴充卡中的目标方法
  5. 執行攔截器方法,擴充卡執行目标方法
  6. 得到目标方法的傳回值
  7. 執行攔截器的postHandle方法
  8. 視圖解析器處理結果
  9. 拿到頁面位址,前端控制器帶着資料轉發到該頁面(渲染頁面)
  10. 執行攔截器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 輸出資料

  1. 從參數中拿到一個Map<K,V>(接口)/Model(接口)/ModelMap,最終都是用同一個BindingAwareModelMap對象将資料放入,資料将傳入request域中。
  2. 傳回值可以是ModelAndView對象,并為其設定模型資料和視圖資訊,資料将傳入request域
  3. @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. 攔截器

  1. 實作HandlerInterceptor接口
  2. 重寫preHandle/postHandle/afterCompletion方法
  3. 在配置檔案中注冊攔截器的工作
<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。

繼續閱讀