第2章 Spring MVC基礎:3、基於註解的控制器
學習目標:
基於註解的控制器
學習大綱:
一、Controller註解型別
二、RequestMapping註解型別
三、編寫請求處理方法
四、Controller接收請求引數的常見方式
五、重定向與轉發
六、應用@Autowired進行依賴注入
七、@ModelAttribute
學習內容:
在使用Spring MVC進行Web應用開發時,Controller是Web應用的核心。Controller實現類包含了對使用者請求的處理邏輯,是使用者請求和業務邏輯之間的橋樑,是Spring MVC框架的核心部分,負責具體的業務邏輯處理。
一、Controller註解型別
在Spring MVC中,使用org.springframework.stereotype.Controller
註解型別宣告某類的例項是一個控制器。例如,2.2.2節中的IndexController控制器類。別忘了在Spring MVC的配置檔案中使用context:component-scan/元素(見【例2-1】)或在Spring MVC配置類中使用@ComponentScan
(見【例2-2】)指定控制器類的基本包,進而掃描所有註解的控制器類。
二、RequestMapping註解型別
在基於註解的控制器類中,可以為每個請求編寫對應的處理方法。需要使用org.springframework.web.bind.annotation.RequestMapping
1.方法級別註解
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping(value="/index/login")
public String login() {
/**login代表邏輯檢視名稱,需要根據Spring MVC配置
* 檔案中internalResourceViewResolver的字首和字尾找到對應的物理檢視
*/
return "login";
}
@RequestMapping(value="/index/register")
public String register() {
return "register";
}
}
2.類級別註解
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**“@Controller”表示IndexController的例項是一個控制器
* @Controller相當於@Controller("indexController")
* 或@Controller(value = "indexController")
*/
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login() {
/**login代表邏輯檢視名稱,需要根據Spring MVC配置
* 檔案中internalResourceViewResolver的字首和字尾找到對應的物理檢視
*/
return "login";
}
@RequestMapping("/register")
public String register() {
return "register";
}
}
為了方便程式維護,建議開發者採用類級別的註解,將相關處理放在同一個控制器類中,例如,對商品的增、刪、改、查處理了方法都可以放在一個名為GoodsOperate的控制類中。
三、編寫請求處理方法
1.請求處理方法中常出現的引數型別
Servlet API、輸入輸出流、表單實體類、註解型別、Model等Java型別。
在控制類中每個請求處理方法中使用Servlet API型別,那麼可以將這些型別作為請求處理方法的引數型別。Servlet API引數型別示例程式碼如下:
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/index")
public class IndexController1
{
@RequestMapping("/login")
public String login(HttpSession session,HttpServletRequest request) {
session.setAttribute("skey", "session範圍的值");
session.setAttribute("rkey", "request範圍的值");
return "login";
}
}
2.請求處理方法常見的返回型別
最常見的返回型別,就是代表邏輯檢視名稱的String型別。除了String型別外,還有Model、View以及其他任意的Java型別。
四、Controller接收請求引數的常見方式
Controller接收請求引數的方式有很多種,有的適合get請求方式,有的適合post請求方式,有的兩者都適合。下面介紹幾種方式:
1.通過實體bean接收請求引數
通過一個實體bean來接收請求引數,適用於get和post提交請求方式。需要注意的是,bean的屬性名稱必須與請求引數名稱相同。下面通過一個例項,講解“通過實體bean接收請求引數”
【例2-3】通過實體bean接收請求引數
具體步驟如下:
1)建立Web應用並匯入JAR包
建立Web應用ch2_3,匯入如圖所示的JAR包。
下載Spring包的方法
2)建立檢視檔案
在應用ch2_3的WEB-INF/jsp/目錄下有register.jsp、login.jsp和main.jsp檔案
register.jsp的程式碼如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/user/register" method="post" name="registForm">
<table border=1>
<tr>
<td>姓名:</td>
<td>
<input type="text" name="uname" value="${user.uname }"/>
</td>
</tr>
<tr>
<td>密碼:</td>
<td><input type="password" name="upass"/></td>
</tr>
<tr>
<td>確認密碼:</td>
<td><input type="password" name="reupass"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="註冊" />
</td>
</tr>
</table>
</form>
</body>
</html>
login.jsp的程式碼如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/user/login" method="post">
<table>
<tr>
<td align="center" colspan="2">登入</td>
</tr>
<tr>
<td>姓名:</td>
<td><input type="text" name="uname"></td>
</tr>
<tr>
<td>密碼:</td>
<td><input type="password" name="upass"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交" >
<input type="reset" value="重置" >
</td>
</tr>
</table>
${messageError }
</form>
</body>
</html>
main.jsp的程式碼如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
主頁面!
</body>
</html>
在ch2_3應用的/WebContent/目錄下有index.jsp,具體程式碼如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
沒註冊的使用者,請<a href="user/register">註冊</a>!<br>
已註冊的使用者,去<a href="user/login">登入</a>!
</body>
</html>
3)建立POJO實體類
在ch2_3應用的src目錄下,建立pojo包,並在該包中建立實體類UserForm,具體程式碼如下:
package pojo;
public class UserForm {
private String uname;//與請求引數名稱相同
private String upass;
private String reupass;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
public String getReupass() {
return reupass;
}
public void setReupass(String reupass) {
this.reupass = reupass;
}
}
4)建立控制器類
在ch2_3應用的src目錄下,建立controller包,並在該包中建立控制器類UserController。
package controller;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import pojo.UserForm;
@Controller
@RequestMapping("/user")
public class UserController {
//得到一個用來記錄日誌的物件,這樣列印資訊的時候能夠標記列印的是那個類的資訊
private static final Log logger = LogFactory.getLog(UserController.class);
/**
* 處理登入
*/
@RequestMapping("/login")
public String login(UserForm user, HttpSession session, Model model) {
if("zhangsan".equals(user.getUname())&&"123456".equals(user.getUpass())){
session.setAttribute("u", user);
logger.info("成功");
return "main";//登入成功,跳轉到main.jsp
}else{
logger.info("失敗");
model.addAttribute("messageError", "使用者名稱或密碼錯誤");
return "login";
}
}
/**
*處理註冊
*/
@RequestMapping("/register")
public String register(UserForm user,Model model) {
if("zhangsan".equals(user.getUname())&&"123456".equals(user.getUpass())){
logger.info("成功");
return "login";//註冊成功,跳轉到login.jsp
}else{
logger.info("失敗");
//使用@ModelAttribute("user")與model.addAttribute("user", user)功能相同
//在register.jsp頁面上可以使用EL表示式${user.uname}取出ModelAttribute的uname值
model.addAttribute("uname", user.getUname());
return "register";//返回register.jsp
}
}
}
5)建立Web與Spring MVC的配置類
在ch2_3應用的src目錄下,建立config包,並在該包中建立Spring MVC配置類SpringMVCConfig和Web配置類WebConfig。
SpringMVCConfig的程式碼如下:
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan("controller")
public class SpringMVCConfig implements WebMvcConfigurer {
/**
* 配置檢視解析器
*/
@Bean
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
/**
* 配置靜態資源
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/html/**").addResourceLocations("/html/");
}
}
WebConfig的程式碼如下:
package config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class WebConfig implements WebApplicationInitializer{
@Override
public void onStartup(ServletContext arg0) throws ServletException {
AnnotationConfigWebApplicationContext ctx
= new AnnotationConfigWebApplicationContext();
ctx.register(SpringMVCConfig.class);//註冊Spring MVC的Java配置類SpringMVCConfig
ctx.setServletContext(arg0);//和當前ServletContext關聯
/**
* 註冊Spring MVC的DispatcherServlet
*/
Dynamic servlet = arg0.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
6)釋出並執行應用
右擊ch2_3應用,選擇Run As|Run on Server命令釋出並執行應用。
2.通過處理方法的形參接收請求引數
通過處理方法的形參接收請求引數,也就是直接把表單引數寫在控制器類相應方法的形參中,即形參名稱與請求引數名稱完全相同。該接收引數方式適用於get和post提交請求方式。見【例2-3】
3.通過@RequestParam
接收請求引數
通過@RequestParam
接收請求引數,適用於get和post提交請求方式。通過@RequestParam
接收請求引數與“通過處理方法的形參接收請求引數”的區別是:當請求引數與接收引數名不一致時,“通過處理方法的形參接收請求引數”不會報400錯誤,而“通過@RequestParam
接收請求引數”會400錯誤。
4.通過@ModelAttribute
接收請求引數
@ModelAttribute
註解放在處理方法的形參上時,用於將多個請求引數封裝到一個實體物件,從而簡化資料繫結流程,而且自動暴露為模型資料用於檢視頁面展示時使用。而“通過實體bean接收請求引數”只是將多個請求引數封裝到一個實體物件,並不能暴露為模型資料(需要使用model.addAttribute
語句才能暴露為模型資料)
五、重定向與轉發
轉發到一個請求方法(同一個控制器類裡,可省略/index/)
return "forward:/index/isLogin";
重定向到一個請求方法
return "redirect:/index/isRegister";
轉發到一個檢視
return "register";
六、應用@Autowired進行依賴注入
可以通過org.springframework.beans.factory.annotation.Autowired
註解型別將依賴注入到一個屬性(成員變數)或方法,如:
@Autowired
public UserService userService;
七、@ModelAttribute
通過org.springframework.web.bind.annotation.ModelAttribute
註解型別,可經常實現如下兩個功能:
1.繫結請求引數到實體物件(表單的命令物件)
public String register(@ModelAttribute("user") UserForm user) {}
“@ModelAttribute(”user“) UserForm user”
語句的功能有兩個,一是將請求引數的輸入封裝到user物件中;一是建立UserForm例項,以“user”為鍵值儲存在Model物件中,與“model.addAttribute(”user“, user)”
語句功能一樣。如果沒有指定鍵值,即“@ModelAttribute UserForm user”
,那麼建立UserForm例項時,以“userForm”為鍵值儲存在Model物件中,與“model.addAttribute(”userForm“, user)”
語句功能一樣。
2.註解一個非請求處理方法
被@ModelAttribute註解的控制器的一個非請求處理方法,將在每次呼叫該控制器類的請求處理方法前被呼叫。這種特性可以用來控制登入許可權。
學習時間:
學習產出:
1、 技術筆記 1 遍
2、CSDN 技術部落格 1 篇