一.Spring的事務
Spring的事務控制可以分爲編程式事務控制和聲明式事務控制。
編程式事務:
就是將業務代碼和事務代碼放在一起書寫,它的耦合性太高,開發中不使用
聲明式事務
其實就是將事務代碼和業務代碼隔離開發, 然後通過一段配置讓他們組裝運行, 最後達到事務控制的目的.
聲明式事務就是通過AOP原理實現的.
(1)Spring的聲明式事務:
在 Spring 配置文件中聲明式的處理事務來代替代碼式的處理事務。底層採用AOP思想來實現的
思想:
目標對象:AccountServiceImpl
通知對象:DataSourceTransactionManager
配置切面:xml,註解
(2)項目搭建:
創建java模塊:Maven項目pom.xml文件依賴:
<!--依賴管理-->
<dependencies>
<!--mysql驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--druid連接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--spring核心-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
編寫AccountDao
public interface AccountDao {
//轉出
void outUser(String outUser, Double money);
//轉入
void inUser(String inUser, Double money);
}
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void outUser(String outUser, Double money) {
// 1.編寫sql
String sql = "update account set money = money - ? where name = ?";
// 2.執行sql
jdbcTemplate.update(sql, money, outUser);
}
@Override
public void inUser(String inUser, Double money) {
// 1.編寫sql
String sql = "update account set money = money + ? where name = ?";
// 2.執行sql
jdbcTemplate.update(sql, money, inUser);
}
}
編寫AccountService
public interface AccountService {
// 轉賬
void transfer(String outUser, String inUser, Double money);
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outUser, String inUser, Double money) {
// 核心業務
accountDao.outUser(outUser, money);
// 模擬異常..
int i = 1 / 0;
accountDao.inUser(inUser, money);
}
}
編寫Spring的配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--加載第三方配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--druid交給ioc-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--jdbcTemplate交給ioc-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!--dao交給ioc-->
<bean id="accountDao" class="com.wsl.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--將service交給ioc-->
<bean id="accountService" class="com.wsl.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--事務管理器交給ioc-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
測試:
@RunWith(SpringRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void test01() throws Exception {
accountService.transfer("tom", "jerry", 100d);
}
}
(3)事務的xml配置:
spring配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/aop
http://www.springframework.org/schema/aop/spring-aop.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">
<!--加載第三方配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--druid交給ioc-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--jdbcTemplate交給ioc-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!--dao交給ioc-->
<bean id="accountDao" class="com.wsl.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--將service交給ioc:目標對象-->
<bean id="accountService" class="com.wsl.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--事務管理器交給ioc-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--將事務管理器升級爲事務通知類-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--定義事務管理器信息 DefaultTransactionDefinition-->
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--aop配置-->
<aop:config>
<!--
僅spring的事務切面配置使用此標籤
通知+切點=切面
-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.com.service..*.*(..))"></aop:advisor>
</aop:config>
</beans>
測試:即可
重要:
事務通知類細節補充;
<!--將事務管理器升級爲事務通知類-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--
定義事務管理器信息 DefaultTransactionDefinition
我們可以控制指定的方法,設置事務隔離級別、傳播行爲、是否只讀、是否超時...
name="transfer" 需要控制事務的方法名
isolation="DEFAULT" 設置當前方法的事務隔離界別,mysql默認級別:repeatable_read
propagation="REQUIRED" 設置當前方法的事務傳播行爲 ,REQUIRED:當前方法必須有一個事務(單獨使用開啓,別人調用加入對方事務)
read-only="false" 當前方式爲非只讀(增刪改用的)
timeout="-1" 事務超時時間,-1:永不超時
-->
<tx:attributes>
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
<tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
</tx:attributes>
</tx:advice>
(4)註解配置anno
開啓註解配置:刪除上述事務的xml配置:
開啓tx事務的註解支持:
在目標對象上,AccountService 使用事務註解:
然後測試接口,事務已經添加上了:
重要:
註解事務細節補充:
二.Spring集成Web環境
(1)web環境搭建:
新建java項目,利用JBjavaToWeb工具轉換成web項目:
新建UserServlet:
@WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 獲取spring容器的上下文對象
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
// 調用service,實現保存功能
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
部署項目即可運行:
問題:我們在Servlet中的方法中,直接創建spring容器,每次訪問每次創建,浪費內容空間和性能
(2)自定義監聽器和工具類:
利用servletContextListener監聽器,在項目啓動時執行,我們就可以創建ClassPathXmlApplicationContext
,我可以將這個spring的app對象,設置到ServletContext域,所有servlet都可以從這個域中,獲取此對象
自定義監聽器:
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>com.wsl.web.listener.MyContextLoaderListener</listener-class>
</listener>
public class MyContextLoaderListener implements ServletContextListener {
ClassPathXmlApplicationContext app = null;
// 在web項目啓動時,創建spring環境
@Override
public void contextInitialized(ServletContextEvent sce) {
// 獲取servletContext域對象
ServletContext servletContext = sce.getServletContext();
// 讀取全局配置參數
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
// 創建spring環境
app = new ClassPathXmlApplicationContext(contextConfigLocation);
// 設置到域中
servletContext.setAttribute("app", app);
System.out.println("spring環境初始化");
}
// 在web項目卸載時,關閉spring環境
@Override
public void contextDestroyed(ServletContextEvent sce) {
app.close();
System.out.println("spring環境銷燬了");
}
}
獲取spring容器的工具類:
// 專門從web最大的域中獲取spring環境
public class MyWebApplicationContextUtils {
public static ApplicationContext getWebApplicationContext(ServletContext servletContext) {
return (ApplicationContext) servletContext.getAttribute("app");
}
}
修改UserServlet
@WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 獲取spring容器的上下文對象
// ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
// ApplicationContext app = (ApplicationContext) request.getServletContext().getAttribute("app");
ApplicationContext app = MyWebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
// 調用service,實現保存功能
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
(3)改造Springweb項目:通過Spring提供的工具類:
導入spring-web座標
<!--spring整合web容器-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
設置spring提供的監聽器
<!--全局配置參數-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
修改UserServlet
@WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 獲取spring容器的上下文對象
WebApplicationContext app = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
// 調用service,實現保存功能
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
三.SpringMVC簡介
(1)MVC模式
* model:模型 JavaBean(1.處理業務邏輯 2.封裝數據)
* view:視圖 Jsp/html(展示數據)
* controller:控制器 Servlet(1.接收請求 2.調用模型 3.轉發視圖)
三層架構:
* web層:用戶與java交互
* service層:處理業務邏輯
* dao層:java與數據庫交互
(2)SpringMVC介紹
SpringMVC 是一種基於 Java 的實現 MVC 設計模式的輕量級 Web 框架,它可以通過一套註解,讓一個簡單的Java類成爲控制器,而無須實現任何接口。
springMVC框架本質上就是一個servlet,封裝了共有的行爲(請求、響應),簡化代碼
四.SpringMVC快速入門
訪問一個url,可以在控制檯打印一句話,然後跳轉到一個新頁面:
分析:
創建web項目,並導入相關座標:
新增
<!--依賴管理-->
<dependencies>
<!--springMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!--jsp-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
配置前端控制器(Servlet)
<?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>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加載指定配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--指定servlet在tomcat啓動時創建-->
<load-on-startup>4</load-on-startup>
</servlet>
<!--攔截url規則:/(默認)-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
編寫controller和jsp
/*
一個模塊對應一個控制器(類)
*/
public class UserController {
// 一個功能(請求)對應一個方法
public String quick() {
System.out.println("quick....");
// 轉發給一個視圖
return "/WEB-INF/pages/success.jsp";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h3>success....</h3>
</body>
</html>
配置Controller
編寫spring-mvc.xml
beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--開啓註解組件掃描-->
<context:component-scan base-package="com.wsl.web"/>
<!--開啓mvc註解支持-->
<mvc:annotation-driven/>
</beans>
部署並測試
運行流程:
五.SpringMVC組件概述
(1)執行流程:
springMVC內部執行流程,涉及11個步驟
(2)三大組件
* 處理器映射器:HandlerMapping
將 請求url 和 處理器的方法 建立映射關係
* 處理器適配器:HandlerAdapter
從多個處理器當中,適配其中一個,調用目標執行...
* 視圖解析器:ViewResolver
將邏輯視圖解析爲物理視圖
Spring的DispatcherServlet默認配置文件:
相關配置:
學了SpringMVC後,在寫代碼的時候就重點關注這些了:
1. 編寫 處理器(controller)
2. 編寫 視圖(jsp、html)
(3)常用註解:
@Controller
SpringMVC基於Spring容器,所以在進行SpringMVC操作時,需要將Controller存儲到Spring容器中,故使用此註解
@RequestMapping
用於建立請求 URL 和處理請求方法之間的對應關係
/*
一個模塊對應一個控制器(類)
*/
@Controller // 交給ioc容器
@RequestMapping("/user")
public class UserController {
/*
@RequestMapping
功能:將請求的url 和 方法 建立映射關係
位置:
類上:建立一級url訪問路徑
方法上:建立二級的url訪問路徑,與一級路徑組成一個完整url路徑
舉個栗子:
/user/add
/user/update
/user/delete
/user/findAll
/order/add
/order/update
/order/delete
常用屬性:
value/path:聲明url訪問路徑
method:限定請求方式,默認支持所有,共有7種(get、post、put、delete)
params:限定請求參數
*/
// 一個功能(請求)對應一個方法
// @RequestMapping("/quick")
@RequestMapping(value = "/quick", method = {RequestMethod.POST,RequestMethod.GET},params = {"username","password"})
public String quick() {
System.out.println("quick....");
return "error";
}
}