1. 流程
Spring MVC依靠的是DispatcherServlet,他是一个分发器,在请求过来的时候它负责分发请求给控制器,当控制器请求处理完成后,它负责根据逻辑视图名查找视图呈现结果
2.配置DispatcherServlet
web.xml中DispatcherServlet的配置
<!-- 定义Spring Dispatcher --> <servlet> <!-- 这个servlet-name需要与<servlet-name>-servlet.xml对应 --> <!-- 否则需要使用init-param指定配置文件 --> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring/config/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
DispatcherServlet的配置文件 dispatcher-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: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"> <!-- 开启Controller自动注册,必须写在这个文件里 --> <context:component-scan base-package="com.qunar.controller"/> <!-- 开启MVC注解功能 --> <mvc:annotation-driven /> <!-- 静态资源文件请求定向,例如请求是/static/test.js会自动定向到/WEB-INF/static/test.js --> <mvc:resources mapping="/static/**" location="/WEB-INF/static/" /> <mvc:default-servlet-handler/> <!-- 配置ControllerURL映射处理bean --> <!-- BeanNameUrlHandlerMappping 根据bean的名字将控制器映射到url --> <!-- ControllerBeanNameHandlerMapping 根据bean的名字将控制器映射到url,bean名字不需要遵循URL约定 --> <!-- ControllerClassNameHandlerMapping 将控制器类名作为URL基础映射到URL --> <!-- DefaultAnnotationHandlerMapping 将请求映射到使用@RequestMapping注解的控制器和控制器方法 --> <!-- SimpleUrlHandlerMapping 使用定义在Spring应用上下文的属性集合将控制器映射给URL --> <!-- 加入不设置这个类,则默认使用 BeanNameUrlHandlerMappping 和 DefaultAnnotationHandlerMapping --> <!--<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />--> <!-- 设置视图解析器 --> <!--InternalResourceViewResolver 使用指定前缀和后缀拼接Controller返回的String得到视图路径 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 设置Tiles视图解析器 --> <!--<bean class="org.springframework.web.servlet.view.tiles2.TilesViewResolver" />--> <!--<!– 设置Tiles视图解析器配置 –>--> <!--<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" >--> <!--<property name="definitions">--> <!--<list>--> <!--<value>/WEB-INF/views/**/views.xml</value>--> <!--</list>--> <!--</property>--> <!--</bean>--> </beans>
3.applicationContext配置
<?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" 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"> <!-- 自动注册 --> <context:component-scan base-package="com.qunar" > <!-- 排除由ServletDispatcher管理的controller包和MyBatis管理的mapper包 --> <!--<context:exclude-filter type="regex" expression=".controller.*" />--> <!--<context:exclude-filter type="regex" expression=".mapper.*" />--> <context:include-filter type="regex" expression=".bean.*" /> <context:include-filter type="regex" expression=".service.*" /> <!-- aop中切面包含的bean似乎只能通过显示的bean注册 不能自动注册,所以此处不写,直接移动到qunarBeans.xml文件 --> </context:component-scan> <!-- 自动扫描并注册Mapper为MapperFactoryBean,效果和spring的context:component-scan差不多 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.qunar.mapper" /> </bean> <!-- 原先所有的Mapper类都封装成这个MapperFactoryBean --> <!--<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">--> <!--<!– 指定sqlSession –>--> <!--<property name="sqlSessionFactory" ref="sqlSessionFactory" />--> <!--<!– 指定映射的实际mapper接口 –>--> <!--<property name="mapperInterface" value="com.qunar.mapper.UserMapper" />--> <!--</bean>--> <!--<bean id="articleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">--> <!--<property name="sqlSessionFactory" ref="sqlSessionFactory" />--> <!--<property name="mapperInterface" value="com.qunar.mapper.ArticleMapper" />--> <!--</bean>--> <!-- 配置spring mutipart解析器,用于文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name="maxUploadSize" value="500000" /> </bean> </beans>
4.典型控制器介绍
package com.qunar.controller; import com.qunar.bean.Article; import com.qunar.bean.User; import com.qunar.mapper.ArticleMapper; import com.qunar.mapper.UserMapper; import com.qunar.service.UserServiceIntf; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-19 * Time: 下午1:13 * To change this template use File | Settings | File Templates. */ @Controller // 自动注册Controller @RequestMapping("/user") // 根url public class UserController { @Autowired private ArticleMapper articleMapper; @Autowired private UserServiceIntf userService; @RequestMapping("/list") // 映射URL public ModelAndView listAll() { System.out.println("Execute listAll()"); List<Article> articleList = articleMapper.getUserAticles(1); ModelAndView mav = new ModelAndView("list"); mav.addObject("articleList", articleList); userService.buyTicket(1); userService.killUser(1); userService.trickUser(1); return mav; } // 标明url和请求方法 @RequestMapping(value = "/showUser", method = RequestMethod.GET) // @RequestParam 标明userId的值需要通过reqUserId参数获取 // 加入没有用@RequestParam,则形参值通过同名的传入参数获取 public String showUser( @RequestParam(value = "reqUserId", defaultValue = "2") int userId, Map<String, Object> model) { User user = userService.getUserById(userId); model.put("user", user); System.out.println(user); return "show"; } // 显示添加用户的页面 // params参数标明该方法只接受带有new参数的请求 @RequestMapping(params = "new", method = RequestMethod.GET) public String showAddUser(Model model) { // 放入一个空User用于添加用户页面的modelAttribute参数使用 model.addAttribute("user", new User()); return "addUser"; } // 添加用户方法 @RequestMapping(value = "/addUser", method = RequestMethod.POST) // @Valid标志需要验证这个user public String addUser(@Valid User user, BindingResult bindingResult, @RequestParam(value = "image", required = false) MultipartFile image) { // 参数校验失败返回添加页面 if (bindingResult.hasErrors()) return "addUser"; // 处理上传文件 // 验证文件 if (!image.isEmpty()) { if (!image.getContentType().equals("image/jpeg")) { throw new RuntimeException("Only jpg images accepted"); } try { File file = new File(System.getProperty("test.root") + File.separator + "resources" + File.separator + image.getName()); FileUtils.writeByteArrayToFile(file, image.getBytes()); } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } userService.saveUser(user); // 动态重定向,可防止重复提交(使用Forward,则可能会重复提交,因为共享了Request和Response) return "redirect:/user/" + user.getUsername(); } // 处理动态重定向请求 @RequestMapping(value = "/{username}", method = RequestMethod.GET) // @PathVariable表示username参数来自url,而value={username}则将这个参数填充到URL public String showProfile(@PathVariable String username, Model model) { model.addAttribute("username", username); System.out.println(username); return "show"; } public void setArticleMapper(ArticleMapper articleMapper) { this.articleMapper = articleMapper; } public void setUserService(UserServiceIntf userService) { this.userService = userService; } }
5. 添加用户页面
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %> <%-- Created by IntelliJ IDEA. User: zhenwei.liu Date: 13-7-24 Time: 下午2:28 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title></title> </head> <body> <sf:form action="/user/addUser" method="POST" modelAttribute="user" enctype="multipart/form-data"> <label>username</label><sf:input path="username" /> <sf:errors path="username" cssClass="error" /> <br> <label>userAge</label><sf:input path="userAge" /><br> <sf:errors path="userAge" cssClass="error" /> <br> <label>userAddress</label><sf:input path="userAddress" /><br> <sf:errors path="userAddress" cssClass="error" /> <br> <label>image</label><input name="image" type="file"><br> <input type="submit" /> </sf:form> </body> </html>
5.注意的问题
很重要的一个问题是需要注意库依赖引入,引入以后要加入Artifact里面,否则会出现很多莫名其妙的问题,下面是几个需要用到的典型的maven lib
验证器需要用到的lib
<!-- 验证器 --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.2.0.Final</version> </dependency>
文件上传和io需要用到的lib
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>