編寫Spring MVC控制器的14個技巧
通常,在Spring MVC中,我們編寫一個控制器類來處理來自客戶端的請求。然後,控制器呼叫業務類來處理與業務相關的任務,然後將客戶端重定向到邏輯檢視名稱,該名稱由Spring的排程程式Servlet解析,以呈現結果或輸出。這樣就完成了典型的請求-響應週期的往返。
使用@Controller構造型
這是建立可以處理一個或多個請求的控制器類的最簡單方法。僅透過用構造型註釋一個類@Controller ,例如:
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class HomeController { @RequestMapping("/") public String visitHome() { return "home"; } }
如你所見,visitHome()方法透過重定向到名為home的檢視來處理來自應用程式上下文路徑(/)的請求。
注意:@Controller原型只能在Spring的配置檔案中啟用註解驅動時使用:
<annotation-driven />
啟用註釋驅動時,Spring容器自動在以下語句指定的包下掃描類:
<context:component-scan base-package="net.codejava.spring" />
由@Controller 註釋註釋的類被配置為控制器。這是最可取的,因為它很簡單:無需在配置檔案中為控制器宣告bean。
注意:透過使用@Controller 註解,您可以擁有一個多動作控制器類,該類能夠處理多個不同的請求。例如:
@Controllerpublic class MultiActionController { @RequestMapping("/listUsers") public ModelAndView listUsers() { } @RequestMapping("/saveUser") public ModelAndView saveUser(User user) { } @RequestMapping("/deleteUser") public ModelAndView deleteUser(User user) { } }
正如你可以在上面的控制器類看,有處理三種不同的請求3種處理方法 /listUsers,/saveUser,和/deleteUser分別。
實現控制器介面
在Spring MVC中建立控制器的另一種(也許是經典的)方法是讓類實現 Controller 介面。例如:
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;public class MainController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("Welcome main"); return new ModelAndView("main"); } }
實現類必須重寫該 handleRequest() 方法,當匹配請求進入時,該方法將由Spring排程程式Servlet呼叫。此控制器處理的請求URL模式在Spring的上下文配置檔案中定義如下:
<bean name="/main" class="net.codejava.spring.MainController" />
但是,此方法的缺點是控制器類無法處理多個請求URL。
擴充套件AbstractController類
如果要輕鬆控制受支援的HTTP方法,會話和內容快取。擴充套件你的控制器 AbstractController 類是理想的選擇。請考慮以下示例:
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.AbstractController; public class BigController extends AbstractController { @Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("You're big!"); return new ModelAndView("big"); } }
這將建立具有有關受支援的方法,會話和快取的配置的單動作控制器,然後可以在控制器的bean宣告中指定這些配置。例如:
<bean name="/big" class="net.codejava.spring.BigController"> <property name="supportedMethods" value="POST"/> </bean>
此配置指示POST 此控制器的hander 方法僅支援該方法。
Spring MVC還提供了幾種針對特定目的而設計的控制器類,包括:
AbstractUrlViewController MultiActionController ParameterizableViewController ServletForwardingController ServletWrappingController UrlFilenameViewController
為處理程式方法指定URL對映
這是編碼控制器類時必須執行的強制性任務,該控制器類旨在處理一個或多個特定請求。Spring MVC提供了@RequestMapping 註釋,該註解用於指定URL對映。
例如:
@RequestMapping("/login")
這對映了/login 要由帶註解的方法或類處理的URL模式。當在類級別使用此註解時,該類將成為單動作控制器。例如:
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;@Controller@RequestMapping("/hello")public class SingleActionController { @RequestMapping(method = RequestMethod.GET) public String sayHello() { return "hello"; } }
當@RequestMapping 註解在方法級別使用的,你可以有一個多動作控制器。例如:
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class UserController { @RequestMapping("/listUsers") public String listUsers() { return "ListUsers"; } @RequestMapping("/saveUser") public String saveUser() { return "EditUser"; } @RequestMapping("/deleteUser") public String deleteUser() { return "DeleteUser"; } }
@RequestMapping註釋還可以用於指定一個方法要處理的多個URL模式。例如:
@RequestMapping({"/hello", "/hi", "/greetings"})
此外,此註解還具有在某些情況下可能有用的其他屬性,例如method。
為處理程式方法指定HTTP請求方法
可以使用 註解的method 屬性 指定處理程式方法支援哪種HTTP方法(GET,POST,PUT等) @RequestMapping。這是一個例子:
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;@Controllerpublic class LoginController { @RequestMapping(value = "/login", method = RequestMethod.GET) public String viewLogin() { return "LoginForm"; } @RequestMapping(value = "/login", method = RequestMethod.POST) public String doLogin() { return "Home"; } }
此控制器有兩個處理相同URL模式的方法/login,但前者用於 GET 方法,而後者用於 POST 方法。
有關使用@RequestMapping 註解的更多資訊,請參見 @RequestMapping註解。
將請求引數對映到處理程式方法
Spring MVC的很酷的功能之一是,您可以使用@RequestParam 註解將請求引數作為處理程式方法的常規引數進行檢索。這是將控制器HttpServletRequest 與Servlet API 的介面分離的好方法。
@RequestMapping(value = "/login", method = RequestMethod.POST) public String doLogin(@RequestParam String username, @RequestParam String password) { }
Spring將方法引數使用者名稱和密碼繫結到具有相同名稱的HTTP請求引數。這意味著您可以按以下方式呼叫URL(如果請求方法是GET):
http:// localhost:8080 / spring / login?username = scott&password = tiger
型別轉換也是自動完成的。例如,如果您宣告integer 如下型別的引數 :
@RequestParam int securityNumber
然後,Spring將在處理程式方法中自動將請求引數(字串)的值轉換為指定的型別(整數)。
如果引數名稱與變數名稱不同,則可以如下指定引數的實際名稱:
@RequestParam("SSN") int securityNumber
該@RequestParam 註解也有兩個額外的屬性,這可能是在某些情況下是有用的。該屬性指定引數是否為必需。例如:required
@RequestParam(required = false) String country
這意味著該引數 country 是可選的;因此,它可能會從請求中丟失。在上面的示例中,country 如果請求中不存在此類引數,則變數 將為null。
另一個屬性是 defaultValue,可以在請求引數為空時用作後備值。例如:
@RequestParam(defaultValue = "18") int age
Map 如果方法引數是type,Spring還允許我們將所有引數作為物件 訪問 Map<String, String>。例如:
doLogin(@RequestParam Map<String, String> params)
然後,對映引數包含鍵-值對形式的所有請求引數。有關使用@RequestParam 註釋的更多資訊,請參見 @RequestParam註解。
返回模型和檢視
處理完業務邏輯後,處理程式方法應返回一個檢視,然後由Spring的排程程式servlet對其進行解析。Spring允許我們ModelAndView 從handler 方法中返回String或 物件 。在以下示例中,該 handler 方法返回一個String並表示一個名為的檢視 LoginForm:
@RequestMapping(value = "/login", method = RequestMethod.GET)public String viewLogin() { return "LoginForm"; }
這是返回檢視名稱的最簡單方法。但是,如果要將其他資料傳送到檢視,則必須返回一個 ModelAndView 物件。考慮以下處理程式方法:
@RequestMapping("/listUsers")public ModelAndView listUsers() { List<User> listUser = new ArrayList<>(); // 從DAO獲取使用者列表… ModelAndView modelView = new ModelAndView("UserList"); modelView.addObject("listUser", listUser); return modelView; }
如您所見,此處理程式方法返回一個 ModelAndView 儲存檢視名稱 UserList 的User 物件和一個可在檢視中使用的物件集合 。
Spring也非常靈活,因為您可以將ModelAndView 物件宣告 為處理程式方法的引數,而不用建立一個新的物件。因此,以上示例可以重寫如下:
@RequestMapping("/listUsers")public ModelAndView listUsers(ModelAndView modelView) { List<User> listUser = new ArrayList<>(); //從DAO獲取使用者列表… modelView.setViewName("UserList"); modelView.addObject("listUser", listUser); return modelView; }
瞭解有關該類的更多資訊,請參見 :ModelAndView class。
將物件放入模型
在遵循MVC架構的應用程式中,控制器(C)應該將資料傳遞到模型(M)中,然後在檢視(V)中使用該模型。正如我們在前面的示例中看到的那樣, 該類的addObject() 方法 ModelAndView是以名稱-值對的形式將物件放入模型中:
modelView.addObject("listUser", listUser); modelView.addObject("siteName", new String("CodeJava.net")); modelView.addObject("users", 1200000);
同樣,Spring非常靈活。你可以Map 在處理程式方法中宣告型別的引數 。Spring使用此對映儲存模型的物件。讓我們看另一個例子:
@RequestMapping(method = RequestMethod.GET)public String viewStats(Map<String, Object> model) { model.put("siteName", "CodeJava.net"); model.put("pageviews", 320000); return "Stats"; }
這比使用ModelAndView 物件還要簡單 。根據你的喜好,可以使用Map 或 使用 ModelAndView 物件。在這裡要感謝Spring的靈活性。
處理程式方法中的重定向
如果你希望在滿足條件的情況下將使用者重定向到另一個URL,請redirect:/ 在URL之前追加。以下程式碼段給出了一個示例:
// 檢查登入狀態....if (!isLogin) { return new ModelAndView("redirect:/login"); }// 返回使用者列表
在上面的程式碼中,/login 如果未登入,使用者將被重定向到該 URL。
處理表格提交和表格驗證
透過提供@ModelAttribute 用於將表單欄位繫結到表單支援物件的註解以及BindingResult 用於驗證表單欄位的介面,Spring使處理表單提交變得容易。 下面的程式碼片段顯示了一種典型的處理程式方法,該方法負責處理和驗證表單資料:
@Controllerpublic class RegistrationController { @RequestMapping(value = "/doRegister", method = RequestMethod.POST) public String doRegister( @ModelAttribute("userForm") User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { // 表單驗證錯誤 } else { // 表單輸入沒問題 } // 註冊過程…… return "Success"; } }
從Spring的官方文件中瞭解有關@ModelAttribute 註釋和BindingResult 介面的更多資訊 :
在方法引數上使用@ModelAttribute
在方法上使用@ModelAttribute
介面繫結結果
處理檔案上傳
透過自動將上傳資料繫結到CommonsMultipartFile 物件陣列,Spring還使在處理程式方法中處理檔案上傳變得容易。Spring使用Apache Commons FileUpload作為基礎的多部分解析器。
以下程式碼段顯示了從客戶端上傳檔案有多麼容易
@RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)public String handleFileUpload( @RequestParam CommonsMultipartFile[] fileUpload) throws Exception { for (CommonsMultipartFile aFile : fileUpload){ // 儲存上傳的檔案 aFile.transferTo(new File(aFile.getOriginalFilename())); } return "Success"; }
在控制器中自動裝配業務類
控制器應將業務邏輯的處理委託給相關的業務類。為此,您可以使用@Autowired 註解讓Spring自動將業務類的實際實現注入控制器。考慮以下控制器類的程式碼段:
@Controllerpublic class UserController { @Autowired private UserDAO userDAO; public String listUser() { // 列出所有使用者的處理方法 userDAO.list(); } public String saveUser(User user) { // 儲存/更新使用者的處理方法 userDAO.save(user); } public String deleteUser(User user) { // 刪除使用者的處理方法 userDAO.delete(user); } public String getUser(int userId) { // 獲取使用者的處理方法 userDAO.get(userId); } }
在此,與使用者管理有關的所有業務邏輯都由該UserDAO 介面的實現提供 。例如:
interface UserDAO { List<User> list(); void save(User user); void checkLogin(User user); }
有關@Autowired 註解的更多資訊,請參見 註釋型別自動裝配。
訪問HttpServletRequest和HttpServletResponse
在某些情況下,您需要直接 在處理程式方法中訪問 HttpServletRequest 或 HttpServletResponse物件。透過Spring的靈活性,只需在處理方法中新增相關引數即可。例如:
@RequestMapping("/download")public String doDownloadFile( HttpServletRequest request, HttpServletResponse response) { // 訪問請求 // 訪問響應 return "DownloadPage"; }
Spring檢測並自動將 HttpServletRequest 和 HttpServletResponse 物件注入方法中。然後,可以訪問請求和響應如獲取 InputStream, OutputStream或返回一個特定的HTTP程式碼。
遵循單一責任原則
最後,在設計和編寫Spring MVC控制器時,有兩個很好的實踐是你應該遵循的:
控制器類不應執行業務邏輯。相反,它應該將業務處理委託給相關的業務類別。這使控制器始終專注於其設計職責是控制應用程式的工作流程。例如:
@Controllerpublic class UserController { @Autowired private UserDAO userDAO; public String listUser() { userDAO.list(); } public String saveUser(User user) { userDAO.save(user); } public String deleteUser(User user) { userDAO.delete(user); } public String getUser(int userId) { userDAO.get(userId); } }
為每個業務域建立每個單獨的控制器。例如, UserController 用於控制使用者管理的OrderController 工作流程, 用於控制訂單處理的工作流程等。例如:
@Controllerpublic class UserController { }@Controllerpublic class ProductController { }@Controllerpublic class OrderController { }@Controllerpublic class PaymentController { }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/27721058/viewspace-2850728/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 換一種方式編寫 Spring MVC 介面SpringMVC
- Linux編寫Bash指令碼的10個技巧Linux指令碼
- 看看一個老程式設計師是如何手寫Spring MVC的!程式設計師SpringMVC
- 【譯】編寫更好JavaScript條件語句的5個技巧JavaScript
- Vivado使用技巧(27):RAM編寫技巧
- Vivado使用技巧(26):HDL編寫技巧
- 手寫Spring MVC框架(一) 實現簡易版mvc框架SpringMVC框架
- 30個類手寫Spring核心原理之MVC對映功能(4)SpringMVC
- IT面試題:附帶答案的14道Spring MVC面試題面試題SpringMVC
- Spring MVC 中文編碼亂碼解決SpringMVC
- 手寫 Spring 事務、IOC、DI 和 MVCSpringMVC
- 帶你一步一步手寫一個簡單的Spring MVCSpringMVC
- 6個小技巧教你編寫乾淨整潔的程式碼
- 14 個拷貝陣列的 JS 技巧陣列JS
- 膜拜阿里架構師全程手寫Spring MVC阿里架構SpringMVC
- 【譯】12個編寫乾淨且可擴充套件的JavaScript技巧套件JavaScript
- spring-boot - 編寫自己的starterSpringboot
- spring - mvcSpringMVC
- spring、spring MVC、spring BootMVCSpring Boot
- Hbuilder快速程式碼編寫技巧UI
- Markdown 編寫技巧彙總(一)
- tomcat + spring mvc原理外傳:spring mvc與前端的糾葛TomcatSpringMVC前端
- 自己寫一個mvc框架吧(五)MVC框架
- 自己寫一個mvc框架吧(四)MVC框架
- 自己寫一個mvc框架吧(二)MVC框架
- 自己寫一個mvc框架吧(一)MVC框架
- 自己寫一個mvc框架吧(三)MVC框架
- Spring MVC 處理一個請求的流程分析SpringMVC
- Spring 系列(二):Spring MVC的父子容器SpringMVC
- MathType數學公式編寫技巧分享公式
- 效能測試報告編寫技巧測試報告
- 編寫運動控制器的 EtherCAT 初始化程式示例
- 如何在ASP.NET Core中編寫高效的控制器ASP.NET
- 使用Go寫一個簡易的MVC的Web框架GoMVCWeb框架
- Spring MVC常用註解,你會幾個?SpringMVC
- spring mvc interceptorsSpringMVC
- spring - mvc - @ScheduledSpringMVC
- spring - mvc - @ValidSpringMVC