Coder Social home page Coder Social logo

banq / jivejdon Goto Github PK

View Code? Open in Web Editor NEW
558.0 24.0 159.0 56.93 MB

Jivejdon is a Domain Driven Design appication with CQRS/ES/Clean/Hexagonal architecture

License: Apache License 2.0

Java 84.87% JavaScript 10.50% CSS 4.28% HTML 0.23% XSLT 0.13%
bbs forum cms blog ddd-architecture ddd ddd-example ddd-events content-management-system jive

jivejdon's Introduction

Jivejdon

Jivejdon is a WordPress-like Blog/Forum and production-ready application with DDD + DomainEvents/Event Soucing/CQRS + clean architecture/Hexagonalarchitecture, powered by jdonframework.

You can check out the canonical deployment of Jivejdon at https://www.jdon.com/(NginX+Tomcat+JDK8+MySQL)

avatar

Domain-centric Architecture.

Domain-centric architecture is a new way to design modern world enterprise applications.

avatar

Use Case

avatar

DDD Aggregate Model

avatar

There are two aggregate roots in jivejdon: FormThread and ForumMessage(Root Message).

com.jdon.jivejdon.domain.model.ForumMessage is a rich model, no "public" setter method, all setter methods are "private":

avatar

Domain Model principles:

  1. *High level of encapsulation All members' setter methods are private`` by default, then internal`. need heavy builder pattern to create aggregate root!

  2. *High level of PI (Persistence Ignorance) No dependencies on infrastructure, databases, or other stuff. All classes are POJO.

The customer/supply model from jdonframework can separate the domain model from Persistence/Repository.

All business datas outside of the domain is packed in a DTO anemic model(AnemicMessageDTO), so business rules in the aggregate root entity will not leak outside of the domain.

avatar

These DTO anemic models can also be packed in Command and Domain Events, so they are managed in DDD ubiquitous business language.

  1. Rich in behavior

All business logic is located in Domain Model. No leaks to the application layer or other places.

  1. Low level of primitive obsession

Primitive attributes of Entities grouped together using ValueObjects.

MessageVO is a value Object and has two attributes for message content: subject/body.

Clean architecture/Hexagonal architecture

Why clean architecture/Hexagonal architecture are a better choice for "Implementing Domain Driven Design"

JiveJdon is developed with JdonFramework that supports the Customer/Supply or pub-sub model, this model can separate domain logic from infrastructure, databases, and other stuff.

avatar

JiveJdon Hexagonal_architecture:

avatar

here is the package view of jivejdon:

avatar

Invoking path:

presentation -> api -> domain -> spi ->infrastructure

models.xml is an adapter for presentation:

	<model key="messageId" class="com.jdon.jivejdon.infrastructure.dto.AnemicMessageDTO">
		<actionForm name="messageForm"/>
		<handler>
			<service ref="forumMessageService">

				<createMethod name="createReplyMessage"/>

			</service>
		</handler>
	</model>

When a user post a replies message, a POST command from the presentation will action the createReplyMessage method of forumMessageService in API :

public interface ForumMessageService {

	Long createReplyMessage(EventModel em) throws Exception;
	....

}

The forumMessageService will delegate the responsibility to the aggregate root entity ForumMessage,

The createReplyMessage() method of the forumMessageService will send a command to the addChild() method of ForumMessage that is too a command handler of CQRS:

avatar

@OnCommand("postRepliesMessageCommand") annotation make addChild() being a command handler, the annotation is from pub-sub model of jdonframework, it can make this method executed with a single-writer pattern - no blocked, no lock, high concurrent. only one thread/process invoking this update method.

"event-sourcing.addReplyMessage" will send a "ReplyMessageCreatedEvent" domain Event to infrastructure layer such as Repository. separate domain logic from infrastructure, databases, and other stuff.

Domain event "ReplyMessageCreatedEvent" occurring in the domain is saved in the event store "jiveMessage", this is a message posted events table. the event can be used for reconstructing the latest replies state of a thread, events replay is in ForumThreadState .

CQRS architecture

CQRS addresses separate reads and writes into separate models, using commands to update data, and queries to read data.

avatar

In jivejdon ForumThread and ForumMessage are saved in the cache, the cache is a snapshot of even logs, if an update command activates one of these models, they will send domain events to clear the cache data, the cache is similar to the database for query/read model, the consistency between with cache and the database for command model is maintained by the domain events such as "ReplyMessageCreatedEvent".

The domain event "ReplyMessageCreatedEvent" do three things:

  1. add a new post message to "jiveMessage" (events log)
  2. clear the query cache (CQRS)
  3. update/project the latest replies state of a thread (event project to state)

Event Sourcing

Posting a message is an event, modifying the latest replies status for one thread.

avatar

How to get the latest replies status for one thread? we must iterate all posted events collection.

JiveMessage is a database storing posted events in time order, with one SQL we can reduce them chronologically to get the current state: the latest posted event:


SELECT messageID from jiveMessage WHERE  threadID = ? ORDER BY modifiedDate DESC

This SQL can quickly find the latest replies post, similar to replaying all posted events to project the current state.

In jiveThread table there is no special field for the latest replies state, all states are from posted events projection. (projection can use SQL!)

When a user posts a new ForumMessage, a ReplyMessageCreatedEvent event will be saved to the event store: JiveMessage, simultaneously refreshing the snapshot of the event: ForumThreadState.

In ForumThreadState there is another method for projecting state from the database, if we want to get the count of all message replies, its projectStateFromEventSource() method can do this:


	public void projectStateFromEventSource() {
		DomainMessage dm = this.forumThread.lazyLoaderRole.projectStateFromEventSource(forumThread.getThreadId());
		OneOneDTO oneOneDTO = null;
		try {
			oneOneDTO = (OneOneDTO) dm.getEventResult();
			if (oneOneDTO != null) {
				latestPost = (ForumMessage) oneOneDTO.getParent();
				messageCount = new AtomicLong((Long) oneOneDTO.getChild());
				dm.clear();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

lazyLoaderRole.projectStateFromEventSource will send a "projectStateFromEventSource" message to ThreadStateLoader:

public void onEvent(EventDisruptor event, boolean endOfBatch) throws Exception {
		try {
			ForumMessage latestPost = forumAbstractFactory.getMessage(lastMessageId);

			long messagereplyCount;
			long messageCount = messageQueryDao.getMessageCount(threadId);
			if (messageCount >= 1)
				messagereplyCount = messageCount - 1;
			else
				messagereplyCount = messageCount;

			OneOneDTO oneOneDTO = new OneOneDTO(latestPost, messagereplyCount);
			event.getDomainMessage().setEventResult(oneOneDTO);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

ThreadStateLoader will reconstruct the current state by SQL from MySQL database, the SQL is "select count(1) ...". and now we refreshed the current state of a ForumThread: the count for all message replies.

Domain model mapping to the database schema:

avatar

Most of the stuff in aggregate root "ForumThread" mapping to jiveThread table, but its "rootMessage" mapping to jiveMessage table, and its state "ForumThreadState" is projected from jiveMessage table. In jiveMessage table, there are two kinds of ForumMessage: root message and replies messages, one thread only has one root message but has many replies messages, these replies messages are replies-posted event log. in the domain model,replies messages (FormMessageReply) is a subclass of Root Message(FormMessage).

There is a new pattern between strictly event sourcing and CRUD, it is DomainEvents List, any element in List can be removed, no appending!

Compile & Package & Install

git clone https://github.com/banq/jivejdon.git (git clone https://gitee.com/banqjdon/jivejdon.git)
cd jivejdon
mvn clean install -U

if clone error, please remove all downloaded files in Maven local repository and try "mvn clean install -U" again, or clone from https://gitee.com/banqjdon/jivejdon

if mvn compile error, please configure your mirror Maven center repository.

Runtime download

(1) Docker:

1. docker pull mysql:latest
2. docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
   
   docker ps 

   docker cp ddl/mysql_jivejdon.sql  container_id:/mysql_jivejdon.sql
   docker cp ddlmysql_security.sql  container_id:/mysql_security.sql
   
   
   docker exec -it container_id bash
   

   mysql -u root -p 
   create database jivejdon character set utf8;

   mysql -u root -p jivejdon < /mysql_jivejdon.sql
   mysql -u root -p jivejdon < /mysql_security.sql

3. docker build -t jivejdonweb -f Dockerfile.web .
4. docker run  -p 8080:8080 jivejdonweb

browser : http://$DOCKER_HOST_IP:8080

(2) jivejdon+tomcat+mysql download passwd:97j9

Start the server:

  1. mysql-5.6.15-winx64\bin\mysqld.exe, and telnet 127.0.0.1 3306
  2. apache-tomcat-7.0.37\bin\debug.bat

app: http://127.0.0.1:8080/

debug port:8000

you can debug jivejdon in IntelliJ Idea by connecting to 8000 port

Document

English install doc

Chinese install doc

Chinese design doc

jivejdon's People

Contributors

banq avatar orangeyts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jivejdon's Issues

Aggregate Root References Each Other

In DDD, there is a strict rule that says "An aggregate root only can give reference each other by id". In your system ForumMessage aggregate root contains another aggregate root which is ForumThread.

对于项目的疑问

老哥,你这代码,ddl语句没有注释,啥意思全靠猜,代码也没有注释,这样的项目用了ddd也可以很容易维护吗?

版本问题

请问,github上的这个资源支持目前的新版Tomcat和JDK版本吗,例如tomcat8 jdk8。因为我看到最新的安装说明是jdk6的,而且我自己部署起来有很多错误,如果不支持,还有更新版本的工程吗

部分依赖缺失

com.jdon:jdon-jdbcTemp:jar:6.6.4
com.jdon:jdon-struts1x:jar:6.6.4
com.jdon:jdon-treepattern:jar:6.6.4
com.jdon:jdonaccessory:jar:6.6.4
tecentweibo:tecentweibo:jar:6.6.4
weibo4j:weibo4j:jar:6.6.4
log4j2.jar
以上依赖都下载不了,mvnrepository上也搜索不到这些依赖

最新版本如何安装运行?

可能我问的这个问题比较弱智,认识JdonFramework是三年前,但真正接触的是从《复杂软件设计之道:领域驱动设计全面解析与实战》这本书开始。读完两遍后,一直想调用运行jivejdon的源码,在关于领域设计和微服务的基础知识准备差不多了,就开始下载源码跑了。

发现doc目录下的Install文档并不适合当前源码,比较doc/tomcat目录不存在。在Idea中打开源码,解析依赖后,发现缺少组件,类似:
image

image

请求作者给予指导,万分感谢。

安装部署后的错误

lib中有jar包,但是提示找不到javax/mail/Authenticator。jsp中有一些报错。点击注册或忘记密码页面显示500的jsp错误,用admin/admin注册跳转提示400请求错误

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.