实习两个半月,参与一个类似企业门户网站开发的项目。项目采用的云计算服务模式包括基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS);项目基于Spring Boot框架和SSM框架,使用Redis数据库;用Consul实现SaaS应用的配置共享,因为要开发相应的移动端app,后又引入API-Gateway来提高移动客户端到服务端的通信效率。以下是实习期间遇到的一些问题及分析、解决方案。
1、问题:
从svn上导入项目到STS?
解决:
File-Import-SVN-从SVN检出项目
2、问题:
从svn上导入项目到Intellij Idea?
解决:启动时选择“Check out from Version Control-Subversion”,添加远程仓库的url,导出项目即可(需要分配svn的账号和密码)。
3、saas-website模块中,大致搞清了数据是如何传递的:
(1)request请求进来,先经过过滤器StaticUrlDispatchFilter,拿到articleService服务,再由uri拿到一整条记录,放到request域的”column”属性中,转发。
(2)进入控制器RenderController,从request域中拿到column记录。
(3)接下来将column作为参数,通过构造方法构造一个ColumnDataMethod类(继承TemplateMethodModelEx,是一个模板方法类),该类内部会自动执行一个exec方法(该方法传入的List类型的参数实际上是由模板页面上<#assign mapdata=cm( "top10") />
传过来的,”top10”是List中索引为0的元素)。
(4)先将传入的参数进行一个判断,然后通过articleCondition对象获得分页的文章列表,把文章信息设置进去,最后返回一个articleList。
(5)也就是说,<#assign mapdata=cm("top10")/>
,”top10”作为参数将会直接被传递给ColumnDataMethod对象,并执行它的exec()方法,然后返回一个Map<data,List<Article>>
对象,赋值给mapdata。
4、问题:
saas_website模块报:
org.springframework.web.client.HttpServerErrorException:
500 Internal Server Error
saas_information模块报:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
Unknown column 'TITLE' in 'field list'
分析:
起因是CMS_ARTICLE等数据表因为要改结构,数据全部清空了
数据库的表结构更改后,相应的Mapper.xml映射文件也要修改,主要是SQL语句。
5、制作freemarker模板页面
例如:
index.html页面使用<#include ""/>
标签嵌入模板页面template.html:
先在index.html中<#assign bindURL=""/>
,将bindURL传入template.html即可获得绑定url的相应数据;
注意点:
1)data-id属性的拼接:data-id="'${columnInfo.name}' + '-1'"
2)链接url的设置:href="${url(a)}" // a是遍历的元素
3)摘要长度的判断:<#if a.content?length < 100 ></#if>
4)时间格式的转换:${a.createTime?number_to_date} // 数据库中取出的是毫秒,这里要转换成yyyy-MM-dd格式,用number_to_date
6、问题:
在新闻中心-专题专栏页面,使用freemarker的<#include/>
标签调用模板。在模板中使用<#list articles as article>
遍历文章时,发现用article.thumbnailChartId
取article标签的属性值为空,导致缩略图取不到。而article的标题、内容等信息都能取到。
原因:
在mapper.xml映射文件中用MySQL语句进行查询时,没有查这个字段。
解决:
修改MySQL语句
7、问题:
使用freemarker调用文章的content时,由于content是使用富文本编辑器保存的,所以会带有html标签。
如果要在页面中获取部分content内容(摘要),例如获取前50个文字,直接用article.content
会使得html标签被注入
解决:
Java去除掉HTML里面所有标签,主要就两种,要么用开源的jar处理,要么就自己写正则表达式。
导入Jsoup开源jar包(maven项目引入依赖),过滤代码如下:
public static String getTextFromTHML(String htmlStr) {
Document doc = Jsoup.parse(htmlStr);
String text = doc.text();
// remove extra white space
StringBuilder builder = new StringBuilder(text);
int index = 0;
while(builder.length()>index){
char tmp = builder.charAt(index);
if(Character.isSpaceChar(tmp) || Character.isWhitespace(tmp)){
builder.setCharAt(index, ' ');
}
index++;
}
text = builder.toString().replaceAll(" +", " ").trim();
return text;
}
在首页显示摘要部分的代码:
<#assign plainText=getPlainText(article.content) />
<#if plainText?length < 50 >
${plainText}
<#else>
${plainText?substring(0,50) + '......'}
</#if>
8、问题:
打开首页,点击上方栏目“企业之窗”,显示404错误;点击其他栏目则正常跳转
原因:
数据库bindURL没配
9、问题:
若数据库存放的文章对象存在,但内容为空,则页面会显示错误。
解决:
用freemarker的“!”给article.content设置默认值
即:${(article.content)!"内容为空"}
10、问题:
页面样式的控制?
解决方案:
在标签中自己添加style属性
11、问题:
轮播图,点击滑动箭头,四张图片只能显示三张,有一张直接滑过
原因:
在加载js时,点击滑动箭头,onclick事件执行了两次,所以会直接滑过某一张图片
解决方案:
在js文件中,用unbind()方法解除onclick事件的绑定,确保该事件只执行一次
12、问题:
企业风采的企业人才部分的
原因:
数据库中数据的问题。
13、问题:
在html中如何控制标签块的显示与隐藏
解决:
在html页面中直接加一个<style/>
标签用来控制样式
<style type="text/css">
ol.am-control-nav {
display: none;
}
</style>
14、问题:
在html页面上,如果页面的一个部分已经被封装了,
解决方案:
基本的解决方案就是,用开发者工具将页面中的html代码copy下来,替换掉封装的代码(一般情况下只需要删掉class名即可),再根据要求进行修改。
15、问题:
项目在本地可以启动,并且正常显示数据;但当项目部署到服务器上后,数据传递出现问题,无法正常显示?
原因:
数据在html页面、Controller和Service之间传递的过程中,不应该使用String类型的数据作为参数进行传递,否则一旦参数过长(例如用来过长的汉字作为参数)部署后服务器无法解析,数据就无法完成传递了。
解决方案:
设置一个id值,使用id作为参数传递数据。
16、问题:
项目打包的时候,一定注意把 redis 的配置改成测试机的配置,不要使用开发机配置,如果没有改,访问了使用开发机 reids 配置的系统,再访问其它的系统,session 会丢失,一定注意。
17、问题:
js中对日期进行格式化的方法?
解决:
在js中要将格式为yyyy-MM-dd hh:mm:ss的日期格式化为yyyy-MM-dd,需要自己写一个format方法:
/**
* 格式化日期的方法
*/
Date.prototype.format = function(fmt) {
var o = {
"M+" : this.getMonth()+1, //月份
"d+" : this.getDate(), //日
"h+" : this.getHours(), //小时
"m+" : this.getMinutes(), //分
"s+" : this.getSeconds(), //秒
"q+" : Math.floor((this.getMonth()+3)/3), //季度
"S" : this.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt)) {
fmt=fmt.replace(RegExp.$1
, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
}
for(var k in o) {
if(new RegExp("("+ k +")").test(fmt)){
fmt = fmt.replace(RegExp.$1
, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
}
}
return fmt;
}
接下来再调用这个方法:
var oldStartTime = (new Date(msg.data[i].startTime)).getTime();
var curStartTime = new Date(oldStartTime).format("yyyy-MM-dd");
18、问题:
html表单页面实现多行单选?
解决:
不给name属性。
19、问题:
AngularJS用ng-repeat指令实现循环输出时,如何添加序号?
解决:
使用{{$index + 1}}
。
20、问题:
报错:TypeError: Converting circular structure to JSON in nodejs
原因分析:
把循环引用的对象,传给JSON.stringify
总会引起错误。
var a = { };
var b = { a: a };
a.b = b;
JSON.stringify(a);
由于以上的 a 和 b 循环引用彼此,结果对象无法转换成 JSON。
解决:
移除任何想转换成 JSON 的对象中的循环引用。
在声明approvalTable表格时,同时声明了一些属性:
vm.approvalTable = [{
"name": " ",
"operatTime": " ",
"attachmentList": [],
"fileUploader": fileOperationService.getUploader(),
"delApproval": function () {
var position = vm.approvalTable.indexOf(this);
vm.approvalTable.splice(position, 1)
}
}]
其中的“fileUploader”是文件上传组件中的一个必要属性。但在数据保存时,如果这个属性不删除,就会导致对象的循环引用。因此必须在保存数据时将这个属性删除。
21、问题:
页面要加载四个下拉框,下拉框中的值是从码表中读取的,每次都要调用masterDataService.listParamConfig
接口来读取码表。例如:
// 码表读取:项目资金情况类型
(function () {
var typeCode = "8137";
vm.moneyTypeList = masterDataService.listParamConfig({
paramCode: typeCode
});
})();
但是,四个下拉框每次都只有三个读取到了值,总有一个读不到,即总有一个调用masterDataService.listParamConfig
接口时请求失败。
那么,我们只要加一个while循环,如果没取到值就重复请求,取到了就不请求。可是,while中的判断条件怎么填呢?
(function () {
var typeCode = "8137";
vm.moneyTypeList = masterDataService.listParamConfig({
paramCode: typeCode
});
while (?) {
vm.moneyTypeList = masterDataService.listParamConfig({
paramCode: typeCode
});
}
})();
这里的问题是,当发送一次请求后,接口返回来的是一个对象,如果对象含有我们需要的码表信息,则该对象包含一个Array数组;而如果请求失败,对象中没有我们所需要的码表信息,则对象既不是undefined,也不是null,而是一个包含_proto_:Array(0)
的Object。这样一来就不能用该对象是否为undefined和null作为判断条件。
解决:
(function () {
var typeCode = "8137";
vm.moneyTypeList = masterDataService.listParamConfig({
paramCode: typeCode
});
while (Object.prototype.toString.call(vm.moneyTypeList).indexOf('Array') == -1) {
vm.moneyTypeList = masterDataService.listParamConfig({
paramCode: typeCode
});
}
})();
先发送一次请求,获得该对象。再判断该对象中是否包含Array数组,可以用
Object.prototype.toString.call(vm.moneyTypeList).indexOf('Array') == -1
来判断Array数组在对象中的索引:不是-1说明请求成功,是-1则说明不存在,重新请求。
22、问题:
申请人信息拿不到?
分析:
问题代码是:
// 申请人id查询申请人姓名数据存储
httpService.processHttp( (1)
approvalService.getApplicantNames,
creatorIdList,
function (applicantMap) {
for (var i = 0; i < data.length; i++) {
data[i].applicantName = applicantMap[data[i].creator].name;
}
});
vm.dataList = data; (2)
vm.itemList = vm.clone(data); (3)
存在同步异步的问题,下面的(2)和(3)比(1)先执行,申请人的数据没有存进dataList中,所以没有拿到申请人姓名。
解决:
httpService.processHttp(
approvalService.getApplicantNames,
creatorIdList,
function (applicantMap) {
for (var i = 0; i < data.length; i++) {
data[i].applicantName = applicantMap[data[i].creator].name;
}
vm.dataList = data;
vm.itemList = vm.clone(data);
});
23、问题:
用户填表数据校验?
解决:
if (vm.project.projectName == undefined
|| vm.project.projectName == null
|| vm.project.projectName == '') {
notificationService.notice({
text : "项目名称为空!请填写"
}).warn();
return;
};