diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml deleted file mode 100644 index 9352518..0000000 --- a/.github/workflows/gradle.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Java CI - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - name: Build with Gradle - run: ./gradlew clean build -x test diff --git a/Issues.md b/Issues.md index c49864e..5804667 100644 --- a/Issues.md +++ b/Issues.md @@ -124,7 +124,7 @@ The dependencies of some of the beans in the application context form a cycle: ↓ productService (field private cn.com.hellowood.dynamicdatasource.mapper.ProductDao cn.com.hellowood.dynamicdatasource.service.ProductService.productDao) ↓ - productDao defined in file [/Users/hellowoodes/Downloads/Dev/SpringBoot/DynamicDataSource/out/production/classes/cn/com/hellowood/dynamicdatasource/mapper/ProductDao.class] + productDao defined in file [/Users/hehuimin/Downloads/Dev/SpringBoot/DynamicDataSource/out/production/classes/cn/com/hellowood/dynamicdatasource/mapper/ProductDao.class] ↓ sqlSessionFactoryBean defined in class path resource [cn/com/hellowood/dynamicdatasource/configuration/DataSourceConfigurer.class] ┌─────┐ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/README.md b/README.md index 87f48a5..50771d6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ # Spring Boot 和 MyBatis 实现多数据源、动态数据源切换 -- **[多数据源分布式事务](https://github.com/helloworlde/spring-cloud-alibaba-component/tree/master/cloud-seata-multi-datasource): 使用 [Seata](https://github.com/seata/seata) 实现的多数据源事务** +> 本项目使用 Spring Boot 和 MyBatis 实现多数据源,动态数据源的切换;有多种不同的实现方式,在学习的过程中发现没有文章将这些方式和常见的问题集中处理,所以将常用的方式和常见的问题都写在了在本项目的不同分支上: + +- [master](https://github.com/helloworlde/SpringBoot-DynamicDataSource): 使用了多数据源的 RESTful API 接口,使用 Druid 实现了 DAO 层数据源动态切换和只读数据源负载均衡 +- [dev](https://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/dev): 最简单的切面和注解方式实现的动态数据源切换 +- [druid](https://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/druid): 通过切面和注解方式实现的使用 Druid 连接池的动态数据源切换 +- [aspect_dao](https://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/aspect_dao): 通过切面实现的 DAO 层的动态数据源切换 +- [roundrobin](https://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/roundrobin): 通过切面使用轮询方式实现的只读数据源负载均衡 +- [hikari](https://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/hikari): 升级到SpringBoot 2.0版本 数据源使用 Hikari + +> 以上分支都是基于 dev 分支修改或扩充而来,基本涵盖了常用的多数据源动态切换的方式,基本的原理都一样,都是通过切面根据不同的条件在执行数据库操作前切换数据源 ### 在使用的过程中基本踩遍了所有动态数据源切换的坑,将常见的一些坑和解决方法写在了 [Issues](https://github.com/helloworlde/SpringBoot-DynamicDataSource/blob/master/Issues.md) 里面 @@ -384,7 +393,7 @@ public class DynamicDataSourceContextHolder { - DynamicDataSourceAspect.java > 动态数据源切换的切面,切 DAO 层,通过 DAO 层方法名判断使用哪个数据源,实现数据源切换 -> 关于切面的 Order 可以不设,因为 `@Transactional` 是最低的,取决于其他切面的设置,并且在 `org.springframework.core.annotation.AnnotationAwareOrderComparator` 会重新排序 +> 关于切面的 Order 可以可以不设,因为 `@Transactional` 是最低的,取决于其他切面的设置,并且在 `org.springframework.core.annotation.AnnotationAwareOrderComparator` 会重新排序 ```java package cn.com.hellowood.dynamicdatasource.configuration; @@ -449,9 +458,9 @@ package cn.com.hellowood.dynamicdatasource.controller; import cn.com.hellowood.dynamicdatasource.common.CommonResponse; import cn.com.hellowood.dynamicdatasource.common.ResponseUtil; -import cn.com.hellowood.dynamicdatasource.model.Product; +import cn.com.hellowood.dynamicdatasource.modal.Product; import cn.com.hellowood.dynamicdatasource.service.ProductService; -import cn.com.hellowood.dynamicdatasource.error.ServiceException; +import cn.com.hellowood.dynamicdatasource.utils.ServiceException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -496,8 +505,8 @@ public class ProductController { package cn.com.hellowood.dynamicdatasource.service; import cn.com.hellowood.dynamicdatasource.mapper.ProductDao; -import cn.com.hellowood.dynamicdatasource.model.Product; -import cn.com.hellowood.dynamicdatasource.error.ServiceException; +import cn.com.hellowood.dynamicdatasource.modal.Product; +import cn.com.hellowood.dynamicdatasource.utils.ServiceException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Service; @@ -558,7 +567,7 @@ public class ProductService { ```java package cn.com.hellowood.dynamicdatasource.mapper; -import cn.com.hellowood.dynamicdatasource.model.Product; +import cn.com.hellowood.dynamicdatasource.modal.Product; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -588,8 +597,3 @@ public interface ProductDao { ## 注意 > 在该应用中因为使用了 DAO 层的切面切换数据源,所以 `@Transactional` 注解不能加在类上,只能用于方法;有 `@Trasactional`注解的方法无法切换数据源 - - -## Stargazers over time - -[![Stargazers over time](https://starchart.cc/helloworlde/SpringBoot-DynamicDataSource.svg)](https://starchart.cc/helloworlde/SpringBoot-DynamicDataSource) diff --git a/build.gradle b/build.gradle index 62f7cc5..2d9b6a6 100644 --- a/build.gradle +++ b/build.gradle @@ -31,8 +31,6 @@ dependencies { compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2') compile('org.springframework.boot:spring-boot-starter-web') compile('org.springframework.boot:spring-boot-starter-aop') - compile('com.alibaba:druid-spring-boot-starter:1.1.6') - compile 'com.alibaba:fastjson:1.2.55' runtime('mysql:mysql-connector-java') testCompile('org.springframework.boot:spring-boot-starter-test') } diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/annotation/ApiResponseBody.java b/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/annotation/ApiResponseBody.java deleted file mode 100644 index 33959d2..0000000 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/annotation/ApiResponseBody.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.com.hellowood.dynamicdatasource.apiutil.annotation; - -import com.alibaba.fastjson.serializer.SerializerFeature; - -import java.lang.annotation.*; - -/** - * 会在拦截器那里判断是否有这个注解,如果存在把结果包装成 {code:'',data:''} 的形式 - * - * @author LDZ - * @date 2020年03月02日 16:36 - */ -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface ApiResponseBody { - /** - * 序列化可选 fastjson - * - * @return - * @see SerializerFeature - */ - SerializerFeature[] serializerFeature() default {}; -} diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/config/BaseWebMvcConfig.java b/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/config/BaseWebMvcConfig.java deleted file mode 100644 index 67ddea3..0000000 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/config/BaseWebMvcConfig.java +++ /dev/null @@ -1,128 +0,0 @@ -package cn.com.hellowood.dynamicdatasource.apiutil.config; - - -import cn.com.hellowood.dynamicdatasource.apiutil.interceptor.ApiResponseBodyReturnValueHandler; -import cn.com.hellowood.dynamicdatasource.configuration.CustomHandlerExceptionResolver; -import com.alibaba.fastjson.support.config.FastJsonConfig; -import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; -import org.springframework.format.FormatterRegistry; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.validation.MessageCodesResolver; -import org.springframework.validation.Validator; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.HandlerMethodReturnValueHandler; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.config.annotation.*; - -import java.util.Collections; -import java.util.List; - - -/** - * spring boot web 通用配置 - * - * @author LDZ - * @date 2020年03月02日 17:12 - */ -public abstract class BaseWebMvcConfig implements WebMvcConfigurer { - - @Override - public void addReturnValueHandlers(List returnValueHandlers) { - returnValueHandlers.add(new ApiResponseBodyReturnValueHandler()); - } - - @Override - public void addInterceptors(InterceptorRegistry registry) { - } - - @Override - public void configureMessageConverters(List> converters) { - FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); - FastJsonConfig fastJsonConfig = new FastJsonConfig(); - - fastJsonConfig.setSerializerFeatures( -// SerializerFeature.PrettyFormat - ); - - fastConverter.setFastJsonConfig(fastJsonConfig); - fastConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8)); - converters.add(0, fastConverter); - - } - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - - } - - @Override - public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { - - } - - @Override - public void configureAsyncSupport(AsyncSupportConfigurer configurer) { - - } - - @Override - public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { - - } - - @Override - public void addFormatters(FormatterRegistry registry) { - - } - - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - - } - - @Override - public void addCorsMappings(CorsRegistry registry) { - - } - - @Override - public void addViewControllers(ViewControllerRegistry registry) { - - } - - @Override - public void configureViewResolvers(ViewResolverRegistry registry) { - - } - - @Override - public void addArgumentResolvers(List argumentResolvers) { - - } - - @Override - public void extendMessageConverters(List> converters) { - - } - - @Override - public void configureHandlerExceptionResolvers(List exceptionResolvers) { - exceptionResolvers.add(new CustomHandlerExceptionResolver()); - } - - @Override - public void extendHandlerExceptionResolvers(List exceptionResolvers) { - - } - - @Override - public Validator getValidator() { - return null; - } - - @Override - public MessageCodesResolver getMessageCodesResolver() { - return null; - } -} diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/BaseExceptionHandler.java b/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/BaseExceptionHandler.java deleted file mode 100644 index 3a72571..0000000 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/BaseExceptionHandler.java +++ /dev/null @@ -1,83 +0,0 @@ -package cn.com.hellowood.dynamicdatasource.apiutil.exception; - -import cn.com.hellowood.dynamicdatasource.apiutil.model.BaseResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.validation.BindException; -import org.springframework.web.bind.MissingServletRequestParameterException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.util.Optional; -import java.util.stream.Collectors; - -import static cn.com.hellowood.dynamicdatasource.apiutil.exception.enums.CustomExceptionEnum.PARAM_ERROR; - -/** - * 错误处理句柄 - * - * @author LDZ - * @date 2020年03月02日 17:19 - */ - -@ControllerAdvice -public class BaseExceptionHandler { - - private static final Logger log = LoggerFactory.getLogger(BaseExceptionHandler.class); - - /** - * @param request 请求 - * @param response 返回 - * @param handler 句柄 - * @param ex 错误 - * @return 统一封装返回值 - */ - @ResponseBody - @ExceptionHandler(MissingServletRequestParameterException.class) - public BaseResponse argumentMissingError(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { - return PARAM_ERROR.handlerBaseResponse("参数错误"); - } - - @ResponseBody - @ExceptionHandler(BindException.class) - public BaseResponse bindError(HttpServletRequest request, HttpServletResponse response, Object handler, BindException ex) { - String errMessage = ex.getFieldErrors().stream().map(fieldError -> fieldError.getField() + ":" + fieldError.getDefaultMessage()).collect(Collectors.joining(",")); - log.warn("server param error ", ex); - return PARAM_ERROR.handlerBaseResponse(errMessage); - - } - - - /** - * 抓取所有的错误 - * - * @param request - * @param response - * @param handler - * @param ex - * @return - */ - @ResponseBody - @ExceptionHandler(Exception.class) - public BaseResponse defaultErrorHandle(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { - log.error("server error ", ex); - return PARAM_ERROR.handlerBaseResponse("服务器繁忙"); - } - - - @ResponseBody - @ExceptionHandler(CustomServiceException.class) - public BaseResponse customExceptionHandle(HttpServletRequest request, HttpServletResponse response, Object handler, CustomServiceException customServiceException) { - - log.debug("business err {} ", customServiceException.getErrorDescription()); - return customServiceException.getCustomExceptionEnum().handlerBaseResponse( - Optional.ofNullable(customServiceException.getErrorDescription()).orElse("服务器繁忙"), - Optional.ofNullable(customServiceException.getData()).orElse(null)); - - - } - -} diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/CustomServiceException.java b/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/CustomServiceException.java deleted file mode 100644 index 339b537..0000000 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/CustomServiceException.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.com.hellowood.dynamicdatasource.apiutil.exception; - -/** - * @author XiaoLei - * @date 2018年4月17日 15:19 - * @description - */ - -import cn.com.hellowood.dynamicdatasource.apiutil.exception.enums.CustomExceptionEnum; - -/** - * 自定义异常 - * - * @author LDZ - * @date 2020年03月02日 17:22 - */ -public class CustomServiceException extends RuntimeException { - - /** - * 自定义错误 - */ - private CustomExceptionEnum customExceptionEnum; - - /** - * 错误的描述 - */ - private String errorDescription; - - /** - * 需要返回的数据 - */ - private Object data; - - - public CustomServiceException(CustomExceptionEnum customExceptionEnum, String desc) { - super(desc); - this.customExceptionEnum = customExceptionEnum; - this.errorDescription = desc; - } - - public CustomServiceException(CustomExceptionEnum customExceptionEnum, String desc, Object data) { - super(desc); - this.customExceptionEnum = customExceptionEnum; - this.errorDescription = desc; - this.data = data; - } - - public CustomExceptionEnum getCustomExceptionEnum() { - return customExceptionEnum; - } - - public void setCustomExceptionEnum(CustomExceptionEnum customExceptionEnum) { - this.customExceptionEnum = customExceptionEnum; - } - - public String getErrorDescription() { - return errorDescription; - } - - public void setErrorDescription(String errorDescription) { - this.errorDescription = errorDescription; - } - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } -} diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/enums/CustomExceptionEnum.java b/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/enums/CustomExceptionEnum.java deleted file mode 100644 index a7631ef..0000000 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/exception/enums/CustomExceptionEnum.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.com.hellowood.dynamicdatasource.apiutil.exception.enums; - -import cn.com.hellowood.dynamicdatasource.apiutil.exception.CustomServiceException; -import cn.com.hellowood.dynamicdatasource.apiutil.model.BaseResponse; -import jdk.nashorn.internal.objects.annotations.Getter; - -import java.util.function.BiFunction; - -/** - * @author LDZ - * @date 2020年03月02日 17:23 - */ -public enum CustomExceptionEnum { - - - /** - * 业务的参数错误 - */ - PARAM_ERROR(105) { - // override - - }; - - - int code; - - public RuntimeException handlerException(String s, Object d) { - return new CustomServiceException(this, s, d); - } - - public RuntimeException handlerException(String s) { - return new CustomServiceException(this, s); - } - - public BaseResponse handlerBaseResponse(String s, Object d) { - return new BaseResponse(this, s, d); - } - - public BaseResponse handlerBaseResponse(String s) { - return new BaseResponse(this, s); - } - - public int getCode() { - return code; - } - - CustomExceptionEnum(int code) { - this.code = code; - } -} diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/interceptor/ApiResponseBodyReturnValueHandler.java b/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/interceptor/ApiResponseBodyReturnValueHandler.java deleted file mode 100644 index 7dee6ce..0000000 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/interceptor/ApiResponseBodyReturnValueHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.com.hellowood.dynamicdatasource.apiutil.interceptor; - -import cn.com.hellowood.dynamicdatasource.apiutil.annotation.ApiResponseBody; -import cn.com.hellowood.dynamicdatasource.apiutil.model.BaseResponse; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.serializer.SerializerFeature; -import org.springframework.core.MethodParameter; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler; -import org.springframework.web.method.support.HandlerMethodReturnValueHandler; -import org.springframework.web.method.support.ModelAndViewContainer; - -import javax.servlet.http.HttpServletResponse; - -/** - * api 层返回值处理句柄 - * - * @author LDZ - * @date 2020年03月02日 16:43 - */ -public class ApiResponseBodyReturnValueHandler implements HandlerMethodReturnValueHandler, AsyncHandlerMethodReturnValueHandler { - /** - * 处理的返回类型 - * - * @param returnType 返回类型 - * @return true 处理 false 不处理 - */ - @Override - public boolean supportsReturnType(MethodParameter returnType) { - // 如果已经是基础的返回值 - return returnType.getParameterType() != ApiResponseBody.class - && (returnType.getAnnotatedElement().getAnnotation(ApiResponseBody.class) != null); - } - - @Override - public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { - mavContainer.setRequestHandled(true); - HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); - assert response != null; - response.setContentType("application/json;charset=utf-8"); - BaseResponse baseResponse = new BaseResponse(); - baseResponse.setCode(100); - baseResponse.setMessage("成功"); - baseResponse.setData(returnValue); - - ApiResponseBody apiResponseBody = returnType.getAnnotatedElement().getAnnotation(ApiResponseBody.class); - - SerializerFeature[] defaultSerializerFeature = { - SerializerFeature.DisableCircularReferenceDetect - }; - - if (apiResponseBody != null && apiResponseBody.serializerFeature().length != 0) { - defaultSerializerFeature = apiResponseBody.serializerFeature(); - } - response.getWriter().write(JSON.toJSONString(baseResponse, defaultSerializerFeature)); - - } - - @Override - public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) { - return supportsReturnType(returnType); - } -} diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/model/BaseResponse.java b/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/model/BaseResponse.java deleted file mode 100644 index fac14fc..0000000 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/apiutil/model/BaseResponse.java +++ /dev/null @@ -1,81 +0,0 @@ -package cn.com.hellowood.dynamicdatasource.apiutil.model; - -import cn.com.hellowood.dynamicdatasource.apiutil.exception.enums.CustomExceptionEnum; - -import java.io.Serializable; - -/** - * 统一返回标志 - * - * @author LDZ - * @date 2020年03月02日 16:48 - */ -public class BaseResponse implements Serializable { - - private static final long serialVersionUID = -6818493817970279447L; - /** - * 返回code码 - */ - private int code; - - /** - * 返回信息 - */ - private String message; - - /** - * 返回数据 - */ - private Object data; - - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } - - - public BaseResponse() { - } - - public BaseResponse(int code, String message, Object data) { - this.code = code; - this.message = message; - this.data = data; - } - - public BaseResponse(int code, String message) { - this.code = code; - this.message = message; - } - - public BaseResponse(CustomExceptionEnum customExceptionEnum, String message, Object data) { - this.code = customExceptionEnum.getCode(); - this.message = message; - this.data = data; - } - - public BaseResponse(CustomExceptionEnum customExceptionEnum, String message) { - this.code = customExceptionEnum.getCode(); - this.message = message; - } - -} diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/common/ResponseUtil.java b/src/main/java/cn/com/hellowood/dynamicdatasource/common/ResponseUtil.java index 2969fd5..562e0aa 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/common/ResponseUtil.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/common/ResponseUtil.java @@ -18,6 +18,69 @@ public class ResponseUtil { private static final Logger logger = LoggerFactory.getLogger(ResponseUtil.class); + /** + * return response with default success or error message by status + * + * @param resultStatus + * @return + */ + public static CommonResponse generateResponse(boolean resultStatus) { + CommonResponse commonResponse = new CommonResponse(); + if (resultStatus) { + commonResponse + .setCode(ResponseCode.SUCCESS) + .setMessage(CommonConstant.DEFAULT_SUCCESS_MESSAGE); + } else { + commonResponse + .setCode(ResponseCode.FAIL) + .setMessage(CommonConstant.DEFAULT_FAIL_MESSAGE); + } + return commonResponse; + } + + /** + * return response with custom message by status + * + * @param message + * @param resultStatus + * @return + */ + public static CommonResponse generateResponse(String message, boolean resultStatus) { + CommonResponse commonResponse = new CommonResponse(); + if (resultStatus) { + commonResponse + .setCode(ResponseCode.SUCCESS) + .setMessage(message); + } else { + commonResponse + .setCode(ResponseCode.FAIL) + .setMessage(message); + } + return commonResponse; + } + + /** + * return response with data,if data is null,return no data message,or return data + * + * @param data + * @return + */ + public static CommonResponse generateResponse(Object data) { + CommonResponse commonResponse = new CommonResponse(); + if (data != null) { + commonResponse + .setCode(ResponseCode.SUCCESS) + .setMessage(CommonConstant.DEFAULT_SUCCESS_MESSAGE) + .setData(data); + } else { + commonResponse + .setCode(ResponseCode.SUCCESS) + .setMessage(CommonConstant.NO_RESULT_MESSAGE); + + } + return commonResponse; + } + /** * Handler response information * diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/CustomHandlerExceptionResolver.java b/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/CustomHandlerExceptionResolver.java index de9c3d8..6795ca8 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/CustomHandlerExceptionResolver.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/CustomHandlerExceptionResolver.java @@ -4,7 +4,7 @@ import cn.com.hellowood.dynamicdatasource.common.CommonResponse; import cn.com.hellowood.dynamicdatasource.common.ResponseCode; import cn.com.hellowood.dynamicdatasource.common.ResponseUtil; -import cn.com.hellowood.dynamicdatasource.error.ServiceException; +import cn.com.hellowood.dynamicdatasource.utils.ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/WebMvcConfigurer.java b/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/WebMvcConfigurer.java index 38edf85..696dc1e 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/WebMvcConfigurer.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/configuration/WebMvcConfigurer.java @@ -1,9 +1,12 @@ package cn.com.hellowood.dynamicdatasource.configuration; -import cn.com.hellowood.dynamicdatasource.apiutil.config.BaseWebMvcConfig; -import cn.com.hellowood.dynamicdatasource.apiutil.exception.BaseExceptionHandler; -import org.springframework.context.annotation.Bean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import java.util.List; /** @@ -15,10 +18,18 @@ */ @Configuration -public class WebMvcConfigurer extends BaseWebMvcConfig { +public class WebMvcConfigurer extends WebMvcConfigurerAdapter { + + private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class); - @Bean - public BaseExceptionHandler baseExceptionHandler() { - return new BaseExceptionHandler(); + /** + * Exception resolver method + * + * @param exceptionResolvers + */ + @Override + public void configureHandlerExceptionResolvers(List exceptionResolvers) { + exceptionResolvers.add(new CustomHandlerExceptionResolver()); } + } diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/controller/ProductController.java b/src/main/java/cn/com/hellowood/dynamicdatasource/controller/ProductController.java index 1bbb233..9c9525c 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/controller/ProductController.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/controller/ProductController.java @@ -1,14 +1,13 @@ package cn.com.hellowood.dynamicdatasource.controller; -import cn.com.hellowood.dynamicdatasource.apiutil.annotation.ApiResponseBody; -import cn.com.hellowood.dynamicdatasource.model.Product; +import cn.com.hellowood.dynamicdatasource.common.CommonResponse; +import cn.com.hellowood.dynamicdatasource.common.ResponseUtil; +import cn.com.hellowood.dynamicdatasource.modal.Product; import cn.com.hellowood.dynamicdatasource.service.ProductService; -import cn.com.hellowood.dynamicdatasource.error.ServiceException; +import cn.com.hellowood.dynamicdatasource.utils.ServiceException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import javax.annotation.Resource; -import java.util.List; - /** * Product controller * @@ -21,7 +20,7 @@ @RequestMapping("/product") public class ProductController { - @Resource + @Autowired private ProductService productService; /** @@ -32,9 +31,8 @@ public class ProductController { * @throws ServiceException */ @GetMapping("/{id}") - @ApiResponseBody - public Product getProduct(@PathVariable("id") Long productId) throws ServiceException { - return productService.select(productId); + public CommonResponse getProduct(@PathVariable("id") Long productId) throws ServiceException { + return ResponseUtil.generateResponse(productService.select(productId)); } /** @@ -44,9 +42,8 @@ public Product getProduct(@PathVariable("id") Long productId) throws ServiceExce * @throws ServiceException */ @GetMapping - @ApiResponseBody - public List getAllProduct() { - return productService.getAllProduct(); + public CommonResponse getAllProduct() { + return ResponseUtil.generateResponse(productService.getAllProduct()); } /** @@ -57,11 +54,9 @@ public List getAllProduct() { * @return * @throws ServiceException */ - @PutMapping("/{id}") - @ApiResponseBody - public Product updateProduct(@PathVariable("id") Long productId, @RequestBody Product newProduct) throws ServiceException { - return productService.update(productId, newProduct); + public CommonResponse updateProduct(@PathVariable("id") Long productId, @RequestBody Product newProduct) throws ServiceException { + return ResponseUtil.generateResponse(productService.update(productId, newProduct)); } /** @@ -72,9 +67,8 @@ public Product updateProduct(@PathVariable("id") Long productId, @RequestBody Pr * @throws ServiceException */ @DeleteMapping("/{id}") - @ApiResponseBody - public boolean deleteProduct(@PathVariable("id") long productId) throws ServiceException { - return productService.delete(productId); + public CommonResponse deleteProduct(@PathVariable("id") long productId) throws ServiceException { + return ResponseUtil.generateResponse(productService.delete(productId)); } /** @@ -85,8 +79,7 @@ public boolean deleteProduct(@PathVariable("id") long productId) throws ServiceE * @throws ServiceException */ @PostMapping - @ApiResponseBody - public boolean addProduct(@RequestBody Product newProduct) throws ServiceException { - return productService.add(newProduct); + public CommonResponse addProduct(@RequestBody Product newProduct) throws ServiceException { + return ResponseUtil.generateResponse(productService.add(newProduct)); } } diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/mapper/ProductDao.java b/src/main/java/cn/com/hellowood/dynamicdatasource/mapper/ProductDao.java index a3db37a..6c8b620 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/mapper/ProductDao.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/mapper/ProductDao.java @@ -1,6 +1,6 @@ package cn.com.hellowood.dynamicdatasource.mapper; -import cn.com.hellowood.dynamicdatasource.model.Product; +import cn.com.hellowood.dynamicdatasource.modal.Product; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/model/Product.java b/src/main/java/cn/com/hellowood/dynamicdatasource/modal/Product.java similarity index 93% rename from src/main/java/cn/com/hellowood/dynamicdatasource/model/Product.java rename to src/main/java/cn/com/hellowood/dynamicdatasource/modal/Product.java index 738c4c0..d8cd76e 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/model/Product.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/modal/Product.java @@ -1,4 +1,4 @@ -package cn.com.hellowood.dynamicdatasource.model; +package cn.com.hellowood.dynamicdatasource.modal; import java.io.Serializable; diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/service/ProductService.java b/src/main/java/cn/com/hellowood/dynamicdatasource/service/ProductService.java index c758fd7..391bc56 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/service/ProductService.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/service/ProductService.java @@ -1,8 +1,8 @@ package cn.com.hellowood.dynamicdatasource.service; import cn.com.hellowood.dynamicdatasource.mapper.ProductDao; -import cn.com.hellowood.dynamicdatasource.model.Product; -import cn.com.hellowood.dynamicdatasource.error.ServiceException; +import cn.com.hellowood.dynamicdatasource.modal.Product; +import cn.com.hellowood.dynamicdatasource.utils.ServiceException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Service; diff --git a/src/main/java/cn/com/hellowood/dynamicdatasource/error/ServiceException.java b/src/main/java/cn/com/hellowood/dynamicdatasource/utils/ServiceException.java similarity index 90% rename from src/main/java/cn/com/hellowood/dynamicdatasource/error/ServiceException.java rename to src/main/java/cn/com/hellowood/dynamicdatasource/utils/ServiceException.java index b6ef2ba..a98a8cc 100644 --- a/src/main/java/cn/com/hellowood/dynamicdatasource/error/ServiceException.java +++ b/src/main/java/cn/com/hellowood/dynamicdatasource/utils/ServiceException.java @@ -1,4 +1,4 @@ -package cn.com.hellowood.dynamicdatasource.error; +package cn.com.hellowood.dynamicdatasource.utils; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 058a8ce..8674cfc 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -33,10 +33,4 @@ spring.datasource.hikari.slave-gamma.password=123456 spring.aop.proxy-target-class=true - -# MyBatis config -mybatis.type-aliases-package=cn.com.hellowood.dynamicdatasource.mapper -mybatis.mapper-locations=mappers/**Mapper.xml -server.port=9999 -spring.mvc.throw-exception-if-no-handler-found=true - +server.port=9999 \ No newline at end of file diff --git a/src/main/resources/mappers/ProductMapper.xml b/src/main/resources/mappers/ProductMapper.xml index 1ff5431..7a5c223 100644 --- a/src/main/resources/mappers/ProductMapper.xml +++ b/src/main/resources/mappers/ProductMapper.xml @@ -2,13 +2,13 @@
    - + - SELECT * FROM product WHERE id = #{id} @@ -20,7 +20,7 @@ FROM product - + UPDATE product SET name = #{name}, price = #{price} WHERE id = #{id} @@ -33,7 +33,7 @@ LIMIT 1 - + INSERT INTO product (name, price) VALUES (#{name}, #{price});

    AltStyle によって変換されたページ (->オリジナル) /