Campus Dormitory Management System: Even a CRUD Project Can Be Full of Pitfalls
How It Started
A campus dormitory management system sounds a lot like a course design project.
Student information, dorm numbers, repair tickets, announcement management—these features are all very common. At first I also thought it was just a CRUD project: write a few APIs, connect a database, and make the pages clickable.
But after actually finishing it, I realized that CRUD is only the outermost shell. As soon as you make the features slightly more complete, you run into many real problems.
The project is in this repository: yfgug/project
Features Implemented
The system mainly has several modules:
- Student management: create, read, update, delete, multi-condition search, batch deletion, avatar upload.
- Repair tickets: submit, in progress, resolved, delete.
- Announcement management: publish, edit, delete.
- Login protection: temporarily lock the account after consecutive incorrect password attempts.
- File upload: extension restriction, size limit, UUID renaming.
The tech stack is Spring Boot 2.5 + MyBatis + MySQL. The backend uses a RESTful API, return values are uniformly wrapped in a Result<T> layer, configuration is placed in YAML, and the database connection pool uses HikariCP.
The First Pitfall Was Querying
The most common requirement in student management is search.
Searching by name alone is simple, and searching by dorm number alone is also simple. But real pages often use combined conditions: name, gender, dorm number, and move-in date range—users fill in whichever ones they want.
If you write a separate SQL statement for every combination, it quickly becomes a disaster.
Later I used MyBatis dynamic SQL to handle it:
- Add name condition if name is present.
- Add gender condition if gender is present.
- Add dorm number condition if dorm number is present.
- Add date range condition if a date range is present.
- For batch deletion, use
<foreach>to expand the id list.
This was the first time I felt quite intuitively that frameworks are not for showing off—they can really save you.
File Uploads Are More Troublesome Than Expected
Avatar upload also looked simple at first: the frontend sends a file, the backend stores it, and then writes the path into the database.
But problems soon appeared:
- Is the file the user uploads actually an image?
- What if the file is too large?
- Will two people uploading files with the same name overwrite each other?
- How is the upload directory mapped to an accessible path?
The final approach was:
- Only allow
jpg/jpeg/png/gif/bmp/webp. - Limit size to 2MB.
- Rename with UUID.
- Set up separate upload configuration and resource mapping.
If these details are not handled, the feature might still run. But once it is actually used by others, problems easily arise.
Login Brute-Force Protection
This feature is not complicated, but I found it quite interesting.
I used ConcurrentHashMap to record the number of failed login attempts. If the same account enters an incorrect password 3 times in a row, it is locked for 5 seconds.
Of course, this is not a professional security solution, nor can it replace captchas, rate limiting, audit logs, and similar things. But for a practice project, it at least got me thinking that “an API cannot consider only the normal path.”
Previously, when writing a login API, I would only think about whether the password is correct. Now I think one step further: what if someone keeps trying passwords?
How It Felt After Finishing
The greatest value of this project is not how many features it has, but that it strings together several common backend tasks:
- Receive requests.
- Validate parameters.
- Call the business layer.
- Access the database.
- Handle files.
- Return a unified result.
- Make the frontend pages actually usable.
Before writing it, I thought Spring Boot was just a bunch of annotations. Looking back after finishing, it is actually helping me organize these repetitive but important tasks.
The project is not large, but it gave me a clearer sense of “what a backend system should look like.”