利用MVC(SpringMVC+Spring+MyBatis)实现购物车
本试题使用Jsp+Spring+Mybatis+Mysql+Maven等技术实现购物车管理。
语言和环境
A、实现语言
Java
B、环境要求
JDK1.8、Eclipse、Tomcat7、SpringMVC、Spring、Mybatis、Mysql、Maven
功能要求
- 分页显示商品表中信息,如下图
- 点击购买,显示购物车中的商品,如下图
数据库设计
源码下载地址
https://download.csdn.net/download/pcbhyy/10765055
主要代码
数据库语句
use mydb;
create table tb_goods(
id varchar(20) primary key,
name varchar(20) not null,
price double not null,
company varchar(100) not null,
leave_date timestamp not null,
`desc` varchar(500)
)
insert into tb_goods values('12323434','桃李面包',6.0,'桃李食品公司','2018-06-09 12:00:05','桃李面包')
insert into tb_goods
values
('9998734','桃李面包1',6.0,'桃李食品公司','2018-06-09 12:00:05','桃李面包'),
('34343434','桃李面包2',12.0,'桃李食品公司','2018-06-09 12:00:05','桃李面包'),
('494594594','桃李面包3',5.50,'桃李食品公司','2018-06-09 12:00:05','桃李面包'),
('458548548','桃李面包4',2.0,'桃李食品公司','2018-06-09 12:00:05','桃李面包')
select id,name,price,company,leave_date leaveDate,`desc` from tb_goods
实体类
package com.neu.entity;
import java.math.BigDecimal;
import java.util.Date;
public class Good {
private String id;
private String name;
private BigDecimal price;
private String company;
private Date leaveDate;
private String desc;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Good other = (Good) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
public Good() {
super();
// TODO Auto-generated constructor stub
}
public Good(String id, String name, BigDecimal price, String company, Date leaveDate, String desc) {
super();
this.id = id;
this.name = name;
this.price = price;
this.company = company;
this.leaveDate = leaveDate;
this.desc = desc;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public Date getLeaveDate() {
return leaveDate;
}
public void setLeaveDate(Date leaveDate) {
this.leaveDate = leaveDate;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
mapper接口
package com.neu.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.junit.runners.Parameterized.Parameters;
import com.neu.entity.Good;
public interface GoodMapper {
public List<Good> getAll();
//pageSize:每页最多有多少行,pageNum:第几页
public List<Good> getPaged(@Param("pageSize") int pageSize,@Param("pageNum") int pageNum);
//表中有多少行数据
public int count();
public Good getById(String id);
}
mapper
<?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.neu.mapper.GoodMapper">
<select id="getAll" resultType="com.neu.entity.Good">
select id,name,price,company,leave_date leaveDate,`desc` from tb_goods
</select>
<select id="getPaged" resultType="com.neu.entity.Good">
select id,name,price,company,leave_date leaveDate,`desc`
from tb_goods
limit ${(pageNum-1)*pageSize},${pageSize}
</select>
<select id="count" resultType="int">
select count(*) from tb_goods
</select>
<select id="getById" resultType="com.neu.entity.Good">
select id,name,price,company,leave_date leaveDate,`desc`
from tb_goods
where id = #{id}
</select>
</mapper>
业务逻辑层接口
package com.neu.service;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.neu.entity.Good;
public interface GoodService {
public List<Good> getAll();
// pageSize:每页最多有多少行,pageNum:第几页
public List<Good> getPaged(int pageSize,int pageNum);
// 表中有多少行数据
public int count();
public Good getById(String id);
}
业务逻辑实现类
package com.neu.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.neu.entity.Good;
import com.neu.mapper.GoodMapper;
@Service
public class GoodServiceImpl implements GoodService {
@Autowired
private GoodMapper goodMapper;
@Override
public List<Good> getAll() {
return goodMapper.getAll();
}
@Override
public List<Good> getPaged(int pageSize, int pageNum) {
return goodMapper.getPaged(pageSize, pageNum);
}
@Override
public int count() {
return goodMapper.count();
}
@Override
public Good getById(String id) {
return goodMapper.getById(id);
}
}
控制器
package com.neu.controller;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.apache.ibatis.annotations.Param;
import org.hibernate.validator.internal.util.IgnoreJava6Requirement;
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.RequestParam;
import com.neu.entity.Good;
import com.neu.service.GoodService;
@Controller
public class GoodController {
@Autowired
private GoodService goodService;
@RequestMapping("getPaged")
public String getAll(@RequestParam(defaultValue="1") int pageNum,Model model) {
int pageSize = 3;
List<Good> list = goodService.getPaged(pageSize, pageNum);
model.addAttribute("list",list);
int count = goodService.count();
//计算一共有多少页
int pageCount = count % pageSize == 0?count/pageSize:count/pageSize+1;
model.addAttribute("pageCount", pageCount);
model.addAttribute("pageNum", pageNum);
return "getall";
}
@RequestMapping("addToCart")
public String addToCart(Good good,HttpSession session,Model model) {
Map<Good, Integer> cart = (Map<Good, Integer>)session.getAttribute("cart");
if(cart == null) {
cart = new HashMap<>();//创建购物车Map集合
good = goodService.getById(good.getId());//从数据库中查询商品信息
cart.put(good, 1);//向购物车map集合中添加商品
session.setAttribute("cart", cart);//向session中添加购物车
}else {
Integer n = cart.get(good);
if(n == null) {
good = goodService.getById(good.getId());//从数据库中查询商品信息
cart.put(good, 1);
}else {
cart.put(good, 1+n);
}
}
BigDecimal sum = new BigDecimal(0);
for(Good g : cart.keySet()) {
sum = sum.add(g.getPrice().multiply( new BigDecimal(cart.get(g))));
}
model.addAttribute("sum", sum);
return "cart";
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>good_demo</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!--
启动两个容器,
父容器:业务逻辑层和数据访问层组件 ,通过监听器,在启动web容器的同时,启动
子容器:控制器组件,通过前端控制器(Servlet),启动
子容器组件可以访问父容器组件
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>
getall.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div style="text-align:center">
<h1>商品信息浏览</h1>
<table border="1" width="800" align="center">
<tr>
<th>编号</th><th>名称</th><th>价格</th><th>出厂日期</th><th>生产厂家</th><th>描述</th><th>操作</th>
</tr>
<c:forEach items="${ list }" var="good">
<tr>
<td>${ good.id }</td>
<td>${ good.name }</td>
<td>${ good.price }</td>
<td><fmt:formatDate value="${ good.leaveDate }" pattern="yyyy-MM-dd HH:mm:ss"/> </td>
<td>${ good.company }</td>
<td>${ good.desc }</td>
<td>
<a href="${ pageContext.request.contextPath }/addToCart?id=${ good.id }">点击购买</a>
</td>
</tr>
</c:forEach>
<tr>
<td colspan="7">
<c:forEach begin="1" end="${ pageCount }" var="pageNum">
<c:if test="${ pageNum == requestScope.pageNum }">
${ pageNum }
</c:if>
<c:if test="${ pageNum != requestScope.pageNum }">
[<a href="${ pageContext.request.contextPath }/getPaged?pageNum=${ pageNum }">${ pageNum }</a>]
</c:if>
</c:forEach>
</td>
</tr>
<tr>
<td colspan="7">
<c:if test="${ pageNum == 1 }">
首页 上一页
</c:if>
<c:if test="${ pageNum > 1 }">
<a href="${ pageContext.request.contextPath }/getPaged?pageNum=1">首页</a>
<a href="${ pageContext.request.contextPath }/getPaged?pageNum=${ pageNum - 1 }">上一页</a>
</c:if>
<c:if test="${ pageNum == pageCount }">
下一页 末页
</c:if>
<c:if test="${ pageNum < pageCount }">
<a href="${ pageContext.request.contextPath }/getPaged?pageNum=${ pageNum + 1 }">下一页</a>
<a href="${ pageContext.request.contextPath }/getPaged?pageNum=${ pageCount }">末页</a>
</c:if>
</td>
</tr>
</table>
</div>
</body>
</html>
cart.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div style="text-align:center;">
<h1>我的购物车</h1>
<table border="1" width="700" align="center">
<tr>
<th>编号</th>
<th>名称</th>
<th>单价</th>
<th>数量</th>
<th>小计</th>
</tr>
<c:forEach items="${ cart }" var="entry">
<tr>
<td>${ entry.key.id }</td>
<td>${ entry.key.name }</td>
<td>${ entry.key.price }</td>
<td>${ entry.value }</td>
<td>${ entry.key.price*entry.value }</td>
</tr>
</c:forEach>
<tr>
<td colspan="5">
总计:${ sum }
</td>
</tr>
<tr>
<td colspan="5">
<a href="javascript:history.go(-1)">返回商品信息页面</a>
</td>
</tr>
</table>
</div>
</body>
</html>
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 组件扫描 -->
<context:component-scan base-package="com.neu.service,com.neu.mapper"></context:component-scan>
<!-- 读取属性文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
</list>
</property>
</bean>
<!-- jdbcTemplate,封装了数据库的常用操作的工具类 -->
<!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> -->
<!-- 数据源,可以支持连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<!-- 最大激活数 -->
<property name="maxActive" value="20"></property>
<!-- 最大闲置数 -->
<property name="maxIdle" value="5"></property>
<!-- 最大等待时间,单位为毫秒,超过这个时间,就抛出异常 -->
<property name="maxWait" value="1000"></property>
</bean>
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.neu.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"></property>
</bean>
</beans>
springmvc.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-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<!-- 组件扫描 -->
<context:component-scan base-package="com.neu.controller"></context:component-scan>
<!-- 日期进行转换的格式设置 -->
<bean id="formattingConversionServiceFactoryBean"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<!-- <bean class="com.neu.controller.DateConverter"></bean> -->
</list>
</property>
</bean>
<!-- 使用springmvc的注解 -->
<mvc:annotation-driven validator="validator" conversion-service="formattingConversionServiceFactoryBean" ></mvc:annotation-driven>
<!-- 视图解析器,通过前缀和后缀来得到视图的物理路径 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置校验错误信息文件,主要用于国际化 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:CustomValidationMessages</value>
</list>
</property>
<property name="fileEncodings" value="utf-8"></property>
<property name="cacheSeconds" value="120"></property>
</bean>
<!-- 配置验证器 -->
<bean
id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
<property name="validationMessageSource" ref="messageSource"></property>
</bean>
<!-- <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
默认的异常处理页面视图
<property name="defaultErrorView" value="error/err"></property>
默认异常名为:exception,但是可以通过该属性修改异常的名称
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<prop key="ArithmeticException">error/ArithmeticException</prop>
<prop key="IOException">error/IOException</prop>
<prop key="java.sql.SQLException">error/SQLException</prop>
</props>
</property>
</bean> -->
<!-- 用于文件上传 -->
<!-- <bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
配置上传文件的总大小,单位为:字节
<property name="maxUploadSize" value="5242880"></property>
设置文本编码
<property name="defaultEncoding" value="utf-8"></property>
</bean> -->
<!-- 配置静态资源的解析方法 -->
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
<mvc:resources location="/css/" mapping="/css/**"></mvc:resources>
<mvc:resources location="/images/" mapping="/images/**"></mvc:resources>
<!-- 登录检查的拦截器 -->
<!-- <mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
需要排除的请求
<mvc:exclude-mapping path="/user/login.action"/>
<bean class="com.neu.controller.LoginCheckInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors> -->
</beans>
SqlMapConfig.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>
<!-- <environments default="mysql">
<environment id="mysql">
事物管理器
<transactionManager type="jdbc"></transactionManager>
type="pooled"表示使用连接池
<dataSource type="pooled">
<property name="url" value="jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC&allowMultiQueries=true"/>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments> -->
<!-- <mappers>
添加映射文件配置
<mapper resource="com/neu/dao/DeptMapper.xml" />
<mapper resource="com/neu/dao/EmpMapper.xml" />
</mappers> -->
</configuration>
db.properties
jdbc.url=jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=root
#jdbc.url=jdbc:oracle:thin:@localhost:1521:ORCL
#jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
#jdbc.username=scott
#jdbc.password=tiger
log4j.properties
# Global logging configuration
#\u751F\u4EA7\u73AF\u5883\u914D\u7F6Einfo ERROR
log4j.rootLogger=DEBUG,stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
CustomValidationMessages.properties
user.username.notblank=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
user.password.notblank=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A