1. 程式人生 > 程式設計 >14個編寫Spring MVC控制器的實用小技巧(吐血整理)

14個編寫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。

啟用註解驅動後,Spring的容器(container)會自動掃描如下包中的類:

帶有@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的內容配置檔案中的定義如下:

這一方法的缺點在於其控制類無法同時處理多個請求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="/big"class="net.codejava.spring.BigController"> 
  <propertyname="supportedMethods"value="POST"/> 
</bean>

這一配置表明該控制器handler方法僅支援POST方法。瞭解更多配置(如會話、快取),參見AbstractController。

SpringMVC還提供了多個支援特定目的的控制器類,包括:

  • AbstractUrlViewController
  • MultiActionController
  • ParameterizableViewController
  • ServletForwardingController
  • ServletWrappingController
  • UrlFilenameViewController

4.為處理器指定URL對映

這是編寫控制器類必不可少的一步,旨在處理一個及以上特定請求。Spring MVC提供了@RequestMapping註解,用於指定URL對映。如:

這一步映射了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模式,並用單一方法對其進行處理。如:

此外,該註解還有其他的屬性,在一些情況下能發揮作用,如下一小節將講到的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型別的引數宣告如下:

則Spring會在處理方法中自動將請求引數的值(String型別)轉換為指定型別(integer)。

為防止引數名與變數名不同,可將引數實名指定如下:

@RequestParam註解還有另外兩個屬性,可在一些情況下發揮作用。其中一個屬性是required,可指定一個引數是強制引數還是可選引數。如:

這就意味著引數country是可選的,在請求中可略去。當請求中沒有引數country時,則變數country為空值。

另一個屬性是defaultValue,可在請求引數為空時充當回退值(fallbackvalue)。如:

當方法引數型別為Map<String,String>時,Spring也支援將所有引數作為Map物件。如:

則對映引數包含所有鍵值對形式的請求引數。瞭解更多@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<>(); 
  // 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<>(); 
  // 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,Object> model) { 
  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(); 
  void save(User user); 
  void checkLogin(User user); 
}

如上所示,使用@Autowired註解使處理器方法可以將任務委託到業務類:

瞭解更多@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中的控制器類程式碼。希望對大家的學習有所幫助,也希望大家多多支援我們。