第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的控制器类UserController中的register方法的代码修改如下:

	@RequestMapping("/register")
//	
//	通过形参接收请求参数,形参名称与请求参数名称完全相同
//	
	public String register(String uname,String upass,Model model) {
		if("zhangsan".equals(uname)&&"123456".equals(upass)){
			logger.info("成功");
			return "login";//注册成功,跳转到login.jsp
		}else{
			logger.info("失败");
		    //在register.jsp页面上可以使用EL表达式${user.uname}取出ModelAttribute的uname值
			model.addAttribute("uname",uname);
			return "register";//返回register.jsp
		}
	}

3.通过@RequestParam接收请求参数
通过@RequestParam接收请求参数,适用于get和post提交请求方式。通过@RequestParam接收请求参数与“通过处理方法的形参接收请求参数”的区别是:当请求参数与接收参数名不一致时,“通过处理方法的形参接收请求参数”不会报400错误,而“通过@RequestParam接收请求参数”会400错误。

	@RequestMapping("/register")
//	
//	通过`@RequestParam`接收请求参数
//	
	public String register(@RequestParam String uname,@RequestParam String upass,Model model) {
		if("zhangsan".equals(uname)&&"123456".equals(upass)){
			logger.info("成功");
			return "login";//注册成功,跳转到login.jsp
		}else{
			logger.info("失败");
		    //在register.jsp页面上可以使用EL表达式${user.uname}取出ModelAttribute的uname值
			model.addAttribute("uname",uname);
			return "register";//返回register.jsp
		}
	}

4.通过@ModelAttribute接收请求参数
@ModelAttribute注解放在处理方法的形参上时,用于将多个请求参数封装到一个实体对象,从而简化数据绑定流程,而且自动暴露为模型数据用于视图页面展示时使用。而“通过实体bean接收请求参数”只是将多个请求参数封装到一个实体对象,并不能暴露为模型数据(需要使用model.addAttribute语句才能暴露为模型数据)

	@RequestMapping("/register")
	public String register(@ModelAttribute("user")UserForm user) {
		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值
			return "register";//返回register.jsp
		}
	}

五、重定向与转发

转发到一个请求方法(同一个控制器类里,可省略/index/)

return "forward:/index/isLogin";

重定向到一个请求方法

return "redirect:/index/isRegister";

转发到一个视图

return "register";

六、应用@Autowired进行依赖注入

可以通过org.springframework.beans.factory.annotation.Autowired注解类型将依赖注入到一个属性(成员变量)或方法,如:

@Autowired
public UserService userService;

七、@ModelAttribute

在前面学习的控制器中,并没有体现MVC的M层,这是因为控制器既充当C层,又充当M层。这样设计程序

通过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 篇

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页