一,Controller层方法(Action)参数映射
1,自动参数映射
1.1,基本数据类型参数映射
方法的参数可以是任意基本数据类型,如果方法参数名与http中请求的参数名称相同时会进行自动映射。例如:
ActionController:
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: returnAction * @描述: 自动参数映射---基本数据类型 * @param model * @param i * @param s * @return 返回视图名称 * @创建人 Zender */ @RequestMapping("/returnAction") public String returnAction(Model model, int i, String s) { model.addAttribute("message", "i:" + i + ",s:" + s); return "index"; } }
Index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 内容:${message} </body> </html>
运行结果:
1.2,自定义数据类型参数映射
自定义的POJO对象,Spring MVC会通过反射把请中的参数设置到对象中,转换类型,例如:
Person:
public class Person { private int id; private String name; private String addrs; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddrs() { return addrs; } public void setAddrs(String addrs) { this.addrs = addrs; } public Person(int id, String name, String addrs) { this.id = id; this.name = name; this.addrs = addrs; } public Person() { } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", addrs=" + addrs + "]"; } }
ActionController:
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: returnPersonAction * @描述: 自动参数映射---自定义数据类型 * @param model * @param person * @return 返回视图名称 * @创建人 Zender */ @RequestMapping("/returnPersonAction") public String returnPersonAction(Model model, Person person){ model.addAttribute("person", person.toString()); return "index"; } }
index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 内容:${person} </body> </html>
运行结果:
1.3,复杂数据类型参数映射
复杂数据类型指的是一个自定义类型中还包含另外一个对象类型,或者包含集合,Map等等对象类型,例如如下Pojo类:
public class SysUser { private String userName; private String userPwd; private Person person; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public SysUser(String userName, String userPwd, Person person) { this.userName = userName; this.userPwd = userPwd; this.person = person; } public SysUser() { } @Override public String toString() { return "SysUser [userName=" + userName + ", userPwd=" + userPwd + ", person=" + person + "]"; } }
Index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form method="post" action="Action/returnSysUserAction"> username:<input name="userName" /><br/> userpwd:<input name="userPwd" /><br/> id:<input name="person.id" /><br/> name:<input name="person.name" /><br/> addrs:<input name="person.addrs" /><br/> <button>提交</button> </form> </body> </html>
return.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 内容:${sysUser} </body> </html>
ActionController:
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: returnSysUserAction * @描述: 自动参数映射---复杂数据类型 * @param model * @param sysUser * @return 返回视图名称 * @创建人 Zender * @创建时间 2017年12月10日下午6:33:43 */ @RequestMapping("/returnSysUserAction") public String returnSysUserAction(Model model, SysUser sysUser){ model.addAttribute("sysUser", sysUser.toString()); return "return"; } }
运行结果:
1.4,集合类型参数映射
List集合类型:
不能直接在方法(action)的参数中指定List<T>类型,定义一个类型包装List集合在其中,例如:
public class PersonList { private List<Person> list; public List<Person> getList() { return list; } public void setList(List<Person> list) { this.list = list; } }
定义方法(action)代码如下:
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: returnListAction * @描述: 自动参数映射---List数据类型 * @param model * @param personList * @return * @创建人 Zender */ @RequestMapping("/returnListAction") public String returnListAction(Model model, PersonList personList){ model.addAttribute("personList", personList.getList().get(0).toString()); return "return"; } }
表单页面如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <base href="<%=basePath%>" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>List</title> <link href="css/bootstrap.css" rel="stylesheet"> <script src="js/jquery-3.2.1.js"></script> <script src="js/bootstrap.js"></script> </head> <body> <form class="form-horizontal" action="<%=request.getContextPath()%>/Action/returnListAction" role="form" method="post"> <div class="form-group"> <label for="firstname" class="col-sm-1 control-label">id</label> <div class="col-sm-3"> <input type="text" class="form-control" name="list[0].id" placeholder="请输入id"> </div> </div> <div class="form-group"> <label for="lastname" class="col-sm-1 control-label">名字</label> <div class="col-sm-3"> <input type="text" class="form-control" name="list[0].name" placeholder="请输名字"> </div> </div> <div class="form-group"> <label for="lastname" class="col-sm-1 control-label">地址</label> <div class="col-sm-3"> <input type="text" class="form-control" name="list[0].addrs" placeholder="请输地址"> </div> </div> <div class="form-group"> <div class="col-sm-offset-1 col-sm-3"> <button type="submit" class="btn btn-default">提交</button> <button type="reset" class="btn btn-default">重置</button> </div> </div> </form> </body> </html>
表单向服务器提交数据,提交后结果如下:
Map集合类型:
Map与List的实现方式基本一样,同样需要包装Map类型,例如:
public class PersonMap { private Map<String,Person> map; public Map<String, Person> getMap() { return map; } public void setMap(Map<String, Person> map) { this.map = map; } }
定义方法(action)代码如下:
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: returnMapAction * @描述: 自动参数映射---Map数据类型 * @param model * @param personMap * @return * @创建人 Zender */ @RequestMapping("/returnMapAction") public String returnMapAction(Model model, PersonMap personMap){ model.addAttribute("personMap", personMap.getMap().get("user1").toString()); return "return"; } }
表单页面如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <base href="<%=basePath%>" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Map</title> <link href="css/bootstrap.css" rel="stylesheet"> <script src="js/jquery-3.2.1.js"></script> <script src="js/bootstrap.js"></script> </head> <body> <form class="form-horizontal" action="<%=request.getContextPath()%>/Action/returnMapAction" role="form" method="post"> <div class="form-group"> <label for="firstname" class="col-sm-1 control-label">id</label> <div class="col-sm-3"> <input type="text" class="form-control" name="map[user1].id" placeholder="请输入id"> </div> </div> <div class="form-group"> <label for="lastname" class="col-sm-1 control-label">名字</label> <div class="col-sm-3"> <input type="text" class="form-control" name="map[user1].name" placeholder="请输名字"> </div> </div> <div class="form-group"> <label for="lastname" class="col-sm-1 control-label">地址</label> <div class="col-sm-3"> <input type="text" class="form-control" name="map[user1].addrs" placeholder="请输地址"> </div> </div> <div class="form-group"> <div class="col-sm-offset-1 col-sm-3"> <button type="submit" class="btn btn-default">提交</button> <button type="reset" class="btn btn-default">重置</button> </div> </div> </form> </body> </html>
表单向服务器提交数据,提交后结果如下:
2,@RequestParam参数绑定
复杂一些的数据需使用@RequestParam完成参数映射,虽然自动参数映射很方便,但有些细节是不能处理的,例如参数是否为必须参数,名称没有办法指定,参数的默认值。如果使用@RequestParam可以实现请求参数绑定,Spring MVC会自动查找请求中的参数转类型并将与参数进行绑定。
2.1,基本数据类型参数绑定
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: requestParamAction * @描述: RequestParam注解参数绑定 * @param model * @param text * @return * @创建人 Zender */ @RequestMapping("/requestParamAction") public String requestParamAction(Model model, @RequestParam(required = false, defaultValue = "默认的文本") String text){ model.addAttribute("text", text); return "return"; } }
@RequestParam共有4个注解属性:
required属性 |
表示是否为必须,默认值为true,如果请求中没有指定的参数会报异常。 |
defaultValue属性 |
用于设置参数的默认值,如果不指定值则使用默认值,只能是String类型的。 |
name与value属性 |
两个互为别名关系用于指定参数名称。 |
运行结果:
2.2,List数据类型参数绑定
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: requestParamListAction * @描述: RequestParam注解List类型参数绑定 * @param model * @param text * @return * @创建人 Zender */ @RequestMapping("/requestParamListAction") public String requestParamListAction(Model model, @RequestParam("text") List<String> text){ model.addAttribute("text", text); return "return"; } }
运行结果:
2.3,自定义数据类型参数绑定与Ajax
如果需要直接绑定更加复杂的数据类型,则需要使用@RequestBody与@ResponseBody注解:
@RequestBody |
将HTTP请求正文转换为适合的HttpMessageConverter对象。 |
@ResponseBody |
将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流。 |
@RequestBody默认接收的Content-Type是application/json,因此发送POST请求时需要设置请求报文头信息,否则Spring MVC在解析集合请求参数时不会自动的转换成JSON数据再解析成相应的集合,Spring默认的json协议解析由Jackson完成。要完成这个功能还需要修改pom.xml,添加jackson依赖,如下:
<!-- jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.2</version> </dependency>
方法(Action)定义如下:
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: requestJSONAction * @描述: 接收JSON格式的数据显示控制台 * @param response * @param person * @throws IOException * @创建人 Zender */ @RequestMapping("/requestJSONAction") //@RequestBody的作用是让Spring MVC在收到客户端请求时将选择合适的转换器将参数转换成相应的对象。 public void requestJSONAction(HttpServletResponse response, @RequestBody List<Person> person) throws IOException{ response.setCharacterEncoding("UTF-8"); System.out.println(Arrays.deepToString(person.toArray())); response.getWriter().write("添加成功"); } /** * * @方法名: requestJSON2Action * @描述: 接收JSON格式的数据返回页面 * @param response * @param person * @return * @throws IOException * @创建人 Zender */ @RequestMapping("/requestJSON2Action") @ResponseBody//该注解会使用jackson将该对象自动序列化成json字符 public List<Person> requestJSON2Action(HttpServletResponse response, @RequestBody List<Person> person) throws IOException{ return person; } }
页面如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <base href="<%=basePath%>" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Map</title> <link href="css/bootstrap.css" rel="stylesheet"> <script src="js/jquery-3.2.1.js"></script> <script src="js/bootstrap.js"></script> </head> <body> <button class="btn btn-default" type="submit" onclick="addPersion();">提交</button> <button class="btn btn-default" type="submit" onclick="getPersion();">获取</button> <p id="msg"></p> <script type="text/javascript"> function addPersion(){ $.ajax({ type : "POST", url : "Action/requestJSONAction", data : '[{"id" : 1, "name" : "Zender", "addrs" : "Shanghai"},' + '{"id" : 2, "name" : "Zender1", "addrs" : "Shanghai1"},' + '{"id" : 3, "name" : "Zender2", "addrs" : "Shanghai2"}]', contentType : "application/json;charset=UTF-8", dataType : "text", success : function(result) { $("#msg").html(result); } }); } function getPersion(){ $.ajax({ type : "POST", url : "Action/requestJSON2Action", data : '[{"id" : 1, "name" : "Zender", "addrs" : "Shanghai"},' + '{"id" : 2, "name" : "Zender1", "addrs" : "Shanghai1"},' + '{"id" : 3, "name" : "Zender2", "addrs" : "Shanghai2"}]', contentType : "application/json;charset=UTF-8", dataType : "json", success : function(result) { var str = ""; $.each(result, function(i, obj) { str += "id:" + obj.id + ",name:" + obj.name + ",addrs:"+ obj.addrs + "<br/>"; }); $("#msg").html(str); } }); } </script> </body> </html>
点击提交按钮运行结果:
控制台:
点击获取按钮运行结果:
3,重定向与RedirectAttributes
在一个请求处理方法Action中如果返回结果为"return"字符则表示转发到视图return,有时候我们需要重定向,则可以在返回的结果前加上一个前缀"redirect:",可以重定向到一个指定的页面也可以是另一个方法(action),代码如下:
@Controller @RequestMapping("/Action") public class ActionController { @RequestMapping("/redirectAction1") public String redirectAction1(Model model, Person person){ model.addAttribute("person", person); System.out.println(person.toString()); return "return"; } @RequestMapping("/redirectAction2") //RedirectAttributes是Spring mvc 3.1版本之后出来的一个功能,专门用于重定向之后还能带参数跳转的. public String redirectAction2(Model model, RedirectAttributes redirectAttributes){ Person person = new Person(1, "Zender", "Shanghai"); redirectAttributes.addFlashAttribute("person", person); return "redirect:redirectAction1"; } }
RedirectAttributes:
RedirectAttributes是Spring mvc 3.1版本之后出来的一个功能,专门用于重定向之后还能带参数跳转的。
他有两种带参的方式:
第一种:
attr.addAttribute("param", value); |
这种方式就相当于重定向之后,在url后面拼接参数,这样在重定向之后的页面或者控制器再去获取url后面的参数就可以了,但这个方式因为是在url后面添加参数的方式,所以暴露了参数,有风险。
第二种:
attr.addFlashAttribute("param", value); |
这种方式也能达到重新向带参,而且能隐藏参数,其原理就是放到session中,session在跳到页面后马上移除对象。所以你刷新一下后这个值就会丢掉参数。
访问redirectAction2,首先创建了一个person对象,将该对象添加到了Flash属性中,在重定向到redirectAction1后取出person对象,显示到页面上。
4,@ModelAttribute注解
@ModelAttribute可以应用在方法参数上或方法上。
注解在参数上 |
会将注解的参数对象添加到Model中。 |
注解在方法上 |
会将该方法(Action)变成一个非请求处理的方法,在其它方法(Action)被调用时会首先调用该方法。 |
4.1,注解在参数上
注解在参数上会将注解的参数对象添加到Model中。
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: modelAttributeAction * @描述: 自动数据绑定 * @param model * @param person * @return 返回视图名称 * @创建人 Zender */ @RequestMapping("/modelAttributeAction") public String modelAttributeAction(Model model, @ModelAttribute(name = "person", binding = true) Person person){ System.out.println("是否在Model里:" + model.containsAttribute("person")); model.addAttribute("person", person); return "return"; } }
运行结果:
4.2,注解在方法上
注解在方法上会将该方法(Action)变成一个非请求处理的方法,在其它方法(Action)被调用时会首先调用该方法。
@Controller @RequestMapping("/Action") public class ActionController { /** * * @方法名: modelAttributeAction * @描述: 自动数据绑定 * @param model * @param person * @return 返回视图名称 * @创建人 Zender */ @RequestMapping("/modelAttributeAction") public String modelAttributeAction(Model model, @ModelAttribute(name = "person", binding = true) Person person){ System.out.println("是否在Model里:" + model.containsAttribute("person")); model.addAttribute("person", person); Map<String, Object> map = model.asMap(); for (String key : map.keySet()) { System.out.println(map.get(key)); } return "return"; } @ModelAttribute public String initAction(){ System.out.println("initAction方法被调用!"); String text = "测试数据"; return text; } @ModelAttribute public void initAction2(){ System.out.println("initAction2方法被调用!"); } }
运行结果:
非请求处理方法可以返回void,也可以返回一个任意对象,该对象会被自动添加到每一个要被访问的Action的Model中。