docs/DEVELOPMENT.md
newbee-mall 是一个基于 Spring Boot 的电商系统,包含前台商城和后台管理两个部分。
项目特点:
主要功能模块:
前台商城:
后台管理:
| 技术 | 版本 | 说明 |
|---|---|---|
| Spring Boot | 2.6.3 | 核心框架 |
| Spring MVC | - | MVC 框架 |
| MyBatis | 2.2.2 | ORM 框架 |
| Thymeleaf | - | 模板引擎 |
| MySQL | 5.7+ | 数据库 |
| Hutool | 5.7.22 | Java 工具库 |
| Maven | 3.x | 项目构建工具 |
| 技术 | 说明 |
|---|---|
| Thymeleaf | 服务端模板引擎 |
| jQuery | JavaScript 库 |
| Bootstrap | UI 框架 |
| AdminLTE | 后台管理模板 |
| jqGrid | 数据表格插件 |
| wangEditor | 富文本编辑器 |
| SweetAlert | 弹窗组件 |
newbee-mall/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── ltd/newbee/mall/
│ │ │ ├── common/ # 公共常量和枚举
│ │ │ │ ├── Constants.java
│ │ │ │ ├── ServiceResultEnum.java
│ │ │ │ └── ...
│ │ │ ├── config/ # 配置类
│ │ │ │ └── WebMvcConfig.java
│ │ │ ├── controller/ # 控制器层
│ │ │ │ ├── admin/ # 后台管理控制器
│ │ │ │ ├── mall/ # 前台商城控制器
│ │ │ │ ├── common/ # 公共控制器
│ │ │ │ └── vo/ # 视图对象
│ │ │ ├── dao/ # 数据访问层
│ │ │ │ ├── AdminUserMapper.java
│ │ │ │ ├── NewBeeMallGoodsMapper.java
│ │ │ │ └── ...
│ │ │ ├── entity/ # 实体类
│ │ │ │ ├── AdminUser.java
│ │ │ │ ├── NewBeeMallGoods.java
│ │ │ │ └── ...
│ │ │ ├── interceptor/ # 拦截器
│ │ │ │ ├── AdminLoginInterceptor.java
│ │ │ │ └── NewBeeMallLoginInterceptor.java
│ │ │ ├── service/ # 服务层接口
│ │ │ │ ├── AdminUserService.java
│ │ │ │ └── ...
│ │ │ │ └── impl/ # 服务层实现
│ │ │ │ ├── AdminUserServiceImpl.java
│ │ │ │ └── ...
│ │ │ ├── util/ # 工具类
│ │ │ │ ├── MD5Util.java
│ │ │ │ ├── Result.java
│ │ │ │ └── ...
│ │ │ └── NewBeeMallApplication.java # 启动类
│ │ └── resources/
│ │ ├── mapper/ # MyBatis XML 映射文件
│ │ │ ├── AdminUserMapper.xml
│ │ │ └── ...
│ │ ├── static/ # 静态资源
│ │ │ ├── admin/ # 后台静态资源
│ │ │ └── mall/ # 前台静态资源
│ │ ├── templates/ # Thymeleaf 模板
│ │ │ ├── admin/ # 后台页面
│ │ │ └── mall/ # 前台页面
│ │ └── application.properties # 配置文件
│ └── test/ # 测试代码
├── docs/ # 项目文档
├── pom.xml # Maven 配置
└── README.md # 项目说明
下载并安装 JDK 1.8 或以上版本,配置环境变量。
验证安装:
java -version
下载并安装 Maven 3.x,配置环境变量。
验证安装:
mvn -version
推荐配置阿里云镜像(修改 settings.xml):
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
下载并安装 MySQL 5.7 或以上版本。
创建数据库:
CREATE DATABASE newbee_mall_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
推荐使用 IntelliJ IDEA 或 Eclipse。
git clone https://github.com/newbee-ltd/newbee-mall.git
cd newbee-mall
执行项目中的 SQL 脚本(通常在 sql 或 database 目录):
mysql -u root -p newbee_mall_db < newbee_mall_schema.sql
mysql -u root -p newbee_mall_db < newbee_mall_data.sql
修改 src/main/resources/application.properties:
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/newbee_mall_db?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=你的密码
# 服务器端口
server.port=28089
NewBeeMallApplication.javaRun 'NewBeeMallApplication'mvn clean install
mvn spring-boot:run
mvn clean package
cd target
java -jar newbee-mall-1.0.0-SNAPSHOT.jar
类名: 使用大驼峰命名法(PascalCase)
public class NewBeeMallGoods { }
方法名: 使用小驼峰命名法(camelCase)
public void saveGoods() { }
常量: 使用全大写,单词间用下划线分隔
public static final int MAX_GOODS_COUNT = 100;
包名: 全小写,使用点分隔
package ltd.newbee.mall.service;
/**
* 商品服务接口
*
* @author 13
*/
public interface NewBeeMallGoodsService {
/**
* 保存商品
*
* @param goods 商品对象
* @return 保存结果
*/
Boolean saveGoods(NewBeeMallGoods goods);
}
@Controller
public class GoodsController {
@Resource
private NewBeeMallGoodsService goodsService;
@GetMapping("/goods/detail/{goodsId}")
public String goodsDetail(@PathVariable Long goodsId, HttpServletRequest request) {
// 参数校验
if (goodsId < 1) {
return "error/error_5xx";
}
// 调用 Service
NewBeeMallGoodsDetailVO goodsDetail = goodsService.getGoodsDetail(goodsId);
// 设置返回数据
request.setAttribute("goodsDetail", goodsDetail);
return "mall/detail";
}
}
@Service
public class NewBeeMallGoodsServiceImpl implements NewBeeMallGoodsService {
@Resource
private NewBeeMallGoodsMapper goodsMapper;
@Override
@Transactional
public Boolean saveGoods(NewBeeMallGoods goods) {
// 业务逻辑处理
if (goods == null) {
return false;
}
// 调用 DAO
return goodsMapper.insertSelective(goods) > 0;
}
}
public interface NewBeeMallGoodsMapper {
int insertSelective(NewBeeMallGoods record);
NewBeeMallGoods selectByPrimaryKey(Long goodsId);
int updateByPrimaryKeySelective(NewBeeMallGoods record);
}
public class NewBeeMallException extends RuntimeException {
public NewBeeMallException(String message) {
super(message);
}
public static void fail(String message) {
throw new NewBeeMallException(message);
}
}
ResultResult result = Result.success();
Result result = Result.error("操作失败");
流程:
代码示例:
@PostMapping("/login")
@ResponseBody
public Result login(@RequestParam("loginName") String loginName,
@RequestParam("password") String password,
HttpSession session) {
// 参数校验
if (StringUtils.isEmpty(loginName) || StringUtils.isEmpty(password)) {
return Result.error("参数不能为空");
}
// 调用 Service 验证
String loginResult = newBeeMallUserService.login(loginName, password, session);
if (ServiceResultEnum.SUCCESS.getResult().equals(loginResult)) {
return Result.success();
}
return Result.error(loginResult);
}
作用: 拦截需要登录才能访问的请求
@Component
public class NewBeeMallLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Object user = session.getAttribute("mallUser");
if (user == null) {
response.sendRedirect("/login");
return false;
}
return true;
}
}
配置拦截器:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private NewBeeMallLoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/personal/**")
.addPathPatterns("/shop-cart/**")
.addPathPatterns("/orders/**")
.excludePathPatterns("/login")
.excludePathPatterns("/register");
}
}
@PostMapping("/shop-cart")
@ResponseBody
public Result saveShoppingCartItem(@RequestBody NewBeeMallShoppingCartItem shoppingCartItem,
HttpSession session) {
// 获取当前登录用户
NewBeeMallUserVO user = (NewBeeMallUserVO) session.getAttribute("mallUser");
shoppingCartItem.setUserId(user.getUserId());
// 调用 Service 保存
String saveResult = newBeeMallShoppingCartService.saveNewBeeMallCartItem(shoppingCartItem);
if (ServiceResultEnum.SUCCESS.getResult().equals(saveResult)) {
return Result.success();
}
return Result.error(saveResult);
}
@GetMapping("/shop-cart")
public String cartListPage(HttpServletRequest request, HttpSession session) {
NewBeeMallUserVO user = (NewBeeMallUserVO) session.getAttribute("mallUser");
// 查询购物车列表
List<NewBeeMallShoppingCartItemVO> myShoppingCartItems =
newBeeMallShoppingCartService.getMyShoppingCartItems(user.getUserId());
request.setAttribute("cartItems", myShoppingCartItems);
return "mall/cart";
}
@PostMapping("/saveOrder")
@ResponseBody
@Transactional
public Result saveOrder(@RequestParam Long addressId,
@RequestParam String cartItemIds,
HttpSession session) {
// 获取当前用户
NewBeeMallUserVO user = (NewBeeMallUserVO) session.getAttribute("mallUser");
// 购物车项 ID 转换
List<Long> itemIdList = Arrays.stream(cartItemIds.split(","))
.map(Long::parseLong)
.collect(Collectors.toList());
// 生成订单
String saveOrderResult = newBeeMallOrderService.saveOrder(user.getUserId(), addressId, itemIdList);
if (ServiceResultEnum.SUCCESS.getResult().equals(saveOrderResult)) {
return Result.success();
}
return Result.error(saveOrderResult);
}
订单状态定义:
@PostMapping("/admin/upload/file")
@ResponseBody
public Result upload(@RequestParam("file") MultipartFile file) {
// 文件名校验
String fileName = file.getOriginalFilename();
String suffixName = fileName.substring(fileName.lastIndexOf("."));
// 生成新文件名
String newFileName = UUID.randomUUID().toString() + suffixName;
// 保存文件
File destFile = new File(uploadPath + newFileName);
file.transferTo(destFile);
// 返回文件访问路径
return Result.success(newFileName);
}
@GetMapping("/admin/goods/list")
@ResponseBody
public Result list(@RequestParam Map<String, Object> params) {
PageQueryUtil pageUtil = new PageQueryUtil(params);
// 查询分页数据
PageResult pageResult = newBeeMallGoodsService.getNewBeeMallGoodsPage(pageUtil);
return Result.success(pageResult);
}
@Controller
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/index")
public String index() {
return "mall/demo/index";
}
}
在 src/main/resources/templates/mall/demo/ 目录下创建 index.html
在 src/main/resources/static/mall/ 目录下添加 CSS、JS 文件
public class Demo {
private Long id;
private String name;
// getter/setter
}
public interface DemoMapper {
List<Demo> selectList();
int insert(Demo demo);
}
<mapper namespace="ltd.newbee.mall.dao.DemoMapper">
<select id="selectList" resultType="ltd.newbee.mall.entity.Demo">
SELECT * FROM tb_demo
</select>
</mapper>
public interface DemoService {
List<Demo> getList();
}
@Service
public class DemoServiceImpl implements DemoService {
@Resource
private DemoMapper demoMapper;
@Override
public List<Demo> getList() {
return demoMapper.selectList();
}
}
@RestController
@RequestMapping("/api/demo")
public class DemoController {
@Resource
private DemoService demoService;
@GetMapping("/list")
public Result list() {
return Result.success(demoService.getList());
}
}
@Component
@EnableScheduling
public class ScheduledTask {
@Scheduled(cron = "0 0 2 * * ?")
public void task() {
// 定时任务逻辑
}
}
@Component
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 前置处理
return true;
}
}
@SpringBootTest
public class GoodsServiceTest {
@Resource
private NewBeeMallGoodsService goodsService;
@Test
public void testGetGoodsDetail() {
NewBeeMallGoodsDetailVO goodsDetail = goodsService.getGoodsDetail(1L);
assertNotNull(goodsDetail);
}
}
使用 Postman 或其他工具测试 API 接口。
手动测试各个功能模块是否正常运行。
mvn clean package -DskipTests
# 上传 jar 包
scp target/newbee-mall-1.0.0-SNAPSHOT.jar user@server:/app/
# SSH 登录服务器
ssh user@server
# 运行项目
nohup java -jar /app/newbee-mall-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod > /app/logs/app.log 2>&1 &
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:28089;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
使用 Let's Encrypt 获取免费 SSL 证书。
详见 FAQ 文档
文档版本: v1.0.0 最后更新: 2025-10-23 维护者: newbee-mall 开发团队