本章节,将介绍如何新建名字为 yudao-module-demo
的示例服务,并添加 RESTful API 接口。
虽然内容看起来比较长,是因为艿艿写的比较详细,大量截图,保姆级教程!其实只有 6 个步骤,保持耐心,跟着艿艿一点点来。🙂 完成之后,你会对整个 项目结构 有更充分的了解。
👍 相关视频教程
1. 新建 demo 模块
① 选择 File -> New -> Module 菜单,如下图所示:
② 选择 Maven 类型,选择父模块为 yudao
,输入名字为 yudao-module-demo
,并点击 Create 按钮,如下图所示:
③ 打开 yudao-module-demo
模块,删除 src 文件,如下图所示:
④ 打开 yudao-module-demo
模块的 pom.xml
文件,修改内容如下:
提示
<!-- -->
部分,只是注释,不需要写到 XML 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>yudao</artifactId> <groupId>cn.iocoder.cloud</groupId> <version>${revision}</version> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-demo</artifactId> <packaging>pom</packaging>
<name>${project.artifactId}</name> <description> demo 模块,主要实现 XXX、YYY、ZZZ 等功能。 </description>
</project>
|
2. 新建 demo-api
子模块
① 新建 yudao-module-demo-api
子模块,整个过程和“新建 demo
模块”是一致的,如下图所示:
② 打开 yudao-module-demo-api
模块的 pom.xml
文件,修改内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>yudao-module-demo</artifactId> <groupId>cn.iocoder.cloud</groupId> <version>${revision}</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>yudao-module-demo-api</artifactId> <packaging>jar</packaging>
<name>${project.artifactId}</name> <description> demo 模块 API,暴露给其它模块调用 </description>
<dependencies> <dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-common</artifactId> </dependency> </dependencies>
</project>
|
③ 【可选】新建 cn.iocoder.yudao.module.demo
基础包,其中 demo
为模块名。之后,新建 api
和 enums
包。如下图所示:
3. 新建 demo-biz 子模块
① 新建 yudao-module-demo-biz
子模块,整个过程和“新建 demo 模块”也是一致的,如下图所示:
② 打开 yudao-module-demo-biz
模块的 pom.xml
文件,修改成内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>yudao-module-demo</artifactId> <groupId>cn.iocoder.cloud</groupId> <version>${revision}</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>jar</packaging>
<artifactId>yudao-module-demo-biz</artifactId>
<name>${project.artifactId}</name> <description> demo 模块,主要实现 XXX、YYY、ZZZ 等功能。 </description>
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-env</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-module-system-api</artifactId> <version>${revision}</version> </dependency> <dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-module-infra-api</artifactId> <version>${revision}</version> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-module-demo-api</artifactId> <version>${revision}</version> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-banner</artifactId> </dependency> <dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId> </dependency> <dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-biz-dict</artifactId> </dependency> <dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId> </dependency> <dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> </dependency> <dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-biz-error-code</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-security</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-mybatis</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-redis</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-rpc</artifactId> </dependency>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-job</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-mq</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-test</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-excel</artifactId> </dependency>
<dependency> <groupId>cn.iocoder.cloud</groupId> <artifactId>yudao-spring-boot-starter-monitor</artifactId> </dependency> </dependencies>
<build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring.boot.version}</version> <configuration> <fork>true</fork> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
|
③ 【必选】新建 cn.iocoder.yudao.module.demo
基础包,其中 demo
为模块名。之后,新建 controller.admin
和 controller.user
等包。如下图所示:
其中 SecurityConfiguration 的 Java 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package cn.iocoder.yudao.module.demo.framework.security.config;
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; import cn.iocoder.yudao.module.system.enums.ApiConstants; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
@Configuration(proxyBeanMethods = false) public class SecurityConfiguration {
@Bean public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { return new AuthorizeRequestsCustomizer() {
@Override public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { registry.antMatchers("/v3/api-docs/**").permitAll() .antMatchers("/swagger-ui.html").permitAll(); registry.antMatchers("/druid/**").anonymous(); registry.antMatchers("/actuator").anonymous() .antMatchers("/actuator/**").anonymous(); registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll(); }
}; }
}
|
其中 DemoServerApplication 的 Java 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package cn.iocoder.yudao.module.demo;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class DemoServerApplication {
public static void main(String[] args) { SpringApplication.run(DemoServerApplication.class, args); }
}
|
④ 打开 Maven 菜单,点击刷新按钮,让引入的 Maven 依赖生效。如下图所示:
⑤ 在 resources
目录下,新建配置文件。如下图所示:
其中 application.yml
的配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| spring: main: allow-circular-references: true allow-bean-definition-overriding: true
servlet: multipart: max-file-size: 16MB max-request-size: 32MB mvc: pathmatch: matching-strategy: ANT_PATH_MATCHER
jackson: serialization: write-dates-as-timestamps: true write-date-timestamps-as-nanoseconds: false write-durations-as-timestamps: true fail-on-empty-beans: false
cache: type: REDIS redis: time-to-live: 1h
---
springdoc: api-docs: enabled: true path: /v3/api-docs swagger-ui: enabled: true path: /swagger-ui.html
knife4j: enable: true setting: language: zh_cn
mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: id-type: NONE
logic-delete-value: 1 logic-not-delete-value: 0 type-aliases-package: ${yudao.info.base-package}.dal.dataobject
--- dubbo: scan: base-packages: ${yudao.info.base-package}.api protocol: name: dubbo port: -1 registry: address: spring-cloud://localhost
---
---
xxl: job: executor: appname: ${spring.application.name} logpath: ${user.home}/logs/xxl-job/${spring.application.name} accessToken: default_token
---
yudao: info: version: 1.0.0 base-package: cn.iocoder.yudao.module.demo web: admin-ui: url: http://dashboard.yudao.iocoder.cn swagger: title: 管理后台 description: 提供管理员管理的所有功能 version: ${yudao.info.version} base-package: ${yudao.info.base-package} tenant: enable: true
debug: false
|
yudao.info.version.base-package
配置项:可以改成你的项目的基准包名。
其中 application-local.yml
的配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| --- spring: autoconfigure: exclude: - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure datasource: druid: web-stat-filter: enabled: true stat-view-servlet: enabled: true allow: url-pattern: /druid/* login-username: login-password: filter: stat: enabled: true log-slow-sql: true slow-sql-millis: 100 merge-sql: true wall: config: multi-statement-allow: true dynamic: druid: initial-size: 5 min-idle: 10 max-active: 20 max-wait: 600000 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 max-evictable-idle-time-millis: 900000 validation-query: SELECT 1 FROM DUAL test-while-idle: true test-on-borrow: false test-on-return: false primary: master datasource: master: name: ruoyi-vue-pro url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true
username: root password: 123456
slave: name: ruoyi-vue-pro url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true
username: root password: 123456
redis: host: 127.0.0.1 port: 6379 database: 0
--- spring: cloud: stream: rocketmq: binder: name-server: 127.0.0.1:9876
---
xxl: job: admin: addresses: http://127.0.0.1:9090/xxl-job-admin
---
lock4j: acquire-timeout: 3000 expire: 30000
---
management: endpoints: web: base-path: /actuator exposure: include: '*'
spring: boot: admin: client: instance: service-host-type: IP
logging: level: cn.iocoder.yudao.module.demo.dal.mysql: debug
---
yudao: env: tag: ${HOSTNAME} security: mock-enable: true xss: enable: false exclude-urls: - ${spring.boot.admin.context-path}/** - ${management.endpoints.web.base-path}/** access-log: enable: false error-code: enable: false demo: false
|
logging.level.cn.iocoder.yudao.module.demo.dal.mysql
配置项:可以改成你的项目的基准包名。
其中 bootstrap.yml
的配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| spring: application: name: demo-server
profiles: active: local
server: port: 48099
logging: file: name: ${user.home}/logs/${spring.application.name}.log
|
spring.application.name
配置项:可以改成你想要的服务名。 server.port
配置项:可以改成你想要的端口号。
其中 bootstrap-local.yml
的配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ---
spring: cloud: nacos: server-addr: 127.0.0.1:8848 discovery: namespace: dev metadata: version: 1.0.0
---
spring: cloud: nacos: config: server-addr: 127.0.0.1:8848 namespace: dev group: DEFAULT_GROUP name: file-extension: yaml
|
其中 logback-spring.xml
的配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml" /> <springProperty scope="context" name="yudao.info.base-package" source="yudao.info.base-package"/> <property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%thread] [%tid] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <pattern>${PATTERN_DEFAULT}</pattern> </layout> </encoder> </appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <pattern>${PATTERN_DEFAULT}</pattern> </layout> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern> <cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart> <maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize> <totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap> <maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory> </rollingPolicy> </appender> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <discardingThreshold>0</discardingThreshold> <queueSize>256</queueSize> <appender-ref ref="FILE"/> </appender>
<appender name="GRPC" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <pattern>${PATTERN_DEFAULT}</pattern> </layout> </encoder> </appender>
<springProfile name="local"> <root level="INFO"> <appender-ref ref="STDOUT"/> <appender-ref ref="GRPC"/> <appender-ref ref="ASYNC"/> </root> </springProfile> <springProfile name="dev,test,stage,prod,default"> <root level="INFO"> <appender-ref ref="STDOUT"/> <appender-ref ref="ASYNC"/> <appender-ref ref="GRPC"/> </root> </springProfile>
</configuration>
|
4. 新建 RESTful API
接口
① 在 controller.admin
包,新建一个 DemoTestController 类,并新建一个 /demo/test/get
接口。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package cn.iocoder.yudao.module.demo.controller.admin;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - Test") @RestController @RequestMapping("/demo/test") @Validated public class DemoTestController {
@GetMapping("/get") @Operation(summary = "获取 test 信息") public CommonResult<String> get() { return success("true"); }
}
|
注意,/demo
是该模块所有 RESTful API 的基础路径,/test
是 Test 功能的基础路径。
① 在 controller.app
包,新建一个 AppDemoTestController 类,并新建一个 /demo/test/get
接口。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package cn.iocoder.yudao.module.demo.controller.app;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "用户 App - Test") @RestController @RequestMapping("/demo/test") @Validated public class AppDemoTestController {
@GetMapping("/get") @Operation(summary = "获取 test 信息") public CommonResult<String> get() { return success("true"); }
}
|
在 Controller 的命名上,额外增加 App 作为前缀,一方面区分是管理后台还是用户 App 的 Controller,另一方面避免 Spring Bean 的名字冲突。
可能你会奇怪,这里我们定义了两个 /demo/test/get
接口,会不会存在重复导致冲突呢?答案,当然是并不会。原因是:
controller.admin
包下的接口,默认会增加 /admin-api
,即最终的访问地址是 /admin-api/demo/test/get
controller.app
包下的接口,默认会增加 /app-api
,即最终的访问地址是 /app-api/demo/test/get
5. 启动 demo 服务
① 运行 SystemServerApplication 类,将 system
服务启动。运行 InfraServerApplication 类,将 infra
服务启动。
② 运行 DemoServerApplication 类,将新建的 demo
服务进行启动。启动完成后,使用浏览器打开 http://127.0.0.1:48099/doc.html (opens new window) 地址,进入该服务的 Swagger 接口文档。
③ 打开“管理后台 - Test”接口,进行 /admin-api/demo/test/get
接口的调试,如下图所示:
④ 打开“用户 App - Test”接口,进行 /app-api/demo/test/get
接口的调试,如下图所示:
6. 网关配置
① 打开 yudao-gateway
网关项目的 application.yml
配置文件,增加 demo
服务的路由配置。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| - id: demo-admin-api uri: grayLb://demo-server predicates: - Path=/admin-api/demo/** filters: - RewritePath=/admin-api/demo/v2/api-docs, /v2/api-docs - id: demo-app-api uri: grayLb://demo-server predicates: - Path=/app-api/demo/** filters: - RewritePath=/app-api/demo/v2/api-docs, /v2/api-docs
|
1 2 3
| - name: demo-server service-name: demo-server url: /admin-api/demo/v3/api-docs
|
② 运行 GatewayServerApplication 类,将 gateway
网关服务启动。
③ 使用浏览器打开 http://127.0.0.1:48080/doc.html (opens new window) 地址,进入网关的 Swagger 接口文档。然后,选择 demo-server
服务,即可进行 /admin-api/demo/test/get
和 /app-api/demo/test/get
接口的调试,如下图所示: