什么是Spring MVC
用来简化基于MVC架构的web应用程序开发,属于Spring框架的一部分
Spring MVC的核心组件
- DispatcherServlet 前端控制器
- HandlerMapping 映射处理器
- Controller 处理器
- ModelAndView 模型和视图
- ViewResolver 视图解析器
##组件之间的相互关系
- 请求先发送给DispatcherServlet,DispatcherServlet收到请求之后,依据HandlerMapping的配置调用对应的Controller来处理。
- Controller将处理结果封装成ModelAndView,然后返回给DispatcherServlet。
- DispatcherServlet依据ViewResolver的解析,调用对应的jsp生成页面。
Spring MVC常用技术
jsp页面
<%@page pageEncoding="utf-8" contentType="text/html" %>
<html>
<form action="login1.do" method="post">
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="登入"></p>
</form>
</html>
读取请求参数值
- 通过request
- 通过@RequestParam
- 通过javabean
@RequestMapping("login2.do")
public String logins(HttpServletRequest req,
@RequestParam("pwd")String password,User user){
System.out.println(req.getParameter("username"));
System.out.println(password);
System.out.println(user);
return "hello";
}
向页面传值
- 将数据绑订到request。
- 返回ModelAndView。
- 将数据绑订到ModelMap。
- 将数据绑订到session。
@RequestMapping("login3.do")
public String loginsss(String username,String pwd,HttpServletRequest request){
//通过requeset传递username
request.setAttribute("username", username);
//通过session
HttpSession session = request.getSession();
session.setAttribute("pwd", pwd);
return "success";
}
@RequestMapping("login4.do")
public ModelAndView login6(String username,String pwd){
User user = new User(username,pwd);
Map<String, Object> data = new HashMap<String,Object>();
data.put("data",user);//页面直接${data}就能得到user
ModelAndView mv = new ModelAndView("success",data);
return mv;
}
@RequestMapping("login5.do")
public String log(String username,String pwd,ModelMap model){
User user = new User(username,pwd);
//需要注意的是ModelMap只能作为参数传入才有效,在方法里new传参无效
model.addAttribute("user",user);
return "success";
}
//演示向页面传值
@RequestMapping("login6.do")
public String logs(@ModelAttribute("user") User user){
return "success";
}
重定向
@RequestMapping("login7.do")
public String redirect(String username){
System.out.println(username);
//当返回值为String时用redirect:路径
return "redirect:hi.do";
}
@RequestMapping("login.do")
public ModelAndView redirects(String pwd){
System.out.println(pwd);
//当返回值为ModelAndView时用RedirectView,参数为重定向路径
RedirectView view = new RedirectView("hi.do");
return new ModelAndView(view);
}
解决中文乱码
为什么会有乱码?
表单提交时,浏览器会对中文参数值使用打开该表单所在页面时的字符集来编码。比如使用”utf-8”来编码。
服务器端默认使用”iso-8859-1”来解码。所以会产生乱码。
如何解决?
在web.xml中配置springmvc提供的过滤器(CharacterEncodingFilter)。
注意:
- 表单提交方式必须设置为”Post”
- 页面编码与过滤器的初始化参数设置的编码要一致。
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
异常处理
Spring MVC提供了三种异常处理机制
使用Spring MVC提供的简单的异常处理器SimpleMappingExceptionResolver即可
该种方式只需要在配置文件里进行配置即可
<!-- 配置spring MVC提供的简单异常处理 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,即系统出现<prop>未指定的异常时就跳转默认指定的页面 -->
<property name="defaultErrorView" value="erroe"/>
<!-- 定义异常处理页面用来获取异常信息的变量名,也可不定义,默认名为exception,即就一个异常对象,
可以在页面获取该异常对象的信息-->
<property name="exceptionAttribute" value="ex" />
<!-- 指定异常类型,并给出相应页面 -->
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">erroe1</prop>
<prop key="entity.MyException">erroe2</prop>
</props>
</property>
</bean>
自定义异常处理器
该种方式需要自定义一个类实现HandlerExceptionResolver接口,根据不同的异常类型采取相应的界面
扫描二维码关注公众号,回复: 2754113 查看本文章
public class MyMappingExceptionResolver implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
//根据异常类型返回相应视图
if(ex instanceof NullPointerException){
return new ModelAndView("erroe1");
}
if(ex instanceof MyException){
return new ModelAndView("erroe2");
}
//其他错误就返回erroe.jsp
return new ModelAndView("erroe");
}
}
2.在配置文件里进行配置
<!-- 配置自定义异常处理器 -->
<bean class="controller.MyMappingExceptionResolver"/>
使用@ExceptionHandler注解实现局部异常处理
该种方式只能针对单一控制器内的异常进行处理,即在哪个处理器(controller)使用该注解,则哪个处理器的异常方法就被处理@Controller
public class ExceptionController {
//但需要注意的是这只是一个局部异常处理注解,即只对当前控制器有效,对其他控制器无效
//指定异常
@ExceptionHandler(NullPointerException.class)
public String ExceptionHandler(){
return "erroe1";
}
//指定异常
@ExceptionHandler(MyException.class)
public String ExceptionHandler1(){
return "erroe2";
}
//其他异常
@ExceptionHandler(Error.class)
public String ExceptionHandler2(){
return "erroe";
}
@RequestMapping("exception.do")
//测试系统异常
public ModelAndView toTest1(){
Map<String,Object> data = new HashMap<String,Object>();
//故意制造一个空指针异常
String str = null;
str = str.substring(0, 5);
data.put("data", str);
ModelAndView mv = new ModelAndView("success",data);
return mv;
}
@RequestMapping("exception1.do")
//测试自定义异常
public ModelAndView toTest2(){
String str = null;
if(str==null){
throw new MyException("完了出错了");
}
Map<String,Object> data = new HashMap<String,Object>();
data.put("data", str);
ModelAndView mv = new ModelAndView("success",data);
return mv;
}
@RequestMapping("exception2.do")
//测试未指定异常
public ModelAndView toTest3(){
String str = "abc";
//故意制造一个类型转换异常
Integer.valueOf(str);
Map<String,Object> data = new HashMap<String,Object>();
data.put("data", str);
ModelAndView mv = new ModelAndView("success",data);
return mv;
}
}
拦截器
什么是拦截器?
DispatcherServlet收到请求之后,如果有拦截器,则先执行拦截器的方法,然后再执行处理器的方法。
注意:
过滤器属于Servlet规范,而拦截器属于Spring框架。
如何实现拦截器?
- 实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类
二者的区别在于前者三个方法都得实现,后者可以根据实际需求重写想要的方法
/**
*该方法是创建拦截器的第二种方法,实现HandlerIntercep
*用来监控登入所消耗的时间
* @author Administrator
*
*/
public class MySecondInterceptor implements HandlerInterceptor {
private long start_time;
private long end_time;
//处理器执行请求前
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
start_time=System.currentTimeMillis();
System.out.println("第二个拦截器请求结束前:第二个拦截器的方法已经执行");
return true;
}
//处理器执行请求结束后,视图层显示前(即控制器向前端发送页面前)
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("第二个拦截器请求结束后:请求结束后执行");
}
//处理器完全执行请求后,即视图已经展示
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
end_time=System.currentTimeMillis();
System.out.println("第二个拦截器请求完全结束后:登入共耗时"+(end_time-start_time)+"毫秒");
}
}
/** * 自定义拦截器,用来实现登入验证 * @author WQP * */ public class MyFirstInterceptor extends HandlerInterceptorAdapter { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("第一个拦截器方法已经执行了"); return true; } }
2.在配置文件中配置拦截器
<!-- 定义拦截器 --> <mvc:interceptors> <!-- 实现登入验证 --> <mvc:interceptor> <!-- 指定拦截路径 --> <mvc:mapping path="/**"/> <!-- 指定不需要拦截的路径 --> <mvc:exclude-mapping path="/tologin.do"/> <mvc:exclude-mapping path="/login.do"/> <!-- 注入拦截的类 --> <bean class="ssm.test.interceptors.MyFirstInterceptor"/> </mvc:interceptor> <!-- 监控登入耗时 --> <mvc:interceptor> <!-- 指定拦截路径 --> <mvc:mapping path="/login.do"/> <!-- 注入拦截的类 --> <bean class="ssm.test.interceptors.MySecondInterceptor"/> </mvc:interceptor> </mvc:interceptors>
3.实现登入操作后的控制台输出