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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
