10springMVC
-
Spring MVC 也叫 Spring Web MVC ,属于展示层框架。SpringMVC 是 Spring 框架的一部分。
Spring Web MVC 框架提供了 MVC (模型 - 视图 - 控制器) 架构和用于开发灵活和松散耦合的 Web 应用程序的组件。 MVC 模式导致应用程序的不同方面(输入逻辑,业务逻辑和 UI 逻辑)分离,同时提供这些元素之间的松散耦合。
- 模型 (Model):封装了应用程序数据,通常它们将由 POJO 类组成。
- 视图 (View):负责渲染模型数据,一般来说它生成客户端浏览器可以解释 HTML 输出。
- 控制器 (Controller):负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染。
- DispatcherServlet 组件类
Spring Web MVC 框架是围绕 DispatcherServlet 设计的,它处理所有的 HTTP 请求和响应。 Spring Web MVC DispatcherServlet 的请求处理工作流如下图所示:
以下是对应于到 DispatcherServlet 的传入 HTTP 请求的事件顺序:
- 在接收到 HTTP 请求后,DispatcherServlet 会查询 HandlerMapping 以调用相应的 Controller。
- Controller 接受请求并根据使用的 GET 或 POST 方法调用相应的服务方法。 服务方法将基于定义的业务逻辑设置模型数据,并将视图名称返回给 DispatcherServlet。
- DispatcherServlet 将从 ViewResolver 获取请求的定义视图。
- 当视图完成,DispatcherServlet 将模型数据传递到最终的视图,并在浏览器上呈现。
所有上述组件,即: HandlerMapping,Controller 和 ViewResolver 是 WebApplicationContext 的一部分,它是普通 ApplicationContext 的扩展,带有 Web 应用程序所需的一些额外功能。
- spring整合springMVC
- pom
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.17.RELEASE</version> </dependency>
- web.xml
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<servlet> <servlet-name>springServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/spring-mvc*.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
- 配置springMVC
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<description>Spring MVC Configuration</description>
<!-- 加载配置属性文件 -->
<context:property-placeholder ignore-unresolvable="true" location="classpath:myshop.properties"/>
<!-- 使用 Annotation 自动注册 Bean,只扫描 @Controller -->
<context:component-scan base-package="com.lusifer.myshop" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 默认的注解映射的支持 -->
<mvc:annotation-driven />
<!-- 定义视图文件解析 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="${web.view.prefix}"/>
<property name="suffix" value="${web.view.suffix}"/>
</bean>
<!-- 静态资源映射 -->
<mvc:resources mapping="/static/**" location="/static/" cache-period="31536000"/>
</beans>
相关配置说明
context:property-placeholder
:动态加载属性配置文件以变量的方式引用需要的值context:component-scan
:当前配置文件为 MVC 相关,故只需要扫描包含@Controller
的注解即可,由于spring-context.xml
配置文件中也配置了包扫描,所以还需要排除@Controller
的注解扫描。InternalResourceViewResolver
:视图文件解析器的一种,用于配置视图资源的路径和需要解释的视图资源文件类型,这里有两个需要配置的属性prefix
(前缀)以及suffix
(后缀)。
prefix
:配置视图资源路径,如:/WEB-INF/views/
suffix
:配置视图资源类型,如:.jsp
mvc:resources
:静态资源映射,主要用于配置静态资源文件存放路径,如:JS、CSS、Image 等
myshop.properties
#============================#
#==== Framework settings ====#
#============================#
# \u89c6\u56fe\u6587\u4ef6\u5b58\u653e\u8def\u5f84
web.view.prefix=/WEB-INF/views/
web.view.suffix=.jsp
去掉spring配置的重复扫描
<!-- 使用 Annotation 自动注册 Bean,在主容器中不扫描 @Controller 注解,在 SpringMVC 中只扫描 @Controller 注解。-->
<context:component-scan base-package="com.funtl.my.shop">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
LoginController
package com.zhou.my.shop.web.controller;
import com.zhou.my.shop.commons.context.SpringContext;
import com.zhou.my.shop.commons.utils.CookieUtils;
import com.zhou.my.shop.entity.User;
import com.zhou.my.shop.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginController extends HttpServlet {
SpringContext springContext=new SpringContext();
private UserService userService= (UserService) springContext.getBean("userService");
private static final String COOKIE_NAME_USER_INFO="userInfo";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userInfo=CookieUtils.getCookieValue(req,COOKIE_NAME_USER_INFO);
if(userInfo!=null){
String[] userInfoArray=userInfo.split(":");
String email=userInfoArray[0];
String password=userInfoArray[1];
req.setAttribute("email",email);
req.setAttribute("password",password);
req.setAttribute("isRemeber",true);
}
resp.sendRedirect(req.getContextPath()+"/index.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String email=req.getParameter("email");
String password=req.getParameter("password");
boolean isRemeber=req.getParameter("isRemeber")==null?false:true;
User admin=userService.login(email,password);
if(admin!=null){
if(isRemeber){
//用户信息存储一周
CookieUtils.setCookie(req,resp,COOKIE_NAME_USER_INFO,String.format("%s:%s",email,password),7*24*60*60);
}
resp.sendRedirect(req.getContextPath()+"/main.jsp");
}else{
String message="找不到该用户";
req.getSession().setAttribute("message",message);
resp.sendRedirect(req.getContextPath()+"/index.jsp");
}
}
}
- Spring拦截器:Spring Web MVC 的处理器拦截器,类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
- 常见应用场景
- 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等
- 权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面
- 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间
- 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现
- SpringMVC拦截器:Spring MVC 拦截器需要实现
HandlerInterceptor
接口,该接口定义了 3 个方法,分别为preHandle()
、postHandle()
和afterCompletion()
,咱们就是通过重写这 3 个方法来对用户的请求进行拦截处理的。
preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)
:该方法在请求处理之前进行调用。Spring MVC 中的 Interceptor 是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor 。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的preHandle
方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为false
时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为true
时,就会继续调用下一个 Interceptor 的preHandle
方法,如果已经是最后一个 Interceptor 的时候,就会是调用当前请求的 Controller 中的方法。postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)
:通过preHandle
方法的解释咱们知道这个方法包括后面要说到的afterCompletion
方法都只能在当前所属的 Interceptor 的preHandle
方法的返回值为true
的时候,才能被调用。postHandle
方法在当前请求进行处理之后,也就是在 Controller 中的方法调用之后执行,但是它会在DispatcherServlet
进行视图返回渲染之前被调用,所以咱们可以在这个方法中对 Controller 处理之后的ModelAndView
对象进行操作。postHandle
方法被调用的方向跟preHandle
是相反的,也就是说,先声明的 Interceptor 的postHandle
方法反而会后执行。afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
:也是需要当前对应的 Interceptor 的preHandle
方法的返回值为true
时才会执行。因此,该方法将在整个请求结束之后,也就是在DispatcherServlet
渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理的工作。
- 创建登录拦截器
import com.funtl.my.shop.entity.User; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 登录拦截器 * <p>Title: LoginInterceptor</p> * <p>Description: </p> * * @author Lusifer * @version 1.0.0 * @date 2018/6/12 5:44 */ public class LoginInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { User user = (User) httpServletRequest.getSession().getAttribute("user"); // 判断用户是否登录 if (user == null) { // 用户未登录,重定向到登录页 httpServletResponse.sendRedirect("/login"); return false; } // 放行 return true; } public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { // 如果请求来自登录页 if (modelAndView.getViewName().endsWith("login")) { // 则直接重定向到首页不再显示登录页 httpServletResponse.sendRedirect("/main"); } } public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
- spring-MVC.xml
<!-- 拦截器配置,拦截顺序:先执行后定义的,排在第一位的最后执行。--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/static/**"/> <mvc:exclude-mapping path="/login"/> <bean class="com.funtl.my.shop.web.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
mvc:interceptor
:定义一个拦截器
mvc:mapping
:映射路径,需要拦截的请求路径mvc:exclude-mapping
:需要排除的请求路径,比如登录页本身是不需要拦截的,这里还包括了静态资源路径也是不需要拦截的bean class
:配置指定的拦截器对象
- Maven模块化开发:在多人协同开发时,特别是规模较大的项目,为了方便日后的代码维护和管理,我们会将每个开发人员的工作细分到具体的功能和模块上。随着项目的不断扩大,模块也会越来越多,后续会更加难以维护和扩展,为了应对这种情况后期我们还会采用微服务架构的方式进行开发。
以当前教程为例,我们可以将模块划分为如下形式:
- 统一的依赖管理(dependencies)
- 通用的工具类(commons)
- 领域模型(domain)
- 管理后台(admin)
- 商城前端(ui)
- 接口模块(api)
- 创建根项目,并建立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>org.example</groupId> <artifactId>my-shop-project</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>my-shop-dependencies</module> <module>my-shop-commons</module> <module>my-shop-domain</module> <module>my-shop-web-admin</module> <module>my-shop-web-ui</module> <module>my-shop-web-api</module> </modules> </project>
- 创建统一依赖管理my-shop-dependencies
<?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> <parent> <groupId>org.example</groupId> <artifactId>my-shop-project</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>my-shop-dependencies</artifactId> <packaging>pom</packaging> <name>my-shop-dependencies</name> <description></description> <properties> <!-- 环境配置 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <!-- 统一的依赖管理 --> <commons-lang3.version>3.5</commons-lang3.version> <jstl.version>1.2</jstl.version> <log4j.version>1.2.17</log4j.version> <servlet-api.version>3.1.0</servlet-api.version> <slf4j.version>1.7.25</slf4j.version> <spring.version>4.3.17.RELEASE</spring.version> </properties> <dependencyManagement> <dependencies> <!-- Spring Begin --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring End --> <!-- Servlet Begin --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <!-- Servlet End --> <!-- Log Begin --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <!-- Log End --> <!-- Commons Begin --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> <!-- Commons End --> </dependencies> </dependencyManagement> <build> <plugins> <!-- Compiler 插件, 设定 JDK 版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${project.build.sourceEncoding}</encoding> <showWarnings>true</showWarnings> </configuration> </plugin> </plugins> <!-- 资源文件配置 --> <resources> <resource> <directory>src/main/java</directory> <excludes> <exclude>**/*.java</exclude> </excludes> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> </build> </project>
- 创建工具类my-shop-commons
<?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> <parent> <groupId>com.funtl</groupId> <artifactId>my-shop-dependencies</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../my-shop-dependencies/pom.xml</relativePath> </parent> <artifactId>my-shop-commons</artifactId> <packaging>jar</packaging> <name>my-shop-commons</name> <description></description> </project>
- 创建领域模型my-shop-domain
<?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> <parent> <groupId>org.example</groupId> <artifactId>my-shop-dependencies</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../my-shop-dependencies/pom.xml</relativePath> </parent> <artifactId>my-shop-domain</artifactId> <packaging>jar</packaging> <name>my-shop-domain</name> <description></description> <dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> </dependencies> </project>
- 创建后台管理my-shop-web-admin
<?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> <parent> <groupId>org.example</groupId> <artifactId>my-shop-dependencies</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../my-shop-dependencies/pom.xml</relativePath> </parent> <artifactId>my-shop-web-admin</artifactId> <packaging>war</packaging> <name>my-shop-web-admin</name> <description></description> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>my-shop-domain</artifactId> <version>${project.parent.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.example</groupId> <artifactId>my-shop-commons</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <!-- Servlet Begin --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!-- Servlet End --> </dependencies> </project>
- 创建商城前端my-shop-web-ui
<?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> <parent> <groupId>org.example</groupId> <artifactId>my-shop-dependencies</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../my-shop-dependencies/pom.xml</relativePath> </parent> <artifactId>my-shop-web-ui</artifactId> <packaging>war</packaging> <name>my-shop-web-ui</name> <description></description> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>my-shop-domain</artifactId> <version>${project.parent.version}</version> </dependency> </dependencies> </project>
- 创建接口模块my-shop-web-api
<?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> <parent> <groupId>org.example</groupId> <artifactId>my-shop-dependencies</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../my-shop-dependencies/pom.xml</relativePath> </parent> <artifactId>my-shop-web-api</artifactId> <packaging>war</packaging> <name>my-shop-web-api</name> <description></description> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>my-shop-domain</artifactId> <version>${project.parent.version}</version> </dependency> </dependencies> </project>
actId>my-shop-dependencies
```<version>1.0.0-SNAPSHOT</version> <relativePath>../my-shop-dependencies/pom.xml</relativePath> </parent> <artifactId>my-shop-web-api</artifactId> <packaging>war</packaging> <name>my-shop-web-api</name> <description></description> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>my-shop-domain</artifactId> <version>${project.parent.version}</version> </dependency> </dependencies>
- Spring-MVC 表单标签库