SSM框架构建电脑配件销售系统全流程解析

SSM框架构建电脑配件销售系统全流程解析 1. 项目概述SSM框架下的电脑配件销售系统全解析电脑配件销售系统作为典型的B2C电商平台其技术实现方案直接影响系统的稳定性、扩展性和开发效率。SSMSpringSpringMVCMyBatis框架组合凭借其轻量级、松耦合的特性成为中小型电商系统的首选技术栈。这个开源项目不仅提供了完整可运行的源码还配套了详细的技术文档和调试指南特别适合Java开发者学习企业级项目开发的全流程。我在实际开发中发现一个合格的电商系统需要平衡三个核心要素商品管理的灵活性、订单处理的高效性以及用户交互的友好性。SSM框架的分层架构恰好能够完美支持这些需求——Spring的IoC容器管理业务组件SpringMVC处理前端交互MyBatis则灵活操作数据库。这个项目源码的价值在于它展示了如何将这些框架有机整合实现从商品展示到支付结算的完整闭环。2. 系统架构设计与技术选型2.1 SSM框架整合方案项目采用经典的MVC三层架构表现层SpringMVC 5.3.22业务层Spring 5.3.22持久层MyBatis 3.5.9整合的关键在于spring-mybatis.xml配置文件的编写。这里分享一个配置技巧通过context:component-scan的base-package属性精确控制扫描范围可以显著提高应用启动速度。我在实际项目中通常会这样划分包结构com.xxx.pcparts ├── controller ├── service │ └── impl ├── dao ├── entity └── util2.2 数据库设计要点电脑配件销售系统的数据库设计有几个特殊考量点商品表需要支持多规格属性如CPU需要Socket类型、核心数等参数配件兼容性关系需要单独建立关联表促销活动需要支持组合优惠如主板CPU套装典型的商品表结构设计示例CREATE TABLE product ( id int(11) NOT NULL AUTO_INCREMENT, category_id int(11) NOT NULL COMMENT 配件类别, name varchar(100) NOT NULL COMMENT 商品名称, spec_json text COMMENT 规格参数(JSON格式), price decimal(10,2) NOT NULL, stock int(11) NOT NULL DEFAULT 0, compatibility_ids varchar(255) DEFAULT NULL COMMENT 兼容产品ID集合, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;提示使用JSON字段存储规格参数比传统的EAV模型更便于查询这是MyBatis处理复杂属性的优势所在。3. 核心功能模块实现3.1 智能商品推荐系统不同于普通电商电脑配件销售需要专业的推荐逻辑。我们实现了基于兼容性规则的推荐算法public ListProduct getCompatibleProducts(Integer productId) { // 1. 查询当前商品的所有兼容性规则 Product current productDao.selectById(productId); String[] compatibleIds current.getCompatibilityIds().split(,); // 2. 构建查询条件 QueryWrapperProduct query new QueryWrapper(); query.in(id, Arrays.asList(compatibleIds)) .orderByDesc(sales) .last(LIMIT 5); // 3. 返回推荐商品列表 return productDao.selectList(query); }3.2 购物车特殊处理电脑配件购物车需要处理几个特殊场景硬件兼容性校验如AMD CPU不能配Intel主板电源功率计算根据配置自动计算所需电源装机套餐优惠对应的Service层实现逻辑public CartCheckResult checkCartCompatibility(ListCartItem items) { CartCheckResult result new CartCheckResult(); // 电源功率计算逻辑 int totalPower items.stream() .mapToInt(item - item.getProduct().getPowerRequirement()) .sum(); result.setRequiredPower(totalPower); // 兼容性检查 ListCompatibilityIssue issues compatibilityService.check(items); result.setCompatibilityIssues(issues); // 套餐优惠计算 result.setPackageDiscount(packageService.calculateDiscount(items)); return result; }4. 开发环境搭建与调试4.1 快速启动指南项目采用Maven构建推荐使用以下环境配置JDK 1.8MySQL 5.7Tomcat 8.5IntelliJ IDEA/Eclipse关键依赖项说明dependencies !-- Spring核心 -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.22/version /dependency !-- MyBatis整合 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.6/version /dependency !-- 数据库连接池 -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.8/version /dependency /dependencies4.2 常见调试问题解决中文乱码问题 在web.xml中添加编码过滤器filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter事务不生效问题 确保在service实现类上添加Transactional注解并在spring配置中开启注解驱动tx:annotation-driven transaction-managertransactionManager/MyBatis映射文件找不到 检查mybatis配置中mapperLocations路径是否正确property namemapperLocations valueclasspath*:mapper/*.xml/5. 系统安全与性能优化5.1 电商安全防护措施XSS防护 在SpringMVC配置中添加消息转换器Bean public HttpMessageConverterString responseBodyConverter() { StringHttpMessageConverter converter new StringHttpMessageConverter(); converter.setSupportedMediaTypes(Collections.singletonList( MediaType.TEXT_HTML)); return converter; }CSRF防护 在Spring Security配置中启用CSRF保护Override protected void configure(HttpSecurity http) throws Exception { http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); }5.2 性能调优实战MyBatis二级缓存配置 在mapper.xml中添加缓存配置cache evictionLRU flushInterval60000 size512 readOnlytrue/静态资源缓存 在SpringMVC配置中添加资源处理器Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/static/**) .addResourceLocations(/static/) .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)); }数据库连接池优化 Druid配置建议参数# 初始连接数 druid.initialSize5 # 最大连接数 druid.maxActive20 # 获取连接等待超时时间(毫秒) druid.maxWait60000 # 间隔检测时间(毫秒) druid.timeBetweenEvictionRunsMillis600006. 项目文档解读与二次开发6.1 接口文档规范项目采用Swagger UI生成API文档关键注解示例ApiOperation(value 获取商品详情, notes 根据ID查询电脑配件详情) GetMapping(/product/{id}) public ResultProduct getProductDetail( ApiParam(value 商品ID, required true) PathVariable Integer id) { // ... }启动后访问http://localhost:8080/swagger-ui.html即可查看完整接口文档。6.2 二次开发建议扩展支付接口 实现PaymentStrategy接口即可添加新的支付方式public interface PaymentStrategy { PayResult pay(Order order); } Service public class AlipayStrategy implements PaymentStrategy { // 具体实现 }添加新的配件类型 在product表的spec_json字段中添加新的规格参数并在前端相应位置增加展示逻辑。促销活动扩展 建议采用策略模式实现不同的促销规则public interface PromotionStrategy { BigDecimal applyPromotion(Order order); } Service ConditionalOnProperty(name promotion.type, havingValue discount) public class DiscountPromotion implements PromotionStrategy { // 折扣优惠实现 }7. 项目部署与运维7.1 生产环境部署要点JVM参数优化 推荐Tomcat的setenv.sh配置JAVA_OPTS-server -Xms1024m -Xmx2048m -XX:MetaspaceSize256m -XX:MaxMetaspaceSize512m -Dfile.encodingUTF-8Nginx前端配置 静态文件服务配置示例server { listen 80; server_name shop.example.com; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; } location /static/ { alias /opt/pcshop/static/; expires 30d; } }7.2 监控方案实施Druid监控中心 在web.xml中添加监控Servletservlet servlet-nameDruidStatView/servlet-name servlet-classcom.alibaba.druid.support.http.StatViewServlet/servlet-class /servlet servlet-mapping servlet-nameDruidStatView/servlet-name url-pattern/druid/*/url-pattern /servlet-mapping日志收集方案 建议采用LogbackELK方案logback-spring.xml配置示例appender nameELK classnet.logstash.logback.appender.LogstashTcpSocketAppender destination192.168.1.100:5000/destination encoder classnet.logstash.logback.encoder.LogstashEncoder / /appender8. 项目源码深度解析8.1 核心设计模式应用建造者模式在订单构建中的应用public class OrderBuilder { private Order order new Order(); public OrderBuilder withUser(Integer userId) { order.setUserId(userId); return this; } public OrderBuilder withItems(ListOrderItem items) { order.setItems(items); order.setTotalAmount(calculateTotal(items)); return this; } public Order build() { // 验证逻辑 return order; } }观察者模式实现库存预警// 定义事件 public class LowStockEvent extends ApplicationEvent { private Product product; // 构造方法和getter } // 发布事件 Service public class InventoryService { Autowired private ApplicationEventPublisher eventPublisher; public void reduceStock(Product product, int quantity) { if (remainingStock threshold) { eventPublisher.publishEvent(new LowStockEvent(this, product)); } } } // 监听事件 Component public class StockAlertListener { EventListener public void handleLowStock(LowStockEvent event) { // 发送预警通知 } }8.2 MyBatis高级特性应用动态SQL构建select idsearchProducts resultTypeProduct SELECT * FROM product where if testcategoryId ! null AND category_id #{categoryId} /if if testminPrice ! null AND price #{minPrice} /if if testkeyword ! null and keyword ! AND name LIKE CONCAT(%,#{keyword},%) /if /where ORDER BY choose when testsortType price_ascprice ASC/when when testsortType price_descprice DESC/when otherwisesales DESC/otherwise /choose /selectTypeHandler处理JSON字段MappedTypes({Map.class}) MappedJdbcTypes(JdbcType.VARCHAR) public class JsonTypeHandler extends BaseTypeHandlerMapString, Object { private static final ObjectMapper mapper new ObjectMapper(); Override public void setNonNullParameter(PreparedStatement ps, int i, MapString, Object parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, mapper.writeValueAsString(parameter)); } // 其他方法实现... }9. 项目调试技巧与实战9.1 接口调试方法论Postman测试集设计 建议按业务模块组织测试集合├── 用户模块 │ ├── 注册 │ ├── 登录 │ └── 个人信息 ├── 商品模块 │ ├── 商品列表 │ ├── 商品搜索 │ └── 商品详情 └── 订单模块 ├── 购物车 ├── 下单 └── 支付Spring测试切片 针对不同层使用不同的测试注解WebMvcTest(ProductController.class) public class ProductControllerTest { Autowired private MockMvc mockMvc; Test public void testGetProduct() throws Exception { mockMvc.perform(get(/product/1)) .andExpect(status().isOk()) .andExpect(jsonPath($.data.name).exists()); } } DataJpaTest public class ProductRepositoryTest { Autowired private TestEntityManager entityManager; Autowired private ProductRepository repository; Test public void testFindByName() { Product saved entityManager.persist(new Product(RTX 4090)); Product found repository.findByName(saved.getName()); assertEquals(saved.getId(), found.getId()); } }9.2 前端调试技巧Thymeleaf开发模式配置 在application.properties中设置spring.thymeleaf.cachefalse spring.thymeleaf.modeHTMLAjax请求调试 推荐使用axios拦截器记录请求日志axios.interceptors.request.use(config { console.log(Request:, config.method.toUpperCase(), config.url); return config; }); axios.interceptors.response.use(response { console.log(Response:, response.status, response.data); return response; });页面性能分析 Chrome DevTools的Lighthouse报告可以分析页面加载性能1. 按F12打开开发者工具 2. 切换到Lighthouse面板 3. 选择Performance类别 4. 点击Generate report10. 项目扩展与演进方向10.1 微服务化改造建议当系统规模扩大时可考虑按功能拆分为微服务pc-parts-shop ├── user-service // 用户服务 ├── product-service // 商品服务 ├── order-service // 订单服务 ├── payment-service // 支付服务 └── gateway // API网关关键改造步骤引入Spring Cloud Alibaba生态使用Nacos作为注册中心和配置中心通过OpenFeign实现服务间调用使用Sentinel实现流量控制10.2 大数据分析扩展用户行为分析 通过埋点收集用户浏览、点击数据使用Flink实时计算热门商品。销售预测模型 基于历史销售数据使用Python构建时序预测模型from statsmodels.tsa.arima.model import ARIMA model ARIMA(sales_data, order(1,1,1)) model_fit model.fit() forecast model_fit.forecast(steps7)推荐系统升级 从基于规则的推荐升级为协同过滤算法from surprise import Dataset, KNNBasic data Dataset.load_builtin(ml-100k) algo KNNBasic() algo.fit(data.build_full_trainset())10.3 前端架构升级前后端分离改造后端提供RESTful API前端采用Vue3Element Plus使用Swagger生成API文档管理端优化 建议使用Vben Admin等成熟方案快速搭建// 典型的路由配置 { path: /product, name: ProductManagement, component: () import(//views/product/index.vue), meta: { title: 商品管理, icon: ion:laptop-outline, } }移动端适配方案使用REM布局适配不同屏幕引入Vant等移动端组件库关键CSS媒体查询示例media screen and (max-width: 768px) { .product-card { width: 100%; margin-bottom: 15px; } }11. 项目质量保障体系11.1 自动化测试策略单元测试覆盖率要求Service层≥80%Controller层≥60%工具类100%JaCoCo配置示例plugin groupIdorg.jacoco/groupId artifactIdjacoco-maven-plugin/artifactId version0.8.7/version executions execution goals goalprepare-agent/goal /goals /execution execution idreport/id phasetest/phase goals goalreport/goal /goals /execution /executions /plugin接口自动化测试 使用TestNGHttpClient构建测试套件public class ProductApiTest { Test public void testSearch() throws IOException { HttpGet request new HttpGet(http://localhost:8080/product/search?keywordRTX); try (CloseableHttpResponse response HttpClients.createDefault().execute(request)) { assertEquals(200, response.getStatusLine().getStatusCode()); String json EntityUtils.toString(response.getEntity()); assertTrue(json.contains(RTX)); } } }11.2 代码质量管控SonarQube检测规则 关键质量门禁设置重复代码率 5%单元测试覆盖率 70%阻断级别问题 0安全热点通过率 90%Git提交规范 采用Angular提交规范type(scope): subject // 示例 feat(product): add compatibility check API fix(order): correct payment amount calculation代码审查要点MyBatis的SQL注入风险事务传播行为设置是否合理循环依赖问题N1查询问题12. 项目文档体系构建12.1 技术文档结构建议完整的项目文档应包含docs/ ├── 01-需求文档 │ ├── 产品需求说明书.md │ └── 接口文档.md ├── 02-设计文档 │ ├── 数据库设计.md │ └── 架构设计.md ├── 03-开发文档 │ ├── 环境搭建指南.md │ └── 编码规范.md └── 04-运维文档 ├── 部署手册.md └── 监控方案.md12.2 API文档生成方案Swagger UI增强配置Configuration EnableSwagger2 public class SwaggerConfig { Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage(com.xxx.pcparts.controller)) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title(电脑配件销售系统API) .description(包含商品、订单、用户等模块接口) .version(1.0) .build(); } }离线文档导出 使用swagger2markup生成AsciiDocRunWith(SpringRunner.class) SpringBootTest public class SwaggerExportTest { Test public void generateAsciiDoc() throws Exception { Swagger2MarkupConfig config new Swagger2MarkupConfigBuilder() .withMarkupLanguage(MarkupLanguage.ASCIIDOC) .build(); Swagger2MarkupConverter.from(new URL(http://localhost:8080/v2/api-docs)) .withConfig(config) .build() .toFile(Paths.get(docs/api)); } }13. 项目实战经验分享13.1 电商系统开发陷阱库存超卖问题 解决方案乐观锁Redis原子操作public boolean reduceStock(Integer productId, Integer quantity) { String key product:stock: productId; return redisTemplate.execute(new RedisCallbackBoolean() { Override public Boolean doInRedis(RedisConnection connection) { connection.watch(key.getBytes()); int current Integer.parseInt(new String(connection.get(key.getBytes()))); if (current quantity) { connection.unwatch(); return false; } connection.multi(); connection.decrBy(key.getBytes(), quantity); ListObject results connection.exec(); return results ! null; } }); }支付状态同步 建议采用状态机模式管理订单状态public enum OrderState { INIT { public OrderState nextState(PaymentResult result) { return result.isSuccess() ? PAID : FAILED; } }, PAID { public OrderState nextState(ShippingInfo info) { return SHIPPED; } }, // 其他状态... }13.2 性能优化实战记录商品列表分页优化 错误做法SELECT * FROM product LIMIT 100000, 10正确做法SELECT * FROM product WHERE id last_seen_id ORDER BY id LIMIT 10MyBatis批量插入优化Insert(script INSERT INTO order_item (order_id, product_id, quantity) VALUES foreach collectionitems itemitem separator, (#{item.orderId}, #{item.productId}, #{item.quantity}) /foreach /script) void batchInsert(Param(items) ListOrderItem items);缓存穿透防护 使用布隆过滤器空值缓存public Product getProduct(Integer id) { // 1. 布隆过滤器判断 if (!bloomFilter.mightContain(id)) { return null; } // 2. 查询缓存 Product product cache.get(id); if (product NULL_OBJECT) { return null; } if (product null) { // 3. 查询数据库 product productDao.selectById(id); if (product null) { cache.put(id, NULL_OBJECT, 300); // 缓存空值5分钟 } else { cache.put(id, product); } } return product; }14. 项目源码深度解析续14.1 Spring事务高级应用多数据源事务管理 配置示例Configuration EnableTransactionManagement public class TransactionConfig { Bean public PlatformTransactionManager orderTxManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } Bean public PlatformTransactionManager logTxManager(Qualifier(logDataSource) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } Service public class OrderService { Transactional(orderTxManager) public void createOrder(Order order) { // 主业务逻辑 } Transactional(logTxManager) public void recordOperationLog(Log log) { // 日志记录 } }事务传播行为实战Service public class CompositeService { Autowired private OrderService orderService; Autowired private InventoryService inventoryService; Transactional(propagation Propagation.REQUIRED) public void placeOrder(Order order) { // 主事务 orderService.createOrder(order); try { // 独立事务执行库存扣减 inventoryService.reduceStock(order.getItems()); } catch (Exception e) { // 库存异常不影响主订单创建 logger.error(库存扣减失败, e); } } } Service public class InventoryService { Transactional(propagation Propagation.REQUIRES_NEW) public void reduceStock(ListOrderItem items) { // 库存扣减逻辑 } }14.2 MyBatis动态SQL高级技巧复用SQL片段sql idproductBaseColumn id, name, category_id, price, stock /sql sql idproductWhereClause where if teststatus ! null AND status #{status} /if if testminPrice ! null AND price #{minPrice} /if /where /sql select idselectProducts resultTypeProduct SELECT include refidproductBaseColumn/ FROM product include refidproductWhereClause/ /select批量更新优化update idbatchUpdateStock UPDATE product SET stock CASE id foreach collectionlist itemitem WHEN #{item.id} THEN #{item.stock} /foreach END WHERE id IN foreach collectionlist itemitem open( separator, close) #{item.id} /foreach /update结果集映射嵌套resultMap idproductWithCategory typeProduct id propertyid columnid/ result propertyname columnname/ association propertycategory javaTypeCategory id propertyid columncategory_id/ result propertyname columncategory_name/ /association /resultMap select idselectProductWithCategory resultMapproductWithCategory SELECT p.id, p.name, p.category_id, c.name as category_name FROM product p LEFT JOIN category c ON p.category_id c.id WHERE p.id #{id} /select15. 项目部署架构演进15.1 单机到集群的演进路径初期单机架构Nginx(Tomcat) → MySQL读写分离阶段Nginx → [Tomcat集群] ↗︎ Master MySQL ↘︎ Slave MySQL分库分表阶段[Nginx] → [Service Layer] → [Sharding JDBC] → [MySQL Cluster] ↗︎ ↖︎ [Redis Cluster] [Elasticsearch]15.2 容器化部署方案Dockerfile示例FROM openjdk:8-jdk-alpine VOLUME /tmp ARG JAR_FILEtarget/*.jar COPY ${JAR_FILE} app.jar ENTRYPOINT [java,-Djava.security.egdfile:/dev/./urandom,-jar,/app.jar]docker-compose.ymlversion: 3 services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: root ports: - 3306:3306 volumes: - mysql_data:/var/lib/mysql redis: image: redis:alpine ports: - 6379:6379 app: build: . ports: - 8080:8080 depends_on: - mysql - redis volumes: mysql_data:Kubernetes部署 关键资源配置示例apiVersion: apps/v1 kind: Deployment metadata: name: pcshop spec: replicas: 3 selector: matchLabels: app: pcshop template: metadata: labels: app: pcshop spec: containers: - name: app image: registry.example.com/pcshop:1.0.0 ports: - containerPort: 8080 env: - name: SPRING_PROFILES_ACTIVE value: prod --- apiVersion: v1 kind: Service metadata: name: pcshop-service spec: selector: app: pcshop ports: - protocol: TCP port: 80 targetPort: 808016. 项目监控与告警体系16.1 应用性能监控Spring Boot Actuator配置management.endpoints.web.exposure.includehealth,info,metrics,prometheus management.metrics.export.prometheus.enabledtrue management.endpoint.health.show-detailsalwaysGrafana监控看板 关键监控指标JVM内存使用线程池状态HTTP请求耗时数据库连接池使用率16.2 业务指标监控订单状态统计RestController RequestMapping(/monitor) public class MonitorController { Autowired private OrderService orderService; GetMapping(/order-stats) public MapString, Integer getOrderStats() { return orderService.getStatusCount(); } }商品销售排行榜SELECT product_id, name, SUM(quantity) as sales FROM order_item JOIN product ON order_item.product_id product.id WHERE create_time DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY product_id ORDER BY sales DESC LIMIT 10;异常告警集成 使用Prometheus Alertmanager配置规则groups: - name: pcshop-alerts rules: - alert: HighErrorRate expr: rate(http_server_requests_errors_total[1m]) 0.1 for: 5m labels: severity: critical annotations: summary: High error rate on {{ $labels.instance }} description: Error rate is {{ $value }}17. 项目安全加固方案17.1 常见Web安全防护SQL注入防护始终使用MyBatis参数绑定禁止拼接SQL语句定期使用SQLMap扫描XSS防护 Spring MVC配置HttpMessageConverterBean public HttpMessageConverterString responseBodyConverter() { StringHttpMessageConverter converter new StringHttpMessageConverter(); converter.setSupportedMediaTypes(Collections.singletonList( MediaType.TEXT_HTML)); return converter; }CSRF防护 Spring Security配置Override protected void configure(HttpSecurity http) throws Exception { http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); }17.2 敏感数据保护密码加密存储public class PasswordUtil { private static final BCryptPasswordEncoder encoder new BCryptPasswordEncoder(); public static String encode(String rawPassword) { return encoder.encode(rawPassword); } public static boolean matches(String rawPassword, String encodedPassword) { return encoder.matches(rawPassword, encodedPassword); } }数据脱敏处理public class DataMasker { public static String maskPhone(String phone) { if (phone null || phone.length() 7) return phone; return phone.substring(0, 3) **** phone.substring(7); } public static String maskIdCard(String idCard) { if (idCard null || idCard.length() 15) return idCard; return idCard.substring(0, 6) ******** idCard.substring(14); } }接口权限控制 Spring Security方法级注解PreAuthorize(hasRole(ADMIN) or #userId authentication.principal.id) public User getUserById(Long userId) { // ... }18. 项目文档自动化18.1 数据库文档生成使用SchemaCrawler生成HTML文档java -jar schemacrawler.jar \ --servermysql --hostlocalhost --databasepcshop \ --userroot --passwordroot --info-levelstandard \ --commandschema --output-formathtml --output-filedb-docs.html18.2 API文档自动化结合Swagger和Asciidoctor生成PDFplugin groupIdorg.asciidoctor/groupId artifactIdasciidoctor-maven-plugin/artifactId version2.2.1/version executions execution idgenerate-docs/id phaseprepare-package/phase goals goalprocess-asciidoc/goal /goals configuration sourceDocumentNameapi.adoc/sourceDocumentName attributes swaggerFile${project.build.directory}/swagger.json/swaggerFile /attributes /configuration