A bulletin-board (게시판) web application built with Spring Boot. Users can register,
log in, and create, edit, delete, search, and comment on posts. Server-rendered with
Thymeleaf and backed by a SQL database accessed directly through JdbcTemplate.
⚠️ This is a learning project, not production software. See Known limitations before deploying or reusing this code.🤖 Working on this repo with a coding agent? Read CLAUDE.md first — it's the agent harness (architecture, commands, conventions, and footguns to avoid).
| Layer | Technology |
|---|---|
| Language | Java 17 |
| Framework | Spring Boot 2.7.12 (spring-boot-starter-web, -thymeleaf, -jdbc) |
| Views | Thymeleaf templates + vanilla JS (fetch) for actions |
| Data access | Spring JdbcTemplate (raw SQL, no JPA/ORM) |
| Database | PostgreSQL (default) — MySQL & H2 drivers also bundled |
| Build | Gradle (wrapper included) |
| Boilerplate | Lombok (@Data) |
| Deploy | Dockerfile (Temurin 17 JRE) |
- Authentication — register an account, log in/out. Login sets a
login_idcookie (30-minute expiry) that gates the board pages. - Posts — create, view, edit, and delete posts. Edited posts are flagged.
- Comments — add and delete comments on a post.
- Search — case-insensitive search across post titles and content.
- Pagination — 10 posts per page.
board/
├── src/main/java/com/choe/board/
│ ├── BoardApplication.java # Spring Boot entry point
│ ├── HomeController.java # landing pages ("/", "/other")
│ ├── LoginRegisterController.java # serves /login and /register pages
│ ├── BulletinBoardController.java # serves board pages (list/view/create/edit)
│ ├── RestfulController.java # JSON/REST endpoints for all data actions
│ ├── User.java Post.java Comment.java # data models (Lombok @Data)
│ └── Hwang.java # leftover sandbox model (see /test* endpoints)
├── src/main/resources/
│ ├── templates/ # Thymeleaf HTML (home, login, bulletin, viewpost, ...)
│ ├── static/{css,js,img}/ # per-page stylesheets and fetch-based scripts
│ ├── application.properties # default (PostgreSQL) datasource config
│ └── application-prod.properties # "prod" profile (MySQL) datasource config
├── Dockerfile
└── build.gradle
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | / |
Home / landing page | — |
| GET | /login |
Login page | — |
| GET | /register |
Registration page | — |
| GET | /board |
Post list (?page=, ?query=) |
✓ |
| GET | /post |
New-post form | ✓ |
| GET | /edit |
Edit-post form (?postId=) |
✓ |
| GET | /view-post/{id} |
Single post + its comments | ✓ |
| Method | Path | Description |
|---|---|---|
| POST | /regiSubmit |
Create a new user |
| POST | /checkDuplicate |
Check if a username is taken |
| POST | /checkLogin |
Validate username + password |
| POST | /submit |
Create a post |
| POST | /submitEdit |
Edit a post |
| POST | /delete-post |
Delete a post (author only) |
| POST | /is-editable |
Check whether current user owns post |
| POST | /submitComment |
Add a comment |
| POST | /delete-comment |
Delete a comment (author only) |
| GET | /test–/test4 |
Sandbox/debug endpoints (not part of the app) |
The app expects these tables to already exist (it does not auto-create them):
-- posts
id SERIAL PRIMARY KEY, title TEXT, author TEXT, content TEXT,
post_date DATE, is_edited BOOLEAN DEFAULT FALSE
-- comments
id SERIAL PRIMARY KEY, post_id INTEGER, author TEXT, content TEXT,
comment_date DATE DEFAULT CURRENT_DATE, is_edited BOOLEAN DEFAULT FALSE
-- "user" (quoted because user is a reserved word)
id SERIAL PRIMARY KEY, username TEXT, password TEXT, email TEXT,
phone TEXT, created_at TIMESTAMP
-- hwang (leftover practice table used by /test3 and /test4)
id SERIAL PRIMARY KEY, name TEXT, reserve_date TEXT, room_num INTEGER- JDK 17
- A reachable SQL database (PostgreSQL, MySQL, or use bundled H2)
Edit src/main/resources/application.properties with your own datasource:
spring.datasource.url=jdbc:postgresql://<host>:5432/<db>
spring.datasource.username=<user>
spring.datasource.password=<password>
spring.datasource.driver-class-name=org.postgresql.DriverDo not commit real credentials — see Known limitations. Prefer environment variables:
spring.datasource.password=${DB_PASSWORD}.
./gradlew bootRun # start on http://localhost:8080To use the MySQL prod profile instead:
./gradlew bootRun --args='--spring.profiles.active=prod'./gradlew build
java -jar build/libs/board-0.0.1-SNAPSHOT.jar./gradlew build
docker build -t board .
docker run -p 8080:8080 boardThis project was built to learn Spring Boot and is intentionally simple. Before reusing it anywhere real, these would need to be addressed:
- SQL injection — queries are built by string concatenation. Switch to parameterized
queries (
jdbcTemplate.query(sql, args...)with?placeholders). - Plaintext passwords — passwords are stored and compared as-is. Hash them (e.g. BCrypt via Spring Security).
- Forgeable auth — login state is an unsigned
login_idcookie holding the raw username; anyone can set it. Use real sessions or signed tokens (Spring Security). - Secrets in source — datasource credentials should come from environment variables,
not be committed to
application.properties. build/is committed — the compiledbuild/directory is checked in; it should be git-ignored.- Debug endpoints —
/test–/test4and thehwangtable are leftovers and should be removed.
No license specified. Personal learning project by @Froggo23.