package com.iplatform.base; import com.iplatform.base.cache.DictCacheProvider; import com.iplatform.base.di.PlatformDataImportEngine; import com.iplatform.base.di.TemplateInfo; import com.iplatform.base.service.DeptServiceImpl; import com.iplatform.base.service.LogServiceImpl; import com.iplatform.base.service.UserServiceImpl; import com.iplatform.base.support.strategy.LoginStrategyManager; import com.iplatform.base.util.MenuUtils; import com.iplatform.core.BeanContextAware; import com.iplatform.model.po.S_dept; import com.iplatform.model.po.S_dict_data; import com.iplatform.model.po.S_oper_log; import com.iplatform.model.po.S_user_core; import com.iplatform.model.po.S_user_login; import com.walker.cache.CacheProvider; import com.walker.infrastructure.utils.DateUtils; import com.walker.infrastructure.utils.FileCopyUtils; import com.walker.infrastructure.utils.NumberGenerator; import com.walker.infrastructure.utils.PhoneNumberUtils; import com.walker.infrastructure.utils.StringUtils; import com.walker.push.PushManager; import com.walker.web.CaptchaProvider; import com.walker.web.CaptchaResult; import com.walker.web.OrgType; import com.walker.web.ResponseCode; import com.walker.web.UserOnlineProvider; import com.walker.web.UserPrincipal; import com.walker.web.UserType; import com.walker.web.WebAgentService; import com.walker.web.WebUserAgent; import com.walker.web.log.BusinessType; import com.walker.web.log.OperateUser; import com.walker.web.util.IdUtils; import com.walker.web.util.ServletUtils; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimerTask; /** * 系统控制器对象,业务所有 Controller 对象,都要继承该对象。 * @author 时克英 * @date 2022-12-01 */ public abstract class SystemController extends AbstractFileOperateSpiController{ /** * 更新给定用户登录缓存中的角色集合内容,roleIds。 *
     *     1) 当用户变更角色后,可以直接刷新界面(重新请求用户信息)获取新的对应菜单权限。
     * 
* @param userId 用户ID * @author 时克英 * @date 2023-12-28 */ protected void updateLoginUserRoleListInCache(Long userId){ S_user_core userCore = this.getUser(userId); if(userCore == null){ throw new PlatformRuntimeException("缓存中未查找到用户,这不正常,userId = " + userId, null); } S_user_login userLogin = this.getLoginStrategyManager().getUserLogin(userCore.getUser_name()); if(userLogin == null){ if(this.logger.isDebugEnabled()){ this.logger.debug("用户:{}不存在登录缓存,无需更新角色(roleId)缓存,userName={}", userId, userCore.getUser_name()); } return; } UserPrincipal existUserPrincipal = BeanContextAware.getBeanByType(UserOnlineProvider.class).getUserPrincipal(userLogin.getUuid()); List existRoleIdList = existUserPrincipal.getRoleIdList(); List roleIdList = this.getUserService().queryUserRoleIdList(userId); if(this.logger.isDebugEnabled()){ this.logger.debug("给定用户:{},包含的角色:{}", userId, roleIdList); } if(StringUtils.isEmptyList(roleIdList)){ roleIdList = new ArrayList<>(4); } // 把原来用户已有的系统级权限角色重新写入,否则用户会重新让登录 if(existRoleIdList != null){ for(String securityRoleName : existRoleIdList){ if(securityRoleName.equals(SecurityConstants.ROLE_USER) || securityRoleName.equals(SecurityConstants.ROLE_ADMIN) || securityRoleName.equals(SecurityConstants.ROLE_SUPER_ADMIN) || securityRoleName.equals(SecurityConstants.ROLE_MERCHANT)){ roleIdList.add(securityRoleName); } } } DefaultUserPrincipal userPrincipal = new DefaultUserPrincipal(userCore); userPrincipal.setRoleIdList(roleIdList); // 更新缓存的登录信息 BeanContextAware.getBeanByType(UserOnlineProvider.class).cacheUserPrincipal(userLogin.getUuid(), userPrincipal, VariableConstants.DEFAULT_TOKEN_EXPIRED_MINUTES); } protected UserLoginCache getUserLoginCache(){ return BeanContextAware.getBeanByType(UserLoginCache.class); } /** * 获得通知提醒模板配置缓存。 * @return * @date 2023-08-25 */ protected NotificationTemplateCache getNotificationTemplateCache(){ return BeanContextAware.getBeanByType(NotificationTemplateCache.class); } /** * 写入成功操作日志 * @param userName 当前用户名,可以是登录ID或名字,可选 * @param operateUser 操作用户类型 * @param businessType 业务类型 * @param title 标题描述,可选 * @param input 输入参数,可选 * @param output 输出参数,可选 * @date 2023-08-13 */ protected void systemLogSuccess(String userName, OperateUser operateUser, BusinessType businessType , String title, String input, String output){ S_oper_log s_oper_log = this.acquireSystemLog(userName, operateUser, businessType, title, input, output); AsyncManager.me().execute(new TimerTask() { @Override public void run() { BeanContextAware.getBeanByType(LogServiceImpl.class).execInsertOperateLog(s_oper_log); } }); } /** * 写入错误日志 * @param userName 当前用户名,可以是登录ID或名字,可选 * @param operateUser 操作用户类型,可选 * @param businessType 业务类型,可选 * @param title 标题描述,可选 * @param input 输入参数,可选 * @param error 错误内容,必填 * @date 2023-08-13 */ protected void systemLogError(String userName, OperateUser operateUser, BusinessType businessType, String title, String input, String error){ if(StringUtils.isEmpty(error)){ logger.warn("调用写入错误日志,但未提供错误内容,日志将不会保存:systemLogError --> error is null!"); return; } S_oper_log s_oper_log = this.acquireSystemLog(userName, operateUser, businessType, title, input, null); s_oper_log.setStatus(ResponseCode.ERROR.getCode()); s_oper_log.setError_msg(StringUtils.substring(error, 0, Constants.LOG_ERROR_MAX_SIZE)); AsyncManager.me().execute(new TimerTask() { @Override public void run() { BeanContextAware.getBeanByType(LogServiceImpl.class).execInsertOperateLog(s_oper_log); } }); } private S_oper_log acquireSystemLog(String userName, OperateUser operateUser, BusinessType businessType , String title, String input, String output){ if(operateUser == null){ operateUser = OperateUser.Manage; } if(businessType == null){ businessType = BusinessType.Other; } WebUserAgent agent = this.getCurrentWebUserAgent(); S_oper_log s_oper_log = new S_oper_log(); s_oper_log.setOper_id(NumberGenerator.getLongSequenceNumber()); s_oper_log.setOper_time(DateUtils.getDateTimeNumber()); s_oper_log.setStatus(ResponseCode.SUCCESS.getCode()); s_oper_log.setOper_name(userName); s_oper_log.setOperate_user(operateUser.getIndex()); s_oper_log.setBusiness_type(businessType.getIndex()); s_oper_log.setOper_ip(agent.getIp()); s_oper_log.setOper_location(agent.getLocation()); s_oper_log.setRequest_method(agent.getMethod()); s_oper_log.setOper_url(agent.getUrl()); s_oper_log.setTitle(title); if(StringUtils.isNotEmpty(input)){ s_oper_log.setOper_param(input); } if(StringUtils.isNotEmpty(output)){ s_oper_log.setJson_result(output); } return s_oper_log; } /** * 返回登录策略管理器对象 * @return * @date 2023-08-05 */ protected LoginStrategyManager getLoginStrategyManager(){ return BeanContextAware.getBeanByType(LoginStrategyManager.class); } /** * 返回当前web浏览器代理对象。 * @return * @date 2023-07-25 */ protected WebUserAgent getCurrentWebUserAgent(){ HttpServletRequest request = this.getRequest(); return this.getWebAgentService().getWebUserAgent(request.getHeader("User-Agent"), request); } protected WebAgentService getWebAgentService(){ return BeanContextAware.getBeanByType(WebAgentService.class); } /** * 判断短信验证码是否正确。 * @param code 验证码 * @param uuid 请求验证码标识 * @return * @date 2023-08-07 */ protected boolean validateSmsCode(String code, String uuid){ CaptchaResult captchaResult = new CaptchaResult(); captchaResult.setCode(code); captchaResult.setUuid(uuid); return this.smsCaptchaProvider.validateCaptcha(captchaResult); } /** * 发送短信验证码。 * @param phoneNumber 手机号 * @return 返回前端需要的uuid,提交登录使用 * @throws PlatformRuntimeException * @date 2023-06-28 */ protected Map sendSmsCodeValidation(String phoneNumber){ if(!PhoneNumberUtils.isCellPhoneNumber(phoneNumber)){ throw new PlatformRuntimeException("手机号码格式错误:" + phoneNumber); } String uuid = IdUtils.simpleUUID(); Map data = new HashMap<>(4); data.put("uuid", uuid); String verifyKey = Constants.CAPTCHA_CODE_PREFIX + uuid; CaptchaResult captchaResult = this.smsCaptchaProvider.generateCaptcha(phoneNumber); if(captchaResult == null){ // return ResponseValue.error("短信验证码生成错误, null"); throw new PlatformRuntimeException("短信验证码生成错误, null"); } // 写入验证码 key 和 code 到缓存中 this.captchaCacheProvider.putCacheData(verifyKey, captchaResult.getCode(), 120); if(this.logger.isDebugEnabled()){ this.logger.debug("生成短信验证码:{}, uuid:{}", captchaResult.getCode(), uuid); } data.put("message", "短信验证码已发送"); return data; } /** * 返回用户归属值,如果是平台为'-1',如果为租户(商户)则为定义的商户ID。 *
     *     注意要点:
     *     1)因为系统框架中用户是长整形(Long),但商户中是(int)因此在实际添加商户数据时,需要按照序列来计算,这样只需要整形即可。
     * 
* @return * @date 2023-06-05 */ protected long getOwner(){ S_user_core user = this.getCurrentUser(); int userType = user.getUser_type(); if(userType == UserType.TYPE_SUPER){ return Constants.OWNER_PLATFORM; } // 其他人需要根据机构中"menu_type"字段区分是平台机构,还是业务独立机构 S_dept dept = this.getDept(user.getOrg_id()); if(dept.getMenu_type().intValue() == MenuUtils.MENU_SCOPE_PLATFORM){ return Constants.OWNER_PLATFORM; } // 机构ID就是业务创建的独立编号(如:商户id),这里商户是int,但系统机构中仍然使用bigint return dept.getId(); } /** * 返回当前用户所在顶级单位,使用的菜单范围:平台0,商户(顶级独立单位菜单范围)4,后续可能会有其他值。 * @return * @date 2023-06-01 */ protected int getCurrentOrgMenuScope(){ long orgId = this.getCurrentUser().getOrg_id(); if(orgId == Constants.SUPERVISOR_ID){ // 超级管理员,返回平台菜单范围 return MenuUtils.MENU_SCOPE_PLATFORM; } return this.getDeptCacheProvider().getDept(orgId).getMenu_type(); } /** * 根据字典数据code,返回字典项名称。 * @param dictCode 字典项编码(主键) * @return * @date 2023-03-26 */ protected String getDictName(long dictCode){ S_dict_data dict_data = this.getDictCacheProvider().getCacheData(String.valueOf(dictCode)); if(dict_data == null){ throw new IllegalStateException("缓存中未找到字典名称,dict_code = " + dictCode); } return dict_data.getDict_label(); } /** * 返回给定机构的名字。 * @param deptId 机构ID * @return * @date 2023-03-23 */ protected String getDeptName(long deptId){ S_dept dept = this.getDept(deptId); return dept == null ? "None":dept.getDept_name(); } /** * 返回给定id的部门对象 * @param deptId 部门ID * @return * @author 时克英 * @date 2023-03-23 */ protected S_dept getDept(long deptId){ return this.getDeptCacheProvider().getDept(deptId); } /** * 从缓存中返回给定的用户 * @param userId 用户id * @return * @date 2023-03-22 */ public S_user_core getUser(long userId){ return this.getUserCacheProvider().getUser(userId); } /** * 下载数据导入模板,该模板由系统自动生成。
* 业务需要提供数据库对应的'表名称',如:s_user_core * @param tableName 表名 * @date 2023-03-18 */ protected void downloadLocalImportTemplate(String tableName){ if(StringUtils.isEmpty(tableName)){ throw new IllegalArgumentException("请提供要导入数据的'表名称'!"); } // 本地文件存储根路径,如: d:/temp/ String templatePath = this.acquireFileOperateSpi().getFileRootConfig(); // 生成的模板文件名称,如:demo.xlsx String templateFileName = Constants.TEMPLATE_IMPORT_PREFIX + tableName + "_" + DateUtils.getDateTimeSecondForShow() + ".xlsx"; TemplateInfo templateInfo = new TemplateInfo(); // 2023-05-07 设置模板生成具体路径。 templateInfo.setTemplatePath(templatePath + templateFileName); templateInfo.setTableName(tableName); logger.debug("templateInfo = {}", templateInfo); File templateFile = this.getDataImportEngine().generateTemplate(templateInfo); try { this.downloadSimpleFile(FileCopyUtils.copyToByteArray(templateFile), templateFileName); } catch (IOException e) { logger.error("下载模板错误:" + e.getMessage() + ", tableName=" + tableName, e); ServletUtils.renderString(getResponse(), "下载模板错误:" + e.getMessage() + ", tableName=" + tableName); } } /** * 返回数据字典缓存对象。

* 注意:这种写法后续要改掉,统一由平台自动注入,无需单独设置。 * @return * @date 2023-03-10 */ protected DictCacheProvider getDictCacheProvider(){ // if(this.dictCacheProvider == null){ // this.dictCacheProvider = BeanContextAware.getBeanByType(DictCacheProvider.class); // } return this.dictCacheProvider; } /** * 返回数据导入引擎实现对象,用来完成 Excel 导入功能。 * @return * @date 2023-02-07 */ protected PlatformDataImportEngine getDataImportEngine(){ // return BeanContextAware.getBeanByType(PlatformDataImportEngine.class); return this.platformDataImportEngine; } public UserCacheProvider getUserCacheProvider() { // if(this.userCacheProvider == null){ // this.userCacheProvider = BeanContextAware.getBeanByType(UserCacheProvider.class); // } return userCacheProvider; } public DeptCacheProvider getDeptCacheProvider() { // if(this.deptCacheProvider == null){ // this.deptCacheProvider = BeanContextAware.getBeanByType(DeptCacheProvider.class); // } return deptCacheProvider; } /** * 返回给定用户的顶级机构ID。 * @param userId * @return * @date 2022-12-15 */ protected long getUserRootOrgId(long userId){ this.checkUserCacheProvider(); S_user_core user_core = this.userCacheProvider.getUser(userId); if(user_core == null){ throw new IllegalStateException("缓存中未找到用户: " + userId); } return user_core.getOrg_id(); } /** * 根据机构(部门等非顶级ID)返回顶级机构ID。 * @param deptId * @return * @date 2022-12-12 */ protected long getRootOrgIdByDept(long deptId){ if(this.deptCacheProvider == null){ throw new IllegalArgumentException("请先设置controller对象: deptCacheProvider"); } S_dept dept = this.deptCacheProvider.getDept(deptId); if(dept == null){ throw new IllegalStateException("缓存中未找到机构: " + deptId); } return dept.getOrg_id(); } /** * 返回当前登录用户可选择的根机构列表,即:第一级机构,通常是集团公司等。

* 这些也称为多租户,系统提供多单位(独立)维护,不同独立单位由各自管理员自行维护。 *
     *     1.超级管理员可以看到所有独立机构列表
     *     2.单位用户只能看到本单位(一个机构)
     * 
* @return * @date 2022-12-01 */ protected List getOrgListScope(){ DeptServiceImpl deptService = BeanContextAware.getBeanByType(DeptServiceImpl.class); S_user_core currentUser = this.getCurrentUser(); List list = null; if(currentUser.getUser_type().intValue() == UserType.TYPE_SUPER){ list = deptService.queryRootOrgList(0); } else { list = deptService.queryRootOrgList(currentUser.getOrg_id().longValue()); } if(StringUtils.isEmptyList(list)){ // 不存在任何机构(数据库没有记录),需要创建默认机构 list = new ArrayList<>(2); list.add(this.createDefaultOrg()); } return list; } private void checkUserCacheProvider(){ if(this.userCacheProvider == null){ throw new IllegalStateException("UserCacheProvider 必须先设置到控制器中。"); } } private S_dept createDefaultOrg(){ S_dept root = new S_dept(); root.setId(0L); root.setParent_id(0L); root.setOrg_type(OrgType.TYPE_ORG); root.setOrder_num(1); root.setDept_name(Constants.DEFAULT_ORG_NAME); return root; } public void setDeptCacheProvider(DeptCacheProvider deptCacheProvider) { this.deptCacheProvider = deptCacheProvider; } public void setUserCacheProvider(UserCacheProvider userCacheProvider) { this.userCacheProvider = userCacheProvider; } public void setPlatformDataImportEngine(PlatformDataImportEngine platformDataImportEngine) { this.platformDataImportEngine = platformDataImportEngine; } public void setDictCacheProvider(DictCacheProvider dictCacheProvider) { this.dictCacheProvider = dictCacheProvider; } public void setPushManager(PushManager pushManager) { this.pushManager = pushManager; } public void setSmsCaptchaProvider(CaptchaProvider smsCaptchaProvider) { this.smsCaptchaProvider = smsCaptchaProvider; } public void setCaptchaCacheProvider(CacheProvider captchaCacheProvider) { this.captchaCacheProvider = captchaCacheProvider; } public CaptchaProvider getSmsCaptchaProvider() { return smsCaptchaProvider; } public CacheProvider getCaptchaCacheProvider() { return captchaCacheProvider; } protected UserServiceImpl getUserService(){ return BeanContextAware.getBeanByType(UserServiceImpl.class); } private CaptchaProvider smsCaptchaProvider; private CacheProvider captchaCacheProvider; /** * 返回推送管理器对象,只有在特殊情况下需要业务直接调用该对象。 * @return * @date 2023-04-25 */ protected PushManager getPushManager() { return pushManager; } private PushManager pushManager; private DeptCacheProvider deptCacheProvider; private UserCacheProvider userCacheProvider; private PlatformDataImportEngine platformDataImportEngine; private DictCacheProvider dictCacheProvider; @Override public void afterPropertiesSet() throws Exception {} }