- 什么是SpringMvc
- 是spring框架的一个模块,springmvc和spring之间不需要中间整合层进行整合
- 是一个基于mvc的web框架
- mvc是一个设计模式
- mvc在b/s系统下的应用
- M:模型,包括pojo、action、service、dao
- V:视图
- C:控制器,接收用户的请求、响应
- 前端控制器(DispatcherServlet)
- 作用:接收请求,响应结果, 相当于转发器
- 处理器映射器(HandlerMapping)
- 作用:根据请求的url查找Handler
- 处理器适配器(HandlerAdapter)
- 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
- 注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才能正确执行Handler
- 视图解析器(View resolver)
- 作用:进行时图解析,根据逻辑视图名解析成真正的视图(View)
- 视图(View)
- View是一个接口,实现类支持不同的View类型
- 入门
- 导入spring-webmvc-4.3.5.RELEASE.jar
- 若报错ClassNotFoundException: org.springframework.web.context.WebApplicationContext,导入spring-web-4.3.5.RELEASE.jar
- Handler编写和调试
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <!-- 配置Handler --> <bean class="cn.muriel.auto.controller.UserController" name="/userController.action"/> <!-- 配置处理器映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- 配置处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 配置视图解析器 解析jsp解析,默认使用jstl标签 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/> </beans> public class UserController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("service/service.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); userService.selectAllUser(); ModelAndView modelAndView = new ModelAndView(); //如果不设置ViewName的话,就会404加参数 //如果url错误就报404 modelAndView.setViewName("WEB-INF/jsp/userList.jsp"); return modelAndView; } }
- 非注解的处理器映射器
<!-- 配置Handler --> <bean class="cn.muriel.auto.controller.UserController" name="/userController.action" id="userController"/> <!-- 配置处理器映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- 多个映射器可以并存,前端控制器判断url能让那些映射器映射,就让正确的映射器处理 所有的映射器都实现HandlerMapping接口 --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/userController.action">userController</prop> </props> </property> </bean>
- 非注解的处理器适配器
<!-- 配置处理器适配器,实现Controller接口 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> public class UserController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { } }
- 注解处理器映射器和处理器适配器
- 使用注解的映射器不用在xml中配置url和handler的映射关系。注解的处理器映射器和处理器适配器必须成对使用
<!-- 配置Handler,配置单个handler --> <bean class="cn.muriel.auto.controller.FoodController" /> <!-- 注解开发中建议使用组建扫名描,进行handler扫描配置 --> <context:component-scan base-package="cn.muriel.auto.controller"/> <!-- 注解映射器 在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器 在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping注解映射器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 注解适配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- mvc:annotation-driven代替上边注解映射器和注解适配器配置, 它默认加载很多的参数绑定方法 --> <mvc:annotation-driven></mvc:annotation-driven> //使用Controller标识它是一个控制器 @Controller public class FoodController { //一般建议将url和方法写成一样,控制器映射器 @RequestMapping("/selectAllFood") public ModelAndView selectAllFood(){ ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("WEB-INF/jsp/foodList.jsp"); return modelAndView; } }
- 使用注解的映射器不用在xml中配置url和handler的映射关系。注解的处理器映射器和处理器适配器必须成对使用
- 视图解析器
<!-- 配置视图解析器 解析jsp解析,默认使用jstl标签 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置Jstl,若与mvc:annotation-driven不需要配置, <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> --> <!-- 配置前缀 --> <property name="prefix" value="WEB-INF/jsp/"/> <!-- 配置后缀 --> <property name="suffix" value=".jsp"/> </bean> //使用Controller标识它是一个控制器 @Controller public class FoodController { //一般建议将url和方法写成一样,控制器映射器 @RequestMapping("/selectAllFood") public ModelAndView selectAllFood(){ ModelAndView modelAndView = new ModelAndView(); //因为在springmvc.xml中配置了前缀和后缀,所以原格式WEB-INF/jsp/foodList.jsp可以改为foodList modelAndView.setViewName("foodList"); return modelAndView; } }
- 服务端校验
- 控制层(controller):校验页面请求的参数的合法性。在服务端控制层controller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
- 业务层(service):主要校验关键业务参数,仅限于service接口中使用的参数
- 持久层(dao):一般不校验
- springmvc一般使用的是hibernate的validation的校验框架
- 导入hibernate-validator-6.0.16.Final.jar、hibernate-validator-annotation-processor-6.0.16.Final.jar、jboss-logging-3.3.2.Final.jar、validation-api-2.0.1.Final.jar
- 异常处理
- springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理
- 全局异常处理器
- 思路
- 系统遇到异常,在程序中手动抛出,dao抛出service、service给controller、controller抛给前端控制器,前端控制器调用全局异常处理器
- 解析出异常类型
- 如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示
- 如果该异常类型不是系统自定义异常,构造一个自定义的异常类型(信息为“未知错误”)
- 思路
- 如果与业务功能相关的异常,建议在service中抛出异常;如果与业务功能无关的异常,建议在controller中抛出异常
/** * 系统自定义异常类,针对预期的异常,需要在程序抛出此类的异常 */ public class CustomException extends Exception { //异常信息 private String message; /** * Constructs a new exception with {@code null} as its detail message. * The cause is not initialized, and may subsequently be initialized by a * call to {@link #initCause}. */ public CustomException(String message) { this.message = message; } @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } /** * 全局异常处理器 */ public class CustomExceptionResolve implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { //创建一个自定义异常对象 CustomException customExcetion = null; //判断异常类型是否是系统自定义异常 if (e instanceof CustomException) customExcetion = (CustomException) e; else customExcetion = new CustomException("未知异常"); //获取错误信息 String errorMessage = customExcetion.getMessage(); //创建一个ModelandView对象 ModelAndView modelAndView = new ModelAndView(); //将错误信息传递到页面 modelAndView.addObject(errorMessage); //设置页面 modelAndView.setViewName("error"); return modelAndView; } } <!-- 在springmvc中进行注册 --> <!-- 配置全局异常处理器 --> <bean class="cn.muriel.ssm.exception.CustomExceptionResolve"></bean>
- 上传图片
- 在页面form中提交enctype="multipart/form-data"的数据时,需要springmvc对multipart类型的数据进行分析
- 在springmvc.xml中配置multipart类型解析器,若不配置参数绑定会失败,无法传递参数
- 导入commons-fileupload-1.4.jar、commons-io-2.6.jar
- requestBody和responseBody实现与json交互
- 请求json、输出json
/** * @ResponseBody: * @RequestBody:将请求的商品信息json串转成指定对象 * @param userCustom * @return */ @RequestMapping(value = "/insertUser",method = RequestMethod.POST) public @ResponseBody UserCustom insertUser(@RequestBody UserCustom userCustom){ JSONObject jsonObject = JSONObject.fromObject(userCustom); System.out.println(jsonObject); return userCustom; }
- 请求key/value、输出json
- 若报错HttpMediaTypeNotSupportedException,则导入jackson-databind-2.9.8.jar
- 若报错java.lang.NoClassDefFoundError: com/fasterxml/jackson/annotation/JsonView,则导入jackson-annotations-2.9.8.jar
- 配置json转换器,导入jackson-core-2.9.8.jar、jackson-mapper-asl-1.9.13.jar、jackson-databind-2.9.8.jar、jackson-annotations-2.9.8.jar
<!-- json转换器配置,若使用<mvc:annotation-driven/>则无需进行配置 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> </bean> </list> </property> </bean>
- 请求json、输出json
- spring对RESTful支持
- RESTful架构,就是一种互联网软件框架,它结构清晰、符合标准、易于理解、扩展方便。
- RESTfule(Representational State Transfer)其实就是一个开发理念,是对http的很好诠释。
- Http四种请求方法
- GET:获取资源
- POST:新建资源,即更新资源
- PUT:更新资源
- DELETE:删除资源
- 思路:
- 不管是删除、添加、更新使用的url是一致的,区别在于http的方法设置为delete、post、get、put
- 后台需要判断http的方法,再执行相应操作
在web.xml进行RESTful控制器配置 <!-- 配置Restful控制器 --> <servlet> <servlet-name>springmvc_rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc_rest</servlet-name> <!-- --> <url-pattern>/</url-pattern> </servlet-mapping> /** * /deleteUserById/{id}里面的{id}表示将这个位置的参数传到@PathVariable指定名称中 * * @param id * @PathVariable:用于将请求URL中的模版变量映射到功能处理方法的参数上 通过在方法中使用@pathVariable获取{xxx}中的xxx变量 */ @RequestMapping("/deleteUserById/{id}") public @ResponseBody UserCustom deleteUserById(@PathVariable("id") Integer id) { UserCustom userCustom = new UserCustom(); userCustom.setId(id); System.out.println("id=" + id); return userCustom; }
- 注意:若使用Restful的方法返回值不要为void,不然可能会去寻找jsp资源,报404
- 通过RESTful访问静态资源,要在springmvc.xml配置静态资源解析,否则会报404
<!-- 静态资源解析,包括JS、css、img等等 --> <mvc:resources mapping="/images/**" location="WEB-INF/images/"/>
- springmvc拦截器
- 例如:统一日志处理器,需要该拦截器preHandle必须放行,且将它防砸拦截器链接中第一个位置
- 例如:登录认证拦截器,放在拦截器链接中第一个位置
- 例如:权限校验拦截器,放在登录认证拦截器之后,因为只有登录通过才能验证
- 针对Mapping配置拦截器
- springmvc拦截器针对HandlerMapping进行拦截设置。
- 如果在某个HandlerMapping中配置拦截,经过该HandlerMapping映射成功的handler最终使用该拦截器
- 类似全局配置拦截器
- springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中
<!-- 拦截器 --> <mvc:interceptors> <!-- 多个拦截器,顺序执行 --> <mvc:interceptor> <!-- /**表示所有url包括子url路径 --> <mvc:mapping path="/**"/> <bean class="cn.muriel.ssm.interceptor.TestInterceptor"/> </mvc:interceptor> </mvc:interceptors> /** * */ public class TestInterceptor implements HandlerInterceptor { /** * 进入Handler方法之前执行 * @param httpServletRequest * @param httpServletResponse * @param o * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { //return false表示拦截,不向下执行 //return true表示放行 return false; } /** * 进入Handler方法之后,返回ModelAndView之前执行 * 应用场景:将共用的数据(例如菜单导航)在这里传到视图,也可以在这里统一指定视图 * @param httpServletRequest * @param httpServletResponse * @param o * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } /** * 执行Handler完成执行此方法 * 应用场景:统一异常处理、统一日至处理 * @param httpServletRequest * @param httpServletResponse * @param o * @param e * @throws Exception */ @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }