Spring的MVC
11.1 Spring MVC的体系结构
- 控制器(两种):①DispatcherServlet(等价于Struts2中的Filter)
②Controller(等价于Struts2中的Action)
2)映射处理器:HandlerMapping(完成请求和Controller之间的调用,等价于Struts2中的ActionMapping)
3)模型视图组件:ModelAndView(封装了模型数据和视图标识)
4)视图解析器:ViewResolver(等价于Struts2中的Result)
5)视图组件:主要用JSP
11.2 Spring MVC的工作流程
- 客户端发送请求,请求到达DispatcherServlet主控制器。
- DispatcherServlet控制器调用HandlerMapping处理。
- HandlerMapping负责维护请求和Controller组件对应关系。HandlerMapping根据请求调用对应的Controller组件处理。
- 执行Controller组件的业务处理,需要访问数据库,可以调用DAO等组件。
- Controller业务方法处理完毕后,会返回一个ModelAndView对象。该组件封装了模型数据和视图标识。
- Servlet主控制器调用ViewResolver组件,根据ModelAndView信息处理。定位视图资源,生成视图响应信息。
- 控制器将响应信息给用户输出。
11.3案例:简易登录(基于XML配置,不推荐使用)
由于此案例没有用到JDBC、Hibernate等访问数据库的技术,所以AOP包可以不用导入!
step1:导入spring-webmvc.jar包
step2:导入Spring的IoC开发包(spring.jar、commons-logging.jar)
step3:配置web.xml
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param><!-- 让容器从指定的src目录下查找applicationContext.xml文件-->
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern><!-- 不能写/*了,影响太广,自定义一种请求形式 -->
</servlet-mapping>
step4:在/WEB-INF/jsp中新建login.jsp和ok.jsp
- login.jsp
<h1>Spring MVC 登录</h1><font size="5" color="red">${error }</font>
<form action="login.do" method="post">
用户名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password" /><br/>
<input type="submit" value="登录"/></form>
- ok.jsp
<h1>欢迎${user },登录成功!</h1>
step5:在WebRoot下新建index.jsp
<a href="toLogin.do">spring mvc(xml)</a>
step6:在org.tarena.controller包中新建ToLoginController类,并实现Controller接口
public class ToLoginController implements Controller {//必须实现Controller,并重写方法
@Override //记得改改参数名字
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {//默认执行的业务方法
ModelAndView mv=new ModelAndView("login");//调用login.jsp,指定视图名称
return mv; } }
step7:在org.tarena.controller包中新建LoginController类,并实现Controller接口
public class LoginController implements Controller {//必须实现Controller,并重写方法
@Override //记得改改参数名字
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {//默认执行的业务方法
String name=request.getParameter("username");
String pwd=request.getParameter("password");
Map<String,Object> map=new HashMap<String, Object>();
if("chang".equals(name) && "123".equals(pwd)){//简单模拟,不访问数据库了
map.put("user", name); return new ModelAndView("ok",map); }
map.put("error", "用户名或密码错误");
return new ModelAndView("login",map);//指定视图名称 } }
step8:新建applicationContext.xml文件,并进行配置
<!-- 定义handlermapping,即定义请求和Controller的映射信息 -->
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="toLogin.do">toLoginController</prop>
<prop key="login.do">loginController</prop>
</props>
</property>
</bean>
<!-- 定义视图解析器,负责根据ModelAndView信息调用View组件 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property><!-- 声明前缀 -->
<!-- 因返回的ModelAndView对象仅有个名字,所以要定义前后缀 -->
<property name="suffix" value=".jsp"></property><!-- 声明后缀 -->
</bean>
<!-- 定义Controller -->
<bean id="toLoginController" class="org.tarena.controller.ToLoginController"></bean>
<bean id="loginController" class="org.tarena.controller.LoginController"></bean>
step9:部署,测试
11.4案例:修改11.3案例(基于注解配置,推荐使用)
由于此案例没有用到JDBC、Hibernate等访问数据库的技术,所以AOP包可以不用导入!
step1:导入spring-webmvc.jar包
step2:导入Spring的IoC开发包(spring.jar、commons-logging.jar)
step3:配置web.xml,与9.3案例step3相同
step4:在/WEB-INF/jsp中新建login.jsp和ok.jsp
- login.jsp
<h1>Spring MVC 登录</h1><font size="5" color="red">${error }</font>
<!-- 模拟请求有多级,即user/login.do,action写user/login.do为相对路径,出现叠加问题;写绝对路径需要加“/”,同时也要写应用名。详细说明见10.2节-->
<form action="/Spring06_MVC2/user/login.do" method="post">
用户名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password" /><br/>
<input type="submit" value="登录"/></form>
2)ok.jsp,与9.3案例step4中2)相同
step5:在WebRoot下新建index.jsp
<a href="toLogin.do">spring mvc(annotation)</a>
step6:新建applicationContext.xml文件,并进行配置
<!-- 开启组件扫描 -->
<context:component-scan base-package="org.tarena" />
<!-- 定义映射处理器,采用注解AnnotationMethodHandlerAdapter指定映射 -->
<bean id="annotationMapping"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
</bean>
<!-- 定义视图解析器,负责根据ModelAndView信息调用View组件(JSP)-->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property><!-- 声明一个前缀 -->
<property name="suffix" value=".jsp"></property><!-- 声明一个后缀 -->
</bean>
step7:在org.tarena.controller包中新建ToLoginController类,并使用注解
@Controller //将组件扫描到Spring容器
@Scope("prototype")
public class ToLoginController {//不用再实现接口了,就是写个普通的类
@RequestMapping(value="/toLogin.do",method=RequestMethod.GET)
public String execute(){//写个最简单的方法,返回类型也可写ModelAndView
return "login";//返回视图名称 } }
step8:在org.tarena.controller包中新建LoginController类,并使用注解
@Controller //将组件扫描到Spring容器
@Scope("prototype")
@RequestMapping("/user/*")//当请求有多级,即有共同前缀,可写类定义前
public class LoginController { //不用去实现Controller接口了,就是写个普通的类
//@RequestMapping(value="/login.do",method=RequestMethod.POST)//没有共同前缀
@RequestMapping(value="login.do",method=RequestMethod.POST)//有共同前缀
public String execute(User user,Model model){//Model是可以传到下一个页面的
Map<String,Object> map=new HashMap<String, Object>();
if("chang".equals(user.getUsername()) && "123".equals(user.getPassword())){
map.put("user", user.getUsername());
model.addAttribute("user",user.getUsername()); return "ok"; }
model.addAttribute("error", "用户名或密码错误");
return "login"; } }
- 注意事项:
- @RequestMapping注解:value属性指定请求;method属性指定请求提交方式。
- Controller中业务方法可以定义成以下格式:
1)public String f1(){}
2)public ModelAndView f1(){}
3)public String f1(HttpServletRequest request){}//需要request就加上,不需要可不写
4)public String f1(HttpServletRequest request,HttpServletResponse response){}
5)public String f1(User user){} //自定义实体类,属性与表单中的提交名一致
6)public String f1(Model model){} //org.springframework.ui.Model中的
7)public String f1(User user,Model model){}
step9:step8中execute方法用到了实体User,所以在org.tarena.entity包下创建User实体
private String username; private String password;//和表单提交名一样 ……get/set方法
step10:部署,测试