概述
文章目录
- 一.CRM项目技术架构介绍
- 二:软件开发的生命周期
- 三:CRM核心业务介绍
- 四:CRM项目所用到的表以及主键字段和表关系简单分析
- 1.市场活动表
- 2.市场活动备注表外键引用市场活动表主键
- 3.线索表
- 4.线索备注表
- 4.线索市场活动关系表
- 5.联系人表
- 6.联系人备注表
- 7.线索市场活动关系表
- 8.客户表
- 9.客户关系表
- 10.字典类型表(下拉列表字段)
- 11.字段类型具体值表
- 12.交易表
- 13.交易备注表
- 14.交易历史表
- 15.用户表
- 主键生成方式
- 外键与表关系
- 五:项目的规范
- 1.web应用根目录下的内容都是不安全的,外界可以通过url直接访问; 所以,一般为了数据的安全,都会把页面放到WEB-INF下,因为WEB-INF目录下的资源是受保护的,外界不能直接访问。(要通过controller层请求转发才可以访问)
- 2.controller下的方法用public,因为将来是给Springmvc的DispatcherServle这个核心处理器调用的
- 3.请求转发只能访问服务器内部资源
- 4.一个资源目录一个controller类
- 5.@RequestMapping的url要和controller方法所处理完请求之后,响应信息回到的页面的资源目录保持一致,后面加方法名
- 6.一张表,对应一个mapper对应一个service
- 7.所有页面都是jsp页面,并且都配置了base 标签等
- 六:mybatis逆向工程创建数据持久层接口及映射文件
- 1.添加mybatis逆向工程插件
- 2.新建一个普通java项目
- 3.在项目的resources目录下放置配置文件和属性配置文件
- 七:ssm整合配置
- 八:用户登录功能安全退出的实现
- 1.用户访问项目首页,首先进入登录页面。
- 2.登录页面做登录验证
- 3.安全退出功能
- 4.Springmvc拦截器
- 九:市场活动功能
- 1.介绍页面切割和模态窗口的概念
- 2.来到市场活动主页面
- 2.创建市场活动
- 3.市场活动的分页查询功能配合分页插件bs_pagination
- 3.删除市场活动
- 4.全选按钮的实现
- 5.修改市场活动
- 6.批量市场活动(全部导出)
- 7.选择导出
- 8.文件导入
- 技术准备:
- 9.市场活动明细页面
- 10.市场活动详细页面的新增备注功能
- 11.删除市场活动备注功能
- 12.修改市场活动备注功能
- 十:线索模块的功能
- 1.线索页面的显示
- 2.创建线索的实现
- 3.线索的分页查询函数实现
- 4.线索详细页面的显示
- 5.线索详细页面的查询市场活动
- 6.实现线索详细页面的市场活动的关联
- 7.实现线索详细页面的市场活动的删除
- 8.线索详细页面点击转化按钮到转化页面
- 9.转化页面的交易里面的市场活动源搜索关联过得市场活动
- 10.线索详细页面转化按钮的实现
- 十一:交易功能的实现
- 1.用户点击菜单的交易来到交易页面
- 2.交易用户点击创建按钮跳转到创建页面
- 3.在创建页面点击市场活动源
- 4.在创建页面点击联系人
- 5.用户点击阶段直接填入可能性配置
- 6.创建交易页面的客户自动搜索补全(利用插件bs_typeahead自动补全插件)
- 7.用户点击保存,保存交易信息
- 8.查看交易详细信息
- 9.交易详细页面的图标显示
- 十二:CRM用到的插件
- 前端插件使用步骤
- 1.前端日历插件基于bootstrap框架(datetimepicker)
- 2.前端分页插件bs_pagination
- 3.代码搜索自动补全插件bs_typeahead
- 4.java文件插件Apache-poi文件的创建
- 5.图表插件echarts
- 十三:前端通用代码
- 1.向标签中打入数据
- 2.全选框选中与取消
- 3.前端隐藏标签
- 4.给元素扩展属性
- 5.父子选择器与和on函数加事件
- 6.controller返回给前端ajax可以使哪几种数据类型
- 7.,ajax向后台发送请求时,可以通过data提交参数,data的数据格式有三种格式:
一.CRM项目技术架构介绍
1.视图层(view):展示数据,跟用户交互。
html,css,js,jquery,bootstrap(ext|easyUI),jsp
2.控制层(Controller):控制业务处理流程(接收请求,接收参数,封装参数;根据不同的请求调用业务层处理业务;根据处理结果,返回响应信息)
(servlet,)springMVC(,webwork,struts1,struts2)
3.业务层(Service):处理业务逻辑(处理业务的步骤以及操作的原子性)
JAVASE(工作流:activiti|JBPM)
1,添加学生
2,记录操作日志
4.持久层(Dao/Mapper):操作数据库.
(jdbc,)mybatis(,hibernate,ibatis)
tbl_table----------pojo
5.整合层:维护类资源,维护数据库资源
spring(IOC,AOP)(,ejb,corba)
二:软件开发的生命周期
1)招标:
投标:----------标书
甲方:
乙方:
2)可行性分析:---------可行性分析报告
技术,经济
3)需求分析:-----------需求文档
产品经理,需求调研
项目原型:容易确定需求,开发项目时作为jsp网页.
4)分析与设计:
架构设计:----------架构文档
物理架构设计:
应用服务器:tomcat(apache),weblogic(bea–>oracle),websphere(ibm),jboss(redhat),resin(MS)
web javaee:13种协议
servlet,jsp,xml,jdbc
mq …
数据库服务器:mysql,oracle,DB2,sqlserver,达梦
逻辑架构设计:代码分层.
视图层–>控制层–>业务层–>持久层–>数据库
技术选型:java,.net
项目设计:---------项目设计文档
物理模型设计:哪些表,哪些字段,字段的类型和长度,以及表和表之间的关系。
powerdesigner-----xxxx.pdm
逻辑模型设计:哪些类,哪些属性和方法,方法的参数和返回值,以及类和类之间关系。
rational rose-----.pdl
界面设计:企业级应用 朴素 -----项目原型
互联网应用 炫酷
算法设计:------算法设计文档
5)搭建开发环境:-----------技术架构文档
创建项目,添加jar包,添加配置文件,添加静态页面,添加公共类以及其它资源;能够正常启动运行。
6)编码实现:-------注释
7)测试:-----------测试用例
8)试运行:---------使用手册
9)上线:-----------实施文档
10)运维:----------运维手册
三:CRM核心业务介绍
1)CRM项目的简介:Customer Relationship Management 客户关系管理系统
企业级应用,传统应用;给销售或者贸易型公司使用,在市场,销售,服务等各个环节中维护客户关系,
CRM项目的宗旨:增加新客户,留住老客户,把已有客户转化为忠诚客户。
2)CRM是一类项目,我们的CRM是给一个大型的进出口贸易公司来使用的,做大宗商品的进出口贸易;商品是受管家管制的。
3)CRM项目的核心业务:
1.系统管理功能:不是直接处理业务数据,为了保证业务管理的功能正常安全运行而设计的功能。用户登录,安全退出,登录验证等给超级管理员,开发和运维人员使用。
2. 业务管理功能:处理业务数据
市场活动:市场部,设计市场活动营销活动
线索:销售部(初级销售),增加线索
客户和联系人:销售部(高级销售),有效地区分和跟踪客户和联系人.
交易:销售部(高级销售),更好地区分和统计交易的各个阶段。
统计图表:管理层,统计交易表中各个阶段数据量。
四:CRM项目所用到的表以及主键字段和表关系简单分析
1.市场活动表
/表: tbl_activity/---------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
owner char(32) utf8_general_ci YES (NULL) select,insert,update,references
name varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
start_date char(10) utf8_general_ci YES (NULL) select,insert,update,references
end_date char(10) utf8_general_ci YES (NULL) select,insert,update,references
cost varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
description varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
2.市场活动备注表外键引用市场活动表主键
/表: tbl_activity_remark/----------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
note_content varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_flag char(1) utf8_general_ci YES (NULL) select,insert,update,references 0
activity_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
3.线索表
/表: tbl_clue/-----------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
fullname varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
appellation varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
owner char(32) utf8_general_ci YES (NULL) select,insert,update,references
company varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
job varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
email varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
phone varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
website varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
mphone varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
state varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
source varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
description varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
contact_summary varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
next_contact_time char(10) utf8_general_ci YES (NULL) select,insert,update,references
address varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
4.线索备注表
/表: tbl_clue_remark/------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
note_content varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_flag char(1) utf8_general_ci YES (NULL) select,insert,update,references
clue_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
4.线索市场活动关系表
/表: tbl_clue_activity_relation/-----------------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
clue_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
activity_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
5.联系人表
/表: tbl_contacts/---------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
owner char(32) utf8_general_ci YES (NULL) select,insert,update,references
source varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
customer_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
fullname varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
appellation varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
email varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
mphone varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
job varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
description varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
contact_summary varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
next_contact_time char(10) utf8_general_ci YES (NULL) select,insert,update,references
address varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
6.联系人备注表
/表: tbl_contacts_remark/----------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
note_content varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_flag char(1) utf8_general_ci YES (NULL) select,insert,update,references
contacts_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
7.线索市场活动关系表
/表: tbl_contacts_activity_relation/---------------------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
contacts_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
activity_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
8.客户表
/表: tbl_customer/---------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
owner char(32) utf8_general_ci YES (NULL) select,insert,update,references
name varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
website varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
phone varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
contact_summary varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
next_contact_time char(10) utf8_general_ci YES (NULL) select,insert,update,references
description varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
address varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
9.客户关系表
/表: tbl_customer_remark/----------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
note_content varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_flag char(1) utf8_general_ci YES (NULL) select,insert,update,references
customer_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
10.字典类型表(下拉列表字段)
/表: tbl_dic_type/---------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
code varchar(255) utf8_general_ci NO PRI (NULL) select,insert,update,references
name varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
description varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
11.字段类型具体值表
/表: tbl_dic_value/----------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
value varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
text varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
order_no varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
type_code varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
12.交易表
/表: tbl_tran/-----------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
owner char(32) utf8_general_ci YES (NULL) select,insert,update,references
money varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
name varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
expected_date char(10) utf8_general_ci YES (NULL) select,insert,update,references
customer_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
stage varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
type varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
source varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
activity_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
contacts_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
description varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
contact_summary varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
next_contact_time char(10) utf8_general_ci YES (NULL) select,insert,update,references
13.交易备注表
/表: tbl_tran_remark/------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
note_content varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_flag char(1) utf8_general_ci YES (NULL) select,insert,update,references
tran_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
14.交易历史表
/表: tbl_tran_history/-------------------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references
stage varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
money varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
expected_date char(10) utf8_general_ci YES (NULL) select,insert,update,references
create_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
tran_id char(32) utf8_general_ci YES (NULL) select,insert,update,references
15.用户表
/表: tbl_user/-----------------
/列信息/-----------
Field Type Collation Null Key Default Extra Privileges Comment
id char(32) utf8_general_ci NO PRI (NULL) select,insert,update,references uuid
login_act varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
name varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
login_pwd varchar(255) utf8_general_ci YES (NULL) select,insert,update,references 密码不能采用明文存储,采用密文,MD5加密之后的数据
email varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
expire_time char(19) utf8_general_ci YES (NULL) select,insert,update,references 失效时间为空的时候表示永不失效,失效时间为2018-10-10 10:10:10,则表示在该时间之前该账户可用。
lock_state char(1) utf8_general_ci YES (NULL) select,insert,update,references 锁定状态为空时表示启用,为0时表示锁定,为1时表示启用。
deptno char(4) utf8_general_ci YES (NULL) select,insert,update,references
allow_ips varchar(255) utf8_general_ci YES (NULL) select,insert,update,references 允许访问的IP为空时表示IP地址永不受限,允许访问的IP可以是一个,也可以是多个,当多个IP地址的时候,采用半角逗号分隔。允许IP是192.168.100.2,表示该用户只能在IP地址为192.168.100.2的机器上使用。
createTime char(19) utf8_general_ci YES (NULL) select,insert,update,references
create_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
edit_time char(19) utf8_general_ci YES (NULL) select,insert,update,references
edit_by varchar(255) utf8_general_ci YES (NULL) select,insert,update,references
主键生成方式
1)主键字段:在数据库表中,如果有一组字段能够唯一确定一条记录,则可以把它们设计成表的主键字段。
推荐使用一个字段做主键,而且推荐使用没有业务含义的字段做主键,比如:id等。
主键字段的类型和长度由主键值的生成方式来决定:
主键值的生成方式:
1)自增:借助数据库自身主键生成机制
数值型 长度由数据量来决定
运行效率低
开发效率高
2)assighed:程序员手动生成主键值,唯一非空,算法.
hi/low:数值型 长度由数据量决定
UUID:字符串 长度是32位(这个CRM项目使用)
3)共享主键:由另一张表的类型和长度决定
tbl_person tbl_card
id name id name
1001 zs 1001 card1
1002 ls
4)联合主键:由多个字段的类型和长度决定
外键与表关系
2)外键字段:用来确定表和表之间的关系。
1)一对多:一张表(A)中的一条记录可以对应另一张表(B)中的多条记录;
另一张表(B)中的一条记录只能对应一张表(A)中的一条记录。
添加数据时,先添加父表记录,再添加子表记录;
删除数据时,先删除子表记录,再删除父表记录;
内连接:查询所有符合条件的数据,并且要求结果在两张表中都有相对应的记录
左外连接:查询左侧表中所有符合条件的数据,即使在右侧表中没有相对应的记录
*如果外键不能为空,优先使用内连接;
如果外键可以为空,
–假如只需要查询那些在另一张表中有相对应的记录,使用内连接
–假如需要查询左侧表中所有符合条件的记录,使用左外连接.
2)一对一:一张表(A)中的一条记录只能对应另一张表(B)中的一条记录;
另一张表(B)中的一条记录也只能对应一张表(A)中的一条记录。
a)共享主键:(不推荐)
添加数据:先添加先产生的表,再后产生的表记录
删除数据:先删除后产生的表记录,再删除先产生的表记录
查询数据:无需进行连接查询
b)唯一外键:
*一对一就是一种特殊的一对多。
*操作跟一对多完全一样。
3)多对多:一张表(A)中的一条记录可以对应另一张表(B)中的多条记录;
另一张表(B)中的一条记录也可以对应一张表(A)中的多条记录。
添加数据时,先添加父表记录,再添加子表记录;
删除数据时,先删除子表记录,再删除父表记录
查询数据时,可能会进行关联查询:
五:项目的规范
1.web应用根目录下的内容都是不安全的,外界可以通过url直接访问; 所以,一般为了数据的安全,都会把页面放到WEB-INF下,因为WEB-INF目录下的资源是受保护的,外界不能直接访问。(要通过controller层请求转发才可以访问)
2.controller下的方法用public,因为将来是给Springmvc的DispatcherServle这个核心处理器调用的
3.请求转发只能访问服务器内部资源
4.一个资源目录一个controller类
5.@RequestMapping的url要和controller方法所处理完请求之后,响应信息回到的页面的资源目录保持一致,后面加方法名
6.一张表,对应一个mapper对应一个service
7.所有页面都是jsp页面,并且都配置了base 标签等
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<%String bg=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";%>
<meta charset="UTF-8">
<base href="<%=bg%>">
六:mybatis逆向工程创建数据持久层接口及映射文件
1.添加mybatis逆向工程插件
<!--myBatis逆向工程插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
2.新建一个普通java项目
3.在项目的resources目录下放置配置文件和属性配置文件
这是属性配置文件
jdbc.driverLocation=E:/apache-maven-3.5.0/repository/mysql/mysql-connector-java/5.1.32/mysql-connector-java-5.1.32.jar
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://127.0.0.1:3306/crm2008
jdbc.userId=root
jdbc.password=xxxxxx
这是逆向工程的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--指定mysql数据库驱动-->
<!--<classPathEntry location="E://repository-p2p//mysql//mysql-connector-java//5.1.43//mysql-connector-java-5.1.43.jar"/>-->
<!--导入属性配置-->
<properties resource="generator.properties"></properties>
<!--指定特定数据库的jdbc驱动jar包的位置-->
<classPathEntry location="${jdbc.driverLocation}"/>
<context id="default" targetRuntime="MyBatis3">
<!-- optional,旨在创建class时,对注释进行控制,false生成注释,true无注释 -->
<commentGenerator>
<property name="suppressDate" value="false"/>
<property name="suppressAllComments" value="false"/>
</commentGenerator>
<!--jdbc的数据库连接 -->
<jdbcConnection
driverClass="${jdbc.driverClass}"
connectionURL="${jdbc.connectionURL}"
userId="${jdbc.userId}"
password="${jdbc.password}">
</jdbcConnection>
<!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
targetPackage 指定生成的model生成所在的包名
targetProject 指定在该项目下所在的路径|指定生成到的工程名称
-->
<javaModelGenerator targetPackage="com.zeng.crm.shi.TranHistory"
targetProject="E:/java220729/crm-project/crm/src/main/java">
<!-- 是否允许子包,即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="false"/>
<!-- 是否对model添加 构造函数 true添加,false不添加-->
<property name="constructorBased" value="false"/>
<!-- 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
<!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
</javaModelGenerator>
<!--Mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
<sqlMapGenerator targetPackage="com.zeng.crm.Mapper.TranHistory"
targetProject="E:/java220729/crm-project/crm/src/main/java">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
-->
<javaClientGenerator targetPackage="com.zeng.crm.Mapper.TranHistory"
targetProject="E:/java220729/crm-project/crm/src/main/java" type="XMLMAPPER">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--这个是配置数据库中的那张表生成持久层和实体类-->
<table tableName="tbl_tran_history" domainObjectName="TranHistory"
enableCountByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableSelectByExample="false"
selectByExampleQueryId="false">
</table>
</context>
</generatorConfiguration>
七:ssm整合配置
配置的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.zeng</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>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</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>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>
配置的mybatis核心配置文件
<?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>
<!--设置日志输出语句,显示相应操作的sql语名-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
配置spring的配置文件
applicationContext_mapper.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--配置属性配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--配置数据源-->
<bean id="mysql" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置sqlsessionFabean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="mysql"></property>
<!--配置sqlmapConfig核心配置文件-->
<property name="configLocation" value="classpath:sqlmapConfig.xml"></property>
<!--实体类起别名-->
<property name="typeAliasesPackage" value="com.zeng.crm.shi"></property>
</bean>
<!--注册mapper.xml文件-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zeng.crm.Mapper"></property>
</bean>
</beans>
配置applicationContext_service.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描包路径-->
<context:component-scan base-package="com.zeng.crm.Service"></context:component-scan>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="mysql"></property>
</bean>
<!-- 添加事务的切面-->
<tx:advice id="myadvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*select*" read-only="true"/>
<tx:method name="*find*" read-only="true"/>
<tx:method name="*get*" read-only="true"/>
<tx:method name="*search*" read-only="true"/>
<tx:method name="*insert*" propagation="REQUIRED"/>
<tx:method name="*save*" propagation="REQUIRED"/>
<tx:method name="*add*" propagation="REQUIRED"/>
<tx:method name="*delete*" propagation="REQUIRED"/>
<tx:method name="*remove*" propagation="REQUIRED"/>
<tx:method name="*clear*" propagation="REQUIRED"/>
<tx:method name="*update*" propagation="REQUIRED"/>
<tx:method name="*modify*" propagation="REQUIRED"/>
<tx:method name="*change*" propagation="REQUIRED"/>
<tx:method name="*set*" propagation="REQUIRED"/>
<tx:method name="*xinsuozhuanhau*" propagation="REQUIRED"></tx:method>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 完成切面和切入点的织入-->
<aop:config>
<aop:pointcut id="mypointcut" expression="execution(* com.zeng.crm.Service.*.*.*(..))"/>
<aop:advisor advice-ref="myadvice" pointcut-ref="mypointcut"></aop:advisor>
</aop:config>
</beans>
配置springmvc
<?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 />-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!-- spring mvc 扫描包下的controller -->
<context:component-scan base-package="com.zeng.crm.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>
<!-- 配置文件上传解析器 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>
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor> <!--拦截这两开头的controller请求 因为所有cntroller的url都遵循规范-->
<mvc:mapping path="/settings/**"/>
<mvc:mapping path="/workbench/**"/>
<!--不拦截去登录页面 和点击登录验证的请求-->
<mvc:exclude-mapping path="/settings/qx/user/tolge.do"/>
<mvc:exclude-mapping path="/settings/qx/user/ypwsfan.do"/>
<bean class="com.zeng.crm.Interceptor.lanjiedenglu"></bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
数据库的属性配置文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/crm2008?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=
配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置中文编码 @Nullable
private String encoding;
private boolean forceRequestEncoding;
private boolean forceResponseEncoding;-->
<filter>
<filter-name>zhong</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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>zhong</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置springmvc框架-->
<servlet>
<servlet-name>ss</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup><!--服务器启动就加载-->
</servlet>
<servlet-mapping>
<servlet-name>ss</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ss</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!--配置spring的监听器 自启动applicationContext容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
<!--指定spring的两个配置文件-->
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext_*.xml</param-value>
</context-param>
<!--欢迎页面设置-->
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
</web-app>
八:用户登录功能安全退出的实现
1.用户访问项目首页,首先进入登录页面。
配置欢迎页,在web.xml中
<!--欢迎页面设置-->
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
配置欢迎页所设置的路径的controller方法跳转到index.jsp页面
@RequestMapping("/")
public String godeng(){
return "index";
}
<script type="text/javascript">/*这里加/项目名 不加不写/开始也行*/
window.location.href = "<%=request.getContextPath()%>/settings/qx/user/tolge.do";
</script>
index.jsp页面再用过访问controller层访问登录页面
/*url要写成完成响应到哪个资源的得目录下 就是响应到的那个资源的目录*/
@RequestMapping("/settings/qx/user/tolge.do")
public String tologe(){
return "settings/qx/user/login";
}
2.登录页面做登录验证
前端jsp代码
<%--拿到登录dom对象 得到数据 发送Ajax--%>
<script>
$(function (){
/*在整个页面加载完成之后给一个窗口加键盘按下事件 再通过keycode来判断是不是按下
* 了Enter键 按下了就发ajax请求 这里可以直接调用登录的点击事件$("#deng").click()无参数 */
$(window).keydown(function (event){//这里参数代表整个事件源 可以直接获取事件的相关信息
//alert(event.keyCode)
if(event.keyCode==13){
$("#deng").click()
}
})
$("#deng").click(function (){
var zhanghu = $.trim($("#text").val());
var mima = $.trim($("#password").val());
var shitain = $("#checkbox").prop("checked");
if(zhanghu==""){
alert("账户不能为空")
return;
}
if(mima==""){
alert("密码不能为空")
return;
}
$.ajax({
url:"settings/qx/user/ypwsfan.do" ,
type:"POST",
data:{
loginAct:zhanghu,
loginPwd:mima,
idRemPwd:shitain},
dataType:"json",
success:function (data){
if(data.code=="0"){
$("#msg").html(data.message)
}
if(data.code=="1"){
/*登陆成功跳转页面 因为要请求转发访问私有 所以跳到controller*/
window.location.href="workbench/index.do";
}
},
beforeSend:function (){
/*这个函数是在发送ajax请求之前执行的 这个函数的返回值如果是true 则执行玩这个函数就发
* 如果是false就不发*/
$("#msg").text("正在加载请稍后.......")
}
})
})
})
</script>
后端controller层接收请求代码
@RequestMapping("/settings/qx/user/ypwsfan.do")
@ResponseBody /*ajax请求*/ /*这个参数名要与前端传过来的数据名称一致*/
public Object ypwsfan(String loginAct, String loginPwd, String idRemPwd,
HttpServletResponse response,
HttpServletRequest request, HttpSession session){
/*用户名或者密码错误,用户已过期,用户状态被锁定,ip受限 都不能登录成功*/
/*1接收参数 2封装参数 3.调用servic不同的方法 4.返回响应信息*/
Map<String,Object> map=new HashMap<>();
map.put("loginAct",loginAct); /*这里的name要与mapper.xml的#{name}一致*/
map.put("loginPwd",loginPwd);
User user = UserServic.selectUserLoginActandPwd(map);
/*返回json用实体类返回自动转json*/
usercan usercan = new usercan();
if(user==null){
//用户民或者密码错误
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("用户民或者密码错误");
}else{
String getdate = SimDate.getdate(new Date()); //获取当前时间的字符串
/*获取请求时的IP*/
String remoteAddr = request.getRemoteAddr();
if(getdate.compareTo(user.getExpireTime())>0){
//过没过期
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("用户民已经过期");
}
else if(user.getLockState().equals("0")){
//用户状态
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("用户已锁定");
}
else if(!(user.getAllowIps().contains(remoteAddr))){
//ip范围
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("用户IP受限");
}
//登录成功
else {
usercan.setCode(chang.CODE_SUCCESS);
usercan.setMessage("登陆成功");
/*登陆成功往session域里面传数据 传整个user 其他页面就可以用了*/
session.setAttribute(chang.SESSION_NAME,user);
/*登录成功看是否相中了十天内免登录 选了则创建cookie 没选了则销毁cookie*/
if(idRemPwd.equals("true")){
Cookie username = new Cookie("username", user.getLoginAct());
Cookie password = new Cookie("password", user.getLoginPwd());
username.setMaxAge(60*60*24*10);
password.setMaxAge(60*60*24*10);
response.addCookie(username);
response.addCookie(password);
}else {
Cookie username = new Cookie("username","1");
Cookie password = new Cookie("password", "1");
username.setMaxAge(0); /*销毁浏览器上的同名cookie*/
password.setMaxAge(0);
response.addCookie(username);
response.addCookie(password);/* 首先默认情况下,如果不设置Cookie的path,默认是“/项目名/当前路径的上一层地址”,
如:请求路径:/cookie/cookieDome/servlet/login,Cookie的请求路径:/cookie/cookieDome/servlet*/
}
}
}
return usercan; //会自动转json 因为插件
}
mapper验证用户名密码是否正确的sql语句
<select id="queryUserLoginActandPwd" resultMap="BaseResultMap" parameterType="map">
select <include refid="Base_Column_List"></include>
from tbl_user
where login_act=#{loginAct} and login_pwd=#{loginPwd}
</select>
选中十天内免登录的页面显示
<div style="width: 350px;"> <%--在这里直接获取浏览器发来的cookie--%>
<input class="form-control" id="text" type="text" value="${cookie.username.value}" placeholder="用户名">
</div>
<div style="width: 350px; position: relative;top: 20px;">
<input class="form-control" id="password" type="password" value="${cookie.password.value}" placeholder="密码">
</div>
<div class="checkbox" style="position: relative;top: 30px; left: 10px;">
<label><%--引入jstl标签库 用if来判断cookie是否为空--%>
<c:if test="${not empty cookie.username and not empty cookie.password}"
var="v">
<input id="checkbox" type="checkbox" checked> 十天内免登录
</c:if>
<c:if test="${empty cookie.username and empty cookie.password}"
>
<input id="checkbox" type="checkbox"> 十天内免登录
</c:if>
</label>
<span id="msg"></span>
</div>
3.安全退出功能
用户点击安全退出要清空cookie和销毁session
删除浏览器中的同名cookie
Cookie username = new Cookie("username","1");
Cookie password = new Cookie("password", "1");
username.setMaxAge(0); /*销毁浏览器上的同名cookie*/
password.setMaxAge(0);
response.addCookie(username);
response.addCookie(password);
销毁session
session.invalidate()
退出完成之后跳转到主页面
/*处理安全退出的请求*/
@RequestMapping("/settings/qx/user/tuichu.do")
public String tuichu(HttpSession session,HttpServletResponse response){
/*删除cookie 销毁session 返回登录页面*/
Cookie username = new Cookie("username","1");
Cookie password = new Cookie("password", "1");
username.setMaxAge(0); /*销毁浏览器上的同名cookie*/
password.setMaxAge(0);
response.addCookie(username);
response.addCookie(password);/* 首先默认情况下,如果不设置Cookie的path,默认是“/项目名/当前路径的上一层地址”,
如:请求路径:/cookie/cookieDome/servlet/login,Cookie的请求路径:/cookie/cookieDome/servlet*/
session.invalidate(); //直接销毁服务器端session
return "redirect:/"; //这里要用重定向 借助springmvc来重定向的 所以不要加/项目名 低层执行response.send...
}
4.Springmvc拦截器
拦截器:
a)提供拦截器类:implements HandlerInterceptor{
–pre
–post
–after
}
public class lanjiedenglu implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
/*在请求被处理前执行这个拦截 判断是否登录过 session里有没有数据*/
HttpSession session = httpServletRequest.getSession();
User user = (User)session.getAttribute(chang.SESSION_NAME);
if(user==null){
/*说明用户没有登录过 拦截 跳到登录页面*/
httpServletResponse.sendRedirect("/crm");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
b)配置拦截器:springmvc.xml
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor> <!--拦截这两开头的controller请求 因为所有cntroller的url都遵循规范-->
<mvc:mapping path="/settings/**"/>
<mvc:mapping path="/workbench/**"/>
<!--不拦截去登录页面 和点击登录验证的请求-->
<mvc:exclude-mapping path="/settings/qx/user/tolge.do"/>
<mvc:exclude-mapping path="/settings/qx/user/ypwsfan.do"/>
<bean class="com.zeng.crm.Interceptor.lanjiedenglu"></bean>
</mvc:interceptor>
</mvc:interceptors>
九:市场活动功能
1.介绍页面切割和模态窗口的概念
<div>和<iframe>:
<div>:切割页面。
<div style="height:10%;width=20%">
<iframe>:显示页面。
<div style="height:10%;width=20%">
<iframe href="url">可以起name
</div>
window.open("打开网页的地址","把网页打开到哪个iframe里面 name属性")
模态窗口:模拟的窗口, 本质上是div,通过设置z-index大小来实现的;
初始时,z-index初始参数是<0,所以不显示;
需要显示时,z-index值设置成>0即可。
bootstrap前端框架来控制z-index的大小。
控制模态窗口的显示与隐藏:
1)方式一:通过标签的属性data-toggle=“modal” data-target=“模态窗口的id”
2)方式二:通过js函数控制:
选择器(选中div).modal(“show”);//显示选中的模态窗口
选择器(选中div).modal(“hide”);//关闭选中的模态窗口
3)方式三:通过标签的属性data-dismiss=“modal”
点击添加了data-dismiss=“modal"属性的标签,自动关闭该标签所在的模态窗口。
模态窗口的意义:
window.open(“url”,”_blank");
模态窗口本质上就是原来页面中的一个div,只有一个页面;所有的操作都是在同一个页面中完成。
2.来到市场活动主页面
用户点击市场活动,发同步请求,跳到市场活动的主页面
<li class="liClass"><a href="workbench/activity/AllUsers.do" target="workareaFrame"><span class="glyphicon glyphicon-play-circle"></span> 市场活动</a></li>
这个接收请求的controller还查询市场活动主页面所需要的数据,调用service层查询
@RequestMapping("/workbench/activity/AllUsers.do")
public String AllUsers(HttpServletRequest request){
/*查到所有用户 把数据方入request域中 请求转发到/activity/index.jsp页面*/
List<User> users = servic.selectAllUsers();
request.setAttribute("users",users);
return "workbench/activity/index";
}
把查询到的结果通过Request域请求转发到主页面
主页面从域中取出数据显示到页面
<select class="form-control" id="create-marketActivityOwner">
<c:forEach items="${users}" var="u">
<option value="${u.id}">${u.name}</option>
</c:forEach>
</select>
2.创建市场活动
用户点击创建,弹出创建市场活动的模态窗口
$("#chuang").click(function (){
/*点击创建就让这个模态窗口中的from表单重置数据 用dom对象的方法*/
$("#chuangmo").get(0).reset()
/*给创建按钮加一个单击事件 点击则显示模态窗口*/
$("#createActivityModal").modal("show")
})
用户填写表单,点击保存发送ajax异步请求,收集参数,所有用户填写的参数发给后端
/*发ajax请求*/
$("#baocun").click(function (){
/*表单验证 先获得参数*/
var owner = $("#create-marketActivityOwner").val();//所有者的iD
var name = $("#create-marketActivityName").val();//活动名
var startDate = $("#create-startTime").val();//开始日期
var endDate = $("#create-endTime").val();//结束日期
var cost = $("#create-cost").val();//成本
var description = $("#create-describe").val();//描述
if(owner==""){
alert("所有者不能为空")
return;
}
if(name==""){
alert("活动名不能为空")
return;
}
if(startDate!="" && endDate!=""){
if(startDate>=endDate){
alert("日期填写错误")
return;
}
}
var zhengze=/^(([1-9]d*)|0)$/;//定义一个正则表达式
if(!zhengze.test(cost)){ //用正则表达式.test来验证cost
alert("成本只能是非负整数")
return;
}
$.ajax({
url:"workbench/activity/saveCreateActivity.do",
data:{
owner:owner,
name:name,
startDate:startDate,
endDate:endDate,
cost:cost,
description:description
},
dataType:"json",
type:"POST",
success:function (data) {
if(data.code=="1"){
//关闭模态窗口
$("#createActivityModal").modal("hide")
//刷新市场活动列,显示第一页数据,保持每页显示条数不变(到时候在写)
queryhuodong(1,$("#fenye").bs_pagination('getOption','rowsPerPage'))
alert("添加成功")
}
if(data.code=="0"){
$("#createActivityModal").modal("show")
//显示错误信息 保持模态窗口
alert(data.message)
}
}
})
})
在controller里接收参数,封装参数为市场活动实体类,调用service层方法,返回响应信息是否增加成功
/*添加市场活动*/
@RequestMapping("/workbench/activity/saveCreateActivity.do")
@ResponseBody /*用springmvc实体类拿到参数*/
public Object saveCreateActivity(Activity activity, HttpSession session){
/*id createTime创建时间 createBy由谁创建应该是当前用户是谁就谁创建的session */
activity.setId(UUIDsaner.getUUID());//UUID生成id32位
activity.setCreateTime(SimDate.getdate(new Date())); //取得当前时间转化为字符串
User user= (User) session.getAttribute(chang.SESSION_NAME);
activity.setCreateBy(user.getId()); //这个是由user的ID
/*需要先处理看业务逻辑层有没有异常*/
usercan usercan = new usercan();
try {
int i = actyServoce.insertActivity(activity);
if(i!=0){
usercan.setCode(chang.CODE_SUCCESS);
usercan.setMessage("添加成功");
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("出现网络繁忙请稍后重试。。。");
}
}catch(Exception e){
e.printStackTrace();//打印异常信息
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("出现网络繁忙请稍后重试。。。");
}
return usercan;
}
在ajax回调函数里面,如果响应信息是成功则关闭窗口,刷新局部页面,如果失败则不关闭模态窗口,但要提示错误信息
3.市场活动的分页查询功能配合分页插件bs_pagination
用户一点击市场活动,来到主页面,在<script 里面就要分页查询市场活动的记录条数显示到页面,发送的是ajax异步请求,要收集参数,按条件查询的参数,但这些条件在sql语句中只能是动态sql,还要每页显示条数和页号作为参数
前端查询函数
/*要把beginNo 和 pagesize定义成函数的参数 应为这两个是要根据用户点动态改变的*/
function queryhuodong(beginNo,pagesize){
/*这里发查询的ajax请求*/
//先获取数据
var name = $("#mingcheng").val();
var owner = $("#suoyouzhe").val();
var startDate = $("#startTime").val();
var endDate = $("#endTime").val();
var beginNo=beginNo; /*初始的时候是1 每页显示10页*/
var pagesize=pagesize;
//发ajax请求
$.ajax({
url:"workbench/activity/queryzong.do",
data:{
name:name,
owner:owner,
startDate:startDate,
endDate:endDate,
beginNo:beginNo,
pagesize:pagesize
},
type:"POST",
dataType: "json",
success:function (data){
/*执行这个拼接字符串 打入表单*/
var html='';
$.each(data.activities,function (i,actv){
html+="<tr class="active">" /*这里的复选框是放的活动的id*/
html+="<td><input type="checkbox" value='"+actv.id+"' /></td>" /*这里改这个超链接 传参数id*/
html+="<td><a style="text-decoration: none; cursor: pointer;" οnclick="window.location.href='workbench/activity/selectActivityandbeizhu.do?id="+actv.id+"'">"+actv.name+"</a></td>"
html+="<td>"+actv.owner+"</td>"
html+="<td>"+actv.startDate+"</td>"
html+="<td>"+actv.endDate+"</td>"
html+="</tr>"
})
$("#huodongbiao").html(html)
/*在每次刷新数据的时候 都把全选设置为false*/
$("#quanxuan").prop('checked',false);
/*计算总页数*/
var zongye=1;/*如果总记录条数摸每页显示条数 不为0 就是总记录条数除每页显示条数取整数加一*/
if(data.zongtiao%pagesize==0){
zongye=data.zongtiao/pagesize;
}else {/*js的系统函数 parseInt()将这个数取整数部分*/
zongye=parseInt(data.zongtiao/pagesize)+1;
}
/*要在这个函数的ajax的回掉函数里加插件查询函数 应为要获取参数 每页条数和总页数和总记录条数 而且
* 每发一次请求这个插件的信息要跟着变*/
$("#fenye").bs_pagination({
currentPage:beginNo,//当前页号 参数传
totalRows:data.zongtiao,//总记录条数 ajax返回了
totalPages:zongye, //总页数是这个函数的必填值 是根据总记录条数 每页显示条数算出来的
rowsPerPage:pagesize,//每页显示条数
visiblePageLinks: 5,//这个是那个卡片数最多5个
showGoToPage: true,//显示跳转部分 默认true显示
showRowsPerPage: true,//显示设置每页条数 默认true显示
showRowsInfo: true,//显示记录的信息部分 默认true显示
onChangePage:function (event,objpage) {
/*这个是每次页号发生改变就会执行这个函数 第一个参数是这个事件源
* 第二个参数是这个 页面对象 包含的是外面的函数发生页号改变的所有属性信息
* 页号发生改变 上面的属性值也会跟着变*/
//当页号发生改变是 再次调用这个函数 去打请求刷新这个页面 把改变后的当前页号和每页显示条数传给他
queryhuodong(objpage.currentPage,objpage.rowsPerPage);
}
})
}
})
}
controller层代码
/*按条件查 市场活动*/
@RequestMapping("/workbench/activity/queryzong.do")
@ResponseBody /*这个参数要和前端传过来的参数名一致*/
public Object queryzong(String name,String owner,String startDate,
String endDate,int beginNo,int pagesize){
/*封装参数 map的key要和mapper.xml的#{name}一致*/
Map<String,Object> map=new HashMap<>();
map.put("name",name);
map.put("owner",owner); /*这里的前四个条件时可以为空的 应为用了动态sql*/
map.put("startDate",startDate);
map.put("endDate",endDate);
map.put("beginNo",(beginNo-1)*pagesize); //分页公式
map.put("pagesize",pagesize);
/*调用业务逻辑层返回数据*/
List<Activity> activities = actyServoce.selectActivityByConditionForPage(map);
int i = actyServoce.queryCountOfActivityByzong(map);
/*利用map封装参数*/
Map<String,Object> map1=new HashMap<>();
map1.put("activities",activities);
map1.put("zongtiao",i);
/*返回数据*/
return map1;
}
查询sql语句
<select id="selectActivityByConditionForPage" parameterType="map" resultMap="BaseResultMap">
select a.id,u1.name as owner,a.name,a.start_date,a.end_date,
a.cost,a.description,a.create_time,u2.name as create_by,
a.edit_time,u3.name as edit_by
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
join tbl_user as u2 on a.create_by=u2.id
left join tbl_user as u3 on a.edit_by=u3.id
<where>
<if test="name!=null and name!=''">
and a.name like concat('%',#{name},'%')
</if>
<if test="owner!=null and owner!=''">
and u1.name like concat('%',#{owner},'%')
</if>
<if test="startDate!=null and startDate!=''">
and a.start_date >= #{startDate}
</if>
<if test="endDate!=null and endDate!=''">
and a.end_date <= #{endDate}
</if>
</where>
order by a.create_time desc
limit #{beginNo},#{pagesize}
</select>
<select id="queryCountOfActivityByzong" resultType="int" parameterType="map">
select count(*)
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
join tbl_user as u2 on a.create_by=u2.id
left join tbl_user as u3 on a.edit_by=u3.id
<where>
<if test="name!=null and name!=''">
and a.name like concat('%',#{name},'%')
</if>
<if test="owner!=null and owner!=''">
and u1.name like concat('%',#{owner},'%')
</if>
<if test="startDate!=null and startDate!=''">
and a.start_date >= #{startDate}
</if>
<if test="endDate!=null and endDate!=''">
and a.end_date <= #{endDate}
</if>
</where>
</select>
在jsp页面中直接调用这个查询函数
/*首先进入页面 默认显示第一页 和每页显示十条*/
queryhuodong(1,10);
3.删除市场活动
用户选择要删除的市场活动,点击删除,发送jajx异步请求,把选中的市场活动id全部传给controller层数组
$("#shanchu").click(function (){
/*收集参数 发ajax请求*/
var s=$("#huodongbiao input[type='checkbox']:checked");
if(s.size()==0){
alert("请选择要删除的数据")
return
}
if(window.confirm("确认要删除吗,,,不可恢复哈")){
var str="";
/*遍历这个被选中的数组 然后做字符串的拼接 id=name1&id=name2*/
$.each(s,function (){ //点value是获取属性值
str+="id="+this.value+"&"
})
str=str.substr(0,str.length-1)
$.ajax({
url:"workbench/activity/deletehuodong.do",
data:str,
dataType:'json',
type:"POST",
success:function (data){
if(data.code=="1"){
queryhuodong($("#fenye").bs_pagination('getOption','currentPage'),$("#fenye").bs_pagination('getOption','rowsPerPage'))
}
if(data.code=="0"){
alert(data.message)
}
}
})
}
})
在controller层用string[] 数组来接收同一参数名不同参数值的数据,
/*删除市场活动*/
@RequestMapping("/workbench/activity/deletehuodong.do")
@ResponseBody //这里的入参是字符串数组 参数名要和前端的参数一
//前端的参数用id=name&id=name2的形式传过来
public Object deletehuodong(String[] id){
usercan usercan = new usercan();
/*只要是增删改都要try业务逻辑层有没有异常*/
try {
int i = actyServoce.deleteActivityByIds(id);
if(i>0){
usercan.setCode(chang.CODE_SUCCESS);
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统异常请稍后");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统异常请稍后");
}
return usercan;
}
调用mapper层批量删除用Foreach标签
<delete id="deleteActivityByIds" parameterType="String">
delete from tbl_activity where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id} /*这里的collection有三个参数 item是代表了遍历出来的一个对象 */
</foreach>
</delete>
controller返回响应信息成功或者失败
在页面端成功就调用查询函数刷新,不成功就提示错误信息
4.全选按钮的实现
事件函数里的this带表当前正在发生这个事件的dom对象
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
/*给全选按钮加单击事件 全选列表则全选 这种加事件的方式只能给固有元素加事件
* 固有元素:当调用事件函数给元素添加事件时,如果元素已经生成,则这些元素叫做固有元素;*/
$("#quanxuan").click(function (){
/*全选的checked属性是true则 列表的checked属性值也是true*/
/*获取全部的列表 父子选择器 中间是空格 则可以筛选所有的子标签 中间是>则只能筛选一级字标签 【属性过滤】
* this代表当前事件元素的dom对象 */
$("#huodongbiao input[type='checkbox']").prop('checked',this.checked)
})
/*给所有列表元素加单击事件 只要有一行没被选中 则全选变暗 如果都全部手动选中 则全选变亮*/
/*这里因为链表是动态生成的 ajax异步请求不用等待排队 所以当加单击事件时 列表元素还没有生成 所有要用另一种
* jquery给元素加事件的方式 这种方式既可以给固有元素加也可以给动态生成的元素加*/
$("#huodongbiao").on('click',"input[type='checkbox']",function () {
/* 父元素:必须是固有元素,可以直接父元素,也可以是间接父元素.
* 事件类型 子选择器 函数*/
//可以获取列表的长度 与列表中被选中的列表长度作比较 如果相等说明全都选中了 反之没有
if($("#huodongbiao input[type='checkbox']").size()==$("#huodongbiao input[type='checkbox']:checked").size()) {
$("#quanxuan").prop('checked',true);
}else{
$("#quanxuan").prop('checked',false);
}
})
5.修改市场活动
用户在市场活动主页面,选择要修改的市场活动,点击"修改"按钮,弹出修改市场活动的模态窗口;
用户在修改市场活动的模态窗口填写表单,点击"更新"按钮,完成修改市场活动的功能.
*每次能且只能修改一条市场活动
*所有者 动态的
*表单验证(同创建)
*修改成功之后,关闭模态窗口,刷新市场活动列表,保持页号和每页显示条数都不变
*修改失败,提示信息,模态窗口不关闭,列表也不刷新
大概步骤
用户点击修改,先发送ajax请求,参数为市场活动的id,去查询这个市场活动的全部信息
/*给修改家单击事件 获取参数 发ajax请求 把响应的数据射到相应的框框中*/
$("#xiugai").click(function (){
var s= $("#huodongbiao input[type='checkbox']:checked");
/*只能选中一个 其他都不行*/
if(s.size()==0){
alert("请选中一个要修改的数据")
return
}
if(s.size()>1){
alert("一次只能修改一个数据")
return
}
/*获取选中的option的value*/
var id=s.val();
$.ajax({
url:"workbench/activity/selectAllByIdActivity.do",
data: {id},
dataType:"json",
type:"POST",
success:function (data){
/*把所有者的(用户)id射到select标签的value里 就会自动选中与这个value相等的option*/
$("#edit-marketActivityOwner").val(data.owner)
/*要把市场活动的id给一个隐藏的标签里面 修改点击保存发请求要用*/
$("#shichangid").val(data.id)
$("#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")
}
})
})
controller层接收到参数,去调用查返回市场活动的实体类对象,return返回
/*点击修改发请求显示这条点击了修改的数据*/
@RequestMapping("/workbench/activity/selectAllByIdActivity.do")
@ResponseBody
public Object selectAllByIdActivity(String id){
/*封装参数 调用业务逻辑层 响应信息*/
Activity activity = actyServoce.selectAllById(id);
return activity;
}
前端在修改市场活动的模态窗口先显示查到的数据
/*给更新加单击事件*/
$("#gengxin").click(function (){
/*获取参数*/
var owner=$("#edit-marketActivityOwner").val() //列表的value就是所有者的value
/*要把市场活动的id给一个隐藏的标签里面 修改点击保存发请求要用*/
var id=$("#shichangid").val()
var name= $("#edit-marketActivityName").val()
var startDate= $("#edit-startTime").val()
var endDate=$("#edit-endTime").val()
var cost=$("#edit-cost").val()
var description=$("#edit-describe").val()
/*表单验证 日期大小 代价非负整数 名称所有者不能为空*/
if(owner==""){
alert("所有者不能为空")
return;
}
if(name==""){
alert("活动名不能为空")
return;
}
if(startDate!="" && endDate!=""){
if(startDate>=endDate){
alert("日期填写错误")
return;
}
}
var zhengze=/^(([1-9]d*)|0)$/;
if(!zhengze.test(cost)){
alert("只能为非负整数")
return
}
$.ajax({
url:"workbench/activity/updateAcyivityById.do",
data:{
id:id,
owner:owner,
name:name,
startDate:startDate,
endDate:endDate,
cost:cost,
description:description
},
dataType:"json",
type:"POST",
success:function (data){
if(data.code=="1"){
/*如果更新成功当前页号和每页显示条数不变 关闭模态窗口*/
queryhuodong($("#fenye").bs_pagination('getOption','currentPage'),$("#fenye").bs_pagination('getOption','rowsPerPage'))
$("#editActivityModal").modal("hide")
}else if(data.code=="0"){
alert(data.message)
$("#editActivityModal").modal("show")
}
}
})
})
显示数据再用户更新完数据之后,用户点击更新,参数为修改市场活动中表单中的参数
controller层收到参数封装为市场活动的实体类对象,调用方法保存这个市场活动,返回响应信息就是成功或者失败
/*点击修改 获取参数 前端只能传7个参数 还有修改时间和修改人自己写 session里获取*/
@RequestMapping("/workbench/activity/updateAcyivityById.do")
@ResponseBody
public Object updateAcyivityById(Activity activity,HttpSession session){
/*获取参数 封装参数 还有要有修改时间和修改人*/
String getdate = SimDate.getdate(new Date());
User user= (User) session.getAttribute(chang.SESSION_NAME);
String id = user.getId(); /*存的也是修改人的id*/
activity.setEditTime(getdate);
activity.setEditBy(id);
usercan usercan = new usercan();//用来封装响应信息的实体类
try {
int i= actyServoce.updateActivityById(activity);
if(i==1){
usercan.setCode(chang.CODE_SUCCESS);
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("当前系统繁忙请稍后重试");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("当前系统繁忙请稍后重试");
}
return usercan;
}
在前端成功就是刷新页面,失败就提示错误信息
6.批量市场活动(全部导出)
技术准备:
使用apache-poi插件生成excel文件
技术准备:
1)使用java生成excel文件:apache-poi
关于办公文档插件使用的基本思想:把办公文档的所有元素封装成普通的Java类,
程序员通过操作这些类达到操作办公文档目的。
文件---------HSSFWorkbook
页-----------HSSFSheet
行-----------HSSFRow
列-----------HSSFCell
样式---------HSSFCellStyle
使用apache-poi生成excel:
a)添加依赖:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
b)使用封装类生成excel文件:
2)文件下载:
filedownloadtest.jsp
ActivityController
|->fileDownload()
*所有文件下载的请求只能发送同步请求。
/*给批量下载按钮加单击事件 发同步请求 因为文件下载只能是同步请求*/
$("#exportActivityAllBtn").click(function (){
window.location.href="workbench/activity/selectAll.do";
})
在controller层使用这个插件生成excel文件
/*这个是处理用户点击批量导出的请求 应为是响应excel文件
* 所以是手动响应到浏览器 不要返回值*/
@RequestMapping("/workbench/activity/selectAll.do")
public void selectAll(HttpServletResponse response) throws IOException {
/*设置响应类型 为二进制文件*/
response.setContentType("application/octet-stream;charset=UTF-8");
/*获取字节输出流*/
ServletOutputStream outputStream = response.getOutputStream();
/*拿到市场活动的信息 先下载到服务器磁盘 这里本机充当服务器*/
List<Activity> activities = actyServoce.selectAll();
/*使用apache-poi插件生成excel文件 要先加依赖*/
/*创建一个文件类 往里面加页*/
HSSFWorkbook wb = new HSSFWorkbook();
/*a往页里加行*/
HSSFSheet sheet = wb.createSheet("市场活动");
/*0代表第一行*/
HSSFRow row = sheet.createRow(0);
/*往行里加列*/
HSSFCell cell = row.createCell(0);
/*给0行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<activities.size();i++){
/*查出来几行就要设置几行*/
row= sheet.createRow(i+1);
cell = row.createCell(0);
/*给0行0列设置值*/
cell.setCellValue(activities.get(i).getId());
cell=row.createCell(1);/*设置第二列*/
cell.setCellValue(activities.get(i).getOwner());
cell=row.createCell(2);
cell.setCellValue(activities.get(i).getName());
cell=row.createCell(3);
cell.setCellValue(activities.get(i).getStartDate());
cell=row.createCell(4);
cell.setCellValue(activities.get(i).getEndDate());
cell=row.createCell(5);
cell.setCellValue(activities.get(i).getCost());
cell=row.createCell(6);
cell.setCellValue(activities.get(i).getDescription());
cell=row.createCell(7);
cell.setCellValue(activities.get(i).getCreateTime());
cell=row.createCell(8);
cell.setCellValue(activities.get(i).getCreateBy());
cell=row.createCell(9);
cell.setCellValue(activities.get(i).getEditTime());
cell=row.createCell(10);
cell.setCellValue(activities.get(i).getEditBy());
}
/*把excel文件输出到服务器*/
/*OutputStream fos = new FileOutputStream("E:\aa\shichanghuodong.xls");
wb.write(fos);*/
/*刷新流 关闭流 */
/*fos.flush(); //这种先写到磁盘 从磁盘读 再写到磁盘效率很低 直接让wb.write写到浏览器输出流 就不要先写到服务器磁盘中
fos.close();*/
/*这里就是处理下载 从服务器里下载*/
/*先把文件从磁盘读到内存 再写*/
/*
FileInputStream fileInputStream = new FileInputStream("E:\aa\shichanghuodong.xls");
byte[] bytes=new byte[256]; //读到字节数组中在从字节数组写出
int len=0; *//*这个read是返回读到字节数组中的长度 没有了就返回负一*//*
while ((len=fileInputStream.read(bytes))!=-1){
*//*响应到浏览器*//*
outputStream.write(bytes,0,len);
}*/
/*应为浏览器默认会自动把响应信息显示到窗口 但我们要弹出下载框 所以要设置响应头信息告诉浏览器 filename=shichang.xls默认下载时的文件名*/
response.addHeader("content-Disposition","attachment;filename=shichang.xls");
wb.write(outputStream);
wb.close();
}
查询的sql
<select id="selectAll" resultMap="BaseResultMap">
select a.id,u1.name as owner,a.name,a.start_date,a.end_date,
a.cost,a.description,a.create_time,u2.name as create_by,
a.edit_time,u3.name as edit_by
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
join tbl_user as u2 on a.create_by=u2.id
left join tbl_user as u3 on a.edit_by=u3.id
order by a.create_time desc
</select>
7.选择导出
只有前端要传递要导出的市场活动的id参数,同名不同值的id参数。然后controller层用的是String[]数组接收
/*给选择导出按钮加单击事件 收集参数 用ajax发同步请求 async设置为false*/
$("#exportActivityXzBtn").click(function (){
/*获取全部选中的列表 遍历拼接id 格式为id=v1&id=v2*/
var Xzarray=$("#huodongbiao input[type='checkbox']:checked");
/*表单验证 为空则提示用户要选至少一个*/
if(Xzarray.size()==0){
alert("请至少选一个")
return
}
var id='';
$.each(Xzarray,function (){
/*this代表每次遍历出来的对象*/
id+="id="+this.value+"&"
})
/*截取字符串*/
id=id.substr(0,id.length-1)
/*发ajax同步请求 不可取*/
/* $.ajax({
url:"workbench/activity/selectByIds.do",
async:false,
data:id,
type:"POST"
})*/
window.location.href="workbench/activity/selectByIds.do?"+id+""
})
controller层:
/*根据用户提交过来的id数组 查出来市场活动信息 再通过
* apache-poi插件写到HSSFwb中 再手动响应给浏览器*/
@RequestMapping("/workbench/activity/selectByIds.do")
public void selectByIds(String[] id,HttpServletResponse response) throws IOException {
/*设置响应类型 为二进制文件*/
response.setContentType("application/octet-stream;charset=UTF-8");
/*获取字节输出流*/
ServletOutputStream outputStream = response.getOutputStream();
/*去调用业务逻辑层查数据*/
List<Activity> activities = actyServoce.selectByIdarray(id);
/*使用apache-poi插件生成excel文件 要先加依赖*/
/*创建一个文件类 往里面加页*/
HSSFWorkbook wb = new HSSFWorkbook();
/*a往页里加行*/
HSSFSheet sheet = wb.createSheet("市场活动");
/*0代表第一行*/
HSSFRow row = sheet.createRow(0);
/*往行里加列*/
HSSFCell cell = row.createCell(0);
/*给0行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<activities.size();i++){
/*查出来几行就要设置几行*/
row= sheet.createRow(i+1);
cell = row.createCell(0);
/*给0行0列设置值*/
cell.setCellValue(activities.get(i).getId());
cell=row.createCell(1);/*设置第二列*/
cell.setCellValue(activities.get(i).getOwner());
cell=row.createCell(2);
cell.setCellValue(activities.get(i).getName());
cell=row.createCell(3);
cell.setCellValue(activities.get(i).getStartDate());
cell=row.createCell(4);
cell.setCellValue(activities.get(i).getEndDate());
cell=row.createCell(5);
cell.setCellValue(activities.get(i).getCost());
cell=row.createCell(6);
cell.setCellValue(activities.get(i).getDescription());
cell=row.createCell(7);
cell.setCellValue(activities.get(i).getCreateTime());
cell=row.createCell(8);
cell.setCellValue(activities.get(i).getCreateBy());
cell=row.createCell(9);
cell.setCellValue(activities.get(i).getEditTime());
cell=row.createCell(10);
cell.setCellValue(activities.get(i).getEditBy());
}
/*直接通过wb.write(浏览器输出流) 输出到浏览器
* 在这之前要设置响应头 告诉浏览器不要直接解析显示到页面(浏览器默认) 而是弹出下载框*/
response.addHeader("content-Disposition","attachment;filename=shichangchoose.xls");
wb.write(outputStream);
wb.close();
}
查询的SQL
<select id="selectByIdarray" resultMap="BaseResultMap" parameterType="string">
select a.id,u1.name as owner,a.name,a.start_date,a.end_date,
a.cost,a.description,a.create_time,u2.name as create_by,
a.edit_time,u3.name as edit_by
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
join tbl_user as u2 on a.create_by=u2.id
left join tbl_user as u3 on a.edit_by=u3.id
where a.id in <foreach collection="array" item="id" close=")" open="(" separator=",">
#{id}
</foreach>
order by a.create_time desc
</select>
8.文件导入
技术准备:
文件上传表单三要素:
表单的input的类型必须是file 考虑到controller层要接收这个文件要给input起一个name
必须使用post请求
form表单的enctype属性必须是multipart/form-data 这个是多样性的表单数据编码(默认的是urlencodeed这个只能对文本数据进行编码)
excel文件上传之后还是使用apache-poi插件解析
文件上传在controller层还是要使用springmvc提供的一个类来接收文件MultpartFile这个类
但必须在springmvc的配置文件中配置上传解析器
<!-- 配置文件上传解析器 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>
加依赖apache-poi
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
在controller层
/*接收ajax请求发来的文件 利用Apache-poi插件解析文件 封装到实体类中
* 返回响应信息*/
@RequestMapping("/workbench/activity/importAct.do")
@ResponseBody /*提交过来的文件会注入到这里 但先要在springmvc中配置文件上传解析器*/
public Object importAct(MultipartFile file,HttpSession session){
usercan usercan = new usercan();
/*先把文件写到服务器 在从服务器通过Apache-poi插件解析文件*/
/*获取文件名*/
// String originalFilename = file.getOriginalFilename();
/*这个方法是将文件通过文件流 写出去 如果写到服务器出错了直接提示用户了 所以要try*/
try {
file.transferTo(new File("E:\aa\" + originalFilename + ""));
/*通过Input流读取文件*/
这就可以不要了 FileInputStream fi=new FileInputStream("E:\aa\" + originalFilename + "");
/*获取session方便取user 创建list 和实体类*/
InputStream fi = file.getInputStream(); //这里直接通过文件获取输入流直接传给wb去解析
User user= (User) session.getAttribute(chang.SESSION_NAME);
List<Activity> list=new ArrayList<>();
/*解析*/
HSSFWorkbook wb = new HSSFWorkbook(fi);
/*获取文件中的页*/
HSSFSheet at = wb.getSheetAt(0);
HSSFRow row=null;
HSSFCell cell=null;
/*获取页中的最后一行的下标方便遍历*/
int lastRowNum = at.getLastRowNum();
for(int i=1;i<lastRowNum+1;i++){
row = at.getRow(i);
/*每遍历一行就创建一个实体类对象存数据*/
Activity activity = new Activity();
/*id生成 所有者和创建人都是当前用户 创建时间就是当前时间*/
activity.setId(UUIDsaner.getUUID());
activity.setOwner(user.getId());
activity.setCreateBy(user.getId());
activity.setCreateTime(SimDate.getdate(new Date()));
/*遍历列 这个是获取列的总列数*/
short lastCellNum = row.getLastCellNum();
for(int j=0;j<lastCellNum;j++){
cell = row.getCell(j);
/*获取列中的值 按顺序设置到实体类中*/
String getcellvalue = Cellvalue.getcellvalue(cell);
if(j==0){
activity.setName(getcellvalue);
}else if(j==1){
activity.setStartDate(getcellvalue);
}else if(j==2){
activity.setEndDate(getcellvalue);
}else if(j==3){
activity.setCost(getcellvalue);
}else if(j==4){
activity.setDescription(getcellvalue);
}
}
/*每循环一行就把实体类加在list中*/
list.add(activity);
}
/*把封装好的list调用service层*/
int i = actyServoce.insertActivityList(list);
/*只要没报异常就说明插入成功 返回响应信息*/
usercan.setCode(chang.CODE_SUCCESS);
usercan.setData(i+"");
}catch (Exception e){
e.printStackTrace();
usercan.setMessage("系统繁忙请等待一小会儿重试");
usercan.setCode(chang.CODE_SHIBAI);
}
return usercan;
}
Apache-poi插件在解析excel文件时的获取文件中的数据的数据格式方法
public static String getcellvalue(HSSFCell cell){
String value="";
if(cell.getCellType()==HSSFCell.CELL_TYPE_STRING){
value= cell.getStringCellValue();
}else if(cell.getCellType()==HSSFCell.CELL_TYPE_BOOLEAN){
value=cell.getBooleanCellValue()+"";
}else if(cell.getCellType()==HSSFCell.CELL_TYPE_NUMERIC){
value=cell.getNumericCellValue()+"";
}else if(cell.getCellType()==HSSFCell.CELL_TYPE_FORMULA){
value=cell.getCellFormula();
}else {
value="";
}
return value;
}
底层的SQL语句
<insert id="insertActivityList" parameterType="activity">
insert into tbl_activity(id, owner, name, start_date,
end_date, cost, description,
create_time, create_by)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.id},#{obj.owner},#{obj.name},#{obj.startDate},#{obj.endDate}
,#{obj.cost},#{obj.description},#{obj.createTime},#{obj.createBy})
</foreach>
</insert>
前端用的ajax发请求和传文件参数
/*给导入模态窗口中的导入加单击事件 收集参数 验证参数*/
$("#importActivityBtn").click(function (){
/*获取用户上传文件的参数名 验证是不是.xls结尾 和文件大小不能超过5mb 通过导入标签获取*/
var filename=$("#activityFile").val();
var f=filename.substr(filename.lastIndexOf(".")+1).toLocaleLowerCase() /*获取后缀转化为小写*/
if(f!="xls"){
alert("必须是以xls后缀结尾的文件")
return
}
/*通过这个文件上传标签的dom对象的files属性可以获取文件数组 .size属型来判断文件大小*/
var file=$("#activityFile").get(0).files[0];
if(file.size>1024*1024*5){
alert("文件超过了5MB")
return;
}
/*利用FormData这个接口来传递参数 这个既可以串字符串数据 也可以串二进制数据 往里面加就行了*/
var formdata=new FormData();
formdata.append("file",file)
/*发ajax请求 把文件传给后台 成功导入则关闭模态窗口刷新数据*/
$.ajax({
url:"workbench/activity/importAct.do",
data:formdata,
dataType:"json",
type:"POST",
processData:false, //这个参数是是否在发请求之前把参数转化为字符串 默认true
contentType:false,//这个参数是是否把参数转化为的字符串用urlenconded编码 因为是传二进制文件所以都为false
success:function (data){
if(data.code=="1"){
alert("成功导入"+data.data+"条数据")
queryhuodong(1,$("#fenye").bs_pagination('getOption','rowsPerPage'))
$("#importActivityModal").modal("hide")
}else {
alert(data.message)
$("#importActivityModal").modal("show")
}
}
})
})
<input type="file" id="activityFile">
9.市场活动明细页面
给标签添加属性:
如果是表单组件标签,优先使用value属性,只有value不方便使用时,使用自定义属性;
如果不是表单组件标签,不推荐使用value,推荐使用自定义属性。
获取属性值时:
如果获取表单组件标签的value属性值:dom对象.value
jquery对象.val()
如果自定义的属性,不管是什么标签,只能用:jquery对象.attr(“属性名”);
mapper层
/*根据id查询市场活动的信息 显示人名用连接查询*/
Activity selectActivityById(String id);
<select id="selectActivityById" parameterType="string" resultMap="BaseResultMap">
select a.id,u1.name as owner,a.name,a.start_date,a.end_date,
a.cost,a.description,a.create_time,u2.name as create_by,
a.edit_time,u3.name as edit_by
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
join tbl_user as u2 on a.create_by=u2.id
left join tbl_user as u3 on a.edit_by=u3.id
where a.id=#{id}
</select>
/*根据市场活动的id查全部的活动备注*/
List<activityRemark> selectByActivityIdRemarks(String id);
<select id="selectByActivityIdRemarks" resultMap="BaseResultMap" parameterType="string">
select a.id,a.note_content,a.create_time,u1.name as create_by,
a.edit_time,u2.name as edit_by,a.edit_flag
from tbl_activity_remark as a
join tbl_user as u1 on a.create_by=u1.id
left join tbl_user as u2 on a.edit_by=u2.id
where a.activity_id=#{id}
</select>
controller层
/*这个用来接收前端传过来的一个市场活动的id返回
* 详情页面的所有信息 是存到请求域里面请求转发 通过jsp向浏览器返回网页*/
@RequestMapping("/workbench/activity/selectActivityandbeizhu.do")
public String selectActivityandbeizhu(String id, HttpServletRequest request){
Activity activity = actyServoce.selectActivityById(id);
List<activityRemark> activityRemarks = actRemarkSerivse.selectByActivityIdRemarks(id);
request.setAttribute("activity",activity);
request.setAttribute("activityRemarks",activityRemarks);
return "workbench/activity/detail";
}
页面片段:
<a style="text-decoration: none; cursor: pointer;" οnclick="window.location.href='workbench/activity/selectActivityandbeizhu.do?id="+actv.id+"'">
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<%String bg=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";%>
<meta charset="UTF-8">
<base href="<%=bg%>">
<link href="jquery/bootstrap_3.3.0/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
<script type="text/javascript" src="jquery/bootstrap_3.3.0/js/bootstrap.min.js"></script>
<%--备注信息用EL表达式 jstl标签库--%>
<c:forEach items="${activityRemarks}" var="act">
<div class="remarkDiv" style="height: 60px;">
<img title="${act.createBy}" src="image/user-thumbnail.png" style="width: 30px; height:30px;">
<div style="position: relative; top: -40px; left: 40px;" >
<h5>${act.noteContent}</h5> <%--这里是刚创建就显示创建时间 被修改过就显示修改时间--%>
<font color="gray">市场活动</font> <font color="gray">-</font> <b>${activity.name}</b> <small style="color: gray;"> ${act.editFlag=="1"?act.editTime:act.createTime } 由${act.editFlag=="1"?act.editBy:act.createBy }${act.editFlag=="1"?'修改':'创建' }</small>
<div style="position: relative; left: 500px; top: -30px; height: 30px; width: 100px; display: none;"> <%--给这两个修改和删除图标加上自定义属性 这个备注的id 修改删除要有 自定义属性只能用Jquery.attr("属性名")获取--%>
<a class="myHref" href="javascript:void(0);" beizhuid="${act.id}"><span class="glyphicon glyphicon-edit" style="font-size: 20px; color: #E6E6E6;"></span></a>
<a class="myHref" href="javascript:void(0);" beizhuid="${act.id}"><span class="glyphicon glyphicon-remove" style="font-size: 20px; color: #E6E6E6;"></span></a>
</div>
</div>
</div>
</c:forEach>
10.市场活动详细页面的新增备注功能
用户只输入备注的内容,用户点击添加,添加成功之后清空输入框,刷新备注列表(在controller层要返回这个增加的备注实体类对象,因为前端要用$(“#remarkDiv”).before(html) 在这个标签外部的前面加上摄入的内容)
2,把页面片段显示在动态显示在页面中:
选择器.html(htmlStr):覆盖显示在标签的内部
选择器.text(htmlStr):覆盖显示在标签的内部
选择器.append(htmlStr):追加显示在指定标签的内部的后边
$(“#remarkDiv”).before(html) /在这个标签外部的前面加上摄入的内容/
选择器.after(htmlStr):追加显示在指定标签的外部的后边
mapper层
/*用户点击保存市场活动备注 插入市场活动*/
int insertAllactivityRemark(activityRemark activityRemark);
<insert id="insertAllactivityRemark" parameterType="activityRemark">
insert into tbl_activity_remark(id, note_content, create_time, create_by,edit_flag, activity_id)
values(#{id},#{noteContent},#{createTime},#{createBy},#{editFlag},#{activityId})
</insert>
controller层
/*添加备注 接收前端传过来的两个参数 一个备注信息 和一个市场活动id
返回响应信息 要把这里封装要插入数据库的数据返回到前端 因为前端直接动态追加显示 不再查数据库了*/
@RequestMapping("/workbench/activity/insertbeizhu.do")
@ResponseBody
public Object insertbeizhu(activityRemark activityRemark,HttpSession session){
/*封装参数 创建用户的id从session中获取*/
User user= (User) session.getAttribute(chang.SESSION_NAME);
activityRemark.setCreateBy(user.getId());
activityRemark.setCreateTime(SimDate.getdate(new Date()));
activityRemark.setId(UUIDsaner.getUUID());
activityRemark.setEditFlag(chang.BEI_ZHU_NO_EIDT);
usercan usercan = new usercan();
/*调用业务逻辑层返回结果*/
try {
int i = actRemarkSerivse.insertAllactivityRemark(activityRemark);
if(i>0){
usercan.setCode(chang.CODE_SUCCESS);
usercan.setData(activityRemark);
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("没有添加备注成功");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("没有添加备注成功");
}
return usercan;
}
前端jsp页面
/*给保存按钮家单击事件 点击保存 收集参数
* 发ajax请求 刷新页面*/
$("#baocun11").click(function (){
/*收集参数*/
var noteContent=$("#remark").val();
var activityId='${activity.id}' /*这里获取在request作用域的数据可以获取 应为在同一个页面*/
/*表单验证*/
if(noteContent==""){
alert("备注不能为空")
return
}
$.ajax({
url:"workbench/activity/insertbeizhu.do",
data:{
noteContent:noteContent,
activityId:activityId
},
type:"POST",
dataType:"json",
success:function (data){
/*这里做字符串的拼接操作 然后动态显示到页面*/
if(data.code=="1"){
var html='';
html+="<div class="remarkDiv" style="height: 60px;">";
html+=" <img title="${sessionScope.sessionUser.name}" src="image/user-thumbnail.png" style="width: 30px; height:30px;">";
html+=" <div style="position: relative; top: -40px; left: 40px;" >";
html+="<h5>"+data.data.noteContent+"</h5>"; <%--这里是刚创建就显示创建时间 被修改过就显示修改时间--%>
html+="<font color="gray">市场活动</font> <font color="gray">-</font> <b>${activity.name}</b> <small style="color: gray;"> "+data.data.createTime+"由${sessionScope.sessionUser.name}创建</small>";
html+="<div style="position: relative; left: 500px; top: -30px; height: 30px; width: 100px; display: none;">"; <%--给这两个修改和删除图标加上自定义属性 这个备注的id 修改删除要有 自定义属性只能用Jquery.attr("属性名")获取--%>
html+="<a class="myHref" href="javascript:void(0);" beizhuid=""+data.data.id+""><span class="glyphicon glyphicon-edit" style="font-size: 20px; color: #E6E6E6;"></span></a>";
html+=" ";
html+="<a class="myHref" href="javascript:void(0);" beizhuid=""+data.data.id+""><span class="glyphicon glyphicon-remove" style="font-size: 20px; color: #E6E6E6;"></span></a>";
html+="</div>";
html+="</div>";
html+="</div>";
$("#remarkDiv").before(html) /*在这个标签外部的前面加上摄入的内容*/
$("#remark").val("") /*清空内容*/
}else{
alert(data.message)
}
}
})
})
/* $(".remarkDiv").mouseover(function(){
$(this).children("div").children("div").show();
});*/
/*用父子选择器on来给所有的备注列表加动态的标签的鼠标移入事件*/
$("#beizhufu").on('mouseover',".remarkDiv",function (){
$(this).children("div").children("div").show();
})
11.删除市场活动备注功能
给元素扩展属性:html页面是可扩展的标记语言,可以给指定的标签任意扩展属性,只要属性名符合标识符的命名规则即可。
两个目的:
1)使用标签保存数据:
如果是表单组件标签,优先使用value属性,只有value不方便使用时,使用自定义属性;
如果不是表单组件标签,不推荐使用value,推荐使用自定义属性。
2)定位标签:
优先考虑id属性,其次考虑name属性,只有id和name属性都不方便使用时,才考虑使用自定义属性。
1.用户点击删除图标发送ajax请求 传参数的备注的id值
这里怎么获取删除图标的Jquery对象用来给所有删除图标加单击事件呢???
通过给删除图标所在的标签扩展属性 用name 修改图标也是
这里加单击事件要用父子选择器.on的方式 因为备注的div是动态的
2收集参数:
用Jquery.attr(“属性名获取”)
这里this代表的是发生这个事件的标签的dom对象 所以$(this).attr()就行了
3.在controller层收集参数调用serivse层去删除备注根据id
4.controller返回是否删除成功的响应信息 用json
5.页面如果收到删除成功 那么就删除这个备注所在的div
如何定位这个备注的div???
给每个div加上id属性 这个值就是用备注的id 这样来确保唯一性 还可以在id前加上前缀进一部保证唯一性
$(“div”).remove()
前端:
$("#beizhufu").on("click","a[name='shanchutubiao']",function (){
/*收集参数 这里this代表的是发生这个事件的标签 所以$(this).attr()就行了*/
var id= $(this).attr("beizhuid");
$.ajax({
url: "workbench/activity/deletebeizhu.do",
data:{id:id},
dataType: "json",
type:"POST",
success:function (data){
if(data.code=="1"){
/*5.页面如果收到删除成功 那么就删除这个备注所在的div
如何定位这个备注的div???
给每个div加上id属性 这个值就是用备注的id 这样来确保唯一性 还可以在id前加上前缀进一部保证唯一性*/
$("#div_"+id).remove()
}else {
alert(data.message)
}
}
})
})
后端:
/*3.在controller层收集参数调用serivse层去删除备注根据id*/
@RequestMapping("/workbench/activity/deletebeizhu.do")
@ResponseBody
public Object deletebeizhu(String id){
usercan usercan = new usercan();
try {
int i = actRemarkSerivse.deleteByIdInt(id);
if(i>0){
usercan.setCode(chang.CODE_SUCCESS);
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后。。。");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后。。。");
}
return usercan;
}
mapper层的sql语句
<delete id="deleteByIdInt" parameterType="string">
delete from tbl_activity_remark
where id=#{id}
</delete>
12.修改市场活动备注功能
$("#beizhufu").on('click',"a[name='xiugaitubiao']",function (){
var id=$(this).attr("beizhuid");
$("#div_"+data.data.id+" h5").text(data.data.noteContent)
1.用户点击修改的图标,给所有图标加上单击事件 把备注id放在模态窗口的隐藏标签里方便点击更新的时候拿
/*1.用户点击修改的图标,给所有图标加上单击事件*/
$("#beizhufu").on('click',"a[name='xiugaitubiao']",function (){
/*拿到这个修改中放的id*/
var id=$(this).attr("beizhuid");
/*通过id定位到最外层的div 在通过父子选择器选择中h5*/
var noteContent=$("#div_"+id+" h5").text();
/*把这些内容放在模态窗口上*/
$("#beizhuidyincang").val(id)
$("#noteContent").val(noteContent)
/*打开模态窗口*/
$("#editRemarkModal").modal("show")
})
2.点击完弹出修改的模态窗口,用户填写完修改后的备注 点击更新
3.发送ajax请求参数为这个市场活动备注的id和内容
$("#updateRemarkBtn").click(function (){
/*获取参数 表单验证*/
var id=$("#beizhuidyincang").val();
var noteContent=$("#noteContent").val()
if(noteContent==""){
alert("修改的备注不能为空")
return;
}
/*发ajax请求*/
$.ajax({
url:"workbench/activity/uptateByidRemark.do",
data:{
id:id,
noteContent:noteContent
},
dataType:"json",
type:"POST",
success:function (data){
/*如果成功就动态刷新页面*/
if(data.code=="1"){
$("#div_"+data.data.id+" h5").text(data.data.noteContent)
$("#div_"+data.data.id+" small").text(""+data.data.editTime+"由${sessionScope.sessionUser.name}修改")
/*关闭模态窗口*/
$("#editRemarkModal").modal("hide")
}else {
alert(data.message)
$("#editRemarkModal").modal("show")
}
}
})
})
4.controller层拿到参数 后还要封装实体类的其他几个参数 修改时间 修改人(session里拿)还有修改标记改为1
5.调用业务逻辑层看修改成功还是失败 返回响应信息 要把实体类返回去 应为前端要动态修改这个div
@RequestMapping("/workbench/activity/uptateByidRemark.do")
@ResponseBody
public Object uptateByidRemark(activityRemark activityRemark,HttpSession session){
usercan usercan = new usercan();
User user= (User) session.getAttribute(chang.SESSION_NAME);
activityRemark.setEditFlag(chang.BEI_ZHU_YES_EIDT);
activityRemark.setEditBy(user.getId());
activityRemark.setEditTime(SimDate.getdate(new Date()));
/*调用service层*/
try {
int i = actRemarkSerivse.updateActivityRemarkId(activityRemark);
if(i>0){
usercan.setCode(chang.CODE_SUCCESS);
usercan.setData(activityRemark);
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后哦");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后哦");
}
return usercan;
}
修改的sql
<update id="updateActivityRemarkId" parameterType="string">
update tbl_activity_remark set note_content=#{noteContent},edit_flag=#{editFlag},edit_time=#{editTime},edit_by=#{editBy}
where id=#{id}
</update>
6.前端拿到数据 通过之前的标签里面的备注id 定位到 最外层的div 通过这个最外层的div和父子选择器定位到里面的标签用来修改内容
十:线索模块的功能
1.线索页面的显示
1.用户点击线索 应为页面在web-inf下面所以要通过controller层的请求转发到达
<li class="liClass"><a href="workbench/clue/selectxialaliebiao.do" target="workareaFrame"><span class="glyphicon glyphicon-search"></span> 线索(潜在客户)</a></li>
2.这个线索页面的下拉列表里的数据是通过数据库里查出来的
<select id="selectBytypecode" parameterType="string" resultMap="BaseResultMap">
select <include refid="Base_Column_List"></include>
from tbl_dic_value
where type_code=#{typeCode}
</select>
<!--查所有用户-->
<select id="queryAllUsers" resultMap="BaseResultMap">
select <include refid="Base_Column_List"></include>
from tbl_user
</select>
3.所以在controller层要拿到下拉列报的数据 请求转发到页面
/*这个controller的方法是给用户点击线索然后 把线索页面所要的数据通过request域转发到页面*/
@RequestMapping("/workbench/clue/selectxialaliebiao.do")
public String selectxialaliebiao(HttpServletRequest request){
/*收集参数*/
/*执行service层的方法拿到数据*/
List<User> users = userServic.selectAllUsers();
List<dicvalue> appellation = dicvlue.selectBytypecode("appellation");//称呼
List<dicvalue> source = dicvlue.selectBytypecode("source");//来源
List<dicvalue> stage = dicvlue.selectBytypecode("stage");//状态
/*把数据封装到request域里面*/
request.setAttribute("users",users);
request.setAttribute("appellation",appellation);
request.setAttribute("source",source);
request.setAttribute("stage",stage);
/*请求转发到页面*/
return "workbench/clue/index";
}
4.在页面用EL表达式和JSTL标签库来显示数据
<div class="form-group">
<label for="edit-source" class="col-sm-2 control-label">线索来源</label>
<div class="col-sm-10" style="width: 300px;">
<select class="form-control" id="edit-source">
<option></option>
<c:forEach items="${source}" var="sou">
<option value="${sou.id}">${sou.value}</option>
</c:forEach>
</select>
</div>
</div>
<%--下拉列表的value属性存id修改表的时候用--%>
2.创建线索的实现
1.用户点击模态窗口中的保存 ,收集参数发送ajax请求
/*给模态窗口中的保存加单击事件*/
$("#baocun").click(function (){
/*收集参数*/
var fullname =$("#create-fullname").val();
var appellation =$("#create-appellation").val();
var owner =$("#create-owner").val();
var company =$("#create-company").val();
var job =$("#create-job").val();
var email =$("#create-email").val();
var phone =$("#create-phone").val();
var website =$("#create-website").val();
var mphone =$("#create-mphone").val();
var state =$("#create-state").val();
var source =$("#create-source").val();
var description =$("#create-description").val();
var contactSummary =$("#create-contact_summary").val();
var nextContactTime=$("#create-next_contact_time").val();
var address =$("#create-address").val();
/*表单验证*/
if(owner==""){
alert("所有者不能为空")
return
}
if(company==""){
alert("公司不能为空")
return
}
if(fullname==""){
alert("姓名不能为空")
return
}
/*验证手机号只能是0-9的数字用正则表达式*/
var zhengze=/^[0-9]*$/
if(!zhengze.test(mphone)){
alert("手机号只能是0-9的数字组成")
return;
}
/*发送ajax请求*/
$.ajax({
url:"workbench/clue/insertAll.do",
data:{
fullname:fullname,
appellation:appellation,
owner:owner,
company:company,
job:job,
email:email,
phone:phone,
website:website,
mphone:mphone,
state:state,
source:source,
description:description,
contactSummary:contactSummary,
nextContactTime:nextContactTime,
address:address
},
type:"POST",
dataType:"json",
success:function (data){
if(data.code=="1"){
/*关闭模态窗口刷新页面*/
$("#createClueModal").modal("hide")
/*刷新页面*/
/*刷新页面 显示第一页 每页显示条数不变*/
selectxianxuo(1,$("#fenyechajian").bs_pagination('getOption','rowsPerPage'))
}else {
alert(data.message)
$("#createClueModal").modal("show")
}
}
})
})
/*给创建的下次联系时间加日历插件*/
$("#create-next_contact_time").datetimepicker({
language:"zh-CN",//设置语言为中文格式
format:"yyyy-mm-dd",//设置选中完日历后返回给文本框的字符串格式
minView:"month",//设置最小可以选择到哪里 写月最小显示到日
autoclose:true, //设置选完后关闭
initialDate:new Date(), //设置初始化时候的选中 为当前时间
todayBtn:true, //设置在下面显示今天按钮 默认false不显示
clearBtn:true, //设置清空按钮 默认为false不显示 这里应为要显示中文的清空 所以改了源码bootstrap-theme.min.css这里面
pickerPosition:'top-right'//在屏幕的上面显示日历
})
2.controller层收集参数(实体类)然后继续封装id,创建时间,创建者
@RequestMapping("/workbench/clue/insertAll.do")
@ResponseBody
public Object insertAll(Clue clue, HttpSession session){
User user= (User) session.getAttribute(chang.SESSION_NAME);
usercan usercan = new usercan();
clue.setId(UUIDsaner.getUUID());
clue.setCreateBy(user.getId());
clue.setCreateTime(SimDate.getdate(new Date()));
try{
int i = clueService.insertByClue(clue);
if(i>0){
usercan.setCode(chang.CODE_SUCCESS);
}else{
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后.....");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后.....");
}
return usercan;
}
3.调用servce层的新建方法返回影响记录条数
<insert id="insertByClue" parameterType="clue">
insert into tbl_clue(id, fullname, appellation, owner, company, job, email, phone, website, mphone, state,
source, create_by, create_time,description, contact_summary,
next_contact_time, address)
values (#{id,jdbcType=CHAR}, #{fullname,jdbcType=VARCHAR}, #{appellation,jdbcType=VARCHAR},
#{owner,jdbcType=CHAR}, #{company,jdbcType=VARCHAR}, #{job,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR},
#{phone,jdbcType=VARCHAR}, #{website,jdbcType=VARCHAR}, #{mphone,jdbcType=VARCHAR},
#{state,jdbcType=VARCHAR}, #{source,jdbcType=VARCHAR}, #{createBy,jdbcType=VARCHAR},
#{createTime,jdbcType=CHAR},
#{description,jdbcType=VARCHAR}, #{contactSummary,jdbcType=VARCHAR}, #{nextContactTime,jdbcType=CHAR},
#{address,jdbcType=VARCHAR})
</insert>
4.根据影响记录条数返回响应信息1成功0失败错误信息
5.前端ajax在回调函数里成功则刷新列表,关闭模态窗口。失败就显示错误信息,模态窗口不关
3.线索的分页查询函数实现
1.用户点击线索,就要在前端收集参数,和页号和每页显示条数,这个前端的查询定义成一个函数,发jaxa异步请求
2.controller层用一个一个参数收集数据,封装为map传给service层去查询总的线索和总记录条数
mapper层的SQL
<select id="selectByClue" parameterType="map" resultMap="BaseResultMap">
select c.id,c.fullname,dv3.value as appellation,c.company,c.phone,c.mphone,dv.value as source,
u1.name as owner,dv2.value as state
from tbl_clue as c
left join tbl_dic_value as dv3 on c.appellation=dv3.id
left join tbl_dic_value as dv on c.source=dv.id
join tbl_user as u1 on c.owner=u1.id
left join tbl_dic_value as dv2 on c.state=dv2.id
<where>
<if test="fullname!=null and fullname!=''">
and c.fullname like concat('%',#{fullname},'%')
</if>
<if test="company!=null and company!=''">
and c.company like concat('%',#{company},'%')
</if>
<if test="phone!=null and phone!=''">
and c.phone like concat('%',#{phone},'%')
</if>
<if test="source!=null and source!=''">
and dv.value =#{source}
</if>
<if test="owner!=null and owner!=''">
and u1.name like concat('%',#{owner},'%')
</if>
<if test="mphone!=null and mphone!=''">
and c.mphone like concat('%',#{mphone},'%')
</if>
<if test="state!=null and state!=''">
and dv2.value =#{state}
</if>
</where>
order by c.create_time desc
limit #{pageNumber},#{pagesize}
</select>
<select id="selectAlltiao" parameterType="map" resultType="int">
select count(*)
from tbl_clue as c
left join tbl_dic_value as dv3 on c.appellation=dv3.id
left join tbl_dic_value as dv on c.source=dv.id
left join tbl_user as u1 on c.owner=u1.id
left join tbl_dic_value as dv2 on c.state=dv2.id
<where>
<if test="fullname!=null and fullname!=''">
and c.fullname like concat('%',#{fullname},'%')
</if>
<if test="company!=null and company!=''">
and c.company like concat('%',#{company},'%')
</if>
<if test="phone!=null and phone!=''">
and c.phone like concat('%',#{phone},'%')
</if>
<if test="source!=null and source!=''">
and dv.value =#{source}
</if>
<if test="owner!=null and owner!=''">
and u1.name like concat('%',#{owner},'%')
</if>
<if test="mphone!=null and mphone!=''">
and c.mphone like concat('%',#{mphone},'%')
</if>
<if test="state!=null and state!=''">
and dv2.value =#{state}
</if>
</where>
</select>
3.把数据封装为map转json返回给前端
/*点击线索就返回线索的根据分页查询的所有记录和返回总记录条数*/
@RequestMapping("/workbench/clue/selectfenye.do")
@ResponseBody
public Object selectfenye(String fullname,String company,String phone,String source,
String owner,String mphone,String state,int pageNumber,int pagesize){
/*封装参数*/
Map<String,Object> map=new HashMap<>();
map.put("fullname",fullname);
map.put("company",company);
map.put("phone",phone);
map.put("source",source);
map.put("owner",owner);
map.put("mphone",mphone);
map.put("state",state);
/*根据页号算出起始页数*/
map.put("pageNumber",(pageNumber-1)*pagesize);
map.put("pagesize",pagesize);
/*调用业务逻辑层拿到参数*/
int i = clueService.selectAlltiao(map);
List<Clue> clues = clueService.selectByClue(map);
/*封装响应数据为map*/
Map<String,Object> map1=new HashMap<>();
map1.put("Listclues",clues);
map1.put("num",i);
return map1;
}
4.前端在ajax的回调函数里面拼接字符串显示列表 然后定义分页插件 需要根据总记录条数和每页显示条数算出总页数
/*定义一个查询的方法 查询线索列表 参数一:页号,参数二:每页显示条数*/
function selectxianxuo(pageNumber,pagesize){
/*收集参数*/
var fullname =$("#mingcheng").val()
var company =$("#gongsi").val()
var phone =$("#gongsizuoji").val()
var source =$("#xiansuolaiyuan").val()
var owner =$("#suoyouzhe").val()
var mphone =$("#shouji").val()
var state =$("#xiansuozhuangtai").val()
var pageNumber=pageNumber
var pagesize =pagesize
/*发ajax请求*/
$.ajax({
url:"workbench/clue/selectfenye.do",
data:{
fullname:fullname,
company:company,
phone:phone,
source:source,
owner:owner,
mphone:mphone,
state:state,
pageNumber:pageNumber,
pagesize:pagesize
},
dataType:"json",
type:"POST",
success:function (data){
/*拿到数据凭借列表*/
var html='';
$.each(data.Listclues,function (i,clue){
html+="<tr>";
html+="<td><input type="checkbox" value='"+clue.id+"' /></td>";
html+="<td><a style="text-decoration: none; cursor: pointer;" οnclick="window.location.href='detail.html';">"+clue.fullname+""+clue.appellation+"</a></td>";
html+="<td>"+clue.company+"</td>";
html+="<td>"+clue.phone+"</td>";
html+="<td>"+clue.mphone+"</td>";
html+="<td>"+clue.source+"</td>";
html+="<td>"+clue.owner+"</td>";
html+="<td>"+clue.state+"</td>";
html+="</tr>";
})
/*打入标签中*/
$("#xiansuobody").html(html)
/*计算出总页数*/
var zongye=0
if(data.num%pagesize==0){
zongye=data.num/pagesize
}
else {
/*js的系统函数 parseInt()将这个数取整数部分*/
zongye=parseInt(data.num/pagesize)+1;
}
/*假如这个分页插件 一引入依赖 二建立容器 三往容器里加函数*/
$("#fenyechajian").bs_pagination({
currentPage:pageNumber,//当前页号 参数传
totalRows:data.num,//总记录条数 ajax返回了
totalPages:zongye, //总页数是这个函数的必填值 是根据总记录条数 每页显示条数算出来的
rowsPerPage:pagesize,//每页显示条数
visiblePageLinks: 5,//这个是那个卡片数最多5个
showGoToPage: true,//显示跳转部分 默认true显示
showRowsPerPage: true,//显示设置每页条数 默认true显示
showRowsInfo: true,//显示记录的信息部分 默认true显示
onChangePage:function (event,objpage) {
/*这个是每次页号发生改变就会执行这个函数 第一个参数是这个事件源
* 第二个参数是这个 页面对象 包含的是外面的函数发生页号改变的所有属性信息
* 页号发生改变 上面的属性值也会跟着变*/
//当页号发生改变是 再次调用这个函数 去打请求刷新这个页面 把改变后的当前页号和每页显示条数传给他
selectxianxuo(objpage.currentPage,objpage.rowsPerPage);
}
})
}
})
5.在入口函数里调用这个函数
selectxianxuo(1,5)
4.线索详细页面的显示
1.用户点击名称栏的超链接,发送同步请求,传递这个线索的id作为参数传给controller
html+="<td><a style="text-decoration: none; cursor: pointer;" οnclick="window.location.href='workbench/activity/selectActivityandbeizhu.do?id="+actv.id+"'">"+actv.name+"</a></td>"
2.controller层1.根据id查询这个线索的所有明细信息2.工具id查这个线索的所有备注信息3.根据id查这个线索参加过哪些市场活动
@RequestMapping("/workbench/clue/selectxiangxi.do")
public String selectxiangxi(String id,HttpServletRequest request){
List<ClueRemark> clueRemarks = clueremarkService.selectByClueIdRemarks(id);
List<Activity> Activitylist = actyServoce.selectByClueIdActivity(id);
Clue clue = clueService.selectByIdone(id);
request.setAttribute("clueRemarks",clueRemarks);
request.setAttribute("Activitylist",Activitylist);
request.setAttribute("clue",clue);
return "workbench/clue/detail";
}
3.查到这三个数据数据,封装到request域中,然后通过请求转发到详细页面
mapper层的SQL
线索 :
<select id="selectByIdone" resultMap="BaseResultMap" parameterType="string">
select c.id,c.fullname,dv3.value as appellation, u1.name as owner,c.company,c.job,c.email,c.phone,c.website,c.mphone,dv.value as source,
dv2.value as state,u2.name as create_by,c.create_time,u3.name as edit_by,
c.edit_time,c.description,c.contact_summary,c.next_contact_time,c.address
from tbl_clue as c
left join tbl_dic_value as dv3 on c.appellation=dv3.id
left join tbl_dic_value as dv on c.source=dv.id
join tbl_user as u1 on c.owner=u1.id
left join tbl_dic_value as dv2 on c.state=dv2.id
join tbl_user as u2 on c.create_by=u2.id
left join tbl_user as u3 on c.edit_by=u3.id
where c.id=#{id}
</select>
市场活动
<select id="selectByClueIdActivity" resultMap="BaseResultMap" parameterType="string">
select a.id,u1.name as owner,a.start_date,a.end_date
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
join tbl_clue_activity_relation as car on a.id=car.activity_id
where car.clue_id=#{clueid}
</select>
线索备注
<select id="selectByClueIdRemarks" parameterType="string" resultMap="BaseResultMap">
select a.id,a.note_content,a.create_time,u1.name as create_by,
a.edit_time,u2.name as edit_by,a.edit_flag
from tbl_clue_remark as a
join tbl_user as u1 on a.create_by=u1.id
left join tbl_user as u2 on a.edit_by=u2.id
where a.clue_id=#{clueid}
order by a.create_time asc
</select>
4.在详细页面通过EL表达式和JSTL标签库显示数据(显示备注和市场活动时都要把id放入 方便增删)
关联的市场活动显示
<c:forEach items="${Activitylist}" var="a">
<tr id="tr_${a.id}">
<td>${a.name}</td>
<td>${a.startDate}</td>
<td>${a.endDate}</td>
<td>${a.owner}</td>
<td><a href="javascript:void(0);" style="text-decoration: none;" shichanghuodongid="${a.id}"><span class="glyphicon glyphicon-remove"></span>解除关联</a></td>
</tr>
</c:forEach>
备注显示
<c:forEach items="${clueRemarks}" var="r">
<div class="remarkDiv" style="height: 60px;" id="div_${r.id}">
<img title="${r.createBy}" src="image/user-thumbnail.png" style="width: 30px; height:30px;">
<div style="position: relative; top: -40px; left: 40px;" >
<h5>${r.noteContent}</h5>
<font color="gray">线索</font> <font color="gray">-</font> <b>${clue.fullname}${clue.appellation}-${clue.company}</b> <small style="color: gray;"> ${r.editFlag=="1"?r.editTime:r.createTime} 由${r.editFlag=="1"?r.editBy:r.createBy}${r.editFlag=="1"?'修改':'创建'}</small>
<div style="position: relative; left: 500px; top: -30px; height: 30px; width: 100px; display: none;">
<a class="myHref" href="javascript:void(0);" beizhuid="${r.id}"><span class="glyphicon glyphicon-edit" style="font-size: 20px; color: #E6E6E6;"></span></a>
<a class="myHref" href="javascript:void(0);" beizhuid="${r.id}"><span class="glyphicon glyphicon-remove" style="font-size: 20px; color: #E6E6E6;"></span></a>
</div>
</div>
</div>
</c:forEach>
5.线索详细页面的查询市场活动
1.用户点击关联市场活动,弹出模态窗口,用户在搜索框输入关键字模糊查询出所有的市场活动,在列表中显示
/*给关联市场活动按钮加单击事件打开模态窗口*/
$("#guanlianshichanghuodong").click(function (){
/*初始化工作*/
$("#bundModal").modal("show")
});
2.用户在搜索框搜索时 给搜索框加上一个键盘谈起事件(keyup),每弹起一次就发送一个ajax异步请求,参数是搜索框里的内容和这个线索的id(
因为要在数据库里查出来哪些市场活动没有被关联 只显示没有关联的市场活动,这要用到线索的id)
/*给搜索框加键盘弹起事件*/
$("#wenbenkuang").keyup(function (){
/*收集参数 this代表当前发生这个事件的dom对象*/
var text=this.value
var clueId='${clue.id}'
/*发ajax请求*/
$.ajax({
url:"workbench/clue/selectActivityByClueIdandText.do",
data:{
text:text,
clueId:clueId
},
dataType:"json",
type:"POST",
success:function (data){
/*遍历集合拼接字符串*/
var html='';
$.each(data,function (i,obj){
html+="<tr>";
html+=" <td><input type="checkbox" value='"+obj.id+"'/></td>";
html+=" <td>"+obj.name+"</td>";
html+=" <td>"+obj.startDate+"</td>";
html+=" <td>"+obj.endDate+"</td>";
html+=" <td>"+obj.owner+"</td>";
html+="</tr>";
})
$("#shichanghuodongsuosou").html(html)
}
})
});
3.在controller层收集参数,封装为map,调用service层的方法获取数据
/*这是显示关联市场活动列表的controller
3.在controller层收集参数,封装为map,调用service层的方法获取数据*/
@RequestMapping("/workbench/clue/selectActivityByClueIdandText.do")
@ResponseBody
public Object selectActivityByClueIdandText(String text,String clueId){
Map<String,Object> map=new HashMap<>();
map.put("actname",text);
map.put("clueid",clueId);
List<Activity> actlist = actyServoce.selectByclueidandtext(map);
return actlist;
}
4.把数据返回至ajax回调函数
5.在前端,ajax收到参数,用字符串拼接列表,打入相应的元素中
mapper层的sql
<select id="selectByclueidandtext" parameterType="map" resultMap="BaseResultMap">
select a.id,a.name,u1.name as owner,a.start_date,a.end_date
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
where a.name like concat('%',#{actname},'%') and a.id not in (
select activity_id
from tbl_clue_activity_relation
where clue_id=#{clueid}
)
</select>
6.实现线索详细页面的市场活动的关联
1.用户在模态窗口选中要关联的市场活动,至少选择一个
收集参数,选中所有被选中的列表
遍历这个列表数组所有的市场活动的id和线索的id用字符串拼接成id=v1&id=v2…&clueid=v9的形式
/*给关联增加点击事件*/
$("#guanlian").click(function (){
/*收集参数*/
var shuzu=$("#shichanghuodongsuosou input[type='checkbox']:checked");
/*表单验证*/
if(shuzu.size()==0){
alert("请至少选择一个关联")
return
}
var ids='';
$.each(shuzu,function (){
ids+="actId="+this.value+"&";
})
ids+="clueID=${clue.id}"
$.ajax({
url:"workbench/clue/guanlianshichanghuodong.do",
data:ids,
dataType: "json",
type: "POST",
success:function (data){
/*8.前端在ajax的回调函数中,如果关联成功就拼接字符串(列表) 然后用.append()追加到tbody中*/
var html='';
if(data.code=="1"){
$.each(data.data,function (i,obj){
html+="<tr>";
html+="<td>"+obj.name+"</td>";
html+="<td>"+obj.startDate+"</td>";
html+="<td>"+obj.endDate+"</td>";
html+="<td>"+obj.owner+"</td>";
html+="<td><a href="javascript:void(0);" style="text-decoration: none;" shichanghuodongid=""+obj.id+""><span class="glyphicon glyphicon-remove"></span>解除关联</a></td>";
html+="</tr>";
})
$("#xiangxiyeSCHD").append(html)
$("#bundModal").modal("hide")
/*自己思想:在ajax回调函数中 可以拿到所有被选中的列表,通过获取这个被选中的列表的父标签父到最外层的tr,
在ajax回调函数里面 只要插入成功就关闭模态窗口,直接遍历这个父标签tr数组删除列表*/
var s=$("#shichanghuodongsuosou input[type='checkbox']:checked").parent().parent();
$.each(s,function (){
this.remove();
})
}else {
alert(data.message)
$("#bundModal").modal("show")
}
}
})
})
2.一点关联,发送ajax异步请求
3.controller层用String数组,和String变量接收市场活动id数组和线索id变量
4.把这些数据封装成市场活动线索关系表实体类型的list集合,每个市场活动id都对应这个线索的id
市场活动线索关系的id用UUID生成
@RequestMapping("/workbench/clue/guanlianshichanghuodong.do")
@ResponseBody
public Object guanlianshichanghuodong(String[] actId,String clueID){
/*遍历actid数组 和clueId组合成实体类封装到list中*/
List<ClueActivityRelation> list=new ArrayList<>();
usercan usercan = new usercan();
ClueActivityRelation car=null;
for(String i:actId){
car=new ClueActivityRelation();
car.setId(UUIDsaner.getUUID());
car.setClueId(clueID);
car.setActivityId(i);
list.add(car);
}
try {
int i = clueActivityrSerivce.insertAllList(list);
if(i>0){
/*插入成功 在去查那个市场活动*/
List<Activity> list1 = actyServoce.selectByIdarray(actId);
usercan.setCode(chang.CODE_SUCCESS);
usercan.setData(list1);
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙清稍后");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙清稍后");
}
return usercan;
}
5.调用service层的方法,在mapper层用的是foreach标签拼接来插入数据
市场活动:
<select id="selectByArrayId" parameterType="string" resultMap="BaseResultMap">
select a.id,a.name,u1.name as owner,a.start_date,a.end_date
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
where a.id in
<foreach collection="array" item="actId" close=")" open="(" separator=",">
#{actId}
</foreach>
</select>
关系表插入:
<insert id="insertAllList" parameterType="clueActivityRelation">
insert into tbl_clue_activity_relation(id,clue_id,activity_id)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.id},#{obj.clueId},#{obj.activityId})
</foreach>
</insert>
6.如果插入成功,还要把刚刚选中的市场活动的信息查出来,应为要动态显示到页面
也是根据foreach拼接查
7.返回响应信息,成功或者失败 和查到的所有市场活动返回list,把这些参数封装为map返回
{code:1/0,
list:[{},{},{}],
message:“dsad”}
8.前端在ajax的回调函数中,如果关联成功就拼接字符串(列表) 然后用.append()追加到tbody中
9.用户再次点击关联市场活动 要清空text和列表
(或者,用户再次点击关联市场活动是不请空text,只把被选中添加的列表从列表中删除
自己思想:在ajax回调函数中 可以拿到所有被选中的列表,通过获取这个被选中的列表的父标签父到最外层的tr,
在ajax回调函数里面 只要插入成功就关闭模态窗口,直接遍历这个父标签tr数组删除列表
var s=$("#shichanghuodongsuosou input[type='checkbox']:checked").parent().parent();
$.each(s,function (){
this.remove();
})
7.实现线索详细页面的市场活动的删除
1.给每个解除关联增加点击事件,用户在页面点击解除关联市场活动,收集参数,收集这个市场活动的id和线索的id确定一条记录
$("#tr_"+activityId).remove() $("#xiangxiyeSCHD").on("click","a",function (){ html+="<tr id="tr_"+obj.id+"">";
2.发送ajax请求 ,controller接收到参数,用实体类接,调用service层的方法去表中删除记录
@RequestMapping("/workbench/clue/deleteshichanghuodong.do")
@ResponseBody
public Object deleteshichanghuodong(ClueActivityRelation relation){
usercan usercan = new usercan();
try {
int i = clueActivityrSerivce.deleteByActIdandClueId(relation);
if(i>0){
usercan.setCode(chang.CODE_SUCCESS);
}else {
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后。。");
}
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后。。");
}
return usercan;
}
mapper层的sql
<delete id="deleteByActIdandClueId" parameterType="clueActivityRelation">
delete from tbl_clue_activity_relation
where clue_id=#{clueId} and activity_id=#{activityId}
</delete>
3.controller返回响应信息,成功或者失败,
4.前端收到响应信息如果成功,就从页面删除这个市场活动 用市场活动的id扩展属性得到jquery对象删除
$("#xiangxiyeSCHD").on("click","a",function (){
/*收集参数 扩展属性只能用jquery。attr获取 this代表当前正在发生事件的标签的dom对象*/
var activityId=$(this).attr("shichanghuodongid")
var clueId='${clue.id}'
/*用户点击确认才发ajax请求去删除*/
if(window.confirm("确定要删除吗")){
/*发ajax请求*/
$.ajax({
url:"workbench/clue/deleteshichanghuodong.do",
data:{
activityId:activityId,
clueId:clueId
},
dataType:"json",
type:"POST",
success:function (data){
if(data.code=="1"){
/*获取的当前的tr删除 tr用扩展属性id定位*/
$("#tr_"+activityId).remove()
}else {
alert(data.message)
}
}
})
}
})
8.线索详细页面点击转化按钮到转化页面
1.给转化增加单击事件,点击转化,发同步请求,参数是这个线索的id
$("#zhuanhuan").click(function (){
/*收集参数发同步请求*/
window.location.href="workbench/clue/selectzhuanhua.do?id=${clue.id}"
})
2.在controller层收集参数,调用service层,查到线索的明细,还有在交易的模态窗口里要显示下拉列表
所以还要在数据字典值表中去查询类型为stage的数据
@RequestMapping("/workbench/clue/selectzhuanhua.do")
public String selectzhuanhua(String id,HttpServletRequest request){
Clue clue = clueService.selectByIdone(id);
List<dicvalue> stage = dicvlue.selectBytypecode("stage");
request.setAttribute("clue",clue);
request.setAttribute("stage",stage);
return "workbench/clue/convert";
}
3.用request域封装参数,请求转发到转化页面
4.在转化页面中显示数据用EL表达式和JSTL标签库
9.转化页面的交易里面的市场活动源搜索关联过得市场活动
1.用户点击市场活动源,弹出模态窗口,用户在搜索框里输入name
$("#shichanghuodongyuan").click(function (){
/*初始化工作*/
$("#searchActivityModal").modal("show")
})
2.给搜索框加上键盘弹起事件,参数为这个内容和这个线索的id(从域中取数据),发ajax请求
$("#sousuokuang").keyup(function (){
/*收集参数*/
var actname=this.value;
var clueId='${clue.id}';
/*发ajax请求*/
$.ajax({
url:"workbench/clue/selectByActivityAndClueIdguan.do",
data:{
actname:actname,
clueId:clueId
},
dataType:"json",
type:"POST",
success:function (data){
/*4.前端拿到数据,在ajax的回调函数里,动态拼接字符串,显示列表,要在单选框里扩展两个
属性,一个存市场活动id,一个存市场活动名字,应为在交易模态窗口要用*/
var html='';
$.each(data,function (i,obj){
html+="<tr>";
html+=" <td><input value='"+obj.id+"' actname='"+obj.name+"' type="radio" name="activity"/></td>";
html+=" <td>"+obj.name+"</td>";
html+=" <td>"+obj.startDate+"</td>";
html+=" <td>"+obj.endDate+"</td>";
html+=" <td>"+obj.owner+"</td>";
html+="</tr>";
})
$("#jiaoyisoushichanghuodong").html(html)
}
})
})
3.controller层拿到数据,封装为map,去查询和这个线索关联过的市场活动,返回市场活动list集合
@RequestMapping("/workbench/clue/selectByActivityAndClueIdguan.do")
@ResponseBody
public Object selectByActivityAndClueIdguan(String actname,String clueId){
/*封装参数*/
Map<String,Object> map=new HashMap<>();
map.put("actname",actname);
map.put("clueId",clueId);
/*调用service层方法*/
List<Activity> list = actyServoce.selectAllByActivityNameAndClueIdguan(map);
return list;
}
4.前端拿到数据,在ajax的回调函数里,动态拼接字符串,显示列表,要在单选框里扩展两个
属性,一个存市场活动id,一个存市场活动名字,应为在交易模态窗口要用
html+=" <td><input value='"+obj.id+"' actname='"+obj.name+"' type="radio" name="activity"/></td>";
5.给每个单选框加上单击事件.on()加,用户选中就把这个单选框里的两个数据,市场活动id’放在隐藏域里面,
名字方法框里面,在关闭模态窗口
(获取自定义属性值要用JQuery.attr()获取 this this)
$("#jiaoyisoushichanghuodong").on('click',"input",function (){
/*获取参数*/
var actID=this.value
var actname=$(this).attr("actname")
/*打入id隐藏框 name打入显示框*/
$("#yincangactid").val(actID)
$("#activityname").val(actname)
/*关闭模态窗口*/
$("#searchActivityModal").modal("hide")
})
mapper层用到的sql
<select id="selectAllByActivityNameAndClueIdguan" parameterType="map" resultMap="BaseResultMap">
select a.id,a.name,u1.name as owner,a.start_date,a.end_date
from tbl_activity as a
join tbl_user as u1 on a.owner=u1.id
where a.name like concat('%',#{actname},'%') and a.id in(
select activity_id
from tbl_clue_activity_relation
where clue_id=#{clueId}
)
</select>
10.线索详细页面转化按钮的实现
谁创建的所有者是谁
1.给转换按钮加单击事件,收集参数,(线索id,交易表单中的数据,是否选中了创建交易(checked属性))
2.表单验证,发ajax请求,在ajax回调函数里面成功就跳转到线索主页面,否则提示信息
$("#zhuanhuanxiansuo").click(function (){
/*收集参数*/
var clueID='${clue.id}';
var money = $("#amountOfMoney").val()
var name = $("#tradeName").val()
var expectedDate = $("#expectedClosingDate").val()
var stage = $("#stage").val()
var activityId = $("#yincangactid").val()
var xiaoyixuanzhongNO = $("#isCreateTransaction").prop("checked")
/*表单验证 交易额不能小于0*/
if(xiaoyixuanzhongNO=="true") {
var zhengze = /^(([1-9]d*)|0)$/
if (!zhengze.test(money)) {
alert("交易额只能是非负整数")
return
}
}
$.ajax({
url:"workbench/clue/zhuanhuanxiansuo.do",
data:{
clueId:clueID,
money:money,
name:name,
expectedDate:expectedDate,
stage:stage,
activityId:activityId,
xiaoyixuanzhongNO:xiaoyixuanzhongNO
},
dataType: "json",
type: "POST",
success:function (data){
if(data.code=="1"){
window.location.href="workbench/clue/selectxialaliebiao.do"
}else {
alert(data.message)
}
}
})
})
3.在controller层接收参数,封装为map对象,调用线索的service层的一个线索转化方法来完成全部的转换工作(因为要在一个事务中完成)
@RequestMapping("/workbench/clue/zhuanhuanxiansuo.do")
@ResponseBody
public Object zhuanhuanxiansuo(String clueId,String money,String name,
String expectedDate,String stage,String activityId,
String xiaoyixuanzhongNO,HttpSession session){
usercan usercan = new usercan();
User user= (User) session.getAttribute(chang.SESSION_NAME);
/*封装参数*/
Map<String,Object> map=new HashMap<>();
map.put("clueId",clueId);
map.put("money",money);
map.put("name",name);
map.put("expectedDate",expectedDate);
map.put("stage",stage);
map.put("activityId",activityId);
map.put("xiaoyixuanzhongNO",xiaoyixuanzhongNO);
map.put(chang.SESSION_NAME,user);
/*调用service层*/
try{
clueService.xinsuozhuanhau(map);
usercan.setCode(chang.CODE_SUCCESS);
}catch (Exception e){
e.printStackTrace();
usercan.setCode(chang.CODE_SHIBAI);
usercan.setMessage("系统忙请稍后。。。。");
}
return usercan;
}
4.在service层,
4.1:先根据线索id,查询线索的全部信息(这里的id查的就是保存的id,因为到时候是插入表中的数据存的都是id),然后把查到的clue对象的
公司信息封装为客户表的实体类对象,在调用客户的mapper层插入数据
public void xinsuozhuanhau(Map<String, Object> map) {
/*4.1:先根据线索id,查询线索的全部信息(这里的id查的就是保存的id,因为到时候是插入表中的数据存的都是id),然后把查到的clue对象的
公司信息封装为客户表的实体类对象,在调用客户的mapper层插入数据*/
String clueID = (String) map.get("clueId");
String shifou = (String) map.get("xiaoyixuanzhongNO");
User user= (User) map.get(chang.SESSION_NAME);
Clue clue = clueMapper.SelectByIdNo(clueID);
Customer customer = new Customer();
/*谁创建的所有者是谁 这个当前用户对象有controller层通过map传过来*/
customer.setCreateBy(user.getId());
customer.setCreateTime(SimDate.getdate(new Date()));
customer.setId(UUIDsaner.getUUID());
customer.setAddress(clue.getAddress());
customer.setDescription(clue.getDescription());
customer.setContactSummary(clue.getContactSummary());
customer.setName(clue.getCompany());
customer.setNextContactTime(clue.getNextContactTime());
customer.setOwner(user.getId());
customer.setPhone(clue.getPhone());
customer.setWebsite(clue.getWebsite());
customerMapper.insertByCustomer(customer);
用到的sql
<select id="SelectByIdNo" resultMap="BaseResultMap" parameterType="string">
select <include refid="Base_Column_List"></include>
from tbl_clue
where id=#{clueId}
</select>
<insert id="insertByCustomer" parameterType="customer">
insert into tbl_customer(id,owner,name,website,phone,create_by,create_time,contact_summary,
next_contact_time, description, address)
values (#{id},#{owner},#{name},#{website},#{phone},#{createBy},#{createTime},#{contactSummary},#{nextContactTime},#{description},#{address})
</insert>
4.2:然后把查到的clue对象的个人信息封装为联系人表的实体类对象,在调用联系人的mapper层插入数据
Contacts contacts = new Contacts();
contacts.setAddress(clue.getAddress());
contacts.setCreateBy(user.getId());
contacts.setCreateTime(SimDate.getdate(new Date()));
contacts.setContactSummary(clue.getContactSummary());
contacts.setId(UUIDsaner.getUUID());
contacts.setDescription(clue.getDescription());
contacts.setAppellation(clue.getAppellation());
contacts.setCustomerId(customer.getId());
contacts.setEmail(clue.getEmail());
contacts.setFullname(clue.getFullname());
contacts.setJob(clue.getJob());
contacts.setMphone(clue.getMphone());
contacts.setNextContactTime(clue.getNextContactTime());
contacts.setOwner(user.getId());
contacts.setSource(clue.getSource());
contactsMapper.insertByContacts(contacts);
用到的sql
<insert id="insertByContacts" parameterType="contacts">
insert into tbl_contacts(id, owner,source, customer_id, fullname, appellation, email, mphone, job, create_by,
create_time,description, contact_summary, next_contact_time,
address)
values (#{id},#{owner},#{source},#{customerId},#{fullname},#{appellation},#{email},#{mphone},#{ job},#{ createBy},#{createTime},#{description},#{ contactSummary},#{ nextContactTime},#{address});
</insert>
4.3:再根据线索id查询这个线索的所有备注,分别忘客户备注表和联系人备注表中加一份
List<ClueRemark> clueRemarks = clueRemarkMapper.selectByClueIdbeizhu(clueID);
ContactsRemark contactsRemark=null;
CustomerRemark customerRemark=null;
List<ContactsRemark> ctrList=new ArrayList<>();
List<CustomerRemark> cmrList=new ArrayList<>();
for(ClueRemark i:clueRemarks){
contactsRemark = new ContactsRemark();
customerRemark = new CustomerRemark();
contactsRemark.setContactsId(contacts.getId());
contactsRemark.setCreateBy(i.getCreateBy());
contactsRemark.setCreateTime(i.getCreateTime());
contactsRemark.setId(UUIDsaner.getUUID());
contactsRemark.setEditBy(i.getEditBy());
contactsRemark.setEditTime(i.getEditTime());
contactsRemark.setEditFlag(i.getEditFlag());
contactsRemark.setNoteContent(i.getNoteContent());
ctrList.add(contactsRemark);
customerRemark.setCustomerId(customer.getId());
customerRemark.setCreateBy(i.getCreateBy());
customerRemark.setCreateTime(i.getCreateTime());
customerRemark.setId(UUIDsaner.getUUID());
customerRemark.setEditBy(i.getEditBy());
customerRemark.setEditTime(i.getEditTime());
customerRemark.setEditFlag(i.getEditFlag());
customerRemark.setNoteContent(i.getNoteContent());
cmrList.add(customerRemark);
}
if(ctrList!=null && ctrList.size()>0) {
contactsRemarkMapper.insertByContactsRemark(ctrList);
}
if(cmrList!=null && cmrList.size()>0) {
customerRemarkMapper.insertByCustomerRemark(cmrList);
}
用到的sql
<select id="selectByClueIdbeizhu" parameterType="string" resultMap="BaseResultMap">
select <include refid="Base_Column_List"></include>
from tbl_clue_remark
where clue_id=#{clueId}
</select>
<insert id="insertByContactsRemark" parameterType="contactsRemark">
insert into tbl_contacts_remark(id, note_content, create_by, create_time, edit_by, edit_time, edit_flag, contacts_id)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.id},#{obj.noteContent},#{obj.createBy},#{obj.createTime},#{obj.editBy},#{obj.editTime},#{obj.editFlag},#{obj.contactsId})
</foreach>
</insert>
<insert id="insertByCustomerRemark" parameterType="customerRemark">
insert into tbl_customer_remark(id, note_content, create_by, create_time, edit_by, edit_time, edit_flag, customer_id)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.id},#{obj.noteContent},#{obj.createBy},#{obj.createTime},#{obj.editBy},#{obj.editTime},#{obj.editFlag},#{obj.customerId})
</foreach>
</insert>
4.4:再根据线索id获取线索和市场活动的关联关系,转为联系人与市场活动的关联关系
List<ClueActivityRelation> list = clueActivityRelationMapper.selectByClueIda(clueID);
List<ContactsActivityRelation> carlist=new ArrayList<>();
ContactsActivityRelation contactsActivityRelation = null;
for(ClueActivityRelation i :list){
contactsActivityRelation= new ContactsActivityRelation();
contactsActivityRelation.setId(UUIDsaner.getUUID());
contactsActivityRelation.setActivityId(i.getActivityId());
contactsActivityRelation.setContactsId(contacts.getId());
carlist.add(contactsActivityRelation);
}
contactsActivityRelationMapper.insetByContactsActivityRelation(carlist);
用到的sql
<select id="selectByClueIda" parameterType="string" resultMap="BaseResultMap">
select <include refid="Base_Column_List"></include>
from tbl_clue_activity_relation
where clue_id=#{clueId}
</select>
<insert id="insetByContactsActivityRelation" parameterType="contactsActivityRelation">
insert into tbl_contacts_activity_relation(id, contacts_id, activity_id)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.id},#{obj.contactsId},#{obj.activityId})
</foreach>
</insert>
4.5:如果用户点击了创建交易框,那就要在service层用交易的实体类对象,创建交易数据
if("true".equals(shifou)){
Tran tran = new Tran();
/* map.put("money",money);
map.put("name",name);
map.put("expectedDate",expectedDate);
map.put("stage",stage);
map.put("activityId",activityId);*/
tran.setMoney((String) map.get("money"));
tran.setName((String) map.get("name"));
tran.setStage((String) map.get("stage"));
tran.setActivityId((String) map.get("activityId"));
tran.setCreateBy(user.getId());
tran.setCreateTime(SimDate.getdate(new Date()));
tran.setId(UUIDsaner.getUUID());
tran.setOwner(user.getId());
tran.setContactsId(contacts.getId());
tran.setExpectedDate((String) map.get("expectedDate"));
tranMapper.insertByTran(tran);
用到的sql
<insert id="insertByTran" parameterType="tran">
insert into tbl_tran( id, owner, money, name, expected_date, customer_id, stage, type, source, activity_id,
contacts_id, create_by, create_time, edit_by, edit_time, description, contact_summary,
next_contact_time)
values (#{id},#{ owner},#{ money},#{ name},#{ expectedDate},#{ customerId},#{ stage},#{ type},#{ source},#{ activityId},#{ contactsId},#{ createBy},#{ createTime},#{ editBy},#{ editTime},#{ description},#{ contactSummary},#{ nextContactTime})
</insert>
4.6:把备注信息再往交易表备注里存一份
List<TranRemark> TranremarkList=new ArrayList<>();
TranRemark tranRemark =null;
for(ClueRemark i:clueRemarks){
tranRemark= new TranRemark();
tranRemark.setTranId(tran.getId());
tranRemark.setCreateBy(i.getCreateBy());
tranRemark.setCreateTime(i.getCreateTime());
tranRemark.setId(UUIDsaner.getUUID());
tranRemark.setEditBy(i.getEditBy());
tranRemark.setEditTime(i.getEditTime());
tranRemark.setEditFlag(i.getEditFlag());
tranRemark.setNoteContent(i.getNoteContent());
TranremarkList.add(tranRemark);
}
if(TranremarkList!=null && TranremarkList.size()>0) {
tranRemarkMapper.insertByTranRemarks(TranremarkList);
}
}
用到的sql
<insert id="insertByTranRemarks" parameterType="tranRemark">
insert into tbl_tran_remark( id, note_content, create_by, create_time, edit_by, edit_time, edit_flag, tran_id)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.id},#{obj.noteContent},#{obj.createBy},#{obj.createTime},#{obj.editBy},#{obj.editTime},#{obj.editFlag},#{obj.tranId})
</foreach>
</insert>
4.7:先删除线索的备注,再删除线索和市场活动的关联关系,再删除这个线索
clueRemarkMapper.deleteBYIda(clueID);
clueActivityRelationMapper.deleteByIda(clueID);
clueMapper.deleteByIda(clueID);
<delete id="deleteBYIda" parameterType="string">
delete from tbl_clue_remark
where clue_id=#{clueID}
</delete>
<delete id="deleteByIda" parameterType="string">
delete from tbl_clue_activity_relation
where clue_id=#{clueId}
</delete>
<delete id="deleteByIda" parameterType="string">
delete from tbl_clue
where id=#{clueID}
</delete>
5.controller层返回响应信息成功或者失败就行
十一:交易功能的实现
1.用户点击菜单的交易来到交易页面
html转jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<%String bg=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";%>
<meta charset="UTF-8">
<base href="<%=bg%>">
1.用户点击交易菜单,发送同步请求,不用提交参数。
<li class="liClass"><a href="workbench/transaction/doindex.do" target="workareaFrame"><span class="glyphicon glyphicon-usd"></span> 交易(商机)</a></li>
2.在controller层,要查出来交易主页面要用到的动态数据,下拉列表里的东西(调用service查以前写过的方法)
@RequestMapping("/workbench/transaction/doindex.do")
public String doindex(HttpServletRequest request){
List<dicvalue> stage = dicvalueMapper.selectBytypecode("stage");
List<dicvalue> transactionType = dicvalueMapper.selectBytypecode("transactionType");
List<dicvalue> source = dicvalueMapper.selectBytypecode("source");
request.setAttribute("stage",stage);
request.setAttribute("transactionType",transactionType);
request.setAttribute("source",source);
return "workbench/transaction/index";
}
3.查出数据,封装在request域中,通过请求转发到主页面
4.在主页面用EL表达式和JSTL标签库显示
2.交易用户点击创建按钮跳转到创建页面
1.用户点击创建按钮,发同步请求,不用参数,准备跳转到创建页面
$("#chuangjian").click(function (){
window.location.href="workbench/transaction/tosave.do";
})
2.controller层接收到请求,要先查出来创建页面要用到的数据,下拉列表里的值和用户表里的
@RequestMapping("/workbench/transaction/tosave.do")
public String tosave(HttpServletRequest request){
List<User> users = userMapper.queryAllUsers();
List<dicvalue> stage = dicvalueMapper.selectBytypecode("stage");
List<dicvalue> transactionType = dicvalueMapper.selectBytypecode("transactionType");
List<dicvalue> source = dicvalueMapper.selectBytypecode("source");
request.setAttribute("stage",stage);
request.setAttribute("transactionType",transactionType);
request.setAttribute("source",source);
request.setAttribute("users",users);
return "workbench/transaction/save";
}
3.查出数据,封装在request域中,通过请求转发到创建页面
4.在主页面用EL表达式和JSTL标签库显示
3.在创建页面点击市场活动源
1.用户点击市场活动源,弹出查询市场活动的模态窗口,
$("#shichanghuodongyuan").click(function (){
$("#findMarketActivity").modal("show");
})
2.给搜索框加上键盘抬起事件,发ajax请求,参数就是这个文本框内容,去模糊查询市场活动
3.在controller层收到参数,去模糊查询市场活动,返回市场活动的list集合
@RequestMapping("/workbench/transaction/selectshichanghuodong.do")
@ResponseBody
public Object selectshichanghuodong(String text){
List<Activity> list = activityMapper.selectAllByActivityaa(text);
return list;
}
4.在ajax的回调函数里拼接字符串显示列表
/*2.给搜索框加上键盘抬起事件,发ajax请求,参数就是这个文本框内容,去模糊查询市场活动
*/ $("#sousuo1").keyup(function (){
/* 收集参数*/
var text= $("#sousuo1").val()
/*发ajax*/
$.ajax({
url:"workbench/transaction/selectshichanghuodong.do",
data:{text:text},
dataType:"json",
type:"POST",
success:function (data){
var html='';
$.each(data,function (i,obj){
html+="<tr>";
html+=" <td><input value='"+obj.id+"' actname='"+obj.name+"' type="radio" name="activity"/></td>";
html+=" <td>"+obj.name+"</td>";
html+=" <td>"+obj.startDate+"</td>";
html+=" <td>"+obj.endDate+"</td>";
html+=" <td>"+obj.owner+"</td>";
html+="</tr>";
})
$("#shichanghuodongaaa").html(html)
}
})
})
5.给每一个市场活动的单选框加上单击事件
6.一点就把这个市场活动的名字显示在文本框里和市场活动的id保存在隐藏域里
$("#shichanghuodongaaa").on('click',"input[type='radio']",function (){
/*6.一点就把这个市场活动的名字显示在文本框里和市场活动的id保存在隐藏域里*/
var actid=this.value
var actname=$(this).attr("actname")
$("#create-activitySrc").val(actname)
$("#yincangactid").val(actid)
/*关闭模态窗口*/
$("#findMarketActivity").modal("hide")
})
4.在创建页面点击联系人
1.用户点击搜索标签,然后打开模态窗口
$("#lianxiren").click(function (){
$("#findContacts").modal("show")
})
2.在文本框上加键盘弹起事件 ,发ajax异步请求,参数为文本框内容,每次都去联系人表中模糊查询这个文本框名称的数据
$("#lianxirenname").keyup(function (){
/*收集参数*/
var text=$("#lianxirenname").val()
$.ajax({
url:"workbench/transaction/selectlianxiren.do",
data:{text:text},
dataType: "json",
type: "POST",
success:function (data){
var html='';
$.each(data,function (i,obj){
html+="<tr>";
html+=" <td><input type="radio" value='"+obj.id+"' ctsname='"+obj.fullname+"' name="activity"/></td>";
html+=" <td>"+obj.fullname+"</td>";
html+=" <td>"+obj.email+"</td>";
html+=" <td>"+obj.mphone+"</td>";
html+="</tr>";
})
$("#lianxirentbdy").html(html)
}
})
})
3.controller层收到参数,调用service层方法去查询
用到的sql
<select id="selectByCtsName" resultMap="BaseResultMap" parameterType="string">
select id,fullname,email,mphone
from tbl_contacts
where fullname like concat('%',#{ctsName},'%')
</select>
@RequestMapping("/workbench/transaction/selectlianxiren.do")
@ResponseBody
public Object selectlianxiren(String text){
List<Contacts> contacts = contactsService.selectByCtsName(text);
return contacts;
}
4.返回查到的联系人list
5.前端在ajax的回调函数里拼接字符串,显示在列表中
6.给每一个联系人的单选框加上单击事件
$("#lianxirentbdy").on('click',"input[type='radio']",function (){
/*6.一点就把这个市场活动的名字显示在文本框里和市场活动的id保存在隐藏域里*/
var ctsid=this.value
var ctsname=$(this).attr("ctsname")
$("#create-contactsName").val(ctsname)
$("#lianxirenyincang").val(ctsid)
/*关闭模态窗口*/
$("#findContacts").modal("hide")
})
6.一点就把这个联系人的名字显示在文本框里和联系人的id保存在隐藏域里
5.用户点击阶段直接填入可能性配置
1.用户提供每个阶段对应的可能性大小的配置文件,这里我们用属性配置文件
资质审查=10
需求分析=20
价值建议=40
确定决策者=60
提案/报价=70
谈判/复审=90
成交=100
丢失的线索=0
因竞争丢失关闭=0
2.用户每次选择阶段中的数据 (改变事件),都发送ajax请求,参数为这个阶段的名称
$("#create-transactionStage").change(function (){
var jieduan= $("#create-transactionStage option:selected").text();
if(jieduan==''){
$("#create-possibility").val("")
return
}
$.ajax({
url:"workbench/transaction/slelectkenengxing.do",
data:{jieduan:jieduan},
dataType:"json",
type:"POST",
success:function (data){
$("#create-possibility").val(data)
}
})
})
3.要进行参数验证,如果这个参数为空,那么把可能性的文本框设置为空,结束事件
3.controller层接收到请求和参数,去用resourcesB。。属性资源绑定器,去根据传过来的阶段名找概率
@RequestMapping("/workbench/transaction/slelectkenengxing.do")
@ResponseBody
public Object slelectkenengxing(String jieduan){
ResourceBundle bundle = ResourceBundle.getBundle("kenengxing");
String string = bundle.getString(jieduan);
return string;
}
4.controller返回概率
5.前端ajax回调函数里接收到参数,把它摄入可能性的文本框
6.创建交易页面的客户自动搜索补全(利用插件bs_typeahead自动补全插件)
当容器加载完成后给这个客户的文本框加上插件的方法typeahead
/*给客户文本框加上自动补全插件函数*/
$("#create-accountName").typeahead({
source:function (Jquery,process){
$.ajax({
url:"workbench/transaction/selectBynamekehu.do",
data:{cstname:Jquery}, //这个搜索下拉列表自动补全参数source:['','','','']
dataType:"json", //传一个这样类型的字符串数组,那么当用户在文本框里输入内容键盘弹起时就会去这个
type:"POST", //字符串里匹配显示到下拉列表中自动补全,这个参数还可以传一个函数
success:function (data){ //这个process函数的第一个参数是这个文本框每次键盘弹起获取的值,第二个参数是一个函数的名称
process(data) //可以给这个函数传递一个['','','','']这样的参数,他就会把它给source去显示
} //用户每抬起键盘一次就会调用这个source的函数 发ajax请求,controller就会返回这个['','','','']数据,直接调用process(data
})
}
})
3.当用户每次弹起键盘时收集参数文本内容,发送ajax请求
4.controller接收到参数,去客户表里模糊查询客户名称,返回List(应为这个插件处理的是[‘’,‘’,‘’,‘’]这样的数组)
@RequestMapping("/workbench/transaction/selectBynamekehu.do")
@ResponseBody
public Object selectBynamekehu(String cstname){
List<String> list = customerServicess.selectByname(cstname);
return list;
}
<select id="selectByname" parameterType="string" resultType="string">
select name
from tbl_customer
where name like concat('%',#{cstname},'%')
</select>
7.用户点击保存,保存交易信息
1.用户填写完表单中的数据,点击保存,收集参数,发ajax异步请求(因为保存不成功不跳转页面)
$("#baocunjiaoyi").click(function (){
/*收集参数*/
var owner =$("#create-transactionOwner").val()
var money =$("#create-amountOfMoney").val()
var name =$("#create-transactionName").val()
var expectedDate =$("#create-expectedClosingDate").val()
var cstname =$("#create-accountName").val()
var stage =$("#create-transactionStage").val()
var type =$("#create-transactionType").val()
var source =$("#create-clueSource").val()
var activityId =$("#yincangactid").val()
var contactsId =$("#lianxirenyincang").val()
var description =$("#create-describe").val()
var contactSummary =$("#create-contactSummary").val()
var nextContactTime =$("#create-nextContactTime").val()
/*表单验证*/
/*发ajax请求*/
$.ajax({
url:"workbench/transaction/baocunTran.do",
data:{
owner:owner,
money:money ,
name:name ,
expectedDate:expectedDate ,
cstname:cstname ,
stage:stage ,
type:type ,
source:source ,
activityId:activityId ,
contactsId:contactsId ,
description:description ,
contactSummary:contactSummary ,
nextContactTime:nextContactTime
},
dataType:"json",
type:"POST",
success:function (data){
if(data.code=="1"){
window.location.href="workbench/transaction/doindex.do"
}else {
alert(data.message)
}
}
})
})
2.controller层收到参数,封装为map(直接写map加上@RequestParam注解),调用service层的方法
@RequestMapping("/workbench/transaction/baocunTran.do")
@ResponseBody
public Object baocunTran(
@RequestParam //要使用前端参数名作为key参数值作为value直接封装为map就要用上这个注解
Map<String,Object> map, HttpSession session){
map.put(chang.SESSION_NAME,session.getAttribute(chang.SESSION_NAME));
usercan usercan = new usercan();
try {
tranSerivce.insertByTrannnn(map);
usercan.setCode(chang.CODE_SUCCESS);
}catch(Exception e){
e.printStackTrace();
usercan.setMessage("系统忙请稍后");
usercan.setCode(chang.CODE_SHIBAI);
}
return usercan;
}
3.在service层要先根据客户名字去查询客户表中有没有这个记录,如果有直接用查到的客户记录的id,如果没有
就要先创建一条客户记录在获取这个新创建的客户记录的id
String cstname= (String) map.get("cstname");
User user= (User) map.get(chang.SESSION_NAME);
Customer customer = customerMapper.selectBycstnameone(cstname);
if(customer==null){
customer=new Customer();
customer.setOwner(user.getId());
customer.setName(cstname);
customer.setId(UUIDsaner.getUUID());
customer.setCreateBy(user.getId());
customer.setCreateTime(SimDate.getdate(new Date()));
customerMapper.insertByCustomer(customer);
}
4.在根据map中的数据封装为交易实体类对象,插入交易表中一条记录
Tran tran = new Tran();
tran.setId(UUIDsaner.getUUID());
tran.setCreateBy(user.getId());
tran.setCreateTime(SimDate.getdate(new Date()));
tran.setOwner((String) map.get("owner"));
tran.setExpectedDate((String) map.get("expectedDate"));
tran.setContactSummary((String) map.get("contactSummary"));
tran.setStage((String) map.get("stage"));
tran.setName((String) map.get("name"));
tran.setContactsId((String) map.get("contactsId"));
tran.setActivityId((String) map.get("activityId"));
tran.setMoney((String) map.get("money"));
tran.setCustomerId(customer.getId());
tran.setDescription((String) map.get("description"));
tran.setNextContactTime((String) map.get("nextContactTime"));
tran.setSource((String) map.get("source"));
tran.setType((String) map.get("type"));
tranMapper.insertByTran(tran);
5.controller层返回响应信息,插入成功还是失败
6.在前端ajax回调函数里面,如果插入成功就跳转到交易主页面,如果失败就不跳转显示提示信息
8.查看交易详细信息
1.用户在交易主页面点击交易名称上的超链接,发送同步请求(因为要跳转页面),参数为这个交易的id
2.controller层收集到id,调用service层的方法,去查询这个交易的详细信息,和这个交易备注的详细信息,和这个交易阶段的历史信息
@RequestMapping("/workbench/transaction/selectxiangxi.do")
public String selectxiangxi(String tranId,HttpServletRequest request){
Tran tran = tranSerivce.selectByTranId(tranId);
List<TranHistory> tranHistories = tranHisService.selectByTranId(tranId);
List<TranRemark> remarkList = TravremarkServicess.selectByTranId(tranId);
/*根据阶段获取可能性 用tran实体类扩展属性传递数据*/
ResourceBundle kenengxing = ResourceBundle.getBundle("kenengxing");
tran.setKenengxingzhi( kenengxing.getString(tran.getStage()));
request.setAttribute("tran",tran);
request.setAttribute("tranHistories",tranHistories);
request.setAttribute("remarkList",remarkList);
return "workbench/transaction/detail";
}
3.controller层根据阶段获取可能性 用tran实体类扩展属性传递数据,把数据封装到request域中,请求转发到交易详细页面
用到的sql
select t.id,u1.name as owner,t.money,t.name,t.expected_date,ct.name as customer_id,
dv.value as stage,dv2.value as type,dv3.value as source,act.name as activity_id,
cts.fullname as contacts_id,u2.name as create_by,t.create_time,
u3.name as edit_by,t.edit_time,t.description,t.contact_summary,t.next_contact_time
from tbl_tran as t
join tbl_user as u1 on u1.id=t.owner
join tbl_customer as ct on ct.id=t.customer_id
join tbl_dic_value as dv on dv.id=t.stage
left join tbl_dic_value as dv2 on dv2.id=t.type
left join tbl_dic_value as dv3 on dv3.id=t.source
left join tbl_activity as act on act.id=t.activity_id
left join tbl_contacts as cts on cts.id=t.contacts_id
join tbl_user as u2 on u2.id=t.create_by
left join tbl_user as u3 on u3.id=t.edit_by
where t.id=#{tranId}
<select id="selectByTranId" parameterType="string" resultMap="BaseResultMap">
select hh.id,dv.value as stage,hh.money,hh.expected_date,hh.create_time,u1.name as create_by
from tbl_tran_history as hh
join tbl_dic_value as dv on dv.id=hh.stage
join tbl_user as u1 on u1.id=hh.create_by
where hh.tran_id=#{tranId}
order by hh.create_time asc
</select>
<select id="selectByTranId" resultMap="BaseResultMap" parameterType="string">
select a.id,a.note_content,a.create_time,u1.name as create_by,
a.edit_time,u2.name as edit_by,a.edit_flag
from tbl_tran_remark as a
join tbl_user as u1 on a.create_by=u1.id
left join tbl_user as u2 on a.edit_by=u2.id
where a.tran_id=#{tranId}
order by a.create_time asc
</select>
4.交易详细页面拿到数据用EL表达式和JSTL标签库显示
9.交易详细页面的图标显示
思路:
1.图标分析
图标的颜色:两种
图标的形状:三种
每一个图标对应一个阶段(所以有多少阶段就又多少图标)
图标的顺序:和阶段顺序一样
什么样的阶段显示什么样的图标:首先要去数据库里按顺序查阶段,再在前端用Jstl循环判断显示图标
三种情况:
如果当期遍历出来的阶段和这条交易所在的阶段的order_no相比等于就显示灯泡绿色
如果当期遍历出来的阶段和这条交易所在的阶段的order_no相比小于就显示√绿色
如果当期遍历出来的阶段和这条交易所在的阶段的order_no相比小于就显示点黑色
图标 图标的样式 鼠标停顿显示当前阶段值 颜色
<span class=“glyphicon glyphicon-ok-circle” data-content=“” style=“color: #90F790;”
<c:forEach items="${stage}" var="stg">
<c:if test="${stg.orderNo==tran.orderNo}">
<span class="glyphicon glyphicon-map-marker mystage" data-toggle="popover" data-placement="bottom" data-content="${stg.value}" style="color: #90F790;"></span>
-----------
</c:if>
<c:if test="${stg.orderNo>tran.orderNo}">
<span class="glyphicon glyphicon-record mystage" data-toggle="popover" data-placement="bottom" data-content="${stg.value}"></span>
-----------
</c:if>
<c:if test="${stg.orderNo<tran.orderNo}">
<span class="glyphicon glyphicon-ok-circle mystage" data-toggle="popover" data-placement="bottom" data-content="${stg.value}" style="color: #90F790;"></span>
-----------
</c:if>
</c:forEach>
要在controller层调用service层查询所有阶段值,通过request域返回给前端,
/*查阶段的所有字段 给显示图标用*/
List<dicvalue> stage = dicvlue.selectBytypecode("stage");
还要查询这个交易的阶段的order_no的值,在查交易的时候多加一个字段和在交易的实体类里扩展一个字段,resourctmap也要变
<result column="order_o" property="orderNo" jdbcType="VARCHAR" />
column查询时起了别名就用别名
十二:CRM用到的插件
前端插件使用步骤
前端插件使用步骤:
1)引入开发包:.js,.css
下载开发包,拷贝到项目webapp目录下
把开发包引入到jsp文件中:<link><script>
2)创建容器:<input type="text"><div>
3)当容器加载完成之后,对容器调用工具函数.
1.前端日历插件基于bootstrap框架(datetimepicker)
/*给创建市场活动的日期输入框加日历 这是自动加单击事件的*/
$("#create-startTime,#create-endTime").datetimepicker({
language:"zh-CN",//设置语言为中文格式
format:"yyyy-mm-dd",//设置选中完日历后返回给文本框的字符串格式
minView:"month",//设置最小可以选择到哪里 写月最小显示到日
autoclose:true, //设置选完后关闭
initialDate:new Date(), //设置初始化时候的选中 为当前时间
todayBtn:true, //设置在下面显示今天按钮 默认false不显示
clearBtn:true //设置清空按钮 默认为false不显示 这里应为要显示中文的清空 所以改了源码bootstrap-theme.min.css这里面
pickerPosition:'top-right'//在屏幕的上面显示日历
})
要用到
<link href="jquery/bootstrap_3.3.0/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
<link href="jquery/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.min.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
<script type="text/javascript" src="jquery/bootstrap_3.3.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="jquery/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.js"></script>
<script type="text/javascript" src="jquery/bootstrap-datetimepicker-master/locale/bootstrap-datetimepicker.zh-CN.js"></script>语言包
2.前端分页插件bs_pagination
<link href="jquery/bootstrap_3.3.0/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
<link href="jquery/bs_pagination-master/css/jquery.bs_pagination.min.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
<script type="text/javascript" src="jquery/bootstrap_3.3.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="jquery/bs_pagination-master/js/jquery.bs_pagination.min.js"></script>
<script type="text/javascript" src="jquery/bs_pagination-master/localization/en.js"></script>
/*要在这个函数的ajax的回掉函数里加插件查询函数 应为要获取参数 每页条数和总页数和总记录条数 而且
* 每发一次请求这个插件的信息要跟着变*/
$("#fenye").bs_pagination({
currentPage:beginNo,//当前页号 参数传
totalRows:data.zongtiao,//总记录条数 ajax返回了
totalPages:zongye, //总页数是这个函数的必填值 是根据总记录条数 每页显示条数算出来的
rowsPerPage:pagesize,//每页显示条数
visiblePageLinks: 5,//这个是那个卡片数最多5个
showGoToPage: true,//显示跳转部分 默认true显示
showRowsPerPage: true,//显示设置每页条数 默认true显示
showRowsInfo: true,//显示记录的信息部分 默认true显示
onChangePage:function (event,objpage) {
/*这个是每次页号发生改变就会执行这个函数 第一个参数是这个事件源
* 第二个参数是这个 页面对象 包含的是外面的函数发生页号改变的所有属性信息
* 页号发生改变 上面的属性值也会跟着变*/
//当页号发生改变是 再次调用这个函数 去打请求刷新这个页面 把改变后的当前页号和每页显示条数传给他
queryhuodong(objpage.currentPage,objpage.rowsPerPage);
}
})
/*如果更新成功当前页号和每页显示条数不变 关闭模态窗口 getOption这个函数 这个分页容器#fenye*/
queryhuodong($("#fenye").bs_pagination('getOption','currentPage'),$("#fenye").bs_pagination('getOption','rowsPerPage'))
3.代码搜索自动补全插件bs_typeahead
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
<script type="text/javascript" src="jquery/bootstrap_3.3.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="jquery/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.js"></script>
<script type="text/javascript" src="jquery/bootstrap-datetimepicker-master/locale/bootstrap-datetimepicker.zh-CN.js"></script>
<script type="text/javascript" src="jquery/bs_typeahead/bootstrap3-typeahead.min.js"></script>
2.当容器加载完成后给这个客户的文本框加上插件的方法typeahead
/*给客户文本框加上自动补全插件函数*/
$("#create-accountName").typeahead({
source:function (Jquery,process){
$.ajax({
url:"workbench/transaction/selectBynamekehu.do",
data:{cstname:Jquery}, //这个搜索下拉列表自动补全参数source:['','','','']
dataType:"json", //传一个这样类型的字符串数组,那么当用户在文本框里输入内容键盘弹起时就会去这个
type:"POST", //字符串里匹配显示到下拉列表中自动补全,这个参数还可以传一个函数
success:function (data){ //这个process函数的第一个参数是这个文本框每次键盘弹起获取的值,第二个参数是一个函数的名称
process(data) //可以给这个函数传递一个['','','','']这样的参数,他就会把它给source去显示
} //用户每抬起键盘一次就会调用这个source的函数 发ajax请求,controller就会返回这个['','','','']数据,直接调用process(data
})
}
})
4.java文件插件Apache-poi文件的创建
关于办公文档插件使用的基本思想:把办公文档的所有元素封装成普通的Java类,
程序员通过操作这些类达到操作办公文档目的。
文件---------HSSFWorkbook
页-----------HSSFSheet
行-----------HSSFRow
列-----------HSSFCell
样式---------HSSFCellStyle
加依赖apache-poi
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
操作类*/
/*创建一个文件类 往里面加页*/
HSSFWorkbook sheets = new HSSFWorkbook();
/*a往页里加行*/
HSSFSheet sheet = sheets.createSheet("学生表单");
/*0代表第一行*/
HSSFRow row = sheet.createRow(0);
/*往行里加列*/
HSSFCell cell = row.createCell(0);
/*给0行0列设置值*/
cell.setCellValue("学生姓名");
cell=row.createCell(1);/*设置第二列*/
cell.setCellValue("学生年龄");
/*给文件创建样式类*/
HSSFCellStyle cellStyle = sheets.createCellStyle();
/*设置对齐样式居中*/
cellStyle.setAlignment(HorizontalAlignment.CENTER);
/*循环创建行*/
for(int i=1;i<=10;i++){
row=sheet.createRow(i);
cell = row.createCell(0);
cell.setCellValue("刘"+i);
cell= row.createCell(1);
/*把样式设置到最后一列中*/
cell.setCellStyle(cellStyle);
cell.setCellValue(i+10);
}
/*输出文件通过文件字节输出流 excel文件是以.xls结尾*/
FileOutputStream fileOutputStream = new FileOutputStream("E:\aa\ceshi.xls");
sheets.write(fileOutputStream);
/*刷新流关闭流 关闭文件*/
fileOutputStream.flush();
fileOutputStream.close();
sheets.close();
5.图表插件echarts
引入开发包
:<%--使用echarts插件他依赖于jquery--%>
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
<script type="text/javascript" src="jquery/echars/echarts.min.js"></script>
建立容器:
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
当容器加载完成之后对容器调用插件函数
: /*插件使用 基于准备好的dom,初始化echarts实例*/
var macharts= echarts.init(document.getElementById("main"))
macharts.setOption(option)
option = {
title: {
text: '交易统计阶段数据'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c}'
},
toolbox: {
feature: {
dataView: { readOnly: false },
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '数据量',
type: 'funnel',
left: '10%',
width: '80%',
label: {
formatter: '{b}'
},
labelLine: {
show: true
},
itemStyle: {
opacity: 0.7
},
emphasis: {
label: {
position: 'inside',
formatter: '{b}: {c}'
}
},
data:data
}
]
};
data:数据的格式是这种形式的
[
{value:值,name:值},
{value:值,name:值}
]
十三:前端通用代码
1.向标签中打入数据
$(“#remarkDiv”).before(html) /在这个标签外部的前面加上摄入的内容/
2,把页面片段显示在动态显示在页面中:
选择器.html(htmlStr):覆盖显示在标签的内部
选择器.text(htmlStr):覆盖显示在标签的内部
选择器.append(htmlStr):追加显示在指定标签的内部的后边
选择器.after(htmlStr):追加显示在指定标签的外部的后边
2.全选框选中与取消
<script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
/*给全选按钮加单击事件 全选列表则全选 这种加事件的方式只能给固有元素加事件
* 固有元素:当调用事件函数给元素添加事件时,如果元素已经生成,则这些元素叫做固有元素;*/
$("#quanxuan").click(function (){
/*全选的checked属性是true则 列表的checked属性值也是true*/
/*获取全部的列表 父子选择器 中间是空格 则可以筛选所有的子标签 中间是>则只能筛选一级字标签 【属性过滤】
* this代表当前事件元素的dom对象 */
$("#huodongbiao input[type='checkbox']").prop('checked',this.checked)
})
/*给所有列表元素加单击事件 只要有一行没被选中 则全选变暗 如果都全部手动选中 则全选变亮*/
/*这里因为链表是动态生成的 ajax异步请求不用等待排队 所以当加单击事件时 列表元素还没有生成 所有要用另一种
* jquery给元素加事件的方式 这种方式既可以给固有元素加也可以给动态生成的元素加*/
$("#huodongbiao").on('click',"input[type='checkbox']",function () {
/* 父元素:必须是固有元素,可以直接父元素,也可以是间接父元素.
* 事件类型 子选择器 函数*/
//可以获取列表的长度 与列表中被选中的列表长度作比较 如果相等说明全都选中了 反之没有
if($("#huodongbiao input[type='checkbox']").size()==$("#huodongbiao input[type='checkbox']:checked").size()) {
$("#quanxuan").prop('checked',true);
}else{
$("#quanxuan").prop('checked',false);
}
})
3.前端隐藏标签
<input type="hidden" id="shichangid"> <%--隐藏标签 存市场活动id--%>
4.给元素扩展属性
给元素扩展属性:html页面是可扩展的标记语言,可以给指定的标签任意扩展属性,只要属性名符合标识符的命名规则即可。
两个目的:
1)使用标签保存数据:
如果是表单组件标签,优先使用value属性,只有value不方便使用时,使用自定义属性;
如果不是表单组件标签,不推荐使用value,推荐使用自定义属性。
2)定位标签:
优先考虑id属性,其次考虑name属性,只有id和name属性都不方便使用时,才考虑使用自定义属性。
5.父子选择器与和on函数加事件
使用jquery的on函数 可以给动态生成的元素加事件 也可以给固有元素加事件
父元素必须是固有元素 而且范围越小越好
$(“父元素选择器”).on(“事件名”,“子元素选择器”,function(){})
列子:
$(“#huodongbiao”).on(‘click’,“input[type=‘checkbox’]”,function () {}
标签选择器
/*获取全部的列表 父子选择器 中间是空格 则可以筛选所有的子标签 中间是>则只能筛选一级字标签 【属性过滤】
* this代表当前事件元素的dom对象 */
$(“#huodongbiao input[type=‘checkbox’]”).prop(‘checked’,this.checked)
6.controller返回给前端ajax可以使哪几种数据类型
实体类对象
list集合
map集合
文本数据
xml
7.,ajax向后台发送请求时,可以通过data提交参数,data的数据格式有三种格式:
3,ajax向后台发送请求时,可以通过data提交参数,data的数据格式有三种格式:
1)data:{
k1:v1,
k2:v2,
…
}
后端controller一个一个参数接 或者实体类接
*劣势:只能向后台提交一个参数名对应一个参数值的数据,
不能向后台提交一个参数名对应多个参数值的数据。
只能向后台提交字符串数据
优势:操作简单
2)data:k1=v1&k2=v2&…
*优势:不但能够向后台提交一个参数名对应一个参数值的数据,
还能向后台提交一个参数名对应多个参数值的数据。
劣势:操作麻烦
只能向后台提交字符串数据
后端controller定义一个参数名相同的数组接
3)data:FormData对象
优势:不但能提交字符串数据,
还能提交二进制数据
劣势:操作更复杂
var a= new FormData()
a.append(“参数名”,“参数值”)
可以追加多个
在ajax里
data:a
最后
以上就是开放眼神为你收集整理的CRM关系管理系统笔记一.CRM项目技术架构介绍二:软件开发的生命周期三:CRM核心业务介绍四:CRM项目所用到的表以及主键字段和表关系简单分析五:项目的规范六:mybatis逆向工程创建数据持久层接口及映射文件七:ssm整合配置八:用户登录功能安全退出的实现九:市场活动功能十:线索模块的功能十一:交易功能的实现十二:CRM用到的插件十三:前端通用代码的全部内容,希望文章能够帮你解决CRM关系管理系统笔记一.CRM项目技术架构介绍二:软件开发的生命周期三:CRM核心业务介绍四:CRM项目所用到的表以及主键字段和表关系简单分析五:项目的规范六:mybatis逆向工程创建数据持久层接口及映射文件七:ssm整合配置八:用户登录功能安全退出的实现九:市场活动功能十:线索模块的功能十一:交易功能的实现十二:CRM用到的插件十三:前端通用代码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复