From 4997a4f5118767578bbd97756ea0a39d1859000b Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Fri, 3 Apr 2020 13:18:08 +0800 Subject: [PATCH 01/29] v3.1.5 --- .../restful/DefaultRestfulErrorRender.java | 109 ----- .../jboot/components/restful/HttpStatus.java | 405 ------------------ .../restful/JbootRestfulManager.java | 238 ---------- .../components/restful/ResponseEntity.java | 67 --- .../components/restful/RestfulAction.java | 14 - .../components/restful/RestfulCallback.java | 21 - .../restful/RestfulErrorRender.java | 35 -- .../components/restful/RestfulHandler.java | 247 ----------- .../components/restful/RestfulInvocation.java | 57 --- .../components/restful/RestfulUtils.java | 201 --------- .../restful/annotation/DeleteMapping.java | 19 - .../restful/annotation/DownloadResponse.java | 12 - .../restful/annotation/GetMapping.java | 16 - .../restful/annotation/PathVariable.java | 27 -- .../restful/annotation/PostMapping.java | 16 - .../restful/annotation/PutMapping.java | 19 - .../restful/annotation/RequestBody.java | 20 - .../restful/annotation/RequestHeader.java | 29 -- .../restful/annotation/RequestParam.java | 29 -- .../restful/annotation/ResponseHeader.java | 17 - .../restful/annotation/ResponseHeaders.java | 12 - .../restful/annotation/RestController.java | 12 - .../ParameterNullErrorException.java | 24 -- .../ParameterParseErrorException.java | 39 -- .../RequestMethodErrorException.java | 39 -- .../java/io/jboot/core/JbootCoreConfig.java | 34 +- .../jboot/test/restful/RestfulController.java | 117 ----- .../io/jboot/test/restful/RestfulService.java | 5 - .../test/restful/RestfulServiceImpl.java | 12 - 29 files changed, 1 insertion(+), 1891 deletions(-) delete mode 100644 src/main/java/io/jboot/components/restful/DefaultRestfulErrorRender.java delete mode 100644 src/main/java/io/jboot/components/restful/HttpStatus.java delete mode 100644 src/main/java/io/jboot/components/restful/JbootRestfulManager.java delete mode 100644 src/main/java/io/jboot/components/restful/ResponseEntity.java delete mode 100644 src/main/java/io/jboot/components/restful/RestfulAction.java delete mode 100644 src/main/java/io/jboot/components/restful/RestfulCallback.java delete mode 100644 src/main/java/io/jboot/components/restful/RestfulErrorRender.java delete mode 100644 src/main/java/io/jboot/components/restful/RestfulHandler.java delete mode 100644 src/main/java/io/jboot/components/restful/RestfulInvocation.java delete mode 100644 src/main/java/io/jboot/components/restful/RestfulUtils.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/DownloadResponse.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/GetMapping.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/PathVariable.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/PostMapping.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/PutMapping.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/RequestBody.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/RequestHeader.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/RequestParam.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java delete mode 100644 src/main/java/io/jboot/components/restful/annotation/RestController.java delete mode 100644 src/main/java/io/jboot/components/restful/exception/ParameterNullErrorException.java delete mode 100644 src/main/java/io/jboot/components/restful/exception/ParameterParseErrorException.java delete mode 100644 src/main/java/io/jboot/components/restful/exception/RequestMethodErrorException.java delete mode 100644 src/test/java/io/jboot/test/restful/RestfulController.java delete mode 100644 src/test/java/io/jboot/test/restful/RestfulService.java delete mode 100644 src/test/java/io/jboot/test/restful/RestfulServiceImpl.java diff --git a/src/main/java/io/jboot/components/restful/DefaultRestfulErrorRender.java b/src/main/java/io/jboot/components/restful/DefaultRestfulErrorRender.java deleted file mode 100644 index 1ba7e278..00000000 --- a/src/main/java/io/jboot/components/restful/DefaultRestfulErrorRender.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.jboot.components.restful; - -import com.jfinal.core.ActionException; -import com.jfinal.log.Log; -import com.jfinal.render.Render; -import com.jfinal.render.RenderException; -import com.jfinal.render.RenderManager; -import io.jboot.components.restful.exception.ParameterNullErrorException; -import io.jboot.components.restful.exception.ParameterParseErrorException; -import io.jboot.components.restful.exception.RequestMethodErrorException; -import io.jboot.web.handler.JbootActionHandler; - -import java.io.Serializable; - -/** - * 默认的restful错误响应处理器 - */ -public class DefaultRestfulErrorRender extends RestfulErrorRender { - - private static final Log log = Log.getLog(JbootActionHandler.class); - - public static class Error implements Serializable { - private String errorClass; - private int code; - private String message; - - public Error(String errorClass, int code, String message) { - this.errorClass = errorClass; - this.code = code; - this.message = message; - } - - public String getErrorClass() { - return errorClass; - } - - public Error setErrorClass(String errorClass) { - this.errorClass = errorClass; - return this; - } - - public int getCode() { - return code; - } - - public Error setCode(int code) { - this.code = code; - return this; - } - - public String getMessage() { - return message; - } - - public Error setMessage(String message) { - this.message = message; - return this; - } - } - - public void render() { - log.error("The restful handler intercepted the error", super.getError()); - Error error = null; - if(super.getError() instanceof ParameterNullErrorException - || super.getError() instanceof ParameterParseErrorException){ - //400 - error = new Error(super.getError().getClass().getName(), - HttpStatus.BAD_REQUEST.value(), super.getError().getMessage()); - } else if(super.getError() instanceof RequestMethodErrorException){ - error = new Error(super.getError().getClass().getName(), - HttpStatus.METHOD_NOT_ALLOWED.value(), super.getError().getMessage()); - } else if(super.getError() instanceof ActionException){ - //解析错误代码 - ActionException actionException = (ActionException)super.getError(); - int errorCode = actionException.getErrorCode(); - String msg = ""; - if (errorCode == 404) { - msg = HttpStatus.NOT_FOUND.getReasonPhrase(); - } else if (errorCode == 400) { - msg = HttpStatus.BAD_REQUEST.getReasonPhrase(); - } else if (errorCode == 401) { - msg = HttpStatus.UNAUTHORIZED.getReasonPhrase(); - } else if (errorCode == 403) { - msg = HttpStatus.FORBIDDEN.getReasonPhrase(); - } else if(errorCode == 405){ - msg = HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase(); - } else { - msg = super.getError().getMessage(); - } - error = new Error(super.getError().getClass().getName(), - errorCode, msg); - } else if(super.getError() instanceof RenderException){ - //500 - error = new Error(super.getError().getClass().getName(), - HttpStatus.INTERNAL_SERVER_ERROR.value(), super.getError().getMessage()); - } else { - //500 - error = new Error(super.getError().getClass().getName(), - HttpStatus.INTERNAL_SERVER_ERROR.value(), super.getError().getMessage()); - } - Render jsonRender = RenderManager.me().getRenderFactory().getJsonRender(error); - jsonRender.setContext(super.request, super.response, super.getAction() == null? "" : super.getAction().getViewPath()); - super.response.setStatus(error.getCode()); - jsonRender.render(); - } - - - -} diff --git a/src/main/java/io/jboot/components/restful/HttpStatus.java b/src/main/java/io/jboot/components/restful/HttpStatus.java deleted file mode 100644 index aa54f020..00000000 --- a/src/main/java/io/jboot/components/restful/HttpStatus.java +++ /dev/null @@ -1,405 +0,0 @@ -package io.jboot.components.restful; - -public enum HttpStatus { - - /** - * {@code 100 Continue}. - * @see HTTP/1.1: Semantics and Content, section 6.2.1 - */ - CONTINUE(100, "Continue"), - /** - * {@code 101 Switching Protocols}. - * @see HTTP/1.1: Semantics and Content, section 6.2.2 - */ - SWITCHING_PROTOCOLS(101, "Switching Protocols"), - /** - * {@code 102 Processing}. - * @see WebDAV - */ - PROCESSING(102, "Processing"), - /** - * {@code 103 Checkpoint}. - * @see A proposal for supporting - * resumable POST/PUT HTTP requests in HTTP/1.0 - */ - CHECKPOINT(103, "Checkpoint"), - - // 2xx Success - - /** - * {@code 200 OK}. - * @see HTTP/1.1: Semantics and Content, section 6.3.1 - */ - OK(200, "OK"), - /** - * {@code 201 Created}. - * @see HTTP/1.1: Semantics and Content, section 6.3.2 - */ - CREATED(201, "Created"), - /** - * {@code 202 Accepted}. - * @see HTTP/1.1: Semantics and Content, section 6.3.3 - */ - ACCEPTED(202, "Accepted"), - /** - * {@code 203 Non-Authoritative Information}. - * @see HTTP/1.1: Semantics and Content, section 6.3.4 - */ - NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"), - /** - * {@code 204 No Content}. - * @see HTTP/1.1: Semantics and Content, section 6.3.5 - */ - NO_CONTENT(204, "No Content"), - /** - * {@code 205 Reset Content}. - * @see HTTP/1.1: Semantics and Content, section 6.3.6 - */ - RESET_CONTENT(205, "Reset Content"), - /** - * {@code 206 Partial Content}. - * @see HTTP/1.1: Range Requests, section 4.1 - */ - PARTIAL_CONTENT(206, "Partial Content"), - /** - * {@code 207 Multi-Status}. - * @see WebDAV - */ - MULTI_STATUS(207, "Multi-Status"), - /** - * {@code 208 Already Reported}. - * @see WebDAV Binding Extensions - */ - ALREADY_REPORTED(208, "Already Reported"), - /** - * {@code 226 IM Used}. - * @see Delta encoding in HTTP - */ - IM_USED(226, "IM Used"), - - // 3xx Redirection - - /** - * {@code 300 Multiple Choices}. - * @see HTTP/1.1: Semantics and Content, section 6.4.1 - */ - MULTIPLE_CHOICES(300, "Multiple Choices"), - /** - * {@code 301 Moved Permanently}. - * @see HTTP/1.1: Semantics and Content, section 6.4.2 - */ - MOVED_PERMANENTLY(301, "Moved Permanently"), - /** - * {@code 302 Found}. - * @see HTTP/1.1: Semantics and Content, section 6.4.3 - */ - FOUND(302, "Found"), - /** - * {@code 302 Moved Temporarily}. - * @see HTTP/1.0, section 9.3 - * @deprecated in favor of {@link #FOUND} which will be returned from {@code HttpStatus.valueOf(302)} - */ - @Deprecated - MOVED_TEMPORARILY(302, "Moved Temporarily"), - /** - * {@code 303 See Other}. - * @see HTTP/1.1: Semantics and Content, section 6.4.4 - */ - SEE_OTHER(303, "See Other"), - /** - * {@code 304 Not Modified}. - * @see HTTP/1.1: Conditional Requests, section 4.1 - */ - NOT_MODIFIED(304, "Not Modified"), - /** - * {@code 305 Use Proxy}. - * @see HTTP/1.1: Semantics and Content, section 6.4.5 - * @deprecated due to security concerns regarding in-band configuration of a proxy - */ - @Deprecated - USE_PROXY(305, "Use Proxy"), - /** - * {@code 307 Temporary Redirect}. - * @see HTTP/1.1: Semantics and Content, section 6.4.7 - */ - TEMPORARY_REDIRECT(307, "Temporary Redirect"), - /** - * {@code 308 Permanent Redirect}. - * @see RFC 7238 - */ - PERMANENT_REDIRECT(308, "Permanent Redirect"), - - // --- 4xx Client Error --- - - /** - * {@code 400 Bad Request}. - * @see HTTP/1.1: Semantics and Content, section 6.5.1 - */ - BAD_REQUEST(400, "Bad Request"), - /** - * {@code 401 Unauthorized}. - * @see HTTP/1.1: Authentication, section 3.1 - */ - UNAUTHORIZED(401, "Unauthorized"), - /** - * {@code 402 Payment Required}. - * @see HTTP/1.1: Semantics and Content, section 6.5.2 - */ - PAYMENT_REQUIRED(402, "Payment Required"), - /** - * {@code 403 Forbidden}. - * @see HTTP/1.1: Semantics and Content, section 6.5.3 - */ - FORBIDDEN(403, "Forbidden"), - /** - * {@code 404 Not Found}. - * @see HTTP/1.1: Semantics and Content, section 6.5.4 - */ - NOT_FOUND(404, "Not Found"), - /** - * {@code 405 Method Not Allowed}. - * @see HTTP/1.1: Semantics and Content, section 6.5.5 - */ - METHOD_NOT_ALLOWED(405, "Method Not Allowed"), - /** - * {@code 406 Not Acceptable}. - * @see HTTP/1.1: Semantics and Content, section 6.5.6 - */ - NOT_ACCEPTABLE(406, "Not Acceptable"), - /** - * {@code 407 Proxy Authentication Required}. - * @see HTTP/1.1: Authentication, section 3.2 - */ - PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required"), - /** - * {@code 408 Request Timeout}. - * @see HTTP/1.1: Semantics and Content, section 6.5.7 - */ - REQUEST_TIMEOUT(408, "Request Timeout"), - /** - * {@code 409 Conflict}. - * @see HTTP/1.1: Semantics and Content, section 6.5.8 - */ - CONFLICT(409, "Conflict"), - /** - * {@code 410 Gone}. - * @see - * HTTP/1.1: Semantics and Content, section 6.5.9 - */ - GONE(410, "Gone"), - /** - * {@code 411 Length Required}. - * @see - * HTTP/1.1: Semantics and Content, section 6.5.10 - */ - LENGTH_REQUIRED(411, "Length Required"), - /** - * {@code 412 Precondition failed}. - * @see - * HTTP/1.1: Conditional Requests, section 4.2 - */ - PRECONDITION_FAILED(412, "Precondition Failed"), - /** - * {@code 413 Payload Too Large}. - * @since 4.1 - * @see - * HTTP/1.1: Semantics and Content, section 6.5.11 - */ - PAYLOAD_TOO_LARGE(413, "Payload Too Large"), - /** - * {@code 413 Request Entity Too Large}. - * @see HTTP/1.1, section 10.4.14 - * @deprecated in favor of {@link #PAYLOAD_TOO_LARGE} which will be - * returned from {@code HttpStatus.valueOf(413)} - */ - @Deprecated - REQUEST_ENTITY_TOO_LARGE(413, "Request Entity Too Large"), - /** - * {@code 414 URI Too Long}. - * @since 4.1 - * @see - * HTTP/1.1: Semantics and Content, section 6.5.12 - */ - URI_TOO_LONG(414, "URI Too Long"), - /** - * {@code 414 Request-URI Too Long}. - * @see HTTP/1.1, section 10.4.15 - * @deprecated in favor of {@link #URI_TOO_LONG} which will be returned from {@code HttpStatus.valueOf(414)} - */ - @Deprecated - REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"), - /** - * {@code 415 Unsupported Media Type}. - * @see - * HTTP/1.1: Semantics and Content, section 6.5.13 - */ - UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"), - /** - * {@code 416 Requested Range Not Satisfiable}. - * @see HTTP/1.1: Range Requests, section 4.4 - */ - REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested range not satisfiable"), - /** - * {@code 417 Expectation Failed}. - * @see - * HTTP/1.1: Semantics and Content, section 6.5.14 - */ - EXPECTATION_FAILED(417, "Expectation Failed"), - /** - * {@code 418 I'm a teapot}. - * @see HTCPCP/1.0 - */ - I_AM_A_TEAPOT(418, "I'm a teapot"), - /** - * @deprecated See - * - * WebDAV Draft Changes - */ - @Deprecated - INSUFFICIENT_SPACE_ON_RESOURCE(419, "Insufficient Space On Resource"), - /** - * @deprecated See - * - * WebDAV Draft Changes - */ - @Deprecated - METHOD_FAILURE(420, "Method Failure"), - /** - * @deprecated - * See - * WebDAV Draft Changes - */ - @Deprecated - DESTINATION_LOCKED(421, "Destination Locked"), - /** - * {@code 422 Unprocessable Entity}. - * @see WebDAV - */ - UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"), - /** - * {@code 423 Locked}. - * @see WebDAV - */ - LOCKED(423, "Locked"), - /** - * {@code 424 Failed Dependency}. - * @see WebDAV - */ - FAILED_DEPENDENCY(424, "Failed Dependency"), - /** - * {@code 426 Upgrade Required}. - * @see Upgrading to TLS Within HTTP/1.1 - */ - UPGRADE_REQUIRED(426, "Upgrade Required"), - /** - * {@code 428 Precondition Required}. - * @see Additional HTTP Status Codes - */ - PRECONDITION_REQUIRED(428, "Precondition Required"), - /** - * {@code 429 Too Many Requests}. - * @see Additional HTTP Status Codes - */ - TOO_MANY_REQUESTS(429, "Too Many Requests"), - /** - * {@code 431 Request Header Fields Too Large}. - * @see Additional HTTP Status Codes - */ - REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large"), - /** - * {@code 451 Unavailable For Legal Reasons}. - * @see - * An HTTP Status Code to Report Legal Obstacles - * @since 4.3 - */ - UNAVAILABLE_FOR_LEGAL_REASONS(451, "Unavailable For Legal Reasons"), - - // --- 5xx Server Error --- - - /** - * {@code 500 Internal Server Error}. - * @see HTTP/1.1: Semantics and Content, section 6.6.1 - */ - INTERNAL_SERVER_ERROR(500, "Internal Server Error"), - /** - * {@code 501 Not Implemented}. - * @see HTTP/1.1: Semantics and Content, section 6.6.2 - */ - NOT_IMPLEMENTED(501, "Not Implemented"), - /** - * {@code 502 Bad Gateway}. - * @see HTTP/1.1: Semantics and Content, section 6.6.3 - */ - BAD_GATEWAY(502, "Bad Gateway"), - /** - * {@code 503 Service Unavailable}. - * @see HTTP/1.1: Semantics and Content, section 6.6.4 - */ - SERVICE_UNAVAILABLE(503, "Service Unavailable"), - /** - * {@code 504 Gateway Timeout}. - * @see HTTP/1.1: Semantics and Content, section 6.6.5 - */ - GATEWAY_TIMEOUT(504, "Gateway Timeout"), - /** - * {@code 505 HTTP Version Not Supported}. - * @see HTTP/1.1: Semantics and Content, section 6.6.6 - */ - HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version not supported"), - /** - * {@code 506 Variant Also Negotiates} - * @see Transparent Content Negotiation - */ - VARIANT_ALSO_NEGOTIATES(506, "Variant Also Negotiates"), - /** - * {@code 507 Insufficient Storage} - * @see WebDAV - */ - INSUFFICIENT_STORAGE(507, "Insufficient Storage"), - /** - * {@code 508 Loop Detected} - * @see WebDAV Binding Extensions - */ - LOOP_DETECTED(508, "Loop Detected"), - /** - * {@code 509 Bandwidth Limit Exceeded} - */ - BANDWIDTH_LIMIT_EXCEEDED(509, "Bandwidth Limit Exceeded"), - /** - * {@code 510 Not Extended} - * @see HTTP Extension Framework - */ - NOT_EXTENDED(510, "Not Extended"), - /** - * {@code 511 Network Authentication Required}. - * @see Additional HTTP Status Codes - */ - NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required"); - - - private final int value; - - private final String reasonPhrase; - - - HttpStatus(int value, String reasonPhrase) { - this.value = value; - this.reasonPhrase = reasonPhrase; - } - - - /** - * Return the integer value of this status code. - */ - public int value() { - return this.value; - } - - /** - * Return the reason phrase of this status code. - */ - public String getReasonPhrase() { - return this.reasonPhrase; - } - -} diff --git a/src/main/java/io/jboot/components/restful/JbootRestfulManager.java b/src/main/java/io/jboot/components/restful/JbootRestfulManager.java deleted file mode 100644 index 4a2f1ed5..00000000 --- a/src/main/java/io/jboot/components/restful/JbootRestfulManager.java +++ /dev/null @@ -1,238 +0,0 @@ -package io.jboot.components.restful; - -import com.jfinal.aop.Interceptor; -import com.jfinal.aop.InterceptorManager; -import com.jfinal.config.Routes; -import com.jfinal.core.Controller; -import com.jfinal.core.NotAction; -import io.jboot.components.restful.annotation.DeleteMapping; -import io.jboot.components.restful.annotation.GetMapping; -import io.jboot.components.restful.annotation.PostMapping; -import io.jboot.components.restful.annotation.PutMapping; -import io.jboot.components.restful.exception.RequestMethodErrorException; -import io.jboot.utils.StrUtil; -import io.jboot.web.controller.annotation.RequestMapping; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class JbootRestfulManager { - - public static class Config { - private boolean mappingSupperClass; - private String baseViewPath; - private Interceptor[] routeInterceptors; - private List routes; - - public Config() { - } - - public Config(boolean mappingSupperClass, String baseViewPath, - Interceptor[] routeInterceptors, List routes) { - this.mappingSupperClass = mappingSupperClass; - this.baseViewPath = baseViewPath; - this.routeInterceptors = routeInterceptors; - this.routes = routes; - } - - public boolean isMappingSupperClass() { - return mappingSupperClass; - } - - public Config setMappingSupperClass(boolean mappingSupperClass) { - this.mappingSupperClass = mappingSupperClass; - return this; - } - - public String getBaseViewPath() { - return baseViewPath; - } - - public Config setBaseViewPath(String baseViewPath) { - this.baseViewPath = baseViewPath; - return this; - } - - public Interceptor[] getRouteInterceptors() { - return routeInterceptors; - } - - public Config setRouteInterceptors(Interceptor[] routeInterceptors) { - this.routeInterceptors = routeInterceptors; - return this; - } - - public List getRoutes() { - return routes; - } - - public Config setRoutes(List routes) { - this.routes = routes; - return this; - } - } - - private static JbootRestfulManager me = new JbootRestfulManager(); - - private Map restfulActions = new HashMap<>(2048, 0.5F); - - protected static final String SLASH = "/"; - - private RestfulErrorRender restfulErrorRender = new DefaultRestfulErrorRender(); - - public static JbootRestfulManager me() { - return me; - } - - public void init(Config config) { - if (config.getRoutes() == null || config.getRoutes().isEmpty()) { - return; - } - InterceptorManager interMan = InterceptorManager.me(); - Class dc; - // 初始化自定义的restful controller - for (Routes.Route route : config.getRoutes()) { - Class controllerClass = route.getControllerClass(); - Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass); - - boolean declaredMethods = config.isMappingSupperClass() - ? controllerClass.getSuperclass() == Controller.class - : true; - - String baseRequestMapping = SLASH; - if (controllerClass.getAnnotation(RequestMapping.class) != null) { - RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class); - if (requestMapping.value().startsWith(SLASH)) { - baseRequestMapping = requestMapping.value(); - } else { - baseRequestMapping = baseRequestMapping + requestMapping.value(); - } - } - - Method[] methods = (declaredMethods ? controllerClass.getDeclaredMethods() : controllerClass.getMethods()); - for (Method method : methods) { - if (declaredMethods) { - if (!Modifier.isPublic(method.getModifiers())) { - continue; - } - } else { - dc = method.getDeclaringClass(); - if (dc == Controller.class || dc == Object.class) { - continue; - } - } - //去除mapping - if (method.getAnnotation(NotAction.class) != null) { - continue; - } - Interceptor[] actionInters = interMan.buildControllerActionInterceptor(config.getRouteInterceptors(), controllerInters, controllerClass, method); - - String actionKey = baseRequestMapping; - - //GET 判断 - GetMapping getMapping = method.getAnnotation(GetMapping.class); - PostMapping postMapping = method.getAnnotation(PostMapping.class); - PutMapping putMapping = method.getAnnotation(PutMapping.class); - DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class); - String requestMethod = "", mappingValue = ""; - if (getMapping != null) { - requestMethod = "GET"; - if (StrUtil.isNotBlank(getMapping.value())) { - mappingValue = getMapping.value(); - } - } else if (postMapping != null) { - requestMethod = "POST"; - if (StrUtil.isNotBlank(postMapping.value())) { - mappingValue = postMapping.value(); - } - } else if (putMapping != null) { - requestMethod = "PUT"; - if (StrUtil.isNotBlank(putMapping.value())) { - mappingValue = putMapping.value(); - } - } else if (deleteMapping != null) { - requestMethod = "DELETE"; - if (StrUtil.isNotBlank(deleteMapping.value())) { - mappingValue = deleteMapping.value(); - } - } else { - //默认为get请求 - requestMethod = "GET"; - mappingValue = SLASH; - } - if (StrUtil.isNotBlank(mappingValue)) { - if (!actionKey.endsWith(SLASH)) { - actionKey = actionKey + SLASH; - } - if (mappingValue.startsWith(SLASH)) { - mappingValue = mappingValue.substring(1); - } - actionKey = actionKey + mappingValue; - } else { - if (actionKey.endsWith(SLASH)) { - actionKey = actionKey.substring(0, actionKey.length() - 1); - } - } - RestfulAction action = new RestfulAction(baseRequestMapping, actionKey, controllerClass, - method, method.getName(), actionInters, route.getFinalViewPath(config.getBaseViewPath())); - String key = requestMethod + ":" + actionKey; - -// RestfulAction restfulAction = new RestfulAction(action, actionKey, requestMethod); - if (restfulActions.put(key, action) != null) { - //已经存在指定的key - throw new RuntimeException(buildMsg(actionKey, controllerClass, method)); - } - } - } - } - - protected String buildMsg(String actionKey, Class controllerClass, Method method) { - StringBuilder sb = new StringBuilder("The action \"") - .append(controllerClass.getName()).append(".") - .append(method.getName()).append("()\" can not be mapped, ") - .append("actionKey \"").append(actionKey).append("\" is already in use."); - - String msg = sb.toString(); - System.err.println("\nException: " + msg); - return msg; - } - - public RestfulAction getRestfulAction(String target, String requestMethod) { - String actionKey = requestMethod + ":" + target; - //先直接获取 - RestfulAction restfulAction = restfulActions.get(actionKey); - if (restfulAction == null) { - //路径判断 - String[] paths = actionKey.split(":")[1].replace(requestMethod, "").split(SLASH); - for (String _actionKey : restfulActions.keySet()) { - String _requestMethod = _actionKey.split(":")[0]; - String _target = _actionKey.split(":")[1]; - System.out.println("---------> target:"+target+",_target:"+_target+",_requestMethod:"+_requestMethod+",requestMethod:" + requestMethod); - if( target.equals(_target) && !_requestMethod.equals(requestMethod) ){ - //请求方法不正确 - throw new RequestMethodErrorException(_actionKey, _requestMethod, target, requestMethod); - } - String[] _paths = _actionKey.split(":")[1].replace(requestMethod, "").split(SLASH); - if (_actionKey.startsWith(requestMethod) && - _actionKey.contains("{") && _actionKey.contains("}") - && paths.length == _paths.length && RestfulUtils.comparePaths(_paths, paths)) { - restfulAction = restfulActions.get(_actionKey); - break; - } - } - } - return restfulAction; - } - - public RestfulErrorRender getRestfulErrorRender() { - return restfulErrorRender; - } - - public JbootRestfulManager setRestfulErrorRender(RestfulErrorRender restfulErrorRender) { - this.restfulErrorRender = restfulErrorRender; - return this; - } -} diff --git a/src/main/java/io/jboot/components/restful/ResponseEntity.java b/src/main/java/io/jboot/components/restful/ResponseEntity.java deleted file mode 100644 index 90aad644..00000000 --- a/src/main/java/io/jboot/components/restful/ResponseEntity.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.jboot.components.restful; - -import java.util.HashMap; -import java.util.Map; - -public class ResponseEntity { - - //响应的数据 - private T data; - - //自定义响应头部信息 - private Map headers = new HashMap<>(); - - //默认http状态 - private HttpStatus httpStatus = HttpStatus.OK; - - public T getData() { - return data; - } - - public ResponseEntity setData(T data) { - this.data = data; - return this; - } - - public ResponseEntity addHeaders(Map headers) { - this.headers.putAll(headers); - return this; - } - - public ResponseEntity addHeader(String key, String value) { - this.headers.put(key, value); - return this; - } - - public Map getHeaders() { - return headers; - } - - public ResponseEntity setHttpStatus(HttpStatus httpStatus) { - this.httpStatus = httpStatus; - return this; - } - - public HttpStatus getHttpStatus() { - return httpStatus; - } - - public ResponseEntity() { - } - - public ResponseEntity(T data, Map headers, HttpStatus httpStatus) { - this.data = data; - this.headers = headers; - this.httpStatus = httpStatus; - } - - public ResponseEntity(Map headers, HttpStatus httpStatus) { - this.headers = headers; - this.httpStatus = httpStatus; - } - - public ResponseEntity(T data) { - this.data = data; - } - -} diff --git a/src/main/java/io/jboot/components/restful/RestfulAction.java b/src/main/java/io/jboot/components/restful/RestfulAction.java deleted file mode 100644 index 7c2ccd4e..00000000 --- a/src/main/java/io/jboot/components/restful/RestfulAction.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.jboot.components.restful; - -import com.jfinal.aop.Interceptor; -import com.jfinal.core.Action; -import com.jfinal.core.Controller; - -import java.lang.reflect.Method; - -public class RestfulAction extends Action { - - public RestfulAction(String controllerKey, String actionKey, Class controllerClass, Method method, String methodName, Interceptor[] interceptors, String viewPath) { - super(controllerKey, actionKey, controllerClass, method, methodName, interceptors, viewPath); - } -} diff --git a/src/main/java/io/jboot/components/restful/RestfulCallback.java b/src/main/java/io/jboot/components/restful/RestfulCallback.java deleted file mode 100644 index 00b6bd66..00000000 --- a/src/main/java/io/jboot/components/restful/RestfulCallback.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.jboot.components.restful; - -import com.jfinal.core.Action; -import com.jfinal.proxy.Callback; - -public class RestfulCallback implements Callback { - - private Action action; - private Object target; - - public RestfulCallback(Action restfulAction, Object target) { - this.action = restfulAction; - this.target = target; - } - - @Override - public Object call(Object[] args) throws Throwable { - return action.getMethod().invoke(target, args); - } - -} diff --git a/src/main/java/io/jboot/components/restful/RestfulErrorRender.java b/src/main/java/io/jboot/components/restful/RestfulErrorRender.java deleted file mode 100644 index d2154da2..00000000 --- a/src/main/java/io/jboot/components/restful/RestfulErrorRender.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.jboot.components.restful; - -import com.jfinal.core.Action; -import com.jfinal.render.Render; - - -public abstract class RestfulErrorRender extends Render { - - private String target; - - private Action action; - - private Exception error; - - public void init (String target, Action action, Exception error) { - this.target = target; - this.action = action; - this.error = error; - } - - protected RestfulErrorRender() { - } - - protected String getTarget() { - return target; - } - - protected Action getAction() { - return action; - } - - protected Exception getError() { - return error; - } -} diff --git a/src/main/java/io/jboot/components/restful/RestfulHandler.java b/src/main/java/io/jboot/components/restful/RestfulHandler.java deleted file mode 100644 index a7637393..00000000 --- a/src/main/java/io/jboot/components/restful/RestfulHandler.java +++ /dev/null @@ -1,247 +0,0 @@ -package io.jboot.components.restful; - -import com.jfinal.aop.Invocation; -import com.jfinal.core.Action; -import com.jfinal.core.Controller; -import com.jfinal.log.Log; -import io.jboot.components.restful.annotation.ResponseHeader; -import io.jboot.components.restful.annotation.ResponseHeaders; -import io.jboot.utils.ArrayUtil; -import io.jboot.utils.StrUtil; -import io.jboot.web.handler.JbootActionHandler; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class RestfulHandler extends JbootActionHandler { - - private static final Log log = Log.getLog(JbootActionHandler.class); - - @Override - public Action getAction(String target, String[] urlPara, HttpServletRequest request) { - Action action = super.getAction(target, urlPara); - if (action == null) { - if (action.getActionKey().equals("/") && action.getMethodName().equals("index") - && StrUtil.isNotBlank(target) && !target.equals(action.getActionKey())) { - action = JbootRestfulManager.me().getRestfulAction(target, request.getMethod()); - } - } - - - return action; - } - - @Override - public Invocation getInvocation(Action action, Controller controller) { - if (action instanceof RestfulAction) { - Object[] args = RestfulUtils.parseActionMethodParameters(action.getActionKey(), action.getActionKey(), - action.getMethod(), controller.getRequest(), controller.getRawData()); - return new RestfulInvocation(action, controller, args); - } else { - return super.getInvocation(action, controller); - } - } - - - // @Override -// public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { -// if (target.indexOf('.') != -1) { -// return; -// } -// -// isHandled[0] = true; -// String[] urlPara = {null}; -// Action action = getAction(target, urlPara); -// RestfulAction restfulAction = null; -// if (action != null && action.getActionKey().equals("/") && action.getMethodName().equals("index") -// && StrUtil.isNotBlank(target) && !target.equals(action.getActionKey())) { -// //如果被默认的"/"拦截,并且为index方法,但是请求的url又和actionKey不匹配,则有可能是restful请求 -// try { -// restfulAction = JbootRestfulManager.me().getRestfulAction(target, request.getMethod()); -// } catch (RequestMethodErrorException e) { -// handleActionException(target, request, response, action, e); -// return; -// } -// if (restfulAction != null) { -// action = null; -// } -// } -// //如果无法从内置的action中获取action则尝试从restful管理的action中获取 -// if (action == null) { -// // 尝试从restful 获取action -// try { -// if (restfulAction == null) { -// restfulAction = JbootRestfulManager.me().getRestfulAction(target, request.getMethod()); -// } -// } catch (RequestMethodErrorException e) { -// handleActionException(target, request, response, action, e); -// return; -// } -// if (restfulAction != null) { -// //restful 风格的请求处理 -// restfulRequest(restfulAction, target, request, response, isHandled); -// return; -// } -// if (log.isWarnEnabled()) { -// String qs = request.getQueryString(); -// log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs)); -// } -// renderManager.getRenderFactory().getErrorRender(404).setContext(request, response).render(); -// return; -// } -// //在获取到了 -// super.handle(target, request, response, isHandled); -// } - -// private void restfulRequest(RestfulAction restfulAction, String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { -// Action action = restfulAction.getAction(); -// Controller controller = null; -// try { -// controller = controllerFactory.getController(action.getControllerClass()); -// //注入依赖 -// if (injectDependency) { -// com.jfinal.aop.Aop.inject(controller); -// } -// //绑定controller本身到当前线程 -// JbootControllerContext.hold(controller); -// //初始化controller -// CPI._init_(controller, action, request, response, null); -// -// //解析参数 -// Object[] args = RestfulUtils.parseActionMethodParameters(target, restfulAction.getActionKey(), -// action.getMethod(), request, controller.getRawData()); -// RestfulCallback restfulCallback = new RestfulCallback(restfulAction, controller); -// -// Invocation invocation = new Invocation(controller, action.getMethod(), action.getInterceptors(), -// restfulCallback, args); -// -// RestfulInvocation fixedInvocation; -// if (devMode) { -// if (ActionReporter.isReportAfterInvocation(request)) { -// fixedInvocation = invokeInvocation(invocation); -// ActionReporter.report(target, controller, action); -// } else { -// ActionReporter.report(target, controller, action); -// fixedInvocation = invokeInvocation(invocation); -// } -// } else { -// fixedInvocation = invokeInvocation(invocation); -// } -// -// Object returnValue = fixedInvocation.getReturnValue(); -// -// // 判断是否带有@DownloadResponse -// DownloadResponse downloadResponse = action.getMethod().getAnnotation(DownloadResponse.class); -// if (returnValue == null && downloadResponse == null) { -// //无返回结果的 restful 请求 -// controller.renderNull(); -// } -// // 如果标记了@DownloadResponse,并且返回值不为空,会被认为自行处理了下载行为 -// if (downloadResponse != null) { -// return; -// } -// if (returnValue != null) { -// //初始化返回值 -// initRenderValue(returnValue, controller); -// } -// -// Render render = controller.getRender(); -// if (render instanceof ForwardActionRender) { -// String actionUrl = ((ForwardActionRender) render).getActionUrl(); -// if (target.equals(actionUrl)) { -// throw new RuntimeException("The forward action url is the same as before."); -// } else { -// handle(actionUrl, request, response, isHandled); -// } -// return; -// } -// -// if (render == null) { -// render = renderManager.getRenderFactory().getDefaultRender(action.getViewPath() + action.getMethodName()); -// } -// -// //初始化自定义头部 -// initResponseHeaders(response, fixedInvocation.getMethod()); -// //响应开始 -// render.setContext(request, response, action.getViewPath()).render(); -// -// } catch (RenderException | ParameterNullErrorException | ParameterParseErrorException | ActionException e) { -// handleActionException(target, request, response, action, e); -// } catch (Exception e) { -// String info = ClassUtil.buildMethodString(action.getMethod()); -// if (log.isErrorEnabled()) { -// String qs = request.getQueryString(); -// String targetInfo = qs == null ? target : target + "?" + qs; -// log.error(info + " : " + targetInfo, e); -// } -// //自定义错误处理 -// handleActionException(target, request, response, action, e); -// } finally { -// JbootControllerContext.release(); -// controllerFactory.recycle(controller); -// } -// } - -// private void handleActionException(String target, HttpServletRequest request, HttpServletResponse response, -// Action action, Exception e) { -// RestfulErrorRender restfulErrorRender = JbootRestfulManager.me().getRestfulErrorRender(); -// restfulErrorRender.setContext(request, response, action == null ? "" : action.getViewPath()); -// restfulErrorRender.init(target, action, e); -// restfulErrorRender.render(); -// } - - -// protected RestfulInvocation invokeInvocation(Invocation inv) { -// RestfulInvocation fixedInvocation = new RestfulInvocation(inv); -// fixedInvocation.invoke(); -// return fixedInvocation; -// } - - @Override - public void setResponse(HttpServletResponse response, Action action) { - ResponseHeader[] responseHeaders = action.getMethod().getAnnotationsByType(ResponseHeader.class); - ResponseHeaders responseHeadersList = action.getMethod().getAnnotation(ResponseHeaders.class); - if (responseHeadersList != null && responseHeadersList.value().length > 0) { - if (responseHeaders != null && responseHeaders.length > 0) { - responseHeaders = ArrayUtil.concat(responseHeaders, responseHeadersList.value()); - } else { - responseHeaders = responseHeadersList.value(); - } - } - if (responseHeaders.length > 0) { - for (ResponseHeader header : responseHeaders) { - response.setHeader(header.key(), header.value()); - } - } - } - -// protected void initRenderValue(Object o, Controller controller) { -// if (o.getClass().equals(String.class) -// || o.getClass().equals(int.class) -// || o.getClass().equals(double.class) -// || o.getClass().equals(byte.class) -// || o.getClass().equals(long.class) -// || o.getClass().equals(float.class) -// || o.getClass().equals(short.class) -// || o.getClass().equals(char.class) -// || o.getClass().equals(boolean.class)) { -// controller.renderText(String.valueOf(o)); -// } else if (o.getClass().equals(File.class)) { -// controller.renderFile((File) o); -// } else if (o.getClass().equals(ResponseEntity.class)) { -// ResponseEntity responseEntity = (ResponseEntity) o; -// //设置自定义头部信息 -// Map headers = responseEntity.getHeaders(); -// -// headers.forEach((k, v) -> controller.getResponse().setHeader(k, v)); -// //设置http状态代码 -// controller.getResponse().setStatus(responseEntity.getHttpStatus().value()); -// initRenderValue(responseEntity.getData(), controller); -// } else if (o instanceof Render) { //如果是render类型直接设置render -// controller.render((Render) o); -// } else { -// controller.renderJson(o); -// } -// } - -} diff --git a/src/main/java/io/jboot/components/restful/RestfulInvocation.java b/src/main/java/io/jboot/components/restful/RestfulInvocation.java deleted file mode 100644 index fe0df0d6..00000000 --- a/src/main/java/io/jboot/components/restful/RestfulInvocation.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.jboot.components.restful; - -import com.jfinal.aop.Invocation; -import com.jfinal.core.Action; -import com.jfinal.core.Controller; - -public class RestfulInvocation extends Invocation { - - private Action action; - - - public RestfulInvocation(Action action, Controller controller, Object[] args) { - super(controller, action.getMethod(), action.getInterceptors(), new RestfulCallback(action, controller), args); - this.action = action; - } - - - @Override - public Controller getController() { - return super.getTarget(); - } - - /** - * Return the action key. - * actionKey = controllerKey + methodName - */ - @Override - public String getActionKey() { - return action.getActionKey(); - } - - /** - * Return the controller key. - */ - @Override - public String getControllerKey() { - return action.getControllerKey(); - } - - /** - * Return view path of this controller. - */ - @Override - public String getViewPath() { - return action.getViewPath(); - } - - /** - * return true if it is action invocation. - */ - @Override - public boolean isActionInvocation() { - return action != null; - } - - -} diff --git a/src/main/java/io/jboot/components/restful/RestfulUtils.java b/src/main/java/io/jboot/components/restful/RestfulUtils.java deleted file mode 100644 index cbb64f62..00000000 --- a/src/main/java/io/jboot/components/restful/RestfulUtils.java +++ /dev/null @@ -1,201 +0,0 @@ -package io.jboot.components.restful; - - -import com.jfinal.kit.JsonKit; -import io.jboot.components.restful.annotation.PathVariable; -import io.jboot.components.restful.annotation.RequestBody; -import io.jboot.components.restful.annotation.RequestHeader; -import io.jboot.components.restful.annotation.RequestParam; -import io.jboot.components.restful.exception.ParameterNullErrorException; -import io.jboot.components.restful.exception.ParameterParseErrorException; -import io.jboot.utils.StrUtil; - -import javax.servlet.http.HttpServletRequest; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.util.HashMap; -import java.util.Map; - -public class RestfulUtils { - - /** - * 从url中解析路径参数 - * - * @param url - * @param actionKey - * @return - */ - public static Map parsePathVariables(String url, String actionKey) { - if (actionKey.contains("{") && actionKey.contains("}")) { - Map pathVariables = new HashMap<>(); - String[] paths = url.split("/"); - String[] _paths = actionKey.split("/"); - for (int i = 0; i < paths.length; i++) { - if (_paths[i].startsWith("{") && _paths[i].endsWith("}")) { - String pathKey = _paths[i].substring(1, _paths[i].length() - 1); - String value = paths[i]; - pathVariables.put(pathKey, value); - } - } - return pathVariables; - } else { - return null; - } - } - - /** - * 转换请求action请求的参数信息 - * - * @param target - * @param actionKey - * @param actionMethod - * @param request - * @param rawData - * @return - * @throws ParameterNullErrorException - * @throws ParameterParseErrorException - */ - public static Object[] parseActionMethodParameters(String target, String actionKey, Method actionMethod, HttpServletRequest request, String rawData) - throws ParameterNullErrorException, ParameterParseErrorException { - Object[] args = new Object[actionMethod.getParameters().length]; - for (int i = 0; i < actionMethod.getParameters().length; i++) { - Parameter parameter = actionMethod.getParameters()[i]; - RequestParam requestParam = parameter.getAnnotation(RequestParam.class); - RequestBody requestBody = parameter.getAnnotation(RequestBody.class); - RequestHeader requestHeader = parameter.getAnnotation(RequestHeader.class); - PathVariable pathVariable = parameter.getAnnotation(PathVariable.class); - String parameterName = parameter.getName(); - String values[]; - if (requestParam != null) { - if (StrUtil.isNotBlank(requestParam.value())) { - parameterName = requestParam.value(); - } - values = request.getParameterValues(parameterName); - parameter.getType(); - args[i] = parseRequestParamToParameter(values, parameterName, parameter.getType()); - if (args[i] == null && requestParam.required()) { - //要求参数为空,但是却并没有提供参数 - throw new ParameterNullErrorException(parameterName); - } - } else if (requestBody != null) { - args[i] = parseRequestBodyToParameter(rawData, parameterName, parameter.getType()); - } else if (requestHeader != null) { - if (StrUtil.isNotBlank(requestHeader.value())) { - parameterName = requestHeader.value(); - } - String value = request.getHeader(parameterName); - args[i] = parseRequestHeaderToParameter(value, parameterName, parameter.getType()); - if (args[i] == null && requestHeader.required()) { - //要求参数为空,但是却并没有提供参数 - throw new ParameterNullErrorException(parameterName); - } - } else if (pathVariable != null) { - if (StrUtil.isNotBlank(pathVariable.value())) { - parameterName = pathVariable.value(); - } - args[i] = parsePathVariableToParameter(target, actionKey, parameterName, parameter.getType()); - } else { - args[i] = null; - } - } - return args; - } - - /** - * 比对url请求路径 - * - * @param sourcePaths action配置的原路径 - * @param targetPaths 请求的目标路径 - * @return - */ - public static boolean comparePaths(String[] sourcePaths, String[] targetPaths) { - int matchingCount = 0; - for (int i = 0; i < sourcePaths.length; i++) { - if (sourcePaths[i].equals(targetPaths[i]) - || (sourcePaths[i].startsWith("{") && sourcePaths[i].endsWith("}"))) { - matchingCount += 1; - } - } - return matchingCount == sourcePaths.length; - } - - private static Object parseRequestParamToParameter(String[] value, String name, Class parameterTypeClass) { - if(parameterTypeClass.isArray()){ - Object [] objects = new Object[value.length]; - for (int i = 0; i < value.length; i++) { - objects[i] = parseCommonValue(value[i], name, parameterTypeClass); - } - return objects; - } else { - if(value != null && value.length > 0){ - return parseCommonValue(value[0], name, parameterTypeClass); - } - } - - return null; - } - - private static Object parseRequestHeaderToParameter(String header, String name, Class parameterTypeClass) { - return parseCommonValue(header, name, parameterTypeClass); - } - - private static Object parseRequestBodyToParameter(String body, String name, Class parameterTypeClass) { - //先当作基本数据来转换 - Object value = parseCommonValue(body, name, parameterTypeClass); - if(value == null){ - value = JsonKit.parse(body, parameterTypeClass); - } - return value; - } - - private static Object parsePathVariableToParameter(String target, String actionKey, String parameterName, Class parameterTypeClass) { - Map pathVariables = parsePathVariables(target, actionKey); - String value = pathVariables.get(parameterName); - return parseCommonValue(value, parameterName, parameterTypeClass); - } - - /** - * 转换基本类型参数,目前支持string,int,double,float,boolean,long基本类型数据 - * @param value - * @param name - * @param parameterTypeClass - * @return - */ - private static Object parseCommonValue(String value, String name, Class parameterTypeClass) { - if (StrUtil.isBlank(value)) { - return null; - } - if (parameterTypeClass.equals(String.class)) { - return value; - } else if (parameterTypeClass.equals(int.class)) { - try { - return Integer.valueOf(value); - } catch (NumberFormatException e) { - throw new ParameterParseErrorException(value, name, parameterTypeClass); - } - } else if (parameterTypeClass.equals(double.class)) { - try { - return Double.valueOf(value); - } catch (NumberFormatException e) { - throw new ParameterParseErrorException(value, name, parameterTypeClass); - } - } else if (parameterTypeClass.equals(float.class)) { - try { - return Float.valueOf(value); - } catch (NumberFormatException e) { - throw new ParameterParseErrorException(value, name, parameterTypeClass); - } - } else if (parameterTypeClass.equals(boolean.class)) { - return Boolean.valueOf(value); - } else if (parameterTypeClass.equals(long.class)) { - try { - return Long.valueOf(value); - } catch (NumberFormatException e) { - throw new ParameterParseErrorException(value, name, parameterTypeClass); - } - } else { - return null; - } - } - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java b/src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java deleted file mode 100644 index 2483f1c3..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * 删除delete 方法注解 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface DeleteMapping { - - /** - * url mapping - * @return - */ - String value() default ""; - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/DownloadResponse.java b/src/main/java/io/jboot/components/restful/annotation/DownloadResponse.java deleted file mode 100644 index c4aa83e8..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/DownloadResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * 标注controller action是一个下载响应,并且需要action自行处理response - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface DownloadResponse { -} diff --git a/src/main/java/io/jboot/components/restful/annotation/GetMapping.java b/src/main/java/io/jboot/components/restful/annotation/GetMapping.java deleted file mode 100644 index c571a745..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/GetMapping.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface GetMapping { - - /** - * url mapping - * @return - */ - String value() default ""; - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/PathVariable.java b/src/main/java/io/jboot/components/restful/annotation/PathVariable.java deleted file mode 100644 index 68a96249..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/PathVariable.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * 路径参数注解 - * /user/{id}/cards - * 支持如下类型参数注入: - * string - * int - * double - * float - * boolean - * long - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -@Documented -public @interface PathVariable { - - /** - * 如果为空则默认为参数名本身 - * @return - */ - String value() default ""; - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/PostMapping.java b/src/main/java/io/jboot/components/restful/annotation/PostMapping.java deleted file mode 100644 index e0f9a45a..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/PostMapping.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface PostMapping { - - /** - * url mapping - * @return - */ - String value() default ""; - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/PutMapping.java b/src/main/java/io/jboot/components/restful/annotation/PutMapping.java deleted file mode 100644 index 8d0c66d2..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/PutMapping.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * Put 请求方法定义 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface PutMapping { - - /** - * url mapping - * @return - */ - String value() default ""; - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/RequestBody.java b/src/main/java/io/jboot/components/restful/annotation/RequestBody.java deleted file mode 100644 index 73327a66..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/RequestBody.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * 请求体参数注解 - * 支持如下类型参数: - * string / string[] - * int / int[] - * double / double[] - * float / float[] - * boolean / boolean[] - * long / long[] - * object / object[] - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -@Documented -public @interface RequestBody { -} diff --git a/src/main/java/io/jboot/components/restful/annotation/RequestHeader.java b/src/main/java/io/jboot/components/restful/annotation/RequestHeader.java deleted file mode 100644 index 5a967970..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/RequestHeader.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * 请求头部信息注解 - * 支持如下类型参数注入: - * string - * int - * double - * float - * boolean - * long - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -@Documented -public @interface RequestHeader { - - /** - * 如果为空则默认为参数名本身 - * @return - */ - String value() default ""; - - boolean required() default false; - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/RequestParam.java b/src/main/java/io/jboot/components/restful/annotation/RequestParam.java deleted file mode 100644 index e4a16089..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/RequestParam.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * 请求参数注解 - * 支持如下类型参数: - * string / string[] - * int / int[] - * double / double[] - * float / float[] - * boolean / boolean[] - * long / long[] - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -@Documented -public @interface RequestParam { - - /** - * 如果为空则默认为参数名本身 - * @return - */ - String value() default ""; - - boolean required() default false; - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java b/src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java deleted file mode 100644 index 626f22bf..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * 自定义响应头 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface ResponseHeader { - - String key(); - - String value(); - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java b/src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java deleted file mode 100644 index d51f43ae..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface ResponseHeaders { - - ResponseHeader[] value(); - -} diff --git a/src/main/java/io/jboot/components/restful/annotation/RestController.java b/src/main/java/io/jboot/components/restful/annotation/RestController.java deleted file mode 100644 index 6650c476..00000000 --- a/src/main/java/io/jboot/components/restful/annotation/RestController.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.jboot.components.restful.annotation; - -import java.lang.annotation.*; - -/** - * rest controller 标识 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Documented -public @interface RestController { -} diff --git a/src/main/java/io/jboot/components/restful/exception/ParameterNullErrorException.java b/src/main/java/io/jboot/components/restful/exception/ParameterNullErrorException.java deleted file mode 100644 index 081867cc..00000000 --- a/src/main/java/io/jboot/components/restful/exception/ParameterNullErrorException.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.jboot.components.restful.exception; - -/** - * 参数为空错误 - */ -public class ParameterNullErrorException extends RuntimeException { - - private String parameterName; - - - public String getParameterName() { - return parameterName; - } - - public ParameterNullErrorException(String parameterName) { - super("Parameter '"+parameterName+"' specifies a forced check, but the value is null"); - this.parameterName = parameterName; - } - - public ParameterNullErrorException(Exception e) { - super(e); - } - -} diff --git a/src/main/java/io/jboot/components/restful/exception/ParameterParseErrorException.java b/src/main/java/io/jboot/components/restful/exception/ParameterParseErrorException.java deleted file mode 100644 index 2a025ab6..00000000 --- a/src/main/java/io/jboot/components/restful/exception/ParameterParseErrorException.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.jboot.components.restful.exception; - -/** - * 参数类型错误 - */ -public class ParameterParseErrorException extends RuntimeException { - - - private String parameterValue; - - private String parameterName; - - private Class parameterType; - - public String getParameterValue() { - return parameterValue; - } - - public String getParameterName() { - return parameterName; - } - - public Class getParameterType() { - return parameterType; - } - - public ParameterParseErrorException(String parameterValue, String parameterName, Class parameterType) { - super("Error resolving parameter '" + parameterName + "', unable to match value '" - + parameterValue + "' to specified type '" + parameterType.getName() + "'"); - this.parameterValue = parameterValue; - this.parameterName = parameterName; - this.parameterType = parameterType; - } - - public ParameterParseErrorException(Exception e) { - super(e); - } - -} diff --git a/src/main/java/io/jboot/components/restful/exception/RequestMethodErrorException.java b/src/main/java/io/jboot/components/restful/exception/RequestMethodErrorException.java deleted file mode 100644 index e72f83c9..00000000 --- a/src/main/java/io/jboot/components/restful/exception/RequestMethodErrorException.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.jboot.components.restful.exception; - -/** - * 请求方法错误 - */ -public class RequestMethodErrorException extends RuntimeException { - - private String actionKey; - - private String actionMethod; - - private String target; - - private String targetMethod; - - public String getActionKey() { - return actionKey; - } - - public String getActionMethod() { - return actionMethod; - } - - public String getTarget() { - return target; - } - - public String getTargetMethod() { - return targetMethod; - } - - public RequestMethodErrorException(String actionKey, String actionMethod, String target, String targetMethod) { - super("'" + target + "' is specified as a '" + actionMethod + "' request. '" + targetMethod + "' requests are not supported"); - this.actionKey = actionKey; - this.actionMethod = actionMethod; - this.target = target; - this.targetMethod = targetMethod; - } -} diff --git a/src/main/java/io/jboot/core/JbootCoreConfig.java b/src/main/java/io/jboot/core/JbootCoreConfig.java index d5209810..204d9dde 100644 --- a/src/main/java/io/jboot/core/JbootCoreConfig.java +++ b/src/main/java/io/jboot/core/JbootCoreConfig.java @@ -36,9 +36,6 @@ import io.jboot.app.config.support.nacos.NacosConfigManager; import io.jboot.components.gateway.JbootGatewayHandler; import io.jboot.components.gateway.JbootGatewayManager; import io.jboot.components.limiter.LimiterManager; -import io.jboot.components.restful.JbootRestfulManager; -import io.jboot.components.restful.RestfulHandler; -import io.jboot.components.restful.annotation.RestController; import io.jboot.components.rpc.JbootrpcManager; import io.jboot.components.schedule.JbootScheduleManager; import io.jboot.core.listener.JbootAppListenerManager; @@ -76,9 +73,6 @@ import java.util.Properties; public class JbootCoreConfig extends JFinalConfig { private List routeList = new ArrayList<>(); - private List restfulRoutes = new ArrayList<>(); - - private JbootRestfulManager.Config restfulConfig = new JbootRestfulManager.Config(); public JbootCoreConfig() { @@ -179,13 +173,6 @@ public class JbootCoreConfig extends JFinalConfig { continue; } - //检查是否是restful类型的controller,如果是则加入restful专门指定的routes - RestController restController = clazz.getAnnotation(RestController.class); - if (restController != null) { - restfulRoutes.add(new Routes.Route(value, clazz, value)); - continue; - } - String viewPath = AnnotationUtil.get(mapping.viewPath()); if (StrUtil.isNotBlank(viewPath)) { @@ -207,18 +194,6 @@ public class JbootCoreConfig extends JFinalConfig { JbootControllerManager.me().setMapping(route.getControllerKey(), route.getControllerClass()); } - if (!restfulRoutes.isEmpty()) { - //处理restful专属的routes - restfulConfig.setRoutes(restfulRoutes) - .setBaseViewPath(routes.getBaseViewPath()) - .setMappingSupperClass(routes.getMappingSuperClass()) - .setRouteInterceptors(routes.getInterceptors()); - for (Routes.Route route : restfulRoutes) { - JbootControllerManager.me().setMapping(route.getControllerKey(), route.getControllerClass()); - } - routeList.addAll(restfulRoutes); - } - routeList.addAll(routes.getRouteItemList()); } @@ -293,15 +268,10 @@ public class JbootCoreConfig extends JFinalConfig { handlers.add(new JbootGatewayHandler()); handlers.add(new JbootFilterHandler()); handlers.add(new JbootHandler()); -// handlers.setActionHandler(new RestfulHandler()); //若用户自己没配置 ActionHandler,默认使用 JbootActionHandler if (handlers.getActionHandler() == null) { - if (restfulRoutes.isEmpty()) { - handlers.setActionHandler(new RestfulHandler()); - } else { - handlers.setActionHandler(new JbootActionHandler()); - } + handlers.setActionHandler(new JbootActionHandler()); } } @@ -324,8 +294,6 @@ public class JbootCoreConfig extends JFinalConfig { JbootSeataManager.me().init(); SentinelManager.me().init(); JbootGatewayManager.me().init(); - JbootRestfulManager.me().init(restfulConfig); - JbootAppListenerManager.me().onStart(); } diff --git a/src/test/java/io/jboot/test/restful/RestfulController.java b/src/test/java/io/jboot/test/restful/RestfulController.java deleted file mode 100644 index 08a2367d..00000000 --- a/src/test/java/io/jboot/test/restful/RestfulController.java +++ /dev/null @@ -1,117 +0,0 @@ -package io.jboot.test.restful; - -import com.jfinal.aop.Before; -import com.jfinal.aop.Inject; -import com.jfinal.aop.Interceptor; -import com.jfinal.aop.Invocation; -import com.jfinal.core.NotAction; -import com.jfinal.kit.JsonKit; -import com.jfinal.kit.StrKit; -import io.jboot.components.restful.HttpStatus; -import io.jboot.components.restful.ResponseEntity; -import io.jboot.components.restful.annotation.*; -import io.jboot.web.controller.JbootController; -import io.jboot.web.controller.annotation.RequestMapping; -import io.jboot.web.cors.EnableCORS; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -@RestController -@RequestMapping("/restful") -public class RestfulController extends JbootController { - - public static class Data implements Serializable { - private String id; - private String name; - private int age; - - public Data(String id, String name, int age) { - this.id = id; - this.name = name; - this.age = age; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public int getAge() { - return age; - } - } - - public static class RestfulInterceptor implements Interceptor { - - public void intercept(Invocation inv) { - System.out.println("--------> restful request begin"); - inv.invoke(); - System.out.println("--------> restful request end"); - } - } - - @Inject - private RestfulService restfulService; - - @NotAction - public List initData(){ - List users = new ArrayList<>(); - users.add(new RestfulController.Data("1", "tom", 18)); - users.add(new RestfulController.Data("2", "andy", 29)); - users.add(new RestfulController.Data("3", "max", 13)); - return users; - } - - //GET /restful - @GetMapping - @EnableCORS - @Before({RestfulInterceptor.class}) - @ResponseHeaders({@ResponseHeader(key = "d-head-1", value = "a"), @ResponseHeader(key = "d-head-2", value = "b")}) - public List users(){ - return initData(); - } - - // GET /restful/randomKey - @GetMapping("/randomKey") - public String randomKey(){ - return restfulService.getRandomKey(); - } - - // GET /restful/users - @GetMapping("/users") - public ResponseEntity> entityUsers(){ - return new ResponseEntity<>(initData()).addHeader("x-token", StrKit.getRandomUUID()).setHttpStatus(HttpStatus.ACCEPTED); - } - - // PUT /restful - @PutMapping - public void create(@RequestBody RestfulController.Data data){ - System.out.println("get request body data:\n" + JsonKit.toJson(data)); - } - - // PUT /restful/createList - @PutMapping("/createList") - public void createUsers(@RequestBody List users){ - System.out.println("get request body data:\n" + JsonKit.toJson(users)); - } - - // DELETE /restful/:id - @DeleteMapping("/{id}") - public void delete(@PathVariable("id") String id){ - System.out.println("delete by id : " + id ); - } - - // DELETE /restful/delete - @DeleteMapping("/delete") - public void deleteByName(@RequestParam(value = "name", required = true) String name, - @RequestHeader String token){ - System.out.println("delete by name : " + name); - System.out.println("get token header : " + token); - } - -} diff --git a/src/test/java/io/jboot/test/restful/RestfulService.java b/src/test/java/io/jboot/test/restful/RestfulService.java deleted file mode 100644 index aea7b1cd..00000000 --- a/src/test/java/io/jboot/test/restful/RestfulService.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.jboot.test.restful; - -public interface RestfulService { - String getRandomKey(); -} diff --git a/src/test/java/io/jboot/test/restful/RestfulServiceImpl.java b/src/test/java/io/jboot/test/restful/RestfulServiceImpl.java deleted file mode 100644 index 1c042af3..00000000 --- a/src/test/java/io/jboot/test/restful/RestfulServiceImpl.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.jboot.test.restful; - -import com.jfinal.kit.StrKit; -import io.jboot.aop.annotation.Bean; - -@Bean -public class RestfulServiceImpl implements RestfulService { - @Override - public String getRandomKey() { - return StrKit.getRandomUUID(); - } -} -- Gitee From 451c0264df0ca43ef2bb711e18db207250e62d12 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 09:23:38 +0800 Subject: [PATCH 02/29] v3.1.5 --- .../io/jboot/test/controller/IndexController.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/io/jboot/test/controller/IndexController.java b/src/test/java/io/jboot/test/controller/IndexController.java index fcbdf8cd..f23b7c76 100644 --- a/src/test/java/io/jboot/test/controller/IndexController.java +++ b/src/test/java/io/jboot/test/controller/IndexController.java @@ -1,6 +1,7 @@ package io.jboot.test.controller; import com.jfinal.kit.PathKit; +import io.jboot.test.db.model.User; import io.jboot.web.controller.JbootController; import io.jboot.web.controller.annotation.RequestMapping; @@ -18,4 +19,14 @@ public class IndexController extends JbootController { public void error500(){ } + + public String rhello(){ + return "hello world"; + } + + public User ruser(){ + User user = new User(); + user.put("aa","bbb"); + return user; + } } -- Gitee From 73ac39624b7e4c013deb88158b6b9708cbb6e67f Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 16:26:00 +0800 Subject: [PATCH 03/29] v3.1.5 --- .../components/gateway/GatewayHttpProxy.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java index 5c4c53f2..5a06ab0d 100644 --- a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java +++ b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java @@ -81,6 +81,10 @@ public class GatewayHttpProxy { */ configConnection(conn, req); + + /** + * 发送 http 请求 + */ conn.connect(); /** @@ -108,16 +112,15 @@ public class GatewayHttpProxy { private void copyRequestStreamToConnection(HttpServletRequest req, HttpURLConnection conn) throws IOException { + + // 如果不是 post 请求,不需要复制 + if ("get".equalsIgnoreCase(req.getMethod())) { + return; + } + OutputStream outStream = null; InputStream inStream = null; try { - - // 如果不是 post 请求,不需要复制 - if ("get".equalsIgnoreCase(req.getMethod())) { - return; - } - - conn.setDoOutput(true); outStream = conn.getOutputStream(); inStream = req.getInputStream(); int n; @@ -202,7 +205,11 @@ public class GatewayHttpProxy { conn.setConnectTimeout(connectTimeOut); conn.setInstanceFollowRedirects(true); conn.setUseCaches(false); -// conn.setDefaultUseCaches(); + + //不是 get 请求 + if (!"get".equalsIgnoreCase(req.getMethod())) { + conn.setDoOutput(true); + } conn.setRequestMethod(req.getMethod()); Enumeration headerNames = req.getHeaderNames(); -- Gitee From 2d0ca683f1f8e2fe1360cbd7aa9eb21d12775bd4 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 16:36:50 +0800 Subject: [PATCH 04/29] v3.1.5 --- .../components/gateway/GatewayHttpProxy.java | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java index 5a06ab0d..8845a07d 100644 --- a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java +++ b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java @@ -81,16 +81,18 @@ public class GatewayHttpProxy { */ configConnection(conn, req); + conn.setRequestMethod(req.getMethod()); - /** - * 发送 http 请求 - */ - conn.connect(); - - /** - * 复制 post 请求内容到目标服务器 - */ - copyRequestStreamToConnection(req, conn); + // get 请求 + if ("get".equalsIgnoreCase(req.getMethod())) { + conn.connect(); + } + // post 请求 + else { + conn.setDoOutput(true); + conn.setDoInput(true); + copyRequestStreamToConnection(req, conn); + } /** @@ -99,7 +101,7 @@ public class GatewayHttpProxy { configResponse(resp, conn); /** - * 复制目标流到 Response + * 复制目标相应流到 Response */ copyStreamToResponse(conn, resp); @@ -112,21 +114,15 @@ public class GatewayHttpProxy { private void copyRequestStreamToConnection(HttpServletRequest req, HttpURLConnection conn) throws IOException { - - // 如果不是 post 请求,不需要复制 - if ("get".equalsIgnoreCase(req.getMethod())) { - return; - } - OutputStream outStream = null; InputStream inStream = null; try { outStream = conn.getOutputStream(); inStream = req.getInputStream(); - int n; + int len; byte[] buffer = new byte[1024]; - while (-1 != (n = inStream.read(buffer))) { - outStream.write(buffer, 0, n); + while ((len = inStream.read(buffer)) != -1) { + outStream.write(buffer, 0, len); } } finally { @@ -152,7 +148,6 @@ public class GatewayHttpProxy { } finally { quetlyClose(inStream, reader); } - } @@ -185,7 +180,6 @@ public class GatewayHttpProxy { } private static InputStream getInputStream(HttpURLConnection conn) throws IOException { - InputStream stream = conn.getResponseCode() >= 400 ? conn.getErrorStream() : conn.getInputStream(); @@ -195,7 +189,6 @@ public class GatewayHttpProxy { } else { return stream; } - } @@ -203,14 +196,9 @@ public class GatewayHttpProxy { conn.setReadTimeout(readTimeOut); conn.setConnectTimeout(connectTimeOut); - conn.setInstanceFollowRedirects(true); + conn.setInstanceFollowRedirects(false); conn.setUseCaches(false); - //不是 get 请求 - if (!"get".equalsIgnoreCase(req.getMethod())) { - conn.setDoOutput(true); - } - conn.setRequestMethod(req.getMethod()); Enumeration headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { -- Gitee From 72a2c2ef0a713c0c9824dc89660499ed48054fb0 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 16:52:49 +0800 Subject: [PATCH 05/29] v3.1.5 --- .../io/jboot/components/gateway/GatewaySentinelProcesser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/jboot/components/gateway/GatewaySentinelProcesser.java b/src/main/java/io/jboot/components/gateway/GatewaySentinelProcesser.java index 7e7de2b8..5aefb152 100644 --- a/src/main/java/io/jboot/components/gateway/GatewaySentinelProcesser.java +++ b/src/main/java/io/jboot/components/gateway/GatewaySentinelProcesser.java @@ -37,7 +37,7 @@ public class GatewaySentinelProcesser { Entry entry = null; String resourceName = GatewayUtil.buildResource(req); try { - entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN); + entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_API_GATEWAY, EntryType.IN); runnable.run(); } catch (BlockException ex) { processBlocked(config, req, resp); -- Gitee From f6ea6cd69fe394dc21a33b820012349ffd0cbe8f Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 16:55:07 +0800 Subject: [PATCH 06/29] v3.1.5 --- src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java index 8845a07d..07a1ae42 100644 --- a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java +++ b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java @@ -81,7 +81,6 @@ public class GatewayHttpProxy { */ configConnection(conn, req); - conn.setRequestMethod(req.getMethod()); // get 请求 if ("get".equalsIgnoreCase(req.getMethod())) { @@ -200,6 +199,7 @@ public class GatewayHttpProxy { conn.setUseCaches(false); conn.setRequestMethod(req.getMethod()); + Enumeration headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); -- Gitee From 83e46ea8722ac6bd74ab25453ebcb89c1475ff04 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 17:40:23 +0800 Subject: [PATCH 07/29] v3.1.5 --- .../components/gateway/GatewayHttpProxy.java | 17 ++++++++++++++--- src/test/resources/jboot.properties | 14 ++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java index 07a1ae42..eabd9f87 100644 --- a/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java +++ b/src/main/java/io/jboot/components/gateway/GatewayHttpProxy.java @@ -171,8 +171,16 @@ public class GatewayHttpProxy { Set headerNames = headerFields.keySet(); for (String headerName : headerNames) { //需要排除 Content-Encoding,因为 Server 可能已经使用 gzip 压缩,但是此代理已经对 gzip 内容进行解压了 - if (StrUtil.isNotBlank(headerName) && !"Content-Encoding".equalsIgnoreCase(headerName)) { - resp.setHeader(headerName, conn.getHeaderField(headerName)); + //需要排除 Content-Type,因为会可能会进行多次设置 + if (StrUtil.isBlank(headerName) + || "Content-Encoding".equalsIgnoreCase(headerName) + || "Content-Type".equalsIgnoreCase(headerName)) { + continue; + } else { + String headerFieldValue = conn.getHeaderField(headerName); + if (StrUtil.isNotBlank(headerFieldValue)) { + resp.setHeader(headerName, headerFieldValue); + } } } } @@ -204,7 +212,10 @@ public class GatewayHttpProxy { while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); if (StrUtil.isNotBlank(headerName)) { - conn.setRequestProperty(headerName, req.getHeader(headerName)); + String headerFieldValue = req.getHeader(headerName); + if (StrUtil.isNotBlank(headerFieldValue)) { + conn.setRequestProperty(headerName, headerFieldValue); + } } } } diff --git a/src/test/resources/jboot.properties b/src/test/resources/jboot.properties index 151711f4..378fb0f8 100644 --- a/src/test/resources/jboot.properties +++ b/src/test/resources/jboot.properties @@ -38,15 +38,13 @@ config.test.test.ccc.type = type3 # 配置 gateway ,访问首页的时候目标地址设置为 baidu 的地址 -jboot.gateway.enable = true -jboot.gateway.uri = https://www.baidu.com -#jboot.gateway.proxyRetries = 2 -jboot.gateway.pathEquals = / +#jboot.gateway.enable = true +#jboot.gateway.uri = https://www.baidu.com +#jboot.gateway.pathEquals = / jboot.gateway.gitee.enable = true -jboot.gateway.gitee.uri= https://gitee.com -jboot.gateway.gitee.sentinelEnable= true -jboot.gateway.gitee.sentinelBlockPage= / -jboot.gateway.gitee.pathStartsWith = /fuhai +jboot.gateway.gitee.uri= https://search.gitee.com +jboot.gateway.gitee.queryContains = q + jboot.rpc.type = local -- Gitee From 7ed5610db071c90cb0923485cf691d75350c2f1c Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 18:11:22 +0800 Subject: [PATCH 08/29] v3.1.5 --- .../io/jboot/test/controller/IndexController.java | 12 ++++-------- src/test/resources/jboot.properties | 9 +++------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/test/java/io/jboot/test/controller/IndexController.java b/src/test/java/io/jboot/test/controller/IndexController.java index f23b7c76..d402d718 100644 --- a/src/test/java/io/jboot/test/controller/IndexController.java +++ b/src/test/java/io/jboot/test/controller/IndexController.java @@ -1,7 +1,6 @@ package io.jboot.test.controller; import com.jfinal.kit.PathKit; -import io.jboot.test.db.model.User; import io.jboot.web.controller.JbootController; import io.jboot.web.controller.annotation.RequestMapping; @@ -20,13 +19,10 @@ public class IndexController extends JbootController { } - public String rhello(){ - return "hello world"; + public String ping(){ + return "ping:" + getPara("ping"); } - public User ruser(){ - User user = new User(); - user.put("aa","bbb"); - return user; - } + + } diff --git a/src/test/resources/jboot.properties b/src/test/resources/jboot.properties index 378fb0f8..d285e323 100644 --- a/src/test/resources/jboot.properties +++ b/src/test/resources/jboot.properties @@ -38,13 +38,10 @@ config.test.test.ccc.type = type3 # 配置 gateway ,访问首页的时候目标地址设置为 baidu 的地址 -#jboot.gateway.enable = true -#jboot.gateway.uri = https://www.baidu.com -#jboot.gateway.pathEquals = / +jboot.gateway.enable = true +jboot.gateway.uri = https://www.baidu.com +jboot.gateway.pathEquals = / -jboot.gateway.gitee.enable = true -jboot.gateway.gitee.uri= https://search.gitee.com -jboot.gateway.gitee.queryContains = q jboot.rpc.type = local -- Gitee From cb0bd0864012328e9ab0d310770cefb4797b7962 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 18:37:21 +0800 Subject: [PATCH 09/29] add group and version config in jbootRpcConfig --- .../jboot/components/rpc/JbootrpcConfig.java | 66 +++++++++++++++++-- .../components/rpc/dubbo/JbootDubborpc.java | 22 ++++++- .../components/rpc/motan/JbootMotanrpc.java | 32 ++++++--- 3 files changed, 103 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java b/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java index 78b01fd1..d132fcdc 100644 --- a/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java +++ b/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java @@ -32,15 +32,27 @@ public class JbootrpcConfig { //用于直连时的配置,直连一般只用于测试环境 //com.service.AAAService:127.0.0.1:8080,com.service.XXXService:127.0.0.1:8080 - private Map urls; + private Map urls; //服务的provider指定,可以通过注解 @RPCBean 指定,也可以通过此处指定,此处的配置优先于注解 //com.service.AAAService:providerName,com.service.XXXService:providerName - private Map providers; + private Map providers; //服务的consumer指定,可以通过注解 @RPCInject 指定,也可以通过此处指定,此处的配置优先于注解 //com.service.AAAService:providerName,com.service.XXXService:providerName - private Map consumers; + private Map consumers; + + //当不配置的时候,默认版本号 + private String defaultVersion = "1.0.0"; + + //指定的服务的版本号 + private Map versions; + + //当不指定的时候,默认分组 + private String defaultGroup; + + //指定的服务的分组 + private Map groups; //本地自动暴露 @RPCBean 的 service private boolean autoExportEnable = true; @@ -62,7 +74,7 @@ public class JbootrpcConfig { this.urls = urls; } - public String getUrl(String serviceClass){ + public String getUrl(String serviceClass) { return urls == null ? null : urls.get(serviceClass); } @@ -74,7 +86,7 @@ public class JbootrpcConfig { this.providers = providers; } - public String getProvider(String serviceClass){ + public String getProvider(String serviceClass) { return providers == null ? null : providers.get(serviceClass); } @@ -86,10 +98,52 @@ public class JbootrpcConfig { this.consumers = consumers; } - public String getConsumer(String serviceClass){ + public String getConsumer(String serviceClass) { return consumers == null ? null : consumers.get(serviceClass); } + public String getDefaultVersion() { + return defaultVersion; + } + + public void setDefaultVersion(String defaultVersion) { + this.defaultVersion = defaultVersion; + } + + public Map getVersions() { + return versions; + } + + public void setVersions(Map versions) { + this.versions = versions; + } + + public String getVersion(String className) { + String version = versions == null ? null : versions.get(className); + return version == null ? defaultVersion : version; + } + + public String getDefaultGroup() { + return defaultGroup; + } + + public void setDefaultGroup(String defaultGroup) { + this.defaultGroup = defaultGroup; + } + + public Map getGroups() { + return groups; + } + + public void setGroups(Map groups) { + this.groups = groups; + } + + public String getGroup(String className) { + String group = groups == null ? null : groups.get(className); + return group == null ? defaultGroup : group; + } + public boolean isAutoExportEnable() { return autoExportEnable; } diff --git a/src/main/java/io/jboot/components/rpc/dubbo/JbootDubborpc.java b/src/main/java/io/jboot/components/rpc/dubbo/JbootDubborpc.java index 169e2bec..1ce4648f 100644 --- a/src/main/java/io/jboot/components/rpc/dubbo/JbootDubborpc.java +++ b/src/main/java/io/jboot/components/rpc/dubbo/JbootDubborpc.java @@ -41,15 +41,23 @@ public class JbootDubborpc extends JbootrpcBase { reference.setInterface(interfaceClass); String directUrl = rpcConfig.getUrl(interfaceClass.getName()); - if (StrUtil.isNotBlank(directUrl)){ + if (StrUtil.isNotBlank(directUrl)) { reference.setUrl(directUrl); } String consumer = rpcConfig.getConsumer(interfaceClass.getName()); - if (consumer != null){ + if (consumer != null) { reference.setConsumer(DubboUtil.getConsumer(consumer)); } + if (reference.getGroup() == null) { + reference.setGroup(rpcConfig.getGroup(interfaceClass.getName())); + } + + if (reference.getVersion() == null) { + reference.setVersion(rpcConfig.getVersion(interfaceClass.getName())); + } + return reference.get(); } @@ -61,10 +69,18 @@ public class JbootDubborpc extends JbootrpcBase { service.setRef((T) object); String provider = rpcConfig.getProvider(interfaceClass.getName()); - if (provider != null){ + if (provider != null) { service.setProvider(DubboUtil.getProvider(provider)); } + if (service.getGroup() == null) { + service.setGroup(rpcConfig.getGroup(interfaceClass.getName())); + } + + if (service.getVersion() == null) { + service.setVersion(rpcConfig.getVersion(interfaceClass.getName())); + } + service.export(); return true; } diff --git a/src/main/java/io/jboot/components/rpc/motan/JbootMotanrpc.java b/src/main/java/io/jboot/components/rpc/motan/JbootMotanrpc.java index f9c1c4b4..9d4282c6 100644 --- a/src/main/java/io/jboot/components/rpc/motan/JbootMotanrpc.java +++ b/src/main/java/io/jboot/components/rpc/motan/JbootMotanrpc.java @@ -51,6 +51,14 @@ public class JbootMotanrpc extends JbootrpcBase { referer.setBasicReferer(MotanUtil.getBaseReferer(consumer)); } + if (referer.getGroup() == null) { + referer.setGroup(rpcConfig.getGroup(interfaceClass.getName())); + } + + if (referer.getVersion() == null) { + referer.setVersion(rpcConfig.getVersion(interfaceClass.getName())); + } + return referer.getRef(); } @@ -62,19 +70,27 @@ public class JbootMotanrpc extends JbootrpcBase { MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, false); - ServiceConfig serviceConfig = MotanUtil.toServiceConfig(config); - serviceConfig.setInterface(interfaceClass); - serviceConfig.setRef((T) object); - serviceConfig.setShareChannel(true); - serviceConfig.setExport(defaultConfig.getExport(interfaceClass.getName())); - serviceConfig.setHost(defaultConfig.getHost(interfaceClass.getName())); + ServiceConfig service = MotanUtil.toServiceConfig(config); + service.setInterface(interfaceClass); + service.setRef((T) object); + service.setShareChannel(true); + service.setExport(defaultConfig.getExport(interfaceClass.getName())); + service.setHost(defaultConfig.getHost(interfaceClass.getName())); String provider = rpcConfig.getProvider(interfaceClass.getName()); if (provider != null) { - serviceConfig.setBasicService(MotanUtil.getBaseService(provider)); + service.setBasicService(MotanUtil.getBaseService(provider)); + } + + if (service.getGroup() == null) { + service.setGroup(rpcConfig.getGroup(interfaceClass.getName())); + } + + if (service.getVersion() == null) { + service.setVersion(rpcConfig.getVersion(interfaceClass.getName())); } - serviceConfig.export(); + service.export(); MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true); } -- Gitee From b5e16bac5ae61b53f0718df89a82985f1afe0a18 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 18:49:21 +0800 Subject: [PATCH 10/29] update gateway docs --- doc/docs/gateway.md | 71 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/doc/docs/gateway.md b/doc/docs/gateway.md index d5192ec0..331836e2 100644 --- a/doc/docs/gateway.md +++ b/doc/docs/gateway.md @@ -6,6 +6,7 @@ - path路由 - host路由 - query路由 +- 多个 Gateway 配置 - 其他 @@ -187,6 +188,74 @@ jboot.gateway.queryContains = aaa 以上配置中,如果用户访问 `www.xxx.com/controller?aaa=bbb` 会自动路由到 `http://youdomain:8080/controller?aaa=bbb` ,或者用户访问 `www.xxx.com/controller?aaa=ccc` 也会路由到 `http://youdomain:8080/controller?aaa=ccc`,因为 query 都包含了 `aaa=**` 的请求,但是如果用户访问 `www.xxx.com/controller?other=aaa`不会路由。 + + +## 多个 Gateway 配置 + +``` +jboot.gateway.aaa.name = name +jboot.gateway.aaa.uri = http://youdomain:8080 +jboot.gateway.aaa.enable = true +jboot.gateway.aaa.sentinelEnable = false +jboot.gateway.aaa.sentinelBlockPage = /block +jboot.gateway.aaa.proxyReadTimeout = 10000 +jboot.gateway.aaa.proxyConnectTimeout = 5000 +jboot.gateway.aaa.proxyContentType = text/html;charset=utf-8 +jboot.gateway.aaa.interceptors = com.xxx.Interceptor1,com.xxx.Interceptor2 +jboot.gateway.aaa.pathEquals = /path +jboot.gateway.aaa.pathContains = /path +jboot.gateway.aaa.pathStartsWith = /path +jboot.gateway.aaa.pathEndswith = /path +jboot.gateway.aaa.hostEquals = xxx.com +jboot.gateway.aaa.hostContains = xxx.com +jboot.gateway.aaa.hostStartsWith = xxx.com +jboot.gateway.aaa.hostEndswith = xxx.com +jboot.gateway.aaa.queryEquals = aa:bb,cc:dd +jboot.gateway.aaa.queryContains = aa,bb + + +jboot.gateway.bbb.name = name +jboot.gateway.bbb.uri = http://youdomain:8080 +jboot.gateway.bbb.enable = true +jboot.gateway.bbb.sentinelEnable = false +jboot.gateway.bbb.sentinelBlockPage = /block +jboot.gateway.bbb.proxyReadTimeout = 10000 +jboot.gateway.bbb.proxyConnectTimeout = 5000 +jboot.gateway.bbb.proxyContentType = text/html;charset=utf-8 +jboot.gateway.bbb.interceptors = com.xxx.Interceptor1,com.xxx.Interceptor2 +jboot.gateway.bbb.pathEquals = /path +jboot.gateway.bbb.pathContains = /path +jboot.gateway.bbb.pathStartsWith = /path +jboot.gateway.bbb.pathEndswith = /path +jboot.gateway.bbb.hostEquals = xxx.com +jboot.gateway.bbb.hostContains = xxx.com +jboot.gateway.bbb.hostStartsWith = xxx.com +jboot.gateway.bbb.hostEndswith = xxx.com +jboot.gateway.bbb.queryEquals = aa:bb,cc:dd +jboot.gateway.bbb.queryContains = aa,bb + + +jboot.gateway.xxx.name = name +jboot.gateway.xxx.uri = http://youdomain:8080 +jboot.gateway.xxx.enable = true +jboot.gateway.xxx.sentinelEnable = false +jboot.gateway.xxx.sentinelBlockPage = /block +jboot.gateway.xxx.proxyReadTimeout = 10000 +jboot.gateway.xxx.proxyConnectTimeout = 5000 +jboot.gateway.xxx.proxyContentType = text/html;charset=utf-8 +jboot.gateway.xxx.interceptors = com.xxx.Interceptor1,com.xxx.Interceptor2 +jboot.gateway.xxx.pathEquals = /path +jboot.gateway.xxx.pathContains = /path +jboot.gateway.xxx.pathStartsWith = /path +jboot.gateway.xxx.pathEndswith = /path +jboot.gateway.xxx.hostEquals = xxx.com +jboot.gateway.xxx.hostContains = xxx.com +jboot.gateway.xxx.hostStartsWith = xxx.com +jboot.gateway.xxx.hostEndswith = xxx.com +jboot.gateway.xxx.queryEquals = aa:bb,cc:dd +jboot.gateway.xxx.queryContains = aa,bb +``` + ## 其他 当配置中,如果一个内容存在多个值的时候,需要用英文逗号(,)隔开。 @@ -202,4 +271,4 @@ jboot.gateway.pathContains = /user,/article 当 path 中,只要存在 `/user` 或者 存在 `/article` 都会匹配到该路由,比如 `www.xxx.com/user/xxx` 或者 `www.xxx.com/article/xxx` 都会匹配到。 -其他同理。 +其他同理。 \ No newline at end of file -- Gitee From c680514e16081996643f95d4629a198b0a8a7139 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 18:49:39 +0800 Subject: [PATCH 11/29] update rpc docs --- doc/docs/rpc.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/docs/rpc.md b/doc/docs/rpc.md index 1d0f3275..b394a4d9 100644 --- a/doc/docs/rpc.md +++ b/doc/docs/rpc.md @@ -79,6 +79,10 @@ jboot.rpc.type = dubbo jboot.rpc.urls = com.yourdomain.AAAService:127.0.0.1:8080,com.yourdomain.XXXService:127.0.0.1:8080 jboot.rpc.providers = com.yourdomain.AAAService:providerName,com.yourdomain.XXXService:providerName jboot.rpc.consumers = com.yourdomain.AAAService:consumerName,com.yourdomain.XXXService:consumerName +jboot.rpc.defaultVersion = 1.0.0 +jboot.rpc.versions = com.yourdomain.AAAService:version1,com.yourdomain.XXXService:version2 +jboot.rpc.defaultGroup = +jboot.rpc.groups = com.yourdomain.AAAService:version1,com.yourdomain.XXXService:version2 jboot.rpc.autoExportEnable = true ``` @@ -86,6 +90,10 @@ jboot.rpc.autoExportEnable = true - jboot.rpc.urls : 一般不用配置,只有直连模式下才会去配置,此处是配置 Service接口和URL地址的映射关系。 - jboot.rpc.providers : 配置 Service 和 Provider 的映射关系( Motan下配置的是 Service 和 BasicService 的映射关系)。 - jboot.rpc.consumers : 配置 Reference 和 consumer 的映射关系( Motan下配置的是 Referer 和 BaseReferer 的映射关系)。 +- jboot.rpc.defaultVersion : 当service不配置版本时,默认的版本号,默认值为 1.0.0 +- jboot.rpc.versions : 每个服务对应的版本号 +- jboot.rpc.defaultGroup : 当服务不配置 group 时,默认的 gourp +- jboot.rpc.groups : 每个服务对应的 group - jboot.rpc.autoExportEnable : 当 Jboot 启动的时候,是否自动暴露 @RPCBean 注解的接口。 -- Gitee From 8ec65a7f289b44ffe92cd36fdc5fd54a5f06bdee Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 20:22:43 +0800 Subject: [PATCH 12/29] v3.1.5 release (^.^)YYa!! --- changes.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/changes.txt b/changes.txt index 37e45638..cb4498bb 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,16 @@ +jboot v3.1.5: +新增:新增 Motan RPC 的 export 和 host 的相关配置以及test代码 +新增:JbootJson 支持驼峰式 JsonKey 输出,感谢Gitee的 @herowjun +新增:新增 Controller 对返回值自动渲染的功能 +新增:JbootRPCConfig 新增默认 version 和 group 配置的支持 +优化:ClassScanner 添加无需扫码的 jar 排除,速度更快 +修复:ClassScanner 在 Windows 平台下可能存在重复扫码而拖慢启动速度的问题 +修复:门户网关 GatewayHttpProxy 在 POST 时的某些情况下会出现无法正确代理的问题 +文档:完善 RPC 配置的相关文档 +文档:完善 Gateway 配置的相关文档 + + + jboot v3.1.4: 优化:重构 ClassScanner ,提高在 fatjar 模式的扫描性能 优化:重构 ConfigManager ,以便更好的支持 fatjar 模式下的配置文件读取 -- Gitee From 5bdf7fb0bed1bd4cf82a288db7ccd361848b5452 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 20:42:38 +0800 Subject: [PATCH 13/29] add fatjar build docks --- README.md | 2 +- doc/docs/build.md | 111 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8a644d48..56653b10 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ public class HelloworldController extends JbootController { - [事件机制](./doc/docs/event.md) - [SPI扩展机制](./doc/docs/spi.md) - [代码生成器](./doc/docs/codegen.md) -- [项目构建](./doc/docs/build.md) +- [项目打包](./doc/docs/build.md) - [项目部署](./doc/docs/deploy.md) - [Jboot与Docker](./doc/docs/docker.md) - [1.x 升级到 2.x 教程](./doc/docs/upgrade.md) diff --git a/doc/docs/build.md b/doc/docs/build.md index 840323c0..afd0cecb 100644 --- a/doc/docs/build.md +++ b/doc/docs/build.md @@ -1,11 +1,12 @@ -# 项目构建 +# 项目打包 ## 目录 -- 单模块 maven 项目构建 -- 多模块 maven 项目构建 +- 单模块 maven 项目打包 +- 多模块 maven 项目打包 +- fatjar 打包(全部打包到一个jar里) -## 单模块 maven 项目构建 +## 单模块 maven 项目打包 在单一模块的maven项目开发中,我们通常在 `src/main/resources` 编写我们的配置文件,因此,在 maven 构建的时候,我们需要添加如下配置: @@ -175,7 +176,7 @@ fi 复制该文件夹到服务器,然后执行里面的 `jboot.sh start` 命令即可上线。 -## 多模块 maven 项目构建 +## 多模块 maven 项目打包 多模块项目在以上配置的基础上,添加 `maven-resources-plugin` maven 插件,用于拷贝其他maven模块的资源文件和html等内容到此运行模块。 @@ -210,4 +211,102 @@ maven 配置如下: ``` -这部分可以参考 jpress 项目,网址:https://gitee.com/fuhai/jpress/blob/v2.0/starter/pom.xml \ No newline at end of file +这部分可以参考 jpress 项目,网址:https://gitee.com/fuhai/jpress/blob/v2.0/starter/pom.xml + +## fatjar 打包(全部打包到一个jar里) + +fatjar 打包指的是,把所有资源(html、css、js)以及项目依赖全部打包到一个 jar 包里,这样我们可以通过 +命令 `java -jar xxx.jar` 启动,更加方便部署,特别是方便在微服务下的多模块部署。 + +fatjar 打包第一步,在 pom.xml 添加如下配置 + +```xml + + + + src/main/resources + + **/*.* + + false + + + + src/main/webapp + + **/*.* + + false + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + UTF-8 + -parameters + + + + + + maven-resources-plugin + + + copy-resources + validate + + copy-resources + + + ${basedir}/target/classes/webapp + + + ${basedir}/src/main/webapp + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.0 + + + make-assembly + package + + single + + + + + io.jboot.app.JbootApplication + + + + + + jar-with-dependencies + + + + + + + +``` + +第二步:通过 Maven 打包 + +执行命令 `mvn clean package` 进行打包,在 pom.xml 对应的模块下会生成一个 xxx-with-dependencies.jar 的 jar 包,复制该 jar +到服务器上,执行 `java -jar xxx-with-dependencies.jar` 即可启动项目。 \ No newline at end of file -- Gitee From e9453fc170cb2eda2977597257fc4200de8861d6 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 20:57:39 +0800 Subject: [PATCH 14/29] add default group for rpc service --- src/main/java/io/jboot/components/rpc/JbootrpcConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java b/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java index d132fcdc..e3b30916 100644 --- a/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java +++ b/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java @@ -49,7 +49,7 @@ public class JbootrpcConfig { private Map versions; //当不指定的时候,默认分组 - private String defaultGroup; + private String defaultGroup = "jboot"; //指定的服务的分组 private Map groups; -- Gitee From eaee41978335ae657632c472617e03e2ecea2897 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sat, 4 Apr 2020 21:08:31 +0800 Subject: [PATCH 15/29] v3.1.5 release (^.^)YYa!! --- changes.txt | 1 + doc/docs/rpc.md | 4 ++-- src/main/java/io/jboot/components/rpc/JbootrpcConfig.java | 6 +++--- .../java/io/jboot/components/rpc/motan/MotanrpcConfig.java | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/changes.txt b/changes.txt index cb4498bb..761b76aa 100644 --- a/changes.txt +++ b/changes.txt @@ -8,6 +8,7 @@ jboot v3.1.5: 修复:门户网关 GatewayHttpProxy 在 POST 时的某些情况下会出现无法正确代理的问题 文档:完善 RPC 配置的相关文档 文档:完善 Gateway 配置的相关文档 +文档:添加 fatjar 打包的相关文档 diff --git a/doc/docs/rpc.md b/doc/docs/rpc.md index b394a4d9..677456d1 100644 --- a/doc/docs/rpc.md +++ b/doc/docs/rpc.md @@ -80,9 +80,9 @@ jboot.rpc.urls = com.yourdomain.AAAService:127.0.0.1:8080,com.yourdomain.XXXServ jboot.rpc.providers = com.yourdomain.AAAService:providerName,com.yourdomain.XXXService:providerName jboot.rpc.consumers = com.yourdomain.AAAService:consumerName,com.yourdomain.XXXService:consumerName jboot.rpc.defaultVersion = 1.0.0 -jboot.rpc.versions = com.yourdomain.AAAService:version1,com.yourdomain.XXXService:version2 +jboot.rpc.versions = com.yourdomain.AAAService:1.0.0,com.yourdomain.XXXService:1.0.1 jboot.rpc.defaultGroup = -jboot.rpc.groups = com.yourdomain.AAAService:version1,com.yourdomain.XXXService:version2 +jboot.rpc.groups = com.yourdomain.AAAService:group1,com.yourdomain.XXXService:group2 jboot.rpc.autoExportEnable = true ``` diff --git a/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java b/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java index e3b30916..9c340558 100644 --- a/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java +++ b/src/main/java/io/jboot/components/rpc/JbootrpcConfig.java @@ -49,7 +49,7 @@ public class JbootrpcConfig { private Map versions; //当不指定的时候,默认分组 - private String defaultGroup = "jboot"; + private String defaultGroup; //指定的服务的分组 private Map groups; @@ -119,7 +119,7 @@ public class JbootrpcConfig { } public String getVersion(String className) { - String version = versions == null ? null : versions.get(className); + String version = versions == null || versions.isEmpty() ? null : versions.get(className); return version == null ? defaultVersion : version; } @@ -140,7 +140,7 @@ public class JbootrpcConfig { } public String getGroup(String className) { - String group = groups == null ? null : groups.get(className); + String group = groups == null || groups.isEmpty() ? null : groups.get(className); return group == null ? defaultGroup : group; } diff --git a/src/main/java/io/jboot/components/rpc/motan/MotanrpcConfig.java b/src/main/java/io/jboot/components/rpc/motan/MotanrpcConfig.java index 1f96175f..258c8f1f 100644 --- a/src/main/java/io/jboot/components/rpc/motan/MotanrpcConfig.java +++ b/src/main/java/io/jboot/components/rpc/motan/MotanrpcConfig.java @@ -77,7 +77,7 @@ public class MotanrpcConfig { } public String getExport(String className) { - String export = exports == null ? null : exports.get(className); + String export = exports == null || exports.isEmpty() ? null : exports.get(className); return StrUtil.isNotBlank(export) ? export : defaultExport; } @@ -90,7 +90,7 @@ public class MotanrpcConfig { } public String getHost(String className) { - String host = hosts == null ? null : hosts.get(className); + String host = hosts == null || hosts.isEmpty() ? null : hosts.get(className); return StrUtil.isNotBlank(host) ? host : defaultHost; } } -- Gitee From 3c15a54062e423f70fc2ce29bbbde4cb86372f2c Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sun, 5 Apr 2020 08:46:07 +0800 Subject: [PATCH 16/29] v3.1.5 release (^.^)YYa!! --- README.md | 2 +- changes.txt | 1 + doc/docs/deploy.md | 88 ++++++++++++++++++++++++- doc/docs/install.md | 2 +- doc/docs/quickstart.md | 2 +- src/main/java/io/jboot/JbootConsts.java | 2 +- 6 files changed, 92 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 56653b10..f6d8e45b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ io.jboot jboot - 3.1.4 + 3.1.5 ``` diff --git a/changes.txt b/changes.txt index 761b76aa..577f3c8c 100644 --- a/changes.txt +++ b/changes.txt @@ -9,6 +9,7 @@ jboot v3.1.5: 文档:完善 RPC 配置的相关文档 文档:完善 Gateway 配置的相关文档 文档:添加 fatjar 打包的相关文档 +文档:完善 fatjar 部署运行的相关文档 diff --git a/doc/docs/deploy.md b/doc/docs/deploy.md index 6486679f..21a2448c 100644 --- a/doc/docs/deploy.md +++ b/doc/docs/deploy.md @@ -2,15 +2,101 @@ ## 目录 - 描述 +- 通过 脚本 运行 - 通过 Jar 运行 - 通过 Tomcat 运行 ## 描述 +本文档提供了 3 种部署方式,对应 Jboot 里的 3 种[打包方式](./build.md)。 + +## 通过 脚本 运行 + +在 [打包方式](./build.md) 文档中,我们可以把项目打包成一个 .zip 的压缩包项目,里面带有 jboot.sh (和 jboot.bat) 执行脚本, +只需要我们解压 .zip 压缩文件,通过如下命令就可以对 jboot 项目进行启动和停止。 + +```shell script +# 启动 +./jboot.sh start + +# 停止 +./jboot.sh stop + +# 重启 +./jboot.sh restart +``` + +在 Windows 系统中,通过如下命令执行 + +```shell script +# 启动 +jboot.bat start + +# 停止 +jboot.bat stop + +# 重启 +jboot.bat restart +``` ## 通过 Jar 运行 -Jboot 通过依赖 `JFinal-Undertow` 内置了 Undertow 服务器,可以直接通过 Jar 的方式进行运行,这部分直接参考文档:https://www.jfinal.com/doc/1-3 即可。 +在 [打包方式](./build.md) 文档中,我们可以把所有的资源文件(html、css、js、配置文件 等)以及项目的所有依赖打包到一个 jar 包 +里去,打包成功后,可以通过如下命令运行。 + +启动(前台启动,命令窗口不能关闭) +```shell script +java -jar xxx.jar +``` +> 当前ssh窗口(命令窗口)被锁定,可按 `CTRL + C` 打断程序运行,或直接关闭窗口,程序退出。 + +启动(后台启动,命令窗口不能关闭) +```shell script +java -jar xxx.jar & +``` +> & 代表在后台运行。当前ssh窗口不被锁定,但是当窗口关闭时,程序中止运行。 + + +启动(后台启动) +```shell script +nohup java -jar xxx.jar & +``` +>nohup 意思是不挂断运行命令,当账户退出或终端关闭时,程序仍然运行,当用 nohup 命令执行作业时,缺省情况下该作业的所有输出被重定向到nohup.out的文件中,除非另外指定了输出文件。 + +启动(后台启动) +```shell script +nohup java -jar xxx.jar>temp.txt & +``` +>command >out.file 是将 command 的输出重定向到 out.file 文件,即输出内容不打印到屏幕上,而是输出到 out.file 文件中。 +>以上命令,就是把 java 启动的输出,输入到 temp.txt 文件里,而不是在屏幕上。 + + +另外:可以通过如下命令实时查看日志: + +```shell script +tail -f temp.text +``` + +可通过jobs命令查看后台运行任务 + +```shell script +jobs +``` + +jobs 命令就会列出所有后台执行的作业,并且每个作业前面都有个编号。如果想将某个作业调回前台控制,只需要 fg + 编号即可。 + +```shell script +fg 33 +``` + +查看程序端口的进程的pid + +```shell script +netstat -nlp | grep:8080 +``` + + + ## 通过 Tomcat 运行 diff --git a/doc/docs/install.md b/doc/docs/install.md index aa964ced..04152d49 100644 --- a/doc/docs/install.md +++ b/doc/docs/install.md @@ -9,7 +9,7 @@ io.jboot jboot - 3.1.4 + 3.1.5 ``` diff --git a/doc/docs/quickstart.md b/doc/docs/quickstart.md index 82fb65b7..603ec045 100644 --- a/doc/docs/quickstart.md +++ b/doc/docs/quickstart.md @@ -28,7 +28,7 @@ io.jboot jboot - 3.1.4 + 3.1.5 ``` diff --git a/src/main/java/io/jboot/JbootConsts.java b/src/main/java/io/jboot/JbootConsts.java index 28a9284b..7d120266 100644 --- a/src/main/java/io/jboot/JbootConsts.java +++ b/src/main/java/io/jboot/JbootConsts.java @@ -22,7 +22,7 @@ package io.jboot; */ public class JbootConsts { - public static String VERSION = "3.1.4"; + public static String VERSION = "3.1.5"; public static final String ATTR_REQUEST = "REQUEST"; -- Gitee From cf6d6099df369f0a269b16b5c93af7972c1f4959 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Sun, 5 Apr 2020 09:00:29 +0800 Subject: [PATCH 17/29] v3.1.5 release (^.^)YYa!! --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 176a2ff2..153cfae9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.jboot jboot - 3.1.5-SNAPSHOT + 3.1.5 jar jboot -- Gitee From 32bda08afd5ae8b019bb77eddb3a318e910425f6 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 14:21:54 +0800 Subject: [PATCH 18/29] v3.1.6 snapshot --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 153cfae9..b72cb4c1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.jboot jboot - 3.1.5 + 3.1.6-SNAPSHOT jar jboot -- Gitee From 65e6b745e2124599c937f37a28d8e1653a604b24 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 15:26:25 +0800 Subject: [PATCH 19/29] optimize JbootReturnValueRender --- .../jboot/web/handler/JbootActionHandler.java | 2 +- .../web/render/JbootReturnValueRender.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/jboot/web/handler/JbootActionHandler.java b/src/main/java/io/jboot/web/handler/JbootActionHandler.java index c5a0a4df..114861e8 100644 --- a/src/main/java/io/jboot/web/handler/JbootActionHandler.java +++ b/src/main/java/io/jboot/web/handler/JbootActionHandler.java @@ -120,7 +120,7 @@ public class JbootActionHandler extends ActionHandler { } if (render == null - && invocation.getReturnValue() != null + && void.class != action.getMethod().getReturnType() && renderManager.getRenderFactory() instanceof JbootRenderFactory) { JbootRenderFactory jrf = (JbootRenderFactory) renderManager.getRenderFactory(); render = jrf.getReturnValueRender(action, invocation.getReturnValue()); diff --git a/src/main/java/io/jboot/web/render/JbootReturnValueRender.java b/src/main/java/io/jboot/web/render/JbootReturnValueRender.java index caab4d13..d95d9635 100644 --- a/src/main/java/io/jboot/web/render/JbootReturnValueRender.java +++ b/src/main/java/io/jboot/web/render/JbootReturnValueRender.java @@ -17,10 +17,7 @@ package io.jboot.web.render; import com.jfinal.core.Action; import com.jfinal.kit.JsonKit; -import com.jfinal.render.FileRender; -import com.jfinal.render.JsonRender; -import com.jfinal.render.Render; -import com.jfinal.render.TextRender; +import com.jfinal.render.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -42,14 +39,20 @@ public class JbootReturnValueRender extends Render { private Render render; public JbootReturnValueRender(Action action, Object returnValue) { + this.action = action; - if (isBaseType(returnValue)) { + + if (returnValue == null) { + this.value = null; + } else if (isBaseType(returnValue)) { this.value = String.valueOf(returnValue); } else { this.value = returnValue; } - if (this.value instanceof File) { + if (this.value == null) { + this.render = new NullRender(); + } else if (this.value instanceof File) { this.render = new FileRender((File) value); } else if (this.value instanceof String) { this.render = new TextRender((String) value); @@ -80,9 +83,6 @@ public class JbootReturnValueRender extends Render { private boolean isBaseType(Object value) { - if (value == null) { - return true; - } Class c = value.getClass(); return c == String.class || c == char.class || c == Integer.class || c == int.class -- Gitee From abf3000f9c5159eaee229de65b7d40848f049bdd Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 15:31:55 +0800 Subject: [PATCH 20/29] optimize JbootGatewayConfig --- .../gateway/JbootGatewayConfig.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/jboot/components/gateway/JbootGatewayConfig.java b/src/main/java/io/jboot/components/gateway/JbootGatewayConfig.java index 048dfc7c..6b89656c 100644 --- a/src/main/java/io/jboot/components/gateway/JbootGatewayConfig.java +++ b/src/main/java/io/jboot/components/gateway/JbootGatewayConfig.java @@ -15,6 +15,7 @@ */ package io.jboot.components.gateway; +import io.jboot.exception.JbootIllegalConfigException; import io.jboot.utils.ClassUtil; import io.jboot.utils.StrUtil; @@ -233,6 +234,7 @@ public class JbootGatewayConfig implements Serializable { private GatewayInterceptor[] inters; + public GatewayInterceptor[] getInters() { if (interceptors == null || interceptors.length == 0) { return null; @@ -255,8 +257,28 @@ public class JbootGatewayConfig implements Serializable { } + private Boolean configOk = null; + public boolean isConfigOk() { - return StrUtil.isNotBlank(uri); + if (configOk != null) { + return configOk; + } + synchronized (this) { + if (configOk == null) { + configOk = StrUtil.isNotBlank(uri); + if (configOk) { + ensureUriPatterCorrect(); + } + } + } + return configOk; + } + + private void ensureUriPatterCorrect() { + if (!uri.toLowerCase().startsWith("http://") + && !uri.toLowerCase().startsWith("https://")) { + throw new JbootIllegalConfigException("gateway uri must start with http:// or https://"); + } } -- Gitee From caaff17d0ce3cf9e21ba211e25b110782f9e45c2 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 15:32:20 +0800 Subject: [PATCH 21/29] add gateway test code --- .../jboot/test/gateway/GatewayController.java | 26 +++++++++++++++++++ src/test/resources/jboot.properties | 6 ++--- 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 src/test/java/io/jboot/test/gateway/GatewayController.java diff --git a/src/test/java/io/jboot/test/gateway/GatewayController.java b/src/test/java/io/jboot/test/gateway/GatewayController.java new file mode 100644 index 00000000..7cca21d8 --- /dev/null +++ b/src/test/java/io/jboot/test/gateway/GatewayController.java @@ -0,0 +1,26 @@ +package io.jboot.test.gateway; + +import io.jboot.web.controller.JbootController; +import io.jboot.web.controller.annotation.RequestMapping; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/4/5 + */ +@RequestMapping("/gateway") +public class GatewayController extends JbootController { + + public void index(){ + + } + + + public void render(){ + Map map = new HashMap(); + map.putAll(getParas()); + renderJson(map); + } +} diff --git a/src/test/resources/jboot.properties b/src/test/resources/jboot.properties index d285e323..f391de5e 100644 --- a/src/test/resources/jboot.properties +++ b/src/test/resources/jboot.properties @@ -37,10 +37,10 @@ config.test.test.ccc.name = name3 config.test.test.ccc.type = type3 -# 配置 gateway ,访问首页的时候目标地址设置为 baidu 的地址 +# 配置 gateway ,当访问 /gateway 的时候,自动路由到 /gateway/render jboot.gateway.enable = true -jboot.gateway.uri = https://www.baidu.com -jboot.gateway.pathEquals = / +jboot.gateway.uri = http://127.0.0.1:9999/gateway/render +jboot.gateway.pathEquals = /gateway -- Gitee From ba81fdee9a4e025512788856bbc1978105665366 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 16:55:33 +0800 Subject: [PATCH 22/29] upgrade dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b72cb4c1..b412af37 100644 --- a/pom.xml +++ b/pom.xml @@ -66,10 +66,10 @@ 4.4.13 4.1.48.Final 1.7.1 - 2.7.5 + 2.7.6 3.11.0.Final 1.1.0 - 1.1.7 + 1.1.8 4.1.5 1.8 -- Gitee From 07e07f0ae1aed55481de3ab5294eb15d47a91696 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 16:59:31 +0800 Subject: [PATCH 23/29] upgrade dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b412af37..282ffdd2 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.13.1 2.10.6 2.8.1 - 3.9 + 3.10 2.6 1.14 4.5.12 @@ -275,7 +275,7 @@ com.alibaba.nacos nacos-client - 1.2.0 + 1.2.1 provided -- Gitee From 37bf6d20f522b93a01e09122d717ff68a783e65d Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 18:18:57 +0800 Subject: [PATCH 24/29] fixed aop docs error --- doc/docs/aop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/docs/aop.md b/doc/docs/aop.md index ec0c8868..0ec52a65 100644 --- a/doc/docs/aop.md +++ b/doc/docs/aop.md @@ -216,7 +216,7 @@ public class AppConfiguration { ``` -这样,在一个 Jboot 应用中,就会存在两份 `CommentService` 他们的名称分别为:myCommentServiceFromConfiguration 和 myCommentService2(当只用了注解 @Bean 但是为添加 name 参数时,名称为方法名) +这样,在一个 Jboot 应用中,就会存在两份 `CommentService` 他们的名称分别为:myCommentServiceFromConfiguration 和 myCommentService2(当只用了注解 @Bean 但是未添加 name 参数时,name 的值为方法的名称) 这样,我们就可以在 Controller 里,通过 `@Inject` 配合 `@Bean(name = ... )` 进行注入,例如: -- Gitee From 67e88a98776dc12228f8d01927c5fe1fef097c5f Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Mon, 6 Apr 2020 18:22:51 +0800 Subject: [PATCH 25/29] add ResponseEntity support --- src/main/java/io/jboot/web/HttpStatus.java | 423 ++++++++++++++++++ .../java/io/jboot/web/ResponseEntity.java | 105 +++++ .../web/render/JbootReturnValueRender.java | 9 +- 3 files changed, 535 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/jboot/web/HttpStatus.java create mode 100644 src/main/java/io/jboot/web/ResponseEntity.java diff --git a/src/main/java/io/jboot/web/HttpStatus.java b/src/main/java/io/jboot/web/HttpStatus.java new file mode 100644 index 00000000..e1e8833c --- /dev/null +++ b/src/main/java/io/jboot/web/HttpStatus.java @@ -0,0 +1,423 @@ +/** + * Copyright (c) 2015-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jboot.web; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/4/6 + */ +public enum HttpStatus { + + /** + * {@code 100 Continue}. + * @see HTTP/1.1: Semantics and Content, section 6.2.1 + */ + CONTINUE(100, "Continue"), + /** + * {@code 101 Switching Protocols}. + * @see HTTP/1.1: Semantics and Content, section 6.2.2 + */ + SWITCHING_PROTOCOLS(101, "Switching Protocols"), + /** + * {@code 102 Processing}. + * @see WebDAV + */ + PROCESSING(102, "Processing"), + /** + * {@code 103 Checkpoint}. + * @see A proposal for supporting + * resumable POST/PUT HTTP requests in HTTP/1.0 + */ + CHECKPOINT(103, "Checkpoint"), + + // 2xx Success + + /** + * {@code 200 OK}. + * @see HTTP/1.1: Semantics and Content, section 6.3.1 + */ + OK(200, "OK"), + /** + * {@code 201 Created}. + * @see HTTP/1.1: Semantics and Content, section 6.3.2 + */ + CREATED(201, "Created"), + /** + * {@code 202 Accepted}. + * @see HTTP/1.1: Semantics and Content, section 6.3.3 + */ + ACCEPTED(202, "Accepted"), + /** + * {@code 203 Non-Authoritative Information}. + * @see HTTP/1.1: Semantics and Content, section 6.3.4 + */ + NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"), + /** + * {@code 204 No Content}. + * @see HTTP/1.1: Semantics and Content, section 6.3.5 + */ + NO_CONTENT(204, "No Content"), + /** + * {@code 205 Reset Content}. + * @see HTTP/1.1: Semantics and Content, section 6.3.6 + */ + RESET_CONTENT(205, "Reset Content"), + /** + * {@code 206 Partial Content}. + * @see HTTP/1.1: Range Requests, section 4.1 + */ + PARTIAL_CONTENT(206, "Partial Content"), + /** + * {@code 207 Multi-Status}. + * @see WebDAV + */ + MULTI_STATUS(207, "Multi-Status"), + /** + * {@code 208 Already Reported}. + * @see WebDAV Binding Extensions + */ + ALREADY_REPORTED(208, "Already Reported"), + /** + * {@code 226 IM Used}. + * @see Delta encoding in HTTP + */ + IM_USED(226, "IM Used"), + + // 3xx Redirection + + /** + * {@code 300 Multiple Choices}. + * @see HTTP/1.1: Semantics and Content, section 6.4.1 + */ + MULTIPLE_CHOICES(300, "Multiple Choices"), + /** + * {@code 301 Moved Permanently}. + * @see HTTP/1.1: Semantics and Content, section 6.4.2 + */ + MOVED_PERMANENTLY(301, "Moved Permanently"), + /** + * {@code 302 Found}. + * @see HTTP/1.1: Semantics and Content, section 6.4.3 + */ + FOUND(302, "Found"), + /** + * {@code 302 Moved Temporarily}. + * @see HTTP/1.0, section 9.3 + * @deprecated in favor of {@link #FOUND} which will be returned from {@code HttpStatus.valueOf(302)} + */ + @Deprecated + MOVED_TEMPORARILY(302, "Moved Temporarily"), + /** + * {@code 303 See Other}. + * @see HTTP/1.1: Semantics and Content, section 6.4.4 + */ + SEE_OTHER(303, "See Other"), + /** + * {@code 304 Not Modified}. + * @see HTTP/1.1: Conditional Requests, section 4.1 + */ + NOT_MODIFIED(304, "Not Modified"), + /** + * {@code 305 Use Proxy}. + * @see HTTP/1.1: Semantics and Content, section 6.4.5 + * @deprecated due to security concerns regarding in-band configuration of a proxy + */ + @Deprecated + USE_PROXY(305, "Use Proxy"), + /** + * {@code 307 Temporary Redirect}. + * @see HTTP/1.1: Semantics and Content, section 6.4.7 + */ + TEMPORARY_REDIRECT(307, "Temporary Redirect"), + /** + * {@code 308 Permanent Redirect}. + * @see RFC 7238 + */ + PERMANENT_REDIRECT(308, "Permanent Redirect"), + + // --- 4xx Client Error --- + + /** + * {@code 400 Bad Request}. + * @see HTTP/1.1: Semantics and Content, section 6.5.1 + */ + BAD_REQUEST(400, "Bad Request"), + /** + * {@code 401 Unauthorized}. + * @see HTTP/1.1: Authentication, section 3.1 + */ + UNAUTHORIZED(401, "Unauthorized"), + /** + * {@code 402 Payment Required}. + * @see HTTP/1.1: Semantics and Content, section 6.5.2 + */ + PAYMENT_REQUIRED(402, "Payment Required"), + /** + * {@code 403 Forbidden}. + * @see HTTP/1.1: Semantics and Content, section 6.5.3 + */ + FORBIDDEN(403, "Forbidden"), + /** + * {@code 404 Not Found}. + * @see HTTP/1.1: Semantics and Content, section 6.5.4 + */ + NOT_FOUND(404, "Not Found"), + /** + * {@code 405 Method Not Allowed}. + * @see HTTP/1.1: Semantics and Content, section 6.5.5 + */ + METHOD_NOT_ALLOWED(405, "Method Not Allowed"), + /** + * {@code 406 Not Acceptable}. + * @see HTTP/1.1: Semantics and Content, section 6.5.6 + */ + NOT_ACCEPTABLE(406, "Not Acceptable"), + /** + * {@code 407 Proxy Authentication Required}. + * @see HTTP/1.1: Authentication, section 3.2 + */ + PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required"), + /** + * {@code 408 Request Timeout}. + * @see HTTP/1.1: Semantics and Content, section 6.5.7 + */ + REQUEST_TIMEOUT(408, "Request Timeout"), + /** + * {@code 409 Conflict}. + * @see HTTP/1.1: Semantics and Content, section 6.5.8 + */ + CONFLICT(409, "Conflict"), + /** + * {@code 410 Gone}. + * @see + * HTTP/1.1: Semantics and Content, section 6.5.9 + */ + GONE(410, "Gone"), + /** + * {@code 411 Length Required}. + * @see + * HTTP/1.1: Semantics and Content, section 6.5.10 + */ + LENGTH_REQUIRED(411, "Length Required"), + /** + * {@code 412 Precondition failed}. + * @see + * HTTP/1.1: Conditional Requests, section 4.2 + */ + PRECONDITION_FAILED(412, "Precondition Failed"), + /** + * {@code 413 Payload Too Large}. + * @since 4.1 + * @see + * HTTP/1.1: Semantics and Content, section 6.5.11 + */ + PAYLOAD_TOO_LARGE(413, "Payload Too Large"), + /** + * {@code 413 Request Entity Too Large}. + * @see HTTP/1.1, section 10.4.14 + * @deprecated in favor of {@link #PAYLOAD_TOO_LARGE} which will be + * returned from {@code HttpStatus.valueOf(413)} + */ + @Deprecated + REQUEST_ENTITY_TOO_LARGE(413, "Request Entity Too Large"), + /** + * {@code 414 URI Too Long}. + * @since 4.1 + * @see + * HTTP/1.1: Semantics and Content, section 6.5.12 + */ + URI_TOO_LONG(414, "URI Too Long"), + /** + * {@code 414 Request-URI Too Long}. + * @see HTTP/1.1, section 10.4.15 + * @deprecated in favor of {@link #URI_TOO_LONG} which will be returned from {@code HttpStatus.valueOf(414)} + */ + @Deprecated + REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"), + /** + * {@code 415 Unsupported Media Type}. + * @see + * HTTP/1.1: Semantics and Content, section 6.5.13 + */ + UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"), + /** + * {@code 416 Requested Range Not Satisfiable}. + * @see HTTP/1.1: Range Requests, section 4.4 + */ + REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested range not satisfiable"), + /** + * {@code 417 Expectation Failed}. + * @see + * HTTP/1.1: Semantics and Content, section 6.5.14 + */ + EXPECTATION_FAILED(417, "Expectation Failed"), + /** + * {@code 418 I'm a teapot}. + * @see HTCPCP/1.0 + */ + I_AM_A_TEAPOT(418, "I'm a teapot"), + /** + * @deprecated See + * + * WebDAV Draft Changes + */ + @Deprecated + INSUFFICIENT_SPACE_ON_RESOURCE(419, "Insufficient Space On Resource"), + /** + * @deprecated See + * + * WebDAV Draft Changes + */ + @Deprecated + METHOD_FAILURE(420, "Method Failure"), + /** + * @deprecated + * See + * WebDAV Draft Changes + */ + @Deprecated + DESTINATION_LOCKED(421, "Destination Locked"), + /** + * {@code 422 Unprocessable Entity}. + * @see WebDAV + */ + UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"), + /** + * {@code 423 Locked}. + * @see WebDAV + */ + LOCKED(423, "Locked"), + /** + * {@code 424 Failed Dependency}. + * @see WebDAV + */ + FAILED_DEPENDENCY(424, "Failed Dependency"), + /** + * {@code 426 Upgrade Required}. + * @see Upgrading to TLS Within HTTP/1.1 + */ + UPGRADE_REQUIRED(426, "Upgrade Required"), + /** + * {@code 428 Precondition Required}. + * @see Additional HTTP Status Codes + */ + PRECONDITION_REQUIRED(428, "Precondition Required"), + /** + * {@code 429 Too Many Requests}. + * @see Additional HTTP Status Codes + */ + TOO_MANY_REQUESTS(429, "Too Many Requests"), + /** + * {@code 431 Request Header Fields Too Large}. + * @see Additional HTTP Status Codes + */ + REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large"), + /** + * {@code 451 Unavailable For Legal Reasons}. + * @see + * An HTTP Status Code to Report Legal Obstacles + * @since 4.3 + */ + UNAVAILABLE_FOR_LEGAL_REASONS(451, "Unavailable For Legal Reasons"), + + // --- 5xx Server Error --- + + /** + * {@code 500 Internal Server Error}. + * @see HTTP/1.1: Semantics and Content, section 6.6.1 + */ + INTERNAL_SERVER_ERROR(500, "Internal Server Error"), + /** + * {@code 501 Not Implemented}. + * @see HTTP/1.1: Semantics and Content, section 6.6.2 + */ + NOT_IMPLEMENTED(501, "Not Implemented"), + /** + * {@code 502 Bad Gateway}. + * @see HTTP/1.1: Semantics and Content, section 6.6.3 + */ + BAD_GATEWAY(502, "Bad Gateway"), + /** + * {@code 503 Service Unavailable}. + * @see HTTP/1.1: Semantics and Content, section 6.6.4 + */ + SERVICE_UNAVAILABLE(503, "Service Unavailable"), + /** + * {@code 504 Gateway Timeout}. + * @see HTTP/1.1: Semantics and Content, section 6.6.5 + */ + GATEWAY_TIMEOUT(504, "Gateway Timeout"), + /** + * {@code 505 HTTP Version Not Supported}. + * @see HTTP/1.1: Semantics and Content, section 6.6.6 + */ + HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version not supported"), + /** + * {@code 506 Variant Also Negotiates} + * @see Transparent Content Negotiation + */ + VARIANT_ALSO_NEGOTIATES(506, "Variant Also Negotiates"), + /** + * {@code 507 Insufficient Storage} + * @see WebDAV + */ + INSUFFICIENT_STORAGE(507, "Insufficient Storage"), + /** + * {@code 508 Loop Detected} + * @see WebDAV Binding Extensions + */ + LOOP_DETECTED(508, "Loop Detected"), + /** + * {@code 509 Bandwidth Limit Exceeded} + */ + BANDWIDTH_LIMIT_EXCEEDED(509, "Bandwidth Limit Exceeded"), + /** + * {@code 510 Not Extended} + * @see HTTP Extension Framework + */ + NOT_EXTENDED(510, "Not Extended"), + /** + * {@code 511 Network Authentication Required}. + * @see Additional HTTP Status Codes + */ + NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required"); + + + private final int value; + + private final String reasonPhrase; + + + HttpStatus(int value, String reasonPhrase) { + this.value = value; + this.reasonPhrase = reasonPhrase; + } + + + /** + * Return the integer value of this status code. + */ + public int value() { + return this.value; + } + + /** + * Return the reason phrase of this status code. + */ + public String getReasonPhrase() { + return this.reasonPhrase; + } +} diff --git a/src/main/java/io/jboot/web/ResponseEntity.java b/src/main/java/io/jboot/web/ResponseEntity.java new file mode 100644 index 00000000..1e9153d3 --- /dev/null +++ b/src/main/java/io/jboot/web/ResponseEntity.java @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2015-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jboot.web; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/4/6 + */ +public class ResponseEntity { + + //响应的数据 + private Object body; + + //自定义响应头部信息 + private Map headers; + + //默认http状态 + private HttpStatus httpStatus = HttpStatus.OK; + + + public ResponseEntity() { + } + + public ResponseEntity(Object body) { + this.body = body; + } + + public ResponseEntity(Map headers, HttpStatus httpStatus) { + this.headers = headers; + this.httpStatus = httpStatus; + } + + public ResponseEntity(Object body, Map headers, HttpStatus httpStatus) { + this.body = body; + this.headers = headers; + this.httpStatus = httpStatus; + } + + public ResponseEntity body(Object body) { + this.body = body; + return this; + } + + public ResponseEntity header(String key, String value) { + if (this.headers == null) { + this.headers = new HashMap<>(); + } + this.headers.put(key, value); + return this; + } + + public ResponseEntity status(int status) { + for (HttpStatus httpStatus : HttpStatus.values()) { + if (Objects.equals(httpStatus.value(), status)) { + this.httpStatus = httpStatus; + break; + } + } + return this; + } + + + public ResponseEntity status(HttpStatus status) { + this.httpStatus = status; + return this; + } + + + public T getBody() { + return (T) body; + } + + public Map getHeaders() { + return headers; + } + + public HttpStatus getHttpStatus() { + return httpStatus; + } + + + public static ResponseEntity ok() { + ResponseEntity responseEntity = new ResponseEntity(); + return responseEntity.status(HttpStatus.OK); + } + + +} diff --git a/src/main/java/io/jboot/web/render/JbootReturnValueRender.java b/src/main/java/io/jboot/web/render/JbootReturnValueRender.java index d95d9635..158dbd1a 100644 --- a/src/main/java/io/jboot/web/render/JbootReturnValueRender.java +++ b/src/main/java/io/jboot/web/render/JbootReturnValueRender.java @@ -18,6 +18,7 @@ package io.jboot.web.render; import com.jfinal.core.Action; import com.jfinal.kit.JsonKit; import com.jfinal.render.*; +import io.jboot.web.ResponseEntity; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -52,12 +53,16 @@ public class JbootReturnValueRender extends Render { if (this.value == null) { this.render = new NullRender(); - } else if (this.value instanceof File) { - this.render = new FileRender((File) value); + } else if (this.value instanceof ResponseEntity) { + //render ResponseEntity } else if (this.value instanceof String) { this.render = new TextRender((String) value); } else if (this.value instanceof Date) { this.render = new TextRender(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) value)); + } else if (this.value instanceof File) { + this.render = new FileRender((File) value); + } else if (this.value instanceof Render) { + this.render = (Render) value; } else { this.render = new JsonRender(JsonKit.toJson(value)); } -- Gitee From 634e98eec6543cb953f52e0f422fac3d9a303817 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Tue, 7 Apr 2020 10:10:17 +0800 Subject: [PATCH 26/29] optimize ClassScanner.java --- src/main/java/io/jboot/utils/ClassScanner.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/jboot/utils/ClassScanner.java b/src/main/java/io/jboot/utils/ClassScanner.java index 1fce8cb1..56cb08dd 100644 --- a/src/main/java/io/jboot/utils/ClassScanner.java +++ b/src/main/java/io/jboot/utils/ClassScanner.java @@ -83,6 +83,7 @@ public class ClassScanner { excludeJars.add("commons-cli"); excludeJars.add("commons-math"); excludeJars.add("commons-jxpath"); + excludeJars.add("commons-compress"); excludeJars.add("audience-"); excludeJars.add("hessian-"); excludeJars.add("metrics-"); @@ -214,6 +215,10 @@ public class ClassScanner { excludeJars.add("hutool-"); excludeJars.add("jakarta."); excludeJars.add("protostuff-"); + excludeJars.add("poi-"); + excludeJars.add("easypoi-"); + excludeJars.add("ognl-"); + excludeJars.add("xmlbeans-"); } @@ -256,7 +261,7 @@ public class ClassScanner { addUnscanClass("com.rabbitmq."); addUnscanClass("com.squareup."); addUnscanClass("com.typesafe."); - addUnscanClass("com.weibo."); + addUnscanClass("com.weibo.api.motan."); addUnscanClass("com.zaxxer."); addUnscanClass("com.mysql."); addUnscanClass("org.gjt."); -- Gitee From face4d15e83c29f7f094c3a903febafb78e02070 Mon Sep 17 00:00:00 2001 From: yangfuhai Date: Tue, 7 Apr 2020 10:29:07 +0800 Subject: [PATCH 27/29] add ResponseEntity Render support --- .../web/render/JbootResponseEntityRender.java | 65 +++++++++++++++++++ .../web/render/JbootReturnValueRender.java | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/jboot/web/render/JbootResponseEntityRender.java diff --git a/src/main/java/io/jboot/web/render/JbootResponseEntityRender.java b/src/main/java/io/jboot/web/render/JbootResponseEntityRender.java new file mode 100644 index 00000000..69efd942 --- /dev/null +++ b/src/main/java/io/jboot/web/render/JbootResponseEntityRender.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015-2016, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jboot.web.render; + +import com.jfinal.kit.JsonKit; +import com.jfinal.render.Render; +import com.jfinal.render.RenderException; +import io.jboot.web.ResponseEntity; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Map; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/4/7 + */ +public class JbootResponseEntityRender extends Render { + + private ResponseEntity responseEntity; + + public JbootResponseEntityRender(ResponseEntity responseEntity) { + this.responseEntity = responseEntity; + } + + @Override + public void render() { + + PrintWriter writer = null; + try { + //默认输出 json,但是 responseEntity 可以配置 Header 覆盖这个输出 + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Content-Type", "application/json; charset=utf-8"); + response.setStatus(responseEntity.getHttpStatus().value()); + + Map headers = responseEntity.getHeaders(); + if (headers != null && !headers.isEmpty()) { + for (Map.Entry entry : headers.entrySet()) { + response.setHeader(entry.getKey(), entry.getValue()); + } + } + + String jsonText = responseEntity.getBody() == null ? "" : JsonKit.toJson(responseEntity.getBody()); + writer = response.getWriter(); + writer.write(jsonText); + // writer.flush(); + } catch (IOException e) { + throw new RenderException(e); + } + + } +} diff --git a/src/main/java/io/jboot/web/render/JbootReturnValueRender.java b/src/main/java/io/jboot/web/render/JbootReturnValueRender.java index 158dbd1a..3e923a00 100644 --- a/src/main/java/io/jboot/web/render/JbootReturnValueRender.java +++ b/src/main/java/io/jboot/web/render/JbootReturnValueRender.java @@ -54,7 +54,7 @@ public class JbootReturnValueRender extends Render { if (this.value == null) { this.render = new NullRender(); } else if (this.value instanceof ResponseEntity) { - //render ResponseEntity + this.render = new JbootResponseEntityRender((ResponseEntity) value); } else if (this.value instanceof String) { this.render = new TextRender((String) value); } else if (this.value instanceof Date) { -- Gitee From 96b4c2038c616e56bc906e75574f5fa55a14746d Mon Sep 17 00:00:00 2001 From: yangyao Date: Wed, 8 Apr 2020 00:06:13 +0800 Subject: [PATCH 28/29] =?UTF-8?q?1.=E5=9F=BA=E4=BA=8E=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E7=9A=84master=E5=88=86=E6=94=AF=E4=BB=A3=E7=A0=81=202.?= =?UTF-8?q?=E4=BD=BF=E7=94=A8jboot=E6=9C=AC=E8=BA=AB=E7=9A=84responseEntit?= =?UTF-8?q?y=203.=E4=BD=BF=E7=94=A8jboot=E6=9C=AC=E8=BA=AB=E7=9A=84HttpSta?= =?UTF-8?q?tus=204.=E6=96=B0=E5=A2=9E=E5=B9=B6=E5=AE=8C=E5=96=84=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../restful/JbootRestfulManager.java | 230 ++++++++++++++++++ .../components/restful/RestfulAction.java | 24 ++ .../components/restful/RestfulCallback.java | 21 ++ .../components/restful/RestfulHandler.java | 57 +++++ .../components/restful/RestfulInvocation.java | 56 +++++ .../components/restful/RestfulUtils.java | 229 +++++++++++++++++ .../restful/annotation/DateFormat.java | 19 ++ .../restful/annotation/DeleteMapping.java | 19 ++ .../restful/annotation/GetMapping.java | 16 ++ .../restful/annotation/PathVariable.java | 30 +++ .../restful/annotation/PostMapping.java | 16 ++ .../restful/annotation/PutMapping.java | 19 ++ .../restful/annotation/RequestBody.java | 23 ++ .../restful/annotation/RequestHeader.java | 31 +++ .../restful/annotation/RequestParam.java | 31 +++ .../restful/annotation/ResponseHeader.java | 17 ++ .../restful/annotation/ResponseHeaders.java | 12 + .../restful/annotation/RestController.java | 12 + .../java/io/jboot/core/JbootCoreConfig.java | 31 ++- .../jboot/test/restful/RestfulController.java | 140 +++++++++++ .../io/jboot/test/restful/RestfulService.java | 5 + .../test/restful/RestfulServiceImpl.java | 12 + 22 files changed, 1049 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/jboot/components/restful/JbootRestfulManager.java create mode 100644 src/main/java/io/jboot/components/restful/RestfulAction.java create mode 100644 src/main/java/io/jboot/components/restful/RestfulCallback.java create mode 100644 src/main/java/io/jboot/components/restful/RestfulHandler.java create mode 100644 src/main/java/io/jboot/components/restful/RestfulInvocation.java create mode 100644 src/main/java/io/jboot/components/restful/RestfulUtils.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/DateFormat.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/GetMapping.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/PathVariable.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/PostMapping.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/PutMapping.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/RequestBody.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/RequestHeader.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/RequestParam.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java create mode 100644 src/main/java/io/jboot/components/restful/annotation/RestController.java create mode 100644 src/test/java/io/jboot/test/restful/RestfulController.java create mode 100644 src/test/java/io/jboot/test/restful/RestfulService.java create mode 100644 src/test/java/io/jboot/test/restful/RestfulServiceImpl.java diff --git a/src/main/java/io/jboot/components/restful/JbootRestfulManager.java b/src/main/java/io/jboot/components/restful/JbootRestfulManager.java new file mode 100644 index 00000000..0f8808c2 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/JbootRestfulManager.java @@ -0,0 +1,230 @@ +package io.jboot.components.restful; + +import com.jfinal.aop.Interceptor; +import com.jfinal.aop.InterceptorManager; +import com.jfinal.config.Routes; +import com.jfinal.core.ActionException; +import com.jfinal.core.Controller; +import com.jfinal.core.NotAction; +import com.jfinal.render.RenderManager; +import io.jboot.components.restful.annotation.DeleteMapping; +import io.jboot.components.restful.annotation.GetMapping; +import io.jboot.components.restful.annotation.PostMapping; +import io.jboot.components.restful.annotation.PutMapping; +import io.jboot.utils.StrUtil; +import io.jboot.web.HttpStatus; +import io.jboot.web.controller.annotation.RequestMapping; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JbootRestfulManager { + + public static class Config { + + private boolean mappingSupperClass; + private String baseViewPath; + private Interceptor[] routeInterceptors; + private List routes; + + public Config() { + } + + public Config(boolean mappingSupperClass, String baseViewPath, + Interceptor[] routeInterceptors, List routes) { + this.mappingSupperClass = mappingSupperClass; + this.baseViewPath = baseViewPath; + this.routeInterceptors = routeInterceptors; + this.routes = routes; + } + + public boolean isMappingSupperClass() { + return mappingSupperClass; + } + + public Config setMappingSupperClass(boolean mappingSupperClass) { + this.mappingSupperClass = mappingSupperClass; + return this; + } + + public String getBaseViewPath() { + return baseViewPath; + } + + public Config setBaseViewPath(String baseViewPath) { + this.baseViewPath = baseViewPath; + return this; + } + + public Interceptor[] getRouteInterceptors() { + return routeInterceptors; + } + + public Config setRouteInterceptors(Interceptor[] routeInterceptors) { + this.routeInterceptors = routeInterceptors; + return this; + } + + public List getRoutes() { + return routes; + } + + public Config setRoutes(List routes) { + this.routes = routes; + return this; + } + } + + private static JbootRestfulManager me = new JbootRestfulManager(); + + private Map restfulActions = new HashMap<>(2048, 0.5F); + + protected static final String SLASH = "/"; + + private RenderManager renderManager = RenderManager.me(); + + public static JbootRestfulManager me() { + return me; + } + + public void init(Config config) { + if (config.getRoutes() == null || config.getRoutes().isEmpty()) { + return; + } + InterceptorManager interMan = InterceptorManager.me(); + Class dc; + // 初始化自定义的restful controller + for (Routes.Route route : config.getRoutes()) { + Class controllerClass = route.getControllerClass(); + Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass); + + boolean declaredMethods = config.isMappingSupperClass() + ? controllerClass.getSuperclass() == Controller.class + : true; + + String baseRequestMapping = SLASH; + if (controllerClass.getAnnotation(RequestMapping.class) != null) { + RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class); + if (requestMapping.value().startsWith(SLASH)) { + baseRequestMapping = requestMapping.value(); + } else { + baseRequestMapping = baseRequestMapping + requestMapping.value(); + } + } + + Method[] methods = (declaredMethods ? controllerClass.getDeclaredMethods() : controllerClass.getMethods()); + for (Method method : methods) { + if (declaredMethods) { + if (!Modifier.isPublic(method.getModifiers())) { + continue; + } + } else { + dc = method.getDeclaringClass(); + if (dc == Controller.class || dc == Object.class) { + continue; + } + } + //去除mapping + if (method.getAnnotation(NotAction.class) != null) { + continue; + } + Interceptor[] actionInters = interMan.buildControllerActionInterceptor(config.getRouteInterceptors(), controllerInters, controllerClass, method); + + String actionKey = baseRequestMapping; + + //GET 判断 + GetMapping getMapping = method.getAnnotation(GetMapping.class); + PostMapping postMapping = method.getAnnotation(PostMapping.class); + PutMapping putMapping = method.getAnnotation(PutMapping.class); + DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class); + String requestMethod = "", mappingValue = ""; + if (getMapping != null) { + requestMethod = "GET"; + if (StrUtil.isNotBlank(getMapping.value())) { + mappingValue = getMapping.value(); + } + } else if (postMapping != null) { + requestMethod = "POST"; + if (StrUtil.isNotBlank(postMapping.value())) { + mappingValue = postMapping.value(); + } + } else if (putMapping != null) { + requestMethod = "PUT"; + if (StrUtil.isNotBlank(putMapping.value())) { + mappingValue = putMapping.value(); + } + } else if (deleteMapping != null) { + requestMethod = "DELETE"; + if (StrUtil.isNotBlank(deleteMapping.value())) { + mappingValue = deleteMapping.value(); + } + } else { + //默认为get请求 + requestMethod = "GET"; + mappingValue = SLASH; + } + if (StrUtil.isNotBlank(mappingValue)) { + if (!actionKey.endsWith(SLASH)) { + actionKey = actionKey + SLASH; + } + if (mappingValue.startsWith(SLASH)) { + mappingValue = mappingValue.substring(1); + } + actionKey = actionKey + mappingValue; + } else { + if (actionKey.endsWith(SLASH)) { + actionKey = actionKey.substring(0, actionKey.length() - 1); + } + } + RestfulAction action = new RestfulAction(baseRequestMapping, actionKey, controllerClass, + method, method.getName(), actionInters, route.getFinalViewPath(config.getBaseViewPath()), requestMethod); + String key = requestMethod + ":" + actionKey; + if (restfulActions.put(key, action) != null) { + //已经存在指定的key + throw new RuntimeException(buildMsg(actionKey, controllerClass, method)); + } + } + } + } + + protected String buildMsg(String actionKey, Class controllerClass, Method method) { + StringBuilder sb = new StringBuilder("The action \"") + .append(controllerClass.getName()).append(".") + .append(method.getName()).append("()\" can not be mapped, ") + .append("actionKey \"").append(actionKey).append("\" is already in use."); + + String msg = sb.toString(); + System.err.println("\nException: " + msg); + return msg; + } + + public RestfulAction getRestfulAction(String target, String requestMethod) { + String actionKey = requestMethod + ":" + target; + //先直接获取 + RestfulAction restfulAction = restfulActions.get(actionKey); + if (restfulAction == null) { + String[] paths = target.split(SLASH); + for(Map.Entry entry : restfulActions.entrySet()){ + String _requestMethod = entry.getValue().getRequestMethod(); + String _target = entry.getValue().getActionKey(); + if (target.equals(_target) && !_requestMethod.equals(requestMethod)) { + //请求方法不正确 + throw new ActionException(HttpStatus.METHOD_NOT_ALLOWED.value(), + renderManager.getRenderFactory().getErrorRender(HttpStatus.METHOD_NOT_ALLOWED.value()), + "'" + target + "' is specified as a '" + _requestMethod + "' request. '" + requestMethod + "' requests are not supported"); + } + String[] _paths = entry.getValue().getActionKey().split(SLASH); + if (entry.getValue().getActionKey().startsWith(requestMethod) && + entry.getValue().getActionKey().contains("{") && entry.getValue().getActionKey().contains("}") + && paths.length == _paths.length && RestfulUtils.comparePaths(_paths, paths)) { + restfulAction = entry.getValue(); + break; + } + } + } + return restfulAction; + } +} diff --git a/src/main/java/io/jboot/components/restful/RestfulAction.java b/src/main/java/io/jboot/components/restful/RestfulAction.java new file mode 100644 index 00000000..1178f8c8 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/RestfulAction.java @@ -0,0 +1,24 @@ +package io.jboot.components.restful; + +import com.jfinal.aop.Interceptor; +import com.jfinal.core.Action; +import com.jfinal.core.Controller; + +import java.lang.reflect.Method; + +public class RestfulAction extends Action { + + private String requestMethod; + + public String getRequestMethod() { + return requestMethod; + } + + public RestfulAction(String controllerKey, String actionKey, Class controllerClass, + Method method, String methodName, Interceptor[] interceptors, String viewPath, String requestMethod) { + super(controllerKey, actionKey, controllerClass, method, methodName, interceptors, viewPath); + this.requestMethod = requestMethod; + } + + +} diff --git a/src/main/java/io/jboot/components/restful/RestfulCallback.java b/src/main/java/io/jboot/components/restful/RestfulCallback.java new file mode 100644 index 00000000..00b6bd66 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/RestfulCallback.java @@ -0,0 +1,21 @@ +package io.jboot.components.restful; + +import com.jfinal.core.Action; +import com.jfinal.proxy.Callback; + +public class RestfulCallback implements Callback { + + private Action action; + private Object target; + + public RestfulCallback(Action restfulAction, Object target) { + this.action = restfulAction; + this.target = target; + } + + @Override + public Object call(Object[] args) throws Throwable { + return action.getMethod().invoke(target, args); + } + +} diff --git a/src/main/java/io/jboot/components/restful/RestfulHandler.java b/src/main/java/io/jboot/components/restful/RestfulHandler.java new file mode 100644 index 00000000..50d32965 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/RestfulHandler.java @@ -0,0 +1,57 @@ +package io.jboot.components.restful; + +import com.jfinal.aop.Invocation; +import com.jfinal.core.Action; +import com.jfinal.core.Controller; +import com.jfinal.log.Log; +import io.jboot.components.restful.annotation.ResponseHeader; +import io.jboot.components.restful.annotation.ResponseHeaders; +import io.jboot.utils.ArrayUtil; +import io.jboot.web.handler.JbootActionHandler; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Arrays; + +public class RestfulHandler extends JbootActionHandler { + + private static final Log log = Log.getLog(JbootActionHandler.class); + + @Override + public Action getAction(String target, String[] urlPara, HttpServletRequest request) { + Action action = super.getAction(target, urlPara); + if (action == null) { + action = JbootRestfulManager.me().getRestfulAction(target, request.getMethod()); + } + return action; + } + + @Override + public Invocation getInvocation(Action action, Controller controller) { + if (action instanceof RestfulAction) { + Object[] args = RestfulUtils.parseActionMethodParameters(action.getActionKey(), action.getActionKey(), + action.getMethod(), controller.getRequest(), controller.getRawData()); + return new RestfulInvocation(action, controller, args); + } else { + return super.getInvocation(action, controller); + } + } + + @Override + public void setResponse(HttpServletResponse response, Action action) { + ResponseHeader[] responseHeaders = action.getMethod().getAnnotationsByType(ResponseHeader.class); + ResponseHeaders responseHeadersList = action.getMethod().getAnnotation(ResponseHeaders.class); + if (responseHeadersList != null && responseHeadersList.value().length > 0) { + if (responseHeaders != null && responseHeaders.length > 0) { + responseHeaders = ArrayUtil.concat(responseHeaders, responseHeadersList.value()); + } else { + responseHeaders = responseHeadersList.value(); + } + } + if (responseHeaders.length > 0) { + Arrays.asList(responseHeaders).forEach((ResponseHeader header) -> { + response.setHeader(header.key(), header.value()); + }); + } + } +} diff --git a/src/main/java/io/jboot/components/restful/RestfulInvocation.java b/src/main/java/io/jboot/components/restful/RestfulInvocation.java new file mode 100644 index 00000000..99e16b58 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/RestfulInvocation.java @@ -0,0 +1,56 @@ +package io.jboot.components.restful; + +import com.jfinal.aop.Invocation; +import com.jfinal.core.Action; +import com.jfinal.core.Controller; + +public class RestfulInvocation extends Invocation { + + private Action action; + + public RestfulInvocation(Action action, Controller controller, Object[] args) { + super(controller, action.getMethod(), action.getInterceptors(), new RestfulCallback(action, controller), args); + this.action = action; + } + + + @Override + public Controller getController() { + return super.getTarget(); + } + + /** + * Return the action key. + * actionKey = controllerKey + methodName + */ + @Override + public String getActionKey() { + return action.getActionKey(); + } + + /** + * Return the controller key. + */ + @Override + public String getControllerKey() { + return action.getControllerKey(); + } + + /** + * Return view path of this controller. + */ + @Override + public String getViewPath() { + return action.getViewPath(); + } + + /** + * return true if it is action invocation. + */ + @Override + public boolean isActionInvocation() { + return action != null; + } + + +} diff --git a/src/main/java/io/jboot/components/restful/RestfulUtils.java b/src/main/java/io/jboot/components/restful/RestfulUtils.java new file mode 100644 index 00000000..7fc18ef5 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/RestfulUtils.java @@ -0,0 +1,229 @@ +package io.jboot.components.restful; + + +import com.jfinal.core.ActionException; +import com.jfinal.kit.JsonKit; +import com.jfinal.render.RenderManager; +import io.jboot.components.restful.annotation.*; +import io.jboot.utils.StrUtil; +import io.jboot.web.HttpStatus; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.TimeZone; + +public class RestfulUtils { + + private static final RenderManager renderManager = RenderManager.me(); + + /** + * 从url中解析路径参数 + * + * @param url + * @param actionKey + * @return + */ + public static Map parsePathVariables(String url, String actionKey) { + if (actionKey.contains("{") && actionKey.contains("}")) { + Map pathVariables = new HashMap<>(); + String[] paths = url.split("/"); + String[] _paths = actionKey.split("/"); + for (int i = 0; i < paths.length; i++) { + if (_paths[i].startsWith("{") && _paths[i].endsWith("}")) { + String pathKey = _paths[i].substring(1, _paths[i].length() - 1); + String value = paths[i]; + pathVariables.put(pathKey, value); + } + } + return pathVariables; + } else { + return null; + } + } + + /** + * 转换请求action请求的参数信息 + * + * @param target + * @param actionKey + * @param actionMethod + * @param request + * @param rawData + * @return + * @throws ActionException + */ + public static Object[] parseActionMethodParameters(String target, String actionKey, Method actionMethod, HttpServletRequest request, String rawData) + throws ActionException { + Object[] args = new Object[actionMethod.getParameters().length]; + for (int i = 0; i < actionMethod.getParameters().length; i++) { + Parameter parameter = actionMethod.getParameters()[i]; + RequestParam requestParam = parameter.getAnnotation(RequestParam.class); + RequestBody requestBody = parameter.getAnnotation(RequestBody.class); + RequestHeader requestHeader = parameter.getAnnotation(RequestHeader.class); + PathVariable pathVariable = parameter.getAnnotation(PathVariable.class); + String parameterName = parameter.getName(); + String values[]; + if (requestParam != null) { + if (StrUtil.isNotBlank(requestParam.value())) { + parameterName = requestParam.value(); + } + values = request.getParameterValues(parameterName); + parameter.getType(); + args[i] = parseRequestParamToParameter(values, parameterName, parameter.getType(), parameter); + if (args[i] == null && requestParam.required()) { + //要求参数不为空,但是却并没有提供参数 + throw genBindError("Parameter '" + parameterName + "' specifies a forced check, but the value is null"); + } + } else if (requestBody != null) { + args[i] = parseRequestBodyToParameter(rawData, parameterName, parameter.getType(), parameter); + } else if (requestHeader != null) { + if (StrUtil.isNotBlank(requestHeader.value())) { + parameterName = requestHeader.value(); + } + String value = request.getHeader(parameterName); + args[i] = parseRequestHeaderToParameter(value, parameterName, parameter.getType(), parameter); + if (args[i] == null && requestHeader.required()) { + //要求参数不为空,但是却并没有提供参数 + throw genBindError("Parameter '" + parameterName + "' specifies a forced check, but the value is null"); + } + } else if (pathVariable != null) { + if (StrUtil.isNotBlank(pathVariable.value())) { + parameterName = pathVariable.value(); + } + args[i] = parsePathVariableToParameter(target, actionKey, parameterName, parameter.getType(), parameter); + } else { + args[i] = null; + } + } + return args; + } + + /** + * 比对url请求路径 + * + * @param sourcePaths action配置的原路径 + * @param targetPaths 请求的目标路径 + * @return + */ + public static boolean comparePaths(String[] sourcePaths, String[] targetPaths) { + int matchingCount = 0; + for (int i = 0; i < sourcePaths.length; i++) { + if (sourcePaths[i].equals(targetPaths[i]) + || (sourcePaths[i].startsWith("{") && sourcePaths[i].endsWith("}"))) { + matchingCount += 1; + } + } + return matchingCount == sourcePaths.length; + } + + private static Object parseRequestParamToParameter(String[] value, String name, Class parameterTypeClass, Parameter parameter) { + if (parameterTypeClass.isArray()) { + Object[] objects = new Object[value.length]; + for (int i = 0; i < value.length; i++) { + objects[i] = parseCommonValue(value[i], name, parameterTypeClass, parameter); + } + return objects; + } else { + if (value != null && value.length > 0) { + return parseCommonValue(value[0], name, parameterTypeClass, parameter); + } + } + + return null; + } + + private static Object parseRequestHeaderToParameter(String header, String name, Class parameterTypeClass, Parameter parameter) { + return parseCommonValue(header, name, parameterTypeClass, parameter); + } + + private static Object parseRequestBodyToParameter(String body, String name, Class parameterTypeClass, Parameter parameter) { + //先当作基本数据来转换 + Object value = parseCommonValue(body, name, parameterTypeClass, parameter); + if (value == null) { + value = JsonKit.parse(body, parameterTypeClass); + } + return value; + } + + private static Object parsePathVariableToParameter(String target, String actionKey, String parameterName, Class parameterTypeClass, Parameter parameter) { + Map pathVariables = parsePathVariables(target, actionKey); + String value = pathVariables.get(parameterName); + return parseCommonValue(value, parameterName, parameterTypeClass, parameter); + } + + /** + * 转换基本类型参数,目前支持string,int,double,float,boolean,long基本类型数据 + * + * @param value + * @param name + * @param parameterTypeClass + * @param parameter + * @return + */ + private static Object parseCommonValue(String value, String name, Class parameterTypeClass, Parameter parameter) { + if (StrUtil.isBlank(value)) { + return null; + } + if (parameterTypeClass.equals(String.class)) { + return value; + } else if (parameterTypeClass.equals(int.class) + || parameterTypeClass.equals(double.class) + || parameterTypeClass.equals(float.class) + || parameterTypeClass.equals(long.class) + || parameterTypeClass.equals(BigDecimal.class) + || parameterTypeClass.equals(short.class)) { + try { + if (parameterTypeClass.equals(int.class)) { + return Integer.valueOf(value); + } else if (parameterTypeClass.equals(double.class)) { + return Double.valueOf(value); + } else if (parameterTypeClass.equals(float.class)) { + return Float.valueOf(value); + } else if (parameterTypeClass.equals(long.class)) { + return Long.valueOf(value); + } else if (parameterTypeClass.equals(BigDecimal.class)) { + return new BigDecimal(value); + } else if (parameterTypeClass.equals(short.class)) { + return Short.valueOf(value); + } else { + return null; + } + } catch (NumberFormatException e) { + throw genBindError("Error resolving parameter '" + name + "', unable to match value '" + + value + "' to specified type '" + parameterTypeClass.getName() + "'"); + } + } else if (parameterTypeClass.equals(boolean.class)) { + return Boolean.valueOf(value); + } else if (parameterTypeClass.equals(Date.class)) { + DateFormat dateFormat = parameter.getAnnotation(DateFormat.class); + SimpleDateFormat simpleDateFormat; + if (dateFormat != null) { + simpleDateFormat = new SimpleDateFormat(dateFormat.value()); + simpleDateFormat.setTimeZone(TimeZone.getTimeZone(dateFormat.timeZone())); + } else { + simpleDateFormat = new SimpleDateFormat(); + } + try { + return simpleDateFormat.parse(value); + } catch (ParseException e) { + throw genBindError("Error resolving parameter '" + name + "', unable to match value '" + + value + "' to specified type '" + parameterTypeClass.getName() + "'"); + } + } else { + return null; + } + } + + private static ActionException genBindError(String message) { + return new ActionException(HttpStatus.BAD_REQUEST.value(), + renderManager.getRenderFactory().getErrorRender(HttpStatus.BAD_REQUEST.value()), message); + } + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/DateFormat.java b/src/main/java/io/jboot/components/restful/annotation/DateFormat.java new file mode 100644 index 00000000..b8939ecf --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/DateFormat.java @@ -0,0 +1,19 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * + * 日期注解,可以结合@PathVarible,@RequestParam,@RequestHeader一起使用 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface DateFormat { + + String value() default "yyyy-MM-dd HH:mm:ss"; + + String timeZone() default "GMT+8"; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java b/src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java new file mode 100644 index 00000000..2483f1c3 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/DeleteMapping.java @@ -0,0 +1,19 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * 删除delete 方法注解 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface DeleteMapping { + + /** + * url mapping + * @return + */ + String value() default ""; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/GetMapping.java b/src/main/java/io/jboot/components/restful/annotation/GetMapping.java new file mode 100644 index 00000000..c571a745 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/GetMapping.java @@ -0,0 +1,16 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface GetMapping { + + /** + * url mapping + * @return + */ + String value() default ""; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/PathVariable.java b/src/main/java/io/jboot/components/restful/annotation/PathVariable.java new file mode 100644 index 00000000..4d0c04c4 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/PathVariable.java @@ -0,0 +1,30 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * 路径参数注解 + * /user/{id}/cards + * 支持如下类型参数注入: + * string + * int + * double + * float + * boolean + * long + * bigDecimal + * date + * short + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface PathVariable { + + /** + * 如果为空则默认为参数名本身 + * @return + */ + String value() default ""; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/PostMapping.java b/src/main/java/io/jboot/components/restful/annotation/PostMapping.java new file mode 100644 index 00000000..e0f9a45a --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/PostMapping.java @@ -0,0 +1,16 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface PostMapping { + + /** + * url mapping + * @return + */ + String value() default ""; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/PutMapping.java b/src/main/java/io/jboot/components/restful/annotation/PutMapping.java new file mode 100644 index 00000000..8d0c66d2 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/PutMapping.java @@ -0,0 +1,19 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * Put 请求方法定义 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface PutMapping { + + /** + * url mapping + * @return + */ + String value() default ""; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/RequestBody.java b/src/main/java/io/jboot/components/restful/annotation/RequestBody.java new file mode 100644 index 00000000..ae2d8826 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/RequestBody.java @@ -0,0 +1,23 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * 请求体参数注解 + * 支持如下类型参数: + * string + * int + * double + * float + * boolean + * long + * object + * bigDecimal + * date + * short + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface RequestBody { +} diff --git a/src/main/java/io/jboot/components/restful/annotation/RequestHeader.java b/src/main/java/io/jboot/components/restful/annotation/RequestHeader.java new file mode 100644 index 00000000..9a9c361c --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/RequestHeader.java @@ -0,0 +1,31 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * 请求头部信息注解 + * 支持如下类型参数注入: + * string + * int + * double + * float + * boolean + * long + * bigDecimal + * date + * short + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface RequestHeader { + + /** + * 如果为空则默认为参数名本身 + * @return + */ + String value() default ""; + + boolean required() default false; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/RequestParam.java b/src/main/java/io/jboot/components/restful/annotation/RequestParam.java new file mode 100644 index 00000000..906af564 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/RequestParam.java @@ -0,0 +1,31 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * 请求参数注解 + * 支持如下类型参数: + * string / string[] + * int / int[] + * double / double[] + * float / float[] + * boolean / boolean[] + * long / long[] + * bigDecimal / bigDecimal[] + * date / date[] + * short / short[] + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface RequestParam { + + /** + * 如果为空则默认为参数名本身 + * @return + */ + String value() default ""; + + boolean required() default false; + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java b/src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java new file mode 100644 index 00000000..626f22bf --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/ResponseHeader.java @@ -0,0 +1,17 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * 自定义响应头 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface ResponseHeader { + + String key(); + + String value(); + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java b/src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java new file mode 100644 index 00000000..d51f43ae --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/ResponseHeaders.java @@ -0,0 +1,12 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface ResponseHeaders { + + ResponseHeader[] value(); + +} diff --git a/src/main/java/io/jboot/components/restful/annotation/RestController.java b/src/main/java/io/jboot/components/restful/annotation/RestController.java new file mode 100644 index 00000000..6650c476 --- /dev/null +++ b/src/main/java/io/jboot/components/restful/annotation/RestController.java @@ -0,0 +1,12 @@ +package io.jboot.components.restful.annotation; + +import java.lang.annotation.*; + +/** + * rest controller 标识 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface RestController { +} diff --git a/src/main/java/io/jboot/core/JbootCoreConfig.java b/src/main/java/io/jboot/core/JbootCoreConfig.java index 204d9dde..201fa77a 100644 --- a/src/main/java/io/jboot/core/JbootCoreConfig.java +++ b/src/main/java/io/jboot/core/JbootCoreConfig.java @@ -36,6 +36,9 @@ import io.jboot.app.config.support.nacos.NacosConfigManager; import io.jboot.components.gateway.JbootGatewayHandler; import io.jboot.components.gateway.JbootGatewayManager; import io.jboot.components.limiter.LimiterManager; +import io.jboot.components.restful.JbootRestfulManager; +import io.jboot.components.restful.RestfulHandler; +import io.jboot.components.restful.annotation.RestController; import io.jboot.components.rpc.JbootrpcManager; import io.jboot.components.schedule.JbootScheduleManager; import io.jboot.core.listener.JbootAppListenerManager; @@ -73,7 +76,9 @@ import java.util.Properties; public class JbootCoreConfig extends JFinalConfig { private List routeList = new ArrayList<>(); + private List restfulRoutes = new ArrayList<>(); + private JbootRestfulManager.Config restfulConfig = new JbootRestfulManager.Config(); public JbootCoreConfig() { @@ -173,6 +178,13 @@ public class JbootCoreConfig extends JFinalConfig { continue; } + //检查是否是restful类型的controller,如果是则加入restful专门指定的routes + RestController restController = clazz.getAnnotation(RestController.class); + if (restController != null) { + restfulRoutes.add(new Routes.Route(value, clazz, value)); + continue; + } + String viewPath = AnnotationUtil.get(mapping.viewPath()); if (StrUtil.isNotBlank(viewPath)) { @@ -194,6 +206,18 @@ public class JbootCoreConfig extends JFinalConfig { JbootControllerManager.me().setMapping(route.getControllerKey(), route.getControllerClass()); } + if (!restfulRoutes.isEmpty()) { + //处理restful专属的routes + restfulConfig.setRoutes(restfulRoutes) + .setBaseViewPath(routes.getBaseViewPath()) + .setMappingSupperClass(routes.getMappingSuperClass()) + .setRouteInterceptors(routes.getInterceptors()); + restfulRoutes.forEach((Routes.Route route) -> { + JbootControllerManager.me().setMapping(route.getControllerKey(), route.getControllerClass()); + }); + routeList.addAll(restfulRoutes); + } + routeList.addAll(routes.getRouteItemList()); } @@ -271,7 +295,11 @@ public class JbootCoreConfig extends JFinalConfig { //若用户自己没配置 ActionHandler,默认使用 JbootActionHandler if (handlers.getActionHandler() == null) { - handlers.setActionHandler(new JbootActionHandler()); + if (!restfulRoutes.isEmpty()) { + handlers.setActionHandler(new RestfulHandler()); + } else { + handlers.setActionHandler(new JbootActionHandler()); + } } } @@ -294,6 +322,7 @@ public class JbootCoreConfig extends JFinalConfig { JbootSeataManager.me().init(); SentinelManager.me().init(); JbootGatewayManager.me().init(); + JbootRestfulManager.me().init(restfulConfig); JbootAppListenerManager.me().onStart(); } diff --git a/src/test/java/io/jboot/test/restful/RestfulController.java b/src/test/java/io/jboot/test/restful/RestfulController.java new file mode 100644 index 00000000..c0774faa --- /dev/null +++ b/src/test/java/io/jboot/test/restful/RestfulController.java @@ -0,0 +1,140 @@ +package io.jboot.test.restful; + +import com.jfinal.aop.Before; +import com.jfinal.aop.Inject; +import com.jfinal.aop.Interceptor; +import com.jfinal.aop.Invocation; +import com.jfinal.core.NotAction; +import com.jfinal.kit.JsonKit; +import com.jfinal.kit.StrKit; +import io.jboot.components.restful.annotation.*; +import io.jboot.web.HttpStatus; +import io.jboot.web.ResponseEntity; +import io.jboot.web.controller.JbootController; +import io.jboot.web.controller.annotation.RequestMapping; +import io.jboot.web.cors.EnableCORS; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@RestController +@RequestMapping("/restful") +public class RestfulController extends JbootController { + + public static class Data implements Serializable { + private String id; + private String name; + private int age; + + public Data(String id, String name, int age) { + this.id = id; + this.name = name; + this.age = age; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + } + + public static class RestfulInterceptor implements Interceptor { + + public void intercept(Invocation inv) { + System.out.println("--------> restful request begin"); + inv.invoke(); + System.out.println("--------> restful request end"); + } + } + + @Inject + private RestfulService restfulService; + + @NotAction + public List initData(){ + List users = new ArrayList<>(); + users.add(new RestfulController.Data("1", "tom", 18)); + users.add(new RestfulController.Data("2", "andy", 29)); + users.add(new RestfulController.Data("3", "max", 13)); + return users; + } + + //GET /restful + @GetMapping + @EnableCORS + @Before({RestfulInterceptor.class}) + @ResponseHeaders({@ResponseHeader(key = "d-head-1", value = "a"), @ResponseHeader(key = "d-head-2", value = "b")}) + public List users(){ + return initData(); + } + + // GET /restful/randomKey + @GetMapping("/randomKey") + public String randomKey(){ + return restfulService.getRandomKey(); + } + + // GET /restful/users + @GetMapping("/users") + public ResponseEntity entityUsers(){ + return new ResponseEntity(initData()) + .header("x-token", StrKit.getRandomUUID()) + .status(HttpStatus.ACCEPTED); + } + + // PUT /restful + @PutMapping + public void create(@RequestBody RestfulController.Data data){ + System.out.println("get request body data:\n" + JsonKit.toJson(data)); + } + + // PUT /restful/createList + @PutMapping("/createList") + public void createUsers(@RequestBody List users){ + System.out.println("get request body data:\n" + JsonKit.toJson(users)); + } + + // DELETE /restful/:id + @DeleteMapping("/{id}") + public void delete(@PathVariable("id") String id){ + System.out.println("delete by id : " + id ); + } + + // DELETE /restful/delete + @DeleteMapping("/delete") + public void deleteByName(@RequestParam(value = "name", required = true) String name, + @RequestHeader String token){ + System.out.println("delete by name : " + name); + System.out.println("get token header : " + token); + } + + @GetMapping("/get-date") + public Date getDate(){ + return new Date(); + } + + @PutMapping("/input-date") + public void inputDate(@RequestParam @DateFormat Date date){ + System.out.println("input date:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date)); + renderNull(); + } + + @PutMapping("/input-big-decimal") + public void inputBigDecimal(@RequestParam BigDecimal num){ + System.out.println("input bigDecimal:"+num.toString()); + renderNull(); + } + + +} diff --git a/src/test/java/io/jboot/test/restful/RestfulService.java b/src/test/java/io/jboot/test/restful/RestfulService.java new file mode 100644 index 00000000..aea7b1cd --- /dev/null +++ b/src/test/java/io/jboot/test/restful/RestfulService.java @@ -0,0 +1,5 @@ +package io.jboot.test.restful; + +public interface RestfulService { + String getRandomKey(); +} diff --git a/src/test/java/io/jboot/test/restful/RestfulServiceImpl.java b/src/test/java/io/jboot/test/restful/RestfulServiceImpl.java new file mode 100644 index 00000000..1c042af3 --- /dev/null +++ b/src/test/java/io/jboot/test/restful/RestfulServiceImpl.java @@ -0,0 +1,12 @@ +package io.jboot.test.restful; + +import com.jfinal.kit.StrKit; +import io.jboot.aop.annotation.Bean; + +@Bean +public class RestfulServiceImpl implements RestfulService { + @Override + public String getRandomKey() { + return StrKit.getRandomUUID(); + } +} -- Gitee From 49759e5dbec7495bf31658f29a3ec89af91dea11 Mon Sep 17 00:00:00 2001 From: yangyao Date: Wed, 8 Apr 2020 00:25:56 +0800 Subject: [PATCH 29/29] =?UTF-8?q?=E4=BC=98=E5=85=88=E4=BB=8Erestful=20acti?= =?UTF-8?q?on=20=E8=8E=B7=E5=8F=96=E8=AF=B7=E6=B1=82=EF=BC=8C=E9=98=B2?= =?UTF-8?q?=E6=AD=A2url=E8=A2=AB=E5=BD=93=E6=88=90urlPara=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/jboot/components/restful/RestfulHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/jboot/components/restful/RestfulHandler.java b/src/main/java/io/jboot/components/restful/RestfulHandler.java index 50d32965..58dcaeff 100644 --- a/src/main/java/io/jboot/components/restful/RestfulHandler.java +++ b/src/main/java/io/jboot/components/restful/RestfulHandler.java @@ -19,9 +19,10 @@ public class RestfulHandler extends JbootActionHandler { @Override public Action getAction(String target, String[] urlPara, HttpServletRequest request) { - Action action = super.getAction(target, urlPara); + //优先从restful action 获取请求,防止url被当成urlPara处理 + Action action = JbootRestfulManager.me().getRestfulAction(target, request.getMethod()); if (action == null) { - action = JbootRestfulManager.me().getRestfulAction(target, request.getMethod()); + action = super.getAction(target, urlPara); } return action; } @@ -54,4 +55,5 @@ public class RestfulHandler extends JbootActionHandler { }); } } + } -- Gitee