├── .gitignore ├── LICENSE ├── README.md ├── algorithm ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── wuwii │ └── leetcode │ ├── AddTwoNumbers.java │ ├── LinkedListSummary.java │ └── TwoSum.java ├── base-point ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── wuwii │ └── regular │ ├── Regular01.java │ ├── Regular02.java │ ├── Regular03.java │ ├── Regular04.java │ └── package-info.java ├── design-pattern ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── wuwii │ ├── factory │ ├── CoderFactory.java │ ├── CoderJava.java │ ├── CoderPhp.java │ ├── CoderPython.java │ └── Coding.java │ ├── observer │ ├── BuyObserver.java │ ├── CouponOberver.java │ ├── Observer.java │ ├── ObserverMain.java │ ├── ProductObservable.java │ └── RecommendOberver.java │ ├── proxy │ ├── HouseOwner.java │ ├── HouseProxy.java │ └── RentHouse.java │ ├── singleton │ ├── SingletonDemo1.java │ ├── SingletonDemo2.java │ ├── SingletonDemo3.java │ ├── SingletonDemo4.java │ └── SingletonDemo5.java │ └── strategy │ ├── Bike.java │ ├── StrategyContext.java │ ├── StrategyDemo.java │ ├── Subway.java │ ├── Taxi.java │ └── Vehicle.java ├── dynamic-schedule ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ └── DynamicScheduleApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── wuwii │ └── DynamicScheduleApplicationTests.java ├── fork-join ├── README.md ├── pom.xml └── src │ └── main │ └── java │ ├── PrintTask.java │ └── SumTask.java ├── html5-butterflies ├── .gitignore ├── README.md ├── config.rb ├── css │ ├── clouds_back.jpg │ ├── clouds_front.jpg │ ├── clouds_left.jpg │ ├── clouds_right.jpg │ ├── clouds_top.jpg │ ├── hazy_lake_top.jpg │ ├── main.css │ ├── reset.css │ └── style.css ├── index.html ├── index1.html ├── js │ └── index.js ├── main.css └── scss │ └── style.scss ├── interview-code ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── wuwii │ │ ├── cas │ │ ├── CasDemo.java │ │ ├── Mutex.java │ │ └── TwinsLock.java │ │ ├── countdownlatch │ │ └── CountDownLatchDemo.java │ │ ├── cyclicbarrier │ │ └── CyclicBarrierDemo.java │ │ └── semaphore │ │ └── SemaphoreDemo.java │ └── test │ └── java │ └── com │ └── wuwii │ └── cas │ ├── MutexTest.java │ └── TwinsLockTest.java ├── java8-function-demo ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── Demo.java ├── jdbc-muti-datasource ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── JdbcMutiDatasourceApplication.java │ │ │ └── config │ │ │ └── DataSourceConfig.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── wuwii │ ├── JdbcMutiDatasourceApplicationTests.java │ └── TestJDBC.java ├── jpa-criteria ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── JpaCriteriaApplication.java │ │ │ ├── controller │ │ │ └── EmployeeController.java │ │ │ ├── dao │ │ │ ├── EmployeeDao.java │ │ │ └── JobDao.java │ │ │ ├── entity │ │ │ ├── Employee.java │ │ │ ├── EmployeeDetail.java │ │ │ ├── EmployeeDetail_.java │ │ │ ├── Employee_.java │ │ │ ├── Job.java │ │ │ └── Job_.java │ │ │ ├── form │ │ │ ├── EmployeeResult.java │ │ │ └── EmployeeSearch.java │ │ │ └── service │ │ │ ├── EmployeeService.java │ │ │ ├── HelloService.java │ │ │ └── impl │ │ │ ├── EmployeeServiceImpl.java │ │ │ └── HelloServiceImpl.java │ └── resources │ │ ├── application.yml │ │ └── learn.sql │ └── test │ └── java │ └── com │ └── wuwii │ ├── JpaCriteriaApplicationTests.java │ ├── controller │ ├── EmployeeController1Test.java │ ├── EmployeeController2Test.java │ └── EmployeeControllerTest.java │ ├── dao │ └── EmployeeDaoTest.java │ ├── paramter │ └── ParameterTest.java │ ├── service │ └── impl │ │ ├── EmployeeServiceImplTest.java │ │ └── HelloServiceImplTest.java │ └── suit │ ├── SuitTest.java │ ├── TaskOneTest.java │ ├── TaskThreeTest.java │ └── TaskTwoTest.java ├── jpa-muti-datasource ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── JpaMutiDatasourceApplication.java │ │ │ └── module │ │ │ ├── system │ │ │ ├── EmployeeDao.java │ │ │ ├── config │ │ │ │ └── FirstDataSourceConfig.java │ │ │ ├── dao │ │ │ │ └── EmployeeDao.java │ │ │ └── entity │ │ │ │ └── Employee.java │ │ │ └── user │ │ │ ├── config │ │ │ ├── SecondDataSource.java │ │ │ └── SecondDataSourceConfig.java │ │ │ ├── dao │ │ │ └── UserDao.java │ │ │ └── entity │ │ │ └── User.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── wuwii │ ├── JpaMutiDatasourceApplicationTests.java │ └── TestDemo.java ├── learn-hystrix ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ ├── HelloWorldHystrixCommand.java │ │ └── HelloWorldHystrixObservableCommand.java │ └── resources │ └── log4j.properties ├── nio-netty ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── wuwii │ ├── netty │ ├── chat │ │ ├── ChatClient.java │ │ ├── ChatClientHandler.java │ │ ├── ChatServer.java │ │ ├── ChatServerHandler.java │ │ ├── ChatServerInitializer.java │ │ └── package-info.java │ ├── core │ │ ├── BaseClientTemplate.java │ │ └── BaseServerTemplate.java │ ├── discard │ │ ├── DisCardServerHandler.java │ │ ├── DiscardServer.java │ │ └── package-info.java │ ├── echo │ │ ├── EchoServer.java │ │ ├── EchoServerHandler.java │ │ └── package-info.java │ ├── pojo │ │ ├── PojoClient.java │ │ ├── PojoClientHandler.java │ │ ├── PojoServer.java │ │ ├── PojoServerHandler.java │ │ ├── TimeDecoder.java │ │ ├── TimeEncoder.java │ │ ├── UnixTime.java │ │ └── package-info.java │ └── time │ │ ├── TimeClient.java │ │ ├── TimeClientHandler.java │ │ ├── TimeServer.java │ │ ├── TimeServerHandler.java │ │ └── package-info.java │ └── nio1 │ ├── Client.java │ └── Server.java ├── pom.xml ├── rocketmq-demo ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── Consumer.java │ │ │ ├── MQConsumeMsgListenerProcessor.java │ │ │ ├── Productor.java │ │ │ └── RocketmqDemoApplication.java │ └── resources │ │ └── application.yaml │ └── test │ └── java │ └── com │ └── wuwii │ └── RocketmqDemoApplicationTests.java ├── sort-algorithm ├── .gitignore ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── sort │ │ │ └── LearnSort.java │ └── resources │ │ └── log4j.properties │ └── test │ └── java │ └── sort │ └── LearnSortTest.java ├── spring-boot-test ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── Application.java │ │ │ ├── controller │ │ │ └── UserController.java │ │ │ ├── model │ │ │ └── User.java │ │ │ ├── repository │ │ │ └── IUserRepository.java │ │ │ └── service │ │ │ ├── IUserService.java │ │ │ └── impl │ │ │ └── UserServiceImpl.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── wuwii │ │ └── service │ │ ├── IUserServiceTest.java │ │ └── SpringDataBaseTest.java │ └── resources │ ├── application-h2.yml │ ├── application-mysql.yml │ ├── application.yml │ ├── data.sql │ └── drop.sql ├── spring-event ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── wuwii │ │ ├── PropertiesChangeEvent.java │ │ ├── PropertiesChangeListener.java │ │ ├── PropertiesChangePublisher.java │ │ └── SpringEventApplication.java │ └── test │ └── java │ └── com │ └── wuwii │ └── PropertiesChangePublisherTest.java ├── springboot-actuator ├── .gitignore ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ └── SpringbootActuatorApplication.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── wuwii │ └── SpringbootActuatorApplicationTests.java ├── springboot-docker ├── README.md ├── docker-compose-swarm.yml ├── docker-compose.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── docker │ └── Dockerfile │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── SpringbootDockerApplication.java │ │ │ ├── dao │ │ │ └── UserDao.java │ │ │ └── entity │ │ │ └── User.java │ └── resources │ │ └── application.yaml │ └── test │ └── java │ └── com │ └── wuwii │ └── SpringbootDockerApplicationTests.java ├── springboot-querydsl ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── SpringbootQuerydslApplication.java │ │ │ ├── config │ │ │ └── JPAQueryConfig.java │ │ │ ├── dao │ │ │ └── EmployeeDao.java │ │ │ ├── entity │ │ │ ├── Employee.java │ │ │ ├── EmployeeDetail.java │ │ │ ├── Job.java │ │ │ ├── QEmployee.java │ │ │ ├── QEmployeeDetail.java │ │ │ └── QJob.java │ │ │ └── service1 │ │ │ ├── EmployeeService1.java │ │ │ ├── impl │ │ │ └── EmployeeServiceImpl1.java │ │ │ └── package-info.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── wuwii │ └── SpringbootQuerydslApplicationTests.java ├── springboot-redis-cache ├── .gitignore ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── SpringbootRedisCacheApplication.java │ │ │ ├── controller.java │ │ │ ├── dao │ │ │ └── EmployeeDao.java │ │ │ ├── entity │ │ │ └── Employee.java │ │ │ └── service │ │ │ ├── EmployeeService.java │ │ │ └── impl │ │ │ └── EmployeeServiceImpl.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── wuwii │ ├── SpringbootRedisCacheApplicationTests.java │ └── service │ └── impl │ └── EmployeeServiceImplTest.java ├── springboot-security ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── wuwii │ │ │ ├── SpringbootSecurityApplication.java │ │ │ ├── config │ │ │ ├── Swagger2Config.java │ │ │ └── security │ │ │ │ ├── SecurityModelFactory.java │ │ │ │ ├── UserDetailServiceImpl.java │ │ │ │ ├── UserDetailsImpl.java │ │ │ │ ├── v1 │ │ │ │ ├── CustomAuthenticationProvider.java │ │ │ │ ├── JwtAuthenticationFilter.java │ │ │ │ ├── LoginFilter.java │ │ │ │ └── WebSecurityConfig.java │ │ │ │ └── v2 │ │ │ │ ├── AuthenticationFilter.java │ │ │ │ ├── WebSecurityConfig.java │ │ │ │ └── authenticate │ │ │ │ ├── LoginAuthenticationProvider.java │ │ │ │ └── TokenAuthenticateProvider.java │ │ │ ├── controller │ │ │ └── UserController.java │ │ │ ├── dao │ │ │ ├── RoleDao.java │ │ │ ├── UserDao.java │ │ │ └── UserRoleDao.java │ │ │ ├── entity │ │ │ ├── Role.java │ │ │ ├── User.java │ │ │ └── UserRole.java │ │ │ ├── excetion │ │ │ ├── ExceptionHandler.java │ │ │ └── KCException.java │ │ │ ├── service │ │ │ ├── UserService.java │ │ │ └── impl │ │ │ │ └── UserServiceImpl.java │ │ │ ├── util │ │ │ └── JwtUtil.java │ │ │ └── vo │ │ │ ├── UserAddDTO.java │ │ │ └── UserVO.java │ └── resources │ │ ├── application.yml │ │ ├── config │ │ └── ehcache.xml │ │ └── static │ │ ├── index.html │ │ ├── login.html │ │ └── logout.html │ └── test │ └── java │ └── com │ └── wuwii │ ├── SpringbootSecurityApplicationTests.java │ └── password │ └── BCryptPasswordEncoderTest.java └── template-design-spring ├── README.md ├── pom.xml └── src └── main └── java └── com └── wuwii ├── Application.java └── service ├── AbstractPay.java ├── AliPay.java ├── Pay.java └── WeChatPay.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | target/ 25 | !.mvn/wrapper/maven-wrapper.jar 26 | 27 | ### STS ### 28 | .apt_generated 29 | .classpath 30 | .factorypath 31 | .project 32 | .settings 33 | .springBeans 34 | 35 | ### IntelliJ IDEA ### 36 | .idea 37 | *.iws 38 | *.iml 39 | *.ipr 40 | */.mvn/ 41 | 42 | ### NetBeans ### 43 | nbproject/private/ 44 | build/ 45 | nbbuild/ 46 | dist/ 47 | nbdist/ 48 | .nb-gradle/ 49 | /.mvn/ 50 | 51 | **/target 52 | **.iml 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # learning-code 2 | Coding for studying 3 | 平常的一些代码的积累 4 | 5 | * design-pattern: 设计模式 6 | * fork-join: fork-join模型 7 | * jdbc-muti-datasource: springboot 中使用jdbc多数据源 8 | * jpa-criteria:Spring Boot 中使用 JPA 完成复杂查询 9 | * jpa-muti-datasource:Spring Boot 中 JPA 多数据源(无分布式事务) 10 | * rxjava 11 | * sort-algorithm:八种基本排序 12 | * springboot-actuator:spring-boot 2.0 中使用 actuator 13 | * springboot-redis-cache:Spring Boot 中使用 redis 完成集中缓存 14 | -------------------------------------------------------------------------------- /algorithm/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | learning-code 7 | com.wuwii 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | algorithm 13 | 14 | 15 | -------------------------------------------------------------------------------- /algorithm/src/main/java/com/wuwii/leetcode/AddTwoNumbers.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.leetcode; 2 | 3 | /** 4 | * https://leetcode.com/problems/add-two-numbers/description/ 5 | *

6 | * medium 7 | *

8 | * You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. 9 | *

10 | * You may assume the two numbers do not contain any leading zero, except the number 0 itself. 11 | *

12 | * Example 13 | *

14 | * Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) 15 | * Output: 7 -> 0 -> 8 16 | * Explanation: 342 + 465 = 807. 17 | *

18 | * Definition for singly-linked list. 19 | * public class ListNode { 20 | * int val; 21 | * ListNode next; 22 | * ListNode(int x) { val = x; } 23 | * } 24 | * 25 | * @author KronChan 26 | * @version 1.0 27 | * @since

2017/12/21 11:48
28 | */ 29 | public class AddTwoNumbers { 30 | class ListNode { 31 | public ListNode next; 32 | public int val; 33 | 34 | public ListNode(int x) { 35 | val = x; 36 | } 37 | } 38 | 39 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 40 | ListNode result = new ListNode(0); 41 | // 进位 42 | int hamal = 0; 43 | ListNode middleware = result; 44 | while (l1 != null && l2 != null) { 45 | int sum = l1.val + l2.val + hamal; 46 | hamal = sum / 10; 47 | middleware.next = new ListNode(sum % 10); 48 | middleware = middleware.next; 49 | l1 = l1.next; 50 | l2 = l2.next; 51 | } 52 | return result.next; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /algorithm/src/main/java/com/wuwii/leetcode/LinkedListSummary.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.leetcode; 2 | 3 | /** 4 | * http://blog.csdn.net/kerryfish/article/details/24043099 5 | * https://www.cnblogs.com/winorgohome/p/6028309.html 6 | * 7 | * @author KronChan 8 | * @version 1.0 9 | * @since
2017/12/22 21:48
10 | */ 11 | public class LinkedListSummary { 12 | 13 | /** 14 | * 获取链表存储元素的数量 15 | * 16 | * @param node 链表 17 | * @return int 18 | */ 19 | public static int size(Node node) { 20 | int i = 0; 21 | for (; node != null; ) { 22 | i++; 23 | node = node.next; 24 | } 25 | return i; 26 | } 27 | 28 | public static Node reversal(Node node) { 29 | Node indirection = node; 30 | for (; indirection != null; ) { 31 | 32 | } 33 | return null; 34 | } 35 | 36 | class Node { 37 | int val; 38 | Node next; 39 | 40 | Node(int val) { 41 | this.val = val; 42 | } 43 | } 44 | 45 | public static void main(String[] args) { 46 | 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /algorithm/src/main/java/com/wuwii/leetcode/TwoSum.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.leetcode; 2 | 3 | /** 4 | * https://leetcode.com/problems/two-sum/description/ 5 | *

6 | * Easy 7 | *

8 | * Given an array of integers, return indices of the two numbers such that they add up to a specific target. 9 | * You may assume that each input would have exactly one solution, and you may not use the same element twice. 10 | *

11 | * Example: 12 | * Given nums = [2, 7, 11, 15], target = 9, 13 | *

14 | * Because nums[0] + nums[1] = 2 + 7 = 9, 15 | * return [0, 1]. 16 | *

17 | * My thoughts: 18 | * 19 | * @author KronChan 20 | * @version 1.0 21 | * @since

2017/12/20 22:49
22 | */ 23 | public class TwoSum { 24 | 25 | public int[] twoSum(int[] nums, int target) { 26 | // complexity O (n^2) 27 | for (int i = 0, len = nums.length; i < len; i++) { 28 | for (int j = i + 1; j < len; j++) { 29 | if (nums[i] + nums[j] == target) { 30 | return new int[]{i, j}; 31 | } 32 | } 33 | } 34 | throw new IllegalArgumentException(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /base-point/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | learning-code 7 | com.wuwii 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | base-point 13 | 14 | 15 | -------------------------------------------------------------------------------- /base-point/src/main/java/com/wuwii/regular/Regular01.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.regular; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | * java 正则 api 基础训练 8 | * 9 | * @author kai.zhang 10 | * @date 2020/1/9 21:21 11 | */ 12 | public class Regular01 { 13 | /** 14 | * 生成一个正则表达式的模式,注意只能用静态方法生成, 15 | */ 16 | private static final Pattern HTTP_PATTERN = Pattern.compile("^https?://.*"); 17 | 18 | private static void matchHttp(String http) { 19 | // 创建指定字符串的匹配对象 20 | Matcher matcher = HTTP_PATTERN.matcher(http); 21 | // 根据创建好的匹配对象,我们可以根据正则表达式的规则操作字符串 22 | // matches 表示,尝试将整个区域与模式匹配,则返回 true,否则返回 false 23 | boolean matches = matcher.matches(); 24 | if (matches) { 25 | System.out.printf("http:%s, matches result=true", http); 26 | } else { 27 | System.err.printf("http:%s, matches result=false", http); 28 | } 29 | } 30 | 31 | public static void main(String[] args) { 32 | String http = "https://github.com/kaimz"; 33 | matchHttp(http); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /base-point/src/main/java/com/wuwii/regular/Regular02.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.regular; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | * 正则表达式的捕获组(capture group) 8 | * 9 | * @author kai.zhang 10 | * @date 2020/1/9 21:42 11 | */ 12 | public class Regular02 { 13 | 14 | /** 15 | * 从正则表达式左侧开始,没出现一个左括号"(" 记做一个子表达式,子表示分组编号从 1 开始. 0 代表整个表达式 16 | * 命名捕获组: 每个以左括号开始的捕获组,都紧跟着 ?,然后才是正则表达式 17 | * 另外: "(?:正则表达式)", 非捕获组: 这种表达方式表示忽略该组,不计算分组编号.这个在使用 "或" 这个功能的时候非常有用 18 | * 19 | * 减少不需要获取的分组,可以提高正则表达式的性能 20 | */ 21 | private static final Pattern HTTP_PATTERN = Pattern.compile("^https?://(?(?:\\w+\\.)+(?:com|cn|net))(?:/.*)+(?\\?.*)"); 22 | 23 | private static void capturing(String http) { 24 | Matcher matcher = HTTP_PATTERN.matcher(http); 25 | matcher.find(); 26 | System.out.println(matcher.group(0)); 27 | // 可以使用编号访问捕获的值. matcher.group(1); 28 | String domain = matcher.group("domain"); 29 | System.out.println(domain); 30 | // matcher.group(2); 31 | String param = matcher.group("param"); 32 | System.out.println(param); 33 | } 34 | 35 | public static void main(String[] args) { 36 | String http = "https://github.com/kaimz?tab=repositories"; 37 | capturing(http); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /base-point/src/main/java/com/wuwii/regular/Regular03.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.regular; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | /** 8 | * find 多次匹配字符串的一部分 9 | * 10 | * @author kai.zhang 11 | * @date 2020/1/10 14:46 12 | */ 13 | public class Regular03 { 14 | public static final String END_MESSAGE = "group:{0}, 结束位置: {1}"; 15 | private static final Pattern PATTERN = Pattern.compile("([a-zA-Z]{2})(?\\d{2,3})"); 16 | private static final String START_MESSAGE = "group:{0}, 开始位置: {1}"; 17 | 18 | private static void find(String str) { 19 | Matcher matcher = PATTERN.matcher(str); 20 | StringBuffer sb = new StringBuffer(); 21 | // 查找与该模式匹配的输入序列的下一个子序列,能匹配返回 true,没有返回 false 22 | while (matcher.find()) { 23 | System.out.println(MessageFormat.format(START_MESSAGE, 0, matcher.start())); 24 | //注: matcher.group(0) 是匹配到的子序列整个的值 25 | System.out.println(matcher.group()); 26 | System.out.println(MessageFormat.format(END_MESSAGE, 0, matcher.end())); 27 | // 匹配开始的位置 28 | System.out.println(MessageFormat.format(START_MESSAGE, 1, matcher.start(1))); 29 | System.out.println(matcher.group(1)); 30 | // 匹配结束的位置 31 | System.out.println(MessageFormat.format(END_MESSAGE, 1, matcher.end(1))); 32 | 33 | System.out.println(MessageFormat.format(START_MESSAGE, "digit", matcher.start("digit"))); 34 | //group2 被重命名 digit,也可以使用group2 35 | System.out.println(matcher.group("digit")); 36 | System.out.println(MessageFormat.format(END_MESSAGE, "digit", matcher.end("digit"))); 37 | 38 | // 替换group1位置的内容,group2保持不变,新的内容保存在新的字符串sb上 39 | matcher.appendReplacement(sb, matcher.group(1).toUpperCase() + matcher.group(2) + "a"); 40 | 41 | System.out.println("----------------"); 42 | } 43 | System.out.println(sb.toString()); 44 | // 最后一次匹配的内容加到sb中,因为不加这个方法,后面没有匹配的内容的将没有加上 45 | matcher.appendTail(sb); 46 | System.out.println(sb); 47 | // 整行匹配的结果 48 | System.out.println(matcher.matches()); 49 | } 50 | 51 | public static void main(String[] args) { 52 | String text = "aa11-bb223-Cc33dd"; 53 | find(text); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /base-point/src/main/java/com/wuwii/regular/Regular04.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.regular; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | * @author kai.zhang 8 | * @date 2020/1/10 18:19 9 | */ 10 | public class Regular04 { 11 | 12 | private static void or() { 13 | // 或者使用 inssy(?:t|a|v) 14 | // ?:pattern 表示匹配 pattern 单不需要获取结果,是一个非获取匹配,不需要存储供以后使用 15 | Pattern pattern = Pattern.compile("do(ing)|(es)"); //do(?:ing|es) 16 | Matcher matcher = pattern.matcher("does"); 17 | System.out.println(matcher.matches()); 18 | } 19 | 20 | private static void test() { 21 | Pattern pattern = Pattern.compile("(?\\w+\\.)+"); 22 | Matcher matcher = pattern.matcher("blog.wuwii"); 23 | System.out.println(matcher.matches()); 24 | 25 | } 26 | 27 | public static void main(String[] args) { 28 | // or(); 29 | test(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /base-point/src/main/java/com/wuwii/regular/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 正则训练和笔记 3 | * 在线训练工具 https://regex101.com/ 4 | * 5 | * @author kai.zhang 6 | * @date 2020/1/10 19:32 7 | */ 8 | package com.wuwii.regular; -------------------------------------------------------------------------------- /design-pattern/README.md: -------------------------------------------------------------------------------- 1 | Java 中 设计模式的学习 -------------------------------------------------------------------------------- /design-pattern/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.wuwii 8 | design-pattern 9 | 1.0-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | UTF-8 14 | 1.8 15 | 16 | 17 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/factory/CoderFactory.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.factory; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | 5 | /** 6 | * 工厂模式,直接利用面向对象和反射实现工厂 7 | * @author Zhang Kai 8 | * @version 1.0 9 | * @since
2018/3/21 18:50
10 | */ 11 | public class CoderFactory { 12 | public static Object getCoder(@NotNull Class clazz) { 13 | Object object = null; 14 | try { 15 | object = Class.forName(clazz.getName()).newInstance(); 16 | } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { 17 | e.printStackTrace(); 18 | } 19 | return object; 20 | } 21 | 22 | public static void main(String[] args) { 23 | Coding java = (CoderJava) CoderFactory.getCoder(CoderJava.class); 24 | java.code(); 25 | Coding python = (CoderPython) CoderFactory.getCoder(CoderPython.class); 26 | python.code(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/factory/CoderJava.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.factory; 2 | 3 | /** 4 | * @author Zhang Kai 5 | * @version 1.0 6 | * @since
2018/3/21 18:56
7 | */ 8 | public class CoderJava implements Coding { 9 | @Override 10 | public void code() { 11 | System.out.println("java"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/factory/CoderPhp.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.factory; 2 | 3 | /** 4 | * @author Zhang Kai 5 | * @version 1.0 6 | * @since
2018/3/21 18:57
7 | */ 8 | public class CoderPhp implements Coding { 9 | @Override 10 | public void code() { 11 | System.out.println("PHP"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/factory/CoderPython.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.factory; 2 | 3 | /** 4 | * @author Zhang Kai 5 | * @version 1.0 6 | * @since
2018/3/21 18:57
7 | */ 8 | public class CoderPython implements Coding { 9 | @Override 10 | public void code() { 11 | System.out.println("Python"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/factory/Coding.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.factory; 2 | 3 | /** 4 | * @author Zhang Kai 5 | * @version 1.0 6 | * @since
2018/3/21 18:49
7 | */ 8 | public interface Coding { 9 | void code(); 10 | } 11 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/observer/BuyObserver.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.observer; 2 | 3 | /** 4 | * Created by KronChan on 18/6/26 上午10:16. 5 | */ 6 | public class BuyObserver implements Observer { 7 | @Override 8 | public void receive(String product) { 9 | System.out.println(String.format("You have bought the %s successfully", product)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/observer/CouponOberver.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.observer; 2 | 3 | /** 4 | * Created by KronChan on 18/6/26 上午10:19. 5 | */ 6 | public class CouponOberver implements Observer { 7 | @Override 8 | public void receive(String product) { 9 | System.out.println(String.format("Give you some coupons for %s.", product)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/observer/Observer.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.observer; 2 | 3 | /** 4 | * Created by KronChan on 18/6/26 上午10:01. 5 | */ 6 | public interface Observer { 7 | /** 8 | * The observer receive the semaphore. 9 | */ 10 | void receive(String product); 11 | } 12 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/observer/ObserverMain.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.observer; 2 | 3 | /** 4 | * Created by KronChan on 18/6/26 上午10:24. 5 | */ 6 | public class ObserverMain { 7 | public static void main(String[] args) { 8 | Observer buyObserver = new BuyObserver(); 9 | Observer couponOberver = new CouponOberver(); 10 | Observer recommendOberver = new RecommendOberver(); 11 | ProductObservable productObservable = new ProductObservable(buyObserver, couponOberver, recommendOberver); 12 | productObservable.BuyProductSuccessfully("Computer"); 13 | productObservable.BuyProductSuccessfully("mouse"); 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/observer/ProductObservable.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.observer; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.concurrent.CopyOnWriteArrayList; 6 | 7 | /** 8 | * Created by KronChan on 18/6/26 上午10:06. 9 | */ 10 | public class ProductObservable { 11 | private List observers = new CopyOnWriteArrayList<>(); 12 | 13 | public ProductObservable(Observer... observers) { 14 | addObserver(observers); 15 | } 16 | 17 | protected void addObserver(Observer... observers) { 18 | this.observers.addAll(Arrays.asList(observers)); 19 | } 20 | 21 | protected void removeObserver(Observer... observers) { 22 | this.observers.removeAll(Arrays.asList(observers)); 23 | } 24 | 25 | public void BuyProductSuccessfully(String product) { 26 | for (Observer observer : observers) { 27 | observer.receive(product); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/observer/RecommendOberver.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.observer; 2 | 3 | /** 4 | * Created by KronChan on 18/6/26 上午10:23. 5 | */ 6 | public class RecommendOberver implements Observer { 7 | @Override 8 | public void receive(String product) { 9 | System.out.println(String.format("Here are recommending you some other %s.", product)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/proxy/HouseOwner.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.proxy; 2 | 3 | /** 4 | * Created by KronChan on 18/6/22 上午11:47. 5 | */ 6 | public class HouseOwner implements RentHouse { 7 | @Override 8 | public void rent() { 9 | // 1. 看房 10 | // 2. 交押金 11 | // …… 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/proxy/HouseProxy.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.proxy; 2 | 3 | /** 4 | * Created by KronChan on 18/6/22 上午11:48. 5 | */ 6 | public class HouseProxy implements RentHouse { 7 | private HouseOwner houseOwner; 8 | 9 | public HouseProxy(HouseOwner houseOwner) { 10 | this.houseOwner = houseOwner; 11 | } 12 | 13 | @Override 14 | public void rent() { 15 | houseOwner.rent(); 16 | afterRent(); 17 | } 18 | 19 | /** 20 | * 租房成功后行为, 21 | */ 22 | private void afterRent() { 23 | // 租成功后要付中介费…… 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/proxy/RentHouse.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.proxy; 2 | 3 | /** 4 | * Created by KronChan on 18/6/22 上午11:46. 5 | */ 6 | public interface RentHouse { 7 | void rent(); 8 | } 9 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/singleton/SingletonDemo1.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.singleton; 2 | 3 | /** 4 | * 懒汉式,线程安全,懒加载 (不适用) 5 | * 6 | * @author Zhang Kai 7 | * @version 1.0 8 | * @since
2018/3/21 15:53
9 | */ 10 | public class SingletonDemo1 { 11 | private static SingletonDemo1 instance; 12 | 13 | private SingletonDemo1() { 14 | 15 | } 16 | 17 | public static synchronized SingletonDemo1 getInstance() { 18 | if (instance == null) { 19 | instance = new SingletonDemo1(); 20 | } 21 | return instance; 22 | } 23 | 24 | public static void main(String[] args) { 25 | SingletonDemo1 demo = SingletonDemo1.getInstance(); 26 | demo.show(); 27 | } 28 | 29 | public void show() { 30 | System.out.println("Hello World."); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/singleton/SingletonDemo2.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.singleton; 2 | 3 | /** 4 | * 饿汉式,线程安全,没有懒加载 5 | * 6 | * @author Zhang Kai 7 | * @version 1.0 8 | * @since
2018/3/21 16:34
9 | */ 10 | public class SingletonDemo2 { 11 | private static SingletonDemo2 instance = new SingletonDemo2(); 12 | 13 | private SingletonDemo2() { 14 | 15 | } 16 | 17 | public static SingletonDemo2 getInstance() { 18 | return instance; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/singleton/SingletonDemo3.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.singleton; 2 | 3 | /** 4 | *  Double-Check 双重检查,线程安全,懒加载, jdk > 1.5 5 | * 6 | * @author Zhang Kai 7 | * @version 1.0 8 | * @since
2018/3/21 16:35
9 | */ 10 | public class SingletonDemo3 { 11 | private volatile static SingletonDemo3 instance; 12 | 13 | private SingletonDemo3() { 14 | 15 | } 16 | 17 | /** 18 | * 为了减少同步的开销,采用双重检查 19 | */ 20 | public static SingletonDemo3 getInstance() { 21 | if (instance == null) { 22 | synchronized (SingletonDemo3.class) { 23 | if (instance == null) { 24 | instance = new SingletonDemo3(); 25 | } 26 | } 27 | } 28 | return instance; 29 | } 30 | 31 | public static void main(String[] args) { 32 | SingletonDemo3 demo = SingletonDemo3.getInstance(); 33 | demo.show(); 34 | } 35 | 36 | public void show() { 37 | System.out.println("Hello World."); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/singleton/SingletonDemo4.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.singleton; 2 | 3 | /** 4 | * 登记式,静态内部类,线程安全,懒加载 5 | * 6 | * @author Zhang Kai 7 | * @version 1.0 8 | * @since
2018/3/21 16:39
9 | */ 10 | public class SingletonDemo4 { 11 | private SingletonDemo4() { 12 | 13 | } 14 | 15 | /** 16 | * 注意的是 》类的静态属性只会在第一次加载类的时候初始化, 17 | * 在初次加载 getInstance 方法时候才会去装载 SingletonHolder 静态类,从而有 Lazy-Loading的作用。 18 | */ 19 | public static SingletonDemo4 getInstance() { 20 | return SingletonHolder.instance; 21 | } 22 | 23 | public static void main(String[] args) { 24 | SingletonDemo4.getInstance().show(); 25 | } 26 | 27 | public void show() { 28 | System.out.println("Hello World."); 29 | } 30 | 31 | private static class SingletonHolder { 32 | static SingletonDemo4 instance = new SingletonDemo4(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/singleton/SingletonDemo5.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.singleton; 2 | 3 | /** 4 | * 使用枚举,枚举本身是单例静态的,线程安全,没有懒加载 5 | * 6 | * @author Zhang Kai 7 | * @version 1.0 8 | * @since
2018/3/21 17:03
9 | */ 10 | public enum SingletonDemo5 { 11 | INSTANCE; 12 | 13 | public static void main(String[] args) { 14 | SingletonDemo5.INSTANCE.show(); 15 | } 16 | 17 | public void show() { 18 | System.out.println("Hello World."); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/strategy/Bike.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.strategy; 2 | 3 | /** 4 | * 5 | */ 6 | public class Bike implements Vehicle { 7 | @Override 8 | public String take() { 9 | return "By bike is good for your health"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/strategy/StrategyContext.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.strategy; 2 | 3 | import com.sun.istack.internal.Nullable; 4 | 5 | /** 6 | * 使用上下文, 7 | */ 8 | public class StrategyContext { 9 | @Nullable 10 | public static Vehicle strategyVehicle(Class clazz) { 11 | if (clazz == null) { 12 | return null; 13 | } 14 | try { 15 | return (Vehicle) Class.forName(clazz.getName()).newInstance(); 16 | } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { 17 | e.printStackTrace(); 18 | } 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/strategy/StrategyDemo.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.strategy; 2 | 3 | /** 4 | * @author KronChan 5 | */ 6 | public class StrategyDemo { 7 | 8 | public static String vehicle(String vehicle) { 9 | switch (vehicle) { 10 | case "taxi": 11 | return "Take the taxi is expensive"; 12 | case "subway": 13 | return "Take the subway is inexpensive"; 14 | default: 15 | return null; 16 | } 17 | } 18 | 19 | public static void main(String[] args) { 20 | System.out.println(StrategyDemo.vehicle("taxi")); 21 | System.out.println(StrategyContext.strategyVehicle(Bike.class).take()); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/strategy/Subway.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.strategy; 2 | 3 | /** 4 | * 5 | */ 6 | public class Subway implements Vehicle { 7 | @Override 8 | public String take() { 9 | return "Take the subway is inexpensive"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/strategy/Taxi.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.strategy; 2 | 3 | /** 4 | * 5 | */ 6 | public class Taxi implements Vehicle { 7 | 8 | @Override 9 | public String take() { 10 | return "Take the taxi is expensive"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /design-pattern/src/main/java/com/wuwii/strategy/Vehicle.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.strategy; 2 | 3 | /** 4 | * 策略行为 5 | */ 6 | public interface Vehicle { 7 | String take(); 8 | } 9 | -------------------------------------------------------------------------------- /dynamic-schedule/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /dynamic-schedule/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/dynamic-schedule/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /dynamic-schedule/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /dynamic-schedule/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.wuwii 7 | dynamic-schedule 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | dynamic-schedule 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.2.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-devtools 36 | runtime 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-maven-plugin 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /dynamic-schedule/src/main/java/com/wuwii/DynamicScheduleApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @SpringBootApplication 10 | public class DynamicScheduleApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(DynamicScheduleApplication.class, args); 14 | } 15 | 16 | @GetMapping("/hello") 17 | public String hello() { 18 | return "hello"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dynamic-schedule/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/dynamic-schedule/src/main/resources/application.properties -------------------------------------------------------------------------------- /dynamic-schedule/src/test/java/com/wuwii/DynamicScheduleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class DynamicScheduleApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /fork-join/README.md: -------------------------------------------------------------------------------- 1 | 学习 java 中 fork join 框架 -------------------------------------------------------------------------------- /fork-join/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.wuwii 8 | fork-join 9 | 1.0-SNAPSHOT 10 | 11 | 12 | -------------------------------------------------------------------------------- /fork-join/src/main/java/PrintTask.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.ForkJoinPool; 2 | import java.util.concurrent.RecursiveAction; 3 | 4 | /** 5 | * @author Zhang Kai 6 | * @version 1.0 7 | * @since
2018/3/20 18:38
8 | */ 9 | // 没有返回值的 fork / join 任务框架 10 | public class PrintTask extends RecursiveAction { 11 | private static final int THRESHOLD = 5; 12 | private int start; 13 | private int end; 14 | 15 | PrintTask(int start, int end) { 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public static void main(String[] args) { 21 | PrintTask task = new PrintTask(0, 25); 22 | // 分配四个线程给它 23 | ForkJoinPool pool = new ForkJoinPool(4); 24 | pool.execute(task); 25 | pool.shutdown(); 26 | } 27 | 28 | @Override 29 | protected void compute() { 30 | if (THRESHOLD >= (end - start)) { 31 | // 满足小任务条件,分配打印任务 32 | for (int i = start; i < end; i++) { 33 | System.out.println(Thread.currentThread().getName() + ": " + i); 34 | } 35 | } else { 36 | // 任务还能继续拆分 37 | int division = (start + end) >> 1; 38 | PrintTask task1 = new PrintTask(start, division); 39 | PrintTask task2 = new PrintTask(division, end); 40 | invokeAll(task1, task2); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /fork-join/src/main/java/SumTask.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.ForkJoinPool; 2 | import java.util.concurrent.RecursiveTask; 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * @author Zhang Kai 7 | * @version 1.0 8 | * @since
2018/3/21 8:49
9 | */ 10 | // 有返回值的 fork / join 任务框架 RecursiveTask 11 | public class SumTask extends RecursiveTask { 12 | private static final int THRESHOLD = 50; 13 | private int start; 14 | private int end; 15 | 16 | public SumTask(int start, int end) { 17 | this.start = start; 18 | this.end = end; 19 | } 20 | 21 | public static void main(String[] args) throws InterruptedException { 22 | final int works = 200; 23 | SumTask task = new SumTask(0, works); 24 | ForkJoinPool forkJoinPool = new ForkJoinPool(4); 25 | long beginTime = System.currentTimeMillis(); 26 | int result = forkJoinPool.invoke(task); 27 | long consumeTime = System.currentTimeMillis() - beginTime; 28 | System.out.println("Fork Join calculated the result is " + result + ",consume " + consumeTime + "ms"); 29 | forkJoinPool.shutdown(); 30 | 31 | result = 0; 32 | beginTime = System.currentTimeMillis(); 33 | for (int i = 0; i < works; i++) { 34 | TimeUnit.SECONDS.sleep(1); 35 | result += i; 36 | } 37 | consumeTime = System.currentTimeMillis() - beginTime; 38 | System.out.println("The correct result is " + result + ",consume " + consumeTime + "ms"); 39 | } 40 | 41 | @Override 42 | protected Integer compute() { 43 | int sum = 0; 44 | if (THRESHOLD >= (end - start)) { 45 | for (int i = start; i < end; i++) { 46 | try { 47 | TimeUnit.SECONDS.sleep(1); 48 | } catch (InterruptedException e) { 49 | e.printStackTrace(); 50 | } 51 | sum += i; 52 | } 53 | System.out.println(Thread.currentThread().getName() + " result is :" + sum); 54 | return sum; 55 | } else { 56 | int division = (start + end) >> 1; 57 | SumTask task1 = new SumTask(start, division); 58 | SumTask task2 = new SumTask(division, end); 59 | invokeAll(task1, task2); 60 | int result1 = task1.join(); 61 | int result2 = task2.join(); 62 | return result1 + result2; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /html5-butterflies/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /.idea/ 3 | -------------------------------------------------------------------------------- /html5-butterflies/README.md: -------------------------------------------------------------------------------- 1 | 这里只是修改的 DEMO 版,修改完的版本已经在 Github 的 home-page 仓库中。 2 | 3 | 这里的代码只是练习使用。 -------------------------------------------------------------------------------- /html5-butterflies/config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | 3 | # Set this to the root of your project when deployed: 4 | http_path = "/" 5 | css_dir = "css" 6 | sass_dir = "scss" 7 | images_dir = "images" 8 | javascripts_dir = "js" 9 | fonts_dir = "fonts" 10 | 11 | output_style = :expanded 12 | 13 | # To enable relative paths to assets via compass helper functions. Uncomment: 14 | # relative_assets = true 15 | 16 | # To disable debugging comments that display the original location of your selectors. Uncomment: 17 | # line_comments = false 18 | color_output = false 19 | 20 | 21 | # If you prefer the indented syntax, you might want to regenerate this 22 | # project again passing --syntax sass, or you can uncomment this: 23 | # preferred_syntax = :sass 24 | # and then run: 25 | # sass-convert -R --from scss --to sass css scss && rm -rf sass && mv scss sass 26 | -------------------------------------------------------------------------------- /html5-butterflies/css/clouds_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/html5-butterflies/css/clouds_back.jpg -------------------------------------------------------------------------------- /html5-butterflies/css/clouds_front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/html5-butterflies/css/clouds_front.jpg -------------------------------------------------------------------------------- /html5-butterflies/css/clouds_left.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/html5-butterflies/css/clouds_left.jpg -------------------------------------------------------------------------------- /html5-butterflies/css/clouds_right.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/html5-butterflies/css/clouds_right.jpg -------------------------------------------------------------------------------- /html5-butterflies/css/clouds_top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/html5-butterflies/css/clouds_top.jpg -------------------------------------------------------------------------------- /html5-butterflies/css/hazy_lake_top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/html5-butterflies/css/hazy_lake_top.jpg -------------------------------------------------------------------------------- /html5-butterflies/css/reset.css: -------------------------------------------------------------------------------- 1 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0} 2 | -------------------------------------------------------------------------------- /interview-code/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | learning-code 7 | com.wuwii 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | interview-code 13 | 14 | 15 | 16 | junit 17 | junit 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /interview-code/src/main/java/com/wuwii/cas/CasDemo.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.cas; 2 | 3 | /** 4 | * Created by KronChan on 2018/5/15 16:58. 5 | */ 6 | public class CasDemo { 7 | public static void main(String[] args) { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /interview-code/src/main/java/com/wuwii/cas/TwinsLock.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.cas; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.concurrent.locks.AbstractQueuedSynchronizer; 5 | import java.util.concurrent.locks.Condition; 6 | import java.util.concurrent.locks.Lock; 7 | 8 | /** 9 | * Created by KronChan on 2018/5/17 16:40. 10 | */ 11 | public class TwinsLock implements Lock { 12 | /** 13 | * 自定义的同步器,能够有两个线程同时获取资源 14 | */ 15 | private final Sync sync = new Sync(2); 16 | 17 | private static final class Sync extends AbstractQueuedSynchronizer { 18 | Sync(int count) { 19 | if (count <= 0) { 20 | throw new IllegalArgumentException("count must large than zero."); 21 | } 22 | setState(count); 23 | } 24 | 25 | @Override 26 | public int tryAcquireShared(int reduceCount) { 27 | for (; ; ) { 28 | int current = getState(); 29 | int newCount = current - reduceCount; 30 | if (newCount < 0 || compareAndSetState(current, newCount)) { 31 | return newCount; 32 | } 33 | } 34 | } 35 | 36 | @Override 37 | public boolean tryReleaseShared(int returnCount) { 38 | for (; ; ) { 39 | int current = getState(); 40 | int newCount = current + returnCount; 41 | if (compareAndSetState(current, newCount)) { 42 | return true; 43 | } 44 | } 45 | } 46 | 47 | Condition newCondtion() { 48 | return new ConditionObject(); 49 | } 50 | } 51 | 52 | @Override 53 | public void lock() { 54 | sync.acquireShared(1); 55 | } 56 | 57 | @Override 58 | public void lockInterruptibly() throws InterruptedException { 59 | sync.acquireSharedInterruptibly(1); 60 | } 61 | 62 | @Override 63 | public boolean tryLock() { 64 | return sync.tryAcquireShared(1) >= 0; 65 | } 66 | 67 | @Override 68 | public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { 69 | return sync.tryAcquireSharedNanos(1, unit.toNanos(time)); 70 | } 71 | 72 | @Override 73 | public void unlock() { 74 | sync.releaseShared(1); 75 | } 76 | 77 | @Override 78 | public Condition newCondition() { 79 | return sync.newCondtion(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /interview-code/src/main/java/com/wuwii/cyclicbarrier/CyclicBarrierDemo.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.cyclicbarrier; 2 | 3 | import java.util.concurrent.*; 4 | import java.util.stream.Stream; 5 | 6 | /** 7 | * 实现让一组线程等待至某个状态之后,再全部一起同时执行下面的, 8 | * 9 | * 10 | * Created by KronChan on 2018/5/14 17:35. 11 | */ 12 | public class CyclicBarrierDemo { 13 | public static void main(String[] args) { 14 | String[] drivers = {"C", "D", "E", "F"}; 15 | int length = drivers.length; 16 | ExecutorService pool = Executors.newFixedThreadPool(length); 17 | // 如果线程都到达barrier状态后,会从四个线程中选择一个线程去执行Runnable。 18 | CyclicBarrier cyclicBarrier = new CyclicBarrier(length, () -> { 19 | System.out.printf("%s 线程告诉你,统计完毕,待继续执行%n", Thread.currentThread().getName()); 20 | }); 21 | Stream.of(drivers).forEach((d) -> { 22 | pool.execute(new StatisticsDemo(d, cyclicBarrier)); 23 | }); 24 | pool.shutdown(); 25 | } 26 | 27 | static class StatisticsDemo implements Runnable { 28 | 29 | private String driveName; 30 | 31 | private CyclicBarrier cyclicBarrier; 32 | 33 | public StatisticsDemo(String driveName, CyclicBarrier cyclicBarrier) { 34 | this.driveName = driveName; 35 | this.cyclicBarrier = cyclicBarrier; 36 | } 37 | 38 | @Override 39 | public void run() { 40 | try { 41 | TimeUnit.SECONDS.sleep((int) (Math.random() * 10)); 42 | System.out.printf("%s 线程统计 %s 盘大小%n", Thread.currentThread().getName(), driveName); 43 | cyclicBarrier.await(); 44 | } catch (InterruptedException | BrokenBarrierException e) { 45 | e.printStackTrace(); 46 | } 47 | System.out.printf("%s 准备退出%n", driveName); 48 | } 49 | } 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /interview-code/src/main/java/com/wuwii/semaphore/SemaphoreDemo.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.semaphore; 2 | 3 | import java.util.concurrent.Semaphore; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * Created by KronChan on 2018/5/14 19:15. 8 | */ 9 | public class SemaphoreDemo { 10 | public static void main(String[] args) { 11 | int num = 10; 12 | Semaphore machines = new Semaphore(5); 13 | for (int i = 0; i < num; i++) { 14 | new Thread(new Worker(i, machines)).start(); 15 | } 16 | } 17 | 18 | static class Worker extends Thread { 19 | private Semaphore machines; 20 | 21 | private int worker; 22 | 23 | Worker(int worker, Semaphore semaphore) { 24 | this.worker = worker; 25 | this.machines = semaphore; 26 | } 27 | @Override 28 | public void run() { 29 | try { 30 | machines.acquire(); 31 | System.out.printf("工人 %d 开始使用机器工作了 %n", worker); 32 | TimeUnit.SECONDS.sleep((int) (Math.random() * 10)); 33 | System.out.printf("工人 %d 干完活了,让出机器了%n", worker); 34 | machines.release(); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /interview-code/src/test/java/com/wuwii/cas/MutexTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.cas; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * Created by KronChan on 2018/5/17 17:14. 9 | */ 10 | public class MutexTest { 11 | @Test 12 | public void test() throws InterruptedException { 13 | Mutex mutex = new Mutex(); 14 | for (int i = 0; i < 5; i++) { 15 | final int j = i; 16 | new Thread(() -> { 17 | try { 18 | mutex.lock(); 19 | TimeUnit.SECONDS.sleep(1); 20 | System.out.println(j); 21 | } catch (InterruptedException e) { 22 | e.printStackTrace(); 23 | } finally { 24 | mutex.unlock(); 25 | } 26 | }).start(); 27 | 28 | TimeUnit.SECONDS.sleep(1); 29 | System.out.println("------------"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /interview-code/src/test/java/com/wuwii/cas/TwinsLockTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.cas; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.concurrent.locks.Lock; 7 | 8 | /** 9 | 10 | */ 11 | public class TwinsLockTest { 12 | @Test 13 | public void test1() throws InterruptedException { 14 | final Lock lock = new TwinsLock(); 15 | 16 | class Worker extends Thread { 17 | @Override 18 | public void run() { 19 | try { 20 | lock.lock(); 21 | TimeUnit.SECONDS.sleep(1); 22 | System.out.println(Thread.currentThread().getName()); 23 | TimeUnit.SECONDS.sleep(1); 24 | } catch (InterruptedException e) { 25 | e.printStackTrace(); 26 | } finally { 27 | lock.unlock(); 28 | } 29 | } 30 | } 31 | 32 | for (int i = 0; i < 10; i++) { 33 | new Worker().start(); 34 | } 35 | 36 | for (int i = 0; i < 10; i++) { 37 | TimeUnit.SECONDS.sleep(1); 38 | System.out.println(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /java8-function-demo/README.md: -------------------------------------------------------------------------------- 1 | JDK 1.8 API包含了很多内建的函数式接口,在老Java中常用到的比如Comparator或者Runnable接口,这些接口都增加了@FunctionalInterface注解以便能用在lambda上。 2 | Java 8 API同样还提供了很多全新的函数式接口来让工作更加方便, -------------------------------------------------------------------------------- /java8-function-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.wuwii 8 | java8-function-demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | -------------------------------------------------------------------------------- /jdbc-muti-datasource/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ 25 | /.mvn/ 26 | -------------------------------------------------------------------------------- /jdbc-muti-datasource/src/main/java/com/wuwii/JdbcMutiDatasourceApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JdbcMutiDatasourceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JdbcMutiDatasourceApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /jdbc-muti-datasource/src/main/java/com/wuwii/config/DataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config; 2 | 3 | import org.springframework.beans.factory.annotation.Qualifier; 4 | import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.Primary; 9 | import org.springframework.jdbc.core.JdbcTemplate; 10 | 11 | import javax.sql.DataSource; 12 | 13 | /** 14 | * JDBC 多数据源配置 15 | * 16 | * @author Zhang Kai 17 | * @version 1.0 18 | * @since
2018/3/14 18:16
19 | */ 20 | @Configuration 21 | public class DataSourceConfig { 22 | 23 | /** 24 | * 注册 data source 25 | * 26 | * @return 27 | */ 28 | @ConfigurationProperties(prefix = "spring.datasource") 29 | @Bean("firstDataSource") 30 | @Primary // 有相同实例优先选择 31 | public DataSource firstDataSource() { 32 | return DataSourceBuilder.create().build(); 33 | } 34 | 35 | @ConfigurationProperties(prefix = "spring.second-datasource") 36 | @Bean("secondDataSource") 37 | public DataSource secondDataSource() { 38 | return DataSourceBuilder.create().build(); 39 | } 40 | 41 | @Bean("firstJdbcTemplate") 42 | @Primary 43 | public JdbcTemplate firstJdbcTemplate(DataSource dataSource) { 44 | return new JdbcTemplate(dataSource); 45 | } 46 | 47 | @Bean("secondJdbcTemplate") 48 | public JdbcTemplate secondJdbcTemplate(@Qualifier("secondDataSource") DataSource dataSource) { 49 | return new JdbcTemplate(dataSource); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /jdbc-muti-datasource/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8022 3 | spring: 4 | datasource: 5 | url: jdbc:mysql://localhost:3306/learn?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 6 | username: root 7 | password: 123456 8 | driver-class-name: com.mysql.jdbc.Driver 9 | 10 | second-datasource: 11 | url: jdbc:mysql://localhost:3306/learn1?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 12 | username: root 13 | password: 123456 14 | driver-class-name: com.mysql.jdbc.Driver 15 | -------------------------------------------------------------------------------- /jdbc-muti-datasource/src/test/java/com/wuwii/JdbcMutiDatasourceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JdbcMutiDatasourceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /jdbc-muti-datasource/src/test/java/com/wuwii/TestJDBC.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.hamcrest.Matchers; 4 | import org.junit.Assert; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.annotation.Qualifier; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.jdbc.core.JdbcTemplate; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | 14 | /** 15 | * @author Zhang Kai 16 | * @version 1.0 17 | * @since
2018/3/14 18:29
18 | */ 19 | @SpringBootTest 20 | @RunWith(SpringRunner.class) 21 | public class TestJDBC { 22 | @Autowired 23 | private JdbcTemplate jdbcTemplate; 24 | @Autowired 25 | @Qualifier("secondJdbcTemplate") 26 | private JdbcTemplate jdbcTemplate1; 27 | 28 | @Before 29 | public void before() { 30 | jdbcTemplate.update("DELETE FROM employee"); 31 | jdbcTemplate1.update("DELETE FROM employee"); 32 | } 33 | 34 | @Test 35 | public void testJDBC() { 36 | jdbcTemplate.update("insert into employee(id,name,age) VALUES (1, 'wuwii', 24)"); 37 | jdbcTemplate1.update("insert into employee(id,name,age) VALUES (1, 'kronchan', 23)"); 38 | Assert.assertThat("wuwii", Matchers.equalTo(jdbcTemplate.queryForObject("SELECT name FROM employee WHERE id=1", String.class))); 39 | Assert.assertThat("kronchan", Matchers.equalTo(jdbcTemplate1.queryForObject("SELECT name FROM employee WHERE id=1", String.class))); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jpa-criteria/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ 25 | /.mvn/ 26 | -------------------------------------------------------------------------------- /jpa-criteria/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/jpa-criteria/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /jpa-criteria/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 2 | -------------------------------------------------------------------------------- /jpa-criteria/README.md: -------------------------------------------------------------------------------- 1 | jpa Specification 复杂查询和 JPA criteria 查询 2 | 3 | 文章地址: 4 | http://blog.wuwii.com/jpa-%20specification.html -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/JpaCriteriaApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JpaCriteriaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JpaCriteriaApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/controller/EmployeeController.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.controller; 2 | 3 | import com.wuwii.form.EmployeeResult; 4 | import com.wuwii.service.EmployeeService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Created by KronChan on 2018/4/25 15:43. 16 | */ 17 | @RestController 18 | @RequestMapping(value = "/emp", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 19 | public class EmployeeController { 20 | private final EmployeeService employeeService; 21 | 22 | @Autowired 23 | public EmployeeController(EmployeeService employeeService) { 24 | this.employeeService = employeeService; 25 | } 26 | 27 | @GetMapping 28 | public ResponseEntity> listAll() { 29 | return ResponseEntity.ok(employeeService.findEmployee()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/dao/EmployeeDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.Employee; 4 | import org.springframework.data.annotation.Id; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | import org.springframework.data.repository.PagingAndSortingRepository; 7 | import org.springframework.stereotype.Repository; 8 | 9 | /** 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since
2018/3/8 10:03
13 | */ 14 | @Repository 15 | public interface EmployeeDao extends JpaSpecificationExecutor, PagingAndSortingRepository { 16 | } 17 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/dao/JobDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.Employee; 4 | import com.wuwii.entity.Job; 5 | import org.springframework.data.annotation.Id; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | import org.springframework.data.repository.PagingAndSortingRepository; 8 | import org.springframework.stereotype.Repository; 9 | 10 | /** 11 | * @author Zhang Kai 12 | * @version 1.0 13 | * @since
2018/3/8 10:44
14 | */ 15 | @Repository 16 | public interface JobDao extends JpaSpecificationExecutor, PagingAndSortingRepository { 17 | } 18 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/entity/Employee.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Zhang Kai 10 | * @version 1.0 11 | * @since
2018/3/8 9:52
12 | */ 13 | @Entity 14 | @Data 15 | public class Employee implements Serializable { 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | private Long id; 19 | 20 | @OneToOne(cascade = CascadeType.ALL) 21 | // 拥有级联维护的一方,参考http://westerly-lzh.github.io/cn/2014/12/JPA-CascadeType-Explaining/ 22 | @JoinColumn(foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) 23 | private EmployeeDetail detail; 24 | 25 | @ManyToOne(fetch = FetchType.LAZY) // 默认 lazy ,通过懒加载,知道需要使用级联的数据,才去数据库查询这个数据,提高查询效率。 26 | // 设置外键的问题,参考http://mario1412.github.io/2016/06/27/JPA%E4%B8%AD%E5%B1%8F%E8%94%BD%E5%AE%9E%E4%BD%93%E9%97%B4%E5%A4%96%E9%94%AE/ 27 | @JoinColumn(name = "jobId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) 28 | private Job job; 29 | } 30 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/entity/EmployeeDetail.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import java.io.Serializable; 10 | 11 | /** 12 | * @author Zhang Kai 13 | * @version 1.0 14 | * @since
2018/3/8 10:00
15 | */ 16 | @Entity 17 | @Data 18 | public class EmployeeDetail implements Serializable { 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private Long id; 22 | 23 | private String name; 24 | 25 | private String phone; 26 | 27 | private Integer age; 28 | } 29 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/entity/EmployeeDetail_.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import javax.persistence.metamodel.SingularAttribute; 4 | import javax.persistence.metamodel.StaticMetamodel; 5 | 6 | /** 7 | * @author Zhang Kai 8 | * @version 1.0 9 | * @since
2018/3/8 10:18
10 | */ 11 | @StaticMetamodel(EmployeeDetail.class) 12 | public class EmployeeDetail_ { 13 | public static volatile SingularAttribute id; 14 | public static volatile SingularAttribute name; 15 | public static volatile SingularAttribute phone; 16 | public static volatile SingularAttribute age; 17 | } 18 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/entity/Employee_.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import javax.persistence.metamodel.SingularAttribute; 4 | import javax.persistence.metamodel.StaticMetamodel; 5 | 6 | /** 7 | * 不知道什么原因 8 | * 这个持久性单元模型需要与实体类相同的包中,否则相关的值不会注入到 spring 容器中 9 | * 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since
2018/3/8 10:16
13 | */ 14 | @StaticMetamodel(Employee.class) 15 | public class Employee_ { 16 | public static volatile SingularAttribute id; 17 | public static volatile SingularAttribute detail; 18 | public static volatile SingularAttribute job; 19 | } 20 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/entity/Job.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | import java.util.Set; 8 | 9 | /** 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since
2018/3/8 9:54
13 | */ 14 | @Entity 15 | @Data 16 | public class Job implements Serializable { 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private Long id; 20 | 21 | private String name; 22 | 23 | @OneToMany(targetEntity = Employee.class, mappedBy = "job") // mappedBy 只有在双向关联的时候设置,表示关系维护的一端,否则会生成中间表A_B 24 | @org.hibernate.annotations.ForeignKey(name = "none") // 注意这里不能使用 @JoinColumn 不然会生成外键 25 | private Set employees; 26 | } 27 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/entity/Job_.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import javax.persistence.metamodel.SetAttribute; 4 | import javax.persistence.metamodel.SingularAttribute; 5 | import javax.persistence.metamodel.StaticMetamodel; 6 | 7 | /** 8 | * @author Zhang Kai 9 | * @version 1.0 10 | * @since
2018/3/8 10:21
11 | */ 12 | @StaticMetamodel(Job.class) 13 | public class Job_ { 14 | public static volatile SingularAttribute id; 15 | public static volatile SingularAttribute name; 16 | public static volatile SetAttribute employees; 17 | } 18 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/form/EmployeeResult.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.form; 2 | 3 | import com.wuwii.entity.Employee; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since
2018/3/8 19:24
13 | */ 14 | @EqualsAndHashCode(callSuper = true) 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class EmployeeResult extends Employee { 19 | private String name; 20 | private Integer age; 21 | } 22 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/form/EmployeeSearch.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.form; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @author Zhang Kai 8 | * @version 1.0 9 | * @since
2018/3/8 11:05
10 | */ 11 | @Getter 12 | @AllArgsConstructor 13 | public class EmployeeSearch { 14 | private Long employeeId; 15 | private String employeeName; 16 | private String jobName; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/service/EmployeeService.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import com.wuwii.entity.Employee; 4 | import com.wuwii.form.EmployeeResult; 5 | import com.wuwii.form.EmployeeSearch; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | import javax.persistence.Tuple; 10 | import java.util.List; 11 | 12 | /** 13 | * @author Zhang Kai 14 | * @version 1.0 15 | * @since
2018/3/8 10:04
16 | */ 17 | public interface EmployeeService { 18 | /** 19 | * 分页查询 20 | * 21 | * @param search 查询属性 22 | * @param pageable 分页和排序 23 | * @return 分页数据 24 | */ 25 | Page pageBySearch(EmployeeSearch search, Pageable pageable); 26 | 27 | void save(Employee em); 28 | 29 | /** 30 | * Search age gt or eq the parameter 31 | * 32 | * @param age 33 | * @return 34 | */ 35 | List listByAge(Integer age); 36 | 37 | /** 38 | * 参数化表达式 39 | * 40 | * @param age 41 | * @return 42 | */ 43 | List listByAge1(Integer age); 44 | 45 | /** 46 | * 分组统计重名数量 47 | * 48 | * @param name 49 | * @return 50 | */ 51 | List groupByName(String name); 52 | 53 | /** 54 | * 使用 构造函数 装载查询出来的数据 55 | * 56 | * @return 57 | */ 58 | List findEmployee(); 59 | } 60 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/service/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | /** 4 | * Created by KronChan on 2018/4/25 16:04. 5 | */ 6 | public interface HelloService { 7 | void say(); 8 | } 9 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/java/com/wuwii/service/impl/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service.impl; 2 | 3 | import com.wuwii.service.HelloService; 4 | 5 | /** 6 | * Created by KronChan on 2018/4/25 16:05. 7 | */ 8 | public class HelloServiceImpl implements HelloService { 9 | @Override 10 | public void say() { 11 | System.out.println("=====>>>> Hello."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/learn?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 4 | username: root 5 | password: 123456 6 | driver-class-name: com.mysql.jdbc.Driver 7 | jpa: 8 | show-sql: true 9 | database: mysql 10 | hibernate: 11 | # update 更新表结构 12 | # create 每次启动删除上次表,再创建表,会造成数据丢失 13 | # create-drop: 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 14 | # validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 15 | ddl-auto: update 16 | properties: 17 | hibernate: 18 | dialect: org.hibernate.dialect.MySQL57Dialect # 方言根据 数据库版本选择吧 19 | -------------------------------------------------------------------------------- /jpa-criteria/src/main/resources/learn.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : localhost mysql 5 | Source Server Version : 50717 6 | Source Host : localhost:3306 7 | Source Database : learn 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50717 11 | File Encoding : 65001 12 | 13 | Date: 2018-03-08 18:29:15 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for employee 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `employee`; 22 | CREATE TABLE `employee` ( 23 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 24 | `detail_id` bigint(20) DEFAULT NULL, 25 | `job_id` bigint(20) DEFAULT NULL, 26 | PRIMARY KEY (`id`) 27 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; 28 | 29 | -- ---------------------------- 30 | -- Records of employee 31 | -- ---------------------------- 32 | INSERT INTO `employee` VALUES ('1', '1', '1'); 33 | INSERT INTO `employee` VALUES ('2', '2', '1'); 34 | INSERT INTO `employee` VALUES ('3', '4', null); 35 | INSERT INTO `employee` VALUES ('4', '5', null); 36 | 37 | -- ---------------------------- 38 | -- Table structure for employee_detail 39 | -- ---------------------------- 40 | DROP TABLE IF EXISTS `employee_detail`; 41 | CREATE TABLE `employee_detail` ( 42 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 43 | `age` int(11) DEFAULT NULL, 44 | `name` varchar(255) DEFAULT NULL, 45 | `phone` varchar(255) DEFAULT NULL, 46 | PRIMARY KEY (`id`) 47 | ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; 48 | 49 | -- ---------------------------- 50 | -- Records of employee_detail 51 | -- ---------------------------- 52 | INSERT INTO `employee_detail` VALUES ('1', '24', 'kronchan', '18772383543'); 53 | INSERT INTO `employee_detail` VALUES ('2', '23', 'tom', '123456'); 54 | INSERT INTO `employee_detail` VALUES ('4', '22', 'jams', '42345'); 55 | INSERT INTO `employee_detail` VALUES ('5', '22', 'jams', '42345'); 56 | 57 | -- ---------------------------- 58 | -- Table structure for job 59 | -- ---------------------------- 60 | DROP TABLE IF EXISTS `job`; 61 | CREATE TABLE `job` ( 62 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 63 | `name` varchar(255) DEFAULT NULL, 64 | PRIMARY KEY (`id`) 65 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 66 | 67 | -- ---------------------------- 68 | -- Records of job 69 | -- ---------------------------- 70 | INSERT INTO `job` VALUES ('1', '程序猿'); 71 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/JpaCriteriaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JpaCriteriaApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/controller/EmployeeController1Test.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.controller; 2 | 3 | import com.wuwii.form.EmployeeResult; 4 | import org.hamcrest.Matchers; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.boot.test.web.client.TestRestTemplate; 11 | import org.springframework.core.ParameterizedTypeReference; 12 | import org.springframework.http.HttpMethod; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * http://fanlychie.github.io/post/spring-boot-testing.html 20 | * Created by KronChan on 2018/4/25 19:02. 21 | */ 22 | @RunWith(SpringRunner.class) 23 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 24 | public class EmployeeController1Test { 25 | @Autowired 26 | private TestRestTemplate restTemplate; 27 | 28 | @Test 29 | public void listAll() { 30 | // 由于我返回的是 List 类型的,一直想不到办法解决,网上给出了解决办法,使用 exchange 函数代替 31 | //public ResponseEntity exchange(String url, HttpMethod method, 32 | // HttpEntity requestEntity, ParameterizedTypeReference responseType, 33 | // Object... urlVariables) throws RestClientException { 34 | ParameterizedTypeReference> type = new ParameterizedTypeReference>() {}; 35 | ResponseEntity> result = restTemplate.exchange("/emp", HttpMethod.GET, null, type); 36 | Assert.assertThat(result.getBody().get(0).getName(), Matchers.notNullValue()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/controller/EmployeeController2Test.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.controller; 2 | 3 | import com.wuwii.service.EmployeeService; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mockito; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 9 | import org.springframework.boot.test.mock.mockito.MockBean; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | import org.springframework.test.web.servlet.MockMvc; 12 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 13 | 14 | import java.util.ArrayList; 15 | 16 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 17 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 18 | 19 | /** 20 | * @author KronChan 21 | * @version 1.0 22 | * @since
2018/4/26 22:51
23 | */ 24 | @RunWith(SpringRunner.class) 25 | @WebMvcTest(EmployeeController.class) 26 | public class EmployeeController2Test { 27 | @Autowired 28 | private MockMvc mvc; 29 | 30 | @MockBean 31 | private EmployeeService employeeService; 32 | 33 | public void setUp() { 34 | // 设置返回的 body 是空的 35 | Mockito.when(employeeService.findEmployee()).thenReturn(new ArrayList<>()); 36 | } 37 | 38 | @Test 39 | public void listAll() throws Exception { 40 | mvc.perform(MockMvcRequestBuilders.get("/emp")) 41 | .andExpect(status().isOk()) // 期待返回状态吗码200 42 | // JsonPath expression https://github.com/jayway/JsonPath 43 | //.andExpect(jsonPath("$[1].name").exists()) // 这里是期待返回值是数组,并且第二个值的 name 存在,所以这里测试是失败的 44 | .andDo(print()); // 打印返回的 http response 信息 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/controller/EmployeeControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.controller; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | import org.springframework.test.web.servlet.MockMvc; 11 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 12 | import org.springframework.web.context.WebApplicationContext; 13 | 14 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 15 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 16 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 17 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 18 | 19 | /** 20 | * Created by KronChan on 2018/4/25 15:56. 21 | */ 22 | @RunWith(SpringRunner.class) 23 | @SpringBootTest 24 | public class EmployeeControllerTest { 25 | /** 26 | * Interface to provide configuration for a web application. 27 | */ 28 | @Autowired 29 | private WebApplicationContext ctx; 30 | 31 | private MockMvc mockMvc; 32 | 33 | /** 34 | * 初始化 MVC 的环境 35 | */ 36 | @Before 37 | public void before() { 38 | mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build(); 39 | } 40 | 41 | @Test 42 | public void listAll() throws Exception { 43 | mockMvc 44 | .perform(get("/emp") // 测试的相对地址 45 | .accept(MediaType.APPLICATION_JSON_UTF8) // accept response content type 46 | ) 47 | .andExpect(status().isOk()) // 期待返回状态吗码200 48 | // JsonPath expression https://github.com/jayway/JsonPath 49 | .andExpect(jsonPath("$[1].name").exists()) // 这里是期待返回值是数组,并且第二个值的 name 存在 50 | .andDo(print()); // 打印返回的 http response 信息 51 | } 52 | } -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/dao/EmployeeDaoTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.Employee; 4 | import com.wuwii.entity.EmployeeDetail; 5 | import org.hamcrest.Matchers; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; 10 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import static org.junit.Assert.assertThat; 15 | 16 | /** 17 | * Spring Data JPA 测试 18 | * Created by KronChan on 2018/4/26 8:30. 19 | */ 20 | @RunWith(SpringRunner.class) 21 | @DataJpaTest 22 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 23 | public class EmployeeDaoTest { 24 | 25 | @Autowired 26 | private EmployeeDao employeeDao; 27 | 28 | @Test 29 | @Transactional 30 | public void testSave() { 31 | Employee employee = new Employee(); 32 | EmployeeDetail detail = new EmployeeDetail(); 33 | detail.setName("kronchan"); 34 | detail.setAge(24); 35 | employee.setDetail(detail); 36 | assertThat(detail.getName(), Matchers.is(employeeDao.save(employee).getDetail().getName())); 37 | ; 38 | } 39 | } -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/paramter/ParameterTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.paramter; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.Parameterized; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import static org.hamcrest.Matchers.is; 11 | import static org.junit.Assert.assertThat; 12 | 13 | /** 14 | * Created by KronChan on 2018/4/25 17:18. 15 | */ 16 | //1.更改默认的测试运行器为RunWith(Parameterized.class) 17 | @RunWith(Parameterized.class) 18 | public class ParameterTest { 19 | // 2.声明变量存放预期值和测试数据 20 | private String firstName; 21 | private String lastName; 22 | 23 | //3.声明一个返回值 为Collection的公共静态方法,并使用@Parameters进行修饰 24 | @Parameterized.Parameters // 25 | public static List param() { 26 | // 这里我给出两个测试用例 27 | return Arrays.asList(new Object[][]{{"Mike", "Black"}, {"Cilcln", "Smith"}}); 28 | } 29 | 30 | //4.为测试类声明一个带有参数的公共构造函数,并在其中为之声明变量赋值 31 | public ParameterTest(String firstName, String lastName) { 32 | this.firstName = firstName; 33 | this.lastName = lastName; 34 | } 35 | 36 | // 5. 进行测试,发现它会将所有的测试用例测试一遍 37 | @Test 38 | public void test() { 39 | String name = firstName + " " + lastName; 40 | assertThat(name, is("Mike Black")); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/service/impl/HelloServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service.impl; 2 | 3 | import com.wuwii.service.HelloService; 4 | import org.junit.*; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * Created by KronChan on 2018/4/25 16:13. 10 | */ 11 | public class HelloServiceImplTest { 12 | 13 | @Before 14 | public void before() throws Exception { 15 | System.out.println("before"); 16 | } 17 | 18 | @After 19 | public void after() throws Exception { 20 | System.out.println("after"); 21 | } 22 | 23 | @BeforeClass 24 | public static void beforeClass() { 25 | System.out.println("Before Class"); 26 | } 27 | 28 | @AfterClass 29 | public static void afterClass() { 30 | System.out.println("After Class"); 31 | } 32 | 33 | @Test 34 | public void say() { 35 | HelloService helloService = new HelloServiceImpl(); 36 | helloService.say(); 37 | } 38 | 39 | @Test(timeout = 1000) 40 | public void testTimeout() throws InterruptedException { 41 | TimeUnit.SECONDS.sleep(2); 42 | System.out.println("Complete"); 43 | } 44 | 45 | @Test(expected = NullPointerException.class) 46 | public void testNullException() { 47 | throw new NullPointerException(); 48 | } 49 | 50 | @Test 51 | @Ignore 52 | public void testIgnore() { 53 | System.out.println("Ignore ?"); 54 | throw new NullPointerException(); 55 | } 56 | } -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/suit/SuitTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.suit; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Suite; 5 | 6 | /** 7 | * Created by KronChan on 2018/4/25 17:51. 8 | */ 9 | @RunWith(Suite.class) // 1. 更改测试运行方式为 Suite 10 | // 2. 将测试类传入进来 11 | @Suite.SuiteClasses({TaskOneTest.class, TaskTwoTest.class, TaskThreeTest.class}) 12 | public class SuitTest { 13 | /** 14 | * 测试套件的入口类只是组织测试类一起进行测试,无任何测试方法, 15 | */ 16 | } 17 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/suit/TaskOneTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.suit; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by KronChan on 2018/4/25 17:48. 7 | */ 8 | public class TaskOneTest { 9 | @Test 10 | public void test() { 11 | System.out.println("Task one do."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/suit/TaskThreeTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.suit; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by KronChan on 2018/4/25 17:50. 7 | */ 8 | public class TaskThreeTest { 9 | @Test 10 | public void test() { 11 | System.out.println("Task Three."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jpa-criteria/src/test/java/com/wuwii/suit/TaskTwoTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.suit; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by KronChan on 2018/4/25 17:49. 7 | */ 8 | public class TaskTwoTest { 9 | @Test 10 | public void test() { 11 | System.out.println("Task two do."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jpa-muti-datasource/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ 25 | /.mvn/ 26 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/main/java/com/wuwii/JpaMutiDatasourceApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JpaMutiDatasourceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JpaMutiDatasourceApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/main/java/com/wuwii/module/system/EmployeeDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.module.system; 2 | 3 | import com.wuwii.module.system.entity.Employee; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @author Zhang Kai 9 | * @version 1.0 10 | * @since
2018/3/15 8:48
11 | */ 12 | @Repository 13 | public interface EmployeeDao extends JpaRepository { 14 | } 15 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/main/java/com/wuwii/module/system/dao/EmployeeDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.module.system.dao; 2 | 3 | import com.wuwii.module.system.entity.Employee; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @author Zhang Kai 9 | * @version 1.0 10 | * @since
2018/3/15 8:48
11 | */ 12 | @Repository 13 | public interface EmployeeDao extends JpaRepository { 14 | } 15 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/main/java/com/wuwii/module/system/entity/Employee.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.module.system.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.Entity; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.GenerationType; 10 | import javax.persistence.Id; 11 | import java.io.Serializable; 12 | 13 | /** 14 | * @author KronChan 15 | * @version 1.0 16 | * @since
2018/3/14 23:18
17 | */ 18 | @Entity 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | public class Employee implements Serializable { 23 | @Id 24 | @GeneratedValue(strategy = GenerationType.IDENTITY) 25 | private Long id; 26 | private String name; 27 | private int age; 28 | } 29 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/main/java/com/wuwii/module/user/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.module.user.dao; 2 | 3 | import com.wuwii.module.user.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @author Zhang Kai 9 | * @version 1.0 10 | * @since
2018/3/15 8:49
11 | */ 12 | @Repository 13 | public interface UserDao extends JpaRepository { 14 | } 15 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/main/java/com/wuwii/module/user/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.module.user.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.Entity; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.GenerationType; 10 | import javax.persistence.Id; 11 | import java.io.Serializable; 12 | 13 | /** 14 | * @author Zhang Kai 15 | * @version 1.0 16 | * @since
2018/3/15 8:22
17 | */ 18 | @Entity 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | public class User implements Serializable { 23 | @Id 24 | @GeneratedValue(strategy = GenerationType.IDENTITY) 25 | private Long id; 26 | private String name; 27 | private int age; 28 | } 29 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8022 3 | spring: 4 | datasource: 5 | url: jdbc:mysql://localhost:3306/learn?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 6 | username: root 7 | password: 123456 8 | driver-class-name: com.mysql.jdbc.Driver 9 | 10 | second-datasource: 11 | url: jdbc:mysql://localhost:3306/learn1?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 12 | username: root 13 | password: 123456 14 | driver-class-name: com.mysql.jdbc.Driver 15 | 16 | jpa: 17 | show-sql: true 18 | database: mysql 19 | hibernate: 20 | # update 更新表结构 21 | # create 每次启动删除上次表,再创建表,会造成数据丢失 22 | # create-drop: 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 23 | # validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 24 | ddl-auto: update 25 | properties: 26 | hibernate: 27 | dialect: org.hibernate.dialect.MySQLDialect -------------------------------------------------------------------------------- /jpa-muti-datasource/src/test/java/com/wuwii/JpaMutiDatasourceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JpaMutiDatasourceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /jpa-muti-datasource/src/test/java/com/wuwii/TestDemo.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import com.wuwii.module.system.dao.EmployeeDao; 4 | import com.wuwii.module.system.entity.Employee; 5 | import com.wuwii.module.user.dao.UserDao; 6 | import com.wuwii.module.user.entity.User; 7 | import org.hamcrest.Matchers; 8 | import org.junit.Assert; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.data.domain.Example; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | 17 | /** 18 | * @author Zhang Kai 19 | * @version 1.0 20 | * @since
2018/3/15 8:50
21 | */ 22 | @SpringBootTest 23 | @RunWith(SpringRunner.class) 24 | public class TestDemo { 25 | @Autowired 26 | private EmployeeDao employeeDao; 27 | @Autowired 28 | private UserDao userDao; 29 | 30 | @Before 31 | public void before() { 32 | employeeDao.deleteAll(); 33 | userDao.deleteAll(); 34 | } 35 | 36 | @Test 37 | public void test() { 38 | Employee employee = new Employee(null, "wuwii", 24); 39 | employeeDao.save(employee); 40 | User user = new User(null, "KronChan", 23); 41 | userDao.save(user); 42 | Assert.assertThat(employee, Matchers.equalTo(employeeDao.findOne(Example.of(employee)))); 43 | Assert.assertThat(user, Matchers.equalTo(userDao.findOne(Example.of(user)))); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /learn-hystrix/README.md: -------------------------------------------------------------------------------- 1 | 学习使用Hystrix,以及它的实现机制。 2 | 3 | https://www.cnblogs.com/yepei/p/7169127.html 4 | 5 | https://www.jianshu.com/p/b9af028efebb -------------------------------------------------------------------------------- /learn-hystrix/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.wuwii 8 | learn-hystrix 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | com.netflix.hystrix 15 | hystrix-core 16 | 1.5.12 17 | 18 | 19 | org.projectlombok 20 | lombok 21 | 1.16.20 22 | provided 23 | 24 | 25 | log4j 26 | log4j 27 | 1.2.17 28 | 29 | 30 | org.slf4j 31 | slf4j-log4j12 32 | 1.7.0 33 | 34 | 40 | 41 | -------------------------------------------------------------------------------- /learn-hystrix/src/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Set root logger level to DEBUG and its only appender to A1. 2 | log4j.rootLogger=DEBUG, A1 3 | 4 | # A1 is set to be a ConsoleAppender. 5 | log4j.appender.A1=org.apache.log4j.ConsoleAppender 6 | 7 | # A1 uses PatternLayout. 8 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n -------------------------------------------------------------------------------- /nio-netty/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | learning-code 7 | com.wuwii 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | nio-netty 13 | 14 | 15 | 16 | io.netty 17 | netty-all 18 | 5.0.0.Alpha2 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/chat/ChatClient.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.chat; 2 | 3 | import com.wuwii.netty.core.BaseClientTemplate; 4 | import io.netty.channel.Channel; 5 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 6 | import io.netty.handler.codec.Delimiters; 7 | import io.netty.handler.codec.string.StringDecoder; 8 | import io.netty.handler.codec.string.StringEncoder; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.io.InputStreamReader; 13 | 14 | /** 15 | * @author kai.zhang 16 | * @date 2019/12/10 19:35 17 | */ 18 | public class ChatClient extends BaseClientTemplate { 19 | public ChatClient(String host, int port) { 20 | super(host, port); 21 | } 22 | 23 | public static void main(String[] args) { 24 | new ChatClient("localhost", 8095).clientTask( 25 | // 处理沾包 26 | new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()), 27 | new StringDecoder(), 28 | new StringEncoder(), 29 | new ChatClientHandler() 30 | ); 31 | } 32 | 33 | @Override 34 | protected void op(Channel channel) { 35 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 36 | while (true) { 37 | try { 38 | channel.writeAndFlush(in.readLine() + "\r\n"); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/chat/ChatClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.chat; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * @author kai.zhang 8 | * @date 2019/12/10 19:35 9 | */ 10 | public class ChatClientHandler extends SimpleChannelInboundHandler { 11 | @Override 12 | protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { 13 | System.out.println(msg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/chat/ChatServer.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.chat; 2 | 3 | import com.wuwii.netty.core.BaseServerTemplate; 4 | import io.netty.channel.ChannelHandler; 5 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 6 | import io.netty.handler.codec.Delimiters; 7 | import io.netty.handler.codec.string.StringDecoder; 8 | import io.netty.handler.codec.string.StringEncoder; 9 | 10 | /** 11 | * @author kai.zhang 12 | * @date 2019/12/10 17:55 13 | */ 14 | public class ChatServer extends BaseServerTemplate { 15 | 16 | public ChatServer(int port) { 17 | super(port); 18 | } 19 | 20 | public static void main(String[] args) { 21 | new ChatServer(8095).serverTask( 22 | // 处理沾包 23 | new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()), 24 | new StringDecoder(), 25 | new StringEncoder(), 26 | new ChatServerHandler() 27 | ); 28 | 29 | } 30 | 31 | @Override 32 | protected ChannelHandler handler(ChannelHandler... channelHandlers) { 33 | return new ChatServerInitializer(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/chat/ChatServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.chat; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.channel.socket.SocketChannel; 7 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 8 | import io.netty.handler.codec.Delimiters; 9 | import io.netty.handler.codec.string.StringDecoder; 10 | import io.netty.handler.codec.string.StringEncoder; 11 | 12 | /** 13 | * @author kai.zhang 14 | * @date 2019/12/10 19:51 15 | */ 16 | @ChannelHandler.Sharable 17 | public class ChatServerInitializer extends ChannelInitializer { 18 | @Override 19 | protected void initChannel(SocketChannel ch) throws Exception { 20 | ChannelPipeline pipeline = ch.pipeline(); 21 | pipeline.addLast( // 处理沾包 22 | new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()), 23 | new StringDecoder(), 24 | new StringEncoder(), 25 | new ChatServerHandler()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/chat/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * netty 聊天室 3 | * 参考 https://waylau.com/netty-chat/ 4 | * 5 | * @author kai.zhang 6 | * @date 2019/12/10 17:46 7 | */ 8 | package com.wuwii.netty.chat; 9 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/core/BaseClientTemplate.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.core; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.channel.ChannelHandler; 7 | import io.netty.channel.ChannelInitializer; 8 | import io.netty.channel.ChannelOption; 9 | import io.netty.channel.EventLoopGroup; 10 | import io.netty.channel.nio.NioEventLoopGroup; 11 | import io.netty.channel.socket.SocketChannel; 12 | import io.netty.channel.socket.nio.NioSocketChannel; 13 | 14 | /** 15 | * @author kai.zhang 16 | * @date 2019/12/10 12:25 17 | */ 18 | public abstract class BaseClientTemplate { 19 | private final int port; 20 | 21 | private final String host; 22 | 23 | public BaseClientTemplate(String host, int port) { 24 | this.port = port; 25 | this.host = host; 26 | } 27 | 28 | public void clientTask(ChannelHandler... channelHandlers) { 29 | // 客户端的 workGroup 30 | EventLoopGroup workGroup = new NioEventLoopGroup(); 31 | try { 32 | // Bootstrap 是对非服务端使用 33 | Bootstrap bootstrap = new Bootstrap(); 34 | bootstrap.group(workGroup) 35 | // 客户端使用的 是 NioSocketChannel, 在客户端创建的时候使用 36 | .channel(NioSocketChannel.class) 37 | // 设置 channel 的属性 38 | .option(ChannelOption.SO_KEEPALIVE, true) 39 | // 设置 handler 40 | .handler(new ChannelInitializer() { 41 | @Override 42 | protected void initChannel(SocketChannel ch) throws Exception { 43 | ch.pipeline().addLast(channelHandlers); 44 | } 45 | }); 46 | // 启动客户端 47 | ChannelFuture future = bootstrap.connect(host, port).sync(); 48 | Channel channel = future.channel(); 49 | op(channel); 50 | // 关闭连接 51 | channel.closeFuture().sync(); 52 | } catch (InterruptedException e) { 53 | e.printStackTrace(); 54 | } finally { 55 | workGroup.shutdownGracefully(); 56 | } 57 | } 58 | 59 | protected void op(Channel channel) { 60 | // NOOP 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/discard/DisCardServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.discard; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * @author kai.zhang 9 | * @date 2019/11/29 20:39 10 | */ 11 | public class DisCardServerHandler extends SimpleChannelInboundHandler { 12 | @Override 13 | protected void messageReceived(ChannelHandlerContext channelHandlerContext, ByteBuf s) throws Exception { 14 | System.out.println(s.toString(io.netty.util.CharsetUtil.US_ASCII)); 15 | System.out.flush(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/discard/DiscardServer.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.discard; 2 | 3 | import com.wuwii.netty.core.BaseServerTemplate; 4 | 5 | /** 6 | * @author kai.zhang 7 | * @date 2019/11/29 21:30 8 | */ 9 | public class DiscardServer extends BaseServerTemplate { 10 | 11 | public DiscardServer(int port) { 12 | super(port); 13 | } 14 | 15 | public static void main(String[] args) { 16 | new DiscardServer(8099).serverTask(new DisCardServerHandler()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/discard/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 丢弃服务器 3 | * 4 | * @author kai.zhang 5 | * @date 2019/12/10 17:46 6 | */ 7 | package com.wuwii.netty.discard; 8 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/echo/EchoServer.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.echo; 2 | 3 | import com.wuwii.netty.core.BaseServerTemplate; 4 | 5 | /** 6 | * @author kai.zhang 7 | * @date 2019/12/9 20:40 8 | */ 9 | public class EchoServer extends BaseServerTemplate { 10 | 11 | public EchoServer(int port) { 12 | super(port); 13 | } 14 | 15 | public static void main(String[] args) { 16 | new EchoServer(8090).serverTask(new EchoServerHandler()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/echo/EchoServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.echo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * @author kai.zhang 9 | * @date 2019/12/9 20:41 10 | */ 11 | public class EchoServerHandler extends SimpleChannelInboundHandler { 12 | public EchoServerHandler() { 13 | // 设置不自动 release,因为 ctx.writeAndFlush(buff)会使此次ByteBuf回收也即将refCnt置为0 14 | super(false); 15 | } 16 | 17 | @Override 18 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 19 | cause.printStackTrace(); 20 | // 出现异常断开通信 21 | ctx.close(); 22 | } 23 | 24 | @Override 25 | protected void messageReceived(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { 26 | System.out.println(byteBuf.toString(io.netty.util.CharsetUtil.US_ASCII)); 27 | // 写入接收到的消息 28 | channelHandlerContext.writeAndFlush(byteBuf); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/echo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 打印输出服务器 3 | * 4 | * @author kai.zhang 5 | * @date 2019/12/10 17:46 6 | */ 7 | package com.wuwii.netty.echo; 8 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/PojoClient.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.pojo; 2 | 3 | import com.wuwii.netty.core.BaseClientTemplate; 4 | 5 | /** 6 | * @author kai.zhang 7 | * @date 2019/12/10 15:33 8 | */ 9 | public class PojoClient extends BaseClientTemplate { 10 | public PojoClient(String host, int port) { 11 | super(host, port); 12 | } 13 | 14 | public static void main(String[] args) { 15 | new PojoClient("localhost", 8094).clientTask(new TimeDecoder(), new PojoClientHandler()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/PojoClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.pojo; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * @author kai.zhang 8 | * @date 2019/12/10 15:32 9 | */ 10 | public class PojoClientHandler extends SimpleChannelInboundHandler { 11 | @Override 12 | protected void messageReceived(ChannelHandlerContext ctx, UnixTime msg) throws Exception { 13 | System.out.println(msg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/PojoServer.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.pojo; 2 | 3 | import com.wuwii.netty.core.BaseServerTemplate; 4 | 5 | /** 6 | * @author kai.zhang 7 | * @date 2019/12/10 15:33 8 | */ 9 | public class PojoServer extends BaseServerTemplate { 10 | public PojoServer(int port) { 11 | super(port); 12 | } 13 | 14 | public static void main(String[] args) { 15 | new PojoServer(8094).serverTask(new TimeEncoder(), new PojoServerHandler()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/PojoServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.pojo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | 9 | /** 10 | * @author kai.zhang 11 | * @date 2019/12/10 15:33 12 | */ 13 | public class PojoServerHandler extends SimpleChannelInboundHandler { 14 | @Override 15 | public void channelActive(ChannelHandlerContext ctx) { 16 | ChannelFuture f = ctx.writeAndFlush(new UnixTime()); 17 | f.addListener(ChannelFutureListener.CLOSE); 18 | } 19 | 20 | @Override 21 | protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/TimeDecoder.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.pojo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.ByteToMessageDecoder; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author kai.zhang 11 | * @date 2019/12/10 15:28 12 | */ 13 | public class TimeDecoder extends ByteToMessageDecoder { 14 | @Override 15 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 16 | // 接收 int 类型 4 字节整形 17 | if (in.readableBytes() < 4) { 18 | return; 19 | } 20 | out.add(new UnixTime(in.readUnsignedInt())); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/TimeEncoder.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.pojo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.MessageToByteEncoder; 6 | 7 | /** 8 | * @author kai.zhang 9 | * @date 2019/12/10 15:34 10 | */ 11 | public class TimeEncoder extends MessageToByteEncoder { 12 | @Override 13 | protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) throws Exception { 14 | out.writeInt((int) msg.getValue()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/UnixTime.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.pojo; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author kai.zhang 7 | * @date 2019/12/10 15:25 8 | */ 9 | public class UnixTime { 10 | private final long value; 11 | 12 | public UnixTime() { 13 | this(System.currentTimeMillis() / 1000L + 123456789); 14 | } 15 | 16 | public UnixTime(long value) { 17 | this.value = value; 18 | } 19 | 20 | public long getValue() { 21 | return value; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return new Date((value - 123456789) * 1000).toString(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/pojo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 使用 pojo 实体类代替 ByteBuf 3 | * 4 | * @author kai.zhang 5 | * @date 2019/12/10 17:47 6 | */ 7 | package com.wuwii.netty.pojo; 8 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/time/TimeClient.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.time; 2 | 3 | import com.wuwii.netty.core.BaseClientTemplate; 4 | 5 | /** 6 | * @author kai.zhang 7 | * @date 2019/12/9 20:51 8 | */ 9 | public class TimeClient extends BaseClientTemplate { 10 | 11 | 12 | public TimeClient(String host, int port) { 13 | super(host, port); 14 | } 15 | 16 | public static void main(String[] args) { 17 | new TimeClient("localhost", 8092).clientTask(new TimeClientHandler()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/time/TimeClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.time; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * @author kai.zhang 11 | * @date 2019/12/9 20:43 12 | */ 13 | public class TimeClientHandler extends SimpleChannelInboundHandler { 14 | @Override 15 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 16 | cause.printStackTrace(); 17 | ctx.close(); 18 | } 19 | 20 | @Override 21 | protected void messageReceived(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { 22 | long currentTimeMillis = (byteBuf.readUnsignedInt() - 123456789L) * 1000L; 23 | System.out.println(new Date(currentTimeMillis)); 24 | channelHandlerContext.close(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/time/TimeServer.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.time; 2 | 3 | import com.wuwii.netty.core.BaseServerTemplate; 4 | 5 | /** 6 | * @author kai.zhang 7 | * @date 2019/12/9 21:55 8 | */ 9 | public class TimeServer extends BaseServerTemplate { 10 | public TimeServer(int port) { 11 | super(port); 12 | } 13 | 14 | public static void main(String[] args) { 15 | new TimeServer(8092).serverTask(new TimeServerHandler()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/time/TimeServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.netty.time; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelHandler; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.SimpleChannelInboundHandler; 9 | 10 | /** 11 | * @author kai.zhang 12 | * @date 2019/12/9 21:55 13 | */ 14 | @ChannelHandler.Sharable 15 | public class TimeServerHandler extends SimpleChannelInboundHandler { 16 | @Override 17 | public void channelActive(final ChannelHandlerContext ctx) { 18 | //channelActive 在建立连接,准备通信的时候被调用 19 | // 构建一个 4 字节, 32 位整数的消息 20 | final ByteBuf time = ctx.alloc().buffer(4); 21 | time.writeInt((int) (System.currentTimeMillis() / 1000L + 123456789L)); 22 | // 因为 netty 里面所有的操作都是异步的,所有的操作不是立即执行的,这里返回一个 还没有发生 I/O 操作 23 | final ChannelFuture f = ctx.writeAndFlush(time); 24 | // 由于 Netty 里面所有逇操作都是异步的, 直接 close channel 会导致消息还没发送,就关闭连接了,我们需要一个监听者,在它写操作完成后,通知我们去关闭通信连接 25 | f.addListener(ChannelFutureListener.CLOSE); 26 | // 下面是自定义的监听器 27 | /*f.addListener((ChannelFutureListener) future -> { 28 | assert f == future; 29 | ctx.close(); 30 | });*/ 31 | } 32 | 33 | @Override 34 | protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/netty/time/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * netty 实现时间服务器 3 | * 4 | * @author kai.zhang 5 | * @date 2019/12/10 17:47 6 | */ 7 | package com.wuwii.netty.time; 8 | -------------------------------------------------------------------------------- /nio-netty/src/main/java/com/wuwii/nio1/Client.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.nio1; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.SocketChannel; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * @author KronChan 11 | * @date 2019-04-07 22:08 12 | */ 13 | public class Client { 14 | public static void main(String[] args) throws IOException, InterruptedException { 15 | for (int i = 0; i < 10; i++) { 16 | new Thread(new Runnable() { 17 | @Override 18 | public void run() { 19 | try { 20 | SocketChannel socket = SocketChannel.open(); 21 | socket.configureBlocking(false); 22 | socket.connect(new InetSocketAddress("127.0.0.1", 6789)); 23 | while (!socket.finishConnect()) { 24 | System.out.println("等待连接中," + System.currentTimeMillis()); 25 | } 26 | System.out.println("连接完成,等待写入" + System.currentTimeMillis()); 27 | TimeUnit.SECONDS.sleep(2); 28 | String msg = Thread.currentThread().getName(); 29 | ByteBuffer byteBuffer = ByteBuffer.allocate(msg.length()); 30 | byteBuffer.put(msg.getBytes()); 31 | byteBuffer.flip(); 32 | socket.write(byteBuffer); 33 | byteBuffer.clear(); 34 | socket.close(); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | }).start(); 40 | //TimeUnit.HOURS.sleep(1); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.wuwii 7 | learning-code 8 | pom 9 | 0.0.1-SNAPSHOT 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.0.1.RELEASE 14 | 15 | 16 | learning-code 17 | Demo project for Spring Boot 18 | 19 | 20 | 21 | vertx-jdbc-client 22 | io.vertx 23 | ${vertx.version} 24 | 25 | 26 | com.h2database 27 | h2 28 | ${h2.version} 29 | 30 | 31 | 32 | 33 | 34 | design-pattern 35 | fork-join 36 | java8-function-demo 37 | jdbc-muti-datasource 38 | jpa-criteria 39 | jpa-muti-datasource 40 | learn-hystrix 41 | sort-algorithm 42 | springboot-actuator 43 | springboot-docker 44 | springboot-querydsl 45 | springboot-redis-cache 46 | springboot-security 47 | template-design-spring 48 | spring-boot-test 49 | interview-code 50 | nio-netty 51 | algorithm 52 | vertx 53 | spring-event 54 | 55 | 56 | 57 | 3.5.3 58 | 1.4.199 59 | 60 | 61 | -------------------------------------------------------------------------------- /rocketmq-demo/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /rocketmq-demo/src/main/java/com/wuwii/MQConsumeMsgListenerProcessor.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; 4 | import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; 5 | import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; 6 | import org.apache.rocketmq.common.message.MessageExt; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.util.CollectionUtils; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Created by KronChan on 18/8/30 下午6:35. 16 | */ 17 | @Component 18 | public class MQConsumeMsgListenerProcessor implements MessageListenerConcurrently { 19 | private static final Logger logger = LoggerFactory.getLogger(MQConsumeMsgListenerProcessor.class); 20 | 21 | /** 22 | * 默认msgs里只有一条消息,可以通过设置consumeMessageBatchMaxSize参数来批量接收消息
23 | * 不要抛异常,如果没有return CONSUME_SUCCESS ,consumer会重新消费该消息,直到return CONSUME_SUCCESS 24 | */ 25 | @Override 26 | public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) { 27 | if (CollectionUtils.isEmpty(msgs)) { 28 | logger.info("接受到的消息为空,不处理,直接返回成功"); 29 | return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; 30 | } 31 | MessageExt messageExt = msgs.get(0); 32 | logger.info("接受到的消息为:" + messageExt.toString()); 33 | if (messageExt.getTopic().equals("你的Topic")) { 34 | if (messageExt.getTags().equals("你的Tag")) { 35 | //TODO 判断该消息是否重复消费(RocketMQ不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重) 36 | //TODO 获取该消息重试次数 37 | int reconsume = messageExt.getReconsumeTimes(); 38 | if (reconsume == 3) {//消息已经重试了3次,如果不需要再次消费,则返回成功 39 | return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; 40 | } 41 | //TODO 处理对应的业务逻辑 42 | } 43 | } 44 | // 如果没有return success ,consumer会重新消费该消息,直到return success 45 | return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rocketmq-demo/src/main/java/com/wuwii/Productor.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.apache.rocketmq.client.exception.MQClientException; 6 | import org.apache.rocketmq.client.producer.DefaultMQProducer; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.boot.context.properties.ConfigurationProperties; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | /** 14 | * Created by KronChan on 18/8/30 下午6:20. 15 | */ 16 | @Configuration 17 | @ConfigurationProperties(prefix = "rocketmq.product") 18 | @Getter 19 | @Setter 20 | public class Productor { 21 | private static final Logger log = LoggerFactory.getLogger(Productor.class); 22 | 23 | private String groupName; 24 | private String namesrvAddr; 25 | /** 26 | * 消息最大大小,默认4M 27 | */ 28 | private Integer maxMessageSize; 29 | /** 30 | * 消息发送超时时间,默认3秒 31 | */ 32 | private Integer sendMsgTimeout; 33 | /** 34 | * 消息发送失败重试次数,默认2次 35 | */ 36 | private Integer retryTimesWhenSendFailed; 37 | 38 | @Bean 39 | public DefaultMQProducer getRocketMQProducer() { 40 | 41 | DefaultMQProducer producer; 42 | producer = new DefaultMQProducer(this.groupName); 43 | producer.setNamesrvAddr(this.namesrvAddr); 44 | //如果需要同一个jvm中不同的producer往不同的mq集群发送消息,需要设置不同的instanceName 45 | //producer.setInstanceName(instanceName); 46 | if (this.maxMessageSize != null) { 47 | producer.setMaxMessageSize(this.maxMessageSize); 48 | } 49 | if (this.sendMsgTimeout != null) { 50 | producer.setSendMsgTimeout(this.sendMsgTimeout); 51 | } 52 | //如果发送消息失败,设置重试次数,默认为2次 53 | if (this.retryTimesWhenSendFailed != null) { 54 | producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed); 55 | } 56 | try { 57 | producer.start(); 58 | producer.setCreateTopicKey("test"); 59 | log.info(String.format("producer is start ! groupName:[%s],namesrvAddr:[%s]" 60 | , this.groupName, this.namesrvAddr)); 61 | } catch (MQClientException e) { 62 | log.error(String.format("producer is error {}" 63 | , e.getMessage(), e)); 64 | } 65 | return producer; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /rocketmq-demo/src/main/java/com/wuwii/RocketmqDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RocketmqDemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RocketmqDemoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /rocketmq-demo/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: @pom.artifactId@ 4 | 5 | group-name: demo 6 | namesrvAddr: k.wuwii.com:9876 7 | rocketmq: 8 | product: 9 | group-name: ${group-name} 10 | namesrvAddr: ${namesrvAddr} 11 | maxMessageSize: 4096 12 | sendMsgTimeout: 10000 13 | retryTimesWhenSendFailed: 3 14 | comsume: 15 | group-name: ${group-name} 16 | namesrvAddr: ${namesrvAddr} 17 | topics: 'test~*' 18 | consumeThreadMin: 10 19 | consumeThreadMax: 60 20 | consumeMessageBatchMaxSize: 2 21 | 22 | -------------------------------------------------------------------------------- /rocketmq-demo/src/test/java/com/wuwii/RocketmqDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.apache.rocketmq.client.exception.MQBrokerException; 4 | import org.apache.rocketmq.client.exception.MQClientException; 5 | import org.apache.rocketmq.client.producer.DefaultMQProducer; 6 | import org.apache.rocketmq.client.producer.SendResult; 7 | import org.apache.rocketmq.common.message.Message; 8 | import org.apache.rocketmq.remoting.exception.RemotingException; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | 17 | @RunWith(SpringRunner.class) 18 | @SpringBootTest 19 | public class RocketmqDemoApplicationTests { 20 | 21 | private static final Logger log = LoggerFactory.getLogger(RocketmqDemoApplicationTests.class); 22 | 23 | @Test 24 | public void contextLoads() { 25 | } 26 | 27 | @Autowired 28 | private DefaultMQProducer defaultMQProducer; 29 | 30 | /** 31 | * 发送消息 32 | *

33 | * 2018年3月3日 zhaowg 34 | * 35 | * @throws InterruptedException 36 | * @throws MQBrokerException 37 | * @throws RemotingException 38 | * @throws MQClientException 39 | */ 40 | @Test 41 | public void send() throws MQClientException, RemotingException, MQBrokerException, InterruptedException { 42 | String msg = "demo msg test"; 43 | log.info("开始发送消息:" + msg); 44 | Message sendMsg = new Message("test", "111", msg.getBytes()); 45 | //默认3秒超时 46 | SendResult sendResult = defaultMQProducer.send(sendMsg); 47 | log.info("消息发送响应信息:" + sendResult.toString()); 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /sort-algorithm/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | .idea/ 25 | .mvn 26 | *.iml 27 | target/ 28 | /log/ 29 | -------------------------------------------------------------------------------- /sort-algorithm/README.md: -------------------------------------------------------------------------------- 1 | [学习八种简单的算法](https://blog.wuwii.com/sort-algorithm.html) -------------------------------------------------------------------------------- /sort-algorithm/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.wuwii 8 | sort-algorithm 9 | 1.0-SNAPSHOT 10 | 11 | 1.2.17 12 | 1.7.21 13 | 4.13.1 14 | 2.0.0.0 15 | 16 | 17 | 18 | log4j 19 | log4j 20 | ${log4j.version} 21 | 22 | 23 | 24 | org.slf4j 25 | slf4j-log4j12 26 | ${slf4j.version} 27 | 28 | 29 | junit 30 | junit 31 | ${junit.version} 32 | test 33 | 34 | 35 | org.hamcrest 36 | hamcrest-junit 37 | ${hamcrest.version} 38 | test 39 | 40 | 41 | -------------------------------------------------------------------------------- /spring-boot-test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | learning-code 7 | com.wuwii 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | spring-boot-test 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-web 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-data-jpa 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-test 25 | 26 | 27 | mysql 28 | mysql-connector-java 29 | runtime 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | 35 | 36 | h2 37 | com.h2database 38 | test 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /spring-boot-test/src/main/java/com/wuwii/Application.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * Created by KronChan on 2018/4/26 11:52. 8 | */ 9 | @SpringBootApplication 10 | public class Application { 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring-boot-test/src/main/java/com/wuwii/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.controller; 2 | 3 | import com.wuwii.model.User; 4 | import com.wuwii.service.IUserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * Created by KronChan on 2018/4/26 13:12. 13 | */ 14 | @RestController 15 | @RequestMapping("/user") 16 | public class UserController { 17 | private final IUserService userService; 18 | 19 | @Autowired 20 | public UserController(IUserService userService) { 21 | this.userService = userService; 22 | } 23 | 24 | @RequestMapping("/{id}") 25 | public ResponseEntity getUser(@PathVariable Long id) { 26 | return ResponseEntity.ok(userService.findOne(id)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /spring-boot-test/src/main/java/com/wuwii/model/User.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.model; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import org.hibernate.annotations.CreationTimestamp; 6 | 7 | import javax.persistence.*; 8 | import java.io.Serializable; 9 | import java.util.Date; 10 | 11 | /** 12 | * Created by KronChan on 2018/4/26 12:08. 13 | */ 14 | @Entity 15 | @Data 16 | @NoArgsConstructor 17 | public class User implements Serializable { 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | 22 | @Column(unique = true, nullable = false, length = 50) 23 | private String username; 24 | 25 | private String password; 26 | 27 | @CreationTimestamp 28 | private Date createDate; 29 | 30 | public User(Long id, String username) { 31 | this.id = id; 32 | this.username = username; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /spring-boot-test/src/main/java/com/wuwii/repository/IUserRepository.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.repository; 2 | 3 | import com.wuwii.model.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * Created by KronChan on 2018/4/26 12:12. 8 | */ 9 | public interface IUserRepository extends JpaRepository { 10 | 11 | User findByUsername(String username); 12 | } 13 | -------------------------------------------------------------------------------- /spring-boot-test/src/main/java/com/wuwii/service/IUserService.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import com.wuwii.model.User; 4 | 5 | /** 6 | * Created by KronChan on 2018/4/26 12:13. 7 | */ 8 | public interface IUserService { 9 | 10 | User findOne(Long id); 11 | 12 | boolean updateUsername(Long id, String usernmae); 13 | 14 | User save(User user); 15 | 16 | User findByUsername(String username); 17 | } 18 | -------------------------------------------------------------------------------- /spring-boot-test/src/main/java/com/wuwii/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service.impl; 2 | 3 | import com.wuwii.model.User; 4 | import com.wuwii.repository.IUserRepository; 5 | import com.wuwii.service.IUserService; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | /** 11 | * Created by KronChan on 2018/4/26 12:14. 12 | */ 13 | @Service 14 | @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 15 | public class UserServiceImpl implements IUserService { 16 | private final IUserRepository userRepository; 17 | 18 | @Override 19 | public User findOne(Long id) { 20 | return userRepository.getOne(id); 21 | } 22 | 23 | @Override 24 | public boolean updateUsername(Long id, String username) { 25 | assert username != null; 26 | User user = findOne(id); 27 | if (user == null) { 28 | return false; 29 | } 30 | user.setUsername(username); 31 | return username.equals(userRepository.save(user).getUsername()); 32 | } 33 | 34 | @Override 35 | public User save(User user) { 36 | return userRepository.save(user); 37 | } 38 | 39 | @Override 40 | public User findByUsername(String username) { 41 | return userRepository.findByUsername(username); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /spring-boot-test/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/learn?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 4 | username: root 5 | password: 123456 6 | driver-class-name: com.mysql.jdbc.Driver 7 | jpa: 8 | show-sql: true 9 | database: mysql 10 | hibernate: 11 | ddl-auto: update 12 | properties: 13 | hibernate: 14 | dialect: org.hibernate.dialect.MySQL57Dialect -------------------------------------------------------------------------------- /spring-boot-test/src/test/java/com/wuwii/service/SpringDataBaseTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import com.wuwii.model.User; 4 | import org.hamcrest.Matchers; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.jdbc.Sql; 11 | import org.springframework.test.context.jdbc.Sql.ExecutionPhase; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | 14 | /** 15 | * @author KronChan 16 | * @date 2019-07-14 23:39 17 | */ 18 | @SpringBootTest 19 | @RunWith(SpringRunner.class) 20 | public class SpringDataBaseTest { 21 | 22 | @Autowired 23 | private IUserService userService; 24 | 25 | @Test 26 | public void testSave() { 27 | User user = mockUser(); 28 | User saveUser = userService.save(user); 29 | Assert.assertThat(saveUser.getUsername(), Matchers.equalTo(user.getUsername())); 30 | } 31 | 32 | @Test 33 | @Sql(value = "classpath:drop.sql", executionPhase = ExecutionPhase.AFTER_TEST_METHOD) 34 | public void testFindByUsername() { 35 | String username = "data.sql"; 36 | String password = "123456"; 37 | User user = userService.findByUsername(username); 38 | Assert.assertThat(user == null ? null : user.getPassword(), Matchers.equalTo(password)); 39 | } 40 | 41 | 42 | private User mockUser() { 43 | User user = new User(); 44 | user.setUsername("jack"); 45 | user.setPassword("32145"); 46 | return user; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /spring-boot-test/src/test/resources/application-h2.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:~/userdb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1 4 | username: sa 5 | tomcat: 6 | init-s-q-l: classpath:data.sql 7 | 8 | h2: 9 | console: 10 | enabled: false 11 | settings: 12 | web-allow-others: true 13 | jpa: 14 | database: h2 15 | -------------------------------------------------------------------------------- /spring-boot-test/src/test/resources/application-mysql.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaimz/learning-code/a6f9ae2d0d2456eea198d23900903df19caa9db7/spring-boot-test/src/test/resources/application-mysql.yml -------------------------------------------------------------------------------- /spring-boot-test/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: h2 4 | 5 | jpa: 6 | show-sql: true 7 | open-in-view: false -------------------------------------------------------------------------------- /spring-boot-test/src/test/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into user(password, username) 2 | values ('123456', 'data.sql'); -------------------------------------------------------------------------------- /spring-boot-test/src/test/resources/drop.sql: -------------------------------------------------------------------------------- 1 | drop table user if exists -------------------------------------------------------------------------------- /spring-event/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | spring-event 6 | 7 | 8 | spring-boot-starter 9 | org.springframework.boot 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-test 14 | test 15 | 16 | 17 | 18 | 4.0.0 19 | 20 | 21 | learning-code 22 | com.wuwii 23 | 0.0.1-SNAPSHOT 24 | 25 | -------------------------------------------------------------------------------- /spring-event/src/main/java/com/wuwii/PropertiesChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import java.util.Date; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author KronChan 8 | * @date 2019-07-14 22:52 9 | */ 10 | public class PropertiesChangeEvent { 11 | 12 | private final Date eventDateTime; 13 | private Map properties; 14 | 15 | public PropertiesChangeEvent(Map properties) { 16 | this.properties = properties; 17 | this.eventDateTime = new Date(); 18 | } 19 | 20 | public Map getProperties() { 21 | return properties; 22 | } 23 | 24 | public void setProperties(Map properties) { 25 | this.properties = properties; 26 | } 27 | 28 | public Date getEventDateTime() { 29 | return eventDateTime; 30 | } 31 | 32 | 33 | @Override 34 | public String toString() { 35 | return "PropertiesChangeEvent{" + 36 | "properties=" + properties + 37 | ", eventDateTime=" + eventDateTime + 38 | '}'; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spring-event/src/main/java/com/wuwii/PropertiesChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.context.event.EventListener; 6 | import org.springframework.scheduling.annotation.Async; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @author KronChan 11 | * @date 2019-07-14 23:00 12 | */ 13 | @Component 14 | public class PropertiesChangeListener { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(PropertiesChangeListener.class); 17 | 18 | /** 19 | * 注意, 如果是需要添加异步任务 @Async,最好是手动配置一个 taskExecutor 的任务线程池,方便追踪任务 20 | * 21 | * @param propertiesChangeEvent event 22 | */ 23 | @EventListener 24 | @Async 25 | public void listen(PropertiesChangeEvent propertiesChangeEvent) { 26 | log.info(">>>>>>>>>>>>>>>> properties change event={}", propertiesChangeEvent); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /spring-event/src/main/java/com/wuwii/PropertiesChangePublisher.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import org.springframework.context.ApplicationEventPublisher; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * @author KronChan 10 | * @date 2019-07-14 22:59 11 | */ 12 | @Component 13 | public class PropertiesChangePublisher { 14 | 15 | private final ApplicationEventPublisher applicationEventPublisher; 16 | 17 | public PropertiesChangePublisher( 18 | ApplicationEventPublisher applicationEventPublisher) { 19 | this.applicationEventPublisher = applicationEventPublisher; 20 | } 21 | 22 | public void publish() { 23 | Map properties = new HashMap<>(); 24 | properties.put("p1", "1"); 25 | properties.put("p2", "2"); 26 | PropertiesChangeEvent propertiesChangeEvent = new PropertiesChangeEvent(properties); 27 | applicationEventPublisher.publishEvent(propertiesChangeEvent); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /spring-event/src/main/java/com/wuwii/SpringEventApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableAsync; 6 | 7 | /** 8 | * @author KronChan 9 | * @date 2019-07-14 22:48 10 | */ 11 | @EnableAsync 12 | @SpringBootApplication 13 | public class SpringEventApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(SpringEventApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /spring-event/src/test/java/com/wuwii/PropertiesChangePublisherTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | 4 | import org.junit.runner.RunWith; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | 9 | /** 10 | * @author KronChan 11 | * @date 2019-07-14 23:07 12 | */ 13 | @RunWith(SpringRunner.class) 14 | @SpringBootTest 15 | public class PropertiesChangePublisherTest { 16 | 17 | @Autowired 18 | private PropertiesChangePublisher propertiesChangePublisher; 19 | 20 | @org.junit.Test 21 | public void publish() { 22 | propertiesChangePublisher.publish(); 23 | } 24 | } -------------------------------------------------------------------------------- /springboot-actuator/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | nbproject/private/ 21 | build/ 22 | nbbuild/ 23 | dist/ 24 | nbdist/ 25 | .nb-gradle/ 26 | /.mvn/ 27 | -------------------------------------------------------------------------------- /springboot-actuator/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.wuwii 7 | springboot-actuator 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | springboot-actuator 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-actuator 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-web 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-devtools 40 | runtime 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /springboot-actuator/src/main/java/com/wuwii/SpringbootActuatorApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @SpringBootApplication 9 | @RestController 10 | public class SpringbootActuatorApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(SpringbootActuatorApplication.class, args); 14 | } 15 | 16 | @GetMapping("/hello") 17 | public String hello() { 18 | return "Hello World."; 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /springboot-actuator/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8003 3 | management: 4 | endpoints: 5 | web: 6 | exposure: 7 | include: "*" # 开启全部的 endpoints 8 | # server: 9 | # port: 8004 10 | # servlet: 11 | # context-path: /monitor 12 | info: 13 | app: 14 | name: springboot-actuator 15 | version: v1.0.0 16 | 17 | -------------------------------------------------------------------------------- /springboot-actuator/src/test/java/com/wuwii/SpringbootActuatorApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringbootActuatorApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-docker/README.md: -------------------------------------------------------------------------------- 1 | Spring Boot 中使用远程 Docker API 完成构建镜像: 2 | 1. `pom.xml` 中加入 `docker-maven-plugin` 插件; 3 | 2. 编写 Dockerfile 文件,注意上下文路径; -------------------------------------------------------------------------------- /springboot-docker/docker-compose-swarm.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | depends_on: 5 | - db 6 | networks: 7 | - overlay 8 | ports: 9 | - "8081:8080" # 建议加上引号,如果单独两位数的数字,可能出现解析问题 10 | # restart: always Swarm 中将不会生效 11 | # build: ./src/docker/ 12 | # context: ./src/docker # Dockerfile 文件的目录,可以远程地址,绝对 or 相对 13 | # dockerfile: Dockerfile # 如果你的 Dockerfile 重命名了,需要指定 14 | image: test:latest 15 | environment: 16 | DB_HOST: db:3306 17 | DATABASE: learn 18 | DB_USERNAME: root # 测试用下 root 19 | DB_PASSWORD: 123456 # # 建议使用 secret 20 | deploy: # swarm 项目中有的 21 | mode: replicated 22 | replicas: 3 23 | update_config: 24 | parallelism: 2 25 | delay: 10s 26 | restart_policy: 27 | condition: on-failure 28 | 29 | db: 30 | image: mysql:5.7 31 | networks: 32 | - overlay 33 | volumes: 34 | - db_data:/var/lib/mysql 35 | # restart: always 失效 36 | environment: 37 | MYSQL_ROOT_PASSWORD: 123456 38 | MYSQL_DATABASE: learn 39 | MYSQL_USER: kronchan 40 | MYSQL_PASSWORD: 123456 41 | deploy: 42 | placement: 43 | constraints: [node.role == manager] 44 | replicas: 1 45 | restart_policy: 46 | condition: on-failure 47 | 48 | visualizer: 49 | image: dockersamples/visualizer:stable 50 | ports: 51 | - "8080:8080" 52 | stop_grace_period: 1m30s 53 | volumes: 54 | - "/var/run/docker.sock:/var/run/docker.sock" 55 | deploy: 56 | placement: 57 | constraints: [node.role == manager] 58 | 59 | volumes: 60 | db_data: # 使用的数据卷必须声明 61 | networks: 62 | overlay: 63 | 64 | -------------------------------------------------------------------------------- /springboot-docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | depends_on: 5 | - db 6 | ports: 7 | - "8080:8080" # 建议加上引号,如果单独两位数的数字,可能出现解析问题 8 | # restart: always Swarm 中将不会生效 9 | # build: ./src/docker/ 10 | # context: ./src/docker # Dockerfile 文件的目录,可以远程地址,绝对 or 相对 11 | # dockerfile: Dockerfile # 如果你的 Dockerfile 重命名了,需要指定 12 | image: test:latest 13 | environment: 14 | DB_HOST: db:3306 15 | DATABASE: learn 16 | DB_USERNAME: root # 测试用下 root 17 | DB_PASSWORD: 123456 # # 建议使用 secret 18 | 19 | db: 20 | image: mysql:5.7 21 | volumes: 22 | - db_data:/var/lib/mysql 23 | restart: always 24 | environment: 25 | MYSQL_ROOT_PASSWORD: 123456 26 | MYSQL_DATABASE: learn 27 | MYSQL_USER: kronchan 28 | MYSQL_PASSWORD: 123456 29 | 30 | volumes: 31 | db_data: # 使用的数据卷必须声明 32 | 33 | -------------------------------------------------------------------------------- /springboot-docker/src/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM java:8 2 | EXPOSE 8080 3 | 4 | VOLUME /tmp 5 | ADD springboot-docker.jar app.jar 6 | ENTRYPOINT ["java","-jar","/app.jar"] -------------------------------------------------------------------------------- /springboot-docker/src/main/java/com/wuwii/SpringbootDockerApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import com.wuwii.dao.UserDao; 4 | import com.wuwii.entity.User; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.data.domain.Sort; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.List; 15 | 16 | @SpringBootApplication 17 | @RestController 18 | public class SpringbootDockerApplication { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(SpringbootDockerApplication.class, args); 22 | } 23 | 24 | @GetMapping("/hello") 25 | public String hello() { 26 | return "Hello World."; 27 | } 28 | 29 | @Autowired 30 | private UserDao userDao; 31 | 32 | @GetMapping("/user") 33 | public List getAllUser() { 34 | Sort sort = new Sort(Sort.Direction.ASC, "id"); 35 | return userDao.findAll(sort); 36 | } 37 | 38 | @PostMapping("/user") 39 | public User addUser(@RequestBody User user) { 40 | return userDao.save(user); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /springboot-docker/src/main/java/com/wuwii/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * 9 | */ 10 | @Repository 11 | public interface UserDao extends JpaRepository { 12 | } 13 | -------------------------------------------------------------------------------- /springboot-docker/src/main/java/com/wuwii/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import java.io.Serializable; 10 | 11 | /** 12 | * 13 | */ 14 | @Entity 15 | @Data 16 | public class User implements Serializable { 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private Long id; 20 | 21 | private String name; 22 | } 23 | -------------------------------------------------------------------------------- /springboot-docker/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://${DB_HOST:localhost:3306}/${DATABASE:learn}?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 4 | username: ${DB_USERNAME:root} 5 | password: ${DB_PASSWORD:123456} 6 | driver-class-name: com.mysql.jdbc.Driver 7 | jpa: 8 | show-sql: true 9 | database: mysql 10 | hibernate: 11 | # update 更新表结构 12 | # create 每次启动删除上次表,再创建表,会造成数据丢失 13 | # create-drop: 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 14 | # validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 15 | ddl-auto: update 16 | properties: 17 | hibernate: 18 | dialect: org.hibernate.dialect.MySQL57Dialect # 方言根据 数据库版本选择吧 19 | 20 | 21 | -------------------------------------------------------------------------------- /springboot-docker/src/test/java/com/wuwii/SpringbootDockerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringbootDockerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-querydsl/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | nbproject/private/ 21 | build/ 22 | nbbuild/ 23 | dist/ 24 | nbdist/ 25 | .nb-gradle/ 26 | /.mvn/ 27 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/SpringbootQuerydslApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.transaction.annotation.EnableTransactionManagement; 6 | 7 | @SpringBootApplication 8 | @EnableTransactionManagement 9 | public class SpringbootQuerydslApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SpringbootQuerydslApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/config/JPAQueryConfig.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config; 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import javax.persistence.EntityManager; 8 | 9 | /** 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since

2018/3/26 18:52
13 | */ 14 | @Configuration 15 | public class JPAQueryConfig { 16 | 17 | @Bean 18 | public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) { 19 | return new JPAQueryFactory(entityManager); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/dao/EmployeeDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.Employee; 4 | import com.wuwii.entity.QEmployee; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.querydsl.QuerydslPredicateExecutor; 7 | 8 | /** 9 | * https://www.jianshu.com/p/69dcb1b85bbb 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since
2018/3/26 18:41
13 | */ 14 | public interface EmployeeDao extends JpaRepository, QuerydslPredicateExecutor { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/entity/Employee.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author Zhang Kai 10 | * @version 1.0 11 | * @since
2018/3/8 9:52
12 | */ 13 | @Entity 14 | @Data 15 | public class Employee implements Serializable { 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | private Long id; 19 | 20 | @OneToOne(cascade = CascadeType.ALL) 21 | // 拥有级联维护的一方,参考http://westerly-lzh.github.io/cn/2014/12/JPA-CascadeType-Explaining/ 22 | @JoinColumn(foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) 23 | private EmployeeDetail detail; 24 | 25 | @ManyToOne(fetch = FetchType.LAZY) // 默认 lazy ,通过懒加载,知道需要使用级联的数据,才去数据库查询这个数据,提高查询效率。 26 | // 设置外键的问题,参考http://mario1412.github.io/2016/06/27/JPA%E4%B8%AD%E5%B1%8F%E8%94%BD%E5%AE%9E%E4%BD%93%E9%97%B4%E5%A4%96%E9%94%AE/ 27 | @JoinColumn(name = "jobId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) 28 | private Job job; 29 | } 30 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/entity/EmployeeDetail.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import java.io.Serializable; 10 | 11 | /** 12 | * @author Zhang Kai 13 | * @version 1.0 14 | * @since
2018/3/8 10:00
15 | */ 16 | @Entity 17 | @Data 18 | public class EmployeeDetail implements Serializable { 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private Long id; 22 | 23 | private String name; 24 | 25 | private String phone; 26 | 27 | private Integer age; 28 | } 29 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/entity/Job.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | import java.util.Set; 8 | 9 | /** 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since
2018/3/8 9:54
13 | */ 14 | @Entity 15 | @Data 16 | public class Job implements Serializable { 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private Long id; 20 | 21 | private String name; 22 | 23 | @OneToMany(targetEntity = Employee.class, mappedBy = "job") // mappedBy 只有在双向关联的时候设置,表示关系维护的一端,否则会生成中间表A_B 24 | @org.hibernate.annotations.ForeignKey(name = "none") // 注意这里不能使用 @JoinColumn 不然会生成外键 25 | private Set employees; 26 | } 27 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/entity/QEmployee.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import com.querydsl.core.types.Path; 4 | import com.querydsl.core.types.PathMetadata; 5 | import com.querydsl.core.types.dsl.EntityPathBase; 6 | import com.querydsl.core.types.dsl.NumberPath; 7 | import com.querydsl.core.types.dsl.PathInits; 8 | 9 | import javax.annotation.Generated; 10 | 11 | import static com.querydsl.core.types.PathMetadataFactory.forVariable; 12 | 13 | 14 | /** 15 | * QEmployee is a Querydsl query type for Employee 16 | */ 17 | @Generated("com.querydsl.codegen.EntitySerializer") 18 | public class QEmployee extends EntityPathBase { 19 | 20 | private static final long serialVersionUID = 1345765399L; 21 | 22 | private static final PathInits INITS = PathInits.DIRECT2; 23 | 24 | public static final QEmployee employee = new QEmployee("employee"); 25 | 26 | public final QEmployeeDetail detail; 27 | 28 | public final NumberPath id = createNumber("id", Long.class); 29 | 30 | public final QJob job; 31 | 32 | public QEmployee(String variable) { 33 | this(Employee.class, forVariable(variable), INITS); 34 | } 35 | 36 | public QEmployee(Path path) { 37 | this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); 38 | } 39 | 40 | public QEmployee(PathMetadata metadata) { 41 | this(metadata, PathInits.getFor(metadata, INITS)); 42 | } 43 | 44 | public QEmployee(PathMetadata metadata, PathInits inits) { 45 | this(Employee.class, metadata, inits); 46 | } 47 | 48 | public QEmployee(Class type, PathMetadata metadata, PathInits inits) { 49 | super(type, metadata, inits); 50 | this.detail = inits.isInitialized("detail") ? new QEmployeeDetail(forProperty("detail")) : null; 51 | this.job = inits.isInitialized("job") ? new QJob(forProperty("job")) : null; 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/entity/QEmployeeDetail.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import com.querydsl.core.types.Path; 4 | import com.querydsl.core.types.PathMetadata; 5 | import com.querydsl.core.types.dsl.EntityPathBase; 6 | import com.querydsl.core.types.dsl.NumberPath; 7 | import com.querydsl.core.types.dsl.StringPath; 8 | 9 | import javax.annotation.Generated; 10 | 11 | import static com.querydsl.core.types.PathMetadataFactory.forVariable; 12 | 13 | 14 | /** 15 | * QEmployeeDetail is a Querydsl query type for EmployeeDetail 16 | */ 17 | @Generated("com.querydsl.codegen.EntitySerializer") 18 | public class QEmployeeDetail extends EntityPathBase { 19 | 20 | private static final long serialVersionUID = -1230694584L; 21 | 22 | public static final QEmployeeDetail employeeDetail = new QEmployeeDetail("employeeDetail"); 23 | 24 | public final NumberPath age = createNumber("age", Integer.class); 25 | 26 | public final NumberPath id = createNumber("id", Long.class); 27 | 28 | public final StringPath name = createString("name"); 29 | 30 | public final StringPath phone = createString("phone"); 31 | 32 | public QEmployeeDetail(String variable) { 33 | super(EmployeeDetail.class, forVariable(variable)); 34 | } 35 | 36 | public QEmployeeDetail(Path path) { 37 | super(path.getType(), path.getMetadata()); 38 | } 39 | 40 | public QEmployeeDetail(PathMetadata metadata) { 41 | super(EmployeeDetail.class, metadata); 42 | } 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/entity/QJob.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import com.querydsl.core.types.Path; 4 | import com.querydsl.core.types.PathMetadata; 5 | import com.querydsl.core.types.dsl.*; 6 | 7 | import javax.annotation.Generated; 8 | 9 | import static com.querydsl.core.types.PathMetadataFactory.forVariable; 10 | 11 | 12 | /** 13 | * QJob is a Querydsl query type for Job 14 | */ 15 | @Generated("com.querydsl.codegen.EntitySerializer") 16 | public class QJob extends EntityPathBase { 17 | 18 | private static final long serialVersionUID = 1065600180L; 19 | 20 | public static final QJob job = new QJob("job"); 21 | 22 | public final SetPath employees = this.createSet("employees", Employee.class, QEmployee.class, PathInits.DIRECT2); 23 | 24 | public final NumberPath id = createNumber("id", Long.class); 25 | 26 | public final StringPath name = createString("name"); 27 | 28 | public QJob(String variable) { 29 | super(Job.class, forVariable(variable)); 30 | } 31 | 32 | public QJob(Path path) { 33 | super(path.getType(), path.getMetadata()); 34 | } 35 | 36 | public QJob(PathMetadata metadata) { 37 | super(Job.class, metadata); 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/service1/EmployeeService1.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service1; 2 | 3 | import com.querydsl.core.QueryResults; 4 | import com.wuwii.entity.Employee; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | /** 8 | * 使用 JPAQueryFactory 实现复杂 CURD 9 | * @author Zhang Kai 10 | * @version 1.0 11 | * @since
2018/3/26 18:38
12 | */ 13 | public interface EmployeeService1 { 14 | long save(Employee employee); 15 | 16 | long update(Employee employee); 17 | 18 | Employee findOne(Long id); 19 | 20 | QueryResults page(Employee employee, Pageable pageable); 21 | } 22 | -------------------------------------------------------------------------------- /springboot-querydsl/src/main/java/com/wuwii/service1/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 使用 JPAQueryFactory 实现复杂 CURD 3 | * @author Zhang Kai 4 | * @version 1.0 5 | * @since
2018/3/26 18:37
6 | */ 7 | package com.wuwii.service1; -------------------------------------------------------------------------------- /springboot-querydsl/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/learn?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 4 | username: root 5 | password: 123456 6 | driver-class-name: com.mysql.jdbc.Driver 7 | jpa: 8 | show-sql: true 9 | database: mysql 10 | hibernate: 11 | # update 更新表结构 12 | # create 每次启动删除上次表,再创建表,会造成数据丢失 13 | # create-drop: 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 14 | # validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 15 | ddl-auto: update 16 | properties: 17 | hibernate: 18 | dialect: org.hibernate.dialect.MySQL57Dialect -------------------------------------------------------------------------------- /springboot-querydsl/src/test/java/com/wuwii/SpringbootQuerydslApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringbootQuerydslApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-redis-cache/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ 25 | /.mvn/ 26 | -------------------------------------------------------------------------------- /springboot-redis-cache/README.md: -------------------------------------------------------------------------------- 1 | 在 Spring Boot 中使用 Redis 作为缓存的处理 -------------------------------------------------------------------------------- /springboot-redis-cache/src/main/java/com/wuwii/SpringbootRedisCacheApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cache.annotation.EnableCaching; 6 | 7 | @SpringBootApplication 8 | @EnableCaching 9 | public class SpringbootRedisCacheApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SpringbootRedisCacheApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/main/java/com/wuwii/controller.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import com.wuwii.entity.Employee; 4 | import com.wuwii.service.EmployeeService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | /** 11 | * @author Zhang Kai 12 | * @version 1.0 13 | * @since
2018/3/13 10:45
14 | */ 15 | @RestController 16 | public class controller { 17 | @Autowired 18 | private EmployeeService service; 19 | 20 | @GetMapping("/{id}") 21 | public ResponseEntity findOne(@PathVariable Long id) { 22 | return ResponseEntity.status(HttpStatus.OK).body(service.findOne(id)); 23 | } 24 | 25 | @PostMapping 26 | public ResponseEntity update(@RequestBody Employee employee) { 27 | return ResponseEntity.status(HttpStatus.CREATED).body(service.update(employee)); 28 | } 29 | 30 | @DeleteMapping("/{id}") 31 | public ResponseEntity delete(@PathVariable Long id) { 32 | service.delete(id); 33 | return ResponseEntity.status(HttpStatus.OK).body("删除成功"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/main/java/com/wuwii/dao/EmployeeDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.Employee; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @author Zhang Kai 9 | * @version 1.0 10 | * @since
2018/3/13 10:38
11 | */ 12 | @Repository 13 | public interface EmployeeDao extends JpaRepository { 14 | } 15 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/main/java/com/wuwii/entity/Employee.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | import org.hibernate.annotations.DynamicUpdate; 5 | 6 | import javax.persistence.*; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author Zhang Kai 11 | * @version 1.0 12 | * @since
2018/3/13 10:36
13 | */ 14 | @Entity 15 | @Data 16 | @DynamicUpdate 17 | public class Employee implements Serializable { 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | private String name; 22 | private Integer age; 23 | } 24 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/main/java/com/wuwii/service/EmployeeService.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import com.wuwii.entity.Employee; 4 | 5 | /** 6 | * @author Zhang Kai 7 | * @version 1.0 8 | * @since
2018/3/13 10:40
9 | */ 10 | public interface EmployeeService { 11 | Employee findOne(Long id); 12 | 13 | Employee update(Employee employee); 14 | 15 | void delete(Long id); 16 | } 17 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/main/java/com/wuwii/service/impl/EmployeeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service.impl; 2 | 3 | import com.wuwii.dao.EmployeeDao; 4 | import com.wuwii.entity.Employee; 5 | import com.wuwii.service.EmployeeService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.cache.annotation.CacheConfig; 8 | import org.springframework.cache.annotation.CacheEvict; 9 | import org.springframework.cache.annotation.CachePut; 10 | import org.springframework.cache.annotation.Cacheable; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | /** 15 | * 控制缓存的生命周期 16 | * @author Zhang Kai 17 | * @version 1.0 18 | * @since
2018/3/13 10:40
19 | */ 20 | @Service 21 | @CacheConfig(cacheNames = "em") 22 | public class EmployeeServiceImpl implements EmployeeService { 23 | @Autowired 24 | private EmployeeDao dao; 25 | 26 | @Override 27 | @Cacheable(key = "#p0") 28 | public Employee findOne(Long id) { 29 | return dao.findOne(id); 30 | } 31 | 32 | /** 33 | * 更新缓存中的数据, 34 | * 由于 redis 是存在外部,不是 ehcache 那样存在于项目进程中,需要我们主动去更新 缓存 35 | * @param employee 36 | * @return 37 | */ 38 | @Override 39 | @Transactional(rollbackFor = Exception.class) 40 | @CachePut(key = "#p0.id") 41 | public Employee update(Employee employee) { 42 | return dao.save(employee); 43 | } 44 | 45 | /** 46 | * 同样主动去删除 cache 47 | * @param id 48 | */ 49 | @Override 50 | @Transactional(rollbackFor = Exception.class) 51 | @CacheEvict(key = "#p0") 52 | public void delete(Long id) { 53 | dao.delete(id); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/learn1?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 4 | username: root 5 | password: 123456 6 | driver-class-name: com.mysql.jdbc.Driver 7 | jpa: 8 | show-sql: true 9 | database: mysql 10 | hibernate: 11 | # update 更新表结构 12 | # create 每次启动删除上次表,再创建表,会造成数据丢失 13 | # create-drop: 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 14 | # validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 15 | ddl-auto: update 16 | properties: 17 | hibernate: 18 | dialect: org.hibernate.dialect.MySQLDialect 19 | redis: 20 | host: 120.79.208.199 # 120.79.208.199 # host ,默认 localhost 21 | port: 6379 # 端口号,默认6379 22 | pool: 23 | # 设置都是默认值,可以按需求设计 24 | max-active: 8 # 可用连接实例的最大数目,默认值为8;如果赋值为-1,则表示不限制; 25 | max-idle: 8 # 控制一个pool最多有多少个状态为idle(空闲的)的redis实例,默认值也是8。 26 | max-wait: -1 # 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。 27 | min-idle: 0 # 控制一个pool最少有多少个状态为idle(空闲的)的redis实例,默认值为0。 28 | timeout: 0 # 连接超时时间 单位 ms,默认为0 29 | password: KronChan123 # 密码,根据自己的 redis 设计,默认为空 30 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/test/java/com/wuwii/SpringbootRedisCacheApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringbootRedisCacheApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-redis-cache/src/test/java/com/wuwii/service/impl/EmployeeServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service.impl; 2 | 3 | import com.wuwii.service.EmployeeService; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | 12 | /** 13 | * EmployeeServiceImpl Tester. 14 | * 15 | * @author Zhang Kai 16 | * @version 1.0 17 | * @since
03/13/2018
18 | */ 19 | @SpringBootTest 20 | @RunWith(SpringRunner.class) 21 | public class EmployeeServiceImplTest { 22 | 23 | @Autowired 24 | private EmployeeService service; 25 | @Before 26 | public void before() throws Exception { 27 | } 28 | 29 | @After 30 | public void after() throws Exception { 31 | } 32 | 33 | /** 34 | * Method: update(Employee employee) 35 | */ 36 | @Test 37 | public void testUpdate() throws Exception { 38 | //TODO: Test goes here... 39 | } 40 | 41 | /** 42 | * Method: findOne(Long id) 43 | */ 44 | @Test 45 | public void testFindOne() throws Exception { 46 | //TODO: Test goes here... 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /springboot-security/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/SpringbootSecurityApplication.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cache.annotation.EnableCaching; 6 | 7 | @SpringBootApplication 8 | @EnableCaching 9 | public class SpringbootSecurityApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SpringbootSecurityApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/Swagger2Config.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.ParameterBuilder; 8 | import springfox.documentation.builders.PathSelectors; 9 | import springfox.documentation.builders.RequestHandlerSelectors; 10 | import springfox.documentation.schema.ModelRef; 11 | import springfox.documentation.service.ApiInfo; 12 | import springfox.documentation.service.Parameter; 13 | import springfox.documentation.spi.DocumentationType; 14 | import springfox.documentation.spring.web.plugins.Docket; 15 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * @author kronchan 22 | */ 23 | @EnableSwagger2 24 | @Configuration 25 | public class Swagger2Config { 26 | @Value("${jwt.header}") 27 | private String header; 28 | @Bean 29 | public Docket createRestApi() { 30 | ParameterBuilder tokenPar = new ParameterBuilder(); 31 | List pars = new ArrayList(); 32 | tokenPar.name(header).description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); 33 | pars.add(tokenPar.build()); 34 | return new Docket(DocumentationType.SWAGGER_2) 35 | .apiInfo(apiInfo()) 36 | .select() 37 | .apis(RequestHandlerSelectors.basePackage("com.wuwii")) 38 | .paths(PathSelectors.any()) 39 | .build() 40 | .globalOperationParameters(pars); 41 | } 42 | 43 | private ApiInfo apiInfo() { 44 | return new ApiInfoBuilder() 45 | .title("Spring Boot中使用Swagger2构建RESTful APIs") 46 | .description("rest api 文档构建利器") 47 | .termsOfServiceUrl("https://blog.wuwii.com/") 48 | .version("1.0") 49 | .build(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/security/SecurityModelFactory.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config.security; 2 | 3 | import com.wuwii.entity.User; 4 | import org.springframework.security.core.userdetails.UserDetails; 5 | 6 | /** 7 | * 生成认证需要的 UserDetails 8 | * @author KronChan 9 | */ 10 | public class SecurityModelFactory { 11 | public static UserDetails create(User user) { 12 | return new UserDetailsImpl(user); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/security/UserDetailServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config.security; 2 | 3 | import com.wuwii.dao.UserDao; 4 | import com.wuwii.entity.User; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.cache.annotation.CacheConfig; 8 | import org.springframework.cache.annotation.Cacheable; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | import org.springframework.security.core.userdetails.UserDetailsService; 11 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 | 13 | /** 14 | * 15 | * 接受一个String类型的用户名参数,返回 UserDetails对象。 16 | */ 17 | @Slf4j 18 | @CacheConfig(cacheNames = "users") 19 | public class UserDetailServiceImpl implements UserDetailsService { 20 | 21 | @Autowired 22 | private UserDao userDao; 23 | 24 | @Override 25 | @Cacheable(key = "#p0") 26 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 27 | User user = userDao.findByUsername(username); 28 | if (user == null) { 29 | throw new UsernameNotFoundException("Username is not valid."); 30 | } 31 | log.debug("The User is {}", user); 32 | return SecurityModelFactory.create(user); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/security/UserDetailsImpl.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config.security; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.wuwii.entity.User; 5 | import com.wuwii.entity.UserRole; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.List; 13 | import java.util.Set; 14 | 15 | /** 16 | * UserDetailsImpl 17 | * @author KronChan 18 | */ 19 | public class UserDetailsImpl implements UserDetails { 20 | private User user; 21 | 22 | public UserDetailsImpl(User user) { 23 | this.user = user; 24 | } 25 | 26 | /** 27 | * 获取权限信息 28 | * @return 29 | */ 30 | @Override 31 | public Collection getAuthorities() { 32 | Set userRoles = user.getUserRoles(); 33 | List auths = new ArrayList<>(userRoles.size()); 34 | userRoles.parallelStream().forEach(userRole -> { 35 | // 默认ROLE_ 为前缀,可以更改 36 | auths.add(new SimpleGrantedAuthority("ROLE_" + userRole.getRole().getName())); 37 | }); 38 | return auths; 39 | } 40 | 41 | @Override 42 | public String getPassword() { 43 | return user.getPassword(); 44 | } 45 | 46 | @Override 47 | public String getUsername() { 48 | return user.getUsername(); 49 | } 50 | 51 | // 账户是否未过期 52 | @JsonIgnore 53 | @Override 54 | public boolean isAccountNonExpired() { 55 | return true; 56 | } 57 | 58 | // 账户是否未锁定 59 | @JsonIgnore 60 | @Override 61 | public boolean isAccountNonLocked() { 62 | return true; 63 | } 64 | 65 | // 密码是否未过期 66 | @JsonIgnore 67 | @Override 68 | public boolean isCredentialsNonExpired() { 69 | return true; 70 | } 71 | 72 | // 账户是否激活 73 | @JsonIgnore 74 | @Override 75 | public boolean isEnabled() { 76 | return true; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/security/v1/CustomAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config.security.v1; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.security.authentication.AuthenticationProvider; 6 | import org.springframework.security.authentication.BadCredentialsException; 7 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.core.AuthenticationException; 10 | import org.springframework.security.core.GrantedAuthority; 11 | import org.springframework.security.core.userdetails.UserDetails; 12 | import org.springframework.security.core.userdetails.UserDetailsService; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | 15 | import java.util.Collection; 16 | 17 | /** 18 | * 19 | */ 20 | @Slf4j 21 | public class CustomAuthenticationProvider implements AuthenticationProvider { 22 | @Autowired 23 | private UserDetailsService userDetailsService; 24 | 25 | @Autowired 26 | private PasswordEncoder passwordEncoder; 27 | 28 | /** 29 | * 验证登录信息,若登陆成功,设置 Authentication 30 | */ 31 | @Override 32 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 33 | String username = authentication.getName(); 34 | String password = (String) authentication.getCredentials(); 35 | UserDetails user = userDetailsService.loadUserByUsername(username); 36 | if (passwordEncoder.matches(password, user.getPassword())) { 37 | Collection authorities = user.getAuthorities(); 38 | return new UsernamePasswordAuthenticationToken(username, password, authorities); 39 | } 40 | throw new BadCredentialsException("The password is not correct."); 41 | } 42 | 43 | /** 44 | * 是否支持对该类型的凭证提供认证服务 45 | */ 46 | @Override 47 | public boolean supports(Class authentication) { 48 | return UsernamePasswordAuthenticationToken.class.equals(authentication); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/security/v1/LoginFilter.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config.security.v1; 2 | 3 | import com.wuwii.util.JwtUtil; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.core.AuthenticationException; 8 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 9 | 10 | import javax.servlet.FilterChain; 11 | import javax.servlet.ServletException; 12 | import javax.servlet.ServletRequest; 13 | import javax.servlet.ServletResponse; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | import java.io.IOException; 17 | 18 | /** 19 | * https://blog.csdn.net/itguangit/article/details/78960127 20 | * auth 拦截器 21 | * @author KronChan 22 | * @version 1.0 23 | * @since
2018/4/18 23:20
24 | */ 25 | public class LoginFilter extends UsernamePasswordAuthenticationFilter { 26 | @Autowired 27 | private JwtUtil jwtUtil; 28 | 29 | /** 30 | * 过滤,我目前使用的是默认的,可以自己看源码按需求更改 31 | */ 32 | @Override 33 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 34 | // todo 在这里可以按需求进行过滤,根据源码来修改扩展非常方便 35 | super.doFilter(request, response, chain); 36 | } 37 | 38 | /** 39 | * 如果需要进行登陆认证,会在这里进行预处理 40 | */ 41 | @Override 42 | public Authentication attemptAuthentication(HttpServletRequest request, 43 | HttpServletResponse response) throws AuthenticationException { 44 | // todo 在登陆认证的时候,可以做些其他的验证操作,比如验证码 45 | return super.attemptAuthentication(request, response); 46 | } 47 | 48 | /** 49 | * 登陆成功调用,返回 token 50 | */ 51 | @Override 52 | protected void successfulAuthentication(HttpServletRequest request, 53 | HttpServletResponse response, 54 | FilterChain chain, Authentication authResult) throws IOException { 55 | String token = jwtUtil.generateToken(authResult.getName()); 56 | response.setStatus(HttpStatus.OK.value()); 57 | response.getWriter().print(token); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/security/v2/authenticate/LoginAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config.security.v2.authenticate; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.authentication.AuthenticationProvider; 5 | import org.springframework.security.authentication.BadCredentialsException; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.AuthenticationException; 9 | import org.springframework.security.core.GrantedAuthority; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | 14 | import java.util.Collection; 15 | 16 | /** 17 | * @author KronChan 18 | * @version 1.0 19 | * @since
2018/4/22 11:13
20 | */ 21 | public class LoginAuthenticationProvider implements AuthenticationProvider { 22 | @Autowired 23 | private UserDetailsService userDetailsService; 24 | 25 | @Autowired 26 | private PasswordEncoder passwordEncoder; 27 | 28 | @Override 29 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 30 | String username = authentication.getName(); 31 | String password = (String) authentication.getCredentials(); 32 | UserDetails user = userDetailsService.loadUserByUsername(username); 33 | if (passwordEncoder.matches(password, user.getPassword())) { 34 | Collection authorities = user.getAuthorities(); 35 | return new UsernamePasswordAuthenticationToken(username, password, authorities); 36 | } 37 | throw new BadCredentialsException("The password is not correct."); 38 | } 39 | 40 | @Override 41 | public boolean supports(Class authentication) { 42 | return UsernamePasswordAuthenticationToken.class.equals(authentication); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/config/security/v2/authenticate/TokenAuthenticateProvider.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.config.security.v2.authenticate; 2 | 3 | import com.wuwii.util.JwtUtil; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.security.authentication.AuthenticationProvider; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.core.AuthenticationException; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.core.userdetails.UserDetailsService; 10 | import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; 11 | 12 | /** 13 | * @author KronChan 14 | * @version 1.0 15 | * @since
2018/4/22 11:15
16 | */ 17 | public class TokenAuthenticateProvider implements AuthenticationProvider { 18 | @Autowired 19 | private JwtUtil jwtUtil; 20 | @Autowired 21 | private UserDetailsService userDetailsService; 22 | 23 | @Override 24 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 25 | String token = authentication.getName(); 26 | String username = jwtUtil.getUsernameFromToken(token); 27 | UserDetails userDetails = userDetailsService.loadUserByUsername(username); 28 | return new PreAuthenticatedAuthenticationToken(username, null, userDetails.getAuthorities()); 29 | } 30 | 31 | @Override 32 | public boolean supports(Class authentication) { 33 | return PreAuthenticatedAuthenticationToken.class.equals(authentication); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.controller; 2 | 3 | import com.wuwii.entity.User; 4 | import com.wuwii.service.UserService; 5 | import com.wuwii.vo.UserAddDTO; 6 | import com.wuwii.vo.UserVO; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.http.ResponseEntity; 11 | import org.springframework.security.access.prepost.PreAuthorize; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * 18 | */ 19 | @RestController 20 | @RequestMapping(value = "/user", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 21 | @PreAuthorize("hasRole('USER')") 22 | public class UserController { 23 | 24 | @Autowired 25 | private UserService userService; 26 | 27 | @GetMapping 28 | @PreAuthorize("hasRole('admin')") 29 | public ResponseEntity> getAllUser() { 30 | List users = userService.findAll(); 31 | List userViews = userService.castUserVO(users); 32 | return ResponseEntity.ok(userViews); 33 | } 34 | 35 | @PostMapping 36 | public ResponseEntity postUser(@RequestBody UserAddDTO userAddDTO) { 37 | userService.insertUser(userAddDTO); 38 | return ResponseEntity.status(HttpStatus.CREATED).build(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/dao/RoleDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.Role; 4 | import org.springframework.data.repository.PagingAndSortingRepository; 5 | 6 | /** 7 | * 8 | */ 9 | public interface RoleDao extends PagingAndSortingRepository { 10 | } 11 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | /** 7 | * 8 | */ 9 | public interface UserDao extends JpaRepository { 10 | User findByUsername(String username); 11 | } 12 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/dao/UserRoleDao.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.dao; 2 | 3 | import com.wuwii.entity.UserRole; 4 | import org.springframework.data.repository.PagingAndSortingRepository; 5 | 6 | /** 7 | * 8 | */ 9 | public interface UserRoleDao extends PagingAndSortingRepository { 10 | } 11 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/entity/Role.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | 7 | /** 8 | * 9 | */ 10 | @Entity 11 | @Data 12 | public class Role { 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | private Long id; 16 | @Column(nullable = false, unique = true) 17 | private String name; 18 | } 19 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | import org.springframework.format.annotation.DateTimeFormat; 5 | 6 | import javax.persistence.*; 7 | import java.util.Date; 8 | import java.util.Set; 9 | 10 | /** 11 | * 12 | */ 13 | @Data 14 | @Entity 15 | public class User { 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | private Long id; 19 | 20 | @Column(unique = true, nullable = false, length = 50) 21 | private String username; 22 | 23 | @Column(nullable = false) 24 | private String password; 25 | 26 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 27 | private Date createDate; 28 | 29 | @OneToMany(targetEntity = UserRole.class, mappedBy = "userId", fetch = FetchType.EAGER) // mappedBy 只有在双向关联的时候设置,表示关系维护的一端,否则会生成中间表A_B 30 | @org.hibernate.annotations.ForeignKey(name = "none") // 注意这里不能使用 @JoinColumn 不然会生成外键 31 | private Set userRoles; 32 | } 33 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/entity/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.entity; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | 7 | /** 8 | * 9 | */ 10 | @Entity 11 | @Data 12 | public class UserRole { 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | private Long id; 16 | 17 | @Column(length = 50, nullable = false) 18 | private Long userId; 19 | 20 | @ManyToOne(targetEntity = Role.class) 21 | @JoinColumn(name = "roleId", nullable = false, foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) 22 | private Role role; 23 | } 24 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import com.wuwii.entity.User; 4 | import com.wuwii.vo.UserAddDTO; 5 | import com.wuwii.vo.UserVO; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 11 | */ 12 | public interface UserService { 13 | UserVO castUserVO(User user); 14 | 15 | List castUserVO(List users); 16 | 17 | List findAll(); 18 | 19 | void insertUser(User user); 20 | 21 | void insertUser(UserAddDTO userAddDTO); 22 | } 23 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service.impl; 2 | 3 | import com.wuwii.dao.UserDao; 4 | import com.wuwii.entity.User; 5 | import com.wuwii.service.UserService; 6 | import com.wuwii.vo.UserAddDTO; 7 | import com.wuwii.vo.UserVO; 8 | import org.springframework.beans.BeanUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.cache.annotation.CacheConfig; 11 | import org.springframework.cache.annotation.Cacheable; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.Date; 16 | import java.util.LinkedList; 17 | import java.util.List; 18 | 19 | /** 20 | * 21 | */ 22 | @Service 23 | @CacheConfig(cacheNames = "users") 24 | public class UserServiceImpl implements UserService { 25 | @Autowired 26 | private UserDao userDao; 27 | @Autowired 28 | private PasswordEncoder passwordEncoder; 29 | 30 | @Override 31 | public UserVO castUserVO(User user) { 32 | return null; 33 | } 34 | 35 | @Override 36 | public List castUserVO(List users) { 37 | List userViews = new LinkedList<>(); 38 | for (User user : users) { 39 | UserVO userView = new UserVO(); 40 | BeanUtils.copyProperties(user, userView); 41 | userViews.add(userView); 42 | } 43 | return userViews; 44 | } 45 | 46 | @Override 47 | @Cacheable 48 | public List findAll() { 49 | return userDao.findAll(); 50 | } 51 | 52 | @Override 53 | public void insertUser(User user) { 54 | user.setCreateDate(new Date()); 55 | user.setPassword(passwordEncoder.encode(user.getPassword())); 56 | userDao.save(user); 57 | } 58 | 59 | @Override 60 | public void insertUser(UserAddDTO userVO) { 61 | User user = new User(); 62 | BeanUtils.copyProperties(userVO, user); 63 | insertUser(user); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/vo/UserAddDTO.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 7 | */ 8 | @Data 9 | public class UserAddDTO { 10 | private String username; 11 | private String password; 12 | } 13 | -------------------------------------------------------------------------------- /springboot-security/src/main/java/com/wuwii/vo/UserVO.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.vo; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 9 | */ 10 | @Data 11 | public class UserVO implements Serializable { 12 | private Long id; 13 | private String username; 14 | } 15 | -------------------------------------------------------------------------------- /springboot-security/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: springboot-security 4 | server: 5 | port: 8666 6 | 7 | spring: 8 | datasource: 9 | url: jdbc:mysql://localhost:3306/learn?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 10 | username: root 11 | password: 123456 12 | driver-class-name: com.mysql.jdbc.Driver 13 | # jackson时间格式化 14 | jackson: 15 | time-zone: GMT+8 16 | date-format: yyyy-MM-dd HH:mm:ss 17 | http: 18 | encoding: 19 | force: true 20 | charset: utf-8 21 | enabled: true 22 | jpa: 23 | show-sql: true 24 | database: mysql 25 | hibernate: 26 | ddl-auto: update 27 | properties: 28 | hibernate: 29 | dialect: org.hibernate.dialect.MySQL57Dialect 30 | cache: 31 | ehcache: 32 | config: config/ehcache.xml # 指定 ehcache.xml 创建EhCache的缓存管理器 33 | type: ehcache # 指定缓存管理器 34 | # jwt 配置 35 | jwt: 36 | # 加密密钥 37 | secret: 61D73234C4F93E03074D74D74D1E39D9 #blog.wuwii.com 38 | # token有效时长 39 | expire: 7 # 7天,单位天 40 | # token 存在 header 中的参数 41 | header: token -------------------------------------------------------------------------------- /springboot-security/src/main/resources/config/ehcache.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 17 | -------------------------------------------------------------------------------- /springboot-security/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Index 6 | 7 | 8 | This is the index.html 9 | 10 | -------------------------------------------------------------------------------- /springboot-security/src/main/resources/static/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 |
9 | 12 | 15 | 16 |
17 | 18 | -------------------------------------------------------------------------------- /springboot-security/src/main/resources/static/logout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | This is the logout.html 9 | 10 | -------------------------------------------------------------------------------- /springboot-security/src/test/java/com/wuwii/SpringbootSecurityApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringbootSecurityApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-security/src/test/java/com/wuwii/password/BCryptPasswordEncoderTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.password; 2 | 3 | import org.junit.Test; 4 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 5 | 6 | /** 7 | * 8 | */ 9 | 10 | public class BCryptPasswordEncoderTest { 11 | 12 | /** 13 | * 获取密码 14 | */ 15 | @Test 16 | public void testEquals() { 17 | BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(5); 18 | String encodePassword = encoder.encode("123456"); 19 | System.out.println(encodePassword); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /template-design-spring/README.md: -------------------------------------------------------------------------------- 1 | 模板模式和策略模式 -------------------------------------------------------------------------------- /template-design-spring/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.wuwii 8 | template-design-spring 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.springframework 14 | spring-context 15 | 4.3.13.RELEASE 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /template-design-spring/src/main/java/com/wuwii/Application.java: -------------------------------------------------------------------------------- 1 | package com.wuwii; 2 | 3 | import com.wuwii.service.AliPay; 4 | import com.wuwii.service.Pay; 5 | import com.wuwii.service.WeChatPay; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 8 | import org.springframework.context.annotation.ComponentScan; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * Created by KronChan on 2018/4/25 10:33. 15 | */ 16 | @Configuration 17 | @ComponentScan(basePackages = {"com.wuwii.service"}) 18 | public class Application { 19 | public static void main(String[] args) { 20 | ApplicationContext context = new AnnotationConfigApplicationContext(Application.class); 21 | Map, Pay> payMethod = Pay.PAY_METHOD; 22 | Pay aliPay = payMethod.get(AliPay.class); 23 | aliPay.pay(12); 24 | Pay weChatPay = payMethod.get(WeChatPay.class); 25 | weChatPay.pay(22); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /template-design-spring/src/main/java/com/wuwii/service/AbstractPay.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import javax.annotation.PostConstruct; 6 | 7 | /** 8 | * Created by KronChan on 2018/4/25 9:37. 9 | */ 10 | @Service 11 | public abstract class AbstractPay implements Pay { 12 | 13 | @PostConstruct 14 | public void init() { 15 | PAY_METHOD.put(this.getClass(), this); 16 | } 17 | 18 | protected boolean check(int money) { 19 | return money > 0; 20 | } 21 | 22 | @Override 23 | public void pay(int money) { 24 | if (check(money)) { 25 | display(money); 26 | } 27 | } 28 | 29 | public abstract void display(int money); 30 | } 31 | -------------------------------------------------------------------------------- /template-design-spring/src/main/java/com/wuwii/service/AliPay.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | /** 6 | * Created by KronChan on 2018/4/25 9:39. 7 | */ 8 | @Service 9 | public class AliPay extends AbstractPay { 10 | @Override 11 | public void display(int money) { 12 | System.out.println("支付宝付款 " + money); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /template-design-spring/src/main/java/com/wuwii/service/Pay.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * Created by KronChan on 2018/4/25 9:35. 8 | */ 9 | public interface Pay { 10 | Map, Pay> PAY_METHOD = new ConcurrentHashMap<>(); 11 | 12 | void pay(int money); 13 | } 14 | -------------------------------------------------------------------------------- /template-design-spring/src/main/java/com/wuwii/service/WeChatPay.java: -------------------------------------------------------------------------------- 1 | package com.wuwii.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | /** 6 | * Created by KronChan on 2018/4/25 9:42. 7 | */ 8 | @Service 9 | public class WeChatPay extends AbstractPay { 10 | @Override 11 | public void display(int money) { 12 | System.out.println("WeChat pay " + money); 13 | } 14 | } 15 | --------------------------------------------------------------------------------