完善单元测试

This commit is contained in:
click33
2022-09-05 06:49:49 +08:00
parent 153785880d
commit 28701115dd
15 changed files with 722 additions and 179 deletions

View File

@@ -0,0 +1,75 @@
package cn.dev33.satoken.core.application;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import cn.dev33.satoken.application.SaApplication;
import cn.dev33.satoken.context.SaHolder;
/**
* SaApplication 存取值测试
*
* @author kong
* @since: 2022-9-4
*/
public class SaApplicationTest {
// 测试
@Test
public void testSaApplication() {
SaApplication application = SaHolder.getApplication();
// 取值
application.set("age", "18");
Assertions.assertEquals(application.get("age").toString(), "18");
Assertions.assertEquals(application.getInt("age"), 18);
Assertions.assertEquals(application.getLong("age"), 18L);
Assertions.assertEquals(application.getFloat("age"), 18f);
Assertions.assertEquals(application.getDouble("age"), 18.0);
Assertions.assertEquals(application.getString("age"), "18");
Assertions.assertEquals(application.get("age", 20), 18);
Assertions.assertEquals(application.get("age2", 20), 20);
Assertions.assertEquals(application.getString("age2"), null);
// lambda 取值,有值时依然是原值
Assertions.assertEquals(application.get("age", () -> "23"), "18");
Assertions.assertEquals(application.getInt("age"), 18);
// lambda 取值,无值时被写入新值
Assertions.assertEquals(application.get("age2", () -> "23"), "23");
Assertions.assertEquals(application.getInt("age2"), 23);
// getModel取值
Assertions.assertEquals(application.getModel("age", int.class), 18);
Assertions.assertEquals(application.getModel("age", int.class, 30), 18);
Assertions.assertEquals(application.getModel("age3", int.class, 30), 30);
// 删除值
application.delete("age");
Assertions.assertNull(application.get("age"));
// 是否为空
Assertions.assertTrue(application.valueIsNull(null));
Assertions.assertTrue(application.valueIsNull(""));
Assertions.assertFalse(application.valueIsNull("abc"));
// 为空时才能写入
application.setByNull("age4", "18");
Assertions.assertEquals(application.getInt("age4"), 18);
application.setByNull("age4", "20");
Assertions.assertEquals(application.getInt("age4"), 18);
// 清空
application.clear();
Assertions.assertEquals(application.keys().size(), 0);
// 获取所有值
application.set("key1", "value1");
application.set("key2", "value2");
application.set("key3", "value3");
Assertions.assertEquals(application.keys().size(), 3);
// 空列表
application.clear();
Assertions.assertEquals(application.keys().size(), 0);
}
}

View File

@@ -22,8 +22,18 @@ public class SaCookieTest {
.setSameSite("Lax")
.setHttpOnly(true)
.setSecure(true);
Assertions.assertEquals(cookie.getName(), "satoken");
Assertions.assertEquals(cookie.getValue(), "xxxx-xxxx-xxxx-xxxx");
Assertions.assertEquals(cookie.getDomain(), "https://sa-token.dev33.cn/");
Assertions.assertEquals(cookie.getMaxAge(), -1);
Assertions.assertEquals(cookie.getPath(), "/");
Assertions.assertEquals(cookie.getSameSite(), "Lax");
Assertions.assertEquals(cookie.getHttpOnly(), true);
Assertions.assertEquals(cookie.getSecure(), true);
Assertions.assertEquals(cookie.toHeaderValue(), "satoken=xxxx-xxxx-xxxx-xxxx; Domain=https://sa-token.dev33.cn/; Path=/; Secure; HttpOnly; sameSite=Lax");
Assertions.assertNotNull(cookie.toString());
}
}

View File

@@ -0,0 +1,29 @@
package cn.dev33.satoken.core.session;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import cn.dev33.satoken.session.TokenSign;
/**
* TokenSign 相关测试
*
* @author kong
* @since: 2022-9-4
*/
public class TokenSignTest {
// 测试
@Test
public void testTokenSign() {
TokenSign tokenSign = new TokenSign();
tokenSign.setDevice("PC");
tokenSign.setValue("ttt-value");
Assertions.assertEquals(tokenSign.getDevice(), "PC");
Assertions.assertEquals(tokenSign.getValue(), "ttt-value");
Assertions.assertNotNull(tokenSign.toString());
}
}

View File

@@ -3,6 +3,7 @@ package cn.dev33.satoken.integrate.configure;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import cn.dev33.satoken.exception.IdTokenInvalidException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
@@ -40,5 +41,11 @@ public class HandlerException {
public SaResult handlerNotSafeException(NotSafeException e) {
return SaResult.error().setCode(901);
}
// id-token 校验失败code=902
@ExceptionHandler(IdTokenInvalidException.class)
public SaResult handlerIdTokenInvalidException(IdTokenInvalidException e) {
return SaResult.error().setCode(902);
}
}

View File

@@ -0,0 +1,39 @@
package cn.dev33.satoken.integrate.id;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.id.SaIdUtil;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.util.SaResult;
/**
* id-token Controller
*
* @author kong
*
*/
@RestController
@RequestMapping("/id/")
public class SaIdTokenController {
// 获取信息
@RequestMapping("getInfo")
public SaResult getInfo() {
// 获取并校验id-token
String idToken = SpringMVCUtil.getRequest().getHeader(SaIdUtil.ID_TOKEN);
SaIdUtil.checkToken(idToken);
// 返回信息
return SaResult.data("info=zhangsan");
}
// 获取信息2
@RequestMapping("getInfo2")
public SaResult getInfo2() {
// 获取并校验id-token
SaIdUtil.checkCurrentRequestToken();
// 返回信息
return SaResult.data("info=zhangsan2");
}
}

View File

@@ -0,0 +1,130 @@
package cn.dev33.satoken.integrate.id;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.exception.IdTokenInvalidException;
import cn.dev33.satoken.id.SaIdUtil;
import cn.dev33.satoken.integrate.StartUpApplication;
import cn.dev33.satoken.util.SaResult;
/**
* id-token Controller 测试
*
* @author kong
*
*/
@SpringBootTest(classes = StartUpApplication.class)
public class SaIdTokenControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mvc;
// 开始
@BeforeEach
public void before() {
mvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
// 获取信息
@Test
public void testGetInfo() {
String token = SaIdUtil.getToken();
// 加token能调通
SaResult res = request("/id/getInfo", token);
Assertions.assertEquals(res.getCode(), 200);
// 不加token不能调通
SaResult res2 = request("/id/getInfo", "xxx");
Assertions.assertEquals(res2.getCode(), 902);
// 获取信息2
token = SaIdUtil.getTokenNh();
// 加token能调通
SaResult res3 = request("/id/getInfo2", token);
Assertions.assertEquals(res3.getCode(), 200);
// 不加token不能调通
SaResult res4 = request("/id/getInfo2", "xxx");
Assertions.assertEquals(res4.getCode(), 902);
}
// 基础测试
@Test
public void testApi() {
String token = SaIdUtil.getToken();
// 刷新一下,会有变化
SaIdUtil.refreshToken();
String token2 = SaIdUtil.getToken();
Assertions.assertNotEquals(token, token2);
// 旧token变为次级token
String pastToken = SaIdUtil.getPastTokenNh();
Assertions.assertEquals(token, pastToken);
// dao中应该有值
String daoToken = SaManager.getSaTokenDao().get("satoken:var:id-token");
String daoToken2 = SaManager.getSaTokenDao().get("satoken:var:past-id-token");
Assertions.assertEquals(token2, daoToken);
Assertions.assertEquals(token, daoToken2);
// 新旧都有效
Assertions.assertTrue(SaIdUtil.isValid(token));
Assertions.assertTrue(SaIdUtil.isValid(token2));
// 空的不行
Assertions.assertFalse(SaIdUtil.isValid(null));
Assertions.assertFalse(SaIdUtil.isValid(""));
// 不抛出异常
Assertions.assertDoesNotThrow(() -> SaIdUtil.checkToken(token));
Assertions.assertDoesNotThrow(() -> SaIdUtil.checkToken(token2));
// 抛出异常
Assertions.assertThrows(IdTokenInvalidException.class, () -> SaIdUtil.checkToken(null));
Assertions.assertThrows(IdTokenInvalidException.class, () -> SaIdUtil.checkToken(""));
Assertions.assertThrows(IdTokenInvalidException.class, () -> SaIdUtil.checkToken("aaa"));
}
// 封装请求
private SaResult request(String path, String idToken) {
try {
// 发请求
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders.post(path)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.accept(MediaType.APPLICATION_PROBLEM_JSON)
.header(SaIdUtil.ID_TOKEN, idToken)
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
// 转 Map
String content = mvcResult.getResponse().getContentAsString();
Map<String, Object> map = SaManager.getSaJsonTemplate().parseJsonToMap(content);
// 转 SaResult 对象
return new SaResult().setMap(map);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -21,7 +21,7 @@ import cn.dev33.satoken.util.SoMap;
/**
* Sa-Token 登录API测试
*
* @author Auster
* @author kong
*
*/
@SpringBootTest(classes = StartUpApplication.class)
@@ -95,8 +95,8 @@ public class LoginControllerTest {
private SoMap request(String path) throws Exception {
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders.post(path)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.accept(MediaType.APPLICATION_PROBLEM_JSON)
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();

View File

@@ -0,0 +1,40 @@
package cn.dev33.satoken.integrate.more;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
/**
* 其它测试
*
* @author kong
*
*/
@RestController
@RequestMapping("/more/")
public class MoreController {
// 一些基本的测试
@RequestMapping("getInfo")
public SaResult getInfo() {
SaRequest req = SaHolder.getRequest();
boolean flag =
SaFoxUtil.equals(req.getParam("name"), "zhang")
&& SaFoxUtil.equals(req.getParam("name2", "li"), "li")
&& SaFoxUtil.equals(req.getParamNotNull("name"), "zhang")
&& req.isParam("name", "zhang")
&& req.isPath("/more/getInfo")
&& req.hasParam("name")
&& SaFoxUtil.equals(req.getHeader("div"), "val")
&& SaFoxUtil.equals(req.getHeader("div", "zhang"), "val")
&& SaFoxUtil.equals(req.getHeader("div2", "zhang"), "zhang")
;
return SaResult.data(flag);
}
}

View File

@@ -0,0 +1,97 @@
package cn.dev33.satoken.integrate.more;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.integrate.StartUpApplication;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.spring.SaTokenContextForSpring;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.util.SaResult;
/**
* 其它测试
*
* @author kong
*
*/
@SpringBootTest(classes = StartUpApplication.class)
public class MoreControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mvc;
// 开始
@BeforeEach
public void before() {
mvc = MockMvcBuilders.webAppContextSetup(wac).build();
// 在单元测试时,通过 request.getServletPath() 获取到的请求路径为空,导致路由拦截不正确
// 虽然不知道为什么会这样,但是暂时可以通过以下方式来解决
SaManager.setSaTokenContext(new SaTokenContextForSpring() {
@Override
public SaRequest getRequest() {
return new SaRequestForServlet(SpringMVCUtil.getRequest()) {
@Override
public String getRequestPath() {
return request.getRequestURI();
}
};
}
});
}
// 基础API测试
@Test
public void testApi() {
SaResult res = request("/more/getInfo?name=zhang");
Assertions.assertEquals(res.getData(), true);
}
// 封装请求
private SaResult request(String path) {
try {
// 发请求
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders.post(path)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.accept(MediaType.APPLICATION_PROBLEM_JSON)
.header("div", "val")
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
// 转 Map
String content = mvcResult.getResponse().getContentAsString();
Map<String, Object> map = SaManager.getSaJsonTemplate().parseJsonToMap(content);
// 转 SaResult 对象
return new SaResult().setMap(map);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,28 @@
package cn.dev33.satoken.integrate.router;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.util.SaResult;
/**
* 路由鉴权测试
*
* @author kong
*
*/
@RestController
@RequestMapping("/rt/")
public class RouterController {
@RequestMapping("getInfo")
public SaResult getInfo() {
return SaResult.ok();
}
@RequestMapping("getInfo*")
public SaResult getInfo2() {
return SaResult.ok();
}
}

View File

@@ -0,0 +1,179 @@
package cn.dev33.satoken.integrate.router;
import java.util.Arrays;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.integrate.StartUpApplication;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.router.SaRouterStaff;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.spring.SaTokenContextForSpring;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.util.SaResult;
/**
* C Controller 测试
*
* @author kong
*
*/
@SpringBootTest(classes = StartUpApplication.class)
public class RouterControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mvc;
// 开始
@BeforeEach
public void before() {
mvc = MockMvcBuilders.webAppContextSetup(wac).build();
// 在单元测试时,通过 request.getServletPath() 获取到的请求路径为空,导致路由拦截不正确
// 虽然不知道为什么会这样,但是暂时可以通过以下方式来解决
SaManager.setSaTokenContext(new SaTokenContextForSpring() {
@Override
public SaRequest getRequest() {
return new SaRequestForServlet(SpringMVCUtil.getRequest()) {
@Override
public String getRequestPath() {
return request.getRequestURI();
}
};
}
});
}
// 基础API测试
@Test
public void testApi() {
// 是否命中
SaRouterStaff staff = SaRouter.match(false);
Assertions.assertFalse(staff.isHit());
// 重置
staff.reset();
Assertions.assertTrue(staff.isHit());
// lambda 形式
SaRouterStaff staff2 = SaRouter.match(r -> false);
Assertions.assertFalse(staff2.isHit());
// 匹配
Assertions.assertTrue(SaRouter.isMatch("/user/**", "/user/add"));
Assertions.assertTrue(SaRouter.isMatch(new String[] {"/user/**", "/art/**", "/goods/**"}, "/art/delete"));
Assertions.assertTrue(SaRouter.isMatch(Arrays.asList("/user/**", "/art/**", "/goods/**"), "/art/delete"));
Assertions.assertTrue(SaRouter.isMatch(new String[] {"POST", "GET", "PUT"}, "GET"));
// 不匹配的
Assertions.assertTrue(SaRouter.notMatch(false).isHit());
Assertions.assertTrue(SaRouter.notMatch(r -> false).isHit());
}
@Test
public void testRouter() {
// getInfo
SaResult res = request("/rt/getInfo?name=zhang");
Assertions.assertEquals(res.getCode(), 201);
// getInfo2
SaResult res2 = request("/rt/getInfo2");
Assertions.assertEquals(res2.getCode(), 202);
// getInfo3
SaResult res3 = request("/rt/getInfo3");
Assertions.assertEquals(res3.getCode(), 203);
// getInfo4
SaResult res4 = request("/rt/getInfo4");
Assertions.assertEquals(res4.getCode(), 204);
// getInfo5
SaResult res5 = request("/rt/getInfo5");
Assertions.assertEquals(res5.getCode(), 205);
// getInfo6
SaResult res6 = request("/rt/getInfo6");
Assertions.assertEquals(res6.getCode(), 206);
// getInfo7
SaResult res7 = request("/rt/getInfo7");
Assertions.assertEquals(res7.getCode(), 200);
// getInfo8
SaResult res8 = request("/rt/getInfo8");
Assertions.assertEquals(res8.getCode(), 200);
// getInfo9
SaResult res9 = request("/rt/getInfo9");
Assertions.assertEquals(res9.getCode(), 209);
// getInfo10
SaResult res10 = request("/rt/getInfo10");
Assertions.assertEquals(res10.getCode(), 200);
// getInfo11
SaResult res11 = request("/rt/getInfo11");
Assertions.assertEquals(res11.getCode(), 211);
// getInfo12
SaResult res12 = request("/rt/getInfo12");
Assertions.assertEquals(res12.getCode(), 212);
// getInfo13
SaResult res13 = request("/rt/getInfo13");
Assertions.assertEquals(res13.getCode(), 213);
// getInfo14
SaResult res14 = request("/rt/getInfo14");
Assertions.assertEquals(res14.getCode(), 214);
// getInfo15
SaResult res15 = request("/rt/getInfo15");
Assertions.assertEquals(res15.getCode(), 215);
}
// 封装请求
private SaResult request(String path) {
try {
// 发请求
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders.post(path)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.accept(MediaType.APPLICATION_PROBLEM_JSON)
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
// 转 Map
String content = mvcResult.getResponse().getContentAsString();
Map<String, Object> map = SaManager.getSaJsonTemplate().parseJsonToMap(content);
// 转 SaResult 对象
return new SaResult().setMap(map);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,79 @@
package cn.dev33.satoken.integrate.router;
import java.util.Arrays;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token 相关配置类
*
* @author kong
* @since: 2022-9-2
*/
@Configuration
public class SaTokenConfigure2 implements WebMvcConfigurer {
// 路由鉴权
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 路由鉴权
registry.addInterceptor(new SaInterceptor(handle -> {
// 匹配 getInfo 返回code=201
SaRouter.match("/**")
.match(SaHttpMethod.POST)
.matchMethod("POST")
.match(SaHolder.getRequest().getMethod().equals("POST"))
.match(r -> SaHolder.getRequest().isPath("/rt/getInfo"))
.match(r -> SaHolder.getRequest().isParam("name", "zhang"))
.back(SaResult.code(201));
// 匹配 getInfo2 返回code=202
SaRouter.match("/rt/getInfo2")
.match(Arrays.asList("/rt/getInfo2", "/rt/*"))
.notMatch("/rt/getInfo3")
.notMatch(false)
.notMatch(r -> false)
.notMatch(SaHttpMethod.GET)
.notMatchMethod("PUT")
.notMatch(Arrays.asList("/rt/getInfo4", "/rt/getInfo5"))
.back(SaResult.code(202));
// 匹配 getInfo3 返回code=203
SaRouter.match("/rt/getInfo3", "/rt/getInfo4", () -> SaRouter.back(SaResult.code(203)));
SaRouter.match("/rt/getInfo4", "/rt/getInfo5", r -> SaRouter.back(SaResult.code(204)));
SaRouter.match("/rt/getInfo5", () -> SaRouter.back(SaResult.code(205)));
SaRouter.match("/rt/getInfo6", r -> SaRouter.back(SaResult.code(206)));
// 通往 Controller
SaRouter.match(Arrays.asList("/rt/getInfo7")).stop();
// 通往 Controller
SaRouter.match("/rt/getInfo8", () -> SaRouter.stop());
SaRouter.matchMethod("POST").match("/rt/getInfo9").free(r -> SaRouter.back(SaResult.code(209)));
SaRouter.match(SaHttpMethod.POST).match("/rt/getInfo10").setHit(false).back();
// 11
SaRouter.notMatch("/rt/getInfo11").reset().match("/rt/getInfo11").back(SaResult.code(211));
SaRouter.notMatch(SaHttpMethod.GET).match("/rt/getInfo12").back(SaResult.code(212));
SaRouter.notMatch(Arrays.asList("/rt/getInfo12", "/rt/getInfo14")).match("/rt/getInfo13").back(SaResult.code(213));
SaRouter.notMatchMethod("GET", "PUT").match("/rt/getInfo14").back(SaResult.code(214));
// SaRouter.match(Arrays.asList("/rt/getInfo15", "/rt/getInfo16"))
if(SaRouter.isMatchCurrURI("/rt/getInfo15")) {
SaRouter.newMatch().free(r -> SaRouter.back(SaResult.code(215)));
}
})).addPathPatterns("/**");
}
}