概要
消費の拡大に伴い、衣類の廃棄量は年々増加しており、資源の浪費と環境負荷が社会課題となっている。従来の回収方式では効率化と可視化が不十分であり、利用者と回収担当者のマッチングにも限界があった。本システムは、Spring Bootをバックエンドに、微信小程序をモバイル入口に、MySQLを永続化層に採用したB/Sアーキテクチャの衣類回収リサイクルプラットフォームである。利用者は微信から回収依頼を行い、付与されたポイントで景品と交換できる。管理者と回収担当者はWeb管理画面から注文の調整と進捗管理を行う。RESTful APIを介して安全かつ効率的にデータをやり取りする。
技術アーキテクチャ
- バックエンド:Spring Boot、MyBatis、Spring Security(認証)、RESTful API
- モバイルフロントエンド:微信小程序(WXML/WXSS/JavaScript)
- 管理画面:Vue.js、Element UI
- データベース:MySQL 8.0
- ビルド・実行:Maven、Tomcat(組込み)
データベース設計
以下に主要な3テーブルを示す。
利用者情報テーブル
| カラム名 | データ型 | 説明 |
|---|---|---|
| member_id | BIGINT | 主キー、会員固有ID |
| wx_openid | VARCHAR(64) | 微信アカウント連携用OpenID |
| nickname | VARCHAR(32) | 表示名 |
| mobile | VARCHAR(16) | 携帯電話番号 |
| created_at | DATETIME | 登録日時(自動生成) |
| points | INT | 所持ポイント |
回収依頼テーブル
| カラム名 | データ型 | 説明 |
|---|---|---|
| request_id | BIGINT | 主キー、回収依頼ID |
| member_id | BIGINT | 依頼者ID |
| collector_id | BIGINT | 回収担当者ID |
| category | VARCHAR(32) | 衣類カテゴリ |
| status | VARCHAR(16) | 受付/配達中/完了/キャンセル |
| pickup_addr | VARCHAR(128) | 回収先住所 |
| created_at | DATETIME | 依頼日時(自動生成) |
ポイント交換テーブル
| カラム名 | データ型 | 説明 |
|---|---|---|
| exchange_id | BIGINT | 主キー、交換履歴ID |
| member_id | BIGINT | 利用者ID |
| item_name | VARCHAR(64) | 交換景品名 |
| consumed_points | INT | 消ポイント |
| ship_status | VARCHAR(16) | 未発送/発送済/配達完了 |
| exchanged_at | DATETIME | 交換日時(自動生成) |
API設計方針
バックエンドはリソースごとにURLを設計し、HTTPメソッドで操作を区別する。認証が不要なエンドポイントはアノテーションで明示し、JWTまたはセッショントークンを検証してから後続処理を実行する。レスポンスは統一されたJSON形式で返却し、コード例を以下に示す。
実装例
アプリケーション起動クラス
package com.recycling;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
@MapperScan(basePackages = "com.recycling.mapper")
public class RecyclingPlatformApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(RecyclingPlatformApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(RecyclingPlatformApplication.class);
}
}
会員認証コントローラー
package com.recycling.controller;
import com.recycling.entity.MemberEntity;
import com.recycling.service.AuthTokenService;
import com.recycling.service.MemberService;
import com.recycling.util.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/api/members")
public class MemberController {
@Autowired
private MemberService memberService;
@Autowired
private AuthTokenService authTokenService;
@PostMapping("/auth/login")
public Response login(@RequestParam String account,
@RequestParam String password,
HttpServletRequest request) {
MemberEntity member = memberService.findByAccount(account);
if (member == null || !member.getPassword().equals(password)) {
return Response.fail("アカウントまたはパスワードが正しくありません");
}
String token = authTokenService.createToken(
member.getMemberId(), account, "member", "会員");
return Response.ok(token);
}
@PostMapping("/auth/register")
public Response register(@RequestBody MemberEntity member) {
if (memberService.existsByAccount(member.getAccount())) {
return Response.fail("既に存在するアカウントです");
}
member.setMemberId(System.currentTimeMillis());
memberService.save(member);
return Response.ok();
}
@PostMapping("/auth/logout")
public Response logout(HttpServletRequest request) {
request.getSession().invalidate();
return Response.ok();
}
@GetMapping("/profile")
public Response profile(HttpServletRequest request) {
Long memberId = (Long) request.getSession().getAttribute("memberId");
MemberEntity member = memberService.findById(memberId);
return Response.ok(member);
}
}