这个版本是一个全新的模块----【线索模块】,也称为**【潜在客户】**,这个模块里面有很多内容都是和市场活动模态一样的,但是我还是自己写了,可能在这里记录的时候我就只说自己完成了哪些内容,至于具体的代码什么的就不放了。
这个全新的模态还是有很多新东西可以玩的。接下来就来看吧~
1.数据字典的使用(cache缓存机制)
数据字典:指的是在应用程序中,做表单元素选择内容用的相关的数据。比如:下拉框,单选框,复选框。这里里面的内容,使用数据字典进行完成比较好,这样就不必每次加载的时候和数据库连接取数据,直接从缓存里面取。
数据字典普遍被应用在下拉框中。
缓存(cache):是指内存中的数据。这里要使用的是一种服务器缓存的机制。就相当于要将数据保存到服务器的内存中。
如果服务器处于开启状态,我们就一直能够从该缓存中取得数据。为了实现这个目的,我们是要把数据扔到application(全局作用域,也叫 上下文作用域)里面的。
在服务器启动阶段,将数据保存到服务器缓存中,服务器启动阶段,数据始终存在。
将数据保存到服务器缓存中的手段:application setattribute();
从服务器缓存中取出数据:application.getAttribute();
那么,上面的数据字典通常是什么怎么实现的呢?其实知道的话就不难。具体实现是:
使用监听器,监听上下文作用域对象的创建。他创建的时候把数据字典扔到application里面。
如何使用监听器?
你要监听哪个对象,你就实现对应的对象监听器接口,然后使用里面的方法。写完之后还要再web.xml文件里面配一下。
具体:在监听器类里面调用service来完成,给我们返回一个Map,里面有7个List集合,装着不同的codeType。这里面使用的service不能使用自动注入的原理来拿到,否则会出现java.lang.IllegalStateException异常,必须在初始化方法里面使用getBean的方式拿到,还得给service起名(这里是需要注意的地方),代码如下:
//这个类的上边不知道要不要加Component注解----试了之后发现加了也没用,还是得用下面的方式
public class SysInitListener implements ServletContextListener {
//@Autowired
//private DicService dicService;---这里不能使用这种方式获得service
@Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("=====监听器执行,数据字典初始化开始====");
//拿到全局作用域对象
ServletContext application = event.getServletContext();
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
DicService dicService = (DicService) wac.getBean("dicService");
//调用service,把查到的那些东西扔到application里面
Map<String, List<DicValue>> map = dicService.getAllDicValue();
//遍历map
Set<String> keySet = map.keySet();
for (String key : keySet){
application.setAttribute(key,map.get(key));
}
System.out.println("=====监听器执行,数据字典初始化结束====");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
在service里面是这样实现的:
@Service("dicService")
public class DicServiceImpl implements DicService {
@Autowired
private DicValueDao dicValueDao;
@Autowired
private DicTypeDao dicTypeDao;
@Override
public Map<String, List<DicValue>> getAllDicValue() {
Map<String, List<DicValue>> map = new HashMap<>();
//1.获取所有的DicType,就是有哪些类型
List<DicType> dicTypeList = dicTypeDao.getDicCode();
//2.获取上面每种类型对应的Value值,遍历List集合
for (DicType dicType : dicTypeList){
String code = dicType.getCode(); //对应的code,根据这个code去查对应的Value
List<DicValue> dicValueList = dicValueDao.getListByCode(code);
map.put(code,dicValueList);
}
return map;
}
}
在两个dao里面:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.crm.settings.dao.DicTypeDao">
<select id="getDicCode" resultType="DicType">
select * from tbl_dic_type
</select>
</mapper>
<select id="getListByCode" resultType="DicValue">
select * from tbl_dic_value where typeCode=#{code}
</select>
在web.xml文件里面,把他配在spring的监听器下面就行了。
<!--数据字典的监听器-->
<listener>
<listener-class>com.bjpowernode.crm.web.listener.SysInitListener</listener-class>
</listener>
通过以上,就可以在服务器启动的时候,把不同类型的数据加入到服务器缓存里面了,我们在前端配合JSTL进行使用,非常的方便。jsp页面前面要加入相关的约束:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
要使用的时候,因为他们是集合,来foreach:
<c:forEach items=”${appellation}” var=”a”>
<option value=”${a.value}”>${a.text}</option>
</c:forEach>
2.线索相关的操作–创建、pageList()、删除、修改等
1)然后接着就是和市场活动模块一样,完成线索的创建。思路和前面一样,就是这次文本框的内容比之前多了很多,还要在里面要使用到上面的数据字典给那些下拉框赋值。所有者还是照常过后台取。
2)pageList()方法,这个也要完成,有一些要处理的小细节包括:引入时间插件,分页插件,全选框操作,点击查询的时候出现的问题—>使用隐藏域解决。
3)删除线索操作。可以同时删除多条,先删备注,再删关系,再删线索。
4)修改线索。一次只能修改一条,直接复制创建的。
3.跳转至线索的详细信息页
这个也是和之前一样的,先过后台,然后在后台把取得的Clue扔到request里面,接一个请求转发跳转至新的jsp页面。这里controller里面的返回值使用的是ModelAndView。
下面的内容也是和之前重复的,课程里面没讲,但是自己完成了:
1)备注信息自动刷新。这个是页面加载完成后自动执行方法。
2)备注的删除、添加、修改操作。这里备注的修改因为他前端没有修改的模态窗口,所以我就没做修改的这个。
4.备注信息页市场活动自动刷新
这个和上面的备注信息的自动刷新是一样的,不过这个需求涉及到3个表的连接,sql是第一次写。因为市场活动和线索是多对多的关系,多对多的时候需要建立其第三张关联关系表。
前端:
//展现该线索关联的市场活动
function showActivityList(){
$.ajax({
url:"workbench/clue/getActivityListByCId.do",
data:{"clueId":"${clue.id}"},
type:"GET",
dataType:"json", //预期服务器返回的数据类型
success:function (data){
// aList: [{市场活动1},{2},{3}]---->返回的id是关联关系表的id
var html = "";
$.each(data,function (i,n){
html += '<tr id="'+n.id+'">';
html += '<td>'+n.name+'</td>';
html += '<td>'+n.startDate+'</td>';
html += '<td>'+n.endDate+'</td>';
html += '<td>'+n.owner+'</td>';
html += '<td><a href="javascript:void(0);" οnclick="deleteRelation(\''+n.id+'\')" style="text-decoration: none;"><span class="glyphicon glyphicon-remove"></span>解除关联</a></td>';
html += '</tr>';
})
$("#activityBody").html(html);
}
})
}
后端dao的sql语句:因为这里要查出的是市场活动的List集合,所以使用的是activityDao,因为有所有者,要关联user表,另外他们的关系是使用第三张关联关系表进行连接的,也要使用到他。还有一个巧妙的地方就是保存的id直接保存成关联关系表的id,到时候接触关联的时候直接根据id进行解除就行,方便了许多。
<select id="getActivityListByCId" resultType="Activity">
select
car.id as id,
u.name as owner,
a.name,
a.startDate,
a.endDate
from tbl_activity a
join tbl_user u
on a.owner=u.id
join tbl_clue_activity_relation car
on a.id=car.activityId
where car.clueId=#{clueId}
</select>
5.解除市场活动和线索的关联关系
这个也是直接使用超链接进行触发,比较简单。
6.市场活动和线索的关联
这个需求时通过点击“关联市场活动”按钮,然后会打开一个相关的查询模态窗口,根据市场活动的名称模糊查询出还未关联的市场活动,最后点击关联按钮,实现市场活动和线索之间的关联,在关联关系表增加记录。
1)首先是文本框绑定敲回车事件,然后查询,这个查询要注意的地方就是除了名字模糊查询之外,还要把已经关联的市场活动去除。
还有一个非常重要的内容就是:在模态窗口中,敲回车会默认触发一个事件:强制刷新并清空当前页面,这样会导致我们页面的数据全部被清空,我们应该将此功能禁用。方式,在展现完市场活动列表后,return false; 即可。
前端:
//为关联市场活动模态窗口的搜索框绑定敲键盘事件
$("#searchActivity").keydown(function (event){
if (event.keyCode==13){ //回车
//展现查询出来的市场活动列表
$.ajax({
url:"workbench/clue/getActivityListByNameAndNotByCId.do",
data:{
"name":$.trim($("#searchActivity").val()),
"cid":"${clue.id}"
},
type:"GET",
dataType:"json", //预期服务器返回的数据类型
success:function (data){
//data: [{市场活动1},{2},{3}]
var html = "";
$.each(data,function (i,n){
html += '<tr>';
html += '<td><input type="checkbox" name="xuanze" value="'+n.id+'"/></td>';
html += '<td>'+n.name+'</td>';
html += '<td>'+n.startDate+'</td>';
html += '<td>'+n.endDate+'</td>';
html += '<td>'+n.owner+'</td>';
html += '</tr>';
})
//写入上面拼的内容
$("#search-activityBody").html(html);
}
})
//将模态窗口默认的回车功能禁用
return false;
}
})
查询的sql语句:(包括了多表联查和子查询)
<select id="getActivityListByNameAndNotByCId" resultType="Activity">
select
a.id,
u.name as owner,
a.name,
a.startDate,
a.endDate
from tbl_activity a
join tbl_user u
on a.owner=u.id
where a.name like '%' #{name} '%' and a.id not in(
select activityId from tbl_clue_activity_relation where clueId=#{cid}
)
</select>
2)就是根据查询出来的结果,勾选需要关联的市场活动,点击关联即可。这里从前端向后端发送的数据由:线索的id,一个或多个市场活动的id,所以这里也不能使用json进行传数据,得用拼字符串的方式。最后,通过实验,我还发现了一个非常有趣的内容,就是springmvc框架在接收参数的时候,如果你的id值有多个,在方法的参数里面可以直接使用数组进行接收,这是比较有趣的。
前端:
//为关联按钮绑定事件
$("#addRelationforAC").click(function (){
//要传线索id和多个activityId
var param = "cid="+"${clue.id}"+"&";
//拿到打钩的复选框
var $xuanzhong = $("input[name=xuanze]:checked");
if ($xuanzhong.length==0){
alert("请选择需要关联的市场活动~");
}else {
for (var i=0; i<$xuanzhong.length; i++){
param += "aid="+$($xuanzhong[i]).val();
if (i<$xuanzhong.length-1){
param += "&";
}
}
$.ajax({
url:"workbench/clue/saveACRelation.do",
data:param,
type:"POST",
dataType:"json", //预期服务器返回的数据类型
success:function (data){
if (data){
//清空搜索框
$("#searchActivity").val("");
//清空搜索框里面的search-activityBody里面的内容
$("#search-activityBody").remove();
//全选框取消选择
$("#quanxuan").prop("checked",false);
//关闭模态窗口
$("#bundModal").modal("hide");
//刷新市场活动列表
showActivityList();
}else {
alert("关联市场活动失败~");
}
}
})
}
})
controller里面:
@ResponseBody
@RequestMapping("/workbench/clue/saveACRelation.do")
public Boolean saveACRelation(String cid,String[] aid){ //可以直接使用数据进行接收aid,有点意思
System.out.println("=====线索控制器,增加线索和市场活动的关联关系=====");
Boolean flag = clueService.saveACRelation(cid,aid);
return flag;
}
service里面:
@Override
public Boolean saveACRelation(String cid, String[] aid) {
Boolean flag = true;
ClueActivityRelation car = new ClueActivityRelation();
for (String id : aid){
car.setId(UUIDUtil.getUUID());
car.setClueId(cid);
car.setActivityId(id);
int count = clueActivityRelationDao.saveACRelation(car);
if (count != 1) {
flag = false;
}
}
return flag;
}
sql语句比较简单,不放了。
以上就是这个版本的全部内容啦~重复的内容比较多,练练手,练熟一点。比较新的内容即使第一个数据字典的使用,还有最后第4个的三表联查,第6个的多表联查结合子查询
然后下个版本还是线索模块的,实现线索的转换。=============