Spring+MyBatis+SpringMvc整合Demo
客户关系管理系统demo
项目分析
该demo使用技术及环境:ssm+maven+bootstrap+jsp+mysql+idea+jdk1.8
需求:客户管理,实现客户列表分页显示如下图


项目开始
环境搭建
-
数据库环境:
数据库与表:
客户表![]()
字典表:[设计初衷 -- 将页面很多定义好且无需更改的字符串统一在字典表管理,优化数据库]
![]()
-
pom.xml -- 引入所需jar
思考:整合:ssm+maven+mysql,需要哪些jar?
-
数据库层:Mysql数据库连接驱动,mybatis相关jar,mybatis与spring整合需要的包
org.mybatis
mybatis
3.2.3
org.mybatis
mybatis-spring
1.2.1
mysql
mysql-connector-java
5.1.6
runtime
c3p0
c3p0
0.9.1.2
-
spring管理(已包含springmvc)
<spring.version>4.2.4.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
org.springframework
spring-core
${spring.version}
org.springframework
spring-beans
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-orm
${spring.version}
org.springframework
spring-test
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.aspectj
aspectjweaver
1.8.7
-
JSON相关
com.fasterxml.jackson.core
jackson-annotations
2.4.0
com.fasterxml.jackson.core
jackson-core
2.4.2
com.fasterxml.jackson.core
jackson-databind
2.4.2
-
日志相关
org.slf4j
slf4j-api
${slf4j.version}
org.slf4j
slf4j-log4j12
${slf4j.version}
-
其他[如果使用idea开发,无自带的jstl标签库,需导入以下Jar坐标]
jstl
jstl
1.2
javax.servlet
servlet-api
2.5
provided
javax.servlet
jsp-api
2.0
provided
-
tomcat插件
org.apache.maven.plugins
maven-compiler-plugin
3.5.1
1.7
1.7
org.apache.tomcat.maven
tomcat7-maven-plugin
2.2
9090
/autoErp
utf-8
src/main/java
**/*.xml
false
-
项目初始结构
![]()
-
项目三层建包结构和配置文件
mapper层:
mybatis配置文件[只需提供约束头,里面内容不用写]
mapper配置文件(接口.xml),写sql语句.
spring整合mapper配置文件 spring-mapper.xml
如下:

需求一:客户列表分页显示
DAO层开发 start
SQL
SELECT
c.cust_id,
c.cust_name,
a.dict_item_name as cust_source,
b.dict_item_name as cust_industry,
d.dict_item_name as cust_level,
c.cust_mobile,
c.cust_phone
FROM
t_customer c
LEFT OUTER JOIN t_basedict a ON c.cust_source = a.dict_id
LEFT OUTER JOIN t_basedict b ON c.cust_industry = b.dict_id
LEFT OUTER JOIN t_basedict d ON c.cust_level = d.dict_id;
编写sqlMapConfig.xml
编写 CustomerMapper接口
分析:
- 列表显示,且列表需要分页
- 参数:当前页,每页显示
- 返回值 集合,泛型是QueryVo -- 该类封装客户端列表所需要的数据(客户表和字典表)
- sql语句xml相关配置
QueryVo -- POJO类
public class QueryVo {
private Integer cust_id;
private String cust_name;
private String cust_source; //来源
private String cust_industry;//行业
private String cust_level; //级别
private String cust_mobil;
private String cust_phone;
private Integer index;//分页开始
private Integer rows;//数据条数
//getter and setter method...
}
CustomerMapper中添加方法
public interface CustomerMapper {
/**
* 查询客户列表
* @param vo 条件对象
* @return 库户列表
*/
public List
}
配置xml
添加db.propertis和log4j.properties配置文件
db.properties:数据库连接的基础配置//数据库,用户名,密码等
log4j.properties:LOG日志所需配置
-
db.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///ssm
##注意!!!!!!!!这个user除了username作为变量名外都可以使用,但如果使用username,将会和系统中的username冲突,造成数据库无法连接成功.
user=root
password= -
log4j.propertis
设置日志记录到控制台的方式
log4j.appender.s=org.apache.log4j.ConsoleAppender
log4j.appender.s.Target=System.out
log4j.appender.s.layout=org.apache.log4j.PatternLayout
log4j.appender.s.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n设置日志记录到文件的方式
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n日志输出的级别,以及配置记录方案
log4j.rootLogger=info, s
编写spring-mapper.xml文件
<context:component-scan base-package="com.xingc.example"/>
<context:property-placeholder location="classpath:db.properties"/>
测试走一波
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-mapper.xml"})
public class CustomerMapperTest {
@Autowired
private CustomerMapper customerMapper;
@Test
public void test(){
QueryVo vo = new QueryVo();
vo.setIndex(0);
vo.setRows(3);
//查询第一页的三条记录
List
System.out.println("\n+++结果数量: "+customerList.size());
System.out.println("\n+++结果显示: "+customerList);
}
}
-
测试结果
![]()
-
至此,mapper测试成功,开发基本完成[单一列表显示功能]
DAO层 end
Service层开发
在service/pom.xml中添加mapper层的jar依赖
module结构

编写spring-service.xml
<tx:advice id="txAdvice" transaction-manager="transactionManager">
tx:attributes
<tx:method name="save" propagation="REQUIRED"/>
<tx:method name="udpate" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="select" read-only="true"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
aop:config
<aop:pointcut id="myPoint" expression="execution(* com.xingc.example.service..(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint"/>
</aop:config>
编写客户业务逻辑接口
public interface CustomerService {
/**
* 查询客户列表
* @param vo 条件对象
* @return 库户列表
*/
public List
}
编写客户业务逻辑实现
//注意:使用该注解的前提是已经配置了 <context:component-scan base-package="com.xingc.example"/>
@Service("customerService")
public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerMapper customerMapper;
@Override
public List
return customerMapper.getCustomerList(vo);
}
}
测试再来一波
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-.xml"})
public class CustomerServiceTest {
@Autowired
private CustomerService customerService;
@Test
public void test() {
QueryVo vo = new QueryVo();
vo.setIndex(0);
vo.setRows(3);
//查询第一页的三条记录
List
System.out.println("\n+++结果数量: " + customerList.size());
System.out.println("\n+++结果显示: " + customerList);
}
}
-
结果
![]()
分页???
由于考虑到前端页面需要对客户列表进行分页,因此这里的业务逻辑需要修改
-
添加分页实体
public class Page
{ private int total;
private int page;
private int size;
private Listrows;
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public ListgetRows() {
return rows;
}
public void setRows(Listrows) {
this.rows = rows;
}}
-
修改后的实现类和接口
public interface CustomerService {
/**
* 查询客户列表
* @param vo 条件对象
* @return 库户列表
*/
public PagegetCustomerList(QueryVo vo, Integer page, Integer rows);
} -
实现
@Service("customerService")
public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerMapper customerMapper;@Override
public PagegetCustomerList(QueryVo vo, Integer page, Integer rows) {
page = page == null ? page = 1 : page;
rows = rows == null ? rows = 8 : rows;
//分页处理
vo.setIndex((page - 1) * rows);
vo.setRows(rows);//获得数据库查出来的对象
Listlist = customerMapper.getCustomerList(vo);
//循环封装
Page p = new Page();
p.setPage(page);
p.setSize(rows);
//总条数
int total = customerMapper.getCount(vo);
p.setTotal(total);List
customers = new ArrayList<>();
Customer customer = null;
for(QueryVo v : list){
customer = new Customer();
customer.setCust_id(v.getCust_id());
customer.setCust_name(v.getCust_name());
customer.setCust_source(v.getCust_source());
customer.setCust_industry(v.getCust_industry());
customer.setCust_level(v.getCust_level());
customer.setCust_mobile(v.getCust_mobil());
customer.setCust_phone(v.getCust_phone());customers.add(customer);
}p.setRows(customers);
return p;
}
}
至此,service层开发基本完成,离实现越来越近啦.....
Web层开发开始
到了这里,想说一点,其实实际开发应该不是这样的步骤开发的,应该先把配置文件和项目架构搭起来,再从dao - service - web - 页面 依次实现,不过因为我是边写该笔记边开发,因此并未完全按照这个开发步骤来实现.叨逼叨结束...
springmvc.xml配置
<context:component-scan base-package="com.xingc.example"/>
<mvc:resources mapping="/css/" location="/css/"/>
<mvc:resources mapping="/js/" location="/js/"/>
<mvc:resources mapping="/fonts/**" location="/fonts/"/>
web.xml配置
controller编写
@Controller
@RequestMapping("/cust/")
public class CustomerController {
@Autowired
private CustomerService customerService;
@RequestMapping("/getCustomerList")
public String getCustomerList(QueryVo vo,Integer page,Integer rows,Model model) {
Page
model.addAttribute("page",p);
return "customer";
}
}
测试

-
说明:到这里,ssm配置及基本环境搭建完成,数据成功查出.列表显示后台部分完结,再看一下此时的项目结构
![]()
三层架构基本完成,开始前端jsp代码编写
JSP页面编写[jsp+bootstrap]
说明:在这里使用自定义标签的方式定义分页工具栏[和jstl标签是一个道理]
首先,创建jsp自定义标签,步骤如下
-
定义一个标签类
/**
* 显示格式 上一页 1 2 3 4 5 下一页
*/
public class NavigationTag extends TagSupport {
static final long serialVersionUID = 2372405317744358833L;/**
* request 中用于保存Page对象的变量名,默认为“page”
*/
private String bean = "page";/**
* 分页跳转的url地址,此属性必须
*/
private String url = null;/**
* 显示页码数量
*/
private int number = 5;@Override
public int doStartTag() throws JspException {
JspWriter writer = pageContext.getOut();
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
Page page = (Page)request.getAttribute(bean);
if (page == null)
return SKIP_BODY;
url = resolveUrl(url, pageContext);
try {
//计算总页数
int pageCount = page.getTotal() / page.getSize();
if (page.getTotal() % page.getSize() > 0) {
pageCount++;
}
writer.print(" "); - <a href="" + pageUrl + "">"+ indexPage +" ");
- <a href="" + nextUrl + "">下一页 ");
-
创建对应tld文件
2.0
1.2
common
http://xingc.com.cn/common/
Common Tag
Common Tag library
page
com.xingc.example.utils.NavigationTag
JSP
create navigation for paging
bean
true
number
true
url
true
true
-
使用时,只需要引入 uri="http://xingc.com.cn/common/" 即可使用该标签
}
//显示当前页码的前2页码和后两页码
//若1 则 1 2 3 4 5, 若2 则 1 2 3 4 5, 若3 则1 2 3 4 5,
//若4 则 2 3 4 5 6 ,若10 则 8 9 10 11 12
int indexPage = (page.getPage() - 2 > 0)? page.getPage() - 2 : 1;
for(int i=1; i <= number && indexPage <= pageCount; indexPage++, i++) {
if(indexPage == page.getPage()) {
writer.print( "<li class="active"><a href="#">"+indexPage+"<span class="sr-only">(current)");
continue;
}
String pageUrl = append(url, "page", indexPage);
pageUrl = append(pageUrl, "rows", page.getSize());
writer.print("
}
//显示“下一页”按钮
if (page.getPage() < pageCount) {
String nextUrl = append(url, "page", page.getPage() + 1);
nextUrl = append(nextUrl, "rows", page.getSize());
writer.print("
} else {
writer.print("<li class="disabled"><a href="#">下一页");
}
writer.print("");
} catch (IOException e) {
e.printStackTrace();
}
return SKIP_BODY;
}
private String append(String url, String key, int value) {
return append(url, key, String.valueOf(value));
}
/**
* 为url 参加参数对儿
*
* @param url
* @param key
* @param value
* @return
*/
private String append(String url, String key, String value) {
if (url == null || url.trim().length() == 0) {
return "";
}
if (url.indexOf("?") == -1) {
url = url + "?" + key + "=" + value;
} else {
if(url.endsWith("?")) {
url = url + key + "=" + value;
} else {
url = url + "&" + key + "=" + value;
}
}
return url;
}
/**
* 为url 添加翻页请求参数
*
* @param url
* @param pageContext
* @return
* @throws javax.servlet.jsp.JspException
*/
private String resolveUrl(String url, javax.servlet.jsp.PageContext pageContext) throws JspException{
//UrlSupport.resolveUrl(url, context, pageContext)
Map params = pageContext.getRequest().getParameterMap();
for (Object key:params.keySet()) {
if ("page".equals(key) || "rows".equals(key)) continue;
Object value = params.get(key);
if (value == null) continue;
if (value.getClass().isArray()) {
url = append(url, key.toString(), ((String[])value)[0]);
} else if (value instanceof String) {
url = append(url, key.toString(), value.toString());
}
}
return url;
}
/**
* @return the bean
*/
public String getBean() {
return bean;
}
/**
* @param bean the bean to set
*/
public void setBean(String bean) {
this.bean = bean;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @param url the url to set
*/
public void setUrl(String url) {
this.url = url;
}
public void setNumber(int number) {
this.number = number;
}
}
JSP页面customer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
<%@ page trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="xingc" uri="http://xingc.com.cn/common/" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "😕/" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
客户管理
<c:forEach items="${page.rows}" var="row">
</c:forEach>
| ID | 客户名称 | 客户来源 | 客户所属行业 | 客户级别 | 固定电话 | 手机 | 操作 |
|---|---|---|---|---|---|---|---|
| ${row.cust_id} | ${row.cust_name} | ${row.cust_source} | ${row.cust_industry} | ${row.cust_level} | ${row.cust_phone} | ${row.cust_mobile} | 修改 删除 |
<itcast:page url="${pageContext.request.contextPath }/customer/list.action"/>
测试结果
访问http://localhost:8080/crmByssm/cust/getCustomerList

客户列表成功显示
说两句
我现在正在学ssm框架,水平不够,如果有什么bug,还请见谅,本来打算写一下条件查询和修改,删除等功能的,但到这里发现自己写了很多,就不赘述了.因为环境搭建好后,别的功能就相对简单一些.







浙公网安备 33010602011771号