簡介
Spring MVC 屬於Spring Framework項目中的一部分。主要用於組建MVC結構的項目。比較相似於Struts的功能。並且Spring MVC對於目前比較流行的RESTful架構風格支持的也是比較好的。html
官方網站:http://projects.spring.io/spring-framework/前端
原理
DispatcherServlet類是spring mvc的核心控制器,負責分發和響應用戶請求。java
DispatcherServlet請求處理工做流程以下圖所示:web
一、用戶將request請求發送至前端控制器(Front controller)ajax
二、前端控制器將請求轉發至具體的業務控制器(Controller)spring
三、業務控制器建立業務邏輯實現(Service)和數據數據庫
四、業務控制器(Controller)將結果返回給前端控制器(Front controller)json
五、前端控制器(Front controller)選擇展現模板(View template)瀏覽器
六、最後將結果經過前端控制器(Front controller)返回給客戶安全
DispatcherServlet繼承於HttpServlet,因此它擁有HttpServlet全部特徵。
加載依賴
因爲本人慣用spring boot進行項目構建,因此配置默認都是spring boot的方式
只要在項目中依賴springframework的包就可使用Spring MVC
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.9.RELEASE</version> </dependency> </dependencies>
若是你使用spring boot來搭建項目,那麼是不須要以上依賴的,由於springboot的依賴已經包含他了
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>1.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
DispatcherServlet攔截配置
DispatcherServlet的url-pattern默認狀況下爲「/」根路徑,全部的url請求都會被DispatcherServlet處理。可是咱們能夠對url-pattern進行配置。
在spring boot的配置文件application.properties中進行配置
#攔截全部以.do結尾的路徑 server.servlet-path=*.do #攔截全部springmvc目錄下的路徑 server.servlet-path=/springmvc/*
這裏須要注意,項目中的RequestMapping請求路徑不能包含攔截內容。好比 攔截路徑爲「server.servlet-path=/springmvc/*「,RequestMapping爲「/index」,那麼請求路徑爲http://localhost:8090/springmvc/index
註解
@Controller
此註解聲明瞭一個Controller層的類,使用此註解的類會被識別爲一個控制器。
@Controller public class StartController { }
在此例子中咱們不用將類聲明爲一個bean,由於spring boot在初始化時使用了@ComponentScan註解進行自動掃描並注入。
@RestController
此註解聲明一個類爲Restful風格的控制器。其實就是@Controller和@ResponseBody兩個註解疊加的效果。
@RestController public class StartController { @PostMapping(value = "/login1") public User login1(@RequestBody User user1) { User user = new User(); user.setUsername(user1.getUsername()); user.setPassword(user1.getPassword()); return user; } }
- @RestController註釋的類中,全部的方法默認添加@ResponseBody,會將內容放在http主體中返回。
@RequestMapping
此註解聲明瞭一個可訪問的資源映射,url能夠經過RequestMapping配置的映射路徑來訪問這個方法。
參數:
value(默認) | 訪問該資源的URI路徑。資源路徑支持通配符訪問。(如例5) 此參數能夠不寫則爲默認訪問。(如例1) 該參數能夠設置URI形式的入參,入參使用{}進行表示。在方法參數中使用@PathVariable能夠將URI參數映射給一個方法入參。(如例4) |
method | 指定http的提交類型。通常使用RequestMethod類來指定類型。 經常使用的基本上就是RequestMethod.GET和RequestMethod.POST。(如例二、3) |
consumes |
指定處理請求的提交內容類型(Content-Type),例如application/json, text/html; |
produces | 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;(如例6) 在作接口時每每使用此參數指定接口出參數據結構類型。 |
params | 指定request中必須包含某些參數值是,才讓該方法處理。 |
headers | 指定request中必須包含某些指定的header值,才能讓該方法處理請求。 |
括號內只寫參數值,則表明此參數是默認參數的值。
例子:
@RequestMapping("/home") public class StartController { @RequestMapping public String index(Model model) { return "index"; } @RequestMapping(value = "/login",method = RequestMethod.GET) public String login(Model model) { return "login"; } @RequestMapping(value = "/login",method = RequestMethod.POST) public String loginPost(Model model) { return "login"; } @RequestMapping(value = "/{parameter}",method = RequestMethod.GET) public String parameter(@PathVariable("parameter") String urlParameter, Model model) { return "login"; } @RequestMapping(value = "/*/login",method = RequestMethod.GET) public String login(Model model) { return "login"; } @RequestMapping(value = "/login1", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8) public String login1(Model model) { return "login"; } }
- RequestMapping能夠標識一個類或一個方法,在類上時表明這個類內全部資源都在該路徑下。在方法上時表明該方法的訪問路徑。如例2的路徑爲「/home/login」
- RequestMapping有一些變種註解,如@GetMapping、@PostMapping等。此類註解省去了method參數。@GetMapping至關於@RequestMapping(method = RequestMethod.GET)
@PathVariable
此註解用於獲取URI形式的參數,參數做爲路徑的一部分被傳遞過來。
參數:
value(默認) | URI形式參數的名稱。也就是@RequestMapping註解使用「{}」來標註的參數名稱。 此參數不寫,則要求方法入參名稱與URI參數名稱一致。(如例3) |
括號內只寫參數值,則表明此參數是默認參數的值。(如例二)
例子:
@RequestMapping(value = "/{parameter}") public String parameter(@PathVariable(value = "parameter") String urlParameter, Model model) { return "login"; } @RequestMapping(value = "/{parameter}") public String parameter(@PathVariable("parameter") String urlParameter, Model model) { return "login"; } @RequestMapping(value = "/{parameter}") public String parameter(@PathVariable String parameter, Model model) { return "login"; }
- 更多關於URI參數的說明請參考官方文檔:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-requestmapping-uri-templates
@RequestParam
得到request請求參數並綁定到方法參數上,get請求時使用此註解獲取參數。
參數:
value(默認) | 請求參數名稱。 此參數不寫,則要求方法入參名稱與請求參數名稱一致。(如例2) |
required | 是否必輸。默認狀況下是true必輸,若是但願那個參數爲非必輸就設置成false(如例3) |
括號內只寫參數值,則表明此參數是默認參數的值。(如例1)
例子:
//如下例子的url參數爲?username=andy&password=111111 @GetMapping(value = "/login1") public String login1(@RequestParam("username") String username ,@RequestParam("password") String password) { return "login"; } @GetMapping(value = "/login2") public String login2(@RequestParam String username ,@RequestParam String password) { return "login"; } @GetMapping(value = "/login3") public String login3(@RequestParam String username ,@RequestParam(required=false) String password) { return "login"; } @GetMapping(value = "/login4") public String login4(@RequestParam Map user) { return "login"; }
- @RequestParam的參數可使用map接收,url的入參名和值,會以鍵值對的形式存儲在map中(如例4)
@RequestHeader
獲取request頭信息。
參數:
value(默認) | 請求頭參數名稱。 此參數不寫,則要求方法入參名稱與請求頭參數名稱一致。(如例2) |
required | 是否必輸。默認狀況下是true必輸,若是但願那個參數爲非必輸就設置成false(如例5) |
括號內只寫參數值,則表明此參數是默認參數的值。(如例1)
例子:
@GetMapping(value = "/login1") public String login1(@RequestHeader("Host") String host) { return "login"; } @GetMapping(value = "/login2") public String login2(@RequestHeader String Host) { return "login"; } @GetMapping(value = "/login3") public String login3(@RequestHeader("Accept-Encoding") List<String> encoding ) { return "login"; } @GetMapping(value = "/login4") public String login4(@RequestHeader Map<String,String> header) { return "login"; } @GetMapping(value = "/login5") public String login5(@RequestHeader(value = "Host",required=false) String host) { return "login"; }
- @RequestHeader可使用list接收一組用逗號分割的值(如例3)。如「gzip,deflate」 就會被list拆分接收。
- @RequestHeader可使用Map來接收全部的頭信息,頭信息會以鍵值對的形式存儲在map中(如例4)。
@RequestBody
獲取request請求,http主體內的參數,post請求時使用此註解獲取參數。
參數:
required | 是否必輸。默認狀況下是true必輸,若是但願那個參數爲非必輸就設置成false(如例2) |
例子:
@PostMapping(value = "/login1") public String login1(@RequestBody User user) { return "login"; } @PostMapping(value = "/login2") public String login2(@RequestBody(required=false) User user) { return "login"; }
- @RequestBody將http主體中的數據轉換到入參對象中(如例1)。
- http主體的形式由http Content Type定義。通常爲application/json或application/xml
- @RequestBody入參接收對象中的屬性名要求與http主體中的變量名一致。如:User類定義了usernam和password兩個屬性,那麼json 形式的http body就應該寫成{"username":"myuser","password":"111111"}
@ResponseBody
將響應內容直接放在http主體中返回。一般的@Controller方法返回的是視圖名稱,並跳轉到這個視圖。
@PostMapping(value = "/login1") @ResponseBody public User login1(@RequestBody User user1) { User user = new User(); user.setUsername(user1.getUsername()); user.setPassword(user1.getPassword()); return user; }
- @ResponseBody常常用於ajax請求和接口方法。由於ajax請求和接口方法要求直接返回內容而不是跳轉到某一視圖。
@SessionAttributes(不經常使用)
用於獲取session中的參數。
@SessionAttributes做用於類的時候,會在方法執行結束時將對應名字的model內容存儲到session中。(如例1)
@SessionAttributes做用於參數的時候,會取出session中對應名字的內容,賦值給當前的參數。(如例2)
參數:
value(默認) | session中的參數名稱。 此參數不寫,則要求方法入參名稱與請求參數名稱一致。(如例3) |
括號內只寫參數值,則表明此參數是默認參數的值。(如例2)
例子:
@Controller @RequestMapping(value = "/home") @SessionAttributes("username") public class StartController { @PostMapping(value = "/login1") public String login1(HttpSession httpSession,Model model) { model.addAttribute("username","woshicanshu"); return "login"; } @PostMapping(value = "/login2") public String login2(@SessionAttribute("user") User user, HttpSession httpSession) { return "login"; } @PostMapping(value = "/login3") public String login3(@SessionAttribute User user, HttpSession httpSession) { return "login"; } }
@RequestAttribute(不經常使用)
獲取request的參數。@RequestAttribute做用於參數的時候,會取出request中對應名字的內容,賦值給當前的方法入參。
參數:
value(默認) | request中的參數名稱。 此參數不寫,則要求方法入參名稱與請求參數名稱一致。(如例2) |
括號內只寫參數值,則表明此參數是默認參數的值。(如例1)
例子:
@PostMapping(value = "/login1") public String login1(@RequestAttribute("username") String username,HttpRequest request) { return "login"; } @PostMapping(value = "/login2") public String login2(@RequestAttribute String username,HttpRequest request) { return "login"; }
@ModelAttribute(不經常使用)
將參數保存到Model模型中,供視圖頁面使用。
- 做用於參數時表示這個參數保存到model中。(如例1)
- 做用於方法時表示將這個方法的出參保存到model中,此方法會在執行任意一個@RequestMapping以前執行一次。(如例2)
參數:
value(默認) | model中的參數名稱。 |
括號內只寫參數值,則表明此參數是默認參數的值。(如例1)
例子:
//本例請求參數爲 ?username=pltx @GetMapping(value = "/login1") public String login1(@ModelAttribute("username") String username,Model model) { return "login"; } @ModelAttribute("password") public String login2(String username) { return "000000"; }
@RequestPart(不經常使用)
用於獲取使用multipart/form-data格式傳遞的http請求的請求體,一般用於獲取上傳文件。
@Autowired
用於在類中注入bean。
@Autowired private Activity2CompanyDao activity2CompanyDao;
@Repository
用於聲明此類爲一個數據庫持久化類(DAO層)。
@Repository public class Activity2ConsumerCouponDaoImpl implements Activity2ConsumerCouponDaoCustom{ }
@Service
用於聲明一個業務層的類。
@Service public class Activity2ConsumerService { }
Controller層
Controller層是項目的轉向控制層,主要負責接收請求、轉發請求到業務層(service)進行處理、將處理結果進行響應、控制頁面跳轉等職責。
須要注意涉及到業務邏輯的代碼儘可能不要在Controller進行編寫,將業務邏輯合理的封裝在service層對項目的結構和複用性都是很是有益的。
Controller層主要經常使用的註解有@Controller、@RequestMapping、@Autowired、@RequestParam、@RequestHeader、@RequestBody、@ResponseBody等。
默認綁定的參數
Controller層的方法入參能夠得到默認綁定的類的實例,這實例咱們能夠經過形參的聲明直接使用。其中主要包括HttpServletRequest、HttpservletResponse、HTTPSession、Model、ModelMap以及他們的衍生類。
HttpServletRequest
此參數能夠得到一個HttpServletRequest實例。
@RequestMapping("/unauthorized") public String unauthorized(HttpServletRequest request, HttpServletResponse response) { }
HttpServletResponse
此參數能夠得到一個HttpservletResponse實例。
@RequestMapping("/unauthorized") public String unauthorized(HttpServletRequest request, HttpServletResponse response) { }
HTTPSession
此參數能夠得到一個HTTPSession實例。
@RequestMapping("/unauthorized") public String unauthorized(HTTPSession session) { }
Model/ModelMap
Model用於將模型數據傳遞到展現層,保存在Model中的數據能夠直接在頁面使用獲取。
@RequestMapping(value = "/list", method = RequestMethod.GET) public String list(String name, Integer openType, Model model) { model.addAttribute("name", name); model.addAttribute("openType", openType); return "/activity2_company/list"; }
RedirectAttributes
model的Attribute參數傳遞的聲明週期爲一次請求。因此若是方法採用重定向到其餘資源則Attribute保存的參數將會丟失,在頁面是沒法獲取的。若是想要在重定向後在頁面獲取參數則須要使用 RedirectAttributes進行保存。
下面的例子在login頁面仍然能夠拿到message參數值。
@RequestMapping(value = "/logout", method = RequestMethod.GET) public String logout(RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("message", "您已安全退出"); return "redirect:login"; } @RequestMapping(value = "/login", method = RequestMethod.GET) public String loginInput() { return "login"; }
RedirectAttributes中有兩個添加參數的方法addAttribute和addFlashAttribute ,addAttribute參數會被放在url中進行傳遞,因此長度和類型會受到限制。而addFlashAttribute 參數放在flashmap內部對象中傳遞,對於長度和類型沒有限制。
在重定向的方法中若是想要拿到,前面方法存入的addAttribute參數,只要在重定向方法入參加入這個參數便可
@GetMapping(value = "/login") public String login(RedirectAttributes redirectAttributes) { redirectAttributes.addAttribute("username","andy"); return "redirect:login1"; } @GetMapping(value = "/login1") public String login1(String username) { System.out.println(username); return "login"; }
在重定向的方法中若是想要拿到,前面方法存入的addFlashAttribute參數,則須要使用@ModelAttribute註解
@GetMapping(value = "/login") public String login(RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("username","andy"); return "redirect:login1"; } @GetMapping(value = "/login1") public String login1(@ModelAttribute("username") String username) { System.out.println(username); return "login"; }
響應方式
返回到頁面
Controller方法的出參直接寫視圖名稱,則表明執行結束後調轉到此視圖。(加ResponseBody不行)
以下例將訪問login頁面
@GetMapping(value = "/login") public String login() { return "login"; }
跳轉到其餘Controller
Controller方法的出參能夠經過增長forward和redirect前綴的方式進行轉發或重定向到,其餘Controller。
@GetMapping(value = "/login") public String login() { return "login"; } @GetMapping(value = "/login1") public String login1() { return "redirect:login"; } @GetMapping(value = "/login2") public String login2() { return "forward:login"; }
強調一下forward和redirect區別。forward是服務器轉發,瀏覽器地址不變,服務器將請求的新地址內容返回給劉藍鰭。redirect是瀏覽器重定向,瀏覽器地址改變,服務器告訴瀏覽器要訪問新的地址後瀏覽器從新訪問新地址。
輸出到頁面
咱們可使用HttpServletResponse對象將內容直接輸出到頁面
@GetMapping(value = "/login") public void login(HttpServletResponse response) { try { response.setHeader("Content-type", "text/html;charset=UTF-8"); response.getWriter().println("<h1>我是標題</h1>"); } catch (IOException e) { e.printStackTrace(); } }