做者:Nam Ha Minh
https://dzone.com/articles/14...譯文:blog.csdn.net/Summer_Lyf/article/details/102911215java
一般,在Spring MVC中,咱們編寫一個控制器類來處理來自客戶端的請求。而後,控制器調用業務類來處理與業務相關的任務,而後將客戶端重定向到邏輯視圖名稱,該名稱由Spring的調度程序Servlet解析,以呈現結果或輸出。 web
這樣就完成了典型的請求-響應週期的往返。面試
今天整理了一下編寫Spring MVC控制器的14個技巧,你今天get到了嗎? \(≧▽≦)/spring
這是建立能夠處理一個或多個請求的控制器類的最簡單方法。僅經過用構造型註釋一個類@Controller
,例如:後端
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HomeController { @RequestMapping("/") public String visitHome() { return "home"; } }
如你所見,visitHome()方法經過重定向到名爲home的視圖來處理來自應用程序上下文路徑(/)的請求。數組
注意: @Controller原型只能在Spring的配置文件中啓用註解驅動時使用:spring-mvc
<annotation-driven />
啓用註釋驅動時,Spring容器自動在如下語句指定的包下掃描類:緩存
<context:component-scan base-package="net.codejava.spring" />
由@Controller
註釋註釋的類被配置爲控制器。這是最可取的,由於它很簡單:無需在配置文件中爲控制器聲明bean。微信
注意: 經過使用@Controller
註解,您能夠擁有一個多動做控制器類,該類可以處理多個不一樣的請求。例如:多線程
@Controller public 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。
若是要輕鬆控制受支持的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還提供了幾種針對特定目的而設計的控制器類,包括:
這是編碼控制器類時必須執行的強制性任務,該控制器類旨在處理一個或多個特定請求。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; @Controller public 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
。
可使用 註解的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; @Controller public 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註解。關注微信公衆號:Java技術棧,在後臺回覆:spring,能夠獲取我整理的 N 篇最新 Spring 教程,都是乾貨。
7.返回模型和視圖
處理完業務邏輯後,處理程序方法應返回一個視圖,而後由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 面試 7 大問題,推薦看下。
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使處理表單提交變得容易。下面的代碼片斷顯示了一種典型的處理程序方法,該方法負責處理和驗證表單數據:
@Controller public 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
接口的更多信息:
經過自動將上傳數據綁定到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自動將業務類的實際實現注入控制器。關注微信公衆號:Java技術棧,在後臺回覆:spring,能夠獲取我整理的 N 篇最新Spring Boot 教程,都是乾貨。
考慮如下控制器類的代碼段:
@Controller public 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
對象。
經過Spring的靈活性,只需在處理方法中添加相關參數便可。例如:
@RequestMapping("/download") public String doDownloadFile( HttpServletRequest request, HttpServletResponse response) { // 訪問請求 // 訪問響應 return "DownloadPage"; }
Spring檢測並自動將 HttpServletRequest
和 HttpServletResponse
對象注入方法中。而後,能夠訪問請求和響應如獲取 InputStream
, OutputStream
或返回一個特定的HTTP代碼。
最後,在設計和編寫Spring MVC控制器時,有兩個很好的實踐是你應該遵循的:
1)控制器類不該執行業務邏輯。相反,它應該將業務處理委託給相關的業務類別。這使控制器始終專一於其設計職責是控制應用程序的工做流程。例如:
@Controller public 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); } }
2)爲每一個業務域建立每一個單獨的控制器。例如, UserController
用於控制用戶管理的OrderController
工做流程, 用於控制訂單處理的工做流程等。例如:
@Controller public class UserController { } @Controller public class ProductController { } @Controller public class OrderController { } @Controller public class PaymentController { }
這14個小技巧,能夠幫助你正確有效地在Spring MVC中編寫控制器類。若是你有其餘提示或建議,請隨時在評論中分享您的想法。
推薦去個人博客閱讀更多:
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
生活很美好,明天見~