(续前文)
8、Service实现类
Service实现类提供Service接口类的代码实现,Service实现类的命名为XXXManServiceImpl。
Service实现类完成CRUD的核心处理代码,CRUD的不同方法,有各自常规的处理流程。
8.1、新增单个对象
新增单个对象的方法名为addItem,处理流程如下:
// 新增对象
public Map<String,Object> addItem(HttpServletRequest request, XXX item);
step1、参数校验,检查必选字段是否都已赋值。考虑到类对象item的各个属性都有默认值,"赋值"这个概念需要重新定义,此处定义如下:
1)值为null,表示未赋值;
2)如果对象值为默认值,且默认值为无效值,如空串或0,则表示未赋值;
3)如果对象值为默认值,且默认值为有效值,如枚举值,则表示已赋值;
4)如果对象值不为默认值,表示已赋值。
实际上,参数校验工作还有很多,如值范围,手机号码格式,email格式,字符串是否为指定形式的有效字符串等,取决于投入产出比,是否需要,视业务需求而定。
step2、外键ID的有效性,如存在外键ID,则需检查参照的外键对象需要存在。
step3、数据权限检查,如对象涉及数据权限,需检查操作者有新增此记录的权限。如用户数据权限中orgId为2,但新增用户数据时,orgId为3,不在操作者的权限范围内,因此无权新增此记录。
step4、枚举值检查,如存在枚举值字段,则需要检查值的有效性,如userType,取值范围为1,2,3,则其它值无效。
step5、唯一字段值检查。新增对象时,往往涉及唯一字段,如对象名称,要求唯一;还要如准唯一字段,如新增用户时,手机号码、证件号码等,如数据库中已存在此唯一值,则抛出异常。
step6、字段业务处理。某些对象新增时,需要进行业务处理,如新增用户对象时,针对前端传入的密码,内部生成salt字段,然后进行加盐MD5,二次加密,生成数据库存储需要的密码。
step7、根据request对象,获取操作者账号信息,并设置对象。
step8、如果ID为全局ID,则需要获取全局ID,并设置对象。
step9、调用Dao的insertItem方法,新增记录。如果涉及数据一致性问题,也一并处理。
step10、如果涉及缓存(如树型结构对象),则刷新缓存。
step11、如果ID为自增ID或全局ID,则构造返回值字典,key为ID属性名,值为ID值。
8.2、批量新增对象
批量新增对象的方法名为addItems,处理流程如下:
// 批量新增对象
public Map<String,Object> addItems(HttpServletRequest request, List<XXX> itemList);
step1、参数校验。针对itemList中的每一项,进行如addItem方法的参数校验。
step2、如果itemList无成员,则返回。
step3、如果要求某个属性值必须为同一个值,则进行检查。如批量新增用户,要求orgId都为同一个值。
step4、针对itemList中的每一项,检查外键ID的有效性,数据权限,枚举值有效性,唯一字段值的唯一性,以及可能的业务处理。
step5、如为全局ID,则批量申请ID。
step6、根据request对象,获取操作者账号信息。
step7、针对itemList中的每一项,设置ID和操作者账号信息。
step8、调用Dao的insertItems方法,新增记录。如果涉及数据一致性问题,也一并处理。
step9、如果涉及缓存(如树型结构对象),则刷新缓存。
step10、如果ID为自增ID或全局ID,则构造返回值字典,key为ID属性名,值为ID值。
8.3、编辑对象
编辑对象的方法名为editItem,处理流程如下:
// 编辑对象
public void editItem(HttpServletRequest request, Map<String, Object> params);
step1、参数校验,必须包含key属性字段参数;参数格式检查,如日期格式。
step2、根据key值,获取数据库中存在对象,如果对象不存在,则抛出异常。
step3、数据权限检查,操作者有编辑此存在对象的数据权限。如果数据权限相关字段允许修改,且有新值,则新值也需要检查数据权限。
step4、如果涉及外键ID值的修改,则检查参照的外键对象的存在性。
step5、如果涉及枚举值的修改,则检查枚举值的有效性。
step6、如果涉及唯一值属性的修改,则检查唯一值的有效性。
step7、移除可能存在的不可编辑项,这是为了防止params中携带了不可编辑的参数项,有点类似于"注入"的情形。
step8、根据request对象,获取操作者账号信息。
step9、调用Dao的updateByKey方法,修改记录。如果涉及数据一致性问题,也一并处理。
step10、如果涉及缓存,则刷新缓存。
8.4、批量修改对象
批量修改对象的方法名为updateItems,处理流程如下:
// 批量修改对象
public void updateItems(HttpServletRequest request, Map<String, Object> params);
step1、参数校验,必须包含至少一个修改字段参数和一个条件字段参数。
step2、增加数据权限范围,确保只修改权限许可的数据。
step3、如果涉及外键ID值的修改,则检查参照的外键对象的存在性。
step4、如果涉及枚举值的修改,则检查枚举值的有效性。
step5、如果涉及唯一值属性的修改,则检查唯一值的有效性。
step6、根据request对象,获取操作者账号信息。
step7、调用Dao的updateItems方法,批量修改记录。如果涉及数据一致性问题,也一并处理。
step8、如果涉及缓存,则刷新缓存。
8.5、删除对象
删除对象的方法名为deleteItem,如果为逻辑删除,则为禁用/启用。如为物理删除,则为删除。处理流程如下:
// 删除对象
public void deleteItem(HttpServletRequest request, Map<String, Object> params);
step1、参数校验,必须包含key字段参数。
step2、根据key值,获取数据库中存在对象,如果对象不存在,则抛出异常。
step3、数据权限检查,操作者有删除或修改此存在对象的数据权限。
step4、如为逻辑删除,获取deleteFlag参数,默认为删除。如果为启用,需要检查启用对象的唯一值是否存在冲突。因为对象被禁用后,相当于释放了一个唯一值;现在启用,就可能发生唯一值冲突的情况。逻辑删除,调用Dao的updateByKey方法,修改deleteFlag字段值,因此,还需要设置操作者账号信息。
step5、如为物理删除,调用Dao的deleteByKey方法。
step6、如果涉及缓存,则刷新缓存。
8.6、批量删除对象
批量删除对象的方法名为deleteItems,只支持物理删除。处理流程如下:
// 批量删除对象
public void deleteItems(HttpServletRequest request, Map<String, Object> params);
step1、参数校验,必须包含至少一个条件参数。
step2、增加数据权限范围,确保只删除权限许可的数据。
step3、调用Dao的deleteItems方法。
step4、如果涉及缓存,则刷新缓存。
8.7、根据key查询对象
根据key查询对象的方法名为getItem。处理流程如下:
// 根据key获取一个XXX对象
public XXX getItem(HttpServletRequest request, Map<String, Object> params)
step1、参数校验,必须包含key字段参数。
step2、调用Dao的selectItemByKey方法,获取对象。
step3、检查数据权限,是否在权限许可范围。
step4、如果涉及外键引用字段赋值,则针对查询结果对象,设置相关值。
step5、返回对象。
8.8、分页查询对象
分页查询对象的方法名为queryItems。处理流程如下:
// 分页查询对象
public PageInfo<XXX> queryItems(HttpServletRequest request, Map<String, Object> params);
step1、增加数据权限范围,确保只查询权限许可的数据。如果查询条件参数包含了权限相关字段列表,则取交集。
step2、调用PageHelper.startPage,启动分页查询。
step3、调用Dao的selectItems方法。
step4、如果涉及外键引用字段赋值,则针对查询结果集的每一个对象,设置相关值。
step5、返回分页对象。
8.9、查询对象列表
查询对象列表的方法名为getItems。处理流程如下:
// 查询对象列表
public List<XXX> getItems(HttpServletRequest request, Map<String, Object> params);
step1、增加数据权限范围,确保只查询权限许可的数据。如果查询条件参数包含了权限相关字段列表,则取交集。
step2、调用Dao的selectItems方法。
step3、如果涉及外键引用字段赋值,则针对查询结果集的每一个对象,设置相关值。
step4、返回对象对象。
8.10、新增或修改对象
新增或修改对象的方法名为FlushItem。处理流程如下:
// 新增或修改对象
public void flushItem(HttpServletRequest request,XXX item);
step1、获取唯一键字段值,或准唯一字段,查询数据库中是否存在对应的对象。
step2、如对象不存在,则调用addItem方法新增。
step3、如对象已存在,则先设置key值,然后调用editItem方法修改。
8.11、导出Excel文件
导出Excel文件的方法名为exportExcelFile。处理流程如下:
// 导出Excel文件
public void exportExcelFile(HttpServletRequest request,HttpServletResponse response,
Map<String,Object> params);
step1、查询条件增加数据权限范围,确保只查询权限许可的数据。如果查询条件参数包含了权限相关字段列表,则取交集。
step2、调用Dao的deleteItems方法,查询数据。如果涉及外键引用字段赋值,则针对查询结果集的每一个对象,设置相关值。
step3、使用Excel导出处理框架,实现Excel数据导出。先定义导出字段列表。
step4、导出类为BaseExportObj,负责将对象列表转为List<String[]>类型的表格数据dataRowList。
step5、如果涉及枚举字段翻译,对dataRowList进行翻译处理。
step6、使用ExcelExportHandler类,将dataRowList写入Excel文件。
step7、调用download公共方法,实现文件下载。
8.12、导入Excel文件
导入Excel文件的方法名为importExcelFile。分为常规导入和异步导入。
8.12.1、常规导入处理
常规处理流程如下:
// 导入Excel文件
public List<String> importExcelFile(HttpServletRequest request,
MultipartFile upfile, Map<String, Object> params);
step1、如果导入对象涉及数据权限,则参数一般需要包含数据权限相关字段值;否则如果数据权限字段在Excel文件中某列,处理会变得复杂,此时,一般简单规定有全部数据权限的操作者方允许操作。
step2、参数校验,必选字段是否包含。
step3、数据权限检查。
step4、使用Excel导入处理框架,实现Excel数据导人。先定义导入字段列表,确定必选标题列。此框架不要求列序号固定。
step5、使用ExcelImportHandler类,将Excel数据读入到List<String[]>类型的dataRows中。如果必选列有缺失,则返回异常信息。
step6、如果涉及枚举字段翻译,对dataRows进行翻译处理。
step7、导入类为BaseImportObj,负责将List<String[]>类型的表格数据转为对象列表。
step8、处理对象列表的入库。
step9、对象列表的入库,有以下策略可选择:
1)常规处理:如果对象存在,则修改;否则新增。这种策略为逐条处理,性能不高。
2)自适应批量入库:先尝试批量新增,遇到异常,则缩小批量,如果为批量为1,且新增仍然失败,意味着此记录异常,加入异常列表。继续新增处理,如果成功,则扩大批量。参见:[https://www.cnblogs.com/alabo1999/p/15828334.html](一种基于二分法的变步长批量处理算法)。这种策略以新增为主,并允许有少量异常记录。
step10、导入完成,返回异常记录列表。此时,正常数据已完成导入,未导入的异常数据有行号信息。
8.12.2、异步导入处理
异步导入处理,使用异步处理框架。异步处理框架是一个通用的异步处理框架。处理逻辑:前端提交任务,获取任务ID,然后根据这个任务ID进行轮询,获取任务处理信息和任务处理结果。后端使用异步处理方式,调用异步处理方法进行处理,完成后保存处理结果一段时间(默认30s),然后释放处理结果。参见:[https://www.cnblogs.com/alabo1999/p/16607827.html](Spring Boot异步请求处理框架)
由于异常处理方法,被反射调用,因此必须是public的方法。
处理流程如下:
// 异步导入Excel文件
public Map<String, Object> importExcelFile(HttpServletRequest request,
MultipartFile upfile, Map<String, Object> params);
step1、参数校验,必选字段是否包含。
step2、数据权限检查。
step3、访问upfile参数,获取文件名和输入流InputStream。
step4、根据request对象,获取操作者账号信息。
step5、构造异步调用的参数集,为文件名,输入流和操作者账号信息。
step6、获取异步处理方法asyncImpProc的Method对象。
step7、调用异步处理的任务管理器的addTask方法,添加异步处理任务,并获取任务ID。
step8、返回任务ID信息。
// 异常导入处理方法:asyncImpProc
public void asyncImpProc(TaskInfo taskInfo);
step1、TaskInfo为任务信息对象,包含了提交任务时的参数集。
step2、使用Excel导入处理框架,实现Excel数据导人。
step3、使用ExcelImportHandler类,将Excel数据读入到List<String[]>类型的dataRows中。如果必选列有缺失,则返回异常信息。
step4、如果涉及枚举字段翻译,对dataRows进行翻译处理。
step5、导入类为BaseImportObj,负责将List<String[]>类型的表格数据转为对象列表。
step6、处理对象列表的入库。有以下处理策略:
1)常规处理:单线程处理,不管是逐条处理,还是分批处理,是在一个线程中逐步处理。
2)多线程处理:可以开启临时线程池或利于已配置的线程池,进行多线程处理,最后通过List<CompletableFuture<List<String>>>合并异常记录列表。
step7、处理过程中可以输出处理日志,以及进度百分比。
step8、任务信息taskInfo,设置异常记录列表作为处理结果。
// 获取导入处理信息:
public Map<String, Object> getImpProcInfo(HttpServletRequest request,Map<String, Object> params);
step1、参数校验,必须包含taskId参数。
step2、根据taskId,从任务管理器中获取任务信息taskInfo。
step3、如果任务信息不存在或已过期,则抛出异常。
step4、如果任务信息有效,则构造并返回输出信息,一般为任务ID、处理状态、进度、提示消息、日志列表、处理结果。
8.13、相关的公共服务和方法
根据前面CRUD的常规方法的处理流程,可以看出需要一些公共的服务和方法,以免不同对象的CRUD重复开发。
8.13.1、服务基类BaseService
BaseService类,提供参数校验接口、启动分页处理和获取用户账号信息的公共方法
/**
*
* @methodName : checkValidForParams
* @description : 输入参数校验,子类根据需要重载此方法
* @param request : request对象
* @param methodName: 方法名称
* @param params : 输入参数
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public void checkValidForParams(HttpServletRequest request,String methodName, Object params) {
}
/**
*
* @methodName : processPageInfo
* @description : 处理分页信息
* @param params : 包含分页信息的map
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public void processPageInfo(Map<String,Object> params) {
// 分页处理
Integer pageNum = (Integer)params.get("pagenum");
if(Objects.isNull(pageNum)) {
pageNum = 1;
}
Integer pageSize = (Integer)params.get("pagesize");
if(Objects.isNull(pageSize)) {
pageSize = 10;
}
PageHelper.startPage(pageNum, pageSize);
}
/**
*
* @methodName : getUserName
* @description : 获取访问账户的用户名
* @param request : request对象
* @return : 访问账户的用户名
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public String getUserName(HttpServletRequest request) {
String userName = "";
if (request == null) {
return userName;
}
// 获取accountId
String accountId = accountCacheService.getId(request);
// 获取用户名
Object userNameObj = accountCacheService.getAttribute(accountId, Constants.USER_NAME);
if (userNameObj != null) {
userName = (String)userNameObj;
}else {
// 说明此时accountId无效,或属性"userName"未注册
return "";
}
return userName;
}
accountCacheService对象是自动注入的AccountCacheService类对象,AccountCacheService是类似于Session管理的类,用于管理账号缓存信息。在跨域服务时,SessionId可能经常发生改变,导致无法定位前端。此时可以通过添加名为x-SessionId的Header参数,根据x-SessionId来定位前端。另外,多机部署时,使用Session,需要Session共享,不如用Redis。AccountCacheService类可以方便用于Redis。
8.13.2、数据权限服务
数据权限服务DataRightsService类,提供数据权限服务的相关方法,包括获取当前用户的各个权限字段的权限类型、权限范围,检查某个权限字段值是否有权限等。
8.13.3、外键ID有效性检查
外键ID的对象是否存在,这个涉及全部对象类型。使用集中式的ID检查类IdCheckService。
先使用枚举类型EIdType定义各种ID,示例代码如下(可以继续添加业务涉及的各种ID):
public enum EIdType {
userId (1,"userId"),
funcId (2,"funcId"),
roleId (3,"roleId"),
drFieldId (4,"fieldId"),
orgId (5,"orgId"),
; // 结束定义
// 枚举值对应的code值
int code;
// 名称
String name;
// 构造函数
private EIdType(int code,String name) {
this.code = code;
this.name = name;
}
// 属性code的getter方法
public int getCode() {
return code;
}
// 属性code的setter方法
public void setCode(int code) {
this.code = code;
}
// name的getter/setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
*
* @methodName : getType
* @description : 根据code获取枚举值
* @param code : code值
* @return : code对应的枚举值
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public static EIdType getType(int code) {
// 返回值变量
EIdType eRet = null;
for (EIdType item : values()) {
// 遍历每个枚举值
if (code == item.getCode()) {
// code匹配
eRet = item;
break;
}
}
return eRet;
}
IdCheckService接口类,提供一个方法,代码如下:
public interface IdCheckService {
/**
*
* @methodName : getObjById
* @description : 检查对象ID的有效性,如果有效则返回对象,如果无效,则抛出异常
* @param eIdType : ID枚举类型
* @param id : ID的值
* @param params : 可选参数,适用于多个key字段的对象
* @return : ID对应的对象
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* yyyy/mm/dd 1.0.0 author 初版
*
*/
public Object getObjById(EIdType eIdType,Object id,Object...params);
}
IdCheckService实现类,示例代码如下:
@Service
public class IdCheckServiceImpl implements IdCheckService{
@Autowired
private UserDao userDao;
// 缓存数据服务类对象
@Autowired
private CacheDataService cds;
// 公共配置数据服务类对象
@Autowired
private GlobalConfigService gcs;
/**
*
* @methodName : getObjById
* @description : 检查对象ID的有效性,如果有效则返回对象,如果无效,则抛出异常
* @remark : 参见接口类相应方法说明
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2023/04/08 1.0.0 sheng.zheng 初版
*
*/
@Override
public Object getObjById(EIdType eIdType,Object id,Object...params) {
Object item = null;
try {
switch(eIdType) {
case userId:
{
item = userDao.selectItemByKey((Long)id);
}
break;
case orgId:
{
OrgnizationService os = (OrgnizationService)gcs.getDataServiceObject("OrgnizationService");
item = os.getItemByKey((Integer)id, false);
}
break;
default:
break;
}
}catch(Exception e) {
LogUtil.error(e);
throw new BaseException(ExceptionCodes.ERROR,e.getMessage());
}
if (item == null) {
throw new BaseException(ExceptionCodes.OBJECT_DOES_NOT_EXIST,
eIdType.getName() + "=" + id);
}
return item;
}
}
各种对象,根据key值获取的方法可以不同,如直接查询数据库,或通过缓存获取等,具体实现方法,不同系统可以有不同的处理。
8.13.4、枚举值有效性检查
为了方便枚举值检查,所有枚举值都加一个getTypeByCode接口。下面是示例代码:
public enum EOrgType {
otOurCompanyE (1,"本公司"),
otCustomE (2,"客户公司"),
; // 结束定义
// 枚举值对应的code值
int code;
// 描述
String desc;
// 构造函数
private EOrgType(int code,String desc) {
this.code = code;
this.desc = desc;
}
// 属性code的getter方法
public int getCode() {
return code;
}
// 属性code的setter方法
public void setCode(int code) {
this.code = code;
}
// desc的getter/setter方法
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
/**
*
* @methodName : getType
* @description : 根据code获取枚举值
* @param code : code值
* @return : code对应的枚举值
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2023/05/17 1.0.0 sheng.zheng 初版
*
*/
public static EOrgType getType(int code) {
// 返回值变量
EOrgType eRet = null;
for (EOrgType item : values()) {
// 遍历每个枚举值
if (code == item.getCode()) {
// code匹配
eRet = item;
break;
}
}
return eRet;
}
// 检查并获取指定code的枚举值
public static EOrgType getTypeByCode(int code) {
EOrgType item = getType(code);
if (item == null) {
throw new BaseException(ExceptionCodes.INVALID_ENUM_VALUE,"EOrgType with code="+code);
}
return item;
}
8.13.5、缓存管理
缓存用于频繁访问的对象,使用缓存,可以减少数据库IO的开销,提升系统处理性能。
缓存要解决数据一致性问题。对于单机部署的系统,可以使用内存;对于多机部署的系统,需要使用Redis来实现缓存数据的一致性。但是还需要解决数据库与缓存数据一致性的问题。
另外,缓存数据还有生命周期,超过一定时间未访问的数据,可以移除,以避免内存需求无限扩大。
缓存一般使用字典管理对象,很少使用全集数据,因为维持全集数据的代价比较大,如增加、修改、删除一个对象都需要重新加载全部数据。
使用字典,修改和删除对象,直接移除此对象;增加对象时,新对象可以不必加入缓存。当需要根据key获取某个对象时,如果缓存中存在,则直接返回缓存对象;如果缓存中不存在,则查询数据库,如果查询到,则加入缓存并返回对象;如果查询不到,则加入空对象(确保短期内不再根据失败的key去查询数据库)。对于Redis,直接使用一个大字典,性能不高,可以针对不同的字典,加对象类别key,然后拆散字典。
使用全集(如列表或树对象),可以设置对象全集的修改标记,任何对象发生改变时,设置修改标记为true,但不立即加载全部数据。当请求全集数据时,检查修改标记,如为true,则重新加载全集数据,并复位修改标记。如修改标记为false,则直接返回缓存中的全集。
每次访问缓存对象,需要更新对象的最近访问时间,从而根据访问热度,移除过期(未访问的)缓存数据。 Redis可以直接使用生命期管理,也可以用此方法代码管理。
为了便于缓存对象管理,使用下列CacheObj,来封装缓存对象。
@Data
public class CacheObj<T> {
// 缓存对象
private T itemObj;
// 最后访问时间,UTC
private long lastAccTime = 0;
// 到期时间,UTC
private long expiredTime = 0;
// 最后查询数据库时间,UTC
private long lastQueryTime = 0;
/**
*
* @methodName : resetLastAccTime
* @description : 重置最后访问时间,同时更新到期时间
* @param accTime : 访问时间
* @param interval : 到期时间间隔
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2022/06/04 1.0.0 sheng.zheng 初版
*
*/
public void resetLastAccTime(long accTime,long interval) {
lastAccTime = accTime;
expiredTime = accTime + interval;
}
// 是否到期
public boolean isExpired() {
return (lastAccTime >= expiredTime);
}
// 是否到期
public boolean isExpired(long current) {
return (current >= expiredTime);
}
// 是否可以查询
public boolean canQuery(long current,long interval) {
return (current >= lastQueryTime + interval);
}
}
缓存对象的管理示例如下:
// 组织缓存对象,key为orgId
Map<Integer,CacheObj<Orgnization>> orgMap = new HashMap<Integer,CacheObj<Orgnization>>();
8.13.6、Excel导入导出处理
Excel导入导出框架的包括下列类:
ImpExpFieldDef:导入导出字段定义;
BaseExportObj:数据导出基类;
ExcelExportHandler:Excel导出处理类;
BaseImportObj:导入对象基类;
ExcelImportHandler:Excel文件导入处理类;
8.13.7、公共方法
常用的方法有:
/**
*
* @methodName : checkKeyFields
* @description : 检查关键字段是否缺失
* @param params : 输入参数
* @param fieldNames: 关键字段名
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public static void checkKeyFields(Map<String,Object> params,String[] fieldNames) {
for(int i = 0; i < fieldNames.length; i++) {
String fieldName = fieldNames[i];
if (!params.containsKey(fieldName)) {
String prompt = ",缺失字段:" + fieldName;
throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR.getCode(),
ExceptionCodes.ARGUMENTS_ERROR.getMessage() + prompt);
}
}
}
/**
*
* @methodName : checkOpKeyFields
* @description : 检查可选关键字段是否存在
* @param params : 输入参数
* @param fieldNames: 关键字段名
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public static void checkOpKeyFields(Map<String,Object> params,String[] fieldNames) {
boolean bFound = false;
String prompt = ",缺失可选字段:";
for(int i = 0; i < fieldNames.length; i++) {
String fieldName = fieldNames[i];
if (params.containsKey(fieldName)) {
bFound = true;
break;
}
if (i != 0) {
prompt += ",";
}
prompt += fieldName;
}
if (!bFound) {
throw new BaseException(ExceptionCodes.ARGUMENTS_ERROR.getCode(),
ExceptionCodes.ARGUMENTS_ERROR.getMessage() + prompt);
}
}
/**
*
* @methodName : removeKeys
* @description : 根据指定key数组,移除字典对应key的项
* @param params : Map<String,Object>类型的字典
* @param keys : 需要移除的key数组
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public static void removeKeys(Map<String,Object> params,String[] keys) {
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
if (params.containsKey(key)) {
params.remove(key);
}
}
}
/**
*
* @methodName : download
* @description : 下载指定路径的文件
* @param response : reponse对象
* @param filePath : 需要下载的文件路径
* @param filename : 下载文件的文件名
* @param contentType : response header中的ContentType,常用取值如下:
* 普通二进制文件 : application/octet-stream
* Excel文件 : application/vnd.ms-excel
* 文本文件 : text/plain; charset=utf-8
* html文件 : text/html; charset=utf-8
* xml文件 : text/xml; charset=utf-8
* jpeg文件 : image/jpeg
* @throws Exception : 异常发生时,抛出。没有异常,说明下载成功。
* @history :
* ------------------------------------------------------------------------------
* date version modifier remarks
* ------------------------------------------------------------------------------
* 2021/01/01 1.0.0 sheng.zheng 初版
*
*/
public static void download(HttpServletResponse response,String filePath,
String filename,String contentType) throws Exception;
详细代码见[https://gitee.com/shengzheng1999/esb-common/tree/master/src/main/java/com/abc/esbcommon/common/utils]。
(未完待续...)
标签:code,对象,Spring,CRUD,ID,处理,params,Boot,public From: https://www.cnblogs.com/alabo1999/p/17483885.html