일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- sqld 시험 정리
- .NET 프레임워크 기초
- 빅분기 필기 pdf
- Mac OS .NET 개발환경
- rdbms nosql 차이
- 컴포지션과 집합
- 빅분기
- SQL
- 오늘은 1일 2쿼리
- 운영체제 면접 답변
- 네트워크 면접 답변
- 빅데이터 분석기사
- MySQL
- 빅분기 1유형
- late 키워드
- mysql mongo 성능 비교
- SpringBoot와 .NET의 차이점
- .NET 게시판 프로젝트
- 빅분기 캐글놀이터
- 작업 1유형
- 1일 1쿼리
- .NET Razor
- 주말에도 1일 1쿼리
- 주말도 한다
- FLUTTER
- ?. ?? ! late
- 빅분기 판다스 100제
- 모델 학습 및 예측
- 작업 2유형
- flutter 믹스인
- Today
- Total
subindev 님의 블로그
[.NET] 2. ASP.NET Core MVC + MySQL 게시판 프로젝트 (VS Code) 본문
📘 ASP.NET Core MVC + MySQL 게시판 만들기
MacOS 환경에 C#과 .NET 개발 환경을 구축한 뒤,
간단한 게시판 프로젝트를 만들어 보기로 했다.
우선 Post 엔티티(모델)을 만들고 글쓰기, 수정, 삭제, 조회 기능을 구현한 뒤,
이후에는 회원가입과 사용자(User), 댓글 기능까지 확장하면서 점차 .NET에 익숙해져보려 한다.
오늘은 제공된 예제 코드를 타이핑하면서
ASP.NET Core MVC의 전반적인 구조와 흐름을 파악하는 데 집중했다.
이전에 경험한 Spring Boot Framework 덕분에 MVC 패턴 자체는 익숙했지만,
학부생 이후로 굉장히 오랜만에 접한 C#과, 새로 접하는 .NET 구조는 새로웠다.
아직 각 코드가 정확히 어떤 의미를 가지는지는 완전히 이해하지 못했지만,
하나씩 공부해가며 .NET 프레임워크의 구조와 특징을 체득해 나갈 예정이다.
또한, SpringBoot와 비교해보며 .NET 프레임워크를 빠르게 익혀나갈 계획이다.
MVC 기반 템플릿 엔진으로는 Razor 사용 (SpringBoot의 Thymeleaf 와 유사)
데이터베이스 서버는 My SQL 사용
1. EF Core + MySQL 세팅
EF Core(Entity Framework Core)
→ .NET에서 사용하는 ORM(Object-Relational Mapping) 프레임워크이다.
ORM은 객체와 데이터베이스의 테이블을 연결해주는 기술로, SQL문을 직접 작성하지 않아도 CRUD가 가능하다.
(SpringBoot의 JPA 개념과 유사)
+) 제공자(Provider)의 역할
EF Core는 단독으로는 “ORM의 틀”일 뿐
→ “어떤 DB를 쓸 것인가”는 제공자(Provider) 가 담당한다.
- SQLite, SQL Server, MySQL, PostgreSQL
나는 기존 사용하던 MySQL을 연결하였다.
MySQL용 패키지 설치
dotnet add package MySql.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design
2. 모델(Entity) 만들기
📁 Models/Post.cs
// 이 파일은 DB의 "Posts" 테이블에 매핑되는 엔티티(Entity) 클래스이다.
// - Spring Boot에서는 @Entity, @Table(name="posts") 같은 어노테이션을 사용했지만,
// .NET에서는 클래스 이름과 DbSet 이름이 자동으로 매핑된다.
namespace BoardApp.Models;
using System.ComponentModel.DataAnnotations; // 데이터 유효성 검사 속성을 제공하는 네임스페이스
public class Post
{
// [Key] : 기본키(Primary Key) 설정
[Key]
public int Id { get; set; }
// [Required] : 필수값 설정 (NULL 허용 X)
// [StringLength(100)] : 최대 길이 제한
[Required, StringLength(100)]
public string Title { get; set; } = string.Empty;
[Required]
public string Content { get; set; } = string.Empty;
[Required]
public string Author { get; set; } = string.Empty;
// 작성 시간 (기본값 = 현재 UTC 시간)
// - Spring Boot에서는 @CreationTimestamp 와 같은 역할
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
3. 데이터베이스 연결 설정
📄 appsettings.json
"ConnectionStrings": {
"Default": "server=localhost;port=3306;database=BoardDb;user=root;password=비밀번호;SslMode=Preferred;AllowPublicKeyRetrieval=True"
}
📄 Data/AppDbContext.cs
using Microsoft.EntityFrameworkCore;
using BoardApp.Models;
namespace BoardApp.Data;
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
public DbSet<Post> Posts => Set<Post>();
}
📄 Program.cs
using BoardApp.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
// DB 연결
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseMySQL(builder.Configuration.GetConnectionString("Default")));
var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Posts}/{action=Index}/{id?}");
app.Run();
4. DB 초기화 (Migration)
dotnet build
dotnet ef migrations add Init
dotnet ef database update
- migrations add : 데이터베이스 구조(스키마)를 코드로 정의
- database update : 실제 DB에 반영 → BoardDb 및 Posts 테이블 생성됨
5. 컨트롤러 만들기
📁 Controllers/PostsController.cs
// 이 컨트롤러는 게시글 CRUD를 처리하는 핵심 클래스이다.
// - Spring Boot에서는 @RestController, @Controller 와 @RequestMapping("/posts") 로 역할을 지정했지만,
// ASP.NET에서는 "PostsController" 이름 자체로 기본 라우팅 경로가 매핑된다. (ex. /Posts/Index)
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using BoardApp.Data;
using BoardApp.Models;
namespace BoardApp.Controllers;
public class PostsController : Controller
{
// AppDbContext : DB 연결 객체 (Spring의 JPA Repository와 유사한 역할)
private readonly AppDbContext _context;
// 의존성 주입 (Dependency Injection)
// - Spring에서는 @Autowired 를 사용했지만, .NET은 생성자 주입으로
public PostsController(AppDbContext context)
{
_context = context;
}
// [1] 목록 보기 (GET)
// - Spring에서의 @GetMapping("/posts") 과 유사
// - View() 메서드는 /Views/Posts/Index.cshtml 파일을 렌더링한다.
public async Task<IActionResult> Index(string? q)
{
// IQueryable : SQL을 나중에 실행하기 위한 지연 쿼리
var query = _context.Posts.AsQueryable();
// 최신 글이 위로 오도록 정렬
var posts = await query.OrderByDescending(p => p.Id).ToListAsync();
// View(posts) → Index.cshtml 에 전달
return View(posts);
}
// [2] 상세 보기 (GET)
// - Spring의 @GetMapping("/posts/{id}") 과 비슷
public async Task<IActionResult> Details(int id)
{
var post = await _context.Posts.FindAsync(id);
return post == null ? NotFound() : View(post);
}
// [3] 글 작성 폼 (GET)
// - Spring에서는 단순히 View를 반환하는 Controller 메서드
public IActionResult Create() => View();
// [4] 글 작성 처리 (POST)
// - Spring의 @PostMapping("/posts") 과 동일한 역할
[HttpPost]
public async Task<IActionResult> Create(Post post)
{
// ModelState : 유효성 검사 결과를 포함 (Spring의 BindingResult 유사)
if (!ModelState.IsValid)
return View(post);
_context.Add(post); // DB에 추가
await _context.SaveChangesAsync(); // 실제 INSERT 쿼리 실행
return RedirectToAction(nameof(Index)); // 완료 후 목록으로 이동
}
// [5] 수정 폼 (GET)
// - Spring의 @GetMapping("/posts/{id}/edit") 과 유사
public async Task<IActionResult> Edit(int id)
{
var post = await _context.Posts.FindAsync(id);
return post == null ? NotFound() : View(post);
}
// [6] 수정 처리 (POST)
// - Spring의 @PutMapping("/posts/{id}") 과 유사
[HttpPost]
public async Task<IActionResult> Edit(int id, Post post)
{
// URL로 받은 id와 폼에서 전달된 id가 다르면 오류
if (id != post.Id)
return BadRequest();
if (!ModelState.IsValid)
return View(post);
_context.Update(post); // 엔티티 수정 상태로 변경
await _context.SaveChangesAsync(); // UPDATE 실행
return RedirectToAction(nameof(Index));
}
// [7] 삭제 처리 (POST)
// - Spring의 @DeleteMapping("/posts/{id}") 과 같은 역할
[HttpPost]
public async Task<IActionResult> Delete(int id)
{
var post = await _context.Posts.FindAsync(id);
if (post == null)
return NotFound();
_context.Posts.Remove(post); // 엔티티 제거
await _context.SaveChangesAsync(); // DELETE 쿼리 실행
return RedirectToAction(nameof(Index));
}
}
6. View 구성
📁 Views/Posts
파일명 | 기능 |
Index.cshtml | 게시글 목록 |
Create.cshtml | 새 글 작성 |
Edit.cshtml | 글 수정 |
Details.cshtml | 상세 보기 |
📄 Views/_ViewImports.cshtml
@using BoardApp.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using : 모델 경로 단축
TagHelpers : HTML + C# 연결 활성화
→ 두 설정 모두 Razor 뷰에서 코드 작성 편의성 향상을 위한 전역 옵션.
📄 Views/Posts/Index.cshtml
@model IEnumerable<BoardApp.Models.Post>
<!-- Razor에서 현재 View가 받을 데이터 타입 지정 -->
<h2>게시글 목록</h2>
<div class="card">
<!-- 📌 Razor의 C# 변수나 표현식은 @를 붙여 바로 사용 가능 -->
<!-- 💬 Thymeleaf에서는 ${변수명} 으로 표현 -->
<div class="toolbar">
<a asp-action="Create" class="btn btn-primary">새 글쓰기</a>
<!-- 📌 asp-action="Create" : Tag Helper 기능, 컨트롤러의 Create 액션으로 자동 링크 -->
<!-- 💬 Thymeleaf th:href="@{/posts/create}"로 표현 -->
</div>
<table class="table">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>관리</th>
</tr>
</thead>
<tbody>
@* 📌 Razor의 foreach 문 — C# 문법 그대로 사용 가능 *@
@foreach (var post in Model)
{
<tr>
<!-- 📌 @post.Id : Model(Post 객체)의 속성 접근 -->
<!-- 💬 Thymeleaf의 ${post.id} -->
<td>@post.Id</td>
<td>
<!-- 📌 asp-route-id : URL 파라미터 자동 바인딩 -->
<a asp-action="Details" asp-route-id="@post.Id">@post.Title</a>
<!-- 💬 th:href="@{/posts/{id}(id=${post.id})}" 과 동일 -->
</td>
<td>@post.Author</td>
<td>@post.CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm")</td>
<td>
<a asp-action="Edit" asp-route-id="@post.Id" class="btn btn-warning">수정</a>
<form asp-action="Delete" asp-route-id="@post.Id" method="post" style="display:inline;">
@Html.AntiForgeryToken()
<!-- 📌 보안 토큰: CSRF 방지 -->
<button type="submit" class="btn btn-danger">삭제</button>
</form>
</td>
</tr>
}
</tbody>
</table>
</div>
이해를 돕기 위해 Spring Boot의 Thymeleaf와 비교하며 코드를 작성해보았다.
언어와 템플릿 엔진은 다르지만, HTML 내부에서 데이터 객체를 다룰 수 있다는 점이 유사해서
전반적인 구조를 이해하기가 훨씬 쉬웠다.
또한 C# 코드를 바로 사용할 수 있다는 점에서 JSP와도 유사한 느낌을 받았다.
7. 디자인 스타일 추가
📄 Views/Shared/_Layout.cshtml
공통되는 디자인을 정의하는 파일 생성
<style>
:root {
--bg:#f5f5f7;--card:#fff;--text:#1d1d1f;--line:#e5e5ea;
--primary:#0a84ff;--danger:#ff3b30;--warning:#ff9f0a;
--radius:16px;--shadow:0 8px 24px rgba(0,0,0,.08);
}
body{
background:var(--bg);
font-family:-apple-system,"SF Pro Text","Noto Sans KR",sans-serif;
}
.page{max-width:960px;margin:40px auto;padding:0 20px;}
.card{
background:var(--card);
border:1px solid var(--line);
border-radius:var(--radius);
box-shadow:var(--shadow);
padding:24px;
}
.btn{padding:8px 14px;border-radius:10px;border:none;cursor:pointer;}
.btn-primary{background:var(--primary);color:white;}
.btn-danger{background:var(--danger);color:white;}
.btn-warning{background:var(--warning);color:white;}
.toolbar{display:flex;gap:8px;justify-content:flex-start;margin-top:16px;}
</style>
8. 실행 및 자동 리로드
dotnet watch run
- 코드를 저장하면 서버가 자동으로 새로 빌드되고
- 브라우저 페이지가 자동으로 새로고침됨
9. 실행 결과 화면
10/15(수) 구현 기능 요약
- 개발 환경 세팅 및 MySQL 연결
- 게시글 CRUD (목록, 작성, 수정, 삭제, 상세보기)
- dotnet watch run으로 실시간 반영
추가 예정 기능
사용자(User), 댓글(Comment), 조회수 등
'프로젝트' 카테고리의 다른 글
[.NET] 1. MacOS - ASP.NET 과 C# 개발 환경 구축 (0) | 2025.10.15 |
---|