昨天,接受一个新需求,将我们通过认证用户身份证分析出用户的年龄、性别并作出统计。通过思考查阅资料最终我选择了Mysql+java+Echarts 实现这个小需求。思路如下:
1、通过Mysql 语句查我们的用户表中身份证号。不仅仅是查。通过稍微有逻辑的语句直接获取到年龄段以及该年龄段个数。语句如下:
select case when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=17 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=23 then '17~23' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=24 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=28 then '24~28' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=29 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=33 then '29~33' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=34 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=38 then '34~38' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=39 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=43 then '39~43' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=44 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=48 then '44~48' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=49 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=53 then '49~53' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=49 and TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())<=59 then '54~59' when TIMESTAMPDIFF(YEAR,STR_TO_DATE(substr(id_card_no,7,8),'%Y%m%d'),sysdate())>=60 then '60+' END age,count(*) count from tb_users where substr(id_card_no,-2,1)%2 = 1 group by age
解释:通过substr()获取身份证号出生年月例如19940627 ,str_to_date()方法将字符串,转化成我时间格式例如str_to_date('19940627','%Y%m%d') 结果是1994-06-27。
TIMESTAMPDIFF 这个类似Oracle 的month_between.这个方法可以计算出两个时间差。第一个参数是差值精确到年、月、日等等。我这里是算年龄,所以是Year。这个计算出当前与身份证出生时间的差值,也就是年龄。
然后case when then 语法做类似if else 操作 这个应该好理解。
最后通过传参数来实现查找男的还是女。思路就是通过substr()获取身份证号倒数第二位,和2取余。奇数男的,偶数女的。这个就是身份证规则。然后group by age 也就是年龄段分组。
2、java 集合转换Json数据
CardUtil工具类
package com.dairuijie.manage.utils; import java.util.Calendar; /** * * @Title: CardUtil.java * @Package com.qzbl.demo01 * @author Drj * @date 2018年5月3日 上午10:36:58 * @version V1.0 */ public class CardUtil { public static String ONE_STAGE = "17~23"; public static String TWO_STAGE = "24~28"; public static String THREE_STAGE = "29~33"; public static String FOUR_STAGE = "34~38"; public static String FIVE_STAGE = "39~43"; public static String SIX_STAGE = "44~48"; public static String SERVEN_STAGE = "49~53"; public static String EIGHT_STAGE = "54~59"; public static String NINE_STAGE = "60+"; /** * 通过身份证号获取年龄 * @param idCard * @return */ public static int getAgeByIdCard(String idCard) { int iAge = 0; Calendar cal = Calendar.getInstance(); String year = idCard.substring(6, 10); int iCurrYear = cal.get(Calendar.YEAR); iAge = iCurrYear - Integer.valueOf(year); return iAge; } /** * 通过身份证号获取性别 * @param idCard * @return */ public static boolean getGenderByIdCard(String idCard) { boolean sGender = true; String sCardNum = idCard.substring(16, 17); if (Integer.parseInt(sCardNum) % 2 != 0) { sGender = true;//男 } else { sGender = false;//女 } return sGender; } /** * 身份证号15位转换18位 * @param IdCardNO * @return */ public static String transIDCard15to18(String IdCardNO){ String cardNo=null; if(null!=IdCardNO&&IdCardNO.trim().length()==15){ IdCardNO=IdCardNO.trim(); StringBuffer sb=new StringBuffer(IdCardNO); sb.insert(6, "19"); sb.append(transCardLastNo(sb.toString())); cardNo=sb.toString(); } return cardNo; } /** * 转换身份证号最后一位 * @param newCardId * @return */ private static String transCardLastNo(String newCardId){ char[] ch=newCardId.toCharArray(); int m=0; int [] co={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}; char [] verCode=new char[]{'1','0','X','9','8','7','6','5','4','3','2'}; for (int i = 0; i < newCardId.length(); i++) { m+=(ch[i]-'0')*co[i]; } int residue=m%11; return String.valueOf(verCode[residue]); } }
封装到集合
/** * 封装男女不同年龄段的集合 * @param allList * @param countMap * @return */ public List<Integer> getUserCountByStage(List<String> allList,List<Map<String,Object>> countMap){ List<Integer> count = new ArrayList<Integer>(); for(int i=0; i< allList.size(); i++) { for(Map<String, Object> male : countMap) { if(male.get("age").toString().equals(allList.get(i).toString())){ count.add(Integer.valueOf((male.get("count").toString()))); } } if(count.size() < i+1) { count.add(0); } } return count; }
配置注解以及ObjectJson
@RequestMapping("/echarts") @ResponseBody public String echarts(HttpServletResponse response){ JSONObject result = new JSONObject(); List<String> allList = new ArrayList<String>(); allList.add(CardUtil.ONE_STAGE); allList.add(CardUtil.TWO_STAGE); allList.add(CardUtil.THREE_STAGE); allList.add(CardUtil.FOUR_STAGE); allList.add(CardUtil.FIVE_STAGE); allList.add(CardUtil.SIX_STAGE); allList.add(CardUtil.SERVEN_STAGE); allList.add(CardUtil.EIGHT_STAGE); allList.add(CardUtil.NINE_STAGE); List<Map<String,Object>> maleList = mRealCertifyService.selectCountInfo(1); List<Map<String,Object>> femaleList = mRealCertifyService.selectCountInfo(0); result.put("maleList", getUserCountByStage(allList,maleList)); result.put("femaleList", getUserCountByStage(allList,femaleList)); return result.toString(); }
3、Echarts实现图形化
$(function(){ $.ajax({ url : "userCreditInfo/echarts.html", dataType : "json", cache : false, success : function(json) { Myecharts(json); }, errr:function(){ layer.alert("error"); } }) })
function Myecharts(obj) { var myChart = echarts.init(document.getElementById('main')); // 指定图表的配置项和数据 var option = { title : { text : '用户统计图' }, tooltip : {}, legend : { data : [ '女', '男' ] }, xAxis : { data : [ "17~23", "24~28", "29~33", "34~38", "39~43", "44~48", "49~53", "54~59", "60+" ], name : '岁' }, yAxis : { name : '人' }, series : [ { name : '女', type : 'bar', data : obj.femaleList }, { name : '男', type : 'bar', data : obj.maleList } ] }; myChart.setOption(option); }
模拟数据如图上
总结:这样可以帮助我们更好分析用户使用我们的产品一个年龄段,为我们做计划,是一个很好的参考。