Spring MVC框架入门(三)

Spring MVC框架介绍

Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。

Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器。


Spring MVC运行原理

1.客户端请求提交到DispatcherServlet

2.由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller

扫描二维码关注公众号,回复: 1908905 查看本文章

3.DispatcherServlet将请求提交到Controller

4.Controller调用业务逻辑处理后,返回ModelAndViewDispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

5.视图负责将结果显示到客户端


Spring MVC优点

1.容易和其它View框架(Titles等)无缝集成,采用IOC便于测试。

2.它是一个典型的教科书式的mvc构架,而不像struts等都是变种或者不是完全基于mvc系统的框架,spring适用于初学者或者想了解mvc的人。

3.它和tapestry一样是一个纯正的servlet系统,这也是它和tapestry相比struts所没有的优势。而且框架本身有代码,而且看起来也不费劲比较简单可以理解。


代码实现

实例基于Spring MVC 5.0.7,JDK1.8

GitHub地址:https://github.com/The-ProgramLife/Demo/tree/master/SpringMVC

新建Java Maven WebApp Project

在pom.xml引入Spring MVC依赖与Servlet依赖

		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.1</version>
			<scope>provided</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.0.7.RELEASE</version>
		</dependency>

修改WEB-INF目录下的web.xml

配置Spring MVC的入口 DispatcherServlet,把所有的请求都提交到该Servlet

<?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_3_0.xsd"
	id="WebApp_ID" version="3.0">

	<servlet>
		<!-- 在没有显式指定的情况下映射配置文件引用此名称 -->
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- 设置编码,解决中文乱码问题 -->
	<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>
	</filter>

	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

</web-app>

在WEB-INF目录下创建 springmvc-servlet.xml

这是Spring MVC的映射配置文件,因为在web.xml中没有显示指定文件,默认使用与<servlet-name>相同的名称。

<?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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<!-- 访问路径/index会交给id=indexController的bean处理 -->
	<bean id="simpleUrlHandlerMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="urlMap">
			<props>
				<prop key="index">indexController</prop>
			</props>
		</property>
	</bean>
	<bean id="indexController" class="controller.IndexController"></bean>

</beans>

新建IndexController类(控制器)

实现Controller接口,覆写handleRequest方法通过 ModelAndView 对象把模型和视图结合在一起。

public class IndexController implements Controller{

	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		//通过 ModelAndView 对象把模型和视图结合在一起
		ModelAndView modelAndView = new ModelAndView("index.jsp");
		modelAndView.addObject("message", "Hello Spring MVC");
		return modelAndView;
	}

}

修改WebContent目录下的index.jsp

使用EL表达式读出模型数据message

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" isELIgnored="false"%>
	
<html>
<body>
	<h2>${message}</h2>
</body>
</html>

部署在tomcat中,重启测试


Spring MVC视图解析

上面使用new ModelAndView("index.jsp");定位视图,视图解析可以做到不添加后缀定位视图

修改springmvc-servlet.xml

添加视图解析组件

	<!-- 将视图定位在/WEB-INF/page/*.jsp -->
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 前缀 -->
		<property name="prefix" value="/WEB-INF/page/" />
		<!-- 后缀 -->
		<property name="suffix" value=".jsp" />
	</bean>

修改IndexController.handleRequest()方法

	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		//通过 ModelAndView 对象把模型和视图结合在一起
		ModelAndView modelAndView = new ModelAndView("index");
		modelAndView.addObject("message", "Hello Spring MVC");
		return modelAndView;
	}

在WEB-INF下新建目录page,把index.jsp移动到 WEB-INF/page 目录下就完成了

视图链

如果需要定位多个视图位置,就需要使用到视图链,将视图解析器串成一条链,只需再添加一个解析器即可。

修改springmvc-servlet.xml

再添加一个Excel解析器

<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
    <!--指定次序,值越大越靠后-->
    <property name="order" value="1"/>
    <property name="location" value="/WEB-INF/views.xml"/>
</bean>

视图重定向

修改IndexController类

添加jump()方法,这里使用到了注解,将在下面进行讲解

	@RequestMapping("/jump")
	public ModelAndView jump() {
		ModelAndView modelAndView = new ModelAndView("redirect:/index");
		return modelAndView;
	}


Spring MVC注解

新建AnnotationTest类

@Controller	//表示该类是一个控制器
public class AnnotationTest {

	@RequestMapping("/annoindex")	// 表示路径/annoindex会映射到该方法上
	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		ModelAndView modelAndView = new ModelAndView("anno_index");
		modelAndView.addObject("message", "Hello Spring MVC");
		return modelAndView;
	}
}

修改springmvc-servlet.xml

添加以下代码

	<!-- 从包annotation下扫描有@Controller注解的类 -->
	<context:component-scan base-package="annotation"></context:component-scan>
	<!-- 开启注解驱动 -->
	<mvc:annotation-driven></mvc:annotation-driven>

新建anno_index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${message}
</body>
</html>


Spring MVC Session

Session在用户登录,一些特殊场合在页面间传递数据的时候会经常用到。下面利用Session记住访问次数功能。

新建SessionTest类

为方法check()提供参数HttpSession session,这样就可以在方法体中使用session了

@Controller
public class SessionTest {
	
	@RequestMapping("/check")
	public ModelAndView check(HttpSession session) {
		Integer i = (Integer)session.getAttribute("count");
		if (i == null)
			i = 0;
			i++;
			session.setAttribute("count", i);
			ModelAndView modelAndView = new ModelAndView("check");
			return modelAndView;
	}

}

新建check.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
session中记录的访问次数:${count}
</body>
</html>


Spring MVC文件上传

在pom.xml引入文件上传依赖

		<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.6</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.3</version>
		</dependency>

配置web.xml允许访问*.jpg

因为配置springmvc的servlet的时候,使用的路径是"/",导致静态资源在默认情况下不能访问,所以要加上这一段,允许访问jpg。 并且必须加在springmvc的servlet之前

	<!-- 允许访问*.jpg -->
	<servlet-mapping>
		<servlet-name>default</servlet-name>
		<url-pattern>*.jpg</url-pattern>
	</servlet-mapping>

配置springmvc-servlet.xml

	<!-- 开放对上传功能的支持 -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

新建upload,jsp

上传页面,需要注意的是form 的两个属性必须提供method="post" 和 enctype="multipart/form-data" 缺一不可上传组件 增加一个属性 accept="image/*" 表示只能选择图片进行上传

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="uploadImage" method="post" enctype="multipart/form-data">
选择图片:<input type="file" name="image" accept="image/*" /> <br> 
         <input type="submit" value="上传">
	</form>
</body>
</html>

新建UploadedImageFile类

在UploadedImageFile中封装MultipartFile类型的字段 image ,用于接受页面的注入这里的字段 image必须和上传页面upload.jsp中的image<input type="file" name="image" accept="image/*" />保持一致

public class UploadedImageFile {

	private MultipartFile image;

	public MultipartFile getImage() {
		return image;
	}

	public void setImage(MultipartFile image) {
		this.image = image;
	}

}

新建UploadController类

@Controller
public class UploadController {

	@RequestMapping("/uploadImage")
	public ModelAndView upload(HttpServletRequest request, UploadedImageFile file)
			throws IllegalStateException, IOException {
		String name = new Random(500).toString();	//随机命名
		String newFileName = name + ".jpg";
		//获取到web目录下的image目录,用于存放上传后的文件
		File newFile = new File(request.getServletContext().getRealPath("/image"), newFileName);
		newFile.getParentFile().mkdirs();
		//复制文件
		file.getImage().transferTo(newFile);

		ModelAndView mav = new ModelAndView("showUploadedFile");
		mav.addObject("imageName", newFileName);
		return mav;
	}

}

新建showUploadedFile.jsp

显示上传的图片

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
《<img src="image/${imageName}">
</body>
</html>


Spring MVC拦截器

Spring的处理器映射机制包含了处理器拦截器。拦截器在你需要为特定类型的请求应用一些功能时可能很有用,比如,检查用户身份等。

新建拦截器类IndexInterceptor

public class IndexInterceptor extends HandlerInterceptorAdapter {

	/**
	 * 在业务处理器处理请求之前被调用 如果返回false 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链 如果返回true
	 * 执行下一个拦截器,直到所有的拦截器都执行完毕 再执行被拦截的Controller 然后进入拦截器链,
	 * 从最后一个拦截器往回执行所有的postHandle() 接着再从最后一个拦截器往回执行所有的afterCompletion()
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO Auto-generated method stub
		System.out.println("preHandle(), 在访问Controller之前被调用");
		return true;
	}

	/**
	 * 在业务处理器处理请求执行完成后,生成视图之前执行的动作 可在modelAndView中加入数据,比如当前时间
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("postHandle(), 在访问Controller之后,访问视图之前被调用,这里可以注入一个时间到modelAndView中,用于后续视图显示");
		modelAndView.addObject("date", "由拦截器生成的时间:" + new Date());
	}

	/**
	 * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
	 * 
	 * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
	 */

	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("afterCompletion(), 在访问视图之后被调用");
	}

}

修改springmvc-servlet.xml

对/index路径进行拦截

	<!-- 配置拦截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/index" />
			<!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
			<bean class="interceptor.IndexInterceptor"></bean>
		</mvc:interceptor>
		<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 --> 
	</mvc:interceptors>

修改 index.jsp

打印拦截器放进去的日期

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" isELIgnored="false"%>
	
<html>
<body>
	<h2>${message}</h2>
	<p>${date}</p>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/the_programlife/article/details/80708784