一、背景
關於swagger的特性功能,用過的人都很清楚,確實也好用。可以參考http://springfox.github.io/springfox/docs/current/。另外關於swagger的使用集成,其實比較簡單,網上博客也不少。尤其是SpringBoot出現後,集成更爲簡單方便。當然有時候也會遇到一些問題,以前集成過幾次,都很順手,但這次卻遇到麻煩。
二、問題
這次swagger的集成,是在原有項目的基礎上進行的。開始是打開不了頁面,後面能打開了卻出不來接口的內容。換過swagger的版本,但仍然不行,網上的資料也看過,還是不能解決。嘗試了幾次之後,終於成功!
出現的問題主要有以下幾種:
- swagger-ui.html頁面打不開;
- swagger-ui.html頁面打開後,接口的內容出不來;
- swagger-resources/configuration/ui報404錯誤;
- 換成高一點的版本後,打開swagger-ui.html頁面時彈窗。
其中比較接近的一些是出現了下面的頁面(下面的圖經過處理了,有點模糊),只是接口的信息沒有列出來。
三、問題的分析與解決
3.1 問題分析
在分析問題時,肯定是要結合項目自身的情況。要清楚項目用了哪些框架,這些框架結合時,哪些地方可能會有影響等。也要清楚swagger本身的一些信息,知道它的結構目錄。大概原理等。當然遇到簡單的問題的話,可以不需要知道這些,但這次解決確實是分析了幾方面的因素。
先介紹下項目本身的情況,項目是分佈式的,已經上線運行了一些時間。使用的框架大概如下:
- Spring MVC;
- Shiro;
- 相關聯的使用了Hibernate、Mybatis、Spring等等。
我需要集成swagger的項目,主要使用了Spring MVC和shiro,其它的沒有影響。Spring MVC都熟悉,shiro是安全方面的框架。清楚這些情況後,開始分析出現問題的可能原因:
- web.xml配置的原因,攔截了swagger-ui.html及相關請求;
- Spring MVC配置文件的原因,比如沒有掃描到相應的Controller;
- shiro的原因,因爲shiro也攔截一些沒有驗證或沒有放開(放開就是可以直接訪問的如js文件)的請求;
- 項目使用了過濾器的原因,也將請求攔截了;
- 其它原因。
經過一定程序的熟悉瞭解,清楚了項目確實有濾器,會將所以請求先進行攔截。而我們在集成swagger後訪問的地址是http://ip:port/projectName/swagger-ui.html。如果在web.xml中配置的請求是*.json,那這個請求就進不去,也就訪問不了了。當時的配置如下所示(自然是訪問不了的):
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
請求進入過濾器後,對很多請求進行攔截驗證,所以這樣一來,就算我讓swager-ui.html請求通過,但請求swagger-ui.html後swagger的其它請求依然不通過,因爲簡單的讓使用swagger時出現的請求通過,不能從根本上解決問題。
對使用swagger時,一些請求及靜態文件也會被shiro攔截,所以也需要修改shiro的配置。
對swagger,要確保它本身請求對應的swagger中的控制器能被掃描到。同時也要在項目中開啓swagger的使用。下面開始找到解決方案,最後解決問題。
3.2 解決方案
根本上面的分析,因爲嘗試過多種方案,所以決定改造swagger-ui,將它本地化。基本做法就是將swagger-ui項目的內容複製到要集成的項目,然後寫Controller以引導swagger-ui.html的訪問,再修改配置文件,最後測試,大概是這樣一個流程。
下面是當時集成時使用的swagger依賴,版本號是2.6.1。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
3.3 問題解決
3.3.3 修改前端(js、頁面)
實現swagger-ui本地化時,是在項目中,直接將swagger-ui的文件複製過來。具體的目錄結構如下圖所示:
其中,webapp/static/swagger目錄下的文件具體目錄如下:
其實static/swagger中的文件是從swagger-ui裏複製過來的,沒有做過任何修改。但在/WEB-INF/pages/swagger目錄下的頁面,swagger-ui.html和o2c.jsp沒用上,只有index.jsp用上了,它也複製的swagger-ui.html的內容,然後引入了兩個js,實現了中文版的界面。index.jsp的具體代碼如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" pageEncoding="UTF-8"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="icon" type="image/png" href="webjars/springfox-swagger-ui/images/favicon-32x32.png" sizes="32x32"/>
<link rel="icon" type="image/png" href="webjars/springfox-swagger-ui/images/favicon-16x16.png" sizes="16x16"/>
<link href='${ctx}/static/swagger/webjars/springfox-swagger-ui/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='${ctx}/static/swagger/webjars/springfox-swagger-ui/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='${ctx}/static/swagger/webjars/springfox-swagger-ui/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='${ctx}/static/swagger/webjars/springfox-swagger-ui/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
<link href='${ctx}/static/swagger/webjars/springfox-swagger-ui/css/print.css' media='print' rel='stylesheet' type='text/css'/>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/object-assign-pollyfill.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/jquery.wiggle.min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/handlebars-4.0.5.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/lodash.min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/backbone-min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/swagger-ui.min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/highlight.9.1.0.pack_extended.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/jsoneditor.min.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/marked.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lib/swagger-oauth.js' type='text/javascript'></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/springfox.js' type='text/javascript'></script>
<!-- 加入下面的兩個js後,訪問swagger時語言會切換到中文 -->
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lang/translator.js' type="text/javascript"></script>
<script src='${ctx}/static/swagger/webjars/springfox-swagger-ui/lang/zh-cn.js' type="text/javascript"></script>
</head>
<body class="swagger-section">
<div id='header'>
<div class="swagger-ui-wrap">
<a id="logo" href="http://swagger.io">
<img class="logo__img" alt="swagger" height="30" width="30" src="${ctx}/static/swagger/webjars/springfox-swagger-ui/images/logo_small.png" />
<span class="logo__title">swagger</span>
</a>
<form id='api_selector'>
<div class='input'>
<select id="select_baseUrl" name="select_baseUrl"/>
</div>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
<div id='auth_container'></div>
<div class='input'><a id="explore" class="header__btn" href="#" data-sw-translate>Explore</a></div>
</form>
</div>
</div>
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate> </div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</body>
</html>
3.3.2 添加Swagger-ui請求的引導類及配置
在輸入http://localhost:8088/swagger-ui.html時,需要引入此請求進入到/pages/swagger/index.jsp,所以需要寫一個Controller來引導此請求的訪問。代碼如下:
@Controller
@RequestMapping
@Slf4j
public class SwaggerController {
/**
* @Description 進入Swagger-ui.html頁面
* @Author Ethan
* @Param []
* @return org.springframework.web.servlet.ModelAndView
* @Version 1.0
*/
@RequestMapping("/swagger-ui")
public ModelAndView index() {
ModelAndView mv = new ModelAndView();
mv.setViewName("swagger/index");
return mv;
}
// @RequestMapping(value = "/webjars/springfox-swagger-ui/o2c", method = RequestMethod.GET)
// public ModelAndView o2c() {
// ModelAndView mv = new ModelAndView();
// mv.setViewName("swagger/o2c");
// return mv;
// }
}
然後寫swagger的配置類,代碼如下:
@Configuration
@EnableWebMvc
@EnableSwagger2
@ComponentScan(basePackages = {"com.corn.web.controller"})
public class SwaggerConfig {
}
3.3.1 關於配置文件:修改web.xml和Spring MVC的配置文件。
修改web.xml文件,如下:
<!-- 使用swagger時,註釋下面的filter,不然swagger的請求會被攔截而不能通過 -->
<!-- <filter>
<filter-name>URL-REDIRECT-FILTER</filter-name>
<filter-class>com.corn.web.filters.UrlAuthAndEncryFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>URL-REDIRECT-FILTER</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<!-- 啓用swagger時,用此配置,因爲接口的後綴是.json,而swagger請求的後綴不一樣,直接用/ -->
<!--<url-pattern>/</url-pattern>-->
<!-- 線上環境時,不啓用swagger,用下面的配置 -->
<url-pattern>*.json</url-pattern>
</servlet-mapping>
修改Spring MVC的配置文件,需要加入swagger中controller所在包的路徑掃描這一配置,如下:
<!-- 在啓用swagger時,因爲需要請求swagger的Controller,所以需要把swagger請求的Controller對應的上層路徑springfox.documentation.swagger2加入掃描中 -->
<context:component-scan base-package="springfox.documentation.swagger2" />
另外,需要注意的是,最初我寫的掃描路徑是springfox.documentation.swagger2.web,但發現報錯了。後面改成springfox.documentation.swagger2就可以了。
下面的截圖是swagger依賴的目錄結構圖,swagger的頁面或其它請求,基本上請求的是Swagger2Controller,從圖中可以看出此類所在的位置。
3.3.4 本地測試
上面的工作完成後,啓動項目,在瀏覽器中輸入地址:http://localhost:8088/swagger-ui.html,打開訪問正常了,說明swagger-ui的本地化成功了。
需要注意的一點是,訪問swagger時輸入的地址一定要有sagger-ui.html,不然打開頁面是空白的,即那些接口是顯示不出來的。另外,有可能打開swagger-ui.html時,會顯示如下內容,但過可能幾秒鐘,接口內容就出來了。