外网解释地址:https://springframework.guru/spring-framework-annotations/
1.@RequestParam注解
@RequestParam有三个参数:
value:参数名;
required:是否必需,默认为true,表示请求参数中必须包含该参数,如果不包含抛出异常。
defaultValue:默认参数值,如果设置了该值自动将required设置为false,如果参数中没有包含该参数则使用默认值。
示例:@RequestParam(value = "userId", required = false, defaultValue = "1")
2.@PathVariable注解
当使用@RequestMapping URI占位符映射时,Url中可以通过一个或多个{xxxx}占位符映射,通过@PathVariable可以绑定占位符参数到方法参数中。
例如:@PathVariable("userId") Long userId,@PathVariable("userName") String userName
(注:Long类型可以根据需求自己改变String或int,spring会自动做转换)
@RequestMapping(“/user/{userId}/{userName}/query")
请求URL:http://localhost/user/8/张山/query
3.ModelAttribute
@ModelAttribute 注解可被应用在方法或方法参数上
注解在方法上的 @ModelAttribute 说明了方法的作用是用于添加一个或多个属性到model上。
这样的方法能接受与 @RequestMapping 注解相同的参数类型,只不过不能直接被映射到具体的请求上。
在同一个控制器中,注解了 @ModelAttribute 的方法实际上会在 @RequestMapping 方法之前被调用
在方法使用@ModelAttribute 方法的两种风格,详情示例代码如下:
public class Account implements Serializable {
private static final long serialVersionUID = -3075041060818483817L;
private String name;
private Integer age;
// getter and setter
}
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/modelAtt")
public class ModeAttributeTest {
/**
* 方法-:
* 方法通过返回值的方式默认地将添加一个属性
*
* 属性名没有被显式指定的时:框架将根据属性的类型给予一个默认名称
* 例如:本例返回一个 Account 类型的对象,则默认的属性名为"account"
* 你可以通过设置 @ModelAttribute 注解的值来改变默认值 @ModelAttribute("myAccount")
* @param name
* @return
*/
@ModelAttribute
public Account addAccount(@RequestParam(value = "name",defaultValue = "test")String name) {
Account ac = new Account();
ac.setName(name);
ac.setAge(12);
return ac;
}
/**
* 方法二:
* 方法接收一个 Model 对象,然后可以向其中添加任意数量的属性
* @param number
* @param model
*/
@ModelAttribute
public void populateModel(@RequestParam(value = "number",defaultValue = "123") String number, Model model) {
model.addAttribute("number", number);
model.addAttribute("other", "other");
}
@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView modelAndView = new ModelAndView("hello");
return modelAndView;
}
}
相关页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
账户名称:${account.name}<br/>
年龄:${account.age}<br/>
number:${number}<br/>
other:${other}<br/>
</body>
</html>
请求:http://localhost:8085/modelAtt/hello?name=zhangsan&number=123
@ModelAttribute 方法通常被用来填充一些公共需要的属性或数据,比如一个下拉列表所预设的几种状态,或者宠物的几种类型,或者去取得一个HTML表单渲染所需要的命令对象,比如 Account 等
注意
@ModelAttribute 注解也可以被用在 @RequestMapping 方法上。这种情况下, @RequestMapping 方法的返回值将会被解释为model的一个属性,而非一个视图名。此时视图名将以视图命名约定来方式来决议,与返回值为void的方法所采用的处理方法类似
以我的配置为例
<!-- 视图解析 -->
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="order" value="2" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
@Controller
@RequestMapping("/modelAtt")
public class ModeAttributeTest {
@ModelAttribute("key")
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
此时在浏览器中请求/hello 时,会去找/WEB-INF/jsp/modelAtt/hello.jsp此页面,并可在页面中获取附带的数据${key}
注解在方法参数上的 @ModelAttribute 说明了该方法参数的值将由model中取得。如果model中找不到,那么该参数会先被实例化,然后被添加到model中。在model中存在以后,请求中所有名称匹配的参数都会填充到该参数中。这在Spring MVC中被称为数据绑定,一个非常有用的特性,节约了你每次都需要手动从表格数据中转换这些字段数据的时间。
@RequestMapping("/hello")
public ModelAndView hello(@ModelAttribute Account account){
account.setAge(12);
account.setName("456");
return new ModelAndView("hello");
}
上面的代码只是一种简单的使用方法
其实account的来源可由以下几种方式获得
- 它可能因为 @SessionAttributes 注解的使用已经存在于model中
- 它可能因为在同个控制器中使用了 @ModelAttribute 方法已经存在于model中
- 它可能是由URI模板变量和类型转换中取得的
- 它可能是调用了自身的默认构造器被实例化出来的
4.BindingResult
在JavaBean中添加数据校验的注解
其中@Length、@email就是Hibernate-validator中的数据校验注解,还可以用javax.validation中的注解,比如@NotNull
public class SystemUser {
@Length(min = 5, max = 20, message = "用户名长度必须位于5到20之间")
private String userName;
@Email(message = "比如输入正确的邮箱")
private String email;
}
在Controller方法中指定需要进行校验
首先,要在需要进行校验的Bean前面加上@Valid注解,告诉SpringMVC框架这个Bean需要进行校验;
同时,还要在需要校验的Bean前面加上@modelattribute注解,从而将Bean暴露给视图,并且指定名字,这有两个作用,第一是显示校验错误需要使用这个名字,第二个是返回原来的页面以后,前面输入的所有值还要显示出来;
其次,每个需要校验的Bean后面紧跟一个BindingResult,SpringMVC框架会将校验结果保存在它里面,通过hasErrors方法可以判断是否有校验错误;
最后,当返回到原页面以后,SpringMVC框架还会将所有校验错误信息保存在上下文中,供页面上取得校验错误,Spring提供了一套JSP自定义标签。
@RequestMapping(value = "/create.html", method = RequestMethod.POST)
public String doCreateUser(
@Valid @ModelAttribute("userDetail") SystemUser user,
BindingResult bindingResult,
HttpServletRequest request) {
// 如果有校验错误,返回添加用户的页面
if (bindingResult.hasErrors()) {
return "/user/create";
}
this.userService.createUser(user);
return "/user/list.html";
}
进行自定义校验
如果需要添加自定义校验,比如验证用户名是否已经被使用了,那么简单的注解自然无能为力,需要自己编码实现,如果校验失败,可以手动将自定义校验错误添加到BindingResult中。
@RequestMapping(value = "/user/create.html", method = RequestMethod.POST)
public String doCreateUser(
@Valid @ModelAttribute("userDetail") SystemUser user,
BindingResult bindingResult,
HttpServletRequest request) {
// 如果有数据校验错误,返回添加用户的页面
if (bindingResult.hasErrors()) {
return "/user/create";
}
boolean isUserNameExist = this.userService.checkUserByUserName(user.getUserName());
// 如果用户名已存在,返回添加用户的页面
if (isUserNameExist) {
// 向BindingResult添加用户已存在的校验错误
bindingResult.rejectValue("userName", "该用户名已存在", "该用户名已存在");
return "/user/create";
}
this.userService.createUser(user);
return "/user/list.html";
}
在JSP页面上显示校验错误信息
返回页面以后,SpringMVC框架将所有校验错误信息都放在了上下文中,可以自己去取出来,但是那样非常麻烦,不过没关系,Spring提供了一套自定义标签,可以方便的显示校验错误信息。
页面头部需要导入Spring的自定义标签库
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
需要一次性显示全部校验错误
(commandName的值就是@modelattribute注解中指定的值)
<form:form commandName="userDetail">
<form:errors path="*" cssStyle="color:red"></form:errors>
</form:form>
需要在对应输入框的后面显示单个校验错误
(通过path指定显示那个具体的校验错误,userDetail正是@modelattribute注解中指定的值,而点号后面则是指定显示Bean中哪个属性的校验错误)
<input type="text" name="userName" value="${userDetail.userName}" >
<form:errors path="userDetail.userName" cssStyle="color:red"></form:errors>
<input type="text" name="email" value="${userDetail.email}">
<form:errors path="userDetail.email" cssStyle="color:red"></form:errors>