SpringBoot3之Web编程

打印 上一主题 下一主题

主题 942|帖子 942|积分 2826

标签:Rest.拦截器.swagger.测试;
一、简介

基于web包的依赖,SpringBoot可以快速启动一个web容器,简化项目的开发;
在web开发中又涉及如下几个功能点:
拦截器:可以让接口被访问之前,将请求拦截到,通过对请求的识别和校验,判断请求是否允许通过;
页面交互:对于服务端的开发来说,需要具备简单的页面开发能力,解决部分场景的需求;
Swagger接口:通过简单的配置,快速生成接口的描述,并且提供对接口的测试能力;
Junit测试:通过编写代码的方式对接口进行测试,从而完成对接口的检查和验证,并且可以不入侵原代码结构;
二、工程搭建

1、工程结构


2、依赖管理
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-web</artifactId>
  4.     <version>${spring-boot.version}</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.springdoc</groupId>
  8.     <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  9.     <version>${springdoc.version}</version>
  10. </dependency>
  11. <dependency>
  12.     <groupId>org.springframework.boot</groupId>
  13.     <artifactId>spring-boot-starter-thymeleaf</artifactId>
  14.     <version>${spring-boot.version}</version>
  15. </dependency>
  16. <dependency>
  17.     <groupId>org.springframework.boot</groupId>
  18.     <artifactId>spring-boot-starter-test</artifactId>
  19.     <version>${spring-boot.version}</version>
  20.     <exclusions>
  21.         <exclusion>
  22.             <groupId>org.slf4j</groupId>
  23.             <artifactId>slf4j-api</artifactId>
  24.         </exclusion>
  25.     </exclusions>
  26. </dependency>
  27. <dependency>
  28.     <groupId>junit</groupId>
  29.     <artifactId>junit</artifactId>
  30.     <version>${junit.version}</version>
  31. </dependency>
复制代码
三、Web开发

1、接口开发

编写四个简单常规的接口,从对资源操作的角度,也就是常说的:增Post、删Delete、改Put、查Get,并且使用了swagger注解,可以快速生成接口文档;
  1. @RestController
  2. @Tag(name = "Rest接口")
  3. public class RestWeb {
  4.     @Operation(summary = "Get接口")
  5.     @GetMapping("rest/get/{id}")
  6.     public String restGet(@PathVariable Integer id) {
  7.         return "OK:"+id;
  8.     }
  9.     @Operation(summary = "Post接口")
  10.     @PostMapping("/rest/post")
  11.     public String restPost(@RequestBody ParamBO param){
  12.         return "OK:"+param.getName();
  13.     }
  14.     @Operation(summary = "Put接口")
  15.     @PutMapping("/rest/put")
  16.     public String restPut(@RequestBody ParamBO param){
  17.         return "OK:"+param.getId();
  18.     }
  19.     @Operation(summary = "Delete接口")
  20.     @DeleteMapping("/rest/delete/{id}")
  21.     public String restDelete(@PathVariable Integer id){
  22.         return "OK:"+id;
  23.     }
  24. }
复制代码
2、页面交互

对于服务端开发来说,在部分场景下是需要进行简单的页面开发的,比如通过页面渲染再去生成文件,或者直接通过页面填充邮件内容等;
数据接口
  1. @Controller
  2. public class PageWeb {
  3.     @RequestMapping("/page/view")
  4.     public ModelAndView pageView (HttpServletRequest request){
  5.         ModelAndView modelAndView = new ModelAndView() ;
  6.         // 普通参数
  7.         modelAndView.addObject("name", "cicada");
  8.         modelAndView.addObject("time", "2023-07-12");
  9.         // 对象模型
  10.         modelAndView.addObject("page", new PageBO(7,"页面数据模型"));
  11.         // List集合
  12.         List<PageBO> pageList = new ArrayList<>() ;
  13.         pageList.add(new PageBO(1,"第一页"));
  14.         pageList.add(new PageBO(2,"第二页"));
  15.         modelAndView.addObject("pageList", pageList);
  16.         // Array数组
  17.         PageBO[] pageArr = new PageBO[]{new PageBO(6,"第六页"),new PageBO(7,"第七页")} ;
  18.         modelAndView.addObject("pageArr", pageArr);
  19.         modelAndView.setViewName("/page-view");
  20.         return modelAndView ;
  21.     }
  22. }
复制代码
页面解析:分别解析了普通参数,实体对象,集合容器,数组容器等几种数据模型;
  1.     <hr/>
  2.     <h5>普通参数解析</h5>
  3.     姓名:
  4.     时间:
  5.     <hr/>
  6.     <h5>对象模型解析</h5>
  7.     整形:
  8.     字符:
  9.     <hr/>
  10.     <h5>集合容器解析</h5>
  11.     <table >
  12.         <tr>
  13.             <th>Key</th>
  14.             <th>Value</th>
  15.         </tr>
  16.         <tr th:each="page:${pageList}">
  17.             <td th:text="${page.getKey()}"></td>
  18.             <td th:text="${page.getValue()}"></td>
  19.         </tr>
  20.     </table>
  21.     <hr/>
  22.     <h5>数组容器解析</h5>
  23.     <table >
  24.         <tr>
  25.             <th>Key</th>
  26.             <th>Value</th>
  27.         </tr>
  28.         <tr th:each="page:${pageArr}">
  29.             <td th:text="${page.getKey()}"></td>
  30.             <td th:text="${page.getValue()}"></td>
  31.         </tr>
  32.     </table>
  33.     <hr/>
复制代码
效果图展示

四、拦截器

1、拦截器定义

通过实现HandlerInterceptor接口,完成对两个拦截器的自定义,请求在访问服务时,必须通过两个拦截器的校验;
  1. /**
  2. * 拦截器一
  3. */
  4. public class HeadInterceptor implements HandlerInterceptor {
  5.     private static final Logger log  = LoggerFactory.getLogger(HeadInterceptor.class);
  6.     @Override
  7.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
  8.                              Object handler) throws Exception {
  9.         log.info("HeadInterceptor:preHandle");
  10.         Iterator<String> headNames = request.getHeaderNames().asIterator();
  11.         log.info("request-header");
  12.         while (headNames.hasNext()){
  13.             String headName = headNames.next();
  14.             String headValue = request.getHeader(headName);
  15.             System.out.println(headName+":"+headValue);
  16.         }
  17.         // 放开拦截
  18.         return true;
  19.     }
  20.     @Override
  21.     public void postHandle(HttpServletRequest request,HttpServletResponse response,
  22.                            Object handler, ModelAndView modelAndView) throws Exception {
  23.         log.info("HeadInterceptor:postHandle");
  24.     }
  25.     @Override
  26.     public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
  27.                                 Object handler, Exception e) throws Exception {
  28.         log.info("HeadInterceptor:afterCompletion");
  29.     }
  30. }
  31. /**
  32. * 拦截器二
  33. */
  34. public class BodyInterceptor implements HandlerInterceptor {
  35.     private static final Logger log  = LoggerFactory.getLogger(BodyInterceptor.class);
  36.     @Override
  37.     public boolean preHandle(HttpServletRequest request,HttpServletResponse response,
  38.                              Object handler) throws Exception {
  39.         log.info("BodyInterceptor:preHandle");
  40.         Iterator<String> paramNames = request.getParameterNames().asIterator();
  41.         log.info("request-param");
  42.         while (paramNames.hasNext()){
  43.             String paramName = paramNames.next();
  44.             String paramValue = request.getParameter(paramName);
  45.             System.out.println(paramName+":"+paramValue);
  46.         }
  47.         // 放开拦截
  48.         return true;
  49.     }
  50.     @Override
  51.     public void postHandle(HttpServletRequest request,HttpServletResponse response,
  52.                            Object handler, ModelAndView modelAndView) throws Exception {
  53.         log.info("BodyInterceptor:postHandle");
  54.     }
  55.     @Override
  56.     public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
  57.                                 Object handler, Exception e) throws Exception {
  58.         log.info("BodyInterceptor:afterCompletion");
  59.     }
  60. }
复制代码
2、拦截器配置

自定义拦截器之后,还需要添加到web工程的配置文件中,可以通过实现WebMvcConfigurer接口,完成自定义的配置添加;
  1. @Configuration
  2. public class WebMvcConfig implements WebMvcConfigurer {
  3.     /**
  4.      * 添加自定义拦截器
  5.      */
  6.     @Override
  7.     public void addInterceptors(InterceptorRegistry registry) {
  8.         registry.addInterceptor(new HeadInterceptor()).addPathPatterns("/**");
  9.         registry.addInterceptor(new BodyInterceptor()).addPathPatterns("/**");
  10.     }
  11. }
复制代码
五、测试工具

1、Swagger接口

添加上述的springdoc依赖之后,还可以在配置文件中简单定义一些信息,访问IP:端口/swagger-ui/index.html即可;
  1. @Configuration
  2. public class WebMvcConfig implements WebMvcConfigurer {
  3.     /**
  4.      * 接口文档配置
  5.      */
  6.     @Bean
  7.     public OpenAPI openAPI() {
  8.         return new OpenAPI()
  9.                 .info(new Info().title("【boot-web】").description("Rest接口文档-2023-07-11")
  10.                 .version("1.0.0"));
  11.     }
  12. }
复制代码

2、Junit测试

在个人的习惯上,Swagger接口文档更偏向在前后端对接的时候使用,而Junit单元测试更符合开发的时候使用,这里是对RestWeb中的接口进行测试;
  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. @AutoConfigureMockMvc
  4. public class RestWebTest {
  5.     @Autowired
  6.     private MockMvc mockMvc;
  7.     @Test
  8.     public void testGet () throws Exception {
  9.         // GET接口测试
  10.         MvcResult mvcResult = mockMvc
  11.                 .perform(MockMvcRequestBuilders.get("/rest/get/1"))
  12.                 .andReturn();
  13.         printMvcResult(mvcResult);
  14.     }
  15.     @Test
  16.     public void testPost () throws Exception {
  17.         // 参数模型
  18.         JsonMapper jsonMapper = new JsonMapper();
  19.         ParamBO param = new ParamBO(null,"单元测试",new Date()) ;
  20.         String paramJson = jsonMapper.writeValueAsString(param) ;
  21.         // Post接口测试
  22.         MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/rest/post")
  23.                 .contentType(MediaType.APPLICATION_JSON)
  24.                 .accept(MediaType.APPLICATION_JSON).content(paramJson)).andReturn();
  25.         printMvcResult(mvcResult);
  26.     }
  27.     @Test
  28.     public void testPut () throws Exception {
  29.         // 参数模型
  30.         JsonMapper jsonMapper = new JsonMapper();
  31.         ParamBO param = new ParamBO(7,"Junit组件",new Date()) ;
  32.         String paramJson = jsonMapper.writeValueAsString(param) ;
  33.         // Put接口测试
  34.         MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.put("/rest/put")
  35.                 .contentType(MediaType.APPLICATION_JSON)
  36.                 .accept(MediaType.APPLICATION_JSON).content(paramJson)).andReturn();
  37.         printMvcResult(mvcResult);
  38.     }
  39.     @Test
  40.     public void testDelete () throws Exception {
  41.         // Delete接口测试
  42.         MvcResult mvcResult = mockMvc
  43.                 .perform(MockMvcRequestBuilders.delete("/rest/delete/2"))
  44.                 .andReturn();
  45.         printMvcResult(mvcResult);
  46.     }
  47.     /**
  48.      * 打印【MvcResult】信息
  49.      */
  50.     private void printMvcResult (MvcResult mvcResult) throws Exception {
  51.         System.out.println("请求-URI【"+mvcResult.getRequest().getRequestURI()+"】");
  52.         System.out.println("响应-status【"+mvcResult.getResponse().getStatus()+"】");
  53.         System.out.println("响应-content【"+mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8)+"】");
  54.     }
  55. }
复制代码
六、参考源码
  1. 文档仓库:
  2. https://gitee.com/cicadasmile/butte-java-note
  3. 源码仓库:
  4. https://gitee.com/cicadasmile/butte-spring-parent
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

自由的羽毛

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表