@ModelAttribute 这个注解注释比较多..
我自己都有点看懵逼了...
还是在原来的例子上的Demo....
@ModelAttribute 和视图解析,以及国际化 我都写一起了,就不分开了..
package com.springmvc.handlers;
import com.springmvc.model.User;
import com.springmvc.model.User2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
/**
* Created by CYX on 2016/4/15.
*/
@SessionAttributes(value = {"user"},types = {String.class})
@RequestMapping("/main")
@Controller
public class Main {
private static final String SUCCESS = "success";
/**
* 视图和视图解析器
* 请求处理方法执行完成后,最终返回一个ModelAndView对象.
* 对于那些返回String,View或ModeMap等类型的处理方法,SpringMVC也会在内部将他们装配成一个ModelAndView对象,它包含了逻辑名和模型对象的视图.
*
* SpringMVC借助视图解析器,得到最终的视图对象,最终的视图可以使JSP,也可能是Excel,JFreeChart等各种表现形式的视图.
* 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现MVC的充分解耦.
*
* 视图: 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户.
* 为了实现视图模型和具体实现技术的解耦,Spring在org.springframework.web.servlet 包中定义了一个高度抽象的View接口.
* 视图对象由视图解析器负责实例化.由于视图是无状态的,所以他们不会有线程安全问题.
*
* 视图解析器: SpringMVC为逻辑视图名的解析提供了不同的策略,可以再SpringWEB上下文中配置一种或多种解析策略,并指定它们之间的先后顺序.
* 每一种映射策略对应一个具体的视图解析器实现类.
* 视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象.
* 所有的视图解析器都必须实现ViewResolver接口.
* @return
*/
@RequestMapping("/testViewAndViewResolver")
public String testViewAndViewResolver() {
System.out.println("testViewAndResolver");
return SUCCESS;
}
/**
* 模拟提交用户表单数据,不提交用于密码,而是直接去数据库中获取,将要更新的参数更新.
* 模拟修改操作
* 1.原始数据为: 1,Tom,123456,tom@163.com,12
* 2.密码不能被修改
* 3.表单回显,模拟操作直接在表单填写对应的属性值
*
* 1.由@ModelAttribute标记的方法,会在每个目标方法执行之前被SpringMVC调用
* 2.@ModelAttribute 注解也可以来修饰目标方法POJO类型的入参.其value属性值有如下的作用:
* (1).SpringMVC 会使用value属性值在 implicitModel 中查找对应的对象,若存在则会直接传入到目标方法的入参中.
* (2).SpringMVC 会一 value为key,POJO 类型的对象为value,存入到request中.
* @param id
* @param map
*/
@ModelAttribute
public void getUser2(@RequestParam(value = "id",required = false)Integer id,
Map<String,Object> map) {
System.out.println("ModelAttribute method");
if (id != null) {
//模拟从数据库中获取对象
User2 user2 = new User2(1, "Tom", "123456", "tom@163.com", 12);
System.out.println("从数据库获取一个对象: "+user2);
map.put("abc", user2);
}
}
/**
* 运行流程:
* 1.执行@ModelAttribute注解修饰的方法: 从数据库中取出对象,把对象放入到Map中,键位 user
* 2.SpringMVC从Map中取出user对象,并把表单的请求参数,赋给该User对象的对应属性.
* 3.SpringMVC把上述对象,传入目标方法的参数
*
* 注意: 在@ModelAttribute修饰的方法中,放入到Map中的键,需要和目标方法入参名字保持一致
*
* SpringMVC 确定目标方法POJO类型入参的过程.
* 1.确定一个key
* (1).若目标方法的POJO类型的参数没有使用@ModelAttribute 作为修饰,则key 为 POJO 类名第一个字母的小写.
* (2).若使用了@ModelAttribute 来修饰,则 key 为@ModelAttribute 注解的value属性值.
* 2.在implicitModel 中查找key对应的对象.若存在,则 作为入参传入.
* (1).若在@ModelAttribute 标记的方法中在Map 中保存过,且key 和 1 确定的key一致,则会获取到.
* 3.若implicitModel 中不存在key对应的对象,则检查当前的Handler是否使用@SessionAttribute注解修饰.
* 若使用了该注解, 且@SessionAttribute 注解的value属性值中包含了key,则会从HttpSession中来获取key所对应的value值,
* 若存在则直接传入到目标方法中,若不存在则将抛出异常.
* 4.若Handler 没有标示@SessionAttribute 注解 或 @SessionAttribute 注解的value值不包含key,则会通过反射来创建POJO类型的参数,传入目标方法的参数
* 5.
*
*
* 源码分析流程:
* 1.首先调用@ModelAttribute 注解修饰的方法, 实际上是把 @ModelAttribute 方法中 Map 中的数据放在了implicitModel中.
* 2.解析请求处理器的目标参数,实际上 该目标参数来自于 WebDataBinder 对象的 target 属性
* (1).创建WebDataBinder 对象:
* 1).确定objectName属性 若传入的attrName 属性值为"",则 objectName为类名第一个字母小写.
* 注意: attrName. 若目标方法的POJO属性使用了@ModelAttribute来修饰,则attrName 即为@ModelAttribute的value属性值.
* 2).确定target属性
* > 在implicitModel中查找attrName对应的属性值. 若存在,OK
* > 若不存在:则验证当前Handler是否使用了@SessionAttributes 进行修饰,若使用了,则尝试从Session中获取attrName 所对应的属性值.
* 若session 中没有对应的属性,则抛出异常
* > 若Handler没有使用@SessionAttribute 进行修饰,或@SessionAttribute 中没有使用value值指定的key和attrName相匹配,则通过反射创建POJO对象
*
* (2).SpringMVC 把表单的请求参数赋给了WebDataBinder 的target对应的属性.
* (3).SpringMVC 会把WebDataBinder 的 attrName 和 target 给到implicitModel
* (4).把WebDataBinder 的tager 作为参数传递给目标方法的入参
* (5).SpringMVCh会把key 和 value 保存到implicitModel中,进而会保存到request中.
*
* @ModelAttribute("abc") 相当于给user2 这个名字 加上一个别名.这样子,abc 也可以 找到 user2 这个对象.
*
*
* @param user2
* @return
*/
@RequestMapping("/testModelAttribute")
public String testModelAttribute( @ModelAttribute("abc") User2 user2) {
System.out.println("修改: "+user2);
return SUCCESS;
}
/**
* @SessionAttributes
* 若希望在多个请求之间共用某个某型属性数据,则可以在控制器类上标注一个@SessionAttributes,SpringMVC将在模型中对应的属性暂存到HttpSession中.
* @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(Value属性值)
* 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(types属性值)
* 这个注解 只能放在类的上面.
*
*
* @param map
* @return
*/
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Map<String,Object> map) {
User user = new User("Tom","123456","Tom@163.com",15);
map.put("user", user);
map.put("school", "亚信");
System.out.println();
return SUCCESS;
}
/**
* 处理模型数据的第二种方式
* 目标方法可以添加Map类型的参数.
*实际上也可以是Model类型,或ModelMap类型.
*
* @param map
* @return
*/
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map) {
System.out.println(map.getClass().getName());
map.put("names", Arrays.asList("Tom", "Jerry", "Mike"));
System.out.println();
return SUCCESS;
}
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
String viewName = SUCCESS;
ModelAndView modelAndView = new ModelAndView(viewName);
System.out.println("testModelAndView");
modelAndView.addObject("time", new Date());
modelAndView.addObject("str", "Hello");
return modelAndView;
}
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(value = "username") String userName,
@RequestParam(value = "age",required = false ,defaultValue = "0") Integer age) {
System.out.println("testRequestParam userName: "+userName+", age: "+age);
return SUCCESS;
}
@RequestMapping("/testPojo")
public String testPojo(User user) {
System.out.println("testPojo User:"+user);
return SUCCESS;
}
@RequestMapping("/testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") Integer id) {
System.out.println("testPathVariable id: "+id);
return SUCCESS;
}
@RequestMapping(value = "/testMethod",method = RequestMethod.POST)
public String testMethod() {
System.out.println("testMethod POST");
return SUCCESS;
}
@RequestMapping("/sayHello")
public String sayHello() {
System.out.println("Hello");
return SUCCESS;
}
}
success.jsp
<%--
Created by IntelliJ IDEA.
User: CYX
Date: 2016/4/15
Time: 22:38
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title></title>
</head>
<body>
Success Page!
<br>
<br>
time:${requestScope.time}
<br>
<br>
String:${requestScope.str}
<br>
<br>
names:${requestScope.names}
<br>
<br>
request user:${requestScope.user}
<br>
<br>
request user2:${requestScope.user2}
<br>
<br>
request school:${requestScope.school}
<br>
<br>
session user:${sessionScope.user}
<br>
<br>
session school:${sessionScope.school}
<br>
<br>
<fmt:message key="i18n.username"></fmt:message>
<fmt:message key="i18n.password"></fmt:message>
</body>
</html>
i18n.username=\u7528\u6237\u540d
i18n.password=\u5BC6\u7801
i18n.username=Username
i18n.password=Password
index.jsp
<%--
Created by IntelliJ IDEA.
User: CYX
Date: 2016/4/15
Time: 21:53
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
<a href="/main/testViewAndViewResolver">testViewAndViewResolver</a>
<!--
模拟修改操作
1.原始数据为: 1,Tom,123456,tom@163.com,12
2.密码不能被修改
3.表单回显,模拟操作直接在表单填写对应的属性值
-->
<br><br>
<form action="main/testModelAttribute" method="post">
<input type="hidden" name="id" value="1">
<br>
username:<input type="text" name="username" value="Tom">
<br>
email:<input type="text" name="email" value="tom@163.com">
<br>
age:<input type="text" name="age" value="12">
<br>
<input type="submit" value="submit">
</form>
<br><br>
<a href="main/testSessionAttributes">testSessionAttribute</a>
<br><br>
<a href="main/testMap">testMap</a>
<br><br>
<a href="main/testModelAndView">testModelAndView</a>
<br><br>
<a href="main/testRequestParam?username=cyx&age=11">testRequestParam</a>
<br><br>
<form action="main/testPojo" method="post">
username:<input type="text" name="username"><br>
password:<input type="text" name="password"><br>
email:<input type="text" name="email"><br>
age:<input type="text" name="age"><br>
city:<input type="text" name="address.city"><br>
province:<input type="text" name="address.province"><br>
<input type="submit" value="PojoUserAddress对象">
</form>
<form action="main/testPojo" method="post">
username:<input type="text" name="username"><br>
password:<input type="text" name="password"><br>
email:<input type="text" name="email"><br>
age:<input type="text" name="age"><br>
<input type="submit" value="PojoUser对象">
</form>
<br>
<a href="main/testPathVariable/1">testPathVaiable id=1</a>
<br>
<form action="main/testMethod" method="post">
<input type="submit" value="testMethodPost">
</form>
<a href="main/testMethod">testMethod Get</a>
<br>
<a href="main/sayHello">sayHello</a>
</body>
</html>
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.springmvc.handlers"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--配置国际化资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
</beans>
部署运行即可...
测试国际化的话,使用IE浏览器,切换Inter中的语言设置即可....