0、什么是SSM?
在软件开发领域里SSM是对Spring、SpringMVC、MyBatis这三大框架的简称。
0.1、Spring
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
0.2、SpringMVC
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
0.3、MyBatis
MyBatis 本是Apache的一个开源项目iBatis, 2010年这个项目由Apache software foundation 迁移到了google code,并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
接下来我们来一步步把他们整合在一起。
1、创建基本的Maven Web项目
在IDEA中创建一个基本的Maven项目。具体过程不是这里的重点,如有有不清楚,请自行百度或Google~。创建好项目后,在pom.xml文件中配置依赖(导包),在pom.xml文件中添加依赖配置如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>5.1.2.RELEASE</spring.version>
<slf4j.version>1.7.7</slf4j.version>
</properties>
<dependencies>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--Spring Start:也不全是Spring的依赖,还包括Spirng能够正常运行的一些支持性的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--Spring上下文核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--上下文支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring Bean工厂-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!--SpEL(Spring表达式)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring面向切面编程-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!--提供对AspectJ的支持,可以方便的将面向切面的功能集成进IDE中-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!--aspectj的runtime外部依赖包(必须)-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<!--aspectjweaver是aspectj的织入包(必须)-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
<!--字节码增强-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
<!--Spring JDBC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring事物管理-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring 对象关系映射-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring web模块核心-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring MVC模块-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring Test:spring-test-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Servlet原生API-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--支持JSP-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.2.1</version>
</dependency>
<!--JSTL用于在控制器中将模型绑定到JSP中-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--文件上传,依赖commons-io-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--增强版的java IO-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!--json数据绑定-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<!--json注解-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!--json核心-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.9</version>
</dependency>
<!--Spring End=-->
<!--MyBatis Start-->
<!--mybatis核心-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--MyBatis与Spring整合的核心包:配置这个包的时候一定要注意你的MyBatis版本和Spring版本和这个包是否兼容-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<!--Jdbc数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!--Druid数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!--MyBatis通用分页插件pageHelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.6</version>
</dependency>
<!--分页插件依赖的包-->
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.5</version>
</dependency>
<!--======MyBatis End=======-->
<!--日志记录-->
<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>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
注意!
配置的时候要特别注意mybatis-spring这个包的版本和你使用的MyBatis以及Spring版本是否兼容,特别适当发生
java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()
错误的时候,还就更要怀疑是这个问题了:
21-Aug-2019 23:47:32.939 涓ラ噸 [http-nio-80-exec-5] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [DispatcherServlet] in context with path [/ssm_merge_war_exploded] threw exception [Handler dispatch failed; nested exception is java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()Ljava/lang/Integer;] with root cause
java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()Ljava/lang/Integer;
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:86)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:408)
at com.sun.proxy.$Proxy17.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:254)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:57)
at com.sun.proxy.$Proxy18.addAccount(Unknown Source)
at com.xust.iot.service.AccountService.addAccount(AccountService.java:20)
at com.xust.iot.service.AccountService$$FastClassBySpringCGLIB$$b6e17b84.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.xust.iot.service.AccountService$$EnhancerBySpringCGLIB$$a5f30121.addAccount(<generated>)
适配的环境:mybatis-spring对JDK、mybatis、spring都有要求

2、配置环境
配置文件的编写是SSM整合的关键,需要配置的东西主要有web.xml、Sprng配置文件applicationContext.xml、Spring MVC配置文件applicationContext-mvc.xml、MyBatis全局配置文件MyBatis-config.xml以及后面的Mapper映射文件的编写。
2.1 配置web.xml文件
web.xml文件的基本配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index</welcome-file>
</welcome-file-list>
<!--启动Spring容器-->
<context-param>
<param-name>contextConfigLoaction</param-name>
<param-value>classpath:Spring/applicationContext.xml</param-value>
</context-param>
<!--用于在Web容器启动的时候根据contextConfigLoaction配置的路径读取Spring配置文件,然后启动Spring-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!--配置前端控制器-->
<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/applicationContext-mvc.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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置Restful过滤器-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2.2 配置MyBatis-config.xml全局配置文件
在MyBatis的全局配置文件中配置一些基本对settings,环境就不要在这里配置了,交给Spring管理就好了(本身MyBatis这个配置文件都是可有可无的,但是用它来写一个settings配置可以使结构清晰,方便修改)。
<?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>
<!--一些有关于mybatis运行时行为的设置-->
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
<!--开启懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--aggressvieLazyLoading当这个参数为true的时候,对任意延迟属性都会完全的加载,当为false时会按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<!--开启自动映射-->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!--开启驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,
hashCode,toString"/>
</settings>
<typeAliases>
<package name="com.xust.iot.bean"/>
</typeAliases>
<!--配置分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
</configuration>
2.3 配置applicationContext-mvc.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">
<!--开启注解扫描-->
<context:component-scan base-package="com.xust.iot" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!--开启扫描静态-->
<mvc:default-servlet-handler/>
<!--开启扫动态-->
<mvc:annotation-driven/>
<!--配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSizePerFile" value="#{1024*1024*5}"/>
<property name="maxUploadSize" value="#{1024*1024*100}"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
</beans>
2.4 配置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"
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.xust.iot">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!--引入外部配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置数据源-->
<bean id="DruidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<property name="maxWait" value="${jdbc.maxWait}"/>
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
<property name="validationQuery" value="${jdbc.validationQuery}"/>
<property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
<property name="testOnBorrow" value="${jdbc.testOnBorrow}"/>
<property name="testOnReturn" value="${jdbc.testOnReturn}"/>
<property name="poolPreparedStatements" value="${jdbc.poolPreparedStatements}"/>
<property name="maxPoolPreparedStatementPerConnectionSize"
value="${jdbc.maxPoolPreparedStatementPerConnectionSize}"/>
<property name="filters" value="${jdbc.filters}"/>
</bean>
<!--配置MyBatis-->
<bean id="SqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" value="#{DruidDataSource}"/>
<!--全局文件的位置-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
<!--指定xml映射文件的位置-->
<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"/>
</bean>
<!-- 扫描DAO持久层接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xust.iot.mapper"/>
</bean>
<!--配置事物管理器:MyBatis使用的是原生的jdbc,所以使用DataSourceTransactionManager来管理事物-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--两种配置数据源的方式-->
<!-- <property name="dataSource" value="#{DruidDataSource}"/>-->
<constructor-arg name="dataSource" value="#{DruidDataSource}"/>
</bean>
<!--配置事物策略-->
<tx:advice id="tx">
<tx:attributes>
<tx:method name="*"/>
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="myPointCut" expression="execution(* com.xust.iot.service.*.*(..))"/>
<aop:advisor advice-ref="tx" pointcut-ref="myPointCut"/>
</aop:config>
<!--开启自动代理-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
2.5 jdbc.properties数据库资源文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/tx?useSSL=false
jdbc.username=root
jdbc.password=95162437
jdbc.initialSize=10
jdbc.minIdle=10
jdbc.maxActive=50
jdbc.maxWait=60000
jdbc.timeBetweenEvictionRunsMillis=60000
jdbc.minEvictableIdleTimeMillis=300000
jdbc.validationQuery=SELECT 'x' FROM DUAL
jdbc.testWhileIdle=true
jdbc.testOnBorrow=false
jdbc.testOnReturn=false
jdbc.poolPreparedStatements=true
jdbc.maxPoolPreparedStatementPerConnectionSize=20
jdbc.filters=wall,stat
对于SSM的配置基本上完成了,下面将使用这个搭建好的框架对对book表进行简单的CRUD操作。
3、一个简单CRUD
3.1 基本准备
创建数据库和表:新建tx数据库,并在tx数据库中新建book表。具体的数据库脚本如下:
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`tx` /*!40100 DEFAULT CHARACTER SET gb2312 */;
USE `tx`;
/*Table structure for table `book` */
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`isbn` varchar(50) NOT NULL,
`book_name` varchar(100) DEFAULT NULL,
`price` int(11) DEFAULT NULL,
PRIMARY KEY (`isbn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf-8;
/*Data for the table `book` */
insert into `book`(`isbn`,`book_name`,`price`) values ('ISBN-001','book01',100),('ISBN-002','book02',200),('ISBN-003','book03',300),('ISBN-004','book04',400),('ISBN-005','book05',500);
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
3.2 编写SQL映射文件以及对应的Mapper接口
在src/main/resources目录下新建mapper目录,在mapper目录下新建BookMapper.xml SQL映射文件。并在源码包的mappr包下新建对应的BookMapper.java接口。
(1)SQL映射文件BookMapper.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.xust.iot.mapper.BookMapper">
<select id="getBookByISBN" resultType="com.xust.iot.bean.Book">
select * from book
<where>
isbn=#{isbn}
</where>
</select>
<select id="getAllBook" resultType="com.xust.iot.bean.Book">
select * from book
</select>
<insert id="addBook" parameterType="com.xust.iot.bean.Book">
insert into book(isbn,book_name,price) values(#{isbn},#{bookName},#{price})
</insert>
<update id="updateBookByISBN" parameterType="com.xust.iot.bean.Book">
update book
<set>
book_name=#{bookName},
price=#{price}
</set>
<where>
isbn=#{isbn}
</where>
</update>
<delete id="deleteBookByISBN" parameterType="string">
delete from book where isbn=#{isbn}
</delete>
</mapper>
(2) Mapper接口
package com.xust.iot.mapper;
import com.xust.iot.bean.Book;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface BookMapper {
/**
* 根据图书的ISBN(主键)获得图书信息
* @param isbn
* @return
*/
public Book getBookByISBN(@Param("isbn") String isbn);
/**
* 得到所有的书
* @return
*/
public List<Book> getAllBook();
/**
* 添加一本书
* @param book
* @return
*/
public void addBook(Book book);
/**
* 根据isbn更新书
* @param book
*/
public void updateBookByISBN(Book book);
/**
* 根据isbn删除一本书
* @param isbn
*/
public void deleteBookByISBN(@Param("isbn") String isbn);
}
3.3 开发业务层(Service层)
为了遵循SOA的开发理念和规范,我们这里还是写一个接口,并实现接口
package com.xust.iot.service;
public interface ServiceBase<T> {
public T getById(Object param);
public void deleteById(Object param);
public void updateAndSave(T t);
public void addAndSave(T t);
public List<T> getAll();
}
在com.xust.iot.service包下新建impl包,然后新建BookService接口的实现类BookServiceImpl。
package com.xust.iot.service.impl;
import com.xust.iot.bean.Book;
import com.xust.iot.mapper.BookMapper;
import com.xust.iot.service.ServiceBase;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class BookServiceimpl implements ServiceBase<Book> {
@Autowired
private BookMapper bookMapper;
@Override
public Book getById(Object param) {
Book book=bookMapper.getBookByISBN(param.toString());
return book;
}
@Override
public void deleteById(Object param) {
bookMapper.deleteBookByISBN((String)param);
}
@Override
public void updateAndSave(Book book) {
bookMapper.updateBookByISBN(book);
}
@Override
public void addAndSave(Book book) {
bookMapper.addBook(book);
}
@Override
public List<Book> getAll() {
List<Book> lists=bookMapper.getAllBook();
return lists;
}
}
3.4 开发控制层(Controller层)
在com.xust.iot.controller包下新建BookController类
package com.xust.iot.controller;
import com.xust.iot.bean.Book;
import com.xust.iot.service.impl.BookServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Controller
public class BookController {
@Autowired
private BookServiceImpl bookService;
private static boolean isNew = false;
@RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(@ModelAttribute("book") Book book, Model model) {
System.out.println(book);
if (isNew) {
bookService.addAndSave(book);
model.addAttribute("msg", "添加成功!");
} else {
bookService.updateAndSave(book);
model.addAttribute("msg", "更新成功!");
}
return "forward:showAll";
}
@RequestMapping("/toUpdatePage")
public String toUpdatePage(@ModelAttribute("book") Book book, Model model) {
model.addAttribute("book",book);
return "edit";
}
@RequestMapping("/delete")
public String delete(@RequestParam("isbn") String isbn,
@RequestParam("pageNo")Integer pageNo,
Model model) {
bookService.deleteById(isbn);
model.addAttribute("msg", "删除成功!");
return "forward:showAll";
}
@RequestMapping("/showAll")
public String showAllBook(@RequestParam("pageNo")Integer pageNo,Model model) {
//分页插件:从pageNo开始显示20条数据,这个语句一定要紧跟着查数据的那条语句,否者分页无效
PageHelper.startPage(pageNo,20);
List<Book> lists = bookService.getAll();
//进一步封装数据,PageInfo的两个参数:(数据集合,连续显示的分页个数),使用这个封装的数据可以拿到首页、末页、上/下一页....信息,非常强大的一个类
PageInfo info=new PageInfo(lists,10);
model.addAttribute("info", info);
return "bookInfo";
}
@ModelAttribute
public void check(@RequestParam(value = "isbn", defaultValue = "") String isbn,
@RequestParam(value = "bookName", defaultValue = "") String bookName,
@RequestParam(value = "price", defaultValue = "") Integer price,
Model model) {
System.out.println(isbn);
Book book = bookService.getById(isbn);
//数据库中没有这本书,那就添加一本书
if (null == book) {
Book book1 = new Book();
book1.setBookName(bookName);
book1.setIsbn(isbn);
book1.setPrice(price);
model.addAttribute("book", book1);
isNew = true;
} else {
//数据库中有这本书,那就直接拿出来更新信息
isNew = false;
model.addAttribute("book", book);
}
}
}
3.5 开发视图层(View层)
(1)index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加账户</title>
</head>
<body>
<h3><a href="toAdd">添加图书</a></h3>
<h3><a href="showAll">所有图书</a></h3>
</body>
</html>
(2)添加图书的页面:add.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加图书</title>
</head>
<body>
<form action="save" method="post">
ISBN: <input type="text" name="isbn"/><br/>
书名:<input type="text" name="bookName"/><br/>
价格:<select name="price">
<c:forEach begin="10" end="100" var="price" step="1">
<option >${price}</option>元
</c:forEach>
</select>
<button type="submit">保存</button>
</form>
</body>
</html>
(3)展示所有图书信息的页面:bookInfo.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>图书信息</title>
</head>
<body>
<center>
<button ><a href="toAdd">添加图书</a></button>
<table border="1px" cellspacing="0" cellpadding="0" align="center" width="50%">
<tr>
<th>图书ISBN编号</th>
<th>书名</th>
<th>价格</th>
<th>操作</th>
</tr>
<c:forEach items="${info.list}" var="book" varStatus="i">
<tr>
<td>${book.isbn}</td>
<td>${book.bookName}</td>
<td>${book.price}</td>
<td><button><a href="delete?isbn=${book.isbn}">删除</a></button><button><a href="toUpdatePage?isbn=${book.isbn}">修改</a></button></td>
</tr>
</c:forEach>
<tr style="align: center">
<td colspan="4" >
<button><a href="showAll?pageNo=1">首页</a></button>
<button><a href="showAll?pageNo=${info.getPrePage()}">上一页</a></button>
<span>
<c:forEach items="${info.navigatepageNums}" var="nav">
<c:if test="${nav==info.pageNum}">
<span style="background-color: greenyellow;border-radius: 5px;width: 30px"> ${nav} </span>
</c:if>
<c:if test="${nav!=info.pageNum}">
<a style="text-decoration: none" color="black" href="showAll?pageNo=${nav}">${nav}</a>
</c:if>
</c:forEach>
</span>
<button><a href="showAll?pageNo=${info.getNextPage()}">下一页</a></button>
<button><a href="showAll?pageNo=${info.getPages()}">末页</a></button>
</td>
</tr>
</table>
<span>${msg}<br/></span>
</center>
</body>
</html>
(4)修改图书信息的页面:edit.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改图书</title>
</head>
<body>
<form action="save" method="post">
ISBN: ${book.isbn}<br/><input type="hidden" name="isbn" value="${book.isbn}"/>
书名:<input type="text" name="bookName" value="${book.bookName}"/><br/>
价格:<select name="price"><br/>
<c:forEach begin="10" end="100" var="price" step="1">
<c:choose>
<c:when test="${price==book.price}">
<option selected>${price}</option>
</c:when>
<c:when test="${price!=book.price}">
<option>${price}</option>
</c:when>
</c:choose>
</c:forEach>
</select> 元<br/>
<button type="submit">保存</button>
</form>
</body>
</html>
最终的测试结果

总结
经过几个小时的斗争,SSM三大框架的简单整合算是完成了,期间也遇到了这样那样的问题,但都一一解决了,从测试结果来看还是比较成功的。然而代码没有写几行,配置文件写了一大堆,我只想说SpringBoot真香!!!