SpringBoot3?Web編程開(kāi)發(fā)的工程搭建攔截器及測(cè)試工具示例
一、簡(jiǎn)介
標(biāo)簽:Rest.攔截器.swagger.測(cè)試;
基于web包的依賴,SpringBoot可以快速啟動(dòng)一個(gè)web容器,簡(jiǎn)化項(xiàng)目的開(kāi)發(fā);
在web開(kāi)發(fā)中又涉及如下幾個(gè)功能點(diǎn):
攔截器:可以讓接口被訪問(wèn)之前,將請(qǐng)求攔截到,通過(guò)對(duì)請(qǐng)求的識(shí)別和校驗(yàn),判斷請(qǐng)求是否允許通過(guò);
頁(yè)面交互:對(duì)于服務(wù)端的開(kāi)發(fā)來(lái)說(shuō),需要具備簡(jiǎn)單的頁(yè)面開(kāi)發(fā)能力,解決部分場(chǎng)景的需求;
Swagger接口:通過(guò)簡(jiǎn)單的配置,快速生成接口的描述,并且提供對(duì)接口的測(cè)試能力;
Junit測(cè)試:通過(guò)編寫(xiě)代碼的方式對(duì)接口進(jìn)行測(cè)試,從而完成對(duì)接口的檢查和驗(yàn)證,并且可以不入侵原代碼結(jié)構(gòu);
二、工程搭建
1、工程結(jié)構(gòu)

2、依賴管理
<!-- 基礎(chǔ)框架組件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- 接口文檔組件 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
<!-- 前端頁(yè)面組件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- 單元測(cè)試組件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>三、Web開(kāi)發(fā)
1、接口開(kāi)發(fā)
編寫(xiě)四個(gè)簡(jiǎn)單常規(guī)的接口,從對(duì)資源操作的角度,也就是常說(shuō)的:增Post、刪Delete、改Put、查Get,并且使用了swagger注解,可以快速生成接口文檔;
@RestController
@Tag(name = "Rest接口")
public class RestWeb {
@Operation(summary = "Get接口")
@GetMapping("rest/get/{id}")
public String restGet(@PathVariable Integer id) {
return "OK:"+id;
}
@Operation(summary = "Post接口")
@PostMapping("/rest/post")
public String restPost(@RequestBody ParamBO param){
return "OK:"+param.getName();
}
@Operation(summary = "Put接口")
@PutMapping("/rest/put")
public String restPut(@RequestBody ParamBO param){
return "OK:"+param.getId();
}
@Operation(summary = "Delete接口")
@DeleteMapping("/rest/delete/{id}")
public String restDelete(@PathVariable Integer id){
return "OK:"+id;
}
}2、頁(yè)面交互
對(duì)于服務(wù)端開(kāi)發(fā)來(lái)說(shuō),在部分場(chǎng)景下是需要進(jìn)行簡(jiǎn)單的頁(yè)面開(kāi)發(fā)的,比如通過(guò)頁(yè)面渲染再去生成文件,或者直接通過(guò)頁(yè)面填充郵件內(nèi)容等;
數(shù)據(jù)接口
@Controller
public class PageWeb {
@RequestMapping("/page/view")
public ModelAndView pageView (HttpServletRequest request){
ModelAndView modelAndView = new ModelAndView() ;
// 普通參數(shù)
modelAndView.addObject("name", "cicada");
modelAndView.addObject("time", "2023-07-12");
// 對(duì)象模型
modelAndView.addObject("page", new PageBO(7,"頁(yè)面數(shù)據(jù)模型"));
// List集合
List<PageBO> pageList = new ArrayList<>() ;
pageList.add(new PageBO(1,"第一頁(yè)"));
pageList.add(new PageBO(2,"第二頁(yè)"));
modelAndView.addObject("pageList", pageList);
// Array數(shù)組
PageBO[] pageArr = new PageBO[]{new PageBO(6,"第六頁(yè)"),new PageBO(7,"第七頁(yè)")} ;
modelAndView.addObject("pageArr", pageArr);
modelAndView.setViewName("/page-view");
return modelAndView ;
}
}頁(yè)面解析:分別解析了普通參數(shù),實(shí)體對(duì)象,集合容器,數(shù)組容器等幾種數(shù)據(jù)模型;
<div style="text-align: center">
<hr/>
<h5>普通參數(shù)解析</h5>
姓名:<span th:text="${name}"></span>
時(shí)間:<span th:text="${time}"></span>
<hr/>
<h5>對(duì)象模型解析</h5>
整形:<span th:text="${page.getKey()}"></span>
字符:<span th:text="${page.getValue()}"></span>
<hr/>
<h5>集合容器解析</h5>
<table style="margin:0 auto;width: 200px">
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr th:each="page:${pageList}">
<td th:text="${page.getKey()}"></td>
<td th:text="${page.getValue()}"></td>
</tr>
</table>
<hr/>
<h5>數(shù)組容器解析</h5>
<table style="margin:0 auto;width: 200px">
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr th:each="page:${pageArr}">
<td th:text="${page.getKey()}"></td>
<td th:text="${page.getValue()}"></td>
</tr>
</table>
<hr/>
</div>效果圖展示

四、攔截器
1、攔截器定義
通過(guò)實(shí)現(xiàn)HandlerInterceptor接口,完成對(duì)兩個(gè)攔截器的自定義,請(qǐng)求在訪問(wèn)服務(wù)時(shí),必須通過(guò)兩個(gè)攔截器的校驗(yàn);
/**
* 攔截器一
*/
public class HeadInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(HeadInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
log.info("HeadInterceptor:preHandle");
Iterator<String> headNames = request.getHeaderNames().asIterator();
log.info("request-header");
while (headNames.hasNext()){
String headName = headNames.next();
String headValue = request.getHeader(headName);
System.out.println(headName+":"+headValue);
}
// 放開(kāi)攔截
return true;
}
@Override
public void postHandle(HttpServletRequest request,HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
log.info("HeadInterceptor:postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
Object handler, Exception e) throws Exception {
log.info("HeadInterceptor:afterCompletion");
}
}
/**
* 攔截器二
*/
public class BodyInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(BodyInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,
Object handler) throws Exception {
log.info("BodyInterceptor:preHandle");
Iterator<String> paramNames = request.getParameterNames().asIterator();
log.info("request-param");
while (paramNames.hasNext()){
String paramName = paramNames.next();
String paramValue = request.getParameter(paramName);
System.out.println(paramName+":"+paramValue);
}
// 放開(kāi)攔截
return true;
}
@Override
public void postHandle(HttpServletRequest request,HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
log.info("BodyInterceptor:postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
Object handler, Exception e) throws Exception {
log.info("BodyInterceptor:afterCompletion");
}
}2、攔截器配置
自定義攔截器之后,還需要添加到web工程的配置文件中,可以通過(guò)實(shí)現(xiàn)WebMvcConfigurer接口,完成自定義的配置添加;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 添加自定義攔截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HeadInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new BodyInterceptor()).addPathPatterns("/**");
}
}五、測(cè)試工具
1、Swagger接口
添加上述的springdoc依賴之后,還可以在配置文件中簡(jiǎn)單定義一些信息,訪問(wèn)IP:端口/swagger-ui/index.html即可;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 接口文檔配置
*/
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.info(new Info().title("【boot-web】").description("Rest接口文檔-2023-07-11")
.version("1.0.0"));
}
}
2、Junit測(cè)試
在個(gè)人的習(xí)慣上,Swagger接口文檔更偏向在前后端對(duì)接的時(shí)候使用,而Junit單元測(cè)試更符合開(kāi)發(fā)的時(shí)候使用,這里是對(duì)RestWeb中的接口進(jìn)行測(cè)試;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class RestWebTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testGet () throws Exception {
// GET接口測(cè)試
MvcResult mvcResult = mockMvc
.perform(MockMvcRequestBuilders.get("/rest/get/1"))
.andReturn();
printMvcResult(mvcResult);
}
@Test
public void testPost () throws Exception {
// 參數(shù)模型
JsonMapper jsonMapper = new JsonMapper();
ParamBO param = new ParamBO(null,"單元測(cè)試",new Date()) ;
String paramJson = jsonMapper.writeValueAsString(param) ;
// Post接口測(cè)試
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/rest/post")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON).content(paramJson)).andReturn();
printMvcResult(mvcResult);
}
@Test
public void testPut () throws Exception {
// 參數(shù)模型
JsonMapper jsonMapper = new JsonMapper();
ParamBO param = new ParamBO(7,"Junit組件",new Date()) ;
String paramJson = jsonMapper.writeValueAsString(param) ;
// Put接口測(cè)試
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.put("/rest/put")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON).content(paramJson)).andReturn();
printMvcResult(mvcResult);
}
@Test
public void testDelete () throws Exception {
// Delete接口測(cè)試
MvcResult mvcResult = mockMvc
.perform(MockMvcRequestBuilders.delete("/rest/delete/2"))
.andReturn();
printMvcResult(mvcResult);
}
/**
* 打印【MvcResult】信息
*/
private void printMvcResult (MvcResult mvcResult) throws Exception {
System.out.println("請(qǐng)求-URI【"+mvcResult.getRequest().getRequestURI()+"】");
System.out.println("響應(yīng)-status【"+mvcResult.getResponse().getStatus()+"】");
System.out.println("響應(yīng)-content【"+mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8)+"】");
}
}參考源碼
文檔倉(cāng)庫(kù):https://gitee.com/cicadasmile/butte-java-note
以上就是SpringBoot3 Web編程開(kāi)發(fā)的工程搭建攔截器及測(cè)試工具示例的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot3 Web搭建攔截器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java經(jīng)典設(shè)計(jì)模式之適配器模式原理與用法詳解
這篇文章主要介紹了Java經(jīng)典設(shè)計(jì)模式之適配器模式,簡(jiǎn)單說(shuō)明了適配器模式的概念、原理,并結(jié)合實(shí)例形式分析了java適配器模式的用法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-08-08
Java數(shù)據(jù)結(jié)構(gòu)中雙向鏈表的實(shí)現(xiàn)
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)中雙向鏈表的實(shí)現(xiàn),雙向鏈表是一種常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),它允許在鏈表中的任意位置進(jìn)行高效的插入和刪除操作,需要的朋友可以參考下2022-05-05
java byte數(shù)組與int,long,short,byte的轉(zhuǎn)換實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇java byte數(shù)組與int,long,short,byte的轉(zhuǎn)換實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
Java實(shí)現(xiàn)非對(duì)稱加密的三種方法
本文主要介紹了Java實(shí)現(xiàn)非對(duì)稱加密的三種方法,主要包括非對(duì)稱加密算法--DH(密鑰交換),非對(duì)稱加密算法--RSA,非對(duì)稱加密算法--EIGamal,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
Springboot基于BCrypt非對(duì)稱加密字符串的實(shí)現(xiàn)
本文主要介紹了Springboot基于BCrypt非對(duì)稱加密字符串的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Java匿名內(nèi)部類導(dǎo)致內(nèi)存泄露的原因與解決方案詳解
這篇文章主要為大家詳細(xì)介紹了Java因?yàn)槟涿麅?nèi)部類導(dǎo)致內(nèi)存泄露的原因以及其解決方案,文中的示例代碼講解詳細(xì),希望對(duì)大家有所幫助2022-11-11
聊一聊new對(duì)象與Spring對(duì)bean的初始化的差別
這篇文章主要介紹了聊一聊new對(duì)象與Spring對(duì)bean的初始化的差別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
SpringBoot 利用MultipartFile上傳本地圖片生成圖片鏈接的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot 利用MultipartFile上傳本地圖片生成圖片鏈接的實(shí)現(xiàn)方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03

