Build an Electronic Document Signing and Contract System with SpringBoot

This article walks through creating a SpringBoot‑based electronic document signing and contract system, covering the problem background, project structure, Maven setup, key controller and service code, utility classes, deployment steps, and a step‑by‑step demo of drafting, approval, sealing and signing workflows.

Java Architect Handbook
Java Architect Handbook
Java Architect Handbook
Build an Electronic Document Signing and Contract System with SpringBoot

Introduction

The author was asked to implement a file signing and stamping feature. Digital signatures use cryptographic techniques to guarantee authenticity, integrity and non‑repudiation, similar to paper signatures. The demo simulates an OA workflow where Word documents are drafted, approved, sealed and finally issued, using PageOffice for online Office handling.

Project Source and Deployment

The system is built with SpringBoot and Thymeleaf , packaged with Maven. The source code can be downloaded from the provided CSDN link, imported into an IDE (e.g., IntelliJ IDEA) as the slndemo project, and run directly.

Project Structure and Frameworks

@Controller
@RequestMapping("/mobile")
public class MobileOfficeController {
    @Value("${docpath}")
    private String docPath;
    @Value("${moblicpath}")
    private String moblicpath;
    @Autowired
    DocService m_docService;

    /** Add MobOffice server‑side authorization servlet (required) */
    @RequestMapping("/opendoc")
    public void opendoc(HttpServletRequest request, HttpServletResponse response,
                        HttpSession session, String type, String userName) throws Exception {
        String fileName = "";
        userName = URLDecoder.decode(userName, "utf-8");
        Doc doc = m_docService.getDocById(1);
        if (type.equals("word")) {
            fileName = doc.getDocName();
        } else {
            fileName = doc.getPdfName();
        }
        OpenModeType openModeType = OpenModeType.docNormalEdit;
        if (fileName.endsWith(".doc")) {
            openModeType = OpenModeType.docNormalEdit;
        } else if (fileName.endsWith(".pdf")) {
            String mode = request.getParameter("mode");
            if (mode.equals("normal")) {
                openModeType = OpenModeType.pdfNormal;
            } else {
                openModeType = OpenModeType.pdfReadOnly;
            }
        }
        MobOfficeCtrl mobCtrl = new MobOfficeCtrl(request, response);
        mobCtrl.setSysPath(moblicpath);
        mobCtrl.setServerPage("/mobserver.zz");
        mobCtrl.setSaveFilePage("/mobile/savedoc?testid=" + Math.random());
        mobCtrl.webOpen("file://" + docPath + fileName, openModeType, userName);
    }

    @RequestMapping("/savedoc")
    public void savedoc(HttpServletRequest request, HttpServletResponse response) {
        FileSaver fs = new FileSaver(request, response);
        fs.saveToFile(docPath + fs.getFileName());
        fs.close();
    }
}
@Service
public class DocServiceImpl implements DocService {
    @Autowired
    DocMapper docMapper;

    @Override
    public Doc getDocById(int id) throws Exception {
        Doc doc = docMapper.getDocById(id);
        if (doc == null) {
            doc = new Doc();
        }
        return doc;
    }

    @Override
    public Integer addDoc(Doc doc) throws Exception {
        return docMapper.addDoc(doc);
    }

    @Override
    public Integer updateStatusForDocById(Doc doc) throws Exception {
        return docMapper.updateStatusForDocById(doc);
    }

    @Override
    public Integer updateDocNameForDocById(Doc doc) throws Exception {
        return docMapper.updateDocNameForDocById(doc);
    }

    @Override
    public Integer updatePdfNameForDocById(Doc doc) throws Exception {
        return docMapper.updatePdfNameForDocById(doc);
    }
}
public class CopyFileUtil {
    // Copy file
    public static boolean copyFile(String oldPath, String newPath) throws Exception {
        boolean copyStatus = false;
        int bytesum = 0;
        int byteread = 0;
        File oldfile = new File(oldPath);
        if (oldfile.exists()) { // file exists
            InputStream inStream = new FileInputStream(oldPath);
            FileOutputStream fs = new FileOutputStream(newPath);
            byte[] buffer = new byte[1444];
            int length;
            while ((byteread = inStream.read(buffer)) != -1) {
                bytesum += byteread; // total bytes
                fs.write(buffer, 0, byteread);
            }
            fs.close();
            inStream.close();
            copyStatus = true;
        } else {
            copyStatus = false;
        }
        return copyStatus;
    }
}
public class QRCodeUtil {
    private String codeText;
    private BarcodeFormat barcodeFormat;
    private int width;
    private int height;
    private String imageformat;
    private int backColorRGB;
    private int codeColorRGB;
    private ErrorCorrectionLevel errorCorrectionLevel;
    private String encodeType;

    public QRCodeUtil() {
        codeText = "www.zhuozhengsoft.com";
        barcodeFormat = BarcodeFormat.PDF_417;
        width = 400;
        height = 400;
        imageformat = "png";
        backColorRGB = 0xFFFFFFFF;
        codeColorRGB = 0xFF000000;
        errorCorrectionLevel = ErrorCorrectionLevel.H;
        encodeType = "UTF-8";
    }
    // ... getters, setters and QR code generation logic omitted for brevity ...
}

Function Demonstration

The demo runs on http://localhost:8888/pc/login with the following credentials:

Account: 张三, Password: 123456 (initial login)

Account: 王五, Password: 123456 (seal and sign)

Key workflow steps:

Login to the system.

Click “Draft Document”, fill content and submit.

Open the pending document, install PageOffice if prompted, then edit.

Save the edited document.

Proceed to approval screens (李总, 赵六, etc.).

During the seal stage, the user must enter name and password; incorrect input triggers an error.

After successful authentication, select a personal seal and apply it.

Finally, click “Sign” to complete the electronic signature.

Save and publish the fully signed and sealed document.

The author notes that the demo only creates a single document for simplicity and that PageOffice provides many more functions (open, edit, merge, fill, trace, seal, etc.) which can be invoked in any web system that needs online Office processing.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavamavenSpringBootelectronic-signaturethymeleafpageofficecontract-system
Java Architect Handbook
Written by

Java Architect Handbook

Focused on Java interview questions and practical article sharing, covering algorithms, databases, Spring Boot, microservices, high concurrency, JVM, Docker containers, and ELK-related knowledge. Looking forward to progressing together with you.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.