디지털 경제의 발전과 함께 전자상거래 플랫폼은 전통적인 농산물 유통 방식을 혁신하고 있다. 본 시스템은 생산자와 소비자를 직접 연결하는 온라인 거래 플랫폼으로, 정보 비대칭 문제를 해소하고 유통 효율성을 제고하는 것을 목표로 한다. 시스템은 신선 농산물의 실시간 판매 관리, 주문 처리 자동화, 안전한 결제 연동 기능을 제공하여 사용자 경험을 향상시킨다.
백엔드는 SpringBoot 프레임워크를 기반으로 개발되었으며, Java 언어와 MySQL 데이터베이스를 사용한다. MyBatis-Plus를 활용한 ORM 설계를 통해 데이터 접근 계층의 개발 생산성을 극대화하였고, Redis 캐싱 메커니즘을 도입하여 고빈도 조회 요청에 대한 응답 속도를 개선했다. 프론트엔드는 Vue.js 3와 Composition API를 적용하여 구성하였으며, Element Plus UI 컴포넌트 라이브러리를 기반으로 반응형 인터페이스를 구현하였다.
주요 데이터 모델
사용자 정보 테이블 (user_info)
| 필드명 | 데이터 타입 | 설명 |
|---|---|---|
| user_id | BIGINT | 사용자 고유 식별자 (기본키) |
| login_id | VARCHAR(50) | 로그인 아이디 |
| pwd_hash | VARCHAR(128) | SHA-256 기반 암호화된 비밀번호 |
| full_name | VARCHAR(50) | 실명 |
| mobile | VARCHAR(15) | 휴대폰 번호 |
| email_addr | VARCHAR(60) | 이메일 주소 |
| reg_date | DATETIME | 가입 일시 (자동 생성) |
| last_access | DATETIME | 최종 접속 시간 |
| role_type | TINYINT | 권한 등급 (1: 일반, 2: 관리자) |
상품 정보 테이블 (product_info)
| 필드명 | 데이터 타입 | 설명 |
|---|---|---|
| item_id | BIGINT | 상품 고유 ID (기본키) |
| item_name | VARCHAR(120) | 상품명 |
| category_code | INT | 카테고리 코드 |
| unit_price | DECIMAL(12,2) | 단가 (원) |
| stock_count | INT | 재고 수량 |
| item_desc | TEXT | 상세 설명 |
| thumbnail_url | VARCHAR(255) | 썸네일 이미지 경로 |
| listing_date | DATETIME | 등록 일시 (자동 생성) |
| sale_status | BOOLEAN | 판매 상태 (true: 판매중) |
주문 정보 테이블 (order_record)
| 필드명 | 데이터 타입 | 설명 |
|---|---|---|
| order_no | BIGINT | 주문 번호 (기본키) |
| customer_id | BIGINT | 구매자 ID |
| product_id | BIGINT | 상품 ID |
| purchase_qty | INT | 구매 수량 |
| total_price | DECIMAL(12,2) | 총 금액 |
| order_timestamp | DATETIME | 주문 시각 (자동 생성) |
| payment_state | TINYINT | 결제 상태 (0: 대기, 1: 완료) |
| delivery_phase | TINYINT | 배송 단계 (0: 준비, 1: 출고, 2: 완료) |
기술 아키텍처
시스템은 RESTful API 기반의 전후방 분리 구조를 채택하였다. 백엔드 서버는 Spring Security를 통한 인증/인가 체계를 구축하고 JWT(JSON Web Token) 기반 세션 관리를 구현하였다. 파일 업로드 기능은 클라우드 스토리지 연동을 고려하여 설계되었으며, 결제 모듈은 가상계좌 및 카드 결제를 지원하는 PG사 API와 연동된다.
핵심 구현 코드
package com.agro.platform;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@ComponentScan(basePackages = "com.agro")
@EnableScheduling
public class AgroMarketApplication {
public static void main(String[] args) {
SpringApplication.run(AgroMarketApplication.class, args);
}
}
package com.agro.controller;
import com.agro.entity.UserInfo;
import com.agro.service.UserService;
import com.agro.util.JwtUtil;
import com.agro.util.ResultResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/auth")
@CrossOrigin(origins = "*")
public class AuthController {
@Autowired
private UserService userService;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/signin")
public ResultResponse login(@RequestBody Map credentials) {
String userId = credentials.get("username");
String password = credentials.get("password");
UserInfo user = userService.authenticateUser(userId, password);
if (user != null) {
String token = jwtUtil.generateToken(userId, user.getRoleType());
Map result = new HashMap<>();
result.put("token", token);
result.put("userInfo", user);
return ResultResponse.success("로그인 성공", result);
} else {
return ResultResponse.error("아이디 또는 비밀번호가 잘못되었습니다.");
}
}
@PostMapping("/signup")
public ResultResponse register(@RequestBody UserInfo userInfo) {
if (userService.existsByLoginId(userInfo.getLoginId())) {
return ResultResponse.error("이미 존재하는 사용자입니다.");
}
userInfo.setRegDate(new java.util.Date());
userInfo.setLastAccess(new java.util.Date());
userService.createUser(userInfo);
return ResultResponse.success("회원가입이 완료되었습니다.");
}
}