SpringMVC 學談 (第二章)
寫在前面:分享技術,共同進步,有不足請見諒,相關意見可評論告知 ~
程式設計路漫之遠兮,運架構式之簡化
勸君專注案前事,亦是杯酒敬蒼生;
目錄
控制器Controller
概述:控制器負責提供訪問應用程式的行為,通常通過介面定義或註解定義兩種方法實現。
作用:控制器負責解析使用者的請求並將其轉換為一個模型。在Spring MVC中一個控制器類可以包含多個方法,對於Controller的配置方式有很多種
實現Controller介面
Controller是一個介面,在org.springframework.web.servlet.mvc
包下,介面中只有以下一個方法;
//實現該介面的類獲得控制器功能 public interface Controller { //處理請求且返回一個模型與檢視物件 ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception; }
測試
//定義控制器 //注意點:不要導錯包,實現Controller介面,重寫方法; public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //返回一個模型檢視物件 ModelAndView mv = new ModelAndView(); mv.addObject("msg","Test1Controller"); mv.setViewName("test"); return mv; } }
編寫完畢後,去Spring配置檔案中註冊請求的bean
,name
對應請求路徑,class
對應處理請求的類
<bean name="/t1" class="com.kuang.controller.ControllerTest1"/>
編寫前端test.jsp,注意在WEB-INF/jsp目錄下編寫,對應我們的檢視解析器
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>lzh</title>
</head>
<body>
${msg}
</body>
</html>
注意:實現介面Controller定義控制器是較老的辦法
缺點:一個控制器中只有一個方法,如果要多個方法則需要定義多個Controller;定義的方式比較麻煩;
Tips:
@Component 元件
@Service service
@Controller controller
@Repository daoMVVM: M V VM(ViewModel雙向繫結)
類上標註@Controller 且方法上沒有標註@ResponseBody,return的值會被檢視解析器處理-----> 被此註解標註的類,所有方法,如果返回值式String ,並且有具體的夜面可以跳轉,那麼就會被檢視解析器解析
使用註解編寫(重要)
@Controller操作
可見Spring學記 (第二章)
跳轉
@Controller
註解型別用於宣告Spring類的例項是一個控制器(IOC還有另外3個註解);
1、Spring可以使用掃描機制來找到應用程式中所有基於註解的控制器類,為了保證Spring能找到控制器,需要在配置檔案中宣告元件掃描。
<!-- 自動掃描指定的包,下面所有註解類交給IOC容器管理 -->
<context:component-scan base-package="com.kuang.controller"/>
2、增加一個ControllerTest2類,使用註解實現;
//@Controller註解的類會自動新增到Spring上下文中
@Controller
public class ControllerTest2{
//對映訪問路徑
@RequestMapping("/t2")
public String index(Model model){
//Spring MVC會自動例項化一個Model物件用於向檢視中傳值
model.addAttribute("msg", "ControllerTest2");
//返回檢視位置
return "test";
}
}
3、執行tomcat測試
總結:我們的兩個請求都可以指向一個檢視,但是頁面結果的結果是不一樣的,從這裡可以看出檢視是被複用的,而控制器與檢視之間是弱偶合關係。
@RequestMapping操作
@RequestMapping
註解用於對映url到控制器類或一個特定的處理程式方法。可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。
①只註解在方法上面情況
@Controller
public class TestController {
@RequestMapping("/h1")
public String test(){
return "test";
}
}
訪問路徑:http://localhost:8080 / 專案名 / h1
專案名 ---> Application.context
②同時註解類與方法
@Controller
@RequestMapping("/admin")
public class TestController {
@RequestMapping("/h1")
public String test(){
return "test";
}
}
訪問路徑:http://localhost:8080 / 專案名/ admin /h1 , 需要先指定類的路徑再指定方法的路徑;
RestFul 風格
概念:Restful就是一個資源定位及資源操作的風格。基於這個風格設計的軟體可以更簡潔,更有層次,更易於實現快取等機制。
資源操作:使用POST、DELETE、PUT、GET,使用不同方法對資源進行操作。
傳統方式
操作資源 :通過不同的引數(post 和 get)來實現不同的效果
http://127.0.0.1/item/queryItem.action?id=1 查詢,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 刪除,GET或POST
實際程式碼:
實際效果:
使用RestFul
使用RESTful操作資源 :可以通過不同的請求方式來實現不同的效果
http://127.0.0.1/item/1 查詢,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 刪除,DELETE
實際測試:
程式碼:
實際效果圖:
路徑變數的優點:
(1)使路徑變得更加簡潔;
(2)獲得引數更加方便,框架會自動進行型別轉換。
(3)通過路徑變數的型別可以約束訪問引數,如果型別不一樣,則訪問不到對應的請求方法,
深入測試:
//對映訪問路徑
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable String p2, Model model){
String result = p1+p2;
//Spring MVC會自動例項化一個Model物件用於向檢視中傳值
model.addAttribute("msg", "結果:"+result);
//返回檢視位置
return "test";
}
使用method屬性指定請求型別
用於約束請求的型別,可以收窄請求範圍。指定請求謂詞的型別如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
//對映訪問路徑,必須是POST請求
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
public String index2(Model model){
model.addAttribute("msg", "hello!");
return "test";
}
如果使用瀏覽器位址列進行訪問預設是Get請求,會報錯405:
解法:將POST修改為GET則正常了;
//對映訪問路徑,必須是Get請求
@RequestMapping(value = "/hello",method = {RequestMethod.GET})
public String index2(Model model){
model.addAttribute("msg", "hello!");
return "test";
}
總結
(1)Spring MVC 的 @RequestMapping
註解能夠處理 HTTP 請求的方法(GET, PUT, POST, DELETE ,PATCH)。所有的位址列請求預設都會是 HTTP GET 型別的。
(2)方法級別的註解變體有如下幾個:組合註解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一個組合註解,常用,實質 @RequestMapping(method =RequestMethod.GET) 的一個快捷方式。
結果跳轉方式
ModelAndView
設定ModelAndView
物件 , 根據view的名稱 , 和檢視解析器跳到指定的頁面 .
頁面 : {檢視解析器字首} + viewName +{檢視解析器字尾}
<!-- 檢視解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 字首 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 字尾 -->
<property name="suffix" value=".jsp" />
</bean>
對應的controller類
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一個模型檢視物件
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
ServletAPI
通過設定ServletAPI , 不需要檢視解析器 .
1、通過HttpServletResponse進行輸出
2、通過HttpServletResponse實現重定向
3、通過HttpServletResponse實現轉發
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//轉發
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
SpringMVC(重要)
通過SpringMVC來實現轉發和重定向 - 無需檢視解析器;
測試前,需要將檢視解析器註釋掉
注意區分轉發與重定向
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//轉發
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//轉發二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
通過SpringMVC來實現轉發和重定向 - 有檢視解析器;
重定向不需要檢視解析器 , 本質就是重新請求一個新地方 , 所以注意路徑問題.
可以重定向到另外一個請求實現 .
Tips:
重定向不能訪問WEB-INF下的資源
轉發才會觸發檢視解析器拼接,重定向不會觸發
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//轉發
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; //hello.do為另一個請求/
}
}
資料處理
處理提交資料
1、提交的域名稱和處理方法的引數名一致
提交資料 : http://localhost:8080/hello?name=lzh
處理方法 :
@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return "hello";
}
實際程式碼:
後臺輸出 : lzh
2、提交的域名稱和處理方法的引數名不一致
username提交的域的名稱
name處理方法的引數名
提交資料 : http://localhost:8080/hello?username=lzhCreate
處理方法 :
//@RequestParam("username") : username提交的域的名稱 .
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){
System.out.println(name);
return "hello";
}
後臺輸出 : lzhCreate
3、提交的是一個物件
要求提交的表單域和物件的屬性名一致 , 引數使用物件即可
關於lombok再述
@Data 只有get post toString()
所以常在下補充
@AllArgsConstructor
@NoArgsConstructor
1、實體類
public class User {
private int id;
private String name;
private int age;
//構造
//get/set
//tostring()
}
2、提交資料 : http://localhost:8080/mvc04/user?name=lzh&id=1&age=15
3、處理方法 :
@RequestMapping("/user")
public String user(User user){
System.out.println(user);
return "hello";
}
後臺輸出 : User { id=1, name='lzh', age=15 }
注意i:如果使用物件的話,前端傳遞的引數名和物件名必須一致,否則就是null。
資料顯示到前端
第一種 : 通過ModelAndView
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一個模型檢視物件
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
第二種 : 通過ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封裝要顯示到檢視中的資料
//相當於req.setAttribute("name",name);
model.addAttribute("name",name);
System.out.println(name);
return "hello";
}
加上引數@RequestParam("username")
代表一定從前端所接收
第三種 : 通過Model
第三種:Model
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
//封裝要顯示到檢視中的資料
//相當於req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
三者對比總結
Model
只有幾個方法只適合用於儲存資料,簡化了對於Model物件的操作和理解;
ModelMap
繼承了 LinkedMap ,除了實現了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;
ModelAndView
可以在儲存資料的同時,可以進行設定返回的邏輯檢視,進行控制展示層的跳轉。(不常用)
常見異常即錯誤分析
①頁面無報錯但不顯示資料
②tomcat 輸出控制檯亂碼問題
解決:在tomcat的VM配置加上-Dfile.encoding=UTF-8
結果:
基於實戰中學習,學習快樂中成長
.
時間會回答成長,成長會回答夢想