第一天

课程安排:

1、什么是springMVC?
2、springMVC框架原理前端控制器、处理器映射器、处理器适配器、视图解析器。
3、springMVC入门程序目的:对前端控制器、处理器映射器、处理器适配器、视图解析器非注解的处理器映射器、处理器适配器注解的处理器映射器、处理器适配器
4、springMVC和mybatis整合
5、springMVC注解开发常用的注解学习参数绑定(简单类型、pojo、集合类型)自定义参数绑定
6、springMVC和struts2的区别

1、springMVC框架

1.1、什么是springMVC

​ springMVC是spring框架的一个模块,springMVC和spring无需通过中间整合层进行整合。

​ springMVC是一个基于MVC的web框架。

1.2、什么是MVC

​ MVC是一个设计模式,MVC在b/s系统下的应用:

1.3、springMVC框架

第一步:发起请求到 前端控制器DispatcherServlet

第二步:前端控制器请求处理器映射器HandlerMapping查找Handler。

​ 可以根据xml配置、注解进行查找。

第三步:处理器映射器HandlerMapping向前端控制器返回Handler

第四步:前端控制器调用处理器适配器去执行Handler。

第五步:处理器适配器HandlerAdapter去执行Handler。

第六步:Handler执行完成给适配器返回ModelAndView

第七步:处理器适配器向前端控制器返回ModelAndView。

​ ModelAndView是springMVC框架的一个底层对象,包括model和view。

第八步:前端控制请求视图解析器去进行视图解析。

​ 根据逻辑视图名解析成真正的视图(jsp)。

第九步:视图解析器向前端控制器返回view。

第十步:前端控制器进行视图渲染。

​ 视图渲染将模型数据(在ModelAndView对象中)填充到request域。

第十一步:前端控制器向用户响应结果。

组件:

​ 1、前端控制器DispatcherServlet(不需要程序员开发)

​ 作用:接收请求,响应结果,相当于转发器、中央处理器。

​ 2、处理器映射器HandlerMapping(不需要程序员开发)

​ 作用:根据请求的url查找Handler

​ 3、处理器适配器HandlerAdapter

​ 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler。

​ 4、处理器Handler(需要程序员开发)

​ 注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。

​ 5、视图解析器View resolver(不需要程序员开发)

​ 作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)

​ 6、视图view(需要程序员开发jsp)

​ view是一个接口,实现类支持不用的view类型(jsp、freemarker、pdf……)

2、入门程序

2.1、环境准备

  • 数据库环境:

    /*
    Navicat MySQL Data TransferSource Server         : ZWD
    Source Server Version : 50711
    Source Host           : localhost:3306
    Source Database       : mybatisTarget Server Type    : MYSQL
    Target Server Version : 50711
    File Encoding         : 65001Date: 2019-11-29 17:34:25
    */SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
    -- Table structure for `items`
    -- ----------------------------
    DROP TABLE IF EXISTS `items`;
    CREATE TABLE `items` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) NOT NULL COMMENT '商品名称',`price` float(10,1) NOT NULL COMMENT '商品定价',`detail` text COMMENT '商品描述',`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',`createtime` datetime NOT NULL COMMENT '生产日期',PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
    -- Records of items
    -- ----------------------------
    INSERT INTO `items` VALUES ('1', '台式机', '3000.0', '该电脑质量非常好!!!!', null, '2015-02-03 13:22:53');
    INSERT INTO `items` VALUES ('2', '笔记本', '6000.0', '笔记本性能好,质量好!!!!!', null, '2015-02-09 13:22:57');
    INSERT INTO `items` VALUES ('3', '背包', '200.0', '名牌背包,容量大质量好!!!!', null, '2015-02-06 13:23:02');-- ----------------------------
    -- Table structure for `orderdetail`
    -- ----------------------------
    DROP TABLE IF EXISTS `orderdetail`;
    CREATE TABLE `orderdetail` (`id` int(11) NOT NULL AUTO_INCREMENT,`orders_id` int(11) NOT NULL COMMENT '订单id',`items_id` int(11) NOT NULL COMMENT '商品id',`items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',PRIMARY KEY (`id`),KEY `FK_orderdetail_1` (`orders_id`),KEY `FK_orderdetail_2` (`items_id`),CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
    -- Records of orderdetail
    -- ----------------------------
    INSERT INTO `orderdetail` VALUES ('1', '1', '2', '3');
    INSERT INTO `orderdetail` VALUES ('2', '2', '3', '5');
    INSERT INTO `orderdetail` VALUES ('3', '2', '2', '3');-- ----------------------------
    -- Table structure for `orders`
    -- ----------------------------
    DROP TABLE IF EXISTS `orders`;
    CREATE TABLE `orders` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NOT NULL COMMENT '下单用户id',`number` varchar(32) NOT NULL COMMENT '订单号',`createtime` datetime NOT NULL COMMENT '创建订单时间',`note` varchar(100) DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`),KEY `FK_orders_1` (`user_id`),CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;-- ----------------------------
    -- Records of orders
    -- ----------------------------
    INSERT INTO `orders` VALUES ('1', '10', '11', '2019-09-18 09:41:28', '33');
    INSERT INTO `orders` VALUES ('2', '1', '10', '2019-11-20 16:48:52', '44');-- ----------------------------
    -- Table structure for `user`
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(32) NOT NULL COMMENT '用户名称',`birthday` date DEFAULT NULL COMMENT '生日',`sex` char(1) DEFAULT NULL COMMENT '性别',`address` varchar(256) DEFAULT NULL COMMENT '地址',PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;-- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES ('1', '张晓敏', null, '2', null);
    INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
    INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('25', '赵文迪', '2019-09-10', '女', '贵州遵义');
    INSERT INTO `user` VALUES ('27', '赵文迪', '2019-09-09', '女', '贵州遵义');
    INSERT INTO `user` VALUES ('28', '赵文迪', '2019-09-09', '女', '贵州遵义');
    INSERT INTO `user` VALUES ('29', '赵文迪', '2019-09-09', '女', '贵州遵义');
    
  • 创建web项目:jdk1.8+tomcat8.0

  • 导入spring的jar包:需要spring4.3所有jar(一定包括spring-webmvc-4.3.0.RELEASE.jar)

2.2、配置前端控制器

​ 在类路径下添加文件:springmvc.xml

​ 在web.xml文件中配置前端控制器。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"><display-name>01.springmvc入门程序</display-name><!-- 配置springMVC前端控制器 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--contextConfigLocation:配置springMVC加载的配置文件如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-servlet.xml(springmvc-servlet.xml)  --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- 第一种:*.action:访问一.action结尾由DispatcherServlet进行解析第二种:/:所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析。使用此种方式可以实现RESTFUL风格的url.第三种:/*:这样配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错 --><url-pattern>*.action</url-pattern></servlet-mapping><!-- 配置springMVC前端控制器 --><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list>
</web-app>

2.3、配置处理其适配器

​ 在类路径下的springmvc.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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置处理器适配器:所有的处理器适配器都实现HandlerAdapter接口-->  <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 配置处理器映射器 -->
<!-- 视图解析器 --></beans>

SimpleControllerHandlerAdapter:支持实现Controller的Handler。

2.5、编写Handler

​ 编写一个实现Controller接口的Handler。ItemsController1.java

package com.zwd.ssm.controller;import java.util.ArrayList;
import java.util.List;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;import com.zwd.ssm.po.Items;
/*** 实现Controller接口的处理器* @author Administrator**/
public class ItemsController1 implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {System.out.println("进来。");//调用serviceList<Items> itemsList = new ArrayList<>();Items item1 = new Items();item1.setId(1);item1.setName("aaa");item1.setPrice(777);Items item2 = new Items();item1.setId(2);item1.setName("BBB");item1.setPrice(888);itemsList.add(item1);itemsList.add(item2);//返回ModelAndViewModelAndView modelAndView = new ModelAndView();//相当于request的setAttribute,在jsp页面中通过itemsList获取数据modelAndView.addObject("itemsList", itemsList);//指定视图modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");return modelAndView;}
}

2.6 、编写前端页面jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
<!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>查询商品列表</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/item/queryItem.action" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td><input type="submit" value="查询"/></td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr><td>商品名称</td><td>商品价格</td><td>生产日期</td><td>商品描述</td><td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item">
<tr><td>${item.name }</td><td>${item.price }</td><td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td><td>${item.detail }</td><td><a href="${pageContext.request.contextPath }/item/editItem.action?id=${item.id}">修改</a></td></tr>
</c:forEach></table>
</form>
</body></html>

2.7、配置处理器映射器

​ 在类路径下的springmvc.xml中配置:

<!-- 2、配置处理器映射器 --><!-- BeanNameUrlHandlerMapping:将bean的name作为url进行查找,需要配置Handler时指定beanName(就是url) --><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean><!-- 配置Handler --><bean name="/queryItems.action" class="com.zwd.ssm.controller.ItemsController1"></bean>

2.8、配置视图解析器

​ 在springmvc.xml中配置视图解析器。

<!-- 3、视图解析器 --><!-- InternalResourceViewResolver:解析jsp,默认使用jstl标签。注意导入jstl的包 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>

​ 整个springmvc.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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 1、配置处理器适配器:所有的处理器适配器都实现HandlerAdapter接口-->  <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>  <!-- 2、配置处理器映射器 --><!-- BeanNameUrlHandlerMapping:将bean的name作为url进行查找,需要配置Handler时指定beanName(就是url) --><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean><!-- 配置Handler --><bean name="/queryItems.action" class="com.zwd.ssm.controller.ItemsController1"></bean><!-- 3、视图解析器 --><!-- InternalResourceViewResolver:解析jsp,默认使用jstl标签。注意导入jstl的包 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean></beans>

2.9、访问页面

http://localhost:8080/01.springmvcFirst/queryItems.action

3、非注解的处理器映射器和适配器

3.1、非注解的处理器映射器

类型1:BeanNameUrlHandlerMapping

<!-- 类型1:BeanNameUrlHandlerMapping:将bean的name作为url进行查找,需要配置Handler时指定beanName(就是url) --><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">      </bean><!-- 配置Handler --><bean name="/queryItems.action" class="com.zwd.ssm.controller.ItemsController1">      </bean>

类型2: SimpleUrlHandlerMapping

 <!-- 类型2:SimpleUrlHandlerMapping --><bean id="itemsController" class="com.zwd.ssm.controller.ItemsController1"></bean><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/queryItems1.action">itemsController</prop><prop key="/queryItems2.action">itemsController</prop></props></property></bean>
<?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 1、配置处理器适配器:所有的处理器适配器都实现HandlerAdapter接口-->  <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>  <!-- 2、配置处理器映射器:两种类型可以并存 --><!-- 类型1:BeanNameUrlHandlerMapping:将bean的name作为url进行查找,需要配置Handler时指定beanName(就是url) --><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean><!-- 配置Handler --><bean id="/queryItems.action" class="com.zwd.ssm.controller.ItemsController1"></bean><!-- 类型2:SimpleUrlHandlerMapping --><bean id="itemsController" class="com.zwd.ssm.controller.ItemsController1"></bean><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/queryItems1.action">itemsController</prop><prop key="/queryItems2.action">itemsController</prop></props></property></bean><!-- 3、视图解析器 --><!-- InternalResourceViewResolver:解析jsp,默认使用jstl标签。注意导入jstl的包 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean></beans>

前端映射器会找到对应url使用的处理器映射器,能使用哪个就使用哪个。

3.2、非注解的适配器

类型1:SimpleControllerHandlerAdapter

<!-- 类型1:要求:需要编写的Handler实现Controller接口 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
package com.zwd.ssm.controller;import java.util.ArrayList;
import java.util.List;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;import com.zwd.ssm.po.Items;
/*** 实现Controller接口的处理器* @author Administrator**/
public class ItemsController1 implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {//调用serviceList<Items> itemsList = new ArrayList<>();Items item1 = new Items();item1.setId(1);item1.setName("aaa");item1.setPrice(777);Items item2 = new Items();item1.setId(2);item1.setName("BBB");item1.setPrice(888);Items item3 = new Items();item1.setId(3);item1.setName("ccc");item1.setPrice(999);itemsList.add(item1);itemsList.add(item2);itemsList.add(item3);//返回ModelAndViewModelAndView modelAndView = new ModelAndView();//相当于request的setAttribute,在jsp页面中通过itemsList获取数据modelAndView.addObject("itemsList", itemsList);//指定视图modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");return modelAndView;}
}

类型2:HttpRequestHandlerAdapter

<!-- 类型2:要求:需要编写的Handler实现HttpRequestHandler接口 -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
</bean>
package com.zwd.ssm.controller;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.HttpRequestHandler;import com.zwd.ssm.po.Items;
/*** 实现HttpRequestHandler的接口* @author Administrator**/
public class ItemsController2 implements HttpRequestHandler {@Overridepublic void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//调用serviceList<Items> itemsList = new ArrayList<>();Items item1 = new Items();item1.setId(1);item1.setName("aaa");item1.setPrice(777);Items item2 = new Items();item1.setId(2);item1.setName("BBB");item1.setPrice(888);Items item3 = new Items();item1.setId(3);item1.setName("ccc");item1.setPrice(999);itemsList.add(item1);itemsList.add(item2);itemsList.add(item3);//设置模型数据request.setAttribute("itemsList", itemsList);//设置转发视图request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward(request, response);//使用此方法可以通过修改response,设置响应的数据格式,比如响应json数据
//      response.setCharacterEncoding("utf-8");
//      response.setContentType("application/json;charset=utf-8");
//      response.getWriter().write("json串");}
}

3.3、DispatcherServlet.properties

​ 前端控制器从上边的文件中加载处理器映射器、适配器、视图解析器等组件,如果不在springmvc.xml中配置,则使用默认加载的。

4、注解的处理器映射器和适配器

4.1、注解处理器映射器

3.1之前使用:

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

3.1之后使用:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

4.2、注解适配器

3.1之前使用:

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

3.1之后使用:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

4.3、配置注解映射器和适配器

​ 记得添加mvc约束。

<!-- 注解的适配器和映射器的配置 --><!-- 方式一:单独配置两个 --><!-- 1、配置注解的处理器适配器:  -->  <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean><!-- 2、配置注解的处理器映射器: --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean><!-- 方式二:使用mvc:annotation-driven代理方式一。 mvc:annotation-driven:默认加载很多的参数绑定方法。比如json转换解析器就默认加载了。实际开发使用mvc:annotation-driven--><mvc:annotation-driven></mvc:annotation-driven>
<?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:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 注解的适配器和映射器的配置 --><!-- 方式一:单独配置两个 --><!-- 1、配置注解的处理器适配器:  -->  <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean><!-- 2、配置注解的处理器映射器: --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean><!-- 方式二:使用mvc:annotation-driven代理方式一。 mvc:annotation-driven:默认加载很多的参数绑定方法。比如json转换解析器就默认加载了。实际开发使用mvc:annotation-driven--><mvc:annotation-driven></mvc:annotation-driven><!--视图解析器 --><!-- InternalResourceViewResolver:解析jsp,默认使用jstl标签。注意导入jstl的包 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean></beans>

4.4、注解Handler编写

@Controller、@RequestMapping

​ @Controller:使用@Controller注解标识该类是一个控制器。

​ @RequestMapping:使用@RequestMapping实现handleRequest方法和url的映射,一个方法对应一个url

注解适配器和注解映射器需要配套使用。

ItemsController3.java

package com.zwd.ssm.controller;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Controller;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.bind.annotation.RequestMapping;import com.zwd.ssm.po.Items;
/*** 使用注解的映射器、适配器的Controller* @author Administrator**/
//处理器适配器:使用@Controller注解标识该类是一个控制器
@Controller
public class ItemsController3{//处理器映射器注解:使用@RequestMapping实现handleRequest方法和url的映射,一个方法对应一个url//一般建议url和方法名称一致。@RequestMapping("/queryItems")public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//调用serviceList<Items> itemsList = new ArrayList<>();Items item1 = new Items();item1.setId(1);item1.setName("aaa");item1.setPrice(777);Items item2 = new Items();item1.setId(2);item1.setName("BBB");item1.setPrice(888);Items item3 = new Items();item1.setId(3);item1.setName("ccc");item1.setPrice(999);itemsList.add(item1);itemsList.add(item2);itemsList.add(item3);//设置模型数据request.setAttribute("itemsList", itemsList);//设置转发视图request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward(request, response);//使用此方法可以通过修改response,设置响应的数据格式,比如响应json数据
//      response.setCharacterEncoding("utf-8");
//      response.setContentType("application/json;charset=utf-8");
//      response.getWriter().write("json串");}//其它方法
}

4.5、将Handler注入aop

<!-- 配置Controller --><!-- <bean class="com.zwd.ssm.controller.ItemsController3"></bean> 或者直接扫描注解 -->
<!-- 扫描注解: -->
<context:component-scan base-package="com.zwd.ssm.controller"></context:component-scan>

4.6、访问调试

http://localhost:8080/03.HandlerMappingAndAdapter_anno/queryItems.action

5、源码分析

分析springmvc的执行过程。

第一步:前端控制器接受请求

调用doDispatch()

第二步:前端控制器调用处理器映射器。根据url查找handler

第三步:根据handler查找对应的处理器适配器,并调用该适配器执行该handler返回ModelAndView

第四步:视图渲染。将model数据填充到request域。

视图解析得到view。

6、入门程序小结

前端控制器

<!-- 配置springMVC前端控制器 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><!--contextConfigLocation:配置springMVC加载的配置文件如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-servlet.xml(springmvc-servlet.xml)  --><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- 第一种:*.action:访问一.action结尾由DispatcherServlet进行解析第二种:/:所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析。使用此种方式可以实现RESTFUL风格的url.第三种:/*:这样配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错 --><url-pattern>*.action</url-pattern></servlet-mapping>

处理器映射器

非注解的处理器映射器(两种):BeanNameUrlHandlerMappingSimpleUrlHandlerMapping

<!-- 类型1:BeanNameUrlHandlerMapping:将bean的name作为url进行查找,需要配置Handler时指定beanName(就是url) --><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">      </bean><!-- 配置Handler --><bean name="/queryItems.action" class="com.zwd.ssm.controller.ItemsController1">  </bean><!-- 类型2:SimpleUrlHandlerMapping --><bean id="itemsController" class="com.zwd.ssm.controller.ItemsController1"></bean><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/queryItems1.action">itemsController</prop><prop key="/queryItems2.action">itemsController</prop></props></property></bean>

处理器适配器

非注解的处理器适配器(两种):SimpleControllerHandlerAdapterHttpRequestHandlerAdapter

<!-- 类型1:要求:需要编写的Handler实现Controller接口 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!-- 类型2:要求:需要编写的Handler实现HttpRequestHandler接口 -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
</bean>

注解的处理器映射器和适配器

<!-- 注解的适配器和映射器的配置 --><!-- 方式一:单独配置两个 --><!-- 1、配置注解的处理器适配器:  -->  <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean><!-- 2、配置注解的处理器映射器: --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean><!-- 方式二:使用mvc:annotation-driven代理方式一。 mvc:annotation-driven:默认加载很多的参数绑定方法。比如json转换解析器就默认加载了。实际开发使用mvc:annotation-driven--><mvc:annotation-driven></mvc:annotation-driven>

视图解析器

<!--视图解析器 --><!-- InternalResourceViewResolver:解析jsp,默认使用jstl标签。注意导入jstl的包 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/items"></property><!-- 前缀 --><property name="suffix" value=".jsp"></property><!-- 后缀 --></bean>
     //在视图解析器中配置前缀和后缀//<property name="prefix" value="/WEB-INF/jsp/"></property><!-- 前缀 -->//<property name="suffix" value=".jsp"></property><!-- 后缀 -->request.getRequestDispatcher("items/itemsList").forward(request, response);

7、springMVC和mybatis整合

7.1、需求

​ 使用springMVC和mybatis完成商品列表的查询。

7.2、整合思路

​ springmvc和mybatis的系统架构

第一步:整合dao层

​ mybatis和spring整合,通过spring管理mapper接口。

​ 使用mapper的扫描器自动扫描mapper接口在spring中的注册。MapperScannerConfigurer

第二步:整合service层

​ 通过spring管理service接口。

​ 通过配置方式将service接口配置在spring配置文件中。

​ 实现事务控制(xml配置)。

第三步:整合springmvc的模块,不需要整合。

7.3、准备环境

  • 创建web项目

  • 导包:数据库连接驱动+数据库连接池+mybatis的jar包+mybatis和spring整合jar包+日志包+spring的jar包+jstl。

  • 在类路径下创建日志文件:log4j.properties

    # Global logging configuration
    # 在开发环境下使用DEBUG;在生产环境下使用info或者error
    log4j.rootLogger=DEBUG, stdout
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    
  • 在类路径下创建数据库配置文件:db.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.username=root
    jdbc.password=root
    

7.4、整合dao

sqlMapConfig.xml

  • 创建sqlMapConfig.xml文件:config->mybatis->sqlMapConfig.xml

    <?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><!-- 1、配置全局settings:根据需要配置 --><!-- 2、配置别名 --><typeAliases><!-- 批量扫描别名 --><package name="com.zwd.ssm.po"/><!-- 单个别名定义 <typeAlias type="" alias=""/>--></typeAliases><!--3、配置mapper:由于使用spring和mybatis的整合包进行mapper扫描,这里就不需要配置了(MapperScannerConfigurer)。必须遵循:mapper.xml和mapper.java文件同名且在一个目录 --><!-- <mappers></mappers> --></configuration>
    

applicationContext_dao.xml

mapper批量扫描器:MapperScannerConfigurer
  • 创建applicationContext.xml文件:config->mybatis->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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 1、配置数据库的连接 -->   <!-- 加载数据库配置文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 通过数据库连接池dpcp连接和管理数据库 --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property><property name="maxActive" value="30"></property><property name="maxIdle" value="5"></property></bean>
    <!-- 2、配置mybatis的SqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 数据源 --><property name="dataSource" ref="dataSource"></property><!-- 配置mybatis的全局配置文件sqlMapConfig.xml --><property name="configLocation" value="classpath:mybatis/sqlMapConfig.xml"></property></bean>
    <!-- 3、配置扫描mapper生成dao的实现类:在此处配置就不用在sqlMapConfig.xml文件中配置mapper扫描 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 扫描包下的mapper,如果需要扫描多个包使用逗号分隔开 --><property name="basePackage" value="com.zwd.ssm.mapper"></property><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property></bean></beans>
    

逆向工程生成po类和mapper

手动定义商品查询mapper

​ 针对综合查询mapper,一般情况会有相关关联查询,建议自定义mapper。

定义Items.java的扩展类:ItemsCusotm.java

package com.zwd.ssm.po;
/*** 商品类的扩展类* @author Administrator**/
public class ItemsCustom extends Items {//扩展属性
}

定义Items.java的包装类(包装了查询条件):ItemsVo.java

package com.zwd.ssm.po;
/*** 商品包装对象* @author Administrator**/
public class ItemsVo {//包装查询条件private ItemsCustom items ;public ItemsCustom getItemsCustom() {return items;}public void setItemsCustom(ItemsCustom items) {this.items = items;}
}
ItemsMapper.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.zwd.ssm.mapper.ItemsMapper" ><sql id="itemsList_where"><if test="items != null"><if test="items.name != null and items.name != ''">name like '%${items.name}%'</if></if></sql><!-- 查询商品信息:parameterType:传入包装对象(包装了查询条件) resultType:建议使用扩展对象--><select id="findItemsList" parameterType="com.zwd.ssm.po.ItemsVo" resultType="com.zwd.ssm.po.ItemsCustom">select * from items <where><include refid="itemsList_where"></include></where></select></mapper>
ItemsMapper.java
package com.zwd.ssm.mapper;import java.util.List;import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.po.ItemsVo;public interface ItemsMapper {/*** 查询商品信息* @param itemsVo* @return*/public List<ItemsCustom> findItemsList(ItemsVo itemsVo) throws Exception;
}

7.5、整合service

ItemsService接口和实现类

ItemsService.java

package com.zwd.ssm.service;import java.util.List;import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.po.ItemsVo;/*** 商品信息的service层接口* @author Administrator**/
public interface ItemsService {/*** 查询商品信息* @param itemsVo* @return* @throws Exception */public List<ItemsCustom> findItemsList(ItemsVo itemsVo) throws Exception;
}

ItemsServiceImpl.java

package com.zwd.ssm.service.impl;import java.util.List;import javax.annotation.Resource;import org.springframework.stereotype.Service;import com.zwd.ssm.mapper.ItemsMapper;
import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.po.ItemsVo;
import com.zwd.ssm.service.ItemsService;
/*** 商品信息service层实现类* @author Administrator**/
//@Service
public class ItemsServiceImpl implements ItemsService {@Resource(name="itemsMapper")private ItemsMapper itemsMapper;@Overridepublic List<ItemsCustom> findItemsList(ItemsVo itemsVo) throws Exception {return itemsMapper.findItemsList(itemsVo);}
}

使用xml配置管理service

applicationContext_service.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:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 配置service -->  <bean id="itemsService" class="com.zwd.ssm.service.impl.ItemsServiceImpl"></bean>
</beans>

使用xml配置管理事务

applicationContext_tx.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:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 配置事务控制 --><!-- 1、配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 2、配置事务的通知 --><tx:advice id="tx_Advice" transaction-manager="transactionManager"><tx:attributes><tx:method name="insert*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="find*" propagation="SUPPORTS" read-only="true"/></tx:attributes></tx:advice><!-- 3、配置aop -->  <aop:config><aop:pointcut expression="execution(* com.zwd.ssm.servie.impl.*.*(..))" id="cut1"/><aop:advisor advice-ref="tx_Advice" pointcut-ref="cut1"/></aop:config>
</beans>

7.6、整合MVC

配置前端控制器web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"><display-name>04.ssm</display-name><!-- 配置springMVC前端控制器 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><!--contextConfigLocation:配置springMVC加载的配置文件如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-servlet.xml(springmvc-servlet.xml)  --><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- 第一种:*.action:访问一.action结尾由DispatcherServlet进行解析第二种:/:所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析。使用此种方式可以实现RESTFUL风格的url.第三种:/*:这样配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错 --><url-pattern>*.action</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list>
</web-app>

配置springmvc.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:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 1、扫描注解 --><context:component-scan base-package="com.zwd.ssm.controller"></context:component-scan><!-- 2、配置注解的处理器适配器和映射器 --><mvc:annotation-driven></mvc:annotation-driven><!-- 3、配置视图解析器 --><!-- InternalResourceViewResolver:解析jsp,默认使用jstl标签。注意导入jstl的包 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/items"></property><!-- 前缀 --><property name="suffix" value=".jsp"></property><!-- 后缀 --></bean>
</beans>

jsp页面itemsList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
<!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>查询商品列表</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/queryItem.action" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td><input type="submit" value="查询"/></td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr><td>商品名称</td><td>商品价格</td><td>生产日期</td><td>商品描述</td><td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item">
<tr><td>${item.name }</td><td>${item.price }</td><td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td><td>${item.detail }</td><td><a href="${pageContext.request.contextPath }/editItem.action?id=${item.id}">修改</a></td></tr>
</c:forEach></table>
</form>
</body></html>

编写Controller

package com.zwd.ssm.controller;import java.util.List;import javax.annotation.Resource;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.service.ItemsService;/*** 商品信息Controller层* * @author Administrator**/
@Controller
public class ItemsController {@Resource(name = "itemsService")private ItemsService itemsService;@RequestMapping("/queryItems")public ModelAndView queryItems() throws Exception {System.out.println("成功!");// 调用serviceList<ItemsCustom> itemsList = itemsService.findItemsList(null);// 返回ModelAndViewModelAndView modelAndView = new ModelAndView();// 相当于request的setAttribute,在jsp页面中通过itemsList获取数据modelAndView.addObject("itemsList", itemsList);// 指定视图modelAndView.setViewName("/itemsList");return modelAndView;}
}

配置spring容器的监听器web.xml

<!-- 加载spring容器 --><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/classes/spring/applicationContext_*.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"><display-name>04.ssm</display-name><!-- 加载spring容器 --><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/classes/spring/applicationContext_*.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 配置springMVC前端控制器 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><!--contextConfigLocation:配置springMVC加载的配置文件如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-servlet.xml(springmvc-servlet.xml)  --><param-name>contextConfigLocation</param-name><param-value>classpath:spring/springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- 第一种:*.action:访问一.action结尾由DispatcherServlet进行解析第二种:/:所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析。使用此种方式可以实现RESTFUL风格的url.第三种:/*:这样配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错 --><url-pattern>*.action</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list>
</web-app>

7.7、部署访问

http://localhost:8080/04.ssm/queryItems.action

8、修改商品信息功能开发

使用上一个例子(7)的环境

8.1、需求

操作流程:

1、进入商品查询列表页面(jsp/items/itemsList.jsp

2、点击修改,进入商品修改页面(jsp/items/editItems.jsp),页面中显示了要修改的商品(从数据库中查询)

​ 要修改的商品从数据库中查询,根据商品id(主键)查询商品信息。

3、在商品修改页面,修改商品信息,修改后,点击提交。页面跳转到jsp/success.jsp

8.2、mapper开发

​ mapper:使用逆向工程中的方法。

​ 1、根据id查询商品信息。selectByPrimaryKey()

​ 2、根据id更新items表的数据。updateByPrimaryKeyWithBLOBs()

8.3、service开发

​ service:

​ 1、根据id查询商品信息

​ 2、修改商品信息

ItemsService.java

package com.zwd.ssm.service;import java.util.List;import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.po.ItemsVo;/*** 商品信息的service层接口* @author Administrator**/
public interface ItemsService {/*** 查询商品信息* @param itemsVo* @return* @throws Exception */public List<ItemsCustom> findItemsList(ItemsVo itemsVo) throws Exception;/*** 根据id查询商品信息* @param id* @return*/public ItemsCustom findItemsById(Integer id);/*** 根据id更新商品信息* @param itemsId* @param items*/public void updateItemsById(Integer itemsId,ItemsCustom itemsCustom);
}

ItemsServiceImpl.java

package com.zwd.ssm.service.impl;import java.util.List;import javax.annotation.Resource;import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.zwd.ssm.mapper.ItemsMapper;
import com.zwd.ssm.mapper.ItemsMapperExample;
import com.zwd.ssm.po.Items;
import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.po.ItemsVo;
import com.zwd.ssm.service.ItemsService;
/*** 商品信息service层实现类* @author Administrator**/
@Service("itemsService")
public class ItemsServiceImpl implements ItemsService {@Resource(name="itemsMapper")private ItemsMapper itemsMapper;@Autowiredprivate ItemsMapperExample ItemsMapperExample;/*** 查询商品信息*/@Overridepublic List<ItemsCustom> findItemsList(ItemsVo itemsVo) throws Exception {return itemsMapper.findItemsList(itemsVo);}/*** 查询商品信息*/@Overridepublic ItemsCustom findItemsById(Integer id) {Items items = ItemsMapperExample.selectByPrimaryKey(id);//中间对商品进行业务处理//...//将所有信息封装到items的扩展类ItemsCustom中ItemsCustom itemsCustom = new ItemsCustom();//将items的属性值拷贝到itemsCustom中BeanUtils.copyProperties(items, itemsCustom);return itemsCustom;}/*** 查询商品信息*/@Overridepublic void updateItemsById(Integer itemsId, ItemsCustom itemsCustom) {//添加业务校验,通常在service中对关键参数进行校验//校验id是否为空,如果为空抛出异常。itemsCustom.setId(itemsId);ItemsMapperExample.updateByPrimaryKeyWithBLOBs(itemsCustom);}
}

8.4、controller开发

​ 方法:

​ 1、商品信息修改页面显示。

​ 2、商品信息修改提交。

商品信息页面和提交成功后的页面

editItems.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
<!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>修改商品信息</title></head>
<body> <form id="itemForm" action="${pageContext.request.contextPath }/editItemsSubmit.action" method="post" >
<input type="hidden" name="id" value="${itemsCustom.id }"/>
修改商品信息:
<table width="100%" border=1>
<tr><td>商品名称</td><td><input type="text" name="name" value="${itemsCustom.name }"/></td>
</tr>
<tr><td>商品价格</td><td><input type="text" name="price" value="${itemsCustom.price }"/></td>
</tr>
<tr><td>商品生产日期</td><td><input type="text" name="createtime" value="<fmt:formatDate value="${itemsCustom.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
</tr>
<%-- <tr><td>商品图片</td><td><c:if test="${item.pic !=null}"><img src="/pic/${item.pic}" width=100 height=100/><br/></c:if><input type="file"  name="pictureFile"/> </td>
</tr> --%>
<tr><td>商品简介</td><td><textarea rows="3" cols="30" name="detail">${itemsCustom.detail }</textarea></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"/>
</td>
</tr>
</table></form>
</body></html>

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="ISO-8859-1"%>
<!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>成功提示</title>
</head>
<body>
哈哈
</body>
</html>

ItemsController

没有实现页面之间的数据传送。

package com.zwd.ssm.controller;import java.util.List;import javax.annotation.Resource;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.service.ItemsService;/*** 商品信息Controller层* * @author Administrator**/
@Controller
public class ItemsController {@Resource(name = "itemsService")private ItemsService itemsService;@RequestMapping("/queryItems")public ModelAndView queryItems() throws Exception {System.out.println("成功!");// 调用serviceList<ItemsCustom> itemsList = itemsService.findItemsList(null);// 返回ModelAndViewModelAndView modelAndView = new ModelAndView();// 相当于request的setAttribute,在jsp页面中通过itemsList获取数据modelAndView.addObject("itemsList", itemsList);// 指定视图modelAndView.setViewName("items/itemsList");return modelAndView;}/*** 修改商品信息页面展示* @return* @throws Exception*/@RequestMapping("/editItems")public ModelAndView editItems() throws Exception{ItemsCustom itemsCustom = itemsService.findItemsById(1);//返回ModelAndViewModelAndView modelAndView = new ModelAndView();modelAndView.addObject("itemsCustom", itemsCustom);modelAndView.setViewName("items/editItems");return modelAndView;}/*** 修改提交商品信息* @return* @throws Exception*/@RequestMapping("/editItemsSubmit")public ModelAndView editItemsSubmit() throws Exception{//获取提交的items,更新到数据库//返回ModelAndViewModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("success");return modelAndView;}}

8.6、部署访问

http://localhost:8080/05.updateItemsInfo/queryItems.action

9、@RequestMapping

使用上一个例子(8)的环境

url映射

定义controller方法对应的url,进行处理器映射使用。

窄化请求映射

限制http请求方式

10、Controller方法返回值

返回ModelAndView

​ 需要在方法结束时定义ModelAndView,将model和view分别进行设置。

/*** 修改商品信息页面展示* @return* @throws Exception*/@RequestMapping("/editItems")public ModelAndView editItems() throws Exception{ItemsCustom itemsCustom = itemsService.findItemsById(1);//返回ModelAndViewModelAndView modelAndView = new ModelAndView();modelAndView.addObject("itemsCustom", itemsCustom);modelAndView.setViewName("items/editItems");return modelAndView;}

返回string

  • 表示返回逻辑视图名:真正视图(jsp路径)=前缀+逻辑视图名+后缀。

    /*** 修改商品信息页面展示:返回值string* @return* @throws Exception*/@RequestMapping("/editItems")public String editItems(Model model) throws Exception{ItemsCustom itemsCustom = itemsService.findItemsById(1);//Model:通过形参中的model将model数据传到页面//相当于modelAndView.addObject("itemsCustom", itemsCustom)方法model.addAttribute("itemsCustom", itemsCustom);return "items/editItems";}
    
  • redirect重定向

    商品修改提交后,重定向到商品查询列表。

    redirect重定向特点:浏览器地址栏中的url会变化。

    ​ 修改提交的request数据无法传到重定向的地址。因为重定向后重新发送一个请求,

    ​ request无法共享。

    //重定向
    return "redirect:queryItems.action";
    
  • forword页面转发

    ​ 通过forward进行页面转发,浏览器地址栏url不变,request可以共享。

    //请求转发
    return "forward:queryItems.action";
    

返回void

在controller方法形参上可以定义request和response,使用request或response指定响应结果:

1、使用request转向页面,如下:

request.getRequestDispatcher("页面路径").forward(request, response);

2、也可以通过response页面重定向:

response.sendRedirect("url")

3、也可以通过response指定响应结果,例如响应json数据如下:

response.setCharacterEncoding("utf-8");response.setContentType("application/json;charset=utf-8");response.getWriter().write("json串");

11、参数绑定

11.1、参数绑定过程

​ 客户端请求key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上。

​ springMVC中,接收页面提交的数据时通过方法形参来接收的。而不是在controller类中定义成员变量接收。

11.2、默认支持的类型

​ 直接在controller方法形参上定义下边类型的对象,就可以使用这些对象。在参数绑定过程中,如果遇到下边类型直接进行绑定。

HttpServletRequest

​ 通过request对象获取请求信息。

HttpServletResponse

​ 通过response处理响应信息。

HttpSession

​ 通过session对象得到session中存放的对象。

Model/ModelMap

​ model是一个接口,modelMap是一个接口实现。

​ 作用:将model数据填充到request域。

11.3、简单类型

@RequestParam

​ 通过@RequestParam对简单类型的参数进行绑定。

​ 如果不使用@RequestParam,要求request传入参数名称和controller方法的形参名称一致。

//参数绑定:@RequestParam里面将request传入的参数名称和形参进行绑定。//value:标签的name属性值//required:该参数是否必须传入//defaultValue:默认值public ModelAndView editItems(@RequestParam(value="id",required=true,defaultValue="1") int id)
 /*** 修改商品信息页面展示* @return* @throws Exception*/@RequestMapping("/editItems")//参数绑定:@RequestParam里面将request传入的参数名称和形参进行绑定。//value:标签的name属性值//required:该参数是否必须传入//defaultValue:默认值public ModelAndView editItems(@RequestParam(value="id",required=true,defaultValue="1") int id) throws Exception{ItemsCustom itemsCustom = itemsService.findItemsById(id);//返回ModelAndViewModelAndView modelAndView = new ModelAndView();modelAndView.addObject("itemsCustom", itemsCustom);modelAndView.setViewName("items/editItems");return modelAndView;}

11.4、pojo绑定

​ 要求:页面中input的name值和controller形参中的pojo的属性名称一致即可完成绑定。

/*** 修改提交商品信息:pojo参数绑定* @return* @throws Exception*/@RequestMapping("/editItemsSubmit")public String editItemsSubmit(Integer id,ItemsCustom itemsCustom) throws Exception{//获取提交的items,更新到数据库itemsService.updateItemsById(id, itemsCustom);//重定向//return "redirect:queryItems.action";//请求转发return "forward:queryItems.action";}

页面input的name值:

形参ItemsCustom中的属性名称:

11.5、自定义参数类型绑定实现日期类型绑定

​ 对于controller形参中pojo对象,如果属性中有日期类型,需要自定义参数绑定。将请求日期数据串传成 日期类型,要转换的日期类型和pojo中日期属性的类型保持一致。

自定义日期类型转换

需要实现Converter类中的convert()方法。

package com.zwd.ssm.controller.converter;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;import org.springframework.core.convert.converter.Converter;public class DateConverter implements Converter<String, Date> {//实现将日期串转为Date日期类型@Overridepublic Date convert(String str) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");try {return simpleDateFormat.parse(str);} catch (ParseException e) {e.printStackTrace();}return null;}
}

在springmvc中配置添加转换器:方式一

<!-- 1、配置注解的适配器和映射器 -->     <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

FormattingConversionServiceFactoryBean

<!-- 4、自定义参数类型绑定 --><bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><!-- 转换器 --><property name="converters"><list><!-- 日期类型转换 --><bean class="com.zwd.ssm.controller.converter.DateConverter"></bean></list></property></bean>

在springmvc中配置添加转换器:方式二(自学)

<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="webBindingInitializer" ref="customBinder"></property>
</bean><!-- 自定义webBinder -->
<bean id="customBinder"class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"><property name="conversionService" ref="conversionService" />
</bean><!-- conversionService -->
<bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><!-- 转换器 --><property name="converters"><list><bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/></list></property></bean>

问题

post乱码

在web.xml添加post乱码filter

在web.xml中加入:

<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>

get乱码

get乱码原因:tomcat编码和文件编码不一致。

对于get请求中文参数出现乱码解决方法有两个:

1、修改tomcat配置文件添加编码与工程编码一致,如下:

<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

2、另外一种方法对参数进行重新编码:

String userName = new
String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码

springMVC和struts的区别

1、springMVC是基于方法开发的,struts2是基于类开发的。

​ springMVC将url和controller方法映射。映射成功后springMVC生成一个Handler对象,对象中值包括了一个method。方法执行结束,形参数据销毁。

2、springMVC可以进行单例开发,并且建议使用单例开发,struts2通过类的成员变量接收参数,无法使用单例,只能使用多例。

3、经过实际测试,struts2速度慢,在于使用struts标签,如果使用struts2建议使用jstl。

第二天

课程安排:

在商品查询和商品修改功能案例驱动下进行学习:包装类型pojo参数绑定集合类型的参数绑定:数组、list、map...商品修改添加校验,学习springMVC提供校验validation(使用的是hibernate校验框架)数据回显统一异常处理上传图片json数据交互restful支持拦截器

1、包装类型pojo参数绑定

1.1、需求

​ 商品查询controller方法中实现商品查询条件传入。

1.2、实现方法

  • 第一种方法:在形参中添加HttpServletRequest request参数,通过接受查询条件参数。
  • 第二种方法:在形参中让包装类型的pojo接受查询条件参数。

1.3、包装类型pojo参数绑定

  • 页面参数:

    商品名称: input name="itemsCustom.name "

    <form action="${pageContext.request.contextPath }/items/queryItems.action" method="post">
    查询条件:
    <table width="100%" border=1>
    <tr>
    <td>商品名称:<input name="itemsCustom.name"/></td><td><input type="submit" value="查询"/></td>
    </tr>
    </table>
    
  • 包装类型pojo: ItemsCustom itemsCustom;

    注意set和get方法要写!!

    package com.zwd.ssm.po;
    /*** 商品信息包装类* @author Administrator**/
    public class ItemsQueryVo {ItemsCustom itemsCustom;public ItemsCustom getItemsCustom() {return itemsCustom;}public void setItemsCustom(ItemsCustom itemsCustom) {this.itemsCustom = itemsCustom;}
    }
    

2、集合类型的参数绑定

2.1、数组

需求

​ 在商品展示页面(itemsList.jsp)批量删除商品。

页面代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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>查询商品列表</title><script type="text/javascript">function deleteItems(){//提交formdocument.itemsForm.action="${pageContext.request.contextPath}/items/deleteItems.action";document.itemsForm.submit();}function queryItems(){//提交formdocument.itemsForm.action="${pageContext.request.contextPath }/items/queryItems.action";document.itemsForm.submit();}
</script>
</head>
<body><formname="itemsForm"action="${pageContext.request.contextPath }/items/queryItems.action"method="post">查询条件:<table width="100%" border=1><tr><td>商品名称:<input name="itemsCustom.name" /></td><td><input type="button" value="查询" οnclick="queryItems()"/><input type="button" value="批量删除" οnclick="deleteItems()"/></td></tr></table>商品列表:<table width="100%" border=1><tr><td>选择</td><td>商品名称</td><td>商品价格</td><td>生产日期</td><td>商品描述</td><td>操作</td></tr><c:forEach items="${itemsList}" var="item"><tr><td><input type="checkbox" name="items_id" value="${item.id}"></input></td><td>${item.name }</td><td>${item.price }</td><td><fmt:formatDate value="${item.createtime}"pattern="yyyy-MM-dd HH:mm:ss" /></td><td>${item.detail }</td><td><ahref="${pageContext.request.contextPath }/items/editItems.action?id=${item.id}">修改</a></td></tr></c:forEach></table></form>
</body></html>

表现层实现

​ 关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。

形参名称与标签的name值一致

​ controller方法定义:

​ 页面定义:

2.2、List

需求

​ 通常在需要批量提交数据时,将提交的数据绑定到List<pojo>中,比如:成绩录入(录入多门课的成绩,然后批量提交)。

​ 该例子需求:批量商品修改。修改多个商品信息,将多个商品信息一起提交到controller。

页面代码:editItemsQuery.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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>查询商品列表</title><script type="text/javascript">function editItemsAllSubmit(){//提交formdocument.itemsForm.action="${pageContext.request.contextPath}/items/editItemsAllSubmit.action";document.itemsForm.submit();}function queryItems(){//提交formdocument.itemsForm.action="${pageContext.request.contextPath }/items/queryItems.action";document.itemsForm.submit();}
</script>
</head>
<body><formname="itemsForm"action="${pageContext.request.contextPath }/items/queryItems.action"method="post">查询条件:<table width="100%" border=1><tr><td>商品名称:<input name="itemsCustom.name" /></td><td><input type="button" value="查询" οnclick="queryItems()"/><input type="button" value="批量提交" οnclick="editItemsAllSubmit()"/></td></tr></table>商品列表:<table width="100%" border=1><tr><td>商品名称</td><td>商品价格</td><td>生产日期</td><td>商品描述</td></tr><c:forEach items="${itemsList}" var="item" varStatus="status"><tr><td><input name="itemsList[${status.index}].name" value="${item.name}"></input></td><td><input name="itemsList[${status.index}].price" value="${item.price}"></input></td><td><input name="itemsList[${status.index}].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"></input></td><td><input name="itemsList[${status.index}].detail" value="${item.detail}"></input></td></tr></c:forEach></table></form>
</body></html>

表现层实现

​ 使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list属性。

展示修改信息页面的controller:

 /*** 5.批量修改商品信息页面:* @return*/@RequestMapping(value="/editItemsQuery",method={RequestMethod.GET,RequestMethod.POST})public ModelAndView  editItemsQuery(ItemsQueryVo itemsQueryVo){List<ItemsCustom> itemsList = itemsService.findItemsList(itemsQueryVo);ModelAndView modelAndView = new ModelAndView();modelAndView.addObject("itemsList", itemsList);modelAndView.setViewName("items/editItemsQuery");return modelAndView;}

点击批量提交后的controller:

/*** 6、批量修改后的提交页面(批量提交):list参数绑定* @param itemsQueryVo* @return*/@RequestMapping(value="/editItemsAllSubmit")public String editItemsAllSubmit(ItemsQueryVo itemsQueryVo){return "redirect:editItemsQuery.action";}

形参类型:需要一个list集合来接收批量提交的数据。

页面定义:

2.3、map

也通过在包装pojo中定义map类型属性。

在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。

包装类中定义Map对象如下:

Public class QueryVo {private Map<String, Object> itemInfo = new HashMap<String, Object>();//get/set方法..
}

页面定义如下:

<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>

Contrller方法定义如下:

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{System.out.println(queryVo.getStudentinfo());
}

3、服务端校验

3.1、校验理解

​ 项目中,通常使用较多的是前端的校验,比如页面中js校验。对于安全要求较高点建议在服务端进行校验。

​ 服务端校验:

​ 控制层controller:校验页面请求的参数的合法性。在服务端控制层controller校验,不区分客户端类型(浏览器,手机客户端,远程调用)

​ 业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。

​ 持久层dao:一般是不校验的。

3.2、springmvc校验

​ springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。

​ 校验思路:

​ 页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。

​ 具体需求:商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。

3.3、环境准备

  • 添加校验的jar包:

3.4、添加校验配置文件:CustomValidationMessages.properties

3.5、配置校验器:springmvc.xml

<!-- 5、配置校验器 --><bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"><!-- 校验器 --><property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property><!-- 指定校验使用的资源文件,如果不指定则默认使用classpath下的ValidationMessages.properties --><property name="validationMessageSource" ref="messageSource"></property></bean><!-- 校验错误信息配置文件 --><bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><!-- 资源文件名 --><property name="basenames"><list><value>classpath:CustomValidationMessages</value></list></property><!-- 资源文件编码格式 --><!--<property name="fileEncodings" value="utf-8"></property>错误配置--><property name="defaultEncoding" value="utf-8"></property> <!-- 资源文件内容缓存时间 ,单位秒--><property name="cacheSeconds" value="120"></property></bean>

3.6、将校验器配置到处理器适配器中:springmvc.xml

配置方式1:

validator="validator"

<!-- 1、配置注解的处理器适配器和映射器 -->  <mvc:annotation-driven conversion-service="conversionService" validator="validator"></mvc:annotation-driven>

配置方式2(自学):

<!-- 自定义webBinder --><bean id="customBinder"class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"><property name="validator" ref="validator" /></bean><!-- 注解适配器 --><beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="webBindingInitializer" ref="customBinder"></property></bean>

3.7、添加校验规则items.java

items.java

  //message:错误输入的提示信息@Size(min=1,max=30,message="{items.name.length.error}")private String name;private Float price;private String pic;@NotNull(message="{items.createtime.isNull}")private Date createtime;

3.8、错误消息文件配置CustomValidationMessages

#配置错误提示信息
items.name.length.error=商品名称在1到30个字符之间
items.createtime.isNull=请输入商品的日期

3.9、在controller中捕获校验信息

**捕获校验信息:**在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult的形参,接收校验出错信息。

注意:@Validated和BindingResult形参是配对出现的,并且顺序是一前一后。

@Validated ItemsCustom itemsCustom,BindingResult bindingResult
 /*** 7、点击提交后的操作:信息校验* @param id* @param itemsCustom* @return*///校验信息:在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult的形参,接收校验出错信息。//注意:@Validated和BindingResult形参是配对出现的,并且顺序是一前一后。@RequestMapping(value="/editItemsSubmit",method={RequestMethod.POST,RequestMethod.GET})public String editItemsSubmit(Integer id,@Validated ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception{//获取校验错误信息if(bindingResult.hasErrors()){List<ObjectError> allErrors = bindingResult.getAllErrors();for (ObjectError objectError : allErrors) {System.out.println(objectError.getDefaultMessage());}}//获取提交的items,更新到数据库itemsService.updateItems(id, itemsCustom);return "forward:queryItems.action";}

3.10、在页面中显示错误信息

  • 将错误信息传到页面:

    List<ObjectError> allErrors = bindingResult.getAllErrors();
    //将错误信息传导页面
    model.addAttribute("allErrors", "allErrors");
    
    /*** 7、点击提交后的操作:信息校验* @param id* @param itemsCustom* @return*///校验信息:在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult的形参,接收校验出错信息。//注意:@Validated和BindingResult形参是配对出现的,并且顺序是一前一后。@RequestMapping(value="/editItemsSubmit",method={RequestMethod.POST,RequestMethod.GET})public String editItemsSubmit(Integer id,Model model,@Validated ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception{//获取校验错误信息if(bindingResult.hasErrors()){List<ObjectError> allErrors = bindingResult.getAllErrors();for (ObjectError objectError : allErrors) {System.out.println(objectError.getDefaultMessage());}//将错误信息传导页面model.addAttribute("allErrors", "allErrors");return null;}//获取提交的items,更新到数据库itemsService.updateItems(id, itemsCustom);return "forward:queryItems.action";}
    
  • 在页面中获取错误信息

<!-- 显示错误信息 -->
<c:if test="${allErrors != null}"><c:forEach items="${allErrors}" var="error">${error.defaultMessage }<br/></c:forEach>
</c:if>

问题:获取到的校验信息乱码

https://blog.csdn.net/stloven5/article/details/53312012

资源文件编码格式配置错误

正确配置方式:

<!-- 资源文件编码格式 --><property name="fileEncodings"><props><prop key="classpath:CustomValidationMessages">UTF-8</prop></props></property>

或者直接配置:

<property name="defaultEncoding" value="utf-8"></property>

3.11、分组校验

需求:

​ 在pojo中定义校验规则,而pojo是被多个controller所共用,当不同的controller方法对同一个pojo进行校验。但是每个controller方法需要不同的校验。

​ 解决方法:

​ 定义多个校验分组(其实是一个java接口),分组中定义有哪些规则。

​ 每个controller方法使用不同的校验分组。

定义分组:接口定义

package com.zwd.ssm.controller.validation;
/*** 校验分组* @author Administrator**/
public interface ValidGroup1 {//此接口中不需要定义任何方法,仅是对不同的校验规则进行分组//此分组校验商品名称长度
}

在校验规则中添加分组

在controller方法上使用分组校验

3.12、校验注解

@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(regex=,flag=) 被注释的元素必须符合指定的正则表达式

Hibernate Validator 附加的 constraint

@NotBlank(message =) 验证字符串非null,且长度必须大于0

@Email 被注释的元素必须是电子邮箱地址

@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内

@NotEmpty 被注释的字符串的必须非空

@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

4、数据回显:

4.1、什么是数据回显

​ 提交后,如果出现错误,将刚才提交的数据回显到刚才的提交的页面。

4.2、pojo数据回显方法:@ModelAttribute

​ 1、springMVC默认对pojo数据进行回显。

pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)。

​ 2、使用@ModelAttribute可以指定pojo回显到页面在request中的key。页面就可以根据该key来取值。

​ 3、@ModelAttribute还可以将方法的返回值传到页面

 /*** 商品分类* @return*///@ModelAttribute表示最终将方法返回值放在request中的key中@ModelAttribute(value="itemTypes")public Map<String,String> getItemTypes(){Map<String,String> itemTypes = new HashMap<String,String>();itemTypes.put("101", "数码");itemTypes.put("102", "母婴");return itemTypes;}
<td>商品名称:<input name="itemsCustom.name" />商品类型:<select name="itemTypes"><c:forEach items="${itemTypes}" var="itemType"><option value="${itemType.key}">${itemType.value}</option></c:forEach></select>
</td>

4.3、简单类型回显方法

​ 对于简单数据类型,如:Integer、String、Float等使用Model将传入的参数再放到request域实现显示。

 @RequestMapping(value="/editItems",method={RequestMethod.GET})public String editItems(Model model,Integer id)throws Exception{//传入的id重新放到request域model.addAttribute("id", id);

5、异常处理

5.1、异常处理思路

​ 系统中异常包括两类,预期异常和运行异常RunTimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

​ 系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springMVC前端控制器交给异常处理器进行异常处理。如下图:

springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

5.2、自定义异常类

​ 对不同的异常类型定义异常类,继承Exception。

package com.zwd.ssm.exception;
/*** 系统自定义的异常类:针对预期的异常,需要在程序中抛出此类异常。* @author Administrator**/
public class CustomException extends Exception {//异常信息private String message;public CustomException(String message){super(message);this.message = message;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}}

5.3、全局异常处理器

思路:

​ 系统遇到异常,在程序中手动抛出,dao抛给service、service给controller,controller抛给前端控制器,前端控制器调用全局异常处理器。

全局异常处理器处理器思路:

​ 解析出异常类型

​ 如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示。

​ 如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)

必须继承HandlerExceptionResolver

package com.zwd.ssm.exception;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/*** 全局异常处理器* @author Administrator**/
public class CustomExceptionResolver implements HandlerExceptionResolver{/***  Object handler:处理器适配器要执行的handler(只有一个method)*  Exception ex:系统抛出的异常*/@Overridepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse respnse, Object handler,Exception ex) {/*        String message = null;
//      解析出异常类型
//      如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示。if(ex instanceof CustomException){message = ex.getMessage();}
//      如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)else{message="未知错误";}*///上面代码重写为:CustomException customException = null;if(ex instanceof CustomException){customException = new CustomException(ex.getMessage());}else{customException = new CustomException("未知错误");}//错误信息String message = customException.getMessage();ModelAndView modelAndView = new ModelAndView();//将错误信息传到页面modelAndView.addObject("message", message);//指向错误页面modelAndView.setViewName("error");return modelAndView;}}

5.4、错误页面

error.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>错误页面</title>
</head>
<body>
错误页面
</body>
</html>

5.5、在springmvc中配置全局异常处理器

<!-- 6、配置全局异常处理器:只要实现了HandlerExceptionResolver接口,就是一个全局异常处理器 --><bean class="com.zwd.ssm.exception.CustomExceptionResolver"></bean>

5.6、异常测试

​ 在controller、service、dao中任意一处需要手动抛出自定义异常。如果是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出异常说明是一个运行时异常,在错误页面只显示“未知错误”。

​ 在商品修改的controller方法中抛出异常 :

​ 在service中抛出异常:

如果与业务功能相关的异常,建议在service中抛出异常。

与业务功能没有关系的异常,建议在controller中抛出。

上边的功能,建议在service中抛出异常。

6、上传图片

6.1、需求

​ 在修改商品页面,添加上传商品图片功能。enctype="multipart/form-data"

<form id="itemForm" action="${pageContext.request.contextPath }/items/editItemsSubmit.action"
method="post" enctype="multipart/form-data">

6.2、导入jar包

6.3、springmvc中对多部件类型的解析

​ 在页面form中提交enctype="multipart/form-data"的数据时,需要springmvc对multipart类型的数据进行解析。

​ 在springmvc.xml中配置解析器:

<!-- 7、上传图片:配置多部件类型解析器--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 设置上传文件的最大尺寸为5MB --><property name="maxUploadSize" ><value>5242880</value></property></bean>

6.4、创建图片虚拟目录来存储图片

  • 通过图形界面来创建:

  • 在tomcat服务器的config/server.xml中添加配置

    <Context docBase="G:\imgs" path="/pic" reloadable="true"/>
    
      <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true"><!-- SingleSignOn valve, share authentication between web applicationsDocumentation at: /docs/config/valve.html --><!--<Valve className="org.apache.catalina.authenticator.SingleSignOn" />--><!-- Access log processes all example.Documentation at: /docs/config/valve.htmlNote: The pattern used is equivalent to using pattern="common" --><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt"/><Context docBase="06.ssm" path="/06.ssm" reloadable="true" source="org.eclipse.jst.jee.server:06.ssm"/><Context docBase="G:\imgs" path="/pic" reloadable="true"/></Host>
    

**注意:**在图片虚拟目录中,一定将图片目录分级创建(提高i/o性能),一般我们采用按日期(年、月、日)进行分级创建。

6.5、上传图片代码

页面代码

<tr><td>商品图片</td><td><c:if test="${itemsCustom.pic !=null}"><img src="/pic/${itemsCustom.pic}" width=100 height=100/><br/></c:if><input type="file"  name="items_pic"/> </td>
</tr>
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
<!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>修改商品信息</title></head>
<body> <!-- 显示错误信息 -->
<c:if test="${allErrors != null}"><c:forEach items="${allErrors}" var="error">${error.defaultMessage }<br/></c:forEach>
</c:if><form id="itemForm" action="${pageContext.request.contextPath }/items/editItemsSubmit.action"
method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="${itemsCustom.id }"/>
修改商品信息:
<table width="100%" border=1>
<tr><td>商品名称</td><td><input type="text" name="name" value="${itemsCustom.name }"/></td>
</tr>
<tr><td>商品价格</td><td><input type="text" name="price" value="${itemsCustom.price }"/></td>
</tr><tr><td>商品生产日期</td><td><input type="text" name="createtime" value="<fmt:formatDate value="${itemsCustom.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
</tr>
<tr><td>商品图片</td><td><c:if test="${itemsCustom.pic !=null}"><img src="/pic/${itemsCustom.pic}" width=100 height=100/><br/></c:if><input type="file"  name="items_pic"/> </td>
</tr>
<tr><td>商品简介</td><td><textarea rows="3" cols="30" name="detail">${itemsCustom.detail }</textarea></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"/>
</td>
</tr>
</table></form>
</body></html>

controller代码

MultipartFile items_pic

/*** 7、点击提交后的操作:上传图片* @param id* @param itemsCustom* @return*///MultipartFile:获取页面上传图片的信息@RequestMapping(value="/editItemsSubmit",method={RequestMethod.POST,RequestMethod.GET})public String editItemsSubmit(Integer id,Model model,@ModelAttribute(value="items") @Validated(value={ValidGroup1.class}) ItemsCustom itemsCustom,BindingResult bindingResult,MultipartFile items_pic) throws Exception{//获取校验错误信息if(bindingResult.hasErrors()){List<ObjectError> allErrors = bindingResult.getAllErrors();for (ObjectError objectError : allErrors) {System.out.println(objectError.getDefaultMessage());}//将错误信息传导页面model.addAttribute("allErrors", allErrors);return "items/editItems";}//上传图片if(items_pic != null && items_pic.getOriginalFilename()!= null && items_pic.getOriginalFilename()!=""){//存储图片的物理路径String pic_path = "G:\\imgs\\";//原始名称String originaleFilename = items_pic.getOriginalFilename();//新的图片名称String newFileName = UUID.randomUUID() + originaleFilename.substring(originaleFilename.lastIndexOf("."));//新图片File newFile = new File(pic_path+newFileName);//将内存中的数据写入磁盘items_pic.transferTo(newFile);//将新图片名称写到itemsCustom中itemsCustom.setPic(newFileName);}//获取提交的items,更新到数据库itemsService.updateItems(id, itemsCustom);return "forward:queryItems.action";}

7、json数据交互

7.1、 为什么要进行json数据交互

​ json数据格式在接口调用中、HTML页面中较常用,json格式比较简单,解析还比较方便。

比如:webService接口,传输json数据。

7.2、springmvc进行json交互

1、请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不太方便。

2、请求key/value、输出json。此方法比较常用。

@RequestBody

作用:

​ @RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。

@ResponseBody

作用:

​ 该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端

7.3、环境准备

​ springmvc中使用jackson的包进行json转换(@RequestBody、@ResponseBody使用下边的包进行json转换)

​ 上述包不适用,已更换为下面三个json包。

7.4、配置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.MappingJacksonHttpMessageConverter"></bean></list></property></bean>

7.5、json测试

7.5.1、输入json,输出json

jsp页面

​ 使用jQuery的ajax提交json串,对输出的json结构进行解析。

  • 将jQuery文件放在WebRoot下:

  • 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>json交互测试</title>
    </head><script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
    <script type="text/javascript">//请求json输出jsonfunction requestJson(){$.ajax({type:'post',url:'${pageContext.request.contextPath }/requestJson.action',contentType:'application/json;charset=utf-8',//请求的数据格式是json串data:'{"name":"手机","price":999}',success:function(data){//data:返回的json串alert(data);}});}//请求key/value输出jsonfunction requestKV(){}</script>
    <body><input type="button" οnclick="requestJson()" value="请求json输出json"/><input type="button" οnclick="requestKV()" value="请求json输出json"/>
    </body>
    </html>
    
controller
package com.zwd.ssm.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.zwd.ssm.po.ItemsCustom;
/*** json的测试controller* @author Administrator**/
@Controller
public class JsonTextController {/*** 输入json(商品信息),输出json(商品信息)* @param itemsCustom* @return*///@RequestBody:将输入的json串转为java对象//@ResponseBody:将输出的java对象转为json串输出@RequestMapping("/requestJson")public @ResponseBody ItemsCustom  requestJson(@RequestBody ItemsCustom itemsCustom){return itemsCustom;}
}
访问
http://localhost:8080/08.json/jsonTest.jsp

7.5.2、输入key/value,输出json

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>json交互测试</title>
</head><script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">//请求json输出jsonfunction requestJson(){$.ajax({type:'post',url:'${pageContext.request.contextPath }/requestJson.action',//ContentType没指定将默认为:application/x-www-form-urlencodedcontentType:'application/json;charset=utf-8',//请求的数据格式是json串data:'{"name":"手机","price":999}',success:function(data){//data:返回的json串alert(data);}});}//请求key/value输出jsonfunction requestKV(){$.ajax({type:'post',url:'${pageContext.request.contextPath }/requestKV.action',//这里不用指定contentType,默认就是这里key/value的类型//contentType:'application/x-www-form-urlencoded',data:'name=手机&price=999',success:function(data){//data:返回的json串alert(data.name);}});}</script>
<body><input type="button" οnclick="requestJson()" value="请求json输出json"/><input type="button" οnclick="requestKV()" value="请求json输出json"/>
</body>
</html>
controller
package com.zwd.ssm.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.zwd.ssm.po.ItemsCustom;
/*** json的测试controller* @author Administrator**/
@Controller
public class JsonTextController {/*** 输入json(商品信息),输出json(商品信息)* @param itemsCustom* @return*///@RequestBody:将输入的json串转为java对象//@ResponseBody:将输出的java对象转为json串输出@RequestMapping("/requestJson")public @ResponseBody ItemsCustom  requestJson(@RequestBody ItemsCustom itemsCustom){return itemsCustom;}/*** 请求key/value,输出json* @param itemsCustom* @return*/@RequestMapping("/requestKV")public @ResponseBody ItemsCustom  requestKV(ItemsCustom itemsCustom){return itemsCustom;}
}
访问
http://localhost:8080/08.json/jsonTest.jsp

报错问题

​ 问题已在上面更改。

  • jquery-1.4.4.min.js找不到,404

    解决:js文件放错位置。应放在WebRoot下。

  • org.springframework.web.HttpMediaTypeNotSupportedException:

    Content type ‘application/json;charset=utf-8’ not supported

    https://blog.csdn.net/fpxty/article/details/72835993
    

    解决:json包版本太低,更换json包。

8、RESTful支持

8.1、什么是RESTful

​ RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

​ RESTful(即Representational State Transfer的缩写)其实是一个开发理念,是对http的很好的诠释。

1、对url进行规范,写RESTful格式的url

​ 非REST的url:http://…/queryItems.action?id=001&type=T01

​ REST的url风格:http://…/items/001

​ 特点:url简洁,将参数通过url传到服务端

2、http的方法规范

​ 不管是删除、添加、更新。。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加。

3、对http的contentType规范

​ 请求时指定contentType,要json数据,设置成json格式的type。。

8.2、REST测试

需求

​ 查询商品信息,返回json数据。

controller

package com.zwd.ssm.controller;import javax.annotation.Resource;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.zwd.ssm.po.ItemsCustom;
import com.zwd.ssm.service.ItemsService;/*** RESTful测试* @author Administrator**/
@Controller
public class RestfulController {@Resource(name="itemsService")private ItemsService itemsService;/*** 查询商品信息:restful风格的url* @param id* @return* @throws Exception*///{id}:表示占位符,通过@PathVariable("id")获取占位符中的参数。//如果占位符中的名称和形参名称一致,在@PathVariable中可以不指定名称@RequestMapping("/restfulItemsquery/{id}")public @ResponseBody ItemsCustom restfulItemsquery(@PathVariable("id") Integer id) throws Exception{ItemsCustom itemsCustom = itemsService.findItemsById(id);return itemsCustom;}//    @RequestMapping("/restfulItemsquery/{id}/{type}")
//  public @ResponseBody ItemsCustom restfulItemsquery1(@PathVariable("id") Integer id,@PathVariable("type") String aaa) throws Exception{//      ItemsCustom itemsCustom = itemsService.findItemsById(id);
//      return itemsCustom;
//  }
}

REST方法的前端控制器配置

​ 因为之前把url-pattern设置成*.action,所以使用restful风格的url(http://localhost:8080/08.json/restfulItemsquery/1)直接访问上面controller时,会发生404错误,找不到对应的url的handler。改成’/'即可访问。

HTTP Status 404 - /08.json/restfulItemsquery/1

 <!-- 2、配置springmvc前端控制器 --><!-- The front controller of this Spring Web application, responsible for handling all application requests --><servlet><servlet-name>springDispatcherServlet</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><load-on-startup>1</load-on-startup></servlet><!--    <servlet-mapping><servlet-name>springDispatcherServlet</servlet-name><url-pattern>*.action</url-pattern></servlet-mapping> --><!-- 使用restful,需要将url-pattern设置成 '/',否则无法访问,因为上述只能访问.action后缀的url --><servlet-mapping><servlet-name>springDispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

对静态资源的访问

http://localhost:8080/08.json/js/jquery-1.4.4.min.js

​ 如果/这样设置,那么在访问静态资源的时候会发生404错误。因为根据地址找不到相应的handler,需要在springmvc.xml中添加对静态资源的访问。

<!-- 8、对静态资源的访问:如果<url-pattern>/</url-pattern>这样设置的,那么再访问静态资源的时候会发生404错误。因为根据地址找不到相应的handler,需要添加对静态资源的访问静态资源包括:js、css、img.... --><mvc:resources location="/js/" mapping="/js/**"/>

报错问题

在添加<mvc:resources location="/js/" mapping="/js/**"/>配置后,启动tomcat异常:

DEBUG [localhost-startStop-1] - Original ConversionService attempt
failed - ignored since PropertyEditor based conversion eventually
succeeded org.springframework.core.convert.ConversionFailedException:
Failed to convert from type java.util.ArrayList<?> to type
java.util.List<org.springframework.core.io.Resource> for value
‘[/js/]’; nested exception is
org.springframework.core.convert.ConverterNotFoundException: No
converter found capable of converting from type java.lang.String to
type org.springframework.core.io.Resource

解决参考地址:

https://blog.csdn.net/jevonsCSDN/article/details/60577714

9、拦截器

9.1、拦截器的定义

继承HandlerInterceptor接口:

package com.zwd.ssm.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;/*** 拦截器例子* @author Administrator**/
public class HandlerInterceptor1 implements HandlerInterceptor{/*** 1、进入Handler方法之前执行*///应用场景:用于身份认证、身份授权//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行@Overridepublic boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {//return false表示拦截,不再向下执行handler方法//return true表示放行return false;}/*** 2、进入handler方法之后,返回modelAndView之前执行。*///应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图@Overridepublic void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception {}/*** 3、handler执行完成后执行此方法*///应用场景:统一异常处理,统一日志处理@Overridepublic void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception {}}

9.2、拦截器配置springmvc.xml

方式一:针对HandlerMapping进行拦截设置

springmvc拦截器针对HandlerMapping进行拦截设置,如果在某个HandlerMapping中配置拦截,经过该HandlerMapping映射成功的handler最终使用该拦截器。一般不推荐使用。

<beanclass="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><property name="interceptors"><list><ref bean="handlerInterceptor1"/><ref bean="handlerInterceptor2"/></list></property>
</bean><bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/><bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

方式二:配置类似全局的拦截器

​ springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。

<!-- 9、全局拦截器配置 --> <mvc:interceptors><!-- 多个拦截器,顺序执行 --><mvc:interceptor><!-- /**:表示拦截所有url包括子url路径 --><mvc:mapping path="/**"/><bean class="com.zwd.ssm.interceptor.HandlerInterceptor1"></bean></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.zwd.ssm.interceptor.HandlerInterceptor2"></bean></mvc:interceptor></mvc:interceptors>

9.3、拦截器的测试

需求

​ 测试多个拦截器各各方法执行时机。

编写两个拦截

HandlerInterceptor1

package com.zwd.ssm.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;/*** 拦截器例子* @author Administrator**/
public class HandlerInterceptor1 implements HandlerInterceptor{/*** 进入Handler方法之前执行*///应用场景:用于身份认证、身份授权//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行@Overridepublic boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {//return false表示拦截,不再向下执行handler方法//return true表示放行System.out.println("HandlerInterceptor1...preHandle");return true;}/*** 进入handler方法之后,返回modelAndView之前执行。*///应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图@Overridepublic void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception {System.out.println("HandlerInterceptor1...postHandle");}/*** handler执行完成后执行此方法*///应用场景:统一异常处理,统一日志处理@Overridepublic void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception {System.out.println("HandlerInterceptor1...afterCompletion");}}

HandlerInterceptor2

package com.zwd.ssm.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;/*** 拦截器例子* @author Administrator**/
public class HandlerInterceptor2 implements HandlerInterceptor{/*** 进入Handler方法之前执行*///应用场景:用于身份认证、身份授权//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行@Overridepublic boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {//return false表示拦截,不再向下执行handler方法//return true表示放行System.out.println("HandlerInterceptor2...preHandle");return true;}/*** 进入handler方法之后,返回modelAndView之前执行。*///应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图@Overridepublic void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception {System.out.println("HandlerInterceptor2...postHandle");}/*** handler执行完成后执行此方法*///应用场景:统一异常处理,统一日志处理@Overridepublic void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception {System.out.println("HandlerInterceptor2...afterCompletion");}
}

拦截器在springmvc.xml中的配置如9.2方式二。

拦截器1和拦截器2都放行

HandlerInterceptor1…preHandle

HandlerInterceptor2…preHandle

HandlerInterceptor2…postHandle

HandlerInterceptor1…postHandle

HandlerInterceptor2…afterCompletion

HandlerInterceptor1…afterCompletion

总结:

preHandle方法按顺序执行

postHandle和afterCompletion按拦截器配置的逆向顺序执行。

拦截器1放行、拦截器2不放行

HandlerInterceptor1…preHandle
HandlerInterceptor2…preHandle
HandlerInterceptor1…afterCompletion

总结:

拦截器1放行,拦截器2 preHandle才会执行。

拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。

只要有一个拦截器不放行,postHandle都不会执行。

拦截器1不放行、拦截器2不放行

HandlerInterceptor1…preHandle

HandlerInterceptor1…preHandle

总结:

拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。

拦截器1 preHandle不放行,拦截器2不执行。

小结

​ 根据测试结果,对拦截器应用进行总结。

比如:统一日志处理拦截器,需要该拦截器preHandle一定要放行,且将它放在拦截器链接中第一个位置。

比如:登陆认证拦截器,放在拦截器链接中第一个位置。权限校验拦截器,放在登陆认证拦截器之后。(因为登陆通过后才校验权限)

9.4、拦截器应用:实现登录认证

需求

​ 1、用户请求url

​ 2、拦截器进行拦截校验

​ 如果请求的url是公开地址(无需登录即可访问的url),让放行

​ 如果用户session不存在跳转到登录页面

​ 如果用户session存在放行,继续操作

登录页面:login.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>系统登陆</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/login.action" method="post">
用户账号:<input type="text" name="username" /><br/>
用户密码 :<input type="password" name="password" /><br/>
<input type="submit" value="登陆"/>
</form>
</body>
</html>

登录的controller方法

LoginController.java

package com.zwd.ssm.controller;import javax.servlet.http.HttpSession;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;/*** 登录* @author Administrator**/
@Controller
public class LoginController {/*** 登录* @param session* @param username* @param password* @return*/@RequestMapping("/login")public String login(HttpSession session,String username,String password){//调用service进行身份认证...session.setAttribute("username", username);//重定向到商品查询页面return "redirect:/items/queryItems.action";}/*** 退出登录* @param session* @return*/@RequestMapping("/logout")public String logout(HttpSession session){//清除sessionsession.invalidate();return "redirect:/items/queryItems.action";}
}

登录认证拦截实现

package com.zwd.ssm.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;/*** 拦截器例子* @author Administrator**/
public class LoginInterceptor implements HandlerInterceptor{/*** 用户身份验证*///应用场景:用于身份认证、身份授权//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {//获取url地址StringBuffer url = request.getRequestURL();//判断该地址是否是公开地址(实际项目中公开地址需要写到配置文件中),这里是登录页面的地址if(url.indexOf("login.action")>=0){//是登录页面,放行return true;}if(request.getSession() != null && request.getSession().getAttribute("username") != null){//不是登录页面,但用户已经登录,放行return true;}//否则:不是登录连接并且session为空:跳转到登录页面,不放行request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);return false;}/*** 进入handler方法之后,返回modelAndView之前执行。*///应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图@Overridepublic void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception {System.out.println("HandlerInterceptor2...postHandle");}/*** handler执行完成后执行此方法*///应用场景:统一异常处理,统一日志处理@Overridepublic void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception {System.out.println("HandlerInterceptor2...afterCompletion");}
}

拦截器配置:springmvc.xml

<!-- 9、全局拦截器配置 --> <mvc:interceptors><!-- 多个拦截器,顺序执行 --><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.zwd.ssm.interceptor.LoginInterceptor"></bean></mvc:interceptor><mvc:interceptor><!-- /**:表示拦截所有url包括子url路径 --><mvc:mapping path="/**"/><bean class="com.zwd.ssm.interceptor.HandlerInterceptor1"></bean></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.zwd.ssm.interceptor.HandlerInterceptor2"></bean></mvc:interceptor></mvc:interceptors>

访问

http://localhost:8080/08.json/items/queryItems.action

框架-springmvc(ssm整合)相关推荐

  1. SSM框架:SSM整合

    SSM框架:SSM整合 文章目录 前言 SSM整合 0. 环境搭建 1.环境要求 2.数据库环境 3.基本环境搭建 1.依赖 2.静态资源导出问题 底层 1. SSM整合:Mybatis层 整合dao ...

  2. ajax在ssm中的使用,Ajax 框架之SSM整合框架实现ajax校验

    刚学习了ssm框架,ajax校验成功,分享下 1.导入jar包 2.配置spring-servlet.xml text/html;charset=UTF-8 text/json;charset=UTF ...

  3. mybatis+spring+springmvc ssm整合

    文章目录 mybatis 开发我的第一个mybatis程序 关于mybatis的核心API:SqlSession对象. mybatis连接数据库操作 log4j jackson parameterTy ...

  4. springMVC——SSM整合(IDEA 搭建简单 ssm 框架最详细最简单教程)

    为开发一个测试程序,特搭建一个简单的ssm框架,因为网上看到很多都是比较老旧的教程,很多包都不能用了,eclipes搭建并且其中还附带了很多的其他东西,所以特此记录一下mac中idea搭建过程. 以下 ...

  5. 【SSM】SSM整合

    文章目录 SSM整合项目视频 项目功能点 技术点 设置maven 引入项目依赖的jar包 引入bootstrap前端框架 编写ssm整合的关键配置文件 web.xml配置 springMVC的配置文件 ...

  6. java框架ssm整合_SSM三大框架整合详细教程(Spring+SpringMVC+MyBatis)

    使用 SSM ( Spring . SpringMVC 和 Mybatis )已经有三个多月了,项目在技术上已经没有什么难点了,基于现有的技术就可以实现想要的功能,当然肯定有很多可以改进的地方.之前没 ...

  7. SSM(Spring+SpringMVC+Mybatis)框架环境搭建(整合步骤)(一)

    SSM(Spring+SpringMVC+Mybatis)框架环境搭建(整合步骤)(一) 1. 前言 最近在写毕设过程中,重新梳理了一遍SSM框架,特此记录一下. 附上源码:https://gitee ...

  8. SpringMvc框架及SSM框架整合

    SpringMvc框架及SSM框架整合 一.SpringMvc相关知识 1.Spring和SpringMvc的关系 ​ 1.1.Spring是IOC和AOP的容器框架,SpringMVC是基于Spri ...

  9. 基于Maven+SpringMVC+Spring+MyBatis+Layui整合框架,超详细的SSM整合❤️

    人生有太多不如意,我们要学会去努力 参考文档:layUI文档:spring家族文档:mybatis文档 前言:SSM 整合 整合的思路是: 先创建spring框架 通过spring整合spring m ...

  10. SpringMVC学习06之SSM整合(一)

    复习 我的环境 环境: IDEA MySQL 5.7.34 Tomcat 8 Maven 3.8.3 一.SSM整合 要求: 需要熟练掌握MySQL数据库,Spring,JavaWeb及MyBatis ...

最新文章

  1. CowNew开源团队新书《自己动手写开发工具》隆重上市
  2. 2016年第七届蓝桥杯决赛Java本科B组试题解析
  3. zk如何实现watch
  4. python写文件追加 按行追加_Python3 自学第14天:文件操作,文件句柄,上下文管理器...
  5. 马逊s3云存储接口_利用 S3tests 测试 S3 接口兼容性
  6. 爱创课堂每日一题第四十天- 说说你对语义化的理解?
  7. 一、后台首页index.php【dedecms后台源码分析】
  8. 跟着老桂学ASP.NET Core 2.0
  9. Tomcat 全攻略
  10. RF工具ride使用
  11. 类似纪念碑谷的unity2d素材包_《纪念碑谷》:引领小清新风格的2.5D插画风游戏...
  12. 全网首发:以字型为例,一维表示的二维数组矩阵,以易理解的方式旋转90、-90
  13. access 知乎 窗体_ACCESS数据可视化之路
  14. 数学差考研考计算机专业,2021考研数学基础差,这4大方法让你快速上手_计算机专业考研...
  15. Deep Learning for Image and Point Cloud Fusionin Autonomous Driving: A Review
  16. python连连看小游戏_python tkinter实现连连看游戏
  17. 乐视尚酷版无线手柄PC驱动 手柄通用驱动教程
  18. 自动备份Linux上的博客数据到坚果云
  19. 小说作者推荐:忘却的悠合集
  20. 国内首部《数字货币词典》在新莫干山会议上启动,巴比特智库担任主编单位...

热门文章

  1. VS2017创建DLL文件并调用
  2. 中国电信ChinaNet骨干网大区片区和省级节点
  3. MyBatis-Plus中关于大于、等于、小于的问题
  4. c语言清除键盘缓冲区函数,C语言程序中清除键盘缓冲区的方法
  5. 三个方案解决短视频APP广告变现问题
  6. 2018版 自考 计算机网络原理 04741 考试大纲
  7. JAVA JAV,javjava
  8. 哈工大深圳计算机学院老师信息的爬取
  9. Jetson-Nano开箱配置及Tensorflow安装使用
  10. 2017云栖大会门票转让_云栖大会的门票可以转让么?门票怎么买?