AOP操作日志记录
AOP操作日志记录
1.创建注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PassportLog {String operatePage();String operateType();ClassTypEnum classType();}
2.创建切面
对于字典,可以通过注解属性去转换,枚举也可以注解属性去转换,但是需要if else判断;对于数组类型的传值,需要if else特殊处理;另外需注意反射获取不到子类的属性private
@Slf4j
@Aspect
@Component
@AllArgsConstructor
public class PassportLogAop {/*** 修改记录-字段的分割符号*/private static final String SEPARATOR = ";";@Resourceprivate PassportMapper passportMapper;@Resourceprivate PassportCardFillMapper passportCardFillMapper;@Resourceprivate PassportFamilyMembersMapper passportFamilyMembersMapper;@Resourceprivate PassportEmergencyContactMapper passportEmergencyContactMapper;@Resourceprivate PassportOperateRecordService passportOperateRecordService;@Resourceprivate SysFeign sysFeign;@Resourceprivate SystemDictService systemDictService;@Before("@annotation(passportLog)")public void before(JoinPoint point, PassportLog passportLog) {try {saveLog(point, passportLog);} catch (Exception e) {log.error(e.getMessage());}}/*** 操作日志记录** @param point* @param passportLog* @throws IntrospectionException* @throws InvocationTargetException* @throws IllegalAccessException*/public void saveLog(JoinPoint point, PassportLog passportLog) throws IntrospectionException, InvocationTargetException, IllegalAccessException {ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (requestAttributes == null) {return;}PassportOperateRecord record = new PassportOperateRecord();record.setDelFlag(PassportCommonConstant.NOT_DELETE);HttpServletRequest request = Objects.requireNonNull(requestAttributes).getRequest();if (ObjUtil.isNotNull(request)) {record.setOperateIp(IpUtil.getIp(request));record.setUrl(StrUtil.sub(URLUtil.getPath(request.getRequestURI()), 0, 255));record.setMethod(StrUtil.sub(point.getTarget().getClass().getName() + "." + point.getSignature().getName() + "()", 0, 255));record.setRequestMethod(request.getMethod());}record.setOperateTime(LocalDateTime.now());record.setOperatePerson(BaseUserEntity.getName());record.setOperateOffice(BaseUserEntity.getDeptName());record.setOperateRole(sysFeign.queryRoleName(new ArrayList<>(BaseUserEntity.getRoleCode())).getData());record.setOperatePage(passportLog.operatePage());record.setOperateType(passportLog.operateType());Object[] args = point.getArgs();String s = JSONUtil.toJsonStr(args[0]);ClassTypEnum classType = passportLog.classType();String prefix = "";String content = "";if (classType.equals(ClassTypEnum.PASSPORT_ACCEPT_INFO)) {//预约办理PassportAcceptInfoDTO newObj = JSONObject.parseObject(s, PassportAcceptInfoDTO.class);String requestNo = newObj.getRequestNo();record.setRequestNo(requestNo);PassportAcceptInfoDTO oldObj = new PassportAcceptInfoDTO();BeanUtil.copyProperties(passportMapper.selectById(newObj.getId()), oldObj);content = this.compare(oldObj, newObj, requestNo, prefix, content);record.setOperateContent(content);//操作类型Integer status = newObj.getStatus();if (ApplyStatusEnum.UN_ACCEPTED.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.QXSL);} else if (ApplyStatusEnum.PENDING_AUDITING.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.SLBDY);}passportOperateRecordService.save(record);} else if (classType.equals(ClassTypEnum.PASSPORT_ACCEPT_INFO_DRAFT)) {//预约办理草稿箱PassportAcceptInfoDraftDTO newObj = JSONObject.parseObject(s, PassportAcceptInfoDraftDTO.class);String requestNo = newObj.getRequestNo();record.setRequestNo(requestNo);PassportAcceptInfoDraftDTO oldObj = new PassportAcceptInfoDraftDTO();BeanUtil.copyProperties(passportMapper.selectById(newObj.getId()), oldObj);record.setOperateContent(this.compare(oldObj, newObj, requestNo, prefix, content));passportOperateRecordService.save(record);} else if (classType.equals(ClassTypEnum.TODAY_APPLY)) {//申请今日受理TodayApplyDTO newObj = JSONObject.parseObject(s, TodayApplyDTO.class);String requestNo = newObj.getRequestNo();record.setRequestNo(requestNo);record.setOperateContent("申请说明:" + newObj.getReason());passportOperateRecordService.save(record);} else if (classType.equals(ClassTypEnum.PASSPORT_SIDE_HANDLE)) {//现场办理PassportSiteHandleDTO newObj = JSONObject.parseObject(s, PassportSiteHandleDTO.class);record.setRequestNo(newObj.getRequestNo());PassportSiteHandleDTO oldObj = new PassportSiteHandleDTO();if (Objects.isNull(oldObj.getId())) {prefix = "新增:";} else {BeanUtil.copyProperties(passportMapper.selectById(newObj.getId()), oldObj);}record.setOperateContent(this.compare(oldObj, newObj, newObj.getRequestNo(), prefix, content));//操作类型Integer status = newObj.getStatus();if (ApplyStatusEnum.UN_ACCEPTED.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.QXSL);} else if (ApplyStatusEnum.PENDING_AUDITING.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.SLBDY);}passportOperateRecordService.save(record);} else if (classType.equals(ClassTypEnum.PASSPORT_SIDE_HANDLE_DRAFT)) {//现场办理草稿箱PassportSiteHandleDraftDTO newObj = JSONObject.parseObject(s, PassportSiteHandleDraftDTO.class);String requestNo = newObj.getRequestNo();record.setRequestNo(requestNo);PassportSiteHandleDraftDTO oldObj = new PassportSiteHandleDraftDTO();if (Objects.isNull(oldObj.getId())) {prefix = "新增:";} else {BeanUtil.copyProperties(passportMapper.selectById(newObj.getId()), oldObj);}content = this.compare(oldObj, newObj, requestNo, prefix, content);record.setOperateContent(content);passportOperateRecordService.save(record);} else if (classType.equals(ClassTypEnum.PASSPORT_CHECK)) {//护照情况核查、退回修改、保存、生成传真并提交审核PassportCheckDTO newObj = JSONObject.parseObject(s, PassportCheckDTO.class);record.setRequestNo(newObj.getRequestNo());PassportCheckDTO oldObj = new PassportCheckDTO();BeanUtil.copyProperties(passportMapper.selectById(newObj.getId()), oldObj);record.setOperateContent(this.compare(oldObj, newObj, newObj.getRequestNo(), prefix, content));//操作类型Integer status = newObj.getStatus();Integer problemStatus = newObj.getProblemStatus();if (ApplyStatusEnum.NOT_VERIFIED.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.BC);}if (PassportProblemEnum.THXG.getCode().equals(problemStatus)) {record.setOperateType(PassportOperateTypeConstant.THXG);} else if (ApplyStatusEnum.PENDING_AUDITING.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.SCCZBTJSH);}passportOperateRecordService.save(record);} else if (classType.equals(ClassTypEnum.PASSPORT_CHECK_BATCH)) {//批量核查List ids = JSONObject.parseObject(s, List.class);for (Object id : ids) {Passport passport = passportMapper.selectById(Long.parseLong(id.toString()));record.setRequestNo(passport.getRequestNo());record.setOperateContent("批量生成传真并提交审核");passportOperateRecordService.save(record);}} else if (classType.equals(ClassTypEnum.PASSPORT_EXAMINE_BATCH)) {//批量审核List ids = JSONObject.parseObject(s, List.class);for (Object id : ids) {Passport passport = passportMapper.selectById(Long.parseLong(id.toString()));record.setRequestNo(passport.getRequestNo());record.setOperateContent("批量审核通过");passportOperateRecordService.save(record);}} else if (classType.equals(ClassTypEnum.PASSPORT_EXAMINE)) {//审核PassportExamineDTO newObj = JSONObject.parseObject(s, PassportExamineDTO.class);record.setRequestNo(newObj.getRequestNo());PassportExamineDTO oldObj = new PassportExamineDTO();BeanUtil.copyProperties(passportMapper.selectById(newObj.getId()), oldObj);//如果老状态是复核则页面应设置为复核页面if (ApplyStatusEnum.PENDING_REVIEW.getCode().equals(oldObj.getStatus())) {record.setOperatePage(PassportOperatePageConstant.HZBL_HZFH_ZHFX);}record.setOperateContent(this.compare(oldObj, newObj, newObj.getRequestNo(), prefix, content));//操作类型Integer status = newObj.getStatus();Integer problemStatus = newObj.getProblemStatus();if (ApplyStatusEnum.PENDING_REVIEW.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.TJFH);} else if (ApplyStatusEnum.RETURNED_ITEMS.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.TJ);} else if (ApplyStatusEnum.PENDING_CERTIFICATION.getCode().equals(status)) {record.setOperateType(PassportOperateTypeConstant.TG);}if (PassportProblemEnum.THXG.getCode().equals(problemStatus)) {record.setOperateType(PassportOperateTypeConstant.THXG);} else if (PassportProblemEnum.GQ.getCode().equals(problemStatus)) {record.setOperateType(PassportOperateTypeConstant.GQ);}passportOperateRecordService.save(record);}}/*** 比较两个对象,并且返回不一致的信息** @param newObj* @param oldObj* @param requestNo* @param prefix* @return*/private String compare(Object oldObj, Object newObj, String requestNo, String prefix, String str) throws IntrospectionException, InvocationTargetException, IllegalAccessException {str += prefix;//1:获取到对象的classClass<?> oldClass = oldObj.getClass();Class<?> newClass = newObj.getClass();//2:获取到对象的属性列表Field[] oldFields = oldClass.getDeclaredFields();Field[] newFields = newClass.getDeclaredFields();for (int i = 0; i < oldFields.length; i++) {if ("serialVersionUID".equals(oldFields[i].getName())) {continue;}//将此对象的 accessible 标志设置为指示的布尔值。// 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。// 值为 false 则指示反射的对象应该实施 Java 语言访问检查;// 实际上setAccessible是启用和禁用访问安全检查的开关,// 并不是为true就能访问为false就不能访问 ;oldFields[i].setAccessible(true);newFields[i].setAccessible(true);//获取到字段上的注解PassportField annotation = oldFields[i].getAnnotation(PassportField.class);//当没有注解的时候跳过本次循环if (annotation == null) {continue;}//获取注解中的字段名String name = annotation.name();ListTypEnum listTypEnum = annotation.listType();SysDictTypeEnum code = annotation.code();TypeEnum typeEnum = annotation.typeEnum();PropertyDescriptor oldPd = new PropertyDescriptor(oldFields[i].getName(), oldClass);PropertyDescriptor newPd = new PropertyDescriptor(newFields[i].getName(), newClass);//调用成员方法Method oldReadMethod = oldPd.getReadMethod();Method newReadMethod = newPd.getReadMethod();//3:获取到参数数值Object oldValue = oldReadMethod.invoke(oldObj);Object newValue = newReadMethod.invoke(newObj);if (StrUtil.isBlank(name)) {//处理listif (listTypEnum.equals(ListTypEnum.CARD_FILL)) {str = this.cardFill(newValue, requestNo, str);continue;} else if (listTypEnum.equals(ListTypEnum.EMERGENCY_CONTACT)) {str = this.emergencyContact(newValue, requestNo, str);continue;} else if (listTypEnum.equals(ListTypEnum.FAMILY_MEMBERS)) {str = this.familyMember(newValue, requestNo, str);continue;}} else {//处理系统字典if (ObjUtil.isNotNull(code) && !SysDictTypeEnum.NULL.equals(code)) {if (ObjUtil.isNotNull(oldValue)) {oldValue = systemDictService.queryDictName(code, oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = systemDictService.queryDictName(code, newValue.toString());}}if (ObjUtil.isNotNull(typeEnum) && !TypeEnum.NULL.equals(typeEnum)) {if (TypeEnum.STATUS.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = ApplyStatusEnum.getMessage(Integer.parseInt(oldValue.toString()));}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = ApplyStatusEnum.getMessage(Integer.parseInt(newValue.toString()));}} else if (TypeEnum.SF.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = PassportFlagEnum.getMessage(Integer.parseInt(oldValue.toString()));}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = PassportFlagEnum.getMessage(Integer.parseInt(newValue.toString()));}} else if (TypeEnum.BIRTHPLACE.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = systemDictService.birthdayPlace(oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = systemDictService.birthdayPlace(newValue.toString());}} else if (TypeEnum.CARD_VALID_UNIT.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = CardValidUnitEnum.getMessage(oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = CardValidUnitEnum.getMessage(newValue.toString());}} else if (TypeEnum.ISSUE_PLACE.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = systemDictService.issuePlace(oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = systemDictService.issuePlace(newValue.toString());}} else if (TypeEnum.ISSUE_CHECK.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = PassportDictIssueEnum.getDiceLabel(oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = PassportDictIssueEnum.getDiceLabel(newValue.toString());}} else if (TypeEnum.EVIDENCE_WAY.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = PassportEvidenceWayEnum.getMessage(Integer.parseInt(oldValue.toString()));}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = PassportEvidenceWayEnum.getMessage(Integer.parseInt(newValue.toString()));}} else if (TypeEnum.DECLARATION_RELATION.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = PassportDictRelationEnum.getDiceLabel(oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = PassportDictRelationEnum.getDiceLabel(newValue.toString());}} else if (TypeEnum.CHECK_OFFICE.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {String[] split = oldValue.toString().split(",");StringBuilder oldValueContent = new StringBuilder();for (String s : split) {oldValueContent.append(systemDictService.queryDictName(SysDictTypeEnum.VERIFICATION_AND_SUBMISSION_AUTHORITY, s));}oldValue = oldValueContent.toString();}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {String[] split = newValue.toString().split(",");StringBuilder newValueContent = new StringBuilder();for (String s : split) {newValueContent.append(systemDictService.queryDictName(SysDictTypeEnum.VERIFICATION_AND_SUBMISSION_AUTHORITY, s));}newValue = newValueContent.toString();}} else if (TypeEnum.EMERGENCY_RELATION.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = PassportDictEmergencyContactEnum.getDiceLabel(oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = PassportDictEmergencyContactEnum.getDiceLabel(newValue.toString());}} else if (TypeEnum.FAMILY_RELATION.equals(typeEnum)) {if (ObjUtil.isNotNull(oldValue) && StrUtil.isNotBlank(oldValue.toString())) {oldValue = PassportDictFamilyEnum.getDiceLabel(oldValue.toString());}if (ObjUtil.isNotNull(newValue) && StrUtil.isNotBlank(newValue.toString())) {newValue = PassportDictFamilyEnum.getDiceLabel(newValue.toString());}}}//获取差异字段str = getDifferenceFieldStr(str, name, oldValue, newValue);}}return str;}/*** 获取差异字段新旧值** @param str* @param fieldName* @param oldValue* @param newValue* @return*/private static String getDifferenceFieldStr(String str, String fieldName, Object oldValue, Object newValue) {if (null == oldValue || StringUtils.isBlank(oldValue.toString())) {oldValue = "无";}if (null == newValue || StringUtils.isBlank(newValue.toString())) {newValue = "无";}if (!oldValue.equals(newValue)) {str += fieldName + "从 " + oldValue + ",修改为 " + newValue + SEPARATOR;}return str;}/*** 处理加注** @param newValue* @param requestNo* @throws IntrospectionException* @throws InvocationTargetException* @throws IllegalAccessException*/private String cardFill(Object newValue, String requestNo, String str) throws IntrospectionException, InvocationTargetException, IllegalAccessException {List<PassportCardFillDTO> newObjects = (List<PassportCardFillDTO>) newValue;List<PassportCardFillDTO> oldObjects = passportCardFillMapper.queryCardFillByRequestNo(requestNo);if (CollectionUtils.isEmpty(newObjects)) {if (!CollectionUtils.isEmpty(oldObjects)) {for (PassportCardFillDTO oldObject : oldObjects) {str = this.compare(oldObject, new PassportCardFillDTO(), requestNo, "删除加注:", str);}}} else {if (CollectionUtils.isEmpty(oldObjects)) {for (PassportCardFillDTO newObject : newObjects) {str = this.compare(new PassportCardFillDTO(), newObject, requestNo, "新增加注:", str);}} else {for (PassportCardFillDTO newObject : newObjects) {if (Objects.isNull(newObject.getId())) {str = this.compare(new PassportCardFillDTO(), newObject, requestNo, "新增加注:", str);} else {List<PassportCardFillDTO> removeFills = new ArrayList<>();for (PassportCardFillDTO oldObject : oldObjects) {if (oldObject.getId().equals(newObject.getId())) {if (!oldObject.equals(newObject)) {str = this.compare(oldObject, newObject, requestNo, "", str);}removeFills.add(oldObject);}}oldObjects.removeAll(removeFills);for (PassportCardFillDTO oldObject : oldObjects) {str = this.compare(oldObject, new PassportCardFillDTO(), requestNo, "删除加注:", str);}}}}}return str;}/*** 处理紧急联系人** @param newValue* @param requestNo* @throws IntrospectionException* @throws InvocationTargetException* @throws IllegalAccessException*/private String emergencyContact(Object newValue, String requestNo, String str) throws IntrospectionException, InvocationTargetException, IllegalAccessException {List<PassportEmergencyContactAddDTO> newObjects = (List<PassportEmergencyContactAddDTO>) newValue;List<PassportEmergencyContactAddDTO> oldObjects = passportEmergencyContactMapper.queryEmergencyContactByRequestNo(requestNo);if (CollectionUtils.isEmpty(newObjects)) {if (CollUtil.isNotEmpty(oldObjects)) {for (PassportEmergencyContactAddDTO oldObject : oldObjects) {str = this.compare(oldObject, new PassportEmergencyContactAddDTO(), requestNo, "删除紧急联系人:", str);}}} else {if (CollUtil.isEmpty(oldObjects)) {for (PassportEmergencyContactAddDTO newObject : newObjects) {str = this.compare(new PassportEmergencyContactAddDTO(), newObject, requestNo, "新增紧急联系人:", str);}} else {for (PassportEmergencyContactAddDTO newObject : newObjects) {if (ObjUtil.isNull(newObject.getId())) {str = this.compare(new PassportEmergencyContactAddDTO(), newObject, requestNo, "新增紧急联系人:", str);} else {for (PassportEmergencyContactAddDTO oldObject : oldObjects) {if (oldObject.getId().equals(newObject.getId())) {if (!oldObject.equals(newObject)) {str = this.compare(oldObject, newObject, requestNo, "", str);}oldObjects.remove(oldObject);}}if (CollUtil.isNotEmpty(oldObjects)) {for (PassportEmergencyContactAddDTO oldObject : oldObjects) {str = this.compare(oldObject, new PassportEmergencyContactAddDTO(), requestNo, "删除紧急联系人:", str);}}}}}}return str;}/*** 处理家庭成员** @param newValue* @param requestNo* @throws IntrospectionException* @throws InvocationTargetException* @throws IllegalAccessException*/private String familyMember(Object newValue, String requestNo, String str) throws IntrospectionException, InvocationTargetException, IllegalAccessException {List<PassportFamilyMembersAddDTO> newObjects = (List<PassportFamilyMembersAddDTO>) newValue;List<PassportFamilyMembersAddDTO> oldObjects = passportFamilyMembersMapper.queryFamilyMemberByRequest(requestNo);if (CollectionUtils.isEmpty(newObjects)) {if (ObjUtil.isNotEmpty(oldObjects)) {for (PassportFamilyMembersAddDTO oldObject : oldObjects) {str = this.compare(oldObject, new PassportFamilyMembersAddDTO(), requestNo, "删除家庭成员:", str);}}} else {if (CollUtil.isEmpty(oldObjects)) {for (PassportFamilyMembersAddDTO newObject : newObjects) {str = this.compare(new PassportFamilyMembersAddDTO(), newObject, requestNo, "新增家庭成员:", str);}} else {for (PassportFamilyMembersAddDTO newObject : newObjects) {if (ObjUtil.isNull(newObject.getId())) {str = this.compare(new PassportFamilyMembersAddDTO(), newObject, requestNo, "新增家庭成员:", str);} else {for (PassportFamilyMembersAddDTO oldObject : oldObjects) {if (oldObject.getId().equals(newObject.getId())) {if (!oldObject.equals(newObject)) {str = this.compare(oldObject, newObject, requestNo, "", str);}oldObjects.remove(oldObject);}}if (CollUtil.isNotEmpty(oldObjects)) {for (PassportFamilyMembersAddDTO oldObject : oldObjects) {str = this.compare(oldObject, new PassportFamilyMembersAddDTO(), requestNo, "删除家庭成员:", str);}}}}}}return str;}}
相关文章:
AOP操作日志记录
AOP操作日志记录 1.创建注解 Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface PassportLog {String operatePage();String operateType();ClassTypEnum classType();}2.创建切面 对于字典,可以通过注解属性去转换,枚举…...
Linux C语言 42-进程间通信IPC之网络通信(套接字)
Linux C语言 42-进程间通信IPC之网络通信(套接字) 本节关键字:C语言 进程间通信 网络通信 套接字 TCP UDP 相关库函数:socket、bind、listen、accept、send、recv、sendto、recvfrom 参考之前的文章 Linux C语言 30-套接字操作…...

微服务知识大杂烩
1.什么是微服务? 微服务(Microservices)是一种软件架构风格,将一个大型应用程序划分为一组小型、自治且松耦合的服务。每个微服务负责执行特定的业务功能,并通过轻量级通信机制(如HTTP)相互协作。每个微服务可以独立开发、部署和扩展,使得应用程序更加灵活、可伸缩和可…...

记录一次vscode markdown的图片路径相关插件学习配置过程
插件及说明查找过程 csdn搜索markdown图片路径,找到关于这一款插件的回答。打开vscode拓展搜索Paste Image这款插件,看到下载量挺高的,应该不赖。 点击仓库,进入该插件开源的github仓库,查看README文件阅读说明. 淡然在Vscode 插件项目下的细…...

设计原则 | 依赖转置原则
一、依赖转置原则(DIP:Dependence Inversion Principle) 1、原理 高层模块不应该依赖低层模块,二者都应该依赖于抽象抽象不应该依赖于细节,细节应该依赖于抽象 2、层次化 Booch曾经说过:所有结构良好的面…...
前端开发实用技巧与经验分享
导语:在前端开发领域,掌握一些实用的技巧和经验可以帮助你更高效地完成任务。本文将分享一些前端开发的实用技巧和经验,帮助你在工作中更好地应对各种挑战。 一、使用开发者工具进行调试和优化 熟练掌握浏览器开发者工具的使用,…...

推荐一款Excel快速加载SQL的插件,方便又好用
如果告诉你只需要双击一下,SQL数据库中存放在表里面的数据,就能加载到你的Excel中,你想不想要? 今天给大家推荐一款好用的Excel插件,安装简单,使用方便,是经常使用SQL数据库的不二。 这款插件…...

Docker快速入门(docker加速,镜像,容器,数据卷常见命令操作整理)
Docker本质是将代码所需的环境依赖进行打包运行,而在Docker中最重要的是镜像和容器 镜像:可以简单地理解为每启动一个docker镜像就会占用计算机一个进程,这个进程和另外起的docker镜像的进程是相互独立的,以数据库为例,每个镜像都会copy一份数据库,在他所在的进程中.别的镜像在…...

http和https的区别有哪些
目录 HTTP(HyperText Transfer Protocol) HTTPS(HyperText Transfer Protocol Secure) 区别与优势 应用场景 未来趋势 当我们浏览互联网时,我们经常听到两个常用的协议:HTTP(HyperText Tra…...

使用Keil-MDK生成*.bin格式可执行文件
使用Keil-MDK生成*.bin格式可执行文件 文章目录 使用Keil-MDK生成*.bin格式可执行文件前言一、fromelf.exe工具二、使用方法1.配置输出2.输出格式 前言 在使用Keil MDK的集成开发环境中,默认情况下可以生成*.axf格式的调试文件和*.hex格式的可执行文件。虽然文件可…...

基于springboot+vue篮球联盟管理系统源码
🍅 简介:500精品计算机源码学习 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 文末获取源码 目录 一、以下学习内容欢迎交流: 二、文档资料截图: 三、项目技术栈 四、项目运行图 背景: 篮球运…...

分页助手入门以及小bug,报sql语法错误
导入坐标 5版本以上的分页助手 可以不用手动指定数据库语言,它会自动识别 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.3.2</version> </dependency&g…...
Java中的并发编程:深入理解CountDownLatch
Java中的并发编程:深入理解CountDownLatch 本文将深入探讨Java中的并发编程,重点关注CountDownLatch的使用。通过理解这些概念和技术,我们可以编写出更高效、稳定的Java程序。 一、CountDownLatch简介 CountDownLatch是Java中的一个同步工具…...
Windows 安装 flash-attention 和 bitsandbytes
首先保证cuda版本为12.1,torch版本为2.1.0及以上,python版本3.10以上 从此处下载最新版的whl,https://github.com/jllllll/bitsandbytes-windows-webui/releases/tag/wheels,通过whl来安装bitsandbytes 从此处下载最新版的whl&a…...

AHB 与 DMA
AHB(先进高性能总线) 随着深亚微米工艺技术日益成熟,集成电路芯片的规模越来越大。数字IC从基于时序驱动的设计方法,发展到基于IP核复用的设计方法,并在SOC设计中得到了广泛应用。在基于IP核复用的SoC(Syst…...
React使用echarts并且修改echarts图大小
React使用echarts 引入 npm install --save echarts-for-react npm install --save echarts使用 <ReactEChartsoption{option}notMerge{true}lazyUpdate{true}style{{"width": "100%","height": "800px"}}theme{"theme_nam…...
【Q6-30min】
1. ifndef/define/endif的作用:避免头文件被重复引用。 2.堆栈溢出主要的原因是: (1)函数调用层次太深。函数递归调用时,系统要在栈中不断保存函数调用时的现场和产生的变量,如果递归调用太深,…...

C++之类和对象(下)
目录 初始化列表 static成员 C11对于非静态成员变量初始化 友元 友元函数 友元类 总结 初始化列表 我们知道,在学习构造函数时,我们知道对象的成员变量的初始化我们是在构造函数函数体内进行初始化的,还有没有其它初始化成员变量的方…...

微服务开发:断路器详解
微服务是目前业界使用的最重要的实现方面。通过使用微服务架构,开发人员可以消除他们以前在单体应用程序中遇到的许多问题。展望未来,人们开始在微服务中搜索和采用各种模式。大多数时候,新模式的产生是为了解决另一个模式中出现的常见问题。…...

Leetcode—383.赎金信【简单】
2023每日刷题(五十) Leetcode—383.赎金信 实现代码 class Solution { public:int arr[26] {0};int arr2[26] {0};bool canConstruct(string ransomNote, string magazine) {int len ransomNote.size();int len2 magazine.size();for(int i 0; i …...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
大数据治理的常见方式
大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法,以下是几种常见的治理方式: 1. 数据质量管理 核心方法: 数据校验:建立数据校验规则(格式、范围、一致性等)数据清洗&…...