最近这一个月一直在弄手机APP了,用的技术或者说框架是APICloud(简称ac),用着还挺好的,因为是初学,用的过程中总是磕磕绊绊的,也遇到过一些乱七八糟的问题。最近总算将总的功能写的差不多了,抽空把遇到的一些大问题总结一下。
先来说说连接自己的数据库这块儿吧,以登陆为例子。
ac其实是自带了云数据库而且有一套自己的操作功能,它通过ajax方法让客户端和服务器通讯。自然手机APP就是客户端,而操作数据库的代码所在的机器就是服务器了。因为我本身的这个项目已经有了数据库自然 就不能使用ac的数据库,也就是得自己写服务器端,ajax中url的值自然就是我的服务器所在的地址了。
这是写“连接自己的数据库”应该树立的思想。
ac的ajax方法介绍时,用的都是它自带的云数据库和服务器,因此对于“要连接自己的数据库”,有一定的迷惑性。得先理解上面说的那个思维才能准确的定位ajax中的url才能使用自己的数据库。这个问题是最初困惑我好久的问题,想明白了上面说的思维,这个问题就迎刃而解了。
好了,废话就说到这里,下面开始上代码。
一、登陆页面的html代码:
用户名:
密 码:
二、validate进行提交:
//先将服务器所在的ip地址存储起来,其他页面直接获取就好,以后要修改起来也容易 $api.setStorage("s_ip","http://127.0.0.1:8090"); $api.setStorage("url",$api.getStorage("s_ip")+"/ac/control");//访问地址 //点击登陆按钮时触发该方法,该方法用来校验输入的用户名和密码是否为空 function validate(){ //html5自带有校验是否为空的功能,但当输入的是空字符串时就不再校验,所以需要再度校验 var name = replaceAll($("#userName").val()," ","");//用户名 var pwd = replaceAll($("#password").val()," ","");//密码 //用户名和密码都不允许为空 if((!isempty(name)) && (!isempty(pwd))){//两者都不为空 //是否有特殊字符 if(checkStr(name) || checkStr(pwd)){//两个当中有一个有特殊字符 showErrorInfoBySys("用户名、密码皆不允许有特殊字符","2"); return false; } }else{ showErrorInfoBySys("用户名、密码皆不允许为空","2") return false; } //显示进度条 api.showProgress({ title: '玩命登陆中', //text: '休息一下...',//默认为:请稍后。。。 modal: false }); //进行登录 api.ajax({ url: $api.getStorage("url"), method: 'post', dataType:"json", data: { values: { "account":name, "pwd":pwd, "time":new Date().getTime() } } }, function(ret, err) { //alert(ret+"\n"+ret.length+"\n"+ret[0]+"\n"+ret[1].s_username); //alert(api.alert({ msg: JSON.stringify(ret) })); if (ret) {//说明有返回值 //1-登陆序号或密码为空 2-密码错误 3-登陆异常 4-登陆成功 var error = parseInt(ret[0]); //alert(error); if(error==4){//说明登录成功 //alert("登录成功"); //将当前登录人信息保存到session中 $api.setStorage("u_id",ret[1].s_user_id); $api.setStorage("u_name",ret[1].s_username); api.openWin({ name: 'indexPage', url: 'index.html' }); }else{ var errorInfo=""; switch(error){ case 1:{ errorInfo="账号或密码为空,请重新输入"; $("#userName").val("").focus();//置空 $("#password").val(""); break; } case 2:{ errorInfo="密码错误,请重新输入"; $("#password").val("").focus(); break; } default:{errorInfo="登陆异常,请稍后重试!"; break;} } //显示错误信息 showErrorInfoBySys(errorInfo,1); } } else { //api.alert({ msg: JSON.stringify(err) }); showErrorInfoBySys(err.msg,1); } }); } /*** * 替换字符串 * @param {Object} str 必选项 原始字符串 * @param {Object} str1 必选项 被替换的字符串 * @param {Object} str2 必选项 用来替换的字符串 * @return {TypeName} */ function replaceAll(str,str1,str2){ var reg=new RegExp("("+str1+")","gm"); str=str.replace(reg,str2); return str; } /**该方法用来判断字符串中是否存在特殊字符,包括特殊标点符号和关键字 /*true:说明有特殊字符 /*false:说明没有特殊字符 */ function checkStr(str){ //var myReg = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\]./<>?~!@#¥……&*()——|{}【】‘;:”“'。,、?%+]"); var myReg = new RegExp("(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"+ "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)"); if(myReg.test(str)) return true; return false; } /** *验证js变量的值是否为空, * true-不存在 * false-存在 * */ function isempty(v){ switch (typeof v){ case 'undefined' : return true; case 'string' : v = jQuery.trim(v); if (v.length == 0)return true; if(v=="null"){return true;} break; case 'boolean' : if(!v) return true; break; case 'number' : if(0 === v) return true; break; case 'object' : if(null === v) return true; if(undefined !== v.length && v.length==0) return true; for(var k in v){return false;} return true; break; } } /** *该方法用来显示错误信息-调用系统定时方法 * @param flag:1-隐藏进度提示框 非1:不隐藏 * @param msg:错误信息 * **/ function showErrorInfoBySys(msg,flag){ if((flag+"")=="1"){ api.hideProgress();//隐藏进度提示框 } //显示错误信息 api.toast({ msg: msg, duration: time, location: 'bottom' }); }
PS:其实ac自带的api.js有很多与jQuery相同的功能,奈何时间有限来不及学ac的功能了,只能api.js和jQuery混着用了,因此写起来有点乱,见谅见谅。
三、后台代码处理,用的简单的servlet+JDBC:
servlet取值:
//1、获取用户名和密码
String account = request.getParameter("account");//账户名
String pwd = request.getParameter("pwd");//密码
Object result = services.isLogined(account,pwd);
String result2="0";
//使用ajax的方式
List list = new ArrayList();
if(result instanceof SUser){
SUser user = (SUser)result;
request.getSession().setAttribute("userInfo",user);
result2="4";
list.add(result2);
list.add(user);
addLog(user,"登陆系统!");
writeLoggerForInfo(user,"输入密码后登陆系统","登陆账号:"+account+"\t密码:"+pwd+"\t结果:登陆成功");
}else{//登陆失败,跳转到首页
result2 = result.toString();
list.add(result2);
writeLoggerForInfo(null,"输入密码后登陆系统","登陆账号:"+account+"\t密码:"+pwd+"\t结果:登陆失败,原因:"+result2+"(1:账号或密码为空 2:密码错误 3:登陆异常,数据库查询错误 4:登陆成功)");
}
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 0);
response.getWriter().write(JSONArray.fromObject(list).toString());
response.getWriter().flush();
response.getWriter().close();
services操作数据库并判断:
/**
* 该方法根据给定的账户名和密码来判断是否登录成功
* @param account:账户名
* @param pwd:密码(明码)
* @return Object:数字标记:1-登陆序号或密码为空 2-密码错误 3-登陆异常 4-登陆成功 若是登陆成功直接返回当前登录人信息
* **/
public Object isLogined(String account,String pwd){
Integer result = 3;//登陆异常
SUser user = null;
//1、校验不能为空
if(account==null || account.trim().length()<=0) return "1";
if(pwd==null || pwd.trim().length()<=0) return "1";
//2、与数据库中的数据进行比对
StringBuffer sql=new StringBuffer();
sql.append("select top 1 s_user_id,s_work_id,s_department_id,s_department_name,s_username,")
.append("s_sex,s_account,s_password,s_job_id,s_job_name from s_user ")
.append("where s_account=? and s_password=?");
//System.out.println("登陆时执行的SQL:"+sql);
try{
rs = execQuery(sql.toString(),new String[]{account,com.wjl.util.Md5.getPWD(pwd)});
while(rs.next()){
user = new SUser(
rs.getInt(1),//主键序号
rs.getString(2),//工作编号
rs.getInt(3),//部门序号
rs.getString(4),//部门名称
rs.getString(5),//用户名
rs.getString(6),//性别
rs.getString(7),//账户
rs.getString(8),//密码
rs.getInt(9),//岗位序号
rs.getString(10)//岗位名称
);
}
if(user==null){return 2;}//说明密码错误
else{//说明登陆成功
writeLoggerForSQL("登陆系统,账户名:"+account+",密码:"+pwd,sql.toString(),user.toString());
return user;
}
}catch(Exception e){
writeLoggerForException("登陆系统,账户名:"+account+",密码:"+pwd,sql.toString(),e);
e.printStackTrace();
result = 3;
}
return result;
}
/**
* 该方法用来执行查询sql-根据条件进行查询
* @param sql:要执行查询的sql
* @param String[]:SQL的查询条件中各个?号对应的值
* @return ResultSet:结果集合
* */
public static ResultSet execQuery(String sql,String[] values){
try{
conn = com.wjl.admin.DBConnection.getConn();
if(conn!=null){
pst = conn.prepareStatement(sql);
//防止SQL注入采用占位的方法进行处理
if(values!=null && values.length>0){//说明有设置占位符
for(int i=0;i
最后再说几个有用的知识点:
1、input框中的placeholder属性:这个属性是用来给input框添加默认值的,如placeholder=‘123456’,打开页面input框显示内容为123456,当鼠标聚焦input时123456又没了,当输入了数据时文本框只显示输入的数据且提交时也只是提交输入的数据,当将文本框中的数据删除文本框中没有数据时它又默认显示123456了。这个属性是不是很神奇,有了它以后再也不用添加默认值、聚焦提交数据时也不用再清空这个值了。但是它又一个缺点:有些浏览器不兼容,譬如说IE8及以下(IE9没试过),别的如IE11、火狐、谷歌、360都兼容。
2、去除h5自带的非空检验:记得同事刚把以上的静态代码给我我迫不及待的测试时,什么也不输点击登陆时弹出了'此字段不能为空'的提示,可是我们两个都没有对这个静态页添加任何的校验代码,同事说可能是H5自带的校验功能。可是这个校验并不是我想要的校验风格,因为它弹出错误提示的地方在文本框的右下角,而我要求的是在手机的低端,因此需要去掉这个自带的提示。经过一通乱改,发现“去掉form标签并将提交按钮的type由submit改成button”之后这个自动校验就没有了。(PS:因为时间关系,依稀记得是这个样子,form元素的去掉是关键。)
3、ac中的存值与取值:存值用$api.setStorage(key,value),取值用$api.getStorage(key);如最开始的存服务器地址:$api.setStorage("s_ip","http://127.0.0.1:8090");,后面的取URL地址:$api.getStorage("s_ip");
4、ac中的进度条:显示进度条用api.showProgress,隐藏用api.hideProgress()。具体用法可以参考APICloud的官网API。
5、ac中的提示语句:api.toast()。这个方法很好用,有了它就不用写错误提示框,也不用写定时关闭提示框了。
APICloud还有很多使用且好用的方法,这篇就写这么几个,其他的大家去挖掘吧,祝好运!