I'M FeiFei
type: channel
link: https://feifei.im/
description: “假如生活欺骗了你/不要悲伤/找个程序员/告诉他/需求变了”一个热爱代码的程序猿修炼之路
items: 一个fastjson转换JSON字符串的报错排查
items: 多说挂了，换回typecho，随便说说
items: Ubuntu 14.04安装java+nginx+tomcat7简要步骤
items: ionic开发的几个小坑
items: 杂记
items: 在CentOS上配置Jetty开机自启动
items: 记一次mysql问题告警和排查
items: GODDAY域名被盗了
items: DB2数据库错误代码（整理版）
items: 一个简单的基于JFinal的分页扩展

一个fastjson转换JSON字符串的报错排查
type: item
date: 2017-07-03T11:15:00+00:00
description: 今天给一个java类加了几个字段，没想到转为json字符串的时候报错了，定位了一下原因，觉得这种情况遇到的应该不多，又想起来很久没写博客了，于是就把遇到的问题以及定位过程记下来，省了以后遇到的人再花时间定位了调用的是JSON.toJSONString(Object object)方法，具体的报错信息如下：Caused by: com.alibaba.fastjson.JSONException: write javaBean error at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:234) at Serializer_5.write1(Unknown Source) at Serializer_5.write(Unknown Source) at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:369) at com.alibaba.fastjson.JSON.toJSONString(JSON.java:393) at com.alibaba.fastjson.JSON.toJSONString(JSON.java:567) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at ... 81 common frames omitted Caused by: com.alibaba.fastjson.JSONException: create asm serializer error, class class com.feifei.bean.TestBean at com.alibaba.fastjson.serializer.SerializeConfig.createJavaBeanSerializer(SerializeConfig.java:113) at com.alibaba.fastjson.serializer.JSONSerializer.getObjectWriter(JSONSerializer.java:527) at com.alibaba.fastjson.serializer.ListSerializer.write(ListSerializer.java:81) at com.alibaba.fastjson.serializer.ObjectFieldSerializer.writeValue(ObjectFieldSerializer.java:118) at com.alibaba.fastjson.serializer.ObjectFieldSerializer.writeProperty(ObjectFieldSerializer.java:67) at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:216) ... 94 common frames omitted Caused by: java.lang.ClassFormatError: JVMCFRE042 bytecode array size > 65535; class=Serializer_57, offset=53261 at java.lang.ClassLoader.defineClassImpl(Native Method) at java.la…

多说挂了，换回typecho，随便说说
type: item
date: 2017-05-10T14:27:52+00:00
description: 之前从typecho换到了hexo,用了多说的评论。现在多说要挂了，不想用Disqs，网易云跟帖之类的插件了，于是换回typecho.尴尬地发现之前博客的备份直接用就行了……也就是说这一年多竟然没写一篇博客……我自己也是无语了～除了懒，有点忙之外，主要精力还是放在主业java上了，毕竟是吃饭的家伙；而且随着一门语言逐渐深入进去，越发觉得自己懂的太少，反而不知道博客能写点什么了不过折腾还是继续，现在抛开ionic，继续折腾ReactNative，多学点东西，拓展一下眼界还是很有必要的～生命不息，折腾不止～

Ubuntu 14.04安装java+nginx+tomcat7简要步骤
type: item
date: 2015-11-05T13:30:00+00:00
description: 之前一直用centOS,试用了一次Ubuntu感觉这是一个对新手很友好的系统，用apt-get安装环境很方便，前端时间换了VPS，重新安装环境很快就搞定了，做个笔记，下次再配置就不用再找了nignx安装Ubuntu14.04默认安装是是1.4.6版本的，而新的稳定版本都到1.8了，所以我要装个更加新的稳定版本，参考nginx的官方教程http://nginx.org/en/linux_packages.html#stable先下载一个key，http://nginx.org/keys/nginx_signing.key添加到apt里apt-key add nginx_signing.key 再修改/etc/apt/sources.list文件，新增配置：deb http://nginx.org/packages/mainline/ubuntu/ trusty nginx deb-src http://nginx.org/packages/mainline/ubuntu/ trusty nginx 保存之后，执行apt-get update apt-get install nginx 这样nginx就一路安装完毕了安装完的nginx配置在/etc/nginx/conf.d/目录jdk安装ubuntu默认安装的jdk是openjdk，安装的话一行命令就可以apt-get install openjdk-7-jdk 不过我想安装orcal的jdk，目前网上很多通过PPA的方式安装的，命令如下apt-get install python-software-properties add-apt-repository ppa:webupd8team/java apt-get update apt-get install oracle-java7-installer 或者你还可以通过下载官方源码包的方式来安装.首先去orcal官网下载需要的jdk版本，我下载的是7u80,http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html上传到服务器后，解压tar -xvf jdk-7u80-linux-x64.tar.gz 创建jvm文件夹，用来安装jdkmkdir /usr/lib/jvm mv ./jdk1.7.0_80 /usr/lib/jvm/ 接下来执行命令：update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.7.0_80/bin/java" 1 update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.7.0_80/bin/javac" 1 update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.7.0_80/bin/javaws" 1 这几个命令的作用是把这个jdk的优先级设置为1，优先级设的很低其实就是为了新安装的这个jdk不会取代当前默认的jdk版本,以便后面调整接下里继续执行命令，设置文件夹权限chmod a+x /usr/bin/java chmod a+x /usr/bin/javac chmod a+x /usr/bin/javaws chown -R root:root /usr/lib/jvm/jdk1.7.0_80 接下来可以分别执行以下命令选择需要的默认JDK版本，root@feifei:~# update-alternatives --config java There are 2 choices for the alternative java (providing /usr/bin/java). Selection Path Priority Status ------------------------------------------------------------ * 0 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java 1071 auto mode 1 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java 1071 manual mode 2 /usr/lib/jvm/jdk1.7.0_80/bin/java 1 manual mode Press enter to keep the current ch…

ionic开发的几个小坑
type: item
date: 2015-07-20T13:19:00+00:00
description: 之前做个小移动客户端，图方便快捷，使用了ionic来开发，整体还是挺顺畅的，就是不太习惯yong其中碰到一些小坑，都是一些知道了就很简单，不知道就很蛋疼的东西，所以做个笔记，帮初次接触ionic和angularjs的人省点事儿1.ionic中的CORS（跨域）问题这个问题一般刚接触ionic的都会遇到，在浏览器中通过ionic serve调试的时候，请求api时会报错XMLHttpRequest cannot load http://localhost:8080/api/p/1. No'Access-Control-Allow-Origin' header is present on the requestedresource. Origin 'http://localhost:8100' is therefore not allowedaccess.网上也有不少解决方案，这边只提供一个最简单的直接安装一个chrome插件，名字就叫：“Allow-Control-Allow-Origin: *”地址在 https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi然后直接用插件打开cors就行了2.$resource的结果获取提示未定义（undefined）的问题如果定义了一个servive：.service('DemoService',['$q','$resource', 'Constants', function($q,$resource, Constants) { var postResource = $resource(Constants.API.baseUrl+'/p/:pid', {pid: '@pid'}); var post = { getPostDetail: function(_pid) { return postResource.get({pid:_pid}); } } return post; }]) 然后在controller中调用获取数据并使用var postDetail = DemoService.getPostDetail($stateParams.pid); 假设返回的是类似于{"status":"Y","message":"成功","postInfo":{"id":113,...}} 这样的json串,如果我们直接取值postDetail.status这样就会报错，提示undefined，从而取不到值，因为$resource的结果是异步返回的，直接调用方法并不能立即就取到返回值。而如果直接$scope.postDetail = postDetail.postInfo的话，页面是可以正常显示的，因为当数据没有返回之前，模板引擎不会渲染，一旦异步数据获取完成，会自动触发模板引擎的渲染机制把数据呈现到视图中。所以如果我们要在controller中获取返回值的话，只要这么写就行了DemoService.getPostDetail($stateParams.pid).$promise.then( function(successData) { //获取成功后处理 var detail = successData.status; }, function(failData) { //获取失败后处理 }); 3.ion-refresher和ion-infinite-scroll调用多次的问题一个页面上，我同时使用了ion-refresher和ion-infinite-scroll用来下拉刷新当前数据以及到底自动获取下一页内容。偶然发现当ion-refresher下拉刷新之后，页面内容刷出来的一瞬间，infinite的方法被调用了多次，因为页面内容当时还没刷出来，列表一片空白，所以此时页面其实就是已经默认到了最底部了，于是就触发了获取下一页的方法解决方法也很简单，就是设置一下immediate-check的值<ion-infinite-scroll ng-if="!noMorePage" immediate-check="false" on-infinite="queryNext()" distance="1%"> </ion-infinite-scroll> 这个设置官方解释是Whether to check the infinite scroll bounds immediately on load就是设置是否在页面加载后立刻触发on-infinite的方法，设为false后，则只有滚动到页面边缘时才会触发，即使页面加载出来已经到最底部，不滚动一下的话也是不会触发的至于…

杂记
type: item
date: 2015-04-28T11:05:00+00:00
description: 唔，发现一晃又是好几个月没写博客了……神说，这里太荒芜了，于是就有了这篇杂记。这段时间比较忙(懒)，手上压了一些东西要做，当然拉，都是自己折腾着玩的，所以基本三天打鱼两天晒网。继而导致手上压的东西越来越多，自己都有点不记得了……干脆写个博客絮叨絮叨，一举两得~上个月把服务器从美国换到了日本，在Linode上连试了7，8个IP，总算找到一个能用的日本节点，顺便把系统从centOS换到了Ubuntu。话说之前用centOS觉得挺方便的，一直听说Ubuntu操作简单，于是就趁这个机会换着试试，觉得果然没有最方便，只有更方便，装环境比之前centOS更简单了。切到日本节点跑了两星期之后发现挺稳定，ping值更是降了一个数量级，于是果断把原先的美国节点删掉了（都是钱呐~~）接下来计划要做的：1.给自己折腾的小站做个移动端。当然拉，不是原生的，原生工作量太大，真搞起来估计是上不了线了。之前发现Ionic貌似挺不错，现在手机性能也越来越好，这种用JS和HTML5开发的混合移动应用性能比起前两年好的不是一点半点，小站功能又不多，访问量又不大，综合权衡一下，就决定用Ionic开发Android和IOS的客户端了2.自己简单封装的第三方登录包增加微信登录功能。之前coding.net做活动，提代码送抱枕的时候，为了拿个抱枕，把自己之前折腾的一个基于java的，整合QQ，微博，豆瓣的功能提取出来放到coding上去赚了个抱枕回来，然后就一直没更新了……记得当时github上也开了个同名项目，连代码都懒得再传一份了（我的懒成啥样……），好吧，其实还是觉得git用着不太习惯唔，希望能赶紧弄好吧

在CentOS上配置Jetty开机自启动
type: item
date: 2015-01-29T12:52:00+00:00
description: 之前vps上安装了jetty跑了几个小站，不过当时没配开机自动启动。今天升级系统Glibc堵幽灵漏洞的时候，需要重启，为了重启后不要手动启动jetty，google了一下，把jetty加入开机自启了。查看一下系统的自启列表，里面已经有一些随机自启的程序了[root@localhost ~]# chkconfig --list mysql 0:关 1:关 2:开 3:开 4:开 5:开 6:关 nginx 0:关 1:关 2:开 3:开 4:开 5:开 6:关 把jetty加入自启动（注意jetty的路径）ln -s /opt/jetty/jetty.sh /etc/init.d/jetty chkconfig --add jetty chkconfig jetty on 当然，JETTY_HOME是要配置的～vim /etc/init.d/jetty 加入一条JETTY_HOME的路径配置 JETTY_HOME=/opt/jetty 完成后再看一下，jetty已经在自启列表里了[root@localhost jetty]# chkconfig --list jetty 0:关 1:关 2:开 3:开 4:开 5:开 6:关 这样下次开机的时候jetty就可以自动启动啦,并且可以通过service jetty start 来启动jetty了

记一次mysql问题告警和排查
type: item
date: 2015-01-12T02:33:00+00:00
description: 今天突然监控宝报警，网站无法访问了，自己一上，果然上不了，提示数据库连接错误由于VPS上除了博客还有其他的两个站，一上，都没法访问，其中一个java站报错：com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections" 我就纳闷了，这几个站平均一天也就那么几十个人访问，怎么可能连接数过多，难道被人攻击了？于是上Linode后台一瞅，流量，CPU，IO都没啥异常啊，那能有啥问题！一怒之下，重启了mysql……发现还是不行，不过这次报错变成了：org.springframework.jdbc.UncategorizedSQLException: ### Error querying database. Cause: java.sql.SQLException: Got error 28 from storage engine ### The error may involve defaultParameterMap ### The error occurred while setting parameters ### Cause: java.sql.SQLException: Got error 28 from storage engine ; uncategorized SQLException for SQL []; SQL state [HY000]; error code [1030]; Got error 28 from storage engine; nested exception is java.sql.SQLException: Got error 28 from storage engine 搜索之，说是磁盘空间不足导致的……我信了你的邪，总共24G的空间，才放了三个小站，怎么呢可能空间不足……ssh上去查看了一把，当时我就震惊了！神马玩意耗了我24个G……联想到mysql的报错，到mysql目录下一查，果然发现一堆奇怪的东西……继续搜索之，说这些都是mysql的数据库操作日志，数据库的操作命令，执行信息都会被存到日志里来，防止哪天数据库出问题了可以来查查原因啊神马的。考虑到空间和实际项目，还是删掉吧……果然删掉之后，所以的站都能正常访问了～最后，为了避免再次发生这种日志撑报磁盘空间的事情，直接把mysql的配置文件 my.cnf 里面的log-bin这一行注释掉，重启一下mysql就OK啦！

GODDAY域名被盗了
type: item
date: 2014-10-20T14:11:00+00:00
description: 放在GODDAY上的域名被盗了，在一封确认邮件都没发给我的情况下，PUSH走了域名，改了域名的注册人信息。最神奇的是，我的账号的密码和注册邮箱都被改了，这竟然也没有任何的邮件确认！！最终只有域名被转走的一份通知邮件！！是的，只是通知邮件，不是确认邮件，告诉你有这么一件事，就完了。真是屎一样的GODDAY，虽然那几个域名只是自己做个小站娱乐娱乐，但是也是好几年的米了，有点感情了。看着被盗了然后解析到各种博彩，垃圾站上，真心纠结------2014年10月30日更新-----给GODADDY的undo和change部门发了邮件，没人理……本来都放弃了，突然过了两周给了来了封邮件：竟然说检测到我账户异常，给我恢复了……赶紧登上去，改密码，改whois，改解析。最后看到正常解析到自己站上还觉得有一种莫名其妙的不真实感……于是决定等保护期一过立马转走，这么一折腾，本来流量就不多的站，现在流量更少了……

DB2数据库错误代码（整理版）
type: item
date: 2014-08-21T08:41:00+00:00
description: 整理了一下DB2的数据库错误代码，当然，内容是网上找的，自己整理了下格式，看起来舒服点……没办法，强迫症表示网上那些参差不齐的排版每次看到都很纠结……整理如下 ↓↓↓↓↓↓↓↓↓ sqlcode sqlstate 说明 +012 01545 未限定的列名被解释为一个有相互关系的引用 +098 01568 动态SQL语句用分号结束 +100 02000 没有找到满足SQL语句的行 +110 01561 用DATA CAPTURE定义的表的更新操作不能发送到原来的子系统 +111 01590 为2型索引设置了SUBPAGES语句 +117 01525 要插入的值的个数不等于被插入表的列数 +162 01514 指定的表空间被置为检查挂起状态 +203 01552 使用非唯一的名字来解决命名的限定列 +204 01532 命名的对象未在DB2中定义 +206 01533 命名的列不在SQL语句中指定的任何表中存在 +218 01537 因为SQL语句引用一个远程对象，不能为该SQL语句执行EXPLAIN +219 01532 命名的PLAN TABLE不存在 +220 01546 不正确定义PLAN TABLE，检查命名列的定义 +236 01005 SQLDA中的SQLN的值至少应于所描述的列的个数一样大 +237 01594 至少有一个被描述的列应该是单值类型，因此扩展的SQLVAR条目需要另外的空间 +238 01005 至少应有一个被描述的列是一个LOB，因此扩展的SQLVAR条目需要另外的空间 +239 01005 至少应有一个被描述的列应是单值类型，因此扩展的SQLVAR条目需要另外的空间 +304 01515 该值不能被分配给宿主变量，因为该值不再数据类型的范围之内 +331 01520 不能被翻译的字符串，因此被设置为NULL +339 01569 由于与DB2 2.2版本的子系统连接，所以可能存在字符转换问题 +394 01629 使用优化提示来选择访问路径 +395 01628 设置了无效的优化提示，原因代码指定了为什么，忽略优化提示 +402 01521 未知的位置 +403 01522 本地不存在CREAT ALIAS对象 +434 01608 在DB2未来发布的版本中将不支持指定的特性，IBM建议你停止使用这些特性 +445 01004 值被CAST函数截取 +462 01Hxx 由用户定义的函数或存储过程发出的警告 +464 01609 命名的存储过程超出了它可能返回的查询结果集的个数限制 +466 01610 指定由命名的存储过程返回的查询结果集的个数。成功完成 +494 01614 由存储过程返回的结果集的个数超过了由ASSOCIATE LOCATORS语句指定的结果集定位器的个数 +495 01616 因为倒台SQL的成本估算超出了在ELST中指定的警告阀值，所以发出警告 +535 01591 请求一个主健的定位更新，或请求一个使用自我引出 约束的表的删除操作 +541 01543 命名外健是一个重复的引用约束 +551 01548 命名的授权ID缺少在命名的DB2对象上执行命名操作的权限 +552 01542 命名的授权ID缺少执行命名操作的权限 +558 01516 已经被授权该PUBLIC，因此WITH GRANT OPTION不可用 +561 01523 对ALTER REFERENCES INDEX 和TRIGGER特权，PUBLIC AT ALL LOCATION无效 +562 01560 因为GRANTEE已经拥有这些特权，所以一个或更多的特权被忽略 +585 01625 模式名指定了不止一次 +599 01596 没有为长字符数据类型（BLOB，CLOB和DBCLOB）建立比较函数 +610 01566 由于建立了一个指定为DEFER YES的索引，指定的对象处于PENDING状态，或者因为使用了ALTER INDEX改变关键值的范围，所以指定的对象处于PENDING状态 +625 01518 因为删除了主健索引，所以表定义被标注为不完整 +626 01529 删除了加强UNIQUE约束的索引，唯一性不在被加强 +645 01528 因为建立的索引中没有包含NULL，所以WHERE NOT NULL被忽略 +650 01538 不能更改或者建立已命名的表为从属表 +653 01551 在已指定的分区表空间中尚没有建立指定的分区索引，所以分区索引不可得 +655 01597 为CREATE或ALTER STOGROUP语句指定特定或者非特定的卷ID，在DB2较新发布的版本中（版本6以后）将不再支持他们 +658 01600 当建立目录索引时，不能指定SUBPAGES语句，SUBPAGE…

一个简单的基于JFinal的分页扩展
type: item
date: 2014-08-12T11:46:00+00:00
description: 前几天试了试JFinal框架，感觉用起来还是蛮方便的，作者似乎借鉴了一些Ruby的思想，并且集成了一些常用的功能类，比如分页，图片验证码等等。个人觉得，与其说这是一个java的开发框架，不如说它是一个简洁的建站解决方案。JFinal的分页类感觉还是很方便的，官方的示例很简单也很清楚，直接调Model的paginate方法，传入当前页码，每页显示数量等参数就行了。不过，这只是分页查询数据库得到的数据列表，除此以外，还得把分页的信息展示在前端页面上，这时候就得自己实现一些分页逻辑以及相应的前端了。所以，我就简单封装了一个分页类，把一些分页需要的页面元素计算封装进去，配合freemarker，实现了一个功能还算完全的分页扩展，其实也不能叫扩展，只是一种简单的实现方式，贴出来给大家参考参考。先贴个效果图：PageHandler 类：package com.eric.huahuajia.dto; import com.jfinal.plugin.activerecord.Page; public class PageHandler { // 当前页码 public int pageNumber; // 每页数量 public int pageSize; // 总页数 public int totalPage; // 总行数 public int totalRow; // 是否有下一页 public boolean hasNextPage; // 是否有前一页 public boolean hasPreviousPage; // 下一页页码 public int nextPageNumber; // 前一页页码 public int previousPageNumber; // 页面基础URL，用作翻页事件 public String basePathUrl; // 偏移量，当分页过多时只显示当前页前后偏移部分页码 public int offSetNum = 3; // 需要显示出来的页码范围 - 起始页码 public int startPageNum; // 需要显示出来的页码范围 - 结束页码 public int endPageNum; /** * 构造函数，初始化 * @param pageNumber * @param pageSize * @param totalPage * @param totalRow */ public PageHandler(int pageNumber,int pageSize,int totalPage,int totalRow) { this.pageNumber = pageNumber; this.pageSize = pageSize; this.totalPage = totalPage; this.totalRow = totalRow; this.calculatePage(); this.calculateShowPage(); } /** * 构造函数，根据JFinal内置Page初始化 * @param pageInfo */ public <T> PageHandler(Page<T> pageInfo){ this.pageNumber = pageInfo.getPageNumber(); this.pageSize = pageInfo.getPageSize(); this.totalPage = pageInfo.getTotalPage(); this.totalRow = pageInfo.getTotalRow(); this.calculatePage(); this.calculateShowPage(); } /** * 计算当前页是否有前后页，并得出前后页码 */ private void calculatePage() { if ((this.pageNumber - 1) > 0) { this.hasPreviousPage = true; this.previousPageNumber = this.pageNumber - 1; } else { this.hasPreviousPage = false; this.previousPageNumber = 0; } if (this.pageNumber >= this.totalPage) { this.hasNextPage = false; this.nextPageNumber = 0; } else { this.hasNextPage = true; this.nextPageNumber = this.pageNumber + 1; } } /** * 计算需要显示出来的页…