• 使用Spring MVC开发RESTful API


    第3章 使用Spring MVC开发RESTful API

    Restful简介

    第一印象

    左侧是传统写法,右侧是RESTful写法

    1. 用url描述资源,而不是行为

    2. 用http方法描述行为,使用http状态码来表示不同的结果(200表示成功,500表示错误)

    3. 使用json交互数据

    4. RESTful只是一种风格,并不是强制的标准

    REST成熟度模型

    编写第一个Restful API

    通过用户查询,创建,删除,修改来学习怎么写一个Restful API

    编写针对RestfullAPI的测试用例

    UserController.java

    @RestController
    @RequestMapping("user")
    public class UserController {
    
        private List<User> getThreeEmptyUsers() {
            List<User> userList = new ArrayList<>();
            userList.add(new User());
            userList.add(new User());
            userList.add(new User());
            return userList;
        }
    
        @RequestMapping(value = "query1", method = RequestMethod.GET)
        public List<User> query() {
            return getThreeEmptyUsers();
        }
    }
    

    UserControllerTest.java

    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UserControllerTest {
        @Autowired
        private WebApplicationContext context;
    
        private MockMvc mockMvc;
    
        @Before
        public void setup() {
            mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
        }
    
        @Test
        public void whenQuerySuccess() throws Exception {
            mockMvc.perform(get("/user/query1")
                    .contentType(MediaType.APPLICATION_JSON_UTF8))
                    .andExpect(status().isOk()) // 返回状态码为200
                    .andExpect(jsonPath("$.length()").value(3));  // 返回数据的集合长度是3
        }
    }
    

    jsonPath表达式

    常用注解

    @RestControlelr 标明此Controller提供RestAPI

    @RequestMapping及其变体,映射http请求url到java方法

    @RequestParam 映射请求参数到Java方法的参数

    @PageableDefault 指定分页参数的默认值

    @JsonView 控制json输出内容,使用步骤如下

    • 使用接口来声明多个视图
    • 在值对象的get方法上指定视图
    • 在Controller方法上指定视图

    @GetMapping @RequestMapping的变体

    传递参数

    @PathVariable 映射url片段到java方法的参数 用户详情服务

    • 在url声明中使用正则表达式

    @RequestBody 映射请求体到java方法的参数

    日期类型参数的处理

    • 传递时间戳,有利于前后台分离

    @Valid注解和BindingResult验证请求参数的合法性并处理校验结果

    参数校验

    常用的验证注解

    2018-09-03_004934.png

    自定义消息

    • message = ""

    自定义校验注解

    • 参照代码的MyConstraint

    服务异常处理

    工具:chrome插件Restlet Client测试Restful接口的插件

    Spring Boot中默认的错误处理机制

    分析源码:BasicErrorController

    如果请求一个不存在的url,app发出的请求返回json格式,浏览器发出的请求返回 页面格式。

    依据Content-Type来判断是请求的页面还是json

    自定义异常处理

    text/html 基于状态码处理

    • 配置404 resources/resources/error/404.html

    application/json

    • 参照代码UserNotExistException

    拦截REST服务

    Filter 过滤器

    自定义过滤器,TimeFilter,加Component注释

    第三方过滤器,LogFilter,通过WebConfig添加

    拿不到Controller方法

    Interceptor 拦截器

    TimeInterceptor

    拿不到Controller方法的参数

    分析源码:DispatcherServlet/doService/doDispatcher/ha.handle(参数的拼装是调用这个方法完成的)

    Aspect 切片

    when/where/do what

    关系

    使用REST方式处理文件服务

    测试方法

    @Test
    public void whenUploadSuccess() throws Exception{
        String result = mockMvc.perform(fileUpload("/file")
                                        .file(new MockMultipartFile("file", "text.txt", "multipart/form-data", "hello update".getBytes("UTF-8"))))
            .andExpect(status().isOk())
            .andReturn().getResponse().getContentAsString();
        System.out.println(result);
    }
    

    文件上传下载

    @RestController
    @RequestMapping("file")
    public class FileController {
        @PostMapping
        public FileInfo upload(MultipartFile file) throws Exception {
    
            System.out.println("name: " + file.getName());
            System.out.println("filename: " + file.getOriginalFilename());
            String filePath = System.getProperty("user.home") + File.separator + new Date().getTime() + ".txt";
            File localFile = new File(filePath);
            file.transferTo(localFile);
    
            return new FileInfo(filePath);
        }
    
        @GetMapping("{id}")
        public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
            String filePath = System.getProperty("user.home") + File.separator + id + ".txt";
            File file = new File(filePath);
            if (!file.exists()) {
                System.out.println("文件不存在");
                return;
            }
            try (
                    InputStream is = new FileInputStream(file);
                    OutputStream os = response.getOutputStream();
            ) {
                response.setContentType("application/x-download");
                response.addHeader("Content-Disposition", "attachment;filename=test.txt");
    
                IOUtils.copy(is, os);
                os.flush();
            }
        }
    }
    
  • 相关阅读:
    博客园发展,我也来谈谈
    为什么说JavaScript是基于对象的语言?
    Email地址加密JS版
    Flash上传文件(结合asp.net)
    软件测试工程师面试题
    asp.net 创建文件夹时出错:未找到路径“D:\”的一部分。(asp.net 使用 FSO)
    发布一个可用在Blog上的Flash Mp3 Player (也支持flv格式)
    一直没掌握的一个简单的Update语句
    句柄的理解(选摘)
    消息的基本概念
  • 原文地址:https://www.cnblogs.com/okokabcd/p/9576616.html
Copyright © 2020-2023  润新知