프로젝트 개요
이 프로젝트는 Spring Boot를 백엔드 프레임워크로, Vue.js를 전면 프론트엔드 프레임워크로, 그리고 UniApp를 통해 모바일 웹 및 네이티브 애플리케이션을 구현하는 통합 애니메이션 정보 포털 사이트입니다. 사용자 중심의 콘텐츠 관리, 게시판 시스템, 로그인 인증, 세션 관리 등 핵심 기능을 포함하며, 실제 운영 환경에서 사용 가능한 수준의 코드 구조를 제공합니다.
기술 스택 구성
- 백엔드: Spring Boot 2.7+, MyBatis-Plus, JWT 기반 인증
- 프론트엔드: Vue 3 + Vite + Axios + Element Plus UI 컴포넌트 라이브러리
- 모바일 클라이언트: UniApp (Vue 3 기반 하이브리드 앱)
- 데이터베이스: MySQL 8.0, UTF-8 인코딩
- 보안: Token 기반 인증, 요청 필터링, 권한 체크, 비밀번호 암호화 처리
핵심 기능 설계
시스템은 사용자 인증, 콘텐츠 게시/댓글, 주소 관리, 사용자 역할 제어 등을 중심으로 설계되었습니다. 특히, 다양한 접근 방식에 대한 유연한 대응을 위해 미들웨어 기반의 인증 필터가 적용되어 있으며, 공통적인 로직을 추상화하여 유지보수성과 확장성을 극대화했습니다.
코드 예시: 인증 토큰 생성 및 검증
// 토큰 생성 메서드
public String generateSessionToken(Long userId, String userName, String roleType, Date expireTime) {
String token = RandomStringUtils.randomAlphanumeric(32);
// 기존 토큰 존재 여부 확인
TokenRecord existing = tokenMapper.selectOne(new QueryWrapper<TokenRecord>()
.eq("user_id", userId)
.eq("role", roleType));
if (existing != null) {
existing.setToken(token);
existing.setExpireTime(expireTime);
tokenMapper.updateById(existing);
} else {
TokenRecord newRecord = new TokenRecord();
newRecord.setUserId(userId);
newRecord.setUsername(userName);
newRecord.setRole(roleType);
newRecord.setToken(token);
newRecord.setExpireTime(expireTime);
tokenMapper.insert(newRecord);
}
return token;
}
// 요청 인증 필터
@Component
public class AuthFilter implements HandlerInterceptor {
private static final String AUTH_HEADER = "X-AUTH-TOKEN";
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// CORS 설정
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-AUTH-TOKEN");
response.setHeader("Access-Control-Max-Age", "3600");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return false;
}
// 무시 대상 엔드포인트 체크
if (handler instanceof HandlerMethod) {
IgnoreAuth ignore = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
if (ignore != null) return true;
}
// 헤더에서 토큰 추출
String authToken = request.getHeader(AUTH_HEADER);
if (authToken == null || authToken.isEmpty()) {
sendErrorResponse(response, "인증 토큰이 누락되었습니다.");
return false;
}
TokenRecord tokenInfo = tokenService.validateToken(authToken);
if (tokenInfo == null) {
sendErrorResponse(response, "유효하지 않은 또는 만료된 토큰입니다.");
return false;
}
// 세션에 사용자 정보 저장
request.getSession().setAttribute("userId", tokenInfo.getUserId());
request.getSession().setAttribute("role", tokenInfo.getRole());
request.getSession().setAttribute("username", tokenInfo.getUsername());
return true;
}
private void sendErrorResponse(HttpServletResponse response, String message) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
try (PrintWriter writer = response.getWriter()) {
writer.write("{\"code\":401,\"msg\":\"" + message + "\"}");
}
}
}
데이터베이스 스키마 예시
CREATE TABLE user_profile (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
nickname VARCHAR(100),
gender VARCHAR(10),
phone VARCHAR(20),
avatar_url TEXT,
score DOUBLE DEFAULT 0.0,
balance DECIMAL(10,2) DEFAULT 0.0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE forum_post (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
title VARCHAR(255) NOT NULL,
content LONGTEXT NOT NULL,
parent_id BIGINT DEFAULT NULL,
user_id BIGINT NOT NULL,
username VARCHAR(100) NOT NULL,
avatar_url TEXT,
status VARCHAR(20) DEFAULT 'active',
is_pinned TINYINT DEFAULT 0,
pin_time DATETIME NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE user_address (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
user_id BIGINT NOT NULL,
recipient_name VARCHAR(100) NOT NULL,
contact_phone VARCHAR(20) NOT NULL,
full_address VARCHAR(500) NOT NULL,
is_default TINYINT DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
테스트 사례 요약
| 테스트 항목 | 입력 값 | 예상 결과 | 실제 결과 | 결과 |
|---|---|---|---|---|
| 로그인 성공 | admin / admin123 / 정확한 캡차 | 토큰 발급 및 메인 페이지 이동 | 정상 동작 | 통과 |
| 비밀번호 오류 | admin / wrongpass / 정확한 캡차 | 오류 메시지 출력 | 비밀번호 불일치 | 통과 |
| 캡차 오류 | admin / admin123 / 잘못된 캡차 | 캡차 오류 알림 | 캡차 오류 발생 | 통과 |
| 사용자 추가 | newuser / 123456 / 일반 사용자 | DB에 추가 및 목록 표시 | 추가 완료 | 통과 |
| 사용자 삭제 | 선택 후 삭제 | 확인 팝업 → 삭제 완료 | 성공적으로 삭제됨 | 통과 |
배포 및 실행 가이드
프로젝트는 다음 단계로 배포 가능합니다:
- MySQL 데이터베이스 생성 및 스키마 적용
- IDEA 또는 VS Code에서 백엔드 프로젝트 열기, 의존성 다운로드 (Maven)
- application.yml 파일 내 데이터베이스 연결 정보 수정
- 백엔드 서버 실행 (`mvn spring-boot:run`)
- 프론트엔드 폴더 진입 → `npm install`, `npm run dev` 실행
- UniApp 프로젝트를 HBuilderX에서 열고, 백엔드 주소 연결 후 앱 빌드
전체 과정에 대한 영상 설명 및 디버깅 팁은 별도의 설명 영상에서 제공됩니다.