SpringMVC
1.在SpringMVC中使用Session
当需要向Session中存入数据时,可以使用【ModelMap】
对象将数据进行封装,操作方式与封装转发的数据完全相同,例如:
modelMap.addAttribute("username", username);
然后,需要在当前控制器类之前添加@SessionAttributes
注解,并且,在注解中显式的指定ModelMap
中封装的哪些数据是需要存储在Session中的,例如:
@Controller
@RequestMapping(value="user")
@SessionAttributes("username")
public class UserController {
// ...
}
当添加了以上注解后,如果【ModelMap】
中被存入了名为【username】
的数据,该数据就在Session中,而【ModelMap
】
中的其它数据依然只能用于转发,也就是数据的作用域只在【Request】级别。
关于【@SessionAttributes】
注解,其属性的配置可以参考该注解的源代码:
@AliasFor("names")
String[] value() default {};
@AliasFor("value")
String[] names() default {};
Class<?>[] types() default {};
通过以上源代码可以看到:【value】
和【names】
属性的作用是完全相同,用于指定【ModelMap】
中的哪些名称对应的数据需要存放到【Session】中,可以使用字符串数组表示多个属性,另外,还可以配置【types】
属性用于指定【Session】的数据的数据类型,也可以是数组类型,与配置的【names】
保持一致即可。
使用这种做法操作Session非常简单,但是,也存在一系列的问题:
1.默认情况下,重定向时会把Session中的数据暴露在URL中;
2.通过ModelMap
存放的数据一定会在Request的作用域中,所以,通过这种方式存放到Session中的数据,其实在Request中也是存在的;
3.通过这种方式存放到Session中的数据,不可以通过Session对象的【invalidate()】
方法清除!只能通过SessionStatus
类的【setComplete()】
方法进行清除!
更加简单的操作Session的方式就是直接在处理请求的方法中添加【HttpSession】
类型的参数,在方法体中直接操作即可。
@RequestMapping("handle_login.do")
public String handleLogin(String username, String password,
ModelMap modelMap, HttpSession session) {
// 日志
System.out.println("UserController.handleLogin()");
System.out.println("\tusername=" + username);
System.out.println("\tpassword=" + password);
// 判断用户名是否正确
if ("root".equals(username)) {
// 是:判断密码是否正确
if ("1234".equals(password)) {
// 是:登录成功,将用户名存入到Session
// modelMap.addAttribute("username", username);
session.setAttribute("username", username);
// 重定向到主页
return "redirect:../index.do";
} else {
// 否:密码错误
modelMap.addAttribute("errorMessage", "ModelMap:密码错误");
return "error";
}
} else {
// 否:用户名错误
modelMap.addAttribute("errorMessage", "ModelMap:用户名错误");
return "error";
}
}
使用这种做法并不存在以上使用@SessionAttributes
时的各种问题,操作也非常简单,缺点就是不易于执行单元测试!
但有时可以忽略这个缺点,甚至“不使用@SessionAttributes
”,原因可能是:可以使用专门的测试工具去测试控制器,所以,在控制器中的方法本身是不需要执行单元测试的,甚至在大型项目中根本就不会使用Session,那各种使用方式都是不需要的!
2.在SpringMVC中统一处理异常
在Java中,异常的继承体系是:
Throwable
Error
OutOfMemoryError
Exception
SQLException
IOEException
FileNotFoundException
RuntimeException
NullPointException
ClassNotFoundException
AirthmeticException
NumberFormatException
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
常见异常处理的做法为捕获【try...catch】或者声明抛出【throw/throws】,在实际处理时,如果当前类适合处理该异常,则捕获,如果不适合,则声明并向上层抛出,由上层调用者决定是否处理该异常,通常适合处理异常的都是【控制器】,但是异常可能在多个功能中都会出现,在处理不同的请求时,采用相同代码处理,则会造成代码冗余,不便于统一管理,所以在SpringMVC框架中提供了统一处理异常的机制。
可以在控制器类中添加统一处理异常的方法,关于该方法:
1.使用【public】权限;
2.返回值的意义与处理请求的方法完全相同;
3.方法名称可以自定义;
4.方法中必须包含异常类型的参数,且参数的类型能包括所有可能需要处理的异常;
5.与处理请求的方法不同,不可以使用【ModelMap】等对象,只能添加【HttpServletRequest】参数;
6.必须添加【@ExceptionHandler】注解,所以,处理i请求的方法可以是:
@ExceptionHandler
public String handleException(Throwable ex, HttpServletRequest request) {
if (ex instanceof NullPointerException) {
request.setAttribute("errorMessage", "空指针异常!");
} else if (ex instanceof ArrayIndexOutOfBoundsException) {
request.setAttribute("errorMessage", "数据下标越界异常异常!");
} else {
request.setAttribute("errorMessage", "未知异常:" + ex.getClass().getName());
}
return "error";
}
一旦添加了该方法,当前类中任何处理请求的方法都不需要处理相关异常,等同于这些方法把异常抛出了,所有抛出的异常将由该方法统一处理,需要注意的是,该方法只能处理该控制器出现的异常,其他控制器类抛出的异常不做处理。所以可以把该处理异常的方法放在所有控制器类公共的父类中,如【BaseController】!
关于@ExceptionHandler
的源代码:
public @interface ExceptionHandler {
/**
* Exceptions handled by the annotated method. If empty, will default to any
* exceptions listed in the method argument list.
*/
Class<? extends Throwable>[] value() default {};
}
该注解可以指定需要被处理的异常的种类,允许定义多个异常处理方法,单独处理同一类型异常,其参数可以是数组,即同时指定多种异常都将被该方法进行处理!
SpringMVC重点内容:
- 理解SpringMVC执行核心流程;
- 掌握获取请求参数的方式;
- 理解转发与重定向;
- 了解转发时如何转发数据;
- 掌握@RequestMapping、@RequestParam注解的使用;
- 掌握拦截器的使用;
- 掌握处理异常的使用。