1. 摘要
本文主要介绍SpringMVC数据绑定,但是数据绑定的前提是接受前台用户的请求,所以本文先介绍SpringMVC如何接受前台请求,再来介绍SpringMVC接受前台数据的7种方式。
2. Spring接受请求
2.1. @RequestMapping
@RequestMapping注解主要是设置SpringMVC请求的映射路径。所谓的映射路径,就是匹配请求路径和执行方法关系的路径。
请求路径:http://localhost:8080/springmvc/method1.do
映射路径:@RequestMapping(value="/method1")
@RequestMapping 用于贴在控制器的类上或者方法上面。如果是贴在控制器的类上面,那么在访问这个类的方法之前必须先加上类上的对应的名称,类似于项目下面的模块名称。如果贴在方法上面,就是访问此方法的资源名称。
@Controller
@RequestMapping("/request") //访问时候必须加上,类似模块名称
public class RequestController {
@RequestMapping(value="/method1") //资源名称
public void method1() {
}
}
访问地址:http://localhost:8080/springmvc/request/method1.do
2.2. 两种限制
SpringMVC支持对请求的限制。如果不满足限制的条件,就不让访问执行方法。这样做,大大提高了执行方法的安全性。
主要的限制有两种:方法限制,参数限制。
2.2.1. 方法限制
就是设置请求的method类型。如果发送过来的请求与方法设置的method不一样,就不能访问执行方法。请求method:GET、POST
--前台页面
<form action="${pageContext.request.contextPath }/login.do" method="get">
<input type="submit" value="登录">
</form>
/**
* 接收的请求,必须是POST
* @return
*/
--后台代码
@RequestMapping(value="login",method=RequestMethod.POST)
public String login(){
System.out.println("-登录-");
return "/login.jsp";
}
--前台发送的是GET请求,而方法限制是POST请求,所以请求无法执行方法。
--方法限制可以配置多个参数
@RequestMapping(value="login",method={RequestMethod.GET,RequestMethod.POST})
public String login(){
System.out.println("-登录-");
return "/login.jsp";
}
2.2.2. 参数限制
1、就是请求里面必须包括哪些参数,或不包括哪些参数。
2、参数包括哪些值,不包括哪些值。
--限制参数格式:
【1】参数必须包括:params={"username","password"}
【2】参数不能包括:params={"!userid"}
【3】参数值必须是指定的值:params={"username=zhangsan"})
【4】参数值必须不是指定的值:params={"userid!=123"})
--请求:没有后台方法指定的参数
<h4>登录页面</h4>
<form action="${pageContext.request.contextPath}/request/method1.do" method="post">
账号:<input name="username"><br>
密码:<input type="password" name="pwd"><br>
<button type="submit">登录</button>
</form>
--后台代码
/**
* 需求:登录时必须包括用户名,密码
* @return
*/
@RequestMapping(value="login2",params={"username","password"})
public String login2(){
System.out.println("-登录-");
return "/login.jsp";
}
如果前台请求没有指定后台要求的参数,会报错.
2.3. Spring方法参数可以注入的类型
SpringMVC的方法默认可以注入 JavaWeb开发常用的数据共享对象。
--HttpServletRequest
--HttpServletResponse
--HttpSession
获取这些共享对象以后,就可以像之前的Servlet一样,做任何数据共享以及页面跳转操作。
/*
* Spring的方法默认可以注入 JavaWeb开发常用的数据共享对象
* HttpServletRequest
* HttpServletResponse
* HttpSession 以后开发 按需注入
*/
@RequestMapping(value = "/method0")
public void method0(HttpServletRequest req,
HttpServletResponse resp,
HttpSession session) {
//TODO
}
3. 数据绑定
3.1. 数据绑定是什么
SpringMVC里面,所谓的数据绑定就是将请求带过来的表单数据绑定到执行方法的参数变量。
实际开发中,SpringMVC作为表现层框架,肯定会接受前台页面传递过来的参数,SpringMVC提供了丰富的接受参数的方法。
3.2. 原始方式request.getParameter()
SpringMVC可以注入HttpServletRequest对象,直接使用getParameter参数接受
--前台页面
<!-- 原始方式request.getParameter() -->
<fieldset>
<legend>原始方式request.getParameter()</legend>
<form action="${pageContext.request.contextPath}/request/method1.do" method="post">
账号: <input name="username"><br>
年龄: <input name="age"><br>
<button type="submit">提交</button>
</form>
</fieldset>
--后台代码
@RequestMapping(value="/method1",method=RequestMethod.POST) //资源名称
public void method1(HttpServletRequest req,HttpServletResponse resp,HttpSession session) {
//原始方式request.getParameter()
String username = req.getParameter("username");
String age = req.getParameter("age");
System.out.println(username);
System.out.println(age);
}
3.3. 方法形参与前台参数同名
在请求方法形参上,声明和表单字段名相同的参数名(可以自动同名匹配,然后进行封装)。
--前台页面
<fieldset>
<legend>方法形参与前台参数同名</legend>
<form action="${pageContext.request.contextPath}/request/method2.do" method="post">
账号: <input name="username"><br>
年龄: <input name="age"><br>
<button type="submit">提交</button>
</form>
</fieldset>
--后台代码
//方法形参与前台参数同名
@RequestMapping(value="/method2",method=RequestMethod.POST)
public ModelAndView method2(String username,String age) {
System.out.println(username);
System.out.println(age);
return null;
}
3.4. 方法形参与前台参数不同名
--前台页面
<fieldset>
<legend>方法形参与前台参数不同名</legend>
<form action="${pageContext.request.contextPath}/request/method3.do" method="post">
账号: <input name="name"><br>
年龄: <input name="age"><br>
<button type="submit">提交</button>
</form>
</fieldset>
--后台代码
// 方法形参与前台参数不同同名
// 解决方案使用 : @RequestParam("前台表单对应的名")
@RequestMapping(value = "/method3", method = RequestMethod.POST)
public ModelAndView method3(@RequestParam("name") String username, String age) {
System.out.println(username);
System.out.println(age);
return null;
}
3.5. 接受数组
--前台页面
<fieldset>
<legend>接收数组或集合</legend>
<form action="${pageContext.request.contextPath}/request/method4.do" method="post">
账号: <input name="name"><br>
年龄: <input name="age"><br>
爱好: <input type="checkbox" name="hobbys" value="java">java
<input type="checkbox" name="hobbys" value="html">html<br>
<button type="submit">提交</button>
</form>
</fieldset>
--后台代码
// 接受数组
@RequestMapping(value = "/method4", method = RequestMethod.POST)
public ModelAndView method4(String[] hobbys) {
System.out.println(Arrays.toString(hobbys));
return null;
}
3.6. 对象传参
后台并不能直接接受集合参数,需要将集合设置到对应的JavaBean中,通过JavaBean接受集合参数。
--Pojo对象
public class User {
private String username;
private String password;
private String email;
private String phone;
private String[] hobbys;
}
--前台页面
<fieldset>
<legend>接受对象,表单参数名必须和后台pojo对象对应的属性名相同</legend>
<form action="${pageContext.request.contextPath}/request/method5.do" method="post">
账号: <input name="username"><br>
密码: <input type="password" name="password"><br>
邮箱: <input name="email"><br>
电话: <input name="phone"><br>
爱好:<input type="checkbox" name="hobbys" value="java">java
<input type="checkbox" name="hobbys" value="C">C
<input type="checkbox" name="hobbys" value="C++">C++<br/>
<button type="submit">提交</button>
</form>
</fieldset>
--后台代码
// 对象传参->对象中有集合
@RequestMapping(value = "/method5", method = RequestMethod.POST)
public ModelAndView method4(User user) {
System.out.println(user);
return null;
}
3.7. 接受参数封装成Map集合
Map集合接受参数,自动把表单的参数名称作为key,把表单的值作为value封装到map集合中。
缺点:map集合只能接受单值的数据,因为map的key是唯一的,无法存储key相同,有多个值的数据。
--前台页面
<fieldset>
<legend>接受参数封装成Map集合</legend>
<form action="${pageContext.request.contextPath}/request/method6.do" method="post">
账号: <input name="username"><br>
密码: <input name="password"><br>
邮箱: <input name="email"><br>
电话: <input name="phone"><br>
<button type="submit">提交</button>
</form>
</fieldset>
--后台代码
// 接受参数封装成Map集合
@RequestMapping(value = "/method6", method = RequestMethod.POST)
public ModelAndView method6(@RequestParam Map<String, Object> map) {
System.out.println("map:" + map);
return null;
}
3.8. RESTful风格支持
3.8.1. RESTFUL 风格介绍
REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在2000年Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,REST倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。
RESTful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
3.8.2. 参数传递方法 GET
例如:根据商品id查询对应的商品信息(如京东网站)。
如果按照我们web开发应该是将商品id跟在url的“?”的后面。
普通方式:https://item.jd.com?product_id=100000287117
但是京东不是使用此种方式,而是使用RESTful风格。
RESTful风格:https://item.jd.com/100000287117.html
3.8.3. 案例代码
// RESTful风格
@RequestMapping(value = "/method7/{product_id}")
public ModelAndView method7(@PathVariable("product_id") Integer product_id) {
System.out.println(product_id); //1231323123
return null;
}
3.8.4. 浏览器访问地址
localhost:8080/springmvc/request/method7/1231323123.html
3.8.5. 使用RESTful优势
1、可以让页面伪静态。
访问页面时感觉像在访问静态html页面,实际上访问的是动态页面(伪静态)。
2、方便搜索引擎的SEO优化。
RESTful的使用条件:必须拦截所有的请求,即DispatcherServlet的拦截路径为“/”,此时如果还想正常访问静态资源,可以搭配<mvc:default-servlet-handler>来处理静态资源。
4. 对静态资源访问
--问题:配置前端控制器的URL模式(<url-pattern>)写成“/”,然后在Web根路径添加index.html,然后不能访问,原因是什么呢?
--原因:Tomcat中处理静态资源访问的servlet(default)的映射路径也为“/”,在启动项目的时候,在Tomcat中的web.xml是先加载的,项目的web.xml是后加载的,如果配置了相同的映射路径,后面的会覆盖前者。也就是说,SpringMVC中的DispatcherServlet的映射路径覆盖了Tomcat默认对静态资源的处理的路径。如果SpringMVC要配置为‘/’,那么就得设置Dispatcherservlet对静态资源进行放行,交由Tomcat来处理。
--Tomcat的DefaultServlet配置信息:
Tomcat 根/confg/web.xml 103行
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
--解决方案:需要在SpringMVC的配置文件中添加对静态资源的访问
<mvc:default-servlet-handler/>
-----------------------------------------------------------------------------------------
<mvc:default-servlet-handler/> 将在 SpringMVC 上下文中定义一个
DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由 Tomcat默认的 Servlet 处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
-----------------------------------------------------------------------------------------
--/和/*的区别:
/ 会匹配url请求/index等 ,也会匹配静态资源*.js,*.html等, 不会匹配*.jsp文件。
/* 会匹配url请求/index等 ,也会匹配静态资源*.js,*.html等, 会匹配*.jsp文件。
实际开发中一般推荐使用“*.后缀”,如*.do、*.action。
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
5. 请求中文乱码问题
SpringMVC默认接受的参数是ISO-8859-1编码参数,单字节,不支持中文,Spring提供了一个过滤器可以让开发者自定义请求参数的字符编码。
--注意:此种方式只对post提交方式有效。
<!-- 统一配置SpringMVC接受请求参数的编码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
--如果提交中文参数是get方式,-tomcat7以及以前需要设置
配置 tomcat/conf/server.xml 添加 URIEncoding="UTF-8"
<Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
建议:以后表单一般使用post,get方式请求尽量不要使用中文作为参数。