學習SpringMVC必知必會(3)~springmvc的請求和響應

一、處理器方法響應處理

Controller方法該怎麼返回、Controller數據該怎麼進行共享

  • 返回void/ModelAndView/String

1、Controller方法返回void

	//返回void類型,此時可以把Controller方法當做Servlet使用【適合用來下載文件】
	@RequestMapping("/test1")
	public void test(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//請求轉發
		request.getRequestDispatcher("/WEB-INF/views/welcome.jsp").forward(request, response);
		//設置共享數據
		request.setAttribute("msg", "hello");
		//輸出json格式
		response.setContentType("text/json;charset=utf-8");
		response.getWriter().println();	
	}

2、【常用】返回ModelAndView

	//返回ModelAndView
	@RequestMapping("/test3")
	public ModelAndView test3() {
		ModelAndView mv = new ModelAndView();
		//設置視圖名稱
//		mv.setViewName("/WEB-INF/views/welcome.jsp");
		mv.setViewName("welcome");
		mv.addObject("msg", "返回ModelNAndView");//設置共享數據的key和value
		mv.addObject("叩丁狼教育");//設置共享數據的value,此時會把value類型的首字母作為key:string
		return mv;
	}

3、【常用】返回String類型(是邏輯視圖名稱),參數是Model類型(是共享數據)

	//返回string,邏輯視圖名稱,此時需要結合參數Model類型 一起使用
	@RequestMapping("/test4")
	public String test4(Model model) {
		//設置共享數據
		model.addAttribute("叩丁狼");
		model.addAttribute("msg", "教育");
		return "welcome";//設置跳轉的視圖
	}

二、請求跳轉

  • 請求轉發、URL重定向、URL重定向共享數據

1、請求轉發

	//請求轉發,瀏覽器地址欄不變,可以共享請求中的數據
	//原理:request.getRequestDispatcher("").forward(request, response);
	@RequestMapping("/test5")
	public String test5(Model model) {
		return "forward:/hello.jsp";//設置跳轉的視圖
	}

2、URL重定向

	//重定向,瀏覽器地址欄改變,不能共享請求中的數據
	//原理:request.sendRedirect("");
	@RequestMapping("/test6")
	public String test6(Model model) {
		return "redirect:/hello.jsp";//設置跳轉的視圖
	}

■ 請求資源的路徑問題:[總結:訪問資源的時候,都使用/開頭]

  • 訪問資源的時候前面帶上/,表示絕對路徑,根路徑開始去尋找資源
  • 訪問資源的時候簽名不加/,表示相對路徑,上一級上下文路徑中去尋找資源

✿ 請求轉發和URL重定向的選擇:

請求轉發/URL重定向 請求轉發 URL重定向
地址欄改變? 不會 會改變
共享數據? 可以 不可以?
表單重複提交? 會發生 不會發生
  • 傳統的方式,在url重定向的時候,因為是兩次不同的請求,所以不能共享請求中的數據。

    在開發中,有時候真的需要重定向跳轉後共享數據————spring3.1開始,提供了Flash屬性。
    只能是從Controller 重定向到 Controller,不能到jsp

3、URL重定向共享數據

	//重定向:從a跳轉到b	
	@RequestMapping("/a")
	public String a(RedirectAttributes ra) {
		ra.addAttribute("msg1", "a傳遞的數據");
		ra.addFlashAttribute("msg2", "msg2");
		return "redirect:/response/b";//設置跳轉的視圖
	}
	
	@RequestMapping("/b")
	public ModelAndView b(String msg1, @ModelAttribute("msg2") String msg2) {
		System.out.println("msg1:" + msg1);
		System.out.println("msg2:" + msg2);
		return null;
	}

  • 重定向共享數據的原理:更大的作用域–session

image

三、處理器方法參數處理(接收請求參數的處理

  • 處理器方法的請求參數該怎麼攜帶、請求參數該怎麼獲取

1、request 和 response 參數

■ 情況一:為了操作Servlet API 對象,此時可以直接以參數形式傳遞,也可以直接使用DI注入。

@Controller
@RequestMapping("/request")
public class HandlerRequestController {

	@Autowired
	private ServletContext context;
	
	@RequestMapping("/test1")
	public void test(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws ServletException, IOException {
		System.out.println("request:" + request);
		System.out.println("response:" + response);
		System.out.println("session:" + session);
		System.out.println("ServletContext:" + this.context);
		
	}
}
  • request、response、session:建議使用參數
  • context 上下文:單例,建議使用屬性,注入

因為Controller(Servlet) 是單例的,執行緒不安全,一般不用成員變數,除非要共享的數據,才作為成員變數。

2、簡單類型參數

  • 處理簡單類型的請求參數

■ 獲取請求參數:【保證輸入的參數和定義的形參名稱一致】

	//獲取請求參數:通過保證請求參數名稱和Controller方法定義的形參(入參)同名即可
	@RequestMapping("/test2")
	public void test2(String username, int age)  {
		System.out.println(username);
		System.out.println(age);
	}

image

■ 獲取請求參數:【輸入的參數和定義的形參名稱不一致】—-註解@RequestParam

	//獲取請求參數:若請求參數和請求參數名稱和形參不同----註解@RequestParam
	@RequestMapping("/test3")
	public void test3(@RequestParam("name") String username, @RequestParam(value="age",required=false) Integer age)  {
		System.out.println("username:" +username);
		System.out.println("age:" + age);
	}

3、中文亂碼處理

■ 在”全局配置”【web.xml】,添加上編碼過濾器:

	<!-- (針對post請求)配置過濾器 -->
	<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>

4、restfull風格傳參

  • restfull 風格:軟體架構風格,嚴格講是一種編碼風格,充分利用http協議本身的語義,從而提供一些設計原則和約束條件,主要是用來作為客戶端和服務端的交互。
  • 簡潔、有層次、容易實現快取機制
	//restfull風格傳遞參數
	//PathVariable: 可以將url中佔位符綁定到方法的形參中
	@RequestMapping("/r/{id}")
	public ModelAndView rest(@PathVariable("id") Integer id) {
		System.out.println("id:" + id);
		return null;
	}

5、數組和List類型參數

	//接收一個參數有很多值的情況
	//使用數組:可以直接接收  Long[] ids
	//使用List: 不可以直接接收,可以在對象中存在一個集合   List<Long> ids
	@RequestMapping("/batchDelete") //batchDelete?ids=10&ids=20&ids=30
	public void batchDelete(FormBean fb) {
		System.out.println(fb.getIds());	
	}
★ 操作一個參數有多個值的情況,一般直接使用數組接收即可,或者使用javaBean對象來封裝數據。

6、■ 獲取請求參數:

JavaBean類型參數【將請求參數封裝成一個對象

	//封裝成一個對象
	@RequestMapping("/bean") //batchDelete?ids=10&ids=20&ids=30
	public void bean(User user) {
		System.out.println(user);	
	}

  • 請求參數封裝成javaBean對象,瀏覽器地址欄直接輸入參數為對象的屬性即可.

image

✿ 總結處理器方法參數處理:

1、直接把請求參數封裝成javaBean對象
2、配置解決中文亂碼的過濾器
3、簡單類型參數—-輸入參數名和定義的形參不同-> @ResultParam
4、使用數組接收多個參數
5、restfull風格傳參

四、ModelAttribute

  • 給共享的model數據設置key名,貼在形參上,也可以貼在方法上,

    針對複合類型參數,預設情況下就會放到model中(共享), 預設的key就是類型首字母小寫

    • 使用註解 @ModelAttribute,起個別名
	//ModelAttribute註解:
	/*
	 *1、給共享的model數據設置key名,貼在形參上,也可以貼在方法上
	 *	針對複合類型(非簡單類型)參數,預設情況下就會放到model中(共享), 預設的key就是類型首字母小寫
	 * 2、可以標註一個非請求處理的方法,被標註的方法,每次在請求處理方法之前都會優先被執行[存放多個請求需要共享的數據]
	 */
	@RequestMapping("/test11")
	public String test1(@ModelAttribute("u") User user)  {
		System.out.println(user);
		return "welcome";
	}

五、其他請求資訊

1、獲取請求頭 @RequestHeader

	@RequestMapping("/test1")
	public ModelAndView test1(@RequestHeader("User-Agent") String userAgent) {
		System.out.println("test1");
		System.out.println("User-Agent:" + userAgent);
		return null;
	}

2、獲取Cookie @CookieValue

	@RequestMapping("/test1")
	public ModelAndView test1(@RequestHeader("User-Agent") String userAgent, @CookieValue("Webstorm-5895a979") String cName) {
		System.out.println("test1");
		System.out.println("User-Agent:" + userAgent);
		System.out.println("cName:" + cName);
		return null;
	}

3、操作HttpSession @SessionAttributes

  • 默認情況下模型數據是保存到 request 作用域的
@Controller
@RequestMapping("/other")
@SessionAttributes("errMsg")
public class OtherController {

	@RequestMapping("/test2")
	public String test2(Model model) {
		System.out.println("操作session");
		model.addAttribute("errMsg", "錯誤資訊");
		return "redirect:/hello.jsp";
	}
}

六、數據綁定流程

image

1、框架把 ServletRequest 對象和請求參數傳遞給 DataBinder

2、DataBinder 首先調用 Spring Web 環境中的 ConversionService 組件,進行數據類型轉換和格式化等操作,將 ServletRequest 中的資訊填充到形參對象中;

3、DataBinder 然後調用 Validator 組件對已經綁定了請求消息數據的形參對象進行數據合法性校驗

4、DataBinder 最後輸出數據綁定結果對象 BindingResult

  • BindingResult 包含了已完成數據綁定的形參對象和校驗錯誤資訊對象

七、多對象封裝傳參

	/*
	 * 需要吧表單數據封裝到多個對象中去,若各個對象有相同的屬性時
	 * 不知道該把哪一個參數封裝到哪一個對象
	 */
	@RequestMapping("/save")
	public ModelAndView save(Cat cat, Dog dog) {
		System.out.println("提交數據");
		System.out.println(cat);
		System.out.println(dog);
		return null;
	}
  • input.jsp 傳遞多個對象的參數時:
	<form action="/save" method="post">
		貓名:<input type="text" name="name" /><br/>
		貓年齡:<input type="text" name="age" /><br/>
		狗名:<input type="text" name="name" /><br/>
		狗年齡:<input type="text" name="age" /><br/>
		<input type="submit" value="提交">
	</form>

image

解決:

  • input.jsp:加上前綴做區分
	<form action="/save" method="post">
		貓名:<input type="text" name="cat.name" /><br/>
		貓年齡:<input type="text" name="cat.age" /><br/>
		狗名:<input type="text" name="dog.name" /><br/>
		狗年齡:<input type="text" name="dog.age" /><br/>
		<input type="submit" value="提交">
	</form>
  • 處理器Controller添加方法:
	//從參數--> 對象,封裝規則需要我們來設置
	
	//自定義數據綁定註冊,將請求參數轉化成對應對象的屬性
	@InitBinder("cat")
	public void initBinderCat(WebDataBinder binder) {
		//設置欄位以什麼做為前綴
		binder.setFieldDefaultPrefix("cat.");
	}
	
	@InitBinder("dog")
	public void initBinderDog(WebDataBinder binder) {
		//設置欄位以什麼做為前綴
		binder.setFieldDefaultPrefix("dog.");
	}

image

八、JSON數據處理

  • JSON處理

1、依賴:

  • jackson-annotations-2.12.2.jar
  • jackson-core-2.12.2.jar
  • jackson-databind-2.12.2.jar

2、處理json的註解 @ResponseBody @RestController @RequestBody

(1) @ResponseBody: 處理響應,把對象轉化成json字元串

  • @ResponseBody 處理響應,把對象轉化成json字元串
    • 貼到方法上:只會針對當前方法做json處理
    • 貼到類上:會對當前類中所有方法做json處理
	//把單個對象/Map轉化成json格式
	@RequestMapping("/test1")
	@ResponseBody
	public User test1() {
		User u = new User();
		u.setUsername("shan");
		u.setAge(18);
		return u;
	}
	
	//把多個對象轉化成json格式
	@RequestMapping("/test2")
	@ResponseBody
	public List<User> test2() {
		User u = new User();
		u.setUsername("shan");
		u.setAge(18);
		return Arrays.asList(u, u, u);
	}


	//返回一個String,默認返回字元串是邏輯視圖名稱,加上@ResponseBody,當做json格式的數據
	@RequestMapping(value="/test3", produces="application/json;charset=utf-8")
	@ResponseBody
	public String test3() {
		return "success, 你好~";
	}

(2) @RestController = @Controller + @ResponseBody

(3) @RequestBody

  • @RequestBody: 處理請求,用於讀取Http請求的內容,把json格式的請求數據封裝成對象
    • application/x-www-form-urlencoded: 表單提交用得比較多,是傳統的key-value格式,處理起來非常方便,無需RequestBody都可以,貼上也可以
    • application/multipart: 文件上傳的請求,springmvc 裝飾設計模式,既可以處理文件上傳,也可以處理表單數據
    • application/json: 參數是json格式的,此時必須使用RequestBody\
    • application/xml

九、日期類型處理

1、前台往後台傳參轉化為Date類型

★ 時間格式的註解:@DateTimeFormat

  • 注意細節:時間Date在util包(java中常用)有,在sql包也有,使用快捷鍵導包的時候可能會默認自動報錯包~
	//從前台---->後台傳遞參數 java.lang.String -> java.util.Date
	//請求參數是Date類型
	@RequestMapping("/test1")
	public ModelAndView test(@DateTimeFormat(pattern = "yyyy-MM-dd")Date date) {
		System.out.println("date:" + date);
		if(date instanceof Date) {
			System.out.println("yes");
		}
		return null;
	}

  • 對象的屬性有時間Date類型的,方式一:貼註解 @DateTimeFormat

    ◆ 方式二:數據綁定的時候處理,通過@InitBinder定義處理時間格式的方法

	@InitBinder
	public void initBinder(WebDataBinder binder) {
		//日期格式
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		//屬性編輯器
		binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(sdf, true));
	}
  • 讓項目中的所有用到時間格式的類都使用到咱定義的處理時間格式的方法,咱將方法抽離出去,定義成一個類,貼上註解處理增強 @ControllerAdvice

    只要抽離的類在ioc的註解驅動掃描範圍內,即可~

@ControllerAdvice
public class DateFormateAdvice {

	@InitBinder
	public void initBinder(WebDataBinder binder) {
		//日期格式
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		//屬性編輯器
		binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(sdf, true));
	}
}

2、jsp中顯示時間格式:將歐美時間格式–>中國時間格式

(1)導入jar包[tomcat伺服器examples案例下的lib就有]:

  • taglibs-standard-impl-1.2.5.jar
  • taglibs-standard-spec-1.2.5.jar

(2)配置引入標籤庫taglib

<%@taglib uri="//java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 

(3) 使用jstl:

	<% pageContext.setAttribute("myDate", new java.util.Date()); %>	
	北京時間: <fmt:formatDate value="${myDate}" pattern="yyyy=MM-dd HH:mm:ss"/>

image

3、後台往前台響應JSON時—Date類型

(1)方法1:在springmvc框架配置中添加json類型轉化相關的配置[配置全局解析器]:

	<!-- MVC註解解析器 -->
	<mvc:annotation-driven>
		<mvc:message-converters>
			<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
				<property name="objectMapper">
					<bean class="com.fasterxml.jackson.databind.ObjectMapper">
						<property name="dateFormat">
							<bean class="java.text.SimpleDateFormat">
								<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />
							</bean>
						</property>
					</bean>
				</property>
			</bean>
		</mvc:message-converters>
	</mvc:annotation-driven>

(2)方式2:使用註解@JsonFormat

@Data
public class User {
	private Long id;
	private String username;
	private Integer age;
	//@DateTimeFormat(pattern = "yyyy-MM-dd")
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
	private Date hireDate;	
}

★ 注意:@DateTimeFormat前台往後台傳參【前台String類型-》後台Date類型】

★ 注意: 是後台響應給前台,響應為json格式(對時間Date類型的處理)

如果本文對你有幫助的話記得給一樂點個贊哦,感謝!