SpringMVC - 传智燕青

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37546891/article/details/82526128

>> SpringMVC 框架基础

~ 什么是 SpringMVC

springmvcspring框架的一个模块,springmvc和spring无需通过中间层进行整合;

springmvc是一个基于MVC的web框架;
这里写图片描述

~ mvc在B/S系统下的应用

mvc是一个设计模式,mvc在B/S系统下的应用:
这里写图片描述

~ SpringMVC 框架原理

这里写图片描述

SpringMVC执行过程:

  • 1、发起请求到前端控制器(DispatcherServlet);
  • 2、前端控制器请求HandlerMapping查找Handler;可以xml配置、或注释进行查找;
  • 3、处理器映射器HandlerMapping向前端控制器返回Handler;
  • 4、前端控制器调用处理器适配器去执行Handler;
  • 5、处理器适配器去执行Handler;
  • 6、Handler执行完成,给适配器返回ModelAndView;
  • 7、处理器适配器向前端控制器返回ModelAndView;ModelAndView是SpringMVC框架的一个底层对象,包括Model和View;
  • 8、前端控制器请求视图解析器去进行试图解析;(根据逻辑视图名解析成真正的视图:jsp…)
  • 9、视图解析器向前端控制器返回View;
  • 10、前端控制器进行视图渲染;
  • 11、前端控制器向用户响应结果;

SpringMVC重要组件:

  • 1、前端控制器DispatcherServlet (不需要程序员开发)
    作用:接收请求啊,响应结果;相当于转发器,中央处理器;有了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…)

>> 入门程序:springmvc

~ 需求

以案例作为驱动:SpringMVC和mybatis使用一个案例(商品订单管理)
功能需求:商品列表查询;

~ 环境准备

1、搭建数据库,4张表:User、Orders、OrderDetail、OItems;
2、创建一个动态Javaweb项目:
3、加入需要的jar包:spring所有jar包、jstl的jar包、logging的jar包、数据库驱动包;

~ 项目结构

这里写图片描述

~ po类:User、Orders、Orderdetail、Items

// User.java
public class User {
    private Integer id;      // 用户id
    private String username; // 用户姓名
    private String sex;      // 用户性别
    private Date birthday;   // 用户生日
    private String address;  // 用户地址
}
// Orders.java
public class Orders {
	private Integer id;      // 订单id
	private Integer userId;  // 下单用户id
	private String number;   // 订单号
	private Date createtime; // 创建订单时间
	private String note;     // 备注
}
// Orderdetail.java
public class Orderdetail {
    private Integer id;
    private Integer ordersId; // 订单id
    private Integer itemsId;  // 商品id
    private Integer itemsNum; // 商品购买数量
}
// Items.java
public class Items {
    private Integer id;
    private String name;     // 商品名称
    private Float price;     // 商品定价
    private String pic;      // 商品图片
    private Date creametime; // 生产日期
    private String detail;   // 商品描述
}

~ 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>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>
	<!-- url-pattern 有3种配置方式:
		 1、*.action,访问以.action为结尾的地址,由DispatcherServlet进行解析;
	 	 2、斜杠/,所有访问的地址,都由DispatcherServlet进行解析,
	 	          对于静态文件的解析需要配置不让DispatcherServlet进行解析;
	 	          使用此种方式可以实现RESTful风格的url;
		 3、/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面,
		          仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到Handler,会报错; -->
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<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 文件头

// 在Beans声明处添加aop、context等命名空间的Schema定义文件的说明,这样在配置文件中就可以使用这些命名空间下的配置标签了;
<?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:mvc="http://www.springframework.org/schema/mvc" 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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
// -----------------------------------------------------------------------------
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd 
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd 
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd">

~ springmvc.xml 文件

// 文件头......
	<!-- 配置非注解 Handler -->
	<bean id="ItemsController1" name="/queryItems.action" 
	      class="cn.itcast.ssm.controller.ItemsController1" />
	<bean id="ItemsController5" class="cn.itcast.ssm.controller.ItemsController1" />
		  
	<!-- 多个映射器可以并存,前端控制器判断url能让哪些映射器去映射,就让正确的映射器处理; -->
	<!-- (1)非注解的处理器映射器:将bean的name作为url进行查找,需要在配置handler时指定beanname(就是url) 
	                           在bean里面配置url -->
	<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
	<!-- (2)非注解的简单处理器映射器:简单url映射;   将url和handler集中进行配置; -->
	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>  <!-- 同一个bean可以有多个url -->
				<!-- 对ItemsController1进行url映射,url是/queryItems1.action -->
				<prop key="/queryItems1.action">ItemsController1</prop>
				<prop key="/queryItems2.action">ItemsController1</prop>
				<prop key="/queryItems5.action">ItemsController5</prop>
			</props>
		</property>
	</bean>
	
	<!-- (1)非注解的处理器适配器1:所有处理器适配器都实现HandlerAdapter接口;
		             要求:handler实现Controller接口; -->
	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
	<!-- (2)非注解的处理器适配器2:所有处理器适配器都实现HandlerAdapter接口;
		             要求:handler实现HttpRequestHandler接口; -->
	<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
	
	<!-- (3)对于注释的Handler可单独配置(不需要写id、name);  
	     实际开发中建议使用组件扫描;可扫描controller、service、...... -->
	<!-- <bean class="cn.itcast.ssm.controller.ItemsController3" /> -->
	<context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>
	
	<!-- (3)注意:注解的映射器和适配器必须配对使用! -->
	<!-- (3)注解的映射器 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
	<!-- (3)注解的适配器 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
	<!-- 使用mvc:annotation-driven代替上边的注解映射器和注解适配器配置;
		 mvc:annotation-driven默认加载很多的参数绑定方法,比如json转换解析器就默认加载了,
		   如果使用mvc:annotation-driven就不用再配置
		   上边的RequestMappingHandlerMapping和RequestMappingHandlerAdapter了;
		   实际开发中使用mvc:annotation-driven -->
	<!-- <mvc:annotation-driven></mvc:annotation-driven> -->
	
	<!-- 视图解析器:解析jsp页面,默认使用jstl标签,classpath系需要有jstl的jar包 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
</beans>

~ Handler - ItemsController1.java

public class ItemsController1 implements Controller { // 实现Controller接口的处理器

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 调用service查找数据库,查询商品列表,这里使用静态数据模拟;
		List<Items> itemsList = new ArrayList<Items>();
		Items items1 = new Items(); // 向List中填充静态数据;
		items1.setName("联想笔记本");
		items1.setPrice(6000f);
		items1.setDetail("我的联想笔记本");
		Items items2 = new Items();
		items2.setName("小米手机");
		items2.setPrice(2000f);
		items2.setDetail("我的小米手机");
		itemsList.add(items1);
		itemsList.add(items2);

		// 返回ModelAndView
		ModelAndView modelAndView = new ModelAndView();
		// 相当于request的setAttribute,在jsp页面中通过itemsList取数据
		modelAndView.addObject("itemsList", itemsList);
		// 指定视图
		// modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
		modelAndView.setViewName("/items/itemsList");
		return modelAndView;
	}
}

~ Handler - ItemsController2.java

public class ItemsController2 implements HttpRequestHandler{
	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		List<Items> itemsList = new ArrayList<Items>(); //........造数据
		// 设置视图模型
		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串");
	}
}

~ Handler - ItemsController3.java

@Controller  // 使用Controllerz注释标识它是一个控制器
public class ItemsController3 { // 注解开发Handler
	// 方法1:查询商品列表
	// @RequestMapping实现对queryItemsAnnotation方法和url进行映射,一个方法对应一个url
	// 一般建议方法名和url写成一样;
	@RequestMapping("queryItemsAnnotation")
	public ModelAndView queryItemsAnnotation() throws Exception {
		List<Items> itemsList = new ArrayList<Items>();
		Items items1 = new Items(); // 向List中填充静态数据;
		items1.setName("联想笔记本");
		items1.setPrice(6000f);
		items1.setDetail("我的联想笔记本");
		Items items2 = new Items();
		items2.setName("小米手机");
		items2.setPrice(2000f);
		items2.setDetail("我的小米手机");
		itemsList.add(items1);
		itemsList.add(items2);
		// 返回ModelAndView
		ModelAndView modelAndView = new ModelAndView();
		// 相当于request的setAttribute,在jsp页面中通过itemsList取数据
		modelAndView.addObject("itemsList", itemsList);
		// 返回ModelAndView
		ModelAndView modelAndView = new ModelAndView();
		// 相当于request的setAttribute,在jsp页面中通过itemsList取数据
		modelAndView.addObject("itemsList", itemsList);
		// 指定视图
		// 下边的路径,如果在视图解析器中配置jsp路径的前缀和jsp路径的后缀,
		// 上边的路径配置可以不在程序中指定jsp路径的前缀和jsp路径的后缀;
		// modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
		modelAndView.setViewName("items/itemsList");
		return modelAndView;
	}
	// 方法2:添加商品......
}

~ 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}/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.creametime}" pattern="yyyy-MM-dd HH:mm:ss" /></td>
						<td>${item.detail}</td>
						<td><ahref="${pageContext.request.contextPath}/item/queryItem.action?id=${item.id}}">修改</a></td>
					</tr>
				</c:forEach>
			</table>
	</form>
</body>
</html>

~ SpringMVC开发步骤

  • 1、在 web.xml 文件中配置前端控制器:
    这里写图片描述
  • 2、在 springmvc.xml 文件中配置处理器适配器:
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
    通过查看源代码,可以看出此适配器能执行实现Controller接口的Handler;
    这里写图片描述
  • **3、开发ItemsController1.java:**Handler需要实现Controller接口,才能由org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter适配器执行;
  • 4、编写itemsList.jsp:
  • 5、配置Handler:将编写的Handler在spring容器中加载
    <bean name="/queryItems.action" class="cn.itcast.ssm.controller.ItemsController1" />
  • 6、在 springmvc.xml 文件中配置处理器映射器:
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
  • 7、springmvc.xml 文件中配置视图解析器:
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
  • 8、部署调试:访问地址:http://localhost:8080/springmvc/queryItems.action
    注意:启动程序的时候使用debug模式,不使用start启动;debug方式启动代码才能实现修改代码时不加方法、参数,不用重启Tomcat,这个叫做热部署,debug才支持热部署
  • 9、常见错误:
  • 在浏览器地址栏中输入地址错误:处理器映射器根据url找不到handler,就会包下面的错误;
    这里写图片描述
  • 在Handler中modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");地址设置错误:处理器映射器根据url找到了Handler,但是转发的jsp页面找不到;
    这里写图片描述

~ 非注解的处理器映射器

多个映射器可以并存,前端控制器判断url能让哪些映射器去映射,就让正确的映射器处理;
(1)class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"
(2)class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"

~ 非注解的处理器适配器

(1)class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"
要求:handler实现Controller接口;
(2)class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"
要求:handler实现HttpRequestHandler接口;

~ 注解的映射器和适配器

  • 配置:
    这里写图片描述
  • 注解开发Handler:
    这里写图片描述
  • 在Spring容器中加载Handler
    这里写图片描述
  • **部署调试:**访问地址:http://localhost:8080/springmvc/queryItemsAnnotation.action

~ 视图解析器前缀和后缀

这里写图片描述

~ 源码分析

  • 1、从web.xml文件中进入前端控制器,通过前端控制器源码,分析springmvc的执行过程:
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  • 2、前端控制器接收请求,调用doDispatch()方法:
    这里写图片描述
  • 3、前端控制器调用处理器映射器查找Handler:映射器根据request中的url找到了Handler,最后返回一个在执行器链,链里面包含Handler;
    这里写图片描述
  • 4、调用处理器适配器去执行Handler,得到执行的结果ModelAndView:
    这里写图片描述
  • 5、视图渲染,将Model的数据填充到request域:
    这里写图片描述
    这里写图片描述

>> springmvc 和 mybatis 整合:springmvc_mybatis

~ 需求

使用springmvc和mybatis完成商品列表查询;

~ 整合思路

springmvc+mybatis的系统架构:
这里写图片描述

  • 第一步:整合dao层:mybatis和springmvc整合,通过spring管理mapper接口;
    使用mapper扫描器自动扫描mapper接口在spring中进行注册;
  • 第二步:整合service:通过spring管理service接口;
    使用配置方式将service接口配置在spring配置文件中,实现事务控制;
  • 第三步:整合springmvc:由于springmvc是spring的模块,不需要整合;

~ 环境准备

1、搭建数据库,4张表:User、Orders、OrderDetail、OItems;
2、创建一个动态Javaweb项目:
3、加入需要的jar包:数据库驱动包、mybatis的jar包、mybatis和spring整合包、log4j的jar包、dbcp数据库连接池的jar包、spring所有jar包、jstl的jar包;

~ 项目结构

这里写图片描述

~ 整合dao

  • 1、配置mybatis自己的配置文件:SqlMapConfig.xml
    这里写图片描述
  • 2、配置mybatis和spring整合的配置文件:applicationContext-dao.xml
    这里写图片描述
  • **3、逆向工程生成po类及mapper(单表的增删改查) :**将逆向工程生成的文件拷贝到项目中(mapper包和po包);
  • **4、创建po类:**商品信息的扩展类ItemsCustom.java 和 商品包装对象类ItemsQueryVo,java
    这里写图片描述
  • 5、手动定义商品查询mapper:ItemsMapperCustom.xmlItemsMapperCustom.java;针对综合查询mapper,一般情况会有关联查询,建议自定义mapper;
    这里写图片描述

~ 整合service

让spring管理service接口;

  • 1、定义service接口ItemsService.java
    这里写图片描述
  • 2、编写service接口实现类ItemsServiceImpl.java
    这里写图片描述
  • 3、在sprig容器中配置service(applicationContext-service.xml):
    这里写图片描述
  • 4、事务控制:在applicationContext-transaction.xml中使用spring声明式事务控制方法;
    这里写图片描述

~ 整合springmvc

创建springmvc.xml文件,配置处理器映射器、适配器、视图解析器;

  • 1、配置springmvc.xml文件:
    这里写图片描述
  • **2、在web.xml文件中配置前端控制器:**参考入门程序;
    这里写图片描述
  • 3、编写Controller(就是Handler):
    这里写图片描述
  • 4、编写jsp:

~ 加载spring的容器

web.xml文件中,添加spring容器监听器,加载spring容器;将mapperservicecontroller加载到spring容器中;建议使用通配符加载配置文件;
applicationContext-dao.xmlapplicationContext-service.xmlapplicationContext-transaction.xml这三个配置文件添加到spring容器监听器中:
这里写图片描述

~ 调试及注意问题

访问地址http://localhost:8080/springmvc_mybatis/queryItems.action

注意问题:Maven项目中,applicationContext-xxx.xml文件、springmvc.xml文件、db.properties文件等,都是放在src/main/resources目录下的,Tomcat部署项目时,src/main/resources目录下的配置文件默认位置为:{项目名}/WEB-INF/classes,而spring却默认在src/main/resources目录下寻找,肯定找不到,因此,配置时需要指定在classpath目录下寻找;

**Eg:**在applicationContext-dao.xml文件中加载配置文件、配置SqlSessionFactory;在web.xml文件中配置前端控制器;
这里写图片描述


>> springmvc 注解开发

~ 商品修改功能开发

  • 操作流程:
  • 1、进入商品查询列表页面;
  • 2、点击修改,进入商品修改页面,页面中显示了要修改的商品(从数据库查询);要修改的商品从数据库根据商品id(主键)查询商品信息;
  • 3、在商品修改页面,修改商品信息,修改后,点击提交;
  • 开发 mapper:(1)根据id查询商品信息,(2)根据id更新Items表的数据;(不用开发,直接使用逆向工程生成的代码)
  • 开发 service接口:ItemsService.java
    接口功能:(1)根据id查询商品信息,(2)修改商品信息;
    这里写图片描述
  • 实现service接口:ItemsServiceImpl.java
    这里写图片描述
  • 开发controller:ItemsController.java
    (1)商品信息修改页面显示(2)商品信息修改提交

    这里写图片描述
  • 编写jsp页面:editItems.jsp

~ RequestMapping 注解

  • **(1)url映射:**定义controller方法对应的url,进行处理器映射使用;
  • (2)窄化请求映射:需要注意的是,定义根路径之后,在jsp页面的相关位置,及浏览器地址栏的url都需要加上根路径;
    浏览器访问地址http://localhost:8080/springmvc_mybatis/items/queryItems.action
    这里写图片描述
  • **(3)限制http请求方法:**处于安全考虑,对http的链接进行方法限制;如果限制请求为post方法,进行get请求会报错;可以同时设置请求为post+get;
    这里写图片描述

~ controller 方法返回值

  • (1)返回ModelAndView:需要方法结束时,定义ModelAndView,将model和view分别进行设置;
  • (2)返回string
  • 1、返回逻辑视图名:真正视图名(jsp路径)=前缀+逻辑视图名+后缀;
  • 2、redirect重定向:商品修改提交后,重定向到商品查询列表;
    特点:浏览器地址栏中的url会变化,修改提交的request数据无法传到重定向的地址,因为重定向后重新进行request(request无法共享);
  • 3、forward页面转发:通过forward进行页面转发,浏览器地址栏url不变,request可以共享;
    这里写图片描述
  • (3)返回void:在controller方法形参上可以定义request和response,使用request或response指定响应结果:
  • 1、使用request转向页面request.getRequestDispatcher("页面路径").forward(request,response);
  • 2、通过response页面重定向response.sendRediret("url");
  • 3、通过response指定响应结果:响应json数据:
    这里写图片描述

~ springmvc 参数绑定

(1)spring参数绑定过程:从客户端请求key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上:

  • **1、**客户端请求key/value,请求发送到前端控制器,前端控制器调用处理器适配器去执行;
  • **2、**处理器适配器调用springmvc提供参数绑定组件将key/value数据转换成controller方法的形参;
    早期参数绑定组件:在springmvc早期版本使用PropertyEditor,只能将字符串转换成java对象;
    后期使用converter(转换器):可进行任意类型的转换;spring提供了很多的converter,在特殊情况下需要自定义converter:对日期数据绑定需要自定义converter;
  • **3、**在controller方法(形参),将数据绑定到controller方法的形参上;

(2)默认支持的类型:直接在controller方法形参上定义下边的类型的对象,就可以使用这些对象;在参数绑定过程中,若遇到下边的类型,直接进行绑定;

  • HttPServletRequest:通过request对象获取请求信息;
  • HttpServletResponse:通过response处理响应信息;
  • HttpSession:通过session对象得到session中存放的缓存;
  • Model/ModelMap:model是一个接口,modelMap是一个接口实现,作用是:将model数据填充到request域;

(3)简单类型:通过@RequestParameter对简单类型的参数进行绑定:

  • 若不使用@RequestParameter,要求request传入参数名称和controller方法形参名称一致,才可绑定成功;
  • 若使用@RequestParameter,不限制request传入参数名称和controller方法的形参名称一致;
    这里写图片描述
  • 通过request属性指定参数是否必须传入,若设置为true,没有传入参数就会报错:
    这里写图片描述

**(4)pojo绑定:**页面中input的name属性和controller的pojo形参中的属性名称一致,将页面中数据绑定到pojo;

  • 页面定义:
    这里写图片描述
  • controller的pojo形参的定义:
    这里写图片描述
  • 在controller的方法中定义pojo类型的形参:
    这里写图片描述

(5)自定义参数绑定实现日期类型绑定
对于controller形参中pojo对象,如果属性中有日期类型,需要自定义参数绑定;将请求日期数据串传成日期类型,需要转换的日期类型和pojo中日期属性的类型保持一致;
这里写图片描述
自定义参数绑定将日期串转成java.util.Date类型,需要向处理器适配器中注入自定义的参数绑定组件;

  • 自定义日期类型绑定:创建CustomDateConverter类,继承Converter,在类里面实现日期串到日期类型的转换;
    这里写图片描述
  • springmvc.xml中配置CustomDateConverter类,将Converter实现类注入到处理器适配器中:
    这里写图片描述

(6)包装类型pojo参数绑定

  • 需求:商品查询controller方法中实现商品查询条件传入;
  • 实现方法
    (1)在形参中添加HttpServletRequest request 参数,通过request接收查询条件参数;
    (2)在形参中让包装类型的pojo接收查询条件参数;
  • 方法2 分析:
  • 页面传参的特点:复杂、多样性;
  • 条件:用户账号、商品编号、订单信息…
  • 如果将用户账号、商品编号、订单信息等放在pojo(属性是简单类型)中,pojo类属性比较多,比较乱,不好维护;
  • 建议使用包装类型的pojo,pojo中的属性时pojo;
  • 页面参数和controller方法形参定义:
    这里写图片描述

(7)数组绑定

  • 需求:商品批量删除,用户在页面选择多个商品,批量删除;
  • 关键:将页面选择(多选)的商品的id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id;
  • 表现层实现
    这里写图片描述

(8)list绑定

  • 需求:通常在需要批量提交数据时,将提交的数据绑定到list中,比如:成绩录入(录入 多门课成绩,批量提交),
  • 本例子需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中;
  • **controller方法定义:**1、进入批量商品修改页面;2、批量商品修改提交;
    使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list属性;
  • 表现层实现
    这里写图片描述

(9)map绑定

也是通过在包装pojo中定义map类型属性;在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收;
这里写图片描述

~ 服务端校验

**(1)校验理解:**项目中,通常使用较多的是服务端的校验,比如页面中的js校验;对于安全要求高点的,建议在服务端进行校验;

服务端校验

  • **控制层controller:**校验页面请求的参数的合法性,在服务端控制层controller校验,不区分客户端类型(浏览器、手机客户端、远程应用);
  • **业务层service(使用较多):**主要校验关键业务参数,仅限于service接口中使用的参数;
  • **持久层dao:**一般不校验;

**(2)springmvc校验:**springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)
校验思路:页面提交请求的参数,请求到controller方法中,使用validation进行校验;若校验出错,将错误信息展示到页面;
具体要求:商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示信息;

**(3)环境准备:**在项目中添加hibernate的校验框架validation所需要的jar包:
这里写图片描述

(4)在springmvc.xml文件中配置校验器并注入到处理器适配器中:
这里写图片描述

(5)在pojo:ItemsCustom.java中添加校验规则:
因为最终参数绑定是绑定到了pojo;由于itemsCustom继承items,所以在items中添加校验;
这里写图片描述

(6)在CustomValidationMessages.properties文件中添加校验提示信息:
这里写图片描述

(7)在controller.java中配置捕获校验错误信息,并使用model传到jsp页面:
这里写图片描述

(8)在editItems.jsp页面显示错误信息:
这里写图片描述

(9)分组校验:
需求:在pojo中定义校验规则,而pojo是被多个controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验;
解决方法:定义多个校验分组(其实就是一个java接口),分组中定义有哪些规则,每个controller方法使用不同的校验分组;

(10)校验分组定义接口:
这里写图片描述

(11)在Items.java 中的校验规则中添加分组
这里写图片描述

(12)在controller方法中使用指定分组的校验:value = { ValidGroup1.class } 指定使用ValidGroup1分组的校验;
这里写图片描述

~ 数据回显

**(1)什么是数据回显:**提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面;

(2)pojo数据回显方法:

  • 1、springmvc默认对pojo数据进行回显:pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写);使用@ModelAttribute 可以指定pojo回显到页面在request中的key;
    这里写图片描述
  • **2、@ModelAttribute还可以将方法的返回值传到页面:**在商品查询列表页面,通过商品类型查询商品信息;在controller中定义商品类型查询方法,最终将商品类型传到页面;
    这里写图片描述
  • 3、使用最简单的方法:使用model,可以不使用@ModelAttribute;
    这里写图片描述

(3)简单类型数据回显:model.addAttribute("id",id);

~ 异常处理

(1)异常处理思路:
系统中异常包括两类:预期异常运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、通过测试手段减少运行时异常的发生;

系统的dao、service、controller出现都通过throws Exception向上抛出,最后springmvc前端控制器交由异常处理器进行异常处理;

springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理;
这里写图片描述

**(2)自定义异常类:**对不同的异常类型定义异常类,继承Exception;
这里写图片描述

(3)全局异常处理器:

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

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

  • 1.解析出异常类型
  • 2.如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示;
  • 3.如果该异常类型不是系统自定义的异常,则构造一个自定义的异常类型(信息为“未知错误”)

springmvc提供一个HandlerExceptionResolver接口;
这里写图片描述

(4)错误页面:
这里写图片描述

(5)在springmvc.xml文件中配置全局异常处理器:
这里写图片描述

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

**在商品修改的controller方法中抛出异常:**需要同时在service中判断items是否为空,否则会报错;
这里写图片描述
在service接口中抛出异常:
这里写图片描述

(7)在service还是controller抛出异常?
如果与操作业务(我们自己的业务:修改商品等)功能相关的异常,建议在service中抛出异常;
如果与业务功能没有关系的异常,建议在controller中抛出异常;【在页面填写信息时,会有校验:校验名称不能是乱字符,这是基于系统的安全性出发,与业务没有关系;】
上边的功能,建议在service中抛出异常;

~ 上传图片

**(1)需求:**在修改商品页面,添加上传商品图片功能;

(2)springmvc中对多部件类型解析:在springmvc.xml文件中配置multipart类型解析器;
在页面form中提交enctype="multipart/form-data"数据时,需要springmvc对multipart类型的数据进行解析;
这里写图片描述

**(3)加入上传图片的jar包:**上边的解析器使用下边的jar包进行图片的上传;commons-fileupload-1.3.3.jarcommons-io-2.6.jar

(4)在Tomcat创建图片虚拟目录存储图片:

1、通过图形界面进行配置:
这里写图片描述
**2、也可以直接配置Tomcat的配置文件:**在D:\Tomcat\conf\server.xml文件中添加虚拟目录<Context docBase="E:\WorkSpace\pictureTemp" path="/pic" reloadable="false"/>
这里写图片描述
**注意:**在图片虚拟目录中,一定要将图片目录分级创建(提高I/O性能),一般我们采用按日期(年、月、日)进行分级创建;

(5)上传图片的代码:

  • editItems.jsp页面:
    这里写图片描述
  • controller方法:
    这里写图片描述

~ json数据交互

**(1)为什么要进行json数据交换:**json数据格式在接口调用中、HTML页面中较常用,json格式比较简单,解析还比较方便,比如:webservice接口,传输json数据;

(2)springmvc 进行json交互:
这里写图片描述

总结:
1、请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转换成json,不太放方便;
2、请求key/value、输出json,此方法比较常用;

(3)加载json转换的jar包: springmvc中使用Jackson的包进行json转换(@RequestBody和@ResponseBody使用下边的jar包进行json转换):jackson-core-2.9.6.jarjackson-mapper-asl-1.9.13.jarjackson-annotations-2.9.6.jarjackson-databind-2.9.6.jar

**(4)配置json转换器:**注意:如果使用<mvc:annotation-driven>,则不用定义下边的内容;
在注解适配器中添加messageConverters:
这里写图片描述

**(5)在WebContent目录下创建js文件夹,往里面存放jQuery的js包:jquery-1.11.3.min.js **;并在需要使用jQuery的jsp页面中引入这个js包;
这里写图片描述

(6)交互测试 - 输入 json 串,输出 json 串:
访问地址:http://localhost:8080/springmvc_mybatis/jsonTest.jsp
(7)交互测试 - 输入 key/value,输出 json 串:
这里写图片描述
(8)测试结果:
这里写图片描述

~ RESTful

**(1)什么是RESTful:**RESTful架构,就是目前最流行的一种互联网软件架构,它结构清晰、符合标准、易于理解、扩展方便。so正得到越来越多的网站采用; RESTful(Representational State Transfer),其实是一个开发理念,是对http的很好的诠释;

**1、对url进行规范,写RESTful风格的url:**特点:url简洁,将参数通过url传到服务端;
非RESTful风格的url:http://.../itmes/queryItems.action?id=001&typr=T01
RESTful风格的url:http://.../items/itemsView/001

**2、http的方法规范:**不管是添加、删除、更新,使用的url是一致的,如果进行删除,需要设置http的方法为delete,添加设置http的方法为post,查询get; **后台controller方法:**判断http方法,如果是delete,就执行删除,如果是post就执行添加操作;

**3、对http的contentType规范:**请求时指定contentType,要json数据,就设置成json格式的type;

**(2)需求:**查询商品信息,返回json数据;

**(3)controller:**定义方法,进行映射使用RESTful风格的url,将查询商品信息的id传入controller,输出json使用@ResponseBody将java对象输出json;
这里写图片描述

**(4)在web.xml文件中配置REST方法的前端控制器:**rest前端控制器可以与前端控制器共存,两者互补影响;
这里写图片描述

(5)访问地址:http://localhost:8080/springmvc_mybatis/items/itemsView/2

**(6)对静态资源的解析:**配置前端控制器的url-partten中指定/,对静态资源的解析会出现问题:
这里写图片描述

**(7)解决办法:**在springmvc.xml文件中添加静态资源解析方法:
这里写图片描述

~ 拦截器

(1)定义拦截器:HandlerInterceptor1.javaHandlerInterceptor2.java,实现HandlerInterceptor接口,接口中实现3个方法:preHandle、postHandle、afterCompletion
这里写图片描述

(2)在springmvc.xml文件中配置拦截器:

  • **针对HandlerMapping配置:**springmvc拦截器针对HandlerMapping进行拦截设置,如果在某个HandlerMapping中配置拦截器,经过该HandlerMapping映射成功的Handler最终使用该拦截器;(一般不推荐使用,麻烦)
    这里写图片描述
  • **类似全局的拦截器:**springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中;
    这里写图片描述

(3)拦截器测试:

  • 测试需求:测试多个拦截器各个方法执行的顺序;
  • 编写两个拦截器:HandlerInterceptor1.java、HandlerInterceptor1.java;
  • 重启Tomcat服务器,随便访问一个urlhttp://localhost:8080/springmvc_mybatis/items/queryItems.action
  • 1、两个拦截器都放行:都return true;
    这里写图片描述
    总结:preHandle方法顺序执行,postHandle和afterCompletion按照在springmvc.xml文件中配置的顺序的逆向顺序执行;
  • 2、拦截器1放行return true,拦截器2不放行return false:
    这里写图片描述
    总结
    拦截器1放行,拦截器2的preHandler才会执行;
    拦截器2不放行preHandler不放行,拦截器2的postHandler和afterCompletion不会执行;
    只要有一个拦截器不放行,postHandler就不会执行;
  • 3、两个拦截器都不放行:HandlerInterceptor1...preHandle
    总结
    拦截器1的perHandler不放行,postHandler和afterCompletion不会执行;
    拦截器1的perHandler不放行,拦截器2不执行;
  • 根据测试结果,对拦截器应用:
    比如:统一日志处理拦截器,需要该拦截器preHandler一定要放行,并且将它放在拦截器链的第一个位置;
    比如:登录认证拦截器,放在拦截器链中的第二个位置(统一日志处理拦截器后面);
    比如:权限校验拦截器,放在登录认证拦截器之后(登录通过之后才会进行权限校验);

(4)拦截器应用:实现登录认证;

  • 需求:
  • 1、用户请求url;
  • 2、如拦截器进行拦截校验:
    如果请求的url是公开地址(无需登录即可访问的url,在项目中会将公开的地址配置在配置文件中);
    如果用户session不存在,则跳转到登录页面;
    如果用户session存在,则放行,继续下面的操作;
  • login.jsp
    这里写图片描述
  • queryItems.jsp页面添加退出按钮:
    这里写图片描述
  • 登录controller方法:
    这里写图片描述
  • 登录认证拦截代码实现:
    这里写图片描述
  • **在springmvc.xml文件中配置登录认证的拦截器:**注意其他两个拦截器都设置成放行;
    这里写图片描述
  • **测试:随便访问某个页面:http://localhost:8080/springmvc_mybatis/items/editItems?id=2 **

~ post/get 请求中文参数出现乱码问题

(1)post 请求:在web.xml 文件中添加乱码过滤器:
这里写图片描述

**(2)get 请求:**解决方法有两个:
1、修改Tomcat配置文件,添加编码与工程编码一致:
这里写图片描述
2、对参数进行重新编码:ISO8859-1是Tomcat默认编码,需要将Tomcat编码后的内容按UTF-8编码;
这里写图片描述


>> springmvc 框架总结

~ springmvc框架

  • DispatcherServlet前端控制器:接收request,进行response;
  • HandlerMapping处理器映射器:根据url查找Handler;(可以通过xml的方式,或注解方式)
  • HandlerAdapter处理器适配器:根据特定规则去执行Handler,编写Handler时需要按照HandlerAdapter的要求去编写;
  • Handler处理器(后端控制器):需要程序员去编写,常用注解开发方式;
    Handler处理器执行后结果是ModelAndView,具体开发时Handler方法返回值类型包括:ModelAndViewString(逻辑视图名)void(通过在Handler形参中添加request和response,类似原始servlet开发方式,注意:可以通过指定response响应的结果类型实现json数据输出)
  • View resolve视图解析器:根据逻辑视图名生成真正的视图名(在springmvc中使用View对象表示);
  • View视图:jsp页面,仅是数据的展示,没有业务逻辑;

~ 注解开发

  • 使用注解的方式配置处理器映射器和处理器适配器:
    这里写图片描述
  • 在实际开发中使用<mvc:annotation-driven>标签代替上面两个处理器映射器和处理器适配器的配置;
  • @controller 注解必须要加上; 作用:标识类是一个Handler处理器;
  • @requestMapping 注解必须要加上; 作用
  • 1、对url和Handler的方法进行映射;
  • 2、可以窄化请求映射,设置Handler的根路径,url就是 根路径+子路径 请求方式;
  • 3、可以限制http请求的方法;
  • 映射成功后,springmvc框架会生成一个Handler对象,对象中只有一个映射成功的method;

~ 注解开发中参数绑定

将request请求过来的key/value的数据(理解成一个串),通过转换(参数绑定的一部分),将key/value串转成形参,将转换后的结果传给形参(整个参数绑定过程);

springmvc支持的参数绑定:

  • 1、默认支持很多类型: HttPServletRequest、HttPServletResponse、HttpSession、Model/ModelMap(将模型数据填充到request域);
  • **2、支持简单数据类型:**整型、字符串、日期;
    只要保证request请求的参数名和形参名称一致,就自动绑定成功;
    如果request请求的参数名和形参名称不一致,可以使用@RequestParam(指定request请求的参数名),@RequestParam加在形参的前边;
  • **3、支持pojo类型:**只要保证request请求的参数名称和pojo中的属性名一致,自动将request请求的参数设置到pojo的属性中;
    注意:形参中既有pojo类型,又有简单类型的时候,参数绑定互不影响;
  • 4、自定义参数绑定:
  • **日期类型绑定自定义:**定义的Converter<源类型,目标类型>接口实现类,比如:Converter<String,Date>表示将请求的日期数据串转换成java中的日期类型;
  • 注意:要转换的目标类型一定要和接收的pojo中的属性类型一致;
  • 将定义的Converter实现类注入到处理器适配器中:
    这里写图片描述

~ springmvc和Struts2的区别

springmvc是面向方法开发的(更接近service接口的开发方式),Struts2面向类开发;
springmvc可以单例开发,Struts2只能多例开发;

猜你喜欢

转载自blog.csdn.net/qq_37546891/article/details/82526128