ЛЕКЦ 12: ВЭБ ПРОГРАМЧЛАЛ (Java Web Programming)
Хичээлийн зорилго: HTTP протокол, Servlet, JSP, MVC загвар, Spring Boot Web (Thymeleaf + REST), CRUD үйлдлүүд, Session/Cookie удирдлага, Form validation, аюулгүй байдал, вэб аппликейшний шилдэг туршлагуудыг эзэмшүүлэх.
Хамрах хүрээ: HTTP Request/Response, Servlet Lifecycle, JSP (Expression Language, JSTL), MVC Pattern, Spring Boot Web, Thymeleaf, Form Handling, CRUD Operations, Session & Cookie, CSRF Protection, Filter & Interceptor, Error Handling, Static Resources, Deployment.
Эх сурвалж: Lectures Web I-III, Lecture 07 (Servlets & JSP), Lecture 08 (Web CRUD), Lecture 09 (State Management & Security), Lecture 11 (Web App Best Practices), Tim Downey — Guide to Web Development with Java.
ХЭСЭГ 1: ОНОЛЫН СУУРЬ (Theory & Foundations)
1.1 HTTP Протокол — Вэбийн суурь
💡 Зүйрлэл: HTTP = Шуудангийн систем. Client (та) = Захидал бичигч. Server = Шуудангийн алба. Request = Захидал. Response = Хариу захидал. URL = Хаяг.
HTTP Request бүтэц:
┌─────────────────────────────────────────┐
│ GET /api/students/1 HTTP/1.1 │ ← Request Line (Method + URL + Version)
│ Host: localhost:8080 │ ← Headers
│ Accept: text/html │
│ Cookie: JSESSIONID=abc123 │
│ │
│ (Body — GET-д ихэвчлэн байхгүй) │ ← Request Body
└─────────────────────────────────────────┘
HTTP Response бүтэц:
┌─────────────────────────────────────────┐
│ HTTP/1.1 200 OK │ ← Status Line
│ Content-Type: text/html; charset=UTF-8 │ ← Headers
│ Set-Cookie: JSESSIONID=abc123 │
│ │
│ <html><body>Hello</body></html> │ ← Response Body
└─────────────────────────────────────────┘
HTTP Method-ууд:
| Method | Зорилго | Idempotent | Body |
|---|
| GET | Өгөгдөл АВАХ (унших) | ✅ Тийм | ❌ Байхгүй |
| POST | Өгөгдөл ҮҮСГЭХ (бичих) | ❌ Үгүй | ✅ Байна |
| PUT | Өгөгдөл бүрэн ШИНЭЧЛЭХ | ✅ Тийм | ✅ Байна |
| DELETE | Өгөгдөл УСТГАХ | ✅ Тийм | ❌ Байхгүй |
| PATCH | Өгөгдөл хэсэгчлэн шинэчлэх | ❌ Үгүй | ✅ Байна |
HTTP Status Code:
| Код | Утга | Жишээ |
|---|
| 200 | OK — Амжилттай | GET хариу |
| 201 | Created — Үүсгэсэн | POST хариу |
| 301 | Moved Permanently — Шилжсэн | Redirect |
| 302 | Found — Түр шилжүүлэх | Login дараа redirect |
| 400 | Bad Request — Буруу хүсэлт | Validation алдаа |
| 401 | Unauthorized — Нэвтрэлтгүй | Login хэрэгтэй |
| 403 | Forbidden — Эрхгүй | Зөвшөөрөлгүй |
| 404 | Not Found — Олдсонгүй | URL буруу |
| 500 | Internal Server Error — Серверийн алдаа | Exception |
1.2 Servlet — Java Web-ийн суурь
Servlet гэж юу вэ?
Servlet = Java CLASS бөгөөд HTTP хүсэлт хүлээн авч, боловсруулж, хариу буцаана. Java web-ийн хамгийн доод түвшний технологи.
Client (Browser)
│
│ HTTP Request
▼
┌──────────────────┐
│ Web Server │
│ (Tomcat) │
│ │
│ ┌────────────┐ │
│ │ Servlet │ │ ← Java class
│ │ Container │ │
│ └────────────┘ │
│ │
└──────────────────┘
│
│ HTTP Response
▼
Client (Browser)
Servlet Lifecycle (Амьдралын мөчлөг):
1. Loading: Web server → Servlet class АЧААЛАХ
2. init(): Servlet ЭХЛҮҮЛЭХ (нэг удаа)
3. service(): Хүсэлт бүрт → doGet() / doPost() ДУУДАХ (олон удаа)
4. destroy(): Servlet УСТГАХ (нэг удаа)
@WebServlet("/students")
public class StudentServlet extends HttpServlet {
@Override
public void init() throws ServletException {
// Нэг удаа — DB холболт, тохиргоо
System.out.println("Servlet initialized!");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// GET хүсэлт — Оюутнуудын жагсаалт
List<Student> students = studentDAO.findAll();
request.setAttribute("students", students);
request.getRequestDispatcher("/WEB-INF/views/students.jsp")
.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// POST хүсэлт — Шинэ оюутан нэмэх
String name = request.getParameter("name");
String email = request.getParameter("email");
studentDAO.save(new Student(name, email));
response.sendRedirect("/students"); // PRG Pattern
}
@Override
public void destroy() {
// Нэг удаа — Нөөц чөлөөлөх
System.out.println("Servlet destroyed!");
}
}
Servlet тохиргоо:
| Арга | Тайлбар |
|---|
| @WebServlet("/path") | Annotation-аар тохируулах (шинэ) |
| web.xml | XML файлаар тохируулах (хуучин) |
<!-- web.xml тохиргоо (хуучин арга) -->
<servlet>
<servlet-name>studentServlet</servlet-name>
<servlet-class>com.example.StudentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>studentServlet</servlet-name>
<url-pattern>/students</url-pattern>
</servlet-mapping>
1.3 JSP (JavaServer Pages)
JSP гэж юу вэ?
JSP = HTML дотор JAVA КОД бичих технологи. Servlet-ийн VIEW хэсэг. Server дээр HTML болж хөрвөнө.
┌─────────────────────────┐
│ students.jsp │
│ │
│ <html> │
│ <h1>${title}</h1> │ ← Expression Language (EL)
│ <c:forEach ...> │ ← JSTL Tag
│ ${student.name} │
│ </c:forEach> │
│ </html> │
└─────────────────────────┘
│
│ Server дээр хөрвөнө
▼
┌─────────────────────────┐
│ HTML (browser-д) │
│ │
│ <html> │
│ <h1>Оюутнууд</h1> │
│ <p>Бат</p> │
│ <p>Сараа</p> │
│ </html> │
└─────────────────────────┘
JSP Syntax:
| Syntax | Зорилго | Жишээ |
|---|
<%= ... %> | Expression (утга хэвлэх) | <%= student.getName() %> |
<% ... %> | Scriptlet (Java код) | <% for(...) { } %> |
<%! ... %> | Declaration (field, method) | <%! int count = 0; %> |
${...} | EL (Expression Language) | ${student.name} ← ЗӨВЛӨМЖТЭЙ |
<c:forEach> | JSTL (Tag library) | Давталт, нөхцөл |
JSP + JSTL жишээ:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head><title>Оюутнууд</title></head>
<body>
<h1>Оюутнуудын жагсаалт</h1>
<table border="1">
<tr>
<th>ID</th>
<th>Нэр</th>
<th>Email</th>
<th>Үйлдэл</th>
</tr>
<c:forEach var="student" items="${students}">
<tr>
<td>${student.id}</td>
<td>${student.name}</td>
<td>${student.email}</td>
<td>
<a href="/students/edit?id=${student.id}">Засах</a>
<a href="/students/delete?id=${student.id}">Устгах</a>
</td>
</tr>
</c:forEach>
</table>
<h2>Шинэ оюутан нэмэх</h2>
<form action="/students" method="POST">
<input type="text" name="name" placeholder="Нэр" required>
<input type="email" name="email" placeholder="Email" required>
<button type="submit">Нэмэх</button>
</form>
</body>
</html>
1.4 MVC Pattern — Вэб аппын бүтэц
MVC гэж юу вэ?
┌──────────────────────────────────────────────────────┐
│ MVC Pattern │
│ │
│ ┌─────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ VIEW │◄───│ CONTROLLER │───►│ MODEL │ │
│ │ (JSP/ │ │ (Servlet/ │ │ (Entity/ │ │
│ │Thymeleaf)│ │ Controller) │ │ Service) │ │
│ └─────────┘ └──────┬───────┘ └──────────────┘ │
│ │ │
│ HTML харуулах Хүсэлт удирдах Бизнес логик + DB │
└──────────────────────────────────────────────────────┘
Browser → Controller → Service → Repository → DB
↓
View (HTML)
↓
Browser
| Хэсэг | Үүрэг | Жишээ |
|---|
| Model | Өгөгдөл + бизнес логик | Student entity, StudentService |
| View | Харуулалт (UI) | JSP, Thymeleaf template |
| Controller | Хүсэлт хүлээн авч, удирдах | Servlet, @Controller |
1.5 Spring Boot Web — Орчин үеийн Java Web
Яагаад Spring Boot?
| Servlet/JSP | Spring Boot Web |
|---|
| web.xml тохиргоо | Автомат тохиргоо |
| Tomcat тусад deploy | Embedded Tomcat (JAR дотор) |
| Manual dependency | Spring Starter |
| Servlet extend | @Controller annotation |
| JSP (хуучин) | Thymeleaf (орчин үе) |
Spring Boot Web dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
@Controller vs @RestController:
| Annotation | Буцаах зүйл | Хэрэглээ |
|---|
| @Controller | VIEW нэр (HTML template) | Вэб хуудас (Thymeleaf) |
| @RestController | JSON/XML (Response body) | REST API |
// @Controller — HTML хуудас буцаана
@Controller
@RequestMapping("/students")
public class StudentController {
@GetMapping
public String list(Model model) {
model.addAttribute("students", studentService.findAll());
return "students/list"; // → templates/students/list.html
}
}
// @RestController — JSON буцаана
@RestController
@RequestMapping("/api/students")
public class StudentApiController {
@GetMapping
public List<StudentResponse> list() {
return studentService.findAll(); // → JSON
}
}
1.6 Thymeleaf — Орчин үеийн Template Engine
Thymeleaf гэж юу вэ?
Thymeleaf = Server-side HTML template engine. JSP-ийн ОРЧИН ҮЕИЙН ОРЛУУЛАГЧ. HTML файлыг browser-д шууд нээж болно (Natural Template).
Thymeleaf vs JSP:
| Шинж | JSP | Thymeleaf |
|---|
| Файл | .jsp | .html |
| Syntax | <%= %>, <c:forEach> | th:text, th:each |
| Browser | Шууд нээхгүй | ✅ Шууд нээж болно |
| Spring Boot | Тусдаа тохиргоо | Автомат |
| Байршил | /WEB-INF/views/ | /templates/ |
Thymeleaf syntax:
<!-- templates/students/list.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Оюутнууд</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<h1 th:text="${title}">Оюутнуудын жагсаалт</h1>
<!-- Хүснэгт -->
<table>
<thead>
<tr>
<th>ID</th>
<th>Нэр</th>
<th>Email</th>
<th>GPA</th>
<th>Үйлдэл</th>
</tr>
</thead>
<tbody>
<tr th:each="student : ${students}">
<td th:text="${student.id}">1</td>
<td th:text="${student.name}">Бат</td>
<td th:text="${student.email}">bat@test.com</td>
<td th:text="${student.gpa}">3.5</td>
<td>
<a th:href="@{/students/edit/{id}(id=${student.id})}">Засах</a>
<a th:href="@{/students/delete/{id}(id=${student.id})}"
onclick="return confirm('Устгах уу?')">Устгах</a>
</td>
</tr>
</tbody>
</table>
<!-- Хоосон байвал -->
<p th:if="${#lists.isEmpty(students)}">Оюутан бүртгэгдээгүй байна.</p>
<a th:href="@{/students/new}">+ Шинэ оюутан нэмэх</a>
</body>
</html>
Thymeleaf гол attribute-ууд:
| Attribute | Зорилго | Жишээ |
|---|
| th:text | Текст харуулах | th:text="${student.name}" |
| th:each | Давталт | th:each="s : ${students}" |
| th:if / th:unless | Нөхцөл | th:if="${students.size() > 0}" |
| th:href | Link үүсгэх | th:href="@{/students/{id}(id=${s.id})}" |
| th:action | Form action | th:action="@{/students}" |
| th:object | Form object bind | th:object="${student}" |
| th:field | Form field bind | th:field="*{name}" |
| th:value | Утга оноох | th:value="${student.name}" |
| th:src | Image src | th:src="@{/images/logo.png}" |
| th:class | CSS class | th:class="${error ? 'error' : ''}" |
| th:fragment | Дахин ашиглах хэсэг | Layout, header, footer |
Full CRUD Flow:
CREATE: GET /students/new → Form харуулах
POST /students → Хадгалах → Redirect
READ: GET /students → Жагсаалт
GET /students/{id} → Дэлгэрэнгүй
UPDATE: GET /students/edit/{id} → Form + одоогийн утга
POST /students/edit/{id} → Шинэчлэх → Redirect
DELETE: GET /students/delete/{id} → Устгах → Redirect
Controller — Full CRUD:
@Controller
@RequestMapping("/students")
public class StudentController {
private final StudentService studentService;
// 1. READ — Жагсаалт
@GetMapping
public String list(Model model) {
model.addAttribute("students", studentService.findAll());
return "students/list";
}
// 2. CREATE — Form харуулах
@GetMapping("/new")
public String showCreateForm(Model model) {
model.addAttribute("student", new StudentForm());
return "students/form";
}
// 3. CREATE — Хадгалах
@PostMapping
public String create(@Valid @ModelAttribute("student") StudentForm form,
BindingResult result,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "students/form"; // Алдаатай бол form руу буцах
}
studentService.create(form);
redirectAttributes.addFlashAttribute("message", "Амжилттай нэмлээ!");
return "redirect:/students"; // PRG Pattern
}
// 4. UPDATE — Form + одоогийн утга
@GetMapping("/edit/{id}")
public String showEditForm(@PathVariable Long id, Model model) {
StudentForm form = studentService.getFormById(id);
model.addAttribute("student", form);
model.addAttribute("editMode", true);
return "students/form";
}
// 5. UPDATE — Шинэчлэх
@PostMapping("/edit/{id}")
public String update(@PathVariable Long id,
@Valid @ModelAttribute("student") StudentForm form,
BindingResult result,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "students/form";
}
studentService.update(id, form);
redirectAttributes.addFlashAttribute("message", "Амжилттай шинэчиллээ!");
return "redirect:/students";
}
// 6. DELETE — Устгах
@GetMapping("/delete/{id}")
public String delete(@PathVariable Long id, RedirectAttributes redirectAttributes) {
studentService.delete(id);
redirectAttributes.addFlashAttribute("message", "Амжилттай устгалаа!");
return "redirect:/students";
}
}
<!-- templates/students/form.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Оюутан</title></head>
<body>
<h1 th:text="${editMode} ? 'Оюутан засах' : 'Шинэ оюутан'">Form</h1>
<form th:action="${editMode} ? @{/students/edit/{id}(id=${student.id})} : @{/students}"
th:object="${student}" method="POST">
<div>
<label>Нэр:</label>
<input type="text" th:field="*{name}">
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="error"></span>
</div>
<div>
<label>Email:</label>
<input type="email" th:field="*{email}">
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="error"></span>
</div>
<div>
<label>GPA:</label>
<input type="number" step="0.1" th:field="*{gpa}">
<span th:if="${#fields.hasErrors('gpa')}" th:errors="*{gpa}" class="error"></span>
</div>
<button type="submit" th:text="${editMode} ? 'Шинэчлэх' : 'Нэмэх'">Submit</button>
<a th:href="@{/students}">Буцах</a>
</form>
</body>
</html>
PRG Pattern (Post-Redirect-Get):
POST /students (form submit)
│
│ Хадгалах
│
▼
302 Redirect → GET /students
│
│ Жагсаалт харуулах
│
▼
200 OK (HTML)
Яагаад PRG?
- Хэрэглэгч F5 (refresh) дарвал → POST давтагдахгүй!
- POST → Redirect → GET = Давхар бичлэг ҮҮСЭХГҮЙ
public class StudentForm {
private Long id;
@NotBlank(message = "Нэр хоосон байж болохгүй")
@Size(min = 2, max = 50, message = "Нэр 2-50 тэмдэгт байна")
private String name;
@NotBlank(message = "Email хоосон байж болохгүй")
@Email(message = "Email формат буруу")
private String email;
@NotNull(message = "GPA хоосон байж болохгүй")
@DecimalMin(value = "0.0", message = "GPA 0.0-аас багагүй")
@DecimalMax(value = "4.0", message = "GPA 4.0-аас ихгүй")
private Double gpa;
// getters, setters
}
Validation алдаа Thymeleaf-д:
<!-- Бүх алдааг нэг дор харуулах -->
<div th:if="${#fields.hasAnyErrors()}" class="alert alert-danger">
<ul>
<li th:each="err : ${#fields.allErrors()}" th:text="${err}"></li>
</ul>
</div>
<!-- Field бүрийн алдаа -->
<input type="text" th:field="*{name}" th:classappend="${#fields.hasErrors('name')} ? 'is-invalid'">
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="invalid-feedback"></div>
1.9 Session & Cookie — State Management
HTTP = Stateless → Session/Cookie-аар state удирдах
┌────────┐ ┌────────┐
│ Client │ ── Request + Cookie ───► │ Server │
│ │ ◄── Response + Set-Cookie│ │
│ │ │ │
│ Cookie:│ │Session:│
│ JSESSIONID=abc123 │ abc123:│
│ │ user: "Бат"│
│ │ role: "ADMIN"│
└────────┘ └────────┘
Session vs Cookie:
| Шинж | Session | Cookie |
|---|
| Хадгалах | SERVER дээр | CLIENT (browser) дээр |
| Хэмжээ | Хязгааргүй | 4KB |
| Аюулгүй | Илүү аюулгүй | XSS-д эмзэг |
| Хугацаа | Timeout (30 мин) | Тохируулах боломжтой |
| Хэрэглээ | Login, cart | Remember me, preferences |
HttpSession ашиглах:
@Controller
public class AuthController {
// Login
@PostMapping("/login")
public String login(@RequestParam String email,
@RequestParam String password,
HttpSession session,
RedirectAttributes redirectAttributes) {
User user = userService.authenticate(email, password);
if (user != null) {
session.setAttribute("currentUser", user);
session.setAttribute("role", user.getRole());
return "redirect:/dashboard";
}
redirectAttributes.addFlashAttribute("error", "Email эсвэл password буруу!");
return "redirect:/login";
}
// Logout
@GetMapping("/logout")
public String logout(HttpSession session) {
session.invalidate(); // Session бүрэн устгах
return "redirect:/login";
}
// Dashboard — Session шалгах
@GetMapping("/dashboard")
public String dashboard(HttpSession session, Model model) {
User user = (User) session.getAttribute("currentUser");
if (user == null) {
return "redirect:/login"; // Нэвтрээгүй бол
}
model.addAttribute("user", user);
return "dashboard";
}
}
Cookie ашиглах:
// Cookie тохируулах
@GetMapping("/set-theme")
public String setTheme(@RequestParam String theme, HttpServletResponse response) {
Cookie cookie = new Cookie("theme", theme);
cookie.setMaxAge(30 * 24 * 60 * 60); // 30 хоног
cookie.setHttpOnly(true); // XSS хамгаалалт
cookie.setSecure(true); // HTTPS only
cookie.setPath("/");
response.addCookie(cookie);
return "redirect:/";
}
// Cookie унших
@GetMapping("/")
public String home(@CookieValue(value = "theme", defaultValue = "light") String theme,
Model model) {
model.addAttribute("theme", theme);
return "home";
}
1.10 Filter & Interceptor — Хүсэлт шүүх
Filter (Servlet түвшин):
@Component
@Order(1)
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
long start = System.currentTimeMillis();
chain.doFilter(request, response); // Дараагийн filter/servlet руу
long duration = System.currentTimeMillis() - start;
System.out.println(req.getMethod() + " " + req.getRequestURI() + " → " + duration + "ms");
}
}
Interceptor (Spring MVC түвшин):
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("currentUser") == null) {
response.sendRedirect("/login");
return false; // Controller руу ДАМЖУУЛАХГҮЙ
}
return true; // Controller руу дамжуулах
}
}
// Interceptor бүртгэх
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/dashboard/**", "/students/**")
.excludePathPatterns("/login", "/register", "/css/**", "/js/**");
}
}
Filter vs Interceptor:
| Шинж | Filter | Interceptor |
|---|
| Түвшин | Servlet (доод) | Spring MVC (дээд) |
| Хамрах | Бүх хүсэлт (static ч) | Controller хүсэлт |
| Тохиргоо | @Component | WebMvcConfigurer |
| Хэрэглээ | Logging, CORS, encoding | Auth, role шалгалт |
1.11 Thymeleaf Layout — Дахин ашиглах
Fragment ашиглах:
<!-- templates/fragments/header.html -->
<header th:fragment="header">
<nav>
<a th:href="@{/}">Нүүр</a>
<a th:href="@{/students}">Оюутнууд</a>
<span th:if="${session.currentUser != null}">
<span th:text="${session.currentUser.name}">User</span>
<a th:href="@{/logout}">Гарах</a>
</span>
<span th:unless="${session.currentUser != null}">
<a th:href="@{/login}">Нэвтрэх</a>
</span>
</nav>
</header>
<!-- templates/fragments/footer.html -->
<footer th:fragment="footer">
<p>© 2024 Student Management System</p>
</footer>
<!-- templates/students/list.html — Fragment ашиглах -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Оюутнууд</title></head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main>
<!-- Амжилтын мэдэгдэл -->
<div th:if="${message}" class="alert alert-success" th:text="${message}"></div>
<h1>Оюутнуудын жагсаалт</h1>
<!-- Хүснэгт -->
</main>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
1.12 Static Resources & Error Handling
Static файлууд:
src/main/resources/
├── static/
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── app.js
│ └── images/
│ └── logo.png
├── templates/
│ ├── students/
│ │ ├── list.html
│ │ └── form.html
│ ├── fragments/
│ │ ├── header.html
│ │ └── footer.html
│ ├── error/
│ │ ├── 404.html
│ │ └── 500.html
│ └── index.html
└── application.yml
Error page (Custom):
<!-- templates/error/404.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>404 - Олдсонгүй</title></head>
<body>
<h1>404</h1>
<p>Хайсан хуудас олдсонгүй.</p>
<a th:href="@{/}">Нүүр хуудас руу буцах</a>
</body>
</html>
Global Exception Handler:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(StudentNotFoundException.class)
public String handleNotFound(StudentNotFoundException ex, Model model) {
model.addAttribute("error", ex.getMessage());
return "error/404";
}
@ExceptionHandler(Exception.class)
public String handleGeneral(Exception ex, Model model) {
model.addAttribute("error", "Серверийн алдаа гарлаа.");
return "error/500";
}
}
1.13 Вэб аппын шилдэг туршлагууд (Best Practices)
| # | Зарчим | Тайлбар |
|---|
| 1 | PRG Pattern | POST → Redirect → GET (давхар submit хамгаалалт) |
| 2 | Input Validation | Server-side @Valid + Client-side HTML5 |
| 3 | CSRF Protection | Spring Security CSRF token (form-д) |
| 4 | XSS Prevention | Thymeleaf автомат escape (th:text) |
| 5 | Session Timeout | server.servlet.session.timeout=30m |
| 6 | HttpOnly Cookie | cookie.setHttpOnly(true) |
| 7 | Error Page | Custom 404, 500 хуудас |
| 8 | Fragment/Layout | Header, footer дахин ашиглах |
| 9 | Flash Message | RedirectAttributes амжилт/алдаа мэдэгдэл |
| 10 | Separation | Controller → Service → Repository давхаргалах |
| 11 | Static Resources | CSS, JS, Image → /static/ |
| 12 | Pagination | Их өгөгдлийг хуудаслах (Pageable) |
| 13 | Responsive | Mobile-friendly дизайн (Bootstrap) |
| 14 | Logging | Хүсэлт, алдаа бүрийг лог бичих |
| 15 | HTTPS | Production-д заавал HTTPS |
ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)
| # | Англи нэр томьёо | Монгол утга | Дэлгэрэнгүй тайлбар |
|---|
| 1 | HTTP | Гипертекст дамжуулах протокол | Client-Server хоорондын хүсэлт/хариу дамжуулах протокол. |
| 2 | Servlet | Серовлет | HTTP хүсэлт хүлээн авч, боловсруулж, хариу буцаах Java class. |
| 3 | JSP | Java серверийн хуудас | HTML дотор Java код бичих template технологи. |
| 4 | Thymeleaf | Таймлиф | Орчин үеийн server-side HTML template engine — Natural template. |
| 5 | MVC | Загвар-Харагдац-Удирдлага | Model-View-Controller — Вэб аппын бүтэц хуваах загвар. |
| 6 | Controller | Удирдагч | HTTP хүсэлт хүлээн авч, Service дуудаж, View буцаах. |
| 7 | Model | Загвар | Өгөгдөл + бизнес логик (Entity, Service). |
| 8 | View | Харагдац | Хэрэглэгчид харуулах UI (HTML template). |
| 9 | CRUD | Үүсгэх-Унших-Шинэчлэх-Устгах | Create, Read, Update, Delete — Өгөгдлийн 4 үндсэн үйлдэл. |
| 10 | Session | Сессия | Server дээр хэрэглэгчийн state хадгалах механизм. |
| 11 | Cookie | Күүки | Client (browser) дээр жижиг өгөгдөл хадгалах механизм. |
| 12 | JSESSIONID | Сессийн ID | Tomcat-ийн session cookie — Хэрэглэгчийг таних. |
| 13 | PRG Pattern | Post-Redirect-Get | POST → 302 Redirect → GET — Давхар submit хамгаалалт. |
| 14 | CSRF | Хуурамч хүсэлт | Cross-Site Request Forgery — Хэрэглэгчийн нэрээр хуурамч хүсэлт. |
| 15 | XSS | Хөндлөн скрипт | Cross-Site Scripting — Хортой JavaScript оруулах халдлага. |
| 16 | Filter | Шүүлтүүр | Servlet түвшинд хүсэлт/хариуг шүүх (logging, encoding). |
| 17 | Interceptor | Тасалдуулагч | Spring MVC түвшинд хүсэлтийг шалгах (auth, role). |
| 18 | @Controller | Контроллер | Spring MVC — HTML view буцаах controller annotation. |
| 19 | @RestController | REST контроллер | JSON/XML буцаах controller — @Controller + @ResponseBody. |
| 20 | @RequestMapping | Хүсэлт зураглалт | URL path-г controller method-д холбох. |
| 21 | @GetMapping | GET зураглалт | HTTP GET хүсэлт хүлээн авах method. |
| 22 | @PostMapping | POST зураглалт | HTTP POST хүсэлт хүлээн авах method. |
| 23 | @PathVariable | Замын хувьсагч | URL-аас утга авах — /students/{id}. |
| 24 | @RequestParam | Хүсэлтийн параметр | Query parameter авах — ?name=Бат. |
| 25 | @ModelAttribute | Загварын атрибут | Form өгөгдлийг Java object-д автомат bind хийх. |
| 26 | @Valid | Баталгаажуулалт | Form object-ийн validation annotation-уудыг шалгах. |
| 27 | BindingResult | Холболтын үр дүн | Validation алдааг хадгалах object. |
| 28 | RedirectAttributes | Чиглүүлэлтийн атрибут | Redirect хийхэд flash message дамжуулах. |
| 29 | th:each | Давталт | Thymeleaf — Collection давталт (for-each). |
| 30 | th:text | Текст | Thymeleaf — Элементийн текстийг тохируулах + XSS escape. |
| 31 | th:field | Талбар | Thymeleaf — Form field-г object property-д bind хийх. |
| 32 | th:fragment | Хэсэг | Thymeleaf — Дахин ашиглах HTML хэсэг (header, footer). |
| 33 | Expression Language | Илэрхийллийн хэл | ${...} — JSP/Thymeleaf-д утга харуулах. |
| 34 | JSTL | JSP стандарт тагийн сан | JSP-д <c:forEach>, <c:if> зэрэг tag-ууд. |
| 35 | Tomcat | Томкат | Apache-ийн Servlet container / Web server. |
| 36 | Web Container | Вэб контейнер | Servlet ажиллуулах орчин (Tomcat, Jetty). |
| 37 | Embedded Server | Суулгасан сервер | Spring Boot-д Tomcat JAR дотор ажиллана. |
| 38 | Static Resource | Статик нөөц | CSS, JS, Image — Server боловсруулахгүй, шууд буцаах. |
| 39 | @ControllerAdvice | Контроллер зөвлөмж | Бүх controller-д хамаарах global exception handler. |
| 40 | Pagination | Хуудаслалт | Их өгөгдлийг хуудас хуудсаар харуулах (Page, Pageable). |