自定义扩展字段设计与实现,产品思维的提升
(这部分内容是我工作中的一些工作成长总结,大家不喜欢可以直接进行跳过,跳转到自定义扩展字段实现)
在本周的工作,导师让我们实现自定义扩展业务。
周一: 分析扩展字段解决方案,实现扩展字段的用户需求,扩展字段所用到的技术, 由于导师请假,看不太懂导师所描述的技术方向,产品需求,就没有选择师傅的扩展字段解决方案。 在没有分析清楚产品需求的情况下,就进行了代码的编写,想采用反射等一类技术来实现动态字段扩展,没有考虑到用户在某个场景下,如何编辑的在扩展字段中添加数据。导致我解决的方案代码,不具有很大的价值
经过反思:编写业务前,一定要反复斟酌,技术为产品而生,编写业务的过程中要具有产品思维,这样做是不是合理的,这样做会不会给用户带来极大的便利,选择一个自己擅长的技术,可能不是完美产品的解决方案,选择产品最适合的技术,虽然不是很擅长,这不正是自己的一种提升吗?
第二天:导师:针对我的解决方案,和代码提出了很多场景下的问题,经过深思熟虑后给出了解决的问题的方式,但是我的解决方案,并不是那么的完美,没有考虑到性能的问题,最终采用Map数据结构来实现动态字段扩展。
第五天:自定义扩展业务已经全部实现,导师向我提出需要如何在搜索中能找到对应扩展字段对应的行数据。因为对es技术不熟悉,甚至有点懵的状态,当我看了公司的es业务后,分析这个庞大的问题,针对这个问题,我应该怎么一步一步去做。然后得到了一个一个细小的问题 ,针对这些问题向师傅提出问题,最终得到了解决问题的方式
当遇到一个问题的时候,找不到解决问题的方式,仔细梳理问题,应该思考如何把问题这个问题拆分成为一个一个小问题,当得到了一个一个细小的问题,就能得到最终问的解决方案。
自定义扩展字段实现
由于不在公司表结构设计不能给大家展示entity展示给大家
扩展字段存储表
vbnet
public class ExtendEntity {
private Long id;
private Long accId;
private Long objectId;
private Long funcId;
private String funcText;
private String type;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
扩展字段表头
vbnet
public class FunctionEntity {
private Long id;
private Integer functionType;
private String functionMain;
private String functionName;
private Integer isnewfunc;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// 省略构造函数和Getter/Setter方法
}
扩展字段开关表
vbnet
public class FunctionSwitchEntity {
private Long id;
private Long accId;
private Long functionId;
private Integer orderNum;
private Integer functionSwitch;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
扩展字段表头开关 dao
java
@Repository
public class FunctionSwitchDao {
@Resource(name = SaasBusinessDsConfig.SaasBusinessDbJdbcTemplateName)
private JdbcTemplate jdbcTemplate;
@Resource(name = SaasBusinessDsConfig.SaasBusinessDbNamedParameterJdbcTemplateName)
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public int PassupdateSwitch(long accId, long id, int functionSwitch) {
StringBuilder ab = new StringBuilder();
ab.append( "UPDATE t_function_switch SET functionswitch = :functionSwitch, updatedat = current_timestamp ");
ab.append( "WHERE accid = :accId AND id = :id");
String sql = ab.toString();
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("functionSwitch", functionSwitch);
params.addValue("accId", accId);
params.addValue("id", id);
return namedParameterJdbcTemplate.update(sql, params);
}
public List<FunctionSwitchDto> getFunctionList(long accId, long funcType) {
StringBuilder sb = new StringBuilder();
sb.append( "SELECT fs.id, fs.functionid, f.functionname,f.functionmain,fs.orderNum,f.functiontype, fs.functionswitch, f.isnewfunc ");
sb.append( "FROM t_function_switch fs " );
sb.append("JOIN t_function f ON fs.functionid = f.id " );
sb.append("WHERE fs.accid = :accId AND f.functiontype = :funcType ");
sb.append("ORDER BY fs.orderNum;");
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("accId", accId);
params.addValue("funcType", funcType);
String sql = sb.toString();
RowMapper<FunctionSwitchDto> rowMapper = new BeanPropertyRowMapper<>(FunctionSwitchDto.class);
List<FunctionSwitchDto> result = namedParameterJdbcTemplate.query(sql, params, rowMapper);
if (result == null || result.isEmpty())
return null;
return result;
}
public void deleteAccid(long accId, long id) {
String query = "DELETE FROM t_function_switch WHERE accid = :accId AND id = :id";
Map<String, Object> parameters = new HashMap<>();
parameters.put("accId", accId);
parameters.put("id", id);
namedParameterJdbcTemplate.update(query, parameters);
}
public int funcidCount(long funcId) {
StringBuilder sb = new StringBuilder();
sb.append( "SELECT COUNT(*) FROM t_function_switch WHERE functionid = :funcId");
String query = sb.toString();
SqlParameterSource parameters = new MapSqlParameterSource("funcId", funcId);
return namedParameterJdbcTemplate.queryForObject(query, parameters, Integer.class);
}
public void insertSwitch(FunctionSwitchEntity functionSwitchEntity) {
String query = "INSERT INTO t_function_switch (accid, functionid, functionswitch,ordernum, createdat, updatedat) " +
"VALUES (:accId, :functionId, :functionSwitch, :ordernum , :createdAt, :updatedAt)";
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("accId", functionSwitchEntity.getAccId())
.addValue("functionId", functionSwitchEntity.getFunctionId())
.addValue("functionSwitch", functionSwitchEntity.getFunctionSwitch())
.addValue("createdAt", functionSwitchEntity.getCreatedAt())
.addValue("ordernum",functionSwitchEntity.getOrderNum() )
.addValue("updatedAt", functionSwitchEntity.getUpdatedAt());
namedParameterJdbcTemplate.update(query, parameters);
}
扩展字段表头dao
ini
@Repository
public class FunctionDao {
@Resource(name = SaasBusinessDsConfig.SaasBusinessDbJdbcTemplateName)
private JdbcTemplate jdbcTemplate;
@Resource(name = SaasBusinessDsConfig.SaasBusinessDbNamedParameterJdbcTemplateName)
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public void deleteById(long functionId) {
String query = "DELETE FROM t_function WHERE id = :functionId";
SqlParameterSource parameters = new MapSqlParameterSource("functionId", functionId);
namedParameterJdbcTemplate.update(query, parameters);
}
public void insert(FunctionEntity functionEntity) {
String query = "INSERT INTO t_function (id ,functiontype, functionmain, functionname, isnewfunc, createdat, updatedat) " +
"VALUES (:id,:functionType, :functionMain, :functionName, :isNewFunc, :createdAt, :updatedAt)";
Map<String, Object> parameters = new HashMap<>();
parameters.put("id",functionEntity.getId() );
parameters.put("functionType", functionEntity.getFunctionType());
parameters.put("functionMain", functionEntity.getFunctionMain());
parameters.put("functionName", functionEntity.getFunctionName());
parameters.put("isNewFunc", functionEntity.getIsnewfunc());
parameters.put("createdAt", functionEntity.getCreatedAt());
parameters.put("updatedAt", functionEntity.getUpdatedAt());
namedParameterJdbcTemplate.update(query, parameters);
}
public List<FunctionEntity> selectByType(long funcType) {
String query = "SELECT * FROM t_function WHERE functiontype = :funcType";
SqlParameterSource parameters = new MapSqlParameterSource("funcType", funcType);
RowMapper<FunctionEntity> rowMapper = new BeanPropertyRowMapper<>(FunctionEntity.class);
return namedParameterJdbcTemplate.query(query, parameters, rowMapper);
}
public FunctionEntity selectById(long id) {
String query = "SELECT * FROM t_function WHERE id = :id";
SqlParameterSource parameters = new MapSqlParameterSource("id", id);
RowMapper<FunctionEntity> rowMapper = new BeanPropertyRowMapper<>(FunctionEntity.class);
List<FunctionEntity> query1 = namedParameterJdbcTemplate.query(query, parameters, rowMapper);
if (query1==null|| query1.isEmpty()){
return null;
}
return query1.get(0);
}
public int updateHeaderName(FunctionEntity functionEntity) {
String query = "UPDATE t_function SET functionname = :functionName ,updatedAt= :updatedAt WHERE id = :id";
Map<String, Object> parameters = new HashMap<>();
parameters.put("functionName", functionEntity.getFunctionName());
parameters.put("id", functionEntity.getId());
parameters.put("updatedAt", functionEntity.getUpdatedAt());
return namedParameterJdbcTemplate.update(query, parameters);
}
}
使用HashMap 解决扩展字段业务实现
scss
@Service
public class FunctionSwitchService {
@Resource
private FunctionSwitchDao functionSwitchDao;
@Resource
private FunctionDao functionDao;
@Resource
private ExtendDao extendDao;
public List<FunctionSwitchDto> getFuncList(long accId, long funcType) {
List<FunctionSwitchDto> functionList = functionSwitchDao.getFunctionList(accId, funcType);
if ((functionList == null || functionList.isEmpty())) {
int num = 0;
List<FunctionEntity> functionEntities = functionDao.selectByType(funcType);
for (FunctionEntity functionEntity : functionEntities) {
FunctionSwitchReq functionSwitchReq = new FunctionSwitchReq();
functionSwitchReq.setFunctionmain(functionEntity.getFunctionMain());
functionSwitchReq.setFunctionname(functionEntity.getFunctionName());
functionSwitchReq.setFunctionswitch(1);
functionSwitchReq.setOrderNum(num);
functionSwitchReq.setId(functionEntity.getId());
insertSwitch(accId, (List<FunctionSwitchReq>) functionSwitchReq);
num++;
}
functionList = functionSwitchDao.getFunctionList(accId, funcType);
}
return functionList;
}
//用户进行开关操作
public List<FunctionSwitchDto> updateSwitch(long accId, long id, long funcType, int functionswitch) {
functionSwitchDao.PassupdateSwitch(accId, id, functionswitch);
List<FunctionSwitchDto> functionList = functionSwitchDao.getFunctionList(accId, funcType);
return functionList;
}
public List<FunctionSwitchDto> insertSwitch(long accId, List<FunctionSwitchReq> functionSwitchReqs) {
for (FunctionSwitchReq functionSwitchReq : functionSwitchReqs) {
FunctionEntity functionEntity = new FunctionEntity();
FunctionSwitchEntity functionSwitchEntity = new FunctionSwitchEntity();
BeanUtils.copyProperties(functionSwitchReq, functionEntity);
BeanUtils.copyProperties(functionSwitchReq, functionSwitchEntity);
functionEntity.setFunctionMain(functionSwitchReq.getFunctionmain() == null ? functionSwitchReq.getFunctionname() : " ");
functionEntity.setFunctionName(functionSwitchReq.getFunctionname());
functionEntity.setCreatedAt(LocalDateTime.now());
functionEntity.setId(functionSwitchReq.getId());
functionEntity.setUpdatedAt(LocalDateTime.now());
functionSwitchEntity.setId(null);
functionSwitchEntity.setFunctionId(functionSwitchReq.getId());
if (functionSwitchReq.getIsnew() != null && !functionSwitchReq.getIsnew().equals(0)) {
functionEntity.setIsnewfunc(1);
long l = UUIDUtils.generateUUID();
functionSwitchEntity.setFunctionId(l);
functionEntity.setFunctionType(functionSwitchReq.getFunctiontype());
functionEntity.setId(l);
functionDao.insert(functionEntity);
}
functionSwitchEntity.setOrderNum(functionSwitchReq.getOrderNum() == null ? 0 : functionSwitchReq.getOrderNum());
functionSwitchEntity.setAccId(accId);
functionSwitchEntity.setFunctionSwitch(functionSwitchReq.getFunctionswitch());
functionSwitchEntity.setCreatedAt(LocalDateTime.now());
functionSwitchEntity.setUpdatedAt(LocalDateTime.now());
functionSwitchDao.insertSwitch(functionSwitchEntity);
}
return functionSwitchDao.getFunctionList(accId, functionSwitchReqs.get(0).getFunctiontype());
}
public void deleteSwitch(long accId, long id, long functionid) {
FunctionEntity functionEntity = functionDao.selectById(functionid);
if (functionEntity.getIsnewfunc() == 0) {
new BussConstrainException("系统功能不能删除");
}
functionSwitchDao.deleteAccid(accId, id);
if (functionSwitchDao.funcidCount(functionid) <= 0) {
functionDao.deleteById(functionid);
}
}
//也要根据状态进行查询,我根据列查询就不用使用
public List<ExtendEntity> getFuncTableExtend(long accId, TableIdReq tableIdReq) {
List<ExtendEntity> extendEntities = extendDao.getTableextend(accId, tableIdReq);
return extendEntities;
}
public List<FunctionSwitchDto> updateTableHeader(long accId, TableHeaderReq tableHeaderReq) {
FunctionEntity functionEntity = functionDao.selectById(tableHeaderReq.getFunctionid());
if (functionEntity == null) {
throw new BussConstrainException("id不存在");
}
if (functionEntity.getIsnewfunc().equals(0)) {
throw new BussConstrainException("系统功能不能修改");
}
functionEntity.setUpdatedAt(LocalDateTime.now());
functionEntity.setFunctionName(tableHeaderReq.getFunctionname());
functionDao.updateHeaderName(functionEntity);
return functionSwitchDao.getFunctionList(accId, tableHeaderReq.getFunctiontype());
}
public int addTableData(long accId, List<TableIdDataReq> tableIdReqs) {
int i = 0;
for (TableIdDataReq tableIdReq :
tableIdReqs) {
if (extendDao.getSelectTable(accId, tableIdReq) != null) {
i += extendDao.updateTableData(accId, tableIdReq);
} else {
i += extendDao.addTableData(accId, tableIdReq);
}
}
return i;
}
public int updateTableData(long accId, TableIdDataReq tableIdReq) {
return extendDao.updateTableData(accId, tableIdReq);
}
/**
* @param accId 商家id
* @param userId 用户id
* @param aggregateQuery 商家传递参数
* @return
*/
public Map<Long, Map<Long, ExtendEntity>> getDataColums(long accId, long userId, TableIdReq aggregateQuery) {
List<FunctionSwitchDto> funcList = this.getFuncList(accId, aggregateQuery.getFuncType());
List<FunctionSwitchDto> collect = funcList.stream()
.filter(dto -> dto.getIsnewfunc() == 1)
.collect(Collectors.toList());
List<Long> functionIds = collect.stream()
.map(FunctionSwitchDto::getFunctionid)
.collect(Collectors.toList());
//比如有三列 他查询出来的是三列的数据
List<ExtendEntity> extendTable = getFuncTableExtend(accId, new TableIdReq(functionIds, aggregateQuery.getObjectId()));
Map<Long, List<ExtendEntity>> extendMap = extendTable.stream().collect(Collectors.groupingBy(k -> k.getObjectId()));
Map<Long, List<ExtendEntity>> resultMap =
extendTable.stream()
.collect(Collectors.groupingBy(ExtendEntity::getFuncId));
Map<Long, Map<Long, ExtendEntity>> newMap = resultMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
.collect(Collectors.toMap(ExtendEntity::getObjectId, entity -> entity))
));
return newMap;
}
public List<ExtendVo> getGoodsIdColumn(long accId, long goodsId) {
return extendDao.getGoodsIdColomn(accId,goodsId );
}
}
搜索引擎中添加扩展字段
当商品 进行存储的时候,远程调用拿到对应的行数据,将所有的map结构, 塞入到商品对应的行
上周工作总结:
同步数据库全自动化数据迁移 功能已全部完成 ,等待导师切换sqlserver 业务支持pgsql,同步任务。预计半个月后完成全部迁移任务。
编写同步数据业务,采用反射,流,算法思维,等技术,实现自动化导出数据库表功能,生成自定义数据库表格,自定义entity,大部分数据库都能正常导出数据,自动插入到新的数据库。