一、方法的参数
1. JavaEE组件
- HttpServletRequest
- HttpServleetResponse
- HttpSession
如下例,新建ParamController.java
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/test1")
public void test1(HttpServletRequest req, HttpServletResponse resp, HttpSession session) throws IOException {
System.out.println("ParamController.test1," + req + "," + resp + "," + session);
String username = req.getParameter("username");
session.setAttribute("username", username);
PrintWriter out = resp.getWriter();
out.print("<h1>" + username + "<h1>");
out.flush();
out.close();
}
}
2. IO流
- InputStream/OutStream
- Reader/Writer
IO流可以直接作为参数获取
@RequestMapping("/test2")
public void test2(InputStream is, OutputStream os) throws IOException {
System.out.println("ParamController.test2," + "," + is + "," + os);
}
@RequestMapping("/test3")
public void test3(Reader reader, Writer writer) throws IOException {
System.out.println("ParamController.test2," + "," + reader + "," + writer);
}
也可以通过HttpServletRequest和HttpServleetResponse获取
@RequestMapping("/test1")
public void test1(HttpServletRequest req, HttpServletResponse resp) throws IOException {
InputStream is = req.getInputStream();
OutputStream os = resp.getOutputStream();
Reader reader = req.getReader();
Writer writer = resp.getWriter();
}
3. 向界面传递数据
使用Model
、Map
、ModelMap
将数据存储到Request作用域中
例:
添加result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>result</title>
</head>
<body>
name:${requestScope.name} <br>
age:${age} <br>
sex:${sex} <br>
address:${address} <br>
</body>
</html>
@RequestMapping("/test4")
public String test4(Model model, Map map, ModelMap modelMap){
model.addAttribute("name", "wql");
map.put("age", 23);
modelMap.addAttribute("sex", "male");
modelMap.put("address", "beijing");
return "result";
}
4. String和基本数据类型及其包装类
4.1 @RequestParam
@RequestParam
表示参数来源于请求参数,如http://localhost:8080/param/test6?name=wql&age=20
中name和age就是请求参数
方法的参数如果是String类型和基本数据类型及其包装类,如果参数前面没有注解,则参数前默认添加@RequestParam
注解
@RequestParam
的源码如下所示
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
String name() default ""
请求参数与方法中的参数名不一致时会用到boolean required() default true;
如果参数前不加注解,参数可为空;如果加上注解@RequestParam
,默认该参数不能为空String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
指定参数的默认值
以test5为例
@RequestMapping("/test5")
public String test5(@RequestParam String name,
@RequestParam(name = "years_old")int age,
@RequestParam(required = false, defaultValue = "1") Integer sex,
String address){
System.out.println("name=" + name + ", age=" + age + ", sex=" + sex + ", address=" + address);
return "result";
}
在地址栏输入http://localhost:8080/param/test5?name=wql&years_old=20&sex=1&address=beijing
,控制台可得到相应的输出
其中参数name不能省略,参数sex可以省略,默认值为1,参数adress可以省略,将地址栏输入改为http://localhost:8080/param/test5?name=wql&years_old=20
,控制台输出如下结果
4.2 @PathVariable
前几天学了@PathVariable
,其表示参数来源于URL,如@RequestMapping("/test6/{name}/{age}")
中name和age就是URL中的参数
test5与test6做一个对比
@RequestMapping("/test6/{name}/{age}")
public String test6(@PathVariable("name") String stuName,
int age,
@RequestParam(required = false, defaultValue = "1") Integer sex,
String address){
System.out.println("name=" + stuName + ", age=" + age + ", sex=" + sex + ", address=" + address);
return "result";
}
int age
,String address
这两个参数前面都没有注解,默认添加@RequestParam
注解,但是可以省略
@PathVariable String name
表示参数来源于URL,如果名字不一致,可在注解中加入
在地址栏输入http://localhost:8080/param/test6/www/20?stuName=wql&age=10
在控制台可得到
从上可以看出,name来自URL,age来自请求参数
4.3 @RequestHeader
@RequestHeader
表示请求参数来源于请求头,关于请求头的内容,在SpringMVC_02中稍微提了一下,下图展示了请求头里的详细内容
我们可以通过@RequestHeader
获取请求头里的内容,
首先往客户端中添加一些cookie
@RequestMapping("/addCookie")
public String addCookie(HttpServletResponse resp){
//向客户端添加cookie
Cookie cookie = new Cookie("username", "wql");
cookie.setMaxAge(7*24*60*60);//7天
resp.addCookie(cookie);
return "result";
}
然后获取请求头中的User-Agent和Cookie
@RequestMapping("test7")
public String test7(@RequestHeader("User-Agent") String userAgent, @RequestHeader("Cookie") String cookie){
System.out.println("userAgent: " + userAgent + "\nCookie:" + cookie);
return "result";
}
4.4 @CookieValue
通过@RequestHeader
可以获取cookie里面的信息,以字符串的形式把所有的cookie返回给我们。但是有时候cookie里面的信息比较多,比如说我们往cookie里添加名为username
的cookie,用@RequestHeader
的方式获取username
的值比较麻烦,我们可以使用@CookieValue
来获取特定的cookie值
通过@CookieValue
获取cookie
@RequestMapping("/test8")
public String test8(@CookieValue String username, @CookieValue("JSESSIONID") String sessionId){
System.out.println("username: " + username + "\nsessionId:" + sessionId);
return "result";
}
4.5 @RequestBody
@RequestBody
表示参数来源于请求体,只有请求方式为POST时才会有请求体。
我们使用SpringMVC_01中设计的表单,将其请求方式改为POST,点击提交之后跳转至/param/test9
在登录页面输入用户名www
,密码111
,点击登录
通过审查元素可以发现多了请求体一栏
我们通过@RequestBody
获取其信息
@RequestMapping("/test9")
public String test9(@RequestBody String requestBody){
System.out.println("requestBody:" + requestBody);
return "result";
}
5. 自定义类型参数
@ModelAttribute
将请求数据转换为对象,如果方法的参数为自定义的类型,默认参数前有@ModelAttribute
注解
条件:对象的属性名必须与表单元素的名称相同
例:我们自定义一个类UserVo
package vo;
public class UserVo {
private String username;
private String password;
private String phone;
private String email;
private Integer age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserVo{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
添加一个注册页面register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>register</title>
</head>
<body>
<h2>用户注册</h2>
<form action="${pageContext.request.contextPath}/user/register" method="post">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
年龄:<input type="text" name="age"> <br>
手机号:<input type="text" name="phone"> <br>
邮箱:<input type="text" name="email"> <br>
<input type="submit" value="注册">
</form>
</body>
</html>
在springmvc.xml配置可以直接访问register.xml页面
<beans>
<mvc:view-controller path="/userRegister" view-name="register"/>
</beans>
配置UserController
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/register")
public String register(UserVo userVo){
System.out.println("UserController.register.userVo:" + userVo);
return "success";
}
}
启动程序,在地址栏输入localhost:8080/userRegister
,可跳转到注册页面
输入注册信息,点击注册,跳转到成功页面,也控制栏输出如下
@ModelAttribute
不仅可以用于自定义类型的数据,还可以用于向request
域中添加数据,与上述方法不一样的地方时,@ModelAttribute
注解需要写在方法的上方。在调用所有目标方法时,都会先调用被@ModelAttribute
所注解的方法,并向模型中添加数据。
例:我们想在request域中添加一个String类型的列表,并在result.jsp中显示出来。首先在result.jsp中做如下修改
<body>
...
位置选择:
<select>
<c:forEach items="${types}" var="type">
<option value="">${type}</0></option>
</c:forEach>
</select>
</body>
在UserController中添加方法,且其被@ModelAttribute
注解
@ModelAttribute("types")
public List<String> getTypes(){
System.out.println("UserController.getTypes");
List<String> list = Arrays.asList("辅助","上单","中单","打野","下路");
return list;
}
添加测试方法,跳转到result.jsp
@RequestMapping("/test")
public String test(){
System.out.println("UserController.test");
return "result";
}
启动程序,在地址栏输入localhost:8080/user/test
可得如下结果
可以看到,程序是先调用getTypes
方法,而后调用test
方法。
result.jsp界面显示如下
6. 错误参数
我们在register.xml页面里添加了一个form表单
<form action="${pageContext.request.contextPath}/user/register" method="post">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
年龄:<input type="text" name="age"> <br>
手机号:<input type="text" name="phone"> <br>
邮箱:<input type="text" name="email"> <br>
<input type="submit" value="注册">
</form>
我们在实际的开发中,需要对表单进行数据校验,其中分为客户端表单校验和服务端表单校验。
客户端表单校验中出现错误会显示给客户端,使用户更改输入的参数;而服务端的表单校验的结果由后台进行操纵。
Errors
和BindingResult
可以用来接收错误信息,实现服务端的数据校验。其中Errors
是BingdingResult
的父类。
接下来在UserController.java中加入错误参数
@RequestMapping("/register")
public String register(@ModelAttribute UserVo userVo, Errors error){
//手动进行服务端数据校验
if(userVo.getAge() < 0 || userVo.getAge() > 120){
error.reject("年龄只能在0-120之间");//手动添加错误
}
//判断是否有错误
if(error.hasErrors()){
System.out.println(error);
return "register";
}
System.out.println("UserController.register.userVo:" + userVo);
return "success";
}
启动程序,来到注册界面,在age一栏输入参数123
,点击注册,控制台输出如下错误