代碼是上一篇的累加!!!
1、基於注解的控制器
①、在基於注解 的控制器類中可以同時編寫多個處理方法,進而可以處理多個請求的url,
這就允許將相關的操作編寫在同一個控制器類中,從而減輕控制器類的數量,方便以后的維護。
②、基於注解的控制器不需要再文件配置文件中部署映射,僅需要使用RequestMapping注解一個方法
進行請求的處理。
1、Controller注解類型
在spring MVC中使用org.springframework.stereotype.Controller;注解來聲明某個類的實例
是一個控制器。如:
package controller; import org.springframework.stereotype.Controller; @Controllerpublic class UserController {
...
}
在spring MVC中使用掃描機制找到對應的注解的控制器類
為了讓控制類被spring MVC掃描到,需要在配置文件中使用spring-context
並且使用<context:component-scan/>元素指定控制器類的包。
如:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 注解 --> <!--使用掃描機制 --> <context:component-scan base-package="controller" />
<!--配置視圖解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--前綴 --> <property name="prefix" value="/WEB-INF/jsp/"></property> <!--后綴--> <property name="suffix" value=".jsp"></property> </bean> </beans>
2、RequestMapping注解類型
使用org.springframework.web.bind.annotation.RequestMapping注解類型將請求與處理方法一一對應
①、方法級注解
package controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class UserController { @RequestMapping("/login") public String login(){ ... } ... }
作用是放在方法上的,注解的value屬性將請求的URL映射到方法
value屬性是RequestMapping注解的默認屬性,若請求只用value一個屬性,可以省略。
②、類級別注解
package controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import pojo.User; import javax.servlet.http.HttpSession; @Controller @RequestMapping("/user") public class UserController { //處理登陸 @RequestMapping("/login") public String login(User user, HttpSession session, Model model){ ... }
.....
}
在類級別注解下,控制器會將類中的所有方法都映射為類級別的請求。
在開發時,為了方便維護程序,建議使用類級別注解,將相關處理放在同一個控制器中。
3、編寫請求處理方法
①、如果請求處理方法需要使用Servlet API類型,那么可以將這些類型作為請求處理方法的參數類型
如:
@Controller @RequestMapping("/user") public class UserController { //處理登陸 @RequestMapping("/login") public String login(HttpServletRequest req, HttpSession session, Model model){ req.setAttribute("req","req...set");
session.setAttribute("session","session...set");
....... } }
其中Model類型,是一個包含Map的Spring框架類型。
每次調用請求處理方法時spring MVC都將創建Model對象。
②、請求處理方法常見的返回類型
最常見的返回類型就是代表邏輯視圖名稱的String類型,除此之外,還有ModelAndView、Model、View以及其他任意的Java類型。
2、Controller接受請求參數最常見的方式
1、通過實體Bean接受請求參數
通過一個實體Bean來接收請求參數,適用於get和post提交請求的方式。
🐖:Bean的屬性名必須和請求參數的名稱相同。
代碼進行測試:
工程從上一次的工程續寫!!!!
①、創建首頁
index.jsp
<%@ page pageEncoding="UTF-8" import="java.util.*" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> 未注冊的用戶,請<a href="<%=request.getContextPath()%>/index/register">注冊</a><br> 已注冊的用戶請<<a href="<%=request.getContextPath()%>/index/login">登陸</a> </body> </html>
2、配置文件
dispatcher-servlet.xml
<!-- 注解 -->
<!--使用掃描機制 -->
<context:component-scan base-package="controller" />
<!--
annotation-driven用於簡化開發的配置,
注解:DefaultAnnotationHandlerMapping、AnnotationMethodHandlerAdapter
-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--
使用resources過濾掉不需要dispatcherServlet的資源(靜態資源、css、js、html....)
使用resources必須使用annotation-driven,否則resources元素會阻止任意控制器被調用
-->
<!--允許css目錄下所有文件可見 -->
<mvc:resources ma pping="/css/**" location="/css/" ></mvc:resources>
<!--允許html目錄下所有文件可見 -->
<mvc:resources mapping="/html/**" location="/html/" ></mvc:resources>
<!--允許image目錄下所有文件可見 -->
<mvc:resources mapping="/image/**" location="/image/" ></mvc:resources>
<!--配置視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前綴 -->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!--后綴-->
<property name="suffix" value=".jsp"></property>
</bean>
③pojo類
public class User { private String uname; private String upass;private String reupass;
//setter getter
}
④、創建控制器的類
package controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/index") public class IndexController { @RequestMapping("/login") public String login(){ return "login"; } @RequestMapping("/register") public String register(){ return "register"; } }
package controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import pojo.User; import javax.servlet.http.HttpSession; @Controller @RequestMapping("/user") public class UserController { //處理登陸 @RequestMapping("/login") public String login(User user, HttpSession session, Model model){ //注意這里將會對前端頁面進行獲取 System.out.println(user); if(user.getUname().equals("admin") && user.getUpass().equals("1")){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","賬戶或者密碼錯誤!!!"); return "login"; } } //處理注冊 @RequestMapping("/register") public String register(User user,Model model){ if (user.getUname().equals("admin") && user.getUpass().equals("1")){ return "login"; }else { model.addAttribute("uname",user.getUname()); return "register"; } } }
⑤、創建頁面視圖
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<b>登陸</b>
<form action="<%=request.getContextPath()%>/user/login" method="post">
<table border="1" bgcolor="#add8e6" align="center">
<tr>
<td>姓名:</td>
<td>
<input type="text" name="uname" value="${uname}">
</td>
</tr>
<tr>
<td>密碼:</td>
<td>
<input type="text" name="upass" >
</td>
</tr>
<tr>
<td>確定密碼:</td>
<td>
<input type="text" name="reupass" >
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="登陸">
</td>
</tr>
</table>
</form>
${msg}
</body>
</html>
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="<%=request.getContextPath()%>/user/register" method="post" name="register">
<table border="1" bgcolor="#add8e6" align="center">
<tr>
<td>姓名:</td>
<td>
<input type="text" name="uname" value="${uname}">
</td>
</tr>
<tr>
<td>密碼:</td>
<td>
<input type="text" name="upass" >
</td>
</tr>
<tr>
<td>確定密碼:</td>
<td>
<input type="text" name="reupass" >
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="注冊">
</td>
</tr>
</table>
</form>
</body>
</html>
⑥、測試

點擊登陸:

按照上圖的方案進行登陸:

這里成功對登陸進行了攔截!
同時可以參考后台的控制台對數據的捕捉

2、通過HttpServlet接受請求參數
對上述的類進行修改:
UserController .java
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/login") public String login(HttpServletRequest request,Model model){ //獲取賬戶和密碼 String uname = request.getParameter("uname"); String upass = request.getParameter("upass"); System.out.println(uname + "---" + upass); if(uname.equals("admin") && upass.equals("1")){ return "main"; }else { model.addAttribute("msg","賬戶或者密碼錯誤!!!"); return "login"; } } //處理注冊 @RequestMapping("/register") public String register(User user,Model model){ if (user.getUname().equals("admin") && user.getUpass().equals("1")){ return "login"; }else { model.addAttribute("uname",user.getUname()); return "register"; } } }
測試:

點擊登陸:

后台控制台的打印:

3、通過處理方法的形參接受請求參數
對上述的類進行修改:
UserController .java
//通過請求方法的形參
@RequestMapping("/login")
public String login(String uname,String upass,Model model){
//獲取賬戶和密碼
System.out.println(uname + "===" + upass);
if(uname.equals("admin") && upass.equals("1")){
return "main";
}else {
model.addAttribute("msg","賬戶或者密碼錯誤!!!");
return "login";
}
}

按照上述的數據進行登陸測試,檢查后端的打印情況

4、通過@PathVariable接受URL中的請求參數
UserController .java
//通過@PathVariable接受URL中的請求參數 //必須使用method屬性 @RequestMapping(value = "/login/{uname}/{upass}",method = RequestMethod.GET) public String login(@PathVariable String uname,@PathVariable String upass, Model model){ //獲取賬戶和密碼 System.out.println(uname + "===" + upass); System.out.println(uname + "---" + upass); if(uname.equals("admin") && upass.equals("1")){ return "main"; }else { model.addAttribute("msg","賬戶或者密碼錯誤!!!"); return "login"; } }
訪問如下地址:

5、通過@RequestParam接受請求參數
UserController .java
@RequestMapping(value = "/login") public String login(@RequestParam String uname, @RequestParam String upass, Model model){ //獲取賬戶和密碼 System.out.println(uname + "===" + upass);if(uname.equals("admin") && upass.equals("1")){ return "main"; }else { model.addAttribute("msg","賬戶或者密碼錯誤!!!"); return "login"; } }
測試數據

后台檢驗:

6、通過@ModelAttribute接受請求參數
@ModelAttribute注解放在處理方法的形參上時,用於將多個請求參數封裝到一個實體對象中,從而簡化數據的綁定流程
而自動暴露為模型數據,在視圖頁面展示時使用。
@ModelAttribute注解接受請求參數適用於get/pos提交方式
UserController .java
//@ModelAttribute @RequestMapping(value = "/login") public String login(@ModelAttribute("user") User user,HttpSession session,Model model){ System.out.println(user); if(user.getUname().equals("admin") && user.getUpass().equals("1")){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","賬戶或者密碼錯誤!!!"); return "login"; } }
測試數據:

后台打印:

3、重定向與轉發
重定向是將用戶從當前處理的請求重定向到另一個視圖或者處理請求,以前的請求中存放的信息全部失效,並且
進入一個新的request作用域。
轉發是將用戶對當前頁面的請求轉發給另一個視圖或者處理請求,以前的request中存放的信息不會失效。
轉發是服務器行為,重定向是客戶端行為。
轉發過程:
客戶瀏覽器發送http請求,Web服務器接受此請求,調用內部的一個方法在容器內部完成請求處理和轉發
動作,將目標資源發送給客戶;在這里轉發的路徑必須是web容器下的url,其不能完成向其他的web路徑上,
中間傳遞的是自己的容器內的request。客戶瀏覽器的地址欄中顯示的仍然是其第一次訪問時的路徑,也就是
說客戶是感覺不到服務器做了請求的轉發。轉發行為是瀏覽器制作了一次訪問的請求。
重定向過程:
客戶瀏覽器發送http請求,web服務器接受請求后發送302狀態代碼響應及時對應新的location給客戶瀏覽器,
客戶瀏覽器發現是302響應,則自動再發送一個新的http請求,請求URL是新的location地址,服務器根據此
請求尋找資源並發送給客戶。在這里location可以重定向到任意的url,既然是瀏覽器重新發送了請求,那么就
沒什么request傳遞的概念了,在客戶瀏覽器的地址欄中顯示的是其重定向的路徑,客戶可以觀察到地址的變化,
重定向行為是瀏覽器做了至少兩次訪問請求。
spring MVC框架中,控制器默認處理方法的return語句就是轉發的實現,只不過轉發的是視圖!!!
index.jsp
<body> 未注冊的用戶,請<a href="<%=request.getContextPath()%>/index/register">注冊</a><br> 已注冊的用戶請<<a href="<%=request.getContextPath()%>/index/login">登陸</a><br> 請求轉發:<a href="<%=request.getContextPath()%>/index/forward">請求轉發</a><br> 重定向:<a href="<%=request.getContextPath()%>/index/redirect">重定向</a><br> </body>
IndexController .java
@Controller @RequestMapping("/index") public class IndexController { @RequestMapping("/login") public String login(){ return "login"; } @RequestMapping("/register") public String register(){ return "register"; }
@RequestMapping("/redirect") public String redirect(){ return "forward: /index/login"; } @RequestMapping("/forward") public String forward(){ return "redirect:/index/register"; } }
轉發使用:forward
重定向:redirect
4、應用@Autowired進行依賴注入
Spring MVC是一個非常優秀的MVC框架,它具有依賴注入的特點。
可以使用@Autowired注解將依賴注入到一個屬性或者方法。
如:
@Autowired
public UserService userService;
spring MVC為了能被作為依賴注入,類必須使用@Service注解注明為@Service(一個服務)
還需要在配置文件中進行掃描<context:component-scan base-package="包" />元素進行掃描以來的基本包。
UserService.java
package service; import pojo.User; public interface UserService { boolean login(User user); boolean register(User user); }
UserServiceImp.java
package service; import org.springframework.stereotype.Service; import pojo.User; @Service public class UserServiceImp implements UserService { @Override public boolean login(User user) { if ("admin".equals(user.getUname()) && "1".equals(user.getUpass())){ return true; }else { return false; } } @Override public boolean register(User user) { if ("admin".equals(user.getUname()) && "1".equals(user.getUpass())){ return true; }else { return false; } } }
UserController.java
@Controller @RequestMapping("/user") public class UserController { @Autowired private UserServiceImp userServiceImp; //測試@Autowire @RequestMapping("/login") public String login(User user, HttpSession session, Model model){ System.out.println(user); if (userServiceImp.login(user)){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","賬戶或者密碼錯誤!!!"); return "login"; } }
}
dispatcher-servlet.xml
<context:component-scan base-package="service"/>
測試:

進行登陸測試:

后台數據打印:

對於依賴注入在開發的時候經常使用,所以作為java工程師,是必須要進行掌握的!!!
5、@ModelAttribute
@ModelAttribute注解類型可經常實現一下兩個功能:
①、綁定請求參數到實體對象(表單的命令對象)
//@ModelAttribute @RequestMapping(value = "/login") public String login(@ModelAttribute("user") User user,HttpSession session,Model model){ System.out.println(user); if(user.getUname().equals("admin") && user.getUpass().equals("1")){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","賬戶或者密碼錯誤!!!"); return "login"; } }
上述有測試和相關截圖!!!
②、注解一個非請求的處理方法
@ModelAttribute注解的方法將在每次調用該控制器類的請求處理方法前被調用。
這種特性可以用來控制登陸的權限。
BaseController .java
public class BaseController { @ModelAttribute public void isLogin(HttpSession session) throws Exception { if (session.getAttribute("user") == null){ throw new Exception("沒有權限!"); } } }
ModelAttributeController .java
@Controller @RequestMapping("/admin") public class ModelAttributeController extends BaseController { @RequestMapping("/add") public String add(){ return "main"; } }
測試:

在該類中,add方法請求處理時,首先調用父類BaseController中的方法進行判斷登陸權限。
