package com.example.demo.api;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface API {
boolean request() default true;
boolean response() default true;
}
以注解的形式对接口进行配置,可配置在Controller的类或方法上。request属性为true,表示请求体需要分公有域和私有域,私有域数据封装在data节点内;为false,表示不区分公有域和私有域。response同理,如果属性为true,会将返回的业务数据封装在data节点内。
package com.example.demo.api;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Arrays;
public enum State {
SUCCESS(0, "success"),
VALID_FAIL(100, "valid fail"),
PASSWORD_ERROR(101, "password error"),
UNKNOWN_ERROR(999, "unknow error");
@JsonValue
private int code;
private String message;
State(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return String.format("[%03d] %s", code, message);
}
public void tryThrow() {
throw new StatefulException(this);
}
public void tryThrow(String message) {
throw new StatefulException(this, message);
}
public void tryThrow(String messageTemplate, Object... params) {
throw new StatefulException(this, messageTemplate, params);
}
public void tryThrow(Throwable cause) {
throw new StatefulException(this, cause);
}
public void isTrue(boolean expression) {
isFalse(!expression);
}
public void isTrue(boolean expression, String message) {
isFalse(!expression, message);
}
public void isTrue(boolean expression, String messageTemplate, Object... params) {
isFalse(!expression, messageTemplate, params);
}
public void isFalse(boolean expression) {
if (expression) {
throw new StatefulException(this);
}
}
public void isFalse(boolean expression, String message) {
if (expression) {
throw new StatefulException(this, message);
}
}
public void isFalse(boolean expression, String messageTemplate, Object... params) {
if (expression) {
throw new StatefulException(this, messageTemplate, params);
}
}
public <T> T notNull(T obj) {
if (obj == null) {
throw new StatefulException(this);
}
return obj;
}
public <T> T notNull(T obj, String message) {
if (obj == null) {
throw new StatefulException(this, message);
}
return obj;
}
public <T> T notNull(T obj, String messageTemplate, Object... params) {
if (obj == null) {
throw new StatefulException(this, messageTemplate, params);
}
return obj;
}
public <T extends CharSequence> T notBlank(CharSequence str) {
if (StrUtil.isBlank(str)) {
throw new StatefulException(this);
}
return (T) str;
}
public <T extends CharSequence> T notBlank(CharSequence str, String message) {
if (StrUtil.isBlank(str)) {
throw new StatefulException(this, message);
}
return (T) str;
}
public <T extends CharSequence> T notBlank(CharSequence str, String messageTemplate, Object... params) {
if (StrUtil.isBlank(str)) {
throw new StatefulException(this, messageTemplate, params);
}
return (T) str;
}
public <T> List<T> notEmpty(List<T> list) {
if (list == null || list.isEmpty()) {
tryThrow();
}
return list;
}
public <T> List<T> notEmpty(List<T> list, String errorMessage) {
if (list == null || list.isEmpty()) {
tryThrow(errorMessage);
}
return list;
}
public <T> List<T> notEmpty(List<T> list, String messageTemplate, Object... params) {
if (list == null || list.isEmpty()) {
tryThrow(messageTemplate, params);
}
return list;
}
@JsonCreator
public static State valueOf(int code) {
return Arrays.stream(values()).filter(state -> state.getCode() == code).findAny().orElse(null);
}
}
定义了错误码、错误信息,以及一些断言。使用断言可以抛出包含错误码和错误信息的异常
package com.example.demo.api;
import cn.hutool.core.util.StrUtil;
public class StatefulException extends RuntimeException {
private State state;
public StatefulException(State state) {
this.state = state;
}
public StatefulException(State state, String message) {
super(message);
this.state = state;
}
public StatefulException(State state, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
this.state = state;
}
public StatefulException(State state, Throwable cause) {
super(cause);
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
@Override
public String toString() {
return StrUtil.isBlank(getMessage()) ? state.toString() : state + ": " + getMessage();
}
}
package com.example.demo.api;
import java.io.Serializable;
public class PublicDomain<T> implements Serializable {
private T data;
public PublicDomain() {
}
public PublicDomain(T data) {
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
将请求和响应分为公有域部分和私有域部分。响应中公有域包含响应码、响应信息和由data封装的私有域。
package com.example.demo.api;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder({"resCode", "resMessage", "errorMessage", "data"})
public class ResultVo<T> extends PublicDomain<T> {
// 响应状态码
private int resCode;
// 响应状态信息
private String resMessage;
// 错误详情
@JsonInclude(JsonInclude.Include.NON_NULL)
private String errorMessage;
public ResultVo() {
this(State.SUCCESS);
}
public ResultVo(T data) {
super(data);
this.resCode = State.SUCCESS.getCode();
this.resMessage = State.SUCCESS.getMessage();
}
public ResultVo(State state) {
this.resCode = state.getCode();
this.resMessage = state.getMessage();
}
public ResultVo(StatefulException statefulException) {
State state = statefulException.getState();
this.resCode = state.getCode();
this.resMessage = state.getMessage();
this.errorMessage = statefulException.getMessage();
}
public ResultVo(State state, Throwable ex) {
this.resCode = state.getCode();
this.resMessage = state.getMessage();
this.errorMessage = ex.getMessage();
}
public int getResCode() {
return resCode;
}
public void setResCode(int resCode) {
this.resCode = resCode;
}
public String getResMessage() {
return resMessage;
}
public void setResMessage(String resMessage) {
this.resMessage = resMessage;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
package com.example.demo.api;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
@RestControllerAdvice(basePackages = "com.example.demo")
public class RequesstApiAdvice extends RequestBodyAdviceAdapter {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
API apiAnn = methodParameter.hasMethodAnnotation(API.class) ?
methodParameter.getMethodAnnotation(API.class) : methodParameter.getDeclaringClass().getAnnotation(API.class);
return apiAnn != null && apiAnn.request() && !PublicDomain.class.equals(methodParameter.getParameterType());
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
JsonNode jsonNode = objectMapper.readTree(inputMessage.getBody());
return new HttpInputMessage() {
@Override
public InputStream getBody() {
JsonNode dataJsonNode = State.VALID_FAIL.notNull(jsonNode.get("data"), "请求体未包含私有域节点data");
return new ByteArrayInputStream(dataJsonNode.toString().getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
};
}
}
响应体的处理可以基于ResponseBodyAdvice,也可以基于HandlerMethodReturnValueHandler,两种方案可以任选其一
package com.example.demo.api;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice(basePackages = "com.example.demo")
public class ResponseApiAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
API apiAnn = returnType.hasMethodAnnotation(API.class) ?
returnType.getMethodAnnotation(API.class) : returnType.getDeclaringClass().getAnnotation(API.class);
return apiAnn != null && apiAnn.response();
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return body instanceof ResultVo ? body : new ResultVo<>(body);
}
}
package com.example.demo.api;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
import java.util.ArrayList;
import java.util.List;
@Component
public class ApiHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
private HandlerMethodReturnValueHandler handler;
public ApiHandlerMethodReturnValueHandler(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
List<HandlerMethodReturnValueHandler> originHandlers = requestMappingHandlerAdapter.getReturnValueHandlers();
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<>(originHandlers.size());
for (HandlerMethodReturnValueHandler originHandler : originHandlers) {
if (originHandler instanceof RequestResponseBodyMethodProcessor) {
newHandlers.add(this);
handler = originHandler;
} else {
newHandlers.add(originHandler);
}
}
requestMappingHandlerAdapter.setReturnValueHandlers(newHandlers);
}
@Override
public boolean supportsReturnType(MethodParameter returnType) {
API apiAnn = returnType.hasMethodAnnotation(API.class) ?
returnType.getMethodAnnotation(API.class) : returnType.getDeclaringClass().getAnnotation(API.class);
return handler.supportsReturnType(returnType) && apiAnn != null && apiAnn.response();
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
Object response = returnValue instanceof ResultVo ? returnValue : new ResultVo<>(returnValue);
handler.handleReturnValue(response, returnType, mavContainer, webRequest);
}
}
HandlerMethodReturnValueHandler 的作用是对处理器的处理结果再进行一次二次加工
package com.example.demo.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionResolver {
private final static Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionResolver.class);
@ExceptionHandler(Exception.class)
public ResultVo exceptionHandle(Exception ex) {
LOGGER.error("error", ex);
return new ResultVo(State.UNKNOWN_ERROR, ex);
}
@ExceptionHandler(RuntimeException.class)
public ResultVo exceptionHandle(RuntimeException ex) {
LOGGER.error("valid fail", ex);
return new ResultVo(State.VALID_FAIL, ex);
}
@ExceptionHandler(StatefulException.class)
public ResultVo exceptionHandle(StatefulException ex) {
LOGGER.error(ex.getState().toString(), ex);
return new ResultVo(ex);
}
}
package com.example.demo.user.entity;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class User {
private String account;
private String name;
private String password;
}
package com.example.demo.user.controller;
import com.example.demo.api.API;
import com.example.demo.api.State;
import com.example.demo.user.entity.User;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@API
@PostMapping("/login/passport")
public User test(@RequestBody User user) {
State.VALID_FAIL.notBlank(user.getAccount(), "账号为空");
State.VALID_FAIL.notBlank(user.getPassword(), "密码为空");
State.PASSWORD_ERROR.isTrue(user.getPassword().equals("123456"), "密码错误");
return user;
}
}
正确请求
{
"data": {
"account": "demo",
"password": "123456"
}
}
响应
{
"resCode": 0,
"resMessage": "success",
"data": {
"account": "demo",
"name": null,
"password": "123456"
}
}
密码错误请求
{
"data": {
"account": "demo",
"password": "123"
}
}
响应
{
"resCode": 101,
"resMessage": "password error",
"errorMessage": "密码错误",
"data": null
}
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h
我正在尝试使用Ruby2.0.0和Rails4.0.0提供的API从imgur中提取图像。我已尝试按照Ruby2.0.0文档中列出的各种方式构建http请求,但均无济于事。代码如下:require'net/http'require'net/https'defimgurheaders={"Authorization"=>"Client-ID"+my_client_id}path="/3/gallery/image/#{img_id}.json"uri=URI("https://api.imgur.com"+path)request,data=Net::HTTP::Get.new(path
Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我的公司有一个巨大的数据库,该数据库接收来自多个来源的(许多)事件,用于监控和报告目的。到目前为止,数据中的每个新仪表板或图形都是一个新的Rails应用程序,在巨大的数据库中有额外的表,并且可以完全访问数据库内容。最近,有一个想法让外部(不是我们公司,而是姊妹公司)客户访问我们的数据,并且决定我们应该公开一个只读的RESTfulAPI来查询我们的数据。我的观点是-我们是否也应该为我们的自己
我读了"BingSearchAPI-QuickStart"但我不知道如何在Ruby中发出这个http请求(Weary)如何在Ruby中翻译“Stream_context_create()”?这是什么意思?"BingSearchAPI-QuickStart"我想使用RubySDK,但我发现那些已被弃用前(Rbing)https://github.com/mikedemers/rbing您知道Bing搜索API的最新包装器(仅限Web的结果)吗? 最佳答案 好吧,经过一个小时的挫折,我想出了一个办法来做到这一点。这段代码很糟糕,因为它是
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:AmazonAPIlibraryforPython?我正在寻找一个AmazonAPI,它可以让我:按书名或作者查找书籍显示书籍封面获取有关每本书的信息(价格、评级、评论数、格式、页数等)Python或Ruby库都可以(我只想要最容易使用的库)。有什么建议么?我知道在SO上还有其他一些关于此的帖子,但这些API似乎很快就过时了。[几个月前我尝试了几个建议的Ruby库,但无法让它们中的任何一个工作。]