CRM项目实现过程中的细节记录(一)

文章目录

  • CRM项目实现过程中的细节记录(一)
    • 一、数据库相关细节
      • 1. 表名
      • 2. 表字段说明
      • 3. 不使用主外键约束
      • 4. 不使用主键自动增长
        • UUID
      • 5. 日期(时间)
      • 6. 实体类
      • 7. MD5密码加密
      • 8. 动态SQL
      • 9. 字符串数字排序
      • 10. Limit
      • 11. MyBatis动态SQL(模糊查询)
      • 12. 表关系
      • 13. 多对多关系的删除与添加
      • 14. 注意使用外连接
    • 二、JSP相关细节
      • 1. HTML文件转JSP文件
    • 三、登录相关细节
      • 1. 考虑用户名与密码框中前后可能输入有空格
      • 2. JS中的函数
      • 3. 请求发送方式
      • 4. 关于网站的初始页面
      • 5. 刷新maven
      • 6. 登录失败时处理思路
      • 7. 拦截器
      • 8. IP地址
      • 9. Session
      • 10. Cookie
      • 11. 将顶层窗口设置为当前窗口
    • 四、工作区相关
      • 1. 页面中加入别的页面
      • 2. Bootstrap的模态窗口只支持发送AJAX请求
      • 3. JS操作模态窗口
      • 4. 清空模态窗口表单的时机
      • 5. 循环拼接请求参数
      • 6. 在controller层抛异常自定义异常
    • 五、数据字典实现相关细节
      • 1. 增删改后不能用请求转发(*)
      • 2. 前端页面弹框后不加感叹号
      • 3. EL表达式取值取出空串
    • 六、代码中的一些方法
      • 1. jQuary
      • 2. json
      • 3. AJAX
        • (1) 模态窗口的带值打开*
        • (2) AJAX请求排错
    • 七、前端
      • 1. 前端页面弹框后不加感叹号
      • 2. 全选框实现
      • 3. 日历控件
      • 4. JavaScript字符串中引号问题
    • 八、踩过的坑
      • 1. @ResponseBody
      • 2. 自动注入
      • 3. JSTL表达式
      • 4. 路径问题
      • 5. input标签disable与readonly
      • 6. SQL语句老写错
    • 九、市场活动模块
      • 1. 用哪个模块的Controller处理,响应什么参数
      • 2. 异常的处理方式
      • 3. 使用隐藏域
      • 4. 给动态生成的标签绑定事件(全选框高级)
      • 5. BootStrap分页框架(bs_pagination)
      • 6. VO类
      • 7. @RequestParam
      • 8. textarea文本域*
      • 9. AJAX传多个同名参数
      • 10. 数据导入/导出(excel格式)
      • 11. 评论(备注)加载时机
      • 12. 使用before追加的方式实现
      • 13. JS中使用EL表达式
      • 14. 禁用超链接
      • 15. 为for循环动态拼接中的元素绑定事件
      • 16. 浮动的下划线

下一篇:Java实现CRM项目过程中的细节记录(二)

一、数据库相关细节

1. 表名

在建表时,表名一般以t_tb_tbl_ 开头

2. 表字段说明

在该项目中,所有的表字段均为字符串,包括数字(在银行等的项目中,字段该是什么类型,就是什么类型)

  • 在创建表时,可以确定是定长(长度固定)的字符串,在表中使用char(),如(性别,UUID生成的唯一id值)
  • 不固定的字符串在表中使用varchar()

3. 不使用主外键约束

表中有外键,但是不使用外键约束,即在创建表时,外键的字段同其它字段的创建方式一致。在表的说明文档中,要说明谁是谁的外键

4. 不使用主键自动增长

当主键字段属性为 int / long 整型时,可以自动递增

  • 主键自动递增涉及到表的添加删除的效率问题(实际操作的是两张表)
  • 数据库移植相关的问题
    在实际项目开发中,更推荐使用字符串类型的主键,即不自动递增。

UUID

如何确保字符串主键的唯一性?
UUID是未来最常见的主键生成机制,该机制是由java.util包为我们提供的工具类,该形式生成的是由数字字母-组成的36位的随机串,这36位的随机串一定是全世界唯一的

  1. UUID为什么是全世界唯一的?
    UUID用了随机数+时间+当前生成UUID所在硬件的机器编码进行计算产生的
  2. 在数据库表中,应该为UUID赋予什么类型?
    由于UUID生成的字符串中-的位置是固定的,所以可以将-去掉,即在数据库中使用char(32)来存储
  3. UUID字符串的生成方式:
public static String getUUID(){return UUID.randomUUID().toString().replaceAll("-","");
}

5. 日期(时间)

在项目开发中,使用字符串来表示时间,共有两种方式

  • 纯日期:yyyy-MM-dd 在表中使用 char(10) 来存储
  • 日期+时间:yyyy-MM-dd HH:mm:ss 在表中使用 char(19) 来存储

6. 实体类

实体类中的属性名与字段名一致,且类型均为String

7. MD5密码加密

public class MD5Util {public static String getMD5(String password) {try {// 得到一个信息摘要器MessageDigest digest = MessageDigest.getInstance("md5");byte[] result = digest.digest(password.getBytes());StringBuffer buffer = new StringBuffer();// 把每一个byte 做一个与运算 0xff;for (byte b : result) {// 与运算int number = b & 0xff;// 加盐String str = Integer.toHexString(number);if (str.length() == 1) {buffer.append("0");}buffer.append(str);}// 标准的md5加密后的结果return buffer.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();return "";}}
}

8. 动态SQL

动态sql中的<foreach>标签中的collection属性指的是集合的属性,有arraylist两个值

9. 字符串数字排序

在字符串数字后+0或者*1

select * from tbl_dic_value order by typeCode,orderNo+0

10. Limit

Limit 1, 2后的第一个参数可以简单的记为:略过的记录数

11. MyBatis动态SQL(模糊查询)

  • "%"#{name}之间要有空格,相当于字符串拼接中的加号"+"
  • <if>标签中的条件要用"and"
  • 第一个<if>标签对中的and可有可无,之后的<if>标签对中的and不能省略
<select id="getActivity" resultType="int">select count(*)from tbl_activity<where><if test="name!=null and name!=''">and name like '%' #{name} '%'</if></where>
</select>

12. 表关系

  • 一对一(如人员表与证件表)、一对多、多对一(如学生表与班级表):

    • 永远在多的一方建立外键,换名话说,有外键的表一定是多的一方(死记)
    • 一对一可以理解成特殊的一对多,在哪一边建外键视具体情况而定
  • 多对多(如学生表与课程表):
    • 建一个单独的表,叫关联关系表,该表有三个字段,分别是该表的主键、多的一方表的外键、另一个多的一方表的外键。

13. 多对多关系的删除与添加

  • 一对多时,删除一方表中的数据时,关联的多方表中的数据也要删除
  • 多对多时,删除的是关联关系表中的数据,添加时也是在关联关系表中进行添加

14. 注意使用外连接

当表中存在非必填的外键时,要极其注意外键为null的情况,使用外连接来避免查不到数据

二、JSP相关细节

1. HTML文件转JSP文件

<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<head><base href="<%=basePath%>">
</head>
  • <base>标签一定要加在<head>标签中的第一行
  • 如果页面中使用了../,将所有的../全部去掉
  • 定个约定:对于前端文件,写路径前面一律不加/,对于后端文件,写路径时一律要加/
  • 前端的图片、jQuery的文件或者文件夹要放在webapp的根路径下

三、登录相关细节

1. 考虑用户名与密码框中前后可能输入有空格

去除空格:

$.trim("字符串");

2. JS中的函数

如果要在绑定事件中引入外部函数,函数不能写在$( )中,要写在$( )之外(为什么?)

3. 请求发送方式

  • get:拿、取

    • 以查询为主要目的的需求
  • post:邮寄、邮递

    • 以添加,修改,删除为目的的需求
    • 如果涉及到参数安全性相关的问题,用post请求

4. 关于网站的初始页面

网站的初始页面约定是index.html,但是登录页面在login.jsp

  • 做法:在index.html中进行重定向到login.jsp页面
<script type="text/javascript">document.location.href = "login.jsp";
</script>

5. 刷新maven

在maven中加入任何外部资源时都需要刷新一下maven

6. 登录失败时处理思路

登录失败时,直接抛出异常,通过SpringMVC来统一处理异常,在异常中返回ajax请求

7. 拦截器

如果登录成功后响应为200,但是返回的是空白页,说明拦截器暂时没有设置为true

8. IP地址

获取ip地址,如果是自己访问自己,则用的是localhost,则下面的方法返回的是 0:0:0:0:0:0:0:1不是一个有效的ip地址,本地访问要用127.0.0.1

String ip = request.getRemoteAddr();

9. Session

Session的销毁方式:

session.invalidate();

10. Cookie

  • Cookie机制中,是通过path来控制权限的。只有servlet<url-pattern>和该path相同或是它的子路径,servlet才能够访问该Cookie。如果把一个Cookie的path设为项目根目录,那么该项目下的所有servlet都能够访问它
  • 如果不设置setMaxAge(过期时间),则浏览器一关闭就过期,默认单位为秒
Cookie loginActCookie = new Cookie("loginAct", loginAct);
loginActCookie.setMaxAge(60*60*24*10);//设置过期时间
loginActCookie.setPath("/");//设置权限
  • Java中,没有对Cookie的销毁提供类似session的销毁方式,所以用新的Cookie替换旧的Cookie
Cookie loginActCookie = new Cookie("loginAct", null);//Cookie的key一定要与要销毁的Cookie键相同
cookie1.setPath("/");
cookie1.setMaxAge(0);//过期时间设置为0

11. 将顶层窗口设置为当前窗口

如果顶层窗口不是当前窗口,则将顶层窗口设置为当前窗口,防止出现登录页显示在<iframe>标签中的bug

$(function(){if(window.top != window){window.top.location = window.location;}
})

四、工作区相关

1. 页面中加入别的页面

使用<iframe></iframe>标签

<div id="workarea"style="position: absolute; top : 0px; left: 18%; width: 82%; height: 100%;"><iframestyle="border-width: 0px; width: 100%; height: 100%;" name="workareaFrame"></iframe>
</div>
$(function(){//在页面加载完成后,默认在工作区中自动打开//参数1:打开哪个页面//参数2:在哪儿打开(工作区的name属性)window.open("workbench/main/toIndex.do","workareaFrame");
})

2. Bootstrap的模态窗口只支持发送AJAX请求

3. JS操作模态窗口

取得指定模态窗口的jquery对象,由该对象调用modal方法,该modal方法有两种取值

  • show:打开模态窗口
  • hide:关闭模态窗口

4. 清空模态窗口表单的时机

添加操作执行之后,要清空表单,可以在打开的时候清,也可以在点击保存添加成功之后清,为了防止失误操作让表单关闭后填写的数据丢失,应该在处理了添加操作之后清空表单

5. 循环拼接请求参数

var attr = "";
var $create = $("#create-form :input");//选中表单下的所有input表单
for (var i = 0; i < $create.length; i++) {attr += $create[i].name + ":'"+ $.trim($create[i].value) + "',";
}
attr = attr.substr(0, attr.length - 1);//去除最后一位的逗号
var obj = eval("({"+attr+"})");//将JSON字符串转为JS对象,AJAX中的data属性要使用对象,不是字符串

6. 在controller层抛异常自定义异常

五、数据字典实现相关细节

1. 增删改后不能用请求转发(*)

增删改后应该使用重定向,返回修改后的页面,使地址栏中的地址与当前页的地址一致。

2. 前端页面弹框后不加感叹号

3. EL表达式取值取出空串

EL表达式取值取出NULL,会自动改为空字符串""

六、代码中的一些方法

1. jQuary

  1. 模拟鼠标点击$(“#code”)元素,click可以换成其它任意事件

    $("#code").trigger("click");
    
  2. 给dom对象赋值:

    $("#span-code").prop("class", spanError);
    
  3. 失去焦点:blur()

  4. 删除时,弹窗用confirm("消息")

  5. el表达式的取值是能够用在js代码中的,只不过需要套用在字符串的引号

  6. 使用JS来实现表单的提交与清空
    submit()jQuary提供的,而reset()JavaScript提供的,故他们的使用方法不同:

    $("#activitySaveForm").submit();
    $("#activitySaveForm")[0].reset();
    
  7. 往前追加同级元素(兄弟标签)用 兄弟元素.before

    $("p").before("<b>追加</b>");
    $("#remarkDiv").before(html);
    

    结果:

    <b>追加</b><p>段落</p>
    
  8. 父级元素中的最后追加子元素(子标签)用 父级元素.append

    $("p").append("<b>追加</b>");
    

    结果:

    <p>段落<b>追加</b></p>
    

2. json

  1. json字符串是键值对,当只有一个键,值是一个数组时,键可省略

    • {"key":[{"id":"001","name":"zhangsan"},{"id":"002","name":"lisi"}]}可以简写成:
    • [{"id":"001","name":"zhangsan"},{"id":"002","name":"lisi"}]

3. AJAX

(1) 模态窗口的带值打开*

$("#toSaveActivityBtn").click(function () {$.ajax({url: "workbench/activity/getUserList.do",type: "get",dataType: "json",//这一步将json字符串转为js对象success: function (data) {var html = "";$.each(data, function (i, n) {html += "<option value='" + n.id+"'>n.name</option>";});$("#create-owner").html(html);//将当前用户默认为被选中的用户$("#create-owner").val("${user.id}");//通过js打开模态窗口//这句话要写在ajax的响应成功函数中$("#createActivityModal").modal("show");//show打开,hide关闭}});
});

(2) AJAX请求排错

点击按钮发送AJAX请求,没有反应,具体排查流程:

  1. 先点击F12,再点击"创建"按钮

    1. 观察你的Network,看看请求有没有发出去
    2. 如果请求没有发出去,一定是该方法中有js代码写错语法了,排查语法,可以使用简单的alert弹框去做标记
    3. 如果请求发出去了,请看第二步
  2. 在你的ajax的回调函数中第一行,加入alert(data)

    1. 观察结果
    2. 如果弹框没反应 说明是后台代码出错了,进入到第三步
    3. 如果弹出了 object Object,说明我们是有json数据的,打印你拼接的html,看看是不是我们想要的拼接后的option
    4. 如果弹出了 [{},{},{}],说明这个json字符串并没有解析为json对象,查看你的dataType
      • (a.看看你是不是写的是dateType b.看看你是不是写的是datatype)
  3. 观察后台

    1. 从Controller开始排查
      (1)看参数是不是我们想要接收的
      (2)观察业务层有没有报错(错误信息大多数情况比较模糊,不容易排查,需要总结异常经验)
    2. 观察Service层
      如果是比较复杂的业务逻辑,需要你打断点一步一步进行调试,每走一步,都需要观察结果,是不是我们想要的
      如果是比较简单的业务逻辑,则不需要观察
    3. 观察dao层
      主要观察的是log4j日志为我们打印的sql语句
      观察sql语句本身
      观察参数
      观察返回记录数
    4. 如果dao层没有问题,service层也没有问题,controller也没问题(这3层都没有抛异常)
      肯定是你的业务层写了一个return null;

七、前端

1. 前端页面弹框后不加感叹号

alert("弹框的内容,内容最后不要随便加感叹号,就像这样!!!")

2. 全选框实现

  • 将多选框的checked属性赋值给单选框
  • 判断单选框的选中的个数(数组长度)与所有单选框的个数是否一致,若一致就让多选框选中
$("#qx").click(function () {//将多选框的checked属性赋值给单选框$("input[name=xz]").prop("checked", this.checked);
})$("input[name=xz]").click(function () {$("#qx").prop("checked", $("input[name=xz]:checked").length === $("input[name=xz]").length);
});

3. 日历控件

引入BootStrap的日历控件,给所有class中带有time的表单加入日历控件

<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><script type="text/javascript">$(".time").datetimepicker({language:  "zh-CN",format: "yyyy-mm-dd",//显示格式minView: "month",//设置只显示到月份// initialDate: new Date(),//初始化当前日期autoclose: true,//选中自动关闭todayBtn: true, //显示今日按钮clearBtn : true,//显示游击队按钮pickerPosition: "bottom-left"//对齐样式});
</script>

4. JavaScript字符串中引号问题

原则:在双引号中如果要再使用引号的话,要使用单引号,在单引号中如果要再使用引号的话,要使用双引号,为了与最外层的双引号做区分,双引号要加上转义"\"

  • 最外层为双引号:" ' \" \" ' "
  • 最外层为单引号:' " \' \' " '

八、踩过的坑

1. @ResponseBody

每次在Controller中return值的时候,都要想一下注解是否加全(有一次忘记加@ResponseBody找了一个多小时bug)

2. 自动注入

Service层使用事务时,Controller层给Service属性自动赋值,属性只能是Service的接口类型,不能是Service的实现类类型(我和另一个人合伙找了快三个小时bug……)

3. JSTL表达式

items属性中的参数一定要从作用域对象中取出来(多次犯错这个错)

<c:forEach items="${dtList}" var="dt" varStatus="i">
</c:forEach>

4. 路径问题

总是在不该加“/”的地方加上"/"(要多注意)

5. input标签disable与readonly

  • disable不会往后台发送表单数据
  • readonly会往后台发送表单数据

6. SQL语句老写错

  • 更新、删除、插入语句
  • from 写成form

九、市场活动模块

1. 用哪个模块的Controller处理,响应什么参数

  • 请求是在市场活动模块发起的,所以由市场活动模块的控制器ActivityController处理请求
  • 但是进入到控制器后,取得用户信息列表,是属于用户的业务范畴,所以业务层要使用的是UserService来处理业务
  • 业务层为控制器返回什么,完全在于控制器想要什么
  • 控制器想要什么,完全在于前端发出的请求,想要响应什么

2. 异常的处理方式

异常处理方式:在控制层捕获业务层所有的异常,然后抛出自定义异常

@RequestMapping("/saveActivity.do")
@ResponseBody
public Map<String,Object> saveActivity(Activity a)throws AjaxRequestException {try {activityService.saveActivity(a);} catch (Exception e) {e.printStackTrace();throw new AjaxRequestException();}return HandleFlag.successTrue();
}

3. 使用隐藏域

<input>标签type属性为"hidden"时,为隐藏域,可以保存一些值,而且不会被浏览器界面看到

<input type="hidden" id="hidden-name"/>
<input type="hidden" id="hidden-owner"/>

应用:

  • 当查询框中加入值时,不点击查询按钮,而是点击下一页,会把查询框中的值传到后台,出现实现查询结果的bug,
  • 解决:当点击查询按钮时,将查询框中的值备份一份到隐藏域中,在往后台查找数据时,将隐藏域中的备份的值恢复到查询框中。

4. 给动态生成的标签绑定事件(全选框高级)

使用的函数:
$(需要绑定的元素的有效的父级元素).on(绑定事件的方式,需要绑定的元素,回调函数)

  • 有效的父级元素是指:不是动态生成的标签元素,如果父级不行,则继续向上扩,直到是有效的父级为止。
  • 原理:on这个方法会为有效的父级元素这个区域添加一个监视器,只要有新的元素进来都会添加上一个事件,如click
    //这里的有效父元素为#activityBody
    $("#activityBody").on("click",$("input[name=xz]"),function () {$("#qx").prop("checked",$("input[name=xz]").length==$("input[name=xz]:checked").length);
    });
    //另一种绑定方式,与上面的区别是这里用的是CSS选择器
    $("#contentRemarkDiv").on("mouseout",".myHref",function(){$(this).children("span").css("color","#E6E6E6");});
    

5. BootStrap分页框架(bs_pagination)

一个完整的ajax查询显示流程:

//pageNo表示当前页,pageSize表示一页显示几条数据
function pageList(pageNo, pageSize) {//将全选的复选框的√灭掉,小细节$("#qx").prop("checked", false);//将隐藏域中的信息取出,重新赋值给搜索框,前面讲的9-3$("#search-name").val($.trim($("#hidden-name").val()));$("#search-owner").val($.trim($("#hidden-owner").val()));$.ajax({//这里来发送请求success: function (data) {//这里来展现后台返回的数据//计算总页数var totalPages = data.total % pageSize == 0 ? data.total / pageSize : parseInt(data.total / pageSize) + 1;$("#activityPage").bs_pagination({currentPage: pageNo, // 页码rowsPerPage: pageSize, // 每页显示的记录条数maxRowsPerPage: 20, // 每页最多显示的记录条数totalPages: totalPages, // 总页数totalRows: data.total, // 总记录条数visiblePageLinks: 3, // 显示几个卡片(显示几个1,2,3,4...这种的页码)showGoToPage: true,showRowsPerPage: true,showRowsInfo: true,showRowsDefaultInfo: true,//该函数的触发时机:在我们点击分页组件的时候(上一页,下一页,首页,尾页,12345...页)onChangePage: function (event, data) {/*data.currentPage:点击分页组件后的当前页码data.rowsPerPage:点击分页组件后每页展现的记录数以上这两个值,是分页插件为我们提供的,我们千万不要去改动*/pageList(data.currentPage, data.rowsPerPage);}});}})
}

调用函数时,有两个框架已经提供好的参数,当实参传入即可,根据具体情况进行使用:

  • $("#activityPage").bs_pagination('getOption', 'currentPage'):维持当前页
  • $("#activityPage").bs_pagination('getOption', 'rowsPerPage'):维持每页展现的记录数
    使用:
pageList($("#activityPage").bs_pagination('getOption', 'currentPage'), $("#activityPage").bs_pagination('getOption', 'rowsPerPage'));

6. VO类

下一层往上一层做值的返回,如果返回的有多个不同类型的值,那么使用的一般都是map类型来处理,当返回的信息复用率比较高,为了方便可读性以及可维护性,我们也可以使用vo类技术来代替传统的map技术来处理

VO:Value Object 用来表现值的对象,用来展现值的类,用法与传统的实体类是一样的,将需要展现的值的信息,一项一项的列在VO类的属性当中,这些属性都是私有的,所有的存取值操作一律使用settergetter来实现;使用泛型式的方式,让每一个模块都能够使用(集合中存不同的实体类)

public class PaginationVo<T> {private List<T> dataList;private int total;//省略getter和setter
}

7. @RequestParam

  1. 使用Map来接收前端发过来的参数,将前端传过来的所有参数以键值对的形式存储到map中
  2. 可以使用value属性来给传递过来的参数起别名,功能和@Param相同,只不过@Param用在dao层,而@RequestParam用在controller
public PaginationVo<Activity> pageList(@RequestParam Map<String,Object> map){}

8. textarea文本域*

textarea文本域是表单元素,但是他操作值的方式与其他元素有些差别,其他的表单元素都有其value值,但是文本域没有value值,而是以textarea标签对中的信息去操作表单元素的值。
虽然textarea操作的是标签对中的内容,但是他也是属于表单元素范畴,所以我们必须以val()方法的方式去操作文本域的值,而不是html()方法

9. AJAX传多个同名参数

data属性规定要发送到服务器的数据, 类型可以是:string,数组,多数是 json,当有多个徤相同的值要往后台发送时,就不能使用json了,而要使用stringstring的格式"id=A001&id=A002&id=A003",后台使用string数组接收,变量名与前台发回的名称一样(id

public PaginationVo<Activity> pageList2(String[] id){}//id这个变量名要与发送回来的参数名一样

10. 数据导入/导出(excel格式)

数据库数据的导入与导出

11. 评论(备注)加载时机

在页面加载完毕后,发出ajax请求取得备注信息列表,采用这种方式的原因:

  • 评论区数据量大,加载时间长,防止网页响应变慢
  • 页面上处理备注的添加,修改,删除操作,每一次操作完毕后,都需要"局部刷新"备注信息列表

12. 使用before追加的方式实现

增、删、改之后要注意一下要定位到更改的那个元素位置,再单独对它进行刷新。不能全部刷

13. JS中使用EL表达式

js中用el表达式一定要加引号,已经在引号中可以直接用(在字符串中)

  • 要加引号:$.ajax({data : {"activityId" : "${a.id}"})
  • 不需要加引号:var html = "</font> <b>${a.name}</b>"

14. 禁用超链接

href="javascript:void(0);":禁用超链接,超链接必须以触发(绑定)事件的形式执行操作
目的:将鼠标移到超链接上,鼠标会变成变手形,只有超链接能办到。

15. 为for循环动态拼接中的元素绑定事件

如果元素是通过在js或者java脚本动态拼接的for循环中的元素,那么我们一般的做法都是以直接触发事件(例如标签中加入onclick="f('id')")的方式来进行操作,而不是绑定事件。
直接触发事件传递的参数(如前面的id)必须要包含在引号当中

16. 浮动的下划线

前端设置了浮动的下划线,当后台没有取到数据时,下划线会跑到上面

  • 解决办法:加空格将下划线压下来,即使没有数据,下划线也不会乱跑

Java实现CRM项目过程中的细节记录(一)相关推荐

  1. [项目过程中所遇到的各种问题记录]编辑器篇——使用FCKeditor生成静态分页HTML...

    继续编辑篇的内容,本文是编辑器篇的最后一篇,前面2篇分别是FCKeditor相关知识及各种常见使用问题和FCKeditor自定义上传路径配置,今天这篇文章主要是介绍如何使用fckeditor来生成静态 ...

  2. [项目过程中所遇到的各种问题记录]部署篇——项目部署过程中那些纠结的问题-SQLServer...

    前一篇文章说了些有关IIS的,这篇则是说SQLServer的,相比IIS来说,SQLServer的配置过程中问题就少了许多,而且都比较有针对性,下面开始记录: 注:由于实际项目的开发都是基于SQL20 ...

  3. [项目过程中所遇到的各种问题记录]图表篇——asp.net上不错的图表选择—FunsionCharts...

    [项目过程中所遇到的各种问题记录]图表篇--asp.net上不错的图表选择-FunsionCharts 在上一篇文章中我介绍了winforms下的图表控件--MSChart,虽然MSChart同样为我 ...

  4. [项目过程中所遇到的各种问题记录]编辑器篇——FCKeditor自定义上传路径配置...

    在上一篇文章中,我介绍了FCKeditor的一些相关知识以及我在使用过程中碰到的一些问题及解决方案,今天这篇则是主要记录如何通过FCKeditor来分类管理上传的文件. 以下是本文所要介绍的内容: 1 ...

  5. [项目过程中所遇到的各种问题记录]工具篇——.NET开发时常用的工具类库

    在日常开发的过程当中我们总是会根据项目的开发需求将一些公用的类或者方法进行抽象封装,这些类或方法的抽象封装可能是基于某个项目或者多个项目,最常见的应该就是SQLHelper了,这些类库在实际使用的过程 ...

  6. 谈谈在项目过程中的发生争论与争吵

        有一句古话说的好, " 有人的地方就有江湖".       与瀑布模式相比, 敏捷开发  更注重人与人的交流. 所以在开发过程中更有 可能会发生 各种争论.争吵.     ...

  7. [项目过程中所遇到的各种问题记录]编辑器篇——FCKeditor相关知识及各种常见使用问题...

    马上2010年就要结束了,所以这几天准备花点时间把这一年中在开发过程中遇到的问题及解决方案记录下来,以备日后使用,目前先规划了:编辑器篇(仅针对asp.net开发中的fckeditor).图表篇(wi ...

  8. java在程序运行过程中_Java内存管理-程序运行过程(一)

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 勿在浮沙筑高台,出来混迟早要还的. 相信在做Java开发的伙伴一定知道 JVM(Java Virtual Machine( ...

  9. 关于本人树莓派捣鼓过程中的一些记录

    关于本人树莓派捣鼓过程中的一些记录 安装debian改版系统,此处不做多描述.刷金TF卡即可. 更换源 sudo cp /etc/apt/sources.list /etc/apt/sources.l ...

最新文章

  1. 网络端口的转发和重定向
  2. Android应用程序模块:应用、任务、进程和线程
  3. $python数据分析基础——初识numpy库
  4. web安全测试---WebScarab工具介绍(中间攻击,可以修改请求参数)
  5. python爬虫架构师之路_一位资深 架构师大牛给予Java技术提升的学习路线建议
  6. 报告 | 73%的“落伍”开发者说:明年要学AI技术
  7. 将输入的字符串进行大写格式化
  8. 中职计算机多媒体教材,中职汽车维修课中计算机多媒体教学的实施
  9. 计算机视觉可分计算成像学()五大类,中国大学 MOOC_化工过程与控制仿真实习_期末考试选修课答案...
  10. Qt怎么实现将bmp图片转换成Ascii_你保存的word和pdf文档图片为什么变模糊了?
  11. Label mx条码软件导入Excel处理异常解决方法
  12. 【FPGA学习笔记】初次使用FPGA硬件编程编程语言Verilog编写HDL程序03
  13. sap 双计量单位_ERP软件中双计量单位如何使用
  14. OKR实施细则(转)
  15. 大数据安全体系介绍之技术体系篇
  16. redis常用命令 (查询出所有的商品,并返回json给客户端)redis之路(八)
  17. java 由普通用户升级为会员_java20(判断是否为会员)
  18. PMP项目管理计算中字母含义 PV、EV、AC、SV、CV、SPI、CPI
  19. FastDFS学习笔记 -- day04 与Nginx整合
  20. 社会工程学之黑客七宗罪——傲慢(Hooking)

热门文章

  1. 【算法S5-贪心方法】
  2. 依赖注入是什么意思?获取依赖的方式是什么?
  3. Android03_事件处理一
  4. 百度前端技术学院--零基础--第二天 给自己做一个在线简历吧
  5. 基于SDN/NFV的卫星互联网服务功能资源分配研究
  6. 中国监管的出拳,矿工们何去何从?
  7. 交换机端口的Vlan、 pvid、tag与untag
  8. mysql时区错乱_记一次线上mysql时区错乱
  9. STM32 无线烧录器
  10. 关于大学生洗澡方式不同调研报告——顶点计划四班五组尚梓杰