restful 开发规范
1.URL命名规则:
1.1. URL命名原则
1、 URL请求采用小写字母,数字,部分特殊符号(非制表符)组成。
2、 URL请求中不采用大小写混合的驼峰命名方式,尽量采用全小写单词,如果需要连接多个单词,则采用连接符“_”连接单词
1.2. URL分级
第一级Pattern为模块,比如组织管理/orgz, 网格化:/grid
第二级Pattern为资源分类或者功能请求,优先采用资源分类
1.3. CRUD请求定义规范(RESTful)
如果为资源分类,则按照RESTful的方式定义第三级Pattern,
RESTful规范中,资源必须采用资源的名词复数定义。
/orgz/members | GET | 获取成员列表 |
/orgz/members/120 | GET | 获取单个成员 |
/orgz/members | POST | 创建成员 |
/orgz/members/120 | PUT | 修改成员 |
/orgz/members | PUT | 批量修改 |
/orgz/members/120 | PATCH | 修改成员的部分属性 |
/orgz/members/120 | DELETE | 删除成员 |
1.4. 复杂查询请求定义规范(RESTful)
/module/tickets?state=open | GET | 过滤 |
/module/tickets?sort=-priority | GET | 排序 |
/module/tickets?sort=-priority,created_at | GET | 排序 |
/module/tickets?sort=-updated_at | GET | 排序 |
/module/tickets?state=closed&sort=-updated_at | GET | 过滤+排序 |
/module/tickets?q=return&state=open&sort=-priority,created_at | GET | 搜索+过滤+排序 |
/module/tickets/recently_closed | GET | 一般数据请求 |
/module/tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at | GET | 指定返回列 |
/cars?offset=10&limit=5 | GET | 分页 |
2.CRUD对应操作的处理
public ResponseEntity<LearningPlayDto> createLearningPlay(@Valid @RequestBody LearningPlayDto toCreate) throws URISyntaxException {
toCreate.setCreator(userId);
toCreate = learningPlayDtoMapper.map(learningPlayService.createLearningPlay(toCreate));
return ResponseEntity.created(new URI("/learningPlays/" + toCreate.getId()))
.headers(HeaderUtil.createEntityCreationAlert(Constants.LEARNING_PLAY_ENTITY_NAME, toCreate.getId()))
.body(toCreate);
}
4.1POST方法应该返回你增加的对象,包括id
4.2HeadUtil
public final class HeaderUtil {private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class);
private static final String APPLICATION_NAME = "****";
private HeaderUtil() {
}
public static HttpHeaders createAlert(String message, String param) {
HttpHeaders headers = new HttpHeaders();
headers.add("X-CAPGENIE-ALERT", message);
headers.add("X-CAPGENIE-PARAMS", param);
return headers;
}
public static HttpHeaders createEntityCreationAlert(String entityName, String param) {
return createAlert(APPLICATION_NAME + "." + entityName + ".created", param);
}
public static HttpHeaders createEntityUpdateAlert(String entityName, String param) {
return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param);
}
public static HttpHeaders createEntityDeletionAlert(String entityName, String param) {
return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param);
}
public static HttpHeaders createFailureAlert(String entityName, String errorKey, String defaultMessage) {
log.error("Entity processing failed, {}", defaultMessage);
HttpHeaders headers = new HttpHeaders();
headers.add("X-CAPGENIE-ERROR", "exception." + errorKey);
headers.add("X-CAPGENIE-PARAMS", entityName);
return headers;
}
4.3IdGenerator(插入数据库之前先生成id的方法)
public interface IdGenerator {
long nextId();}
4.4(调用nextId方法生成id)
import com.capgemini.genie.learningplay.service.IdGenerator;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
public class SnowflakeIdGenerator implements IdGenerator {
private Logger logger = LoggerFactory.getLogger(SnowflakeIdGenerator.class);
private long microserviceId;
private long machineId;
private long sequence;
public SnowflakeIdGenerator(long microserviceId, long machineId, long sequence){
// sanity check for microserviceId
if (microserviceId > maxMicroserviceId || microserviceId < 0) {
throw new IllegalArgumentException(String.format("microservice Id can't be greater than %d or less than 0", maxMicroserviceId));
}
if (machineId > maxMachineId || machineId < 0) {
throw new IllegalArgumentException(String.format("machine Id can't be greater than %d or less than 0", maxMachineId));
}
logger.warn("worker starting. timestamp left shift %d, machine id bits %d, microservice id bits %d, sequence bits %d, microservice id %d %n",
timestampLeftShift, machineIdBits, microserviceIdBits, sequenceBits, microserviceId);
this.microserviceId = microserviceId;
this.machineId = machineId;
this.sequence = sequence;
}
private long twepoch = 1522207715092L;
private long microserviceIdBits = 8L;
private long machineIdBits = 6L;
private long maxMicroserviceId = -1L ^ (-1L << microserviceIdBits);
private long maxMachineId = -1L ^ (-1L << machineIdBits);
private long sequenceBits = 8L;
private long microserviceIdShift = sequenceBits;
private long machineIdShift = sequenceBits + microserviceIdBits;
private long timestampLeftShift = sequenceBits + microserviceIdBits + machineIdBits;
private long sequenceMask = -1L ^ (-1L << sequenceBits);
private long lastTimestamp = -1L;
public long getMicroserviceId(){
return microserviceId;
}
public long getMachineId(){
return machineId;
}
public long getTimestamp(){
return System.currentTimeMillis();
}
@Override
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) |
(machineId << machineIdShift) |
(microserviceId << microserviceIdShift) |
sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
private long timeGen(){
return System.currentTimeMillis();
}
}