https://www.bilibili.com/video/BV1Sb411s7qa
P46~54
三层架构
先保证每个框架能单独运行
然后用Spring整合另外2个
准备数据库 account表,以前建过了,继续用
搭建环境 创建Maven工程,选webapp
解决创建项目过慢,加一对archetypeCatalog:internal
pom.xml 版本锁定
1 2 3 4 5 6 7 8 9 10 <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <maven.compiler.source > 1.8</maven.compiler.source > <maven.compiler.target > 1.8</maven.compiler.target > <spring.version > 5.0.2.RELEASE</spring.version > <slf4j.version > 1.6.6</slf4j.version > <log4j.version > 1.2.12</log4j.version > <mysql.version > 5.1.6</mysql.version > <mybatis.version > 3.4.5</mybatis.version > </properties >
加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.6.8</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-aop</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-tx</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > compile</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > ${mysql.version}</version > </dependency > <dependency > <groupId > c3p0</groupId > <artifactId > c3p0</artifactId > <version > 0.9.1.2</version > <type > jar</type > <scope > compile</scope > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-web</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > <version > 2.5</version > <scope > provided</scope > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.0</version > <scope > provided</scope > </dependency > <dependency > <groupId > jstl</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > ${log4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-api</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-log4j12</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > ${mybatis.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 1.3.0</version > </dependency > </dependencies >
创建目录 java和resources文件夹
用到的类
Account三个属性
1 2 3 private Integer id;private String name;private Double money;
做2个方法
1 2 public List<Account> findAll () ;public void saveAccount (Account account) ;
Spring框架 配置 applicationContext.xml resources下新建applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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" 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/tx http://www.springframework.org/schema/tx/spring-tx.xsd" > <context:component-scan base-package ="com.coconutnut" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > </beans >
controller是表现层的,Spring框架不管
加注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Service("accountService") public class AccountServiceImpl implements IAccountService { @Override public List<Account> findAll () { System.out.println("业务层:查询所有" ); return null ; } @Override public void saveAccount (Account account) { System.out.println("业务层:保存账户" ); } }
测试 用junit单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class TestSpring { @Test public void test () { ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml" ); IAccountService as = (IAccountService) ac.getBean("accountService" ); as.findAll(); } }
WARNING说没有log4j的配置文件
复制一个log4j.properties到resources目录下即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 log4j.rootCategory =info, CONSOLE, LOGFILE log4j.logger.org.apache.axis.enterprise =FATAL, CONSOLE log4j.appender.CONSOLE =org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout =org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern =%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n log4j.appender.LOGFILE =org.apache.log4j.FileAppender log4j.appender.LOGFILE.File =/Users/coconutnut/TREE/Midgard/Idea/SSM/axis.log log4j.appender.LOGFILE.Append =true log4j.appender.LOGFILE.layout =org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern =%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
要改一下路径
SpringMVC框架 配置 web.xml WEB-INF文件夹下的web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <web-app > <display-name > Archetype Created Web Application</display-name > <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:springmvc.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > dispatcherServlet</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > <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 > </web-app >
配置 springmvc.xml resources文件夹下新建springmvc.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?xml version="1.0" encoding="UTF-8"?> <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.coconutnut" > <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > <bean id ="internalResourceViewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/pages/" /> <property name ="suffix" value =".jsp" /> </bean > <mvc:resources location ="/css/" mapping ="/css/**" /> <mvc:resources location ="/images/" mapping ="/images/**" /> <mvc:resources location ="/js/" mapping ="/js/**" /> <mvc:annotation-driven /> </beans >
页面 index.jsp中加一个超链接
1 2 3 4 5 6 7 8 9 10 <html> <head> <title>Title</title> </head> <body> <a href="account/findAll" >测试</a> </body> </html>
WEB-INF中新建pages文件夹,新建list.jsp
1 2 3 4 5 6 7 8 9 10 <html> <head> <title>Title</title> </head> <body> <h3>查询所有的账户信息</h3> </body> </html>
控制器 1 2 3 4 5 6 7 8 9 10 11 @Controller @RequestMapping("/account") public class AccountController { @RequestMapping("/findAll") public String findAll () { System.out.println("表现层:查询所有" ); return "TODO" ; } }
部署
测试
Spring整合SpringMVC 目标:Controller中调用业务层方法
方法:要把Service注入到Controller中
问题:web.xml中配置了springmvc.xml,springmvc.xml中配置了对Controller的扫描,其它扫描的配置在applicationContext.xml中,而这个文件始终没有被加载过
解决:启动tomcat服务器时,加载Spring的配置文件applicationContext.xml
ServletContext对象生命周期和服务器相同,可以用监听器监听其创建和销毁
于是,可以在web.xml中用监听器加载Spring的配置文件
监听器是spring-web提供的
它默认只加载WEB-INF目录下的applicationContext.xml配置文件
可以复制一份丢到WEB-INF目录,或者手动设置路径
1 2 3 4 5 6 7 8 <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > <context-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:applicationContext.xml</param-value >
这样启动服务器时,Spring的配置文件也加载了
Service和Controller都放到容器中了
于是可以在AccountController中进行依赖注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Controller @RequestMapping("/account") public class AccountController { @Autowired private IAccountService accountService; @RequestMapping("/findAll") public String findAll () { System.out.println("表现层:查询所有" ); accountService.findAll(); return "list" ; } }
测试 点击浏览器中测试按钮
成功
MyBatis框架 加注解 1 2 3 4 5 6 7 8 9 public interface IAccountDao { @Select("select * from account") public List<Account> findAll () ; @Insert("insert into account (name,money) values (#{name},#{money})") public void saveAccount (Account account) ; }
配置 sqlMapConfig.xml 在resources中新建sqlMapConfig.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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 > <environments default ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/groot?characterEncoding=utf8" /> <property name ="username" value ="root" /> <property name ="password" value ="iamgroot" /> </dataSource > </environment > </environments > <mappers > <package name ="com.coconutnut.dao" /> </mappers > </configuration >
测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class TestMyBatis { @Test public void test01 () throws Exception { InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml" ); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); SqlSession session = factory.openSession(); IAccountDao dao = session.getMapper(IAccountDao.class); List<Account> list = dao.findAll(); for (Account account : list){ System.out.println(account); } session.close(); in.close(); } @Test public void test02 () throws Exception { Account account = new Account(); account.setName("熊大" ); account.setMoney(400d ); InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml" ); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); SqlSession session = factory.openSession(); IAccountDao dao = session.getMapper(IAccountDao.class); dao.saveAccount(account); session.commit(); session.close(); in.close(); } }
测试查询
测试保存
Spring整合MyBatis 目标:Service能调用Dao
此时Service已经在容器中了,需要把生成的Dao的代理对象也存到容器中
配置 在Spring的配置文件applicationContext.xml中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <bean id ="dataSource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name ="driverClass" value ="com.mysql.jdbc.Driver" /> <property name ="jdbcUrl" value ="jdbc:mysql://localhost:3306/groot?characterEncoding=utf8" /> <property name ="user" value ="root" /> <property name ="password" value ="iamgroot" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> </bean > <bean id ="mapperScanner" class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="com.coconutnut.dao" /> </bean >
有了这段配置,sqlMapConfig.xml其实就不需要了,可以删除
加注解 在AccountDao上加@Repository注解
在AccountServiceImpl中注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Service("accountService") public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; @Override public List<Account> findAll () { System.out.println("业务层:查询所有" ); return accountDao.findAll(); } @Override public void saveAccount (Account account) { System.out.println("业务层:保存账户" ); accountDao.saveAccount(account); } }
在AccountController中把查出的数据存入Model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Controller @RequestMapping("/account") public class AccountController { @Autowired private IAccountService accountService; @RequestMapping("/findAll") public String findAll (Model model) { System.out.println("表现层:查询所有" ); List<Account> list = accountService.findAll(); model.addAttribute("list" ,list); return "list" ; } }
页面 在list.jsp中打印出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> </head> <body> <h3>查询所有的帐户</h3> <c:forEach items="${list}" var ="account" > ${account.name} </c:forEach> </body> </html>
测试查询 出了一个异常
1 2 3 4 5 2020-04-07 12:31:59,102 36291 [r$PoolThread-#0] WARN resourcepool.BasicResourcePool - com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@64fe7a60 -- Acquisition Attempt Failed!!! Clearing pending acquires. While trying to acquire a needed new resource, we failed to succeed more than the maximum number of allowed acquisition attempts (30). Last acquisition attempt exception: java.sql.SQLException: Unknown system variable 'tx_isolation' at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) ...
查询发现是mysql-connector-java版本太低导致
在pom.xml中将
1 <mysql.version > 5.1.6</mysql.version >
改为
1 <mysql.version > 5.1.48</mysql.version >
再试
成功
事务 保存方法还需管理事务
Spring中进行声明式事务管理,在applicationContext.xml中增加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <tx:advice id ="txAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="find*" read-only ="true" /> <tx:method name ="*" isolation ="DEFAULT" /> </tx:attributes > </tx:advice > <aop:config > <aop:advisor advice-ref ="txAdvice" pointcut ="execution(* com.coconutnut.service.impl.*ServiceImpl.*(..))" /> </aop:config >
页面 在index.jsp中新增表单
1 2 3 4 5 6 7 8 9 10 11 12 13 <body> <a href="account/findAll" >测试查询</a> <h3>测试保存</h3> <form action="account/save" method="post" > 姓名:<input type="text" name="name" /><br/> 金额:<input type="text" name="money" /><br/> <input type="submit" value="保存" /><br/> </form> </body>
控制器 增加save方法
1 2 3 4 5 6 @RequestMapping("/save") public void save (Account account, HttpServletRequest request, HttpServletResponse response) throws IOException { accountService.saveAccount(account); response.sendRedirect(request.getContextPath()+"/account/findAll" ); return ; }
存完重定向到list页面
测试保存
点击保存
成功
项目结构