[DocumentComparison] Java Spring Framework Example

Follow the API request/response shapes shown in the controller. The DB schema is just a starting point — adapt as needed.

DocumentVersionController.java

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Controller
public class DocumentVersionController {
    private final DocumentVersionService documentVersionService;

    /** Save a document version. */
    @PostMapping("/saveDocumentVersionData")
    public String saveDocumentVersionData(
            UserInfo userInfo,
            @RequestParam("docId") final String docId,
            @RequestParam("jsonData") final String jsonData) {
        documentVersionService.insertDocumentVersion(
            userInfo.getUserId(),
            domainService.getDomainInfo(userInfo).getId(),
            Long.parseLong(docId),
            jsonData
        );
        return ResponseEntity.ok(Map.of("message", "Document saved successfully."));
    }

    /** List versions for a document. */
    @PostMapping("/getDocumentVersionList")
    public ResponseEntity<String> getDocumentVersionList(@RequestBody Map<String, Object> request) throws JsonProcessingException {
        long docId = Long.parseLong((String) request.get("docId"));

        List<DocumentVersionModel> versions = documentVersionService.getDocumentVersions(docId);
        List<Map<String, Object>> formatted = versions.stream().map(version -> {
            Map<String, Object> v = new HashMap<>();
            v.put("id",     version.getId());
            v.put("date",   version.getCreatedAt());
            v.put("author", version.getUsername());
            return v;
        }).collect(Collectors.toList());

        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(formatted);
        return ResponseEntity.ok()
            .header("Content-Type", "application/json; charset=UTF-8")
            .body(json);
    }

    /** Fetch one version's data. */
    @PostMapping("/getDocumentVersionData")
    public String getDocumentVersionData(@RequestBody Map<String, Object> request) {
        long id = Long.parseLong((String) request.get("id"));
        String json = documentVersionService.getDocumentVersionJson(id);
        return ResponseEntity.ok()
            .header("Content-Type", "application/json; charset=UTF-8")
            .body(json);
    }

    /** Delete a version. */
    @DeleteMapping("/getDocumentVersionData")
    public ResponseEntity<Map<String, Object>> deleteDocumentVersionData(@RequestBody Map<String, Object> request) {
        long id = Long.parseLong((String) request.get("id"));
        documentVersionService.deleteDocumentVersion(id);
        return ResponseEntity.ok(Map.of("message", "Document deleted successfully."));
    }
}

DocumentVersionService.java

import java.util.Comparator;
import java.util.List;

@Slf4j
@Service
public class DocumentVersionService {
    @Autowired DocumentVersionModelDao documentVersionModelDao;
    @Autowired SynapUserInfoDao        synapUserInfoDao;

    public void insertDocumentVersion(String userId, int domainId, long docId, String json) {
        documentVersionModelDao.insert(new DocumentVersionModel(userId, domainId, docId, json));
    }

    public String getDocumentVersionJson(long id) {
        return documentVersionModelDao.getDocumentVersionById(id).getJson();
    }

    public List<DocumentVersionModel> getDocumentVersions(long docId) {
        List<DocumentVersionModel> list = documentVersionModelDao.getDocumentVersionByDocId(docId);
        list.sort(Comparator.comparing(DocumentVersionModel::getUserId));

        String currentUserId   = "";
        String targetUsername  = "";
        for (DocumentVersionModel m : list) {
            if (!m.getUserId().equals(currentUserId)) {
                currentUserId  = m.getUserId();
                targetUsername = synapUserInfoDao.getUserInfoByUserIdAndDomain(currentUserId, m.getDomainId()).getUserName();
            }
            m.setUsername(targetUsername);
        }
        list.sort(Comparator.comparing(DocumentVersionModel::getId).reversed());
        return list;
    }

    public void deleteDocumentVersion(long id) {
        documentVersionModelDao.delete(id);
    }
}

DocumentVersionModelDao.java

import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Repository
public class DocumentVersionModelDao extends AbstractDao {
    public void insert(DocumentVersionModel m) { insert("DocumentVersion.insert", m); }
    public void delete(long id)                 { delete("DocumentVersion.remove", id); }

    public DocumentVersionModel getDocumentVersionById(long id) {
        Map<String, Object> params = new HashMap<>();
        params.put("id", id);
        return (DocumentVersionModel) select("DocumentVersion.getDocumentVersionById", params);
    }

    public List<DocumentVersionModel> getDocumentVersionByDocId(long docId) {
        return list("DocumentVersion.getDocumentVersionByDocId", docId);
    }
}

AbstractDao.java

import com.ibatis.sqlmap.client.SqlMapClient;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import java.util.List;

@SuppressWarnings("deprecation")
public abstract class AbstractDao extends SqlMapClientDaoSupport {
    protected AbstractDao() {}

    public final Object insert(String queryId, Object p) { return getSqlMapClientTemplate().insert(queryId, p); }
    public final int    update(String queryId, Object p) { return getSqlMapClientTemplate().update(queryId, p); }
    public final int    delete(String queryId, Object p) { return getSqlMapClientTemplate().delete(queryId, p); }
    public final Object select(String queryId, Object p) { return getSqlMapClientTemplate().queryForObject(queryId, p); }

    @SuppressWarnings("rawtypes")
    public final List   list  (String queryId, Object p) { return getSqlMapClientTemplate().queryForList(queryId, p); }
}

DocumentVersionModel.java

import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.sql.Date;

@Data
@NoArgsConstructor
public class DocumentVersionModel implements Serializable {
    private long   id;
    private String userId;
    private int    domainId;
    private String username;
    private long   docId;
    private String json;
    private Date   createdAt;

    DocumentVersionModel(String userId, int domainId, long docId, String json) {
        this.userId   = userId;
        this.domainId = domainId;
        this.docId    = docId;
        this.json     = json;
    }
}

DocumentVersion.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="DocumentVersion">
    <resultMap id="documentVersion" class="(DocumentVersionModel path)">
        <result property="id"        column="id"         columnIndex="1"/>
        <result property="userId"    column="user_id"    columnIndex="2"/>
        <result property="domainId"  column="domain_id"  columnIndex="3"/>
        <result property="docId"     column="doc_id"     columnIndex="4"/>
        <result property="json"      column="json"       columnIndex="5"/>
        <result property="createdAt" column="created_at" columnIndex="6"/>
    </resultMap>
    <resultMap id="documentVersionList" class="(DocumentVersionModel path)">
        <result property="id"        column="id"         columnIndex="1"/>
        <result property="userId"    column="user_id"    columnIndex="2"/>
        <result property="domainId"  column="domain_id"  columnIndex="3"/>
        <result property="docId"     column="doc_id"     columnIndex="4"/>
        <result property="createdAt" column="created_at" columnIndex="5"/>
    </resultMap>

    <insert id="insert">
        INSERT INTO document_version(user_id, domain_id, doc_id, json, created_at)
        VALUES (#userId#, #domainId#, #docId#, #json#, SYSDATE())
    </insert>

    <delete id="remove">
        DELETE FROM document_version WHERE id = #id#
    </delete>

    <select id="getDocumentVersionById" resultMap="documentVersion">
        SELECT id, user_id, domain_id, doc_id, json, created_at
        FROM document_version
        WHERE id = #id#
    </select>

    <select id="getDocumentVersionByDocId" resultClass="java.util.List" resultMap="documentVersionList">
        SELECT id, user_id, domain_id, doc_id, created_at
        FROM document_version
        WHERE doc_id = #docId#
        ORDER BY id DESC
        LIMIT 500
    </select>
</sqlMap>

Example Table

CREATE TABLE `document_version` (
  `id`         bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id`    varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `domain_id`  int(11)      NOT NULL DEFAULT 1,
  `doc_id`     bigint(20)   NOT NULL,
  `json`       longtext     COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` datetime     NOT NULL DEFAULT current_timestamp(),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=671 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;