最近本社会闲散人员去面试了,某公司终面的是个大佬,于是就有了下面的对话:
大佬一脸不耐烦地拿着简历:有没有做过支付啊?给我说下支付流程吧
我战战兢兢:有的有的,XX项目里接入了%*&(&*%
大佬扶了扶眼镜,皱皱眉头:你们项目任务调度用的啥?
我:xxl-job
大佬看了我一眼:说说他底层怎么实现的?
我:…
大佬:那有没有做过除了增删查改之外的东西?
我苦思冥想:(是在问我有写过框架吗…)没有的,都是在写业务,对数据处理…
大佬更加不耐烦:那你这不是码农吗
恍恍惚惚从公司走出来后不禁陷入了思考。好像也确实是这样,工作以来基本都在写业务,已经沦为工具人一名了,但工作除了CRUD还能写啥呢?
可能是被大佬的气势压迫了,面试的时候一下想不起来还是搞了一些些除CRUD外的东西的,比如:检测U盘的插入读取文件什么的、简单封装了类似Mybatis的东东、简单的消息中间件、AOP打日志这个算吗…
那其实现在基本框架的底层都是反射+代理模式了。这次我封装的其实是个类JDBC的玩意(泛微软件的RecordSet),在其基础上实现自动执行语句、查询后实体类赋值、根据注解查询条件、分页等等简单功能,实现就靠Java的反射和注解而已。
改造前代码:
RecordSet rs = new RecordSet();
String querySql = "SELECT * from formtable_main_59 where htmc = ?";
rs.executeQuery(querySql, contractId);
BigDecimal requestedMoney = new BigDecimal(0);
while (rs.next()){
String requestId = rs.getString("requestId");
//根据流程ID进行查询
RecordSet recordSet = new RecordSet();
String workFlow = "SELECT * from workflow_requestbase where REQUESTID = ?";
recordSet.executeQuery(workFlow, requestId);
if(recordSet.next()){
String requestAmount = rs.getString("bcsqje");
requestedMoney = requestedMoney.add(new BigDecimal(StringUtils.isEmpty(requestAmount) ? "0" : requestAmount));
}
}
可以看到这种写法就很像原始的JDBC,SQL语句写在业务代码里,不仅臃肿且难以维护。而且代码难以复用和没有实体类,都靠复制粘贴,而且取值也很麻烦。
这个时候,就要想办法解决这些问题了,不然以后系统怎么维护?
数据处理类:
其实就是反射+注解。
在实体类上加入表名的注解,根据
public class DataSourcesHandler{
private final RecordSet rs = new RecordSet();
public <T> List<T> selectList(T condition) {
if (null == condition) {
return null;
}
List<T> result = new ArrayList<>();
Class<?> clazz = condition.getClass();
//getTableName方法为根据注解取到真正的表名
String tableName = this.getTableName(clazz);
StringBuilder whereKey = new StringBuilder();
List<Object> whereValue = new ArrayList<>();
if (ObjectUtil.isNotNull(condition)) {
Field[] fields = this.getAllFields(clazz);
for (Field field : fields) {
String fieldName = this.getFieldName(field);
Object fieldValue = this.getFieldValue(condition, field.getName());
if (null != fieldValue) {
whereKey.append(" and ").append(fieldName).append(" = ?");
whereValue.add(fieldValue);
}
}
}
//开始拼接SQLyuju
String executeSql = "select * from " + tableName + " where 1 = 1 " + whereKey.toString();
rs.executeQuery(executeSql, whereValue);
//根据实体类进行赋值
Field[] fields = getAllFields(clazz);
Map<String, Object> map;
while (rs.next()) {
map = new LinkedHashMap<>();
String[] columnNames = rs.getColumnName();
for (Field field : fields) {
String fieldName = this.getFieldName(field);
for (String columnName : columnNames) {
if (columnName.toLowerCase().equals(fieldName.toLowerCase())) {
map.put(field.getName(), rs.getString(fieldName));
}
}
}
result.add((T) JSON.parseObject(JSON.toJSONString(map), condition.getClass()));
}
return result;
}
}
private String getTableName(Class<?> clazz) {
TableName tableNameAnnotation = clazz.getAnnotation(TableName.class);
if (null != tableNameAnnotation) {
return tableNameAnnotation.value();
} else {
TableMapping workflowMapping = clazz.getAnnotation(TableMapping.class);
if (null != workflowMapping) {
String mappingName = workflowMapping.value();
String tableName = getMappingTableName(mappingName);
if (null != tableName) {
return tableName;
} else {
log.info("注解[WorkflowMapping]的值[" + mappingName + "]没有查询到数据");
throw new ECException("注解[WorkflowMapping]的值[" + mappingName + "]没有查询到数据");
}
} else {
log.info("CLASS【" + clazz.getTypeName() + "】中未没有包含注解[TableName]或[WorkflowMapping]");
throw new ECException("CLASS【" + clazz.getTypeName() + "】中未没有包含注解[TableName]或[WorkflowMapping]");
}
}
}
改造后的业务代码:
只需要实例化数据处理类,调用里面的selectList方法,就可以实现根据实体类里的值查询并且赋值。
这样的代码就简洁多了,并且后续维护成本也低很多。
private final DataSourcesHandler dataSources = new DataSourcesHandler();
List<QualificationsOrderByDeal> buyList = dataSources.selectList(
new QualificationsOrderByDeal().setHtmc(String.valueOf(contractId)));