はじめに
本稿では、JavaとSSM(Spring+SpringMVC+MyBatis)フレームワーク、Vue.jsを組み合わせて構築したオンラインショッピングモールシステムについて解説します。このシステムは、BtoC電子商取引プラットフォームとして設計され、ユーザー管理、商品カタログ、ショッピングカート、決済処理といった主要機能を備えています。
技術スタック
バックエンドフレームワーク:Spring Boot
Spring Bootは、Springベースのアプリケーションを構築するためのフレームワークです。主な目的は、開発プロセスを簡素化し、すぐに使える機能を提供しつつ、コアの強力さと柔軟性を維持することです。
Spring Bootは、「設定より規約」という原則に基づき、自動設定機能を提供することで、開発者が定型コードの記述作業を減らすことができます。組み込みのWebサーバー(Tomcat、Undertow、Jettyなど)を備えており、アプリケーションを実行可能なJARファイルにパッケージ化できます。これにより、アプリケーションのデプロイと実行が非常に簡単になります。
さらに、Spring Bootは豊富なプラグインと拡張メカニズムを提供し、セキュリティ認証、データアクセス、メッセージキュー、キャッシュなどの機能を簡単に統合できます。
フロントエンドフレームワーク:Vue.js
Vue.jsは、ユーザーインターフェース(UI)とシングルページアプリケーション(SPA)を構築するための人気のJavaScriptフレームワークです。2014年に尤雨溪によって作成され、軽量で学習が容易、かつ柔軟なフレームワークです。
Vue.jsの主な利点は、レスポンシブなデータバインディングシステムにあります。これにより、開発者はビューとデータの変更を簡単に管理できます。また、簡潔で直感的なAPIセットを提供し、開発プロセスをより効率的で柔軟にします。
Vueのコンポーネントベースの開発モデルにより、開発者はアプリケーションを小さく独立したコンポーネントに分割し、これらを組み合わせて完全なアプリケーションを構築できます。このモデルにより、コードの再利用性が高まり、保守とテストも容易になります。
コア実装
アプリケーションエントリーポイント
package com.ecommerce;
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.ecommerce.mapper"})
public class EcommerceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(EcommerceApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {
return applicationBuilder.sources(EcommerceApplication.class);
}
}
ユーザーコントローラ
package com.ecommerce.controller;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import com.ecommerce.utils.ValidatorUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.ecommerce.entity.CustomerEntity;
import com.ecommerce.entity.view.CustomerView;
import com.ecommerce.service.CustomerService;
import com.ecommerce.service.TokenService;
import com.ecommerce.utils.PageUtils;
import com.ecommerce.utils.R;
import com.ecommerce.utils.MPUtil;
/**
* 顧客管理コントローラ
*/
@RestController
@RequestMapping("/customer")
public class CustomerController {
@Autowired
private CustomerService customerService;
@Autowired
private TokenService tokenService;
/**
* ログイン
*/
@IgnoreAuth
@RequestMapping(value = "/login")
public R login(String username, String password, HttpServletRequest request) {
CustomerEntity user = customerService.selectOne(
new EntityWrapper<CustomerEntity>().eq("account_name", username));
if(user == null || !user.getPassword().equals(password)) {
return R.error("アカウント名またはパスワードが正しくありません");
}
String token = tokenService.generateToken(
user.getId(), username, "customer", "顧客");
return R.ok().put("token", token);
}
/**
* 登録
*/
@IgnoreAuth
@RequestMapping("/register")
public R register(@RequestBody CustomerEntity customer) {
CustomerEntity existingUser = customerService.selectOne(
new EntityWrapper<CustomerEntity>().eq("account_name", customer.getAccountName()));
if(existingUser != null) {
return R.error("このアカウント名は既に使用されています");
}
Long userId = System.currentTimeMillis();
customer.setId(userId);
customerService.insert(customer);
return R.ok();
}
/**
* ログアウト
*/
@RequestMapping("/logout")
public R logout(HttpServletRequest request) {
request.getSession().invalidate();
return R.ok("ログアウトしました");
}
/**
* 現在のユーザーセッション情報を取得
*/
@RequestMapping("/session")
public R getCurrUser(HttpServletRequest request) {
Long id = (Long)request.getSession().getAttribute("userId");
CustomerEntity user = customerService.selectById(id);
return R.ok().put("data", user);
}
/**
* パスワードリセット
*/
@IgnoreAuth
@RequestMapping(value = "/resetPass")
public R resetPass(String username, HttpServletRequest request) {
CustomerEntity user = customerService.selectOne(
new EntityWrapper<CustomerEntity>().eq("account_name", username));
if(user == null) {
return R.error("アカウントが存在しません");
}
user.setPassword("123456");
customerService.updateById(user);
return R.ok("パスワードがリセットされました: 123456");
}
/**
* 管理者向けリスト
*/
@RequestMapping("/page")
public R page(@RequestParam Map params, CustomerEntity customer,
HttpServletRequest request) {
EntityWrapper<CustomerEntity> ew = new EntityWrapper<>();
PageUtils page = customerService.queryPage(
params, MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, customer), params), params));
return R.ok().put("data", page);
}
/**
* 顧客向けリスト
*/
@IgnoreAuth
@RequestMapping("/list")
public R list(@RequestParam Map params, CustomerEntity customer,
HttpServletRequest request) {
EntityWrapper<CustomerEntity> ew = new EntityWrapper<>();
PageUtils page = customerService.queryPage(
params, MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, customer), params), params));
return R.ok().put("data", page);
}
/**
* 詳細情報
*/
@RequestMapping("/info/{id}")
public R info(@PathVariable("id") Long id) {
CustomerEntity customer = customerService.selectById(id);
return R.ok().put("data", customer);
}
/**
* 顧客向け詳細情報
*/
@IgnoreAuth
@RequestMapping("/detail/{id}")
public R detail(@PathVariable("id") Long id) {
CustomerEntity customer = customerService.selectById(id);
return R.ok().put("data", customer);
}
/**
* 管理者向け保存
*/
@RequestMapping("/save")
public R save(@RequestBody CustomerEntity customer, HttpServletRequest request) {
if(customerService.selectCount(
new EntityWrapper<CustomerEntity>().eq("account_name", customer.getAccountName())) > 0) {
return R.error("アカウント名は既に使用されています");
}
customer.setId(System.currentTimeMillis());
customerService.insert(customer);
return R.ok();
}
/**
* 顧客向け追加
*/
@RequestMapping("/add")
public R add(@RequestBody CustomerEntity customer, HttpServletRequest request) {
if(customerService.selectCount(
new EntityWrapper<CustomerEntity>().eq("account_name", customer.getAccountName())) > 0) {
return R.error("アカウント名は既に使用されています");
}
customer.setId(System.currentTimeMillis());
customerService.insert(customer);
return R.ok();
}
/**
* 更新
*/
@RequestMapping("/update")
@Transactional
public R update(@RequestBody CustomerEntity customer, HttpServletRequest request) {
if(customerService.selectCount(
new EntityWrapper<CustomerEntity>().ne("id", customer.getId())
.eq("account_name", customer.getAccountName())) > 0) {
return R.error("アカウント名は既に使用されています");
}
customerService.updateById(customer);
return R.ok();
}
/**
* 削除
*/
@RequestMapping("/delete")
public R delete(@RequestBody Long[] ids) {
customerService.deleteBatchIds(Arrays.asList(ids));
return R.ok();
}
}
システムテスト
システムテストは、複数の角度からシステムの問題点を特定するための重要なプロセスです。機能テストを通じてシステムの欠陥を見つけ、修正することで、システムが欠陥のない状態を保証します。テストプロセスを通じて、システムが顧客の要件を満たしていることを証明し、問題や不足があれば速やかに修正します。
システムテストの目的
オンラインショッピングモールの開発サイクルにおいて、システムテストは不可欠で忍耐強さが求められるプロセスです。その重要性は、システムの品質と信頼性を保証する最終関門であり、システム開発プロセスにおける最終的な検査でもあります。
システムテストは、ユーザーが使用中に問題が発生しないようにし、ユーザーエクスペリエンスを向上させることを目的としています。システムが直面する可能性のある問題を多角的に考慮し、さまざまなシミュレーションシナリオを通じて欠陥を発見し解決することが重要です。テストプロセスを通じて、システムの品質状況、システム機能が十分かどうか、システムの論理がスムーズかどうかを把握できます。
システム機能テスト
システムの機能モジュールに対してテストを実施し、クリック、境界値の入力、必須項目と任意項目の検証などの方法による一連のブラックボックステストを行います。テストケースを作成し、その内容に基づいてテストを実施し、最終的にテスト結論を導き出します。
ログイン機能テスト案:システムにログインする際、アカウントとパスワードなどの機能ポイントで検証を行います。ユーザーはデータベースに保存されているデータと一致する内容を入力する必要があります。いずれかの入力が間違っている場合、システムは入力エラーを表示します。このインターフェースでは、ロール権限にも対応した検証が行われ、ユーザーロールが管理者ロールに設定されている場合もエラーが返されます。
システムテストの結論
本システムでは主にブラックボックステストを使用し、ユーザーがシステムを使用して各機能を実現する様子をシミュレートしてテストケースを作成し、テストを実施しました。これにより、システムフローの正確性を確認します。システムテストは不可欠であり、システムをより完全にし、使用可能性を高めます。
このシステムのテストは、システムの機能モジュールが当初の設計理念を満たしているかどうか、各機能モジュールの論理が正しいかどうかを検証することを主目的としています。このシステムは、ユーザーが操作しやすいように、複雑な論理処理を必要としません。テストの最終目的もユーザーの使用を中心に展開されます。テストプロセス中のすべてのシナリオはユーザーの要件に適合するものであり、要件目標から逸れてはなりません。問題が発生した場合は、ユーザーの視点から思考する必要があります。一連のテストプロセスを経て最終的なテスト結果が得られ、その結果から、実装されたシステムは機能と性能の両面で設計要件を満たしていることがわかります。