分享 14 個 Spring MVC 頂級技巧!

做者: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

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-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分別。

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的上下文配置文件中定義以下:

<bean name="/main" class="net.codejava.spring.MainController" />

可是,此方法的缺點是控制器類沒法處理多個請求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;  
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

4.爲處理程序方法指定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;  
@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

5.爲處理程序方法指定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;  
@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註解。

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註解。關注微信公衆號: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。 

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使處理表單提交變得容易。下面的代碼片斷顯示了一種典型的處理程序方法,該方法負責處理和驗證表單數據:

@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接口的更多信息:

  • 在方法參數上使用@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自動將業務類的實際實現注入控制器。關注微信公衆號: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 註解的更多信息,請參見  註釋類型自動裝配。

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)控制器類不該執行業務邏輯。相反,它應該將業務處理委託給相關的業務類別。這使控制器始終專一於其設計職責是控制應用程序的工做流程。例如:

@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中編寫控制器類。若是你有其餘提示或建議,請隨時在評論中分享您的想法。

推薦去個人博客閱讀更多:

1.Java JVM、集合、多線程、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、後端、架構、阿里巴巴等大廠最新面試題

生活很美好,明天見~

相關文章
相關標籤/搜索