1. 项目概述与技术栈选型
这套基于Java SpringBoot+Vue3+MyBatis的网上商城系统,采用了当前主流的前后端分离架构。前端使用Vue3组合式API开发,后端基于SpringBoot 2.7.x构建,数据持久层采用MyBatis-Plus增强框架,数据库选用MySQL 8.0。系统实现了商品管理、订单处理、支付对接、用户权限等电商核心功能模块。
技术选型背后的思考:Vue3的Composition API更适合复杂商城的状态管理,SpringBoot的自动配置特性简化了微服务整合,MyBatis-Plus的ActiveRecord模式显著减少样板代码,而MySQL 8.0的JSON支持便于处理商品规格参数等半结构化数据。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发环境搭建与工程初始化
2.1 后端工程配置
使用Spring Initializr创建项目时,关键依赖包括:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
数据库连接池配置示例(application.yml):
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/mall?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
hikari:
maximum-pool-size: 20
connection-timeout: 30000
2.2 前端工程初始化
通过Vite创建Vue3项目时推荐选择以下配置:
bash复制npm create vite@latest mall-frontend --template vue-ts
Element Plus按需引入配置(vite.config.ts):
typescript复制import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
})
3. 核心业务模块实现
3.1 商品模块设计
商品表的核心字段设计:
sql复制CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '商品名称',
`price` decimal(10,2) NOT NULL COMMENT '售价',
`stock` int NOT NULL DEFAULT '0' COMMENT '库存',
`specs` json DEFAULT NULL COMMENT '规格参数',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
MyBatis-Plus的Service层实现示例:
java复制@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
implements ProductService {
@Override
public Page<Product> queryByPage(PageParam param) {
LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(param.getKeyword()),
Product::getName, param.getKeyword());
return this.page(new Page<>(param.getPageNum(), param.getPageSize()), wrapper);
}
}
3.2 订单状态机实现
使用Spring StateMachine处理订单状态流转:
java复制@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> {
@Override
public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states)
throws Exception {
states.withStates()
.initial(OrderState.UNPAID)
.states(EnumSet.allOf(OrderState.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions)
throws Exception {
transitions
.withExternal()
.source(OrderState.UNPAID).target(OrderState.PAID)
.event(OrderEvent.PAY)
.and()
.withExternal()
.source(OrderState.PAID).target(OrderState.DELIVERED)
.event(OrderEvent.SHIP);
}
}
4. 前后端交互关键实现
4.1 接口安全设计
JWT认证过滤器核心逻辑:
java复制public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (StringUtils.isBlank(token) || !token.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
try {
String username = JwtUtil.parseToken(token.substring(7));
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (Exception e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return;
}
chain.doFilter(request, response);
}
}
4.2 文件上传处理
前后端分离下的文件上传方案:
vue复制<template>
<el-upload
action="/api/upload"
:headers="{Authorization: `Bearer ${token}`}"
:on-success="handleSuccess">
<el-button type="primary">点击上传</el-button>
</el-upload>
</template>
<script setup>
const token = localStorage.getItem('token')
const handleSuccess = (response) => {
if(response.code === 200) {
ElMessage.success('上传成功')
}
}
</script>
SpringBoot后端处理:
java复制@PostMapping("/upload")
public Result<String> upload(@RequestParam("file") MultipartFile file) {
String filename = UUID.randomUUID() +
file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
Path path = Paths.get("/upload", filename);
Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
return Result.success("/static/" + filename);
}
5. 性能优化实践
5.1 缓存策略设计
多级缓存实现方案:
java复制@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements ProductService {
private final ProductMapper productMapper;
private final RedisTemplate<String, Object> redisTemplate;
@Cacheable(value = "product", key = "#id")
public Product getById(Long id) {
String cacheKey = "product:" + id;
Product product = (Product) redisTemplate.opsForValue().get(cacheKey);
if (product != null) return product;
product = productMapper.selectById(id);
if (product != null) {
redisTemplate.opsForValue().set(cacheKey, product, 30, TimeUnit.MINUTES);
}
return product;
}
}
5.2 SQL性能优化
MyBatis-Plus查询优化示例:
java复制// 错误做法:N+1查询问题
List<Order> orders = orderMapper.selectList(null);
orders.forEach(order -> {
User user = userMapper.selectById(order.getUserId());
order.setUser(user);
});
// 正确做法:关联查询
@Select("SELECT o.*, u.username FROM order o LEFT JOIN user u ON o.user_id = u.id")
List<OrderVO> selectOrderWithUser();
6. 部署与监控方案
6.1 Docker容器化部署
后端Dockerfile示例:
dockerfile复制FROM openjdk:17-jdk-slim
VOLUME /tmp
COPY target/mall-backend-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
前端Nginx配置:
nginx复制server {
listen 80;
server_name mall.com;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
}
}
6.2 Arthas诊断实践
监控MyBatis SQL执行:
bash复制# 启动Arthas
java -jar arthas-boot.jar
# 监控Mapper接口方法调用
watch com.example.mapper.* * '{params,returnObj}' -x 3
# 统计方法调用耗时
trace com.example.service.* *
7. 常见问题解决方案
7.1 跨域问题处理
SpringBoot全局跨域配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
7.2 MyBatis特殊符号转义
XML中特殊字符处理方案:
xml复制<!-- 错误示例 -->
<select id="selectByPrice" resultType="Product">
SELECT * FROM product WHERE price < #{maxPrice}
</select>
<!-- 正确方案1:CDATA包裹 -->
<select id="selectByPrice" resultType="Product">
SELECT * FROM product
<![CDATA[
WHERE price < #{maxPrice}
]]>
</select>
<!-- 正确方案2:转义字符 -->
<select id="selectByPrice" resultType="Product">
SELECT * FROM product WHERE price < #{maxPrice}
</select>
8. 项目扩展方向建议
- 支付模块增强:集成支付宝/微信沙箱环境,实现完整的支付回调处理
- 搜索引擎整合:接入Elasticsearch实现商品全文检索
- 消息队列应用:使用RabbitMQ处理秒杀订单的异步削峰
- 微服务改造:基于SpringCloud Alibaba拆分用户/商品/订单服务
- 移动端适配:开发Uniapp版本兼容小程序生态
这套商城系统源码已在实际项目中验证过稳定性,我在开发过程中特别注意到几个关键点:MyBatis的批处理操作需要手动控制session刷新频率、Vue3的Composition API更适合封装业务hook、SpringBoot的@Transactional注解在异常处理时要注意传播行为。建议初次接触完整项目的开发者重点关注模块间的接口设计规范,这对后续维护扩展至关重要。
