全文共4248字,預計學習時長
9分鐘編寫Spring MVC控制器的最佳技巧
本文介紹了編寫Spring MVC框架的控制器(controller)的基礎技巧和最佳操作。在Spring MVC框架中,編寫控制器類通常是為了處理用戶提出的請求。
編寫完成後,控制器會調用一個業務類來處理業務相關任務,進而重定向客戶到邏輯視圖名。Springdispatcher servlet會對邏輯視圖名進行解析,並渲染結果或輸出。這就是一個典型的“請求—響應”的完整流程。
1.使用@controllerstereotype
創建一個能夠處理單個或多個請求的控制器類,最簡單的方法就是使用@controllerstereotype註解一個類,如:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
publicclassHomeController {
@RequestMapping("/")
publicString visitHome() {
// do something before returning view name
return"home";
}
}
如上所示,visitHome()方法通過重定向跳轉到視圖名home來處理應用程序內容路徑(/)收到的請求。
注意:只有在Spring配置文件中啟用了註解驅動,才能使用@controllerstereotype。
<annotation-driven>
啟用註解驅動後,Spring的容器(container)會自動掃描如下包中的類:
<component-scanbase-package>
帶有@controller註解的類會被標記成控制器。由於其簡單方便,且不再需要對配置文件中的控制器聲明beans,這一方法非常實用。
注意:使用@controller註解可以創建一個多動作控制器類,可同時處理多個不同的請求。如:
@Controller
publicclassMultiActionController {
@RequestMapping("/listUsers")
public ModelAndView listUsers() {
}
@RequestMapping("/saveUser")
public ModelAndView saveUser(User user) {
}
@RequestMapping("/deleteUser")
public ModelAndView deleteUser(User user) {
}
}
如上所示,有三個處理器(handler)在分別處理三個請求,/listUsers,/saveUser,和/deleteUser。
2.實現控制器接口
在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;
publicclassMainControllerimplements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out.println("Welcome main");
returnnew ModelAndView("main");
}
}
實現類必須重寫handleRequest()方法(當收到相匹配的請求時,Spring dispatcher servlet會調用handleRequest)。由該控制器處理的請求URL模式在Spring的內容配置文件中的定義如下:
<beanname>
這一方法的缺點在於其控制類無法同時處理多個請求URL。
3.繼承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;
publicclassBigControllerextends AbstractController {
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out.println("You're big!");
returnnew ModelAndView("big");
}
}
上例創建了一個配置了受支持的方法、會話和緩存的單動作控制器,能夠在控制器的bean聲明中被指明。如:
<beanname>
<propertyname>
這一配置表明該控制器handler方法僅支持POST方法。瞭解更多配置(如會話、緩存),參見AbstractController。
SpringMVC還提供了多個支持特定目的的控制器類,包括:
- AbstractUrlViewController
- MultiActionController
- ParameterizableViewController
- ServletForwardingController
- ServletWrappingController
- UrlFilenameViewController
4.為處理器指定URL映射
這是編寫控制器類必不可少的一步,旨在處理一個及以上特定請求。Spring MVC提供了@RequestMapping註解,用於指定URL映射。如:
@RequestMapping("/login")
這一步映射了URL模式/login,並用註解或註解類對其進行了處理。@RequestMapping註解用於類上時,類變成了單動作控制器。如:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/hello")
publicclassSingleActionController {
@RequestMapping(method = RequestMethod.GET)
publicString sayHello() {
return"hello";
}
}
@RequestMapping註解用於方法上時,則可生成多動作控制器。如:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
publicclassUserController {
@RequestMapping("/listUsers")
publicString listUsers() {
return"ListUsers";
}
@RequestMapping("/saveUser")
publicString saveUser() {
return"EditUser";
}
@RequestMapping("/deleteUser")
publicString deleteUser() {
return"DeleteUser";
}
}
@RequestMapping註解也可用於指定多個URL模式,並用單一方法對其進行處理。如:
@RequestMapping({"/hello", "/hi", "/greetings"})
此外,該註解還有其他的屬性,在一些情況下能發揮作用,如下一小節將講到的method屬性。
5.為處理器方法指定HTTP請求方法
使用@RequestMapping註解的method屬性,可以指定處理器方法支持的HTTP方法(包括GET、POST、PUT等)。如:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
publicclassLoginController {
@RequestMapping(value = "/login", method = RequestMethod.GET)
publicString viewLogin() {
return"LoginForm";
}
@RequestMapping(value = "/login", method = RequestMethod.POST)
publicString doLogin() {
return"Home";
}
}
如上所示,對於同一個URL模式/login,該控制器有兩個處理方法。第一個方法用於GET方法,第二個則用於POST方法。
瞭解更多@RequestMapping註解相關知識,參見@RequestMapping註解。
6.將請求參數映射至處理器方法
SpringMVC的特徵之一,就是可以使用@RequestParam註解將請求參數作為處理器方法的常規參數取回。這是一個將控制器從ServletAPI的HttpServletRequest接口中解耦出來的好方法。
如:
@RequestMapping(value = "/login", method = RequestMethod.POSTpublic String doLogin(@RequestParamString username @RequestParamString password) {}
Spring將方法參數用戶名及密碼和命名相同的HTTP請求參數綁定到一起。這也就意味著可用如下方式調用一個URL(以GET請求方法為例):
http://localhost:8080/spring/login?username=scott&password=tiger
類型轉換也自動完成了。如果對一個integer類型的參數聲明如下:
@RequestParamint securityNumber
則Spring會在處理方法中自動將請求參數的值(String類型)轉換為指定類型(integer)。
為防止參數名與變量名不同,可將參數實名指定如下:
@RequestParam("SSN") int securityNumber
@RequestParam註解還有另外兩個屬性,可在一些情況下發揮作用。其中一個屬性是required,可指定一個參數是強制參數還是可選參數。如:
@RequestParam(required = false) String country
這就意味著參數country是可選的,在請求中可略去。當請求中沒有參數country時,則變量country為空值。
另一個屬性是defaultValue,可在請求參數為空時充當回退值(fallbackvalue)。如:
@RequestParam(defaultValue = "18") int age
當方法參數類型為Map<string>時,Spring也支持將所有參數作為Map對象。如:/<string>
doLogin(@RequestParam Map<string> params)/<string>
則映射參數包含所有鍵值對形式的請求參數。瞭解更多@RequestParam註解相關知識,參見@RequestParam註解。
7.返回模型和視圖
處理器方法在處理完業務邏輯後,會返回一個視圖,該視圖隨後由Springdispatcher servlet進行解析。Spring支持handler方法返回String對象或ModelAndView對象。如下所示,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<>();/<user>
// get user list from 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<>();/<user>
// get user list from DAO...
modelView.setViewName("UserList");
modelView.addObject("listUser", listUser);
return modelView;
}
瞭解更多ModelAndView類相關知識,參見ModelAndView類。
8.將對象放入模型
在MVC架構的應用程序中,控制器將數據輸入到模型中,該模型則被用在視圖中。從上一節中的舉例中可以看到,ModelAndView類的addObject()用於將對象以名值對的形式放入模型中:
modelView.addObject("listUser", listUser);
modelView.addObject("siteName", newString("CodeJava.net"));
modelView.addObject("users", 1200000);
Spring同樣支持聲明處理器方法中的Map類型參數。Spring使用這一映射存儲將放入模型的對象。如:
@RequestMapping(method = RequestMethod.GET)
publicStringviewStats(Map<string> model) {/<string>
model.put("siteName", "CodeJava.net");
model.put("pageviews", 320000);
return"Stats";
}
這一方法比使用ModelAndView對象更加簡單。Spring支持用戶靈活選擇Map對象和ModelAndView對象。
9.處理器方法中的重定向
當條件允許時,只需在URL前加上redirect:/就可將用戶重定向跳轉到另一個URL。如:
// check login status....
if (!isLogin) {
returnnew ModelAndView("redirect:/login");
}
// return a list of Users
在上述代碼中,沒有登陸的用戶將會跳轉到/loginURL。
10.處理表單提交和表單驗證
Spring中的@ModelAttribute註解支持將表單字段綁定到表單返回對象,BingingRequest接口則支持驗證表單字段。這使得處理表單提交變得非常簡單。一個處理和驗證表單數據的典型處理器方法的代碼如下所示:
@Controller
publicclassRegistrationController {
@RequestMapping(value = "/doRegister", method = RequestMethod.POST)
publicString doRegister(
@ModelAttribute("userForm") User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// form validation error
} else {
// form input is OK
}
// process registration...
return"Success";
}
}
瞭解更多@ModelAttribute註解和BindingResult接口相關知識,參見Spring官方文檔:
- Using @ModelAttribute on a method argument
- Using @ModelAttribute on a method
- Interface BindingResult
11.處理文件上傳
Spring支持自動將上傳數據綁定到CommonsMultiparFile數組對象,這使得在處理器方法中處理文件上傳變得非常簡單。Spring使用Apache CommonsFileUpload作為深層多部分解析器(underlyingmultipart resolver)。
簡單上傳用戶文件的代碼如下所示:
@RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)
publicStringhandleFileUpload(
@RequestParam CommonsMultipartFile[] fileUpload) throws Exception {
for (CommonsMultipartFile aFile : fileUpload){
// stores the uploaded file
aFile.transferTo(new File(aFile.getOriginalFilename()));
}
return"Success";
}
瞭解Spring MVC處理文件上傳的完整方法,參見Spring MVC 文件上傳教程。
12.在處理器中自動注入業務類
為了讓控制器將業務邏輯處理委託到相關業務類,可以使用@Autowired註解,讓Spring自動將業務類的實際實現注入到控制器中。如:
@Controller
publicclassUserController {
@Autowired
private UserDAO userDAO;
publicString listUser() {
// handler method to list all users
userDAO.list();
}
publicString saveUser(User user) {
// handler method to save/update a user
userDAO.save(user);
}
publicString deleteUser(User user) {
// handler method to delete a user
userDAO.delete(user);
}
publicString getUser(int userId) {
// handler method to get a user
userDAO.get(userId);
}
}
本例中所有與用戶管理相關的業務邏輯都由UserDAO接口的實現提供。如:
interfaceUserDAO {
List<user> list();/<user>
void save(User user);
void checkLogin(User user);
}
如上所示,使用@Autowired註解使處理器方法可以將任務委託到業務類:
List<user> listUser = userDAO.list();/<user>
瞭解更多@Autowired註解相關知識,參見Annotation TypeAutowired。
13.獲取HttpServletRequest和HttpServletResponse
有些情況要求在處理器方法中直接獲取HttpServletRequest或HttpServletResponse對象。在Spring靈活的框架中,僅需給處理器方法加上一個相關參數就可以完成此任務。如:
@RequestMapping("/download")
publicStringdoDownloadFile(
HttpServletRequest request, HttpServletResponse response) {
// access the request
// access the response
return"DownloadPage";
}
Spring支持檢測並自動將HttpServletRequest和HttpServletResponse對象注入到方法中。這樣一來,就可以直接獲取請求和響應,如獲取InputStream、OutputStream或返回特定的HTTP代碼。
14.遵守單一職責原則
在Spring MVC中設計和編寫控制器時,應遵循以下兩個非常實用的操作:
- 不要用控制器類來執行業務邏輯,應該用控制器類將業務處理委託到相關的業務類。這可以保證控制器專注於其指定職責,即控制應用程序的工作流。如:
@Controller
publicclassUserController {
@Autowired
private UserDAO userDAO;
publicString listUser() {
// handler method to list all users
userDAO.list();
}
publicString saveUser(User user) {
// handler method to save/update a user
userDAO.save(user);
}
publicString deleteUser(User user) {
// handler method to delete a user
userDAO.delete(user);
}
publicString getUser(int userId) {
// handler method to get a user
userDAO.get(userId);
}
}
- 給每個業務領域創建一個獨立的控制器。如,用UserController控制用戶管理的工作流,用OrderController控制訂單處理的工作流,等等:
@Controller
publicclassUserController {
}
@Controller
publicclassProductController {
}
@Controller
publicclassOrderController {
}
@Controller
publicclassPaymentController {
}
以上就是本文全部內容,希望這14個小技巧可以幫助讀者準確且高效地編寫Spring MVC中的控制器類代碼。有任何技巧分享或建議,歡迎在評論區留言。
我們一起分享AI學習與發展的乾貨
閱讀更多 讀芯術 的文章