SpringMVC是Spring家族的一员,Spring是将现在开发中流行的组件进行组合而成的一个框架!它用在 基于MVC的表现层开发,类似于struts2框架
我们在之前已经学过了Struts2这么一个基于MVC的框架....那么我们已经学会了Struts2,为啥要要学习SpringMVC呢???
下面我们来看一下Struts2不足之处:
基于这么一些原因,并且业内现在SpringMVC已经逐渐把Struts2给替代了...因此我们 学习SpringMVC一方面能够让我们跟上业界的潮流框架,一方面SpringMVC确实是非常好用 !
可以这么说, Struts2能做的东西,SpringMVC也能够做 ....
在Struts2中,我们的开发特点是这样的:
前6个是Spring的核心功能包【IOC】,第7个是关于web的包,第8个是SpringMVC包
Action实现Controller接口
public class HelloAction implements Controller { @Override public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception { return null; } }
我们只要 实现handleRequest方法即可 ,该方法已经说了request和response对象给我们用了。这是我们非常熟悉的request和response对象。然而该方法返回的是ModelAndView这么一个对象,这是和Struts2不同的。Struts2返回的是字符串,而SpringMVC返回的是ModelAndView
ModelAndView其实他就是 将我们的视图路径和数据封装起来而已【我们想要跳转到哪,把什么数据存到request域中,设置这个对象的属性就行了】 。
public class HelloAction implements Controller { @Override public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception { ModelAndView modelAndView = new ModelAndView(); //跳转到hello.jsp页面。 modelAndView.setViewName("/hello.jsp"); return modelAndView; } }
在Struts2中,我们想要使用Struts2的功能,那么就得在web.xml文件中配置过滤器。而我们使用SpringMVC的话,我们是在web.xml中配置核心控制器
<!-- 注册springmvc框架核心控制器 --> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--到类目录下寻找我们的配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:hello.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <!--映射的路径为.action--> <url-pattern>*.action</url-pattern> </servlet-mapping>
我们在hello.xml配置文件中把SpringMVC的控制器创建出来
<!-- 注册控制器 name属性的值表示的是请求的路径【也就是说,当用户请求到/helloAction时,就交由HelloAction类进行处理】 --> <bean class="HelloAction" name="/hello.action"></bean>
当我们在浏览器访问 http://localhost:8080/hello.action
的时候,Spring会读取到我们的访问路径,然后对比一下我们的配置文件中是否有配置 /hello.action
,如果有。那么就交由对应的Action类来进行处理。Action类的业务方法将其请求输出到hello.jsp页面上。
上面的工作流程中, 我们是没有讲过映射器,适配器,视图解析器这样的东西的。但是SpringMVC的环境还是被我们搭建起来了。
下面就由我来一个一个来介绍他们是有什么用的!
我们在web.xml中配置规定 只要是.action为后缀的请求都是会经过SpringMVC的核心Servlet 。
当我们接收到请求的时候,我们发现是hello.action,是会经过我们的核心Servlet的,那么 核心Servlet就会去找有没有专门的Action类来处理hello.action请求的 。
也就是说: 映射器就是用于处理“什么样的请求提交给Action”处理 。 【默认可省略的】 .....
其实我们在快速入门的例子已经配置了: name属性就是规定了hello.action到HelloAction控制器中处理 !
<!-- 注册控制器 name属性的值表示的是请求的路径【也就是说,当用户请求到/helloAction时,就交由HelloAction类进行处理】 --> <bean class="HelloAction" name="/hello.action"></bean>
映射器默认的值是这样的:
<!-- 注册映射器(handler包)(框架)【可省略】 --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> </bean>
当然了,上面我们在创建控制器的时候【也就是HelloAction】可以不使用name属性来指定路径,可以使用我们的映射器来配置。如以下的代码:
<bean class="HelloAction" id="helloAction"></bean> <!-- 注册映射器(handler包)(框架) --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.action">helloAction</prop> </props> </property> </bean>
当我们需要多个请求路径都交由helloAction控制器来处理的话,我们只要添加prop标签就行了!
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.action">helloAction</prop> <prop key="/bye.action">helloAction</prop> </props> </property> </bean>
当我们映射器找到对应的Action来处理请求的时候,核心控制器会 让适配器去找该类是否实现了Controller接口 。 【默认可省略的】
也就是说: 适配器就是去找实现了Controller接口的类
<!-- 适配器【可省略】 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
我们把结果封装到ModelAndView以后,SpringMVC会使用视图解析器来对ModelAndView进行解析。 【默认可省略的】
也有一种情况是不能省略的。 我们在快速入门的例子中,将结果封装到ModelAndView中,用的是绝对真实路径 !如果我们用的是逻辑路径,那么就必须对其配置,否则SpringMVC是找不到对应的路径的。
那什么是逻辑路径呢??? 我们在Struts2中,返回的是"success"这样的字符串,从而跳转到success.jsp这样的页面上。我们就可以把"success"称作为逻辑路径 。
在Action中返回hello, hello是一个逻辑路径。需要我们使用视图解析器把逻辑路基补全
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception { ModelAndView modelAndView = new ModelAndView(); //跳转到hello.jsp页面。 modelAndView.setViewName("hello"); return modelAndView; }
如果不使用视图解析器的话,那么就会找不到页面:
因此,我们需要配置视图解析器
<!-- 如果Action中书写的是视图逻辑名称,那么视图解析器就必须配置 如果Action中书写的是视图真实名称,那么视图解析器就可选配置 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 路径前缀 --> <property name="prefix" value="/"/> <!-- 路径后缀 --> <property name="suffix" value=".jsp"/> <!-- 前缀+视图逻辑名+后缀=真实路径 --> </bean>
我们在之前使用Struts2的时候, 如果仅仅要跳转到某个WEB-INF/JSP页面,也要写业务方法。而业务方法也仅仅是返回一个简单的字符串。
如下的代码:
public String home(){ return "home"; }
<package name="nsfw-home" namespace="/nsfw" extends="struts-default"> <action name="nsfw_*" class="zhongfucheng.nsfw.HomeAction" method="{1}"> <result name="{1}">/WEB-INF/jsp/nsfw/{1}.jsp</result> </action> </package>
在SpringMVC中,如果仅仅是跳转到某个视图上,我们可以省略该Action和业务方法。 配置的Action只要继承着ParameterizableViewController这个类就行了 !
<!-- 专用于jsp到jsp/html的转发控制器 --> <bean name="/ok.action" class="org.springframework.web.servlet.mvc.ParameterizableViewController"> <!-- 转发到真实视图名 --> <property name="viewName" value="/WEB-INF/ok.jsp"/> </bean>
到目前为止,我们都没有将SpringMVC是怎么接收web端传递过来的参数的。
我们在Struts2中,只要在Action类上写对应的成员变量,给出对应的set和get方法。那么Struts2就会帮我们把参数封装到对应的成员变量中,是非常方便的。
那么我们在SpringMVC中是怎么获取参数的呢????我们是 将Action继承AbstractCommandController这么一个类的。
public class HelloAction extends AbstractCommandController { @Override protected ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, BindException e) throws Exception { return null; } }
在讲解该控制器之前,首先我们要明白SpringMVC控制器一个与Struts2不同的地方: SpringMVC的控制器是单例的,Struts2的控制器是多例的 !
也就是说: Struts2收集变量是定义成员变量来进行接收,而SpringMVC作为单例的,是不可能使用成员变量来进行接收的【因为会有多个用户访问,就会出现数据不合理性】 !
那么SpringMVC作为单例的, 他只能通过方法的参数来进行接收对应的参数 ! 只有方法才能保证不同的用户对应不同的数据 !
实体的属性要和web页面上的name提交过来的名称是一致的。这和Struts2是一样的!
public class User { private String id; private String username; public User() { } public User(String id, String username) { this.id = id; this.username = username; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String toString() { return "User{" + "id='" + id + '/'' + ", username='" + username + '/'' + '}'; } }
<form action="${pageContext.request.contextPath}/hello.action" method="post"> <table align="center"> <tr> <td>用户名:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>编号</td> <td><input type="text" name="id"></td> </tr> <tr> <td colspan="2"> <input type="submit" value="提交"> </td> </tr> </table> </form>
<bean class="HelloAction" id="helloAction"></bean> <!-- 注册映射器(handler包)(框架) --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.action">helloAction</prop> </props> </property> </bean>
public class HelloAction extends AbstractCommandController { /*设置无参构造器,里边调用setCommandClass方法,传入要封装的对象*/ public HelloAction() { this.setCommandClass(User.class); } /** * * @param httpServletRequest * @param httpServletResponse * @param o 这里的对象就表示已经封装好的了User对象了。! * @param e * @return * @throws Exception */ @Override protected ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, BindException e) throws Exception { User user = (User) o; System.out.println(user); ModelAndView modelAndView = new ModelAndView(); //跳转到ok.jsp modelAndView.setViewName("/WEB-INF/ok.jsp"); //将数据封装到ModelAndView中 modelAndView.addObject("USER", user); return modelAndView; } }
Struts2和SpringMVC存值的区别:
如果文章有错的地方欢迎指正,大家互相交流。 习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y