天天看點

編寫Spring MVC控制器的14個技巧

通常,在Spring MVC中,我們編寫一個控制器類來處理來自用戶端的請求。然後,控制器調用業務類來處理與業務相關的任務,然後将用戶端重定向到邏輯視圖名稱,該名稱由Spring的排程程式Servlet解析,以呈現結果或輸出。

這樣就完成了典型的請求-響應周期的往返。

今天整理了一下編寫Spring MVC控制器的14個技巧,你今天get到了嗎?(≧▽≦)/

1.使用@Controller構造型

這是建立可以處理一個或多個請求的控制器類的最簡單方法。僅通過用構造型注釋一個類@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容器自動在以下語句指定的包下掃描類:

<context:component-scan base-package="net.codejava.spring" />複制代碼

由@Controller 注釋注釋的類被配置為控制器。這是最可取的,因為它很簡單:無需在配置檔案中為控制器聲明bean。

注意:通過使用@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分别。

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;

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的上下文配置檔案中定義如下:

但是,此方法的缺點是控制器類無法處理多個請求URL。

3.擴充AbstractController類

如果要輕松控制受支援的HTTP方法,會話和内容緩存。擴充你的控制器 AbstractController 類是理想的選擇。

請考慮以下示例:

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聲明中指定這些配置。例如:

<property name="supportedMethods" value="POST"/>           

此配置訓示POST 此控制器的hander 方法僅支援該方法。

Spring MVC還提供了幾種針對特定目的而設計的控制器類,包括:

AbstractUrlViewController

MultiActionController

ParameterizableViewController

ServletForwardingController

ServletWrappingController

UrlFilenameViewController

4.為處理程式方法指定URL映射

這是編碼控制器類時必須執行的強制性任務,該控制器類旨在處理一個或多個特定請求。Spring MVC提供了@RequestMapping 注釋,該注解用于指定URL映射。例如:

@RequestMapping("/login")複制代碼

這映射了/login 要由帶注解的方法或類處理的URL模式。當在類級别使用此注解時,該類将成為單動作控制器。例如:

import org.springframework.web.bind.annotation.RequestMethod;

@RequestMapping("/hello")

public class SingleActionController {

@RequestMapping(method = RequestMethod.GET)
public String sayHello() {
    return "hello";
}           

當@RequestMapping 注解在方法級别使用的,你可以有一個多動作控制器。例如:

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。

5.為處理程式方法指定HTTP請求方法

可以使用 注解的method 屬性 指定處理程式方法支援哪種HTTP方法(GET,POST,PUT等) @RequestMapping。這是一個例子:

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注解。

6.将請求參數映射到處理程式方法

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注解。

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也非常靈活,因為您可以将ModelAndView 對象聲明 為處理

手機遊戲賬号購買平台

程式方法的參數,而不用建立一個新的對象。是以,以上示例可以重寫如下:

public ModelAndView listUsers(ModelAndView modelView) {

List<User> listUser = new ArrayList<>();
//從DAO擷取使用者清單…
modelView.setViewName("UserList");
modelView.addObject("listUser", listUser);
return modelView;           

了解有關該類的更多資訊,請參見:ModelAndView class。

8.将對象放入模型

在遵循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的靈活性。

9.處理程式方法中的重定向

如果你希望在滿足條件的情況下将使用者重定向到另一個URL,請redirect:/ 在URL之前追加。以下代碼段給出了一個示例:

// 檢查登入狀态....

if (!isLogin) {

return new ModelAndView("redirect:/login");           

}

// 傳回使用者清單複制代碼

在上面的代碼中,/login 如果未登入,使用者将被重定向到該 URL。

10.處理表格送出和表格驗證

通過提供@ModelAttribute 用于将表單字段綁定到表單支援對象的注解以及BindingResult 用于驗證表單字段的界面,Spring使處理表單送出變得容易。下面的代碼片段顯示了一種典型的處理程式方法,該方法負責處理和驗證表單資料:

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 接口的更多資訊:

在方法參數上使用@ModelAttribute

在方法上使用@ModelAttribute

接口綁定結果

11.處理檔案上傳

通過自動将上傳資料綁定到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";           

12.在控制器中自動裝配業務類

控制器應将業務邏輯的處理委托給相關的業務類。為此,您可以使用@Autowired 注解讓Spring自動将業務類的實際實作注入控制器。

考慮以下控制器類的代碼段:

@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 注解的更多資訊,請參見 注釋類型自動裝配。

13.通路HttpServletRequest和HttpServletResponse

在某些情況下,您需要直接 在處理程式方法中通路 HttpServletRequest 或 HttpServletResponse對象。

通過Spring的靈活性,隻需在處理方法中添加相關參數即可。例如:

@RequestMapping("/download")

public String doDownloadFile(

HttpServletRequest request, HttpServletResponse response) {
// 通路請求
// 通路響應
return "DownloadPage";           

Spring檢測并自動将 HttpServletRequest 和 HttpServletResponse 對象注入方法中。然後,可以通路請求和響應如擷取 InputStream, OutputStream或傳回一個特定的HTTP代碼。

14.遵循單一責任原則

最後,在設計和編寫Spring MVC控制器時,有兩個很好的實踐是你應該遵循的:

1)控制器類不應執行業務邏輯。相反,它應該将業務處理委托給相關的業務類别。這使控制器始終專注于其設計職責是控制應用程式的工作流程。例如:

@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 工作流程, 用于控制訂單處理的工作流程等。例如:

public class ProductController {

public class OrderController {

public class PaymentController {

這14個小技巧,可以幫助你正确有效地在Spring MVC中編寫控制器類。如果你有其他提示或建議,請随時在評論中分享您的想法。