SpringMVC 註解實現參數映射
參考資料:https://spring-mvc.linesh.tw/
1. 請求參數映射
@RequestMapping
註解的作用是建立請求 URL 和處理方法之間數據的對應關係。
該註解可以作用在方法和類上:
- 作用在類上:一級訪問目錄
- 作用在方法上:二級訪問目錄
注意:/ 表示應用的根目錄開始,路徑上不能只寫一個 /
1.1 RequestMapping
屬性:
path: 指定請求路徑的 url
value: value 屬性和 path 屬性是一樣的
method: 指定該方法的請求方式
params: 指定限制請求參數的條件
headers: 發送的請求中必須包含的請求頭
1.2 請求參數的映射
映射機制:
表單提交的數據都是 k=v 格式的,如 username=jack&password=123
SpringMVC 的參數映射過程是把表單提交的請求參數,作爲控制器中方法的參數進行映射的
映射要求:
提交表單的 name屬性 和 形參的名稱 必須相同
,否則獲取到的爲 null。
支持類型:
- 基本數據類型和字符串類型
- 實體類型(JavaBean)
- 集合數據類型(List、map集合等)
- 日期類型轉換處理(Date)
1.2.1 基本類型/字符串屬性封裝
提交表單的name和參數的名稱必須相同
的,區分大小寫。
1.2.2 實體類屬性封裝
要求提交表單的 name 和 JavaBean 中的屬性名稱需要一致,如果一個 JavaBean 類中包含其他的引用類型,那麼表單的name屬性需要編寫成:對象.屬性
1.2.3 集合屬性封裝
list[index].屬性名
map['key'].屬性名
注意:如果請求參數是中文,可以在 web.xml 中配置 Spring 提供的字符集過濾器來解決中文亂碼問題
User
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private List<Car> carList;
private Map<String, Car> carMap;
private Date birth;
}
UserController
@Controller // spring 三層中的控制層註解
@RequestMapping("/user") // 類上:指定控制器即 Servlet 的一級目錄
public class UserController {
// <a href="user/login">登陸1</a>
@RequestMapping("/login") // 方法上:指定控制器即 Servlet 的二級目錄
public String login() {
System.out.println("login...");
return "/success.jsp";
}
//name=id 與形參 id 相同: <a href="user/test_param?id=2001">登陸2</a>
@RequestMapping("/test_param")
public void test_param(String id) {
System.out.println("id=" + id);
}
// @RequestParam 註解映射 name 名稱爲相同:<a href="user/test_param2?id=2001&name=張三">登陸3</a>
@RequestMapping("/test_param2")
public void test_param2(@RequestParam("id") String uid, String name) {
System.out.println("uid=" + uid + ", name=" + name);
}
/**
* 實體類型 + 集合類型 + 日期類型的映射
* <form action="user/test_entity" method="get">
* 編號:<input type="text" name="id"> <br>
* 姓名:<input type="text" name="username"> <br>
* 密碼:<input type="password" name="password"> <br>
* list:<input type="text" name="carList[1].cname"> <br>
* list:<input type="text" name="carList[2].cname"> <br>
* map: <input type="text" name="carMap['mycar'].cname"> <br>
*
* date:<input type="date" name="birth">
* <input type="submit">
* </form>
*/
@RequestMapping("/test_entity")
public void test_entity(User user) {
System.out.println(user);
}
}
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>
<!--配置中文亂碼過濾器-->
<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>
<!--配置前端控制器-->
<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:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springmvc.xml
<!--開啓註解掃描-->
<context:component-scan base-package="com.demo"/>
<!--視圖解析對象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp"/>
</bean>
<!--開啓SpringMVC框架註解支持-->
<mvc:annotation-driven/>
1.2.4 Date類型封裝
如果對象的屬性中有Date類型,頁面輸入參數格式是 2019/1/1 可以自動參數映射,如果頁面輸入參數格式是 2019-1-1 則無法映射,需要使用自定義類型轉換器來解決。
注意:表單提交的任何數據類型全部都是字符串類型,但是後臺定義 Integer 類型,數據也可以封裝上,說明 Spring 框架內部會默認進行數據類型轉換。
如果想自定義數據類型轉換,可以實現 Converter 的接口
。
- 創建日期轉換工具類
//把字符串轉換日期
public class StringToDateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
if ("".equals(s)) {
throw new RuntimeException("日期字符串不能爲空");
}
try {
return new SimpleDateFormat("yyyy-MM-dd").parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
throw new RuntimeException("日期類型轉換異常");
}
}
- 修改 springmvc.xml
<!--開啓註解掃描-->
<context:component-scan base-package="com.demo"/>
<!--視圖解析對象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp"/>
</bean>
<!--配置自定義類型轉換器 - 解決日期轉換問題-->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.demo.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!--開啓SpringMVC框架註解支持-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>
1.3 常用註解
-
@RequestParam 註解
作用:把請求中的指定名稱的參數傳遞給控制器中的形參賦值- value:請求參數中的名稱
- required:請求參數中是否必須提供此參數,默認值是true,必須提供
-
@PathVariable 註解
作用:擁有映射 url 中的佔位符的。url 中有 /delete/{id} ,{id} 就是佔位符,也叫URI模板
- value:指定 url 中的佔位符名稱
jsp:
<a href="user/testPathVariable/123">testPathVariable</a>
controller:
@RequestMapping(value="/testPathVariable/{uid}")
public String testPathVariable(@PathVariable(name="uid") String id){
System.out.println(id); // 123
return "success";
}
Restful 風格的 URL,即通過 PathVariable 實現:
請求路徑一樣,可以根據不同的請求方式去執行後臺的不同方法,如京東的商品鏈接…
restful風格的URL優點:結構清晰、符合標準、易於理解、擴展方便
1.4 其他註解
- @RequestHeader 註解
作用:獲取指定請求頭的值- value:請求頭的名稱
jsp:
<a href="user/testRequestHeader">RequestHeader</a>
controller:
@RequestMapping(value="/testRequestHeader")
public String testRequestHeader(@RequestHeader(value="Accept") String header){
System.out.println(header); // 打印 accept 的頭信息
return "success";
}
- @CookieValue 註解
作用:用於獲取指定cookie的名稱的值- value:cookie的名稱
jsp:
<a href="user/testCookieValue">CookieValue</a>
controller:
@RequestMapping(value="/testCookieValue")
public String testCookieValue(@CookieValue(value="JSESSIONID") String cookieValue){
System.out.println(cookieValue); // session id值
return "success";
}
2. 響應數據和結果視圖
2.1 返回值分類
-
String
Controller 方法返回字符串可以指定邏輯視圖的名稱,根據視圖解析器爲物理視圖的地址。
應用時可以設置參數類型爲 Model,使用 Model 對象調用 addAttribute 方法來存儲數據,同 request。request.setAttribute(“data”, data);
model.addAttribute(“data”, data);
-
void
如果控制器的方法返回值編寫成 void,執行程序報 404 的異常,默認查找 JSP 頁面沒有找到。
應用時可以設置參數類型爲 HttpServletRequest 和 HttpServletResponse,使用轉發或者重定向來跳轉頁面 -
ModelAndView
ModelAndView 對象是 Spring 提供的一個對象,可以調用 addObject 方法來保存數據以及調用 setViewName 方法來跳轉頁面。 -
forward: & redirect: 前綴
可以在前端控制器的方法中直接返回 forward: 或 redirect: 爲前綴的路徑字符串,由 SpringMVC 反射中自動解析路徑選擇 轉發或重定向 跳轉頁面。使用forward關鍵字進行請求轉發:return “forward:轉發的JSP路徑”
使用redirect關鍵字進行重定向(
默認會把項目路徑加上
):return “redirect:重定向的JSP路徑”
User
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
}
UserController
@Controller
@RequestMapping("/user")
public class UserController {
public List<User> getUsers() {
List<User> list = new ArrayList<User>();
list.add(new User(1, "aaa", "123"));
list.add(new User(2, "bbb", "456"));
list.add(new User(3, "ccc", "789"));
return list;
}
// String 返回值跳轉
@RequestMapping("/testString")
public String testString(HttpServletRequest request) {
List<User> users = getUsers();
request.setAttribute("users", users);
return "/list.jsp";
}
// void 無返回值跳轉
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<User> users = getUsers();
request.setAttribute("users", users);
request.getRequestDispatcher("/WEB-INF/jsp/list.jsp").forward(request, response);
}
// ModelAndView 返回值跳轉
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
List<User> users = getUsers();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("users", users);
modelAndView.setViewName("/list.jsp");
return modelAndView;
}
// forward / redirect 前綴指定 轉發 或 重定向
@RequestMapping("testForwardAndRedirect")
public String testForwardAndRedirect(HttpServletRequest request) {
List<User> users = getUsers();
request.getSession().setAttribute("users", users);
return "forward:/index.jsp";
//return "redirect:/index.jsp";
}
}
web.xml:中文亂碼過濾器、前端控制器。
springmvc.xml
<!--開啓註解掃描-->
<context:component-scan base-package="com.demo"/>
<!--視圖解析對象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp"/>
</bean>
<!--開啓SpringMVC框架註解支持-->
<mvc:annotation-driven />
3. 配置不攔截靜態資源
DispatcherServlet 會攔截到所有的資源,導致一個問題就是靜態資源 img、css、js 也會被攔截到,從而不能被使用。
解決方案就是需要配置靜態資源不進行攔截,在 springmvc.xml 配置文件添加如下配置:
方式一:<mvc:resources>
+ <servlet-mapping>
<!-- springmvc.xml 前端控制器,哪些靜態資源不攔截-->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<!-- web.xml 配置 servlet 映射,html資源不被攔截 -->
<servlet-mapping>
<serlvet-name>default</serlvet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
方式二:所有靜態資源不被攔截
<!-- springmvc.xml 所有靜態資源不攔截-->
<mvc:default-servlet-handler />