Why?
技術(shù)變革的車輪不斷向前,伴隨著k8s、docker等新技術(shù)的落地,陳舊的技術(shù)棧,千瘡百孔的工程,已經(jīng)逐步成為技術(shù)負(fù)債的黑洞。秉承著“前人挖坑后人罵,后人填坑苦哈哈”的精神,我來吧,苦哈哈。
What?
-
Jersey2.x 多Servlet-Mapping
Spring 3 映射Mappings,基于web.xml 映射Servlet,如以下代碼示例,目的是為了實(shí)現(xiàn)接口的默認(rèn)前綴并控制接口版本,以映射不同的鑒權(quán)版本、攔截器等
<servlet>
<servlet-name>Jersey2</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey2</servlet-name>
<url-pattern>/rest/v1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Jersey2</servlet-name>
<url-pattern>/rest/v2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Jersey2</servlet-name>
<url-pattern>/rest/v3</url-pattern>
</servlet-mapping>
基于springboot想實(shí)現(xiàn)接口的默認(rèn)前綴,存在以下幾種方式
每一個接口添加前綴 或多個接口實(shí)現(xiàn)(當(dāng)我沒說)- @ApplicationPath
然而無法實(shí)現(xiàn)多個path共存的想法,因此貌似走到了怪圈里。。走了好久好久好久。。
直到發(fā)現(xiàn)了以下的文檔:
Springboot 中Jersey 的multiple Application實(shí)現(xiàn)
核心思想:即對Servlet掃描規(guī)則進(jìn)行了拓展,完美的解決了以上問題。
-
SpringBoot Jar包運(yùn)行,提示FileNotFound
原本的配置是這個樣子的,基于IDE調(diào)試的過程中一直很順利,直到基于jar部署的時候,涼涼了
public class JerseyConfig extends ResourceConfig {
public JerseyConfig(){
//掃描Jersey實(shí)例所在包
packages("com.xx.xx");
// 注冊JacksonFeature
register(JacksonFeature.class);
}
}
貌似又走到了怪圈里。。走了好久好久好久。。
直到發(fā)現(xiàn)了以下的文檔:
jersey在 spring boot 添加 packages 掃描路徑支持
核心思想:springboot打包成jar之后,jersey packages掃描不到相關(guān)類,故使用Spring的掃描機(jī)制進(jìn)行處理
此處發(fā)現(xiàn)可以優(yōu)化的點(diǎn),之前是進(jìn)行包下的所有類掃描并注冊,之后啟動后會提示一些警告,故可以在之中判斷class是有@Path的引用,再進(jìn)行注冊
-
多Application實(shí)例,注冊不成功
原以為逃離了怪圈。。好遠(yuǎn)好遠(yuǎn)好遠(yuǎn)。。基于Jar部署后,啟動成功了,然而調(diào)用接口后,404??!
又又又涼涼涼了。。
貌似又又走到了怪圈里。。走了好久好久。。
之后毅然決然的查看了Application的相關(guān)源碼,發(fā)現(xiàn)了事情的真相。
public class Application {
public Set<Class<?>> getClasses() {
return Collections.emptySet();
}
...省略
}
getClasses() 方法即為基于以上實(shí)例掃描到的Jersey實(shí)例,通過debug發(fā)現(xiàn)以下為空,瞬間懂了,將上文掃描到的classes,返回即可。
希望這回真的逃離了怪圈。。好遠(yuǎn)好遠(yuǎn)好遠(yuǎn)好遠(yuǎn)。。
-
@ Produces 不指定類型或者干脆沒有這個注解
基于以上的一通兒操作,我以為我今天一定可以霸屏"填坑走多遠(yuǎn)排行版"第一把交椅,然而又又又又TM的出現(xiàn)了,已經(jīng)一個正常的請求,后臺提示 text/html 沒有解析器。
?。?!這是一個應(yīng)該響應(yīng)成JSON的請求!!!
貌似又又又又又又走到了怪圈里。。有點(diǎn)走走走走走走不動了。。
冷靜了許久。。想到了兩個解決方案:
全局搜索,然后一個一個補(bǔ)全,之后打死哪些不寫全代碼的人- 配置默認(rèn)的響應(yīng)MediaType
最終在Jersey包下找到了以下類ContainerResponseFilter,大體的源碼如下
package javax.ws.rs.container;
import java.io.IOException;
public interface ContainerResponseFilter {
/**
* Filter method called after a response has been provided for a request
* (either by a {@link ContainerRequestFilter request filter} or by a
* matched resource method.
* <p>
* Filters in the filter chain are ordered according to their {@code javax.annotation.Priority}
* class-level annotation value.
* </p>
*
* @param requestContext request context.
* @param responseContext response context.
* @throws IOException if an I/O exception occurs.
*/
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException;
}
關(guān)鍵的一段英文在下面
Filter method called after a response has been provided for a request
?。?!在請求的響應(yīng)返回時觸發(fā) ?。?!
果斷實(shí)現(xiàn)接口,對于代碼做容錯,大體邏輯如下:
沒有@Produces 響應(yīng)默認(rèn)為MediaType.APPLICATION_JSON
有@Produces 但是沒有值,則一樣變成MediaType.APPLICATION_JSON