一、请求数据传入(从页面获取数据)
1、JavaWeb 获取请求数据
请求数据:请求参数、cookie 信息、请求头信息......
JavaWEB:
- HttpRequest;
- Request.getParameter(参数名);
- Request.getParameterMap();
- Request.getCookie();
- Request.getHeader();
2、请求处理方法签名
(1)Spring MVC 通过分析处理方法的签名(方法名+参数列表),将 HTTP 请求信息绑定到处理方法的相应入参中;
(2)Spring MVC 对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方式对方法进行签名;
(3)必要时可以对方法及方法形参标注相应的注解(@PathVariable、@RequestParam、@RequestHeader 等);
(4)Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理;
二、@RequestParam 注解
1、用法
使用 SpringMVC 时,可以自动把根据请求中的参数映射到入参上面,即在处理请求的方法中,加入相对应的形参,保证入参参数名和传递的数据的参数名保持一致,就可以自动赋值。
当请求中的参数名与入参参数名不一致时,就可以在处理方法形参处使用 @RequestParam
可以把请求参数传递给请求方法;
2、属性
value 参数名
当不满足赋值条件时,可以使用 value 属性,指定映射关系;
required 是否必须。
默认为 true,必须赋值,表示请求参数中必须包含对应的参数,若不存在,将抛出异常。
若设置为 false,则不必须赋值,因此形参的值可能为 null。
defaultValue 默认值,当没有传递参数时使用该值;
若形参所获得的值为 null,则设置一个默认值,(用在分页和模糊查询中)
3、示例
/**
* @RequestMapping 注解用于映射请求参数
* value 用于映射请求参数名称
* required 用于设置请求参数是否必须赋值
* defaultValue 设置默认值,当没有传递参数时使用该值
*
*/
@RequestMapping(value = "/handle01")
public String handle01(@RequestParam(value = "user", required = false, defaultValue = "Tom")String userName, String age) {
System.out.println("handle01...");
System.out.println("userName = " + userName);
System.out.println("age = " + age);
return "success";
}
请求链接:
<a href="/handle01?user=abc&age=10">testRequestParam</a>
4、细节
(1)默认方式获取请求参数
直接给方法入参上写一个和请求参数名相同的变量,这个变量就用来接收请求参数的值;
如果请求中带值:就是获取的参数值;
如果请求中没带值:获取为 null
对于上面案例中的 age 就是这样获取方式;
(2)@RequestParam 注解
使用 @RequestParam 注解获取请求参数,参数默认是必须带的,如果没有会报错,可以使用 required 指定该参数是否为必须;还可以使用 defaultValue 指定参数的默认值。
@RequestParam("user")String userName
相当于
userName = request.getParameter("user");
(3)@RequestParam 与 @PathVariable 区别?
@RequestParam 是获取请求参数?后面的值
@PathVariable 是获取路径中的参数值
/book/[{user}pathVariable]?[user=admin(requestParam)]
三、@RequestHeader 注解
1、用法
(1)使用 @RequestHeader 绑定请求报头的属性值;
(2)请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中。
2、属性
value 获取的请求头,指定映射关系;
required 是否必须。
默认为 true,必须赋值,表示请求头中必须包含对应的参数,若不存在,将抛出异常。
若设置为 false,则不必须赋值,因此值为 null。
defaultValue 设置请求头默认值,当没有传递请求头时使用该值;
3、示例
@RequestMapping(value = "/handle02")
public String handle02(@RequestHeader(value = "User-Agent", required = false, defaultValue = "Chrome")String userAgent) {
System.out.println("handle02...");
System.out.println("userAgent = " + userAgent);
return "success";
}
注意:如果请求头中没有对应的值就会报错,可以使用 required 和 defaultValue 属性;
四、@CookieValue 注解
1、用法
(1)使用 @CookieValue
绑定请求中的 cookie 值;
(2)@CookieValue
可让处理方法形参绑定某个 cookie 值
2、属性
value 绑定请求中的 cookie 值,指定映射关系;
required 是否必须。
默认为 true,必须赋值,表示 cookie 中必须包含对应的参数,若不存在,将抛出异常。
若设置为 false,则不必须赋值,因此值为 null。
defaultValue 设置 cookie 默认值,当没有传递指定 cookie 时就使用该值;
3、示例
@RequestMapping(value = "/handle03")
public String handle03(@CookieValue(value = "JSESSIONID", required = false, defaultValue = "sessionID")String jid) {
System.out.println("handle03...");
System.out.println("cookie = " + jid);
return "success";
}
五、使用 POJO 作为参数
1、用法
(1)使用 POJO 对象绑定请求参数值;
(2)Spring MVC 会按请求参数名和 POJO 属性名自动匹配,自动为该对象填充属性值,支持级联属性。如 dept.deptId、dept.deptaddress.tel 等
2、示例
① 增加实体类
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private Address address;
}
public class Address {
private String province;
private String city;
private String country;
}
② 控制器方法
@RequestMapping(value = "/handle04")
public String handle04(User user) {
System.out.println("handle04...");
System.out.println("user = " + user);
return "success";
}
③ 表单页面
<!-- 测试 POJO 对象传参,支持级联属性-->
<form action="/handle04" method="post">
username:<input type="text" name="username" /><br />
password:<input type="text" name="password" /><br />
age:<input type="text" name="age" /><br />
province:<input type="text" name="address.province" /><br />
city:<input type="text" name="address.city" /><br />
country:<input type="text" name="address.country" /><br />
<input type="submit" value="添加" />
</form>
④ 测试
可以看到数据可以封装进来,但是存在请求的乱码问题。
3、提交的中文乱码
对于提交的数据出现了乱码情况:
请求乱码:
方式一:修改 Tomcat 的 server.xml,在 8080 端口处添加 URIEncoding="UTF-8";
方式二:将请求参数转码(SpringMVC 中不可用)
String user = new String(request.getParameter("user").getBytes("ISO-8859-1"), "UTF-8");
响应乱码:
response.setContentType("text/html;charset=utf-8"); //解决响应乱码
六、使用 Servlet 原生 API 作为参数
1、SpringMVC 的 Handler 方法可以接受 Servlet 原生 Servlet API 类型的参数:
(1)HttpServletRequest 请求对象
(2)HttpServletResponse 响应对象
(3)HttpSession 会话对象
(4)java.security.Pincipal HTTPS 安全相关
(5)Locale 国际化有关的区域信息对象
(6)InputStream 获取字节输入流 request.getInputStream()
(8)OutputStream 获取字节输出流 request.getOutputStream()
(9)Reader 获取字符输入流 request.getReader()
(10)Writer 获取字符输出流 request.getWriter()
2、示例
控制器:
/*
SpringMVC 可以直接在参数上写原生API
*/
@RequestMapping(value = "/handle05")
public String handle05(HttpServletRequest request, HttpSession session) {
System.out.println("handle05...");
request.setAttribute("request", "这个是 request 域");
session.setAttribute("session", "这个是 session 域");
return "success";
}
请求链接:
<!-- 测试 Servlet API 作为处理请求参数 -->
<a href="handle05">testServletAPI</a>
3、源码参考:
源码:AnnotationMethodHandlerAdapter
(L866)
@Override
protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
if (ServletRequest.class.isAssignableFrom(parameterType) ||
MultipartRequest.class.isAssignableFrom(parameterType)) {
Object nativeRequest = webRequest.getNativeRequest(parameterType);
if (nativeRequest == null) {
throw new IllegalStateException(
"Current request is not of type [" + parameterType.getName() + "]: " + request);
}
return nativeRequest;
}
else if (ServletResponse.class.isAssignableFrom(parameterType)) {
this.responseArgumentUsed = true;
Object nativeResponse = webRequest.getNativeResponse(parameterType);
if (nativeResponse == null) {
throw new IllegalStateException(
"Current response is not of type [" + parameterType.getName() + "]: " + response);
}
return nativeResponse;
}
else if (HttpSession.class.isAssignableFrom(parameterType)) {
return request.getSession();
}
else if (Principal.class.isAssignableFrom(parameterType)) {
return request.getUserPrincipal();
}
else if (Locale.class.equals(parameterType)) {
return RequestContextUtils.getLocale(request);
}
else if (InputStream.class.isAssignableFrom(parameterType)) {
return request.getInputStream();
}
else if (Reader.class.isAssignableFrom(parameterType)) {
return request.getReader();
}
else if (OutputStream.class.isAssignableFrom(parameterType)) {
this.responseArgumentUsed = true;
return response.getOutputStream();
}
else if (Writer.class.isAssignableFrom(parameterType)) {
this.responseArgumentUsed = true;
return response.getWriter();
}
return super.resolveStandardArgument(parameterType, webRequest);
}
八、字符编码过滤器(解决请求中文乱码)
1、字符编码过滤器
SpringMVC 给我们提供了一个字符编码过滤器 CharacterEncodingFilter
。
如果有中文乱码问题,需要配置字符编码过滤器,而且一定要配置其他过滤器之前,如(HiddenHttpMethodFilter),否则不起作用。
2、在 web.xml 中配置字符编码过滤器:
<!-- 字符编码过滤器 -->
<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>
<!-- 强制设置响应进行编码 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 对所有的请求都拦截,处理所有响应-->
</filter-mapping>
注意:字符编码过滤器一定要在配置文件其他过滤器之前,否则不起作用。
获取在获取流或者其他处理的时候就不起作用。
3、字符编码过滤器 CharacterEncodingFilter 源码
public class CharacterEncodingFilter extends OncePerRequestFilter {
private String encoding;
private boolean forceEncoding = false;
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public void setForceEncoding(boolean forceEncoding) {
this.forceEncoding = forceEncoding;
}
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
request.setCharacterEncoding(this.encoding);
if (this.forceEncoding) {
response.setCharacterEncoding(this.encoding);
}
}
filterChain.doFilter(request, response);
}
}