本篇文章我们来学习一下SpringMVC中是如何处理请求中的参数的。
回想一下原生Servlet是如何处理请求参数的?我们需要使用HttpServletRequest调用getParameter方法进行获取,就像这样:
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取参数值
String username = req.getParameter("username");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
下面来看看SpringMVC是如何处理这一需求的。
在SpringMVC中,我们可以直接在方法上声明入参获取请求参数,比如:
@Controller
public class HelloController {
@RequestMApping("/hello")
public String hello(String username) {
System.out.println(username);
return "success";
}
}
那在传递参数的时候参数名就必须指定为username,这样处理方法就能够直接获取到请求参数,当然了,这样获取有一个弊端,就是参数名被固定了,只能是username,我们可以在参数前添加@RequestParam注解来解决:
@RequestMapping("/hello")
public String hello(@RequestParam("user") String username) {
System.out.println(username);
return "success";
}
此时参数名就可以随意定义,转而由@RequestParam注解来指定需要接收的参数名。
当请求中未携带user参数时,程序就会出错:
Resolved exception caused by handler execution: org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'user' is not present
这是因为@RequestParam默认要求参数必须携带,否则就会报错,可以通过修改注解中的required属性值来解决这一个问题:
@RequestMapping("/hello")
public String hello(@RequestParam(value = "user",required = false) String username) {
System.out.println(username);
return "success";
}
此时无论是否携带user参数,程序都不会出错,当未携带user参数时,username值为null。
还可以通过配置defaultValue属性值来指定当参数未携带时的默认值:
@RequestMapping("/hello")
public String hello(@RequestParam(value = "user",required = false,defaultValue = "zhang") String username) {
System.out.println(username);
return "success";
}
此时当请求未携带user参数时,username值为 zhang 。
SpringMVC中也能非常方便地获取请求头中的信息,如:
@RequestMapping("/hello")
public String hello(@RequestHeader("User-Agent") String userAgent) {
System.out.println(userAgent);
return "success";
}
通过@RequestHeader注解即可轻松获取请求头信息,其value值为请求头的key,和@RequestParam注解类似,当试图去获取一个不存在的请求头时,程序便会报错:
@RequestMapping("/hello")
public String hello(@RequestHeader("test") String userAgent) {
System.out.println(userAgent);
return "success";
}
报错信息为:
Missing request header 'test' for method parameter of type String
所以也可以在注解中添加required属性来解决:
@RequestMapping("/hello")
public String hello(@RequestHeader(value = "test",required = false) String userAgent) {
System.out.println(userAgent);
return "success";
}
defaultValue属性也是一样的用法。
在前后端分离的项目开发中,后端接收到的往往并不是一个直接的字符参数,而是一串JSON数据,那么该如何处理JSON类型的请求参数呢?
其实很简单,先接收到JSON参数,再通过一些第三方库将JSON解析成正常的属性值即可,而在SpringMVC中,可以直接使用@RequestBody注解来解决:
@RequestMapping("/hello")
public String hello(@RequestBody String json) {
System.out.println(json);
return "success";
}
通过这种方式能够获取到前端提交的JSON参数:
{"name:"张三","age":"20"}
你还可以直接将请求参数中的JSON串转换为Bean对象:
@RequestMapping("/hello")
public String hello(@RequestBody Person person) {
System.out.println(person);
return "success";
}
此时SpringMVC将按照参数名和Person对象中的属性名进行一一对应,并将参数值封装到Person中生成一个对象,这样便极大地方便了开发流程。
通过@CookieValue注解可以很方便地获取到请求中的cookie信息:
@RequestMapping("/hello")
public String hello(@CookieValue("_ga") String ga) {
System.out.println(ga);
return "success";
}
同理,若是获取不存在的cookie,也会出现错误,解决方案和前面是一样的,就不再赘述了。
当请求参数较为复杂时,比如一个对象,如果借助@RequestParam注解,就必须这样:
@RequestMapping("/hello")
public String hello(
@RequestParam("name") String name,
@RequestParam("age") Integer age,
@RequestParam("sex") Character sex,
@RequestParam("address") String address
) {
System.out.println(name);
System.out.println(age);
System.out.println(sex);
System.out.println(address);
return "success";
}
并且随着参数的增多,这种冗余的代码还要继续编写,为此,SpringMVC有一个更加优雅的解决方案,就是直接接收一个对象类型的参数,所以,要先将这些参数封装成一个对象:
@Data
@ToString
public class Person {
private String name;
private Integer age;
private Character sex;
private String address;
}
此时方法中只需接收一个Person类型的参数即可:
@RequestMapping("/hello")
public String hello(Person person) {
System.out.println(person);
return "success";
}
它同时还支持级联封装,如:
@Data
@ToString
public class Person {
private String name;
private Integer age;
private Character sex;
private Address address;
}
@Data
@ToString
public class Address {
private String province;
private String city;
}
现在Person对象中的地址属性仍然是一个对象,SpringMVC仍然能够将数据准确无误地封装到Person参数中,但请求参数在传递时就需要通过 . 来进行传送,比如:
http://localhost:8080/hello?name=zhangsan&sex=f&age=20&address.province=jiangxi&address.city=nanchang
需要注意的是请求参数中的参数名必须和对象中定义的属性名一致。
有时候一些需求也不得不使用到原生的API,比如设置cookie、session等,SpringMVC当然也考虑到了这一点,所以若是想使用原生的API,则直接写到方法的入参中即可,如:
@RequestMapping("/hello")
public String hello(HttpServletResponse response) {
Cookie cookie = new Cookie("test", "test");
response.addCookie(cookie);
return "success";
}
想操作Session,就将HttpSession作为参数传入:
@RequestMapping("/hello")
public String hello(HttpSession session) {
session.setAttribute("test","test");
return "success";
}
SpringMVC支持以下九个ServletAPI的对象:
1.HttpServletRequest2.HttpServletResponse3.HttpSession4.JAVA.security.Principal5.Locale6.InputStream7.OutputStream8.Reader9.Writer
这九个对象都能够直接以参数的形式传入方法中。
如果在发送请求时携带的参数是中文的,就会产生乱码,在原生的Servlet开发中,我们通常使用:
request.setCharacterEncoding("UTF-8");
但这是用来解决POST请求乱码的,对于响应的乱码,应使用:
response.setContentType("text/html;charset=utf-8");
然而在SpringMVC中,我们通常不会使用到HttpServletRequest和HttpServletResponse对象,那么乱码问题该如何解决呢?
可以定义一个Filter过滤器,来拦截所有请求,并在过滤器中集中处理乱码的问题,SpringMVC已经考虑到了这一点,并为我们提供了一个专门解决乱码问题的过滤器CharacterEncodingFilter,只需在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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:若项目中配置了多个Filter,则CharacterEncodingFilter一定要配置在其它Filter之前。
以上便是有关SpringMVC中处理请求参数的全部内容!