2020-06-9 SSM 黑马BOOT客户管理系统 -2017040632

1.数据库设计

1.1系统用户表

1-1系统用户表.png

1.2客户信息表

1-2系统用户表.png

1.3数据字典表

1-3数据字典表.png

2.系统环境搭建

2.1准备需要的JAR包

由于本系统使用的是SSM框架开发,因此需要准备这三大框架的JAR包。除此之外,项目中还涉及数据库连接、JSTL标签等,所以还要准备其他JAR包。整个系统所需要准备的JAR共计35个,具体如下所示。
1.Spring框架所需的JAR包(10个)
主要包括4个核心??镴AR, AOP开发使用的JAR, JDBC和事务的JAR。
· aopalliance-1.0.jar
· aspectjweaver-1.8.10.jar
· spring-aop-4.3.6.RELEASE.jar
· spring-aspects-4.3.6.RELEASE.jar
· spring-beans-4.3.6.RELEASE.jar
· spring-context-4.3.6.RELEASE.jar
· spring-core-4.3.6.RELEASE.jar
· spring-expression-4.3.6.RELEASE.jar
· spring-jdbc-4.3.6.RELEASE.jar
· spring-tx-4.3.6.RELEASE.jar
2.Spring MVC框架所需要的JAR包(2个)
· spring-web-4.3.6.RELEASE.jar
· spring-webmvc-4.3.6.RELEASE.jar
3.MyBatis框架所需的JAR包(13个)主要包括核心包mybatis-3.4.2.jar,以及其解压文件夹中lib目录下的所有JAR。
· ant-1.9.6.jar
· ant-launcher-1.9.6.jar
· asm-5.1.jar· cglib-3.2.4.jar
· commons-logging-1.2.jar
· javassist-3.21.0-GA.jar
· log4j-1.2.17.jar
· log4j-api-2.3.jar
· log4j-core-2.3.jar
· mybatis-3.4.2.jar
· ognl-3.1.12.jar
· slf4j-api-1.7.22.jar
· slf4j-log4j12-1.7.22.jar
4.MyBatis与Spring整合的中间JAR(1个)
· mybatis-spring-1.3.1.jar
5.数据库驱动JAR包(1个)
· mysql-connector-java-5.1.40-bin.jar
6.数据源dbcp所需JAR包(2个)
· commons-dbcp2-2.1.1.jar
· commons-pool2-2.4.2.jar
7.JSTL标签库JAR包(2个)
· taglibs-standard-impl-1.2.5.jar
· taglibs-standard-spec-1.2.5.jar
8.Jackson框架所需JAR包(3个)
· jackson-annotations-2.8.6.jar
· jackson-core-2.8.6.jar
· jackson-databind-2.8.6.jar
9.Java工具类JAR(1个)
· commons-lang3-3.4.jar

2.2准备数据库资源

方法一:
(1)创建数据库。
create database boot_crm;
(2)选择所创建的数据库。
use boot_crm;
(3)导入数据库文件,这里假设该文件在C盘的根目录下,其导入命令如下。
source C:\boot_crm.sql;
方法二:
通过Navicat软件导入sql文件,创建boot_crm数据库,执行sql

3.3准备项目环境

1创建项目,引入JAR包

在Eclipse中,创建一个名称为boot-crm的Web项目,将系统所准备的全部JAR包复制到项目的lib目录中,并发布到类路径下。

2编写配置文件

(1)在项目目录下创建一个源文件夹config,并在config文件夹下分别创建数据库常量配置文件、Spring配置文件、MyBatis配置文件、log4j配置文件、资源配置文件以及Spring MVC配置文件。

mybatis-config.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>

    <!-- 别名 -->
    <typeAlises>
        <package name="com.itheima.core.pojo"/>
    </typeAlises>    
    
</configuration>

jdbc.properties(配置数据库信息)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/crm?characterEncoding=utf-8
jdbc.username=root (ZPS)
jdbc.password=root (123456)

log4j.properties(配置日志信息)

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# 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

applicationContext.xml
(需要配置:加载properties文件,数据源,SqlSessionFactory,Mapper扫描)

<?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.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 配置 读取properties文件 jdbc.properties -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!-- 配置 数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!-- 数据库驱动 -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <!-- 连接数据库的url -->
        <property name="url" value="${jdbc.url}" />
        <!-- 连接数据库的用户名 -->
        <property name="username" value="${jdbc.username}" />
        <!-- 连接数据库的密码 -->
        <property name="password" value="${jdbc.password}" />
    </bean>
    
    <!-- 配置Mybatis的工厂 SqlSessionFactory -->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 设置MyBatis核心配置文件所在位置 -->
        <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
        <!-- 设置数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    
        <!-- 事务管理器 -->
    <bean id="transactionManager"   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 传播行为 -->
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="query*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>

    <!-- 切面 -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice"
            pointcut="execution(* cn.itcast.crm.service.*.*(..))" />
    </aop:config>
    
        <!-- 配置Mapper扫描 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 设置Mapper扫描包 -->
        <property name="basePackage" value="com.itheima.crm.mapper" />
    </bean>
    
    <!-- 配置Service扫描 -->
    <context:component-scan base-package="com.itheima.crm.service" />
    
</beans>

resource.properties

#客户来源
CUSTOMER_FROM_TYPE=002
#客户行业
CUSTOMER_INDUSTRY_TYPE=001
#客户级别
CUSTOMER_LEVEL_TYPE=006

上述配置代码分别表示客户来源、所属行业和客户级别,其值对应的是数据字典表中dict_type_code字段的值。

springmvc-config.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:p="http://www.springframework.org/schema/p"
    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.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    <!-- 配置Controller扫描 -->
    <context:component-scan base-package="com.itheima.crm.controller" />
    
    <!-- 加载屬性文件 controller需要的配置信息 -->
    <context:property-placeholder location="classpath:resource.properties" />

    <!-- 配置注解驱动:处理器映射器和适配器-->
    <mvc:annotation-driven />
    
    <!-- 对静态资源放行,此配置中的文件,将不被前端控制器拦截-->
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/js/" mapping="/js/**"/>
    <mvc:resources location="/fonts/" mapping="/fonts/**"/>
    
    <!-- 另外一种方式 解决静态资源无法被springMVC处理的问题 -->
    <mvc:default-servlet-handler />


    <!-- 配置视图解析器 -->
    <bean   class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/" />
        <!-- 后缀 -->
        <property name="suffix" value=".jsp" />
    </bean>
    
</beans>

上述代码除配置了需要扫描的包、注解驱动和视图解析器外,还增加了加载属性文件和访问静态资源的配置。

(2)web.xml配置

配置Spring的监听器、编码过滤器和SpringMVC的前端控制器等信息

<?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"
    id="WebApp_ID" version="2.5">
    <display-name>ssm</display-name>
    <!-- 系统默认页面-->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <!-- 配置spring -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/applicationContext.xml</param-value>
    </context-param>

    <!-- 配置监听器加载spring -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 配置编码过滤器,解决post的乱码问题 -->
    <filter>
        <filter-name>encoding</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>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置SpringMVC前端核心控制器 -->
    <servlet>
        <servlet-name>crm</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
        <!-- 配置springmvc什么时候启动,参数必须为整数 -->
        <!-- 如果为0或者大于0,则springMVC随着容器启动而启动 -->
        <!-- 如果小于0,则在第一次请求进来的时候启动 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>crm</servlet-name>
        <!-- 所有的请求都进入springMVC -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

3.引入页面资源将项目运行所需要的CSS文件、字体、图片、JS、自定义标签文件和JSP文件按照图2-1中的结构引入到项目中。

2-1项目结构图.png

以上步骤完成对于环境的搭建,访问http://localhost:8080/boot-crm/index.jsp进行测试验证,图2-2为项目首页。

2-2 项目首页.png

3 用户登录???/h2>

BOOT客户管理系统用户登录功能的实现流程如图4-1所示。


图4-1.png

可以看出,用户登录过程中首先要验证用户名和密码是否正确,如果正确,可以成功登录系统,系统会自动跳转到主页;如果错误,则在登录页面给出错误提示信息给用户。

实现的具体步骤如下:
1创建持久化类
在src目录下,创建一个com.itheima.crm. pojo包,在包中创建用户持久化类User,并在User类中定义用户相关属性以及相应的getter/setter方法。

User.java

package com.itheima.core.pojo;
import java.io.Serializable;
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer user_id; // 用户id
    private String user_code; // 用户账户
    private String user_name; // 用户名称
    private String use_password; // 用户密码
    // getter/setter方法
}

2实现DAO
(1)创建用户DAO层接口。在src目录下,创建一个com.itheima.crm.dao包,在包中创建一个用户接口UserDao,并在接口中编写通过账号和密码查询用户的方法。

UserDao.java

public interface UserDao {
   
   /**
    * 通过账户和密码查询用户
    * @param usercode
    * @param password
    * @return
    */
   public User findUser(@Param("usercode") String usercode,@Param("password")String password);
}

在上述方法代码的参数中,@Param("usercode")表示为参数usercode命名,命名后,在映射文件的SQL中,使用#{usercode}就可以获取usercode的参数值。

(2)创建映射文件。
在com.itheima.core.dao包中,创建一个MyBatis映射文件UserDao.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.itheima.core.dao.UserDao">
    <!-- 查询用户 -->
    <select id="findUser" parameterType="String" resultType="User">
        select * 
        from sys_user
        where user_code = #{usercode}
        and user_password = #{password}
        and user_state = '1'
    </select>
</mapper>

上述代码通过映射查询语句来查询系统用户表中的可用用户。

3实现Service
(1)创建用户Service层接口。
在src目录下,创建一个com.itheima.core.service包,在包中创建UserService接口,并在该接口中编写一个通过账号和密码查询用户的方法。

UserService.java

public interface UserService {
    /**
     * 通过账号和密码查询用户
     * @param usercode
     * @param password
     * @return
     */
    public User findUser(String usercode,String password);
}

2)创建用户Service层接口的实现类。
在src目录下,创建一个com.itheima.core.service. impl包,并在包中创建UserService接口的实现类UserServiceImpl,在类中编辑并实现接口中的方法。

UserServiceImpl.java

@Service
@Transactional
public class UserServiceImpl implements UserService {
    // 注入Userdao
    @Autowired
    private UserDao userdao;    
    @Override
    public User findUser(String usercode, String password) {
        User user=this.userdao.findUser(usercode, password);
        return user;
    }
}

在上述代码的findUser()方法中,调用了UserDao对象中的findUser()方法来查询用户信息,并将查询到的信息返回。

4实现Controller

在src目录下,创建一个com.itheima.core.web.controller包,在包中创建用户控制器类UserController。

UserController.java

public class UserController {

    @Autowired
    private UserService userService;
    
    /**
     * 用户登录
     * @param usercode
     * @param password
     * @param model
     * @param session
     * @return
     */
    @RequestMapping(value="/login",method=RequestMethod.POST)
    public String login(String usercode,String password,Model model,HttpSession session) {
        
        User user= userService.findUser(usercode,password);
        
        if(user!=null) {
            //将用户对象添加到Session
            session.setAttribute("USER_SESSION", user);
            // 跳转到主页面
            return "customer";
        }
        model.addAttribute("msg", "账号或密码错误,请重新登录!");
        // 返回到登录页面
        return "login";             
    }
}

上述,首先通过@Autowired注解将UserService对象注入到了本类中,然后创建了一个用于用户登录的login()方法。由于在用户登录时,表单都会以POST方式提交,所以将@RequestMapping注解的method属性值设置为RequestMethod.POST。在login()方法中,首先通过页面中传递过来的账号和密码查询用户,然后通过if语句判断是否存在该用户。如果存在,就将用户信息存储到Session中,并跳转到系统主页面;如果不存在,则提示错误信息,并返回到登录页面。

5实现页面功能
(1)系统默认首页index.jsp主要实现了一个转发功能,在访问时会转发到登录页面。

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
  <!-- 转发到登录页面 -->
  <jsp:forward page="/WEB-INF/jsp/login.jsp"></jsp:forward>
</body>
</html>

(2)登录页面中,主要包含一个登录表单。

login.jsp

核心代码是用户登录操作的form表单,该表单在提交时会通过check()方法检查账户或密码是否为空,如果为空,则通过标签提示用户“账号或密码不能为空!”;如果账号和密码都已填写,则将表单提交到以“/login.action”结尾的请求中。

6启动项目,测试登录
将项目发布到Tomcat服务器并启动,成功访问登录页面后,即可输入账号和密码登录系统。在执行登录操作之前,先查看一下数据库中sys_user表中的数据。

图6-1.png

表sys_user中包含4个账号(user_code)以m开头的用户信息。此时在登录页面中输入账号“m0001”和密码“123”,单击“登录”按钮后,浏览器的显示结果如图6-2所示。


图6-2.png

4.2 实现登录验证

虽然在上文已经实现了用户登录功能,但是此功能还并不完善。假设在其他控制器类中也包含一个访问客户管理页面的方法,那么用户完全可以绕过登录步骤,而直接通过访问该方法的方式进入客户管理页面。为了验证上述内容,我们可以在用户控制器类UserController中编写一个跳转到客户管理页面的方法,其代码如下所示。

    /**
     * 模拟其他类中跳转到客户管理页面的方法
     * @return
     */
    @RequestMapping(value="/toCustomer.action")
    public String toCustomer() {
        return "customer";

    }

此时,如果通过浏览器访问地址http://localhost:8080/boot-crm/toCustomer.action,浏览器就会直接显示客户管理页面

显然,让未登录的用户直接访问到客户管理页面,是十分不安全的。为了避免此种情况的发生,并提升系统的安全性,我们可以创建一个登录拦截器来拦截所有请求。只有已登录用户的请求才能够通过,而对于未登录用户的请求,系统会将请求转发到登录页面,并提示用户登录,其执行流程如图6-3所示。


图6-3.png

实现用户登录验证的具体过程如下。

LoginInterceptor.java

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
        
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求的URL
        String url=request.getRequestURI();
        // URL:除了登录请求外,其他的URL都进行拦截控制
        if(url.indexOf("/login.action")>=0) {
            return true;
        }
        // 获取session
        HttpSession session = request.getSession();
        User user = (User)session.getAttribute("USER_SESSION");
        // 判断Session中是否有用户数据,如果有,则返回true,继续向下执行
        if(user!=null) {
            return true;
        }
        // 不符合条件的给出提示信息,并转发到登录页面
        request.setAttribute("msg", "您还没有登录,请先登录!");
        request.getRequestDispatcher("/WEB_INF/jsp/login.jsp").forward(request, response);
        return false;
    }
}

在preHandle()方法中,首先获取了用户URL请求,然后通过请求来判断是否为用户登录操作,只有对用户登录的请求才不进行拦截。接下来获取了Session对象,并获取Session中的用户信息。如果Session中的用户信息不为空,则表示用户已经登录,拦截器将放行;如果Session中的用户信息为空,则表示用户未登录,系统会转发到登录页面,并提示用户登录。

2配置拦截器
在springmvc-config.xml文件中,配置登录拦截器信息,其配置代码如下。

<!-- 配置拦截器 -->
<mvc:interceptors>
  <mvc:interceptor>
      <mvc:mapping path="/**"/>
      <bean class="com.itheima.core.interceptor.LoginInterceptor"/>       
  </mvc:interceptor>  
</mvc:interceptors>

上述配置代码会将所有的用户请求都交由登录拦截器来处理。至此,登录拦截器的实现工作就已经完成。

发布项目并启动Tomcat服务器后,再次通过浏览器访问地址http://localhost:8080/boot-crm/toCustomer.action时,浏览器的显示结果如图6-4所示。

图6-4.png

从图6-4可以看出,未登录的用户在执行访问客户管理页面方法后,并没有成功跳转到客户管理页面,而是转发到了系统登录页面,同时在页面的登录窗口中也给出了提示信息。这也就说明用户登录验证功能已成功实现。

4.3退出登录
用户登录模块中还包含一个功能——退出登录。成功登录后的用户会跳转到客户管理页面,并且在页面中会显示已登录的用户名称,如图6-5所示。

图6-5.png

实现“退出登录”功能

customer.jsp

            <ul class="dropdown-menu dropdown-user">
                <li><a href="#"><i class="fa fa-user fa-fw"></i>
                               用户:${USER_SESSION.user_name}
                    </a>
                </li>
                <li><a href="#"><i class="fa fa-gear fa-fw"></i> 系统设置</a></li>
                <li class="divider"></li>
                <li>
                    <a href="${pageContext.request.contextPath }/logout.action">
                    <i class="fa fa-sign-out fa-fw"></i>退出登录
                    </a>
                </li>
            </ul>

从上述代码中可以看出,显示的登录用户名称是通过EL表达式从Session中获取的,而单击“退出登录”链接时,会提交一个以“/logout.action”结尾的请求。为了完成退出登录功能,我们需要在用户控制器类中编写一个退出登录的方法。在方法执行时,需要清除Session中的用户信息,并且在退出登录后,系统要返回到登录页面。因此,需要在用户控制器类UserController中编写退出登录和返回到登录页面的方法,这两个方法的实现代码如下。

    /**
     * 退出登录
     * @param session
     * @return
     */
    @RequestMapping(value="/logout.action")
    public String logout(HttpSession session) {
        // 清除Session
        session.invalidate();
        // 重定向到登录页面的跳转方法
        return "redirect:login.action";
    }
    /**
     * 向用户登录页面跳转
     * @return
     */
@RequestMapping(value="/logout.action",method= RequestMethod.GET)
    public String tologin() {
        return "login";
    }

至此,“退出登录”的功能代码就已经编写完成。重启项目并登录系统后,单击图6-5中的“退出登录”即可退出系统。

5客户管理???/h2>

客户管理??槭潜鞠低车暮诵哪??,该??橹惺迪至硕钥突У牟檠?、添加、修改和下文将对这几个功能的实现进行详细讲解。

5.1 查询客户
在实际应用中,无论是企业级项目,还是互联网项目,使用最多的一定是查询操作。不管是在列表中展示所有数据的操作,还是对单个数据的修改或者删除操作,都需要先查询并展示出数据库中的数据。

查询操作通??梢苑治刺跫檠筒檠?,但在实际使用时,我们可以将这两种查询编写在一个方法中使用,即当有条件时,就按照条件查询;当没有条件时,就查询所有。同时,由于数据库中的数据可能有很多,如果让这些数据在一个页面中全部显示出来,势必会使页面数据的可读性变得很差,所以我们还需要考虑将这些数据进行分页查询显示。

综合上述分析以及客户页面的显示功能,BOOT客户管理系统的查询功能需要实现的功能如图5-1所示。


图5-1.png

从图5-1可以看出,客户管理模块中的查询可分为按照条件查询和分页查询,这两种查询操作所查询出的数据都会显示在客户信息列表中。如果未选择任何条件,那么客户信息列表将分页查询显示出所有数据。

实现客户的条件查询和分页查询
分析:
前台发起请求,需要接收请求过来的查询条件数据,可以使用pojo接收数据,编写QueryVo,里面包含查询条件属性和分页数据。
前台需要分页显示,根据准备好的分页实现,应该返回分页类Page,而创建Page分页类需要数据总条数,所以也需要查询数据总条数的逻辑。
根据分析,DAO需要编写两个方法:

需要根据条件分页查询客户信息
需要根据条件查询数据总条数

1创建持久化类
在com.itheima.core.pojo包中,创建客户持久化类、数据字典持久化类、查询条件包装类。

Customer.java

public class Customer implements Serializable{
   private static final long serialVersionUID = 1L;    
   private Long cust_id;// 客户编号
   private String cust_name;// 客户名称
   private Long cust_user_id;// 负责人id
   private Long cust_create_id;// 创建人id
   private String cust_source;// 客户信息来源
   private String cust_industry;// 客户所属行业
   private String cust_level;// 客户级别
   private String cust_linkman;// 联系人
   private String cust_phone;// 固定电话
   private String cust_mobile;// 移动电话 
   private String cust_zipcode;// 邮政编码
   private String cust_address;// 联系地址
   private Date cust_createtime;// 创建时间
   //getter setter方法
}

上文声明了与客户数据表对应的属性并定义了各个属性的getter/setter方法。

BaseDict.java

public class BaseDict implements Serializable {
    
    private static final long serialVersionUID = 1L;
    private String dict_id;// 数据字典id
    private String dict_type_code;// 数据字典类别代码
    private String dict_type_name;// 数据字典类别名称
    private String dict_item_name; // 数据字典项目名称
    private String dict_item_code;// 数据字典项目代码
    private Integer dict_sort;// 排序字段
    private String dict_enable;//  是否可用
    private String dict_memo;// 备注
     //getter setter方法
}

上文声明了与数据字典表对应的属性并定义了各个属性的getter/setter方法。

QueryVo.java

public class QueryVo {   
    private String custName;// 客户名称
    private String custSource; // 客户来源 
    private String custIndustry;// 所属行业 
    private String custLevel;// 客户级别   
    private Integer page = 1;// 当前页码数  默认查询第1页  
    private Integer start;// 起始行  数据库从哪一条数据开始查 
    private Integer rows = 10; // 所取行数  每页显示数据条数 
    //getter setter方法
}

受请求参数的QueryVo,里面包含查询条件属性和分页数据。需要注意的是,属性中的star和rows用于执行分页操作,其中start表示分页操作中的起始行,而rows则表示分页中所选取的行数。

2实现DAO层
(1)创建客户DAO层接口和映射文件。
在com.itheima.core.dao包中,创建一个CustomerDao接口,并在接口中编写查询客户列表和客户总数的方法,然后创建一个与接口同名的映射文件。

CustomerDao.java

public interface CustomerDao {
    /**
     * 根据queryVo分页查询数据
     * 
     * @param queryVo
     * @return
     */
    List<Customer> queryCustomerByQueryVo(QueryVo queryVo);

    /**
     * 根据queryVo查询数据条数
     * 
     * @param queryVo
     * @return
     */
    Integer queryCountByQueryVo(QueryVo queryVo);
}

CustomerDao.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.itheima.core.dao.CustomerDao">
    <!-- SQL片段-->
    <sql id="customerQueryVo">
        <where>
            <if test="custName != null and custName != ''">
                AND a.cust_name LIKE '%${custName}%'
            </if>
            <if test="custSource != null and custSource != ''">
                AND a.cust_source = #{custSource}
            </if>
            <if test="custIndustry != null and custIndustry != ''">
                AND a.cust_industry = #{custIndustry}
            </if>
            <if test="custLevel != null and custLevel != ''">
                AND a.cust_level = #{custLevel}
            </if>
        </where>
    </sql>

    <!-- 根据queryVo分页查询数据 -->
    <select id="queryCustomerByQueryVo" parameterType="com.itheima.core.pojo.QueryVo"
        resultType="com.itheima.core.pojo.Customer">
      SELECT
        a.cust_id,
        a.cust_name,
        a.cust_user_id,
        a.cust_create_id,
        b.dict_item_name cust_source,
        c.dict_item_name cust_industry,
        d.dict_item_name cust_level,
        a.cust_linkman,
        a.cust_phone,
        a.cust_mobile,
        a.cust_zipcode,
        a.cust_address,
        a.cust_createtime
      FROM
        customer a
        LEFT JOIN base_dict b ON a.cust_source = b.dict_id
        LEFT JOIN base_dict c ON a.cust_industry = c.dict_id
        LEFT JOIN base_dict d ON a.cust_level = d.dict_id
        <include refid="customerQueryVo" />
        <!-- 执行分页查询-->
        <if test="start != null">
            LIMIT #{start}, #{rows}
        </if>
    </select>

    <!-- 根据queryVo查询数据条数 -->
    <select id="queryCountByQueryVo" parameterType="com.itheima.core.pojo.QueryVo"
        resultType="integer">
        SELECT count(1) FROM customer a
        <include refid="customerQueryVo" />
    </select>
</mapper>

上文首先编写了一个SQL片段来作为映射查询客户信息的条件,然后编写了查询所有客户的映射查询方法。在方法的SQL中,分别通过左外连接的方式从数据字典表base_dict中的类别代码字段查询出了相应的类别信息,同时通过limit来实现数据的分页查询。最后编写了一个查询客户总数的映射查询语句用于分页使用。

(2)创建数据字典DAO层接口和映射文件。

在com.itheima.core.dao包中,创建一个BaseDictDao接口,并在接口中编写根据类别代码查询数据字典的方法,然后创建一个与接口同名的映射文件。

BaseDictDao.java

public interface BaseDictDao {
    
    /**
     * 根据类别代码查询数据
     * @param dictTypecode
     * @return
     */
    public List<BaseDict> queryBaseDictByDictTypeCode(String dictTypecode);
    
}

BaseDictDao.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.itheima.core.dao.BaseDictDao">
    <!-- 根据类别代码查询数据 -->
    <select id="queryBaseDictByDictTypeCode" parameterType="String"
        resultType="com.itheima.core.pojo.BaseDict">
        SELECT * FROM base_dict WHERE dict_type_code =
        #{dict_type_code}
    </select>   
</mapper>

3实现Service层
(1)引入分页标签类。
在src目录下,创建一个com.itheima.common.utils包,在包中引入分页时使用的标签类文件Page.java和NavigationTag.java。

Page.java

public class Page<T> {
    
    private int total;// 总条数
    private int page; // 当前页
    private int size; // 每页数
    private List<T> rows; // 结果集
    // getter setter 方法
  }

** NavigationTag.java**

/**
 * 显示格式:首页 上一页 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\">");
            //首页链接路径
            String homeUrl = append(url, "page", 1);
            //末页链接路径
            String backUrl = append(url, "page", pageCount);
            // 显示“上一页”按钮
            if (page.getPage() > 1) {
                String preUrl = append(url, "page", page.getPage() - 1);
                preUrl = append(preUrl, "rows", page.getSize());
        writer.print("<li><a href=\"" + homeUrl + "\">" + "首页</a></li>");
        writer.print("<li><a href=\"" + preUrl + "\">" + "上一页</a></li>");
            } else {
writer.print("<li class=\"disabled\"><a href=\"#\">" + "首页 </a></li>");
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 =1;
            if(page.getPage() - 2 <=0){
                indexPage=1;
            }else if(pageCount-page.getPage() <=2){
                indexPage=pageCount-4;
            }else{
                indexPage= page.getPage() - 2;
            }
    for (int i= 1;i <= number && indexPage <= pageCount;indexPage++,i++){
                if (indexPage == page.getPage()) {
            writer.print("<li class=\"active\"><a href=\"#\">" + indexPage
                +"<spanclass=\"sr-only\"></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>");
        writer.print("<li><a href=\"" + backUrl + "\">" + "尾页</a></li>");
            } else {
writer.print("<li class=\"disabled\"><a href=\"#\">" + "下一页</a></li>");
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 参加参数对儿
     */
    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 + "&amp;" + key + "=" + value;
            }
        }
        return url;
    }
    /**
     * 为url 添加翻页请求参数
     */
    private String resolveUrl(String url, 
        javax.servlet.jsp.PageContext pageContext) throws JspException {
        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;
    }
    public String getBean() {
        return bean;
    }
    public void setBean(String bean) {
        this.bean = bean;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public void setNumber(int number) {
        this.number = number;
    }
}    

(2)创建数据字典及客户的Service层接口。
在com.itheima.core.service包中创建一个名称为BaseDictService和CustomerService的接口。

BaseDictService.java

public interface BaseDictService {
    /**
     * 根据类别代码查询
     * 
     * @param dictTypeCode
     * @return
     */
    List<BaseDict> queryBaseDictByDictTypeCode(String dictTypeCode);
}

CustomerService.java

public interface CustomerService {

    /**
     * 根据条件分页查询客户
     * 
     * @param queryVo
     * @return
     */
    Page<Customer> queryCustomerByQueryVo(QueryVo queryVo);
    
}

3)创建数据字典及客户Service层接口的实现类。
在com.itheima.core.service.impl包中分别创建数据字典和客户Service层接口的实现类BaseDictServiceImpl和CustomerServiceImpl。

BaseDictServiceImpl.java

@Service    
public class BaseDictServiceImpl implements BaseDictService{
    
    @Autowired
    private BaseDictDao baseDictDao;

    @Override
    public List<BaseDict> queryBaseDictByDictTypeCode(String dictTypeCode) {
        
        return baseDictDao.queryBaseDictByDictTypeCode(dictTypeCode);
    }

}

** CustomerServiceImpl.java**

@Service
public class CustomerServiceImpl implements CustomerService {
    
    @Autowired
    private CustomerDao customerDao;
    
    @Override
    public Page<Customer> queryCustomerByQueryVo(QueryVo queryVo) {
        
        // 判断参数对象
        if(null != queryVo) {
            if(StringUtils.isNotBlank(queryVo.getCustName())) {
                queryVo.setCustName(queryVo.getCustName());
            }
            if(StringUtils.isNotBlank(queryVo.getCustSource())) {
                queryVo.setCustSource(queryVo.getCustSource());
            }
            if(StringUtils.isNotBlank(queryVo.getCustIndustry())) {
                queryVo.setCustIndustry(queryVo.getCustIndustry());
            }
            if(StringUtils.isNotBlank(queryVo.getCustLevel())) {
                queryVo.setCustLevel(queryVo.getCustLevel());
            }
            if(StringUtils.isNotBlank(queryVo.getCustName())) {
                queryVo.setCustName(queryVo.getCustName());
            }
            if(StringUtils.isNotBlank(queryVo.getCustName())) {
                queryVo.setCustName(queryVo.getCustName());
            }
            
        }

        // 设置查询条件,从哪一条数据开始查  page和rows有初始值
        queryVo.setStart((queryVo.getPage() - 1) * queryVo.getRows());

        // 查询数据结果集
        List<Customer> list = this.customerDao.queryCustomerByQueryVo(queryVo);
        
        // 查询到的数据总条数
        int total = this.customerDao.queryCountByQueryVo(queryVo);

        // 封装返回的page对象
        Page<Customer> page = new Page<Customer>();
        page.setPage(queryVo.getPage());// 当前页 和参数一样
        page.setRows(list);// 结果集
        page.setSize(queryVo.getRows());// 每页数 和参数一样
        page.setTotal(total);// 总条数
        return page;        
    }

在上文的实现方法中,首先判断参数是否为空,然后判断条件查询中的客户名称、信息来源、所属行业和客户级别是否为空,只有不为空时,才添加到参数对象中。接下来获取了页面传递过来的当前页page和每页数信息rows,由此得到起始行start。然后查询所有的客户信息以及客户总数。最后将查询出的所有信息封装到Page对象中并返回。

4实现Controller
在com.itheima.core.controller包中,创建客户控制器类CustomerController。

** CustomerController.java**

@Controller
public class CustomerController {
        
    // 客户来源
    @Value("${CUSTOMER_FROM_TYPE}")
    private String CUSTOMER_FROM_TYPE;
    // 客户行业
    @Value("${CUSTOMER_INDUSTRY_TYPE}")
    private String CUSTOMER_INDUSTRY_TYPE;
    // 客户级别
    @Value("${CUSTOMER_LEVEL_TYPE}")
    private String CUSTOMER_LEVEL_TYPE;

    
    @Autowired
    private BaseDictService baseDictService;
    
    @Autowired
    private CustomerService customerService;
    
    /**
     * 显示用户列表
     * @return
     */
    @RequestMapping(value="/customer/list")
    public String list(Model model,QueryVo queryVo) {

//      已在tomcat的server.xml中修改了uri的编码为UTF-8,此处代码可不写         <Connector URIEncoding="UTF-8" />   
//      try {
//          // 解决get请求乱码问题
//          if (StringUtils.isNotBlank(queryVo.getCustName())) {
//              queryVo.setCustName(new String(queryVo.getCustName().getBytes("ISO-8859-1"), "UTF-8"));
//          }
//      } catch (Exception e) {
//          e.printStackTrace();
//      }
        
        // 客户来源
        List<BaseDict> fromType = baseDictService.queryBaseDictByDictTypeCode(CUSTOMER_FROM_TYPE);
        // 所属行业
        List<BaseDict> industryType =baseDictService.queryBaseDictByDictTypeCode(CUSTOMER_INDUSTRY_TYPE);
        // 客户级别
        List<BaseDict> levelType = baseDictService.queryBaseDictByDictTypeCode(CUSTOMER_LEVEL_TYPE);
        
        // 把前端页面需要显示的数据放到模型中
        model.addAttribute("fromType", fromType);
        model.addAttribute("industryType", industryType);
        model.addAttribute("levelType", levelType);
        
        // 条件、分页查询数据
        Page<Customer> page = this.customerService.queryCustomerByQueryVo(queryVo);
        // 把分页查询的结果放到模型中
        model.addAttribute("page", page);

        // 数据回显
        model.addAttribute("custName", queryVo.getCustName());
        model.addAttribute("custSource", queryVo.getCustSource());
        model.addAttribute("custIndustry", queryVo.getCustIndustry());
        model.addAttribute("custLevel", queryVo.getCustLevel());


        return "customer";
    }

在客户控制器类中,首先声明了customerService和baseDictService属性,并通过@Autowired注解将这两个对象注入到本类中;然后分别定义了客户来源、所属行业和客户级别属性,并通过@Value注解将resource.properties文件中的属性值赋给这3个属性;最后编写了查询客户列表的方法来执行查询操作,其中第1个参数page的默认值为1,表示从第1条开始,第2个参数的默认值为10,表示每页显示10条数据。

5实现页面显示
(1)自定义标签文件主要用于实现分页功能,其标签名称为commons.tld。

commons.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的版本号 -->
    <jsp-version>1.2</jsp-version>
    <!-- 指定标签库的名称 -->
    <short-name>common</short-name>
    <!-- 指定标签库的URI -->
    <uri>http://itheima.com/common/</uri>
    <!-- 指定标签库的显示名称 -->
    <display-name>Common Tag</display-name>
    <!-- 指定标签库的描述 -->
    <description>Common Tag library</description>
    <!-- 注册一个自定义标签 -->
    <tag>
        <!-- 指定注册的自定义标签名称 -->
        <name>page</name>
        <!-- 指定自定义标签的标签处理器类 -->
        <tag-class>com.itheima.common.utils.NavigationTag</tag-class>
        <!-- 指定标签体类型 -->
        <body-content>JSP</body-content>
        <!-- 描述 -->
        <description>create navigation for paging</description>
        <!-- 指定标签中的属性 -->
        <attribute>
            <!-- 指定属性名称 -->
            <name>url</name>
            <!-- 该属性为true时表示其指定是属性为必须属性 -->
            <required>true</required>
            <!-- 该属性用于指定能不能使用表达式来动态指定数据,为true时表示可以 -->
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>bean</name> 
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>number</name> 
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
</taglib>

在上文中,第13行代码就是我们在使用自定义标签时引入的URI,第23行代码指定了自定义标签的处理器类。

(2)在customer.jsp中,编写条件查询和显示客户列表以及分页查询的代码。

customer.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="itheima" uri="http://itcast.cn/common/"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() 
                       + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>客户管理-BootCRM</title>
    <!-- 引入css样式文件 -->
    <!-- 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" />
</head>
<body>
...
    <!-- 客户列表查询部分  start-->
    <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" method="get" 
                      action="${pageContext.request.contextPath }/customer/list.action">
                    <div class="form-group">
                        <label for="customerName">客户名称</label> 
                        <input type="text" class="form-control" id="customerName" 
                                           value="${custName }" name="custName" />
                    </div>

5.2 客户的增删改查

CustomerDao.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.itheima.core.dao.CustomerDao">
    <!--SQL片段  -->
    <sql id="selectCustomerListWhere">
        <where>
           <if test="cust_name != null" >
               cust_name like "%"#{cust_name}"%"
           </if>
           <if test="cust_source != null" >
            and cust_source = #{cust_source}
           </if>
           <if test="cust_industry != null" >
            and cust_industry = #{cust_industry}
           </if>
           <if test="cust_level != null" >
            and cust_level = #{cust_level}
           </if>
        </where>
    </sql>
    <!-- 查询客户列表  -->
    <select id="selectCustomerList" parameterType="customer" 
                                           resultType="customer">
        SELECT
            cust_id,
            cust_name,
            cust_user_id,
            cust_create_id,
            b.dict_item_name cust_source,
            c.dict_item_name cust_industry,
            d.dict_item_name cust_level,
            cust_linkman,
            cust_phone,
            cust_mobile,
            cust_createtime
        FROM
            customer a
        LEFT JOIN (
            SELECT
                dict_id,
                dict_item_name
            FROM
                base_dict
            WHERE
                dict_type_code = '002'
        ) b ON a.cust_source = b.dict_id
        LEFT JOIN (
            SELECT
                dict_id,
                dict_item_name
            FROM
                base_dict
            WHERE
                dict_type_code = '001'
        ) c ON a.cust_industry = c.dict_id
        LEFT JOIN (
            SELECT
                dict_id,
                dict_item_name
            FROM
                base_dict
            WHERE
                dict_type_code = '006'
        ) d ON a.cust_level = d.dict_id
        <include refid="selectCustomerListWhere"/>
        <!-- 执行分页查询 -->
        <if test="start !=null and rows != null">
            limit #{start},#{rows}
        </if>
    </select>
    <!-- 查询客户总数 -->
    <select id="selectCustomerListCount" parameterType="customer" 
                                                 resultType="Integer">
        select count(*) from customer
        <include refid="selectCustomerListWhere"/>
    </select>   
    
    <!-- 添加客户 -->
    <insert id="createCustomer" parameterType="customer">
        insert into customer(
                         cust_name,
                         cust_user_id,
                         cust_create_id,
                         cust_source,
                         cust_industry,
                         cust_level,
                         cust_linkman,
                         cust_phone,
                         cust_mobile,
                         cust_zipcode,
                         cust_address,
                         cust_createtime
                 )
                 values(#{cust_name},
                        #{cust_user_id},
                        #{cust_create_id},
                        #{cust_source},
                        #{cust_industry},
                        #{cust_level},
                        #{cust_linkman},
                        #{cust_phone},
                        #{cust_mobile},
                        #{cust_zipcode},
                        #{cust_address},
                        #{cust_createtime}
                )
    </insert>
    <!-- 根据id获取客户信息 -->
    <select id="getCustomerById" parameterType="Integer" 
    resultType="customer">
        select * from customer where cust_id = #{id}
    </select>
    <!-- 更新客户 -->
    <update id="updateCustomer" parameterType="customer">
        update customer
        <set>
            <if test="cust_name!=null">
                cust_name=#{cust_name},
            </if>
            <if test="cust_user_id!=null">
                cust_user_id=#{cust_user_id},
            </if>
            <if test="cust_create_id!=null">
                cust_create_id=#{cust_create_id},
            </if>
            <if test="cust_source!=null">
                cust_source=#{cust_source},
            </if>
            <if test="cust_industry!=null">
                cust_industry=#{cust_industry},
            </if>
            <if test="cust_level!=null">
                cust_level=#{cust_level},
            </if>
            <if test="cust_linkman!=null">
                cust_linkman=#{cust_linkman},
            </if>
            <if test="cust_phone!=null">
                cust_phone=#{cust_phone},
            </if>
            <if test="cust_mobile!=null">
                cust_mobile=#{cust_mobile},
            </if>
            <if test="cust_zipcode!=null">
                cust_zipcode=#{cust_zipcode},
            </if>
            <if test="cust_address!=null">
                cust_address=#{cust_address},
            </if>
            <if test="cust_createtime!=null">
                cust_createtime=#{cust_createtime},
            </if>
        </set>
        where cust_id=#{cust_id}
    </update>
    <!-- 删除客户 -->
    <delete id="deleteCustomer" parameterType="Integer">
        delete from customer where cust_id=#{id}
    </delete>
</mapper>

CustomerService.java

package com.itheima.core.service;
import com.itheima.common.utils.Page;
import com.itheima.core.po.Customer;
public interface CustomerService {
    // 查询客户列表
    public Page<Customer> findCustomerList(Integer page, Integer rows, 
                                        String custName,String custSource,
                                        String custIndustry,String custLevel);
    
    public int createCustomer(Customer customer);
    
    // 通过id查询客户
    public Customer getCustomerById(Integer id);
    // 更新客户
    public int updateCustomer(Customer customer);
    // 删除客户
    public int deleteCustomer(Integer id);

}

CustomerServiceImpl.java

package com.itheima.core.service.impl;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.itheima.common.utils.Page;
import com.itheima.core.dao.CustomerDao;
import com.itheima.core.po.Customer;
import com.itheima.core.service.CustomerService;
/**
 * 客户管理
 */
@Service("customerService")
@Transactional
public class CustomerServiceImpl implements CustomerService {
    // 声明DAO属性并注入
    @Autowired
    private CustomerDao customerDao;
    // 客户列表
    public Page<Customer> findCustomerList(Integer page, Integer rows, 
            String custName,  String custSource,String custIndustry,
                                                          String custLevel) {
        // 创建客户对象
         Customer customer = new Customer();
        // 判断客户名称
        if(StringUtils.isNotBlank(custName)){
            customer.setCust_name(custName);
        }
        // 判断客户信息来源
        if(StringUtils.isNotBlank(custSource)){
            customer.setCust_source(custSource);
        }
        // 判断客户所属行业
        if(StringUtils.isNotBlank(custIndustry)){
            customer.setCust_industry(custIndustry);
        }
        // 判断客户级别
        if(StringUtils.isNotBlank(custLevel)){
            customer.setCust_level(custLevel);
        }
        // 当前页
        customer.setStart((page-1) * rows) ;
        // 每页数
        customer.setRows(rows);
        // 查询客户列表
        List<Customer> customers = 
                            customerDao.selectCustomerList(customer);
        // 查询客户列表总记录数
        Integer count = customerDao.selectCustomerListCount(customer);
        // 创建Page返回对象
        Page<Customer> result = new Page<>();
        result.setPage(page);
        result.setRows(customers);
        result.setSize(rows);
        result.setTotal(count);
        return result;
    }
    /**
     * 创建客户
     */
    @Override
    public int createCustomer(Customer customer) {
        return customerDao.createCustomer(customer);
    }
    /**
     * 通过id查询客户
     */
    @Override
    public Customer getCustomerById(Integer id) {   
        Customer customer = customerDao.getCustomerById(id);
        return customer;        
    }
    /**
     * 更新客户
     */
    @Override
    public int updateCustomer(Customer customer) {
        return customerDao.updateCustomer(customer);
    }
    /**
     * 删除客户
     */
    @Override
    public int deleteCustomer(Integer id) {
        return customerDao.deleteCustomer(id);  
    }

    
}

CustomerController.java

package com.itheima.core.web.controller;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.itheima.common.utils.Page;
import com.itheima.core.po.BaseDict;
import com.itheima.core.po.Customer;
import com.itheima.core.po.User;
import com.itheima.core.service.BaseDictService;
import com.itheima.core.service.CustomerService;
/**
 * 客户管理控制器类
 */
@Controller
public class CustomerController {
    // 依赖注入
    @Autowired
    private CustomerService customerService;
    @Autowired
    private BaseDictService baseDictService;
    // 客户来源
    @Value("${customer.from.type}")
    private String FROM_TYPE;
    // 客户所属行业
    @Value("${customer.industry.type}")
    private String INDUSTRY_TYPE;
    // 客户级别
    @Value("${customer.level.type}")
    private String LEVEL_TYPE;
    /**
     *  客户列表
     */
    @RequestMapping(value = "/customer/list.action")
    public String list(@RequestParam(defaultValue="1")Integer page,
            @RequestParam(defaultValue="10")Integer rows, 
            String custName, String custSource, String custIndustry,
            String custLevel, Model model) {
        // 条件查询所有客户
        Page<Customer> customers = customerService
                .findCustomerList(page, rows, custName, 
                                        custSource, custIndustry,custLevel);
        model.addAttribute("page", customers);
        // 客户来源
        List<BaseDict> fromType = baseDictService
                .findBaseDictByTypeCode(FROM_TYPE);
        // 客户所属行业
        List<BaseDict> industryType = baseDictService
                .findBaseDictByTypeCode(INDUSTRY_TYPE);
        // 客户级别
        List<BaseDict> levelType = baseDictService
                .findBaseDictByTypeCode(LEVEL_TYPE);
        // 添加参数
        model.addAttribute("fromType", fromType);
        model.addAttribute("industryType", industryType);
        model.addAttribute("levelType", levelType);
        model.addAttribute("custName", custName);
        model.addAttribute("custSource", custSource);
        model.addAttribute("custIndustry", custIndustry);
        model.addAttribute("custLevel", custLevel);
        return "customer";
    }
    
    /**
     * 创建客户
     */
    @RequestMapping("/customer/create.action")
    @ResponseBody
    public String customerCreate(Customer customer,HttpSession session) {
        // 获取Session中的当前用户信息
        User user = (User) session.getAttribute("USER_SESSION");
        // 将当前用户id存储在客户对象中
        customer.setCust_create_id(user.getUser_id());
        // 创建Date对象
        Date date = new Date();
        // 得到一个Timestamp格式的时间,存入mysql中的时间格式“yyyy/MM/dd HH:mm:ss”
        Timestamp timeStamp = new Timestamp(date.getTime());
        customer.setCust_createtime(timeStamp);
        // 执行Service层中的创建方法,返回的是受影响的行数
        int rows = customerService.createCustomer(customer);
        if(rows > 0){
            return "OK";
        }else{
            return "FAIL";
        }
    }

    /**
     * 通过id获取客户信息
     */
    @RequestMapping("/customer/getCustomerById.action")
    @ResponseBody
    public Customer getCustomerById(Integer id) {
        Customer customer = customerService.getCustomerById(id);
        return customer;
    }
    /**
     * 更新客户
     */
    @RequestMapping("/customer/update.action")
    @ResponseBody
    public String customerUpdate(Customer customer) {
        int rows = customerService.updateCustomer(customer);
        if(rows > 0){
            return "OK";
        }else{
            return "FAIL";
        }
    }

    /**
     * 删除客户
     */
    @RequestMapping("/customer/delete.action")
    @ResponseBody
    public String customerDelete(Integer id) {
        int rows = customerService.deleteCustomer(id);
        if(rows > 0){           
            return "OK";
        }else{
            return "FAIL";          
        }
    }

}

5.3 结果展示

添加客户

修改客户

查询客户

删除客户

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351