参数绑定
作用:接受client提交的数据
支持的数据类型
基本类型参数:包括基本类型和 String 类型
POJO 类型参数:包括实体类,以及关联的实体类
数组和集合类型参数:包括 List 结构和 Map 结构的集合(包括数组)
示例
使用原生的ServletAPI对象
只需要在控制器的方法中将servletApi对象当作参数传入即可
@RequestMapping(value = "/converter1",method = RequestMethod.POST)
public void converter1(HttpServletRequest request) {
String username = request.getParameter("username");
String age = request.getParameter("age");
String birthDay = request.getParameter("birthDay");
System.out.println(username + "----" + age + "----" + birthDay);
}
springmvc支持传入的Sevlet原生api一共有以下这些:
1. HttpServletRequest
2. HttpServletResponse
3. HttpSession
4. java.security.Principal
5. Locale
6. InputStream
7. OutputStream
8. Reader
9. Writer
基本数据类型+String
要求参数名称必须和控制器中方法的形参名称保持一致。 (严格区分大小写)
//jsp 代码:
<a href="account/findAccount?accountId=10&accountName=zhangsan">查询账户</a>
控制器代码:
@RequestMapping("/findAccount")
public String findAccount(Integer accountId,String accountName) {
System.out.println("查询了账户。。。。 "+accountId+","+accountName);
return "success";
}
POJO 类型作为参数
要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
jsp 代码:
<form action="account/saveAccount" method="post">
账户名称: <input type="text" name="name" ><br/>
账户金额: <input type="text" name="money" ><br/>
账户省份: <input type="text" name="address.provinceName" ><br/>
账户城市: <input type="text" name="address.cityName" ><br/>
<input type="submit" value="保存">
</form>
实体类代码:
//账户信息
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
private Address address;
//getters and setters
}
//地址的实体类
public class Address implements Serializable {
private String provinceName;
private String cityName;
//getters and setters
}
控制器代码:
@RequestMapping("/saveAccount")
public String saveAccount(Account account) {
System.out.println("保存了账户。。。。 "+account);
return "success";
}
POJO 类中包含集合类型参数
第一种:要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。给List 集合中的元素赋值, 使用下标。给 Map 集合中的元素赋值, 使用键值对。
第二种:接收的请求参数是 json 格式数据。需要借助一个注解实现
实体类代码:
// 用户实体类
public class User implements Serializable {
private String username;
private String password;
private Integer age;
private List<Account> accounts;
private Map<String,Account> accountMap;
//getters and setters
}
控制器代码:
@RequestMapping("/updateAccount")
public String updateAccount(User user) {
System.out.println("更新了账户。。。。 "+user);
return "success";
}
jsp 代码:
<form action="account/updateAccount" method="post">
用户名称: <input type="text" name="username" ><br/>
用户密码: <input type="password" name="password" ><br/>
用户年龄: <input type="text" name="age" ><br/>
账户 1 名称: <input type="text" name="accounts[0].name" ><br/>
账户 1 金额: <input type="text" name="accounts[0].money" ><br/>
账户 2 名称: <input type="text" name="accounts[1].name" ><br/>
账户 2 金额: <input type="text" name="accounts[1].money" ><br/>
账户 3 名称: <input type="text" name="accountMap['one'].name" ><br/>
账户 3 金额: <input type="text" name="accountMap['one'].money" ><br/>
账户 4 名称: <input type="text" name="accountMap['two'].name" ><br/>
账户 4 金额: <input type="text" name="accountMap['two'].money" ><br/>
<input type="submit" value="保存">
</form>
自定义类型转换器
当参数通过URL或者表单传递时都会转换为字符串,前面形参为Integer时也不会报错是因为SpringMVC可以实现一些数据类型的自动转换。内置转换器全都在:org.springframework.core.convert.support 包下 ,有java.lang.Boolean -> java.lang.String : ObjectToStringConverter java.lang.Character -> java.lang.Number : CharacterToNumberFactory java.lang.Character -> java.lang.String : ObjectToStringConverter java.lang.Enum -> java.lang.String : EnumToStringConverter
……………………………………等很多。
如遇特殊类型转换要求,需要我们自己编写自定义类型转换器
第一步:定义一个类,实现 Converter 接口,该接口有两个泛型。
public interface Converter<S, T> {//S:表示接受的类型, T:表示目标类型
/**
* 实现类型转换的方法
*/
@Nullable
T convert(S source);
}
//自定义类型转换器
public class StringToDateConverter implements Converter<String, Date> {
//用于把 String 类型转成日期类型
@Override
public Date convert(String source) {
DateFormat format = null;
try {
if(StringUtils.isEmpty(source)) {
throw new NullPointerException("请输入要转换的日期");
}
format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse(source);
return date;
} catch (Exception e) {
throw new RuntimeException("输入日期有误");
}
}
}
第二步:在 springMVC 配置文件中配置类型转换器。
spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。
<!-- 配置类型转换器工厂 -->
<bean id="converterService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 要给 converters属性注入值,是个set集合-->
<property name="converters">
<set>
<!-- 配置自定义类型转换器 -->
<bean class="com.mg.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
第三步:在 annotation-driven 标签中引用配置的类型转换服务
<!-- 引用自定义类型转换器 -->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
响应数据和结果视图
返回值分类
字符串
controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。controller 方法在提供了 String 类型的返回值之后,默认就是请求转发。
@RequestMapping("/testReturnString")
public String testReturnString() {
System.out.println("AccountController 的 testReturnString 方法执行了。。。。 ");
//此字符串会通过配置文件中配置的视图解析器解析为物理路径:如 /WEB-INF/pages/success.jsp
return "success";
}
void
如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。默认会跳转到@RequestMapping(value=”/hello”) hello的页面
也可以使用servlet原生API操作请求转发或者重定向跳转到指定的页面
@RequestMapping(value = "/converter1",method = RequestMethod.POST)
public void converter1(HttpServletRequest request, HttpServletResponse response) {
//使用 request 转向页面:请求转发
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
//也可以通过 response 页面重定向:
response.sendRedirect("testRetrunString");
//也可以通过 response 指定响应结果, 例如响应 json 数据:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json 串");
}
ModelAndView
ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值 。
返回 ModelAndView 类型时,浏览器跳转是请求转发
@RequestMapping("/testReturnModelAndView")
public ModelAndView testReturnModelAndView() {
ModelAndView mv = new ModelAndView();
//存值
mv.addObject("username", "张三");
//跳转的页面,会通过视图解析器解析为物理视图地址 如:/WEB-INF/pages/success.jsp
mv.setViewName("success");
return mv;
}
响应的 jsp 代码:success.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>执行成功</title>
</head>
<body>
执行成功!
${requestScope.username}
</body>
</html>
转发和重定向
forward请求转发
controller 方法在提供了 String 类型的返回值之后,默认就是请求转发。 我们也可以写成:
@RequestMapping("/testForward")
public String testForward() {
System.out.println("AccountController 的 testForward 方法执行了。。。。 ");
return "forward:/WEB-INF/pages/success.jsp";
}
需要注意的是,如果用了 formward: 则路径必须写成实际视图 url,不能写逻辑视图。转发的JSP路径,不走视图解析器了,所以需要编写完整的路径
它相当于“ request.getRequestDispatcher("url").forward(request,response)” 。使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法。
Redirect 重定向
contrller 方法提供了一个 String 类型返回值之后, 它需要在返回值里使用:redirect:
@RequestMapping("/testRedirect")
public String testRedirect() {
System.out.println("AccountController 的 testRedirect 方法执行了。。。。 ");
return "redirect:testReturnModelAndView";
//return "redirect:/add.jsp";重定向到jsp页面
}
它相当于“response.sendRedirect(url)” 。需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不能写在 WEB-INF 目录中,否则无法找到
ResponseBody响应json数据
该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据如: json,xml 等,通过 Response 响应给客户端
Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入jackson 的包
jsp 中的代码:
<script type="text/javascript"
src="${pageContext.request.contextPath}/js/jquery.min.js">
</script>
<script type="text/javascript">
$(function(){
$("#testJson").click(function(){
$.ajax({
type:"post",
url:"${pageContext.request.contextPath}/testResponseJson",
contentType:"application/json;charset=utf-8",
data:'{"id":1,"name":"test","money":999.0}',
dataType:"json",
success:function(data){
alert(data);
}
});
});
})
</script>
<input type="button" value="测试 ajax 请求 json 和响应 json" id="testJson"/>
控制器中的代码:
@Controller("jsonController")
public class JsonController {
@RequestMapping("/testResponseJson")
@ResponseBody
public Account testResponseJson(@RequestBody Account account) {
System.out.println("异步请求: "+account);
return account;
}
}
请求参数乱码问题
post 请求方式:在 web.xml 中配置一个过滤器
<!-- 配置 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 请求方式:tomacat 对 GET 和 POST 请求处理方式是不同的, GET 请求的编码问题, 要改 tomcat 的server.xml
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"
useBodyEncodingForURI="true"/>
如果遇到 ajax 请求仍然乱码,请把:
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"
即可
静态资源访问
- 在web.xml中 配置url-pattern标签时,在没有特殊要求的情况下, SpringMVC 的中央调度器 DispatcherServlet 的url-pattern使用后辍匹配方式,如写为*.do 或者 *.action, *.mvc 等。
- 可以写为/,因为 DispatcherServlet 会将向静态资源的获取请求,例如.css、 .js、 .jpg、 .png等资源的获取请求,当作是一个普通的 Controller 请求。 中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误。
url-pattern的值并不是说写为/后,静态资源就无法访问了。经过一些配置后,该问题也是可以解决的。
使用mvc:default-servlet-handler标签
只需要在 springmvc.xml 中添加mvc:default-servlet-handler标签即可
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:default-servlet-handler></mvc:default-servlet-handler>
</beans>
声明了<mvc:default-servlet-handler/>后,springmvc框架会在容器中创建DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入 DispatcherServlet的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet 处理。一般的服务器都有默认的Servlet。
在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。其<servlet-name/>为 default。可以处理各种静态资源访问请求。该 Servlet 注册在 Tomcat 服务器的 web.xml 中。在 Tomcat 安装目录/conf/web.xml。
使用mvc:resources
在 Spring3.0 版本后, Spring 定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler。并且添加了mvc:resources标签,专门用于解决静态资源无 法访问问题。 需要在 springmvc 配置文件中添加如下形式的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
</beans>
location 表示静态资源所在目录。 当然, 目录不要使用/WEB-INF/及其子目录。
mapping表示对该资源的请求(以/images/开始的请求,如/image/beauty.jpg,/images/car.png等)。注意,后面是两个星号**代表该目录下的文件及子目录下的文件