SpringMVC 使用Restful api,让你的代码变得更优雅,让你的文档看起来更漂亮

1,258 阅读5分钟

0. 什么是Restful

服务器后台设计API接口时,目前最流行的风格(原则/标准/规范)就是RESTful,往往简称为REST。

其中 REST=REpresentational State Transfer

REST直译:表现层状态转移
REST核心含义:无状态的资源 资源的变化(CURD)都是通过操作去实现的 资源可以用 URI 表示 用不同的URI和方法,表示对资源的不同操作

简单的说,就是使用同一个URI,就能实现增删改查的请求。而区别增删改查则需要以下典型的Rest方法:

  • GET:获取资源
  • POST:新建资源
  • PUT:更新资源
  • DELETE:删除资源

1.Spring中对Restful的支持

Spring对Restful有很好的支持,提供了以下注解分别对应上述的方法。

@GetMapping

@PostMapping

@PutMapping

@DeleteMapping

2.使用Restful实现增删改查

那么我们走一遍增删改查。通过以下例子可以看出,不管增删改查,URI都是http://localhost:8081/test/companies/。这样对你的程序设计,维护,文档设计,维护都很有帮助。

2.1 @GetMapping 取得数据

前端请求url例子

http://localhost:8081/test/companies/任意公司ID

后端接收代码。这里要讲解的就是,@GetMapping中的{companyId}代表具体的公司id,配合@PathVariable注解,就能够将URL中的字符串提取成参数变量。

@GetMapping(value="/companies/{companyId}")
public ResponseDto getCompany(@PathVariable("companyId") int companyId) {
	return service.getCompany(companyId);
}

2.2 @PostMapping 插入数据。取到Json的值,做数据校验

前端请求url例子

http://localhost:8081/test/companies/

如果用postman测试,你需要包含一段json,作为你要插入的数据。

后端代码。因为你的接收数据在body中,所以实体类前必须添加@RequestBody注解。当然了,你也可以进行数据校验,并把结果放入BindingResult。

@PostMapping(value="/companies")
public ResponseDto regitsCompany(@Valid @RequestBody MCompany dto, BindingResult result) {
    return service.registCompany(dto);
}

2.3 @PutMapping 更新数据。同时取到URL的值跟json的值

前端URL例子。跟2.2中的post一样,body中传递json。这里就不截图了。

http://localhost:8081/test/companies/任意公司ID

后端代码。这里又有一个变通,就是既需要使用@PathVariable,又要使用@RequestBody,才能把url中的值跟json的值同时取到。

@PutMapping(value="/companies/{companyId}")
@Transactional
public ResponseDto updateCompany(@PathVariable("companyId") int companyId, @Valid @RequestBody MCompany dto,
        BindingResult result) {
    dto.setCompanyId(companyId);
    return service.updateCompany(dto);
}

2.4 @DeleteMapping 删除数据

前端URL例子

http://localhost:8081/test//companies/任意公司ID

后端代码。这个就没什么好讲的了。

@Transactional
@DeleteMapping("/companies/{companyId}")
public ResponseDto deleteCompany(@PathVariable("companyId") int companyId) {
    return service.deleteCompany(companyId);
}

3. 返回数据的格式跟风格

3.1 请求处理正常

上述controller中ResponseDto的代码是这样的。

@Data
@Component
public class ResponseDto {
	// 状态码
	private String code;
	
	// 状态信息
	private String msg;
	
	// 响应数据
	private Object data;
}

这是Restful返回的比较标准的格式。

3.2 请求处理异常

发生异常的话,有可能是数据校验出错,那样压根不进入controller方法体。也有可能在其他地方出错,比如进入方法体后的片段中出错,我们应该统一在ExceptionHander中处理。

像下面这样,我们返回ResponseEntity,并与HttpStatus关联,当然可以是400,404,500。ResponseDto中你可以放同样的code,也可以是你自己自定义的错误码。这里我们为了方便就设置成同样的。

比如请求中的邮件地址非法,就会进入ValidationException的分支,出现上述图片的错误。

@RestControllerAdvice
public class GlobalExceptionController {
    Logger logger = LogManager.getLogger(GlobalExceptionController.class);
    
    @Autowired
    ResponseDto res;
    
    private ResponseEntity<ResponseDto> buildResponse(Exception e, HttpStatus status) {
        logger.error(e.getMessage());
        res.setCode(String.valueOf(status.value()));
        res.setMsg(e.getMessage());
        res.setData("");
        
        return new ResponseEntity<ResponseDto>(res, status);
    }
    
    // 数据校验错误
    @ExceptionHandler(ValidationException.class)
    public ResponseEntity<ResponseDto> handleError(ValidationException e) {
        return buildResponse(e, HttpStatus.BAD_REQUEST);
    }
    
    // 文件IO错误
    @ExceptionHandler(FileException.class)
    public Object handleError(FileException e) {
        return buildResponse(e, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    // 业务逻辑错误
    @ExceptionHandler(SiLEDBusinessException.class)
    public Object handleError(SiLEDBusinessException e) {
        return buildResponse(e, HttpStatus.BAD_REQUEST);
    }
    
    // 其他错误
    @ExceptionHandler(Exception.class)
    public Object handleError(Exception e) {
        return buildResponse(e, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

4. Restful的其他事项

4.1正则表达式

如果你想精准的匹配URL,可以使用正则表达式。


@RequestMapping(value = "/{name:([a-z][0-9a-z-]{3,31}}/mytest",method = {RequestMethod.GET})
public void test(@PathVariable String name){
 
}

4.2 put跟patch的区别

上面没有讲到一种patch请求,该请求也是更新请求,但是是局部更新。什么是局部更新?加入有个user类,你更新他的所有属性,就用put。只更新username可以用put,但是显得很大题小作,因为put是全面替换。这时可以使用patch,仅更新username。

4.3 Options请求跟web.xml配置

如果涉及到跨域,在请求Restful之前,浏览器会先发送一个Options请求给后台,询问该接口/端点支持哪些方法。所以需要配置该许可。

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <!-- OPTIONS请求许可 -->
        <param-name>dispatchOptionsRequest</param-name>
        <param-value>true</param-value>
        
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

5. API接口文档

前文提到了使用Restful有助于你的文档维护。这里推荐一款免费软件叫做Stoplight Studio

Stoplight Studio

  • 能够实现API文档的编辑跟读取
  • 有Web 版跟Desktop 版,有一定的功能差异
  • Desktop 版分别对应/ Windows / Linux
  • 总结

    Restful是一种设计风格,它能够让你用一个URI实现增删改查。目前是前后台交互的主流方式,它让你的代码,甚至api都变得优雅。