Spring+MyBatis+SpringMvc整合Demo

客户关系管理系统demo

项目分析

该demo使用技术及环境:ssm+maven+bootstrap+jsp+mysql+idea+jdk1.8

需求:客户管理,实现客户列表分页显示如下图

项目开始

环境搭建

  1. 数据库环境:

    数据库与表:
    客户表

    字典表:[设计初衷 -- 将页面很多定义好且无需更改的字符串统一在字典表管理,优化数据库]

  2. 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


  1. 项目初始结构

  2. 项目三层建包结构和配置文件

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接口

分析:

  1. 列表显示,且列表需要分页
  2. 参数:当前页,每页显示
  3. 返回值 集合,泛型是QueryVo -- 该类封装客户端列表所需要的数据(客户表和字典表)
  4. 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 getCustomerList(QueryVo vo);
}

配置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 customerList = customerMapper.getCustomerList(vo);
System.out.println("\n+++结果数量: "+customerList.size());
System.out.println("\n+++结果显示: "+customerList);
}
}

  • 测试结果

  • 至此,mapper测试成功,开发基本完成[单一列表显示功能]

DAO层 end

Service层开发

在service/pom.xml中添加mapper层的jar依赖



com.xingc.example
mapper
1.0-SNAPSHOT

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 getCustomerList(QueryVo vo);
}

编写客户业务逻辑实现

//注意:使用该注解的前提是已经配置了 <context:component-scan base-package="com.xingc.example"/>

@Service("customerService")
public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerMapper customerMapper;

@Override
public List getCustomerList(QueryVo vo) {
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 customerList = customerService.getCustomerList(vo);
System.out.println("\n+++结果数量: " + customerList.size());
System.out.println("\n+++结果显示: " + customerList);
}
}

  • 结果

分页???

由于考虑到前端页面需要对客户列表进行分页,因此这里的业务逻辑需要修改

  • 添加分页实体

    public class Page {

    private int total;
    private int page;
    private int size;
    private List rows;
    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 List getRows() {
    return rows;
    }
    public void setRows(List rows) {
    this.rows = rows;
    }

    }

  • 修改后的实现类和接口

    public interface CustomerService {
    /**
    * 查询客户列表
    * @param vo 条件对象
    * @return 库户列表
    */
    public Page getCustomerList(QueryVo vo, Integer page, Integer rows);
    }

  • 实现

    @Service("customerService")
    public class CustomerServiceImpl implements CustomerService {
    @Autowired
    private CustomerMapper customerMapper;

    @Override
    public Page getCustomerList(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);

    //获得数据库查出来的对象
    List list = 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:annotation-driven/


<mvc:resources mapping="/css/" location="/css/"/>
<mvc:resources mapping="/js/
" location="/js/"/>
<mvc:resources mapping="/fonts/**" location="/fonts/"/>





web.xml配置


Archetype Created Web Application



contextConfigLocation
classpath:spring-.xml



org.springframework.web.context.ContextLoaderListener



springmvc
org.springframework.web.servlet.DispatcherServlet


contextConfigLocation
classpath*:springmvc.xml


springmvc
/

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 p = customerService.getCustomerList(vo, page, rows);
model.addAttribute("page",p);
return "customer";
}
}

测试

  • 说明:到这里,ssm配置及基本环境搭建完成,数据成功查出.列表显示后台部分完结,再看一下此时的项目结构

三层架构基本完成,开始前端jsp代码编写

JSP页面编写[jsp+bootstrap]

说明:在这里使用自定义标签的方式定义分页工具栏[和jstl标签是一个道理]

首先,创建jsp自定义标签,步骤如下

  1. 定义一个标签类

    /**
    * 显示格式 上一页 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("

  2. ");
    }
    //显示当前页码的前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("
  3. <a href="" + pageUrl + "">"+ indexPage +"
  4. ");
    }
    //显示“下一页”按钮
    if (page.getPage() < pageCount) {
    String nextUrl = append(url, "page", page.getPage() + 1);
    nextUrl = append(nextUrl, "rows", page.getSize());
    writer.print("
  5. <a href="" + nextUrl + "">下一页
  6. ");
    } 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;
    }

    }

  7. 创建对应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


  8. 使用时,只需要引入 uri="http://xingc.com.cn/common/" 即可使用该标签

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 + "/";
%>







客户列表-BootCRM













客户管理
































客户信息列表
















<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,还请见谅,本来打算写一下条件查询和修改,删除等功能的,但到这里发现自己写了很多,就不赘述了.因为环境搭建好后,别的功能就相对简单一些.

posted @ 2017-09-04 14:52  星尘h  阅读(251)  评论(0)    收藏  举报