@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,[email protected],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", "[email protected]", 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","[email protected]",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
<%-- 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,[email protected],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="[email protected]"> <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>
<?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中的语言设置即可....