SpringMVC 入門、請求、響應

Juno3550發表於2021-12-19


SpringMVC 概述

SSM 簡介

SSM 三層架構

  • 表現層:負責資料展示

  • 業務層:負責業務處理

  • 資料層:負責資料操作

image


MVC 簡介

MVC(Model View Controller)是一種用於設計及建立 Web 應用程式表現層的模式。

  • Model(模型):資料模型,用於封裝資料

  • View(檢視):頁面檢視,用於展示資料

    • jsp
    • html
  • Controller(控制器):處理使用者互動的排程器,用於根據使用者需求處理程式邏輯

    • Servlet
    • SpringMVC

image

SpringMVC 簡介

SpringMVC 是一種基於 Java 實現的、MVC 模型的、輕量級的 Web 框架。

SpringMVC 優點

  1. 使用簡單
  2. 效能突出(相比現有的框架技術)
  3. 靈活性強

入門案例

SpringMVC 工作流程分析:

  1. 伺服器啟動:
    1. 載入 web.xml 中 DispatcherServlet;
    2. 讀取 spring-mvc.xml 中的配置,載入所有 com 包中所有標記為 bean 的類;
    3. 讀取 bean 中方法上方標註 @RequestMapping 的內容;
  2. 處理請求:
    1. DispatcherServlet 配置攔截所有請求“/”;
    2. 使用請求路徑與所有載入的 @RequestMapping 的內容進行比對;
    3. 執行對應的方法;
    4. 根據方法的返回值在 webapp 目錄中查詢對應的頁面並展示。

實現示例

  1. 匯入 SpringMVC 相關的 Maven 依賴:
<!-- servlet3.1規範的座標 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
<!--jsp座標-->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
</dependency>
<!--spring的座標-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<!--spring web的座標-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<!--springmvc的座標-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
  1. 定義表現層處理器 Controller(等同於 Servlet),並配置成 Spring 的 bean:
@Controller
public class UserController {

    public void save(){
        System.out.println("user mvc controller is running ...");
    }
}
  1. 定義 SpringMVC 配置檔案(格式與 Spring 配置檔案一致):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!--掃描載入所有的控制類類-->
    <context:component-scan base-package="com"/>

</beans>
  1. web.xml 中配置 SpringMVC 核心控制器,用於將請求轉發到對應的具體業務處理器 Controller 中(等同於 Servlet 配置):
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring-mvc.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
  1. 設定具體 Controller 的訪問路徑與返回頁面(等同於 Servlet 在 web.xml 中的配置):
// 設定當前方法的訪問對映地址
@RequestMapping("/save")
// 設定當前方法返回值型別為String,用於指定請求完成後跳轉的頁面
public String save(){
    System.out.println("user mvc controller is running ...");
    // 設定具體跳轉的頁面
    return "success.jsp";
}

Spring 技術架構

image

  1. DispatcherServlet(前端控制器):是整體流程控制的中心,由其呼叫其它元件處理使用者的請求,有效降低了元件間的耦合性。
  2. HandlerMapping(處理器對映器):負責根據使用者請求找到對應具體的 Handler 處理器。
  3. Handler(處理器):業務處理的核心類,通常由開發者編寫,描述具體的業務。
  4. HandlAdapter(處理器介面卡):通過它對處理器進行執行。
  5. View Resolver(檢視解析器):將處理結果生成 View 檢視。
  6. View(檢視):最終產出結果,常用檢視如 jsp、html。

SpringMVC 基礎配置

常規配置

Controller 載入控制

SpringMVC 的處理器對應的 bean 必須按照規範格式開發,為了避免加入無效的 bean,可通過 bean 載入過濾器進行包含設定或排除設定。

例如,表現層 bean 標註通常設定為 @Controller,因此可以通過註解名稱進行過濾控制:

<context:component-scan base-package="com">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

靜態資源載入

<!--放行指定型別靜態資源配置方式-->
<mvc:resources mapping="/img/**" location="/img/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>

<!--SpringMVC提供的通用資源放行方式-->
<mvc:default-servlet-handler/>

中文亂碼處理

web.xml

<!-- 亂碼處理過濾器,與Servlet中使用的完全相同,差異之處在於處理器的類由Spring提供 -->
<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>

註解驅動

目標:刪除 web.xml 和 spring-mvc.xml 。

注意
image

實現示例

  1. 使用註解形式,將 SpringMVC 核心配置檔案替換為配置類
package com.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.Controller;

@Configuration
@ComponentScan(
        value="com",
        includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes={Controller.class})
)
public class SpringMvcConfig implements WebMvcConfigurer {

    // 註解配置放行指定資源格式
    // @Override
    // public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //     registry.addResourceHandler("/img/**").addResourceLocations("/img/");
    //     registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    //     registry.addResourceHandler("/css/**").addResourceLocations("/css/");
    // }

    // 註解配置通用放行資源的格式
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();;
    }
}
  1. 替換 web.xml:基於 servlet3.0 規範,自定義 Servlet 容器初始化配置類,載入 SpringMVC 核心配置類
package com.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;
import java.util.Objects;

public class ServletInitConfig extends AbstractDispatcherServletInitializer {
    /*
    建立 Servlet 容器時,使用註解的方式載入 SpringMVC 配置類中的資訊,並載入成 Web 專用的 ApplicationContext 物件
    該物件放入了 ServletContext 範圍,後期在整個 Web 容器中可以隨時獲取呼叫
     */
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

    // 註解配置對映地址方式,服務於 SpringMVC 的核心控制器 DispatcherServlet
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    // 亂碼處理作為過濾器,在 servlet 容器啟動時進行配置
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(Objects.<ServletContext>requireNonNull(servletContext));
        CharacterEncodingFilter cef = new CharacterEncodingFilter();
        cef.setEncoding("UTF-8");
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", cef);
        registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD,
                DispatcherType.INCLUDE), false, "/*");
    }
}

請求

請求對映:@RequestMapping

@RequestMapping 使用

  • 型別:類註解;方法註解
  • 位置:處理器類定義上方;處理器類中的方法定義上方
  • 作用:為當前處理器中所有方法設定公共的訪問路徑字首;繫結請求地址與對應處理方法間的關係
// 示例:方法註解
@Controller
public class UserController {
    // 訪問 URI:/user/requestURL1
    @RequestMapping("/requestURL1")
    public String requestURL2() {
        return "page.jsp";
    }
}

// 示例:類註解
@Controller
@RequestMapping("/user")
public class UserController {
    // 訪問 URI:/user/requestURL2
    @RequestMapping("/requestURL2")
    public String requestURL2() {
        return "page.jsp";
    }
}

常用屬性

@RequestMapping(
    value="/requestURL3",  // 設定請求路徑,與path屬性、value屬性相同
    method = RequestMethod.GET,  // 設定請求方式
    params = "name",  // 設定請求引數條件
    headers = "content-type=text/*",  // 設定請求訊息頭條件
    consumes = "text/*",  // 用於指定可以接收的請求正文型別(MIME型別)
    produces = "text/*"  // 用於指定可以生成的響應正文型別(MIME型別)
)
public String requestURL3() {
    return "/page.jsp";
}

普通型別傳參

// URL 訪問:http://localhost:8080/requestParam1?name=xiaoming&age=14
@RequestMapping("/requestParam1")
public String requestParam1(String name ,String age){
    System.out.println("name="+name+", age="+age);
    return "page.jsp";
}

@RequestParam

  • 型別:形參註解
  • 位置:處理器類中的方法形參前方
  • 作用:繫結請求引數與處理方法形參間的關係

示例

// http://localhost:8080/requestParam2?userName=Jock
@RequestMapping("/requestParam2")
public String requestParam2(@RequestParam(
                            name = "userName",
                            required = true,
                            defaultValue = "xiaohuang") String name) {
    System.out.println("name="+name);
    return "page.jsp";
}
  • 當未傳參即直接訪問“/requestParam2”時,方法會取預設值“xiaohuang”。
  • 當配置了“required=true”但未配置“defaultValue”時,訪問時不傳參則會報 400 錯。
    image

物件型別傳參

POJO

當使用 POJO(簡單 Java 物件)時,傳參名稱與 POJO 類屬性名保持一致即可。

  • POJO 類
package com.bean;

public class User {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
  • Controller
// URL 訪問:http://localhost:8080/requestParam3?name=xiaodong&age=18
@RequestMapping("/requestParam3")
public String requestParam3(User user){
    System.out.println("name="+user.getName());
    return "page.jsp";
}

引數衝突

當 POJO 的屬性與其他形參出現同名問題時,將被同時賦值。

// 訪問 URL:http://localhost:8080/requestParam4?name=xiaoyi&age=14
@RequestMapping("/requestParam4")
public String requestParam4(User user, String age){
    System.out.println("user.age="+user.getAge()+", age="+age);  // user.age=14, age=14
    return "page.jsp";
}

建議使用 @RequestParam 註解進行區分。

複雜物件型別

當物件中出現物件屬性時,則要求入參名稱與物件層次結構名稱保持一致。

image

物件集合

1)當複雜物件中出現用 List 儲存物件資料時,要求入參名稱與物件層次結構名稱保持一致,並使用陣列格式描述集合中物件的位置。

  • bean:
public class User {
    private String name;
    private Integer age;
    private List<Address> addresses;
}

public class Address {
    private String province;
    private String city;
    private String address;
}
  • Controller:
// 訪問URL:http://localhost:8080/requestParam7?addresses[0].province=bj&addresses[1].province=tj
@RequestMapping("/requestParam7")
public String requestParam7(User user){
    System.out.println("user.addresses="+user.getAddresses());
    return "page.jsp";
}

注意The valid characters are defined in RFC 7230 and RFC 3986
問題解決

2)當複雜物件中出現用 Map 儲存物件資料時,要求入參名稱與物件層次結構名稱保持一致,並使用對映格式描述集合中物件的位置。

  • bean:
public class User {
    private String name;
    private Integer age;
    private Map<String, Address> addressMap;
}

public class Address {
    private String province;
    private String city;
    private String address;
}
  • controller:
// 訪問 URL:http://localhost:8080/requestParam8?addressMap['home'].province=bj&addressMap['job'].province=tj
@RequestMapping("/requestParam8")
public String requestParam8(User user){
    System.out.println("user.addressMap="+user.getAddressMap());
    return "page.jsp";
}

陣列集合型別傳參

// 訪問 URL:http://localhost:8080/requestParam9?nick=xiaoming1&nick=xiaoming2
@RequestMapping("/requestParam9")
public String requestParam9(String[] nick){
    System.out.println(nick[0]+", "+nick[1]);  // xiaoming1, xiaoming2
    return "page.jsp";
}

// 訪問 URL:http://localhost:8080/requestParam10?nick=xiaoming1&nick=xiaoming2
@RequestMapping("/requestParam10")
public String requestParam10(@RequestParam("nick") List<String> nick){
    System.out.println(nick);  // [xiaoming1, xiaoming2]
    return "page.jsp";
}

注意:

  • SpringMVC 預設將 List 作為物件處理,賦值前先建立物件,然後將 nick 作為物件的屬性進行處理。而由於 List 是介面,無法建立物件,報無法找到構造方法異常;修復型別為可建立物件的 ArrayList 型別後,物件可以建立,但沒有 nick 屬性,因此資料為空。

  • 此時需要告知 SpringMVC 的處理器 nick 是一組資料,而不是一個單一資料。

  • 因此通過 @RequestParam 註解,將數量大於 1 個的 names 引數打包成引數陣列後, SpringMVC 才能識別該資料格式,並判定形參型別是否為陣列或集合,並按陣列或集合物件的形式運算元據。


型別轉換器

SpringMVC 會對接收的引數進行自動型別轉換,該工作通過 Converter 介面實現。

image

image

標量轉換器

  • StringToBooleanConverter String —> Boolean
  • ObjectToStringConverter Object —> String
  • StringToNumberConverterFactory String —> Number( Integer、Long 等)
  • NumberToNumberConverterFactory Number子型別之間(Integer、Long、Double 等)
  • StringToCharacterConverter String —> java.lang.Character
  • NumberToCharacterConverter Number子型別(Integer、Long、Double 等) —> java.lang.Character
  • CharacterToNumberFactory java.lang.Character —> Number 子型別(Integer、Long、Double 等)
  • StringToEnumConverterFactory String —> enum 型別
  • EnumToStringConverter enum 型別 —> String
  • StringToLocaleConverter String —> java.util.Local
  • PropertiesToStringConverter java.util.Properties —> String
  • StringToPropertiesConverter String —> java.util.Properties

集合、陣列相關轉換器

  • ArrayToCollectionConverter 陣列 —> 集合(List、Set)
  • CollectionToArrayConverter 集合(List、Set) —> 陣列
  • ArrayToArrayConverter(陣列間轉換)
  • CollectionToCollectionConverter 集合間(List、Set)
  • MapToMapConverter Map間
  • ArrayToStringConverter 陣列 —> String 型別
  • StringToArrayConverter String —> 陣列(實現方式為 trim 後使用 "," 進行 split)
  • ArrayToObjectConverter 陣列 —> Object
  • ObjectToArrayConverter Object —> 單元素陣列
  • CollectionToStringConverter 集合(List、Set) —> String
  • StringToCollectionConverter String —> 集合(List、Set)(實現方式為 trim 後使用 "," 進行 split)
  • CollectionToObjectConverter 集合 —> Object
  • ObjectToCollectionConverter Object —> 單元素集合

預設轉換器

  • ObjectToObjectConverter(Object 間轉換)
  • IdToEntityConverter Id —> Entity
  • FallbackObjectToStringConverter Object —> String

日期型別格式轉換

配置版:宣告自定義的轉換格式並覆蓋系統轉換格式

<!-- 啟用自定義Converter -->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 1.設定格式型別Converter,註冊為Bean,受SpringMVC管理 -->
<bean id="conversionService"
      class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <!-- 2.自定義Converter格式型別設定,該設定使用的是同型別覆蓋的思想 -->
    <property name="formatters">
        <!-- 3.使用set保障相同型別的轉換器僅保留一個,避免衝突 -->
        <set>
            <!-- 4.設定具體的格式型別 -->
            <bean class="org.springframework.format.datetime.DateFormatter">
                <!-- 5.型別規則 -->
                <property name="pattern" value="yyyy-MM-dd"/>
            </bean>
        </set>
    </property>
</bean>

註解版

  • 名稱:@DateTimeFormat
  • 型別:形參註解、成員變數註解
  • 位置:形參前面或成員變數上方
  • 作用:為當前引數或變數指定型別轉換規則
  • 注意:依賴註解驅動支援(<mvc:annotation-driven />)
  • 範例:
// 形參前
// 訪問 URL:http://localhost:8080/requestParam11?date=2021-12-12
@RequestMapping("/requestParam11")
public String requestParam11(@DateTimeFormat(pattern="yyyy-MM-dd") Date date){
    System.out.println("date="+date);
    return "page.jsp";
}

// 成員變數上方
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday;

自定義型別轉換器

1)實現 Converter 介面,並制定轉換前與轉換後的型別:

  • 配置:
  <!-- 1.將自定義Converter註冊為Bean,受SpringMVC管理 -->
  <bean id="myDateConverter" class="com.itheima.converter.MyDateConverter"/>
  <!-- 2.設定自定義Converter服務bean -->
  <bean id="conversionService"
        class="org.springframework.context.support.ConversionServiceFactoryBean">
      <!-- 3.注入所有的自定義Converter,該設定使用的是同型別覆蓋的思想 -->
      <property name="converters">
          <!-- 4.set保障同型別轉換器僅保留一個,去重規則以Converter<S,T>的泛型為準 -->
          <set>
              <!-- 5.具體的型別轉換器 -->
              <ref bean="myDateConverter"/>
          </set>
      </property>
  </bean>
  • 實現類:
// 自定義型別轉換器,實現Converter介面,介面中指定的泛型即為最終作用的條件
// 本例中的泛型填寫的是<String,Date>,最終出現字串轉日期時,該型別轉換器生效
public class MyDateConverter implements Converter<String, Date> {
    // 重寫介面的抽象方法,引數由泛型決定
    public Date convert(String source) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        // 型別轉換器無法預計使用過程中出現的異常,因此必須在型別轉換器內部捕獲,不允許丟擲,框架無法預計此類異常如何處理
        try {
            date = df.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

2)通過註冊自定義轉換器,將該功能加入到 SpringMVC 的轉換服務 ConverterService 中:

<!-- 開啟註解驅動,載入自定義格式化轉換器對應的型別轉換服務 -->
<mvc:annotation-driven conversion-service="conversionService"/>

響應

頁面跳轉:轉發與重定向

    // 轉發
    @RequestMapping("/showPage1")
    public String showPage1() {
        System.out.println("user mvc controller is running ...");
        return "forward:page.jsp";  // 支援訪問WEB-INF下的頁面
    }

    // 重定向
    @RequestMapping("/showPage2")
    public String showPage2() {
        System.out.println("user mvc controller is running ...");
        return "redirect:page.jsp";  // 不支援訪問WEB-INF下的頁面
    }

請求轉發與重定向的區別

  • 當使用請求轉發時,Servlet 容器將使用一個內部的方法來呼叫目標頁面,新的頁面繼續處理同一個請求,而瀏覽器將不會知道這個過程(即伺服器行為)。與之相反,重定向的含義是第一個頁面通知瀏覽器傳送一個新的頁面請求。因為當使用重定向時,瀏覽器中所顯示的 URL 會變成新頁面的 URL(瀏覽器行為)。而當使用轉發時,該 URL 會保持不變。

  • 重定向的速度比轉發慢,因為瀏覽器還得發出一個新的請求。

  • 同時,由於重定向產生了一個新的請求,所以經過一次重定向後,第一次請求內的物件將無法使用。

總結

  • 重定向:兩次請求,瀏覽器行為,位址列改變,請求域中的資料會丟失。
  • 請求轉發:一次請求,伺服器行為,位址列不變,請求域中的資料不丟失。

怎麼選擇是重定向還是轉發呢

  • 通常情況下轉發更快,而且能保持請求內的物件,所以它是第一選擇。但是由於在轉發之後,瀏覽器中 URL 仍然指向開始頁面,此時如果過載當前頁面,開始頁面將會被重新呼叫。如果不想看到這樣的情況,則選擇重定向。

  • 不要僅僅為了把變數傳到下一個頁面而使用 session 作用域,那會無故增大變數的作用域,轉發也許可以幫助解決這個問題。

    • 重定向:以前的請求中存放的變數全部失效,並進入一個新的請求作用域。
    • 轉發:以前的請求中存放的變數不會失效,就像把兩個頁面拼到了一起。

頁面訪問快捷設定(InternalResourceViewResolver)

通常,展示頁面的儲存位置比較固定且結構相似,因此可以設定通用的訪問路徑,來簡化頁面配置。

image

示例

<!-- 設定頁面載入的字首字尾,僅適用於預設形式,不適用於手工標註轉發或重定向的方式 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/"/>
    <property name="suffix" value=".jsp"/>
</bean>
public String showPage3() {
    return "page";
}

而如果未設定返回值,使用 void 型別,則預設使用訪問路徑來拼接前字尾:

// 最簡頁面配置方式:使用訪問路徑作為返回的頁面名稱,省略返回值
@RequestMapping("/showPage5")
public void showPage5() {
    System.out.println("user mvc controller is running ...");
}

帶資料頁面跳轉

public class Book {
    private String name;
    private Double price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
import com.bean.Book;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

@Controller
public class BookController {

    // 使用原生response物件響應資料
    @RequestMapping("/showData1")
    public void showData1(HttpServletResponse response) throws IOException {
        response.getWriter().write("message");
    }
	
    // 使用原生request物件傳遞引數
    @RequestMapping("/showPageAndData1")
    public String showPageAndData1(HttpServletRequest request) {
        request.setAttribute("name", "xiaoming");
        return "page";
    }
    
    // 使用Model形參傳遞引數
    @RequestMapping("/showPageAndData2")
    public String showPageAndData2(Model model) {
        Book book  = new Book();
        book.setName("SpringMVC入門案例");
        book.setPrice(66.66d);
        // 新增資料的方式
        model.addAttribute("name", "xiaoming");
        model.addAttribute("book", book);
        return "page";
    }

    // 使用ModelAndView形參傳遞引數,該物件還封裝了頁面資訊
    @RequestMapping("/showPageAndData3")
    public ModelAndView showPageAndData3(ModelAndView modelAndView) {
        // ModelAndView mav = new ModelAndView();  // 替換形參中的引數
        Book book = new Book();
        book.setName("SpringMVC入門案例");
        book.setPrice(66.66d);
        // 新增資料的方式
        modelAndView.addObject("book", book);
        modelAndView.addObject("name", "xiaoming");
        // 設定返回頁面(若該方法存在多個,則以最後一個為準)
        modelAndView.setViewName("page");
        // 返回值設定成ModelAndView物件
        return modelAndView;
    }

    // ModelAndView物件支援轉發的手工設定,該設定不會啟用字首字尾的頁面拼接格式
    @RequestMapping("/showPageAndData4")
    public ModelAndView showPageAndData4(ModelAndView modelAndView) {
        modelAndView.setViewName("forward:/WEB-INF/pages/page.jsp");
        return modelAndView;
    }

    // ModelAndView物件支援重定向的手工設定,該設定不會啟用字首字尾的頁面拼接格式
    @RequestMapping("/showPageAndData5")
    public ModelAndView showPageAndData6(ModelAndView modelAndView) {
        modelAndView.setViewName("redirect:index.jsp");
        return modelAndView;
    }

}

返回 JSON 資料

  • 匯入 maven 座標:
        <!--json相關座標3個-->
        <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>
  • Controller:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;


    // 使用@ResponseBody將返回的結果作為響應內容,而非響應的頁面名稱
    @RequestMapping("/showData2")
    @ResponseBody
    public String showData2(){
        return "{\"name\":\"xiaoming\"}";
    }

    // 使用jackson進行json資料格式轉化(會有中文亂碼問題)
    @RequestMapping("/showData3")
    @ResponseBody
    public String showData3() throws JsonProcessingException {
        Book book  = new Book();
        book.setName("SpringMVC入門案例");
        book.setPrice(66.66d);
        ObjectMapper om = new ObjectMapper();
        return om.writeValueAsString(book);
    }

    /*
    <!--開啟springmvc註解驅動,對@ResponseBody的註解進行格式增強,追加其型別轉換的功能,具體實現由MappingJackson2HttpMessageConverter進行-->
    <mvc:annotation-driven/>
     */
    // 使用SpringMVC註解驅動,對標註@ResponseBody註解的控制器方法進行結果轉換
    // 由於返回值為引用型別,自動呼叫jackson提供的型別轉換器進行格式轉換
    @RequestMapping("/showData4")
    @ResponseBody
    public Book showData4() {
        Book book  = new Book();
        book.setName("SpringMVC入門案例");
        book.setPrice(66.66d);
        return book;
    }

    // 轉換集合型別資料
    @RequestMapping("/showData5")
    @ResponseBody
    public List showData5() {
        Book book1 = new Book();
        book1.setName("SpringMVC入門案例");
        book1.setPrice(66.66d);

        Book book2 = new Book();
        book2.setName("SpringMVC入門案例");
        book2.setPrice(66.66d);

        ArrayList<Book> al = new ArrayList<>();
        al.add(book1);
        al.add(book2);
        return al;  // 返回 [{"name":"SpringMVC入門案例","price":66.66},{"name":"SpringMVC入門案例","price":66.66}]
    }

Servlet 相關介面

SpringMVC 提供訪問原始 Servlet 介面 API 的功能,通過形參宣告即可。

    @RequestMapping("/servletApi")
    public String servletApi(HttpServletRequest request,
            HttpServletResponse response, HttpSession session){
        System.out.println(request);  // org.apache.catalina.connector.RequestFacade@6d3a1615
        System.out.println(response);  // org.apache.catalina.connector.ResponseFacade@55405578
        System.out.println(session);  // org.apache.catalina.session.StandardSessionFacade@714a7020
        request.setAttribute("name", "xiaoming");
        System.out.println(request.getAttribute("name"));  // xiaoming
        return "page.jsp";
    }

Header 資料獲取:

  • 名稱:@RequestHeader
  • 型別:形參註解
  • 位置:處理器類中的方法形參前方
  • 作用:繫結請求頭資料與對應處理方法形參間的關係
    // header 資料獲取
    @RequestMapping("/headApi")
    public String headApi(@RequestHeader("Accept-Language") String head){
        System.out.println(head);  // zh-CN,zh;q=0.9
        return "page.jsp";
    }

Cookie 資料獲取:

  • 名稱:@CookieValue
  • 型別:形參註解
  • 位置:處理器類中的方法形參前方
  • 作用:繫結請求 Cookie 資料與對應處理方法形參間的關係
    // cookie 資料獲取
    @RequestMapping("/cookieApi")
    public String cookieApi(@CookieValue("JSESSIONID") String jsessionid){
        System.out.println(jsessionid);
        return "page.jsp";
    }

Session 資料獲取:

  • 名稱:@SessionAttribute
  • 型別:形參註解
  • 位置:處理器類中的方法形參前方
  • 作用:繫結請求 Session 資料與對應處理方法形參間的關係
    // 測試用方法,為下面的試驗服務,用於在session中放入資料
    @RequestMapping("/setSessionData")
    public String setSessionData(HttpSession session){
        session.setAttribute("name", "xiaoming");
        return "page";
    }

    // session 資料獲取
    @RequestMapping("/sessionApi")
    public String sessionApi(@SessionAttribute("name") String name){
        System.out.println(name);  // 獲取session中的name值
        return "page.jsp";
    }

Session 資料設定:

  • 名稱:@SessionAttributes
  • 型別:類註解
  • 位置:處理器類上方
  • 作用:宣告放入 session 範圍的變數名稱,適用於 Model 型別資料傳參
@Controller
// 設定當前類中名稱為age和gender的變數放入session範圍(不常用,瞭解即可)
@SessionAttributes(names={"age","gender"})
public class ServletController {
	
    // 配合 @SessionAttributes(names={"age","gender"}) 使用
    // 將資料放入session儲存範圍,通過Model物件實現資料set,通過@SessionAttributes註解實現範圍設定
    @RequestMapping("/setSessionData2")
    public String setSessionDate2(Model model) {
        model.addAttribute("age",39);
        model.addAttribute("gender","男");
        return "page.jsp";
    }
}

相關文章