SSM整合
步骤:
1:创建一个动态的web工程 ssm01
2:在 ssm01工程中先整合Spring和SpringMVC
3:在 ssm01工程中整合MyBatis
- 需要使用Spring和MyBatis的适配包
(mybatis-spring-1.3.0.jar【支持MyBatis3.4.0及更高版本,支持Spring3.0及更高版本】)
- 需要加入MyBatis的jar包
4:在SpringIOC容器的配置文件 中加入MyBatis的配置
5:编写测试程序
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>SpringMVC03</display-name><!-- SpringMVC03项目名 -->
<welcome-file-list><!-- 配置欢迎界面 -->
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- Spring IOC容器在Tomcat启动时就会被加载 -->
<context-param><!-- 上下文参数 -->
<param-name>contextConfigLocation</param-name><!-- contextConfigLocation上下文配置文件的路径 -->
<param-value>classpath:applicationContext.xml</param-value><!-- 在类路径下classpath:applicationContext.xml -->
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- SpringMVC IOC容器在Tomcat启动时就会加载 -->
<servlet>
<servlet-name>SpringMVC</servlet-name><!-- 使用默认配置,在WEB-INF目录下SpringMVC-servlet.xml -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup><!-- 在服务器启动时加载 -->
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern><!-- 处理所有请求 -->
</servlet-mapping>
<!-- 将post请求转换为put或delete请求,REST FUL风格 -->
<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>
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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.wanbangee">
<!-- Spring不扫描Controller 和 ControllerAdvice注解 -->
<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:db.properties"/>
<!-- 配置连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driver}"></property>
<property name="jdbcUrl" value="${url}"></property>
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="maxPoolSize" value="${maxSize}"></property>
<property name="initialPoolSize" value="${initSize}"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--
启用事务注解
- 默认情况下,事务注解会使用IOC容器中名称为transactionManager的bean,如果不存在,则保存
- 我们也可以配置事务注解使用IOC容器中bean的名称
- transaction-manager : 配置具体的事务管理器的bean名称
- 约定大于配置大于编码
-->
<tx:annotation-driven/>
<!-- 配置myBatis : 将SQLSessionFactoryBean 配置进IOC容器,生产sqlSession对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property> <!-- 配置引用的数据源 -->
<property name="configLocation" value="classpath:mybatis.xml"></property><!-- 加载MyBatis的全局配置文件 -->
<property name="mapperLocations" value="classpath:com/wanbangee/dao/*.xml"></property>
<!-- 注册所有的sql映射文件,*是通配符表示所有的xml文件都行 -->
<!-- 所有的MyBatis全局配置文件中的配置,都可以在此处完成 -->
</bean>
<!-- Dao代理实现类作为Spring IOC容器中的bean 被IOC容器管理 -->
<mybatis-spring:scan base-package="com.wanbangee.dao"/>
<!-- 旧的方式:扫描所有的DAO接口中的@Mapper注解,并将DAO接口的代理实现类作为Spring IOC容器中的bean 被IOC容器管理 -->
<!-- <bean id="configure" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wanbangee.dao"></property>
</bean> -->
</beans>
SpringMVC-servlet.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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
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-4.0.xsd">
<!-- 配置自动扫描的包 SpringMVC只掃描 Controller註解和ControllerAdvice註解-->
<context:component-scan base-package="com.wanbangee" 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>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 处理静态资源 : SpringMVC会认为所有的请求都是静态资源,所以会导致正常经过请求处理器的请求出现404-->
<mvc:default-servlet-handler/>
<!-- 万能的注解驱动配置 : 表示请求先找静态资源,如果没有静态资源则找正常的请求处理器 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置国际化资源文件的bean,需要的时候再配 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
<!-- 配置本地化解析器,需要的时候再配 -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
</bean>
<!-- 本地化拦截器,需要的时候再配 -->
<!-- 配置拦截器 -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
<!-- 配置MultipartResolver,需要的时候再配 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<!-- 文件上传的最大字节数 1024*1024*5 -->
<property name="maxUploadSize" value="6000000"></property>
</bean>
</beans>
mybatis.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>
<settings>
<!-- 开启延迟加载策略 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 设置自动驼峰命名 -->
<setting name="mapUnderscoreToCamelCase" value="true"></setting>
<!-- 开启二级缓存 : 虽然默认是开启的,但是确定的配置,不管默认,都需要配置 -->
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
db.properties外部属性文件配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssbuybooks?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
user=root
password=3306
maxSize=10
initSize=5
antlr-2.7.7.jar
c3p0-0.9.1.2.jar
classmate-0.8.0.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-fileupload-1.2.1.jar
commons-io-2.0.jar
commons-logging-1.1.3.jar
hibernate-validator-5.0.0.CR2.jar
hibernate-validator-annotation-processor-5.0.0.CR2.jar
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
jboss-logging-3.1.1.GA.jar
jstl.jar
mybatis-3.4.1.jar
mybatis-spring-1.3.0.jar
mysql-connector-java-5.1.37-bin.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar
standard.jar
validation-api-1.1.0.CR1.jar
结合之前的SS整合买书程序操作用SSM完成
接口中增删改方法不要用void,建议用int long boolean等类型。
只有查询才有查询返回结果集类型resultType,如resultType=“int”
resultType=“com.wanbangee.entities.BookCar”
只需将DAOIMP换成SQL映射文件
package com.wanbangee.dao;
import org.apache.ibatis.annotations.Param;
import com.wanbangee.entities.Account;
public interface AccountDao {
/**
* 登录,根据用户名和密码查询用户信息
* @param accName
* @param accPass
* @return
*/
public Account selectAccountByAccNameAndAccPass(@Param("accName")String accName,@Param("accPass")String accPass);
/**
* 根据用户名及密码查询数据笔数,来判断是否登录成功,查询到一笔数据表示登入成功
* 这是JdbcTemplate的一个缺陷,查询成功一定要返回查询的数据笔数
* @param accName
* @param accPass
* @return
*/
public int selectCountByAccNameAndAccPass(@Param("accName")String accName,@Param("accPass")String accPass);
/**
* 查询账户余额,根据账户ID
* @param accId
* @return
*/
public double selectAccBalanceByAccId(@Param("accId")Integer accId);
/**
* 修改账户余额,根据账户ID
* 买书减钱,买一本书减少一本书的钱,买多本书减少多本书的钱
* 充值加钱,和买书减少账户余额一样,只是传递的money参数不同,充值是加钱
* @param accId
* @param money
* @return
*/
public int updateAccBalanceByAccId(@Param("accId")Integer accId,@Param("money")Double money);
}
<?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.wanbangee.dao.AccountDao" >
<select id="selectAccountByAccNameAndAccPass" resultType="com.wanbangee.entities.Account">
select acc_id,acc_name,acc_balance,acc_pic from account where acc_name = #{accName} and acc_pass = #{accPass}
</select>
<select id="selectCountByAccNameAndAccPass" resultType="int">
select count(*) from account where acc_name = #{accName} and acc_pass = #{accPass}
</select>
<select id="selectAccBalanceByAccId" resultType="double">
select acc_balance from account where acc_id = #{accId}
</select>
<update id="updateAccBalanceByAccId">
update account set acc_balance = acc_balance + #{accId} where acc_id = #{money}
</update>
</mapper>
package com.wanbangee.dao;
import org.apache.ibatis.annotations.Param;
import com.wanbangee.entities.BookStock;
public interface BookStockDao {
/**
* 查询图书库存信息,根据库存ID
* @param stockId
* @return
*/
public BookStock selectBookStockByStockId(@Param("stockId")Integer stockId);
/**
* 查询图书库存,根据图书ID
* @param bookNo
* @return
*/
public int selectStockNumByBookNo(@Param("bookNo")Integer bookNo);
/**
* 减少图书库存,根据图书ID,买一本书库存减一,也可以根据图书号购买多本书
* @param bookNo
* @return
*/
public int updateStockNumByBookNo(@Param("bookNo")Integer bookNo,@Param("bookNum")Integer bookNum);
}
<?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.wanbangee.dao.BookStockDao">
<select id="selectBookStockByStockId" resultType="com.wanbangee.entities.BookStock">
select stock_id,stock_num,book_no from book_stock where stock_id = #{stockId}
</select>
<select id="selectStockNumByBookNo" resultType="int">
select stock_num from book_stock where book_no = #{bookNo}
</select>
<update id="updateStockNumByBookNo">
update book_stock set stock_num = stock_num - #{bookNum} where book_no = #{bookNo}
</update>
</mapper>
package com.wanbangee.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.wanbangee.entities.BookCar;
public interface BookCarDao {
/**
* 加入购物车,谁的购物车,买了哪本书,购物车数量默认为1
* 加入购物车,就是往这个表中插入一笔数据,先查询到图书一些信息再插入到这个表中
* 加入购物车-购物车中不存在该本图书
* @param accId
* @param bookNo
* @return
*/
public int insertBookCar(@Param("accId")Integer accId,@Param("bookNo")Integer bookNo);
/**
* 同一个图书多次加入到购物车时修改图书的数量 和 总价
* 加入购物车-已经存在该本图书
* @param accId
* @param bookNo
* @return
*/
public int updateBookCarByAccIdAndBookNo(@Param("accId")Integer accId,@Param("bookNo")Integer bookNo);
/**
* 查询当前登录人购物车中是否有对应编号的图书
* 判断该用户购物车中是否存在该图书
* @param accId
* @param bookNo
* @return
*/
public int selectCountByAccIdAndBookNo(@Param("accId")Integer accId,@Param("bookNo")Integer bookNo);
/**
* 根据用户ID查询购物车数据信息
* @param accId
* @return
*/
public List<BookCar> selectBookCarByAccId(@Param("accId")Integer accId);
/**
* 修改购物车中图书数量和总价
* @param carId
* @param bookNum
* @return
*/
public int updateBookCarByBookNumAndTotoalPrice(@Param("carId")Integer carId,@Param("bookNum")Integer bookNum);
/**
* 删除购物车
* @param carId
* @return
*/
public int deleteBookCar(@Param("carId")Integer carId);
}
<?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.wanbangee.dao.BookCarDao">
<insert id="insertBookCar">
insert into book_car(book_no,book_name,book_price,book_num,total_price,acc_id) select book_no,book_name,book_price,1,book_price,#{accId}"
+ " from book_info where book_no = #{bookNo}
</insert>
<update id="updateBookCarByAccIdAndBookNo">
update book_car set book_num = book_num + 1 ,total_price = total_price+book_price where acc_id = #{accId} and book_no = #{bookNo}
</update>
<select id="selectCountByAccIdAndBookNo" resultType="int">
select count(car_id) from book_car where acc_id = #{accId} and book_no = #{bookNo}
</select>
<select id="selectBookCarByAccId" resultType="com.wanbangee.entities.BookCar">
select car_id,book_no,book_name,book_price,book_num,total_price from book_car where acc_id = #{accId}
</select>
<update id="updateBookCarByBookNumAndTotoalPrice">
update book_car set book_num = #{bookNum} , total_price = #{bookNum}*book_price where car_id = #{carId}
</update>
<delete id="deleteBookCar">
delete from book_car where car_id = #{carId}
</delete>
</mapper>
package com.wanbangee.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.wanbangee.entities.BookInfo;
public interface BookInfoDao {
/**
* 查询图书单价,根据图书号
* @param bookNo
* @return
*/
public double selectBookPriceByBookNo(@Param("bookNo")Integer bookNo);
/**
* 查询所有图书信息,并分页显示
* @param pageSize
* @param pageCurrent
* @return
*/
public List<BookInfo> selectBookInfo(@Param("pageSize")Integer pageSize,@Param("startSize")Integer pageCurrent);
/**
* 查询数据笔数,便于后面做分页操作
* @return
*/
public int selectCount();
}
<?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.wanbangee.dao.BookInfoDao">
<select id="selectBookPriceByBookNo" resultType="double">
select book_price from book_info where book_no = #{bookNo}
</select>
<resultMap type="com.wanbangee.entities.BookInfo" id="MyBookInfo">
<association property="bookStock" select="com.wanbangee.dao.BookStockDao.selectBookStockByStockId" column="stock_id" fetchType="eager">
</association>
</resultMap>
<select id="selectBookInfo" resultMap="MyBookInfo">
select book_no,book_price,book_name,stock_id from book_info limit #{pageSize},#{startSize}
</select>
<select id="selectCount" resultType="int">
select count(*) from book_info
</select>
</mapper>
//图书信息查询业务
@Override
public List<BookInfo> selectBookInfo(Integer pageSize, Integer pageCurrent) {
List<BookInfo> bookInfos = this.bookInfoDao.selectBookInfo(pageSize, pageCurrent);
/*for (BookInfo bookInfo : bookInfos) {
if(bookInfo.getStockId() != null) {//查询库存封装到集合中,stock_id不为空才封装
bookInfo.setBookStock(this.bookStockDao.selectBookStockByStockId(bookInfo.getStockId()));
}
}*/
return bookInfos;
}
图书信息列表展示,在SQL映射文件中用association分步查询,延迟/即时加载
<resultMap type="com.wanbangee.entities.BookInfo" id="MyBookInfo">
<association property="bookStock" select="com.wanbangee.dao.BookStockDao.selectBookStockByStockId" column="stock_id">
</association>
</resultMap>
<select id="selectBookInfo" resultMap="MyBookInfo">
select book_no,book_price,book_name,stock_id from book_info limit #{pageSize},#{startSize}
</select>
上面写法会有问题,前端页面会无法获得图书信息,因为association分步查询默认是延迟加载,延迟加载会导致前端JSon数据格式转换有问题。
解决方法有两种:
1.在相应实体类加上下面注解
//@JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler"})
public class BookInfo {
2.取消association分步查询默认延迟加载行为,加上 fetchType="eager">让其变为即时加载。
<resultMap type="com.wanbangee.entities.BookInfo" id="MyBookInfo">
<association property="bookStock" select="com.wanbangee.dao.BookStockDao.selectBookStockByStockId" column="stock_id" fetchType="eager">
</association>
</resultMap>
<select id="selectBookInfo" resultMap="MyBookInfo">
select book_no,book_price,book_name,stock_id from book_info limit #{pageSize},#{startSize}
</select>