├── .gitignore ├── LICENSE ├── ReadMe.md ├── boot-datasource ├── pom.xml └── src │ ├── main │ ├── java │ │ └── cn │ │ │ └── com │ │ │ └── wudskq │ │ │ ├── BootDataSourceApplication.java │ │ │ ├── annotation │ │ │ └── DataSource.java │ │ │ ├── aspectj │ │ │ └── DataSourceAspect.java │ │ │ ├── config │ │ │ └── DruidConfig.java │ │ │ ├── controller │ │ │ └── DruidController.java │ │ │ ├── core │ │ │ └── text │ │ │ │ ├── CharsetKit.java │ │ │ │ ├── Convert.java │ │ │ │ └── StrFormatter.java │ │ │ ├── datasource │ │ │ ├── DynamicDataSource.java │ │ │ └── DynamicDataSourceContextHolder.java │ │ │ ├── enums │ │ │ └── DataSourceType.java │ │ │ ├── mapper │ │ │ └── DruidMapper.java │ │ │ ├── properties │ │ │ └── DruidProperties.java │ │ │ ├── sevice │ │ │ └── impl │ │ │ │ ├── DruidSevice.java │ │ │ │ └── DruidSeviceImpl.java │ │ │ └── utils │ │ │ ├── StringUtils.java │ │ │ └── spring │ │ │ └── SpringUtils.java │ └── resources │ │ ├── application.yml │ │ ├── logback.xml │ │ ├── mapper │ │ └── DruidMapper.xml │ │ └── sql │ │ └── druid.sql │ └── test │ └── java │ └── cn │ └── com │ └── wudskq │ └── DruidSourceTest.java ├── boot-kafka ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── wudskq │ │ ├── BootKafkaApplication.java │ │ ├── config │ │ ├── KafkaOneConfig.java │ │ └── KafkaTwoConfig.java │ │ ├── consumer │ │ └── Consumer.java │ │ └── producer │ │ └── ProducerController.java │ └── resources │ └── application.yml ├── boot-mqtt ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── wudskq │ │ ├── MqttBootApplication.java │ │ ├── config │ │ └── MqttConfig.java │ │ ├── controller │ │ └── MqttController.java │ │ └── model │ │ └── MqttDTO.java │ └── resources │ └── application.yml ├── boot-mybatis-Interceptor ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── wudskq │ │ ├── MybatisInterceptorApplication.java │ │ ├── annotation │ │ ├── CreateBy.java │ │ ├── CreateTime.java │ │ ├── SensitiveData.java │ │ ├── SensitiveField.java │ │ ├── UpdateBy.java │ │ └── UpdateTime.java │ │ ├── controller │ │ └── MybatisController.java │ │ ├── interceptor │ │ ├── ConvertParameter.java │ │ ├── CustomInterceptor.java │ │ ├── DecryptInterceptor.java │ │ └── EncryptInterceptor.java │ │ ├── mapper │ │ └── MybatisMapper.java │ │ ├── model │ │ ├── Plan.java │ │ └── common │ │ │ └── BaseDTO.java │ │ ├── sevice │ │ ├── MybatisSevice.java │ │ ├── aes │ │ │ ├── AESDecrypt.java │ │ │ ├── AESEncrypt.java │ │ │ ├── DecryptUtil.java │ │ │ └── EncryptUtil.java │ │ └── impl │ │ │ └── MybatisSeviceImpl.java │ │ └── utils │ │ └── AESUtil.java │ └── resources │ ├── application.yml │ ├── mapper │ └── MybatisMapper.xml │ └── sql │ └── plan.sql ├── boot-mybatis-plus-interceptor ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── wudskq │ │ ├── MybatisPlusInterceptorApplication.java │ │ ├── config │ │ └── MyMetaObjectHandler.java │ │ ├── controller │ │ └── MybatisPlusController.java │ │ ├── mapper │ │ └── MybatisPlusMapper.java │ │ ├── model │ │ ├── Plan.java │ │ └── common │ │ │ └── BaseDTO.java │ │ └── sevice │ │ ├── MybatisPlusSevice.java │ │ └── impl │ │ └── MybatisPlusSeviceImpl.java │ └── resources │ ├── application.yml │ └── mapper │ └── MybatisMapper.xml ├── boot-rabbitmq ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── wudskq │ │ ├── BootRabbitMqApplication.java │ │ └── listener │ │ └── AmqListener.java │ └── resources │ └── application.yml ├── boot-redis └── pom.xml ├── boot-security ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── wudskq │ │ ├── BootSecurityApplication.java │ │ ├── conf │ │ ├── JWTConfig.java │ │ ├── Knife4jConfiguration.java │ │ └── WebSecurityConfig.java │ │ ├── controller │ │ ├── IndexController.java │ │ └── TSysUserController.java │ │ ├── dao │ │ ├── TSysResMapper.java │ │ ├── TSysRoleMapper.java │ │ ├── TSysRoleResMapper.java │ │ ├── TSysUserMapper.java │ │ └── TSysUserRoleMapper.java │ │ ├── expection │ │ ├── MyException.java │ │ ├── TopException.java │ │ └── UserAccessDeniedHandler.java │ │ ├── filter │ │ └── JWTAuthenticationFilter.java │ │ ├── handler │ │ ├── UserAuthenticationProvider.java │ │ ├── UserLoginFailureHandler.java │ │ ├── UserLoginSuccessHandler.java │ │ ├── UserLogoutSuccessHandler.java │ │ └── UserNotLoginHandler.java │ │ ├── model │ │ ├── SysUserDetails.java │ │ ├── dto │ │ │ ├── TSysRes.java │ │ │ ├── TSysRole.java │ │ │ ├── TSysRoleRes.java │ │ │ ├── TSysUser.java │ │ │ └── TSysUserRole.java │ │ └── vo │ │ │ └── Result.java │ │ ├── permssion │ │ └── UserPermissionEvaluator.java │ │ ├── service │ │ ├── TSysResService.java │ │ ├── TSysRoleResService.java │ │ ├── TSysRoleService.java │ │ ├── TSysUserRoleService.java │ │ ├── TSysUserService.java │ │ └── impl │ │ │ ├── SysUserDetailsService.java │ │ │ ├── TSysResServiceImpl.java │ │ │ ├── TSysRoleResServiceImpl.java │ │ │ ├── TSysRoleServiceImpl.java │ │ │ ├── TSysUserRoleServiceImpl.java │ │ │ └── TSysUserServiceImpl.java │ │ └── util │ │ ├── JWTTokenUtil.java │ │ └── Md5Util.java │ └── resources │ ├── application.yml │ └── project.sql └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # Build Tools 3 | 4 | .gradle 5 | /build/ 6 | !gradle/wrapper/gradle-wrapper.jar 7 | 8 | target/ 9 | !.mvn/wrapper/maven-wrapper.jar 10 | 11 | ###################################################################### 12 | # IDE 13 | HELP.md 14 | /target/ 15 | !.mvn/wrapper/maven-wrapper.jar 16 | ### 通用 ### 17 | *.class 18 | rebel.xml 19 | 20 | ### STS ### 21 | .apt_generated 22 | .classpath 23 | .factorypath 24 | .project 25 | .settings 26 | .springBeans 27 | .sts4-cache 28 | 29 | ### IntelliJ IDEA ### 30 | .idea 31 | *.iws 32 | *.iml 33 | *.ipr 34 | 35 | ### NetBeans ### 36 | /nbproject/private/ 37 | /nbbuild/ 38 | /dist/ 39 | /nbdist/ 40 | /.nb-gradle/ 41 | /build/ 42 | 43 | ### VS Code ### 44 | .vscode/ 45 | 46 | nbproject/private/ 47 | build/* 48 | nbbuild/ 49 | dist/ 50 | nbdist/ 51 | .nb-gradle/ 52 | 53 | ###################################################################### 54 | # Others 55 | *.log 56 | *.xml.versionsBackup 57 | *.swp 58 | 59 | !*/build/*.java 60 | !*/build/*.html 61 | !*/build/*.xml 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 wudskq 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | ## SpringBoot整合示例项目 2 | 3 | ![Spring-Boot](https://img.shields.io/badge/Spring--Boot-2.2.13.RELEASE-brightgreen) ![kafka](https://img.shields.io/badge/Kafka-卡夫卡-orange) ![datasoirce](https://img.shields.io/badge/DataSource-多数据源-blue) ![mqtt](https://img.shields.io/badge/Mqtt-物联网-lightgrey) ![Mybatis](https://img.shields.io/badge/-Myabtis-success) ![](https://img.shields.io/badge/-Myabtis--Plus-success) ![](https://img.shields.io/badge/-RabbitMQ-orange) ![](https://img.shields.io/badge/-Redis-green) ![](https://img.shields.io/badge/-Spring--Security-blue) 4 | 5 | **Spring Boot 中依赖集成的示例项目, 每个模块都为单独工程, 可单独作为最小依赖进行运行** 6 | 7 | 示例代码: 8 | 9 | - [boot-datasource](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-datasource) 配置多数据源 10 | - [boot-kafka](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-kafka) 集成Kafka 11 | - [boot-mqtt](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-mqtt) 集成MQTT 12 | - [boot-mybatis-Interceptor](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-mybatis-Interceptor) 配置Mybatis拦截器 13 | - [boot-mybatis-plus-interceptor](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-mybatis-plus-interceptor) 配置Mybatis-Plus拦截器 14 | - [boot-rabbitmq](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-rabbitmq) 集成RabbitMQ 15 | - [boot-redis](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-redis) 集成Redis 16 | - [boot-security](https://github.com/wudskq/spring-boot-project-case/tree/dev/boot-security) 集成SpringSecurity 17 | -------------------------------------------------------------------------------- /boot-datasource/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-datasource 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | mysql 32 | mysql-connector-java 33 | 34 | 35 | 36 | com.alibaba 37 | druid-spring-boot-starter 38 | 1.2.6 39 | 40 | 41 | 42 | org.mybatis 43 | mybatis 44 | 3.5.7 45 | 46 | 47 | 48 | com.baomidou 49 | mybatis-plus 50 | 3.4.3 51 | 52 | 53 | 54 | com.baomidou 55 | mybatis-plus-boot-starter 56 | 3.4.3 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-starter-jdbc 62 | 63 | 64 | 65 | org.apache.commons 66 | commons-lang3 67 | 3.9 68 | 69 | 70 | 71 | org.aspectj 72 | aspectjweaver 73 | 74 | 75 | 76 | junit 77 | junit 78 | test 79 | 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-test 84 | 85 | 86 | 87 | org.springframework 88 | spring-test 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/BootDataSourceApplication.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 7 | 8 | /** 9 | * @author chenfangchao 10 | * @title: cn.com.wudskq.BootDataSourceApplication 11 | * @projectName boot-project 12 | * @description: TODO boot配置多数据源 13 | * @date 2022/4/2 11:13 AM 14 | */ 15 | //排除数据源自动配置 16 | @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) 17 | @MapperScan("cn.com.wudskq.**.mapper") 18 | public class BootDataSourceApplication { 19 | public static void main(String[] args) { 20 | SpringApplication.run(BootDataSourceApplication.class,args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/annotation/DataSource.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.annotation; 2 | 3 | 4 | 5 | import cn.com.wudskq.enums.DataSourceType; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * 自定义多数据源切换注解 11 | * 12 | * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 13 | * 14 | * @author seat 15 | */ 16 | @Target({ ElementType.METHOD, ElementType.TYPE }) 17 | @Retention(RetentionPolicy.RUNTIME) 18 | @Documented 19 | @Inherited 20 | public @interface DataSource 21 | { 22 | /** 23 | * 切换数据源名称 24 | */ 25 | public DataSourceType value() default DataSourceType.MASTER; 26 | } 27 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/aspectj/DataSourceAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.aspectj; 2 | 3 | 4 | import cn.com.wudskq.annotation.DataSource; 5 | import cn.com.wudskq.datasource.DynamicDataSourceContextHolder; 6 | import cn.com.wudskq.utils.StringUtils; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.Around; 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.aspectj.lang.annotation.Pointcut; 11 | import org.aspectj.lang.reflect.MethodSignature; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.core.annotation.AnnotationUtils; 15 | import org.springframework.core.annotation.Order; 16 | import org.springframework.stereotype.Component; 17 | 18 | import java.util.Objects; 19 | 20 | /** 21 | * 多数据源处理 22 | * 23 | * @author seat 24 | */ 25 | @Aspect 26 | @Order(1) 27 | @Component 28 | public class DataSourceAspect 29 | { 30 | protected Logger logger = LoggerFactory.getLogger(getClass()); 31 | 32 | @Pointcut("@annotation(cn.com.wudskq.annotation.DataSource)" 33 | + "|| @within(cn.com.wudskq.annotation.DataSource)") 34 | public void dsPointCut() 35 | { 36 | 37 | } 38 | 39 | @Around("dsPointCut()") 40 | public Object around(ProceedingJoinPoint point) throws Throwable 41 | { 42 | DataSource dataSource = getDataSource(point); 43 | 44 | if (StringUtils.isNotNull(dataSource)) 45 | { 46 | DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); 47 | } 48 | 49 | try 50 | { 51 | return point.proceed(); 52 | } 53 | finally 54 | { 55 | // 销毁数据源 在执行方法之后 56 | DynamicDataSourceContextHolder.clearDataSourceType(); 57 | } 58 | } 59 | 60 | /** 61 | * 获取需要切换的数据源 62 | */ 63 | public DataSource getDataSource(ProceedingJoinPoint point) 64 | { 65 | MethodSignature signature = (MethodSignature) point.getSignature(); 66 | DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); 67 | if (Objects.nonNull(dataSource)) 68 | { 69 | return dataSource; 70 | } 71 | 72 | return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/config/DruidConfig.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.config; 2 | 3 | 4 | import cn.com.wudskq.datasource.DynamicDataSource; 5 | import cn.com.wudskq.enums.DataSourceType; 6 | import cn.com.wudskq.properties.DruidProperties; 7 | import cn.com.wudskq.utils.spring.SpringUtils; 8 | import com.alibaba.druid.pool.DruidDataSource; 9 | import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; 10 | import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; 11 | import com.alibaba.druid.util.Utils; 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 13 | import org.springframework.boot.context.properties.ConfigurationProperties; 14 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 15 | import org.springframework.context.annotation.Bean; 16 | import org.springframework.context.annotation.Configuration; 17 | import org.springframework.context.annotation.Primary; 18 | 19 | import javax.servlet.*; 20 | import javax.sql.DataSource; 21 | import java.io.IOException; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | /** 26 | * druid 配置多数据源 27 | * 28 | * @author seat 29 | */ 30 | @Configuration 31 | public class DruidConfig 32 | { 33 | @Bean 34 | @ConfigurationProperties("spring.datasource.druid.master") 35 | public DataSource masterDataSource(DruidProperties druidProperties) 36 | { 37 | DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); 38 | return druidProperties.dataSource(dataSource); 39 | } 40 | 41 | @Bean 42 | @ConfigurationProperties("spring.datasource.druid.slave") 43 | @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") 44 | public DataSource slaveDataSource(DruidProperties druidProperties) 45 | { 46 | DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); 47 | return druidProperties.dataSource(dataSource); 48 | } 49 | 50 | @Bean 51 | @ConfigurationProperties("spring.datasource.druid.slave1") 52 | @ConditionalOnProperty(prefix = "spring.datasource.druid.slave1", name = "enabled", havingValue = "true") 53 | public DataSource slaveDataSource1(DruidProperties druidProperties) 54 | { 55 | DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); 56 | return druidProperties.dataSource(dataSource); 57 | } 58 | 59 | @Bean(name = "dynamicDataSource") 60 | @Primary 61 | public DynamicDataSource dataSource(DataSource masterDataSource) 62 | { 63 | Map targetDataSources = new HashMap<>(10); 64 | targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); 65 | setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); 66 | setDataSource(targetDataSources, DataSourceType.SLAVE1.name(), "slaveDataSource1"); 67 | return new DynamicDataSource(masterDataSource, targetDataSources); 68 | } 69 | 70 | /** 71 | * 设置数据源 72 | * 73 | * @param targetDataSources 备选数据源集合 74 | * @param sourceName 数据源名称 75 | * @param beanName bean名称 76 | */ 77 | public void setDataSource(Map targetDataSources, String sourceName, String beanName) 78 | { 79 | try 80 | { 81 | DataSource dataSource = SpringUtils.getBean(beanName); 82 | targetDataSources.put(sourceName, dataSource); 83 | } 84 | catch (Exception e) 85 | { 86 | } 87 | } 88 | 89 | /** 90 | * 去除监控页面底部的广告 91 | */ 92 | @SuppressWarnings({ "rawtypes", "unchecked" }) 93 | @Bean 94 | @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") 95 | public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) 96 | { 97 | // 获取web监控页面的参数 98 | DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); 99 | // 提取common.js的配置路径 100 | String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; 101 | String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); 102 | final String filePath = "support/http/resources/js/common.js"; 103 | // 创建filter进行过滤 104 | Filter filter = new Filter() 105 | { 106 | @Override 107 | public void init(javax.servlet.FilterConfig filterConfig) throws ServletException 108 | { 109 | } 110 | @Override 111 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 112 | throws IOException, ServletException 113 | { 114 | chain.doFilter(request, response); 115 | // 重置缓冲区,响应头不会被重置 116 | response.resetBuffer(); 117 | // 获取common.js 118 | String text = Utils.readFromResource(filePath); 119 | // 正则替换banner, 除去底部的广告信息 120 | text = text.replaceAll("
", ""); 121 | text = text.replaceAll("powered.*?shrek.wang", ""); 122 | response.getWriter().write(text); 123 | } 124 | @Override 125 | public void destroy() 126 | { 127 | } 128 | }; 129 | FilterRegistrationBean registrationBean = new FilterRegistrationBean(); 130 | registrationBean.setFilter(filter); 131 | registrationBean.addUrlPatterns(commonJsPattern); 132 | return registrationBean; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/controller/DruidController.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.controller; 2 | 3 | import cn.com.wudskq.sevice.impl.DruidSevice; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | /** 11 | * @author chenfangchao 12 | * @title: DruidController 13 | * @projectName boot-project 14 | * @description: TODO 15 | * @date 2022/4/2 4:33 PM 16 | */ 17 | @RestController 18 | @RequestMapping("/duird/") 19 | public class DruidController { 20 | 21 | 22 | @Autowired 23 | @Qualifier("testSeviceImpl") 24 | private DruidSevice druidSevice; 25 | 26 | @GetMapping("/master") 27 | public String master(){ 28 | return druidSevice.Master(); 29 | } 30 | 31 | @GetMapping("/slave1") 32 | public String slave1(){ 33 | return druidSevice.Slave1(); 34 | } 35 | 36 | @GetMapping("/slave2") 37 | public String slave2(){ 38 | return druidSevice.Slave2(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/core/text/CharsetKit.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.core.text; 2 | 3 | 4 | 5 | import cn.com.wudskq.utils.StringUtils; 6 | 7 | import java.nio.charset.Charset; 8 | import java.nio.charset.StandardCharsets; 9 | 10 | /** 11 | * 字符集工具类 12 | * 13 | * @author seat 14 | */ 15 | public class CharsetKit 16 | { 17 | /** ISO-8859-1 */ 18 | public static final String ISO_8859_1 = "ISO-8859-1"; 19 | /** UTF-8 */ 20 | public static final String UTF_8 = "UTF-8"; 21 | /** GBK */ 22 | public static final String GBK = "GBK"; 23 | 24 | /** ISO-8859-1 */ 25 | public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); 26 | /** UTF-8 */ 27 | public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); 28 | /** GBK */ 29 | public static final Charset CHARSET_GBK = Charset.forName(GBK); 30 | 31 | /** 32 | * 转换为Charset对象 33 | * 34 | * @param charset 字符集,为空则返回默认字符集 35 | * @return Charset 36 | */ 37 | public static Charset charset(String charset) 38 | { 39 | return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); 40 | } 41 | 42 | /** 43 | * 转换字符串的字符集编码 44 | * 45 | * @param source 字符串 46 | * @param srcCharset 源字符集,默认ISO-8859-1 47 | * @param destCharset 目标字符集,默认UTF-8 48 | * @return 转换后的字符集 49 | */ 50 | public static String convert(String source, String srcCharset, String destCharset) 51 | { 52 | return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); 53 | } 54 | 55 | /** 56 | * 转换字符串的字符集编码 57 | * 58 | * @param source 字符串 59 | * @param srcCharset 源字符集,默认ISO-8859-1 60 | * @param destCharset 目标字符集,默认UTF-8 61 | * @return 转换后的字符集 62 | */ 63 | public static String convert(String source, Charset srcCharset, Charset destCharset) 64 | { 65 | if (null == srcCharset) 66 | { 67 | srcCharset = StandardCharsets.ISO_8859_1; 68 | } 69 | 70 | if (null == destCharset) 71 | { 72 | destCharset = StandardCharsets.UTF_8; 73 | } 74 | 75 | if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) 76 | { 77 | return source; 78 | } 79 | return new String(source.getBytes(srcCharset), destCharset); 80 | } 81 | 82 | /** 83 | * @return 系统字符集编码 84 | */ 85 | public static String systemCharset() 86 | { 87 | return Charset.defaultCharset().name(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/core/text/StrFormatter.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.core.text; 2 | 3 | 4 | import cn.com.wudskq.utils.StringUtils; 5 | 6 | /** 7 | * 字符串格式化 8 | * 9 | * @author seat 10 | */ 11 | public class StrFormatter 12 | { 13 | public static final String EMPTY_JSON = "{}"; 14 | public static final char C_BACKSLASH = '\\'; 15 | public static final char C_DELIM_START = '{'; 16 | public static final char C_DELIM_END = '}'; 17 | 18 | /** 19 | * 格式化字符串
20 | * 此方法只是简单将占位符 {} 按照顺序替换为参数
21 | * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
22 | * 例:
23 | * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
24 | * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
25 | * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
26 | * 27 | * @param strPattern 字符串模板 28 | * @param argArray 参数列表 29 | * @return 结果 30 | */ 31 | public static String format(final String strPattern, final Object... argArray) 32 | { 33 | if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) 34 | { 35 | return strPattern; 36 | } 37 | final int strPatternLength = strPattern.length(); 38 | 39 | // 初始化定义好的长度以获得更好的性能 40 | StringBuilder sbuf = new StringBuilder(strPatternLength + 50); 41 | 42 | int handledPosition = 0; 43 | int delimIndex;// 占位符所在位置 44 | for (int argIndex = 0; argIndex < argArray.length; argIndex++) 45 | { 46 | delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); 47 | if (delimIndex == -1) 48 | { 49 | if (handledPosition == 0) 50 | { 51 | return strPattern; 52 | } 53 | else 54 | { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 55 | sbuf.append(strPattern, handledPosition, strPatternLength); 56 | return sbuf.toString(); 57 | } 58 | } 59 | else 60 | { 61 | if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) 62 | { 63 | if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) 64 | { 65 | // 转义符之前还有一个转义符,占位符依旧有效 66 | sbuf.append(strPattern, handledPosition, delimIndex - 1); 67 | sbuf.append(Convert.utf8Str(argArray[argIndex])); 68 | handledPosition = delimIndex + 2; 69 | } 70 | else 71 | { 72 | // 占位符被转义 73 | argIndex--; 74 | sbuf.append(strPattern, handledPosition, delimIndex - 1); 75 | sbuf.append(C_DELIM_START); 76 | handledPosition = delimIndex + 1; 77 | } 78 | } 79 | else 80 | { 81 | // 正常占位符 82 | sbuf.append(strPattern, handledPosition, delimIndex); 83 | sbuf.append(Convert.utf8Str(argArray[argIndex])); 84 | handledPosition = delimIndex + 2; 85 | } 86 | } 87 | } 88 | // 加入最后一个占位符后所有的字符 89 | sbuf.append(strPattern, handledPosition, strPattern.length()); 90 | 91 | return sbuf.toString(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/datasource/DynamicDataSource.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.datasource; 2 | 3 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 4 | 5 | import javax.sql.DataSource; 6 | import java.util.Map; 7 | 8 | /** 9 | * 动态数据源 10 | * 11 | * @author seat 12 | */ 13 | public class DynamicDataSource extends AbstractRoutingDataSource 14 | { 15 | public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) 16 | { 17 | super.setDefaultTargetDataSource(defaultTargetDataSource); 18 | super.setTargetDataSources(targetDataSources); 19 | super.afterPropertiesSet(); 20 | } 21 | 22 | @Override 23 | protected Object determineCurrentLookupKey() 24 | { 25 | return DynamicDataSourceContextHolder.getDataSourceType(); 26 | } 27 | } -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/datasource/DynamicDataSourceContextHolder.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.datasource; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | /** 7 | * 数据源切换处理 8 | * 9 | * @author seat 10 | */ 11 | public class DynamicDataSourceContextHolder 12 | { 13 | public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); 14 | 15 | /** 16 | * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, 17 | * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 18 | */ 19 | private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); 20 | 21 | /** 22 | * 设置数据源的变量 23 | */ 24 | public static void setDataSourceType(String dsType) 25 | { 26 | log.info("切换到{}数据源", dsType); 27 | CONTEXT_HOLDER.set(dsType); 28 | } 29 | 30 | /** 31 | * 获得数据源的变量 32 | */ 33 | public static String getDataSourceType() 34 | { 35 | return CONTEXT_HOLDER.get(); 36 | } 37 | 38 | /** 39 | * 清空数据源变量 40 | */ 41 | public static void clearDataSourceType() 42 | { 43 | CONTEXT_HOLDER.remove(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/enums/DataSourceType.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.enums; 2 | 3 | /** 4 | * 数据源 5 | * 6 | * @author seat 7 | */ 8 | public enum DataSourceType 9 | { 10 | /** 11 | * 主库 12 | */ 13 | MASTER, 14 | 15 | /** 16 | * 从库 17 | */ 18 | SLAVE, 19 | 20 | /** 21 | * 从库 postgres 22 | */ 23 | SLAVE1 24 | } 25 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/mapper/DruidMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.mapper; 2 | 3 | import cn.com.wudskq.annotation.DataSource; 4 | import cn.com.wudskq.enums.DataSourceType; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | /** 8 | * @author chenfangchao 9 | * @title: DruidMapper 10 | * @projectName boot-project 11 | * @description: TODO 12 | * @date 2022/4/2 3:38 PM 13 | */ 14 | @Mapper 15 | public interface DruidMapper { 16 | 17 | //测试主数据源 18 | @DataSource(DataSourceType.MASTER) 19 | String masterDateSource(); 20 | 21 | //测试从数据源 22 | @DataSource(DataSourceType.SLAVE) 23 | String salve1DateSource(); 24 | 25 | //测试从数据源 26 | @DataSource(DataSourceType.SLAVE1) 27 | String slave2DateSource(); 28 | } 29 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/properties/DruidProperties.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.properties; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * druid 配置属性 9 | * TODO 链接池配置 10 | * @author seat 11 | */ 12 | @Configuration 13 | public class DruidProperties 14 | { 15 | @Value("${spring.datasource.druid.initialSize}") 16 | private int initialSize; 17 | 18 | @Value("${spring.datasource.druid.minIdle}") 19 | private int minIdle; 20 | 21 | @Value("${spring.datasource.druid.maxActive}") 22 | private int maxActive; 23 | 24 | @Value("${spring.datasource.druid.maxWait}") 25 | private int maxWait; 26 | 27 | @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") 28 | private int timeBetweenEvictionRunsMillis; 29 | 30 | @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") 31 | private int minEvictableIdleTimeMillis; 32 | 33 | @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") 34 | private int maxEvictableIdleTimeMillis; 35 | 36 | @Value("${spring.datasource.druid.validationQuery}") 37 | private String validationQuery; 38 | 39 | @Value("${spring.datasource.druid.testWhileIdle}") 40 | private boolean testWhileIdle; 41 | 42 | @Value("${spring.datasource.druid.testOnBorrow}") 43 | private boolean testOnBorrow; 44 | 45 | @Value("${spring.datasource.druid.testOnReturn}") 46 | private boolean testOnReturn; 47 | 48 | public DruidDataSource dataSource(DruidDataSource datasource) 49 | { 50 | /** 配置初始化大小、最小、最大 */ 51 | datasource.setInitialSize(initialSize); 52 | datasource.setMaxActive(maxActive); 53 | datasource.setMinIdle(minIdle); 54 | 55 | /** 配置获取连接等待超时的时间 */ 56 | datasource.setMaxWait(maxWait); 57 | 58 | /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ 59 | datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); 60 | 61 | /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ 62 | datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); 63 | datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); 64 | 65 | /** 66 | * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 67 | */ 68 | datasource.setValidationQuery(validationQuery); 69 | /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ 70 | datasource.setTestWhileIdle(testWhileIdle); 71 | /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ 72 | datasource.setTestOnBorrow(testOnBorrow); 73 | /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ 74 | datasource.setTestOnReturn(testOnReturn); 75 | return datasource; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/sevice/impl/DruidSevice.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Qualifier; 4 | import org.springframework.stereotype.Service; 5 | 6 | /** 7 | * @author chenfangchao 8 | * @title: DruidSevice 9 | * @projectName boot-project 10 | * @description: TODO 11 | * @date 2022/4/2 4:45 PM 12 | */ 13 | @Service 14 | @Qualifier("testSevice") 15 | public interface DruidSevice { 16 | 17 | String Master(); 18 | 19 | String Slave1(); 20 | 21 | String Slave2(); 22 | } 23 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/sevice/impl/DruidSeviceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.impl; 2 | 3 | import cn.com.wudskq.mapper.DruidMapper; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.stereotype.Service; 7 | 8 | /** 9 | * @author chenfangchao 10 | * @title: DruidSeviceImpl 11 | * @projectName boot-project 12 | * @description: TODO 13 | * @date 2022/4/2 4:46 PM 14 | */ 15 | @Service 16 | @Qualifier("testSeviceImpl") 17 | public class DruidSeviceImpl implements DruidSevice{ 18 | 19 | @Autowired 20 | private DruidMapper druidMapper; 21 | 22 | @Override 23 | public String Master() { 24 | return druidMapper.masterDateSource(); 25 | } 26 | 27 | @Override 28 | public String Slave1() { 29 | return druidMapper.salve1DateSource(); 30 | } 31 | 32 | @Override 33 | public String Slave2() { 34 | return druidMapper.slave2DateSource(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.utils; 2 | 3 | 4 | import cn.com.wudskq.core.text.StrFormatter; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * 字符串工具类 10 | * 11 | * @author seat 12 | */ 13 | public class StringUtils extends org.apache.commons.lang3.StringUtils 14 | { 15 | /** 空字符串 */ 16 | private static final String NULLSTR = ""; 17 | 18 | /** 下划线 */ 19 | private static final char SEPARATOR = '_'; 20 | private static final String XIA = "_"; 21 | 22 | /** 23 | * 获取参数不为空值 24 | * 25 | * @param value defaultValue 要判断的value 26 | * @return value 返回值 27 | */ 28 | public static T nvl(T value, T defaultValue) 29 | { 30 | return value != null ? value : defaultValue; 31 | } 32 | 33 | /** 34 | * * 判断一个Collection是否为空, 包含List,Set,Queue 35 | * 36 | * @param coll 要判断的Collection 37 | * @return true:为空 false:非空 38 | */ 39 | public static boolean isEmpty(Collection coll) 40 | { 41 | return isNull(coll) || coll.isEmpty(); 42 | } 43 | 44 | /** 45 | * * 判断一个Collection是否非空,包含List,Set,Queue 46 | * 47 | * @param coll 要判断的Collection 48 | * @return true:非空 false:空 49 | */ 50 | public static boolean isNotEmpty(Collection coll) 51 | { 52 | return !isEmpty(coll); 53 | } 54 | 55 | /** 56 | * * 判断一个对象数组是否为空 57 | * 58 | * @param objects 要判断的对象数组 59 | ** @return true:为空 false:非空 60 | */ 61 | public static boolean isEmpty(Object[] objects) 62 | { 63 | return isNull(objects) || (objects.length == 0); 64 | } 65 | 66 | /** 67 | * * 判断一个对象数组是否非空 68 | * 69 | * @param objects 要判断的对象数组 70 | * @return true:非空 false:空 71 | */ 72 | public static boolean isNotEmpty(Object[] objects) 73 | { 74 | return !isEmpty(objects); 75 | } 76 | 77 | /** 78 | * * 判断一个Map是否为空 79 | * 80 | * @param map 要判断的Map 81 | * @return true:为空 false:非空 82 | */ 83 | public static boolean isEmpty(Map map) 84 | { 85 | return isNull(map) || map.isEmpty(); 86 | } 87 | 88 | /** 89 | * * 判断一个Map是否为空 90 | * 91 | * @param map 要判断的Map 92 | * @return true:非空 false:空 93 | */ 94 | public static boolean isNotEmpty(Map map) 95 | { 96 | return !isEmpty(map); 97 | } 98 | 99 | /** 100 | * * 判断一个字符串是否为空串 101 | * 102 | * @param str String 103 | * @return true:为空 false:非空 104 | */ 105 | public static boolean isEmpty(String str) 106 | { 107 | return isNull(str) || NULLSTR.equals(str.trim()); 108 | } 109 | 110 | /** 111 | * * 判断一个字符串是否为非空串 112 | * 113 | * @param str String 114 | * @return true:非空串 false:空串 115 | */ 116 | public static boolean isNotEmpty(String str) 117 | { 118 | return !isEmpty(str); 119 | } 120 | 121 | /** 122 | * * 判断一个对象是否为空 123 | * 124 | * @param object Object 125 | * @return true:为空 false:非空 126 | */ 127 | public static boolean isNull(Object object) 128 | { 129 | return object == null; 130 | } 131 | 132 | /** 133 | * * 判断一个对象是否非空 134 | * 135 | * @param object Object 136 | * @return true:非空 false:空 137 | */ 138 | public static boolean isNotNull(Object object) 139 | { 140 | return !isNull(object); 141 | } 142 | 143 | /** 144 | * * 判断一个对象是否是数组类型(Java基本型别的数组) 145 | * 146 | * @param object 对象 147 | * @return true:是数组 false:不是数组 148 | */ 149 | public static boolean isArray(Object object) 150 | { 151 | return isNotNull(object) && object.getClass().isArray(); 152 | } 153 | 154 | /** 155 | * 去空格 156 | */ 157 | public static String trim(String str) 158 | { 159 | return (str == null ? "" : str.trim()); 160 | } 161 | 162 | /** 163 | * 截取字符串 164 | * 165 | * @param str 字符串 166 | * @param start 开始 167 | * @return 结果 168 | */ 169 | public static String substring(final String str, int start) 170 | { 171 | if (str == null) 172 | { 173 | return NULLSTR; 174 | } 175 | 176 | if (start < 0) 177 | { 178 | start = str.length() + start; 179 | } 180 | 181 | if (start < 0) 182 | { 183 | start = 0; 184 | } 185 | if (start > str.length()) 186 | { 187 | return NULLSTR; 188 | } 189 | 190 | return str.substring(start); 191 | } 192 | 193 | /** 194 | * 截取字符串 195 | * 196 | * @param str 字符串 197 | * @param start 开始 198 | * @param end 结束 199 | * @return 结果 200 | */ 201 | public static String substring(final String str, int start, int end) 202 | { 203 | if (str == null) 204 | { 205 | return NULLSTR; 206 | } 207 | 208 | if (end < 0) 209 | { 210 | end = str.length() + end; 211 | } 212 | if (start < 0) 213 | { 214 | start = str.length() + start; 215 | } 216 | 217 | if (end > str.length()) 218 | { 219 | end = str.length(); 220 | } 221 | 222 | if (start > end) 223 | { 224 | return NULLSTR; 225 | } 226 | 227 | if (start < 0) 228 | { 229 | start = 0; 230 | } 231 | if (end < 0) 232 | { 233 | end = 0; 234 | } 235 | 236 | return str.substring(start, end); 237 | } 238 | 239 | /** 240 | * 格式化文本, {} 表示占位符
241 | * 此方法只是简单将占位符 {} 按照顺序替换为参数
242 | * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
243 | * 例:
244 | * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
245 | * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
246 | * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
247 | * 248 | * @param template 文本模板,被替换的部分用 {} 表示 249 | * @param params 参数值 250 | * @return 格式化后的文本 251 | */ 252 | public static String format(String template, Object... params) 253 | { 254 | if (isEmpty(params) || isEmpty(template)) 255 | { 256 | return template; 257 | } 258 | return StrFormatter.format(template, params); 259 | } 260 | 261 | /** 262 | * 字符串转set 263 | * 264 | * @param str 字符串 265 | * @param sep 分隔符 266 | * @return set集合 267 | */ 268 | public static final Set str2Set(String str, String sep) 269 | { 270 | return new HashSet(str2List(str, sep, true, false)); 271 | } 272 | 273 | /** 274 | * 字符串转list 275 | * 276 | * @param str 字符串 277 | * @param sep 分隔符 278 | * @param filterBlank 过滤纯空白 279 | * @param trim 去掉首尾空白 280 | * @return list集合 281 | */ 282 | public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) 283 | { 284 | List list = new ArrayList(); 285 | if (StringUtils.isEmpty(str)) 286 | { 287 | return list; 288 | } 289 | 290 | // 过滤空白字符串 291 | if (filterBlank && StringUtils.isBlank(str)) 292 | { 293 | return list; 294 | } 295 | String[] split = str.split(sep); 296 | for (String string : split) 297 | { 298 | if (filterBlank && StringUtils.isBlank(string)) 299 | { 300 | continue; 301 | } 302 | if (trim) 303 | { 304 | string = string.trim(); 305 | } 306 | list.add(string); 307 | } 308 | 309 | return list; 310 | } 311 | 312 | /** 313 | * 驼峰转下划线命名 314 | */ 315 | public static String toUnderScoreCase(String str) 316 | { 317 | if (str == null) 318 | { 319 | return null; 320 | } 321 | StringBuilder sb = new StringBuilder(); 322 | // 前置字符是否大写 323 | boolean preCharIsUpperCase = true; 324 | // 当前字符是否大写 325 | boolean curreCharIsUpperCase = true; 326 | // 下一字符是否大写 327 | boolean nexteCharIsUpperCase = true; 328 | for (int i = 0; i < str.length(); i++) 329 | { 330 | char c = str.charAt(i); 331 | if (i > 0) 332 | { 333 | preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); 334 | } 335 | else 336 | { 337 | preCharIsUpperCase = false; 338 | } 339 | 340 | curreCharIsUpperCase = Character.isUpperCase(c); 341 | 342 | if (i < (str.length() - 1)) 343 | { 344 | nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); 345 | } 346 | 347 | if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) 348 | { 349 | sb.append(SEPARATOR); 350 | } 351 | else if (i != 0 && !preCharIsUpperCase) 352 | { 353 | if (curreCharIsUpperCase){ 354 | sb.append(SEPARATOR); 355 | } 356 | } 357 | sb.append(Character.toLowerCase(c)); 358 | } 359 | 360 | return sb.toString(); 361 | } 362 | 363 | /** 364 | * 是否包含字符串 365 | * 366 | * @param str 验证字符串 367 | * @param strs 字符串组 368 | * @return 包含返回true 369 | */ 370 | public static boolean inStringIgnoreCase(String str, String... strs) 371 | { 372 | if (str != null && strs != null) 373 | { 374 | for (String s : strs) 375 | { 376 | if (str.equalsIgnoreCase(trim(s))) 377 | { 378 | return true; 379 | } 380 | } 381 | } 382 | return false; 383 | } 384 | 385 | /** 386 | * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld 387 | * 388 | * @param name 转换前的下划线大写方式命名的字符串 389 | * @return 转换后的驼峰式命名的字符串 390 | */ 391 | public static String convertToCamelCase(String name) 392 | { 393 | StringBuilder result = new StringBuilder(); 394 | // 快速检查 395 | if (name == null || name.isEmpty()) 396 | { 397 | // 没必要转换 398 | return ""; 399 | } 400 | else if (!name.contains(XIA)) 401 | { 402 | // 不含下划线,仅将首字母大写 403 | return name.substring(0, 1).toUpperCase() + name.substring(1); 404 | } 405 | // 用下划线将原始字符串分割 406 | String[] camels = name.split("_"); 407 | for (String camel : camels) 408 | { 409 | // 跳过原始字符串中开头、结尾的下换线或双重下划线 410 | if (camel.isEmpty()) 411 | { 412 | continue; 413 | } 414 | // 首字母大写 415 | result.append(camel.substring(0, 1).toUpperCase()); 416 | result.append(camel.substring(1).toLowerCase()); 417 | } 418 | return result.toString(); 419 | } 420 | 421 | /** 422 | * 驼峰式命名法 例如:user_name->userName 423 | */ 424 | public static String toCamelCase(String s) 425 | { 426 | if (s == null) 427 | { 428 | return null; 429 | } 430 | s = s.toLowerCase(); 431 | StringBuilder sb = new StringBuilder(s.length()); 432 | boolean upperCase = false; 433 | for (int i = 0; i < s.length(); i++) 434 | { 435 | char c = s.charAt(i); 436 | 437 | if (c == SEPARATOR) 438 | { 439 | upperCase = true; 440 | } 441 | else if (upperCase) 442 | { 443 | sb.append(Character.toUpperCase(c)); 444 | upperCase = false; 445 | } 446 | else 447 | { 448 | sb.append(c); 449 | } 450 | } 451 | return sb.toString(); 452 | } 453 | 454 | @SuppressWarnings("unchecked") 455 | public static T cast(Object obj) 456 | { 457 | return (T) obj; 458 | } 459 | } -------------------------------------------------------------------------------- /boot-datasource/src/main/java/cn/com/wudskq/utils/spring/SpringUtils.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.utils.spring; 2 | 3 | import cn.com.wudskq.utils.StringUtils; 4 | import org.springframework.aop.framework.AopContext; 5 | import org.springframework.beans.BeansException; 6 | import org.springframework.beans.factory.NoSuchBeanDefinitionException; 7 | import org.springframework.beans.factory.config.BeanFactoryPostProcessor; 8 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.context.ApplicationContextAware; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * spring工具类 方便在非spring管理环境中获取bean 15 | * 16 | * @author seat 17 | */ 18 | @Component 19 | public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware 20 | { 21 | /** Spring应用上下文环境 */ 22 | private static ConfigurableListableBeanFactory beanFactory; 23 | 24 | private static ApplicationContext applicationContext; 25 | 26 | @Override 27 | public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException 28 | { 29 | SpringUtils.beanFactory = beanFactory; 30 | } 31 | 32 | @Override 33 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 34 | { 35 | SpringUtils.applicationContext = applicationContext; 36 | } 37 | 38 | /** 39 | * 获取对象 40 | * 41 | * @param name 42 | * @return Object 一个以所给名字注册的bean的实例 43 | * @throws BeansException 44 | * 45 | */ 46 | @SuppressWarnings("unchecked") 47 | public static T getBean(String name) throws BeansException 48 | { 49 | return (T) beanFactory.getBean(name); 50 | } 51 | 52 | /** 53 | * 获取类型为requiredType的对象 54 | * 55 | * @param clz 56 | * @return 57 | * @throws BeansException 58 | * 59 | */ 60 | public static T getBean(Class clz) throws BeansException 61 | { 62 | T result = (T) beanFactory.getBean(clz); 63 | return result; 64 | } 65 | 66 | /** 67 | * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true 68 | * 69 | * @param name 70 | * @return boolean 71 | */ 72 | public static boolean containsBean(String name) 73 | { 74 | return beanFactory.containsBean(name); 75 | } 76 | 77 | /** 78 | * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) 79 | * 80 | * @param name 81 | * @return boolean 82 | * @throws NoSuchBeanDefinitionException 83 | * 84 | */ 85 | public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException 86 | { 87 | return beanFactory.isSingleton(name); 88 | } 89 | 90 | /** 91 | * @param name 92 | * @return Class 注册对象的类型 93 | * @throws NoSuchBeanDefinitionException 94 | * 95 | */ 96 | public static Class getType(String name) throws NoSuchBeanDefinitionException 97 | { 98 | return beanFactory.getType(name); 99 | } 100 | 101 | /** 102 | * 如果给定的bean名字在bean定义中有别名,则返回这些别名 103 | * 104 | * @param name 105 | * @return 106 | * @throws NoSuchBeanDefinitionException 107 | * 108 | */ 109 | public static String[] getAliases(String name) throws NoSuchBeanDefinitionException 110 | { 111 | return beanFactory.getAliases(name); 112 | } 113 | 114 | /** 115 | * 获取aop代理对象 116 | * 117 | * @param invoker 118 | * @return 119 | */ 120 | @SuppressWarnings("unchecked") 121 | public static T getAopProxy(T invoker) 122 | { 123 | return (T) AopContext.currentProxy(); 124 | } 125 | 126 | /** 127 | * 获取当前的环境配置,无配置返回null 128 | * 129 | * @return 当前的环境配置 130 | */ 131 | public static String[] getActiveProfiles() 132 | { 133 | return applicationContext.getEnvironment().getActiveProfiles(); 134 | } 135 | 136 | /** 137 | * 获取当前的环境配置,当有多个环境配置时,只获取第一个 138 | * 139 | * @return 当前的环境配置 140 | */ 141 | public static String getActiveProfile() 142 | { 143 | final String[] activeProfiles = getActiveProfiles(); 144 | return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /boot-datasource/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #端口配置 2 | server: 3 | port: 8081 4 | 5 | #多数据源配置 6 | spring: 7 | datasource: 8 | druid: 9 | master: 10 | type: com.alibaba.druid.pool.DruidDataSource 11 | driverClassName: com.mysql.cj.jdbc.Driver 12 | url: jdbc:mysql://localhost:3306/dev_database?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 13 | username: root 14 | password: root 15 | slave: 16 | type: com.alibaba.druid.pool.DruidDataSource 17 | driverClassName: com.mysql.cj.jdbc.Driver 18 | # 从数据源开关/默认关闭 19 | enabled: true 20 | url: jdbc:mysql://localhost:3306/dev_database1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 21 | username: root 22 | password: root 23 | slave1: 24 | type: com.alibaba.druid.pool.DruidDataSource 25 | driverClassName: com.mysql.cj.jdbc.Driver 26 | enabled: true 27 | url: jdbc:mysql://localhost:3306/dev_database2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 28 | username: root 29 | password: root 30 | # 初始连接数 31 | initialSize: 5 32 | # 最小连接池数量 33 | minIdle: 10 34 | # 最大连接池数量 35 | maxActive: 20 36 | # 配置获取连接等待超时的时间 37 | maxWait: 60000 38 | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 39 | timeBetweenEvictionRunsMillis: 60000 40 | # 配置一个连接在池中最小生存的时间,单位是毫秒 41 | minEvictableIdleTimeMillis: 300000 42 | # 配置一个连接在池中最大生存的时间,单位是毫秒 43 | maxEvictableIdleTimeMillis: 900000 44 | # 配置检测连接是否有效 45 | validationQuery: SELECT 1 46 | testWhileIdle: true 47 | testOnBorrow: false 48 | testOnReturn: false 49 | webStatFilter: 50 | enabled: true 51 | statViewServlet: 52 | enabled: true 53 | # 设置白名单,不填则允许所有访问 54 | allow: 55 | url-pattern: /druid/* 56 | # 控制台管理用户名和密码 57 | login-username: admin 58 | login-password: 123456 59 | filter: 60 | stat: 61 | enabled: true 62 | # 慢SQL记录 63 | log-slow-sql: true 64 | slow-sql-millis: 1000 65 | merge-sql: true 66 | wall: 67 | config: 68 | multi-statement-allow: true 69 | mybatis-plus: 70 | # 搜索指定包别名 71 | # typeAliasesPackage: cn.com.wudskq 72 | # 配置mapper的扫描,找到所有的mapper.xml映射文件 73 | mapperLocations: classpath*:mapper/*Mapper.xml 74 | # 加载全局的配置文件 75 | # configLocation: classpath:mybatis/mybatis-config.xml 76 | # 打印日志 77 | # configuration: 78 | # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 79 | configuration: 80 | #这个配置会将执行的sql打印出来,在开发或测试的时候可以用 81 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 82 | #返回类型为Map,显示null对应的字段 83 | call-setters-on-nulls: true 84 | global-config: 85 | db-config: 86 | logic-delete-field: delFlag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) 87 | logic-delete-value: 1 # 逻辑已删除值(默认为 ) 88 | logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) 89 | id-type: assign_id -------------------------------------------------------------------------------- /boot-datasource/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ${log.pattern} 14 | 15 | 16 | 17 | 18 | 19 | ${log.path}/sys-info.log 20 | 21 | 22 | 23 | ${log.path}/sys-info.%d{yyyy-MM-dd}.log 24 | 25 | 60 26 | 27 | 28 | ${log.pattern} 29 | 30 | 31 | 32 | INFO 33 | 34 | ACCEPT 35 | 36 | DENY 37 | 38 | 39 | 40 | 41 | ${log.path}/sys-error.log 42 | 43 | 44 | 45 | ${log.path}/sys-error.%d{yyyy-MM-dd}.log 46 | 47 | 60 48 | 49 | 50 | ${log.pattern} 51 | 52 | 53 | 54 | ERROR 55 | 56 | ACCEPT 57 | 58 | DENY 59 | 60 | 61 | 62 | 63 | 64 | ${log.path}/sys-user.log 65 | 66 | 67 | ${log.path}/sys-user.%d{yyyy-MM-dd}.log 68 | 69 | 60 70 | 71 | 72 | ${log.pattern} 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /boot-datasource/src/main/resources/mapper/DruidMapper.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 16 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /boot-datasource/src/main/resources/sql/druid.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `druid` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT, 3 | `name` varchar(255) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; -------------------------------------------------------------------------------- /boot-datasource/src/test/java/cn/com/wudskq/DruidSourceTest.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | 4 | import cn.com.wudskq.mapper.DruidMapper; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | 11 | /** 12 | * @author chenfangchao 13 | * @title: DruidSourceTest 14 | * @projectName boot-project 15 | * @description: TODO 16 | * @date 2022/4/2 3:46 PM 17 | */ 18 | @RunWith(SpringRunner.class) 19 | @SpringBootTest 20 | public class DruidSourceTest { 21 | 22 | 23 | //sh start.sh 24 | 25 | @Autowired 26 | private DruidMapper druidMapper; 27 | 28 | @Test 29 | public void testMaster(){ 30 | System.out.println(druidMapper.masterDateSource()); 31 | } 32 | 33 | @Test 34 | public void testSlave1(){ 35 | System.out.println(druidMapper.salve1DateSource()); 36 | } 37 | 38 | @Test 39 | public void testSlave2(){ 40 | System.out.println(druidMapper.slave2DateSource()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /boot-kafka/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-kafka 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | 21 | 22 | org.springframework.kafka 23 | spring-kafka 24 | 25 | 26 | 27 | org.apache.kafka 28 | kafka-clients 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | org.slf4j 43 | slf4j-api 44 | 45 | 46 | 47 | org.slf4j 48 | slf4j-log4j12 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /boot-kafka/src/main/java/cn/com/wudskq/BootKafkaApplication.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author chenfangchao 8 | * @title: BootKafkaApplication 9 | * @projectName boot-project 10 | * @description: TODO 11 | * @date 2022/4/7 2:54 AM 12 | */ 13 | @SpringBootApplication 14 | public class BootKafkaApplication { 15 | public static void main(String[] args) { 16 | SpringApplication.run(BootKafkaApplication.class,args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /boot-kafka/src/main/java/cn/com/wudskq/config/KafkaOneConfig.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.config; 2 | 3 | import org.apache.kafka.clients.CommonClientConfigs; 4 | import org.apache.kafka.clients.consumer.ConsumerConfig; 5 | import org.apache.kafka.clients.producer.ProducerConfig; 6 | import org.apache.kafka.common.config.SaslConfigs; 7 | import org.apache.kafka.common.serialization.StringDeserializer; 8 | import org.apache.kafka.common.serialization.StringSerializer; 9 | import org.springframework.beans.factory.NamedBean; 10 | import org.springframework.beans.factory.annotation.Qualifier; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.kafka.annotation.EnableKafka; 15 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 16 | import org.springframework.kafka.config.KafkaListenerContainerFactory; 17 | import org.springframework.kafka.core.*; 18 | import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | /** 24 | * @author chenfangchao 25 | * @title: KafkaOneConfig 26 | * @projectName boot-project 27 | * @description: TODO 28 | * @date 2022/4/7 4:47 AM 29 | */ 30 | @EnableKafka 31 | @Configuration 32 | public class KafkaOneConfig { 33 | 34 | //集群服务 35 | @Value("${spring.kafka.bootstrap-servers}") 36 | private String bootstrapServers; 37 | 38 | //是否自动提交 39 | @Value("${spring.kafka.consumer.enable-auto-commit}") 40 | private boolean enableAutoCommit; 41 | 42 | //自动提交的时间间隔 ms 43 | private final int autoCommitInterval = 1000; 44 | 45 | //下次读取topic位置 46 | @Value("${spring.kafka.consumer.auto-offset-reset}") 47 | private String autoOffsetReset; 48 | 49 | 50 | public static final String USER_NAME = "admin"; 51 | 52 | public static final String PASS_WORD = "admin"; 53 | 54 | @Bean(value = "kafkaOneTemplate") 55 | public KafkaTemplate kafkaOneTemplate() { 56 | return new KafkaTemplate<>(producerFactory()); 57 | } 58 | 59 | @Bean 60 | KafkaListenerContainerFactory> kafkaOneContainerFactory() { 61 | ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); 62 | factory.setConsumerFactory(consumerFactory()); 63 | factory.setConcurrency(3); 64 | factory.getContainerProperties().setPollTimeout(3000); 65 | return factory; 66 | } 67 | 68 | private ProducerFactory producerFactory() { 69 | return new DefaultKafkaProducerFactory<>(producerConfigs()); 70 | } 71 | 72 | public ConsumerFactory consumerFactory() { 73 | return new DefaultKafkaConsumerFactory<>(consumerConfigs()); 74 | } 75 | 76 | private Map producerConfigs() { 77 | Map props = new HashMap<>(); 78 | props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); 79 | props.put(ProducerConfig.RETRIES_CONFIG, 3); 80 | props.put(ProducerConfig.ACKS_CONFIG, "1"); 81 | props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 82 | props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 83 | //protocol 84 | props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG,"SASL_PLAINTEXT"); 85 | //sasl 86 | props.put(SaslConfigs.SASL_MECHANISM,"SCRAM-SHA-512"); 87 | String jassc = "org.apache.kafka.common.security.scram.ScramLoginModule required\n" 88 | + "username = \"" + USER_NAME + "\"\n" 89 | + "password =\"" + PASS_WORD + "\";"; 90 | props.put(SaslConfigs.SASL_JAAS_CONFIG,jassc); 91 | return props; 92 | } 93 | 94 | private Map consumerConfigs() { 95 | Map props = new HashMap<>(); 96 | props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); 97 | props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, enableAutoCommit); 98 | props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitInterval); 99 | props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset); 100 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 101 | props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 102 | //protocol 103 | props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG,"SASL_PLAINTEXT"); 104 | //sasl 105 | props.put(SaslConfigs.SASL_MECHANISM,"SCRAM-SHA-512"); 106 | String jassc = "org.apache.kafka.common.security.scram.ScramLoginModule required\n" 107 | + "username = \"" + USER_NAME + "\"\n" 108 | + "password =\"" + PASS_WORD + "\";"; 109 | props.put(SaslConfigs.SASL_JAAS_CONFIG,jassc); 110 | //listener-监听线程池 111 | props.put("concurrency",5); 112 | props.put("ackMode","manual_immediate"); 113 | props.put("topicsFatal",false); 114 | return props; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /boot-kafka/src/main/java/cn/com/wudskq/config/KafkaTwoConfig.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.config; 2 | 3 | import org.apache.kafka.clients.CommonClientConfigs; 4 | import org.apache.kafka.clients.consumer.ConsumerConfig; 5 | import org.apache.kafka.clients.producer.ProducerConfig; 6 | import org.apache.kafka.common.config.SaslConfigs; 7 | import org.apache.kafka.common.serialization.StringDeserializer; 8 | import org.apache.kafka.common.serialization.StringSerializer; 9 | import org.springframework.beans.factory.annotation.Qualifier; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | import org.springframework.kafka.annotation.EnableKafka; 14 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 15 | import org.springframework.kafka.config.KafkaListenerContainerFactory; 16 | import org.springframework.kafka.core.*; 17 | import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | /** 23 | * @author chenfangchao 24 | * @title: KafkaTwoConfig 25 | * @projectName boot-project 26 | * @description: TODO 27 | * @date 2022/4/7 5:13 AM 28 | */ 29 | @Configuration 30 | public class KafkaTwoConfig { 31 | 32 | //集群服务 33 | @Value("${spring.kafka.bootstrap-servers}") 34 | private String bootstrapServers; 35 | 36 | //是否自动提交 37 | @Value("${spring.kafka.consumer.enable-auto-commit}") 38 | private boolean enableAutoCommit; 39 | 40 | //自动提交的时间间隔 ms 41 | private final int autoCommitInterval = 1000; 42 | 43 | //下次读取topic位置 44 | @Value("${spring.kafka.consumer.auto-offset-reset}") 45 | private String autoOffsetReset; 46 | 47 | //批量拉取记录数 48 | private final String maxPollRecordsConfig = "100"; 49 | 50 | public static final String USER_NAME = "admin"; 51 | 52 | public static final String PASS_WORD = "admin"; 53 | 54 | 55 | @Bean(value = "kafkaTwoTemplate") 56 | public KafkaTemplate kafkaTwoTemplate() { 57 | return new KafkaTemplate<>(producerFactory()); 58 | } 59 | 60 | @Bean 61 | KafkaListenerContainerFactory> kafkaTwoContainerFactory() { 62 | ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); 63 | factory.setConsumerFactory(consumerFactory()); 64 | factory.setBatchListener(true); 65 | factory.getContainerProperties().setPollTimeout(3000); 66 | return factory; 67 | } 68 | 69 | private ProducerFactory producerFactory() { 70 | return new DefaultKafkaProducerFactory<>(producerConfigs()); 71 | } 72 | 73 | public ConsumerFactory consumerFactory() { 74 | return new DefaultKafkaConsumerFactory<>(consumerConfigs()); 75 | } 76 | 77 | private Map producerConfigs() { 78 | Map props = new HashMap<>(); 79 | props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); 80 | props.put(ProducerConfig.RETRIES_CONFIG, 3); 81 | props.put(ProducerConfig.ACKS_CONFIG, "1"); 82 | props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 83 | props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 84 | //protocol 85 | props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG,"SASL_PLAINTEXT"); 86 | //sasl 87 | props.put(SaslConfigs.SASL_MECHANISM,"SCRAM-SHA-512"); 88 | String jassc = "org.apache.kafka.common.security.scram.ScramLoginModule required\n" 89 | + "username = \"" + USER_NAME + "\"\n" 90 | + "password =\"" + PASS_WORD + "\";"; 91 | props.put(SaslConfigs.SASL_JAAS_CONFIG,jassc); 92 | return props; 93 | } 94 | 95 | private Map consumerConfigs() { 96 | Map props = new HashMap<>(); 97 | props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); 98 | props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, enableAutoCommit); 99 | props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitInterval); 100 | props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset); 101 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 102 | props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 103 | //poll record 批量拉取数 104 | props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG,maxPollRecordsConfig); 105 | //protocol 106 | props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG,"SASL_PLAINTEXT"); 107 | //sasl 108 | props.put(SaslConfigs.SASL_MECHANISM,"SCRAM-SHA-512"); 109 | String jassc = "org.apache.kafka.common.security.scram.ScramLoginModule required\n" 110 | + "username = \"" + USER_NAME + "\"\n" 111 | + "password =\"" + PASS_WORD + "\";"; 112 | props.put(SaslConfigs.SASL_JAAS_CONFIG,jassc); 113 | //listener-监听线程池 114 | props.put("concurrency",5); 115 | props.put("ackMode","manual_immediate"); 116 | props.put("topicsFatal",false); 117 | return props; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /boot-kafka/src/main/java/cn/com/wudskq/consumer/Consumer.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.consumer; 2 | 3 | import org.apache.kafka.clients.consumer.ConsumerRecord; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.kafka.annotation.KafkaListener; 8 | import org.springframework.kafka.annotation.TopicPartition; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * @author chenfangchao 16 | * @title: Consumer 17 | * @projectName boot-project 18 | * @description: TODO 消费者 19 | * @date 2022/4/7 4:23 AM 20 | */ 21 | @Component 22 | public class Consumer { 23 | 24 | Logger logger = LoggerFactory.getLogger(getClass()); 25 | 26 | 27 | @Value("${wudskq.kafka.topic.test0}") 28 | private String topic0; 29 | 30 | @Value("${wudskq.kafka.topic.test1}") 31 | private String topic1; 32 | 33 | @Value("${wudskq.kafka.topic.test2}") 34 | private String topic2; 35 | 36 | @Value("${wudskq.kafka.topic.consumer.test3}") 37 | private String topic3; 38 | 39 | 40 | //默认消费 41 | @KafkaListener(topics = "${wudskq.kafka.topic.test0}", groupId = "${wudskq.kafka.topic.group}") 42 | public void consumer1(ConsumerRecord record){ 43 | Object value = record.value(); 44 | logger.info("默认消费者收到 "+topic0+ "的消息 "+ value); 45 | } 46 | 47 | //配置的第一个消费者 48 | @KafkaListener(topics = "${wudskq.kafka.topic.test1}", groupId = "${wudskq.kafka.topic.group}", 49 | containerFactory = "kafkaOneContainerFactory") 50 | public void listenerOne(ConsumerRecord record) { 51 | logger.info("第一个消费者收到 "+topic1+ "的消息 "+record.value()); 52 | } 53 | 54 | 55 | //配置的第二个接入的消费者 56 | //设置批量拉取poll 57 | @KafkaListener(topics = "${wudskq.kafka.topic.test2}", groupId = "${wudskq.kafka.topic.group}", 58 | containerFactory = "kafkaTwoContainerFactory") 59 | public void listenerTwo(List> record) { 60 | record.forEach(consumerRecord -> { 61 | logger.info("第二个消费者收到 "+topic2+ "的消息 "+consumerRecord.value()); 62 | }); 63 | } 64 | 65 | //kafka分区消费 66 | @KafkaListener( 67 | groupId = "${wudskq.kafka.topic.group}", 68 | topicPartitions = { 69 | @TopicPartition( 70 | topic = "${wudskq.kafka.topic.consumer.test3}", 71 | partitions = {"#{'${wudskq.kafka.topic.consumer.partitions0}'.split(',')}"} 72 | ) 73 | } 74 | ) 75 | public void listenerPartitions0(ConsumerRecord record) { 76 | logger.info("第一个消费者收到 "+topic3+"分区"+"partitions0的消息 "+record.value()); 77 | } 78 | 79 | //kafka分区消费 80 | @KafkaListener( 81 | groupId = "${wudskq.kafka.topic.group}", 82 | topicPartitions = { 83 | @TopicPartition( 84 | topic = "${wudskq.kafka.topic.consumer.test3}", 85 | partitions = {"#{'${wudskq.kafka.topic.consumer.partitions1}'.split(',')}"} 86 | ) 87 | } 88 | ) 89 | public void listenerPartitions1(ConsumerRecord record) { 90 | logger.info("第一个消费者收到 "+topic3+"分区"+"partitions1的消息 "+record.value()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /boot-kafka/src/main/java/cn/com/wudskq/producer/ProducerController.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.producer; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Qualifier; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.kafka.core.KafkaTemplate; 9 | import org.springframework.kafka.support.SendResult; 10 | import org.springframework.util.concurrent.ListenableFuture; 11 | import org.springframework.util.concurrent.ListenableFutureCallback; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | 17 | 18 | /** 19 | * @author chenfangchao 20 | * @title: ProducerController 21 | * @projectName boot-project 22 | * @description: TODO 生产者正常在业务逻辑中,再此简单示例 23 | * @date 2022/4/7 3:08 AM 24 | */ 25 | @RestController 26 | @RequestMapping("/producer") 27 | public class ProducerController { 28 | 29 | Logger log = LoggerFactory.getLogger(getClass()); 30 | 31 | // @Autowired 32 | // private KafkaTemplate kafkaTemplate; 33 | 34 | @Autowired 35 | @Qualifier(value = "kafkaOneTemplate") 36 | private KafkaTemplate kafkaOneTemplate; 37 | 38 | @Autowired 39 | @Qualifier(value = "kafkaTwoTemplate") 40 | private KafkaTemplate kafkaTwoTemplate; 41 | 42 | @Value("${wudskq.kafka.topic.test0}") 43 | private String topic0; 44 | 45 | @Value("${wudskq.kafka.topic.test1}") 46 | private String topic1; 47 | 48 | @Value("${wudskq.kafka.topic.test2}") 49 | private String topic2; 50 | 51 | @Value("${wudskq.kafka.topic.consumer.test3}") 52 | private String topic3; 53 | 54 | 55 | // //默认生产者 56 | // @GetMapping("/0") 57 | // public void produce(){ 58 | // ListenableFuture> future = kafkaTemplate.send(topic0, "producer0"); 59 | // future.addCallback(new ListenableFutureCallback>() { 60 | // @Override 61 | // public void onFailure(Throwable throwable) { 62 | // //发送失败的处理 63 | // log.info(topic0 + " - 生产者 发送消息失败:" + throwable.getMessage()); 64 | // } 65 | // @Override 66 | // public void onSuccess(SendResult stringObjectSendResult) { 67 | // //成功的处理 68 | // log.info(topic0 + " - 生产者 发送消息成功:" + stringObjectSendResult.toString()); 69 | // } 70 | // }); 71 | // } 72 | 73 | //配置的第一个生产者 74 | @GetMapping("/1") 75 | public void produce1(){ 76 | ListenableFuture> future = kafkaOneTemplate.send(topic1, "producer1"); 77 | future.addCallback(new ListenableFutureCallback>() { 78 | @Override 79 | public void onFailure(Throwable throwable) { 80 | //发送失败的处理 81 | log.info(topic1 + " - 生产者 发送消息失败:" + throwable.getMessage()); 82 | } 83 | @Override 84 | public void onSuccess(SendResult stringObjectSendResult) { 85 | //成功的处理 86 | log.info(topic1 + " - 生产者 发送消息成功:" + stringObjectSendResult.toString()); 87 | } 88 | }); 89 | } 90 | 91 | //配置的第二个生产者 92 | @GetMapping("/2") 93 | public void produce2(){ 94 | ListenableFuture> future = kafkaTwoTemplate.send(topic2, "producer2"); 95 | future.addCallback(new ListenableFutureCallback>() { 96 | @Override 97 | public void onFailure(Throwable throwable) { 98 | //发送失败的处理 99 | log.info(topic2 + " - 生产者 发送消息失败:" + throwable.getMessage()); 100 | } 101 | @Override 102 | public void onSuccess(SendResult stringObjectSendResult) { 103 | //成功的处理 104 | log.info(topic2 + " - 生产者 发送消息成功:" + stringObjectSendResult.toString()); 105 | } 106 | }); 107 | } 108 | 109 | //分区发送消息 110 | @GetMapping("/partitions") 111 | public void producePartitions0(){ 112 | ListenableFuture> future = kafkaOneTemplate.send(topic3, "partitions"); 113 | future.addCallback(new ListenableFutureCallback>() { 114 | @Override 115 | public void onFailure(Throwable throwable) { 116 | //发送失败的处理 117 | log.info(topic3 + " - 生产者 发送消息失败:" + throwable.getMessage()); 118 | } 119 | @Override 120 | public void onSuccess(SendResult stringObjectSendResult) { 121 | //成功的处理 122 | log.info(topic3 + " - 生产者 发送消息成功:" + stringObjectSendResult.toString()); 123 | } 124 | }); 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /boot-kafka/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8083 3 | 4 | spring: 5 | ##kafka 6 | kafka: 7 | bootstrap-servers: 47.111.231.31:9092 8 | consumer: 9 | auto-commit-interval: 1S 10 | # 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理: 11 | # latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录) 12 | # earliest :在偏移量无效的情况下,消费者将从起始位置读取分区的记录 13 | # 自动提交的时间间隔 在spring boot 2.X 版本中这里采用的是值的类型为Duration 需要符合特定的格式,如1S,1M,2H,5D 14 | # 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理: 15 | # latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录) 16 | # earliest :在偏移量无效的情况下,消费者将从起始位置读取分区的记录 17 | auto-offset-reset: latest 18 | # 是否自动提交偏移量,默认值是true,为了避免出现重复数据和数据丢失,可以把它设置为false,然后手动提交偏移量 19 | enable-auto-commit: false 20 | key-deserializer: org.apache.kafka.common.serialization.StringDeserializer 21 | value-deserializer: org.apache.kafka.common.serialization.StringDeserializer 22 | producer: 23 | retries: 3 24 | batch-size: 16384 25 | buffer-memory: 33554432 26 | key-serializer: org.apache.kafka.common.serialization.StringSerializer 27 | value-serializer: org.apache.kafka.common.serialization.StringSerializer 28 | # acks=0 : 生产者在成功写入消息之前不会等待任何来自服务器的响应。 29 | # acks=1 : 只要集群的首领节点收到消息,生产者就会收到一个来自服务器成功响应。 30 | # acks=all :只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。 31 | acks: 1 32 | properties: 33 | security: 34 | protocol: SASL_PLAINTEXT 35 | sasl: 36 | mechanism: SCRAM-SHA-512 37 | jaas: 38 | config: 'org.apache.kafka.common.security.scram.ScramLoginModule required username="admin" password="admin";' 39 | listener: 40 | # 在侦听器容器中运行的线程数。 41 | concurrency: 5 42 | #listner负责ack,每调用一次,就立即commit 43 | ack-mode: manual_immediate 44 | missing-topics-fatal: false 45 | 46 | wudskq: 47 | kafka: 48 | topic: 49 | test0: 'test-topic0' #用作默认生产与消费 50 | test1: 'test-topic1' #用于测试集成的第一个生产者与消费者 51 | test2: 'test-topic2' #用于测试集成的第二个生产者与消费者 52 | group: '2022040711' 53 | consumer: 54 | test3: 'test-topic3' #分区消费 55 | partitions0: 0 56 | partitions1: 1 -------------------------------------------------------------------------------- /boot-mqtt/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-mqtt 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | org.springframework.integration 32 | spring-integration-mqtt 33 | 5.1.3.RELEASE 34 | 35 | 36 | 37 | org.eclipse.paho 38 | org.eclipse.paho.client.mqttv3 39 | 1.2.4 40 | 41 | 42 | 43 | com.google.guava 44 | guava 45 | 30.1.1-jre 46 | 47 | 48 | 49 | org.slf4j 50 | slf4j-api 51 | 52 | 53 | 54 | org.slf4j 55 | slf4j-log4j12 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /boot-mqtt/src/main/java/cn/com/wudskq/MqttBootApplication.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author chenfangchao 8 | * @title: MqttBootApplication 9 | * @projectName boot-project 10 | * @description: TODO 11 | * @date 2022/4/7 5:47 PM 12 | */ 13 | @SpringBootApplication 14 | public class MqttBootApplication { 15 | public static void main(String[] args) { 16 | SpringApplication.run(MqttBootApplication.class,args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /boot-mqtt/src/main/java/cn/com/wudskq/config/MqttConfig.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.config; 2 | 3 | 4 | 5 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 6 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.integration.annotation.MessagingGateway; 15 | import org.springframework.integration.annotation.ServiceActivator; 16 | import org.springframework.integration.channel.DirectChannel; 17 | import org.springframework.integration.core.MessageProducer; 18 | import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; 19 | import org.springframework.integration.mqtt.core.MqttPahoClientFactory; 20 | import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; 21 | import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; 22 | import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; 23 | import org.springframework.integration.mqtt.support.MqttHeaders; 24 | import org.springframework.messaging.MessageChannel; 25 | import org.springframework.messaging.MessageHandler; 26 | import org.springframework.messaging.handler.annotation.Header; 27 | import org.springframework.stereotype.Component; 28 | 29 | import java.util.concurrent.ArrayBlockingQueue; 30 | import java.util.concurrent.ThreadFactory; 31 | import java.util.concurrent.ThreadPoolExecutor; 32 | import java.util.concurrent.TimeUnit; 33 | 34 | /** 35 | * @author chenfangchao 36 | * @version 1.0.0 37 | * @ClassName SpringMqttConfig.java 38 | * @Description TODO 39 | * @createTime 2021年10月29日 03:17:00 40 | */ 41 | @Component 42 | @Configuration 43 | @ConditionalOnProperty(value = "mqtt.enabled", havingValue = "true") 44 | public class MqttConfig { 45 | 46 | Logger logger = LoggerFactory.getLogger(getClass()); 47 | 48 | @Value("${mqtt.host}") 49 | private String host; 50 | 51 | @Value("${mqtt.userName}") 52 | private String userName; 53 | 54 | @Value("${mqtt.passWord}") 55 | private String passWord; 56 | 57 | @Value("${mqtt.keepLiveTime}") 58 | private Integer keepLiveTime; 59 | 60 | @Value("${mqtt.cilentId}") 61 | private String cilentId; 62 | 63 | @Value("${mqtt.topic.topic0}") 64 | private String faceTopic; 65 | 66 | @Value("${mqtt.topic.topic1}") 67 | private String carTopic; 68 | 69 | 70 | /***** 71 | * 创建MqttPahoClientFactory,设置MQTT Broker连接属性,如果使用SSL验证,也在这里设置。 72 | * @return 73 | */ 74 | @Bean 75 | public MqttPahoClientFactory mqttClientFactory() { 76 | DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); 77 | MqttConnectOptions options = new MqttConnectOptions(); 78 | options.setServerURIs(new String[]{host}); 79 | options.setUserName(userName); 80 | options.setPassword(passWord.toCharArray()); 81 | options.setKeepAliveInterval(keepLiveTime); 82 | options.setAutomaticReconnect(true); 83 | /* 连接断开后清除会话,下次连接重新建立会话 */ 84 | options.setCleanSession(true); 85 | factory.setConnectionOptions(options); 86 | return factory; 87 | } 88 | 89 | @Bean 90 | public MessageChannel mqttInputChannel() { 91 | return new DirectChannel(); 92 | } 93 | 94 | @Bean 95 | public MessageProducer inbound() { 96 | MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(cilentId, 97 | mqttClientFactory(), faceTopic, carTopic); 98 | adapter.setCompletionTimeout(5000); 99 | adapter.setConverter(new DefaultPahoMessageConverter()); 100 | adapter.setQos(2); 101 | adapter.setOutputChannel(mqttInputChannel()); 102 | return adapter; 103 | } 104 | 105 | private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder().setNameFormat("thread-pool-mqtt").build(); 106 | 107 | /** 108 | * 使用线程池初始化kafka-sdk服务,消费MQTT数据 109 | */ 110 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(9, 10, 5, 111 | TimeUnit.MINUTES, new ArrayBlockingQueue<>(10), THREAD_FACTORY, new ThreadPoolExecutor.AbortPolicy()); 112 | 113 | @Bean 114 | //ServiceActivator注解表明当前方法用于处理MQTT消息,inputChannel参数指定了用于接收消息信息的channel。 115 | @ServiceActivator(inputChannel = "mqttInputChannel") 116 | public MessageHandler handler() { 117 | return message -> { 118 | threadPoolExecutor.execute(() -> { 119 | String payload = message.getPayload().toString(); 120 | String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); 121 | // 根据topic分别进行消息处理。 122 | if (topic.equals(faceTopic)) { 123 | System.out.println("处理消息------>" + faceTopic); 124 | logger.info("处理业务逻辑1"); 125 | } else if (topic.equals(carTopic)) { 126 | System.out.println("处理消息------>" + carTopic); 127 | logger.info("处理业务逻辑2"); 128 | } else { 129 | System.out.println("丢弃消息------>" + topic); 130 | logger.info("丢弃消息"); 131 | } 132 | }); 133 | }; 134 | } 135 | 136 | 137 | @Bean 138 | public MessageChannel mqttOutboundChannel() { 139 | return new DirectChannel(); 140 | } 141 | 142 | /***** 143 | * 发送消息和消费消息Channel可以使用相同MqttPahoClientFactory 144 | * @return 145 | */ 146 | @Bean 147 | @ServiceActivator(inputChannel = "mqttOutboundChannel") 148 | public MessageHandler outbound() { 149 | // 在这里进行mqttOutboundChannel的相关设置 150 | MqttPahoMessageHandler messageHandler = 151 | new MqttPahoMessageHandler("publishClient", mqttClientFactory()); 152 | messageHandler.setAsync(true); //如果设置成true,发送消息时将不会阻塞。 153 | return messageHandler; 154 | } 155 | 156 | @MessagingGateway(defaultRequestChannel = "mqttOutboundChannel") 157 | public interface MqttGateway { 158 | // 定义重载方法,用于消息发送 159 | void sendToMqtt(String payload); 160 | // 指定topic进行消息发送 161 | void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload); 162 | void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload); 163 | } 164 | 165 | 166 | public String getHost() { 167 | return host; 168 | } 169 | 170 | public void setHost(String host) { 171 | this.host = host; 172 | } 173 | 174 | public String getUserName() { 175 | return userName; 176 | } 177 | 178 | public void setUserName(String userName) { 179 | this.userName = userName; 180 | } 181 | 182 | public String getPassWord() { 183 | return passWord; 184 | } 185 | 186 | public void setPassWord(String passWord) { 187 | this.passWord = passWord; 188 | } 189 | 190 | public String getFaceTopic() { 191 | return faceTopic; 192 | } 193 | 194 | public void setFaceTopic(String faceTopic) { 195 | this.faceTopic = faceTopic; 196 | } 197 | 198 | public Integer getKeepLiveTime() { 199 | return keepLiveTime; 200 | } 201 | 202 | public void setKeepLiveTime(Integer keepLiveTime) { 203 | this.keepLiveTime = keepLiveTime; 204 | } 205 | 206 | public String getCarTopic() { 207 | return carTopic; 208 | } 209 | 210 | public void setCarTopic(String carTopic) { 211 | this.carTopic = carTopic; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /boot-mqtt/src/main/java/cn/com/wudskq/controller/MqttController.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.controller; 2 | 3 | import cn.com.wudskq.config.MqttConfig; 4 | import cn.com.wudskq.model.MqttDTO; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | /** 15 | * @author chenfangchao 16 | */ 17 | @RestController 18 | @ConditionalOnProperty(value = "mqtt.enabled", havingValue = "true") 19 | @RequestMapping("/mqtt") 20 | public class MqttController { 21 | 22 | private Logger logger = LoggerFactory.getLogger(MqttController.class); 23 | 24 | @Autowired 25 | private MqttConfig.MqttGateway mqttGateway; 26 | 27 | 28 | @PostMapping("/send") 29 | public String send(@RequestBody MqttDTO message) { 30 | mqttGateway.sendToMqtt(message.getTopic(), message.getPayload()); 31 | return "send message : " + message; 32 | } 33 | } -------------------------------------------------------------------------------- /boot-mqtt/src/main/java/cn/com/wudskq/model/MqttDTO.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author chenfangchao 7 | * @version 1.0.0 8 | * @ClassName MqttDTO.java 9 | * @Description TODO 10 | * @createTime 2021年10月29日 10:18:00 11 | */ 12 | 13 | public class MqttDTO implements Serializable { 14 | 15 | private static final long serialVersionUID = 2127171152435094427L; 16 | 17 | private String topic; 18 | 19 | private String payload; 20 | 21 | public String getTopic() { 22 | return topic; 23 | } 24 | 25 | public void setTopic(String topic) { 26 | this.topic = topic; 27 | } 28 | 29 | public String getPayload() { 30 | return payload; 31 | } 32 | 33 | public void setPayload(String payload) { 34 | this.payload = payload; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /boot-mqtt/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8085 3 | 4 | mqtt: 5 | host: tcp://47.111.231.31:1883 6 | userName: mqtt 7 | passWord: mqtt 8 | keepLiveTime: 100 9 | enabled: true 10 | cilentId: ${random.uuid} 11 | topic: 12 | topic0: artemis/topic0/3187675137/admin 13 | topic1: artemis/topic1/3204452353/admin -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-mybatis-Interceptor 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | mysql 31 | mysql-connector-java 32 | 33 | 34 | 35 | com.alibaba 36 | druid-spring-boot-starter 37 | 1.2.6 38 | 39 | 40 | 41 | org.mybatis.spring.boot 42 | mybatis-spring-boot-starter 43 | 2.1.3 44 | 45 | 46 | 47 | com.baomidou 48 | mybatis-plus-boot-starter 49 | 3.4.3 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-jdbc 55 | 56 | 57 | 58 | org.apache.commons 59 | commons-lang3 60 | 3.9 61 | 62 | 63 | 64 | org.aspectj 65 | aspectjweaver 66 | 67 | 68 | 69 | junit 70 | junit 71 | test 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-test 77 | 78 | 79 | 80 | org.springframework 81 | spring-test 82 | 83 | 84 | 85 | org.projectlombok 86 | lombok 87 | 88 | 89 | 90 | org.bouncycastle 91 | bcpkix-jdk15on 92 | 1.64 93 | 94 | 95 | 96 | commons-net 97 | commons-net 98 | 3.1 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/MybatisInterceptorApplication.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * @author chenfangchao 9 | * @title: MybatisInterceptorApplicatioon 10 | * @projectName boot-project 11 | * @description: TODO mybatis拦截器 12 | * @date 2022/4/4 5:39 AM 13 | */ 14 | @SpringBootApplication 15 | @MapperScan("cn.com.wudskq.**.mapper") 16 | public class MybatisInterceptorApplication { 17 | public static void main(String[] args) { 18 | SpringApplication.run(MybatisInterceptorApplication.class,args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/annotation/CreateBy.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author chenfangchao 10 | * @projectName boot-project 11 | * @description: TODO 解密result 12 | * @date 2022/4/5 12:25 AM 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.FIELD}) 16 | public @interface CreateBy { 17 | String value() default ""; 18 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/annotation/CreateTime.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | 9 | /** 10 | * @author chenfangchao 11 | * @projectName boot-project 12 | * @description: TODO 解密result 13 | * @date 2022/4/5 12:25 AM 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target({ElementType.FIELD}) 17 | public @interface CreateTime { 18 | String value() default ""; 19 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/annotation/SensitiveData.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 注解敏感信息类的注解 7 | */ 8 | @Inherited 9 | @Target({ ElementType.TYPE }) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface SensitiveData { 12 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/annotation/SensitiveField.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 注解敏感信息类中敏感字段的注解 7 | */ 8 | @Inherited 9 | @Target({ ElementType.FIELD }) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface SensitiveField { 12 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/annotation/UpdateBy.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author chenfangchao 10 | * @projectName boot-project 11 | * @description: TODO 解密result 12 | * @date 2022/4/5 12:25 AM 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.FIELD}) 16 | public @interface UpdateBy { 17 | String value() default ""; 18 | } 19 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/annotation/UpdateTime.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author chenfangchao 10 | * @projectName boot-project 11 | * @description: TODO 解密result 12 | * @date 2022/4/5 12:25 AM 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.FIELD}) 16 | public @interface UpdateTime { 17 | String value() default ""; 18 | } 19 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/controller/MybatisController.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.controller; 2 | 3 | import cn.com.wudskq.model.Plan; 4 | import cn.com.wudskq.sevice.MybatisSevice; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * @author chenfangchao 13 | * @title: MybatisController 14 | * @projectName boot-project 15 | * @description: TODO 16 | * @date 2022/4/4 5:50 AM 17 | */ 18 | @RequestMapping("/mybatis/interceptor") 19 | @RestController 20 | public class MybatisController { 21 | 22 | @Autowired 23 | private MybatisSevice mybatisSevice; 24 | 25 | @GetMapping("/insert") 26 | public void insert(){ 27 | Plan plan = new Plan("计划一", "2022年"); 28 | mybatisSevice.insert(plan); 29 | } 30 | 31 | @GetMapping("/insert1") 32 | public void insert1(){ 33 | Plan plan = new Plan("计划一", "2022年"); 34 | mybatisSevice.insert1(plan); 35 | } 36 | 37 | @GetMapping("/update") 38 | public void update(){ 39 | Plan plan = new Plan("计划一", "2022年"); 40 | plan.setId(1L); 41 | mybatisSevice.update(plan); 42 | } 43 | 44 | @GetMapping("/info") 45 | public Plan getInfo(@RequestParam("id")Long id){ 46 | return mybatisSevice.getInfo(id); 47 | } 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/interceptor/ConvertParameter.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.interceptor; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * @author chenfangchao 7 | * @title: ConvertParameter 8 | * @projectName boot-project 9 | * @description: TODO 判断mapper.xml层是否多个参数 @Param 10 | * @date 2022/4/5 12:25 AM 11 | */ 12 | public class ConvertParameter { 13 | 14 | //常量 15 | public static final String PARAM_DATA = "data"; 16 | 17 | /** 18 | * 处理@Param注解读取参数获取失效问题 19 | */ 20 | public static Object convertParameter(Object parameter) { 21 | final Object[] object = new Object[1]; 22 | //判断获取到的mapper入参是否为集合类型 23 | if (parameter instanceof Map) { 24 | Map param = (Map) parameter; 25 | param.forEach((s, o) -> { 26 | if (s.equals(PARAM_DATA)) { 27 | object[0] = o; 28 | } 29 | }); 30 | return object[0]; 31 | } else { 32 | return parameter; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/interceptor/CustomInterceptor.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.interceptor; 2 | 3 | import cn.com.wudskq.annotation.CreateBy; 4 | import cn.com.wudskq.annotation.CreateTime; 5 | import cn.com.wudskq.annotation.UpdateBy; 6 | import cn.com.wudskq.annotation.UpdateTime; 7 | import org.apache.ibatis.executor.Executor; 8 | import org.apache.ibatis.mapping.MappedStatement; 9 | import org.apache.ibatis.mapping.SqlCommandType; 10 | import org.apache.ibatis.plugin.*; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.lang.reflect.Field; 16 | import java.util.*; 17 | 18 | /** 19 | * 自定义 Mybatis 插件,自动设置 createTime 和 updatTime 的值。 20 | * 拦截 update 操作(添加和修改) 21 | */ 22 | // 不能使用xml配置文件,因为会和其他mybatis的配置冲突,因此添加 @Component 23 | @Component 24 | @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) 25 | public class CustomInterceptor implements Interceptor { 26 | 27 | private static final Logger logger = LoggerFactory.getLogger(CustomInterceptor.class); 28 | 29 | @Override 30 | public Object intercept(Invocation invocation) throws Throwable { 31 | MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 32 | // 获取 SQL 命令 33 | SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); 34 | // 获取参数 35 | Object parameter = invocation.getArgs()[1]; 36 | 37 | /** 38 | * 处理mapper.xml入参为多个 39 | * data 约定为DDL映射实体类 40 | * param1统一标注为@Param("data") 41 | */ 42 | parameter = ConvertParameter.convertParameter(parameter); 43 | //存储属性 44 | ArrayList declaredFields = new ArrayList<>(); 45 | //当前class私有属性 46 | declaredFields.addAll(Arrays.asList(parameter.getClass().getDeclaredFields())); 47 | //当前class父类私有属性 48 | declaredFields.addAll(Arrays.asList(parameter.getClass().getSuperclass().getDeclaredFields())); 49 | 50 | //抽离的业务逻辑 51 | for (Field field : declaredFields) { 52 | // insert 语句插入 createTime 53 | if (field.getAnnotation(CreateTime.class) != null) { 54 | if (SqlCommandType.INSERT.equals(sqlCommandType)) { 55 | field.setAccessible(true); 56 | field.set(parameter,new Date()); 57 | } 58 | } 59 | // update 语句插入 updateTime 60 | if (field.getAnnotation(UpdateTime.class) != null) { 61 | if (SqlCommandType.UPDATE.equals(sqlCommandType)) { 62 | field.setAccessible(true); 63 | field.set(parameter,new Date()); 64 | } 65 | } 66 | //TODO正常业务下当前操作用户应从token中解析并获取 67 | // insert 语句插入 createBy 68 | if (field.getAnnotation(CreateBy.class) != null) { 69 | if (SqlCommandType.INSERT.equals(sqlCommandType)) { 70 | field.setAccessible(true); 71 | field.set(parameter, "admin01"); 72 | } 73 | } 74 | // update 语句插入 updateBy 75 | if (field.getAnnotation(UpdateBy.class) != null) { 76 | if (SqlCommandType.UPDATE.equals(sqlCommandType)) { 77 | field.setAccessible(true); 78 | field.set(parameter, "admin02"); 79 | } 80 | } 81 | } 82 | return invocation.proceed(); 83 | } 84 | 85 | @Override 86 | public Object plugin(Object o) { 87 | return Plugin.wrap(o, this); 88 | } 89 | 90 | @Override 91 | public void setProperties(Properties properties) { 92 | logger.warn(properties.toString()); 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/interceptor/DecryptInterceptor.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.interceptor; 2 | 3 | import cn.com.wudskq.annotation.SensitiveData; 4 | import cn.com.wudskq.sevice.aes.DecryptUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.ibatis.executor.resultset.ResultSetHandler; 7 | import org.apache.ibatis.plugin.*; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.core.annotation.AnnotationUtils; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.util.CollectionUtils; 12 | 13 | import java.sql.Statement; 14 | import java.util.ArrayList; 15 | import java.util.Objects; 16 | import java.util.Properties; 17 | 18 | /** 19 | * @author chenfangchao 20 | * @title: DecryptInterceptor 21 | * @projectName boot-project 22 | * @description: TODO 解密result 23 | * @date 2022/4/5 12:25 AM 24 | */ 25 | @Slf4j 26 | @Component 27 | @Intercepts({ 28 | @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}) 29 | }) 30 | public class DecryptInterceptor implements Interceptor { 31 | 32 | @Autowired 33 | DecryptUtil aesDecrypt; 34 | 35 | @Override 36 | public Object intercept(Invocation invocation) throws Throwable { 37 | //取出查询的结果 38 | Object resultObject = invocation.proceed(); 39 | if (Objects.isNull(resultObject)) { 40 | return null; 41 | } 42 | //基于selectList 43 | if (resultObject instanceof ArrayList) { 44 | ArrayList resultList = (ArrayList) resultObject; 45 | if (!CollectionUtils.isEmpty(resultList) && needToDecrypt(resultList.get(0))) { 46 | for (Object result : resultList) { 47 | //逐一解密 48 | aesDecrypt.decrypt(result); 49 | } 50 | } 51 | //基于selectOne 52 | } else { 53 | if (needToDecrypt(resultObject)) { 54 | aesDecrypt.decrypt(resultObject); 55 | } 56 | } 57 | return resultObject; 58 | } 59 | 60 | //判断需要解密的Class 61 | private boolean needToDecrypt(Object object) { 62 | Class objectClass = object.getClass(); 63 | //判断Class是否包含 SensitiveData注解 64 | SensitiveData sensitiveData = AnnotationUtils.findAnnotation(objectClass, SensitiveData.class); 65 | return Objects.nonNull(sensitiveData); 66 | } 67 | 68 | 69 | @Override 70 | public Object plugin(Object target) { 71 | return Plugin.wrap(target, this); 72 | } 73 | 74 | @Override 75 | public void setProperties(Properties properties) { 76 | 77 | } 78 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/interceptor/EncryptInterceptor.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.interceptor; 2 | 3 | import cn.com.wudskq.annotation.SensitiveData; 4 | import cn.com.wudskq.sevice.aes.EncryptUtil; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.ibatis.executor.parameter.ParameterHandler; 7 | import org.apache.ibatis.plugin.*; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.core.annotation.AnnotationUtils; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.lang.reflect.Field; 13 | import java.sql.PreparedStatement; 14 | import java.util.Objects; 15 | import java.util.Properties; 16 | 17 | /** 18 | * @author chenfangchao 19 | * @title: EncryptInterceptor 20 | * @projectName boot-project 21 | * @description: TODO 加密 param 22 | * @date 2022/4/5 12:25 AM 23 | */ 24 | @Slf4j 25 | @Component 26 | @Intercepts({ 27 | @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class), 28 | }) 29 | public class EncryptInterceptor implements Interceptor { 30 | 31 | private final EncryptUtil encryptUtil; 32 | 33 | @Autowired 34 | public EncryptInterceptor(EncryptUtil encryptUtil) { 35 | this.encryptUtil = encryptUtil; 36 | } 37 | 38 | 39 | @Override 40 | public Object intercept(Invocation invocation) throws Throwable { 41 | //@Signature 指定了 type= parameterHandler 后,这里的 invocation.getTarget() 便是parameterHandler 42 | //若指定ResultSetHandler ,这里则能强转为ResultSetHandler 43 | ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget(); 44 | // 获取参数对像,即 mapper 中 paramsType 的实例 45 | Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject"); 46 | parameterField.setAccessible(true); 47 | 48 | //取出实例 49 | Object parameterObject = parameterField.get(parameterHandler); 50 | 51 | /** 52 | * 处理mapper.xml入参为多个 53 | * data 约定为DDL映射实体类 54 | * param1统一标注为@Param("data") 55 | */ 56 | parameterObject = ConvertParameter.convertParameter(parameterObject); 57 | 58 | if (parameterObject != null) { 59 | Class parameterObjectClass = parameterObject.getClass(); 60 | //校验该实例的类是否被@SensitiveData所注解 61 | SensitiveData sensitiveData = AnnotationUtils.findAnnotation(parameterObjectClass, SensitiveData.class); 62 | if (Objects.nonNull(sensitiveData)) { 63 | //取出当前当前类所有字段,传入加密方法 64 | Field[] declaredFields = parameterObjectClass.getDeclaredFields(); 65 | encryptUtil.encrypt(declaredFields, parameterObject); 66 | } 67 | } 68 | return invocation.proceed(); 69 | } 70 | 71 | /** 72 | * 切记配置,否则当前拦截器不会加入拦截器链 73 | */ 74 | @Override 75 | public Object plugin(Object o) { 76 | return Plugin.wrap(o, this); 77 | } 78 | 79 | //自定义配置写入,没有自定义配置的可以直接置空此方法 80 | @Override 81 | public void setProperties(Properties properties) { 82 | } 83 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/mapper/MybatisMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.mapper; 2 | 3 | import cn.com.wudskq.model.Plan; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import javax.xml.ws.Response; 8 | 9 | /** 10 | * @author chenfangchao 11 | * @title: MybatisMapper 12 | * @projectName boot-project 13 | * @description: TODO 14 | * @date 2022/4/4 5:47 AM 15 | */ 16 | @Mapper 17 | public interface MybatisMapper { 18 | 19 | //单个对象 20 | void insert(Plan plan); 21 | 22 | //多个参数 23 | void insert1(@Param("data") Plan plan,@Param("remark") String remark); 24 | 25 | void update(Plan plan); 26 | 27 | Plan getInfo(@Param("id") Long id); 28 | } 29 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/model/Plan.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model; 2 | 3 | import cn.com.wudskq.annotation.*; 4 | import cn.com.wudskq.model.common.BaseDTO; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author chenfangchao 11 | * @title: Plan 12 | * @projectName boot-project 13 | * @description: TODO 计划数据模型 14 | * @date 2022/4/4 5:59 AM 15 | */ 16 | @SensitiveData 17 | @Data 18 | public class Plan extends BaseDTO implements Serializable { 19 | 20 | //id 21 | private Long id; 22 | 23 | //名称 24 | private String planName; 25 | 26 | //内容 27 | @SensitiveField 28 | private String planContent; 29 | 30 | public Plan(String planName, String planContent) { 31 | this.planName = planName; 32 | this.planContent = planContent; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/model/common/BaseDTO.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.common; 2 | 3 | import cn.com.wudskq.annotation.CreateBy; 4 | import cn.com.wudskq.annotation.CreateTime; 5 | import cn.com.wudskq.annotation.UpdateBy; 6 | import cn.com.wudskq.annotation.UpdateTime; 7 | import lombok.Data; 8 | 9 | import java.io.Serializable; 10 | import java.util.Date; 11 | 12 | /** 13 | * @author chenfangchao 14 | * @title: BaseDTO 15 | * @projectName boot-project 16 | * @description: TODO 基础数据模型 17 | * @date 2022/4/4 6:03 AM 18 | */ 19 | @Data 20 | public class BaseDTO implements Serializable { 21 | 22 | @CreateTime 23 | private Date createTime; 24 | 25 | @CreateBy 26 | private String createBy; 27 | 28 | @UpdateTime 29 | private Date updateTime; 30 | 31 | @UpdateBy 32 | private String updateBy; 33 | } 34 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/sevice/MybatisSevice.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice; 2 | 3 | import cn.com.wudskq.model.Plan; 4 | 5 | import javax.xml.ws.Response; 6 | 7 | /** 8 | * @author chenfangchao 9 | * @title: MybatisSevice 10 | * @projectName boot-project 11 | * @description: TODO 12 | * @date 2022/4/4 5:49 AM 13 | */ 14 | public interface MybatisSevice { 15 | 16 | void insert(Plan plan); 17 | 18 | void insert1(Plan plan); 19 | 20 | void update(Plan plan); 21 | 22 | Plan getInfo(Long id); 23 | } 24 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/sevice/aes/AESDecrypt.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.aes; 2 | 3 | import cn.com.wudskq.annotation.SensitiveField; 4 | import cn.com.wudskq.utils.AESUtil; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.lang.reflect.Field; 9 | import java.util.Objects; 10 | 11 | @Component 12 | public class AESDecrypt implements DecryptUtil { 13 | 14 | /** 15 | * 解密 16 | * 17 | * @param result resultType的实例 18 | * @return T 19 | * @throws IllegalAccessException 字段不可访问异常 20 | */ 21 | @Override 22 | public T decrypt(T result) throws IllegalAccessException { 23 | //取出resultType的类 24 | Class resultClass = result.getClass(); 25 | Field[] declaredFields = resultClass.getDeclaredFields(); 26 | for (Field field : declaredFields) { 27 | //取出所有被EncryptDecryptField注解的字段 28 | SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class); 29 | if (!Objects.isNull(sensitiveField)) { 30 | field.setAccessible(true); 31 | Object object = field.get(result); 32 | //只支持String的解密 33 | if (object instanceof String) { 34 | String value = (String) object; 35 | //对注解的字段进行逐一解密 36 | field.set(result, AESUtil.decrypt(value)); 37 | } 38 | } 39 | } 40 | return result; 41 | } 42 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/sevice/aes/AESEncrypt.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.aes; 2 | 3 | import cn.com.wudskq.annotation.SensitiveField; 4 | import cn.com.wudskq.utils.AESUtil; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.lang.reflect.Field; 8 | import java.util.Objects; 9 | 10 | @Component 11 | public class AESEncrypt implements EncryptUtil { 12 | 13 | /** 14 | * 加密 15 | * 16 | * @param declaredFields paramsObject所声明的字段 17 | * @param paramsObject mapper中paramsType的实例 18 | * @return T 19 | * @throws IllegalAccessException 字段不可访问异常 20 | */ 21 | @Override 22 | public T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException { 23 | for (Field field : declaredFields) { 24 | //取出所有被EncryptDecryptField注解的字段 25 | SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class); 26 | if (!Objects.isNull(sensitiveField)) { 27 | field.setAccessible(true); 28 | Object object = field.get(paramsObject); 29 | //暂时只实现String类型的加密 30 | if (object instanceof String) { 31 | String value = (String) object; 32 | //加密 这里我使用自定义的AES加密工具 33 | field.set(paramsObject, AESUtil.encrypt(value)); 34 | } 35 | } 36 | } 37 | return paramsObject; 38 | } 39 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/sevice/aes/DecryptUtil.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.aes; 2 | 3 | public interface DecryptUtil { 4 | 5 | /** 6 | * 解密 7 | * 8 | * @param result resultType的实例 9 | * @return T 10 | * @throws IllegalAccessException 字段不可访问异常 11 | */ 12 | T decrypt(T result) throws IllegalAccessException; 13 | 14 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/sevice/aes/EncryptUtil.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.aes; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | public interface EncryptUtil { 6 | 7 | /** 8 | * 加密 9 | * 10 | * @param declaredFields paramsObject所声明的字段 11 | * @param paramsObject mapper中paramsType的实例 12 | * @return T 13 | * @throws IllegalAccessException 字段不可访问异常 14 | */ 15 | T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException; 16 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/sevice/impl/MybatisSeviceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.impl; 2 | 3 | import cn.com.wudskq.mapper.MybatisMapper; 4 | import cn.com.wudskq.model.Plan; 5 | import cn.com.wudskq.sevice.MybatisSevice; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.xml.ws.Response; 10 | 11 | /** 12 | * @author chenfangchao 13 | * @title: MybatisSeviceImpl 14 | * @projectName boot-project 15 | * @description: TODO 16 | * @date 2022/4/4 5:50 AM 17 | */ 18 | @Service 19 | public class MybatisSeviceImpl implements MybatisSevice { 20 | 21 | @Autowired 22 | private MybatisMapper mybatisMapper; 23 | 24 | @Override 25 | public void insert(Plan plan) { 26 | mybatisMapper.insert(plan); 27 | } 28 | 29 | @Override 30 | public void insert1(Plan plan) { 31 | mybatisMapper.insert1(plan,"参数二"); 32 | } 33 | 34 | 35 | @Override 36 | public void update(Plan plan) { 37 | mybatisMapper.update(plan); 38 | } 39 | 40 | @Override 41 | public Plan getInfo(Long id) { 42 | return mybatisMapper.getInfo(id); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/java/cn/com/wudskq/utils/AESUtil.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.utils; 2 | 3 | import org.springframework.util.Base64Utils; 4 | 5 | import javax.crypto.Cipher; 6 | import javax.crypto.KeyGenerator; 7 | import javax.crypto.SecretKey; 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.security.NoSuchAlgorithmException; 10 | import java.security.SecureRandom; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | 14 | public class AESUtil { 15 | 16 | private static final String KEY_ALGORITHM = "AES"; 17 | private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算法 18 | 19 | //自定义密码 20 | private static final String ASSETS_DEV_PWD_FIELD = "nGjwx5fwg&Yir#3$0"; 21 | 22 | public static String getAssetsDevPwdField() { 23 | return ASSETS_DEV_PWD_FIELD; 24 | } 25 | 26 | /** 27 | * AES 加密操作 28 | * 29 | * @param content 待加密内容 30 | * @return 返回Base64转码后的加密数据 31 | */ 32 | public static String encrypt(String content) { 33 | try { 34 | Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器 35 | 36 | byte[] byteContent = content.getBytes("utf-8"); 37 | 38 | cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(ASSETS_DEV_PWD_FIELD));// 初始化为加密模式的密码器 39 | 40 | byte[] result = cipher.doFinal(byteContent);// 加密 41 | 42 | return Base64Utils.encodeToString(result);//通过Base64转码返回 43 | } catch (Exception ex) { 44 | Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex); 45 | } 46 | 47 | return null; 48 | } 49 | 50 | /** 51 | * AES 解密操作 52 | * @param content 53 | * @return 54 | */ 55 | public static String decrypt(String content) { 56 | 57 | try { 58 | //实例化 59 | Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); 60 | 61 | //使用密钥初始化,设置为解密模式 62 | cipher.init(Cipher.DECRYPT_MODE, getSecretKey(ASSETS_DEV_PWD_FIELD)); 63 | 64 | //执行操作 65 | byte[] result = cipher.doFinal(Base64Utils.decodeFromString(content)); 66 | String s = new String(result, "utf-8"); 67 | return s; 68 | } catch (Exception ex) { 69 | ex.printStackTrace(); 70 | Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex); 71 | } 72 | 73 | return null; 74 | } 75 | 76 | /** 77 | * 生成加密秘钥 78 | * 79 | * @return 80 | */ 81 | private static SecretKeySpec getSecretKey(String password) { 82 | //返回生成指定算法密钥生成器的 KeyGenerator 对象 83 | KeyGenerator kg = null; 84 | try { 85 | kg = KeyGenerator.getInstance(KEY_ALGORITHM); 86 | SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 87 | random.setSeed(password.getBytes()); 88 | //AES 要求密钥长度为 128 89 | kg.init(128, random); 90 | //生成一个密钥 91 | SecretKey secretKey = kg.generateKey(); 92 | return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥 93 | } catch (NoSuchAlgorithmException ex) { 94 | Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex); 95 | } 96 | return null; 97 | } 98 | 99 | public static void main(String[] args) { 100 | String origin = "my test string"; 101 | String encrypt = AESUtil.encrypt(origin); 102 | String decrypt = AESUtil.decrypt(encrypt); 103 | System.out.println(origin); 104 | System.out.println(encrypt); 105 | System.out.println(decrypt); 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #端口配置 2 | server: 3 | port: 8081 4 | 5 | #数据源配置 6 | spring: 7 | datasource: 8 | druid: 9 | type: com.alibaba.druid.pool.DruidDataSource 10 | driverClassName: com.mysql.cj.jdbc.Driver 11 | url: jdbc:mysql://localhost:3306/dev_database?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 12 | username: root 13 | password: root 14 | # 初始连接数 15 | initialSize: 5 16 | # 最小连接池数量 17 | minIdle: 10 18 | # 最大连接池数量 19 | maxActive: 20 20 | # 配置获取连接等待超时的时间 21 | maxWait: 60000 22 | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 23 | timeBetweenEvictionRunsMillis: 60000 24 | # 配置一个连接在池中最小生存的时间,单位是毫秒 25 | minEvictableIdleTimeMillis: 300000 26 | # 配置一个连接在池中最大生存的时间,单位是毫秒 27 | maxEvictableIdleTimeMillis: 900000 28 | # 配置检测连接是否有效 29 | validationQuery: SELECT 1 30 | testWhileIdle: true 31 | testOnBorrow: false 32 | testOnReturn: false 33 | webStatFilter: 34 | enabled: true 35 | statViewServlet: 36 | enabled: true 37 | # 设置白名单,不填则允许所有访问 38 | allow: 39 | url-pattern: /druid/* 40 | # 控制台管理用户名和密码 41 | login-username: admin 42 | login-password: 123456 43 | filter: 44 | stat: 45 | enabled: true 46 | # 慢SQL记录 47 | log-slow-sql: true 48 | slow-sql-millis: 1000 49 | merge-sql: true 50 | wall: 51 | config: 52 | multi-statement-allow: true 53 | mybatis-plus: 54 | # 搜索指定包别名 55 | typeAliasesPackage: cn.com.wudskq.model 56 | # 配置mapper的扫描,找到所有的mapper.xml映射文件 57 | mapperLocations: classpath*:mapper/*Mapper.xml 58 | # 加载全局的配置文件 59 | # configLocation: classpath:mybatis/mybatis-config.xml 60 | # 打印日志 61 | # configuration: 62 | # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 63 | configuration: 64 | #这个配置会将执行的sql打印出来,在开发或测试的时候可以用 65 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 66 | #返回类型为Map,显示null对应的字段 67 | call-setters-on-nulls: true 68 | global-config: 69 | db-config: 70 | logic-delete-field: delFlag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) 71 | logic-delete-value: 1 # 逻辑已删除值(默认为 ) 72 | logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) 73 | id-type: assign_id -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/resources/mapper/MybatisMapper.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | insert into plan (plan_name, plan_content, create_time, create_by, update_time, update_by) 9 | values (#{planName},#{planContent},#{createTime},#{createBy}, 10 | #{updateTime},#{updateBy}) 11 | 12 | 13 | 14 | insert into plan (plan_name, plan_content, create_time, create_by, update_time, update_by) 15 | values (#{data.planName},#{data.planContent},#{data.createTime},#{data.createBy}, 16 | #{data.updateTime},#{data.updateBy}) 17 | 18 | 19 | 20 | update plan 21 | set plan_name = #{planName},plan_content = #{planContent}, 22 | update_time = #{updateTime},update_by = #{updateBy} 23 | where id = #{id} 24 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /boot-mybatis-Interceptor/src/main/resources/sql/plan.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `plan` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT, 3 | `plan_name` varchar(255) DEFAULT NULL COMMENT '计划名称', 4 | `plan_content` varchar(255) DEFAULT NULL COMMENT '计划内容', 5 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 6 | `create_by` varchar(60) DEFAULT NULL COMMENT '创建人', 7 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 8 | `update_by` varchar(60) DEFAULT NULL COMMENT '更新人', 9 | PRIMARY KEY (`id`) 10 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4; -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-mybatis-plus-interceptor 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | mysql 32 | mysql-connector-java 33 | 34 | 35 | 36 | com.alibaba 37 | druid-spring-boot-starter 38 | 1.2.6 39 | 40 | 41 | 42 | 43 | com.baomidou 44 | mybatis-plus-boot-starter 45 | 3.4.3 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-jdbc 51 | 52 | 53 | 54 | org.apache.commons 55 | commons-lang3 56 | 3.9 57 | 58 | 59 | 60 | org.aspectj 61 | aspectjweaver 62 | 63 | 64 | 65 | junit 66 | junit 67 | test 68 | 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-test 73 | 74 | 75 | 76 | org.springframework 77 | spring-test 78 | 79 | 80 | 81 | org.projectlombok 82 | lombok 83 | 84 | 85 | 86 | org.bouncycastle 87 | bcpkix-jdk15on 88 | 1.64 89 | 90 | 91 | 92 | commons-net 93 | commons-net 94 | 3.1 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/MybatisPlusInterceptorApplication.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author chenfangchao 8 | * @title: MybatisPlusInterceptorApplication 9 | * @projectName boot-project 10 | * @description: TODO boot集成mybatis-plus 11 | * @date 2022/4/6 2:38 PM 12 | */ 13 | @SpringBootApplication 14 | public class MybatisPlusInterceptorApplication { 15 | public static void main(String[] args) { 16 | SpringApplication.run(MybatisPlusInterceptorApplication.class,args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/config/MyMetaObjectHandler.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.config; 2 | 3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 4 | import org.apache.ibatis.reflection.MetaObject; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * @author chenfangchao 11 | * @title: MyMetaObjectHandler 12 | * @projectName boot-project 13 | * @description: TODO 数据入库前处理 mp 14 | * @date 2022/4/7 11:04 AM 15 | */ 16 | @Configuration 17 | public class MyMetaObjectHandler implements MetaObjectHandler { 18 | 19 | //使用mp实现添加操作,这个方法会执行,metaObject元数据(表中的名字,表中的字段) 20 | @Override 21 | public void insertFill(MetaObject metaObject) { 22 | this.setFieldValByName("createTime",new Date(),metaObject); 23 | this.setFieldValByName("updateTime",new Date(),metaObject); 24 | } 25 | 26 | @Override 27 | public void updateFill(MetaObject metaObject) { 28 | this.setFieldValByName("updateTime",new Date(),metaObject); 29 | } 30 | } -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/controller/MybatisPlusController.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.controller; 2 | 3 | import cn.com.wudskq.model.Plan; 4 | import cn.com.wudskq.sevice.MybatisPlusSevice; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * @author chenfangchao 13 | * @title: MybatisController 14 | * @projectName boot-project 15 | * @description: TODO 16 | * @date 2022/4/7 11:06 AM 17 | */ 18 | @RequestMapping("/mybatis/interceptor") 19 | @RestController 20 | public class MybatisPlusController { 21 | 22 | @Autowired 23 | private MybatisPlusSevice mybatisSevice; 24 | 25 | @GetMapping("/insert") 26 | public void insert(){ 27 | Plan plan = new Plan("计划一", "2022年"); 28 | mybatisSevice.insert(plan); 29 | } 30 | 31 | @GetMapping("/update") 32 | public void update(){ 33 | Plan plan = new Plan("计划一", "2022年"); 34 | plan.setId(1L); 35 | mybatisSevice.update(plan); 36 | } 37 | 38 | @GetMapping("/info") 39 | public Plan getInfo(@RequestParam("id")Long id){ 40 | return mybatisSevice.getInfo(id); 41 | } 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/mapper/MybatisPlusMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.mapper; 2 | 3 | import cn.com.wudskq.model.Plan; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | /** 9 | * @author chenfangchao 10 | * @title: MybatisMapper 11 | * @projectName boot-project 12 | * @description: TODO 13 | * @date 2022/4/4 5:47 AM 14 | */ 15 | @Mapper 16 | public interface MybatisPlusMapper extends BaseMapper { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/model/Plan.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model; 2 | 3 | import cn.com.wudskq.model.common.BaseDTO; 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableField; 6 | import com.baomidou.mybatisplus.annotation.TableId; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | import lombok.Data; 9 | 10 | import java.io.Serializable; 11 | 12 | /** 13 | * @author chenfangchao 14 | * @title: Plan 15 | * @projectName boot-project 16 | * @description: TODO 计划数据模型 17 | * @date 2022/4/4 5:59 AM 18 | */ 19 | @TableName("plan") 20 | @Data 21 | public class Plan extends BaseDTO implements Serializable { 22 | 23 | //id 24 | private Long id; 25 | 26 | //名称 27 | @TableField("plan_name") 28 | private String planName; 29 | 30 | @TableField("plan_content") 31 | private String planContent; 32 | 33 | public Plan(String planName, String planContent) { 34 | this.planName = planName; 35 | this.planContent = planContent; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/model/common/BaseDTO.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.common; 2 | 3 | import com.baomidou.mybatisplus.annotation.FieldFill; 4 | import com.baomidou.mybatisplus.annotation.TableField; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Date; 9 | 10 | /** 11 | * @author chenfangchao 12 | * @title: BaseDTO 13 | * @projectName boot-project 14 | * @description: TODO 基础数据模型 15 | * @date 2022/4/4 6:03 AM 16 | */ 17 | @Data 18 | public class BaseDTO implements Serializable { 19 | 20 | @TableField(fill = FieldFill.INSERT,value = "create_time") 21 | private Date createTime; 22 | 23 | @TableField("create_by") 24 | private String createBy; 25 | 26 | @TableField(fill = FieldFill.INSERT,value = "update_time") 27 | private Date updateTime; 28 | 29 | @TableField("update_by") 30 | private String updateBy; 31 | } 32 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/sevice/MybatisPlusSevice.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice; 2 | 3 | import cn.com.wudskq.model.Plan; 4 | 5 | /** 6 | * @author chenfangchao 7 | * @title: MybatisSevice 8 | * @projectName boot-project 9 | * @description: TODO 10 | * @date 2022/4/4 5:49 AM 11 | */ 12 | public interface MybatisPlusSevice { 13 | 14 | void insert(Plan plan); 15 | 16 | void update(Plan plan); 17 | 18 | Plan getInfo(Long id); 19 | } 20 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/java/cn/com/wudskq/sevice/impl/MybatisPlusSeviceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.sevice.impl; 2 | 3 | import cn.com.wudskq.mapper.MybatisPlusMapper; 4 | import cn.com.wudskq.model.Plan; 5 | import cn.com.wudskq.sevice.MybatisPlusSevice; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @author chenfangchao 11 | * @title: MybatisSeviceImpl 12 | * @projectName boot-project 13 | * @description: TODO 14 | * @date 2022/4/4 5:50 AM 15 | */ 16 | @Service 17 | public class MybatisPlusSeviceImpl implements MybatisPlusSevice { 18 | 19 | @Autowired 20 | private MybatisPlusMapper mybatisMapper; 21 | 22 | @Override 23 | public void insert(Plan plan) { 24 | mybatisMapper.insert(plan); 25 | } 26 | 27 | @Override 28 | public void update(Plan plan) { 29 | mybatisMapper.updateById(plan); 30 | } 31 | 32 | @Override 33 | public Plan getInfo(Long id) { 34 | return mybatisMapper.selectById(id); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8082 3 | 4 | #数据源配置 5 | spring: 6 | datasource: 7 | druid: 8 | type: com.alibaba.druid.pool.DruidDataSource 9 | driverClassName: com.mysql.cj.jdbc.Driver 10 | url: jdbc:mysql://localhost:3306/dev_database?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 11 | username: root 12 | password: root 13 | # 初始连接数 14 | initialSize: 5 15 | # 最小连接池数量 16 | minIdle: 10 17 | # 最大连接池数量 18 | maxActive: 20 19 | # 配置获取连接等待超时的时间 20 | maxWait: 60000 21 | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 22 | timeBetweenEvictionRunsMillis: 60000 23 | # 配置一个连接在池中最小生存的时间,单位是毫秒 24 | minEvictableIdleTimeMillis: 300000 25 | # 配置一个连接在池中最大生存的时间,单位是毫秒 26 | maxEvictableIdleTimeMillis: 900000 27 | # 配置检测连接是否有效 28 | validationQuery: SELECT 1 29 | testWhileIdle: true 30 | testOnBorrow: false 31 | testOnReturn: false 32 | webStatFilter: 33 | enabled: true 34 | statViewServlet: 35 | enabled: true 36 | # 设置白名单,不填则允许所有访问 37 | allow: 38 | url-pattern: /druid/* 39 | # 控制台管理用户名和密码 40 | login-username: admin 41 | login-password: 123456 42 | filter: 43 | stat: 44 | enabled: true 45 | # 慢SQL记录 46 | log-slow-sql: true 47 | slow-sql-millis: 1000 48 | merge-sql: true 49 | wall: 50 | config: 51 | multi-statement-allow: true 52 | mybatis-plus: 53 | # 搜索指定包别名 54 | typeAliasesPackage: cn.com.wudskq.model 55 | # 配置mapper的扫描,找到所有的mapper.xml映射文件 56 | mapperLocations: classpath*:mapper/*Mapper.xml 57 | # 加载全局的配置文件 58 | # configLocation: classpath:mybatis/mybatis-config.xml 59 | # 打印日志 60 | # configuration: 61 | # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 62 | configuration: 63 | #这个配置会将执行的sql打印出来,在开发或测试的时候可以用 64 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 65 | #返回类型为Map,显示null对应的字段 66 | call-setters-on-nulls: true 67 | global-config: 68 | db-config: 69 | logic-delete-field: delFlag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) 70 | logic-delete-value: 1 # 逻辑已删除值(默认为 ) 71 | logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) 72 | id-type: assign_id -------------------------------------------------------------------------------- /boot-mybatis-plus-interceptor/src/main/resources/mapper/MybatisMapper.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /boot-rabbitmq/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-rabbitmq 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | org.slf4j 32 | slf4j-api 33 | 34 | 35 | 36 | org.slf4j 37 | slf4j-log4j12 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-amqp 43 | 44 | 45 | 46 | org.projectlombok 47 | lombok 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /boot-rabbitmq/src/main/java/cn/com/wudskq/BootRabbitMqApplication.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | import org.springframework.amqp.rabbit.annotation.EnableRabbit; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * @author chenfangchao 9 | * @title: BootRabbitMqApplication 10 | * @projectName boot-project 11 | * @description: TODO 12 | * @date 2022/4/7 4:36 PM 13 | */ 14 | @EnableRabbit 15 | @SpringBootApplication 16 | public class BootRabbitMqApplication { 17 | public static void main(String[] args) { 18 | SpringApplication.run(BootRabbitMqApplication.class,args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /boot-rabbitmq/src/main/java/cn/com/wudskq/listener/AmqListener.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.listener; 2 | 3 | import lombok.Data; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.amqp.core.ExchangeTypes; 7 | import org.springframework.amqp.rabbit.annotation.Exchange; 8 | import org.springframework.amqp.rabbit.annotation.Queue; 9 | import org.springframework.amqp.rabbit.annotation.QueueBinding; 10 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.stereotype.Component; 14 | 15 | @Data 16 | @Component 17 | public class AmqListener { 18 | 19 | public static Logger log = LoggerFactory.getLogger(AmqListener.class.getName()); 20 | 21 | 22 | @Value("${infovision-rabbit.groupId}") 23 | private String groupId; 24 | 25 | private final String QUEUE_PREFIX = "taiji_"; 26 | 27 | /* 动态生成queue*/ 28 | @Bean 29 | public org.springframework.amqp.core.Queue queue(){ 30 | long currentTimeMillis = System.currentTimeMillis(); 31 | groupId = groupId.replaceAll("-", "_"); 32 | log.info("本次rabbitMq动态生成消费者组ID为------------>"+groupId); 33 | return new org.springframework.amqp.core.Queue(groupId,false,true,true); 34 | } 35 | 36 | 37 | @RabbitListener(bindings = @QueueBinding( 38 | value = @Queue(value =QUEUE_PREFIX+"xalarm_aps_exchange_consumer_queue_"+"#{queue.name}", 39 | durable = "false", exclusive ="true",autoDelete = "true"), 40 | exchange = @Exchange(value = "xalarm_aps_exchange_forward_to_component", type = ExchangeTypes.DIRECT), 41 | key = "iservice1") 42 | ) 43 | public void processServiceLogic0(String content) { 44 | log.info(content.toString()); 45 | log.info("-----------处理业务逻辑Logic0--------------"); 46 | } 47 | 48 | @RabbitListener(bindings = @QueueBinding( 49 | value = @Queue(value =QUEUE_PREFIX+"xalarm_aps_exchange_consumer_queue_"+"#{queue.name}", 50 | durable = "false" ,exclusive ="true",autoDelete = "true"), 51 | exchange = @Exchange(value = "xalarm_aps_exchange_forward_to_component", type = ExchangeTypes.DIRECT), 52 | key = "iservice2") 53 | ) 54 | public void processServiceLogic1(String content) { 55 | log.info(content.toString()); 56 | log.info("-----------处理业务逻辑Logic1--------------"); 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /boot-rabbitmq/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8084 3 | 4 | spring: 5 | rabbitmq: 6 | host: 47.111.231.31 7 | port: 5672 8 | username: rabbitmq 9 | password: root 10 | 11 | infovision-rabbit: 12 | groupId: 202201011 -------------------------------------------------------------------------------- /boot-redis/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-redis 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | -------------------------------------------------------------------------------- /boot-security/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | boot-project 7 | cn.com.wudskq 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | boot-security 13 | 14 | 15 | 8 16 | 8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | org.springframework.security 32 | spring-security-taglibs 33 | 34 | 35 | 36 | com.github.pagehelper 37 | pagehelper-spring-boot-starter 38 | 1.3.0 39 | 40 | 41 | 42 | org.thymeleaf.extras 43 | thymeleaf-extras-springsecurity5 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-security 49 | 50 | 51 | 52 | 53 | io.jsonwebtoken 54 | jjwt 55 | 0.9.0 56 | 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | 62 | 63 | 64 | com.alibaba 65 | fastjson 66 | 1.2.70 67 | 68 | 69 | 70 | apache-lang 71 | commons-lang 72 | 2.0 73 | 74 | 75 | 76 | com.github.xiaoymin 77 | knife4j-spring-boot-starter 78 | 79 | 3.0.3 80 | 81 | 82 | 83 | com.baomidou 84 | mybatis-plus-boot-starter 85 | 3.4.3 86 | 87 | 88 | 89 | mysql 90 | mysql-connector-java 91 | 92 | 93 | 94 | org.springframework.boot 95 | spring-boot-starter-data-redis 96 | 97 | 98 | 99 | com.alibaba 100 | druid-spring-boot-starter 101 | 1.2.6 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/BootSecurityApplication.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author chenfangchao 8 | * @title: BootSecurityApplication 9 | * @projectName boot-project 10 | * @description: TODO 11 | * @date 2022/4/18 7:44 PM 12 | */ 13 | @SpringBootApplication 14 | public class BootSecurityApplication { 15 | public static void main(String[] args) { 16 | SpringApplication.run(BootSecurityApplication.class,args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/conf/JWTConfig.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.conf; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | 7 | @Component 8 | @ConfigurationProperties(prefix = "jwt") 9 | public class JWTConfig { 10 | 11 | /** 12 | * 密匙Key 13 | */ 14 | public static String secret; 15 | 16 | /** 17 | * HeaderKey 18 | */ 19 | public static String tokenHeader; 20 | 21 | /** 22 | * Token前缀 23 | */ 24 | public static String tokenPrefix; 25 | 26 | /** 27 | * 过期时间 28 | */ 29 | public static Integer expiration; 30 | 31 | /** 32 | * 配置白名单 33 | */ 34 | public static String antMatchers; 35 | 36 | /** 37 | * 将过期时间单位换算成毫秒 38 | * 39 | * @param expiration 过期时间,单位秒 40 | */ 41 | public void setExpiration(Integer expiration) { 42 | JWTConfig.expiration = expiration * 1000; 43 | } 44 | 45 | public void setSecret(String secret) { 46 | JWTConfig.secret = secret; 47 | } 48 | 49 | public void setTokenHeader(String tokenHeader) { 50 | JWTConfig.tokenHeader = tokenHeader; 51 | } 52 | 53 | public void setTokenPrefix(String tokenPrefix) { 54 | JWTConfig.tokenPrefix = tokenPrefix + " "; 55 | } 56 | 57 | public void setAntMatchers(String antMatchers) { 58 | JWTConfig.antMatchers = antMatchers; 59 | } 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/conf/Knife4jConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.conf; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import springfox.documentation.builders.ApiInfoBuilder; 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.spi.DocumentationType; 9 | import springfox.documentation.spring.web.plugins.Docket; 10 | import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; 11 | 12 | @Configuration 13 | @EnableSwagger2WebMvc 14 | public class Knife4jConfiguration { 15 | 16 | @Bean(value = "boot集成security") 17 | public Docket defaultApi2() { 18 | Docket docket=new Docket(DocumentationType.SWAGGER_2) 19 | .apiInfo(new ApiInfoBuilder() 20 | .description("#boot集成security") 21 | .version("1.0") 22 | .build()) 23 | //分组名称 24 | .groupName("2.X版本") 25 | .select() 26 | //这里指定Controller扫描包路径 27 | .apis(RequestHandlerSelectors.basePackage("cn.com.wudskq.controller")) 28 | .paths(PathSelectors.any()) 29 | .build(); 30 | return docket; 31 | } 32 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/conf/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.conf; 2 | 3 | import cn.com.wudskq.expection.UserAccessDeniedHandler; 4 | import cn.com.wudskq.filter.JWTAuthenticationFilter; 5 | import cn.com.wudskq.handler.*; 6 | import cn.com.wudskq.permssion.UserPermissionEvaluator; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 12 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 13 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 14 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 15 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 16 | import org.springframework.security.config.http.SessionCreationPolicy; 17 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 18 | import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; 19 | 20 | @Configuration 21 | @EnableWebSecurity 22 | @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法权限注解 23 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 24 | 25 | /** 26 | * 无权限处理类 27 | */ 28 | @Autowired 29 | private UserAccessDeniedHandler userAccessDeniedHandler; 30 | 31 | /** 32 | * 用户未登录处理类 33 | */ 34 | @Autowired 35 | private UserNotLoginHandler userNotLoginHandler; 36 | 37 | /** 38 | * 用户登录成功处理类 39 | */ 40 | @Autowired 41 | private UserLoginSuccessHandler userLoginSuccessHandler; 42 | 43 | /** 44 | * 用户登录失败处理类 45 | */ 46 | @Autowired 47 | private UserLoginFailureHandler userLoginFailureHandler; 48 | 49 | /** 50 | * 用户登出成功处理类 51 | */ 52 | @Autowired 53 | private UserLogoutSuccessHandler userLogoutSuccessHandler; 54 | 55 | /** 56 | * 用户登录验证 57 | */ 58 | @Autowired 59 | private UserAuthenticationProvider userAuthenticationProvider; 60 | 61 | /** 62 | * 用户权限注解 63 | */ 64 | @Autowired 65 | private UserPermissionEvaluator userPermissionEvaluator; 66 | 67 | /** 68 | * 加密方式,没使用这种加密方式 69 | */ 70 | @Bean 71 | public BCryptPasswordEncoder bCryptPasswordEncoder() { 72 | return new BCryptPasswordEncoder(); 73 | } 74 | 75 | /** 76 | * 注入自定义PermissionEvaluator 77 | * 78 | * @return 79 | */ 80 | @Bean 81 | public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() { 82 | DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler(); 83 | handler.setPermissionEvaluator(userPermissionEvaluator); 84 | return handler; 85 | } 86 | 87 | /** 88 | * 用户登录验证 89 | */ 90 | @Override 91 | protected void configure(AuthenticationManagerBuilder auth) { 92 | auth.authenticationProvider(userAuthenticationProvider); 93 | } 94 | 95 | 96 | @Value("${jwt.antMatchers}") 97 | private String antMatchers;//白名单,这里是不做验证的方法 98 | 99 | /** 100 | * 安全权限配置 101 | */ 102 | @Override 103 | protected void configure(HttpSecurity http) throws Exception { 104 | http.authorizeRequests() // 权限配置 105 | // 获取白名单(不进行权限验证) 106 | .antMatchers(antMatchers.split(",")).permitAll() 107 | //匿名访问url 108 | .antMatchers("/page/**").permitAll() 109 | // 其他的需要登陆后才能访问 110 | .anyRequest().authenticated() 111 | // 配置未登录处理类 112 | .and().httpBasic().authenticationEntryPoint(userNotLoginHandler) 113 | // 配置登录URL 114 | .and().formLogin().loginProcessingUrl("/user/login") 115 | //.and().formLogin().loginPage("/user/login")// 配置登录URL 116 | // 配置登录成功处理类 117 | .successHandler(userLoginSuccessHandler) 118 | // 配置登录失败处理类 119 | .failureHandler(userLoginFailureHandler) 120 | // 配置登出地址 121 | .and().logout().logoutUrl("/logout/submit") 122 | // 配置用户登出处理类 123 | .logoutSuccessHandler(userLogoutSuccessHandler) 124 | .and().logout() //退出登录相关配置 125 | //退出成功后跳转的页面 126 | .logoutSuccessUrl("/page/index") 127 | //退出时要删除的Cookies的名字 128 | .deleteCookies("JSESSIONID") 129 | // 配置没有权限处理类 130 | .and().exceptionHandling().accessDeniedHandler(userAccessDeniedHandler) 131 | // 开启跨域 132 | .and().cors() 133 | // 禁用跨站请求伪造防护 134 | .and().csrf().disable(); 135 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 禁用session(使用Token认证) 136 | // 禁用缓存 137 | http.headers().cacheControl(); 138 | //添加JWT过滤器 139 | http.addFilter(new JWTAuthenticationFilter(authenticationManager())); 140 | } 141 | 142 | } 143 | 144 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.controller; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @RequestMapping("/page") 9 | public class IndexController { 10 | 11 | @GetMapping("/index") 12 | public String index() { 13 | return "index"; 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/controller/TSysUserController.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.controller; 2 | 3 | import cn.com.wudskq.model.vo.Result; 4 | import io.swagger.annotations.*; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.security.access.prepost.PreAuthorize; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | 10 | @Slf4j 11 | @RequestMapping("tSysUser") 12 | @RestController 13 | @Api(value = "系统用户服务", tags = "系统用户服务") 14 | public class TSysUserController { 15 | 16 | @PreAuthorize("hasRole('ROLE_/tSysUser/findByPage')") 17 | @PostMapping("findByPage") 18 | @ApiOperation(value = "添加系统用户", notes = "添加系统用户", produces = "application/json") 19 | public Result findByPage(){ 20 | log.info("测试用户分页查询权限"); 21 | return Result.success("测试用户分页查询权限"); 22 | } 23 | 24 | @PreAuthorize("hasRole('ROLE_/tSysUser/add')") 25 | @PostMapping("add") 26 | @ApiOperation(value = "添加系统用户", notes = "添加系统用户", produces = "application/json") 27 | public Result add(){ 28 | log.info("测试用户添加权限"); 29 | return Result.success("测试用户添加权限"); 30 | } 31 | 32 | @PreAuthorize("hasRole('ROLE_/tSysUser/edit')") 33 | @PostMapping("edit") 34 | @ApiOperation(value = "修改系统用户", notes = "修改系统用户", produces = "application/json") 35 | public Result edit(){ 36 | log.info("测试用户编辑权限"); 37 | return Result.success("测试用户编辑权限"); 38 | } 39 | 40 | @PreAuthorize("hasRole('ROLE_/tSysUser/delete')") 41 | @PostMapping("delete") 42 | @ApiOperation(value = "删除系统用户", notes = "删除系统用户", produces = "application/json") 43 | public Result delete(){ 44 | log.info("测试用户删除权限"); 45 | return Result.success("测试用户删除权限"); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/dao/TSysResMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.dao; 2 | 3 | import cn.com.wudskq.model.dto.TSysRes; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | @Mapper 8 | public interface TSysResMapper extends BaseMapper { 9 | 10 | 11 | } 12 | 13 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/dao/TSysRoleMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.dao; 2 | 3 | import cn.com.wudskq.model.dto.TSysRole; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.apache.ibatis.annotations.Select; 7 | 8 | import java.util.List; 9 | 10 | 11 | @Mapper 12 | public interface TSysRoleMapper extends BaseMapper { 13 | 14 | @Select("SELECT r.* FROM t_sys_role r " + 15 | "LEFT JOIN t_sys_user_role ur ON ur.role_id = r.id " + 16 | "WHERE " + 17 | "ur.user_id = #{userId} ") 18 | List findRoleByUserId(String userId); 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/dao/TSysRoleResMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.dao; 2 | 3 | import cn.com.wudskq.model.dto.TSysRoleRes; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | 12 | @Mapper 13 | public interface TSysRoleResMapper extends BaseMapper { 14 | 15 | List selectRoleResByMap(Map map); 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/dao/TSysUserMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.dao; 2 | 3 | 4 | import cn.com.wudskq.model.dto.TSysUser; 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | 9 | @Mapper 10 | public interface TSysUserMapper extends BaseMapper { 11 | 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/dao/TSysUserRoleMapper.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.dao; 2 | 3 | import cn.com.wudskq.model.dto.TSysUserRole; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | 8 | @Mapper 9 | public interface TSysUserRoleMapper extends BaseMapper { 10 | 11 | 12 | } 13 | 14 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/expection/MyException.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.expection; 2 | 3 | 4 | public class MyException extends RuntimeException{ 5 | 6 | private int code; 7 | private String msg; 8 | 9 | public MyException(int code, String msg){ 10 | super(msg); 11 | this.code = code; 12 | } 13 | 14 | public int getCode() { 15 | return code; 16 | } 17 | 18 | public void setCode(int code) { 19 | this.code = code; 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/expection/TopException.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.expection; 2 | 3 | import cn.com.wudskq.model.vo.Result; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.security.access.AccessDeniedException; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | @ControllerAdvice 12 | public class TopException { 13 | 14 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 15 | 16 | @ExceptionHandler(value = Exception.class) 17 | @ResponseBody 18 | public Result handle(Exception e){ 19 | 20 | if(e instanceof MyException){ 21 | logger.error("业务日志",e); 22 | MyException myException = (MyException) e; 23 | return Result.error(myException.getCode(),myException.getMessage()); 24 | }else if(e instanceof AccessDeniedException){ 25 | return Result.error(403,"访问权限不足"); 26 | } 27 | 28 | logger.error("系统日志",e); 29 | return Result.error(1000,"业务繁忙"); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/expection/UserAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.expection; 2 | 3 | import cn.com.wudskq.model.vo.Result; 4 | import org.springframework.security.access.AccessDeniedException; 5 | import org.springframework.security.web.access.AccessDeniedHandler; 6 | import org.springframework.stereotype.Component; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | 13 | @Component 14 | public class UserAccessDeniedHandler implements AccessDeniedHandler { 15 | 16 | @Override 17 | public void handle(HttpServletRequest request, HttpServletResponse response, 18 | AccessDeniedException accessDeniedException) throws IOException, ServletException { 19 | Result.responseJson(response, Result.response(403, "权限不足,拒绝访问", accessDeniedException.getMessage())); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/filter/JWTAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.filter; 2 | 3 | import cn.com.wudskq.conf.JWTConfig; 4 | import cn.com.wudskq.model.SysUserDetails; 5 | import cn.com.wudskq.util.JWTTokenUtil; 6 | import org.springframework.security.authentication.AuthenticationManager; 7 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 8 | import org.springframework.security.core.context.SecurityContextHolder; 9 | import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; 10 | 11 | import javax.servlet.FilterChain; 12 | import javax.servlet.ServletException; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.io.IOException; 16 | 17 | 18 | public class JWTAuthenticationFilter extends BasicAuthenticationFilter { 19 | 20 | public JWTAuthenticationFilter(AuthenticationManager authenticationManager) { 21 | super(authenticationManager); 22 | } 23 | 24 | @Override 25 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 26 | throws IOException, ServletException { 27 | // 取出Token 28 | String token = request.getHeader(JWTConfig.tokenHeader); 29 | 30 | if (token != null && token.startsWith(JWTConfig.tokenPrefix)) { 31 | SysUserDetails sysUserDetails = JWTTokenUtil.parseAccessToken(token); 32 | 33 | if (sysUserDetails != null) { 34 | UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( 35 | sysUserDetails, sysUserDetails.getId(), sysUserDetails.getAuthorities()); 36 | SecurityContextHolder.getContext().setAuthentication(authentication); 37 | } 38 | } 39 | filterChain.doFilter(request, response); 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/handler/UserAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.handler; 2 | 3 | import cn.com.wudskq.model.SysUserDetails; 4 | import cn.com.wudskq.service.impl.SysUserDetailsService; 5 | import cn.com.wudskq.util.Md5Util; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.authentication.AuthenticationProvider; 8 | import org.springframework.security.authentication.BadCredentialsException; 9 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.security.core.AuthenticationException; 12 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 13 | import org.springframework.stereotype.Component; 14 | import org.springframework.util.StringUtils; 15 | 16 | @Component 17 | public class UserAuthenticationProvider implements AuthenticationProvider { 18 | 19 | @Autowired 20 | private SysUserDetailsService userDetailsService; 21 | 22 | /** 23 | * 身份验证 24 | */ 25 | @Override 26 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 27 | String username = (String) authentication.getPrincipal(); // 获取用户名 28 | String password = (String) authentication.getCredentials(); // 获取密码 29 | if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { 30 | throw new UsernameNotFoundException("用户名或密码不能为空"); 31 | } 32 | if(username.equals("admin") && password.equals("123456")){ 33 | SysUserDetails sysUserDetails = (SysUserDetails) userDetailsService.loadUserByUsername(username); 34 | return new UsernamePasswordAuthenticationToken(sysUserDetails, password, sysUserDetails.getAuthorities()); 35 | } else if (username.equals("admin") && !password.equals("123456")){ 36 | throw new BadCredentialsException("用户名或密码错误"); 37 | } else { 38 | SysUserDetails sysUserDetails = (SysUserDetails) userDetailsService.loadUserByUsername(username); 39 | if (sysUserDetails == null) { 40 | throw new UsernameNotFoundException("用户名不存在"); 41 | } 42 | if(!sysUserDetails.getPassword().equals(Md5Util.MD5(password))){ 43 | throw new BadCredentialsException("用户名或密码错误"); 44 | } 45 | return new UsernamePasswordAuthenticationToken(sysUserDetails, password, sysUserDetails.getAuthorities()); 46 | } 47 | } 48 | 49 | /** 50 | * 支持指定的身份验证 51 | */ 52 | @Override 53 | public boolean supports(Class authentication) { 54 | return true; 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/handler/UserLoginFailureHandler.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.handler; 2 | 3 | import cn.com.wudskq.model.vo.Result; 4 | import org.springframework.security.core.AuthenticationException; 5 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 6 | import org.springframework.stereotype.Component; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | @Component 12 | public class UserLoginFailureHandler implements AuthenticationFailureHandler { 13 | 14 | @Override 15 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, 16 | AuthenticationException exception) { 17 | Result.responseJson(response, Result.response(500, "登录失败", exception.getMessage())); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/handler/UserLoginSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.handler; 2 | 3 | import cn.com.wudskq.model.SysUserDetails; 4 | import cn.com.wudskq.model.vo.Result; 5 | import cn.com.wudskq.util.JWTTokenUtil; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | @Component 16 | public class UserLoginSuccessHandler implements AuthenticationSuccessHandler { 17 | 18 | @Override 19 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, 20 | Authentication authentication) { 21 | SysUserDetails sysUserDetails = (SysUserDetails) authentication.getPrincipal(); 22 | String token = JWTTokenUtil.createAccessToken(sysUserDetails); 23 | Map tokenMap = new HashMap<>(); 24 | tokenMap.put("token", token); 25 | Result.responseJson(response, Result.response(0, "登录成功", tokenMap)); 26 | } 27 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/handler/UserLogoutSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.handler; 2 | 3 | import cn.com.wudskq.model.vo.Result; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | @Component 13 | public class UserLogoutSuccessHandler implements LogoutSuccessHandler { 14 | 15 | @Override 16 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, 17 | Authentication authentication) { 18 | SecurityContextHolder.clearContext(); 19 | Result.responseJson(response, Result.response(200, "登出成功", null)); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/handler/UserNotLoginHandler.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.handler; 2 | 3 | import cn.com.wudskq.model.vo.Result; 4 | import org.springframework.security.core.AuthenticationException; 5 | import org.springframework.security.web.AuthenticationEntryPoint; 6 | import org.springframework.stereotype.Component; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | 13 | @Component 14 | public class UserNotLoginHandler implements AuthenticationEntryPoint { 15 | 16 | @Override 17 | public void commence(HttpServletRequest request, HttpServletResponse response, 18 | AuthenticationException authException) throws IOException, ServletException { 19 | Result.responseJson(response, Result.response(401, "未登录", authException.getMessage())); 20 | } 21 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/model/SysUserDetails.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model; 2 | 3 | import cn.com.wudskq.model.dto.TSysUser; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.userdetails.UserDetails; 8 | 9 | import java.io.Serializable; 10 | import java.util.Collection; 11 | 12 | 13 | @Data 14 | @EqualsAndHashCode(callSuper = false) 15 | public class SysUserDetails extends TSysUser implements UserDetails, Serializable { 16 | private static final long serialVersionUID = 1L; 17 | 18 | /** 19 | * 用户角色 20 | */ 21 | private Collection authorities; 22 | 23 | /** 24 | * 账号是否过期 25 | */ 26 | private boolean isAccountNonExpired = false; 27 | 28 | /** 29 | * 账号是否锁定 30 | */ 31 | private boolean isAccountNonLocked = false; 32 | 33 | /** 34 | * 证书是否过期 35 | */ 36 | private boolean isCredentialsNonExpired = false; 37 | 38 | /** 39 | * 账号是否有效 40 | */ 41 | private boolean isEnabled = true; 42 | 43 | /** 44 | * 获得用户权限 45 | */ 46 | @Override 47 | public Collection getAuthorities() { 48 | return authorities; 49 | } 50 | 51 | /** 52 | * 判断账号是否过期 53 | */ 54 | @Override 55 | public boolean isAccountNonExpired() { 56 | return isAccountNonExpired; 57 | } 58 | 59 | /** 60 | * 判断账号是否锁定 61 | */ 62 | @Override 63 | public boolean isAccountNonLocked() { 64 | return isAccountNonLocked; 65 | } 66 | 67 | /** 68 | * 判断证书是否过期 69 | */ 70 | @Override 71 | public boolean isCredentialsNonExpired() { 72 | return isCredentialsNonExpired; 73 | } 74 | 75 | /** 76 | * 判断账号是否有效 77 | */ 78 | @Override 79 | public boolean isEnabled() { 80 | return isEnabled; 81 | } 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/model/dto/TSysRes.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.dto; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | 9 | 10 | @Data 11 | @TableName("t_sys_res") 12 | public class TSysRes { 13 | 14 | @TableId 15 | private String id;//主键 16 | private String name;//资源名称 17 | private String resUrl;//资源路径 18 | private String permission;//做拦截的code 19 | private String resType;//0菜单 1按钮 20 | private String pid;//父级id 21 | private String icon;//菜单图标 22 | private String createUser;//创建人 23 | private Date createDate;//创建时间 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/model/dto/TSysRole.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.dto; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | 9 | 10 | @Data 11 | @TableName("t_sys_role") 12 | public class TSysRole { 13 | 14 | @TableId 15 | private String id;//主键 16 | private String roleName;//角色名称 17 | private String roleExplain;//角色描述 18 | private String createUser;//创建人 19 | private Date createDate;//创建时间 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/model/dto/TSysRoleRes.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.dto; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | 8 | @Data 9 | @TableName("t_sys_role_res") 10 | public class TSysRoleRes { 11 | 12 | @TableId 13 | private String id;//主键 14 | private String roleId;//角色id 15 | private String resId;//资源id 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/model/dto/TSysUser.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.dto; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Date; 9 | 10 | 11 | @Data 12 | @TableName("t_sys_user") 13 | public class TSysUser implements Serializable { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | @TableId 18 | private String id;//主键 19 | private String username;//用户名 20 | private String password;//密码 21 | private String nickName;//昵称 22 | private String cellPhone;//电话 23 | private String mail;//邮件 24 | private Date birthday;//生日 25 | private String status;//状态(0-正常,1-禁用,2-删除) 26 | private String accountType;//1系统账号 2客户账号 27 | private String inviteCode;//邀请码 28 | private String sex;//性别:0男 1女 29 | private String address;//地址 30 | private Integer upNum;//获赞总量 31 | private Integer readNum;//文章被阅读总量 32 | private String sign;//签名 33 | private String pictureId;//用户头像 34 | private String createUser;//创建人 35 | private Date createDate;//创建时间 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/model/dto/TSysUserRole.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.dto; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableId; 4 | import com.baomidou.mybatisplus.annotation.TableName; 5 | import lombok.Data; 6 | 7 | @Data 8 | @TableName("t_sys_user_role") 9 | public class TSysUserRole { 10 | 11 | @TableId 12 | private String id;//主键 13 | private String userId;//用户名id 14 | private String roleId;//角色id 15 | } 16 | 17 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/model/vo/Result.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.model.vo; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | import javax.servlet.ServletResponse; 7 | import java.io.PrintWriter; 8 | import java.util.List; 9 | 10 | @Data 11 | public class Result { 12 | 13 | @ApiModelProperty(value = "返回码") 14 | private int code; 15 | 16 | @ApiModelProperty(value = "返回数据") 17 | private Object data; 18 | 19 | @ApiModelProperty(value = "返回描述") 20 | private String msg; 21 | 22 | @ApiModelProperty(value = "返回长度") 23 | private long count; 24 | 25 | /** 26 | * 返回成功 27 | */ 28 | public static Result success(List data, long count) { 29 | Result result = new Result(); 30 | result.setCode(0);//成功 31 | result.setMsg("成功");//提示语 32 | result.setData(data); 33 | result.setCount(count); 34 | return result; 35 | } 36 | 37 | /** 38 | * 返回成功 39 | */ 40 | public static Result success(List data) { 41 | Result result = new Result(); 42 | result.setCode(0);//成功 43 | result.setMsg("成功");//提示语 44 | result.setData(data); 45 | result.setCount(data == null || data.size() == 0 ? 0 : data.size()); 46 | return result; 47 | } 48 | 49 | /** 50 | * 返回成功 51 | */ 52 | public static Result successForPage(List data, Integer count) { 53 | Result result = new Result(); 54 | result.setCode(0);//成功 55 | result.setMsg("成功");//提示语 56 | result.setData(data); 57 | result.setCount(count == null ? 0 : count); 58 | return result; 59 | } 60 | 61 | /** 62 | * 返回成功 63 | */ 64 | public static Result success() { 65 | Result result = new Result(); 66 | result.setCode(0);//成功 67 | result.setMsg("成功");//提示语 68 | return result; 69 | } 70 | 71 | /** 72 | * 返回成功 73 | */ 74 | public static Result success(Object object) { 75 | Result result = new Result(); 76 | result.setCode(0);//成功 77 | result.setMsg("成功");//提示语 78 | result.setData(object);//返回内容 79 | return result; 80 | } 81 | 82 | /** 83 | * 返回失败 84 | */ 85 | public static Result error() { 86 | Result result = new Result(); 87 | result.setCode(1);//失败 88 | result.setMsg("失败");//提示语 89 | return result; 90 | } 91 | 92 | /** 93 | * 返回失败 94 | */ 95 | public static Result error(int code, String msg) { 96 | Result result = new Result(); 97 | result.setCode(code);//失败 98 | result.setMsg(msg);//提示语 99 | return result; 100 | } 101 | 102 | /** 103 | * 返回信息 104 | */ 105 | public static Result response(int code, String msg, Object data) { 106 | Result result = new Result(); 107 | result.setCode(code); 108 | result.setMsg(msg); 109 | result.setData(data); 110 | return result; 111 | } 112 | 113 | /** 114 | * Response输出Json格式 115 | */ 116 | public static void responseJson(ServletResponse response, Object data) { 117 | PrintWriter out = null; 118 | try { 119 | response.setCharacterEncoding("UTF-8"); 120 | response.setContentType("application/json"); 121 | out = response.getWriter(); 122 | out.println(JSON.toJSONString(data)); 123 | out.flush(); 124 | } catch (Exception e) { 125 | System.out.println("Response输出Json异常:" + e); 126 | } finally { 127 | if (out != null) { 128 | out.close(); 129 | } 130 | } 131 | } 132 | 133 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/permssion/UserPermissionEvaluator.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.permssion; 2 | 3 | import cn.com.wudskq.expection.MyException; 4 | import cn.com.wudskq.model.SysUserDetails; 5 | import cn.com.wudskq.model.dto.TSysRes; 6 | import cn.com.wudskq.service.TSysResService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.access.PermissionEvaluator; 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.io.Serializable; 14 | import java.util.HashSet; 15 | import java.util.List; 16 | import java.util.Set; 17 | 18 | @Configuration 19 | @Component 20 | public class UserPermissionEvaluator implements PermissionEvaluator { 21 | 22 | @Autowired 23 | private TSysResService tSysResService; 24 | 25 | @Override 26 | public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) { 27 | SysUserDetails sysUserDetails = null; 28 | try { 29 | sysUserDetails = (SysUserDetails) authentication.getPrincipal(); 30 | } catch (Exception e){ 31 | throw new MyException(403,"权限不足"); 32 | } 33 | 34 | Set permissions = new HashSet(); // 用户权限 35 | 36 | List authList = tSysResService.findResByUserId(sysUserDetails.getId()); 37 | 38 | for (int i = 0; i < authList.size() ; i++) { 39 | permissions.add(authList.get(i).getPermission()); 40 | } 41 | 42 | // 判断是否拥有权限 43 | if (permissions.contains(permission.toString())) { 44 | return true; 45 | } 46 | return false; 47 | } 48 | 49 | @Override 50 | public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, 51 | Object permission) { 52 | return false; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/TSysResService.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service; 2 | 3 | 4 | import cn.com.wudskq.model.dto.TSysRes; 5 | 6 | import java.util.List; 7 | 8 | 9 | public interface TSysResService { 10 | 11 | List findResByUserId(String userId); 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/TSysRoleResService.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service; 2 | 3 | 4 | public interface TSysRoleResService { 5 | 6 | 7 | } 8 | 9 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/TSysRoleService.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service; 2 | 3 | 4 | public interface TSysRoleService { 5 | 6 | 7 | } 8 | 9 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/TSysUserRoleService.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service; 2 | 3 | 4 | 5 | public interface TSysUserRoleService { 6 | 7 | } 8 | 9 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/TSysUserService.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service; 2 | 3 | 4 | import cn.com.wudskq.model.dto.TSysUser; 5 | 6 | public interface TSysUserService { 7 | 8 | TSysUser findByUsername(String username); 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/impl/SysUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service.impl; 2 | 3 | import cn.com.wudskq.dao.TSysResMapper; 4 | import cn.com.wudskq.model.SysUserDetails; 5 | import cn.com.wudskq.model.dto.TSysRes; 6 | import cn.com.wudskq.model.dto.TSysUser; 7 | import cn.com.wudskq.service.TSysResService; 8 | import cn.com.wudskq.service.TSysUserService; 9 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 10 | import com.github.pagehelper.util.StringUtil; 11 | import org.springframework.beans.BeanUtils; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.security.core.GrantedAuthority; 14 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 15 | import org.springframework.security.core.userdetails.UserDetails; 16 | import org.springframework.security.core.userdetails.UserDetailsService; 17 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 18 | import org.springframework.stereotype.Service; 19 | 20 | import javax.annotation.Resource; 21 | import java.util.HashSet; 22 | import java.util.List; 23 | import java.util.Set; 24 | 25 | 26 | @Service 27 | public class SysUserDetailsService implements UserDetailsService { 28 | 29 | @Autowired 30 | private TSysUserService tSysUserService; 31 | 32 | @Resource 33 | private TSysResMapper tSysResMapper; 34 | 35 | @Autowired 36 | private TSysResService tSysResService; 37 | 38 | /** 39 | * 说明:重写UserDetailsService中的loadUserByUsername,就是查询用户详细信息封装到 UserDetails 40 | * 业务: 41 | * ①如果是admin会拥有全部权限 42 | * ②如果不是admin就去查用户信息和用户拥有的权限 43 | * [username] 44 | */ 45 | @Override 46 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 47 | List resList = null; 48 | if(username.equals("admin")){ 49 | TSysUser tSysUser = new TSysUser(); 50 | tSysUser.setId("admin"); 51 | tSysUser.setUsername("admin"); 52 | tSysUser.setNickName("系统管理员"); 53 | SysUserDetails sysUserDetails = new SysUserDetails(); 54 | BeanUtils.copyProperties(tSysUser, sysUserDetails); 55 | Set authorities = new HashSet<>(); // 角色集合 56 | 57 | //admin用户有的资源集合 58 | resList = tSysResMapper.selectList(new QueryWrapper<>()); 59 | for (int i = 0; i < resList.size() ; i++) { 60 | if(StringUtil.isNotEmpty(resList.get(i).getPermission())){ 61 | authorities.add(new SimpleGrantedAuthority("ROLE_" + resList.get(i).getPermission())); 62 | } 63 | } 64 | sysUserDetails.setAuthorities(authorities); 65 | return sysUserDetails; 66 | } 67 | TSysUser tSysUser = tSysUserService.findByUsername(username); 68 | if (tSysUser != null) { 69 | SysUserDetails sysUserDetails = new SysUserDetails(); 70 | BeanUtils.copyProperties(tSysUser, sysUserDetails); 71 | 72 | Set authorities = new HashSet<>(); // 角色集合 73 | 74 | resList = tSysResService.findResByUserId(sysUserDetails.getId());//当前用户有的资源集合 75 | if(resList != null){ 76 | for (int i = 0; i < resList.size() ; i++) { 77 | if(StringUtil.isNotEmpty(resList.get(i).getPermission())){ 78 | authorities.add(new SimpleGrantedAuthority("ROLE_" + resList.get(i).getPermission())); 79 | } 80 | } 81 | } 82 | sysUserDetails.setAuthorities(authorities); 83 | return sysUserDetails; 84 | } 85 | return null; 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/impl/TSysResServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service.impl; 2 | 3 | import cn.com.wudskq.dao.TSysResMapper; 4 | import cn.com.wudskq.dao.TSysRoleMapper; 5 | import cn.com.wudskq.dao.TSysRoleResMapper; 6 | import cn.com.wudskq.model.dto.TSysRes; 7 | import cn.com.wudskq.model.dto.TSysRole; 8 | import cn.com.wudskq.service.TSysResService; 9 | import org.springframework.stereotype.Service; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | 17 | @Service 18 | public class TSysResServiceImpl implements TSysResService { 19 | 20 | @Resource 21 | private TSysResMapper tSysResMapper; 22 | 23 | @Resource 24 | private TSysRoleMapper tSysRoleMapper; 25 | 26 | @Resource 27 | private TSysRoleResMapper tSysRoleResMapper; 28 | 29 | 30 | /** 31 | * 根据用户id查询用户拥有的资源 32 | * [userId] 33 | * @return {@link List< TSysRes>} 34 | * @throws 35 | */ 36 | @Override 37 | public List findResByUserId(String userId) { 38 | //获取用户有的角色 39 | //根据当前登录用户获取角色 40 | List roleList = tSysRoleMapper.findRoleByUserId(userId); 41 | if(roleList == null || roleList.size() == 0){ //如果用户没有角色返回没有权限 42 | return null; 43 | } 44 | //根据角色获取菜单资源id关系集合 45 | Map map = new HashMap<>(); 46 | map.put("roleList",roleList); 47 | List tSysRoleResList = tSysRoleResMapper.selectRoleResByMap(map); 48 | if(tSysRoleResList == null || tSysRoleResList.size() == 0){ //如果用户没有角色返回没有权限 49 | return null; 50 | } 51 | //根据资源id获取菜单资源 52 | return tSysResMapper.selectBatchIds(tSysRoleResList); 53 | 54 | } 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/impl/TSysRoleResServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service.impl; 2 | 3 | import cn.com.wudskq.service.TSysRoleResService; 4 | import org.springframework.stereotype.Service; 5 | 6 | 7 | 8 | @Service 9 | public class TSysRoleResServiceImpl implements TSysRoleResService { 10 | 11 | } 12 | 13 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/impl/TSysRoleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service.impl; 2 | 3 | 4 | import cn.com.wudskq.service.TSysRoleService; 5 | import org.springframework.stereotype.Service; 6 | 7 | 8 | 9 | @Service 10 | public class TSysRoleServiceImpl implements TSysRoleService { 11 | 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/impl/TSysUserRoleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service.impl; 2 | 3 | 4 | import cn.com.wudskq.service.TSysUserRoleService; 5 | import org.springframework.stereotype.Service; 6 | 7 | 8 | 9 | @Service 10 | public class TSysUserRoleServiceImpl implements TSysUserRoleService { 11 | 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/service/impl/TSysUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.service.impl; 2 | 3 | import cn.com.wudskq.dao.TSysUserMapper; 4 | import cn.com.wudskq.model.dto.TSysUser; 5 | import cn.com.wudskq.service.TSysUserService; 6 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.Resource; 10 | 11 | @Service 12 | public class TSysUserServiceImpl implements TSysUserService { 13 | 14 | @Resource 15 | private TSysUserMapper tSysUserMapper; 16 | 17 | 18 | public TSysUser findByUsername(String username) { 19 | QueryWrapper queryWrapper = new QueryWrapper(); 20 | queryWrapper.eq("username",username); 21 | return tSysUserMapper.selectOne(queryWrapper); 22 | } 23 | 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/util/JWTTokenUtil.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.util; 2 | 3 | import cn.com.wudskq.conf.JWTConfig; 4 | import cn.com.wudskq.model.SysUserDetails; 5 | import com.alibaba.fastjson.JSON; 6 | import com.alibaba.fastjson.TypeReference; 7 | import io.jsonwebtoken.Claims; 8 | import io.jsonwebtoken.Jwts; 9 | import io.jsonwebtoken.SignatureAlgorithm; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.commons.lang.StringUtils; 12 | import org.springframework.security.core.GrantedAuthority; 13 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 14 | 15 | import java.util.*; 16 | 17 | 18 | @Slf4j 19 | public class JWTTokenUtil { 20 | 21 | /** 22 | * 创建Token 23 | * 24 | * @param sysUserDetails 用户信息 25 | * @return 26 | */ 27 | public static String createAccessToken(SysUserDetails sysUserDetails) { 28 | String token = Jwts.builder().setId(// 设置JWT 29 | sysUserDetails.getId()) // 用户Id 30 | .setSubject(sysUserDetails.getUsername()) // 主题 31 | .setIssuedAt(new Date()) // 签发时间 32 | .setIssuer("limoumou") // 签发者 33 | .setExpiration(new Date(System.currentTimeMillis() + JWTConfig.expiration)) // 过期时间 34 | .signWith(SignatureAlgorithm.HS512, JWTConfig.secret) // 签名算法、密钥 35 | .claim("authorities", JSON.toJSONString(sysUserDetails.getAuthorities())).compact(); // 自定义其他属性,如用户组织机构ID,用户所拥有的角色,用户权限信息等 36 | return JWTConfig.tokenPrefix + token; 37 | } 38 | 39 | /** 40 | * 解析Token 41 | * 42 | * @param token Token信息 43 | * @return 44 | */ 45 | public static SysUserDetails parseAccessToken(String token) { 46 | SysUserDetails sysUserDetails = null; 47 | if (StringUtils.isNotEmpty(token)) { 48 | try { 49 | // 去除JWT前缀 50 | token = token.substring(JWTConfig.tokenPrefix.length()); 51 | 52 | // 解析Token 53 | Claims claims = Jwts.parser().setSigningKey(JWTConfig.secret).parseClaimsJws(token).getBody(); 54 | 55 | // 获取用户信息 56 | sysUserDetails = new SysUserDetails(); 57 | sysUserDetails.setId(claims.getId()); 58 | sysUserDetails.setUsername(claims.getSubject()); 59 | // 获取角色 60 | Set authorities = new HashSet(); 61 | String authority = claims.get("authorities").toString(); 62 | if (StringUtils.isNotEmpty(authority)) { 63 | List> authorityList = JSON.parseObject(authority, 64 | new TypeReference>>() { 65 | }); 66 | for (Map role : authorityList) { 67 | if (!role.isEmpty()) { 68 | authorities.add(new SimpleGrantedAuthority(role.get("authority"))); 69 | } 70 | } 71 | } 72 | sysUserDetails.setAuthorities(authorities); 73 | } catch (Exception e) { 74 | log.error("解析Token异常:" + e); 75 | } 76 | } 77 | return sysUserDetails; 78 | } 79 | 80 | } 81 | 82 | -------------------------------------------------------------------------------- /boot-security/src/main/java/cn/com/wudskq/util/Md5Util.java: -------------------------------------------------------------------------------- 1 | package cn.com.wudskq.util; 2 | 3 | import java.security.MessageDigest; 4 | 5 | 6 | public class Md5Util { 7 | 8 | public final static String MD5(String s) { 9 | char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 10 | try { 11 | // 密码+盐组合 12 | byte[] btInput = s.getBytes(); 13 | // 获得MD5摘要算法的 MessageDigest 对象 14 | MessageDigest mdInst = MessageDigest.getInstance("MD5"); 15 | // 使用指定的字节更新摘要 16 | mdInst.update(btInput); 17 | // 获得密文 18 | byte[] md = mdInst.digest(); 19 | // 把密文转换成十六进制的字符串形式 20 | int j = md.length; 21 | char str[] = new char[j * 2]; 22 | int k = 0; 23 | for (int i = 0; i < j; i++) { 24 | byte byte0 = md[i]; 25 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 26 | str[k++] = hexDigits[byte0 & 0xf]; 27 | } 28 | return new String(str); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | return null; 32 | } 33 | } 34 | 35 | public static void main(String[] args) { 36 | String pwd = Md5Util.MD5("123456"); 37 | System.out.println(pwd ); 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /boot-security/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | 4 | #数据源 5 | spring: 6 | datasource: 7 | driver-class-name: com.mysql.cj.jdbc.Driver 8 | url: jdbc:mysql://localhost:3306/dev-local?useUnicode=true&characterEncoding=UTF-8 9 | username: root 10 | password: root 11 | #日期配置 yyyy-MM-dd HH:mm:ss 12 | jackson: 13 | date-format: yyyy-MM-dd HH:mm:ss 14 | 15 | #映射xml 16 | mybatis-plus: 17 | mapper-locations: classpath:mapper/*.xml 18 | type-aliases-package: cn.com.wudskq.model.dto 19 | configuration: 20 | #开启驼峰 21 | map-underscore-to-camel-case: true 22 | 23 | # JWT配置 24 | jwt: 25 | # 密匙Key 26 | secret: Awhq^%!*@AJ1263(*@ 27 | # HeaderKey 28 | tokenHeader: Authorization 29 | # Token前缀 30 | tokenPrefix: Bearer 31 | # 过期时间,单位秒 32 | expiration: 86400 33 | # 配置白名单(不需要认证) 34 | antMatchers: /swagger-resources/**,/swagger-ui.html,/v2/api-docs,/webjars/**,/doc.html 35 | 36 | -------------------------------------------------------------------------------- /boot-security/src/main/resources/project.sql: -------------------------------------------------------------------------------- 1 | SET NAMES utf8mb4; 2 | SET FOREIGN_KEY_CHECKS = 0; 3 | 4 | -- ---------------------------- 5 | -- Table structure for t_sys_res 6 | -- ---------------------------- 7 | DROP TABLE IF EXISTS `t_sys_res`; 8 | CREATE TABLE `t_sys_res` ( 9 | `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源id', 10 | `name` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源名称', 11 | `res_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '资源路径', 12 | `permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '资源code', 13 | `res_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '0菜单 1按钮', 14 | `pid` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '父级id', 15 | `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, 16 | `create_date` datetime DEFAULT NULL, 17 | `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '菜单图标' 18 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-资源表【菜单】' ROW_FORMAT = Compact; 19 | 20 | -- ---------------------------- 21 | -- Records of t_sys_res 22 | -- ---------------------------- 23 | INSERT INTO `t_sys_res` VALUES ('101', '用户添加', '/tSysUser/add', '/tSysUser/add', '1', '100', NULL, NULL, ''); 24 | INSERT INTO `t_sys_res` VALUES ('100', '用户管理', '/tSysUser/findByPage', '/tSysUser/findByPage', '0', '', NULL, NULL, 'fa fa-snowflake-o'); 25 | INSERT INTO `t_sys_res` VALUES ('102', '用户修改', '/tSysUser/edit', '/tSysUser/edit', '1', '100', NULL, NULL, 'fa fa-home'); 26 | INSERT INTO `t_sys_res` VALUES ('103', '用户删除', '/tSysUser/delete', '/tSysUser/delete', '1', '100', NULL, NULL, 'fa fa-home'); 27 | 28 | -- ---------------------------- 29 | -- Table structure for t_sys_role 30 | -- ---------------------------- 31 | DROP TABLE IF EXISTS `t_sys_role`; 32 | CREATE TABLE `t_sys_role` ( 33 | `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id', 34 | `role_name` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称', 35 | `role_explain` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述', 36 | `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人', 37 | `create_date` datetime DEFAULT NULL COMMENT '创建时间' 38 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-角色表' ROW_FORMAT = Compact; 39 | 40 | -- ---------------------------- 41 | -- Records of t_sys_role 42 | -- ---------------------------- 43 | INSERT INTO `t_sys_role` VALUES ('277144172094291968', '部门经理', '部门经理', NULL, '2021-08-27 10:22:51'); 44 | INSERT INTO `t_sys_role` VALUES ('277144675716956160', '普通员工', '普通员工', NULL, '2021-08-27 10:24:51'); 45 | INSERT INTO `t_sys_role` VALUES ('277646459757658112', '测试员工', '测试员工', '', '2021-08-28 19:38:46'); 46 | 47 | -- ---------------------------- 48 | -- Table structure for t_sys_role_res 49 | -- ---------------------------- 50 | DROP TABLE IF EXISTS `t_sys_role_res`; 51 | CREATE TABLE `t_sys_role_res` ( 52 | `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', 53 | `role_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id', 54 | `res_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源id' 55 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-角色资源表中间表' ROW_FORMAT = Compact; 56 | 57 | -- ---------------------------- 58 | -- Records of t_sys_role_res 59 | -- ---------------------------- 60 | INSERT INTO `t_sys_role_res` VALUES ('1234', '277144675716956160', '101'); 61 | INSERT INTO `t_sys_role_res` VALUES ('12345', '277144675716956160', '100'); 62 | INSERT INTO `t_sys_role_res` VALUES ('123456', '277144172094291968', '100'); 63 | INSERT INTO `t_sys_role_res` VALUES ('123457', '277144172094291968', '101'); 64 | INSERT INTO `t_sys_role_res` VALUES ('123458', '277144172094291968', '102'); 65 | 66 | -- ---------------------------- 67 | -- Table structure for t_sys_user 68 | -- ---------------------------- 69 | DROP TABLE IF EXISTS `t_sys_user`; 70 | CREATE TABLE `t_sys_user` ( 71 | `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', 72 | `username` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名', 73 | `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码', 74 | `nick_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '昵称', 75 | `cell_phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '手机号', 76 | `mail` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邮件', 77 | `birthday` datetime DEFAULT NULL COMMENT '生日', 78 | `status` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '状态(0-正常,1-删除,2-禁用)', 79 | `account_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '1系统账号 2客户账号', 80 | `invite_code` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邀请码', 81 | `sex` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '性别:0男 1女', 82 | `up_num` int(11) DEFAULT NULL COMMENT '所有获赞总量', 83 | `read_num` int(11) DEFAULT NULL COMMENT '所有文章阅读总量', 84 | `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '地址', 85 | `create_user` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人', 86 | `create_date` datetime DEFAULT NULL COMMENT '创建时间', 87 | `sign` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户签名', 88 | `picture_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户头像' 89 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-用户表' ROW_FORMAT = Compact; 90 | 91 | -- ---------------------------- 92 | -- Records of t_sys_user 93 | -- ---------------------------- 94 | INSERT INTO `t_sys_user` VALUES ('276866508766838784', 'liqingwei', 'E10ADC3949BA59ABBE56E057F20F883E', '李庆伟', '15801174628', 'liqingwei01@cnpc.cn', NULL, '0', '1', '3781941dd39446b89e98cb661766aade', NULL, 0, 0, NULL, NULL, '2021-08-26 15:59:31', NULL, NULL); 95 | INSERT INTO `t_sys_user` VALUES ('277657251341139964', 'zhangsan', 'E10ADC3949BA59ABBE56E057F20F883E', '张三', '15801174626', 'zhangsan@qq.com', '2021-08-04 00:00:00', '0', '1', 'ea819ca462914e938943752d48ae8bcc', '0', 0, 0, '河南北京北', 'admin', '2021-08-28 20:21:38', '啥也不是。。。', '287348042074423296'); 96 | 97 | -- ---------------------------- 98 | -- Table structure for t_sys_user_role 99 | -- ---------------------------- 100 | DROP TABLE IF EXISTS `t_sys_user_role`; 101 | CREATE TABLE `t_sys_user_role` ( 102 | `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', 103 | `user_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户id', 104 | `role_id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id', 105 | PRIMARY KEY (`id`) USING BTREE 106 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统-用户角色中间表' ROW_FORMAT = Compact; 107 | 108 | -- ---------------------------- 109 | -- Records of t_sys_user_role 110 | -- ---------------------------- 111 | INSERT INTO `t_sys_user_role` VALUES ('111', '276866508766838784', '277144675716956160'); 112 | INSERT INTO `t_sys_user_role` VALUES ('222', '277657251341139964', '277144172094291968'); 113 | 114 | SET FOREIGN_KEY_CHECKS = 1; 115 | 116 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cn.com.wudskq 8 | boot-project 9 | pom 10 | 1.0.0 11 | 12 | boot-datasource 13 | boot-kafka 14 | boot-rabbitmq 15 | boot-redis 16 | boot-mybatis-Interceptor 17 | boot-mybatis-plus-interceptor 18 | boot-mqtt 19 | boot-security 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-parent 25 | 2.2.13.RELEASE 26 | 27 | 28 | 29 | 8 30 | 8 31 | 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------