概述
- 实现MVC设计模式的企业级开发框架
MVC设计模式
- Web应用分为三层
- 控制层:接收并处理请求,响应给客户端
- 模型层:处理具体业务逻辑,产生模型数据
- 视图层:交互窗口
图解
- 控制器首先接收请求,然后针对不同请求,调用模型层不同的方法,不同的业务方法会对数据库进行不同的持久化操作,取得模型数据后,视图层根据模型数据渲染,最后把结果响应给客户端
- SpringMVC得名由来:
- 封装MVC设计模式,屏蔽底层代码
- 以Spring框架为基础,利用容器特性简化配置
核心组件
-
DispatcherServlet:SpringMVC的控制核心,控制调度其他组件,相当于总指挥
-
Handler:针对不同请求,有不同的Handler处理器
-
HandlerMapping:体现请求与Handler间的映射关系
-
处理器执行链(HandlerExecutionChain)=handler+handleInterceptor
- 一般有默认拦截器,若要额外添加,则实现该接口,从而添加拦截器
-
处理器拦截器:至少会有一个拦截器(有default的拦截器)
-
处理器适配器:Handler处理之前要进行表单数据验证,数据类型转换或者封装到Bean等操作——》DispatcherServlet通过HandleAdapter来执行不同handler,从而执行具体业务方法
-
ModelAndView:装载逻辑视图和模型数据
- 视图信息为逻辑视图,作为处理结果返回给DispatcherServlet
-
处理结果要解析——》使用ViewResolver(视图解析器),用于将逻辑视图解析为Web工程的物理视图,且将模型数据填充到view中,返回view给DispatcherServlet,最后将结果渲染后,响应给客户端
实现流程概述
组件交互过程(底层原理)
- 注意箭头代表流程
- 首先DispatcherServlet接收请求
- 然后通过HandlerMapping(Handler+HanldeInterceptor结合起来,以HandlerExecutionChain返回给总指挥)映射到具体的handler
- 然后总指挥通过adapter去执行具体的handler ,返回ModelAndView,包含两部分数据:模型数据与逻辑视图,然后借助ViewResolver解析,将逻辑视图解析为物理视图,且填充视图 ,最后响应客户端
开发概述
- 开发者集中干两件事
- 通过配置将组件间关联
- Handler和View(JSP)手动编写
基于XML方式
- resource文件夹:存放配置文件
- webapp文件夹:存放web组件
- 引入依赖(Servlet依赖和SpringMVC依赖的jar包)
- 配置总指挥,即前置控制器(web.xml)
- 配置文件设置:配置HandlerMapping,Handler和视图解析器
- 编写Handler文件(实现接口,重写方法)和JSP文件(利用EL表达式从request对象中取出数据并显示)
- 配置Tomcat服务器
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
//注解方式要实现接口
public class MyHandler implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//装载模型数据和逻辑视图
ModelAndView modelAndView = new ModelAndView();
//添加模型数据
//键值对形式添加,name为key,tom为对应值
//可在JSP的request域中根据key,即name,取出对应值,即tom
modelAndView.addObject("name","tom");
//添加逻辑视图
modelAndView.setViewName("show"); //show对应show.jsp
//返回modelAndView
return modelAndView;
//然后SpringMVC会自动将ModelAndView的模型数据放到Request的作用域中(JSP的内置对象)
}
}
//配置总指挥——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:springmvc.xml</param-value> //指示配置文件的位置,此处为类路径下的springmvc.xml文件
</init-param>
</servlet>
//一个servlet对应一个mapping
<servlet-mapping>
<servlet-name>springmvc</servlet-name> //此处的springmvc与上文对应
<url-pattern>/</url-pattern>
</servlet-mapping>
- 初始化参数:指定配置文件位置,让servlet了解位置
- 拦截所有请求:用斜杆表示
- Ctrl+I:IDEA中实现接口快捷键
- SpringMVC会自动将ModelAndView的模型数据放到Request的作用域中(JSP的内置对象)
- 然后使用EL表达式取出数据——》使用EL需要先添加一段代码(false),表示可以使用,如下所示:
//Handler部分代码
modelAndView.addObject("user",user);
modelAndView.setViewName("index");
-----------------
//index.jsp文件
<%@ page isELIgnored="false" %>
<html>
<body>
<h2>Hello World!</h2>
${requestScope.user.name}
</body>
</html>
配置文件
- springmvc.xml:
- 配置Handler
- 配置Mapping
- 配置视图解析器(需要配置前缀和后缀)
//配置mapping,将请求映射到Handler上
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/test">XMLHandler</prop>
//用户自定义,XMLHandler对应下文,/test为自定义的Url请求,使用如下图
</props>
</property>
</bean>
//配置Handler
<bean id="XMLHandler" class="com.imooc.controller.XMLHandler" />
- springmvc.xml文件内容
//配置视图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
-
配置视图解析器,关注两个属性的配置:前缀和后缀,作用如下
- /表示根目录
- 将逻辑视图(show)解析为jsp文件(/show/jsp——添加了前缀和后缀),即将show字符串映射到JSP文件
-
看URL地址
基于注解方式
1. 引入依赖(Servlet依赖和SpringMVC依赖的jar包)
2. 配置总指挥,即前置控制器(web.xml)
3. 配置文件设置:只配置视图解析器,其他通过注解方式
4. 编写Handler文件(注解指明对应类,注解指明处理的业务方法)和JSP文件(利用EL表达式从request对象中取出数据并显示)
5. 配置Tomcat服务器
- 少两个Bean的XML配置
- 不需要实现接口
- 要求
- XML配置开启自动扫描
- Controller注解(相当于XML中的接口实现类),RequestMapping注解(相当于XML中的URL请求)
- 更多的业务处理书写方式
- ModelAndView
- 拆分为model和view
- 拆分为Map+String
//来自JSP文件
<form class="form-horizontal" role="form" action="AnnotationHandler/add" method="post">
- 注意action的值,对应下文的add业务处理方法
- action和注解值对应
@RequestMapping("/AnnotationHandler") //此处注解不可忘
@Controller
public class AnnotationHandler {
//业务方法:Model传值,String进行视图解析
@RequestMapping("/ModelTest")
public String ModelTest(Model model){
User user = new User();
user.setName("Tom");
model.addAttribute("user",user);
return "index";
}
//业务方法另一种书写方式
@RequestMapping("/MapTest")
public String MapTest(Map<String,User> map){
User user = new User();
user.setName("Jerry");
map.put("user",user);
return "index";
}
//业务方法另一种书写方式
//ModelAndView完成数据的传递,视图的解析
@RequestMapping("/ModelAndViewTest")
public ModelAndView ModelAndViewTest(){
User user = new User();
user.setName("Cat");
//创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
//填充模型数据
modelAndView.addObject("user",user);
//设置逻辑视图
modelAndView.setViewName("index");
return modelAndView;
}
@RequestMapping("/add")
public ModelAndView add(Goods goods){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("goods",goods);
modelAndView.setViewName("show");
return modelAndView;
}
}
实战
- 需求:前台输入商品信息,提交后添加商品信息——》将商品信息封装到对应的实体类——》另一个前台展示
- 采用注解方式,步骤同上,注意点如下
- 封装操作只需要Entity类的属性名同JSP页面表单input的name名,即下文的name和price
- 页面:form表单
public class Goods {
private String name;
private double price;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public double getPrice(){
return this.price;
}
public void setPrice(double price){
this.price = price;
}
}
-------------------------------
<form class="form-horizontal" role="form" action="AnnotationHandler/add" method="post">
<div class="form-group">
<label class="col-sm-1 control-label">名称</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="name" placeholder="请输入商品名称">
</div>
</div>
<div class="form-group">
<label class="col-sm-1 control-label">价格</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="price" placeholder="请输入商品价格">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-1 col-sm-3">
<button type="submit" class="btn btn-default">提交</button>
</div>
</div>
</form>
- 处理中文乱码——》web.xml配置——》filter与filter-mapping标签
- 静态资源(如css,image)没有加载进来——》被配置的总指挥拦截了——》再配置ServletMapping,使得所有静态资源被默认的Servlet捕获
<servlet-name>default</servlet-name>
//处理中文乱码
<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>
//处理静态资源未加载问题
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>