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整合需要的包
<!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.3</version> </dependency> <!--spring和mybatis整合--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.1</version> </dependency> <!--驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> <scope>runtime</scope> </dependency> <!--连接池--> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency>
-
spring管理(已包含springmvc)
<properties> <spring.version>4.2.4.RELEASE</spring.version> <slf4j.version>1.6.6</slf4j.version> <log4j.version>1.2.12</log4j.version> </properties> <dependencies> <!-- spring ++start++ --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!-- springmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>
-
JSON相关
<!--json--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.4.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.4.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.4.2</version> </dependency>
-
日志相关
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency>
-
其他[如果使用idea开发,无自带的jstl标签库,需导入以下Jar坐标]
<dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!--jsp引入,后面自定义分页标签会使用--> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency>
-
tomcat插件
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <!-- 指定端口 --> <port>9090</port> <!-- 请求路径 --> <path>/autoErp</path> <!-- uri编码 --> <uriEncoding>utf-8</uriEncoding> </configuration> </plugin> </plugins> <!--注意!!!!!!!如果用的是IDEA开发,需配上该项,否则默认不会将mybatis的xml配置文件编译到target中--> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
-
项目初始结构
-
项目三层建包结构和配置文件
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
<?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>
</configuration>
编写 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<QueryVo> getCustomerList(QueryVo vo);
}
配置xml
<?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.xingc.example.mapper.CustomerMapper">
<select id="getCustomerList" parameterType="com.xingc.example.pojo.QueryVo"
resultType="com.xingc.example.pojo.QueryVo">
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
<where>
<if test="cust_name != null and cust_name != ''">
and c.custname LIKE '%${cust_name}%'
</if>
<if test="cust_source != null and cust_source != ''">
and cust_source = #{cust_source}
</if>
<if test="cust_industry != null and cust_industry != ''">
and cust_industry = #{cust_industry}
</if>
<if test="cust_level != null and cust_level != ''">
and cust_level = #{cust_level}
</if>
</where>
limit #{index},#{rows}
</select>
</mapper>
添加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文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!--开启注解-->
<context:component-scan base-package="com.xingc.example"/>
<!--引入外部配置propertis文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--数据库连接池,这里使用c3p0连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
</bean>
<!--spring来管理mybatis的session工厂-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
<!--使用包扫描即无需指定具体的xml文件,因此注释-->
<!--<property name="mapperLocations">
<array>
<value>com/xingc/example/mapper/CustomerMapper.xml</value>
</array>
</property>-->
</bean>
<!--包扫描,所有mapper,此时spring将会管理mapper根据xml生成对应的代理类,取代理对象只需要使用@Autowired注解即可-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xingc.example.mapper"></property>
</bean>
</beans>
测试走一波
@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<QueryVo> customerList = customerMapper.getCustomerList(vo);
System.out.println("\n+++结果数量: "+customerList.size());
System.out.println("\n+++结果显示: "+customerList);
}
}
-
测试结果
-
至此,mapper测试成功,开发基本完成[单一列表显示功能]
DAO层 end
Service层开发
在service/pom.xml中添加mapper层的jar依赖
<dependencies>
<dependency>
<groupId>com.xingc.example</groupId>
<artifactId>mapper</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
module结构
编写spring-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!--需要配置的内容:事务[如果使用注解式申明事务,完全可以省略该配置,只需在需要事务的类或方法中配置@Transactional即可]-->
<!--事务管理bean-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--前提是将mapper层的spring-mapper.xml也一起加载,否则该连接池无法使用,[web.xml中需同时加载spring-mapper.xml文件]-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务-->
<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>
</beans>
编写客户业务逻辑接口
public interface CustomerService {
/**
* 查询客户列表
* @param vo 条件对象
* @return 库户列表
*/
public List<QueryVo> 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<QueryVo> 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<QueryVo> customerList = customerService.getCustomerList(vo);
System.out.println("\n+++结果数量: " + customerList.size());
System.out.println("\n+++结果显示: " + customerList);
}
}
-
结果
分页???
由于考虑到前端页面需要对客户列表进行分页,因此这里的业务逻辑需要修改
-
添加分页实体
public class Page<T> { private int total; private int page; private int size; private List<T> 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<T> getRows() { return rows; } public void setRows(List<T> rows) { this.rows = rows; } }
-
修改后的实现类和接口
public interface CustomerService { /** * 查询客户列表 * @param vo 条件对象 * @return 库户列表 */ public Page<Customer> getCustomerList(QueryVo vo, Integer page, Integer rows); }
-
实现
@Service("customerService") public class CustomerServiceImpl implements CustomerService { @Autowired private CustomerMapper customerMapper; @Override public Page<Customer> 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<QueryVo> list = customerMapper.getCustomerList(vo); //循环封装 Page p = new Page(); p.setPage(page); p.setSize(rows); //总条数 int total = customerMapper.getCount(vo); p.setTotal(total); List<Customer> 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配置
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!--开启注解-->
<context:component-scan base-package="com.xingc.example"/>
<!--默认使用springmvc的各种映射器/适配器等-->
<mvc:annotation-driven/>
<!--静态资源映射-->
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/fonts/**" location="/fonts/"/>
<!--试图解析器配置[解析xontroller的逻辑视图为物理视图,就是去哪里找jsp]-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
web.xml配置
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--spring-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-*.xml</param-value>
</context-param>
<!--监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--springmvc-->
<servlet>
<servlet-name>springmvc</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>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
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<Customer> p = customerService.getCustomerList(vo, page, rows);
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<E> 对象的变量名,默认为“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("<nav><ul class=\"pagination\">"); //显示“上一页”按钮 if (page.getPage() > 1) { String preUrl = append(url, "page", page.getPage() - 1); preUrl = append(preUrl, "rows", page.getSize()); writer.print("<li><a href=\"" + preUrl + "\">上一页</a></li>"); } else { writer.print("<li class=\"disabled\"><a href=\"#\">上一页</a></li>"); } //显示当前页码的前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)</span></a></li>"); continue; } String pageUrl = append(url, "page", indexPage); pageUrl = append(pageUrl, "rows", page.getSize()); writer.print("<li><a href=\"" + pageUrl + "\">"+ indexPage +"</a></li>"); } //显示“下一页”按钮 if (page.getPage() < pageCount) { String nextUrl = append(url, "page", page.getPage() + 1); nextUrl = append(nextUrl, "rows", page.getSize()); writer.print("<li><a href=\"" + nextUrl + "\">下一页</a></li>"); } else { writer.print("<li class=\"disabled\"><a href=\"#\">下一页</a></li>"); } writer.print("</nav>"); } 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; } }
-
创建对应tld文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>2.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>common</short-name> <uri>http://xingc.com.cn/common/</uri> <display-name>Common Tag</display-name> <description>Common Tag library</description> <tag> <name>page</name> <tag-class>com.xingc.example.utils.NavigationTag</tag-class> <body-content>JSP</body-content> <description>create navigation for paging</description> <attribute> <name>bean</name> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>number</name> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>url</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
-
使用时,只需要引入 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 + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>客户列表-BootCRM</title>
<!-- Bootstrap Core CSS -->
<link href="<%=basePath%>css/bootstrap.min.css" rel="stylesheet">
<!-- MetisMenu CSS -->
<link href="<%=basePath%>css/metisMenu.min.css" rel="stylesheet">
<!-- DataTables CSS -->
<link href="<%=basePath%>css/dataTables.bootstrap.css" rel="stylesheet">
<!-- Custom CSS -->
<link href="<%=basePath%>css/sb-admin-2.css" rel="stylesheet">
<!-- Custom Fonts -->
<link href="<%=basePath%>css/font-awesome.min.css" rel="stylesheet"
type="text/css">
<link href="<%=basePath%>css/boot-crm.css" rel="stylesheet"
type="text/css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div id="wrapper">
<!-- Navigation -->
<nav class="navbar navbar-default navbar-static-top" role="navigation"
style="margin-bottom: 0">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse"
data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">BOOT客户管理系统 v2.0</a>
</div>
<!-- /.navbar-header -->
<ul class="nav navbar-top-links navbar-right">
<li class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" href="#"> <i class="fa fa-envelope fa-fw"></i>
<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-messages">
<li><a href="#">
<div>
<strong>令狐冲</strong> <span class="pull-right text-muted">
<em>昨天</em>
</span>
</div>
<div>今天晚上向大哥找我吃饭,讨论一下去梅庄的事...</div>
</a></li>
<li class="divider"></li>
<li><a class="text-center" href="#"> <strong>查看全部消息</strong>
<i class="fa fa-angle-right"></i>
</a></li>
</ul> <!-- /.dropdown-messages --></li>
<!-- /.dropdown -->
<li class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" href="#"> <i class="fa fa-tasks fa-fw"></i>
<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-tasks">
<li><a href="#">
<div>
<p>
<strong>任务 1</strong> <span class="pull-right text-muted">完成40%</span>
</p>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-success"
role="progressbar" aria-valuenow="40" aria-valuemin="0"
aria-valuemax="100" style="width: 40%">
<span class="sr-only">完成40%</span>
</div>
</div>
</div>
</a></li>
<li class="divider"></li>
<li><a href="#">
<div>
<p>
<strong>任务 2</strong> <span class="pull-right text-muted">完成20%</span>
</p>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" role="progressbar"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"
style="width: 20%">
<span class="sr-only">完成20%</span>
</div>
</div>
</div>
</a></li>
<li class="divider"></li>
<li><a class="text-center" href="#"> <strong>查看所有任务</strong>
<i class="fa fa-angle-right"></i>
</a></li>
</ul> <!-- /.dropdown-tasks --></li>
<!-- /.dropdown -->
<li class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" href="#"> <i class="fa fa-bell fa-fw"></i>
<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-alerts">
<li><a href="#">
<div>
<i class="fa fa-comment fa-fw"></i> 新回复 <span
class="pull-right text-muted small">4分钟之前</span>
</div>
</a></li>
<li class="divider"></li>
<li><a href="#">
<div>
<i class="fa fa-envelope fa-fw"></i> 新消息 <span
class="pull-right text-muted small">4分钟之前</span>
</div>
</a></li>
<li class="divider"></li>
<li><a href="#">
<div>
<i class="fa fa-tasks fa-fw"></i> 新任务 <span
class="pull-right text-muted small">4分钟之前</span>
</div>
</a></li>
<li class="divider"></li>
<li><a href="#">
<div>
<i class="fa fa-upload fa-fw"></i> 服务器重启 <span
class="pull-right text-muted small">4分钟之前</span>
</div>
</a></li>
<li class="divider"></li>
<li><a class="text-center" href="#"> <strong>查看所有提醒</strong>
<i class="fa fa-angle-right"></i>
</a></li>
</ul> <!-- /.dropdown-alerts --></li>
<!-- /.dropdown -->
<li class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" href="#"> <i class="fa fa-user fa-fw"></i>
<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#"><i class="fa fa-user fa-fw"></i> 用户设置</a></li>
<li><a href="#"><i class="fa fa-gear fa-fw"></i> 系统设置</a></li>
<li class="divider"></li>
<li><a href="login.html"><i class="fa fa-sign-out fa-fw"></i>
退出登录</a></li>
</ul> <!-- /.dropdown-user --></li>
<!-- /.dropdown -->
</ul>
<!-- /.navbar-top-links -->
<div class="navbar-default sidebar" role="navigation">
<div class="sidebar-nav navbar-collapse">
<ul class="nav" id="side-menu">
<li class="sidebar-search">
<div class="input-group custom-search-form">
<input type="text" class="form-control" placeholder="查询内容...">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<i class="fa fa-search" style="padding: 3px 0 3px 0;"></i>
</button>
</span>
</div> <!-- /input-group -->
</li>
<li><a href="customer.action" class="active"><i
class="fa fa-edit fa-fw"></i> 客户管理</a></li>
<li><a href="salevisit.action"><i
class="fa fa-dashboard fa-fw"></i> 客户拜访</a></li>
</ul>
</div>
<!-- /.sidebar-collapse -->
</div>
<!-- /.navbar-static-side --> </nav>
<div id="page-wrapper">
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">客户管理</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="panel panel-default">
<div class="panel-body">
<form class="form-inline" action="${pageContext.request.contextPath }/customer/list.action"
method="get">
<div class="form-group">
<label for="customerName">客户名称</label>
<input type="text" class="form-control" id="customerName" value="${custName }" name="custName">
</div>
<div class="form-group">
<label for="customerFrom">客户来源</label>
<select class="form-control" id="customerFrom" placeholder="客户来源" name="custSource">
<option value="">--请选择--</option>
<c:forEach items="${fromType}" var="item">
<option value="${item.dict_id}"<c:if
test="${item.dict_id == custSource}"> selected</c:if>>${item.dict_item_name }</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<label for="custIndustry">所属行业</label>
<select class="form-control" id="custIndustry" name="custIndustry">
<option value="">--请选择--</option>
<c:forEach items="${industryType}" var="item">
<option value="${item.dict_id}"<c:if
test="${item.dict_id == custIndustry}"> selected</c:if>>${item.dict_item_name }</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<label for="custLevel">客户级别</label>
<select class="form-control" id="custLevel" name="custLevel">
<option value="">--请选择--</option>
<c:forEach items="${levelType}" var="item">
<option value="${item.dict_id}"<c:if
test="${item.dict_id == custLevel}"> selected</c:if>>${item.dict_item_name }</option>
</c:forEach>
</select>
</div>
<button type="submit" class="btn btn-primary">查询</button>
</form>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">客户信息列表</div>
<!-- /.panel-heading -->
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>ID</th>
<th>客户名称</th>
<th>客户来源</th>
<th>客户所属行业</th>
<th>客户级别</th>
<th>固定电话</th>
<th>手机</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${page.rows}" var="row">
<tr>
<td>${row.cust_id}</td>
<td>${row.cust_name}</td>
<td>${row.cust_source}</td>
<td>${row.cust_industry}</td>
<td>${row.cust_level}</td>
<td>${row.cust_phone}</td>
<td>${row.cust_mobile}</td>
<td>
<a href="#" class="btn btn-primary btn-xs" data-toggle="modal"
data-target="#customerEditDialog" onclick="editCustomer(${row.cust_id})">修改</a>
<a href="#" class="btn btn-danger btn-xs" onclick="deleteCustomer(${row.cust_id})">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="col-md-12 text-right">
<itcast:page url="${pageContext.request.contextPath }/customer/list.action"/>
</div>
<!-- /.panel-body -->
</div>
<!-- /.panel -->
</div>
<!-- /.col-lg-12 -->
</div>
</div>
<!-- /#page-wrapper -->
</div>
<!-- 客户编辑对话框 -->
<div class="modal fade" id="customerEditDialog" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">修改客户信息</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id="edit_customer_form">
<input type="hidden" id="edit_cust_id" name="cust_id"/>
<div class="form-group">
<label for="edit_customerName" class="col-sm-2 control-label">客户名称</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="edit_customerName" placeholder="客户名称"
name="cust_name">
</div>
</div>
<div class="form-group">
<label for="edit_customerFrom" style="float:left;padding:7px 15px 0 27px;">客户来源</label>
<div class="col-sm-10">
<select class="form-control" id="edit_customerFrom" placeholder="客户来源" name="cust_source">
<option value="">--请选择--</option>
<c:forEach items="${fromType}" var="item">
<option value="${item.dict_id}"<c:if
test="${item.dict_id == custSource}"> selected</c:if>>${item.dict_item_name }</option>
</c:forEach>
</select>
</div>
</div>
<div class="form-group">
<label for="edit_custIndustry" style="float:left;padding:7px 15px 0 27px;">所属行业</label>
<div class="col-sm-10">
<select class="form-control" id="edit_custIndustry" name="cust_industry">
<option value="">--请选择--</option>
<c:forEach items="${industryType}" var="item">
<option value="${item.dict_id}"<c:if
test="${item.dict_id == custIndustry}"> selected</c:if>>${item.dict_item_name }</option>
</c:forEach>
</select>
</div>
</div>
<div class="form-group">
<label for="edit_custLevel" style="float:left;padding:7px 15px 0 27px;">客户级别</label>
<div class="col-sm-10">
<select class="form-control" id="edit_custLevel" name="cust_level">
<option value="">--请选择--</option>
<c:forEach items="${levelType}" var="item">
<option value="${item.dict_id}"<c:if
test="${item.dict_id == custLevel}"> selected</c:if>>${item.dict_item_name }</option>
</c:forEach>
</select>
</div>
</div>
<div class="form-group">
<label for="edit_linkMan" class="col-sm-2 control-label">联系人</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="edit_linkMan" placeholder="联系人"
name="cust_linkman">
</div>
</div>
<div class="form-group">
<label for="edit_phone" class="col-sm-2 control-label">固定电话</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="edit_phone" placeholder="固定电话"
name="cust_phone">
</div>
</div>
<div class="form-group">
<label for="edit_mobile" class="col-sm-2 control-label">移动电话</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="edit_mobile" placeholder="移动电话"
name="cust_mobile">
</div>
</div>
<div class="form-group">
<label for="edit_zipcode" class="col-sm-2 control-label">邮政编码</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="edit_zipcode" placeholder="邮政编码"
name="cust_zipcode">
</div>
</div>
<div class="form-group">
<label for="edit_address" class="col-sm-2 control-label">联系地址</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="edit_address" placeholder="联系地址"
name="cust_address">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" onclick="updateCustomer()">保存修改</button>
</div>
</div>
</div>
</div>
<!-- /#wrapper -->
<!-- jQuery -->
<script src="<%=basePath%>js/jquery.min.js"></script>
<!-- Bootstrap Core JavaScript -->
<script src="<%=basePath%>js/bootstrap.min.js"></script>
<!-- Metis Menu Plugin JavaScript -->
<script src="<%=basePath%>js/metisMenu.min.js"></script>
<!-- DataTables JavaScript -->
<script src="<%=basePath%>js/jquery.dataTables.min.js"></script>
<script src="<%=basePath%>js/dataTables.bootstrap.min.js"></script>
<!-- Custom Theme JavaScript -->
<script src="<%=basePath%>js/sb-admin-2.js"></script>
<script type="text/javascript">
function editCustomer(id) {
$.ajax({
type: "get",
url: "<%=basePath%>customer/edit.action",
data: {"id": id},
success: function (data) {
$("#edit_cust_id").val(data.cust_id);
$("#edit_customerName").val(data.cust_name);
$("#edit_customerFrom").val(data.cust_source)
$("#edit_custIndustry").val(data.cust_industry)
$("#edit_custLevel").val(data.cust_level)
$("#edit_linkMan").val(data.cust_linkman);
$("#edit_phone").val(data.cust_phone);
$("#edit_mobile").val(data.cust_mobile);
$("#edit_zipcode").val(data.cust_zipcode);
$("#edit_address").val(data.cust_address);
}
});
}
function updateCustomer() {
$.post("<%=basePath%>customer/update.action", $("#edit_customer_form").serialize(), function (data) {
alert("客户信息更新成功!");
window.location.reload();
});
}
function deleteCustomer(id) {
if (confirm('确实要删除该客户吗?')) {
$.post("<%=basePath%>customer/delete.action", {"id": id}, function (data) {
alert("客户删除更新成功!");
window.location.reload();
});
}
}
</script>
</body>
</html>
测试结果
访问http://localhost:8080/crmByssm/cust/getCustomerList
客户列表成功显示
说两句
我现在正在学ssm框架,水平不够,如果有什么bug,还请见谅,本来打算写一下条件查询和修改,删除等功能的,但到这里发现自己写了很多,就不赘述了.因为环境搭建好后,别的功能就相对简单一些.