源码:https://github.com/GiraffePeng/spring-cloud-scaffolding
网关服务
- 路由分发,作为所有接口请求入口,负责进行请求的流量转发
- 动态路由配置与更新,可以将路由配置移至redis或者DB中,达到实时改变路由配置。
- Ribbon均衡负载
- 统一的zuul网关层异常处理,方便调用方统一的异常数据解析处理
- 请求限流,将阈值写入配置,动态配置限流的阈值大小
- 服务层级熔断降级,服务宕机后,可及时进行熔断处理,防止服务器雪崩
- Swagger API文档,在线实时生成接口文档以及接口测试,
- zuul过滤器,可在网关层加入各种过滤器,达到转发实际服务器前的一系列操作
- zuul网关层身份认证(oauth2.0),作为资源认证服务,将需要带有令牌访问的接口进行认证,如果不符合要求,进行返回错误信息
1、搭建网关服务
搭建最基本的zuul网关
- 1、配置pom.xml,添加spring-cloud-starter-zuul的依赖
- 2、配置application.yml,设置分流操作
- 3、配置启动类,添加@EnableZuulProxy注解,开启动态路由
- 4、配置过滤器,实现ZuulFilter抽象类
- 5、配置过滤器到启动类。
第4和第5步,不是非必须的,而是自定义过滤器的操作
这里就不过多描述
2、动态路由配置与更新
在没有集成cloud或者apollo等配置中心时,无法做到配置的热更新,但是我们想动态的去更改zuul的路由信息时,可以采用以下方式:
2.1、从redis中获取路由信息
集成各种配置进行实例化,调用DynamicRouteLocator的构造函数,修改路由信息。
/**
* 动态路由配置类
*/
@Configuration
public class DynamicRouteConfiguration {
private Registration registration;
private DiscoveryClient discovery;
private ZuulProperties zuulProperties;
private ServerProperties server;
private RedisTemplate redisTemplate;
public DynamicRouteConfiguration(Registration registration, DiscoveryClient discovery,
ZuulProperties zuulProperties, ServerProperties server, RedisTemplate redisTemplate) {
this.registration = registration;
this.discovery = discovery;
this.zuulProperties = zuulProperties;
this.server = server;
this.redisTemplate = redisTemplate;
}
@Bean
public DynamicRouteLocator dynamicRouteLocator() {
return new DynamicRouteLocator(server.getServlet().getServletPrefix()
, discovery
, zuulProperties
, registration
, redisTemplate);
}
}
DynamicRouteLocator类集成DiscoveryClientRouteLocator,重写路由配置
ps:这里zuul网关会自动去轮询调用locateRoutesFromDb方法来获取最新的路由配置信息,无须关注是否要触发更新,只关注如何取路由信息和更新路由数据即可。
/**
* 动态路由实现
*/
@Slf4j
public class DynamicRouteLocator extends DiscoveryClientRouteLocator {
private ZuulProperties properties;
private RedisTemplate redisTemplate;
public DynamicRouteLocator(String servletPath, DiscoveryClient discovery, ZuulProperties properties,
ServiceInstance localServiceInstance, RedisTemplate redisTemplate) {
super(servletPath, discovery, properties, localServiceInstance);
this.properties = properties;
this.redisTemplate = redisTemplate;
}
/**
* 重写路由配置
* <p>
* 1. properties 配置。
* 2. eureka 默认配置。
* 3. DB数据库配置。
* 4. redis自定义数据格式配置
* @return
*/
@Override
protected LinkedHashMap<String, ZuulProperties.ZuulRoute> locateRoutes() {
LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();
//读取properties配置、eureka默认配置
routesMap.putAll(super.locateRoutes());
log.debug("初始默认的路由配置完成");
routesMap.putAll(locateRoutesFromDb());
LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
String path = entry.getKey();
if (!path.startsWith("/")) {
path = "/" + path;
}
if (StringUtils.isNotBlank(this.properties.getPrefix())) {
path = this.properties.getPrefix() + path;
if (!path.startsWith("/")) {
path = "/" + path;
}
}
values.put(path, entry.getValue());
}
return values;
}
/**
* Redis中保存的,没有从系统模块取,避免启动链路依赖问题(取舍),网关依赖业务模块的问题
*
* @return
*/
private Map<String, ZuulProperties.ZuulRoute> locateRoutesFromDb() {
Map<String, ZuulProperties.ZuulRoute> routes = new LinkedHashMap<>();
//从redis中获取路由信息
String obj = (String)redisTemplate.opsForValue().get("_ROUTE_KEY");
if (obj == null) {
return routes;
}
//转换为ZuulRoute集合
List<ZuulRoute> results = JSONObject.parseArray(obj, ZuulRoute.class);
//List<ZuulRoute> results = (List<ZuulRoute>) obj;
//循环路由集合,给zuulRoute赋值,并装进Map集合中
for (ZuulRoute result : results) {
if (StringUtils.isBlank(result.getPath()) && StringUtils.isBlank(result.getUrl())) {
continue;
}
ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
try {
zuulRoute.setId(result.getServiceId());
zuulRoute.setPath(result.getPath());
zuulRoute.setServiceId(result.getServiceId());
zuulRoute.setRetryable(StringUtils.equals(result.getRetryable(), "0") ? Boolean.FALSE : Boolean.TRUE);
zuulRoute.setStripPrefix(StringUtils.equals(result.getStripPrefix(), "0") ? Boolean.FALSE : Boolean.TRUE);
zuulRoute.setUrl(result.getUrl());
if (StringUtils.isNotBlank(result.getSensitiveheadersList())) {
String[] split = result.getSensitiveheadersList().split(",");
Set<String> sensitiveHeaderSet = new HashSet<String>();
for (int i = 0; i < split.length; i++) {
sensitiveHeaderSet.add(split[i]);
}
zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
zuulRoute.setCustomSensitiveHeaders(true);
}
} catch (Exception e) {
log.error("从缓存加载路由配置异常", e);
}
log.debug("添加自定义的路由配置,path:{},serviceId:{}", zuulRoute.getPath(), zuulRoute.getServiceId());
routes.put(zuulRoute.getPath(), zuulRoute);
}
return routes;
}
}
ZuulRoute路由实体类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ZuulRoute implements Serializable{
private static final long serialVersionUID = 1L;
/**
* router Id
*/
private Integer id;
/**
* 路由路径
*/
private String path;
/**
* 服务名称
*/
private String serviceId;
/**
* url代理
*/
private String url;
/**
* 转发去掉前缀
*/
private String stripPrefix;
/**
* 是否重试
*/
private String retryable;
/**
* 是否启用
*/
private String enabled;
/**
* 敏感请求头
*/
private String sensitiveheadersList;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 删除标识(0-正常,1-删除)
*/
private String delFlag;
}
2.2、在redis中放入路由信息
建立controller,注入RedisTemplate,提供接口放入路由信息,代码如下:
@RestController
public class ProjectServiceController {
@Autowired
RedisTemplate redisTemplate;
private final static String ZUUL_ROUTE = "_ROUTE_KEY";
/**
* 通过传递参数修改redis中的路由信息
* path:路由路径
* serviceId:服务名称
* stripPrefix:转发去掉前缀
* enabled:是否启用
* retryable:是否重试
* 来动态变更路由消息。
* @param zuulRoutes
*/
@PostMapping("/zuulRoute/refresh")
public void refreshZuulRoute(@RequestBody List<ZuulRoute> zuulRoutes){
for (ZuulRoute zuulRoute : zuulRoutes) {
if(StringUtils.isBlank(zuulRoute.getPath()) || StringUtils.isBlank(zuulRoute.getServiceId())) {
throw new RuntimeException("路由更新传入的参数缺失");
}
if(StringUtils.isBlank(zuulRoute.getStripPrefix()) || !(zuulRoute.getStripPrefix().equals("1") || zuulRoute.getStripPrefix().equals("0"))) {
throw new RuntimeException("路由更新传入的参数缺失");
}
if(StringUtils.isBlank(zuulRoute.getEnabled()) || !(zuulRoute.getEnabled().equals("1") || zuulRoute.getEnabled().equals("0"))) {
throw new RuntimeException("路由更新传入的参数缺失");
}
if(StringUtils.isBlank(zuulRoute.getRetryable()) || !(zuulRoute.getRetryable().equals("1") || zuulRoute.getRetryable().equals("0"))) {
throw new RuntimeException("路由更新传入的参数缺失");
}
}
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set(ZUUL_ROUTE, JSONObject.toJSONString(zuulRoutes));
}
}
2.3、从关系型数据库中获取路由信息
除了使用redis,还可以使用关系型数据库获取路由信息,通过更改数据库表中的路由信息,进行动态加载。
以mysql数据库为例,数据库表结构如下:
CREATE TABLE `sys_zuul_route` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'router Id',
`path` varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '路由路径',
`service_id` varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '服务名称',
`url` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'url代理',
`strip_prefix` char(1) CHARACTER SET utf8mb4 DEFAULT '1' COMMENT '转发去掉前缀',
`retryable` char(1) CHARACTER SET utf8mb4 DEFAULT '1' COMMENT '是否重试',
`enabled` char(1) CHARACTER SET utf8mb4 DEFAULT '1' COMMENT '是否启用',
`sensitiveHeaders_list` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '敏感请求头',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
`del_flag` char(1) CHARACTER SET utf8mb4 DEFAULT '0' COMMENT '删除标识(0-正常,1-删除)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='动态路由配置表';
这里不在具体展示从数据库中如何获取路由,大体思路为,集成mybatis或者jpa,在DynamicRouteLocator类中查询该表的数据,进行转换为List<ZuulRoute>即可。
3、统一的zuul网关层异常处理
在没有对网关错误进行特殊处理时,通过网关调用其他服务出现错误会出现如下错误信息:
{
"timestamp": "2019-07-11T06:11:46.557+0000",
"status": 500,
"error": "Internal Server Error",
"message": "GENERAL"
}
当我们要求对返回结果有统一的成功或者失败格式时,这种错误返回格式就会不满足我们的需要,我们需要进行改造。
修改网关的异常返回信息的方式有很多,这里选择比较简单的,直接通过实现ErrorController接口,重写getErrorPath()方法,将至引导到自己实现的异常处理方法上,代码如下:
/**
* zuul网关层统一的异常处理,错误返回格式的修改
*/
@RestController
public class ErrorHandler implements ErrorController{
private final ErrorAttributes errorAttributes;
@Autowired
public ErrorHandler(ErrorAttributes errorAttributes) {
this.errorAttributes = errorAttributes;
}
@RequestMapping(value = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ErrorResult error(HttpServletRequest request) {
WebRequest webRequest = new ServletWebRequest(request);
Map<String, Object> errorAttributes = this.errorAttributes.getErrorAttributes(webRequest, true);
String msg = errorAttributes.getOrDefault("error", "not found").toString();
String code = errorAttributes.getOrDefault("status", 404).toString();
return ErrorResult.builder().code(Integer.valueOf(code)).msg(msg).build();
}
//重写getErrorPath()方法,将至引导到自己实现的异常处理方法上
@Override
public String getErrorPath() {
return "/error";
}
}
ErrorResult异常数据封装类
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResult implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer code;
private String msg;
}
重启zuul网关服务,调用接口报错提示内容如下:
{
"code": 500,
"msg": "Internal Server Error"
}
4、zuul的请求过滤器
zuul还能进行请求过滤,演这里示了一个授权校验的例子,检查请求是否提供了token参数,如果没有的话拒绝转发服务,返回401响应状态码和错误信息,首先我们需要先新建一个TokenFilter类来继承ZuulFilter这个类,实现它的四个接口
public class TokenFilter extends ZuulFilter {
/**
* 四种类型:pre,routing,error,post
pre:主要用在路由映射的阶段是寻找路由映射表的
routing:具体的路由转发过滤器是在routing路由器,具体的请求转发的时候会调用
error:一旦前面的过滤器出错了,会调用error过滤器。
post:当routing,error运行完后才会调用该过滤器,是在最后阶段的
*/
@Override
public String filterType() {
return PRE_TYPE;
}
//自定义过滤器执行的顺序,数值越大越靠后执行,越小就越先执行
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
}
//控制过滤器生效不生效,可以在里面写一串逻辑来控制
@Override
public boolean shouldFilter() {
return true;
}
//执行过滤逻辑
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getParameter("token");
if(token == null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().setCharacterEncoding("UTF-8");
ctx.getResponse().getWriter().write("禁止访问");
} catch (Exception e){}
return null;
}
return null;
}
}
filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
- 1.pre:可以在请求被路由之前调用,用在路由映射的阶段是寻找路由映射表的
- 2.route:在路由请求时候被调用,具体的路由转发过滤器是在routing路由器具体的请求转发的时候会调用
- 3.error:处理请求时发生错误时被调用
- 4.post:当routing,error运行完后才会调用该过滤器,是在最后阶段的
然后接下来使用spring的java中显式配置bean(即@Configuration和@Bean的使用),注册过滤器到启动类
@Configuration
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulServerApplication {
public static void main(String[] args) {
SpringApplication.run( ZuulServerApplication.class, args );
}
@Bean
public TokenFilter getZuulFilter(){
return new TokenFilter();
}
}
5、网关请求限流
RateLimiter是Google开源的实现了令牌桶算法的限流工具(速率限制器)。
令牌桶的大体算法逻辑如下:
- a.按特定的速率向令牌桶投放令牌
- b.根据预设的匹配规则先对报文进行分类,不符合匹配规则的报文不需要经过令牌桶的处理,直接发送;
- c.符合匹配规则的报文,则需要令牌桶进行处理。当桶中有足够的令牌则报文可以被继续发送下去,同时令牌桶中的令牌 量按报文的长度做相应的减少;
- d.当令牌桶中的令牌不足时,报文将不能被发送,只有等到桶中生成了新的令牌,报文才可以发送。这就可以限制报文的流量只能是小于等于令牌生成的速度,达到限制流量的目的。
Spring Cloud Zuul RateLimiter结合Zuul对RateLimiter进行了封装,通过实现ZuulFilter提供了服务限流功能.
限流粒度/类型 | 说明 |
---|---|
服务粒度 | 默认配置,当前服务模块的限流控制 |
用户粒度 | 针对请求的用户进行限流 |
ORIGIN粒度 | 用户请求的origin作为粒度控制 |
接口URL粒度 | 请求接口的地址作为粒度控制 |
以上粒度自由组合,又可以支持多种情况。
如果还不够,自定义RateLimitKeyGenerator实现。
因为使用到令牌桶算法,作为令牌桶的容器,也支持多个,分别为:
- InMemoryRateLimiter - 使用 ConcurrentHashMap作为数据存储
- ConsulRateLimiter - 使用 Consul 作为数据存储
- RedisRateLimiter - 使用 Redis 作为数据存储
- SpringDataRateLimiter - 使用 数据库 作为数据存储
集成Spring Cloud Zuul RateLimiter的步骤非常简单,大体分为三步:
- 1、引入pom依赖
- 2、修改yml配置文件,加入限流规则
- 3、如果提供的已有限流规则不满足条件,可以自定义(该步可省略)
5.1、引入pom依赖
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
5.2、修改yml配置文件,加入限流规则
#为所有服务进行限流,3秒内只能请求1次,并且请求时间总数不能超过5秒
zuul:
ratelimit:
#开启限流
enabled: true
#令牌桶的容器方式,使用redis
repository: REDIS
#默认全部服务开启限流, default-policy
default-policy:
#限制请求次数
limit: 1
#限制请求时间
quota: 5
#多少秒后重置令牌桶
refresh-interval: 3
开启限流后访问服务,3秒内第二次请求会出现如下错误:
{
"code": 429,
"msg": "Too Many Requests"
}
6、网关服务级别的熔断处理
针对服务级别层次进行熔断处理,代码如下:
/**
* 定制服务级别的熔断处理
*/
@Component
public class ZuulRoteFallback implements FallbackProvider{
/**
* 指定针对哪个服务进行熔断处理
*/
@Override
public String getRoute() {
//指定针对哪个服务进行熔断处理
return "userservice";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
/**
* 熔断后返回的内容
*/
@Override
public InputStream getBody() throws IOException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 500);
jsonObject.put("msg", "用户服务不可用,请稍后重试");
return new ByteArrayInputStream(jsonObject.toJSONString().getBytes());
}
@Override
public String getStatusText() throws IOException {
return this.getStatusCode().getReasonPhrase();
}
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return this.getStatusCode().value();
}
@Override
public void close() {
}
};
}
}
需要注意的地方有三处:
- 1、实现FallbackProvider接口 重写两个方法。
- 2、getRoute()方法指定需要对哪个服务进行熔断处理,如果配置为*,则表示对所有服务进行熔断处理。
- 3、ClientHttpResponse中的getBody()指定熔断后提示的错误信息,自己根据系统要求自定义即可。
当userservice不可用时,提示如下信息:
{
"msg": "用户服务不可用,请稍后重试",
"code": 500
}
7、利用oauth2.0统一鉴权:
实现资源服务器,详情点击此处
8、网关集成swagger:
因为存在网关,需求为通过zuul统一查看各个服务的REST API文档,不再需要访问单独业务服务的地址来查阅API文档。
8.1、引入依赖
建议引入的swagger版本使用比较高的,此处version使用2.9.2。
<!-- Swagger核心包 start -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- Swagger核心包 end -->
8.2、添加认证过滤url
由于用zuul作为资源服务器,如果不将swagger的页面和请求路径进行过滤,将无法正常访问API文档。添加代码如下:
zuul-server中application.yml文件
ignore:
urls[3]: /swagger-resources/**
urls[4]: /swagger-ui.html
urls[5]: /*/v2/api-docs
urls[6]: /swagger/api-docs
urls[7]: /webjars/**
然后在ResourceServerConfig类中统一循环过滤
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry hasAuthority = http.authorizeRequests();
//从yml配置文件中获取不需要认证的url
filterIgnorePropertiesConfig.getUrls().forEach(url -> hasAuthority.antMatchers(url).permitAll());
hasAuthority.antMatchers("/**").hasAuthority("USER");
}
8.3、构建swagger的服务下拉列表
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulServerApplication {
public static void main(String[] args) {
SpringApplication.run( ZuulServerApplication.class, args );
}
@Component
@Primary
class DocumentationConfig implements SwaggerResourcesProvider {
//此处通过根据zuul的路由配置,进行添加swagger的服务下拉列表
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<SwaggerResource>();
resources.add(swaggerResource("用户服务","/user/v2/api-docs","1.0"));
resources.add(swaggerResource("项目服务","/project/v2/api-docs","1.0"));
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
}
8.4、构建swagger在zuul的统一界面
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
Parameter build = ticketPar.name("Authorization").description("jwt的Token")
.modelRef(new ModelRef("string")).parameterType("header")
.required(false).build(); //header中的Authorization参数非必填,传空也可以
pars.add(build);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()).globalOperationParameters(pars);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("脚手架")
.description("spring cloud 脚手架")
.termsOfServiceUrl("")
.version("1.0")
.build();
}
@Bean
UiConfiguration uiConfig() {
return new UiConfiguration(null, "list", "alpha", "schema",
UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS, false, true, 60000L);
}
}
至此zuul项目的改造完成,接下来是针对对应服务的改造,此处只提及userservice-server的改造,其他业务项目步骤是一致的。
8.5、改造userservice-server 引入依赖
因为依赖是引入在了父级pom工程中,此处无需再次依赖
8.6、改造userservice-server 配置swagger的config
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
//加入swagger中的header固定头部信息(Authorization),为了传递jwt的token令牌使用。
ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
Parameter build = ticketPar.name("Authorization").description("jwt的Token")
.modelRef(new ModelRef("string")).parameterType("header")
.required(false).build(); //header中的Authorization参数非必填,传空也可以
pars.add(build);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()) // 配置说明
.select() // 选择那些路径和 api 会生成 document
.apis(RequestHandlerSelectors.basePackage("com.peng"))
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build().globalOperationParameters(pars); // 创建
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("用户服务 Swagger API").description("spring cloud 脚手架")
.termsOfServiceUrl("").version("1.0").build();
}
}
8.7、改造userservice-server 在controller上加入swagger介绍注解
@RestController
@RequestMapping("/user")
@Api(tags = "用户平台接口") //swagger类注解
public class UserServiceController implements UserService {
@Autowired
UserRepository userRepository;
@Autowired
UserServiceDetail userServiceDetail;
@Autowired
RedissonClient redissonClient;
@PostMapping("/register")
@ApiOperation(value = "用户注册接口", httpMethod = "POST") //swagger方法注解
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String", defaultValue = "请输入用户名"),
@ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", defaultValue = "请输入密码")
})
public com.peng.userservice.server.User postUser(@RequestParam("username") String username,
@RequestParam("password") String password){
return userServiceDetail.insertUser(username, password);
}
}
8.8、swagger的大体注解如下:
作用范围 | API | 使用位置 |
---|---|---|
对象属性 | @ApiModelProperty | 用在出入参数对象的字段上 |
协议集描述 | @Api | 用于controller类上 |
协议描述 | @ApiOperation | 用在controller的方法上 |
Response集 | @ApiResponses | 用在controller的方法上 |
Response | @ApiResponse | 用在 @ApiResponses里边 |
非对象参数集 | @ApiImplicitParams | 用在controller的方法上 |
非对象参数描述 | @ApiImplicitParam | 用在@ApiImplicitParams的方法里边 |
描述返回对象的意义 | @ApiModel | 用在返回对象类上 |