最代码网站中关于动态表event的设计思路
原文:最代码网站中关于动态表event的设计思路 为了能将最代码整站用户的操作都展现出来,需要设计一种动态类型,既可以根据业务无限扩展,也可以指定某些用户行为是可以产生多少牛币交换的,这样就在原先javaniu的零散的表设计基础上抽象出event表 表结构如
原文:最代码网站中关于动态表event的设计思路
为了能将最代码整站用户的操作都展现出来,需要设计一种动态类型,既可以根据业务无限扩展,也可以指定某些用户行为是可以产生多少牛币交换的,这样就在原先javaniu的零散的表设计基础上抽象出event表
表结构如下:
CREATE TABLE `javaniu_event` ( `id` bigint(20) unsigned NOT NULL auto_increment, `create_time` datetime NOT NULL, `update_time` datetime default NULL, `event_rule_id` bigint(20) NOT NULL default '0' COMMENT '用户注册\r\n下载代码\r\n浏览分享\r\n浏览寻求\r\n收藏分享\r\n收藏寻求\r\n浏览活动\r\n追加悬赏\r\n加入活动\r\n拜师\r\n关注用户\r\n发表心情\r\n发表寻求\r\n评论寻求\r\n评论代码\r\n上传代码\r\n下载代码\r\n分享代码\r\n关注用户\r\n浏览分享\r\n浏览寻求\r\n管理员删除代码\r\n收藏分享\r\n收藏寻求\r\n获取勋章\r\n拜师傅\r\n发起活动\r\n浏览活动\r\n加入活动\r\n追加悬赏\r\n连续一周发表心情\r\n用户周贡献排行\r\n用户月贡献排行\r\n用户年贡献排行\r\n代码下载周排行\r\n代码下载月排行\r\n代码下载年排行', `user_id` bigint(20) NOT NULL default '0', `source_user_id` bigint(20) NOT NULL default '0', `source_id` bigint(20) NOT NULL default '0', `target_id` bigint(20) NOT NULL default '0', `status` int(2) NOT NULL default '0' COMMENT '-1删除0待审核2正常', `type` int(2) NOT NULL default '0', PRIMARY KEY (`id`), KEY `create_time` (`create_time`), KEY `userid_status` (`user_id`,`status`), KEY `event_rule_id_source_id` (`event_rule_id`,`source_id`), KEY `event_rule_id_status` (`event_rule_id`,`status`), KEY `type_source_id` (`type`,`source_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
关联表event_rule可以指定牛币规则及其动态显示信息,结构如下:
CREATE TABLE `javaniu_event_rule` ( `id` bigint(20) unsigned NOT NULL auto_increment, `create_time` datetime NOT NULL, `update_time` datetime default NULL, `type` int(1) NOT NULL COMMENT '注册+1\r\n发表心情+1\r\n连续一周发表心情+5\r\n分享代码+1\r\n分享代码被下载+n(n为分享者者自定义牛币)\r\n寻求代码-2\r\n上传代码+1\r\n上传代码被下载+1\r\n代码被设为最佳+n(n为寻求者者自定义牛币)\r\n删除代码-1\r\n无效寻求-2\r\n无效代码-2\r\n管理员奖赏+n\r\n管理员惩罚-n\r\n周top10+5\r\n月top10+10\r\n年top10+100\r\n信息完善+1\r\n包月vip+100\r\n师傅赠送+n牛币\r\n授予徽章+5牛币\r\n', `name` varchar(100) NOT NULL, `niubi` int(11) NOT NULL, `extend_json` varchar(1000) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
event的用户行为数据模型抽象如下:
模型一:用户a通过事件x产生动态0=user_id_a 0 0 0
a=>x=>0
模型二:用户a通过事件x产生产生用户a的数据1=user_id_a 0 0 1
a=>x=>1
模型三:用户a通过事件x对用户b的数据1产生用户a的数据2=user_id_a b 1 2
a=>x+b+1=>2
模型四:用户a通过事件x对用户b的数据1产生动态0=user_id_a b 1 0
a=>x+b+1=>0
模型五:用户a通过事件x对用户b产生动态0=user_id_a b 0 0
a=>x+b=>0
排列组合:
user_id source_user_id source_id target_id
user_id
user_id source_user_id
user_id source_user_id source_id
user_id source_user_id source_id target_id
这样就囊括了所有会出现的用户event,只要在java层做业务转换即可:
最核心的event数据转换java类源码:
package com.zuidaima.core.service.impl; private void setSourceAndTarget(Event event, EventRule _eventRule) { try { EventRule eventRule = new EventRule(); eventRule.setCreateTime(_eventRule.getCreateTime()); eventRule.setExtendJson(_eventRule.getExtendJson()); eventRule.setId(_eventRule.getId()); eventRule.setName(_eventRule.getName()); eventRule.setNiubi(_eventRule.getNiubi()); eventRule.setType(_eventRule.getType()); eventRule.setUpdateTime(_eventRule.getUpdateTime()); BaseEntity source = null; BaseEntity target = null; long sourceId = event.getSourceId(); long targetId = event.getTargetId(); JSONObject extend = eventRule.getExtend(); extend = eventRule.getExtend(); String description = (String) extend.get("description"); String _description = null; Answer answer = null; Project project = null; switch (eventRule.getType()) { case ModuleConstants.EVENT_TYPE_RULE_PROJECT_CREATE: case ModuleConstants.EVENT_TYPE_RULE_PROJECT_DELETE_BY_USER: case ModuleConstants.EVENT_TYPE_RULE_PROJECT_DELETE_BY_ADMIN: case ModuleConstants.EVENT_TYPE_RULE_PROJECT_VIEW: case ModuleConstants.EVENT_TYPE_RULE_PROJECT_COLLECT: case ModuleConstants.EVENT_TYPE_RULE_PROJECT_REWARD: if (sourceId > 0) { source = projectService.findOneById(sourceId); } if (targetId > 0) { target = projectService.findOneById(targetId); } project = (Project) target; if (source != null) { project = (Project) source; } if (project == null) { return; } _description = String.format( description, ModuleConstants.PROJECT_TYPE_DESC_MAP.get( project.getType()).getDesc()); break; case ModuleConstants.EVENT_TYPE_RULE_POST_CREATE: case ModuleConstants.EVENT_TYPE_RULE_POST_DELETE_BY_USER: case ModuleConstants.EVENT_TYPE_RULE_POST_DELETE_BY_ADMIN: if (sourceId > 0) { source = postService.findOneById(sourceId); } if (targetId > 0) { target = postService.findOneById(targetId); } Post post = (Post) target; if (source != null) { post = (Post) source; } _description = String.format(description, ModuleConstants.POST_TYPE_DESC_MAP.get(post.getType())); break; // case ModuleConstants.EVENT_TYPE_RULE_GROUP_CREATE://暂时没有这种动态 case ModuleConstants.EVENT_TYPE_RULE_GROUP_JOIN_IN: case ModuleConstants.EVENT_TYPE_RULE_GROUP_DELETE_BY_USER: // case // ModuleConstants.EVENT_TYPE_RULE_GROUP_DELETE_BY_ADMIN://暂时没有这种动态 if (sourceId > 0) { source = groupService.findOneById(sourceId); } if (targetId > 0) { target = groupService.findOneById(targetId); } Group group = (Group) source; _description = String .format(description, ModuleConstants.GROUP_TYPE_DESC_MAP.get(group .getType())); break; case ModuleConstants.EVENT_TYPE_RULE_COMMENT_CREATE: case ModuleConstants.EVENT_TYPE_RULE_COMMENT_DELETE_BY_USER: case ModuleConstants.EVENT_TYPE_RULE_COMMENT_DELETE_BY_ADMIN: target = commentService.findOneById(targetId); Comment comment = (Comment) target; int commentType = comment.getType(); if (commentType == ModuleConstants.COMMENT_TYPE_ANSWER) { source = answerService.findOneById(sourceId); answer = (Answer) source; project = (Project) answer.getTarget(); _description = String.format( description, ModuleConstants.PROJECT_TYPE_DESC_MAP.get( project.getType()).getDesc()); } else if (commentType == ModuleConstants.COMMENT_TYPE_PROJECT) { source = projectService.findOneById(sourceId); project = (Project) source; _description = String.format( description, ModuleConstants.PROJECT_TYPE_DESC_MAP.get( project.getType()).getDesc()); } else if (commentType == ModuleConstants.COMMENT_TYPE_POST) { source = postService.findOneById(sourceId); post = (Post) source; _description = String.format(description, ModuleConstants.POST_TYPE_DESC_MAP.get(post .getType())); } else { } break; case ModuleConstants.EVENT_TYPE_RULE_ANSWER_CREATE: case ModuleConstants.EVENT_TYPE_RULE_ANSWER_BEEN_SET_PERFECT: source = projectService.findOneById(sourceId); target = answerService.findOneById(targetId); project = (Project) source; _description = String.format( description, ModuleConstants.PROJECT_TYPE_DESC_MAP.get( project.getType()).getDesc()); break; case ModuleConstants.EVENT_TYPE_RULE_ANSWER_GET: case ModuleConstants.EVENT_TYPE_RULE_ANSWER_DELETE_BY_USER: case ModuleConstants.EVENT_TYPE_RULE_ANSWER_DELETE_BY_ADMIN: source = answerService.findOneById(sourceId); answer = (Answer) source; Project _project = (Project) answer.getTarget(); _description = String.format( description, ModuleConstants.PROJECT_TYPE_DESC_MAP.get( _project.getType()).getDesc()); break; case ModuleConstants.EVENT_TYPE_RULE_REPUTATION_CREATE: if (sourceId > 0) { source = reputationService.findOneById(sourceId); } if (targetId > 0) { target = reputationService.findOneById(targetId); } break; case ModuleConstants.EVENT_TYPE_RULE_USER_FOLLOW: source = userService.findOneById(sourceId); User _user = (User) source; _description = String .format(description, "<a href='/user/n/" + _user.getName() + ".htm'>" + _user.getName() + "</a>"); break; case ModuleConstants.EVENT_TYPE_RULE_MENTION_COMMENT: target = commentService.findOneById(targetId); comment = (Comment) target; commentType = comment.getType(); if (commentType == ModuleConstants.COMMENT_TYPE_ANSWER) { source = answerService.findOneById(sourceId); answer = (Answer) source; project = (Project) answer.getTarget(); _description = String.format( description, ModuleConstants.PROJECT_TYPE_DESC_MAP.get( project.getType()).getDesc()); } else if (commentType == ModuleConstants.COMMENT_TYPE_PROJECT) { source = projectService.findOneById(sourceId); project = (Project) source; _description = String.format( description, ModuleConstants.PROJECT_TYPE_DESC_MAP.get( project.getType()).getDesc()); } else if (commentType == ModuleConstants.COMMENT_TYPE_POST) { source = postService.findOneById(sourceId); post = (Post) source; _description = String.format(description, ModuleConstants.POST_TYPE_DESC_MAP.get(post .getType())); } else { } break; case ModuleConstants.EVENT_TYPE_RULE_MENTION_POST: source = postService.findOneById(sourceId); break; default: _description = description; } extend.put("description", _description); eventRule.setExtend(extend); eventRule.setExtendJson(extend.toString()); event.setEventRule(eventRule); event.setSource(source); event.setTarget(target); } catch (Exception e) { logger.error("Fail to setSourceAndTarget event:" + event); } }
freemarker显示层转换核心代码:
<#switch event.eventRule.type> <#case event_type_rule_post_create> <@event_post_macro event.target/> <#break> <#case event_type_rule_project_create> <@event_project_macro event event.target/> <#break> <#case event_type_rule_project_view> <#case event_type_rule_project_collect> <#case event_type_rule_project_reward> <@event_project_macro event event.source/> <#break> <#case event_type_rule_comment_create> <@event_comment_macro event event.target/> <#break> <#case event_type_rule_answer_create> <@event_answer_macro event event.target/> <#break> <#case event_type_rule_answer_get> <#case event_type_rule_answer_been_set_perfect> <@event_answer_macro event event.source/> <#break> <#case event_type_rule_mention_comment> <@event_comment_macro event event.target/> <#break> <#case event_type_rule_mention_post> <@event_post_macro event.source/> <#break> </#switch>
比如其中一种event type的freemarker macro代码如下:
<!--event post--> <#macro event_post_macro post> <div class="content margin_top5"> ${post.contentExt} <span class="comments_count"> <a target="_blank" href="/mood/${post.id}/comment.htm" rel="nofollow"><img src="/static/imghw/default1.png" data-src="/resource/img/comment.gif" class="lazy" alt="${post.thirdSort}个评论"> ${post.thirdSort}</a> </span> </div> </#macro>
这样的设计符合高内聚低耦合的设计思路,未来可以根据业务实现无限扩张,当然代价就是event表越来越大,但可以通过分库分表来分担压力,大家可以参考下,有好的意见可以留言。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











가상 머신을 생성할 때 디스크 유형을 선택하라는 메시지가 표시되며 고정 디스크 또는 동적 디스크를 선택할 수 있습니다. 고정 디스크를 선택했지만 나중에 동적 디스크가 필요하다는 사실을 깨닫게 된다면 어떻게 될까요? 아니면 그 반대의 경우도 가능합니다. 이번 포스팅에서는 VirtualBox 고정 디스크를 동적 디스크로 또는 그 반대로 변환하는 방법을 살펴보겠습니다. 동적 디스크는 처음에는 크기가 작다가 가상 머신에 데이터를 저장함에 따라 크기가 커지는 가상 하드 디스크입니다. 동적 디스크는 필요한 만큼만 호스트 저장 공간을 차지하므로 저장 공간을 절약하는 데 매우 효율적입니다. 그러나 디스크 용량이 늘어나면 컴퓨터 성능이 약간 영향을 받을 수 있습니다. 고정 디스크와 동적 디스크는 일반적으로 가상 머신에서 사용됩니다.

4월 26일 뉴스에 따르면 ZTE의 5G 휴대용 Wi-Fi U50S는 현재 899위안부터 공식 판매되고 있습니다. 외관 디자인 측면에서 ZTE U50S 휴대용 Wi-Fi는 심플하고 스타일리시하며 쥐기 쉽고 포장이 쉽습니다. 크기는 159/73/18mm로 휴대가 간편해 언제 어디서나 5G 고속 네트워크를 즐길 수 있어 방해받지 않는 모바일 오피스와 엔터테인먼트 경험을 선사합니다. ZTE 5G 휴대용 Wi-Fi U50S는 최대 1800Mbps의 속도로 고급 Wi-Fi 6 프로토콜을 지원합니다. Snapdragon X55 고성능 5G 플랫폼을 사용하여 사용자에게 매우 빠른 네트워크 경험을 제공합니다. 5G 듀얼 모드 SA+NSA 네트워크 환경과 Sub-6GHz 주파수 대역을 지원할 뿐만 아니라 측정된 네트워크 속도도 놀라운 500Mbps에 도달해 쉽게 만족할 수 있습니다.

17일 뉴스에 따르면 HMD는 유명 맥주 브랜드 하이네켄, 크리에이티브 기업 보데가와 손잡고 독특한 폴더폰 '보링폰(The Boring Phone)'을 출시했다. 이 전화기는 디자인 혁신으로 가득 차 있을 뿐만 아니라 기능면에서도 자연으로 돌아가 사람들을 진정한 대인 관계로 돌아가게 하고 친구들과 함께 술을 마시는 순수한 시간을 즐기는 것을 목표로 합니다. Boring 휴대폰은 독특한 투명 플립 디자인을 채택하여 단순하면서도 우아한 미학을 보여줍니다. 내부에는 2.8인치 QVGA 디스플레이, 외부에는 1.77인치 디스플레이가 탑재되어 사용자에게 기본적인 시각적 상호 작용 경험을 제공합니다. 사진의 경우 3000만 화소 카메라만 탑재되어 있지만 간단한 일상 업무를 처리하기에는 충분하다.

7월 12일 뉴스에 따르면, 새로운 Honor Vision Soothing Oasis 눈 보호 화면을 탑재한 Honor Magic V3 시리즈가 오늘 공식 출시되었습니다. 화면 자체는 높은 사양과 품질을 갖추고 있으면서도 AI 능동형 눈 보호 장치 도입을 개척했습니다. 기술. 근시를 완화하는 전통적인 방법은 근시 안경의 도수가 고르게 분포되어 있어 중심 시력 영역은 망막에 맺히지만 주변 영역은 망막 뒤에 맺히는 것으로 알려져 있습니다. 망막은 상이 뒤쳐져 있음을 감지하여 눈의 축방향 성장을 촉진시켜 정도를 심화시킵니다. 현재 근시 발생을 완화시키는 주요 방법 중 하나가 '디포커스 렌즈'다. 중심 영역은 정상적인 도수를 갖고, 주변 영역은 광학 설계 파티션을 통해 조절해 주변 영역의 상이 안으로 들어가게 한다. 망막 앞.

4월 3일 뉴스에 따르면 Taipower가 곧 출시할 M50 Mini 태블릿 컴퓨터는 풍부한 기능과 강력한 성능을 갖춘 장치입니다. 이 새로운 8인치 소형 태블릿에는 8.7인치 IPS 화면이 탑재되어 사용자에게 뛰어난 시각적 경험을 제공합니다. 메탈 바디 디자인은 아름다울 뿐만 아니라 기기의 내구성도 높여줍니다. 성능 측면에서 M50Mini에는 A75 코어 2개와 A55 코어 6개를 갖춘 Unisoc T606 8코어 프로세서가 탑재되어 원활하고 효율적인 실행 환경을 보장합니다. 동시에 태블릿에는 6GB+128GB 스토리지 솔루션이 탑재되어 있으며 8GB 메모리 확장을 지원하여 스토리지 및 멀티태스킹에 대한 사용자 요구 사항을 충족합니다. 배터리 수명 측면에서 M50Mini는 5000mAh 배터리가 장착되어 있으며 Ty를 지원합니다.

직장에서 ppt는 전문가들이 자주 사용하는 사무용 소프트웨어입니다. 완전한 ppt는 좋은 마무리 페이지를 가지고 있어야 합니다. 전문적인 요구 사항이 다르면 PPT 제작 특성도 달라집니다. 엔드페이지 제작에 있어서 어떻게 하면 좀 더 매력적으로 디자인할 수 있을까요? PPT의 마지막 페이지를 디자인하는 방법을 살펴보겠습니다! ppt 끝 페이지의 디자인은 텍스트와 애니메이션 측면에서 조정할 수 있으며 필요에 따라 단순하거나 눈부신 스타일을 선택할 수 있습니다. 다음으로는 요구사항에 맞는 PPT 엔드페이지를 만들기 위해 혁신적인 표현방법을 활용하는 방법에 대해 집중적으로 살펴보겠습니다. 그럼 오늘의 튜토리얼을 시작하겠습니다. 1. 끝 페이지 제작에는 사진 속 어떤 텍스트라도 사용할 수 있습니다. 끝 페이지에서 중요한 점은 프레젠테이션이 끝났다는 의미입니다. 2. 이 단어들 외에도,

프로그래머로서 저는 코딩 경험을 단순화하는 도구에 흥미를 느낍니다. 인공 지능 도구의 도움으로 데모 코드를 생성하고 요구 사항에 따라 필요한 수정 작업을 수행할 수 있습니다. Visual Studio Code에 새로 도입된 Copilot 도구를 사용하면 자연어 채팅 상호 작용을 통해 AI 생성 코드를 만들 수 있습니다. 기능을 설명함으로써 기존 코드의 의미를 더 잘 이해할 수 있습니다. Copilot을 사용하여 코드를 생성하는 방법은 무엇입니까? 시작하려면 먼저 최신 PowerPlatformTools 확장을 가져와야 합니다. 이를 위해서는 확장 페이지로 이동하여 "PowerPlatformTool"을 검색하고 설치 버튼을 클릭해야 합니다.

5월 13일 뉴스에 따르면 vivoX100s는 오늘 밤 공식적으로 출시되었으며 뛰어난 이미지 외에도 신호 성능도 매우 뛰어납니다. vivo의 공식 소개에 따르면 vivoX100s는 최대 21개의 안테나가 장착된 혁신적인 범용 신호 증폭 시스템을 사용합니다. 이 디자인은 5G, 4G, Wi-Fi, GPS, NFC 등 다양한 신호 요구 사항의 균형을 맞추기 위해 다이렉트 화면을 기반으로 다시 최적화되었습니다. 이로써 vivoX100s는 생체 역사상 가장 강력한 신호 수신 기능을 갖춘 휴대폰이 되었습니다. 새 휴대폰은 또한 안테나가 본체 주위에 분산된 독특한 360° 서라운드 디자인을 사용합니다. 이 디자인은 신호 강도를 향상시킬 뿐만 아니라 다양한 일상 자세를 최적화하여 부적절한 쥐기 방법으로 인해 발생하는 문제를 방지합니다.
