1. 程式人生 > 其它 >第2章 Spring MVC基礎:3、基於註解的控制器

第2章 Spring MVC基礎:3、基於註解的控制器

技術標籤:springjavamvcweb

學習目標:

基於註解的控制器


學習大綱:

一、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 篇