Spring MVC教程——检视阅读css
参考html
Spring MVC教程——一点——蓝本前端
Spring MVC教程——c语言中午网——3.0版本太老了vue
Spring MVC教程——易百——4.0版本不是经过maven建立的java
Spring MVC教程——javaschool纯理论mysql
Spring MVC应用——javaschool纯理论react
Spring MVC学习总结jquery
Spring MVC 4.2.4.RELEASE 中文文档——基础学习后看git
SpringMVC面试题程序员
目前大多数使用的是spring4.x.
springboot基于 Spring Framework 5.0 on JDK 8 & 9
Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。
什么是MVC
MVC是一个架构,或者说是一个设计模式,它就是强制性使应用程序的输入,处理和输出分开。将一个应用程序分为三个部分:Model,View,Controller。
原理图 :
Model模型:负责完成业务逻辑:由JavaBean构成,在MVC的三个部件中,模型拥有最多的处理任务。例如它可能用像EJB和javabean这样的构件对象来处理数据库。因为应用于模型的代码只需写一次就能够被多个视图重用,因此减小了代码的重复性。
View视图:就是负责跟用户交互的界面。通常就是由HTML,css元素组成的界面,固然如今还有一些像js,ajax,flex一些也都属于视图层。 在视图层里没有真正的处理发生,只负责数据输出,并容许用户操纵的方式。MVC能为应用程序处理不少不一样的视图。
Controller控制器:负责接收请求—>调用模型—>根据结果派发页面并通过模型处理返回相应数据。
MVC的优势
一、分工明确:使用MVC能够把数据库开发,程序业务逻辑开发,页面开发分开,每一层都具备相同的特征,方便之后的代码维护。它使程序员能够集中精力于各自的模型开发领域。
二、松耦合:视图层和业务层分离,这样就容许更改视图层代码而不用从新编译模型和控制器代码,一样,一个应用的业务流程或者业务规则的改变只须要改动MVC的模型层便可。由于模型与控制器和视图相分离,因此很容易改变应用程序的数据层和业务规则。
三、复用性高(利于各层逻辑的复用):像多个视图可以共享一个模型,不论你视图层是用flash界面或是wap界面,用一个模型就能处理他们。将数据和业务规则从表示层分开,就能够最大化从用代码。
四、有利于标准化.
MVC的缺点
一、有时会致使级联的修改。这种修改尤为体如今自上而下的方向。若是在表示层中须要增长一个功能,为保证其设计符合分层式结构,可能须要在相应的业务逻辑层和数据访问层中都增长相应的代码。
二、下降了系统的性能。这是不言而喻的。若是不采用分层式结构,不少业务能够直接造访数据库,以此获取相应的数据,现在却必须经过中间层来完成。
三、增长理解的复杂度。因为它没有明确的定义,因此彻底理解MVC并非很容易。
常见的MVC框架
常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常见前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另一些模式如:MVP、MVVM。
什么是Spring MVC
Spring MVC概述
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。Spring MVC的特色:
Spring MVC功能
Spring MVC围绕DispatcherServlet设计。 DispatcherServlet的做用是将请求分发到不一样的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户能够采用基于注解的Controller声明方式。官网上说Spring的Web模块提供了大量独特的功能,包括:
Spring MVC 快速入门
示例:
一、能够经过module建立工程,再经过"JBLJavaToWeb"插件把Java项目改成Web项目。
二、直接maven建立一个webapp工程,再添加对应的文件夹和包。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.self</groupId> <artifactId>hellospringmvc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <!--SpringMVC依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies> </project>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置核心控制器 :DispatcherServlet --> <servlet> <servlet-name>hellospringmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- springmvc配置文件加载路径 1)默认状况下,读取WEB-INF下面的default-servlet.xml文件 2)能够改成加载类路径下(resources目录),加上classpath: --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/hellospringmvc-servlet.xml</param-value> </init-param> <!--init-param必须放在load-on-startup前,不然会报错:invalid content was found starting with element 'init-param'. One of '{"http://java.sun.com/xml/ns/javaee":run-as, "http://java.sun.com/xml/ns/javaee":security-role-ref}' is expected--> <!-- DispatcherServlet对象建立时间问题 1)默认状况下,第一次访问该Servlet时建立对象,默认是访问时建立,意味着在这个时间才去加载hellospringmvc-servlet.xml 2)能够改变为在项目启动时候就建立该Servlet,提升用户访问体验。 <load-on-startup>1</load-on-startup> 数值越大,对象建立优先级越低! (数值越低,越先建立) --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hellospringmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
注意事项:
hellospringmvc-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.扫描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.开启mvc注解驱动--> <!--不添加也能使用,高版本spring已经默认实现了。 在Spring中通常采用@RequestMapping注解来完成映射关系,要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例,这两个实例分别在类级别和方法级别处理。而<mvc:annotation-driven/>配置帮助咱们自动完成上述两个实例的注入。 --> <!--<mvc:annotation-driven/>--> </beans>
Controller控制器
控制器类是开发Spring MVC程序过程写的最多的类了。控制器类一般叫Controller,在里面编写接收参数,调用业务方法,返回视图页面等逻辑。
@Controller注解是为了让Spring IOC容器初始化时自动扫描到该Controller类;@RequestMapping是为了映射请求路径,这里由于类与方法上都有映射因此访问时应该是/hello;方法返回的结果是视图的名称success,该名称不是完整页面路径,最终会通过视图解析器解析为完整页面路径并跳转。
@Controller public class HelloController { @RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello Spring MVP</title> </head> <body> <h1>Hello Spring MVPPPPPPPPPPPPPPPPPPPPPP!</h1> </body> </html>
请求:http://localhost:8080/hellospringmvc/hello
输出:
报错:
一、UnsupportedClassVersionError : Unsupported major.minor version 52.0 。
报错以下。
Caused by: java.lang.UnsupportedClassVersionError: org/springframework/web/SpringServletContainerInitializer : Unsupported major.minor version 52.0 (unable to load class org.springframework.web.SpringServletContainerInitializer)
A:这是由于JDK版本太低了,spring5.X要求JDK版本要8及以上,目前配置的是JDK7,版本不符合要求了。换成JDK8便可。
二、请求404,获取/hellospringmvc/WEB-INF/pagessuccess.jsp 没有结果。
报错以下:
A:这是由于在配置springmvc配置文件hellospringmvc-servlet.xml时配置视图解析器没配置好,很明显确实了/斜杠分隔符。这视图解析器视图根据先后缀来拼接jsp视图的路径时因为前缀少了斜杠而致使映射路径不对,加上便可,在新增jsp视图时也要按照格式规范在/WEB-INF/pages/路径下添加jsp页面,不然会致使视图解析器拼接时报错。
<!-- 2.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean>
Spring MVC 执行流程分析
Spring MVC执行流程图
关键组件分析
Spring MVC 三大组件
处理映射器
处理映射器做用
经过处理器映射,你能够将Web 请求映射到正确的处理器 Controller 上。当接收到请求时,DispactherServlet 将请求交给 HandlerMapping 处理器映射,让他检查请求并找到一个合适的HandlerExecutionChain,这个HandlerExecutionChain 包含一个能处理该请求的处理器 Controller。而后,DispactherServlet 执行在HandlerExecutionChain 中的处理器 Controller。
Spring内置了许多处理器映射策略,目前主要由三个实现。
SimpleUrlHandlerMapping、 BeanNameUrlHandlerMapping RequestMappingHandlerMapping。 //注意:Spring MVC3.1以前使用DefaultAnnotationHandlerMapping,Spring MVC3.1以后改成RequestMappingHandlerMapping。
1)SimpleUrlHandlerMapping
SimpleUrlHandlerMapping 在应用上下文中能够进行配置,而且有Ant风格的路径匹配功能。例如咱们在springmvc.xml 中配置一个SimpleUrlHandlerMapping 处理器映射。
实例:
simple-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立SimpleUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello">simpleController</prop> <!--若是有更多的请求映射就在这边添加映射配置--> </props> </property> </bean> <!--2.建立Controller对象--> <bean id="simpleController" class="com.self.controller.SimpleController"/> <!--每一个请求Controller或者说Handler就要配置一个bean对象--> <!-- 3.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 3.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 3.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> </beans>
web.xml
<init-param> <param-name>contextConfigLocation</param-name> <!--<param-value>WEB-INF/hellospringmvc-servlet.xml</param-value>--> <param-value>WEB-INF/simple-servlet.xml</param-value> </init-param>
SimpleController
//实现org.springframework.web.servlet.mvc.Controller接口的handleRequest方法 public class SimpleController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("----------SimpleController-----handleRequest---------------"); ModelAndView mv = new ModelAndView("success"); return mv; } }
pom.xml
<!--servlet依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
报错:
一、@Override is not allowed when implementing interface method
A:这是由于idea的java编译设置中设置的是jdk1.5的,跟编译器版本问题有关。编译器1.5只支持@Override注释重写父类方法,不支持实现接口方法。将language level设置高于jdk1.5版本便可 。
参考
2)BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping 将收到的Http请求映射到bean的名字上。
示例:
beanname-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立Controller对象,这里的id必须页面访问的路径(以斜杠开头)--> <!--若是要继续添加映射只要在这里配置好映射路径和注册bean便可--> <bean id="/hello" class="com.self.BeanNameController"/> <!-- 3.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 3.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 3.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> </beans> //实现org.springframework.web.servlet.mvc.Controller接口的handleRequest方法 public class BeanNameController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("----------BeanNameController-----handleRequest---------------"); ModelAndView mv = new ModelAndView("success"); return mv; } }
pom.xml
<!--servlet依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
web.xml
<init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/beanname-servlet.xml</param-value> <!--<param-value>WEB-INF/hellospringmvc-servlet.xml</param-value>--> </init-param>
请求:http://localhost:8080/hellospringmvc/hello
注意:在bean的id中要加上斜杆,Controller的代码跟前面的SimpleUrlHandlerMapping同样,实现Controller,重写handlerRequest()方法便可。
在默认状况下,若是没有在上下文中没有找处处理器映射,DispactherServlet 会为你建立一个BeanNameUrlHandlerMapping。
3)RequestMappingHandlerMapping
RequestMappingHandlerMapping是三个中最经常使用的HandlerMapping,由于注解方式比较通俗易懂,代码界面清晰,只须要在代码前加上@RequestMapping()的相关注释就能够了 。
实例:
@Controller public class HelloController { //@RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
hellospringmvc-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.扫描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.开启mvc注解驱动--> <!--不添加也能使用,高版本spring已经默认实现了。 在Spring中通常采用@RequestMapping注解来完成映射关系,要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例,这两个实例分别在类级别和方法级别处理。而<mvc:annotation-driven/>配置帮助咱们自动完成上述两个实例的注入。 --> <!--<mvc:annotation-driven/>--> </beans>
注意:重点是添加mvc:annotation-driven/标签! 这个要在有其余HandlerMapping接口的状况下才须要。
处理适配器
处理器适配器做用
HandlerAdapter字面上的意思就是处理适配器,它的做用就是调用具体的方法对用户发来的请求来进行处理。当HandlerMapping获取到执行请求的Controller时,DispatcherServlte会根据Controller对应的Controller类型来调用相应的HandlerAdapter来进行处理。
HandlerAdapter的实现有:
1)HttpRequestHandlerAdapter
HttpRequestHandlerAdapter能够处理类型为HttpRequestHandler的handler,对handler的处理是调用HttpRequestHandler的handleRequest()方法。
示例:
public class HttpRequestHandlerController implements HttpRequestHandler{ @Override public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { //HttpRequestHandlerAdapter用来处理HttpRequestHandler类型的Controller //注意该类型Controller都没有ModelAndView,至关于servlet httpServletResponse.getWriter().write("Hello HttpRequestHandler."); } }
httprequesthandler-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立HttpRequestHandlerAdapter,用来处理HttpRequestHandler类型的Controller--> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/> <!--3.建立Controller对象,这里的id必须页面访问的路径(以斜杠开头)--> <!--若是要继续添加映射只要在这里配置好映射路径和注册bean便可--> <bean id="/hi" class="com.self.HttpRequestHandlerController"/> </beans>
输出:
报错:The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler 。
A:这是由于建立HttpRequestHandlerAdapter,用来处理HttpRequestHandler类型的Controller,而public class BeanNameController implements Controller 不是HttpRequestHandler类型的Controller,处理不了,因此报错,应该换上合适的HandlerAdapter,如RequestMappingHandlerAdapter。
2)SimpleServletHandlerAdapter
SimpleServletHandlerAdapter能够处理类型为Servlet,就是把Servlet当作Controller来处理,使用Servlet的service方法处理用户请求。 业务Controller继承HttpServlet 实现doGet()或doPost()方法。
示例:
public class SimpleServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //SimpleServletHandlerAdapter用来处理HttpServlet类型的Controller resp.getWriter().write("Hello HttpServlet."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
httpservletHandler-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立SimpleServletHandlerAdapter--> <bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/> <!--3.建立Controller对象,这里的id必须页面访问的路径(以斜杠开头)--> <!--若是要继续添加映射只要在这里配置好映射路径和注册bean便可--> <bean id="/hi" class="com.self.SimpleServlet"/> </beans>
输出:
3)SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter能够处理类为Controller的控制器,使用Controller的handlerRequest方法处理用户请求。
beanname-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立Controller对象,这里的id必须页面访问的路径(以斜杠开头)--> <!--若是要继续添加映射只要在这里配置好映射路径和注册bean便可--> <bean id="/hi" class="com.self.BeanNameController"/> <!-- 3.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 3.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 3.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> <!--默认不配置SimpleControllerHandlerAdapter, 也能处理Controller类型为org.springframework.web.servlet.mvc.Controller的接口, SimpleControllerHandlerAdapter会默认注册--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> </beans> //实现org.springframework.web.servlet.mvc.Controller接口的handleRequest方法 public class BeanNameController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("----------BeanNameController-----handleRequest---------------"); ModelAndView mv = new ModelAndView("success"); return mv; } }
4)RequestMappingHandlerAdapter
RequestMappingHandlerAdapter能够处理类型为HandlerMethod的控制器,经过Java反射调用HandlerMethod的方法来处理用户请求。
补充:类型为HandlerMethod的控制器是在容器初始化时,经过RequestMappingHandlerMapping在添加映射时把咱们写业务Controller转化为HandlerMethod类型,存储在LinkedHashMap中。
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod
注意:
若是有在web.xml中配置指定的HandlerMapping 和 HandlerAdapter 的话,则只注册配置的处理器。
示例:
hellospringmvc-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.扫描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--2.建立RequestMappingHandlerMapping--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!--3.建立RequestMappingHandlerAdapter--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 4.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 4.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 4.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> </beans> @Controller public class HelloController { @RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
视图解析器
视图解析器做用
Spring MVC中的视图解析器的主要做用就是将逻辑视图转换成用户能够看到的物理视图。
流转逻辑:
当用户对SpringMVC应用程序发起请求时,这些请求都会被Spring MVC的DispatcherServlet处理,经过处理器找到最为合适的HandlerMapping定义的请求映射中最为合适的映射,而后经过HandlerMapping找到相对应的Handler,而后再经过相对应的HandlerAdapter处理该Handler。返回结果是一个ModelAndView对象,当该ModelAndView对象中不包含真正的视图,而是一个逻辑视图路径的时候,ViewResolver就会把该逻辑视图路径解析为真正的View视图对象,而后经过View的渲染,将最终结果返回给用户。
SpringMVC中处理视图最终要的两个接口就是ViewResolver和View,ViewResolver的做用是将逻辑视图解析成物理视图,View的主要做用是调用其render()方法将物理视图进行渲染。
常见的视图解析器
如下为Spring MVC提供常见视图解析器:
视图类型 说明
BeanNameViewResolver 将逻辑视图名称解析为一个Bean,Bean的Id等于逻辑视图名
InternalResourceViewResolver 将视图名解析为一个URL文件,通常使用该解析器将视图名映射为一个保存在WEB-INF目录下的程序文件,如 JSP
JaperReportsViewResolver JapserReports是基于Java的开源报表工具,该解析器解析为报表文件对应的URL
FreeMarkerViewResolver 解析为基于FreeMarker模板的模板文件
VelocityViewResolver 解析为Velocity模板技术的模板文件
VelocityLayoutViewResolver 解析为Velocity模板技术的模板文件
其中,最经常使用的是InternalResourceViewResolver,配置以下:
<!-- 4.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 4.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 4.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean>
Spring MVC 核心源码分析
DispathcerServlet属性配置
Spring MVC核心包里面有一个配置文件:DispathcerServlet.properties
E:/localwarehouse/org/springframework/spring-webmvc/5.0.2.RELEASE/spring-webmvc-5.0.2.RELEASE.jar!/org/springframework/web/servlet/DispatcherServlet.properties
该配置提供许多的默认组件,这些组件为Spring MVC的执行提供了支持,其中划线部分就是咱们以前说到的Spring MVC三大组件。
doDispatch方法源码追踪
DispatcherServlet类的层次结构 :
从Spring MVC的执行流程咱们知道,用户的请求最早到达就是DispatcherServlet,它是Spring MVC的核心,能够把它叫作中央处理器,所以咱们分析源码以前,先看看他是什么样的流程,经过源码能够看出,它是继承FrameworkServlet,它也是Spring MVC提供的类,继续往下继承关系看,FrameworkServlet继承HttpServletBean,它是Spring提供的类,最终直到到它继承HttpServlet。
DispathcerServlet既然是Servlet,那么它确定有一个service方法(Servlet最核心的方法),咱们看这个方法在哪里实现的,一个个看,发现HttpServletBean并无,在FrameworkServlet中,所以Spring实现这个serivice方法在这里实现的。
serivice()方法的做用的就是获得客户端的请求,而后判断这个请求是否是PATCH请求方式,若是不是就调用父类(HttpServlet)中的service方法,咱们调用父类这个service方法其实实际是调用该类的doGet方法或者doPost方法等等,拿到不一样的请求方式处理不一样的业务,咱们以get方式为例:
进入到processRequest方法,直接进入doService方法.跳到DispatcherServlet这个类里面来了,其实doSerivice能够猜到被子类各类重写 。
到此为止,咱们知道DispatcherServlet做为Spring MVC的核心控制器,把用户请求最终转到了它里面的doDispatch()方法来完成具体工做。
处理器映射器核心源码
在doDispathcer方法里面,首先是建立一个ModelAndView对象 = null,判断当前请求是否是二进制(文件上传)的请求。
processedRequest = this.checkMultipart(request)
再往下看代码:
mappedHandler = this.getHandler(processedRequest);
这句代码很是重要!这是根据当前请求去拿一个Handler(控制器),这个Handler其实就是咱们写的Controller类,进入到getHandler方法的源码:
有个handlerMappings的List集合,该集合存储了当前环境全部HandlerMapping对象,经过遍历该List集合,经过最合适的HandlerMapping找到Handler对象。
找到了Handler对象后,返回的是一个HandlerExecutionChain类型的Handle,这里面封装了一个HelloController,也就是咱们本身的建立Controlller,若是有配置拦截器,还会使用一个interceptors集合封装全部拦截器。
处理器适配器核心源码
doDispatcher方法咱们往下看,会到如下代码:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
Spring MVC会根据当前环境的配置和代码去选择一个合适的HandlerAdapter实现类来执行Handler。
最后,handler方法会返回ModelAndView对象。该对象交给给后面的视图解析器解析处理。
视图解析器核心源码
回到DispathcerServlet的doDispatcher方法,咱们往下走,看到这行代码:
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
这行代码包含了Spring MVC获取对应的View以及选择合适的ViewResolver解析视图的逻辑。
@RequestMapping注解
@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的全部响应请求的方法都是以该地址做为父路径。
@RequestMapping经常使用属性
value属性
指定控制器的方法URI 。
若是类和方法上都指定value值,那么方法的最终方法路径为:http://localhost:8080/hellospringmvc/say/hello
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
method属性
指定请求的method类型,能够接受GET,POST,PUT,DELETE等.
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping(value = "/hello",method = RequestMethod.GET) public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
注意:当注解有两个值时,就要有键值对对应关系,不能使用默认的值。
@RequestMapping("/hello") //注解有两个值时使用下面的写法 @RequestMapping(value = "/hello",method = RequestMethod.GET)
consumes、produces属性
consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html; produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。
@RequestMapping(value = "/hello.do",consumes = "application/json",produces = "application/json") public void hello(HttpServletRequest request,HttpServletResponse response) throws IOException { response.getWriter().write("Hello-World"); }
报错:
使用时会报415.The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.
待解决。
params、headers属性
params:指定request中必须包含某些参数值,才让该方法处理。
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
params示例:
@RequestMapping(value = "/hello",method = RequestMethod.GET,params = "id=3") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; }
输出:
headers示例:
@RequestMapping(value = "/hello.do",headers = "Referer=http://www.hello.com/") public void hello(HttpServletRequest request,HttpServletResponse response) throws IOException { response.getWriter().write("Hello"); }
Spring MVC支持对多种类型的请求参数进行封装
Spring MVC 基本类型封装
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本类型参数封装</h2> <form action="http://localhost:8080/hellospringmvc/say/helloParam"> 用户名:<input type="text" name="name"><br> 年龄:<input type="text" name="age"><br> <input type="submit" value="提交"> </form> </body> </html> @RequestMapping("/helloParam") public String helloParam(String name, Integer age) { System.out.println("用户名:" + name); System.out.println("年龄:" + age); return "success"; }
输出:
用户名:恶龙吟风 年龄:null ------------------------------ 用户名:恶龙吟风 年龄:365 ------------------------------- 用户名: 年龄:365
注意:
当接收的基本类型参数不是包装类时,如 int age,这时候要求age必须有值传进来,不然报错HTTP Status 400 -错误。The request sent by the client was syntactically incorrect. 若是是用包装类接收,如Integer age,则没有传值时age = null,String name 没有值默认空字符串 name=""
Spring MVC Post中文乱码
在Spring MVC表单若是是Post方法提交中文内容时,会出现乱码 。
这是咱们能够配置Spring MVC提供字符编码过滤器来解决问题。
配置字符编码过滤器
web.xml
<!--字符编码过滤器--> <!-- 字符编码过滤器的配置效果是当咱们没有指定请求响应的编码格式时,该字符编码过滤器会 默认以配置的编码格式去解码和编码,如配置的是utf-8--> <filter> <filter-name>characterEncodingFilter</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> <!-- 下面配置是否强制设置编码格式为指定的转换编码格式:utf-8 若是强制,则因此的请求响应都会按照utf-8来解码和编码,当请求的格式是GBK等其余编码时, 就会所以而乱码,因此通常是不配置这个选项的。 <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param>--> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
@RequestParam注解
在SpringMvc后台进行获取数据,通常有三种:
其实能够不使用@RequestParam注解,直接接收,若是不使用该注解要求controller方法中的参数名称要跟form中name名称一致,使用该注解只是方便随意取参数名称,不过value属性仍是要与name一致,该注解只适合一些任性的盆友使用 。
使用
@RequestParam做用:将请求参数绑定到你控制器的方法参数上(是springmvc中接收普通参数的注解) 。
在使用SpringMVC接收基本参数类型的时候,咱们发现若是控制器中形参的名称与表单的name名称不一致时,没法接收参数。这是可使用@RequestParam注解解决这个问题。
注意:页面表单的name和控制器的形参(方法参数)并不一致,可是@RequestParam注解的value值(即接收请求参数的名称)必须和页面表单的name保持一致。不然就接收不到参数。
@RequestParam里name和value的区别:没有区别。源码注解的意思就是name的别名是value,value的别名是name。两者皆可,而且开发中两个都能得到参数,得到同样的结果。
@RequestParam注解还有两个属性:
实例:
@RequestMapping(value ="/requestParam",method = RequestMethod.GET) public String requestParam(@RequestParam("userName") String name, @RequestParam("userAge")Integer userAge) { System.out.println("用户名:" + name); System.out.println("年龄:" + userAge); return "success"; } /** * * @param name 默认defaultValue= "大青山",required = true失效,为false * @param userAge value = "userAge" ,required = false 能够不传,不传时为null * @return */ @RequestMapping(value ="/requestParam1",method = RequestMethod.GET) public String requestParam1(@RequestParam(value = "userName" ,required = true,defaultValue = "大青山") String name, @RequestParam(value = "userAge" ,required = false)Integer userAge) { System.out.println("用户名:" + name); System.out.println("年龄:" + userAge); return "success"; }
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本类型参数封装</h2> <form action="http://localhost:8080/hellospringmvc/say/requestParam1"> 用户名:<input type="text" name="userName"><br> 年龄:<input type="text" name="userAge"><br> <input type="submit" value="提交"> </form> </body> </html>
Spring MVC Pojo参数封装
以前咱们接收参数的时候都是定义一个个的基本类型来接收,这样比较繁琐,Spring MVC提供了使用Pojo(或者称为JavaBean)类型来封装请求参数。
实例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本类型参数封装</h2> <%--设置请求类型为post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamPojo" method="post"> 用户名:<input type="text" name="userName"><br> 年龄:<input type="text" name="userAge"><br> <input type="submit" value="提交"> </form> </body> </html> /** * method = RequestMethod.POST 能够不标记,不标记就都能匹配 * @param user * @return */ @RequestMapping(value ="/helloParamPojo" ,method = RequestMethod.POST) public String helloParamPojo(User user) { System.out.println("用户名:" + user.getUserName()); System.out.println("年龄:" + user.getUserAge()); return "success"; } public class User { private String userName; private Integer userAge; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getUserAge() { return userAge; } public void setUserAge(Integer userAge) { this.userAge = userAge; } }
Spring MVC 包装参数封装——Pojo嵌套Pojo对象
在Spring MVC的应用过程当中,咱们在后端通过须要将表单数据封装在一个包装Pojo类型中,所谓包装Pojo类型,就是Pojo对象中包含另外一个Pojo对象。
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本类型参数封装</h2> <%--设置请求类型为post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamPojos" method="post"> 用户名:<input type="text" name="userName"><br> 年龄:<input type="text" name="userAge"><br> <%--封装用户的地址信息,name为address.province这种写法,这表明把数据封装到User对象->Address对象的province属性中。--%> 省份:<input type="text" name="address.province"><br> 城市:<input type="text" name="address.city"><br> <input type="submit" value="提交"> </form> </body> </html> public class User { private String userName; private Integer userAge; private Address address; //...... } public class Address { private String province; private String city; //...... } @RequestMapping(value ="/helloParamPojos" ,method = RequestMethod.POST) public String helloParamPojos(User user) { System.out.println("用户名:" + user.getUserName()); System.out.println("年龄:" + user.getUserAge()); System.out.println("省份:"+user.getAddress().getProvince()); System.out.println("城市:"+user.getAddress().getCity()); return "success"; }
输出:
用户名:艾米 年龄:18 省份:艾米帝国 城市:帝都
Spring MVC List集合参数封装
咱们是一个Address对象来接收一个地址信息,若是有多个地址信息怎么呢?这时咱们可使用List集合来封装。
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本类型参数封装</h2> <%--设置请求类型为post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamList" method="post"> 用户名:<input type="text" name="userName"><br> 年龄:<input type="text" name="userAge"><br> <%--address[0].province,表明给User对象->List<Address>集合->第一个Address对象的province属性赋值--%> 省份1:<input type="text" name="address[0].province"><br> 城市1:<input type="text" name="address[0].city"><br> 省份2:<input type="text" name="address[1].province"><br> 城市2:<input type="text" name="address[1].city"><br> <input type="submit" value="提交"> </form> </body> </html> public class User { private String userName; private Integer userAge; private List<Address> address; //...... } @RequestMapping(value ="/helloParamList" ,method = RequestMethod.POST) public String helloParamList(User user) { System.out.println("用户名:" + user.getUserName()); System.out.println("年龄:" + user.getUserAge()); List<Address> address = user.getAddress(); for (Address addressTemp : address) { System.out.println("省份:"+addressTemp.getProvince()); System.out.println("城市:"+addressTemp.getCity()); } return "success"; } 用户名:许三多 年龄:25 省份:上海 城市:魔都 省份:北京 城市:帝都
Spring MVC Map集合参数封装
咱们利用List集合来封装多个地址信息,其实把List集合换成Map集合也是能够的 。
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本类型参数封装</h2> <%--设置请求类型为post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamMap" method="post"> 用户名:<input type="text" name="userName"><br> 年龄:<input type="text" name="userAge"><br> <%--这里的address['a1'].city,a1是赋值给Map的key,city是赋值给Address的city属性--%> 省份1:<input type="text" name="address['a1'].province"><br> 城市1:<input type="text" name="address['a1'].city"><br> 省份2:<input type="text" name="address['a2'].province"><br> 城市2:<input type="text" name="address['a2'].city"><br> <input type="submit" value="提交"> </form> </body> </html>
注意:这里的address['a1'].city,a1是赋值给Map的key,city是赋值给Address的city属性 .
@RequestMapping(value ="/helloParamMap" ,method = RequestMethod.POST) public String helloParamMap(User user) { System.out.println("用户名:" + user.getUserName()); System.out.println("年龄:" + user.getUserAge()); Map<String, Address> addressMap = user.getAddress(); Set<Map.Entry<String, Address>> entries = addressMap.entrySet(); for (Map.Entry<String, Address> entry : entries) { System.out.println(entry.getKey()+"--"+JSON.toJSONString(entry.getValue())); } return "success"; } public class User { private String userName; private Integer userAge; private Map<String,Address> address; //...... } 用户名:艾米 年龄:18 a1--{"city":"深圳","province":"粤"} a2--{"city":"金门","province":"闽"}
Spring MVC 自定义类型转换
Spring MVC默认状况下能够对基本类型进行类型转换,例如能够将String转换为Integer,Double,Float等。可是Spring MVC并不能转换日期类型(java.util.Date),若是但愿把字符串参数转换为日期类型,必须自定义类型转换器。接下来说解如何自定义类型转换器。
//通常项目不会用上
Spring MVC 使用Servlet API
在Spring MVC应用中,咱们也常常须要使用到原生的Servlet API来知足功能的开发需求。接下来介绍如何在Spring MVC中使用Servlet 相关API。
实例:
@RequestMapping("/leap") public void leap(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException { request.setAttribute("request","take leap of faith"); session.setAttribute("session","take leap of faith"); response.sendRedirect("/hellospringmvc/say/hello"); }
@RequestHeader注解
Spring MVC提供@RequestHeader注解方便咱们获取请求头信息。
示例:
@RequestMapping(value ="/helloHeader") public String helloHeader(@RequestHeader("host") String host, @RequestHeader("accept") String accept) { System.out.println("host---"+host); System.out.println("accept---"+accept); return "success"; }
输出:
host---localhost:8080 accept---text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
@CookieValue注解
Spring MVC提供@CookieValue方便咱们获取指定Cookie数据。
示例:
@RequestMapping(value ="/helloCookie") public String helloHeader(@CookieValue("JSESSIONID") String sessionId) { System.out.println("JSESSIONID---"+sessionId); return "success"; }
Spring MVC 静态资源访问
没法访问静态资源的缘由
当Spring MVC配置的拦截路径为 / 或 /* 的时候,咱们项目会没法访问静态资源文件,如:
springmvc.xml配置:
<servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
三种Spring MVC访问静态资源的方案
一、经过Tomcat的DefaultServlet配置访问静态资源。
在咱们应用的web.xml从新配置DefaultServlet的映射路径,让其对特定的静态资源进行处理。
首先,咱们要明白在Spring MVC应用之因此访问不了静态资源,是由于咱们配置的DispathcerServlet映射路径覆盖了Tomcat的DefaultServlet的映射路径。
Tomcat的DefaultServlet配置,在Tomcat根目录的conf/web.xml
实现方式,在项目的web.xml配置:
<!--从新配置Tomcat的DefaultServlet的映射路径--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.js</url-pattern> <url-pattern>*.png</url-pattern> <url-pattern>*.gif</url-pattern> </servlet-mapping>
二、经过mvc:resources/标签,把页面的不一样请求,转发到项目内部的某个目录下
Spring MVC提供了mvc:resources/标签,该标签的做用能够把页面的不一样请求,转发到项目内部的某个目录下。该标签配置在hellospringmvc-servlet.xml文件下。 <!--静态资源处理--> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/js/**" location="/js/"/>
mapping:表明映射页面的访问路径。
location:表明项目内的具体的物理路径地址。
三、经过mvc:default-servlet-handler/把全部静态资源目录的文件对外映射出去。
第二种方案的使用比较繁琐,由于须要一个个目录进行配置,其实有一个更加方便的标签: mvc:default-servlet-handler/,该标签至关于一次帮助咱们把全部静态资源目录的文件对外映射出去。该标签配置在hellospringmvc-servlet.xml文件下。 <!--静态资源处理--> <mvc:default-servlet-handler/>
Model与ModelMap
Spring MVC应用中,咱们常常须要在Controller将数据传递到JSP页面,除了能够经过HttpServletRequest域传递外,Spring MVC还提供了两个Api,分别为Model接口和ModelMap类。
Model与ModelMap的关系
Model接口和ModelMap类都有一个共同的子类:BindingAwareModelMap 。而BindingAwareModelMap底层实际上是往HttpServletRequest域存入数据,因此Model接口或者ModelMap的底层也是往request域存入数据!
示例:
show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>show page</title> </head> <body> <%--能够直接取也能够经过requestScope取值--%> <%--获取Model数据-${requestScope.question}--%> 获取Model数据-${question} <hr/> 获取ModelMap数据-${requestScope.answer} </body> </html> @Controller public class ModelController { @RequestMapping("/helloModel") public String helloModel(Model model){ model.addAttribute("question","what do you want?"); return "show"; } @RequestMapping("/helloModelMap") public String helloModelMap(ModelMap modelMap){ modelMap.addAttribute("answer","I want my phone call!"); return "show"; } }
输出:
@ModelAttribute注解
@ModelAttribute做用
@ModelAttribute注解的做用,将请求参数绑定到Model对象。被@ModelAttribute注释的方法会在Controller每一个方法执行前被执行(若是在一个Controller映射到多个URL时,要谨慎使用)。
@ModelAttribute注解的使用总结
@ModelAttribute使用位置
在SpringMVC的Controller中使用@ModelAttribute时,其位置包括下面三种:
一、应用在方法上
用在无返回值的方法
在model方法以前会执行setAttribute()方法。所以在setAttribute()方法中,请求传递的name参数存入Model对象,该参数值也会随着model方法带到JSP页面中。
实例:
result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>@ModelAttribute注解的使用</title> </head> <body> ${name} </body> </html> @Controller public class ModelAttributeController { @ModelAttribute public void setAttribute(@RequestParam(value = "userName",required = false) String name, Model model){ model.addAttribute("name",name); } @RequestMapping("/result") public String result(){ return "result"; } }
请求:<http://localhost:8080/hellospringmvc/result?userName=艾米
输出:
用在带返回值的方法
带有返回值的状况,其实就是自动把方法返回值存入Model对象,@ModelAttribute的value属性就是Model的key。至关于
model.addAttribute("name",name);
示例:
@Controller public class ModelAttributeController { @ModelAttribute("name") public String setAttribute(@RequestParam(value = "userName",required = false) String name){ return name; } @RequestMapping("/result") public String result(){ return "result"; } }
二、应用在方法的参数上
@ModelAttribute注解应用在方法的参数上,其实就是从Model对象中取出对应的属性值。
示例:
@Controller public class ModelAttributeController { @ModelAttribute("name") public String setAttribute(@RequestParam(value = "userName",required = false) String name){ return name; } @RequestMapping("/resultPara") public String resultPara(@ModelAttribute("name") String name){ System.out.println("name="+name); return "result"; } }
方法上+@RequestMapping
@ModelAttribute和@RequestMapping同时应用在方法上的时候,有两层意义:
示例:这种使用方式请求的时候是经过其余方法调用进来的。
@RequestMapping("/result") @ModelAttribute("name") public String resultMapping(@RequestParam(value = "userName",required = false) String name){ System.out.println("name="+name); return name; }
@SessionAttributes注解
通常不用这个注解,范围太广,有其余代替方法,最简单的就是用个redis缓存。
@SessionAttributes做用
默认状况下Spring MVC将模型中的数据存储到request域中。当一个请求结束后,数据就失效了。若是要跨页面使用。那么须要使用到session。而@SessionAttributes注解就可使得模型中的数据存储一份到session域中。
注意:@SessionAttributes注解只能用在类上!
@SessionAttributes属性:
示例:
@Controller @SessionAttributes(names = "name",types = String.class) public class SessionAttributeController { @RequestMapping("/showSession") public String showSession(Model model,String name){ model.addAttribute("name",name); return "sessionResult"; } }
sessionResult.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>@SessionAttributes注解的使用</title> </head> <body> request:${requestScope.name}<br/> session:${sessionScope.name}<br/> </body> </html>
输出:
Spring MVC 控制器返回值
Spring MVC的控制器方法返回值能够支持多种写法,每种写法的场景和效果都不同。下面分别来看看每种返回值的使用。
普通字符串——jsp页面地址+页面名称
返回普通字符串这种状况比较常见,主要用在咱们处理完业务逻辑后,须要跳转到应用的其余页面。
只能转发到视图解析器指定的特定目录。
/** * 1)字符串 - 普通字符串(表明页面名称,不是完整路径,最后通过视图解析器的解析) * 优点:写法简单 * 劣势:只能转发到视图解析器指定的特定目录 */ @RequestMapping("/hello") public String sayHello() { return "success"; }
转发字符串
普通字符串,只能转发到视图解析器指定前缀的目录下的页面,若是想转发到视图解析器目录之外的页面,这时可使用转发字符串的写法。
forward:完整页面的路径 。
示例:能够传递request域对象数据
/** * 2)字符串 - 转发字符串 * 转发字符串格式: * forward:完整页面的路径 例如:forward:/pages/index.jsp * * 优点:更加灵活,能够转到本项目下的任何页面,能够传递request域对象数据 * 劣势:写法稍复杂 */ @RequestMapping("/forward") public String forward(){ return "forward:/index.jsp"; }
重定向字符串
若是但愿使用重定向的方式跳转页面,这时可使用重定向字符串完成。
示例:不能转发reques域对象数据
/** * 3)字符串 - 重定向字符串 * 重定向字符串格式: * redirect:完整页面的路径 例如:redirect:/pages/index.jsp * * 优点:很灵活,能够重定向到项目内和项目之外的页面 * 劣势:写法稍复杂,不能转发reques域对象数据 */ @RequestMapping("/redirect") public String redirect(){ return "redirect:http://www.baidu.com"; }
返回空
通常咱们在文件下载的时候,就不须要控制器方法返回任何内容,因此设置为void便可。
示例:
/** * 4)返回void * 用于文件下载 */ @RequestMapping("/download") public void download(HttpServletResponse response) { //模拟文件下载 //1.读取须要下载的文件 File file = new File("e:/car.jpg"); //2.构建文件输入流 try (InputStream in = new FileInputStream(file); OutputStream out = response.getOutputStream()) { //4.边读边写 byte[] buf = new byte[1024]; int len = 0; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } } catch (Exception e) { e.printStackTrace(); } return; }
ModelAndView
Spring MVC提供了ModelAndView对象,该对象既能够存储数据到request域,也能够设置视图。其实Spring MVC任何处理器适配器最终执行完控制器后,都会返回ModelAndView对象。因此这是一个比较底层的对象。
示例:
@RequestMapping("/mv") public ModelAndView mv(){ ModelAndView mv = new ModelAndView(); //设置模型数据 值attributeValue能够是任何对象Object mv.addObject("name","池寒枫"); //设置视图数据 //设置viewName表明页面名称,不是完整路径,最后通过视图解析器的解析 mv.setViewName("result"); return mv; }
输出:
返回Java对象
这里返回的Java对象,多是普通JavaBean,也能够是List或Map集合等。通常但愿把控制器的返回Java对象转换为Json字符串,才须要返回Java对象。
Spring MVC JSON数据转换
场景:
在开发中后端常常须要接受来自于前端传递的Json字符串数据并把把Json字符串转换为Java对象 。
后端也常常须要给前端把Java对象数据转换为Json字符串返回 。
办法:
使用@RequestBody和@ResponseBody注解。
Spring MVC默认是没法实现Json数据转换功能的,须要额外导入fastjson包来支持Json数据转换。
编写JsonController,这里用到两个关键注解@RequestBody和@ResponseBody。
示例:
<!-- 平时处理json用的 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.29</version> </dependency> <!-- jackson支持包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> @Controller public class JsonController { @RequestMapping("/json") @ResponseBody public MercenaryUser showJson(@RequestBody MercenaryUser user){ System.out.println("前端发送的数据:"+ JSON.toJSONString(user)); //后台返回json字符串给前端 user.setId(1); user.setName("艾米"); user.setAge(20); user.setRide("冥牙"); return user; } @RequestMapping("/toJson") public String toJson(){ return "json"; } }
json.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>JSON格式转换</title> <%--使用jQuery实现ajax异步请求后端Controller,同时发送Json字符串对象--%> <%--<script src="/hellospringmvc/js/jquery-1.7.1.min.js"></script>--%> <%--CDN--%> <script src="http://code.jquery.com/jquery-1.12.0.min.js"></script> </head> <body> <script> //页面加载完毕 $(function () { //点击按钮,发送post请求,传递json参数 $("#btn").click(function () { $.ajax({ //设置请求类型 type: 'post', //请求路径 url: 'http://localhost:8080/hellospringmvc/json', //传递json参数 data: '{"id":3,"name":"池傲天","age":21,"ride":"DeathDragon"}', //指定参数类型(若是json参数格式,必须设置为json类型) contentType: 'application/json;charset=utf-8', //该方法接收后台返回的数据格式 dataType: 'json', //处理方法 success: function (result) { alert(result.id + '--' + result.name + '--' + result.age + '--' + result.ride); } }); }); }); </script> <input type="button" value="Json字符串与Java对象转换" id="btn"> </body> </html> public class MercenaryUser { private Integer id; private String name; private Integer age; private String ride; //... }
hellospringmvc-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.扫描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 4.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 4.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 4.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.开启mvc注解驱动--> <!-- 3.建立处理器适配器和处理器映射器--> <!--在Spring中通常采用@RequestMapping注解来完成映射关系, 要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例, 这两个实例分别在类级别和方法级别处理。而<mvc:annotation-driven/>配置帮助咱们自动完成上述两个实例的注入。 --> <mvc:annotation-driven/> <!--静态资源处理--> <!--该标签至关于一次帮助咱们把全部静态资源目录的文件对外映射出去。--> <mvc:default-servlet-handler/> </beans>
输出:
前端发送的数据:{"age":21,"id":3,"name":"池傲天","ride":"DeathDragon"}
报错:
一、jquery方法执行不了。json请求页面无响应。
A:首先要引入jquery-1.7.1.min.js 文件,放到项目目录上,并经过从项目名开始的路径引用,或者全路径,从主机路径开始,不然会找不到js文件,由于咱们没有设置相对路径。 <%--使用jQuery实现ajax异步请求后端Controller,同时发送Json字符串对象--%> <script src="/hellospringmvc/js/jquery-1.7.1.min.js"></script>
二、发起ajax请求时415报错——不支持的媒体类型(Unsupported media type)
jquery-1.7.1.min.js:2660 POST http://localhost:8080/hellospringmvc/json 415 ()
A:咱们须要一:在hellospringmvc-servlet.xml中配置开启mvc注解驱动,该配置会建立处理器适配器和处理器映射器,自动注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean。 AnnotationMethodHandlerAdapter将会初始化7个转换器,能够经过调用AnnotationMethodHandlerAdapter的getMessageConverts()方法来获取转换器的一个集合 List<HttpMessageConverter>。 ByteArrayHttpMessageConverter StringHttpMessageConverter ResourceHttpMessageConverter SourceHttpMessageConverter XmlAwareFormHttpMessageConverter Jaxb2RootElementHttpMessageConverter MappingJacksonHttpMessageConverter 对于json的解析就是经过MappingJacksonHttpMessageConverter转换器完成的。 二:依赖jackson包,这样才能经过转换器+jackson解析json数据,@RequestBody须要。 <!-- jackson支持包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency>
若是仍是报415错误,那多是由于在hellospringmvc-servlet.xml显式配置的处理器和适配器,致使转换器没有初始化出来。要注释掉。以下:
<!--2.建立RequestMappingHandlerMapping--> <!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>--> <!--3.建立RequestMappingHandlerAdapter--> <!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
参考:使用@RequestBody注解处理json时,报出HTTP Status 415的解决方案
注意:在hellospringmvc-servlet.xml配置中,当咱们配置了静态资源处理时,就必定要开启mvc注解驱动,不然咱们请求的处理都会被静态资源处理器处理了,致使请求的页面报404请求资源不存在。所以在hellospringmvc-servlet.xml配置中,两个都是必定要配置的,缺一不可。
<!-- 3.开启mvc注解驱动--> <!-- 3.建立处理器适配器和处理器映射器--> <!--在Spring中通常采用@RequestMapping注解来完成映射关系, 要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例, 这两个实例分别在类级别和方法级别处理。而<mvc:annotation-driven/>配置帮助咱们自动完成上述两个实例的注入。 --> <mvc:annotation-driven/> <!--静态资源处理--> <!--该标签至关于一次帮助咱们把全部静态资源目录的文件对外映射出去。--> <mvc:default-servlet-handler/>
Spring MVC RESTful风格开发
什么是RESTful风格?
RESTful,也叫REST(英文: Representational State Transfer, 简称 REST) 描述了一个架构样式的网络系统,好比 web 应用程序。它首次出如今 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种 Web 服务交互方案中,REST 相比于SOAP(Simple Object Access protocol, 简单对象访问协议) 以及 XML-RPC 更加简单明了, 不管是对 URL 的处理仍是对 Payload 的编码, REST 都倾向于用更加简单轻量的方法设计和实现。 值得注意的是 REST 并无一个明确的标准, 而更像是一种设计的风格。REST 其核心价值在于如何设计出符合 REST 风格的网络接口。 基于这个风格设计的软件能够更简洁, 更有层次, 更易于实现缓存等机制。
简单地说:使用RESTful风格可让咱们客户端与服务端访问的URL更加简洁方便!
如下给出两个例子,前者没有采用RESTful风格,后者采用RESTful风格。
没有采用RESTful风格的URL:
采用RESTful风格的URL:
对比发现,RESTful风格更加简洁,RESTful主要依靠不一样的请求方法来区分不一样操做类型,这个与传统URL最大的区别。
Spring MVC开发RESTful应用
前置条件
为了在前端模拟出不一样的请求方式,须要在web.xml引入SpringMVC提供的HiddenHttpMethodFilter,这是个配置请求方式转换过滤器。
<!-- 转换请求方式的过滤器 --> <filter> <filter-name>hiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>hiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
restful.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC进行RESTful风格开发</title> </head> <body> <!--增长 --> <form action="/hellospringmvc/rest" method="post"> <input type="submit" value="增长"> </form> <!--查询 --> <form action="/hellospringmvc/rest" method="get"> <input type="submit" value="查询"> </form> <!--修改 --> <form action="/hellospringmvc/rest/8" method="post"> <input type="hidden" name="_method" value="put"> <input type="submit" value="修改"> </form> <!--删除 --> <form action="/hellospringmvc/rest/9" method="post"> <input type="hidden" name="_method" value="delete"> <input type="submit" value="删除"> </form> </body> </html> @Controller @RequestMapping("/rest") public class RestfulController { @RequestMapping(method = RequestMethod.POST) @ResponseBody public String save() { System.out.println("增长..."); return "success"; } @RequestMapping(method = RequestMethod.GET) @ResponseBody public String get() { System.out.println("查询..."); return "success"; } /* @RequestMapping(value = "/{id}",method = RequestMethod.POST) @ResponseBody public String update(@PathVariable("id") Integer id){ System.out.println("修改...id="+id); return "success"; }*/ @RequestMapping(value = "/{id}", method = RequestMethod.PUT) @ResponseBody public String update(@PathVariable("id") Integer id) { System.out.println("修改...id=" + id); return "success"; } @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable("id") Integer id) { System.out.println("删除...id=" + id); return "success"; } }
注意点:
请求:http://localhost:8080/hellospringmvc/restful.jsp
输出:
增长... 查询... 修改...id=8 删除...id=9
报错:若是不配置转换请求方式的过滤器HiddenHttpMethodFilter,请求会报错。
Spring MVC 文件上传
文件上传是表现层常见的需求,在Spring MVC中底层使用Apache的Commons FileUpload工具来完成文件上传,对其进行封装,让开发者使用起来更加方便。
文件上传须要:
注意:
上传表单注意:
注意:
这里使用MultipartFile对象接收文件,并把文件存放在项目的upload目录下,同时还接收了普通参数。
示例:
pom.xml
<!-- commons-fileUpload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
hellospringmvc-servlet.xml
<!-- 配置文件上传解析器 注意:必须配置id,且名称必须为multipartResolver--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置限制文件上传大小 (字节为单位)--> <property name="maxUploadSize" value="1024000"/> </bean>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello Spring MVP</title> </head> <body> <h1>上传成功!</h1> </body> </html>
upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>文件上传</title> </head> <body> <h3>SpringMVC方式文件上传</h3> <form action="/hellospringmvc/upload" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="fileName"> <br/> 文件描述:<input type="text" name="desc"> <br/> <input type="submit" value="上传"> </form> </body> </html> @Controller public class UploadController { @RequestMapping("/upload") public String upload(HttpServletRequest request, MultipartFile fileName, String desc) { //1.获取网站的upload目录的路径: ServletContext对象 //F:\self\hellospringmvc\target\hellospringmvc-1.0-SNAPSHOT\upload String upload = request.getSession().getServletContext().getRealPath("upload"); ///F:/self/hellospringmvc/target/hellospringmvc-1.0-SNAPSHOT/WEB-INF/classes//upload String upload2 = UploadController.class.getResource("/").getFile()+"/upload"; //判断该目录是否存在,不存在,本身建立 File file = new File(upload); if (!file.exists()) { file.mkdir(); } //把文件保存到upload目录 //2.1 原来的文件名 String originalFilename = fileName.getOriginalFilename(); //2.生成随机文件名称 String uuId = UUID.randomUUID().toString(); //2.3 获取文件后缀 如 .jpg String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); //2.4 最终的文件名 String newName = uuId + suffix; //3.保存 try { //目标文件传入地址路径+名称 fileName.transferTo(new File(upload + "/" + newName)); } catch (IOException e) { e.printStackTrace(); } System.out.println("文件描述:" + desc); //跳转到上传成功页面 return "success"; } }
请求:http://localhost:8080/hellospringmvc/upload.jsp
输出:上传成功。
Spring MVC 文件下载
准备下载的文件
示例:
download.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>文件下载</title> </head> <body> <h3>SpringMVC文件下载</h3> <a href="/hellospringmvc/download">下载</a> </body> </html> @Controller public class DownloadController { @RequestMapping("/download") public void download(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException { //InputStream inputStream = session.getServletContext().getResourceAsStream("/download/template.gif"); InputStream inputStream = request.getSession().getServletContext().getResourceAsStream("/download/template.gif"); //2.输出文件 //设置响应头 response.setHeader("Content-Disposition","attachment;filename=template.gif"); OutputStream outputStream = response.getOutputStream(); byte[] buff = new byte[1024]; int lenth = 0; while ((lenth= inputStream.read(buff))!= -1){ outputStream.write(buff,0,lenth); } //3.关闭资源 outputStream.close(); inputStream.close(); } }
请求:http://localhost:8080/hellospringmvc/download.jsp
Spring MVC 拦截器
Spring MVC中的拦截器(Interceptor)相似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并做相应的处理。例如经过拦截器能够进行权限验证、记录请求信息的日志、判断用户是否登陆,session是否超时等。
要使用Spring MVC中的拦截器,就须要对拦截器类进行定义和配置。
一般拦截器类能够经过两种方式来定义:
注意:拦截器配置的顺序决定了拦截器的执行顺序,先配置会先被执行!
注意:一个拦截器和多个拦截器的执行顺序看下图。
一个拦截器的执行顺序:
多个拦截器的执行顺序:
示例:
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping(value = "/hello", method = RequestMethod.GET) public String sayHello() { //System.out.println("----------HelloController-----sayHello---------------"); System.out.println("3.目标控制器-HelloController"); return "success"; } } public class FirstInterceptor implements HandlerInterceptor { /** *preHandle: 在控制器(目标)的方法以前被执行 * 返回值:控制afterCompletion方法是否被执行 * true: 执行afterCompletion * false: 不执行afterCompletion */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("1.FirstInterceptor的preHandle"); return true; } /** * postHandle: 在控制器(目标)的方法成功执行完成以后(注意:控制器方法失败不执行) */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("5.FirstInterceptor的postHandle"); } /** * afterCompletion: 在执行完前面全部(拦截器和目标)的方法以后执行(注意: 无论控制器方法执行成功与否都会被执行 ) */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("7.FirstInterceptor的afterCompletion"); } } public class SecondInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("2.SecondInterceptor的preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("4.SecondInterceptor的postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("6.SecondInterceptor的afterCompletion"); } }
hellospringmvc-servlet.xml
<!--配置拦截器 :拦截器配置的顺序决定了拦截器的执行顺序,先配置会先被执行!--> <mvc:interceptors> <mvc:interceptor> <!--要拦截请求路径--> <mvc:mapping path="/**/*"/> <bean class="com.self.interceptor.FirstInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/say/hello"/> <!--若是只这么写就是只拦截路径为/hello的,上面的/say/hello是不会被拦截的--> <mvc:mapping path="/hello"/> <bean class="com.self.interceptor.SecondInterceptor"/> </mvc:interceptor> </mvc:interceptors>
请求:http://localhost:8080/hellospringmvc/say/hello
输出:
1.FirstInterceptor的preHandle 2.SecondInterceptor的preHandle 3.目标控制器-HelloController 4.SecondInterceptor的postHandle 5.FirstInterceptor的postHandle 6.SecondInterceptor的afterCompletion 7.FirstInterceptor的afterCompletion
登陆超时拦截器:
public class RequestSessionTimeOutInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try{ String uri = request.getRequestURI(); if(uri == null){ return true; } HttpSession session = request.getSession(); if (null == session) { //401:HTTP401错误表明用户没有访问权限,须要进行身份认证 response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } return true; } catch (Exception e){ //异常状况不拦截 logger.error("拦截器配置失败",e); return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
Spring MVC 异常处理机制
在控制器的方法发生异常后,默认状况会显示Tomcat的500页面,这种用户体验并很差。若是咱们在每一个控制器方法自行捕获异常,显然又太繁琐。有没有好的异常处理办法呢?有的,就是Spring MVC的全局异常处理机制。Spring MVC提供了两种全局异常处理机制:
编写全局异常处理类
全局异常类编写方式一
实现HandlerExceptionResolver接口,而后实现resolveException方法,编写处理异常逻辑。
示例:
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping(value = "/error") public String error() { int i = 100/0; return "success"; } } public class SimpleHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView mv = new ModelAndView("error"); mv.addObject("errorMsg",ex.getMessage()); return mv; } }
hellospringmvc-servlet.xml
<!--建立自定义异常处理对象--> <bean class="com.self.exceptionhandler.SimpleHandlerExceptionResolver"/>
全局异常类编写方式二
直接在类上使用@ControllerAdvice,在异常处理方法上添加@ExceptionHandler注解。这种作法底层是AOP思想。
示例:
@ControllerAdvice public class SimpleExceptionHandler { @ExceptionHandler public ModelAndView handlerException(Exception e){ ModelAndView mv = new ModelAndView(); mv.setViewName("error"); mv.addObject("errorMsg",e.getMessage()); return mv; } }
hellospringmvc-servlet.xml
<!--建立自定义异常处理对象--> <bean class="com.self.exceptionhandler.SimpleExceptionHandler"/>
请求:http://localhost:8080/hellospringmvc/say/error
Spring MVC 异常处理机制没处理前:
HTTP Status 500 - Request processing failed; nested exception is java.lang.ArithmeticException: / by zero
处理后:
注意:若是两种都配置了,会被面向切面先执行返回了。类上使用@ControllerAdvice,在异常处理方法上添加@ExceptionHandler注解。这种作法底层是AOP思想。
Spring MVC 表单数据验证
Spring MVC提供了表单数据验证功能 。
前提:导入数据验证依赖包。
表单数据验证的重点是在Pojo类使用相关注解指定每一个属性的验证规则。如下为可使用的注解:
注解名称 说明
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内(长度大小)
@Digits(integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个未来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
在Controller中,咱们须要判断Pojo是否产生了验证错误信息,若是有的话,则把信息转给JSP页面显示。
示例:
pom.xml
<!-- 验证器所需的包 --> <dependency> <groupId>com.fasterxml</groupId> <artifactId>classmate</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.2.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> public class User { private Integer id; @NotNull @Pattern(regexp = "^([a-zA-Z]*[0-9_-]*$)", message = "只能包含字母、数字、下划线,且不能以数字或下划线开头") @Size(min = 1, max = 110) private String name; @NotNull @Range(min = 1,max = 100,message = "年龄不在合法范围内") private Integer age; @Pattern(regexp = "^([a-zA-Z]*$)", message = "只能包含字母") private String ride; //... } @Controller public class ValidateController { @RequestMapping("/check") public String check(@Valid User user, BindingResult result, Model model) { //若是表单数据验证有异常 if (result.hasErrors()) { //取出全部失败信息 List<FieldError> fieldErrors = result.getFieldErrors(); for (FieldError fieldError : fieldErrors) { //把错误信息存入request域,传递到JSP页面显示 model.addAttribute("ERROR_" + fieldError.getField(), fieldError.getDefaultMessage()); } return "forward:validate.jsp"; } System.out.println("User=" + JSON.toJSONString(user)); return "success"; } }
validate.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>表单数据验证</title> </head> <body> <form action="/hellospringmvc/check" method="post"> 用户名:<input type="text" name="name">${ERROR_name}<br/> 年龄:<input type="text" name="age">${ERROR_age}<br/> 坐骑:<input type="text" name="ride">${ERROR_ride}<br/> <input type="submit" value="提交"> </form> </body> </html>
请求:http://localhost:8080/hellospringmvc/validate.jsp
输出:
Maven单模块SSM整合
本文讲解使用Maven单模块方式进行Spring MVC+Spring+MyBatis整合。为了把整合步骤体现地更加清晰,咱们能够把步骤分为如下六个部分:
一、准备数据库环境
CREATE TABLE `t_user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(64) NOT NULL COMMENT '姓名', `dept` varchar(254) NOT NULL COMMENT '部门', `phone` varchar(16) NOT NULL COMMENT '电话', `height` decimal(10,2) DEFAULT NULL COMMENT '身高', `create_emp` bigint(20) NOT NULL COMMENT '建立人', `create_time` datetime DEFAULT NULL COMMENT '建立时间', `modify_emp` bigint(20) DEFAULT NULL COMMENT '修改人', `modify_time` datetime DEFAULT NULL COMMENT '修改时间', PRIMARY KEY (`id`), KEY `idx_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户表';
二、单独搭建Spring环境
建立Web项目——使用原来的hellospringmvc
SSM相关依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.self</groupId> <artifactId>hellospringmvc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> <!-- SSM整合的基础依赖 --> <!-- 1.spring相关的依赖 --> <dependencies> <!-- 1.1 ioc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--1.2 aop --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <!-- 1.3 声明式事务--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- 1.4 test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- 2. mybatis相关依赖 --> <!-- 2.1 mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!-- 2.2 数据源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <!-- 2.3 mybatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- 3. springmvc相关依赖--> <!-- 3.1 springmvc核心包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--3.2 servlet依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!--3.3 jstl标签库--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- 4. log4j日志 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <!-- 5. spring与mybatis整合包 *** --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.29</version> </dependency> <!-- jackson支持包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> <!-- 验证器所需的包 --> <dependency> <groupId>com.fasterxml</groupId> <artifactId>classmate</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.2.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> </dependencies> </project>
设计Pojo
public class User { /** * id */ private int id; /** * 名字 */ private String name; /** * 部门,帝国 */ private String dept; /** * 联系号码 */ private String phone; /** * 身高 */ private BigDecimal height; /** * 建立人 */ private Long createEmp; /** * 建立时间 */ private Date createTime; /** * 修改人 */ private Long modifyEmp; /** * 修改时间 */ private Date modifyTime; //... }
编写业务接口和实现
public interface UserService { List<User> getALlUsers(); } //给业务实现类加入@Service注解,目的是把该对象放入Spring IOC容器。 @Service("userService") //@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); @Override public List<User> getALlUsers() { logger.error("查询全部用户成员..."); return userMapper.getALlUsers(); } }
编写Spring配置
applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--spring 容器扫描配置--> <context:component-scan base-package="com.self"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> </beans>
Spring环境单元测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringTest { @Autowired private UserService userService; @Test public void test() { userService.getALlUsers(); } }
输出表示spring环境搭建成功:
查询全部用户成员...
三、 单独搭建Spring MVC环境
Spring MVC核心控制器web.xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置核心控制器 :DispatcherServlet --> <servlet> <servlet-name>hellospringmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- springmvc配置文件加载路径 1)默认状况下,读取WEB-INF下面的default-servlet.xml文件 2)能够改成加载类路径下(resources目录),加上classpath: --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/hellospringmvc-servlet.xml</param-value> <!--<param-value>WEB-INF/simple-servlet.xml</param-value>--> </init-param> <!--init-param必须放在load-on-startup前,不然会报错:invalid content was found starting with element 'init-param'. One of '{"http://java.sun.com/xml/ns/javaee":run-as, "http://java.sun.com/xml/ns/javaee":security-role-ref}' is expected--> <!-- DispatcherServlet对象建立时间问题 1)默认状况下,第一次访问该Servlet时建立对象,默认是访问时建立,意味着在这个时间才去加载hellospringmvc-servlet.xml 2)能够改变为在项目启动时候就建立该Servlet,提升用户访问体验。 <load-on-startup>1</load-on-startup> 数值越大,对象建立优先级越低! (数值越低,越先建立) --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hellospringmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--从新配置Tomcat的DefaultServlet的映射路径--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.js</url-pattern> <url-pattern>*.png</url-pattern> </servlet-mapping> </web-app>
springmvc配置——hellospringmvc-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.扫描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.开启mvc注解驱动--> <mvc:annotation-driven/> </beans>
编写UserController
@RequestMapping("/user") @Controller public class UserController { /** * 查询全部用户 */ @RequestMapping("list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入数据到request域 model.addAttribute("list","用户数据"); //返回list.jsp页面 return "userList"; } }
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>显示用户数据</title> </head> <body> ${list} </body> </html>
项目部署到Tomcat
请求:http://localhost:8080/user/list
4 、Spring整合Spring MVC
配置Spring监听器
Spring和Spring MVC融合使用,只要在web.xml配置监听器,在项目启动的时候,加载applicationContext.xml文件,把Spring环境启动便可。
web.xml
<!-- 配置spring监听器,用于加载applicationContext.xml(初始化SpringIOC容器) --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
在控制层调用业务层,若是Controller成功注入Service,表明Spring与Spring MVC整合成功!
@RequestMapping("/user") @Controller public class UserController { @Autowired private UserService userService; /** * 查询全部用户 */ @RequestMapping("list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入数据到request域 model.addAttribute("list","用户数据"); //返回list.jsp页面 return "userList"; } }
输出:
五、 单独搭建MyBatis环境
编写UserDao接口
@Repository public interface UserMapper { List<User> getALlUsers(); }
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.self.dao.UserMapper"> <select id="getALlUsers" resultType="User"> select u.create_time createTime,u.id id ,u.name name ,u.dept dept,u.phone phone from `t_user` u where 1 = 1 </select> </mapper>
mybatis-config.xml——该文件是MyBatis核心配置,里面配置数据源及Dao接口映射等信息。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 读取jdbc.properties --> <properties resource="jdbc.properties"/> <!--1.别名扫描 --> <typeAliases> <package name="com.self.pojo"/> </typeAliases> <!--2.数据库链接 --> <environments default="mysql"> <environment id="mysql"> <transactionManager type="jdbc"></transactionManager> <dataSource type="pooled"> <property name="url" value="${jdbc.url}"/> <property name="driver" value="${jdbc.driver}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!--3.映射关联 --> <mappers> <package name="com.self.dao"/> </mappers> </configuration>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/hello_mybatis?characterEncoding=utf8 jdbc.username=root jdbc.password=123456 jdbc.initialSize=3 jdbc.maxActive=10
MyBatis测试类
public class MabatisTest { @Test public void testFindAll() throws IOException { //1.加载SqlMapConfig.xml InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); //2.建立SqlSessionFactory SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.建立SqlSession SqlSession sqlSession = factory.openSession(); //4.建立Dao代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //5.执行方法 List<User> list = userMapper.getALlUsers(); System.out.println(JSON.toJSONString(list)); //6.释放资源 sqlSession.close(); in.close(); } }
输出:
[{"createTime":1585635455000,"dept":"amy empire","id":1,"name":"大青山","phone":"123456"},{"createTime":1585635455000,"dept":"amy empire","id":2,"name":"艾米哈珀","phone":"123456"},{"createTime":1585635455000,"dept":"amy empire","id":3,"name":"池寒枫","phone":"123456"},{"createTime":1585647970000,"dept":"森林矮人王国","id":4,"name":"霍恩斯","phone":"852-253521"}]
参考代码位置:
6 、MyBatis整合Spring
整合的思路是:Spring依赖IOC容器建立MyBatis所须要的SqlSessionFactory,从而利用SqlSessionFactory完成Dao层的操做。
注意:
由于Spring已经把以前MyBatis的数据源及Dao映射等信息都集成了,因此MyBatis的mybatis-config.xml已经不须要啦,能够删除。
applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--spring 容器扫描配置--> <context:component-scan base-package="com.self"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--载入properties--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 1. 建立数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 2. 为了建立Dao代理对象,先建立SqlSessionFactory对象 --> <!-- SqlSessionFactoryBean: 建立SqlSessionFactory对象的工具 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入数据源 --> <property name="dataSource" ref="dataSource"/> <!--typeAliasesPackage:批量别名处理 经过这些property就能够把mybatis-config.xml替代掉了--> <property name="typeAliasesPackage" value="com.self.pojo"/> <!-- 全部配置的mapper文件 该配置至关因而mybatis-config.xml里的mappers配置,在这边直接扫描获取了--> <!--<property name="mapperLocations" value="classpath*:com/self/dao/*.xml"/>--> </bean> <!-- 3. 扫描Dao接口所在包,扫描后用于建立Dao代理对象,把代理对象放入IOC容器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- Dao扫描目录 --> <property name="basePackage" value="com.self.dao"/> <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>--> </bean> <!-- 添加事务支持 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 注册事务管理驱动 表示支持声明式事务 @Transactional 注解标注的会被代理实现事务,但要用在有接口的public方法中--> <!--基于注解的方式使用事务配置声明--> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
业务层注入持久层对象
//给业务实现类加入@Service注解,目的是把该对象放入Spring IOC容器。 @Service("userService") //@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); @Override public List<User> getALlUsers() { logger.error("查询全部用户成员..."); return userMapper.getALlUsers(); } }
编写测试类
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value = "classpath:applicationContext.xml") public class SpringMyBatisTest { //从IOC容器中获取业务实现 @Autowired private UserService userService; @Test public void testFindAll(){ System.out.println(JSON.toJSONString(userService.getALlUsers())); } }
SSM框架已经整合完成。剩下就是把数据显示到JSP页面上。
修改UserController类
@RequestMapping("/user") @Controller public class UserController { @Autowired private UserService userService; /** * 查询全部用户 */ @RequestMapping("list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入数据到request域 model.addAttribute("list", users); //model.addAttribute("list","用户数据"); //返回list.jsp页面 return "userList"; } }
修改JSP页面显示内容
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>显示用户数据</title> </head> <body> <h3>用户列表</h3> <table border="1"> <tr> <td>编号</td> <td>用户名</td> <td>帝国</td> <td>电话号码</td> <td>建立时间</td> </tr> <!-- items: 须要须要遍历的集合 var: 每一个对象的变量名称 --> <c:forEach items="${list}" var="user"> <tr> <td>${user.id}</td> <td>${user.name}</td> <td>${user.dept}</td> <td>${user.phone}</td> <td>${user.createTime}</td> </tr> </c:forEach> </table> </body> </html>
输出:
报错:
一、在经过controller请求到底层service时报错:springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.self.service.UserService'。
A:这种状况下通常是UserService没有注册到spring容器中,通常分两种状况,要么扫描bean时没有扫到,因此没添加,要嘛是UserService实现类(注意不是UserService接口)没有配置@Service,因此spring没有把他当成一个组件注册到容器中。还有就是在配置UserService实现类时配置@Service错误,要指定名称,不然默认是类名首字母小写后的全称,所以会找不到bean。
还有就是web.xml缺乏ContextLoaderListener配置,致使spring容器里的bean没有被加载。
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
二、启动项目时没法启动成功,userService注入不了dao依赖。
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userMapper' defined in file [F:\practice\hellospringmvc\target\hellospringmvc-1.0-SNAPSHOT\WEB-INF\classes\com\self\dao\UserMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'User'. Cause: java.lang.ClassNotFoundException: Cannot find class: User <!--A:这是因为UserMapper.xml的resultType="User",没有指定全路径,这时候要嘛指定全路径,要嘛在applicationContext.xml配置sqlSessionFactory时批量别名处理。 以下: --> <!-- 2. 为了建立Dao代理对象,先建立SqlSessionFactory对象 --> <!-- SqlSessionFactoryBean: 建立SqlSessionFactory对象的工具 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入数据源 --> <property name="dataSource" ref="dataSource"/> <!--typeAliasesPackage:批量别名处理 经过这些property就能够把mybatis-config.xml替代掉了--> <property name="typeAliasesPackage" value="com.self.pojo"/> </bean>
Maven多模块SSM整合
一些中大型项目,我但愿采用Maven多模块构建方式来搭建SSM整合项目。
Maven多模块构建SSH项目架构图:
示例:
新建一个noodle-parent的project工程。子项目经过右击项目名建立新的maven依赖模块。
总体结构:
一、创建parent工程
配置父工程noodle-parent——pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.self</groupId> <artifactId>noodle-parent</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>noodle-pojo</module> <module>noodle-dao</module> <module>noodle-service</module> <module>noodle-web</module> </modules> <!-- SSM整合的基础依赖 --> <!-- 1.spring相关的依赖 --> <dependencies> <!-- 1.1 ioc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--1.2 aop --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <!-- 1.3 声明式事务--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- 1.4 test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- 2. mybatis相关依赖 --> <!-- 2.1 mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!-- 2.2 数据源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <!-- 2.3 mybatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- 3. springmvc相关依赖--> <!-- 3.1 springmvc核心包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--3.2 servlet依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <!--3.3 jstl标签库--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- 4. log4j日志 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- 5. spring与mybatis整合包 *** --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> </dependencies> </project>
二、创建pojo工程
编写Pojo类
public class User { /** * id */ private int id; /** * 名字 */ private String name; /** * 部门,帝国 */ private String dept; /** * 联系号码 */ private String phone; /** * 身高 */ private BigDecimal height; /** * 建立人 */ private Long createEmp; /** * 建立时间 */ private Date createTime; /** * 修改人 */ private Long modifyEmp; /** * 修改时间 */ private Date modifyTime; //... }
三、创建dao工程
依赖domain工程
<dependencies> <dependency> <groupId>com.self</groupId> <artifactId>noodle-pojo</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> public interface UserMapper { List<User> getALlUsers(); }
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.self.dao.UserMapper"> <select id="getALlUsers" resultType="User"> select u.create_time createTime,u.id id ,u.name name ,u.dept dept,u.phone phone from `t_user` u where 1 = 1 </select> </mapper>
编写Spring的Dao配置
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/hello_mybatis?characterEncoding=utf8 jdbc.username=root jdbc.password=123456
applicationContext-dao.xml文件只存放与Dao有关的配置 。
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--载入properties--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 1. 建立数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 2. 为了建立Dao代理对象,先建立SqlSessionFactory对象 --> <!-- SqlSessionFactoryBean: 建立SqlSessionFactory对象的工具 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入数据源 --> <property name="dataSource" ref="dataSource"/> <!--typeAliasesPackage:批量别名处理 经过这些property就能够把mybatis-config.xml替代掉了--> <property name="typeAliasesPackage" value="com.self.pojo"/> <!-- 全部配置的mapper文件 该配置至关因而mybatis-config.xml里的mappers配置,在这边直接扫描获取了--> <!--<property name="mapperLocations" value="classpath*:com/self/dao/*.xml"/>--> </bean> <!-- 3. 扫描Dao接口所在包,扫描后用于建立Dao代理对象,把代理对象放入IOC容器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- Dao扫描目录 --> <property name="basePackage" value="com.self.dao"/> <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>--> </bean> </beans>
四、创建Service工程
依赖Dao工程 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>noodle-parent</artifactId> <groupId>com.self</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>noodle-service</artifactId> <dependencies> <dependency> <groupId>com.self</groupId> <artifactId>noodle-dao</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project> public interface UserService { List<User> getALlUsers(); } //给业务实现类加入@Service注解,目的是把该对象放入Spring IOC容器。 @Service("userService") //@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public List<User> getALlUsers() { System.out.println("查询全部用户成员..."); return userMapper.getALlUsers(); } }
编写Spring的Service配置
applicationContext-service.xml
该配置主要须要扫描Service实现类和配置Spring声明式事务。
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--spring 容器扫描配置--> <context:component-scan base-package="com.self"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--Spring声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="load*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="select*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="find*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--事务切面--> <aop:config> <!--切入点--> <aop:pointcut id="pt" expression="execution(* com.self.service.impl.*ServiceImpl.*(..))"/> <!--切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> </aop:config> </beans>
五、创建Web工程——项目为Web项目
依赖Service工程 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>noodle-parent</artifactId> <groupId>com.self</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>war</packaging> <artifactId>noodle-web</artifactId> <dependencies> <dependency> <groupId>com.self</groupId> <artifactId>noodle-service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
配置监听器和核心控制器
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置核心控制器 :DispatcherServlet --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- springmvc配置文件加载路径 1)默认状况下,读取WEB-INF下面的default-servlet.xml文件 2)能够改成加载类路径下(resources目录),加上classpath: --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:noodlespringmvc-servlet.xml</param-value> <!--<param-value>WEB-INF/simple-servlet.xml</param-value>--> </init-param> <!--init-param必须放在load-on-startup前,不然会报错:invalid content was found starting with element 'init-param'. One of '{"http://java.sun.com/xml/ns/javaee":run-as, "http://java.sun.com/xml/ns/javaee":security-role-ref}' is expected--> <!-- DispatcherServlet对象建立时间问题 1)默认状况下,第一次访问该Servlet时建立对象,默认是访问时建立,意味着在这个时间才去加载hellospringmvc-servlet.xml 2)能够改变为在项目启动时候就建立该Servlet,提升用户访问体验。 <load-on-startup>1</load-on-startup> 数值越大,对象建立优先级越低! (数值越低,越先建立) --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--从新配置Tomcat的DefaultServlet的映射路径--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.js</url-pattern> <url-pattern>*.png</url-pattern> </servlet-mapping> <!-- 配置spring监听器,用于加载applicationContext.xml(初始化SpringIOC容器) --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 字符编码过滤器 --> <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> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
注意:
Spring监听器读取的路径为classpath*:,这个语法指加载当前项目及依赖工程的全部符合条件的文件。由于applicationContext.xml分布在不一样的Maven工程,因此必须使用该语法加载!
noodlespringmvc-servlet.xml
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.扫描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 页面前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 页面后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.开启mvc注解驱动--> <!--不添加也能使用,高版本spring已经默认实现了。 在Spring中通常采用@RequestMapping注解来完成映射关系,要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例,这两个实例分别在类级别和方法级别处理。而<mvc:annotation-driven/>配置帮助咱们自动完成上述两个实例的注入。 --> <mvc:annotation-driven/> <!--<mvc:default-servlet-handler/>--> </beans> @RequestMapping("/user") @Controller public class UserController { @Autowired private UserService userService; /** * 查询全部用户 */ @RequestMapping("/list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入数据到request域 model.addAttribute("list", users); //model.addAttribute("list","用户数据"); //返回list.jsp页面 return "userList"; } }
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>显示用户数据</title> </head> <body> <h3>用户列表</h3> <table border="1"> <tr> <td>编号</td> <td>用户名</td> <td>帝国</td> <td>电话号码</td> <td>建立时间</td> </tr> <!-- items: 须要须要遍历的集合 var: 每一个对象的变量名称 --> <c:forEach items="${list}" var="user"> <tr> <td>${user.id}</td> <td>${user.name}</td> <td>${user.dept}</td> <td>${user.phone}</td> <td>${user.createTime}</td> </tr> </c:forEach> </table> </body> </html>
输出:
注意:当咱们配置项目到tomcat上时,在建立artifact时能够指定项目名称(不必定要是项目名)做为请求的路径,像这样接在localhost后面,http://localhost:8080/noodle/user/list。若是只是设置/ (斜杠)则直接在端口后面接请求地址。
疑问
Q:在springmvc容器的配置文件hellospringmvc-servlet.xml中配置开启mvc注解驱动的做用是什么?都做用在哪些地方?何时用到?
教程里的解释是在Spring中通常采用@RequestMapping注解来完成映射关系,要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例,这两个实例分别在类级别和方法级别处理。而mvc:annotation-driven/配置帮助咱们自动完成上述两个实例的注入。 可是在实践中咱们就算没有显式注册这两个bean实例或者在spring mvc配置的hellospringmvc-servlet.xml中加上 mvc:annotation-driven/这句配置也不妨碍咱们使用@RequestMapping注解来完成映射关系,为何?
<!-- 3.开启mvc注解驱动--> <mvc:annotation-driven/>
Q:什么叫Ant风格的路径匹配功能?
A: ANT通配符有如下三种:
通配符 说明
? 匹配任何单字符
匹配0或者任意数量的字符
** 匹配0或者更多的目录
例子:
URL路径 说明
/app/.x 匹配(Matches)全部在app路径下的.x文件
/app/p?ttern 匹配(Matches) /app/pattern 和 /app/pXttern,可是不包括/app/pttern
/**/example 匹配(Matches) /app/example, /app/foo/example, 和 /example
/app//dir/file. 匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java
/*/.jsp 匹配(Matches)任何的.jsp 文件
属性: 最长匹配原则(has more characters) 说明,URL请求/app/dir/file.jsp,如今存在两个路径匹配模式/*/.jsp和/app/dir/.jsp,那么会根据模式/app/dir/.jsp来匹配
参考
Q:RequestMappingHandlerMapping会被默认建立么?在什么状况下建立,标记有@RequestMapping("/hello") 注解时仍是扫描Controller时?
A:是在web.xml配置mvc:annotation-driven/时。RequestMappingHandlerMapping和RequestMappingHandlerAdapter会默认注册。
固然,通常状况下咱们是不须要配置mvc:annotation-driven/的,默认会注册,但当咱们web.xml中配置了其余如BeanNameUrlHandlerMapping处理映射器时,就要加这句,不然不会默认帮咱们注册,这个须要研究下代码是怎么个处理方式。
在不配置HandlerMapping 的状况下,容器默认会注册初始化BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping来处理映射。而HandlerAdapter会有三种,分别是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapter。
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
注意:若是有在web.xml中配置指定的HandlerMapping 和 HandlerAdapter 的话,则只注册配置的处理器。
mvc:annotation-driven的做用
Spring 3.0.x中使用了mvc:annotation-driven后,默认会帮咱们注册默认处理请求,参数和返回值的类,其中最主要的两个类:DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter ,分别为HandlerMapping的实现类和HandlerAdapter的实现类,从3.1.x版本开始对应实现类改成了RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
mvc:annotation-driven的做用参考
Q:若是咱们没有配置HandlerAdapter ,默认是建立什么类型的HandlerAdapter 来处理咱们的Controller呢?
A:默认不配置SimpleControllerHandlerAdapter, 也能处理Controller类型为org.springframework.web.servlet.mvc.Controller的接口,SimpleControllerHandlerAdapter会默认注册.
Q:保存HandlerMethod类型的容器mappingLookup为何要初始化为new LinkedHashMap<>();而不是HashMap<>()类型呢?出于什么考虑?LinkedHashMap和HashMap各类的使用场景和优点缺点是什么?
A:考虑动态添加的效率?
Q:转发和重定向的区别?
Q:在目前主流的三种 Web 服务交互方案中,REST 相比于SOAP(Simple Object Access protocol, 简单对象访问协议) 以及 XML-RPC 更加简单明了。了解下目前主流的Web 服务交互方案。
Q:什么叫 Payload 的编码?
Q:通常实践中的RESTful风格的请求开发是经过请求方式POST、GET等的不一样来区分的么?
Q:ApplicationContext和WebApplicationContext有什么区别?用他们去getBean()是同样的?
A:Spirng容器只有一个,spring和springmvc的配置能够互相放在各自的配置xml中,最后都做用在spring容器中。待详细了解。
Q:为何叫Spring MVC、MyBatis整合Spring?而不是反过来叫Spring MVC整合Spring呢?是随便叫仍是有什么区别?
Q:ContextLoaderListener的做用?
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
Q:@Repository注解在mybatis中有什么用么?通常不都是经过扫包来得到dao对象么?
//不须要加注解 //@Repository //@Mapper public interface UserMapper { List<User> getALlUsers(); }
其余:
一、md删除线使用:
若是段落上的文字要添加删除线,只须要在文字的两端加上两个波浪线 ~~ 便可 ~~shanchu.com~~
二、DispatcherServlet.properties ——DispatcherServlet初始化默认配置
org.springframework.web.servlet.DispatcherServlet#defaultStrategies jdk1.8 284行 # Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
三、IDEA的tomcat日志输出乱码问题的解决。
这是由于下载的tomcat8中\apache-tomcat-8.5.55\conf\logging.properties 配置默认编码是UTF-8.而Windows系统的默认编码格式是GBK,所以在对输出的字符打印时由于解码不对而致使的乱码。只要对logging.properties中的编码格式UTF-8配置注释掉便可。
参考
四、JDK1.8对接口的默认实现。
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } }