Spring与SpringMVC整合
目前Spring和SPringMVC已经很好的在一起工作了,需要整合吗?需要,框架和流水线生产一样,需要分工明细:
- 业务层和数据访问层交给SpringIOC容器
- 控制层交给SpringMVC的IOC容器
也就是说整合之后,会存在两个IOC容器。
SpringIOC和SpringMVCIOC容器会调用默认无参构造器,默认使用全类名反射完成注解(dao,service,controller)的实例化
Spring在整合SpringMVC的时候需要有两个配置文件,两个IOC容器,但是要注意两个配置文件需要扫描的注解不同,
一个只负责扫描Spring,一个只负责扫描SpringMVC,要区别开来,不然会导致扫描两次的。
新建个动态WEB工程,new个conf类资源文件夹,用来存放Spring的配置文件(命名为applicationContext.xml),
在WEB-INF目录下new个SpringMVC的配置文件(和Spring的配置文件是一样的,命名为SpringMVC-servlet.xml)
这两个IOC容器要在服务器启动时加载,所以在web.xml文件中配置。
先配SpringIOC的,ContextConfigLocation
再配SpringMVCIOC的,DispatcherServlet
再加个HiddenHttpMethodFilter过滤器配置,将post请求转换为put或delete请求,REST FUL风格
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>
<!-- HiddenHttpMethodFilter过滤器将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>
SpringMVC的配置文件(要注意命名约定规范)
<?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>
</beans>
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: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/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="${mysql.driver}"></property>
<property name="jdbcUrl" value="${mysql.url}"></property>
<property name="user" value="${mysql.user}"></property>
<property name="password" value="${mysql.password}"></property>
<property name="maxPoolSize" value="${mysql.maxSize}"></property>
<property name="initialPoolSize" value="${mysql.initSize}"></property>
</bean>
<!-- JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></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/>
</beans>
整合Spring和SpringMVC的时候出现的问题
控制层,业务层,数据访问层即被SpringIOC容器管理,又被SpringMVCIOC容器管理,
没有达到明细分工的要求。解决方案:配置只扫描和不扫描。
<!-- 配置自動掃描的包 Spring不掃描 Controller註解和ControllerAdvice异常处理器註解-->
<context:component-scan base-package="com.wanbangee">
<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>
<!-- 配置自動掃描的包 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>
整合Spring和SpringMVC的解决方案
现在分开两个IOC容器之后,会考虑到,Controller中是否能够自动装配Service,
因为Controller是在SpringMVC的IOC容器中,而Service在SpringIOC容器中,
在实际情况中SpringIOC容器和SpringMVCIOC容器是一个包含关系,如下图:
也就是说,SpringMVC可以获取SpringIOC容器中的bean,反之,Spring不能获取SpringMVCIOC容器中的bean。
就是在业务实现层不能自动装配控制层对象,只能在控制层自动装配业务实现层对象。
SpringMVC对比Struts2
1.入口不同,SpringMVC用的是Servlet,Struts2用的是Filter(过滤器)
2.速度不同,SpringMVC会比Struts2执行速度更快,效率更高。Struts2好多拦截器,Struts2每完成一个功能就是一个拦截器。
3.设计理念不同,Struts2是基于类的设计(一个类对应一个映射地址),
SpringMVC是基于方法的(一个方法对应一个映射地址)
4.SpringMVC更加简洁,比如请求参数接收的时候
5.SpringMVC支持JSR303验证,而且处理Ajax请求更加方便
6.在传统的JavaEE开发中,Struts2的优势在于,提供了强大的标签库,能够将值栈中(域对象中)的信息快速输出到页面,
当然这些标签库只能在JSP使用。JSP是后端语言,传统JAVAEE使用的技术,JS是前端语言。
买书程序
买书程序,开发全程使用Ajax
以后开发前端全用HTML,HTML不能传递session域,不能将用户信息放到session域那样是没有意义的,
把用户信息放到redis缓存中,浏览器用cooki存个hard头信息,头信息每次向后端请求时把头信息传递到后端去。
先设计原型界面,要实现哪些接口,界面要调用后端,就写一个接口,从上到下一个个接口实现。
CREATE DATABASE ssbuybooks;
CREATE TABLE account(
acc_id INT PRIMARY KEY AUTO_INCREMENT,
acc_name VARCHAR(20),
acc_pass VARCHAR(20),
acc_balance DOUBLE,
acc_pic VARCHAR(100)
);
CREATE TABLE book_info(
book_no INT PRIMARY KEY AUTO_INCREMENT,
book_name VARCHAR(20),
book_price DOUBLE,
stock_id INT
);
CREATE TABLE book_stock(
stock_id INT PRIMARY KEY AUTO_INCREMENT,
book_no INT,
stock_num INT
);
CREATE TABLE book_car(
car_id INT PRIMARY KEY AUTO_INCREMENT,
book_no INT,
book_name VARCHAR(20),
book_price DOUBLE,
book_num INT,
total_price DOUBLE,
acc_id INT
); //数据冗余了
db.properties(数据库的外部属性文件)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssbuybooks
user=root
password=3306
maxSize=10
initSize=5
实体类
package com.wanbangee.entrties;
public class Account {
private Integer accId;
private String accName;
private String accPass;
private Double accBalance;
private String accPic;
public Integer getAccId() {
return accId;
}
public void setAccId(Integer accId) {
this.accId = accId;
}
public String getAccName() {
return accName;
}
public void setAccName(String accName) {
this.accName = accName;
}
public String getAccPass() {
return accPass;
}
public void setAccPass(String accPass) {
this.accPass = accPass;
}
public Double getAccBalance() {
return accBalance;
}
public void setAccBalance(Double accBalance) {
this.accBalance = accBalance;
}
public String getAccPic() {
return accPic;
}
public void setAccPic(String accPic) {
this.accPic = accPic;
}
}
package com.wanbangee.entrties;
public class BookStock {
private Integer stockId;
private Integer bookNo;
private Integer stockNum;
public Integer getStockId() {
return stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public Integer getBookNo() {
return bookNo;
}
public void setBookNo(Integer bookNo) {
this.bookNo = bookNo;
}
public Integer getStockNum() {
return stockNum;
}
public void setStockNum(Integer stockNum) {
this.stockNum = stockNum;
}
}
package com.wanbangee.entrties;
public class BookInfo {
private Integer bookNo;
private String bookName;
private Double bookPrice;
private Integer stockId;
private BookStock bookStock;//引用库存表
public Integer getBookNo() {
return bookNo;
}
public void setBookNo(Integer bookNo) {
this.bookNo = bookNo;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Double getBookPrice() {
return bookPrice;
}
public void setBookPrice(Double bookPrice) {
this.bookPrice = bookPrice;
}
public Integer getStockId() {
return stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public BookStock getBookStock() {
return bookStock;
}
public void setBookStock(BookStock bookStock) {
this.bookStock = bookStock;
}
}
package com.wanbangee.entrties;
public class BookCar {
private Integer carId;
private Integer bookNo;
private String bookName;
private Double bookPrice;
private Integer bookNum;
private Double totalPrice;
private Integer accId;
public Integer getCarId() {
return carId;
}
public void setCarId(Integer carId) {
this.carId = carId;
}
public Integer getBookNo() {
return bookNo;
}
public void setBookNo(Integer bookNo) {
this.bookNo = bookNo;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Double getBookPrice() {
return bookPrice;
}
public void setBookPrice(Double bookPrice) {
this.bookPrice = bookPrice;
}
public Integer getBookNum() {
return bookNum;
}
public void setBookNum(Integer bookNum) {
this.bookNum = bookNum;
}
public Double getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(Double totalPrice) {
this.totalPrice = totalPrice;
}
public Integer getAccId() {
return accId;
}
public void setAccId(Integer accId) {
this.accId = accId;
}
}
DAO
package com.wanbangee.dao;
import com.wanbangee.entrties.Account;
public interface AccountDao {
/**
* 登录,根据用户名和密码查询用户信息
* @param accName
* @param accPass
* @return
*/
public Account selectAccountByAccNameAndAccPass(String accName,String accPass);
/**
* 根据用户名及密码查询数据笔数,来判断是否登录成功,查询到一笔数据表示登入成功
* 这是JdbcTemplate的一个缺陷,查询成功一定要返回查询的数据笔数
* @param accName
* @param accPass
* @return
*/
public int selectCountByAccNameAndAccPass(String accName,String accPass);
/**
* 查询账户余额,根据账户ID
* @param accId
* @return
*/
public double selectAccBalanceByAccId(Integer accId);
/**
* 修改账户余额,根据账户ID
* 买书减钱,买一本书减少一本书的钱,买多本书减少多本书的钱
* 充值加钱,和买书减少账户余额一样,只是传递的money参数不同,充值是加钱
* @param accId
* @param money
* @return
*/
public int updateAccBalanceByAccId(Integer accId,Double money);
}
package com.wanbangee.dao;
import com.wanbangee.entrties.BookStock;
public interface BookStockDao {
/**
* 查询图书库存信息,根据库存ID
* @param stockId
* @return
*/
public BookStock selectBookStockByStockId(Integer stockId);
/**
* 查询图书库存,根据图书ID
* @param bookNo
* @return
*/
public int selectStockNumByBookNo(Integer bookNo);
/**
* 减少图书库存,根据图书ID,买一本书库存减一,也可以根据图书号购买多本书
* @param bookNo
* @return
*/
public void updateStockNumByBookNo(Integer bookNo,Integer bookNum);
}
package com.wanbangee.dao;
import java.util.List;
import com.wanbangee.entrties.BookInfo;
public interface BookInfoDao {
/**
* 查询图书单价,根据图书号
* @param bookNo
* @return
*/
public double selectBookPriceByBookNo(Integer bookNo);
/**
* 查询所有图书信息,并分页显示
* @param pageSize
* @param pageCurrent
* @return
*/
public List<BookInfo> selectBookInfo(Integer pageSize,Integer pageCurrent);
/**
* 查询数据笔数,便于后面做分页操作
* @return
*/
public int selectCount();
}
package com.wanbangee.dao;
import java.util.List;
import com.wanbangee.entrties.BookCar;
public interface BookCarDao {
/**
* 加入购物车,谁的购物车,买了哪本书,购物车数量默认为1
* 加入购物车,就是往这个表中插入一笔数据,先查询到图书一些信息再插入到这个表中
* 加入购物车-购物车中不存在该本图书
* @param accId
* @param bookNo
* @return
*/
public int insertBookCar(Integer accId,Integer bookNo);
/**
* 同一个图书多次加入到购物车时修改图书的数量 和 总价
* 加入购物车-已经存在该本图书
* @param accId
* @param bookNo
* @return
*/
public int updateBookCarByAccIdAndBookNo(Integer accId,Integer bookNo);
/**
* 查询当前登录人购物车中是否有对应编号的图书
* 判断该用户购物车中是否存在该图书
* @param accId
* @param bookNo
* @return
*/
public int selectCountByAccIdAndBookNo(Integer accId,Integer bookNo);
/**
* 根据用户ID查询购物车数据信息
* @param accId
* @return
*/
public List<BookCar> selectBookCarByAccId(Integer accId);
/**
* 修改购物车中图书数量和总价
* @param carId
* @param bookNum
* @return
*/
public int updateBookCarByBookNumAndTotoalPrice(Integer carId,Integer bookNum);
/**
* 删除购物车
* @param carId
* @return
*/
public int deleteBookCar(Integer carId);
}
DAOIMP
package com.wanbangee.dao.imp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.entrties.Account;
@Repository
public class AccountDaoImp implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//根据用户名和密码查询用户信息
@Override
public Account selectAccountByAccNameAndAccPass(String accName, String accPass) {
String sql = "select acc_id,acc_name,acc_balance,acc_pic from account where acc_name = ? and acc_pass = ?";
RowMapper<Account> rowMapper = new BeanPropertyRowMapper<>(Account.class);
return this.jdbcTemplate.queryForObject(sql, rowMapper,accName,accPass);
}
//根据用户名及密码查询数据笔数
@Override
public int selectCountByAccNameAndAccPass(String accName, String accPass) {
String sql = "select count(*) from account where acc_name = ? and acc_pass = ?";
return this.jdbcTemplate.queryForObject(sql, Integer.class,accName,accPass);
}
//查询账户余额
@Override
public double selectAccBalanceByAccId(Integer accId) {
String sql = "select acc_balance from account where acc_id = ?";
return this.jdbcTemplate.queryForObject(sql, Double.class,accId);
}
//修改账户余额,买书减钱,充值加钱
@Override
public int updateAccBalanceByAccId(Integer accId, Double money) {
String sql = "update account set acc_balance = acc_balance + ? where acc_id = ?";
return this.jdbcTemplate.update(sql,money,accId);
}
//JdbcTemplate的update方法返回的是int类型,表示影响的数据笔数,增删改都会影响数据,如果增删改操作影响的数据笔数是0笔,说明操作失败了
}
package com.wanbangee.dao.imp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.wanbangee.dao.BookStockDao;
import com.wanbangee.entrties.Account;
import com.wanbangee.entrties.BookStock;
@Repository
public class BookStockDaoImp implements BookStockDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//查询图书库存信息,根据库存ID
@Override
public BookStock selectBookStockByStockId(Integer stockId) {
String sql = "select stock_id,stock_num,book_no from book_stock where stock_id = ?";
RowMapper<BookStock> rowMapper = new BeanPropertyRowMapper<>(BookStock.class);
return this.jdbcTemplate.queryForObject(sql, rowMapper,stockId);
}
//查询图书库存,根据图书ID
@Override
public int selectStockNumByBookNo(Integer bookNo) {
String sql = "select stock_num from book_stock where book_no = ?";
return this.jdbcTemplate.queryForObject(sql, Integer.class,bookNo);
}
//减少图书库存,根据图书ID
@Override
public void updateStockNumByBookNo(Integer bookNo,Integer bookNum) {
String sql = "update book_stock set stock_num = stock_num - ? where book_no = ?";
this.jdbcTemplate.update(sql,bookNum,bookNo);
}
}
package com.wanbangee.dao.imp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.wanbangee.dao.BookInfoDao;
import com.wanbangee.entrties.BookInfo;
import com.wanbangee.entrties.BookStock;
@Repository
public class BookInfoDaoImp implements BookInfoDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//查询图书单价,根据图书号
@Override
public double selectBookPriceByBookNo(Integer bookNo) {
String sql = "select book_price from book_info where book_no = ?";
return this.jdbcTemplate.queryForObject(sql, Double.class,bookNo);
}
//查询所有图书信息,并分页显示
@Override
public List<BookInfo> selectBookInfo(Integer pageSize, Integer pageCurrent) {
String sql = "select book_no,book_price,book_name,stock_id from book_info limit ?,?";
RowMapper<BookInfo> rowMapper = new BeanPropertyRowMapper<>(BookInfo.class);
return this.jdbcTemplate.query(sql, rowMapper,(pageCurrent-1)*pageSize,pageSize);
//图书列表查询要显示图书库存,
//这里只有库存ID,stock_id,没有库存数据,还好图书表实体类引用了库存表,在库存表做个查询库存信息
}
//查询数据笔数,便于后面做分页操作
@Override
public int selectCount() {
String sql = "select count(*) from book_info";
return this.jdbcTemplate.queryForObject(sql, Integer.class);
}
}
package com.wanbangee.dao.imp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.wanbangee.dao.BookCarDao;
import com.wanbangee.entrties.BookCar;
@Repository
public class BookCarDaoImp implements BookCarDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//加入购物车-购物车中不存在该本图书
@Override
public int insertBookCar(Integer accId, Integer bookNo) {
//book_num加入购物车的图书数量默认为1,total_price总价,因为只购买一本书所以总价total_price为图书单价book_price
String sql = "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,?"
+ " from book_info where book_no = ?";
//将查询的结果作为插入的数据
return this.jdbcTemplate.update(sql,accId,bookNo);
}
//判断该用户购物车中是否存在该图书
@Override //判断这本书有没有在这个人的购物车中
public int selectCountByAccIdAndBookNo(Integer accId, Integer bookNo) {
String sql = "select count(car_id) from book_car where acc_id = ? and book_no = ?";
return this.jdbcTemplate.queryForObject(sql, Integer.class,accId,bookNo);
}
//加入购物车-已经存在该本图书
@Override //一次加购一本书,总价就加上这本书的单价
public int updateBookCarByAccIdAndBookNo(Integer accId, Integer bookNo) {
String sql = "update book_car set book_num = book_num + 1 ,total_price = total_price+book_price where acc_id = ? and book_no = ?";
return this.jdbcTemplate.update(sql,accId,bookNo);
}
//根据用户ID查询购物车数据信息
@Override
public List<BookCar> selectBookCarByAccId(Integer accId) {
String sql = "select car_id,book_no,book_name,book_price,book_num,total_price from book_car where acc_id = ?";
RowMapper<BookCar> rowMapper = new BeanPropertyRowMapper<>(BookCar.class);
return this.jdbcTemplate.query(sql, rowMapper,accId);
}
// 修改购物车中图书数量和总价
@Override //total_price = ?*book_price
public int updateBookCarByBookNumAndTotoalPrice(Integer carId, Integer bookNum) {
String sql = "update book_car set book_num = ? , total_price = "+bookNum+"*book_price where car_id = ?";
return this.jdbcTemplate.update(sql,bookNum,carId); //(sql,bookNum,bookNum,carId);
}
//删除购物车
@Override
public int deleteBookCar(Integer carId) {
String sql = "delete from book_car where car_id = ?";
return this.jdbcTemplate.update(sql,carId);
}
}
service
package com.wanbangee.service;
import com.wanbangee.entrties.Account;
public interface LoginService {
/**
* 登入业务
* @param accName
* @param accPass
* @return
*/
public Account login(String accName,String accPass);
}
package com.wanbangee.service;
import java.util.List;
import com.wanbangee.entrties.BookCar;
import com.wanbangee.entrties.BookInfo;
public interface BuyBookService {
/**
* 买书业务
* @param accId
* @param bookNo
*/
public void buyBook(Integer accId,Integer bookNo);
/**
* 查询账户余额
* @param accId
* @return
*/
public double selectAccBalanceByAccId(Integer accId);
/**
* 修改账户余额
* @param accId
* @param money
* @return
*/
public int updateAccBalanceByAccId(Integer accId,Double money);
/**
* 图书信息查询
* @param pageSize
* @param pageCurrent
* @return
*/
public List<BookInfo> selectBookInfo(Integer pageSize,Integer pageCurrent);
/**
* 查询数据总笔数,便于分页查询操作
* @return
*/
public int selectCount();
/**
* 增加购物车
* @param accId
* @param bookNo
* @return
*/
public int addCar(Integer accId,Integer bookNo);
/**
* 获得购物车信息
* @param accId
* @return
*/
public List<BookCar> getBookCar(Integer accId);
/**
* 修改购物车数量
* @param carId
* @param bookNum
* @return
*/
public int updateBookCar(Integer carId,Integer bookNum);
/**
* 删除购物车
* @param carId
* @return
*/
public int deleteBookCar(Integer carId);
/**
* 提交购物车
* @param accId
*/
public void submitBookCar(Integer accId);
}
serviceIMP
package com.wanbangee.service.imp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.entrties.Account;
import com.wanbangee.service.LoginService;
@Service
public class LoginServiceImp implements LoginService {
@Autowired
private AccountDao accountDao;
@Override
public Account login(String accName, String accPass) {
//1.查询数据笔数
int count = this.accountDao.selectCountByAccNameAndAccPass(accName, accPass);
if(count == 1) {
return this.accountDao.selectAccountByAccNameAndAccPass(accName, accPass);
}
return null;
}
}
package com.wanbangee.service.imp;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.dao.BookCarDao;
import com.wanbangee.dao.BookInfoDao;
import com.wanbangee.dao.BookStockDao;
import com.wanbangee.entrties.BookCar;
import com.wanbangee.entrties.BookInfo;
import com.wanbangee.service.BuyBookService;
@Service
public class BuyBookServiceImp implements BuyBookService {
@Autowired
private AccountDao accountDao;
@Autowired
private BookInfoDao bookInfoDao;
@Autowired
private BookStockDao bookStockDao;
@Autowired
private BookCarDao bookCarDao;
//买书业务
@Transactional //加上事务管理
@Override
public void buyBook(Integer accId, Integer bookNo) {
//1 查询图书单价
double money = this.bookInfoDao.selectBookPriceByBookNo(bookNo);
//2 减少账户余额,要用到图书单价
this.accountDao.updateAccBalanceByAccId(accId, money*-1);
//2.1 查询账户余额,买书是减少,money*-1
if(this.accountDao.selectAccBalanceByAccId(accId)<0) {
throw new RuntimeException("账户余额不足");
}
//3 减少图书库存,买一本书减少图书库存1
this.bookStockDao.updateStockNumByBookNo(bookNo,1);
//3.1 查询图书库存
if(this.bookStockDao.selectStockNumByBookNo(bookNo)<0) {
throw new RuntimeException("图书库存不足");
}
}
//查询账户余额业务
@Override
public double selectAccBalanceByAccId(Integer accId) {
return this.accountDao.selectAccBalanceByAccId(accId);
}
//充值业务,修改账户余额
@Override
public int updateAccBalanceByAccId(Integer accId, Double money) {
return this.accountDao.updateAccBalanceByAccId(accId, money);
}
//图书信息查询业务
@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;
}
//查询数据总笔数,便于分页查询操作
@Override
public int selectCount() {
return this.bookInfoDao.selectCount();
}
//只用改业务层,加入购物车会来到这个方法addCar,业务处理都是在service完成的,
//控制层调用数据访问层,中间加个业务层来处理复杂业务
//加入购物车,多次测试看看效果,账户ID相同,图书号不同
@Override
public int addCar(Integer accId, Integer bookNo) {
//1 判断当前人购物车中是否有当前的图书
int count = this.bookCarDao.selectCountByAccIdAndBookNo(accId, bookNo);
//2 如果有 则修改数据
if(count > 0) {
return this.bookCarDao.updateBookCarByAccIdAndBookNo(accId, bookNo);
}
//3 如果没有则新增数据
return this.bookCarDao.insertBookCar(accId, bookNo);
}
//获得购物车信息
@Override
public List<BookCar> getBookCar(Integer accId) {
return this.bookCarDao.selectBookCarByAccId(accId);
}
//修改购物车数量
@Override
public int updateBookCar(Integer carId, Integer bookNum) {
return this.bookCarDao.updateBookCarByBookNumAndTotoalPrice(carId, bookNum);
}
//删除购物车
@Override //这个业务比较简单,直接返回数据访问层
public int deleteBookCar(Integer carId) {
return this.bookCarDao.deleteBookCar(carId);
}
//提交购物车业务
@Transactional //加上事务管理
@Override
public void submitBookCar(Integer accId) {
//1 查询accId 的所有购物车数据
List<BookCar> bookCars = this.bookCarDao.selectBookCarByAccId(accId);
for (BookCar bookCar : bookCars) {
//2 减少图书库存
this.bookStockDao.updateStockNumByBookNo(bookCar.getBookNo(), bookCar.getBookNum());
//2.1 查询图书库存
if(this.bookStockDao.selectStockNumByBookNo(bookCar.getBookNo()) < 0) {
throw new RuntimeException("图书库存不足");
}
//3 减少账户余额
this.accountDao.updateAccBalanceByAccId(accId, bookCar.getTotalPrice()*-1);
//3.1 查询账户余额
if(this.accountDao.selectAccBalanceByAccId(accId) < 0) {
throw new RuntimeException("账户余额不足");
}
//4 清空购物车
this.bookCarDao.deleteBookCar(bookCar.getCarId());
}
}
}
controller
package com.wanbangee.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.wanbangee.entrties.Account;
import com.wanbangee.service.LoginService;
@Controller
public class LoginController {
@Autowired
private LoginService loginService;
/**
* 根据用户名和密码查询账户信息,如果存在账户信息,则登录成功,返回ture,将账户信息加入到session域中,否则返回false
* @param accName
* @param accPass
* @return
*/
@ResponseBody //可将Map<String,Object> map放入方法入参中
@RequestMapping(value="login",method=RequestMethod.POST)//用GET请求密码显示在地址栏不安全
public Map<String,Object> login(String accName,String accPass,HttpSession session) {
Map<String,Object> map = new HashMap<>();
Account account = this.loginService.login(accName, accPass);
if(account != null) {
session.setAttribute("account", account);//将用户信息加入到session域中
//这里用原生的,SpringMVC就是加个session注解
map.put("account", account);//将用户信息的数据加入到请求域
map.put("code", "1001");
map.put("message", "登录成功");
}else {
map.put("code", "1003");
map.put("message", "登录失败");
}
return map;
}
}
package com.wanbangee.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.wanbangee.entrties.BookCar;
import com.wanbangee.entrties.BookInfo;
import com.wanbangee.service.BuyBookService;
@Controller
public class BuyBookController {
@Autowired
private BuyBookService buyBookService;
/**
* 买书
* @param accId
* @param bookNo
* @return
*/
@ResponseBody //请求方式以修改为主,买书要修改账户余额图书库存,是个修改操作
@RequestMapping(value="buyBook",method=RequestMethod.PUT)
public Map<String,Object> buyBook(Integer accId,Integer bookNo){
Map<String,Object> map = new HashMap<>();
try {
this.buyBookService.buyBook(accId, bookNo);
map.put("code", 1001);
map.put("message", "买书成功");
return map;
} catch (Exception e) {//有异常就失败
e.printStackTrace();
map.put("code", 1002);
map.put("message", "买书失败,有异常");
return map;
}
}
/**
* 图书列表信息查询
* @param pageSize
* @param pageCurrent
* @return
*/
@ResponseBody
@RequestMapping(value="getBookInfo",method=RequestMethod.GET)
public Map<String,Object> getBookInfo(Integer pageSize,Integer pageCurrent){
Map<String,Object> map = new HashMap<>();
try {
List<BookInfo> bookInfos = this.buyBookService.selectBookInfo(pageSize, pageCurrent);
if(bookInfos.isEmpty()) {//查询结果为空,或者有异常就失败
map.put("code", 1002);
map.put("message", "查询失败");
return map;
}
map.put("code", 1001);
map.put("message", "查询成功");
map.put("bookInfos", bookInfos);//把查询到的数据放到map中响应给前端
map.put("total", this.buyBookService.selectCount());//做分页查询,把查询到的数据总笔数响应给前端
return map;
} catch (Exception e) {//有异常就失败
e.printStackTrace();
map.put("code", 1002);
map.put("message", "查询失败,有异常");
return map;
}
}
/**
* 充值
* @param accId
* @param addMoney
* @return
*/
@ResponseBody //请求方式以修改为主,充值要修改账户余额,是个修改操作
@RequestMapping(value="addMoney",method=RequestMethod.PUT)
public Map<String,Object> addMoney(Integer accId,Double money){
Map<String,Object> map = new HashMap<>();
int count = 0;
count = this.buyBookService.updateAccBalanceByAccId(accId, money);
try {
count = this.buyBookService.updateAccBalanceByAccId(accId, money);
if(count == 0) {//影响的数据笔数是0笔,或者出现异常,就会充值失败
map.put("code", 1002);
map.put("message", "充值失败");
return map;
}
map.put("code", 1001);
map.put("message", "充值成功");
return map;
} catch (Exception e) {//有异常就失败
e.printStackTrace();
map.put("code", 1002);
map.put("message", "充值失败,有异常");
return map;
}
}
/**
* 查询账户余额
* @param accId
* @return
*/
@ResponseBody
@RequestMapping(value="getAccBalance",method=RequestMethod.GET)
public Map<String,Object> getAccBalance(Integer accId){
Map<String,Object> map = new HashMap<>();
double accBalance = 0;
try {
accBalance = this.buyBookService.selectAccBalanceByAccId(accId);
map.put("code", 1001);
map.put("message", "账户余额查询成功");
map.put("accBalance",accBalance);//把查询到的数据响应给前端
return map;
} catch (Exception e) {//有异常就失败
e.printStackTrace();
map.put("code", 1002);
map.put("message", "账户余额查询失败,有异常");
return map;
}
}
/**
* 加个购物车
* 同一个商品加入购物车两次,应该是在数量和总价上更改,而不是再加一笔购物车数据
* 每增加一个商品,要先判断这个商品在购物车里是否存在,没有的话才新增数据,有的话就不新增数据
* @param accId
* @param bookNo
* @return
*/
@ResponseBody
@RequestMapping(value="addCar",method=RequestMethod.POST)
public Map<String,Object> addCar(Integer accId,Integer bookNo){
Map<String,Object> map = new HashMap<>();
try {
int count = this.buyBookService.addCar(accId, bookNo);
if(count == 0) {
map.put("code", 1002);
map.put("message", "加入购物车失败");
return map;
}
map.put("code", 1001);
map.put("message", "加入购物车成功");
return map;
} catch (Exception e) {//有异常就失败
e.printStackTrace();
map.put("code", 1002);
map.put("message", "加入购物车失败,有异常");
return map;
}
}
/**
* 购物车列表查询
* 没有分页不用放数据的笔数
* @param accId
* @return
*/
@ResponseBody
@RequestMapping(value="getBookCar",method=RequestMethod.GET)
public Map<String,Object> getBookCar(Integer accId){
Map<String,Object> map = new HashMap<>();
try {
List<BookCar> bookCars = this.buyBookService.getBookCar(accId);
if(bookCars.isEmpty()) {
map.put("code", 1002);
map.put("message", "查询失败");
return map;
}
map.put("code", 1001);
map.put("message", "查询成功");
map.put("bookCars", bookCars);
return map;
} catch (Exception e) {
e.printStackTrace();
map.put("code", 1002);
map.put("message", "查询失败,有异常");
return map;
}
}
/**
* 修改购物车数量
* @param carId
* @param bookNum
* @return
*/
@ResponseBody
@RequestMapping(value="updateBookCar",method=RequestMethod.PUT)
public Map<String,Object> updateBookCar(Integer carId,Integer bookNum){
Map<String,Object> map = new HashMap<>();
try {
int count = this.buyBookService.updateBookCar(carId, bookNum);
if(count == 0) {
map.put("code", 1002);
map.put("message", "修改失败");
return map;
}
map.put("code", 1001);
map.put("message", "修改成功");
return map;
} catch (Exception e) {
e.printStackTrace();
map.put("code", 1002);
map.put("message", "修改失败,有异常");
return map;
}
}
/**
* 删除购物车
* @param carId
* @param bookNum
* @return
*/
@ResponseBody
@RequestMapping(value="deleteBookCar",method=RequestMethod.DELETE)
public Map<String,Object> deleteBookCar(Integer carId){
Map<String,Object> map = new HashMap<>();
try {
int count = this.buyBookService.deleteBookCar(carId);
if(count == 0) {
map.put("code", 1002);
map.put("message", "移除失败");
return map;
}
map.put("code", 1001);
map.put("message", "移除成功");
return map;
} catch (Exception e) {
e.printStackTrace();
map.put("code", 1002);
map.put("message", "移除失败,有异常");
return map;
}
}
//提交购物车,查询这个人的所有的购物车数据,然后在一笔笔去购买图书,减少图书库存和账户余额
/**
* 提交购物车
* @param accId
* @return
*/
@RequestMapping(value="submitBookCar",method=RequestMethod.PUT)
@ResponseBody
public Map<String,Object> submitBookCar(Integer accId){
Map<String,Object> map = new HashMap<>();
try {
this.buyBookService.submitBookCar(accId);
map.put("code", 1001);
map.put("message", "提交购物车成功");
return map;
} catch (Exception e) {
e.printStackTrace();
map.put("code", 1002);
map.put("message", "提交购物车失败,有异常");
return map;
}
}
}