SpringMVC学习笔记
基础介绍篇
基础概念介绍
BS和CS开发架构
- B/S架构:也就是浏览器/服务器架构
- C/S架构:也就是客户端/服务端结构
说明:我们现在使用Java开发的大多数都是web应用,这些应用几乎全部都是基于B/S架构进行开发的。在B/S架构中,应用系统标准的三层架构分为:表现层、业务层、持久层。这种三层架构在我们的实际开发中使用得非常多。
- JavaEE制定了一套规范,去进行BS架构的处理,这套规范就是Servlet。
应用系统三层架构
- 表现层
- 也就是我们常说的 Web 层
- 它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web层,web层需要接收http请求,完成http响应
- 表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示
- 表现层依赖业务层,接收到客户端请求一般会调用业务层处理,并将处理结果响应给客户端
- 表现层的设计一般都使用 MVC 模型(MVC是表现层的设计模型,和其他层没有关系)
- 业务层
- 也就是我们常说的service层(真正的开发人员的核心)
- 它负责业务逻辑处理,和我们开发项目的需求息息相关。web层依赖业务层,但是业务层不依赖web层
- 业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事物一致性(也就是我们说的,事务应该放到业务层来控制)
- 持久层
- 也就是我们常说的dao层
- 负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。
- 通俗的讲,持久层就是和数据库交互,对数据库进行增删改查的
MVC设计模式
- MVC 是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计编写 web 应用程序表现层的模式。MVC设计模式的三大角色:
- Model(模型):模型包含业务模型和数据模型,数据模型用于封装数据,业务模型用于处理业务。
- View(视图):通常指的就是我们的 jsp 或者 html,作用一般就是展示数据的,通常视图是依据数据模型创建的。
- Controller(控制器):是应用程序中处理用户交互的部分,作用一般就是处理程序逻辑的。
SpringMVC介绍
SpringMVC是什么
- SpringMVC是一种基于MVC设计模型的请求驱动类型的轻量级 Web 框架,属于SpringFramework的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建Web应用程序的全功能 MVC 模块。
- 使用Spring可插入的MVC构架,从而使用Spring进行Web开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2等
- SpringMVC已经成为目前最主流的MVC框架之一,并且随着 Spring3.0的发布,全面超越Struts2,成为最优秀的MVC框架。
- 他通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时它还支持Restful编程风格的请求。
SpringMVC与Spring的联系
Spring MVC 全名叫做Spring Web MVC
,它是Spring家族Web模块的一个重要成员。这一点,我们可以从spring的整体结构中看得出来:
SSM项目搭建篇
搭建springmvc工程
- 创建一个Maven工程
添加依赖
- 主要添加 MVC、jstl、和servlet-api 依赖
<!-- Spring MVC依赖包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
开发步骤
配置web.xml
- 添加前端控制器
DispatcherServlet
的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>springmvc-demo</display-name>
<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>
<!--
学习前置条件
问题1:web.xml中servlet、filter、listener、context-param加载顺序
问题2:load-on-startup标签的作用,影响了servlet对象创建的时机
问题3:url-pattern标签的配置方式有四种:
/dispatcherServlet
/servlet/*
*
/
加载顺序是如何的
问题4:url-pattern标签配置为/*报错,原因是它拦截了JSP请求,但是又不能处理JSP请求,为什么配置/就不拦截JSP请求?
问题5:配置了springmvc去读取spring配置文件之后,就产生了spring父子容器的问题
-->
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
设置spring配置文件路径
如果不设置初始化参数,那么DispatcherServlet会读取默认路径下的配置文件(即:/WEB-INF/springmvc-servlet.xml)
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
指定初始化时机,设置为2,表示Tomcat启动时,DispatcherServlet会跟随着初始化
如果不指定初始化时机,DispatcherServlet就会在第一次被请求的时候,才会初始化,而且只会初始化一次
-->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
URL-PATTERN的设置
不要设置为/*,否则会报错
通俗理解:/*会拦截整个项目中的资源访问,包含JSP和静态资源的访问,对于静态资源的访问 spring mvc提供了默认的Handler处理器
烦死对于JSP来讲,spring mvc没有提供默认的处理器,我们也没有手动编写对应的处理器,此时按照spring mvc的处理流程分析得知,他短路了
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- springmvc.xml:
DispatcherServlet
启动时会去加载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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--
配置处理器bean的读取
扫描Controller注解,多个包中间使用半角逗号分隔
-->
<context:component-scan base-package="com.yw.springmvc.example.controller"/>
<!--
配置三大组件之处理器适配器和处理器映射器
内置了RequestMappingHandlerMapping和RequestMappingHandlerAdapter等组件注册
-->
<mvc:annotation-driven/>
<!--
配置三大组件之视图解析器
InternalResourceViewResolver:默认支持JSP视图解析
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
编码
- Controller 控制器开发方式有多种:
- 实现HttpRequestHandler接口
- 实现Controller接口
- 使用注解方式:在企业开发中,推荐使用注解方式开发处理器
// @Controller:在类上加该注解,指定该类为一个请求处理器,不需要实现任何接口获取继承任何类
@Controller
public class HelloController {
// @RequestMapping:在方法上或者类上加该注解,指定请求的`url`由该方法处理
@RequestMapping("hello")
public ModelAndView hello(){
ModelAndView mv = new ModelAndView();
/**
* 设置数据模型
* 相当于request的setAttribute方法
* 底层是个Map,先将K-V数据放入Map中,最终根据视图对象不同,再进行后续处理
*/
mv.addObject("msg", "springmvc-demo");
// 设置视图(逻辑路径)
mv.setViewName("hello");
return mv;
}
}
注意:@Controller注解的类中每个@RequestMapping注解的方法,最终都会转为HandlerMethod类(而这个类才是SpringMVC注解开发方式中真正意义上的处理器)
- 创建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=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h1>${msg}!!!</h1>
</body>
</html>
测试
- 项目打包成war,发布到Tomcat,访问地址:http://localhost:8080/hello
SSM框架整合
整合思路
- 将工程的三层结构中的
JavaBean
分别使用Spring容器(通过XML方式)进行管理:- 整合持久层
mapper
,包括数据源
、SqlSessionFactory
及mapper
代理对象的整合; - 整合业务层
Service
,包括事务bean
及bean
的配置; - 整合表现层
Controller
,直接使用springmvc
的配置; web.xml
加载spring
容器(包含多个XML文件,还分为父子容器
)
- 整合持久层
- 核心配置文件包括:
- applicationContext-dao.xml
- applicationContext-service.xml
- springmvc.xml
- web.xml
工程搭建
- 依赖包:
- spring(包括springmvc)
- mybatis
- mybatis-spring整合包
- 数据库驱动
- 第三方连接池
- JSTL
- servlet-api
<!-- 持久层依赖 开始 -->
<!-- spring ioc组件需要的依赖包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- spring 事务管理和JDBC依赖包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- mysql数据库驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
<!-- dbcp连接池的依赖包 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- mybatis和spring的整合依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- 持久层依赖 结束 -->
<!-- 业务层依赖 开始 -->
<!-- 基于AspectJ的aop依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- 业务层依赖 结束 -->
<!-- 表现层依赖 开始 -->
<!-- spring MVC依赖包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- jstl 取决于视图对象是否是JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- servlet -->
<!-- <dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency> -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<!-- 表现层依赖 结束 -->
工程整合(配置文件)
整合Mapper
- db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.254.128:3306/ssm?characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
- applicationContext-dao.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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 加载db.properties配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="30"/>
<property name="maxIdle" value="5"/>
</bean>
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 加载mybatis的配置文件(如果配置文件中没有配置项,可以忽略该文件) -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置mapper扫描器,SqlSessionConfig.xml中的mapper配置去掉 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定扫描的包 -->
<property name="basePackage" value="com.yw.springmvc.example.dao.mapper"/>
</bean>
</beans>
- 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>
</configuration>
- log4j.properties
# dev env [debug] product env [info]
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
整合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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描Service -->
<context:component-scan base-package="com.yw.springmvc.example.service"/>
<!--
配置事务
事务管理器,对mybatis操作数据库进行事务控制,此处使用jdbc的事务控制
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 指定要进行事务管理的数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="select*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- aop -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.yw.springmvc.example.service.*Impl.*(..))"/>
</aop:config>
</beans>
整合Controller
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>springmvc</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>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置扫描Controller注解 -->
<context:component-scan base-package="com.yw.springmvc.example.controller"/>
<!-- 配置处理器适配器和处理器映射器 -->
<mvc:annotation-driven/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
web.xml加载spring父容器
- 在web.xml中,使用监听器来对spring的配置文件进行加载:
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
编写测试代码
需求
- 实现商品查询列表,从MySQL数据库查询商品信息。
需求分析
- 表现层:
- 请求URL:/queryItem
- 请求参数:无
- 请求返回值:ModelAndView指定Model和View(item-list.jsp)
- Request域(Model):kay为itemList
- 业务层:业务处理逻辑是实现商品列表的查询。
- 持久层:只针对表进行增删改查操作
代码实现
- 持久层代码:根据需求分析,持久层需要查询item表中的记录,使用逆向工程生成代码即可。通过逆向工程,把po类、mapper.xml和mapper.java类生成出来并拷贝到项目中。
- 业务层代码:根据需求开发Service的接口以及实现类,注意:使用注解@Service开发Service
/**
* 商品服务接口
*/
public interface ItemService {
/**
* 查询商品信息(全部)
*/
List<Item> queryItemList() throws Exception;
}
/**
* 商品服务实现类
*/
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemMapper itemMapper;
@Override
public List<Item> queryItemList() throws Exception {
ItemExample example = new ItemExample();
return itemMapper.selectByExample(example);
}
}
- 表现层代码
/**
* 商品item控制器
*/
@Controller
@RequestMapping("item")
public class ItemController {
@Autowired
private ItemService itemService;
@RequestMapping("query")
@ResponseBody
public List<Item> queryItem(){
return itemService.queryItemList();
}
}
- 部署测试:访问 http://localhost:8080/item/query
// 返回结果:
[{"id":1,"name":"华为手机","price":3000.0,"pic":"","createtime":1454563375000,"detail":null},{"id":2,"name":"苹果笔记本","price":6000.0,"pic":null,"createtime":1423459377000,"detail":null},{"id":3,"name":"黑寡妇电视机","price":2000.0,"pic":"4d4d1b22-9706-429b-86f0-211b3b2742da.jpg","createtime":1423200182000,"detail":null}]