SpringBoot总结(十五)——接口架构风格(RESTful)

【第一部分】历史文章:
SpringBoot总结(一)——第一个SpringBoot项目
SpringBoot总结(二)——Spring Boot的自动配置
SpringBoot总结(三)——SpringBoot的配置文件
SpringBoot总结(四)——@Value和@ConfigurationProperties的区别
SpringBoot总结(五)——@PropertySource注解与@ImportResource注解
SpringBoot总结(六)——SpringBoot配置文件占位符
SpringBoot总结(七)——Profile的使用
SpringBoot总结(八)——配置文件的加载位置
SpringBoot总结(九)——@Conditional注解与自动配置报告
SpringBoot总结(十)——SpringBoot+Mybatis实现数据库的CRUD(从建立到实现【超详细附代码】)
SpringBoot总结(十一)——SpringBoot的静态资源映射规则
SpringBoot总结(十二)——登陆界面的实现
SpringBoot总结(十三)——修改嵌入式Servlet容器配置
SpringBoot总结(十四)——SpringBoot整合JDBCTemplate及Druid链接池java


接口架构风格(RESTful)



前言

本篇文章主要介绍了RESTful的一些知识点,以及基于RESTful风格的CRUD的例子,和基于SpringBoot为手机APP、PC、构建统一风格的Restful API。git


1、什么是REST

REST是软件架构的规范体系结构,它将资源的状态以适合客户端的形式从服务器端发送到客户端(或者相反的方向)。在REST中,经过URL进行资源定位,用HTTP动做(GET、POST、DELETE、PUT等)描述操做完成功能。github

遵循RESTful风格,可使得开发的接口通用,以便调用者理解接口的做用。所以,基于REST构建的API就是RESTful(REST风格)API。
各大机构提供的API基本都是RESTful风格的。这样能够统一规范,减小沟通,学习和开发的成本。web

2、HTTP动做与CRUD动做映射

RESTful风格使用同一个URL,经过约定不一样的HTTP方法来实施不一样的业务。
下面是普通网页的CRUD和RESTful风格的CRUD的区别:spring

动做 普通CRUD的URL 普通CRUD的HTTP方法 ReSTful的URL RESTful的CRUD的HTTP方法
查询 Article/id=1 GET Article/{id} GET
添加 Article?title=xxx&body=xxx GET/POST Article POST
修改 Article/update?id=xxx GET Article/{id} PUT或者PATCH
删除 Article/delete?id=xxx GET Article/{id} DELETE

3、基于RESTful风格的CRUD例子

3.一、主要代码

下面是基于RESTful风格的CRUD的例子,而且定义了统一的数据返回格式。
操做数据库的方式采用了SpringBootSpringDataJPA整合的方式;具体这里将再也不详细介绍,下面附上一些主要的代码。数据库

ArticleController.javaapi

package com.example.controller;
import com.example.entity.Article;
import com.example.repository.ArticleRepository;
import com.example.result.ExceptionMsg;
import com.example.result.Response;
import com.example.result.ResponseData;
import io.github.yedaxia.apidocs.ApiDoc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/** * 文章接口类 */
@RequestMapping("/article")
@RestController
public class ArticleController { 
 
  

    protected Response result(ExceptionMsg msg){ 
 
  
        return new Response(msg);
    }
    protected Response result(){ 
 
  
        return new Response();
    }

    @Autowired
    private ArticleRepository articleRepository;


    /** * 查询全部文章 * @return */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ResponseData getArticleList() { 
 
  
        List<Article> list = new ArrayList<Article>(articleRepository.findAll());
        return new ResponseData(ExceptionMsg.SUCCESS,list);

    }

    /** * 增长文章信息 * @param article 文章对象 * @return */
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public ResponseData add(@RequestBody Article article) { 
 
  
        articleRepository.save(article);
        return new ResponseData(ExceptionMsg.SUCCESS,article);
    }


    /** * 删除文章信息 * @param id 文章id * @return Response */
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public Response delete(@PathVariable("id") int id) { 
 
  
        articleRepository.deleteById(id);
        return result(ExceptionMsg.SUCCESS);

    }


    /** * 修改文章信息 * @param model 文章对象 * @return ResponseData */
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public ResponseData update(@RequestBody Article model) { 
 
  
        articleRepository.save(model);
        return new ResponseData(ExceptionMsg.SUCCESS,model);
    }

    /** * 根据文章id 查询文章信息 * @param id * @return ResponseData * @throws IOException */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ResponseData findArticle(@PathVariable("id") int id) throws IOException { 
 
  
        Article article = articleRepository.findById(id);
        if (article != null) { 
 
  
            return new ResponseData(ExceptionMsg.SUCCESS,article);
        }
        return new ResponseData(ExceptionMsg.FAILED,article);
    }

}

3.二、测试数据

启动项目,进行以下的测试。服务器

4、为手机APP、PC、H5网页提供统一风格的API

4.一、实现响应的枚举类

package com.example.result;
//实现响应的枚举类
public enum ExceptionMsg { 
 
  
	SUCCESS("200", "操做成功"),
	FAILED("999999","操做失败"),
    ParamError("000001", "参数错误!"),
    FileEmpty("000400","上传文件为空"),
    LimitPictureSize("000401","图片大小必须小于2M"),
    LimitPictureType("000402","图片格式必须为'jpg'、'png'、'jpge'、'gif'、'bmp'")
    ;
   private ExceptionMsg(String code, String msg) { 
 
  
        this.code = code;
        this.msg = msg;
    }
    private String code;
    private String msg;
    
	public String getCode() { 
 
  
		return code;
	}
	public String getMsg() { 
 
  
		return msg;
	}

    
}

4.二、实现返回的对象实体

package com.example.result;

/** * @author 2017810402084 * 实现返回对象实体 */
public class Response { 
 
  
	/** 返回信息码*/
	private String rspCode="000000";
	/** 返回信息内容*/
	private String rspMsg="操做成功";

	public Response() { 
 
  
	}
	
	public Response(ExceptionMsg msg){ 
 
  
		this.rspCode=msg.getCode();
		this.rspMsg=msg.getMsg();
	}
	
	public Response(String rspCode) { 
 
  
		this.rspCode = rspCode;
		this.rspMsg = "";
	}

	public Response(String rspCode, String rspMsg) { 
 
  
		this.rspCode = rspCode;
		this.rspMsg = rspMsg;
	}
	public String getRspCode() { 
 
  
		return rspCode;
	}
	public void setRspCode(String rspCode) { 
 
  
		this.rspCode = rspCode;
	}
	public String getRspMsg() { 
 
  
		return rspMsg;
	}
	public void setRspMsg(String rspMsg) { 
 
  
		this.rspMsg = rspMsg;
	}

	@Override
	public String toString() { 
 
  
		return "Response{" +
				"rspCode='" + rspCode + '\'' +
				", rspMsg='" + rspMsg + '\'' +
				'}';
	}
}

4.三、封装返回结果

package com.example.result;

import com.example.exception.BusinessException;

/** * @author 2017810402084 * 返回结果数据格式封装 */
public class ResponseData extends Response { 
 
  
    private Object data;


    public ResponseData() { 
 
  

    }

    public ResponseData(Object data) { 
 
  
        this.data = data;
    }

    public ResponseData(ExceptionMsg msg) { 
 
  
        super(msg);
    }

    public ResponseData(String rspCode, String rspMsg) { 
 
  
        super(rspCode, rspMsg);
    }

    public ResponseData(String rspCode, String rspMsg, Object data) { 
 
  
        super(rspCode, rspMsg);
        this.data = data;
    }

    public ResponseData(ExceptionMsg msg, Object data) { 
 
  
        super(msg);
        this.data = data;
    }

    public Object getData() { 
 
  
        return data;
    }

    public void setData(Object data) { 
 
  
        this.data = data;
    }


    /** * 自定义异常的返回结果 * @param de * @return */
    public static ResponseData defineBusinessException(BusinessException de) { 
 
  
        ResponseData responseData = new ResponseData();
        responseData.setRspCode(de.getCode());
        responseData.setRspMsg(de.getMsg());
        responseData.setData(null);
        return responseData;
    }
}

4.四、统一处理异常

package com.example.exception;
import com.example.result.ResponseData;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/** * @author 2017810402084 * 定义全局异常处理类:来处理各类的异常,包括本身定义的异常和内部的异常 */
@RestControllerAdvice
public class GlobalExceptionHandler { 
 
  

    /** * (1)处理自定义异常BusinessException */

    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public ResponseData bizBusinessException(BusinessException e) { 
 
  
        return  ResponseData.defineBusinessException(e);
    }


    /** * (2)处理其余的异常 */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseData exceptionHandler(Exception e) { 
 
  
        return new ResponseData(e);
    }
}

4.五、自定义异常

package com.example.exception;
/** * @author 2017810402084 * 建立自定义异常处理类:BusinessException.java */

public class BusinessException extends RuntimeException{ 
 
  

    private String code;
    private String msg;

    public BusinessException(String code, String msg) { 
 
  
       this.msg = msg;
        this.code = code;
    }

    public String getCode() { 
 
  
        return code;
    }

    public void setCode(String code) { 
 
  
        this.code = code;
    }

    public String getMsg() { 
 
  
        return msg;
    }

    public void setMsg(String msg) { 
 
  
        this.msg = msg;
    }
}

4.六、进行测试

package com.example.controller;
import com.example.exception.BusinessException;
import com.example.exception.UserNameNotMatchPasswordException;
import com.example.result.ResponseData;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
/** * * 统一异常测试类 */

@RestController
@RequestMapping("/test")

public class TestController { 
 
  

    /** * 自定义异常测试 * @return */
    @RequestMapping("/BusinessException")
    public ResponseData DeException() { 
 
  
        throw new BusinessException("40000000", "出错了!");
    }


    /** * 处理其余的异常 * @return */
    @RequestMapping("/getException")
    public ResponseData Exception() { 
 
  

        ResponseData responseData = new ResponseData();
        responseData.setRspCode("400");
        responseData.setRspMsg("出错");

        return responseData;
    }
}

在这里插入图片描述
在这里插入图片描述


总结

以上就是本篇所介绍的内容,以一个简单的例子,来演示了基于RESTful风格的CRUD操做,以及构造统一风格的RESTful API。但愿经过这个例子能给予你们帮助。😊

关于本项目代码获取方式:关注+私信并回复:【RESTful项目】便可获取哦
在这里插入图片描述架构