Spring MVC 的Controller
一、基于注解的控制器
前面提到Spring MVC的控制器可以通过传统的方式来创建,即实现Controller
接口。但是传统风格的控制器不仅需要在配置文件中部署URL映射,而且只能编写一个处理方法,不够灵活。而使用基于注解的控制器具有以下两个优点:
(1)基于注解的控制器类中,可以编写多个处理方法,从而能够处理多个请求。
(2)基于注解的控制器不需要配置映射文件,只需要使用@RequestMapping
注解标注在处理方法上即可完成映射,进行请求处理。
Spring MVC中的两个重要的注解类型@Controller
和 @RequestMapping
。
@Controller注解
Spring MVC中使用org.springframework.stereotype.Controller
注解类型来声明某类的实例是一个控制器。在使用@Controller
注解时需要在配置文件中声明spring-context命名空间,并使用< context:componet-scan />
元素指定控制器类的基本包。
@RequestMapping注解
使用org.springframework.web.bind.annotation.RequestMapping
注解类型可以将请求与处理方法一一对应。
1. 方法级别注解
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/index/login")
public String login() {
System.out.println("login");
return "/login.jsp";
}
@RequestMapping(value = "/index/register",method = RequestMethod.POST)
public String register() {
System.out.println("register");
return "/register.jsp";
}
}
2. 类级别注解
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login() {
System.out.println("login");
return "/login.jsp";
}
@RequestMapping("/register")
public String register() {
System.out.println("register");
return "/register.jsp";
}
}
处理方法的参数类型以及返回值类型
(1)处理方法的参数类型可以是多个不同类型的参数,例如Servlet API类型、输入输出流、表单实体类、注解类型、与Spring相关的类型以及其它Java类型等。
(2)最常见的返回类型是代表逻辑视图名称的String类型。除此之外,还有ModelAndView类型、Model、View以及其它任意Java类型。
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login(HttpServletRequest request, HttpSession session) {
// ......
System.out.println("login");
return "/login.jsp";
}
//......
}
二、Controller接收请求参数的常见方式
现在前端有一个表单:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/login" method="post" name="loginForm">
用户名:<input type="text" id="uname" name="uname" value="${uname}" ><br/>
密 码:<input type="password" id="upsd" name="upsd"><br/>
<input type="submit" value="登录">
</form>
<p style="color: red">${loginErrorMsg}</p>
</body>
</html>
那么如何获取上述表单请求过来的参数呢?
通过实体Bean接收请求参数
通过一个实体Bean来接收请求参数,适用于post和get提交方式。要注意的是,Bean的属性名称必须与请求参数名称一致。例如 创建一个UserForm的实体Bean 。
package pojo;
public class UserForm {
//与请求参数名一致
private String uname;
private String upsd;
//省略setter和getter方法
}
通过UserForm来接收请求参数:
@Controller
@RequestMapping("/user")
public class UserController {
//得到一个用来记录日志信息的对象,这样在打印信息的时候能够标记打印的是哪个类的信息
private static final Log logger = LogFactory.getLog(UserController.class);
/**
* 处理登录
* 使用UserForm对象(实体类Bean)user来接收登录页面的提交的请求参数
*/
@RequestMapping("/login")
public String userLogin(UserForm user, HttpSession session, Model model) {
System.out.println(user);
if ("zhangsan".equals(user.getUname()) && "123456".equals(user.getUpsd())) {
session.setAttribute("user", user);
logger.info("登录成功!");
return "/main.jsp";
} else {
logger.info("登录失败!");
model.addAttribute("loginErrorMsg", "用户名或密码错误!");
return "/login.jsp";
}
}
// 省略其他代码.....
}
通过处理方法的形参接收请求参数
直接把表单的请求参数写在控制器的处理方法的形参中,形参名必须与请求参数名一致。适用于post和get提交方式。
/**
* 通过处理方法的形参接收请求参数,形参名称与请求参数名称完全一致
* */
@RequestMapping("/login")
public String userLogin(String uname, String upsd ,HttpSession session) {
// ...省略代码...
return null;
}
通过HttpServletRequest接收请求参数
适用于post和get提交方式。
/**
* 通过HttpServletRequest接收请求参数
* */
@RequestMapping("/login")
public String userLogin(HttpServletRequest request) {
String umame = request.getParameter("umame");
String upsd = request.getParameter("upsd");
// ...省略代码...
return null;
}
通过@PathVariable接收URL中的请求参数
适用于get提交方式。
形如 http://xxxx.xxx.xxx/login/zhangsan/123456,这里zhangsan和123456就是请求参数
必须添加method属性
/**
* 通过@PathVariable接收URL中的请求参数
* 必须添加method属性
* */
@RequestMapping(value="/login/{uname}/{upsd}",method = RequestMethod.GET)
public String userLogin(@PathVariable String uname,@PathVariable String upsd) {
// ...省略代码...
return null;
}
通过@RequestParam接收请求参数
适用于post和get提交方式。
与“通过处理方法的形参接收请求参数”的区别 在于: 当请求参数与接收参数名不一致时, “通过形参接收请求参数” 不会报404错误,而 “通过@RequestParam接收请求参数” 则会报404错误。
/**
* 通过@RequestParam接收请求参数
* */
@RequestMapping("/login")
public String userLogin(@RequestParam String uname, @RequestParam String upsd) {
// ...省略代码...
return null;
}
除此之外,@RequestParam
还有其他属性。例如:
required
:说明该参数不是必要的,可以接收值也可以不接收值。defaultValue
:当该参数没有对应的值时,可以设置默认值。
@RequestParam(value="uame", required=false, defaultValue="zhangsan")
通过@ModelAttribute接收请求参数
使用 @ModelAttribute
注解在处理方法的形参上,用于将多个请求参数封装到一个实体对象中,并自动暴露为模型数据 ,在视图页面展示时使用;而“通过实体Bean接收请求参数” 只是将多个请求参数封装到一个实体对象,并没有暴露为模型数据,需要通过model.addAttribute
语句才能实现。适用于post和get提交方式。
/**
* 通过@ModelAttribute接收请求参数
* */
@RequestMapping("/login")
public String userLogin(@ModelAttribute("user") UserForm user) {
// 使用 @ModelAttribute("user")与 model.addAttribute("user",user)功能相同
// ...省略代码...
return null;
}
拓展:@ModelAttribute
上述内容提到,@ModelAttribute注解可以绑定请求参数到实体对象,并自动暴露为模型数据。
除此之外,@ModelAttribute还可以注解一个非请求处理方法。
被@ModelAttribute注解的方法将在每次调用该控制器类的请求处理方法前被调用。这种特性可以用来控制登录权限。当然,控制登录权限的方法有很多种,比如拦截器、过滤器等。