问题?SpringMvc学习与使用 SpringMvc的运行流程 SpringMvc是什么? SpringMvc作用是什么? SpringMvc相比其他框架有什么优势?
一、SpringMvc是什么?
Spring MVC属于SpringFrameWork的后续产品,Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块,使用 Spring 可插入的 MVC架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架。说白了它是基于spring在MVC上的一个框架。
二、SpringMvc的作用是什么?
框架的作用都是为了提高代码的质量,也就是高质量的代码,而不是提高代码的性能。各种框架都有各自的性能,各不相同各自有可取之处也有不可取之处。当然,springmvc也有它的优势,它的处理器映射机制、控制器、分发器、处理各个程序之间的处理机制,变得非常容易。
三、SpringMvc相比其他框架有什么优势?
打个比较,就s2sh框架和springmvc框架的比较来看,SSH框架的系统从职责上分为四层:表示层、业务逻辑层、数据持久层和域模块层,以帮助开发人员在短期内搭建结构清晰、可复用性好、维护方便的Web应用程序。
SpringMVC和SSH的比较:
springmvc比较接近原生servlet,灵活度高。而且因为springmvc的controller是单例的,以及没有大量的过滤器,性能要比struts2好。SSH中操作数据库使用的是Hibernate的数据映射,操作的是对象。Hibernate本来就是基于JDBC的封装,所以较之执行原生态SQL效率上肯定比操作对象更快。还有最重要的一点就是springmvc开发起来更加便利,或许在总体性能上来说,不算是最好的。
Struts1使用JSTL EL表达式,但是对集合和索引属性的支持很弱。Struts2采用OGNL。
struts2是类级别的拦截, 一个类对应一个request上下文,springmvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应。
Strust1中通常以action访问时.do,struts2、spring mvc 都是以.action做结尾。
spring3 mvc可以认为已经100%零配置了。
注意它是如何保证安全的:springmvc controller是单例模式,整个程序只有一个对象实例。Spring的安全性是通过绑定threadlocal实现
注意:如果想使用Spring来实现Hibernate的功能,那么可以知己封装
四、SpringMvc的运行流程
1.struts2与springmvc的比较
Stuts2类级别,例如:model,request,response,类中所有的方法都共享
Struts2使用model对象来从页面封装参数到action;从action封装数据到页面;(双向)
SpringMVC方法级别,例如:model(MAP),只从action封装数据到页面(单向:但是springmvc有办法解决)
从这里就可以看出,springmvc的速度空前的强。
2.springmvc的工作原理(Struts和springmvc工作原理图比较)
springmvc:Jsp——>DispatcherServlet分发器——>通过handlerMapping处理器映射找到要处理的controller层——>最后处理完返回结果(newModelAndView)并通过视图解析器找到返回路径——>回到Jsp
3.springmvc的核心知识点儿
(1)分发器DispacherServlet是什么,它的作用是什么?
(2)处理器映射handlerMapping是什么?它的工作原理是什么?
(3)如何找到逻辑controller层,有哪几种方式?
(4)试图解析器是ViewResolver什么?如何构造?
4.常用的handlerMapping处理器映射
作用:分发器发过来的请求,通过该处理器映射找到对应的controller层的类及方法,这就是它的作用
1.第一种:BeanNameUrlHandlerMapping(默认)
2.第二种:SimpleUrlHandlerMapping(通过ID访问)
3.第三种:ControllerClassNameHandlerMapping(通过类名访问)
5.常用的控制器有哪些?
1.命令控制器
2.表单控制器
3.向导表单控制器
五、SpringMvc的使用
1.开发步骤,简单体验最简单的springmvc:
(1)、新建web project
(2)、引入jar包
(3)、配置分发器servlet DispatchServlet
(4)、创建控制器类
(5)、配置beans
(6)、创建jsp文件
(7)、发布、测试
jar包下载:Spring-framework官网下载地址:点击打开链接 本地下载还有案例:点击打开链接
当然如果怕出现错误:你把spring-freamwork的所有包的全部导进去,绝对没问题。
在web.xml中配置分发器:
<servlet> <servlet-name>action</servlet-name><!-- servlet-name和配置文件的前面名字相同 --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.action</url-pattern><!-- 这里不能换成/*,会出错的 --> </servlet-mapping>
package cn.itcast.com.controler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; public class HomeController extends AbstractController{ @Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { // TODO Auto-generated method stub System.out.println(request.getParameter("username")); System.out.println(request.getRequestURI()); System.out.println(request.getRequestURL()); return new ModelAndView("customer/form1");//这里就是逻辑名 } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 1.配置handlerMapping处理器映射 --> <!-- 默认:BeanNameUrlHandlerMapping,所以不用配置这个的话, 它会找bean的name属性值访问,但是只能找一个,有缺陷) ,在没有配置其他三个映射之前,配不配都一样--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" </bean> <!-- 配置Controller,检测三个处理器映射--> <bean id="controller1" name="/home.action" class="cn.itcast.com.controler.HomeController"></bean> <!-- 内部资源视图解析器 ViewResolver,由它来解析ModelAndView返回的逻辑名--> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 规则:前缀+逻辑名+后缀 /WEB-INF/pages/index.jsp ,因为逻辑名在controller哪里已经写了,就不用写 了--> <property name="prefix" value="/WEB-INF/page/" /> <property name="suffix" value=".jsp"></property> </bean> </beans>
其实springmvc的处理过程就是那么简单,不难.
2.介绍三个处理器映射
保持controller层不变,这里主要介绍,可以通过几种处理器来找controller层:
(1)BeanNameUrlHandlerMapping(默认):这个上面一句介绍了,它是通过name属性找类的
(2)SimpleUrlHandlerMapping(需要配置):通过ID号找类
<!--2. SimpleUrlHandlerMapping: a.action,b.action,c.action 支持多个访问映射到同一个controller,找bena的ID值来访问,下面那个controller1就是ID--> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/a.action">controller1</prop> <prop key="/b.action">controller1</prop> <prop key="/home.action">controller1</prop> </props> </property> <property name="order" value="1"></property> </bean>
(3)ControllerClassNameHandlerMapping(需要配置): 通过Controller的类名来访问到相应的controller类
<!-- 3.ControllerClassNameHandlerMapping : 通过controller类名进行访问的 (因为实例了,所以访问的时候类名第一个字母是小写其他都一样, 还有一种是可以写小写的前面几个字母)--> <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"> <property name="order" value="0"></property> </bean>
如: http://localhost:8080/SpingMvcEg1/home.action?username=1234
http://localhost:8080/SpingMvcEg1/homeController.action?username=1234
(这里就有一个问题了,跟默认的那个找name相同了,那么它是通过那个呢?这就是上面设置<propertyname="order" value="0"></property>来控制优先级的问题了,看代码即可)
默认顺序是一下顺序,通过控制优先级可以改变:
3.改变一下配置文件action-servlet.action,看看源码我们就知道,为什么是这个名字了
在DispatcherServlet extends FrameworkServlet的父类FranmeworkServlet中的以下东西,组成了这个配置文件的名字。
重点: public static final StringDEFAULT_NAMESPACE_SUFFIX = " -servlet ";
改变一下,通常这样spring配置文件我们都是放在src下面的,我们也可以改变一下它的名字(但是要配置才能)
web.xml配置:
<servlet> <servlet-name>action</servlet-name><!-- servlet-name和配置文件的前面名字相同 --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name><!-- 这里的名字可不是随便去的,源码中决定的 --> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
在dispacterServlet的父类org.springframework.web.servlet.FrameworkServlet中有这样一个路径设置set方法,只需要在web.xml中配置contextConfigLocation即可。
4.介绍几种常见控制器Controller
(1).CommandController命令控制器,就做到了jsp页面封装数据到实体类。
实体类:
package cn.itcast.com.domain; import java.io.Serializable; public class Customer implements Serializable{ private String username; private String password; private Integer age; public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Customer [username=" + username + ", password=" + password + ", age=" + age + "]"; } }
在原来的工程上,新建controller类:MyCommendController.java
package cn.itcast.com.controler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.validation.BindException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractCommandController; import cn.itcast.com.domain.Customer; //AbstractCommandController这是命令控制器 public class MyCommendController extends AbstractCommandController{ //在默认的构造器中设置 public MyCommendController() { // TODO Auto-generated constructor stub //告诉spingmvc,我给command封装的是这个Customer实体类对象 this.setCommandClass(Customer.class); } @Override protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { // TODO Auto-generated method stub //Object command: //BindException errors: Customer customer = (Customer) command; System.out.println(customer.toString()); return null; } }
<!-- 配置CommandController命令控制器 --> <bean class="cn.itcast.com.controler.MyCommendController"></bean>
http://localhost:8080/SpingMvcEg1/mycommendController.action?username=1234&password=123&age=2
(2).表单控制器
MyFormController.java
package cn.itcast.com.controler; import org.springframework.web.servlet.mvc.SimpleFormController; import cn.itcast.com.domain.Customer; public class MyFormController extends SimpleFormController{ public MyFormController(){ this.setCommandClass(Customer.class); } //当以get方式提交的时候,会直接跳转jsp页面而不会触发doSubmitAction方法,在web.xml中设置 //以form表单post提交的时候,会自动调用doSubmitAction方法,自动封装到实体类 @Override protected void doSubmitAction(Object command) throws Exception { // TODO Auto-generated method stub Customer customer = (Customer)command; System.out.println(customer.toString()); } }
<!-- 配置表单控制器 --> <!-- 说明:因为视图解析器已经把前缀和后缀已经配置好了,所以只需要逻辑名即可 --> <!-- formView:form视图 --> <!-- successView:成功视图 --> <bean class="cn.itcast.com.controler.MyFormController"> <property name="formView" value="customer/form1"></property> <property name="successView" value="index"></property> </bean>
再填写数据,提交到成功页面了。
(3).向导表单控制器
在业务系统中,有时用户要填写的内容很多。51job填写简历,基本信息,教育经历,工作经历。分开填写,加入前面感觉需要修改,但是数据不能丢失(数据回显),可以在原来的基础上进行修改。
做一个例子,如下效果:
inf.jsp
<span style="font-family:Microsoft YaHei;"> <form action="${pageContext.request.contextPath }/mywizardController.action" method="post"> <table> <tr> <td>USER:</td> <td><input type="text" name="username" value="${customer.username }"></td> </tr> <tr> <td><input type="submit" value="下一页" name="_target1"></td> <td><input type="submit" value="取消" name="_cancel"></td> </tr> </table></span>
<span style="font-family:Microsoft YaHei;"> <form action="${pageContext.request.contextPath }/mywizardController.action" method="post"> <table> <tr> <td>PASS:</td> <td><input type="text" name="password" value="${customer.password }"></td> </tr> <tr> <td><input type="submit" value="上一页" name="_target0"></td> <td><input type="submit" value="下一页" name="_target2"></td> <td><input type="submit" value="取消" name="_cancel"></td> </tr> </table> </form></span>
<span style="font-family:Microsoft YaHei;"><form action="${pageContext.request.contextPath }/mywizardController.action" method="post"> <table> <tr> <td>AGE:</td> <td><input type="text" name="age" value="${customer.age }"></td> </tr> <tr> <td><input type="submit" value="上一页" name="_target1"></td> <td><input type="submit" value="取消" name="_cancel"></td> <td><input type="submit" value="完成" name="_finish"></td> </tr> </table> </form></span>
<span style="font-family:Microsoft YaHei;">package cn.itcast.com.controler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.validation.BindException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractWizardFormController; import cn.itcast.com.domain.Customer; /*3、向导表单控制器*/ public class MyWizardController extends AbstractWizardFormController { public MyWizardController() { // TODO Auto-generated constructor stub this.setCommandClass(Customer.class); //回显数据的保存,这是关键的地方: this.setCommandName("customer"); } //成功完成 @Override protected ModelAndView processFinish(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { // TODO Auto-generated method stub Customer customer =(Customer) command; System.out.println(customer.toString()); return new ModelAndView("index"); } //取消,转向第一个页面重新填写 @Override protected ModelAndView processCancel(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { // TODO Auto-generated method stub return new ModelAndView("/wizard/Inf"); } } </span>
springmvc-servlet.xml文件
<span style="font-family:Microsoft YaHei;"> <!-- 配置向导表单控制器 --> <!-- 按着list顺序执行,这个效果就有点儿像前面的感觉错了,想要回去一步,重新填写,但是要数据回显,这个向导表单就做这个事情 --> <bean class="cn.itcast.com.controler.MyWizardController"> <property name="pages"> <list> <value>wizard/Inf</value> <value>wizard/Edu</value> <value>wizard/Work</value> </list> </property> </bean></span>
试一试填写信息,分别上一步,下一步,取消,提交。看看效果
六、注解形式开发
1.注解开发
在sprimgmvc3.0之后,它就全面支持
前面的,写一个类就得在配置文件写bean,很麻烦都体现不出spring的强大之处。用注解的形式进行开发
加必须的jar包,springmv-servlet.xml文件放在src下面,web.xml文件写分发器及spring文件的路径配置,都写好
写一个controller类:HomeController.java,开始运用注解
package com.itcast.control; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HomeController { //1.逻辑处理 //2.跳转页面 @RequestMapping("home.action") //访问的URL public String goHome(HttpServletRequest request){ System.out.println(request.getParameter("user")); System.out.println(request.getRequestURI()); return "index"; //逻辑名称,通过视图解析器ViewResolver拼接,找到跳转地址 } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 对所有的Controller包进行扫描 --> <context:component-scan base-package="com.itcast.control"/> <!-- 内部资源视图解析器 ViewResolver,由它来解析ModelAndView返回的逻辑名--> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 规则:前缀+逻辑名+后缀 /WEB-INF/pages/index.jsp ,因为逻辑名在controller哪里已经写了,就不用写 了--> <property name="prefix" value="/WEB-INF/page/" /> <property name="suffix" value=".jsp"></property> </bean> <!-- 配置文件上传的视图解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"></property><!-- 10M --> </bean> </beans>
配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <!-- 管理spring容器 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 管理springmvc --> <servlet> <servlet-name>action</servlet-name><!-- servlet-name和配置文件的前面名字相同 --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
http://localhost:8080/SpringMvcNoteEg1/home.action?user=李三
2.springmvc自定义的标签库使用
Struts2标签非常丰富,远远超过springmvc
案例中有详细说明
3.文件上传
它的功能跟struts2,案例中有详细说明
4.拦截配置
" *.action "拦截所有URL后缀action资源 , "/" 拦截所有URL请求,包括action,静态资源js/iimages/css
这样就会导致静态资源不会被放行,但是有办法解决,在springmvc-servlet.xml中配置<!-- 静态资源配置 location:共享资源路径 mapping:资源映射 **=子目录+资源-->
<mvc:resources location="/image/" mapping="/image/**"/>
5.集群认识
Apache+tomcat(集群) NGnix+tomcat(集群)
静态资源交给Apache/Ngnix解决,而动态资源则交给tomcat管理了。
Apache比tomcat解析资源速度差不多快10倍左右。Ngnix比Apache快100倍左右。大型网站,几乎38%都 是用Ngnix
动静分离时,至少将*.action交给springmvc管理
六、总结
就是以上知识点,多多打代码即可。