├── src ├── main │ ├── resources │ │ ├── application.properties │ │ ├── db │ │ │ ├── ddl_create_database_01.sql │ │ │ ├── dml_create_user_04.sql │ │ │ ├── dml_create_fund_02.sql │ │ │ └── dml_create_msg_log_03.sql │ │ ├── static │ │ │ └── css │ │ │ │ └── fonts │ │ │ │ └── fonts │ │ │ │ ├── element-icons.ttf │ │ │ │ └── element-icons.woff │ │ ├── templates │ │ │ ├── 404.html │ │ │ ├── error.html │ │ │ └── index.html │ │ └── application-dev.properties │ └── java │ │ └── com │ │ └── wangzaiplus │ │ └── test │ │ ├── designpattern │ │ ├── factory │ │ │ ├── IPay.java │ │ │ ├── ALiPay.java │ │ │ ├── UnionPay.java │ │ │ ├── WeChatPay.java │ │ │ ├── factorymethod │ │ │ │ ├── FactoryMethod.java │ │ │ │ ├── AFactory.java │ │ │ │ ├── BFactory.java │ │ │ │ └── PayService.java │ │ │ ├── PayTypeEnum.java │ │ │ └── simplefactory │ │ │ │ ├── PayFactory.java │ │ │ │ └── PayService.java │ │ ├── strategy │ │ │ ├── PayStrategy.java │ │ │ ├── Main.java │ │ │ ├── WxPayStrategy.java │ │ │ ├── UnionPayStrategy.java │ │ │ ├── AliPayStrategy.java │ │ │ └── PayContext.java │ │ ├── staticproxy │ │ │ ├── PayService.java │ │ │ ├── PayServiceImpl.java │ │ │ ├── Test.java │ │ │ └── PayProxy.java │ │ └── dynamicproxy │ │ │ ├── PayService.java │ │ │ ├── PayServiceImpl.java │ │ │ ├── Test.java │ │ │ └── PayProxy.java │ │ ├── service │ │ ├── strategy │ │ │ ├── CalculateService.java │ │ │ ├── CalculateStrategy.java │ │ │ ├── AddCalculateServiceImpl.java │ │ │ ├── DivideCalculateServiceImpl.java │ │ │ ├── MultiplyCalculateServiceImpl.java │ │ │ ├── SubtractCalculateServiceImpl.java │ │ │ └── CalculateServiceFactory.java │ │ ├── batch │ │ │ ├── BatchProcessMapper.java │ │ │ └── mapperproxy │ │ │ │ └── MapperProxy.java │ │ ├── LoginLogService.java │ │ ├── LoginService.java │ │ ├── TokenService.java │ │ ├── TestService.java │ │ ├── MsgLogService.java │ │ ├── FundService.java │ │ ├── UserService.java │ │ ├── impl │ │ │ ├── LoginLogServiceImpl.java │ │ │ ├── MsgLogServiceImpl.java │ │ │ ├── TestServiceImpl.java │ │ │ ├── TokenServiceImpl.java │ │ │ └── UserServiceImpl.java │ │ ├── threadpool │ │ │ ├── TestJob.java │ │ │ ├── ThreadPoolFactory.java │ │ │ ├── LockSupportTest.java │ │ │ └── Test.java │ │ └── LoginServiceImpl.java │ │ ├── annotation │ │ ├── ColNum.java │ │ ├── ApiIdempotent.java │ │ └── AccessLimit.java │ │ ├── mapper │ │ ├── LoginLogMapper.java │ │ ├── MsgLogMapper.java │ │ ├── UserMapper.java │ │ ├── FundMapper.java │ │ ├── UserMapperWithAnnotation.java │ │ ├── LoginLogMapper.xml │ │ ├── MsgLogMapper.xml │ │ ├── UserMapper.xml │ │ └── FundMapper.xml │ │ ├── dto │ │ ├── FundRankDto.java │ │ ├── FundTypeDto.java │ │ ├── FundYieldDto.java │ │ ├── FundJsonResponseDto.java │ │ ├── SearchFormDto.java │ │ ├── UserDto.java │ │ └── FundDto.java │ │ ├── pojo │ │ ├── CalculateDto.java │ │ ├── LoginLog.java │ │ ├── User.java │ │ ├── Mail.java │ │ ├── Fund.java │ │ └── MsgLog.java │ │ ├── mq │ │ ├── BaseConsumer.java │ │ ├── consumer │ │ │ ├── LoginLogConsumer.java │ │ │ ├── MailConsumer.java │ │ │ └── SimpleMailConsumer.java │ │ ├── MessageHelper.java │ │ ├── listener │ │ │ ├── MailListener.java │ │ │ └── LoginLogListener.java │ │ └── BaseConsumerProxy.java │ │ ├── controller │ │ ├── ViewController.java │ │ ├── Test.java │ │ ├── TokenController.java │ │ ├── LoginController.java │ │ ├── RedissonController.java │ │ ├── UserController.java │ │ ├── FundController.java │ │ ├── StrategyController.java │ │ └── TestController.java │ │ ├── util │ │ ├── PageUtils.java │ │ ├── ConfigUtil.java │ │ ├── ListUtils.java │ │ ├── SpringContextUtil.java │ │ ├── ViewUtils.java │ │ ├── IpUtil.java │ │ ├── RegexUtil.java │ │ ├── SerializableUtil.java │ │ ├── JsonUtil.java │ │ ├── MailUtil.java │ │ ├── BeanUtils.java │ │ ├── RandomUtil.java │ │ ├── JedisUtil.java │ │ ├── OkHttpUtils.java │ │ ├── JodaTimeUtil.java │ │ └── FundUtils.java │ │ ├── exception │ │ ├── ServiceException.java │ │ └── MyControllerAdvice.java │ │ ├── config │ │ ├── RedissonConfig.java │ │ ├── JedisConfig.java │ │ ├── OkHttpConfig.java │ │ └── RabbitConfig.java │ │ ├── common │ │ ├── ResponseCode.java │ │ ├── ServerResponse.java │ │ └── Constant.java │ │ ├── interceptor │ │ ├── ApiIdempotentInterceptor.java │ │ └── AccessLimitInterceptor.java │ │ ├── task │ │ └── ResendMsg.java │ │ └── TestApplication.java └── test │ └── java │ └── com │ └── wangzaiplus │ └── test │ ├── TestApplicationTests.java │ ├── util │ └── MailUtilTest.java │ └── controller │ └── test │ └── TestControllerTest.java ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ ├── maven-wrapper.properties │ └── MavenWrapperDownloader.java ├── .gitignore ├── pom.xml └── mvnw.cmd /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=dev -------------------------------------------------------------------------------- /src/main/resources/db/ddl_create_database_01.sql: -------------------------------------------------------------------------------- 1 | create database test; -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzaiplus/springboot/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /src/main/resources/static/css/fonts/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzaiplus/springboot/HEAD/src/main/resources/static/css/fonts/fonts/element-icons.ttf -------------------------------------------------------------------------------- /src/main/resources/static/css/fonts/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzaiplus/springboot/HEAD/src/main/resources/static/css/fonts/fonts/element-icons.woff -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/IPay.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory; 2 | 3 | public interface IPay { 4 | 5 | boolean pay(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 6 | 7 | 8 | 404 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | error 6 | 7 | 8 | error 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/strategy/PayStrategy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.strategy; 2 | 3 | public interface PayStrategy { 4 | 5 | void pay(String userId); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/strategy/CalculateService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.strategy; 2 | 3 | public interface CalculateService { 4 | 5 | int calculate(int a, int b); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/staticproxy/PayService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.staticproxy; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public interface PayService { 6 | 7 | void pay(String username, BigDecimal money); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/ALiPay.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory; 2 | 3 | public class ALiPay implements IPay{ 4 | 5 | @Override 6 | public boolean pay() { 7 | // 支付相关逻辑... 8 | return true; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/UnionPay.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory; 2 | 3 | public class UnionPay implements IPay{ 4 | 5 | @Override 6 | public boolean pay() { 7 | // 支付相关逻辑... 8 | return true; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/WeChatPay.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory; 2 | 3 | public class WeChatPay implements IPay{ 4 | 5 | @Override 6 | public boolean pay() { 7 | // 支付相关逻辑... 8 | return true; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/annotation/ColNum.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | @Documented 6 | @Retention(RetentionPolicy.RUNTIME) 7 | @Target(ElementType.FIELD) 8 | public @interface ColNum { 9 | 10 | int colNum(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/LoginLogMapper.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mapper; 2 | 3 | import com.wangzaiplus.test.pojo.LoginLog; 4 | 5 | public interface LoginLogMapper { 6 | 7 | void insert(LoginLog loginLog); 8 | 9 | LoginLog selectByMsgId(String msgId); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/batch/BatchProcessMapper.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.batch; 2 | 3 | import java.util.List; 4 | 5 | public interface BatchProcessMapper { 6 | 7 | void batchInsert(List list); 8 | 9 | void batchUpdate(List list); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/LoginLogService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.pojo.LoginLog; 4 | 5 | public interface LoginLogService { 6 | 7 | void insert(LoginLog loginLog); 8 | 9 | LoginLog selectByMsgId(String msgId); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/LoginService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.dto.UserDto; 5 | 6 | public interface LoginService { 7 | 8 | ServerResponse doLogin(UserDto userDto); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/factorymethod/FactoryMethod.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory.factorymethod; 2 | 3 | import com.wangzaiplus.test.designpattern.factory.IPay; 4 | 5 | public interface FactoryMethod { 6 | 7 | IPay createPay(String payType); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/strategy/Main.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.strategy; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | PayContext payContext = new PayContext(); 7 | payContext.pay("3", "aaa"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/dynamicproxy/PayService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.dynamicproxy; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public interface PayService { 6 | 7 | void pay(String username, BigDecimal money); 8 | 9 | void a(); 10 | 11 | void b(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/dto/FundRankDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.dto; 2 | 3 | import lombok.*; 4 | 5 | @Getter 6 | @Setter 7 | @NoArgsConstructor 8 | @AllArgsConstructor 9 | @ToString 10 | @Builder 11 | public class FundRankDto { 12 | 13 | private Integer rank; 14 | private String desc; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/dto/FundTypeDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.dto; 2 | 3 | import lombok.*; 4 | 5 | @Getter 6 | @Setter 7 | @NoArgsConstructor 8 | @AllArgsConstructor 9 | @ToString 10 | @Builder 11 | public class FundTypeDto { 12 | 13 | private Integer type; 14 | private String desc; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/dto/FundYieldDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.dto; 2 | 3 | import lombok.*; 4 | 5 | @Getter 6 | @Setter 7 | @NoArgsConstructor 8 | @AllArgsConstructor 9 | @ToString 10 | @Builder 11 | public class FundYieldDto { 12 | 13 | private String yield; 14 | private String desc; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/pojo/CalculateDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.pojo; 2 | 3 | import lombok.*; 4 | 5 | @Getter 6 | @Setter 7 | @NoArgsConstructor 8 | @AllArgsConstructor 9 | @ToString 10 | @Builder 11 | public class CalculateDto { 12 | 13 | Integer type; 14 | Integer a; 15 | Integer b; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/strategy/WxPayStrategy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.strategy; 2 | 3 | public class WxPayStrategy implements PayStrategy { 4 | 5 | @Override 6 | public void pay(String userId) { 7 | System.out.println("WxPayStrategy userId: " + userId); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/strategy/UnionPayStrategy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.strategy; 2 | 3 | public class UnionPayStrategy implements PayStrategy { 4 | 5 | @Override 6 | public void pay(String userId) { 7 | System.out.println("UnionPayStrategy userId: " + userId); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/BaseConsumer.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import org.springframework.amqp.core.Message; 5 | 6 | import java.io.IOException; 7 | 8 | public interface BaseConsumer { 9 | 10 | void consume(Message message, Channel channel) throws IOException; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/TokenService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | public interface TokenService { 8 | 9 | ServerResponse createToken(); 10 | 11 | void checkToken(HttpServletRequest request); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/dto/FundJsonResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.dto; 2 | 3 | import lombok.*; 4 | 5 | @Getter 6 | @Setter 7 | @NoArgsConstructor 8 | @AllArgsConstructor 9 | @ToString 10 | @Builder 11 | public class FundJsonResponseDto { 12 | 13 | private Integer total; 14 | private Integer pageIndex; 15 | private String data; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/TestService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.pojo.Mail; 5 | 6 | public interface TestService { 7 | 8 | ServerResponse testIdempotence(); 9 | 10 | ServerResponse accessLimit(); 11 | 12 | ServerResponse send(Mail mail); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/factorymethod/AFactory.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory.factorymethod; 2 | 3 | import com.wangzaiplus.test.designpattern.factory.IPay; 4 | 5 | public class AFactory implements FactoryMethod { 6 | 7 | @Override 8 | public IPay createPay(String payType) { 9 | return null; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/factorymethod/BFactory.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory.factorymethod; 2 | 3 | import com.wangzaiplus.test.designpattern.factory.IPay; 4 | 5 | public class BFactory implements FactoryMethod { 6 | 7 | @Override 8 | public IPay createPay(String payType) { 9 | return null; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/ViewController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | 6 | @Controller 7 | public class ViewController { 8 | 9 | @GetMapping("home") 10 | public String index() { 11 | return "index"; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/staticproxy/PayServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.staticproxy; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class PayServiceImpl implements PayService { 6 | 7 | @Override 8 | public void pay(String username, BigDecimal money) { 9 | System.out.println(username + "支付了" + money + "元钱"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/strategy/AliPayStrategy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.strategy; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public class AliPayStrategy implements PayStrategy { 7 | 8 | @Override 9 | public void pay(String userId) { 10 | System.out.println("AliPayStrategy userId: " + userId); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/factorymethod/PayService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory.factorymethod; 2 | 3 | import com.wangzaiplus.test.designpattern.factory.IPay; 4 | 5 | public class PayService { 6 | 7 | public void pay(String payType) { 8 | FactoryMethod aFactory = new AFactory(); 9 | IPay pay = aFactory.createPay(payType); 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/staticproxy/Test.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.staticproxy; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class Test { 6 | 7 | public static void main(String[] args) { 8 | PayService payService = new PayServiceImpl(); 9 | PayProxy payProxy = new PayProxy(payService); 10 | payProxy.pay("马云", BigDecimal.TEN); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/dto/SearchFormDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.dto; 2 | 3 | import lombok.*; 4 | 5 | import java.util.List; 6 | 7 | @Getter 8 | @Setter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @ToString 12 | @Builder 13 | public class SearchFormDto { 14 | 15 | private List typeList; 16 | private List yieldList; 17 | private List rankList; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/wangzaiplus/test/TestApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test; 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 TestApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/annotation/ApiIdempotent.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 在需要保证 接口幂等性 的Controller的方法上使用此注解 10 | */ 11 | @Target({ElementType.METHOD}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface ApiIdempotent { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/MsgLogService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.pojo.MsgLog; 4 | 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | public interface MsgLogService { 9 | 10 | void updateStatus(String msgId, Integer status); 11 | 12 | MsgLog selectByMsgId(String msgId); 13 | 14 | List selectTimeoutMsg(); 15 | 16 | void updateTryCount(String msgId, Date tryTime); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/Test.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import org.springframework.boot.ApplicationArguments; 4 | import org.springframework.boot.ApplicationRunner; 5 | 6 | /** 7 | * TODO 8 | * 9 | * @author: 北瓜 10 | * @date: 2021/8/23 21:40 11 | */ 12 | public class Test implements ApplicationRunner { 13 | 14 | @Override 15 | public void run(ApplicationArguments args) throws Exception { 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/PageUtils.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import org.springframework.beans.BeanUtils; 5 | 6 | import java.util.List; 7 | 8 | public class PageUtils { 9 | 10 | public static PageInfo merge(PageInfo pageInfo, List list) { 11 | PageInfo target = new PageInfo(); 12 | BeanUtils.copyProperties(pageInfo, target); 13 | target.setList(list); 14 | return target; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/wangzaiplus/test/util/MailUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 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 MailUtilTest { 11 | 12 | @Test 13 | public void send() { 14 | } 15 | 16 | @Test 17 | public void sendAttachment() { 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/annotation/AccessLimit.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 在需要保证 接口防刷限流 的Controller的方法上使用此注解 10 | */ 11 | @Target({ElementType.METHOD}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface AccessLimit { 14 | 15 | int maxCount();// 最大访问次数 16 | 17 | int seconds();// 固定时间, 单位: s 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/FundService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.dto.FundDto; 5 | import com.wangzaiplus.test.dto.SearchFormDto; 6 | 7 | import java.util.List; 8 | 9 | public interface FundService { 10 | 11 | ServerResponse rank(FundDto fundDto); 12 | 13 | ServerResponse search(SearchFormDto searchFormDto); 14 | 15 | void update(List list); 16 | 17 | ServerResponse getSearchFormDto(); 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/MsgLogMapper.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mapper; 2 | 3 | import com.wangzaiplus.test.pojo.MsgLog; 4 | import com.wangzaiplus.test.service.batch.BatchProcessMapper; 5 | 6 | import java.util.List; 7 | 8 | public interface MsgLogMapper extends BatchProcessMapper { 9 | 10 | void insert(MsgLog msgLog); 11 | 12 | void updateStatus(MsgLog msgLog); 13 | 14 | List selectTimeoutMsg(); 15 | 16 | void updateTryCount(MsgLog msgLog); 17 | 18 | MsgLog selectByPrimaryKey(String msgId); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/dynamicproxy/PayServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.dynamicproxy; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class PayServiceImpl implements PayService { 6 | 7 | @Override 8 | public void pay(String username, BigDecimal money) { 9 | System.out.println(username + "支付了" + money + "元钱"); 10 | } 11 | 12 | @Override 13 | public void a() { 14 | System.out.println("a"); 15 | } 16 | 17 | @Override 18 | public void b() { 19 | System.out.println("b"); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/strategy/CalculateStrategy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.strategy; 2 | 3 | import com.google.common.collect.Maps; 4 | 5 | import java.util.Map; 6 | 7 | public class CalculateStrategy { 8 | 9 | private static Map map = Maps.newConcurrentMap(); 10 | 11 | public static void register(Integer type, CalculateService calculateService) { 12 | map.put(type, calculateService); 13 | } 14 | 15 | public static CalculateService getCalculateService(Integer type) { 16 | return map.get(type); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/staticproxy/PayProxy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.staticproxy; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class PayProxy implements PayService { 6 | 7 | private PayService payService; 8 | 9 | public PayProxy(PayService payService) { 10 | this.payService = payService; 11 | } 12 | 13 | @Override 14 | public void pay(String username, BigDecimal money) { 15 | System.out.println(username + "发起支付..."); 16 | 17 | payService.pay(username, money); 18 | 19 | System.out.println("支付状态: 成功"); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/PayTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory; 2 | 3 | /** 4 | * 支付方式 5 | */ 6 | public enum PayTypeEnum { 7 | 8 | ALI_PAY("1", "支付宝支付"), 9 | WE_CHAT_PAY("2", "微信支付"), 10 | UNION_PAY("3", "银联支付"), 11 | ; 12 | 13 | private String code; 14 | private String msg; 15 | 16 | PayTypeEnum(String code, String msg) { 17 | this.code = code; 18 | this.msg = msg; 19 | } 20 | 21 | public String getCode() { 22 | return code; 23 | } 24 | 25 | public String getMsg() { 26 | return msg; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/pojo/LoginLog.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.pojo; 2 | 3 | import lombok.*; 4 | 5 | import java.io.Serializable; 6 | import java.util.Date; 7 | 8 | @Getter 9 | @Setter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @ToString 13 | public class LoginLog implements Serializable { 14 | 15 | private static final long serialVersionUID = 9035584359424322830L; 16 | 17 | private Integer id; 18 | private Integer userId; 19 | private Integer type; 20 | private String description; 21 | private Date createTime; 22 | private Date updateTime; 23 | private String msgId;// 消息id 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/pojo/User.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.pojo; 2 | 3 | import lombok.*; 4 | 5 | import java.util.Date; 6 | 7 | @Getter 8 | @Setter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @ToString 12 | @Builder 13 | public class User { 14 | 15 | private Integer id; 16 | private String username; 17 | private String password; 18 | private String passwordSalt; 19 | private String ip; 20 | private String mobile; 21 | private String mail; 22 | private Integer type; 23 | private Integer status; 24 | private Integer isDeleted; 25 | private Date createdTime; 26 | private Date updatedTime; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/dto/UserDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.dto; 2 | 3 | import lombok.*; 4 | 5 | import java.util.Date; 6 | 7 | @Getter 8 | @Setter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @ToString 12 | @Builder 13 | public class UserDto { 14 | 15 | private Integer id; 16 | private String username; 17 | private String password; 18 | private String passwordSalt; 19 | private String ip; 20 | private String mobile; 21 | private String mail; 22 | private Integer type; 23 | private Integer status; 24 | private Integer isDeleted; 25 | private Date createdTime; 26 | private Date updatedTime; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/dynamicproxy/Test.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.dynamicproxy; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class Test { 6 | 7 | public static void main(String[] args) { 8 | // PayService service = new PayServiceImpl(); 9 | // PayProxy payProxy = new PayProxy(service); 10 | // PayService payService = (PayService) payProxy.getProxy(); 11 | // payService.pay("马云", BigDecimal.TEN); 12 | 13 | PayProxy payProxy2 = new PayProxy(new PayServiceImpl()); 14 | PayServiceImpl payService2 = (PayServiceImpl) payProxy2.getPayProxy(); 15 | payService2.pay("马云2", BigDecimal.TEN); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/pojo/Mail.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.pojo; 2 | 3 | import lombok.*; 4 | 5 | import javax.validation.constraints.NotBlank; 6 | import javax.validation.constraints.Pattern; 7 | 8 | @Getter 9 | @Setter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @ToString 13 | @Builder 14 | public class Mail { 15 | 16 | @Pattern(regexp = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$", message = "邮箱格式不正确") 17 | private String to; 18 | 19 | @NotBlank(message = "标题不能为空") 20 | private String title; 21 | 22 | @NotBlank(message = "正文不能为空") 23 | private String content; 24 | 25 | private String msgId;// 消息id 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.pojo.User; 5 | 6 | import java.util.List; 7 | 8 | public interface UserService { 9 | 10 | List getAll(); 11 | 12 | User getOne(Integer id); 13 | 14 | void add(User user); 15 | 16 | void update(User user); 17 | 18 | void delete(Integer id); 19 | 20 | User getByUsernameAndPassword(String username, String password); 21 | 22 | ServerResponse login(String username, String password); 23 | 24 | void batchInsert(List list); 25 | 26 | void batchUpdate(List list); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/strategy/AddCalculateServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.strategy; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import org.springframework.beans.factory.InitializingBean; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service("addCalculateServiceImpl") 8 | public class AddCalculateServiceImpl implements CalculateService, InitializingBean { 9 | 10 | @Override 11 | public int calculate(int a, int b) { 12 | return a + b; 13 | } 14 | 15 | @Override 16 | public void afterPropertiesSet() throws Exception { 17 | CalculateStrategy.register(Constant.CalculateTypeEnum.ADD.getType(), this); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/simplefactory/PayFactory.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory.simplefactory; 2 | 3 | import com.wangzaiplus.test.designpattern.factory.*; 4 | 5 | public class PayFactory { 6 | 7 | public static IPay createPay(String payType) { 8 | if (PayTypeEnum.ALI_PAY.getCode().equals(payType)) { 9 | return new ALiPay(); 10 | } 11 | 12 | if (PayTypeEnum.WE_CHAT_PAY.getCode().equals(payType)) { 13 | return new WeChatPay(); 14 | } 15 | 16 | if (PayTypeEnum.UNION_PAY.getCode().equals(payType)) { 17 | return new UnionPay(); 18 | } 19 | 20 | return null; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/strategy/DivideCalculateServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.strategy; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import org.springframework.beans.factory.InitializingBean; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service("divideCalculateServiceImpl") 8 | public class DivideCalculateServiceImpl implements CalculateService, InitializingBean { 9 | 10 | @Override 11 | public int calculate(int a, int b) { 12 | return a / b; 13 | } 14 | 15 | @Override 16 | public void afterPropertiesSet() throws Exception { 17 | CalculateStrategy.register(Constant.CalculateTypeEnum.DIVIDE.getType(), this); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/strategy/MultiplyCalculateServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.strategy; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import org.springframework.beans.factory.InitializingBean; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service("multiplyCalculateServiceImpl") 8 | public class MultiplyCalculateServiceImpl implements CalculateService, InitializingBean { 9 | 10 | @Override 11 | public int calculate(int a, int b) { 12 | return a * b; 13 | } 14 | 15 | @Override 16 | public void afterPropertiesSet() throws Exception { 17 | CalculateStrategy.register(Constant.CalculateTypeEnum.MULTIPLY.getType(), this); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/strategy/SubtractCalculateServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.strategy; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import org.springframework.beans.factory.InitializingBean; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service("subtractCalculateServiceImpl") 8 | public class SubtractCalculateServiceImpl implements CalculateService, InitializingBean { 9 | 10 | @Override 11 | public int calculate(int a, int b) { 12 | return a - b; 13 | } 14 | 15 | @Override 16 | public void afterPropertiesSet() throws Exception { 17 | CalculateStrategy.register(Constant.CalculateTypeEnum.SUBTRACT.getType(), this); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mapper; 2 | 3 | import com.wangzaiplus.test.pojo.User; 4 | import com.wangzaiplus.test.service.batch.BatchProcessMapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | public interface UserMapper extends BatchProcessMapper { 10 | 11 | List selectAll(); 12 | 13 | User selectOne(Integer id); 14 | 15 | void insert(User user); 16 | 17 | void update(User user); 18 | 19 | void delete(Integer id); 20 | 21 | User selectByUsernameAndPassword(@Param("username") String username, @Param("password") String password); 22 | 23 | User selectByUsername(@Param("username") String username); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/TokenController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.service.TokenService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | @RequestMapping("/token") 12 | public class TokenController { 13 | 14 | @Autowired 15 | private TokenService tokenService; 16 | 17 | @GetMapping 18 | public ServerResponse token() { 19 | return tokenService.createToken(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/impl/LoginLogServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.impl; 2 | 3 | import com.wangzaiplus.test.mapper.LoginLogMapper; 4 | import com.wangzaiplus.test.pojo.LoginLog; 5 | import com.wangzaiplus.test.service.LoginLogService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class LoginLogServiceImpl implements LoginLogService { 11 | 12 | @Autowired 13 | private LoginLogMapper loginLogMapper; 14 | 15 | @Override 16 | public void insert(LoginLog loginLog) { 17 | loginLogMapper.insert(loginLog); 18 | } 19 | 20 | @Override 21 | public LoginLog selectByMsgId(String msgId) { 22 | return loginLogMapper.selectByMsgId(msgId); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/threadpool/TestJob.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.threadpool; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | public class TestJob implements Runnable{ 6 | 7 | private CountDownLatch countDownLatch; 8 | 9 | public TestJob(CountDownLatch countDownLatch) { 10 | this.countDownLatch = countDownLatch; 11 | } 12 | 13 | @Override 14 | public void run() { 15 | try { 16 | System.out.println("开始干活..."); 17 | Thread.sleep(3000); 18 | Test.a = Test.a + 1; 19 | System.out.println("干完了.a: " + Test.a + ", " + countDownLatch.getCount()); 20 | countDownLatch.countDown(); 21 | } catch (InterruptedException e) { 22 | e.printStackTrace(); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/threadpool/ThreadPoolFactory.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.threadpool; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | public class ThreadPoolFactory { 8 | 9 | private static final int testCorePoolSize = 2; 10 | private static final int testMaxPoolSize = 4; 11 | private static final long testKeepAliveTime = 2; 12 | private static final int testBlockingQueueSize = 20; 13 | 14 | public static ThreadPoolExecutor testThreadPool() { 15 | return new ThreadPoolExecutor(testCorePoolSize, 16 | testMaxPoolSize, 17 | testKeepAliveTime, 18 | TimeUnit.SECONDS, new ArrayBlockingQueue(testBlockingQueueSize)); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/db/dml_create_user_04.sql: -------------------------------------------------------------------------------- 1 | drop table if exists t_user; 2 | 3 | create table t_user( 4 | id int not null auto_increment comment '主键', 5 | username varchar(255) not null comment '用户名', 6 | password varchar(255) not null comment '密码', 7 | password_salt varchar(255) not null comment '密码随机盐值', 8 | ip varchar(255) comment 'IP地址', 9 | mobile varchar(11) comment '手机号', 10 | mail varchar(255) comment '邮箱', 11 | type int default 0 not null comment '类型(0:普通用户,1:超级管理员)', 12 | status int default 0 not null comment '状态(0:正常,1:黑名单,2:已注销)', 13 | is_deleted int default 0 not null comment '是否删除(0:有效,1:无效删除)', 14 | created_time datetime default now() not null comment '创建时间', 15 | updated_time datetime default now() not null comment '更新时间', 16 | primary key(id) 17 | ) comment = '用户表'; 18 | 19 | create unique index unq_idx_username on t_user(username); -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/exception/ServiceException.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.exception; 2 | 3 | /** 4 | * 业务逻辑异常 5 | */ 6 | public class ServiceException extends RuntimeException{ 7 | 8 | private String code; 9 | private String msg; 10 | 11 | public ServiceException() { 12 | } 13 | 14 | public ServiceException(String msg) { 15 | this.msg = msg; 16 | } 17 | 18 | public ServiceException(String code, String msg) { 19 | this.code = code; 20 | this.msg = msg; 21 | } 22 | 23 | public String getCode() { 24 | return code; 25 | } 26 | 27 | public void setCode(String code) { 28 | this.code = code; 29 | } 30 | 31 | public String getMsg() { 32 | return msg; 33 | } 34 | 35 | public void setMsg(String msg) { 36 | this.msg = msg; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/pojo/Fund.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.pojo; 2 | 3 | import lombok.*; 4 | 5 | import java.math.BigDecimal; 6 | import java.util.Date; 7 | 8 | @Getter 9 | @Setter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @ToString 13 | @Builder 14 | public class Fund { 15 | 16 | private Integer id; 17 | private String code; 18 | private String name; 19 | private BigDecimal netValue; 20 | private String yieldOfOneYear; 21 | private String yieldOfTwoYear; 22 | private String yieldOfThreeYear; 23 | private String yieldOfFiveYear; 24 | private int type; 25 | private Date establishedTime; 26 | private String asset; 27 | private String manager; 28 | private Integer status; 29 | private Integer isDeleted; 30 | private Date createdTime; 31 | private Date updatedTime; 32 | 33 | private Integer tempRank; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/FundMapper.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mapper; 2 | 3 | import com.wangzaiplus.test.dto.FundDto; 4 | import com.wangzaiplus.test.pojo.Fund; 5 | import com.wangzaiplus.test.service.batch.BatchProcessMapper; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface FundMapper extends BatchProcessMapper { 12 | 13 | List selectAll(); 14 | 15 | Fund selectOne(Integer id); 16 | 17 | void insert(Fund fund); 18 | 19 | void update(Fund fund); 20 | 21 | void delete(Integer id); 22 | 23 | Fund selectByCodeAndType(Fund fund); 24 | 25 | List selectByType(FundDto fundDto); 26 | 27 | List selectTempRankByType(FundDto fundDto); 28 | 29 | List selectFundTypeList(); 30 | 31 | List selectByNameOrCode(FundDto fundDto); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/ConfigUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.util.Properties; 6 | 7 | public class ConfigUtil { 8 | 9 | public ConfigUtil() { 10 | } 11 | 12 | private static Properties props = new Properties(); 13 | 14 | static { 15 | try { 16 | props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("application.properties")); 17 | } catch (FileNotFoundException e) { 18 | e.printStackTrace(); 19 | } catch (IOException e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | 24 | public static String getValue(String key) { 25 | return props.getProperty(key); 26 | } 27 | 28 | public static void updateProperties(String key, String value) { 29 | props.setProperty(key, value); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/wangzaiplus/test/controller/test/TestControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller.test; 2 | 3 | import org.junit.Test; 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.boot.test.web.client.TestRestTemplate; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | @RunWith(SpringRunner.class) 11 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 12 | public class TestControllerTest { 13 | 14 | @Autowired 15 | private TestRestTemplate testRestTemplate; 16 | 17 | @Test 18 | public void testLogin() { 19 | for (int i = 0; i < 100; i++) { 20 | testRestTemplate.postForObject("/user/login?username={username}&password={password}", null, String.class, "wangzaiplus", "123456"); 21 | } 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/config/RedissonConfig.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.config; 2 | 3 | import org.redisson.Redisson; 4 | import org.redisson.api.RedissonClient; 5 | import org.redisson.config.Config; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class RedissonConfig { 12 | 13 | @Value("${spring.redis.host}") 14 | private String host; 15 | 16 | @Value("${spring.redis.port}") 17 | private String port; 18 | 19 | @Value("${spring.redis.password}") 20 | private String password; 21 | 22 | @Bean 23 | public RedissonClient redissonClient() { 24 | Config config = new Config(); 25 | config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password); 26 | return Redisson.create(config); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/LoginController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.dto.UserDto; 5 | import com.wangzaiplus.test.service.LoginService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | @RequestMapping("/login") 15 | @Slf4j 16 | public class LoginController { 17 | 18 | @Autowired 19 | private LoginService loginService; 20 | 21 | @PostMapping("/doLogin") 22 | public ServerResponse doLogin(@RequestBody UserDto userDto) { 23 | return loginService.doLogin(userDto); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/factory/simplefactory/PayService.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.factory.simplefactory; 2 | 3 | import com.wangzaiplus.test.designpattern.factory.IPay; 4 | import com.wangzaiplus.test.exception.ServiceException; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | public class PayService { 8 | 9 | public void pay(String payType) { 10 | if (StringUtils.isBlank(payType)) { 11 | throw new ServiceException("支付方式异常"); 12 | } 13 | 14 | boolean isPaySuccess = isPaySuccess(payType); 15 | if (isPaySuccess) { 16 | // 巴拉巴拉 17 | } else { 18 | // 巴拉巴拉 19 | } 20 | } 21 | 22 | private boolean isPaySuccess(String payType) { 23 | IPay iPay = PayFactory.createPay(payType); 24 | if (null == iPay) { 25 | throw new ServiceException("支付方式异常"); 26 | } 27 | 28 | return iPay.pay(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/ListUtils.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import org.apache.commons.collections4.CollectionUtils; 5 | 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | public class ListUtils { 10 | 11 | public List intersection(List> lists, boolean removeDuplication) { 12 | if (CollectionUtils.isEmpty(lists)) { 13 | return null; 14 | } 15 | 16 | int size = lists.size(); 17 | List list = lists.get(Constant.INDEX_ZERO); 18 | if (size == Constant.NUMBER_ONE) { 19 | return list; 20 | } 21 | 22 | for (int i = 1; i < size; i++) { 23 | list.retainAll(lists.get(i)); 24 | } 25 | 26 | if (removeDuplication) { 27 | list = list.stream().distinct().collect(Collectors.toList()); 28 | } 29 | 30 | return list; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/consumer/LoginLogConsumer.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq.consumer; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import com.wangzaiplus.test.mq.BaseConsumer; 5 | import com.wangzaiplus.test.mq.MessageHelper; 6 | import com.wangzaiplus.test.pojo.LoginLog; 7 | import com.wangzaiplus.test.service.LoginLogService; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.amqp.core.Message; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | @Slf4j 15 | public class LoginLogConsumer implements BaseConsumer { 16 | 17 | @Autowired 18 | private LoginLogService loginLogService; 19 | 20 | @Override 21 | public void consume(Message message, Channel channel) { 22 | log.info("收到消息: {}", message.toString()); 23 | LoginLog loginLog = MessageHelper.msgToObj(message, LoginLog.class); 24 | loginLogService.insert(loginLog); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/exception/MyControllerAdvice.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.exception; 2 | 3 | import com.wangzaiplus.test.common.ResponseCode; 4 | import com.wangzaiplus.test.common.ServerResponse; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | 10 | @ControllerAdvice 11 | @Slf4j 12 | public class MyControllerAdvice { 13 | 14 | @ResponseBody 15 | @ExceptionHandler(ServiceException.class) 16 | public ServerResponse serviceExceptionHandler(ServiceException se) { 17 | return ServerResponse.error(se.getMsg()); 18 | } 19 | 20 | @ResponseBody 21 | @ExceptionHandler(Exception.class) 22 | public ServerResponse exceptionHandler(Exception e) { 23 | log.error("Exception: ", e); 24 | return ServerResponse.error(ResponseCode.SERVER_ERROR.getMsg()); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/threadpool/LockSupportTest.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.threadpool; 2 | 3 | import java.util.concurrent.locks.LockSupport; 4 | 5 | public class LockSupportTest { 6 | 7 | private static final char[] a = "abcd".toCharArray(); 8 | private static final char[] A = "ABCD".toCharArray(); 9 | 10 | private static Thread aThread; 11 | private static Thread AThread; 12 | 13 | public static void main(String[] args) { 14 | aThread = new Thread(() -> { 15 | for (char c : a) { 16 | System.out.println(c); 17 | LockSupport.unpark(AThread); 18 | LockSupport.park(); 19 | } 20 | }); 21 | 22 | AThread = new Thread(() -> { 23 | for (char c : A) { 24 | LockSupport.park(); 25 | System.out.println(c); 26 | LockSupport.unpark(aThread); 27 | } 28 | }); 29 | 30 | aThread.start(); 31 | AThread.start(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/SpringContextUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class SpringContextUtil implements ApplicationContextAware { 10 | 11 | private static ApplicationContext applicationContext; 12 | 13 | @Override 14 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 15 | SpringContextUtil.applicationContext = applicationContext; 16 | } 17 | 18 | public static ApplicationContext getApplicationContext() { 19 | return applicationContext; 20 | } 21 | 22 | public static Object getBean(String name) { 23 | return applicationContext.getBean(name); 24 | } 25 | 26 | public static T getBean(Class clazz) { 27 | return applicationContext.getBean(clazz); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/threadpool/Test.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.threadpool; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | 6 | public class Test { 7 | 8 | public static volatile int a = 0; 9 | 10 | public static void main(String[] args) { 11 | doJob(); 12 | } 13 | 14 | private static void doJob() { 15 | CountDownLatch countDownLatch = new CountDownLatch(5); 16 | ThreadPoolExecutor pool = ThreadPoolFactory.testThreadPool(); 17 | for (int i = 0; i < 5; i++) { 18 | System.out.println(a); 19 | if (a >= 3) { 20 | System.out.println("over"); 21 | break; 22 | } 23 | 24 | pool.execute(new TestJob(countDownLatch)); 25 | } 26 | 27 | try { 28 | countDownLatch.await(); 29 | } catch (InterruptedException e) { 30 | e.printStackTrace(); 31 | } 32 | pool.shutdown(); 33 | 34 | System.out.println("doJob end"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/consumer/MailConsumer.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq.consumer; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import com.wangzaiplus.test.exception.ServiceException; 5 | import com.wangzaiplus.test.mq.BaseConsumer; 6 | import com.wangzaiplus.test.mq.MessageHelper; 7 | import com.wangzaiplus.test.pojo.Mail; 8 | import com.wangzaiplus.test.util.MailUtil; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.amqp.core.Message; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | @Component 15 | @Slf4j 16 | public class MailConsumer implements BaseConsumer { 17 | 18 | @Autowired 19 | private MailUtil mailUtil; 20 | 21 | public void consume(Message message, Channel channel) { 22 | Mail mail = MessageHelper.msgToObj(message, Mail.class); 23 | log.info("收到消息: {}", mail.toString()); 24 | 25 | boolean success = mailUtil.send(mail); 26 | if (!success) { 27 | throw new ServiceException("send mail error"); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/dynamicproxy/PayProxy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.dynamicproxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | 7 | public class PayProxy { 8 | 9 | private Object target; 10 | 11 | public PayProxy(Object target) { 12 | this.target = target; 13 | } 14 | 15 | public Object getPayProxy() { 16 | ClassLoader classLoader = target.getClass().getClassLoader(); 17 | Class[] interfaces = target.getClass().getInterfaces(); 18 | 19 | Object proxy = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() { 20 | @Override 21 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 22 | System.out.println("start..."); 23 | 24 | Object result = method.invoke(target, args); 25 | 26 | System.out.println("stop"); 27 | return result; 28 | } 29 | }); 30 | 31 | return proxy; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/db/dml_create_fund_02.sql: -------------------------------------------------------------------------------- 1 | drop table if exists fund; 2 | 3 | create table fund( 4 | id int not null auto_increment comment '主键', 5 | code varchar(255) not null comment '基金代码', 6 | name varchar(255) not null comment '基金名称', 7 | net_value decimal(10, 4) not null comment '单位净值', 8 | yield_of_one_year varchar(255) not null comment '近1年收益率', 9 | yield_of_two_year varchar(255) not null comment '近2年收益率', 10 | yield_of_three_year varchar(255) not null comment '近3年收益率', 11 | yield_of_five_year varchar(255) not null comment '近5年收益率', 12 | type int not null comment '基金类型(1:股票型,2:混合型,3:债券型,4:指数型,5:QDII)', 13 | established_time datetime comment '成立时间', 14 | asset varchar(255) comment '基金规模,资产', 15 | manager varchar(255) comment '基金经理', 16 | status int default 1 not null comment '基金状态(1:正常开放,2:暂停交易)', 17 | is_deleted int default 0 not null comment '是否删除(0:有效,1:无效删除)', 18 | created_time datetime default now() not null comment '创建时间', 19 | updated_time datetime default now() not null comment '更新时间', 20 | primary key(id) 21 | ) comment = '基金表'; 22 | 23 | create unique index unq_idx_type_code on fund(type, code); 24 | create index idx_type_name_code on fund(type, name, code); -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/MessageHelper.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq; 2 | 3 | import com.wangzaiplus.test.util.JsonUtil; 4 | import org.springframework.amqp.core.Message; 5 | import org.springframework.amqp.core.MessageBuilder; 6 | import org.springframework.amqp.core.MessageDeliveryMode; 7 | import org.springframework.amqp.core.MessageProperties; 8 | 9 | public class MessageHelper { 10 | 11 | public static Message objToMsg(Object obj) { 12 | if (null == obj) { 13 | return null; 14 | } 15 | 16 | Message message = MessageBuilder.withBody(JsonUtil.objToStr(obj).getBytes()).build(); 17 | message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);// 消息持久化 18 | message.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON); 19 | 20 | return message; 21 | } 22 | 23 | public static T msgToObj(Message message, Class clazz) { 24 | if (null == message || null == clazz) { 25 | return null; 26 | } 27 | 28 | String str = new String(message.getBody()); 29 | T obj = JsonUtil.strToObj(str, clazz); 30 | 31 | return obj; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/designpattern/strategy/PayContext.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.designpattern.strategy; 2 | 3 | import com.wangzaiplus.test.designpattern.factory.PayTypeEnum; 4 | import com.wangzaiplus.test.exception.ServiceException; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | //@Component 12 | public class PayContext { 13 | 14 | // @Autowired 15 | // private Map map; 16 | 17 | private static Map map2 = new ConcurrentHashMap<>(); 18 | static { 19 | map2.put(PayTypeEnum.ALI_PAY.getCode(), new AliPayStrategy()); 20 | map2.put(PayTypeEnum.WE_CHAT_PAY.getCode(), new WxPayStrategy()); 21 | map2.put(PayTypeEnum.UNION_PAY.getCode(), new UnionPayStrategy()); 22 | } 23 | 24 | public void pay(String payType, String userId) { 25 | PayStrategy payStrategy = map2.get(payType); 26 | if (null == payStrategy) { 27 | throw new ServiceException("payType: " + payType + " not supported"); 28 | } 29 | 30 | payStrategy.pay(userId); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/UserMapperWithAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mapper; 2 | 3 | import com.wangzaiplus.test.pojo.User; 4 | import org.apache.ibatis.annotations.*; 5 | import org.apache.ibatis.type.JdbcType; 6 | 7 | import java.util.List; 8 | 9 | public interface UserMapperWithAnnotation { 10 | 11 | @Select("select * from user") 12 | @Results({ 13 | @Result(property = "username", column = "username", jdbcType = JdbcType.VARCHAR), 14 | @Result(property = "password", column = "password") 15 | }) 16 | List selectAll(); 17 | 18 | @Select("select * from user where id = #{id}") 19 | @Results({ 20 | @Result(property = "username", column = "username", jdbcType = JdbcType.VARCHAR), 21 | @Result(property = "password", column = "password") 22 | }) 23 | User selectOne(Integer id); 24 | 25 | @Insert("insert into user(username, password) values(#{username}, #{password})") 26 | void insert(User user); 27 | 28 | @Update("update user set username=#{username}, password=#{password} where id = #{id}") 29 | void update(User user); 30 | 31 | @Delete("delete from user where id = #{id}") 32 | void delete(Integer id); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/pojo/MsgLog.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.pojo; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import com.wangzaiplus.test.util.JodaTimeUtil; 5 | import com.wangzaiplus.test.util.JsonUtil; 6 | import lombok.*; 7 | 8 | import java.util.Date; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @ToString 15 | public class MsgLog { 16 | 17 | private String msgId; 18 | private String msg; 19 | private String exchange; 20 | private String routingKey; 21 | private Integer status; 22 | private Integer tryCount; 23 | private Date nextTryTime; 24 | private Date createTime; 25 | private Date updateTime; 26 | 27 | public MsgLog(String msgId, Object msg, String exchange, String routingKey) { 28 | this.msgId = msgId; 29 | this.msg = JsonUtil.objToStr(msg); 30 | this.exchange = exchange; 31 | this.routingKey = routingKey; 32 | 33 | this.status = Constant.MsgLogStatus.DELIVERING; 34 | this.tryCount = 0; 35 | 36 | Date date = new Date(); 37 | this.createTime = date; 38 | this.updateTime = date; 39 | this.nextTryTime = (JodaTimeUtil.plusMinutes(date, 1)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/ViewUtils.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | public class ViewUtils { 6 | 7 | private static final String VIEW_PREFIX = "/templates"; 8 | private static final String VIEW_SUFFIX = ".html"; 9 | 10 | private static final String ERROR = "error"; 11 | private static final String NOT_FOUND = "404"; 12 | 13 | private static final String TO_ERROR = "/common/error"; 14 | private static final String TO_404 = "/common/404"; 15 | 16 | private static final String ERROR_PAGE = VIEW_PREFIX + TO_ERROR + VIEW_SUFFIX; 17 | private static final String NOT_FOUND_PAGE = VIEW_PREFIX + TO_404 + VIEW_SUFFIX; 18 | 19 | private static final String PATH_SEPARATOR = "/"; 20 | 21 | public static String to(String view) { 22 | if (StringUtils.isBlank(view) || ERROR.equals(view)) { 23 | return ERROR_PAGE; 24 | } 25 | 26 | if (NOT_FOUND.equals(view)) { 27 | return NOT_FOUND_PAGE; 28 | } 29 | 30 | if (!view.startsWith(PATH_SEPARATOR)) { 31 | view = PATH_SEPARATOR + view; 32 | } 33 | 34 | return VIEW_PREFIX + view + VIEW_SUFFIX; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/IpUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | public class IpUtil { 6 | 7 | /** 8 | * 获取客户端真实ip地址 9 | * 10 | * @param request 11 | * @return 12 | */ 13 | public static String getIpAddress(HttpServletRequest request) { 14 | String ip = request.getHeader("x-forwarded-for"); 15 | 16 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 17 | ip = request.getHeader("Proxy-Client-IP"); 18 | } 19 | 20 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 21 | ip = request.getHeader("WL-Proxy-Client-IP"); 22 | } 23 | 24 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 25 | ip = request.getHeader("HTTP_CLIENT_IP"); 26 | } 27 | 28 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 29 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 30 | } 31 | 32 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 33 | ip = request.getRemoteAddr(); 34 | } 35 | 36 | return ip; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/common/ResponseCode.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.common; 2 | 3 | /** 4 | * 响应状态码 5 | */ 6 | public enum ResponseCode { 7 | 8 | // 系统模块 9 | SUCCESS(0, "操作成功"), 10 | ERROR(1, "操作失败"), 11 | SERVER_ERROR(500, "服务器异常"), 12 | 13 | // 通用模块 1xxxx 14 | ILLEGAL_ARGUMENT(10000, "参数不合法"), 15 | REPETITIVE_OPERATION(10001, "请勿重复操作"), 16 | ACCESS_LIMIT(10002, "请求太频繁, 请稍后再试"), 17 | MAIL_SEND_SUCCESS(10003, "邮件发送成功"), 18 | 19 | // 用户模块 2xxxx 20 | NEED_LOGIN(20001, "登录失效"), 21 | USERNAME_OR_PASSWORD_EMPTY(20002, "用户名或密码不能为空"), 22 | USERNAME_OR_PASSWORD_WRONG(20003, "用户名或密码错误"), 23 | USER_NOT_EXISTS(20004, "用户不存在"), 24 | WRONG_PASSWORD(20005, "密码错误"), 25 | 26 | // 订单模块 4xxxx 27 | 28 | ; 29 | 30 | ResponseCode(Integer code, String msg) { 31 | this.code = code; 32 | this.msg = msg; 33 | } 34 | 35 | private Integer code; 36 | 37 | private String msg; 38 | 39 | public Integer getCode() { 40 | return code; 41 | } 42 | 43 | public void setCode(Integer code) { 44 | this.code = code; 45 | } 46 | 47 | public String getMsg() { 48 | return msg; 49 | } 50 | 51 | public void setMsg(String msg) { 52 | this.msg = msg; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/listener/MailListener.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq.listener; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import com.wangzaiplus.test.config.RabbitConfig; 5 | import com.wangzaiplus.test.mq.BaseConsumer; 6 | import com.wangzaiplus.test.mq.BaseConsumerProxy; 7 | import com.wangzaiplus.test.mq.consumer.MailConsumer; 8 | import com.wangzaiplus.test.service.MsgLogService; 9 | import org.springframework.amqp.core.Message; 10 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.io.IOException; 15 | 16 | @Component 17 | public class MailListener { 18 | 19 | @Autowired 20 | private MailConsumer mailConsumer; 21 | 22 | @Autowired 23 | private MsgLogService msgLogService; 24 | 25 | @RabbitListener(queues = RabbitConfig.MAIL_QUEUE_NAME) 26 | public void consume(Message message, Channel channel) throws IOException { 27 | BaseConsumerProxy baseConsumerProxy = new BaseConsumerProxy(mailConsumer, msgLogService); 28 | BaseConsumer proxy = (BaseConsumer) baseConsumerProxy.getProxy(); 29 | if (null != proxy) { 30 | proxy.consume(message, channel); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/listener/LoginLogListener.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq.listener; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import com.wangzaiplus.test.config.RabbitConfig; 5 | import com.wangzaiplus.test.mq.BaseConsumer; 6 | import com.wangzaiplus.test.mq.BaseConsumerProxy; 7 | import com.wangzaiplus.test.mq.consumer.LoginLogConsumer; 8 | import com.wangzaiplus.test.service.MsgLogService; 9 | import org.springframework.amqp.core.Message; 10 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.io.IOException; 15 | 16 | @Component 17 | public class LoginLogListener { 18 | 19 | @Autowired 20 | private LoginLogConsumer loginLogConsumer; 21 | 22 | @Autowired 23 | private MsgLogService msgLogService; 24 | 25 | @RabbitListener(queues = RabbitConfig.LOGIN_LOG_QUEUE_NAME) 26 | public void consume(Message message, Channel channel) throws IOException { 27 | BaseConsumerProxy baseConsumerProxy = new BaseConsumerProxy(loginLogConsumer, msgLogService); 28 | BaseConsumer proxy = (BaseConsumer) baseConsumerProxy.getProxy(); 29 | if (null != proxy) { 30 | proxy.consume(message, channel); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/LoginServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service; 2 | 3 | import com.wangzaiplus.test.common.ResponseCode; 4 | import com.wangzaiplus.test.common.ServerResponse; 5 | import com.wangzaiplus.test.dto.UserDto; 6 | import com.wangzaiplus.test.mapper.UserMapper; 7 | import com.wangzaiplus.test.pojo.User; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | @Slf4j 15 | public class LoginServiceImpl implements LoginService { 16 | 17 | @Autowired 18 | private UserMapper userMapper; 19 | 20 | @Override 21 | public ServerResponse doLogin(UserDto userDto) { 22 | String username = userDto.getUsername(); 23 | String password = userDto.getPassword(); 24 | 25 | if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { 26 | return ServerResponse.error(ResponseCode.USERNAME_OR_PASSWORD_EMPTY.getMsg()); 27 | } 28 | 29 | User user = userMapper.selectByUsernameAndPassword(username, password); 30 | if (null == user) { 31 | return ServerResponse.error(ResponseCode.USERNAME_OR_PASSWORD_WRONG.getMsg()); 32 | } 33 | return null; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/config/JedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.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 redis.clients.jedis.JedisPool; 7 | import redis.clients.jedis.JedisPoolConfig; 8 | 9 | @Configuration 10 | public class JedisConfig { 11 | 12 | @Value("${spring.redis.host}") 13 | private String host; 14 | 15 | @Value("${spring.redis.port}") 16 | private int port; 17 | 18 | @Value("${spring.redis.password}") 19 | private String password; 20 | 21 | @Value("${spring.redis.jedis.pool.max-idle}") 22 | private int maxIdle; 23 | 24 | @Value("${spring.redis.jedis.pool.max-wait}") 25 | private long maxWait; 26 | 27 | @Value("${spring.redis.jedis.pool.min-idle}") 28 | private int minIdle; 29 | 30 | @Value("${spring.redis.timeout}") 31 | private int timeout; 32 | 33 | @Bean 34 | public JedisPool redisPoolFactory() { 35 | JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); 36 | jedisPoolConfig.setMaxIdle(maxIdle); 37 | jedisPoolConfig.setMaxWaitMillis(maxWait); 38 | jedisPoolConfig.setMinIdle(minIdle); 39 | 40 | JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password); 41 | 42 | return jedisPool; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/batch/mapperproxy/MapperProxy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.batch.mapperproxy; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.wangzaiplus.test.service.batch.BatchProcessMapper; 5 | import org.apache.commons.collections4.CollectionUtils; 6 | 7 | import java.util.List; 8 | 9 | import static com.wangzaiplus.test.common.Constant.MAX_SIZE_PER_TIME; 10 | 11 | public class MapperProxy implements BatchProcessMapper { 12 | 13 | private BatchProcessMapper batchProcessMapper; 14 | 15 | public MapperProxy(BatchProcessMapper batchProcessMapper) { 16 | this.batchProcessMapper = batchProcessMapper; 17 | } 18 | 19 | @Override 20 | public void batchInsert(List list) { 21 | if (CollectionUtils.isEmpty(list)) { 22 | return; 23 | } 24 | 25 | List> partition = Lists.partition(list, MAX_SIZE_PER_TIME); 26 | for (List batchList : partition) { 27 | batchProcessMapper.batchInsert(batchList); 28 | } 29 | } 30 | 31 | @Override 32 | public void batchUpdate(List list) { 33 | if (CollectionUtils.isEmpty(list)) { 34 | return; 35 | } 36 | 37 | List> partition = Lists.partition(list, MAX_SIZE_PER_TIME); 38 | for (List batchList : partition) { 39 | batchProcessMapper.batchUpdate(batchList); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/LoginLogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | id, user_id, type, description, create_time, update_time 15 | 16 | 17 | 18 | INSERT INTO login_log(user_id, type, description, create_time, update_time) 19 | VALUES (#{userId}, #{type}, #{description}, #{createTime}, #{updateTime}) 20 | 21 | 22 | 27 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/RedissonController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import org.redisson.api.RLock; 4 | import org.redisson.api.RedissonClient; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.concurrent.TimeUnit; 10 | 11 | @RestController 12 | @RequestMapping("/redisson") 13 | public class RedissonController { 14 | 15 | @Autowired(required = false) 16 | private RedissonClient redissonClient; 17 | 18 | @RequestMapping("testRedisson") 19 | public String testRedisson() { 20 | RLock lock = redissonClient.getLock("testRedissonLock"); 21 | boolean locked = false; 22 | try { 23 | locked = lock.tryLock(0, 10, TimeUnit.SECONDS); 24 | if (locked) { 25 | Thread.sleep(30000); 26 | return "ok......................................."; 27 | } else { 28 | return "获取锁失败......................................."; 29 | } 30 | } catch (InterruptedException e) { 31 | e.printStackTrace(); 32 | return "获取锁异常......................................."; 33 | } finally { 34 | if (!locked) { 35 | return "获取锁失败"; 36 | } 37 | lock.unlock(); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/impl/MsgLogServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.impl; 2 | 3 | import com.wangzaiplus.test.mapper.MsgLogMapper; 4 | import com.wangzaiplus.test.pojo.MsgLog; 5 | import com.wangzaiplus.test.service.MsgLogService; 6 | import com.wangzaiplus.test.util.JodaTimeUtil; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | @Service 14 | public class MsgLogServiceImpl implements MsgLogService { 15 | 16 | @Autowired 17 | private MsgLogMapper msgLogMapper; 18 | 19 | @Override 20 | public void updateStatus(String msgId, Integer status) { 21 | MsgLog msgLog = new MsgLog(); 22 | msgLog.setMsgId(msgId); 23 | msgLog.setStatus(status); 24 | msgLog.setUpdateTime(new Date()); 25 | msgLogMapper.updateStatus(msgLog); 26 | } 27 | 28 | @Override 29 | public MsgLog selectByMsgId(String msgId) { 30 | return msgLogMapper.selectByPrimaryKey(msgId); 31 | } 32 | 33 | @Override 34 | public List selectTimeoutMsg() { 35 | return msgLogMapper.selectTimeoutMsg(); 36 | } 37 | 38 | @Override 39 | public void updateTryCount(String msgId, Date tryTime) { 40 | Date nextTryTime = JodaTimeUtil.plusMinutes(tryTime, 1); 41 | 42 | MsgLog msgLog = new MsgLog(); 43 | msgLog.setMsgId(msgId); 44 | msgLog.setNextTryTime(nextTryTime); 45 | 46 | msgLogMapper.updateTryCount(msgLog); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/resources/db/dml_create_msg_log_03.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT, 3 | `username` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', 4 | `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `unq_username` (`username`) 7 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 8 | 9 | CREATE TABLE `login_log` ( 10 | `id` int(11) NOT NULL AUTO_INCREMENT, 11 | `user_id` int(11) NOT NULL COMMENT '用户id', 12 | `type` int(11) NOT NULL COMMENT '日志类型:1登录 2登出', 13 | `description` varchar(255) DEFAULT NULL COMMENT '日志描述', 14 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 15 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 16 | PRIMARY KEY (`id`) 17 | ) ENGINE=InnoDB AUTO_INCREMENT=2045 DEFAULT CHARSET=utf8mb4 COMMENT='登录日志表'; 18 | 19 | CREATE TABLE `msg_log` ( 20 | `msg_id` varchar(255) NOT NULL DEFAULT '' COMMENT '消息唯一标识', 21 | `msg` text COMMENT '消息体, json格式化', 22 | `exchange` varchar(255) NOT NULL DEFAULT '' COMMENT '交换机', 23 | `routing_key` varchar(255) NOT NULL DEFAULT '' COMMENT '路由键', 24 | `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态: 0投递中 1投递成功 2投递失败 3已消费', 25 | `try_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数', 26 | `next_try_time` datetime DEFAULT NULL COMMENT '下一次重试时间', 27 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 28 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 29 | PRIMARY KEY (`msg_id`), 30 | UNIQUE KEY `unq_msg_id` (`msg_id`) USING BTREE 31 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息投递日志'; 32 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.pojo.User; 5 | import com.wangzaiplus.test.service.UserService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | @RequestMapping("/user") 13 | public class UserController { 14 | 15 | @Autowired 16 | private UserService userService; 17 | 18 | @GetMapping("users") 19 | public String getAll() { 20 | List users = userService.getAll(); 21 | return users.toString(); 22 | } 23 | 24 | @GetMapping("{id}") 25 | public String getOne(@PathVariable Integer id) { 26 | User user = userService.getOne(id); 27 | if (null != user) { 28 | return user.toString(); 29 | } else { 30 | return "not exists"; 31 | } 32 | } 33 | 34 | @PostMapping 35 | public String add(User user) { 36 | userService.add(user); 37 | return "nice"; 38 | } 39 | 40 | @PutMapping 41 | public String update(User user) { 42 | userService.update(user); 43 | return "nice"; 44 | } 45 | 46 | @DeleteMapping("{id}") 47 | public String delete(@PathVariable Integer id) { 48 | userService.delete(id); 49 | return "nice"; 50 | } 51 | 52 | @PostMapping("login") 53 | public ServerResponse login(String username, String password) { 54 | return userService.login(username, password); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/strategy/CalculateServiceFactory.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.strategy; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import com.wangzaiplus.test.exception.ServiceException; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Qualifier; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class CalculateServiceFactory { 11 | 12 | @Autowired 13 | @Qualifier("addCalculateServiceImpl") 14 | private CalculateService addCalculateServiceImpl; 15 | 16 | @Autowired 17 | @Qualifier("subtractCalculateServiceImpl") 18 | private CalculateService subtractCalculateServiceImpl; 19 | 20 | @Autowired 21 | @Qualifier("multiplyCalculateServiceImpl") 22 | private CalculateService multiplyCalculateServiceImpl; 23 | 24 | @Autowired 25 | @Qualifier("divideCalculateServiceImpl") 26 | private CalculateService divideCalculateServiceImpl; 27 | 28 | public CalculateService getCalculateService(Integer type) { 29 | CalculateService calculateService; 30 | 31 | if (Constant.CalculateTypeEnum.ADD.getType().equals(type)) { 32 | calculateService = addCalculateServiceImpl; 33 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 34 | calculateService = subtractCalculateServiceImpl; 35 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 36 | calculateService = multiplyCalculateServiceImpl; 37 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 38 | calculateService = divideCalculateServiceImpl; 39 | } else { 40 | throw new ServiceException("type error: " + type); 41 | } 42 | 43 | return calculateService; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/FundController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import com.wangzaiplus.test.common.ServerResponse; 4 | import com.wangzaiplus.test.dto.FundDto; 5 | import com.wangzaiplus.test.dto.SearchFormDto; 6 | import com.wangzaiplus.test.service.FundService; 7 | import com.wangzaiplus.test.util.FundUtils; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.util.List; 16 | 17 | @RestController 18 | @RequestMapping("/fund") 19 | @Slf4j 20 | public class FundController { 21 | 22 | @Autowired 23 | private FundService fundService; 24 | 25 | @PostMapping("getFundDtoList") 26 | public ServerResponse getFundDtoList(@RequestBody FundDto fundDto) { 27 | List fundDtoList = FundUtils.getFundDtoList(fundDto.getType()); 28 | fundService.update(fundDtoList); 29 | return ServerResponse.success("success"); 30 | } 31 | 32 | @PostMapping("rank") 33 | public ServerResponse rank(@RequestBody FundDto fundDto) { 34 | long start = System.currentTimeMillis(); 35 | ServerResponse response = fundService.rank(fundDto); 36 | log.info("rank costs: {} ms", System.currentTimeMillis() - start); 37 | return response; 38 | } 39 | 40 | @PostMapping("search") 41 | public ServerResponse search(@RequestBody SearchFormDto searchFormDto) { 42 | return fundService.search(searchFormDto); 43 | } 44 | 45 | @PostMapping("getSearchFormDto") 46 | public ServerResponse getSearchFormDto() { 47 | return fundService.getSearchFormDto(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/interceptor/ApiIdempotentInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.interceptor; 2 | 3 | import com.wangzaiplus.test.annotation.ApiIdempotent; 4 | import com.wangzaiplus.test.service.TokenService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.method.HandlerMethod; 7 | import org.springframework.web.servlet.HandlerInterceptor; 8 | import org.springframework.web.servlet.ModelAndView; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.lang.reflect.Method; 13 | 14 | /** 15 | * 接口幂等性拦截器 16 | */ 17 | public class ApiIdempotentInterceptor implements HandlerInterceptor { 18 | 19 | @Autowired 20 | private TokenService tokenService; 21 | 22 | @Override 23 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 24 | if (!(handler instanceof HandlerMethod)) { 25 | return true; 26 | } 27 | 28 | HandlerMethod handlerMethod = (HandlerMethod) handler; 29 | Method method = handlerMethod.getMethod(); 30 | 31 | ApiIdempotent methodAnnotation = method.getAnnotation(ApiIdempotent.class); 32 | if (methodAnnotation != null) { 33 | check(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示 34 | } 35 | 36 | return true; 37 | } 38 | 39 | private void check(HttpServletRequest request) { 40 | tokenService.checkToken(request); 41 | } 42 | 43 | @Override 44 | public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { 45 | } 46 | 47 | @Override 48 | public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | server.port=8088 2 | spring.resources.static-locations=classpath:/templates/,classpath:/static/ 3 | spring.mvc.view.suffix=.html 4 | 5 | # redis 6 | spring.redis.host=localhost 7 | spring.redis.port=6379 8 | spring.redis.password=root 9 | spring.redis.jedis.pool.max-idle=32 10 | spring.redis.jedis.pool.max-wait=-1 11 | spring.redis.jedis.pool.min-idle=0 12 | spring.redis.timeout=0 13 | 14 | # mysql 15 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 16 | spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&autoR&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true 17 | spring.datasource.username=root 18 | spring.datasource.password=root 19 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 20 | 21 | # show sql in console 22 | logging.level.com.wangzaiplus.test.mapper=debug 23 | 24 | # rabbitmq 25 | spring.rabbitmq.host=localhost 26 | spring.rabbitmq.port=5672 27 | spring.rabbitmq.username=guest 28 | spring.rabbitmq.password=guest 29 | # ����confirms�ص� P -> Exchange 30 | spring.rabbitmq.publisher-confirms=true 31 | # ����returnedMessage�ص� Exchange -> Queue 32 | spring.rabbitmq.publisher-returns=true 33 | # �����ֶ�ȷ��(ack) Queue -> C 34 | spring.rabbitmq.listener.simple.acknowledge-mode=manual 35 | spring.rabbitmq.listener.simple.prefetch=100 36 | 37 | # mail 38 | spring.mail.host=smtp.163.com 39 | spring.mail.username=18621142249@163.com 40 | spring.mail.password=123456wangzai 41 | spring.mail.from=18621142249@163.com 42 | spring.mail.properties.mail.smtp.auth=true 43 | spring.mail.properties.mail.smtp.starttls.enable=true 44 | spring.mail.properties.mail.smtp.starttls.required=true 45 | spring.mail.properties.mail.smtp.ssl.enable=true 46 | 47 | ok.http.connect-timeout=30 48 | ok.http.read-timeout=30 49 | ok.http.write-timeout=30 50 | # ���ӳ�������Ŀ������ӵ�������� 51 | ok.http.max-idle-connections=200 52 | # ���ӿ���ʱ�����Ϊ 300 �� 53 | ok.http.keep-alive-duration=300 -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/impl/TestServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.impl; 2 | 3 | import com.wangzaiplus.test.mq.MessageHelper; 4 | import com.wangzaiplus.test.common.ResponseCode; 5 | import com.wangzaiplus.test.common.ServerResponse; 6 | import com.wangzaiplus.test.config.RabbitConfig; 7 | import com.wangzaiplus.test.mapper.MsgLogMapper; 8 | import com.wangzaiplus.test.pojo.Mail; 9 | import com.wangzaiplus.test.pojo.MsgLog; 10 | import com.wangzaiplus.test.service.TestService; 11 | import com.wangzaiplus.test.util.RandomUtil; 12 | import org.springframework.amqp.rabbit.connection.CorrelationData; 13 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Service; 16 | 17 | @Service 18 | public class TestServiceImpl implements TestService { 19 | 20 | @Autowired 21 | private MsgLogMapper msgLogMapper; 22 | 23 | @Autowired 24 | private RabbitTemplate rabbitTemplate; 25 | 26 | @Override 27 | public ServerResponse testIdempotence() { 28 | return ServerResponse.success("testIdempotence: success"); 29 | } 30 | 31 | @Override 32 | public ServerResponse accessLimit() { 33 | return ServerResponse.success("accessLimit: success"); 34 | } 35 | 36 | @Override 37 | public ServerResponse send(Mail mail) { 38 | String msgId = RandomUtil.UUID32(); 39 | mail.setMsgId(msgId); 40 | 41 | MsgLog msgLog = new MsgLog(msgId, mail, RabbitConfig.MAIL_EXCHANGE_NAME, RabbitConfig.MAIL_ROUTING_KEY_NAME); 42 | msgLogMapper.insert(msgLog);// 消息入库 43 | 44 | CorrelationData correlationData = new CorrelationData(msgId); 45 | rabbitTemplate.convertAndSend(RabbitConfig.MAIL_EXCHANGE_NAME, RabbitConfig.MAIL_ROUTING_KEY_NAME, MessageHelper.objToMsg(mail), correlationData);// 发送消息 46 | 47 | return ServerResponse.success(ResponseCode.MAIL_SEND_SUCCESS.getMsg()); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/task/ResendMsg.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.task; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import com.wangzaiplus.test.mq.MessageHelper; 5 | import com.wangzaiplus.test.pojo.MsgLog; 6 | import com.wangzaiplus.test.service.MsgLogService; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.amqp.rabbit.connection.CorrelationData; 9 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.scheduling.annotation.Scheduled; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.List; 15 | 16 | //@Component 17 | @Slf4j 18 | public class ResendMsg { 19 | 20 | @Autowired 21 | private MsgLogService msgLogService; 22 | 23 | @Autowired 24 | private RabbitTemplate rabbitTemplate; 25 | 26 | // 最大投递次数 27 | private static final int MAX_TRY_COUNT = 3; 28 | 29 | /** 30 | * 每30s拉取投递失败的消息, 重新投递 31 | */ 32 | @Scheduled(cron = "0/30 * * * * ?") 33 | public void resend() { 34 | log.info("开始执行定时任务(重新投递消息)"); 35 | 36 | List msgLogs = msgLogService.selectTimeoutMsg(); 37 | msgLogs.forEach(msgLog -> { 38 | String msgId = msgLog.getMsgId(); 39 | if (msgLog.getTryCount() >= MAX_TRY_COUNT) { 40 | msgLogService.updateStatus(msgId, Constant.MsgLogStatus.DELIVER_FAIL); 41 | log.info("超过最大重试次数, 消息投递失败, msgId: {}", msgId); 42 | } else { 43 | msgLogService.updateTryCount(msgId, msgLog.getNextTryTime());// 投递次数+1 44 | 45 | CorrelationData correlationData = new CorrelationData(msgId); 46 | rabbitTemplate.convertAndSend(msgLog.getExchange(), msgLog.getRoutingKey(), MessageHelper.objToMsg(msgLog.getMsg()), correlationData);// 重新投递 47 | 48 | log.info("第 " + (msgLog.getTryCount() + 1) + " 次重新投递消息"); 49 | } 50 | }); 51 | 52 | log.info("定时任务执行结束(重新投递消息)"); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/consumer/SimpleMailConsumer.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq.consumer; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import com.wangzaiplus.test.common.Constant; 5 | import com.wangzaiplus.test.config.RabbitConfig; 6 | import com.wangzaiplus.test.mq.MessageHelper; 7 | import com.wangzaiplus.test.pojo.Mail; 8 | import com.wangzaiplus.test.pojo.MsgLog; 9 | import com.wangzaiplus.test.service.MsgLogService; 10 | import com.wangzaiplus.test.util.MailUtil; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.amqp.core.Message; 13 | import org.springframework.amqp.core.MessageProperties; 14 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Component; 17 | 18 | import java.io.IOException; 19 | 20 | @Component 21 | @Slf4j 22 | public class SimpleMailConsumer { 23 | 24 | @Autowired 25 | private MsgLogService msgLogService; 26 | 27 | @Autowired 28 | private MailUtil mailUtil; 29 | 30 | @RabbitListener(queues = RabbitConfig.MAIL_QUEUE_NAME) 31 | public void consume(Message message, Channel channel) throws IOException { 32 | Mail mail = MessageHelper.msgToObj(message, Mail.class); 33 | log.info("收到消息: {}", mail.toString()); 34 | 35 | String msgId = mail.getMsgId(); 36 | 37 | MsgLog msgLog = msgLogService.selectByMsgId(msgId); 38 | if (null == msgLog || msgLog.getStatus().equals(Constant.MsgLogStatus.CONSUMED_SUCCESS)) {// 消费幂等性 39 | log.info("重复消费, msgId: {}", msgId); 40 | return; 41 | } 42 | 43 | MessageProperties properties = message.getMessageProperties(); 44 | long tag = properties.getDeliveryTag(); 45 | 46 | boolean success = mailUtil.send(mail); 47 | if (success) { 48 | msgLogService.updateStatus(msgId, Constant.MsgLogStatus.CONSUMED_SUCCESS); 49 | channel.basicAck(tag, false);// 消费确认 50 | } else { 51 | channel.basicNack(tag, false, true); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/impl/TokenServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.impl; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import com.wangzaiplus.test.common.ResponseCode; 5 | import com.wangzaiplus.test.common.ServerResponse; 6 | import com.wangzaiplus.test.exception.ServiceException; 7 | import com.wangzaiplus.test.service.TokenService; 8 | import com.wangzaiplus.test.util.JedisUtil; 9 | import com.wangzaiplus.test.util.RandomUtil; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.apache.commons.lang3.text.StrBuilder; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Service; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | 17 | @Service 18 | public class TokenServiceImpl implements TokenService { 19 | 20 | private static final String TOKEN_NAME = "token"; 21 | 22 | @Autowired 23 | private JedisUtil jedisUtil; 24 | 25 | @Override 26 | public ServerResponse createToken() { 27 | String str = RandomUtil.UUID32(); 28 | StrBuilder token = new StrBuilder(); 29 | token.append(Constant.Redis.TOKEN_PREFIX).append(str); 30 | 31 | jedisUtil.set(token.toString(), token.toString(), Constant.Redis.EXPIRE_TIME_MINUTE); 32 | 33 | return ServerResponse.success(token.toString()); 34 | } 35 | 36 | @Override 37 | public void checkToken(HttpServletRequest request) { 38 | String token = request.getHeader(TOKEN_NAME); 39 | if (StringUtils.isBlank(token)) {// header中不存在token 40 | token = request.getParameter(TOKEN_NAME); 41 | if (StringUtils.isBlank(token)) {// parameter中也不存在token 42 | throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg()); 43 | } 44 | } 45 | 46 | if (!jedisUtil.exists(token)) { 47 | throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg()); 48 | } 49 | 50 | Long del = jedisUtil.del(token); 51 | if (del <= 0) { 52 | throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg()); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/dto/FundDto.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.dto; 2 | 3 | import com.wangzaiplus.test.annotation.ColNum; 4 | import lombok.*; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.Date; 8 | import java.util.List; 9 | import java.util.Objects; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @ToString 16 | @Builder 17 | public class FundDto { 18 | 19 | private Integer id; 20 | @ColNum(colNum = 1) 21 | private String code; 22 | @ColNum(colNum = 2) 23 | private String name; 24 | @ColNum(colNum = 3) 25 | private BigDecimal netValue; 26 | @ColNum(colNum = 4) 27 | private String yieldOfOneYear; 28 | @ColNum(colNum = 5) 29 | private String yieldOfTwoYear; 30 | @ColNum(colNum = 6) 31 | private String yieldOfThreeYear; 32 | @ColNum(colNum = 7) 33 | private String yieldOfFiveYear; 34 | private int type; 35 | private String typeDesc; 36 | private Date establishedTime; 37 | private String asset; 38 | private String manager; 39 | private Integer status; 40 | private Integer isDeleted; 41 | private Date createdTime; 42 | private Date updatedTime; 43 | 44 | private String orderBy; 45 | private String sort; 46 | private Integer limit; 47 | 48 | List orderByList; 49 | 50 | private String nameOrCode; 51 | private Integer tempRank; 52 | private String rankOne; 53 | private String rankTwo; 54 | private String rankThree; 55 | private String rankFive; 56 | 57 | private Integer pageNum; 58 | private Integer pageSize; 59 | 60 | private String replacementSource; 61 | private String replacementTarget; 62 | 63 | @Override 64 | public boolean equals(Object obj) { 65 | if (this == obj) { 66 | return true; 67 | } 68 | 69 | if (!(obj instanceof FundDto)) { 70 | return false; 71 | } 72 | 73 | FundDto dto = (FundDto) obj; 74 | return Objects.equals(this.getCode(), dto.getCode()); 75 | } 76 | 77 | @Override 78 | public int hashCode() { 79 | return Objects.hash(getCode()); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/common/ServerResponse.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.common; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import java.io.Serializable; 6 | 7 | public class ServerResponse implements Serializable{ 8 | 9 | private static final long serialVersionUID = 7498483649536881777L; 10 | 11 | private Integer status; 12 | 13 | private String msg; 14 | 15 | private Object data; 16 | 17 | public ServerResponse() { 18 | } 19 | 20 | public ServerResponse(Integer status, String msg, Object data) { 21 | this.status = status; 22 | this.msg = msg; 23 | this.data = data; 24 | } 25 | 26 | @JsonIgnore 27 | public boolean isSuccess() { 28 | return this.status == ResponseCode.SUCCESS.getCode(); 29 | } 30 | 31 | public static ServerResponse success() { 32 | return new ServerResponse(ResponseCode.SUCCESS.getCode(), null, null); 33 | } 34 | 35 | public static ServerResponse success(String msg) { 36 | return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg, null); 37 | } 38 | 39 | public static ServerResponse success(Object data) { 40 | return new ServerResponse(ResponseCode.SUCCESS.getCode(), null, data); 41 | } 42 | 43 | public static ServerResponse success(String msg, Object data) { 44 | return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg, data); 45 | } 46 | 47 | public static ServerResponse error(String msg) { 48 | return new ServerResponse(ResponseCode.ERROR.getCode(), msg, null); 49 | } 50 | 51 | public static ServerResponse error(Object data) { 52 | return new ServerResponse(ResponseCode.ERROR.getCode(), null, data); 53 | } 54 | 55 | public static ServerResponse error(String msg, Object data) { 56 | return new ServerResponse(ResponseCode.ERROR.getCode(), msg, data); 57 | } 58 | 59 | public Integer getStatus() { 60 | return status; 61 | } 62 | 63 | public void setStatus(Integer status) { 64 | this.status = status; 65 | } 66 | 67 | public String getMsg() { 68 | return msg; 69 | } 70 | 71 | public void setMsg(String msg) { 72 | this.msg = msg; 73 | } 74 | 75 | public Object getData() { 76 | return data; 77 | } 78 | 79 | public void setData(Object data) { 80 | this.data = data; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/TestApplication.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test; 2 | 3 | import com.wangzaiplus.test.interceptor.AccessLimitInterceptor; 4 | import com.wangzaiplus.test.interceptor.ApiIdempotentInterceptor; 5 | import org.mybatis.spring.annotation.MapperScan; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.scheduling.annotation.EnableAsync; 10 | import org.springframework.scheduling.annotation.EnableScheduling; 11 | import org.springframework.web.cors.CorsConfiguration; 12 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 13 | import org.springframework.web.filter.CorsFilter; 14 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 15 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 16 | 17 | @SpringBootApplication 18 | @MapperScan("com.wangzaiplus.test.mapper") 19 | @EnableScheduling 20 | @EnableAsync 21 | public class TestApplication extends WebMvcConfigurerAdapter { 22 | 23 | public static void main(String[] args) { 24 | SpringApplication.run(TestApplication.class, args); 25 | } 26 | 27 | /** 28 | * 跨域 29 | * @return 30 | */ 31 | @Bean 32 | public CorsFilter corsFilter() { 33 | final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); 34 | final CorsConfiguration corsConfiguration = new CorsConfiguration(); 35 | corsConfiguration.setAllowCredentials(true); 36 | corsConfiguration.addAllowedOrigin("*"); 37 | corsConfiguration.addAllowedHeader("*"); 38 | corsConfiguration.addAllowedMethod("*"); 39 | urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); 40 | return new CorsFilter(urlBasedCorsConfigurationSource); 41 | } 42 | 43 | @Override 44 | public void addInterceptors(InterceptorRegistry registry) { 45 | // 接口幂等性拦截器 46 | registry.addInterceptor(apiIdempotentInterceptor()); 47 | // 接口防刷限流拦截器 48 | registry.addInterceptor(accessLimitInterceptor()); 49 | 50 | super.addInterceptors(registry); 51 | } 52 | 53 | @Bean 54 | public ApiIdempotentInterceptor apiIdempotentInterceptor() { 55 | return new ApiIdempotentInterceptor(); 56 | } 57 | 58 | @Bean 59 | public AccessLimitInterceptor accessLimitInterceptor() { 60 | return new AccessLimitInterceptor(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/RegexUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import java.util.regex.Pattern; 6 | 7 | public class RegexUtil { 8 | 9 | // 正则表达式: 验证手机号 10 | public static final String REGEX_MOBILE = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$"; 11 | // 验证邮箱 12 | public static final String REGEX_EMAIL = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"; 13 | // 验证汉字 14 | public static final String REGEX_CHINESE = "^[\u4e00-\u9fa5],{0,}$"; 15 | // 验证身份证 16 | public static final String REGEX_ID_CARD = "(^\\d{18}$)|(^\\d{15}$)"; 17 | // 验证URL 18 | public static final String REGEX_URL = "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?"; 19 | // 验证IP地址 20 | public static final String REGEX_IP_ADDR = "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)"; 21 | 22 | /** 23 | * 手机号 24 | * 25 | * @param mobile 26 | * @return 27 | */ 28 | public static boolean isMobile(String mobile) { 29 | return StringUtils.isNotBlank(mobile) && Pattern.matches(REGEX_MOBILE, mobile); 30 | } 31 | 32 | /** 33 | * 邮箱 34 | * 35 | * @param email 36 | * @return 37 | */ 38 | public static boolean isEmail(String email) { 39 | return StringUtils.isNotBlank(email) && Pattern.matches(REGEX_EMAIL, email); 40 | } 41 | 42 | /** 43 | * 汉字 44 | * 45 | * @param chinese 46 | * @return 47 | */ 48 | public static boolean isChinese(String chinese) { 49 | return StringUtils.isNotBlank(chinese) && Pattern.matches(REGEX_CHINESE, chinese); 50 | } 51 | 52 | /** 53 | * 身份证 54 | * 55 | * @param idCard 56 | * @return 57 | */ 58 | public static boolean isIDCard(String idCard) { 59 | return StringUtils.isNotBlank(idCard) && Pattern.matches(REGEX_ID_CARD, idCard); 60 | } 61 | 62 | /** 63 | * URL 64 | * 65 | * @param url 66 | * @return 67 | */ 68 | public static boolean isUrl(String url) { 69 | return StringUtils.isNotBlank(url) && Pattern.matches(REGEX_URL, url); 70 | } 71 | 72 | /** 73 | * IP地址 74 | * 75 | * @param ipAddr 76 | * @return 77 | */ 78 | public static boolean isIPAddr(String ipAddr) { 79 | return StringUtils.isNotBlank(ipAddr) && Pattern.matches(REGEX_IP_ADDR, ipAddr); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/SerializableUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.*; 7 | 8 | /** 9 | * Serializable工具(JDK) 10 | */ 11 | public class SerializableUtil { 12 | 13 | private static final Logger LOGGER = LoggerFactory.getLogger(SerializableUtil.class); 14 | 15 | /** 16 | * 序列化 17 | * 18 | * @param object 19 | * @return 20 | */ 21 | public static byte[] serializable(Object object) { 22 | ByteArrayOutputStream baos = null; 23 | ObjectOutputStream oos = null; 24 | try { 25 | baos = new ByteArrayOutputStream(); 26 | oos = new ObjectOutputStream(baos); 27 | oos.writeObject(object); 28 | return baos.toByteArray(); 29 | } catch (IOException e) { 30 | LOGGER.error("serializable异常: " + e.getMessage()); 31 | throw new RuntimeException("serializable异常: " + e.getMessage()); 32 | } finally { 33 | try { 34 | if (oos != null) { 35 | oos.close(); 36 | } 37 | if (baos != null) { 38 | baos.close(); 39 | } 40 | } catch (IOException e) { 41 | LOGGER.error("serializable异常: " + e.getMessage()); 42 | throw new RuntimeException("serializable异常: " + e.getMessage()); 43 | } 44 | } 45 | } 46 | 47 | /** 48 | * 反序列化 49 | * 50 | * @param bytes 51 | * @return 52 | */ 53 | public static Object unserializable(byte[] bytes) { 54 | ByteArrayInputStream bais = null; 55 | ObjectInputStream ois = null; 56 | try { 57 | bais = new ByteArrayInputStream(bytes); 58 | ois = new ObjectInputStream(bais); 59 | return ois.readObject(); 60 | } catch (Exception e) { 61 | throw new RuntimeException("unserializable异常: " + e.getMessage()); 62 | } finally { 63 | try { 64 | if (ois != null) { 65 | ois.close(); 66 | } 67 | if (bais != null) { 68 | bais.close(); 69 | } 70 | } catch (IOException e) { 71 | LOGGER.error("unserializable异常: " + e.getMessage()); 72 | throw new RuntimeException("unserializable异常: " + e.getMessage()); 73 | } 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/MsgLogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | msg_id, msg, exchange, routing_key, status, try_count, next_try_time, create_time, update_time 18 | 19 | 20 | 21 | INSERT INTO msg_log(msg_id, msg, exchange, routing_key, status, try_count, next_try_time, create_time, update_time) 22 | VALUES (#{msgId}, #{msg}, #{exchange}, #{routingKey}, #{status}, #{tryCount}, #{nextTryTime}, #{createTime}, #{updateTime}) 23 | 24 | 25 | 26 | update msg_log set status = #{status}, update_time = now() 27 | where msg_id = #{msgId} 28 | 29 | 30 | 36 | 37 | 38 | update msg_log set try_count = try_count + 1, next_try_time = #{nextTryTime}, update_time = now() 39 | where msg_id = #{msgId} 40 | 41 | 42 | 48 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.core.type.TypeReference; 5 | import com.fasterxml.jackson.databind.DeserializationFeature; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.fasterxml.jackson.databind.SerializationFeature; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.commons.lang3.StringUtils; 10 | 11 | import java.text.SimpleDateFormat; 12 | 13 | @Slf4j 14 | public class JsonUtil { 15 | 16 | private static ObjectMapper objectMapper = new ObjectMapper(); 17 | private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; 18 | 19 | static { 20 | // 对象的所有字段全部列入 21 | objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); 22 | // 取消默认转换timestamps形式 23 | objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); 24 | // 忽略空bean转json的错误 25 | objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 26 | // 统一日期格式 27 | objectMapper.setDateFormat(new SimpleDateFormat(DATE_FORMAT)); 28 | // 忽略在json字符串中存在, 但在java对象中不存在对应属性的情况, 防止错误 29 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 30 | } 31 | 32 | public static String objToStr(T obj) { 33 | if (null == obj) { 34 | return null; 35 | } 36 | 37 | try { 38 | return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj); 39 | } catch (Exception e) { 40 | log.warn("objToStr error: ", e); 41 | return null; 42 | } 43 | } 44 | 45 | public static T strToObj(String str, Class clazz) { 46 | if (StringUtils.isBlank(str) || null == clazz) { 47 | return null; 48 | } 49 | 50 | try { 51 | return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz); 52 | } catch (Exception e) { 53 | log.warn("strToObj error: ", e); 54 | return null; 55 | } 56 | } 57 | 58 | public static T strToObj(String str, TypeReference typeReference) { 59 | if (StringUtils.isBlank(str) || null == typeReference) { 60 | return null; 61 | } 62 | 63 | try { 64 | return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference)); 65 | } catch (Exception e) { 66 | log.error("strToObj error", e); 67 | return null; 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/MailUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import com.wangzaiplus.test.pojo.Mail; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.core.io.FileSystemResource; 8 | import org.springframework.mail.MailException; 9 | import org.springframework.mail.SimpleMailMessage; 10 | import org.springframework.mail.javamail.JavaMailSender; 11 | import org.springframework.mail.javamail.MimeMessageHelper; 12 | import org.springframework.stereotype.Component; 13 | 14 | import javax.mail.internet.MimeMessage; 15 | import java.io.File; 16 | 17 | @Component 18 | @Slf4j 19 | public class MailUtil { 20 | 21 | @Value("${spring.mail.from}") 22 | private String from; 23 | 24 | @Autowired 25 | private JavaMailSender mailSender; 26 | 27 | /** 28 | * 发送简单邮件 29 | * 30 | * @param mail 31 | */ 32 | public boolean send(Mail mail) { 33 | String to = mail.getTo();// 目标邮箱 34 | String title = mail.getTitle();// 邮件标题 35 | String content = mail.getContent();// 邮件正文 36 | 37 | SimpleMailMessage message = new SimpleMailMessage(); 38 | message.setFrom(from); 39 | message.setTo(to); 40 | message.setSubject(title); 41 | message.setText(content); 42 | 43 | try { 44 | mailSender.send(message); 45 | log.info("邮件发送成功"); 46 | return true; 47 | } catch (MailException e) { 48 | log.error("邮件发送失败, to: {}, title: {}", to, title, e); 49 | return false; 50 | } 51 | } 52 | 53 | /** 54 | * 发送附件邮件 55 | * 56 | * @param mail 邮件 57 | * @param file 附件 58 | */ 59 | public boolean sendAttachment(Mail mail, File file) { 60 | String to = mail.getTo(); 61 | String title = mail.getTitle(); 62 | String content = mail.getContent(); 63 | 64 | MimeMessage message = mailSender.createMimeMessage(); 65 | try { 66 | MimeMessageHelper helper = new MimeMessageHelper(message, true); 67 | helper.setFrom(from); 68 | helper.setTo(to); 69 | helper.setSubject(title); 70 | helper.setText(content); 71 | FileSystemResource resource = new FileSystemResource(file); 72 | String fileName = file.getName(); 73 | helper.addAttachment(fileName, resource); 74 | mailSender.send(message); 75 | log.info("附件邮件发送成功"); 76 | return true; 77 | } catch (Exception e) { 78 | log.error("附件邮件发送失败, to: {}, title: {}", to, title, e); 79 | return false; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/config/OkHttpConfig.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.config; 2 | 3 | import okhttp3.ConnectionPool; 4 | import okhttp3.OkHttpClient; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | import javax.net.ssl.*; 10 | import java.security.*; 11 | import java.security.cert.CertificateException; 12 | import java.security.cert.X509Certificate; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | @Configuration 16 | public class OkHttpConfig { 17 | 18 | @Value("${ok.http.connect-timeout}") 19 | private Integer connectTimeout; 20 | 21 | @Value("${ok.http.read-timeout}") 22 | private Integer readTimeout; 23 | 24 | @Value("${ok.http.write-timeout}") 25 | private Integer writeTimeout; 26 | 27 | @Value("${ok.http.max-idle-connections}") 28 | private Integer maxIdleConnections; 29 | 30 | @Value("${ok.http.keep-alive-duration}") 31 | private Long keepAliveDuration; 32 | 33 | @Bean 34 | public OkHttpClient okHttpClient() { 35 | return new OkHttpClient.Builder() 36 | .sslSocketFactory(sslSocketFactory(), x509TrustManager()) 37 | // 是否开启缓存 38 | .retryOnConnectionFailure(false) 39 | .connectionPool(pool()) 40 | .connectTimeout(connectTimeout, TimeUnit.SECONDS) 41 | .readTimeout(readTimeout, TimeUnit.SECONDS) 42 | .writeTimeout(writeTimeout,TimeUnit.SECONDS) 43 | .hostnameVerifier((hostname, session) -> true) 44 | .build(); 45 | } 46 | 47 | @Bean 48 | public X509TrustManager x509TrustManager() { 49 | return new X509TrustManager() { 50 | @Override 51 | public void checkClientTrusted(X509Certificate[] chain, String authType) 52 | throws CertificateException { 53 | } 54 | @Override 55 | public void checkServerTrusted(X509Certificate[] chain, String authType) 56 | throws CertificateException { 57 | } 58 | @Override 59 | public X509Certificate[] getAcceptedIssuers() { 60 | return new X509Certificate[0]; 61 | } 62 | }; 63 | } 64 | 65 | @Bean 66 | public SSLSocketFactory sslSocketFactory() { 67 | try { 68 | // 信任任何链接 69 | SSLContext sslContext = SSLContext.getInstance("TLS"); 70 | sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom()); 71 | return sslContext.getSocketFactory(); 72 | } catch (NoSuchAlgorithmException | KeyManagementException e) { 73 | e.printStackTrace(); 74 | } 75 | return null; 76 | } 77 | 78 | @Bean 79 | public ConnectionPool pool() { 80 | return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.SECONDS); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/interceptor/AccessLimitInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.interceptor; 2 | 3 | import com.wangzaiplus.test.annotation.AccessLimit; 4 | import com.wangzaiplus.test.common.Constant; 5 | import com.wangzaiplus.test.common.ResponseCode; 6 | import com.wangzaiplus.test.exception.ServiceException; 7 | import com.wangzaiplus.test.util.IpUtil; 8 | import com.wangzaiplus.test.util.JedisUtil; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.method.HandlerMethod; 11 | import org.springframework.web.servlet.HandlerInterceptor; 12 | import org.springframework.web.servlet.ModelAndView; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | import java.lang.reflect.Method; 17 | 18 | /** 19 | * 接口防刷限流拦截器 20 | */ 21 | public class AccessLimitInterceptor implements HandlerInterceptor { 22 | 23 | @Autowired 24 | private JedisUtil jedisUtil; 25 | 26 | @Override 27 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 28 | if (!(handler instanceof HandlerMethod)) { 29 | return true; 30 | } 31 | 32 | HandlerMethod handlerMethod = (HandlerMethod) handler; 33 | Method method = handlerMethod.getMethod(); 34 | 35 | AccessLimit annotation = method.getAnnotation(AccessLimit.class); 36 | if (annotation != null) { 37 | check(annotation, request); 38 | } 39 | 40 | return true; 41 | } 42 | 43 | private void check(AccessLimit annotation, HttpServletRequest request) { 44 | int maxCount = annotation.maxCount(); 45 | int seconds = annotation.seconds(); 46 | 47 | StringBuilder sb = new StringBuilder(); 48 | sb.append(Constant.Redis.ACCESS_LIMIT_PREFIX).append(IpUtil.getIpAddress(request)).append(request.getRequestURI()); 49 | String key = sb.toString(); 50 | 51 | Boolean exists = jedisUtil.exists(key); 52 | if (!exists) { 53 | jedisUtil.set(key, String.valueOf(1), seconds); 54 | } else { 55 | int count = Integer.valueOf(jedisUtil.get(key)); 56 | if (count < maxCount) { 57 | Long ttl = jedisUtil.ttl(key); 58 | if (ttl <= 0) { 59 | jedisUtil.set(key, String.valueOf(1), seconds); 60 | } else { 61 | jedisUtil.set(key, String.valueOf(++count), ttl.intValue()); 62 | } 63 | } else { 64 | throw new ServiceException(ResponseCode.ACCESS_LIMIT.getMsg()); 65 | } 66 | } 67 | } 68 | 69 | @Override 70 | public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { 71 | } 72 | 73 | @Override 74 | public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/BeanUtils.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import com.wangzaiplus.test.annotation.ColNum; 4 | import com.wangzaiplus.test.exception.ServiceException; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.collections4.CollectionUtils; 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import java.beans.PropertyDescriptor; 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.Method; 12 | import java.math.BigDecimal; 13 | import java.util.List; 14 | 15 | @Slf4j 16 | public class BeanUtils { 17 | 18 | private static final String TYPE_STRING = "String"; 19 | private static final String TYPE_DATE = "Date"; 20 | private static final String TYPE_INT = "int"; 21 | private static final String TYPE_INTEGER = "Integer"; 22 | private static final String TYPE_LONG = "Long"; 23 | private static final String TYPE_DOUBLE = "Double"; 24 | private static final String TYPE_BOOLEAN = "Boolean"; 25 | private static final String TYPE_BIG_DECIMAL = "BigDecimal"; 26 | 27 | public static void convert(List list, Object o) throws Exception { 28 | if (CollectionUtils.isEmpty(list) || null == o) { 29 | throw new ServiceException("converter param error"); 30 | } 31 | 32 | Class clazz = o.getClass(); 33 | Field[] fields = clazz.getDeclaredFields(); 34 | for (Field field : fields) { 35 | ColNum colNum = field.getAnnotation(ColNum.class); 36 | if (null == colNum) { 37 | continue; 38 | } 39 | 40 | int num = colNum.colNum(); 41 | if (num < 1 || num > list.size()) { 42 | throw new ServiceException("colNum error: " + num); 43 | } 44 | 45 | String value = list.get(num - 1); 46 | PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz); 47 | Method writeMethod = pd.getWriteMethod(); 48 | if (null == writeMethod || StringUtils.isBlank(value)) { 49 | continue; 50 | } 51 | 52 | String fieldType = field.getType().getSimpleName(); 53 | Object parsedValue = parseValue(fieldType, value); 54 | writeMethod.invoke(o, parsedValue); 55 | } 56 | } 57 | 58 | private static Object parseValue(String fieldType, String value) { 59 | if (TYPE_STRING.equals(fieldType)) { 60 | return value; 61 | } else if (TYPE_DATE.equals(fieldType)) { 62 | return JodaTimeUtil.strToDate(value); 63 | } else if (TYPE_INT.equals(fieldType) || TYPE_INTEGER.equals(value)) { 64 | return Integer.parseInt(value); 65 | } else if (TYPE_LONG.equalsIgnoreCase(fieldType)) { 66 | return Long.parseLong(value); 67 | } else if (TYPE_DOUBLE.equalsIgnoreCase(fieldType)) { 68 | return Double.parseDouble(value); 69 | } else if (TYPE_BOOLEAN.equalsIgnoreCase(fieldType)) { 70 | return Boolean.TRUE.toString().equalsIgnoreCase(fieldType); 71 | } else if (TYPE_BIG_DECIMAL.equalsIgnoreCase(fieldType)) { 72 | return new BigDecimal(value); 73 | } else { 74 | throw new ServiceException("fieldType error: "+ fieldType); 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mq/BaseConsumerProxy.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.mq; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import com.wangzaiplus.test.common.Constant; 5 | import com.wangzaiplus.test.pojo.MsgLog; 6 | import com.wangzaiplus.test.service.MsgLogService; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.amqp.core.Message; 9 | import org.springframework.amqp.core.MessageProperties; 10 | 11 | import java.lang.reflect.Proxy; 12 | import java.util.Map; 13 | 14 | @Slf4j 15 | public class BaseConsumerProxy { 16 | 17 | private Object target; 18 | 19 | private MsgLogService msgLogService; 20 | 21 | public BaseConsumerProxy(Object target, MsgLogService msgLogService) { 22 | this.target = target; 23 | this.msgLogService = msgLogService; 24 | } 25 | 26 | public Object getProxy() { 27 | ClassLoader classLoader = target.getClass().getClassLoader(); 28 | Class[] interfaces = target.getClass().getInterfaces(); 29 | 30 | Object proxy = Proxy.newProxyInstance(classLoader, interfaces, (proxy1, method, args) -> { 31 | Message message = (Message) args[0]; 32 | Channel channel = (Channel) args[1]; 33 | 34 | String correlationId = getCorrelationId(message); 35 | 36 | if (isConsumed(correlationId)) {// 消费幂等性, 防止消息被重复消费 37 | log.info("重复消费, correlationId: {}", correlationId); 38 | return null; 39 | } 40 | 41 | MessageProperties properties = message.getMessageProperties(); 42 | long tag = properties.getDeliveryTag(); 43 | 44 | try { 45 | Object result = method.invoke(target, args);// 真正消费的业务逻辑 46 | msgLogService.updateStatus(correlationId, Constant.MsgLogStatus.CONSUMED_SUCCESS); 47 | channel.basicAck(tag, false);// 消费确认 48 | return result; 49 | } catch (Exception e) { 50 | log.error("getProxy error", e); 51 | channel.basicNack(tag, false, true); 52 | return null; 53 | } 54 | }); 55 | 56 | return proxy; 57 | } 58 | 59 | /** 60 | * 获取CorrelationId 61 | * 62 | * @param message 63 | * @return 64 | */ 65 | private String getCorrelationId(Message message) { 66 | String correlationId = null; 67 | 68 | MessageProperties properties = message.getMessageProperties(); 69 | Map headers = properties.getHeaders(); 70 | for (Map.Entry entry : headers.entrySet()) { 71 | String key = (String) entry.getKey(); 72 | String value = (String) entry.getValue(); 73 | if (key.equals("spring_returned_message_correlation")) { 74 | correlationId = value; 75 | } 76 | } 77 | 78 | return correlationId; 79 | } 80 | 81 | /** 82 | * 消息是否已被消费 83 | * 84 | * @param correlationId 85 | * @return 86 | */ 87 | private boolean isConsumed(String correlationId) { 88 | MsgLog msgLog = msgLogService.selectByMsgId(correlationId); 89 | if (null == msgLog || msgLog.getStatus().equals(Constant.MsgLogStatus.CONSUMED_SUCCESS)) { 90 | return true; 91 | } 92 | 93 | return false; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import java.util.Random; 4 | import java.util.UUID; 5 | 6 | public class RandomUtil { 7 | 8 | public static final String allChar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 9 | 10 | public static final String letterChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 11 | 12 | public static final String numberChar = "0123456789"; 13 | 14 | public static String UUID32() { 15 | String str = UUID.randomUUID().toString(); 16 | return str.replaceAll("-", ""); 17 | } 18 | 19 | public static String UUID36() { 20 | return UUID.randomUUID().toString(); 21 | } 22 | 23 | /** 24 | * 生成包含大、小写字母、数字的字符串 25 | * 26 | * @param length 27 | * @return 如: zsK8rCCi 28 | */ 29 | public static String generateStr(int length) { 30 | StringBuffer sb = new StringBuffer(); 31 | Random random = new Random(); 32 | for (int i = 0; i < length; i++) { 33 | sb.append(allChar.charAt(random.nextInt(allChar.length()))); 34 | } 35 | return sb.toString(); 36 | } 37 | 38 | /** 39 | * 生成纯数字字符串 40 | * 41 | * @param length 42 | * @return 如: 77914 43 | */ 44 | public static String generateDigitalStr(int length) { 45 | StringBuffer sb = new StringBuffer(); 46 | Random random = new Random(); 47 | for (int i = 0; i < length; i++) { 48 | sb.append(numberChar.charAt(random.nextInt(numberChar.length()))); 49 | } 50 | return sb.toString(); 51 | } 52 | 53 | /** 54 | * 生成只包含大小写字母的字符串 55 | * 56 | * @param length 57 | * @return 如: XetrWaYc 58 | */ 59 | public static String generateLetterStr(int length) { 60 | StringBuffer sb = new StringBuffer(); 61 | Random random = new Random(); 62 | for (int i = 0; i < length; i++) { 63 | sb.append(letterChar.charAt(random.nextInt(letterChar.length()))); 64 | } 65 | return sb.toString(); 66 | } 67 | 68 | /** 69 | * 生成只包含小写字母的字符串 70 | * 71 | * @param length 72 | * @return 如: nzcaunmk 73 | */ 74 | public static String generateLowerStr(int length) { 75 | return generateLetterStr(length).toLowerCase(); 76 | } 77 | 78 | /** 79 | * 生成只包含大写字母的字符串 80 | * 81 | * @param length 82 | * @return 如: KZMQXSXW 83 | */ 84 | public static String generateUpperStr(int length) { 85 | return generateLetterStr(length).toUpperCase(); 86 | } 87 | 88 | /** 89 | * 生成纯0字符串 90 | * 91 | * @param length 92 | * @return 如: 00000000 93 | */ 94 | public static String generateZeroStr(int length) { 95 | StringBuffer sb = new StringBuffer(); 96 | for (int i = 0; i < length; i++) { 97 | sb.append('0'); 98 | } 99 | return sb.toString(); 100 | } 101 | 102 | /** 103 | * 根据数字生成字符串,长度不够前面补0 104 | * 105 | * @param num 数字 106 | * @param strLength 字符串长度 107 | * @return 如: 00000099 108 | */ 109 | public static String generateStrWithZero(int num, int strLength) { 110 | StringBuffer sb = new StringBuffer(); 111 | String strNum = String.valueOf(num); 112 | if (strLength - strNum.length() >= 0) { 113 | sb.append(generateZeroStr(strLength - strNum.length())); 114 | } else { 115 | throw new RuntimeException("将数字" + num + "转化为长度为" + strLength + "的字符串异常!"); 116 | } 117 | sb.append(strNum); 118 | return sb.toString(); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/config/RabbitConfig.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.config; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import com.wangzaiplus.test.service.MsgLogService; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.amqp.core.Binding; 7 | import org.springframework.amqp.core.BindingBuilder; 8 | import org.springframework.amqp.core.DirectExchange; 9 | import org.springframework.amqp.core.Queue; 10 | import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; 11 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 12 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.context.annotation.Configuration; 16 | 17 | @Configuration 18 | @Slf4j 19 | public class RabbitConfig { 20 | 21 | @Autowired 22 | private CachingConnectionFactory connectionFactory; 23 | 24 | @Autowired 25 | private MsgLogService msgLogService; 26 | 27 | @Bean 28 | public RabbitTemplate rabbitTemplate() { 29 | RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); 30 | rabbitTemplate.setMessageConverter(converter()); 31 | 32 | // 消息是否成功发送到Exchange 33 | rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> { 34 | if (ack) { 35 | log.info("消息成功发送到Exchange"); 36 | String msgId = correlationData.getId(); 37 | msgLogService.updateStatus(msgId, Constant.MsgLogStatus.DELIVER_SUCCESS); 38 | } else { 39 | log.info("消息发送到Exchange失败, {}, cause: {}", correlationData, cause); 40 | } 41 | }); 42 | 43 | // 触发setReturnCallback回调必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发回调 44 | rabbitTemplate.setMandatory(true); 45 | // 消息是否从Exchange路由到Queue, 注意: 这是一个失败回调, 只有消息从Exchange路由到Queue失败才会回调这个方法 46 | rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> { 47 | log.info("消息从Exchange路由到Queue失败: exchange: {}, route: {}, replyCode: {}, replyText: {}, message: {}", exchange, routingKey, replyCode, replyText, message); 48 | }); 49 | 50 | return rabbitTemplate; 51 | } 52 | 53 | @Bean 54 | public Jackson2JsonMessageConverter converter() { 55 | return new Jackson2JsonMessageConverter(); 56 | } 57 | 58 | // 登录日志 59 | public static final String LOGIN_LOG_QUEUE_NAME = "login.log.queue"; 60 | public static final String LOGIN_LOG_EXCHANGE_NAME = "login.log.exchange"; 61 | public static final String LOGIN_LOG_ROUTING_KEY_NAME = "login.log.routing.key"; 62 | 63 | @Bean 64 | public Queue logUserQueue() { 65 | return new Queue(LOGIN_LOG_QUEUE_NAME, true); 66 | } 67 | 68 | @Bean 69 | public DirectExchange logUserExchange() { 70 | return new DirectExchange(LOGIN_LOG_EXCHANGE_NAME, true, false); 71 | } 72 | 73 | @Bean 74 | public Binding logUserBinding() { 75 | return BindingBuilder.bind(logUserQueue()).to(logUserExchange()).with(LOGIN_LOG_ROUTING_KEY_NAME); 76 | } 77 | 78 | // 发送邮件 79 | public static final String MAIL_QUEUE_NAME = "mail.queue"; 80 | public static final String MAIL_EXCHANGE_NAME = "mail.exchange"; 81 | public static final String MAIL_ROUTING_KEY_NAME = "mail.routing.key"; 82 | 83 | @Bean 84 | public Queue mailQueue() { 85 | return new Queue(MAIL_QUEUE_NAME, true); 86 | } 87 | 88 | @Bean 89 | public DirectExchange mailExchange() { 90 | return new DirectExchange(MAIL_EXCHANGE_NAME, true, false); 91 | } 92 | 93 | @Bean 94 | public Binding mailBinding() { 95 | return BindingBuilder.bind(mailQueue()).to(mailExchange()).with(MAIL_ROUTING_KEY_NAME); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | id, username, password, password_salt, ip, mobile, mail, type, status, is_deleted, created_time, updated_time 21 | 22 | 23 | 28 | 29 | 35 | 36 | 37 | INSERT INTO t_user(username, password) VALUES (#{username}, #{password}) 38 | 39 | 40 | 41 | UPDATE t_user SET 42 | 43 | username = #{username}, 44 | 45 | 46 | password = #{password} 47 | 48 | WHERE id = #{id} 49 | 50 | 51 | 52 | DELETE FROM t_user WHERE id =#{id} 53 | 54 | 55 | 61 | 62 | 63 | insert into t_user(username, password) 64 | values 65 | 66 | (#{item.username}, #{item.password}) 67 | 68 | 69 | 70 | 71 | update t_user 72 | 73 | 74 | 75 | when id = #{item.id} then #{item.username} 76 | 77 | 78 | 79 | 80 | when id = #{item.id} then #{item.password} 81 | 82 | 83 | 84 | where id in 85 | 86 | #{item.id} 87 | 88 | 89 | 90 | 96 | 97 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.service.impl; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import com.wangzaiplus.test.common.ResponseCode; 5 | import com.wangzaiplus.test.common.ServerResponse; 6 | import com.wangzaiplus.test.config.RabbitConfig; 7 | import com.wangzaiplus.test.mapper.MsgLogMapper; 8 | import com.wangzaiplus.test.mapper.UserMapper; 9 | import com.wangzaiplus.test.mq.MessageHelper; 10 | import com.wangzaiplus.test.pojo.LoginLog; 11 | import com.wangzaiplus.test.pojo.MsgLog; 12 | import com.wangzaiplus.test.pojo.User; 13 | import com.wangzaiplus.test.service.UserService; 14 | import com.wangzaiplus.test.service.batch.mapperproxy.MapperProxy; 15 | import com.wangzaiplus.test.util.JedisUtil; 16 | import com.wangzaiplus.test.util.JodaTimeUtil; 17 | import com.wangzaiplus.test.util.RandomUtil; 18 | import lombok.extern.slf4j.Slf4j; 19 | import org.apache.commons.lang3.StringUtils; 20 | import org.springframework.amqp.rabbit.connection.CorrelationData; 21 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.stereotype.Service; 24 | 25 | import java.util.Date; 26 | import java.util.List; 27 | 28 | @Service 29 | @Slf4j 30 | public class UserServiceImpl implements UserService { 31 | 32 | @Autowired 33 | private UserMapper userMapper; 34 | 35 | @Autowired 36 | private RabbitTemplate rabbitTemplate; 37 | 38 | @Autowired 39 | private MsgLogMapper msgLogMapper; 40 | 41 | @Autowired 42 | private JedisUtil jedisUtil; 43 | 44 | @Override 45 | public List getAll() { 46 | return userMapper.selectAll(); 47 | } 48 | 49 | @Override 50 | public User getOne(Integer id) { 51 | return userMapper.selectOne(id); 52 | } 53 | 54 | @Override 55 | public void add(User user) { 56 | userMapper.insert(user); 57 | } 58 | 59 | @Override 60 | public void update(User user) { 61 | userMapper.update(user); 62 | } 63 | 64 | @Override 65 | public void delete(Integer id) { 66 | userMapper.delete(id); 67 | } 68 | 69 | @Override 70 | public User getByUsernameAndPassword(String username, String password) { 71 | return userMapper.selectByUsernameAndPassword(username, password); 72 | } 73 | 74 | @Override 75 | public ServerResponse login(String username, String password) { 76 | if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { 77 | return ServerResponse.error(ResponseCode.USERNAME_OR_PASSWORD_EMPTY.getMsg()); 78 | } 79 | 80 | User user = userMapper.selectByUsernameAndPassword(username, password); 81 | if (null == user) { 82 | return ServerResponse.error(ResponseCode.USERNAME_OR_PASSWORD_WRONG.getMsg()); 83 | } 84 | 85 | saveAndSendMsg(user); 86 | 87 | return ServerResponse.success(); 88 | } 89 | 90 | /** 91 | * 保存并发送消息 92 | * @param user 93 | */ 94 | private void saveAndSendMsg(User user) { 95 | String msgId = RandomUtil.UUID32(); 96 | 97 | LoginLog loginLog = new LoginLog(); 98 | loginLog.setUserId(user.getId()); 99 | loginLog.setType(Constant.LogType.LOGIN); 100 | Date date = new Date(); 101 | loginLog.setDescription(user.getUsername() + "在" + JodaTimeUtil.dateToStr(date) + "登录系统"); 102 | loginLog.setCreateTime(date); 103 | loginLog.setUpdateTime(date); 104 | loginLog.setMsgId(msgId); 105 | 106 | CorrelationData correlationData = new CorrelationData(msgId); 107 | rabbitTemplate.convertAndSend(RabbitConfig.LOGIN_LOG_EXCHANGE_NAME, RabbitConfig.LOGIN_LOG_ROUTING_KEY_NAME, MessageHelper.objToMsg(loginLog), correlationData); 108 | 109 | MsgLog msgLog = new MsgLog(msgId, loginLog, RabbitConfig.LOGIN_LOG_EXCHANGE_NAME, RabbitConfig.LOGIN_LOG_ROUTING_KEY_NAME); 110 | msgLogMapper.insert(msgLog); 111 | } 112 | 113 | @Override 114 | public void batchInsert(List list) { 115 | new MapperProxy(userMapper).batchInsert(list); 116 | } 117 | 118 | @Override 119 | public void batchUpdate(List list) { 120 | new MapperProxy(userMapper).batchUpdate(list); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 首页 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 |
20 | 21 | 基金定投 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 登录 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | 53 | 54 |
55 |
56 | 57 | 58 |
59 | 77 |
78 |
79 |
80 | 81 | 82 | 112 | 113 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/StrategyController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import com.wangzaiplus.test.common.Constant; 4 | import com.wangzaiplus.test.common.ServerResponse; 5 | import com.wangzaiplus.test.exception.ServiceException; 6 | import com.wangzaiplus.test.pojo.CalculateDto; 7 | import com.wangzaiplus.test.service.strategy.CalculateService; 8 | import com.wangzaiplus.test.service.strategy.CalculateServiceFactory; 9 | import com.wangzaiplus.test.service.strategy.CalculateStrategy; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Qualifier; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestBody; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | @RestController 18 | @RequestMapping("/test") 19 | public class StrategyController { 20 | 21 | @Autowired 22 | @Qualifier("addCalculateServiceImpl") 23 | private CalculateService addCalculateServiceImpl; 24 | 25 | @Autowired 26 | @Qualifier("subtractCalculateServiceImpl") 27 | private CalculateService subtractCalculateServiceImpl; 28 | 29 | @Autowired 30 | @Qualifier("multiplyCalculateServiceImpl") 31 | private CalculateService multiplyCalculateServiceImpl; 32 | 33 | @Autowired 34 | @Qualifier("divideCalculateServiceImpl") 35 | private CalculateService divideCalculateServiceImpl; 36 | 37 | @Autowired 38 | private CalculateServiceFactory calculateServiceFactory; 39 | 40 | @PostMapping("strategy1") 41 | public ServerResponse strategy1(@RequestBody CalculateDto dto) { 42 | Integer type = dto.getType(); 43 | CalculateService calculateService; 44 | 45 | if (Constant.CalculateTypeEnum.ADD.getType().equals(type)) { 46 | calculateService = addCalculateServiceImpl; 47 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 48 | calculateService = subtractCalculateServiceImpl; 49 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 50 | calculateService = multiplyCalculateServiceImpl; 51 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 52 | calculateService = divideCalculateServiceImpl; 53 | } else { 54 | throw new ServiceException("type error: " + type); 55 | } 56 | 57 | int result = calculateService.calculate(dto.getA(), dto.getB()); 58 | 59 | return ServerResponse.success(result); 60 | } 61 | 62 | @PostMapping("strategy2") 63 | public ServerResponse strategy2(@RequestBody CalculateDto dto) { 64 | CalculateService calculateService = getCalculateService(dto.getType()); 65 | int result = calculateService.calculate(dto.getA(), dto.getB()); 66 | return ServerResponse.success(result); 67 | } 68 | 69 | private CalculateService getCalculateService(Integer type) { 70 | CalculateService calculateService; 71 | 72 | if (Constant.CalculateTypeEnum.ADD.getType().equals(type)) { 73 | calculateService = addCalculateServiceImpl; 74 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 75 | calculateService = subtractCalculateServiceImpl; 76 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 77 | calculateService = multiplyCalculateServiceImpl; 78 | } else if (Constant.CalculateTypeEnum.SUBTRACT.getType().equals(type)) { 79 | calculateService = divideCalculateServiceImpl; 80 | } else { 81 | throw new ServiceException("type error: " + type); 82 | } 83 | 84 | return calculateService; 85 | } 86 | 87 | @PostMapping("strategy3") 88 | public ServerResponse strategy3(@RequestBody CalculateDto dto) { 89 | CalculateService calculateService = calculateServiceFactory.getCalculateService(dto.getType()); 90 | int result = calculateService.calculate(dto.getA(), dto.getB()); 91 | return ServerResponse.success(result); 92 | } 93 | 94 | @PostMapping("strategy4") 95 | public ServerResponse strategy4(@RequestBody CalculateDto dto) { 96 | CalculateService calculateService = CalculateStrategy.getCalculateService(dto.getType()); 97 | int result = calculateService.calculate(dto.getA(), dto.getB()); 98 | return ServerResponse.success(result); 99 | } 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/JedisUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | import redis.clients.jedis.Jedis; 7 | import redis.clients.jedis.JedisPool; 8 | 9 | @Component 10 | @Slf4j 11 | public class JedisUtil { 12 | 13 | @Autowired(required = false) 14 | private JedisPool jedisPool; 15 | 16 | private Jedis getJedis() { 17 | return jedisPool.getResource(); 18 | } 19 | 20 | /** 21 | * 设值 22 | * 23 | * @param key 24 | * @param value 25 | * @return 26 | */ 27 | public String set(String key, String value) { 28 | Jedis jedis = null; 29 | try { 30 | jedis = getJedis(); 31 | return jedis.set(key, value); 32 | } catch (Exception e) { 33 | log.error("set key: {} value: {} error", key, value, e); 34 | return null; 35 | } finally { 36 | close(jedis); 37 | } 38 | } 39 | 40 | /** 41 | * 设值 42 | * 43 | * @param key 44 | * @param value 45 | * @param expireTime 过期时间, 单位: s 46 | * @return 47 | */ 48 | public String set(String key, String value, int expireTime) { 49 | Jedis jedis = null; 50 | try { 51 | jedis = getJedis(); 52 | return jedis.setex(key, expireTime, value); 53 | } catch (Exception e) { 54 | log.error("set key:{} value:{} expireTime:{} error", key, value, expireTime, e); 55 | return null; 56 | } finally { 57 | close(jedis); 58 | } 59 | } 60 | 61 | /** 62 | * 设值 63 | * 64 | * @param key 65 | * @param value 66 | * @return 67 | */ 68 | public Long setnx(String key, String value) { 69 | Jedis jedis = null; 70 | try { 71 | jedis = getJedis(); 72 | return jedis.setnx(key, value); 73 | } catch (Exception e) { 74 | log.error("set key:{} value:{} error", key, value, e); 75 | return null; 76 | } finally { 77 | close(jedis); 78 | } 79 | } 80 | 81 | /** 82 | * 取值 83 | * 84 | * @param key 85 | * @return 86 | */ 87 | public String get(String key) { 88 | Jedis jedis = null; 89 | try { 90 | jedis = getJedis(); 91 | return jedis.get(key); 92 | } catch (Exception e) { 93 | log.error("get key:{} error", key, e); 94 | return null; 95 | } finally { 96 | close(jedis); 97 | } 98 | } 99 | 100 | /** 101 | * 删除key 102 | * 103 | * @param key 104 | * @return 105 | */ 106 | public Long del(String key) { 107 | Jedis jedis = null; 108 | try { 109 | jedis = getJedis(); 110 | return jedis.del(key.getBytes()); 111 | } catch (Exception e) { 112 | log.error("del key:{} error", key, e); 113 | return null; 114 | } finally { 115 | close(jedis); 116 | } 117 | } 118 | 119 | /** 120 | * 判断key是否存在 121 | * 122 | * @param key 123 | * @return 124 | */ 125 | public Boolean exists(String key) { 126 | Jedis jedis = null; 127 | try { 128 | jedis = getJedis(); 129 | return jedis.exists(key.getBytes()); 130 | } catch (Exception e) { 131 | log.error("exists key:{} error", key, e); 132 | return null; 133 | } finally { 134 | close(jedis); 135 | } 136 | } 137 | 138 | /** 139 | * 设值key过期时间 140 | * 141 | * @param key 142 | * @param expireTime 过期时间, 单位: s 143 | * @return 144 | */ 145 | public Long expire(String key, int expireTime) { 146 | Jedis jedis = null; 147 | try { 148 | jedis = getJedis(); 149 | return jedis.expire(key.getBytes(), expireTime); 150 | } catch (Exception e) { 151 | log.error("expire key:{} error", key, e); 152 | return null; 153 | } finally { 154 | close(jedis); 155 | } 156 | } 157 | 158 | /** 159 | * 获取剩余时间 160 | * 161 | * @param key 162 | * @return 163 | */ 164 | public Long ttl(String key) { 165 | Jedis jedis = null; 166 | try { 167 | jedis = getJedis(); 168 | return jedis.ttl(key); 169 | } catch (Exception e) { 170 | log.error("ttl key:{} error", key, e); 171 | return null; 172 | } finally { 173 | close(jedis); 174 | } 175 | } 176 | 177 | private void close(Jedis jedis) { 178 | if (null != jedis) { 179 | jedis.close(); 180 | } 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | https://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/OkHttpUtils.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import okhttp3.*; 5 | import org.apache.commons.lang3.exception.ExceptionUtils; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Map; 10 | 11 | @Slf4j 12 | @Component 13 | public class OkHttpUtils { 14 | 15 | private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); 16 | private static final MediaType XML = MediaType.parse("application/xml; charset=utf-8"); 17 | 18 | @Autowired 19 | private OkHttpClient okHttpClient; 20 | 21 | /** 22 | * get 请求 23 | * @param url 请求url地址 24 | * @return string 25 | * */ 26 | public String doGet(String url) { 27 | return doGet(url, null, null); 28 | } 29 | 30 | /** 31 | * get 请求 32 | * @param url 请求url地址 33 | * @param params 请求参数 map 34 | * @return string 35 | * */ 36 | public String doGet(String url, Map params) { 37 | return doGet(url, params, null); 38 | } 39 | 40 | /** 41 | * get 请求 42 | * @param url 请求url地址 43 | * @param headers 请求头字段 {k1, v1 k2, v2, ...} 44 | * @return string 45 | * */ 46 | public String doGet(String url, String[] headers) { 47 | return doGet(url, null, headers); 48 | } 49 | 50 | /** 51 | * get 请求 52 | * @param url 请求url地址 53 | * @param params 请求参数 map 54 | * @param headers 请求头字段 {k1, v1 k2, v2, ...} 55 | * @return string 56 | * */ 57 | public String doGet(String url, Map params, String[] headers) { 58 | StringBuilder sb = new StringBuilder(url); 59 | if (params != null && params.keySet().size() > 0) { 60 | boolean firstFlag = true; 61 | for (String key : params.keySet()) { 62 | if (firstFlag) { 63 | sb.append("?").append(key).append("=").append(params.get(key)); 64 | firstFlag = false; 65 | } else { 66 | sb.append("&").append(key).append("=").append(params.get(key)); 67 | } 68 | } 69 | } 70 | 71 | Request.Builder builder = new Request.Builder(); 72 | if (headers != null && headers.length > 0) { 73 | if (headers.length % 2 == 0) { 74 | for (int i = 0; i < headers.length; i = i + 2) { 75 | builder.addHeader(headers[i], headers[i + 1]); 76 | } 77 | } else { 78 | log.warn("headers's length[{}] is error.", headers.length); 79 | } 80 | 81 | } 82 | 83 | Request request = builder.url(sb.toString()).build(); 84 | log.info("do get request and url[{}]", sb.toString()); 85 | return execute(request); 86 | } 87 | 88 | /** 89 | * post 请求 90 | * @param url 请求url地址 91 | * @param params 请求参数 map 92 | * @return string 93 | */ 94 | public String doPost(String url, Map params) { 95 | FormBody.Builder builder = new FormBody.Builder(); 96 | 97 | if (params != null && params.keySet().size() > 0) { 98 | for (String key : params.keySet()) { 99 | builder.add(key, params.get(key)); 100 | } 101 | } 102 | Request request = new Request.Builder().url(url).post(builder.build()).build(); 103 | log.info("do post request and url[{}]", url); 104 | 105 | return execute(request); 106 | } 107 | 108 | 109 | /** 110 | * post 请求, 请求数据为 json 的字符串 111 | * @param url 请求url地址 112 | * @param json 请求数据, json 字符串 113 | * @return string 114 | */ 115 | public String doPostJson(String url, String json) { 116 | log.info("do post request and url[{}]", url); 117 | return exectePost(url, json, JSON); 118 | } 119 | 120 | /** 121 | * post 请求, 请求数据为 xml 的字符串 122 | * @param url 请求url地址 123 | * @param xml 请求数据, xml 字符串 124 | * @return string 125 | */ 126 | public String doPostXml(String url, String xml) { 127 | log.info("do post request and url[{}]", url); 128 | return exectePost(url, xml, XML); 129 | } 130 | 131 | 132 | private String exectePost(String url, String data, MediaType contentType) { 133 | RequestBody requestBody = RequestBody.create(contentType, data); 134 | Request request = new Request.Builder().url(url).post(requestBody).build(); 135 | 136 | return execute(request); 137 | } 138 | 139 | private String execute(Request request) { 140 | Response response = null; 141 | try { 142 | response = okHttpClient.newCall(request).execute(); 143 | if (response.isSuccessful()) { 144 | return response.body().string(); 145 | } 146 | } catch (Exception e) { 147 | log.error(ExceptionUtils.getStackTrace(e)); 148 | } finally { 149 | if (response != null) { 150 | response.close(); 151 | } 152 | } 153 | return ""; 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.controller; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.wangzaiplus.test.annotation.AccessLimit; 5 | import com.wangzaiplus.test.annotation.ApiIdempotent; 6 | import com.wangzaiplus.test.common.ServerResponse; 7 | import com.wangzaiplus.test.dto.UserDto; 8 | import com.wangzaiplus.test.mapper.MsgLogMapper; 9 | import com.wangzaiplus.test.mapper.UserMapper; 10 | import com.wangzaiplus.test.pojo.Mail; 11 | import com.wangzaiplus.test.pojo.User; 12 | import com.wangzaiplus.test.service.TestService; 13 | import com.wangzaiplus.test.service.batch.mapperproxy.MapperProxy; 14 | import com.wangzaiplus.test.util.MailUtil; 15 | import com.wangzaiplus.test.util.RandomUtil; 16 | import lombok.extern.slf4j.Slf4j; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.scheduling.annotation.Async; 19 | import org.springframework.validation.Errors; 20 | import org.springframework.validation.annotation.Validated; 21 | import org.springframework.web.bind.annotation.PostMapping; 22 | import org.springframework.web.bind.annotation.RequestBody; 23 | import org.springframework.web.bind.annotation.RequestMapping; 24 | import org.springframework.web.bind.annotation.RestController; 25 | 26 | import java.util.List; 27 | 28 | @RestController 29 | @RequestMapping("/test") 30 | @Slf4j 31 | public class TestController { 32 | 33 | @Autowired 34 | private TestService testService; 35 | 36 | @Autowired 37 | private UserMapper userMapper; 38 | 39 | @Autowired 40 | private MsgLogMapper msgLogMapper; 41 | 42 | @Autowired 43 | private MailUtil mailUtil; 44 | 45 | @ApiIdempotent 46 | @PostMapping("testIdempotence") 47 | public ServerResponse testIdempotence() { 48 | return testService.testIdempotence(); 49 | } 50 | 51 | @AccessLimit(maxCount = 5, seconds = 5) 52 | @PostMapping("accessLimit") 53 | public ServerResponse accessLimit() { 54 | return testService.accessLimit(); 55 | } 56 | 57 | @PostMapping("send") 58 | public ServerResponse sendMail(@Validated Mail mail, Errors errors) { 59 | if (errors.hasErrors()) { 60 | String msg = errors.getFieldError().getDefaultMessage(); 61 | return ServerResponse.error(msg); 62 | } 63 | 64 | return testService.send(mail); 65 | } 66 | 67 | @PostMapping("single") 68 | public ServerResponse single(int size) { 69 | List list = Lists.newArrayList(); 70 | 71 | for (int i = 0; i < size; i++) { 72 | String str = RandomUtil.UUID32(); 73 | User user = User.builder().username(str).password(str).build(); 74 | list.add(user); 75 | } 76 | 77 | long startTime = System.nanoTime(); 78 | log.info("batch insert costs: {} ms", (System.nanoTime() - startTime) / 1000000); 79 | 80 | return ServerResponse.success(); 81 | } 82 | 83 | @PostMapping("batchInsert") 84 | public ServerResponse batchInsert(int size) { 85 | List list = Lists.newArrayList(); 86 | 87 | for (int i = 0; i < size; i++) { 88 | String str = RandomUtil.UUID32(); 89 | User user = User.builder().username(str).password(str).build(); 90 | list.add(user); 91 | } 92 | 93 | new MapperProxy(userMapper).batchInsert(list); 94 | 95 | return ServerResponse.success(); 96 | } 97 | 98 | @PostMapping("batchUpdate") 99 | public ServerResponse batchUpdate(String ids) { 100 | List list = Lists.newArrayList(); 101 | 102 | String[] split = ids.split(","); 103 | for (String id : split) { 104 | User user = User.builder().id(Integer.valueOf(id)).username("batchUpdate_" + RandomUtil.UUID32()).password("123456").build(); 105 | list.add(user); 106 | } 107 | 108 | new MapperProxy(userMapper).batchUpdate(list); 109 | 110 | return ServerResponse.success(); 111 | } 112 | 113 | @PostMapping("sync") 114 | public ServerResponse sync() { 115 | List list = Lists.newArrayList(); 116 | for (int i = 0; i < 300; i++) { 117 | String uuid32 = RandomUtil.UUID32(); 118 | User user = User.builder().username(uuid32).password(uuid32).build(); 119 | list.add(user); 120 | } 121 | 122 | userMapper.batchInsert(list); 123 | 124 | check(list); 125 | 126 | return ServerResponse.success(); 127 | } 128 | 129 | @Async 130 | public void check(List list) { 131 | String username = list.get(list.size() - 1).getUsername(); 132 | User user = userMapper.selectByUsername(username); 133 | log.info(user.getUsername()); 134 | } 135 | 136 | @PostMapping("sendMail") 137 | public ServerResponse sendMail(@RequestBody Mail mail) { 138 | Mail build = Mail.builder().to(mail.getTo()).title(mail.getTitle()).content(mail.getContent()).build(); 139 | boolean send = mailUtil.send(build); 140 | return ServerResponse.success(send); 141 | } 142 | 143 | public static ThreadLocal userDtoThreadLocal = new ThreadLocal<>(); 144 | 145 | public static void main(String[] args) { 146 | userDtoThreadLocal.set(UserDto.builder().build()); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.5.RELEASE 9 | 10 | 11 | com.wangzaiplus 12 | test 13 | 0.0.1-SNAPSHOT 14 | test 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 2.9.0 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-web 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | 34 | org.redisson 35 | redisson 36 | 3.6.5 37 | 38 | 39 | 40 | redis.clients 41 | jedis 42 | ${jedis.version} 43 | 44 | 45 | 46 | org.mybatis.spring.boot 47 | mybatis-spring-boot-starter 48 | 2.0.0 49 | 50 | 51 | com.github.pagehelper 52 | pagehelper-spring-boot-starter 53 | 1.3.0 54 | 55 | 56 | 57 | mysql 58 | mysql-connector-java 59 | 60 | 61 | 62 | org.projectlombok 63 | lombok 64 | 1.16.10 65 | 66 | 67 | 68 | org.apache.commons 69 | commons-lang3 70 | 3.4 71 | 72 | 73 | 74 | org.springframework.boot 75 | spring-boot-starter-aop 76 | 77 | 78 | 79 | com.google.guava 80 | guava 81 | 26.0-jre 82 | 83 | 84 | 85 | joda-time 86 | joda-time 87 | 2.10 88 | 89 | 90 | 91 | org.springframework.boot 92 | spring-boot-starter-amqp 93 | 94 | 95 | 96 | org.springframework.boot 97 | spring-boot-starter-mail 98 | 99 | 100 | org.apache.commons 101 | commons-collections4 102 | 4.1 103 | 104 | 105 | com.alibaba 106 | druid 107 | 1.1.20 108 | 109 | 110 | org.jdom 111 | jdom 112 | 2.0.2 113 | 114 | 115 | com.squareup.okhttp3 116 | okhttp 117 | 3.10.0 118 | 119 | 120 | 121 | org.codehaus.groovy 122 | groovy-all 123 | 3.0.0 124 | pom 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | org.springframework.boot 133 | spring-boot-maven-plugin 134 | 135 | 136 | 137 | 138 | 139 | 140 | src/main/java 141 | 142 | **/*.* 143 | 144 | 145 | 146 | src/main/resources 147 | 148 | **/*.* 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | spring-snapshots 157 | Spring Snapshots 158 | https://repo.spring.io/snapshot 159 | 160 | true 161 | 162 | 163 | 164 | spring-milestones 165 | Spring Milestones 166 | https://repo.spring.io/milestone 167 | 168 | 169 | 170 | 171 | spring-snapshots 172 | Spring Snapshots 173 | https://repo.spring.io/snapshot 174 | 175 | true 176 | 177 | 178 | 179 | spring-milestones 180 | Spring Milestones 181 | https://repo.spring.io/milestone 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/common/Constant.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.common; 2 | 3 | import com.wangzaiplus.test.dto.FundRankDto; 4 | import com.wangzaiplus.test.dto.FundTypeDto; 5 | import com.wangzaiplus.test.dto.FundYieldDto; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.Optional; 10 | import java.util.stream.Collectors; 11 | 12 | public class Constant { 13 | 14 | public static final int MAX_SIZE_PER_TIME = 1000; 15 | public static final int INDEX_ZERO = 0; 16 | public static final int INDEX_ONE = 1; 17 | public static final int INDEX_TWO = 2; 18 | public static final int INDEX_THREE = 3; 19 | 20 | public static final int NUMBER_ZERO = 0; 21 | public static final int NUMBER_ONE = 1; 22 | 23 | public static final String COLON = ":"; 24 | public static final String COMMA = ","; 25 | public static final String DOUBLE_STRIGULA = "--"; 26 | public static final String REPLACEMENT_TARGET = "-99999%"; 27 | 28 | public static final String UNKNOWN_TYPE = "未知类型"; 29 | 30 | public interface Redis { 31 | String OK = "OK"; 32 | // 过期时间, 60s, 一分钟 33 | Integer EXPIRE_TIME_MINUTE = 60; 34 | // 过期时间, 一小时 35 | Integer EXPIRE_TIME_HOUR = 60 * 60; 36 | // 过期时间, 一天 37 | Integer EXPIRE_TIME_DAY = 60 * 60 * 24; 38 | String TOKEN_PREFIX = "token:"; 39 | String MSG_CONSUMER_PREFIX = "consumer:"; 40 | String ACCESS_LIMIT_PREFIX = "accessLimit:"; 41 | String FUND_RANK = "fundRank"; 42 | String FUND_LIST = "fundList"; 43 | } 44 | 45 | public interface LogType { 46 | // 登录 47 | Integer LOGIN = 1; 48 | // 登出 49 | Integer LOGOUT = 2; 50 | } 51 | 52 | public interface MsgLogStatus { 53 | // 消息投递中 54 | Integer DELIVERING = 0; 55 | // 投递成功 56 | Integer DELIVER_SUCCESS = 1; 57 | // 投递失败 58 | Integer DELIVER_FAIL = 2; 59 | // 已消费 60 | Integer CONSUMED_SUCCESS = 3; 61 | } 62 | 63 | public enum CalculateTypeEnum { 64 | ADD(1, "加"), 65 | SUBTRACT(2, "减"), 66 | MULTIPLY(3, "乘"), 67 | DIVIDE(4, "除") 68 | ; 69 | 70 | Integer type; 71 | String desc; 72 | 73 | CalculateTypeEnum(Integer type, String desc) { 74 | this.type = type; 75 | this.desc = desc; 76 | } 77 | 78 | public Integer getType() { 79 | return type; 80 | } 81 | 82 | public String getDesc() { 83 | return desc; 84 | } 85 | } 86 | 87 | public enum FundType { 88 | STOCK_FUND(1, "股票型"), 89 | HYBRID_FUND(2, "混合型"), 90 | BOND_FUND(3, "债券型"), 91 | INDEX_FUND(4, "指数型"), 92 | QDII(5, "QDII") 93 | ; 94 | 95 | private Integer type; 96 | private String desc; 97 | 98 | FundType(Integer type, String desc) { 99 | this.type = type; 100 | this.desc = desc; 101 | } 102 | 103 | public Integer getType() { 104 | return type; 105 | } 106 | 107 | public String getDesc() { 108 | return desc; 109 | } 110 | 111 | public static boolean contains(Integer type) { 112 | FundType[] values = FundType.values(); 113 | return Arrays.stream(values).filter(fundType -> fundType.getType() == type).findAny().isPresent(); 114 | } 115 | 116 | public static List getTypeList() { 117 | FundType[] values = FundType.values(); 118 | return Arrays.stream(values).map(fundType -> 119 | FundTypeDto.builder() 120 | .type(fundType.getType()) 121 | .desc(fundType.getDesc()) 122 | .build() 123 | ).collect(Collectors.toList()); 124 | } 125 | 126 | public static String getDescByType(Integer type) { 127 | FundType[] values = FundType.values(); 128 | Optional first = Arrays.stream(values).filter(fundType -> fundType.getType() == type).findFirst(); 129 | boolean exists = first.isPresent(); 130 | return exists ? first.get().getDesc() : UNKNOWN_TYPE; 131 | } 132 | } 133 | 134 | public enum FundYield { 135 | YIELD_OF_ONE_YEAR("yield_of_one_year", "近1年收益率"), 136 | YIELD_OF_TWO_YEAR("yield_of_two_year", "近2年收益率"), 137 | YIELD_OF_THREE_YEAR("yield_of_three_year", "近3年收益率"), 138 | YIELD_OF_FIVE_YEAR("yield_of_five_year", "近5年收益率") 139 | ; 140 | 141 | private String yield; 142 | private String desc; 143 | 144 | FundYield(String yield, String desc) { 145 | this.yield = yield; 146 | this.desc = desc; 147 | } 148 | 149 | public String getYield() { 150 | return yield; 151 | } 152 | 153 | public String getDesc() { 154 | return desc; 155 | } 156 | 157 | public static boolean contains(String yield) { 158 | FundYield[] values = FundYield.values(); 159 | return Arrays.stream(values).filter(fundYield -> fundYield.getYield().equals(yield)).findAny().isPresent(); 160 | } 161 | 162 | public static List getYieldList() { 163 | FundYield[] values = FundYield.values(); 164 | return Arrays.stream(values).map(fundYield -> 165 | FundYieldDto.builder() 166 | .yield(fundYield.getYield()) 167 | .desc(fundYield.getDesc()) 168 | .build() 169 | ).collect(Collectors.toList()); 170 | } 171 | } 172 | 173 | public enum FundRank { 174 | TOP_50(50, "前50"), 175 | TOP_100(100, "前100"), 176 | TOP_150(150, "前150"), 177 | TOP_200(200, "前200"), 178 | ; 179 | 180 | private Integer rank; 181 | private String desc; 182 | 183 | FundRank(Integer rank, String desc) { 184 | this.rank = rank; 185 | this.desc = desc; 186 | } 187 | 188 | public Integer getRank() { 189 | return rank; 190 | } 191 | 192 | public String getDesc() { 193 | return desc; 194 | } 195 | 196 | public static List getRankList() { 197 | FundRank[] values = FundRank.values(); 198 | return Arrays.stream(values).map(rank -> 199 | FundRankDto.builder() 200 | .rank(rank.getRank()) 201 | .desc(rank.getDesc()) 202 | .build() 203 | ).collect(Collectors.toList()); 204 | } 205 | } 206 | 207 | public enum FundSortType { 208 | ASC("asc"), 209 | DESC("desc"), 210 | ; 211 | 212 | private String type; 213 | 214 | FundSortType(String type) { 215 | this.type = type; 216 | } 217 | 218 | public String getType() { 219 | return type; 220 | } 221 | } 222 | 223 | } 224 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/JodaTimeUtil.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.apache.commons.lang3.StringUtils; 5 | import org.joda.time.DateTime; 6 | import org.joda.time.format.DateTimeFormat; 7 | import org.joda.time.format.DateTimeFormatter; 8 | 9 | import java.util.Date; 10 | 11 | @Slf4j 12 | public class JodaTimeUtil { 13 | 14 | private static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss"; 15 | 16 | /** 17 | * date类型 -> string类型 18 | * 19 | * @param date 20 | * @return 21 | */ 22 | public static String dateToStr(Date date) { 23 | return dateToStr(date, STANDARD_FORMAT); 24 | } 25 | 26 | /** 27 | * date类型 -> string类型 28 | * 29 | * @param date 30 | * @param format 自定义日期格式 31 | * @return 32 | */ 33 | public static String dateToStr(Date date, String format) { 34 | if (date == null) { 35 | return null; 36 | } 37 | 38 | format = StringUtils.isBlank(format) ? STANDARD_FORMAT : format; 39 | DateTime dateTime = new DateTime(date); 40 | return dateTime.toString(format); 41 | } 42 | 43 | /** 44 | * string类型 -> date类型 45 | * 46 | * @param timeStr 47 | * @return 48 | */ 49 | public static Date strToDate(String timeStr) { 50 | return strToDate(timeStr, STANDARD_FORMAT); 51 | } 52 | 53 | /** 54 | * string类型 -> date类型 55 | * 56 | * @param timeStr 57 | * @param format 自定义日期格式 58 | * @return 59 | */ 60 | public static Date strToDate(String timeStr, String format) { 61 | if (StringUtils.isBlank(timeStr)) { 62 | return null; 63 | } 64 | 65 | format = StringUtils.isBlank(format) ? STANDARD_FORMAT : format; 66 | 67 | DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(format); 68 | DateTime dateTime; 69 | try { 70 | dateTime = dateTimeFormatter.parseDateTime(timeStr); 71 | } catch (Exception e) { 72 | log.error("strToDate error: timeStr: {}", timeStr, e); 73 | return null; 74 | } 75 | 76 | return dateTime.toDate(); 77 | } 78 | 79 | /** 80 | * 判断date日期是否过期(与当前时刻比较) 81 | * 82 | * @param date 83 | * @return 84 | */ 85 | public static Boolean isTimeExpired(Date date) { 86 | String timeStr = dateToStr(date); 87 | return isBeforeNow(timeStr); 88 | } 89 | 90 | /** 91 | * 判断date日期是否过期(与当前时刻比较) 92 | * 93 | * @param timeStr 94 | * @return 95 | */ 96 | public static Boolean isTimeExpired(String timeStr) { 97 | if (StringUtils.isBlank(timeStr)) { 98 | return true; 99 | } 100 | 101 | return isBeforeNow(timeStr); 102 | } 103 | 104 | /** 105 | * 判断timeStr是否在当前时刻之前 106 | * 107 | * @param timeStr 108 | * @return 109 | */ 110 | private static Boolean isBeforeNow(String timeStr) { 111 | DateTimeFormatter format = DateTimeFormat.forPattern(STANDARD_FORMAT); 112 | DateTime dateTime; 113 | try { 114 | dateTime = DateTime.parse(timeStr, format); 115 | } catch (Exception e) { 116 | log.error("isBeforeNow error: timeStr: {}", timeStr, e); 117 | return null; 118 | } 119 | return dateTime.isBeforeNow(); 120 | } 121 | 122 | /** 123 | * 日期加天数 124 | * 125 | * @param date 126 | * @param days 127 | * @return 128 | */ 129 | public static Date plusDays(Date date, int days) { 130 | return plusOrMinusDays(date, days, 0); 131 | } 132 | 133 | /** 134 | * 日期减天数 135 | * 136 | * @param date 137 | * @param days 138 | * @return 139 | */ 140 | public static Date minusDays(Date date, int days) { 141 | return plusOrMinusDays(date, days, 1); 142 | } 143 | 144 | /** 145 | * 加减天数 146 | * 147 | * @param date 148 | * @param days 149 | * @param type 0:加天数 1:减天数 150 | * @return 151 | */ 152 | private static Date plusOrMinusDays(Date date, int days, Integer type) { 153 | if (null == date) { 154 | return null; 155 | } 156 | 157 | DateTime dateTime = new DateTime(date); 158 | if (type == 0) { 159 | dateTime = dateTime.plusDays(days); 160 | } else { 161 | dateTime = dateTime.minusDays(days); 162 | } 163 | 164 | return dateTime.toDate(); 165 | } 166 | 167 | /** 168 | * 日期加分钟 169 | * 170 | * @param date 171 | * @param minutes 172 | * @return 173 | */ 174 | public static Date plusMinutes(Date date, int minutes) { 175 | return plusOrMinusMinutes(date, minutes, 0); 176 | } 177 | 178 | /** 179 | * 日期减分钟 180 | * 181 | * @param date 182 | * @param minutes 183 | * @return 184 | */ 185 | public static Date minusMinutes(Date date, int minutes) { 186 | return plusOrMinusMinutes(date, minutes, 1); 187 | } 188 | 189 | /** 190 | * 加减分钟 191 | * 192 | * @param date 193 | * @param minutes 194 | * @param type 0:加分钟 1:减分钟 195 | * @return 196 | */ 197 | private static Date plusOrMinusMinutes(Date date, int minutes, Integer type) { 198 | if (null == date) { 199 | return null; 200 | } 201 | 202 | DateTime dateTime = new DateTime(date); 203 | if (type == 0) { 204 | dateTime = dateTime.plusMinutes(minutes); 205 | } else { 206 | dateTime = dateTime.minusMinutes(minutes); 207 | } 208 | 209 | return dateTime.toDate(); 210 | } 211 | 212 | /** 213 | * 日期加月份 214 | * 215 | * @param date 216 | * @param months 217 | * @return 218 | */ 219 | public static Date plusMonths(Date date, int months) { 220 | return plusOrMinusMonths(date, months, 0); 221 | } 222 | 223 | /** 224 | * 日期减月份 225 | * 226 | * @param date 227 | * @param months 228 | * @return 229 | */ 230 | public static Date minusMonths(Date date, int months) { 231 | return plusOrMinusMonths(date, months, 1); 232 | } 233 | 234 | /** 235 | * 加减月份 236 | * 237 | * @param date 238 | * @param months 239 | * @param type 0:加月份 1:减月份 240 | * @return 241 | */ 242 | private static Date plusOrMinusMonths(Date date, int months, Integer type) { 243 | if (null == date) { 244 | return null; 245 | } 246 | 247 | DateTime dateTime = new DateTime(date); 248 | if (type == 0) { 249 | dateTime = dateTime.plusMonths(months); 250 | } else { 251 | dateTime = dateTime.minusMonths(months); 252 | } 253 | 254 | return dateTime.toDate(); 255 | } 256 | 257 | /** 258 | * 判断target是否在开始和结束时间之间 259 | * 260 | * @param target 261 | * @param startTime 262 | * @param endTime 263 | * @return 264 | */ 265 | public static Boolean isBetweenStartAndEndTime(Date target, Date startTime, Date endTime) { 266 | if (null == target || null == startTime || null == endTime) { 267 | return false; 268 | } 269 | 270 | DateTime dateTime = new DateTime(target); 271 | return dateTime.isAfter(startTime.getTime()) && dateTime.isBefore(endTime.getTime()); 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/mapper/FundMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | id 26 | ,code 27 | ,name 28 | ,net_value 29 | ,yield_of_one_year 30 | ,yield_of_two_year 31 | ,yield_of_three_year 32 | ,yield_of_five_year 33 | ,type 34 | ,established_time 35 | ,asset 36 | ,manager 37 | ,status 38 | ,is_deleted 39 | ,created_time 40 | ,updated_time 41 | 42 | 43 | 48 | 49 | 55 | 56 | 57 | INSERT INTO fund( 58 | code 59 | ,name 60 | ,net_value 61 | ,yield_of_one_year 62 | ,yield_of_two_year 63 | ,yield_of_three_year 64 | ,yield_of_five_year 65 | ,type 66 | ,established_time 67 | ,asset 68 | ,manager 69 | ) 70 | VALUES ( 71 | #{code} 72 | ,#{name} 73 | ,#{netValue} 74 | ,#{yieldOfOneYear} 75 | ,#{yieldOfTwoYear} 76 | ,#{yieldOfThreeYear} 77 | ,#{yieldOfFiveYear} 78 | ,#{type} 79 | ,#{establishedTime} 80 | ,#{asset} 81 | ,#{manager} 82 | ) 83 | 84 | 85 | 86 | UPDATE fund SET 87 | 88 | code = #{code}, 89 | 90 | 91 | name = #{name}, 92 | 93 | 94 | net_value = #{netValue}, 95 | 96 | 97 | yield_of_one_year = #{yieldOfOneYear}, 98 | 99 | 100 | yield_of_two_year = #{yieldOfTwoYear}, 101 | 102 | 103 | yield_of_three_year = #{yieldOfThreeYear}, 104 | 105 | 106 | yield_of_five_year = #{yieldOfFiveYear}, 107 | 108 | 109 | type = #{type}, 110 | 111 | 112 | established_time = #{establishedTime}, 113 | 114 | 115 | asset = #{asset}, 116 | 117 | 118 | manager = #{manager}, 119 | 120 | 121 | status = #{status}, 122 | 123 | 124 | is_deleted = #{isDeleted}, 125 | 126 | updated_time = now() 127 | WHERE id = #{id} 128 | 129 | 130 | 131 | DELETE FROM fund WHERE id =#{id} 132 | 133 | 134 | 135 | insert into user(username, password, password2, password3, password4, password5, password6, 136 | password7, password8, password9, password10) 137 | values 138 | 139 | (#{item.username}, #{item.password}, #{item.password2}, #{item.password3}, 140 | #{item.password4}, #{item.password5}, #{item.password6}, #{item.password7}, 141 | #{item.password8}, #{item.password9}, #{item.password10}) 142 | 143 | 144 | 145 | 146 | update user 147 | 148 | 149 | 150 | when id = #{item.id} then #{item.username} 151 | 152 | 153 | 154 | 155 | when id = #{item.id} then #{item.password} 156 | 157 | 158 | 159 | where id in 160 | 161 | #{item.id} 162 | 163 | 164 | 165 | 171 | 172 | 181 | 182 | 190 | 191 | 202 | 203 | 212 | 213 | -------------------------------------------------------------------------------- /src/main/java/com/wangzaiplus/test/util/FundUtils.java: -------------------------------------------------------------------------------- 1 | package com.wangzaiplus.test.util; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.wangzaiplus.test.common.Constant; 5 | import com.wangzaiplus.test.dto.FundDto; 6 | import com.wangzaiplus.test.dto.FundJsonResponseDto; 7 | import com.wangzaiplus.test.exception.ServiceException; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.commons.collections4.CollectionUtils; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.jdom2.Document; 12 | import org.jdom2.Element; 13 | import org.jdom2.input.SAXBuilder; 14 | 15 | import java.io.ByteArrayInputStream; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.stream.Collectors; 19 | 20 | @Slf4j 21 | public class FundUtils { 22 | 23 | private static final String BODY = "tbody"; 24 | private static final String TR = "tr"; 25 | private static final String TD = "td"; 26 | private static final String COMMA = ","; 27 | private static final String QUESTION_MARK = "?"; 28 | private static final String COLS_NUM = "3,4,6,8,9,10,11"; 29 | private static final String PARAM_T = "t="; 30 | private static final String PARAM_PAGE = "&page=1&psize=50000"; 31 | 32 | public static final String FUND_URL = "http://fund.eastmoney.com/api/Dtshph.ashx"; 33 | 34 | public static List getFundDtoList(Integer type) { 35 | if (!Constant.FundType.contains(type)) { 36 | throw new ServiceException("type error: " + type); 37 | } 38 | 39 | List> lists = getFundData(type); 40 | if (CollectionUtils.isEmpty(lists)) { 41 | return null; 42 | } 43 | 44 | return lists.stream().map(list -> { 45 | FundDto dto = FundDto.builder().type(type).build(); 46 | try { 47 | BeanUtils.convert(list, dto); 48 | } catch (Exception e) { 49 | log.error("BeanUtils.convert error: " + e.getMessage(), e); 50 | } 51 | return dto; 52 | }).collect(Collectors.toList()); 53 | } 54 | 55 | public static List> getFundData(Integer type) { 56 | if (!Constant.FundType.contains(type)) { 57 | throw new ServiceException("type error: " + type); 58 | } 59 | 60 | OkHttpUtils httpUtils = SpringContextUtil.getBean(OkHttpUtils.class); 61 | try { 62 | String response = httpUtils.doGet(FUND_URL + QUESTION_MARK + PARAM_T + type + PARAM_PAGE); 63 | List> lists = parseTable(response); 64 | return extract(lists, COLS_NUM); 65 | } catch (Exception e) { 66 | log.error("request fund data error: " + e.getMessage(), e); 67 | return null; 68 | } 69 | } 70 | 71 | public static List> parse(String string) { 72 | String json = getJsonFromResponse(string); 73 | String data = getData(json); 74 | return extract(parseTable(data), COLS_NUM); 75 | } 76 | 77 | private static String getJsonFromResponse(String response) { 78 | if (StringUtils.isBlank(response)) { 79 | log.info("response is blank"); 80 | return null; 81 | } 82 | 83 | List list = extractMessage(response); 84 | if (CollectionUtils.isEmpty(list)) { 85 | log.info("extractFromBracket empty"); 86 | return null; 87 | } 88 | 89 | return list.get(Constant.INDEX_ZERO); 90 | } 91 | 92 | private static String getData(String json) { 93 | if (StringUtils.isBlank(json)) { 94 | return null; 95 | } 96 | 97 | FundJsonResponseDto dto = JsonUtil.strToObj(json, FundJsonResponseDto.class); 98 | if (null == dto) { 99 | return null; 100 | } 101 | 102 | return dto.getData(); 103 | } 104 | 105 | /** 106 | * 提取中括号中内容,忽略中括号中的中括号 107 | * @param msg 108 | * @return 109 | */ 110 | public static List extractMessage(String msg) { 111 | List list = new ArrayList<>(); 112 | int start = 0; 113 | int startFlag = 0; 114 | int endFlag = 0; 115 | for (int i = 0; i < msg.length(); i++) { 116 | if (msg.charAt(i) == '(') { 117 | startFlag++; 118 | if (startFlag == endFlag + 1) { 119 | start = i; 120 | } 121 | } else if (msg.charAt(i) == ')') { 122 | endFlag++; 123 | if (endFlag == startFlag) { 124 | list.add(msg.substring(start + 1, i)); 125 | } 126 | } 127 | } 128 | return list; 129 | } 130 | 131 | /** 132 | * 解析table中td元素 133 | * @param data 134 | * @return 135 | */ 136 | public static List> parseTable(String data) { 137 | if (StringUtils.isBlank(data)) { 138 | return null; 139 | } 140 | 141 | ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes()); 142 | Document document; 143 | try { 144 | document = new SAXBuilder().build(is); 145 | } catch (Exception e) { 146 | log.error("build error, " + e.getMessage(), e); 147 | return null; 148 | } 149 | 150 | Element root = document.getRootElement(); 151 | List bodyList = root.getChildren(BODY); 152 | if (CollectionUtils.isEmpty(bodyList)) { 153 | log.info("body empty"); 154 | return null; 155 | } 156 | 157 | Element element = bodyList.get(Constant.INDEX_ZERO); 158 | List trList = element.getChildren(TR); 159 | if (CollectionUtils.isEmpty(trList)) { 160 | log.info("tr empty"); 161 | return null; 162 | } 163 | 164 | List> parentList = Lists.newArrayList(); 165 | for (Element tr : trList) { 166 | List tdList = tr.getChildren(TD); 167 | if (CollectionUtils.isEmpty(tdList)) { 168 | log.info("td empty"); 169 | continue; 170 | } 171 | 172 | List childrenList = Lists.newArrayList(); 173 | for (Element td : tdList) { 174 | childrenList.add(td.getValue()); 175 | } 176 | 177 | parentList.add(childrenList); 178 | } 179 | 180 | return parentList; 181 | } 182 | 183 | /** 184 | * 提取指定列 185 | * @param lists 186 | * @param colsNum 187 | * @return 188 | */ 189 | private static List> extract(List> lists, String colsNum) { 190 | if (CollectionUtils.isEmpty(lists)) { 191 | return null; 192 | } 193 | 194 | for (List list : lists) { 195 | if (!checkCols(colsNum, list.size())) { 196 | return null; 197 | } 198 | } 199 | 200 | String[] split = colsNum.split(COMMA); 201 | List> parentList = Lists.newArrayList(); 202 | for (List list : lists) { 203 | List childrenList = Lists.newArrayList(); 204 | for (String s : split) { 205 | Integer colNum = Integer.valueOf(s.trim()); 206 | Integer colIndex = colNum - Constant.NUMBER_ONE; 207 | childrenList.add(list.get(colIndex)); 208 | } 209 | parentList.add(childrenList); 210 | } 211 | 212 | return parentList; 213 | } 214 | 215 | /** 216 | * 校验列序号是否合法 217 | * @param colsNum 如:1,2,5,8 218 | * @param size 219 | * @return 220 | */ 221 | private static boolean checkCols(String colsNum, int size) { 222 | if (StringUtils.isBlank(colsNum)) { 223 | return false; 224 | } 225 | 226 | String[] split = colsNum.split(COMMA); 227 | for (String col : split) { 228 | Integer colNum; 229 | try { 230 | colNum = Integer.valueOf(col.trim()); 231 | } catch (Exception e) { 232 | log.error("Integer.valueOf error, " + e.getMessage(), e); 233 | return false; 234 | } 235 | 236 | if (colNum < Constant.NUMBER_ONE) { 237 | log.error("colNum can't be less than 1"); 238 | return false; 239 | } 240 | 241 | if (colNum > size) { 242 | log.error("colNum: {} can't be greater than colSize: {}", colNum, size); 243 | return false; 244 | } 245 | } 246 | 247 | return true; 248 | } 249 | 250 | } 251 | --------------------------------------------------------------------------------