昨天,接受一个新需求,将我们通过认证用户身份证分析出用户的年龄、性别并作出统计。通过思考查阅资料最终我选择了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);
}
模拟数据如图上
总结:这样可以帮助我们更好分析用户使用我们的产品一个年龄段,为我们做计划,是一个很好的参考。