跳至主要內容

SpringMVC 基础(二)

Yaien Blog原创大约 8 分钟SpringMVC基础

SpringMVC 基础(二)

SpringMVC 基础笔记系列

接收请求参数

(不推荐) 使用HttpServletRequest

在处理请求的方法的参数列表中添加HttpServletRequest参数,然后,在处理过程中,调用requestgetParameter()方法即可获取各请求参数的值:

	@RequestMapping("handle_register.do")
	public String handleRegister(HttpServletRequest request) {
		System.out.println("UserController.handleRegister()");
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		Integer age = Integer.valueOf(request.getParameter("age"));
		String phone = request.getParameter("phone");
		String email = request.getParameter("email");
		System.out.println("\tusername=" + username);
		System.out.println("\tpassword=" + password);
		System.out.println("\tage=" + age);
		System.out.println("\tphone=" + phone);
		System.out.println("\temail=" + email);
		return null;
	}

以上做法的不足有:

  • 如果期望的数据类型不是String,需要自行转换!

  • 获取数据的操作比较繁琐;

  • 不便于执行单元测试。

(推荐) 将请求参数设计为处理请求的方法的参数

当需要获取请求参数时,直接将它们添加到处理请求的方法的参数列表中即可:

	@RequestMapping("handle_register.do")
	public String handleRegister(
			String username, String password, 
			Integer age, String phone, String email) {
		System.out.println("UserController.handleRegister()");
		System.out.println("\tusername=" + username);
		System.out.println("\tpassword=" + password);
		System.out.println("\tage=" + (age + 1));
		System.out.println("\tphone=" + phone);
		System.out.println("\temail=" + email);
		return null;
	}

这种操作要求请求参数的名称与处理请求的方法的参数名称保持一致!如果名称不一致,则处理请求的方法中的参数值将是null

在设计处理请求的方法的参数列表时,各参数的类型可以直接声明为期望的数据类型,例如期望名为age的量是Integer类型,则直接声明为Integer即可,无需在方法中自行转换!

这种做法的缺陷在于:不适合处理过多的请求参数。

(推荐) 使用封装的类型作为处理请求的方法的参数

当请求参数较多时,可以将这些参数封装到1个自定义的类型中:

	public class User {
	
		private String username;
		private String password;
		private Integer age;
		private String phone;
		private String email;

	}

然后,将自定义的数据类型作为处理请求的方法的参数即可:

	@RequestMapping("handle_register.do")
	public String handleRegister(User user) {
		System.out.println("UserController.handleRegister()");
		System.out.println("\t" + user);
		return null;
	}

同样,这种做法仍要求请求参数的名称,与封装的类型中的属性名称保持一致!

这种做法还有1个优点:当请求参数的数量发生变化时,也许处理请求的方法的参数列表可以不用调整,而只调整自定义的封装类型即可。

如何选取各种获取请求参数的方式

第1种做法是始终不推荐的,即完全不使用第1种做法。

如果参数的数量较多,应该优先选取第3种做法;如果参数的数量可能发生变化,应该优先选取第3种做法;如果参数的数量较少且固定,应该优先选取第2种做法。

另外,第2种做法和第3种做法可以混合在一起使用!

重定向

在处理请求的方法中,返回String类型的结果时,返回值使用redirect:作为前缀,则表示重定向!在redirect:右侧的必须是重定向到的目标的相对定位或绝对定义的URL,例如:

	return "redirect:xxx.do";

假设当前用户的注册一定能成功,且注册成功后显示登录页面,则:

	@RequestMapping("handle_register.do")
	public String handleRegister(User user) {
		System.out.println("UserController.handleRegister()");
		System.out.println("\t" + user);
		return "redirect:login.do";
	}

转发数据

(不推荐) 通过HttpServletRequest参数封装转发的数据

在SpringMVC中,如果方法的返回值类型是String类型,默认转发!

假设在控制器的方法中处理登录时,只有root/1234是正确的用户名和密码,登录成功后重定向到主页,而登录失败,将错误信息转发到**/WEB-INF/error.jsp**错误页面。

当需要转发时,可以在处理请求的方法中添加HttpServletRequest参数,在使用时,调用参数对象的setAttribute()方法即可封装转发的数据,然后,执行转发即可(无需获取转发器等):

	@RequestMapping("handle_login.do")
	public String handleLogin(String username, String password, HttpServletRequest request) {
		System.out.println("UserController.handleLogin();");
		System.out.println("\tusername=" + username);
		System.out.println("\tpassword=" + password);
		
		// 定义错误提示信息
		String errorMessage;
		// 判断用户名是否正确
		if ("root".equals(username)) {
			// 用户名正确,继续判断密码是否正确
			if ("1234".equals(password)) {
				// 密码也正确,则登录成功,重定向到主页
				return "redirect:index.do";
			} else {
				// 密码错误,先准备好错误提示
				errorMessage = "登录失败!密码错误!";
				// 将错误提示封装到请求对象中
				request.setAttribute("msg", errorMessage);
				// 执行转发
				return "error";
			}
		} else {
			// 用户名错误
			errorMessage = "登录失败!用户名不存在!";
			request.setAttribute("msg", errorMessage);
			return "error";
		}
		
	}

(更不推荐) 使用ModelAndView

可以使用ModelAndView作为处理请求的方法的返回值类型,在该类型的对象中,设置其viewName属性即可确定需要转发到的视图名称,另外还使用了Map<String, ?>类型的数据作为需要转发的数据:

	@RequestMapping("handle_login.do")
	public ModelAndView handleLogin(String username, String password) {
		System.out.println("UserController.handleLogin();");
		System.out.println("\tusername=" + username);
		System.out.println("\tpassword=" + password);
		
		// 准备返回值对象
		ModelAndView mav;
		// 封装转发的数据的Map
		Map<String, Object> model = new HashMap<String, Object>();
		// 定义错误提示信息
		String errorMessage;
		// 判断用户名是否正确
		if ("root".equals(username)) {
			// 用户名正确,继续判断密码是否正确
			if ("1234".equals(password)) {
				// 密码也正确,则登录成功,重定向到主页
				return null;
			} else {
				// 密码错误,先准备好错误提示
				errorMessage = "登录失败!密码错误!";
				// 将错误提示封装到请求对象中
				model.put("msg", errorMessage);
				mav = new ModelAndView("error", model);
				// 执行转发
				return mav;
			}
		} else {
			// 用户名错误
			errorMessage = "登录失败!用户名不存在!";
			model.put("msg", errorMessage);
			mav = new ModelAndView("error", model);
			return mav;
		}
		
	}

(推荐) 使用ModelMap封装转发的数据

使用方式与使用HttpServletRequest是相同的:

	@RequestMapping("handle_login.do")
	public String handleLogin(String username, String password, ModelMap modelMap) {
		System.out.println("UserController.handleLogin();");
		System.out.println("\tusername=" + username);
		System.out.println("\tpassword=" + password);
		
		// 定义错误提示信息
		String errorMessage;
		// 判断用户名是否正确
		if ("root".equals(username)) {
			// 用户名正确,继续判断密码是否正确
			if ("1234".equals(password)) {
				// 密码也正确,则登录成功,重定向到主页
				return null;
			} else {
				// 密码错误,先准备好错误提示
				errorMessage = "[ModelMap] 登录失败!密码错误!";
				// 将错误提示封装到请求对象中
				modelMap.addAttribute("msg", errorMessage);
				// 执行转发
				return "error";
			}
		} else {
			// 用户名错误
			errorMessage = "[ModelMap] 登录失败!用户名不存在!";
			modelMap.addAttribute("msg", errorMessage);
			return "error";
		}
		
	}

关于@RequestMapping注解

在处理请求的方法之前添加@RequestMapping用于配置请求路径与处理响应的方法之间的映射。

该注解也可以添加在类的声明之前,例如:

	@RequestMapping("user")
	@Controller
	public class UserController {
	}

添加在类之前的@RequestMapping注解用于配置请求路径中的层次!将作用于当前类中配置的所有请求路径!原有的例如login.do的请求路径就会变成user/login.do

无论是添加在类之前配置路径,还是在方法之前配置路径,在配置时,路径的左右两侧都可以添加/符号,例如:

@RequestMapping("/user/")

在使用该注解时,对左右两侧的/是没有要求的,例如在类和方法之前分别配置:

	user		login.do
	/user		/login.do
	/user/		/login.do
	/user/		login.do

以上各种配置方式都是正确的!在实际使用时,应该保持自己的代码风格统一!

在实际应用中,推荐为每一个类都添加该注解!

配置注解中的value属性或path属性,可以配置请求路径与处理请求的方法的映射,且值可以是数组类型:

	@RequestMapping(name="hahaha", path={"reg.do", "register.do"})

可以在注解中配置method属性,以限制某个请求路径的允许使用的若干种请求方式,例如:

	@RequestMapping(path="handle_login.do", method=RequestMethod.POST)

或:

	@RequestMapping(path="handle_login.do", method={RequestMethod.POST, RequestMethod.GET})

如果使用错误的请求方式发出请求,则会导致405错误:

	HTTP Status 405 - Request method 'GET' not supported

关于@RequestParam注解

@RequestParam是添加在请求参数之前的注解!

使用该注解可以解决客户端提交的请求参数名称,与服务器端的处理请求的方法的参数名称不统一的问题:

	@RequestParam("uname") String username

当添加以上注解后,默认情况下,该参数就是必须提交的,如果请求中没有提交该参数,就会出现400错误:

	HTTP Status 400 - Required String parameter 'uname' is not present

这种表现是由于该属性中的required属性决定的,在该注解的源代码:

	boolean required() default true;

所以,如果并不强制要求客户端提交该参数,可以:

	@RequestParam(name="uname", required=false)

另外,还可以配置defaultValue属性,用于配置默认值,即当客户端没有提交该请求参数时,视为客户端提交了某个值:

	@RequestParam(name="uname", required=false, defaultValue="JSD1902")

当然,在设置defaultValue时,需要显式的将required设置为false

所以,通常@RequestParam注解的使用场景:

  • 客户端提交的请求参数名称与服务器端处理请求的方法的参数名称不一致时;

  • 强制要求客户端提交某些参数时;

  • 需要为某些请求参数设置默认值时。

上次编辑于:
贡献者: yanggl