CRM项目(SSM)总结

CRM项目(SSM)总结 byYOnGKAnG

目录

CRM项目(SSM)总结 byYOnGKAnG

一.搭建环境

1.配置字符集,和配置文件(properties、xml)文件中的字符集,编译器、项目字符集,静态资源字符集统一设置成utf-8字符集

​2.设置web项目(前提是没有使用maven),由于做项目的时候使用maven快捷搭建项目加载不出来。

pom.xml

 applicationContext.xml

applicationContext-datasource.xml

applicationContext-mvc.xml

 mybatis-config.xml

二.编码实现

1.用户登录

1)十天内免登录

 2.市场活动

 1)分页显示和动态显示活动

 2)修改功能,点击修改会将所点击的记录对应数据显示在文本框中

3)删除功能,可以同时删除多条记录,ajax三种向后台提交数据的方式

4)上传列表数据功能,将xls转为 java数据

5)导出,下载功能,java转xls 

3.市场活动细节

1)备注,对动态标签添加事件

4.交易

1)根据前端传给后端的键,通过properties获取对应的值

2)自动补全功能 

三.其他

1.关于配置文件

1)properties配置文件:

2)xml配置文件:标签语言

2.后端向前端发送实体类,集合问题

3.关于idea报sql语句错误

1)发现错误日志,sql语句短缺

2)语句没错但结果为空

3)mapper.xml中传入参数不能同时传入两个对象,多个数据需要使用实体类或集合传递

4.给标签添加属性

1)使用标签保存数据,以便在需要的时候能够获取到这些数据

2)获取属性值时:如果获取表单组件标签的value属性值:

5.物理模型设计(表)

1)关于主键设置(大部分为id)

6.配置tomact时没有可用的工件以及tomact访问路径问题


一.搭建环境

1.配置字符集,和配置文件(properties、xml)文件中的字符集,编译器、项目字符集,静态资源字符集统一设置成utf-8字符集


2.设置web项目(前提是没有使用maven),由于做项目的时候使用maven快捷搭建项目加载不出来。


    在file->project structure选项卡moudle中点击‘+’号添加web项目


3.配置maven,pom文件

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.zhai</groupId>
  <artifactId>crm</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>crm Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf</artifactId>
      <version>3.0.15.RELEASE</version>
    </dependency>
    <!-- MySQL数据库连接驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.43</version>
    </dependency>
    <!-- JDBC数据源连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.1</version>
    </dependency>
    <!-- MyBatis框架依赖 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.1</version>
    </dependency>
    <!-- Spring框架依赖的JAR配置 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-oxm</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
    <!-- Spring AOP支持-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
    </dependency>
    <!-- MyBatis与Spring整合依赖 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.0</version>
    </dependency>
    <!-- servlet及jstl标签库依赖的JAR配置 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>jstl-api</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-spec</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-impl</artifactId>
      <version>1.2.1</version>
    </dependency>

    <!-- 加载jackson插件依赖 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.7.3</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.7.3</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.7.3</version>
    </dependency>

    <!--poi依赖-->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>3.15</version>
    </dependency>

    <!-- 文件上传 -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

    <!-- Log4j2依赖的JAR配置 -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-jcl</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>
      <resource>
      <directory>src/main/resources</directory>
      <includes>
        <include>**/*.xml</include>
        <include>**/*.properties</include>
      </includes>
    </resource>
    </resources>
    <finalName>crm</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.2.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.2</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

4.配置spring、springmvc、mybatis配置文件

 applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--命名空间-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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:task="http://www.springframework.org/schema/task"
       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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 加载系统配置文件
    <context:property-placeholder location="classpath:*.properties" />-->
    <!-- 扫描注解 -->
    <context:component-scan base-package="com.bjpowernode.crm.settings.service" />
    <context:component-scan base-package="com.bjpowernode.crm.workbench.service"/>
    <context:component-scan base-package="com.bjpowernode.crm.zhaiyongkang.service"/>
    <!-- 导入数据相关配置 -->
    <import resource="applicationContext-datasource.xml" />
</beans>

applicationContext-datasource.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.3.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    <!-- 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/crm?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
    </bean>
    <!-- 配置SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 必须注入属性dataSource -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 如果mybatis没有特殊的配置(比如别名等),configLocation可以省去 ;否则,不能省略-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>
    <!-- mapper注解扫描器配置,扫描@MapperScan注解,自动生成代码对象 -->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.bjpowernode.crm.settings.mapper
                                            com.bjpowernode.crm.workbench.mapper
                                            com.bjpowernode.crm.zhaiyongkang.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置事务 -->
    <aop:config>
        <aop:pointcut expression="execution(* com.bjpowernode.crm..service.*.*(..))" id="allMethodPointcut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allMethodPointcut"/>
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="do*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
    </tx:advice>
</beans>

applicationContext-mvc.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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
    <!-- dispatcherServlet截获所有URL请求 -->
    <mvc:default-servlet-handler />
    <!-- spring mvc 扫描包下的controller -->
    <context:component-scan base-package="com.bjpowernode.crm.web.controller"/>
    <context:component-scan base-package="com.bjpowernode.crm.settings.web.controller"/>
    <context:component-scan base-package="com.bjpowernode.crm.workbench.web.controller"/>
    <context:component-scan base-package="com.bjpowernode.crm.zhaiyongkang.controller"/>
    <!-- 配置注解驱动 -->
    <mvc:annotation-driven/>
    <!-- 配置视图解析器 -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <mvc:interceptors>
        <mvc:interceptor>
<!--            拦截url还有controller,因为我们controller url起名的时候和资源路径一致-->
<!--            /settings/*代表settings下的一层子目录,/settings/**代表settings下子目录下多层子目录-->
            <mvc:mapping path="/settings/**"/>
            <mvc:mapping path="/workbench/**"/>
<!--            为登录页面放行-->
            <mvc:exclude-mapping path="/settings/qx/user/login.do"/>
            <mvc:exclude-mapping path="/settings/qx/user/toLogin.do"/>
            <bean class="com.bjpowernode.crm.settings.web.interceptor.LoginInteceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    <!-- 配置文件上传解析器 id:必须是multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="#{1024*1024*80}"/>
        <property name="defaultEncoding" value="utf-8"/>
    </bean>
</beans>

 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>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
<!--    别名-->
    <typeAliases>
        <package name="com.bjpowernode.crm.model"/>
    </typeAliases>
    <mappers>
        <package name="com.bjpowernode.crm.mapper"/>
    </mappers>
</configuration>

二.编码实现

1.用户登录

功能:免登录,十天内免登录

代码:UserConroller、UserService、UserServiceImpl、UserMapper、UserMapper.xml

主要部分:

1)十天内免登录

@RequestMapping("/settings/qx/user/login.do")
    public @ResponseBody Object login(String loginAct, String loginPwd, String isRemPwd, HttpServletRequest request, HttpSession session, HttpServletResponse response){
        Map<String,Object> map=new HashMap<>();
        map.put("loginAct",loginAct);
        map.put("loginPwd",loginPwd);
        User user = userService.queryUserByLoginActAndPwd(map);
        ReturnObject returnObject=new ReturnObject();
        if (user==null){
            //登录失败
            returnObject.setCode("0");
            returnObject.setMessage("用户民或密码错误");
        }else{//判断时间是否过期
            if (DateUtils.formateDateTime(new Date()).compareTo(user.getExpireTime())>0){
                //账号过期
                returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
                returnObject.setMessage("账号过期");
            }else if("0".equals(user.getLockState())){
                //账号被锁定
                returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
                returnObject.setMessage("账号被锁定");
            }else if(!user.getAllowIps().contains(request.getRemoteAddr())){
                //检查ip
                returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
                returnObject.setMessage("IP受限");
            }else{
                returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
                session.setAttribute("sessionUser",user);
            }
        }
        //如果用户选择十天内记住密码,则往浏览器写cookie
        if ("true".equals(isRemPwd)){
            Cookie c1=new Cookie("loginAct",loginAct);
            c1.setMaxAge(10*24*60*60);
            response.addCookie(c1);
            Cookie c2=new Cookie("loginPwd",loginPwd);
            c2.setMaxAge(10*24*60*60);
            response.addCookie(c2);
        }else{
            /**
             * 如果用户没有点击或取消十天内记住密码,则利用浏览器kill cookie,
             * 也就是将cookie的寿命设置为0,
             * 设置同名cookie可以将原有cookie的属性覆盖包括生命周期
             */
            Cookie c1=new Cookie("loginAct","1");
            c1.setMaxAge(0);
            response.addCookie(c1);
            Cookie c2=new Cookie("loginPwd","2");
            c2.setMaxAge(0);
            response.addCookie(c2);
        }
        return returnObject;
    }

 描述:方法接受来自前端的账号和密码封装成map,将map参数传给UserService、service调用mapper,通过账号和密码查询user,返回一个user对象,如果数据库中没有符合条件的,user则为空,则登录失败,如果不为空则依次判定条件,直到最后条件都满足,则把user对象放入session,然后判断、用户是否选择了记住密码,选择了就创建cookie通过response传给客户端本地保存,用户再次访问页面,会将本地cookie取出判断是否为空

<form action="workbench/index.html" class="form-horizontal" role="form">
				<div class="form-group form-group-lg">
					<div style="width: 350px;">
						<input class="form-control" type="text" placeholder="用户名" id="loginAct" value="${cookie.loginAct.value}">
					</div>
					<div style="width: 350px; position: relative;top: 20px;">
						<input class="form-control" type="password" placeholder="密码" id="loginPwd" value="${cookie.loginPwd.value}">
					</div>
					<div class="checkbox"  style="position: relative;top: 30px; left: 10px;">
<%--						使用jstl标签做判断,如果客户端有cookie且值不为空则复选框是选中的状态否则不是--%>
						<label>
							<c:if test="${not empty cookie.loginAct.value and not empty cookie.loginPwd.value}">
								<input type="checkbox" id="isRemPwd" checked> 十天内免登录
							</c:if>
							<c:if test="${empty cookie.loginAct.value or empty cookie.loginPwd.value}">
								<input type="checkbox" id="isRemPwd"> 十天内免登录
							</c:if>
						</label>
						&nbsp;&nbsp;
						<span id="msg"></span>
					</div>
					<button type="button" id="loginBtn" class="btn btn-primary btn-lg btn-block"  style="width: 350px; position: relative;top: 45px;">登录</button>
				</div>
			</form>

 cookie中有值则显示,空就显示空,复选框按钮cookie有值就是选中状态,没有则不是选中状态

 2.市场活动

功能:分页显示活动条数,创建、修改、删除、表转.xls、xls转表(对应导入导出功能)、下载、模糊查询

代码:ActivityMapper、ActivityMapper.xml、ActivityController、ActivityService、ActivityServiceImpl

主要部分:

 1)分页显示和动态显示活动

function queryActivityByConditionForPage(pageNo,pageSize){
			//获取四个查询条件文本框的值
			var name=$("#query-name").val();
			var owner=$("#query-owner").val();
			var endDate=$("#query-endDate").val();
			var startDate=$("#query-startDate").val();
			//发送请求
			$.ajax({
				url:'workbench/activity/queryActivityConditionForPage.do',
				data:{
					name:name,
					owner:owner,
					startDate:startDate,
					endDate:endDate,
					pageSize:pageSize,
					pageNo:pageNo
				},
				type: 'post',
				dataType: 'json',
				success:function(data){
					// $("#totalRowsB").text(data.totalRows);
					var htmlStr="";
					htmlStr+="<li>";
					htmlStr+="<a href=\"#\" aria-label=\"Previous\">";
					htmlStr+="<span aria-hidden=\"true\">&laquo;</span>";
					htmlStr+="</a>";
					htmlStr+="</li>";
					for (var i=1;i<=data.yeshu;i++){
						htmlStr+="<li><a name=\""+i+"\" onclick=\"findActivity(this.name)\" href=\"javascript:;\">"+i+"</a></li>";
					}
					htmlStr+="<li>";
					htmlStr+="<a href=\"#\" aria-label=\"Next\">";
					htmlStr+="<span aria-hidden=\"true\">&raquo;</span>";
					htmlStr+="</a>";
					htmlStr+="</li>";
					//.html意思就是指定容器下要显示的html是,而append有追加的意思每一回调用函数都会追加
					$("#page-table").html(htmlStr);
					var htmlStr="";
					$.each(data.activityList,function (index,obj){
						htmlStr+="<tr class=\"active\">";//双引号之中不允许再有双引号需要使用转义字符'\'
						htmlStr+="<td><input type=\"checkbox\" value=\""+obj.id+"\"/></td>";
						//给名称超链接绑定活动id
						htmlStr+="<td><a style=\"text-decoration: none; cursor: pointer;\" onclick=\"window.location.href='workbench/activity/detailActivity.do?id="+obj.id+"'\">"+obj.name+"</a></td>";
						htmlStr+="<td>"+obj.owner+"</td>";
						htmlStr+="<td>"+obj.startDate+"</td>";
						htmlStr+="<td>"+obj.endDate+"</td>";
						htmlStr+="</tr>";
					});
					$("#tboday-activity").html(htmlStr);
				}
			});

描述:这里的pageNo和pageSize是固定的是1和10意思就是默认从第一页查,每一页最多十条记录,同时获取四个查询文本框的值,异步提交给controller,最主要的就是mapper.xml文件中的sql语句使用了动态sql,如果四个条件参数有值则根据条件查询,没值则条件查询不成立,会把全部数据返回

@RequestMapping("/workbench/activity/queryActivityConditionForPage.do")
    @ResponseBody
    public Object queryActivityConditionForPage(String owner, String name, String startDate, String endDate, @RequestParam(value="pageNo",defaultValue = "1")int pageNo, @RequestParam(value="pageSize",defaultValue="10")int pageSize){
        //利用map封装查询条件
        Map<String,Object> map=new HashMap();
        map.put("name",name);
        map.put("owner",owner);
        map.put("endDate",endDate);
        map.put("startDate",startDate);
        map.put("beginNo",(pageNo-1)*pageSize);
        map.put("pageSize",pageSize);
        //返回查询的记录,如果条件为空会将从pageNo开始pageSize个记录返回到客户端
        List<Activity> activityList=activityService.queryActicityByConditionForPage(map);
        int totalRows=activityService.queryCountOfActivityCondition(map);//总共记录数,前台会利用总记录数和每页显示条数计算页数
        Map<String,Object> retmap=new HashMap<>();//以json格式返回数据
        retmap.put("activityList",activityList);
        retmap.put("totalRows",totalRows);
        int yeshu;//返回页数,能除尽直接返回,除不尽则进行取整操作
        if (totalRows%pageSize==0){
            yeshu=totalRows/pageSize;
        }else {
            yeshu=totalRows/pageSize+1;
        }
        retmap.put("yeshu",yeshu);
        return retmap;
    }

描述:后台将客户端传来的数据封装成一个map集合,后台对map集合中的值进行修改创建,作为查询条件传给Activitymapper.xml,mysql实现分页是使用limt实现,后台将客户端需要的数据用json格式返回给客户端(就是map集合转成json数据)

前端ajax,success函数中创建动态标签,分别创建了两个动态标签,一个是动态创建分页,一个是将表记录(市场活动)数据动态创建到客户端

 动态创建分页标签的时候会把页号绑定到a标签的name属性中,单击对应页号(例如:2)时,会将页号传给函数function findActivity(pageNo)然后再次异步提交给后台,后台根据新的页号再次异步提交,其中pageSize还是固定的10,map.put("beginNo",(pageNo-1)*pageSize);,通过运算实际查询的数据就是查询从第10条记录查,查十条记录返回到客户端

limit #{beginNo},#{pageSize}

意思是将查询到的数据从第beginNo条开始查询pageSize条数据返回 

 2)修改功能,点击修改会将所点击的记录对应数据显示在文本框中

		//修改按钮单击事件
		$("#editActivityBtn").click(function (){
			var checks=$("#tboday-activity input[type='checkbox']:checked");
			if(checks.size()==0){
				alert("请选中要修改的数据");
				return;
			}
			if(checks.size()>1){
				alert("只能修改一条数据");
				return;
			}
			var id=checks.get(0).value;
			$.ajax({
				url:'workbench/activity/selectActivityById.do',
				data:{
					id:id
				},
				type:'post',
				dataType:'json',
				success:function (data){
					$("#edit-id").val(data.id);
					$("#edit-marketActivityOwner").val(data.owner);
					$("#edit-marketActivityName").val(data.name);
					$("#edit-startTime").val(data.startDate);
					$("#edit-endTime").val(data.endDate);
					$("#edit-cost").val(data.cost);
					$("#edit-describe").val(data.description);
					$("#editActivityModal").modal("show");
				}
			});
		});

描述:点击修改按钮会执行依次异步提交,ajax会获取所修改记录的id并传给后端,后端进行查询封装成一个实体类对象返回给客户端ajax,ajax将数据显示在模态窗口中 ,对数据进行修改完之后点击更新按钮,将模态窗口中修改过后的数据异步提交后端,传给mapper,对数据库表进行更新,更新成功够关闭模态窗口

3)删除功能,可以同时删除多条记录,ajax三种向后台提交数据的方式

$("#deleteActivityBtn").click(function (){
			//获取参数
			//获取所有被选中的复选框
			var checks=$("#tboday-activity input[type='checkbox']:checked");
			if(checks.size()==0){
				alert("请选择要删除的选项");
				return;
			}
			//ajax向后台传数据有三种方式详见笔记,向后台提交数据格式id=xxx&id=xxx
			if (window.confirm("确定要删除吗")) {
				var ids="";
				$.each(checks,function (index,obj){
					ids+="id="+this.value+"&";
				});
				//substr从startIndex截到endIndex
				//substring从startIndex截几个字符
				ids=ids.substr(0,ids.length-1);
				$.ajax({
					url:'workbench/activity/deleteByIds.do',
					data:ids,
					type:'post',
					dataType:'json',
					success:function (data){
						if (data.code=="1"){
							alert(data.message);
							queryActivityByConditionForPage(1,10);
						}else{
							alert(data.message);
						}
					}
				});
			} else {
			}
		});

描述:其中最主要的就是ajax向后台提交数据有三种方式,第一种是常用的json形式。第二种就是这种拼接字符串的的形式,在这里,后端需要提供String[]接受客户端传来的参数第三种就是FormData,FormData是ajax提供的接口(用java的理解js的接口就相当于java类),模拟键值对向后台提交数据 ,它最大的优点就是不仅能向后台提交文本数据,还能提交二进制数据,会在导入功能中使用,实现将文件传递给后端

  <delete id="deleteByIds" parameterType="string">
    delete from tbl_activity where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>

其中mapper.xml文件解析字符数组用到了foreach循环遍历 ,collection参数可以是list、array

4)上传列表数据功能,将xls转为 java数据

@RequestMapping("/workbench/activity/saveActivityByList.do")
    @ResponseBody
    public Object saveActivityByList(MultipartFile activityFile,HttpSession session,String userName){
        ReturnObject returnObject=new ReturnObject();
        System.out.println(userName);
        try {
            String originalFilename = activityFile.getOriginalFilename();
            User user=(User)session.getAttribute(Contants.SESSION_USER);
            InputStream inputStream = activityFile.getInputStream();
            HSSFWorkbook hw=new HSSFWorkbook(inputStream);
            HSSFSheet sheet=hw.getSheetAt(0);
            HSSFRow row=null;
            HSSFCell cell=null;
            Activity activity=null;
            List<Activity> list=new ArrayList<>();
            for (int i=1;i<=sheet.getLastRowNum();i++){
                row=sheet.getRow(i);
                activity=new Activity();
                activity.setId(UUIDUtils.getUUID());
                activity.setOwner(user.getId());
                activity.setCreateTime(DateUtils.formateDateTime(new Date()));
                activity.setCreateBy(user.getId());
                String cellValue;
                for (int j=0;j<row.getLastCellNum();j++) {
                    cell = row.getCell(j);
                    if (cell!=null) {
                         cellValue = USSFUUtils.getCellValueForStr(cell);
                    }else{
                        cellValue="";
                    }
                    if (j == 0) {
                        activity.setName(user.getName());
                    } else if (j == 1) {
                        activity.setStartDate(cellValue);
                    } else if (j == 2) {
                        activity.setEndDate(cellValue);
                    } else if (j == 3) {
                        activity.setCost(cellValue);
                    } else if (j == 4) {
                        activity.setDescription(cellValue);
                    }
                }
                list.add(activity);
            }
            //调用service方法
            int i = activityService.saveActivityByList(list);
            returnObject.setMessage("输入"+i+"条记录");
        } catch (IOException e) {
            e.printStackTrace();
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
            returnObject.setMessage("系统der了");
        }
        return returnObject;
    }
package com.bjpowernode.crm.commons.utils;

import org.apache.poi.hssf.usermodel.HSSFCell;

public class USSFUUtils {
    public static String getCellValueForStr(HSSFCell cell) {
        String ret = "";
        if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
            ret = cell.getStringCellValue();
        } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
            ret = cell.getNumericCellValue() + "";
        } else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {
            ret = cell.getBooleanCellValue() + "";
        } else if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
            ret = cell.getCellFormula();
        } else {
            ret = "";
        }
        return ret;
    }
}

描述:这里用到了poi插件,最主要的是提供了HSSFWorkbook对象,还有自定义的工具类,会将从xls文件中获取的数据自动转为字符串,Row行,Cell列

5)导出,下载功能,java转xls 

@RequestMapping("/workbench/activity/exportAllActivitys")
    public void exportAllActivitys(HttpServletResponse response)throws Exception{
        List<Activity> list=activityService.selectAllActivity();
        HSSFWorkbook hw=new HSSFWorkbook();
        if (list!=null&&list.size()!=0){
            HSSFSheet sheet=hw.createSheet();
            HSSFRow row=sheet.createRow(0);
            HSSFCell cell=row.createCell(0);
            cell.setCellValue("id");
            cell=row.createCell(1);
            cell.setCellValue("所有者");
            cell=row.createCell(2);
            cell.setCellValue("名称");
            cell=row.createCell(3);
            cell.setCellValue("开始日期");
            cell=row.createCell(4);
            cell.setCellValue("结束日期");
            cell=row.createCell(5);
            cell.setCellValue("成本");
            cell=row.createCell(6);
            cell.setCellValue("描述");
            cell=row.createCell(7);
            cell.setCellValue("创建时间");
            cell=row.createCell(8);
            cell.setCellValue("创建者");
            cell=row.createCell(9);
            cell.setCellValue("修改时间");
            cell=row.createCell(10);
            cell.setCellValue("修改者");
            //遍历list
            for (int i=0;i<list.size();i++){
                Activity activity=list.get(i);
                //每遍历出一条记录,都往对应坐标的单元格写数据
                row=sheet.createRow(i+1);
                cell=row.createCell(0);
                cell.setCellValue(activity.getId());
                cell=row.createCell(1);
                cell.setCellValue(activity.getOwner());
                cell=row.createCell(2);
                cell.setCellValue(activity.getName());
                cell=row.createCell(3);
                cell.setCellValue(activity.getStartDate());
                cell=row.createCell(4);
                cell.setCellValue(activity.getEndDate());
                cell=row.createCell(5);
                cell.setCellValue(activity.getCost());
                cell=row.createCell(6);
                cell.setCellValue(activity.getDescription());
                cell=row.createCell(7);
                cell.setCellValue(activity.getCreateTime());
                cell=row.createCell(8);
                cell.setCellValue(activity.getCreateBy());
                cell=row.createCell(9);
                cell.setCellValue(activity.getEditTime());
                cell=row.createCell(10);
                cell.setCellValue(activity.getEditBy());
            }

//            hw.write(fileOutputStream);
//            //关闭资源
//            fileOutputStream.close();
        }
//        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\翟永康\\OneDrive\\桌面\\img\\activity.xls");
        //设置响应数据类型
        response.setContentType("application/octet-stream;charset=utf-8");
        OutputStream out=response.getOutputStream();
        //设置响应头信息,客户端收到响应信息之后,直接激活文件下载窗口,即使能打开也不打开,filename是附加参数意为文件名还能加时间戳
        response.addHeader("Content-Disposition","attachment;filename=activity.xls");
//        InputStream in=new FileInputStream(new File("C:\\Users\\翟永康\\OneDrive\\桌面\\img\\activity.xls"));
//        byte [] buff=new byte[256];//缓冲区,如果不用缓冲区默认每回读一个字节效率低
//        int len=0;
//        while((len=in.read(buff))!=-1){
//            out.write(buff,0,len);
//        }
        hw.write(out);
        //关闭资源,关闭自己new的资源outputstream是tomact,new的tomact管它
        //刷新流
        hw.close();
        out.flush();
    }

描述:还是使用poi插件对HSSFWorkbook对象进行操作Row行,Cell列,实现下载功能,需要设置响应数据类型,响应头信息,使用poi插件的write方法将返回给浏览器

3.市场活动细节

主要功能:显示市场活动细节,有备注

代码:ActivityRemark、ActivityRemarkMapper、ActivityRemarkMapper.xml、ActivityService、ActivityServiceMap

主要部分:

1)备注,对动态标签添加事件

//备注保存按钮添加单击事件
		$("#saveActivityRemarkBtn").click(function (){
			var activityId='${activity.id}';
			var noteContent=$.trim($("#remark").val());
			$("#remarkForm").get(0).reset();//清空表单,添加备注清楚文本框的效果。得在获取值之后清空
			if (noteContent==""){
				alert("内容不能为空");
				return;
			}
			$.ajax({
				url:'workbench/activity/saveCreateActivityRemark.do',
				data:{
					noteContent:noteContent,
					activityId:activityId
				},
				type:'post',
				dataType:'json',
				success:function (data){
					if (data.code=="1"){
						var htmlstr="";
						htmlstr+="<div class=\"remarkDiv\" id=\"div_"+data.retData.id+"\" style=\"height: 60px;\">";
						htmlstr+="<img title=\"${sessionScope.sessionUser.name}\" src=\"image/user-thumbnail.png\" style=\"width: 30px; height:30px;\">";
						htmlstr+="<div style=\"position: relative; top: -40px; left: 40px;\" >";
						htmlstr+="<h5>"+noteContent+"</h5>";
						htmlstr+="<font color=\"gray\">市场活动</font> <font color=\"gray\">-</font> <b>${activity.name}</b> <small style=\"color: gray;\"> "+data.retData.createTime+" 由${sessionScope.sessionUser.name}创建</small>";
						htmlstr+="<div style=\"position: relative; left: 500px; top: -30px; height: 30px; width: 100px; display: none;\">";
						htmlstr+="<a class=\"myHref myHrefEdit\" remarkId=\"${remark.id}\" href=\"javascript:void(0);\"><span class=\"glyphicon glyphicon-edit\" style=\"font-size: 20px; color: #E6E6E6;\"></span></a>";
						htmlstr+="&nbsp;&nbsp;&nbsp;&nbsp;";
						htmlstr+="<a class=\"myHref myHrefRemove\" remarkId=\"${remark.id}\" href=\"javascript:void(0);\"><span class=\"glyphicon glyphicon-remove\" style=\"font-size: 20px; color: #E6E6E6;\"></span></a>"
						htmlstr+="</div>";
						htmlstr+="</div>";
						htmlstr+="</div>";
						$("#remarkDiv").before(htmlstr);
					}else{
						alert(data.message);
					}
				}
			});
		});

 描述:把页面片段动态显示在网页中

还有一个就是上面的$("#remarkDiv").before(htmlstr);,根据使用场景选择,其中生成的是动态标签,动态标签的事件(如jQuery click)和固定标签的事件是不一样的,需要用到父选择器.on("事件","子选择器",function(){});

$("#disableRemark").on("mouseover",".remarkDiv",function (){
			$(this).children("div").children("div").show();
		});
		$("#disableRemark").on("mouseout",".remarkDiv",function (){
			$(this).children("div").children("div").hide();
		});
		//备注修改和删除按钮的css样式改变
		$("#disableRemark").on("mouseover",".myHref",function (){
			$(this).children("span").css("color","red");
		});
		$("#disableRemark").on("mouseout",".myHref",function (){
			$(this).children("span").css("color","#E6E6E6");
		});

 上边就是对动态标签添加事件的例子,其中父选择器必须是固定标签,父选择器范围越小越好

4.交易

主要功能:在创建交易的时候使用了自动补全插件,还有与properties文件键值绑定

代码:TranController、TranService、TranServiceImpl、TransactionMapper.xml、TransactionMapper

主要部分

1)根据前端传给后端的键,通过properties获取对应的值

    @RequestMapping("/workbench/transaction/getPossibiltyByStage.do")
    @ResponseBody
    public Object getPossibiltyByStage(String stage){
        //resources就是根目录,遍历properties文件
        ResourceBundle possibilty = ResourceBundle.getBundle("possibilty");
        String ret = possibilty.getString(stage);
        return ret;
    }

 使用ResourceBundle获取名为possibilty的properties文件,其中properties配置文件的特点就是数据是以键值的形式存放的

	$("#create-transactionStage").change(function (){
		// var stage=$(this).find("option:selected").text();
		var stage=$("#create-transactionStage option:selected").text();//这是第二种上面是第一种
		$.ajax({
			url:'workbench/transaction/getPossibiltyByStage.do',
			data:{
				stage:stage
			},
			type:'post',
			dataType:'json',
			success:function (data){
				$("#create-possibility").val(data);
			}
		});
	});

描述:下拉列表框发生改变就会获取所选选项中的文本值var stage=$("#create-transactionStage option:selected").text();这是第二种上面是第一种,获取文本值发送到后端,作为键查询properties中所对应的值返回给前端显示在可能性文本框中 

2)自动补全功能 

$("#create-accountName").keyup(function (){
		//自动补全动态获取数据
		$("#create-accountName").typeahead({
			source:function (jquery,process){//process里的数据格式是['xxx','xxxxx'...]
				$.ajax({
					url:'workbench/transaction/queryAllCustomerName.do',
					data:{
						customerName:jquery
					},
					type:'post',
					dataType:'json',
					success:function (data){//['xxx','xxxxx'...]
						process(data);
					}
				});
			}
		});
	});

描述:jquery中存放的是id值为create-accountName的文本框中的值,ajax将文本框中的值传给后端,后端进行模糊查询将返回的数据传递给客户端,通过process(data)将返回的数据在客户端上显示

三.其他

1.关于配置文件

1)properties配置文件:

                                        key1=value1

                                        key2=value2

                                        key3=value3

                                        ...

几乎没有冗余数据,效率高,解析相对简单:properties、BundleResource

2)xml配置文件:标签语言

适合配置复杂数据,产生冗余数据,效率低,解析相对复杂:dom4j、jdom

2.后端向前端发送实体类,集合问题

例如在crm项目中

如果在returnobject.setRetData(Object object)中存入的是实体类,那么前端ajax成功返回函数中直接调用data.retData.id,或者其他属性就可以

但是存放的是集合数据,那么就需要$.each(data.retData,function(index.obj){});来遍历集中的集合数据在遍历函数中使用obj.id来获取值

3.关于idea报sql语句错误

1)发现错误日志,sql语句短缺

如customer_id=u,其实应该是customer_id=u1,但实际上mapper.xml文件中sql语句中响应位置并没有短缺,这里其实是因为sql语句有错误并不是误报

2)语句没错但结果为空

如果使用了内外连接则大概率就是因为连接出了问题

3)mapper.xml中传入参数不能同时传入两个对象,多个数据需要使用实体类或集合传递

4.给标签添加属性

1)使用标签保存数据,以便在需要的时候能够获取到这些数据

给标签添加属性:如果是表单组件标签,优先使用value属性,只有value不方便使用时,

                             如果不是表单组件标签,不推荐使用value,推荐使用自定义属性

2)获取属性值时:如果获取表单组件标签的value属性值:

                                                                                                dom对象.value

                                                                                               jquery对象.val()

                                如果自定义的属性,不管是什么标签,只能用:jquery对象.attr("属性名");

5.物理模型设计(表)

1)关于主键设置(大部分为id)

在数据库中如果有一组字段能够唯一确定一条记录的,则可以把他设计成表的主键,推荐使用没有业务含义的字段做主键,比如id

主键值的生成方式有自增、自己通过代码逻辑添加(hi/low、uuid、雪花算法)、还有共享主键、联合主键,其中主键生成方式效率最低的就是自增方式,因为它需要在每次添加记录的时候查询mysql内部一个表获取字段值

6.配置tomact时没有可用的工件以及tomact访问路径问题

在File选项卡下project structure Artifacts下设置添加工件,在modules下配置web.xml路径和web resource路径,有时候tomact启动会提示classnotfounder如java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener

此时就要检查

lib下有没有需要的jar包

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CRM(Customer Relationship Management,客户关系管理)系统是一种帮助企业管理客户关系、提高客户满意度并促进销售的信息化管理系统。SSM框架是指SpringSpringMVC和MyBatis三个框架的集成,是目前较为流行的Java Web开发框架之一。 下面是基于SSM框架的CRM系统设计思路: 1.需求分析:根据企业的实际需求,分析需要实现的功能模块,包括客户管理、销售管理、服务管理等。 2.数据库设计:根据需求分析,设计出数据库表结构,建立相应的表关系,确保数据的完整性和一致性。 3.项目搭建:使用Maven构建项目框架,将SpringSpringMVC和MyBatis三个框架集成起来,搭建出项目的基本框架。 4.编写实体类、DAO层和Service层:根据数据库表结构,编写Java实体类,并在DAO层封装数据访问操作,Service层则负责处理业务逻辑。 5.编写控制器:使用SpringMVC框架编写控制器,处理前端请求,调用Service层处理业务逻辑,并返回相应的视图。 6.编写前端页面:使用HTML、CSS和JavaScript等技术编写前端页面,将数据渲染到页面上,实现用户交互。 7.测试和部署:完成开发后,进行系统测试和调试,并对系统进行部署,使其能够在生产环境中正常运行。 总之,基于SSM框架的CRM系统设计思路包括需求分析、数据库设计、项目搭建、编写实体类、DAO层和Service层、编写控制器、编写前端页面、测试和部署等步骤,通过这些步骤,可以实现一个高效、稳定、易用的CRM系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值