├── .gitignore ├── LICENSE ├── README.en.md ├── README.md ├── apijson ├── README.md ├── apijson.conf ├── apijson.rest ├── apijson.sql ├── bills.sql ├── checkcode.rest ├── district.sql ├── doc2fill.docx ├── pdnovel.rest ├── service.rest └── tables.sql ├── http_load.sh ├── knife4j ├── group.json └── swagger.json ├── my.pwd ├── pom.xml ├── postman.json ├── src ├── main │ ├── java │ │ ├── apijson │ │ │ ├── JSON.java │ │ │ ├── framework │ │ │ │ ├── APIJSONApplication.java │ │ │ │ └── APIJSONSQLExecutor.java │ │ │ └── orm │ │ │ │ └── AbstractParser.java │ │ ├── ch │ │ │ └── qos │ │ │ │ └── logback │ │ │ │ ├── classic │ │ │ │ └── redis │ │ │ │ │ └── RedisAppender.java │ │ │ │ └── core │ │ │ │ └── util │ │ │ │ └── ExecutorServiceUtil.java │ │ ├── com │ │ │ ├── alibaba │ │ │ │ └── druid │ │ │ │ │ └── util │ │ │ │ │ └── Base64.java │ │ │ ├── mysql │ │ │ │ └── jdbc │ │ │ │ │ ├── AbandonedConnectionCleanupThread$1.class │ │ │ │ │ ├── AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference.class │ │ │ │ │ ├── AbandonedConnectionCleanupThread.class │ │ │ │ │ └── AbandonedConnectionCleanupThread.java │ │ │ ├── networknt │ │ │ │ ├── client │ │ │ │ │ └── Http2Client.java │ │ │ │ ├── config │ │ │ │ │ ├── AesCrypto.java │ │ │ │ │ └── RefreshScope.java │ │ │ │ └── server │ │ │ │ │ ├── Servers.java │ │ │ │ │ └── UrlConfigLoader.java │ │ │ └── xlongwei │ │ │ │ └── light4j │ │ │ │ ├── Servers.java │ │ │ │ ├── apijson │ │ │ │ ├── DemoApplication.java │ │ │ │ ├── DemoController.java │ │ │ │ ├── DemoFunctionParser.java │ │ │ │ ├── DemoObjectParser.java │ │ │ │ ├── DemoParser.java │ │ │ │ ├── DemoSQLConfig.java │ │ │ │ ├── DemoSQLExecutor.java │ │ │ │ ├── DemoVerifier.java │ │ │ │ └── model │ │ │ │ │ ├── Privacy.java │ │ │ │ │ ├── User.java │ │ │ │ │ └── Verify.java │ │ │ │ ├── beetl │ │ │ │ ├── dao │ │ │ │ │ └── UserDao.java │ │ │ │ └── model │ │ │ │ │ ├── District.java │ │ │ │ │ ├── Ecdict.java │ │ │ │ │ └── User.java │ │ │ │ ├── handler │ │ │ │ ├── DemoHandler.java │ │ │ │ ├── ServiceHandler.java │ │ │ │ ├── UploadHandler.java │ │ │ │ ├── WeixinHandler.java │ │ │ │ ├── demo │ │ │ │ │ ├── IndexHandler.java │ │ │ │ │ └── LogHandler.java │ │ │ │ ├── service │ │ │ │ │ ├── AnsjHandler.java │ │ │ │ │ ├── ApijsonHandler.java │ │ │ │ │ ├── BankCardHandler.java │ │ │ │ │ ├── Base64ImageHandler.java │ │ │ │ │ ├── CheckcodeHandler.java │ │ │ │ │ ├── DatetimeHandler.java │ │ │ │ │ ├── DelayHandler.java │ │ │ │ │ ├── DesHandler.java │ │ │ │ │ ├── DictHandler.java │ │ │ │ │ ├── DistrictHandler.java │ │ │ │ │ ├── DocHandler.java │ │ │ │ │ ├── DruidHandler.java │ │ │ │ │ ├── ExamHandler.java │ │ │ │ │ ├── ExcelHandler.java │ │ │ │ │ ├── HtmlHandler.java │ │ │ │ │ ├── IdcardHandler.java │ │ │ │ │ ├── IpHandler.java │ │ │ │ │ ├── LayuiHandler.java │ │ │ │ │ ├── MobileHandler.java │ │ │ │ │ ├── MoneyHandler.java │ │ │ │ │ ├── PdfHandler.java │ │ │ │ │ ├── PdnovelHandler.java │ │ │ │ │ ├── PinyinHandler.java │ │ │ │ │ ├── PlateHandler.java │ │ │ │ │ ├── PropertyHandler.java │ │ │ │ │ ├── QrcodeHandler.java │ │ │ │ │ ├── RsaHandler.java │ │ │ │ │ ├── SequenceHandler.java │ │ │ │ │ ├── TrainHandler.java │ │ │ │ │ ├── UploadHandler.java │ │ │ │ │ ├── ValidateHandler.java │ │ │ │ │ └── WeixinHandler.java │ │ │ │ └── weixin │ │ │ │ │ ├── CalcHandler.java │ │ │ │ │ ├── ClickHandler.java │ │ │ │ │ ├── CounterHandler.java │ │ │ │ │ ├── DictHandler.java │ │ │ │ │ ├── FangdaiHandler.java │ │ │ │ │ ├── ImageHandler.java │ │ │ │ │ ├── KeyHandler.java │ │ │ │ │ ├── LocationHandler.java │ │ │ │ │ ├── NongliHandler.java │ │ │ │ │ ├── PinyinHandler.java │ │ │ │ │ ├── PlateHandler.java │ │ │ │ │ ├── PoetryHandler.java │ │ │ │ │ ├── PostHandler.java │ │ │ │ │ ├── SubscribeHandler.java │ │ │ │ │ ├── TrainHandler.java │ │ │ │ │ ├── VoiceHandler.java │ │ │ │ │ └── YoudaoHandler.java │ │ │ │ ├── openapi │ │ │ │ ├── OpenapiHandler.java │ │ │ │ ├── extend │ │ │ │ │ ├── DummyMiddlewareHandler.java │ │ │ │ │ ├── MyCorrelationHandler.java │ │ │ │ │ ├── MyJwtShiroHandler.java │ │ │ │ │ └── MyRedisSessionRepository.java │ │ │ │ └── handler │ │ │ │ │ ├── DatetimeHandler.java │ │ │ │ │ ├── ServiceHandler.java │ │ │ │ │ └── UploadHandler.java │ │ │ │ ├── provider │ │ │ │ ├── WebSocketAbstractCallback.java │ │ │ │ ├── WebSocketChatCallback.java │ │ │ │ ├── WebSocketHandlerProvider.java │ │ │ │ └── WebSocketServiceCallback.java │ │ │ │ └── util │ │ │ │ ├── AdtUtil.java │ │ │ │ ├── BankUtil.java │ │ │ │ ├── CardBin.java │ │ │ │ ├── ConfigUtil.java │ │ │ │ ├── DateUtil.java │ │ │ │ ├── DesUtil.java │ │ │ │ ├── DictUtil.java │ │ │ │ ├── DocxUtil.java │ │ │ │ ├── DruidUtil.java │ │ │ │ ├── EcdictUtil.java │ │ │ │ ├── ExcelUtil.java │ │ │ │ ├── ExecUtil.java │ │ │ │ ├── ExpUtil.java │ │ │ │ ├── ExpireTimeMap.java │ │ │ │ ├── FenciUtil.java │ │ │ │ ├── FileUtil.java │ │ │ │ ├── HandlerUtil.java │ │ │ │ ├── HolidayUtil.java │ │ │ │ ├── HtmlUtil.java │ │ │ │ ├── Http2Util.java │ │ │ │ ├── HttpSessionNetworknt.java │ │ │ │ ├── HttpSessionUndertow.java │ │ │ │ ├── HttpSessionWrapper.java │ │ │ │ ├── HttpUtil.java │ │ │ │ ├── IdCardUtil.java │ │ │ │ ├── IdWorker.java │ │ │ │ ├── ImageUtil.java │ │ │ │ ├── JsonUtil.java │ │ │ │ ├── MailUtil.java │ │ │ │ ├── MySqlUtil.java │ │ │ │ ├── NumberUtil.java │ │ │ │ ├── PathEndpointSource.java │ │ │ │ ├── PdfUtil.java │ │ │ │ ├── PdnovelUtil.java │ │ │ │ ├── PinyinUtil.java │ │ │ │ ├── PlateUtil.java │ │ │ │ ├── PostUtil.java │ │ │ │ ├── QnObject.java │ │ │ │ ├── RedisCache.java │ │ │ │ ├── RedisConfig.java │ │ │ │ ├── RedisPubsub.java │ │ │ │ ├── RedisUtil.java │ │ │ │ ├── RelationUtil.java │ │ │ │ ├── RsaUtil.java │ │ │ │ ├── SealUtil.java │ │ │ │ ├── ShiroUtil.java │ │ │ │ ├── SqlInsert.java │ │ │ │ ├── StringUtil.java │ │ │ │ ├── TaskUtil.java │ │ │ │ ├── ThrowingFunction.java │ │ │ │ ├── TokenCounter.java │ │ │ │ ├── TrainUtil.java │ │ │ │ ├── UploadUtil.java │ │ │ │ ├── WeixinUtil.java │ │ │ │ ├── WordUtil.java │ │ │ │ ├── XmlObject.java │ │ │ │ ├── ZhDate.java │ │ │ │ └── ZxingUtil.java │ │ ├── net │ │ │ └── sourceforge │ │ │ │ └── pinyin4j │ │ │ │ ├── PinyinHelper2.java │ │ │ │ └── multipinyin │ │ │ │ └── Trie.java │ │ └── unitauto │ │ │ └── MethodUtil.java │ └── resources │ │ ├── META-INF │ │ └── services │ │ │ └── java.sql.Driver │ │ ├── beetl │ │ ├── demo │ │ │ ├── index.html │ │ │ └── index │ │ │ │ ├── mysql.html │ │ │ │ └── script.html │ │ └── sql │ │ │ └── user.md │ │ ├── btsql-ext.properties │ │ ├── config │ │ ├── client.truststore │ │ ├── config.yml │ │ ├── consul.yml │ │ ├── correlation.yml │ │ ├── datetime.yml │ │ ├── handler.yml │ │ ├── jwt.yml │ │ ├── light4j.yml │ │ ├── openapi.yaml │ │ ├── secret.yml │ │ ├── security.yml │ │ ├── server.crt │ │ ├── server.keystore │ │ ├── server.yml │ │ ├── service.yml │ │ ├── startup.yml │ │ └── values.yml │ │ ├── houbb │ │ ├── char.txt │ │ ├── phrase.txt │ │ └── ts.txt │ │ ├── log4jdbc.properties │ │ ├── logback.xml │ │ ├── logserver.xml │ │ ├── public │ │ ├── chat.html │ │ └── exam.html │ │ ├── shiro.ini │ │ └── singleNodeConfig.json └── test │ └── java │ └── com │ └── xlongwei │ └── light4j │ ├── AesCryptoTest.java │ ├── BankUtilTest.java │ ├── ConsulTest.java │ ├── CrawlTest.java │ ├── DistrictUtilTest.java │ ├── EcdictTest.java │ ├── HolidayUtilTest.java │ ├── MySqlUtilTest.java │ ├── PinyinTest.java │ ├── QnObjectTest.java │ ├── RedisTest.java │ └── ZhDateTest.java ├── start.bat └── start.sh /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | bower_components/ 3 | node_modules/ 4 | dist/ 5 | .history 6 | .idea/ 7 | .settings 8 | *.iml 9 | *.log 10 | *.tmp 11 | *.zip 12 | dependency-reduced-pom.xml 13 | 14 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 15 | hs_err_pid* 16 | 17 | .metadata 18 | bin/ 19 | tmp/ 20 | logs 21 | *.tmp 22 | *.bak 23 | *.swp 24 | *~.nib 25 | local.properties 26 | .settings 27 | .vscode 28 | .loadpath 29 | .recommenders 30 | .classpath 31 | .project 32 | .class 33 | 34 | # External tool builders 35 | .externalToolBuilders/ 36 | 37 | # Locally stored "Eclipse launch configurations" 38 | *.launch 39 | 40 | # PyDev specific (Python IDE for Eclipse) 41 | *.pydevproject 42 | 43 | # CDT-specific (C/C++ Development Tooling) 44 | .cproject 45 | 46 | # CDT- autotools 47 | .autotools 48 | 49 | # Java annotation processor (APT) 50 | .factorypath 51 | 52 | # PDT-specific (PHP Development Tools) 53 | .buildpath 54 | 55 | # sbteclipse plugin 56 | .target 57 | 58 | # Tern plugin 59 | .tern-project 60 | 61 | # TeXlipse plugin 62 | .texlipse 63 | 64 | # STS (Spring Tool Suite) 65 | .springBeans 66 | 67 | # Code Recommenders 68 | .recommenders/ 69 | 70 | # Annotation Processing 71 | .apt_generated/ 72 | 73 | # Scala IDE specific (Scala & Java development for Eclipse) 74 | .cache-main 75 | .scala_dependencies 76 | .worksheet 77 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # light4j 2 | 3 | #### Description 4 | a microservice project using light-4j 5 | 6 | #### Software Architecture 7 | Software architecture description 8 | 9 | #### Installation 10 | 11 | 1. redis-server 12 | 2. sh start.sh install 13 | 3. mvn compile 14 | 4. mvn exec:exec 15 | 16 | profile "debug" is activated by default. 17 | 18 | #### Instructions 19 | 20 | 1. rewrite configs in config/light4j.yml 21 | 22 | -Dupload.save=/soft/uploads -Dlight4j.directory=/soft/softwares/library/ 23 | 24 | 2. append logs to logserver or logfile 25 | 26 | -Dlogserver -Dlogfile=path/log 27 | 28 | ### Debug 29 | 30 | 1. com.networknt.server.Server 31 | 32 | you can config vm arguments -Dupload.save=/soft/uploads -Dlight4j.directory=/soft/softwares/library/ 33 | 34 | 2. using postman(chrome plugin) to import postman.json 35 | 36 | #### Deploy 37 | 38 | 1. mvn compile jar:jar 39 | 40 | 2. mvn dependency:copy-dependencies -DoutputDirectory=target/deploy 41 | 42 | 3. copy target/light4j-3.0.1.jar target/deploy 43 | 44 | you need only upload "deploy" directory once, after that you just need to update light4j-3.0.1.jar. 45 | 46 | 4. java -Dlight4j.directory=H:/works/itecheast/Servers/library/ -Dupload.save=H:/works/itecheast/Servers/uploads/ -jar target/deploy/light4j-3.0.1.jar 47 | 48 | redis-server is required. "mvn package -P release -Dmaven.javadoc.skip=true" will package one-jar "target/light4j-3.0.1.jar" that can be deployed also. 49 | 50 | #### Features 51 | 52 | 1. lombok 53 | 54 | org.projectlombok:lombok:1.16.18+ 55 | 56 | 2. logback if/else 57 | 58 | org.codehaus.janino:janino:2.6.1 59 | 60 | ### Test 61 | 62 | By default, all endpoints are protected by OAuth jwt token verifier. It can be turned off with config change through for development. 63 | 64 | 65 | In order to access the server, there is a long lived token below issued by my 66 | oauth2 server [light-oauth2](https://github.com/networknt/light-oauth2) 67 | 68 | ``` 69 | Bearer eyJraWQiOiIxMDAiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ1cm46Y29tOm5ldHdvcmtudDpvYXV0aDI6djEiLCJhdWQiOiJ1cm46Y29tLm5ldHdvcmtudCIsImV4cCI6MTg4MjUwNjM1NiwianRpIjoiQTlaUHVjM3RsS1BoWmM0RnpzTlJjQSIsImlhdCI6MTU2NzE0NjM1NiwibmJmIjoxNTY3MTQ2MjM2LCJ2ZXJzaW9uIjoiMS4wIiwidXNlcl9pZCI6ImFkbWluIn0.Jb89PTAOY7zDQBUpLS-5L9iDz28__fBUhXgmXqjXByiu6HG1sSemHHs-C0n-ZFUH4Tn3yfVbcHndSjNtVQ__gZMmpKi4PCg7NTiSo7TZZmVYI9uinQEdnDlFT2YA97AL6jBCGJW2Ol6q-odSajpCdoMfOh9KM2yXKQPqr95P5v4Du7L-MNL8dW7evfa0gBpGA2FF4Sr4txerS_SXJg3ED4_px_WbbkqZYpzo6_MupNK9nfJVG7ycP50r21-HMrSnBR7pUN1JvF8mxpfmcQi8j0W4TiYFZV2PKV2AGqsJ9d4IuPu--3YHNpevG3Pv78982o6qK22o_4h4Z8VFzr_NUQ 70 | ``` 71 | 72 | Postman is the best tool to test REST APIs 73 | 74 | Add "Authorization" header with value as above token and a dummy message will return from the generated stub. 75 | 76 | 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # light4j 2 | 3 | #### 项目简介 4 | 使用light-4j构建的微服务接口应用 5 | 6 | #### 本地测试 7 | 1. 获取依赖:sh start.sh install,项目构建:sh start.sh package 8 | 2. 启动缓存:redis-server,运行项目:start.bat 9 | 3. 测试访问:[chat](http://localhost:8080/ws/chat.html),[datetime](http://localhost:8080/service/datetime.json) 10 | 4. VSCode+Mysql:"vmArgs": "-Dapijson.enabled=true", "env": {"db.hostPort": "host:port"} 11 | 12 | #### 线上部署 13 | 1. 获取依赖:sh start.sh install,项目打包:sh start.sh deploy 14 | 2. 提取脚本:jar xvf light4j.jar start.sh,修改配置:vi start.sh 15 | 3. 启动缓存:redis-server,运行服务:sh start.sh start 16 | 17 | #### 配置说明 18 | vi start.sh 19 | 20 | 1. -Dredis.configDb、-Dredis.cacheDbs,配置redis地址 21 | 2. -Dlight4j.directory,相关资源可在[library](http://t.xlongwei.com/softwares/library/)获取 22 | 3. -Dlogserver,在/etc/hosts配置logserver地址:127.0.0.1 logserver 23 | 4. -DcontextName=light4j,修改应用的日志上下文 24 | 5. -Djava.compiler=none,禁用JIT可节约内存,默认启用JIT可提高性能 25 | 6. https、registry可自行研究,sh start.sh keystore转换密钥为相关文件 26 | 27 | #### 其他说明 28 | 29 | 1. WeixinHandler支持响应微信公众号消息,关注xlongwei试试[help](https://api.xlongwei.com/service/weixin/chat.json?text=help) 30 | 2. LayuiHandler和openapi支持前后端分离,参考[admin](http://layui.xlongwei.com/admin/) 31 | 3. WebSocketHandlerProvider支持web socket消息,参考[chat](https://api.xlongwei.com:8443/ws/chat.html) 32 | -------------------------------------------------------------------------------- /apijson/apijson.conf: -------------------------------------------------------------------------------- 1 | server { 2 | # http://apijson.cn/api/ APIAuto不支持/service/apijson,因此用独立子域名apijson提供服务 3 | server_name apijson.xlongwei.com; 4 | location / { 5 | if ( $request_method = OPTIONS ) { 6 | add_header Access-Control-Allow-Origin $http_origin; 7 | add_header Access-Control-Allow-Credentials 'true'; 8 | add_header Access-Control-Allow-Methods 'GET, PUT, POST, DELETE, HEAD, OPTIONS'; 9 | add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; 10 | return 204; 11 | } 12 | proxy_pass http://localhost:8080/service/apijson/; 13 | } 14 | location /method/ { 15 | if ( $request_method = OPTIONS ) { 16 | add_header Access-Control-Allow-Origin $http_origin; 17 | add_header Access-Control-Allow-Credentials 'true'; 18 | add_header Access-Control-Allow-Methods 'GET, PUT, POST, DELETE, HEAD, OPTIONS'; 19 | add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; 20 | return 204; 21 | } 22 | # /method/list => /service/apijson/method_list 23 | proxy_pass http://localhost:8080/service/apijson/method_; 24 | } 25 | location /unit/ { 26 | alias E:/GITHUB/APIJSON/UnitAuto/UnitAuto-Admin/; 27 | autoindex on; 28 | } 29 | } -------------------------------------------------------------------------------- /apijson/bills.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `bills` ( 2 | `_id` char(24) NOT NULL, 3 | `apiCode` smallint(6) DEFAULT NULL, 4 | `apiName` varchar(11) DEFAULT NULL, 5 | `slaveId` char(24) DEFAULT NULL, 6 | `slaveName` varchar(14) DEFAULT NULL, 7 | `payTime` datetime DEFAULT NULL, 8 | `realPayMoney` smallint(6) DEFAULT NULL, 9 | PRIMARY KEY (`_id`) 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='bills'; 11 | SELECT apiCode 12 | ,apiName 13 | ,COUNT(*) AS num 14 | ,SUM(realPayMoney)/1000.0 AS sum 15 | FROM bills 16 | GROUP BY apiCode ORDER BY num desc; -------------------------------------------------------------------------------- /apijson/checkcode.rest: -------------------------------------------------------------------------------- 1 | @host=http://localhost:8080 2 | @checkcode={{host}}/service/checkcode 3 | ### type=-2字母数字 4 | {{checkcode}}/code?secure=false 5 | ### type=-1随机取0汉字 1算术 2拆字 6 | {{checkcode}}/code?secure=false&type=-1 7 | ### type=-3三方easy-captcha style支持spec gif chinese arithmetic chinesegif 8 | {{checkcode}}/code?secure=false&type=-3&style=random 9 | ### image 获取验证码图片 type支持-3|-4|空 10 | {{checkcode}}/image?checkcode=1234&type=&ajax=true 11 | ### image 直接拿图片,需提供sid 12 | {{checkcode}}/image?sid=12345678901234&type= 13 | ### type=-4三方hutool style=circle gif shear line 14 | {{checkcode}}/code?secure=false&type=-4&style=random 15 | ### type=-5三方tianai style=ROTATE CONCAT WORD_IMAGE_CLICK 16 | {{checkcode}}/code?secure=false&type=-5&style=RANDOM 17 | ### check行为验证码 18 | {{checkcode}}/check?checkcode=0.3169491&sid=1560884810192494594 -------------------------------------------------------------------------------- /apijson/doc2fill.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xlongwei/light4j/16d0030e8aae1ed9f7b7687c3a05f43cbb88a5a6/apijson/doc2fill.docx -------------------------------------------------------------------------------- /apijson/pdnovel.rest: -------------------------------------------------------------------------------- 1 | 2 | @host=http://localhost:8080 3 | @service={{host}}/service 4 | ### grant all privileges on bbs.* to apijson; 5 | @pdnovel={{service}}/pdnovel 6 | ### 书 7 | {{pdnovel}}/books 8 | ### 卷 9 | {{pdnovel}}/volumes?novelid=1 10 | ### 章 11 | {{pdnovel}}/chapters?novelid=1&volumeid=1 12 | ### 延迟队列 13 | @delay={{service}}/delay 14 | {{delay}}?delay=3&unit=SECONDS&url=https://api.xlongwei.com/service/datetime 15 | ### X-Traceability-Id: 用于跟踪日志 16 | {{service}}/?handler=datetime&path=isworkday 17 | X-Traceability-Id: {{$guid}} 18 | ### X-Handler-Path指定handler/path,与/service/handler/path的概念一致 19 | {{service}}/ 20 | X-Handler-Path: datetime/isworkday -------------------------------------------------------------------------------- /http_load.sh: -------------------------------------------------------------------------------- 1 | hostPort=localhost:8080 2 | clients=3 3 | seconds=5 4 | 5 | echo "http://$hostPort/ws/ok" > /tmp/urls.txt 6 | http_load -parallel $clients -seconds $seconds /tmp/urls.txt 7 | -------------------------------------------------------------------------------- /knife4j/group.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "name" : "swagger", 3 | "url" : "/json/swagger.json", 4 | "swaggerVersion" : "2.0" 5 | } ] 6 | -------------------------------------------------------------------------------- /my.pwd: -------------------------------------------------------------------------------- 1 | #daemon=true 2 | #profile="-P mysql5" 3 | #includeCallerData=false 4 | token=xlongwei 5 | ipsConfig=service.controller.ips.config -------------------------------------------------------------------------------- /src/main/java/ch/qos/logback/core/util/ExecutorServiceUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Logback: the reliable, generic, fast and flexible logging framework. 3 | * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 4 | * 5 | * This program and the accompanying materials are dual-licensed under 6 | * either the terms of the Eclipse Public License v1.0 as published by 7 | * the Eclipse Foundation 8 | * 9 | * or (per the licensee's choosing) 10 | * 11 | * under the terms of the GNU Lesser General Public License version 2.1 12 | * as published by the Free Software Foundation. 13 | */ 14 | package ch.qos.logback.core.util; 15 | 16 | import java.util.List; 17 | import java.util.concurrent.Callable; 18 | import java.util.concurrent.ExecutorService; 19 | import java.util.concurrent.Executors; 20 | import java.util.concurrent.Future; 21 | import java.util.concurrent.ScheduledExecutorService; 22 | import java.util.concurrent.ScheduledThreadPoolExecutor; 23 | import java.util.concurrent.ThreadFactory; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | /** 27 | * Static utility methods for manipulating an {@link ExecutorService}. 28 | * 29 | * @author Carl Harris 30 | * @author Mikhail Mazursky 31 | */ 32 | public class ExecutorServiceUtil { 33 | 34 | private static final ThreadFactory THREAD_FACTORY = new ThreadFactory() { 35 | 36 | private final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); 37 | private final AtomicInteger threadNumber = new AtomicInteger(1); 38 | 39 | public Thread newThread(Runnable r) { 40 | Thread thread = defaultFactory.newThread(r); 41 | if (!thread.isDaemon()) { 42 | thread.setDaemon(true); 43 | } 44 | thread.setName("logback-" + threadNumber.getAndIncrement()); 45 | return thread; 46 | } 47 | }; 48 | 49 | public static final LogbackScheduler scheduler = new LogbackScheduler(1, THREAD_FACTORY); 50 | 51 | public static ScheduledExecutorService newScheduledExecutorService() { 52 | return scheduler; 53 | } 54 | 55 | /** 56 | * Creates an executor service suitable for use by logback components. 57 | * @return executor service 58 | */ 59 | public static ExecutorService newExecutorService() { 60 | return scheduler.getExecutorService(); 61 | } 62 | 63 | /** 64 | * Shuts down an executor service. 65 | *

66 | * @param executorService the executor service to shut down 67 | */ 68 | public static void shutdown(ExecutorService executorService) { 69 | executorService.shutdownNow(); 70 | } 71 | 72 | /** 73 | * ScheduledThreadPoolExecutor不会按需创建新的线程,logback调用submit、execute时可能会长期占用线程,导致缺少线程执行scheduleWithFixedDelay等定时任务, 74 | * 因此LogbackScheduler创建额外的线程池来执行此类耗时任务 75 | */ 76 | public static class LogbackScheduler extends ScheduledThreadPoolExecutor { 77 | ExecutorService es = null; 78 | public LogbackScheduler(int corePoolSize, ThreadFactory threadFactory) { 79 | super(corePoolSize, threadFactory); 80 | es = Executors.newCachedThreadPool(threadFactory); 81 | } 82 | public ExecutorService getExecutorService() { 83 | return es; 84 | } 85 | @Override 86 | public void execute(Runnable command) { 87 | es.execute(command); 88 | } 89 | @Override 90 | public Future submit(Runnable task) { 91 | return es.submit(task); 92 | } 93 | @Override 94 | public Future submit(Runnable task, T result) { 95 | return es.submit(task, result); 96 | } 97 | @Override 98 | public Future submit(Callable task) { 99 | return es.submit(task); 100 | } 101 | @Override 102 | public void shutdown() { 103 | super.shutdown(); 104 | es.shutdown(); 105 | } 106 | @Override 107 | public List shutdownNow() { 108 | es.shutdownNow(); 109 | return super.shutdownNow(); 110 | } 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/mysql/jdbc/AbandonedConnectionCleanupThread$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xlongwei/light4j/16d0030e8aae1ed9f7b7687c3a05f43cbb88a5a6/src/main/java/com/mysql/jdbc/AbandonedConnectionCleanupThread$1.class -------------------------------------------------------------------------------- /src/main/java/com/mysql/jdbc/AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xlongwei/light4j/16d0030e8aae1ed9f7b7687c3a05f43cbb88a5a6/src/main/java/com/mysql/jdbc/AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference.class -------------------------------------------------------------------------------- /src/main/java/com/mysql/jdbc/AbandonedConnectionCleanupThread.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xlongwei/light4j/16d0030e8aae1ed9f7b7687c3a05f43cbb88a5a6/src/main/java/com/mysql/jdbc/AbandonedConnectionCleanupThread.class -------------------------------------------------------------------------------- /src/main/java/com/networknt/config/RefreshScope.java: -------------------------------------------------------------------------------- 1 | package com.networknt.config; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Map; 5 | 6 | import net.sf.cglib.proxy.Enhancer; 7 | import net.sf.cglib.proxy.MethodInterceptor; 8 | import net.sf.cglib.proxy.MethodProxy; 9 | 10 | /** 11 | * 相比Config.getJsonObjectConfig、getJsonMapConfig增加一层代理,获取配置时直接从缓存取值,以便刷新配置后可以实时更新相应配置 12 | * @author xlongwei 13 | * 14 | */ 15 | @SuppressWarnings("unchecked") 16 | public class RefreshScope { 17 | 18 | public static T getJsonObjectConfig(String configName, Class clazz) { 19 | return (T)create(new JsonObjectConfigCallback(configName, clazz, "")); 20 | } 21 | 22 | public static T getJsonObjectConfig(String configName, Class clazz, String path) { 23 | return (T)create(new JsonObjectConfigCallback(configName, clazz, path)); 24 | } 25 | 26 | public static Map getJsonMapConfig(String configName) { 27 | return (Map)create(new JsonMapConfigCallback(configName, Map.class, "")); 28 | } 29 | 30 | public static Map getJsonMapConfig(String configName, String path) { 31 | return (Map)create(new JsonMapConfigCallback(configName, Map.class, path)); 32 | } 33 | 34 | static Object create(ConfigCallback cc) { 35 | final Enhancer enhancer = new Enhancer(); 36 | enhancer.setSuperclass(cc.clazz); 37 | enhancer.setCallback(cc); 38 | return enhancer.create(); 39 | } 40 | 41 | static abstract class ConfigCallback implements MethodInterceptor { 42 | String configName, path; 43 | Class clazz; 44 | abstract Object getConfig(); 45 | ConfigCallback(String configName, Class clazz, String path){ 46 | this.configName = configName; 47 | this.clazz = clazz; 48 | this.path = path; 49 | } 50 | @Override 51 | public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 52 | Object config = getConfig(); 53 | return proxy.invoke(config, args); 54 | } 55 | } 56 | 57 | static class JsonObjectConfigCallback extends ConfigCallback { 58 | public JsonObjectConfigCallback(String configName, Class clazz, String path) { 59 | super(configName, clazz, path); 60 | } 61 | @Override 62 | Object getConfig() { 63 | return Config.getInstance().getJsonObjectConfig(configName, clazz, path); 64 | } 65 | } 66 | 67 | static class JsonMapConfigCallback extends ConfigCallback { 68 | public JsonMapConfigCallback(String configName, Class clazz, String path) { 69 | super(configName, clazz, path); 70 | } 71 | @Override 72 | Object getConfig() { 73 | return Config.getInstance().getJsonMapConfig(configName, path); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/Servers.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j; 2 | 3 | import com.networknt.server.Server; 4 | import com.networknt.server.ServerConfig; 5 | 6 | /** 7 | * listen both http and https 8 | * @author xlongwei 9 | * 10 | */ 11 | public class Servers { 12 | 13 | public static void main(String[] args) { 14 | ServerConfig serverConfig = Server.getServerConfig(); 15 | boolean enableHttps = serverConfig.isEnableHttps(); 16 | boolean enableRegistry = serverConfig.isEnableRegistry(); 17 | if(enableHttps==false && enableRegistry) { 18 | //http启动时禁用enableRegistry 19 | serverConfig.setEnableRegistry(false); 20 | } 21 | Server.main(args); 22 | if(enableHttps==false) { 23 | serverConfig.setEnableHttps(true); 24 | serverConfig.setEnableRegistry(enableRegistry); 25 | Server.main(args); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/apijson/DemoObjectParser.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package com.xlongwei.light4j.apijson; 16 | 17 | import java.util.List; 18 | 19 | import javax.servlet.http.HttpSession; 20 | 21 | import com.alibaba.fastjson.JSONObject; 22 | 23 | import apijson.NotNull; 24 | import apijson.RequestMethod; 25 | import apijson.framework.APIJSONObjectParser; 26 | import apijson.orm.AbstractParser; 27 | import apijson.orm.Join; 28 | import apijson.orm.SQLConfig; 29 | 30 | 31 | /**简化Parser,getObject和getArray(getArrayConfig)都能用 32 | * @author Lemon 33 | */ 34 | public class DemoObjectParser extends APIJSONObjectParser { 35 | 36 | public DemoObjectParser(HttpSession session, @NotNull JSONObject request, String parentPath, SQLConfig arrayConfig 37 | , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { 38 | super(session, request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable); 39 | } 40 | 41 | @Override 42 | public DemoObjectParser setMethod(RequestMethod method) { 43 | super.setMethod(method); 44 | return this; 45 | } 46 | 47 | @Override 48 | public DemoObjectParser setParser(AbstractParser parser) { 49 | super.setParser(parser); 50 | return this; 51 | } 52 | 53 | 54 | @Override 55 | public SQLConfig newSQLConfig(RequestMethod method, String table, String alias, JSONObject request, List joinList, boolean isProcedure) throws Exception { 56 | return DemoSQLConfig.newSQLConfig(method, table, alias, request, joinList, isProcedure); 57 | } 58 | 59 | @Override 60 | public JSONObject parseResponse(SQLConfig config, boolean isProcedure) throws Exception { 61 | try{ 62 | return super.parseResponse(config, isProcedure); 63 | }finally { 64 | if(parser.getSQLExecutor() != null) { 65 | parser.getSQLExecutor().close(); 66 | } 67 | } 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/apijson/DemoParser.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package com.xlongwei.light4j.apijson; 16 | 17 | import com.alibaba.fastjson.JSONObject; 18 | 19 | import apijson.RequestMethod; 20 | import apijson.framework.APIJSONObjectParser; 21 | import apijson.framework.APIJSONParser; 22 | import apijson.orm.SQLConfig; 23 | import apijson.orm.SQLCreator; 24 | import apijson.orm.SQLExecutor; 25 | 26 | 27 | /**请求解析器 28 | * @author Lemon 29 | */ 30 | public class DemoParser extends APIJSONParser { 31 | 32 | public DemoParser() { 33 | super(); 34 | } 35 | public DemoParser(RequestMethod method) { 36 | super(method); 37 | } 38 | public DemoParser(RequestMethod method, boolean needVerify) { 39 | super(method, needVerify); 40 | } 41 | 42 | /** 43 | * bug修复:父类parseResponse总是调createSQLExecutor,而getStructure是正确的,问题为修改时借了两个数据库连接,最后只还了一个,原因为sqlExecutor被覆盖,没有调用到close方法 44 | * @return 每个parser只有一个sqlExecutor,并且每次都有close 45 | */ 46 | @Override 47 | public SQLExecutor createSQLExecutor() { 48 | if(sqlExecutor == null) { 49 | sqlExecutor = super.createSQLExecutor(); 50 | } 51 | return sqlExecutor; 52 | } 53 | @Override 54 | public JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, String name, 55 | JSONObject request, int maxUpdateCount, SQLCreator creator) throws Exception { 56 | try{ 57 | return super.parseCorrectRequest(method, tag, version, name, request, maxUpdateCount, creator); 58 | }finally { 59 | if(sqlExecutor != null) { 60 | sqlExecutor.close(); 61 | } 62 | } 63 | } 64 | 65 | //可重写来设置最大查询数量 66 | @Override 67 | public int getMaxQueryCount() { 68 | return 1000; 69 | } 70 | @Override 71 | public int getMaxQueryPage() { 72 | return 10000; 73 | } 74 | 75 | @Override 76 | public APIJSONObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig 77 | , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { 78 | return new DemoObjectParser(getSession(), request, parentPath, arrayConfig 79 | , isSubquery, isTable, isArrayMainTable).setMethod(getMethod()).setParser(this); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/apijson/DemoSQLExecutor.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package com.xlongwei.light4j.apijson; 16 | 17 | import apijson.framework.APIJSONSQLExecutor; 18 | 19 | 20 | /**executor for query(read) or update(write) MySQL database 21 | * @author Lemon 22 | */ 23 | public class DemoSQLExecutor extends APIJSONSQLExecutor { 24 | public static final String TAG = "DemoSQLExecutor"; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/apijson/DemoVerifier.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package com.xlongwei.light4j.apijson; 16 | 17 | 18 | import apijson.framework.APIJSONVerifier; 19 | 20 | 21 | /**权限验证器 22 | * @author Lemon 23 | */ 24 | public class DemoVerifier extends APIJSONVerifier { 25 | public static final String TAG = "DemoVerifier"; 26 | 27 | // 重写方法来自定义字段名等 28 | // @Override 29 | // public String getVisitorIdKey(SQLConfig config) { 30 | // return super.getVisitorIdKey(config); // return "userid"; // return "uid" 等自定义的字段名 31 | // } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/apijson/model/Privacy.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package com.xlongwei.light4j.apijson.model; 16 | 17 | import static apijson.RequestRole.ADMIN; 18 | import static apijson.RequestRole.OWNER; 19 | import static apijson.RequestRole.UNKNOWN; 20 | 21 | import com.alibaba.fastjson.annotation.JSONField; 22 | 23 | import apijson.MethodAccess; 24 | import apijson.framework.BaseModel; 25 | 26 | /** 27 | * 漏洞:如果GETS允许CONTACT,则CONTACT能看到自己的余额,tag可以不是Privacy-circle。 28 | * 所以需要在Request表中增加role字段。或者干脆这里GETS只允许OWNER, ADMIN,需要用其它角色查时走独立接口。 29 | */ 30 | /**用户隐私信息 31 | * @author Lemon 32 | */ 33 | @MethodAccess( 34 | GET = {}, 35 | GETS = {OWNER, ADMIN}, 36 | POST = {UNKNOWN, ADMIN}, 37 | DELETE = {ADMIN} 38 | ) 39 | public class Privacy extends BaseModel { 40 | private static final long serialVersionUID = 1L; 41 | 42 | public static final int PASSWORD_TYPE_LOGIN = 0; 43 | public static final int PASSWORD_TYPE_PAY = 1; 44 | 45 | private String phone; //手机 46 | private String password; //登录密码,隐藏字段 47 | private String payPassword; //支付密码,隐藏字段 48 | private Double balance; //余额 49 | 50 | public Privacy() { 51 | super(); 52 | } 53 | 54 | public Privacy(long id) { 55 | this(); 56 | setId(id); 57 | } 58 | 59 | public Privacy(String phone, String password) { 60 | this(); 61 | setPhone(phone); 62 | setPassword(password); 63 | } 64 | 65 | 66 | 67 | public String getPhone() { 68 | return phone; 69 | } 70 | public Privacy setPhone(String phone) { 71 | this.phone = phone; 72 | return this; 73 | } 74 | 75 | /**fastjson-1.2.71会解析为__password,因此使用注解指定名称*/ 76 | @JSONField(name="_password") 77 | public String get__password() { 78 | return password; 79 | } 80 | public Privacy setPassword(String password) { 81 | this.password = password; 82 | return this; 83 | } 84 | 85 | /**fastjson-1.2.71会解析为__password,因此使用注解指定名称*/ 86 | @JSONField(name="_payPassword") 87 | public String get__payPassword() { 88 | return payPassword; 89 | } 90 | public Privacy setPayPassword(String payPassword) { 91 | this.payPassword = payPassword; 92 | return this; 93 | } 94 | 95 | public Double getBalance() { 96 | return balance; 97 | } 98 | public Privacy setBalance(Double balance) { 99 | this.balance = balance; 100 | return this; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/apijson/model/User.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package com.xlongwei.light4j.apijson.model; 16 | 17 | import static apijson.RequestRole.ADMIN; 18 | import static apijson.RequestRole.UNKNOWN; 19 | 20 | import java.util.List; 21 | 22 | import apijson.MethodAccess; 23 | import apijson.framework.BaseModel; 24 | import apijson.orm.Visitor; 25 | 26 | /**用户开放信息 27 | * @author Lemon 28 | */ 29 | @MethodAccess( 30 | POST = {UNKNOWN, ADMIN}, 31 | DELETE = {ADMIN} 32 | ) 33 | public class User extends BaseModel implements Visitor { 34 | private static final long serialVersionUID = 1L; 35 | 36 | public static final int SEX_MAIL = 0; 37 | public static final int SEX_FEMALE = 1; 38 | public static final int SEX_UNKNOWN = 2; 39 | 40 | 41 | private Integer sex; //性别 42 | private String head; //头像url 43 | private String name; //姓名 44 | private String tag; //标签 45 | private List pictureList; //照片列表 46 | private List contactIdList; //朋友列表 47 | 48 | /**默认构造方法,JSON等解析时必须要有 49 | */ 50 | public User() { 51 | super(); 52 | } 53 | public User(long id) { 54 | this(); 55 | setId(id); 56 | } 57 | 58 | public Integer getSex() { 59 | return sex; 60 | } 61 | public User setSex(Integer sex) { 62 | this.sex = sex; 63 | return this; 64 | } 65 | public String getHead() { 66 | return head; 67 | } 68 | public User setHead(String head) { 69 | this.head = head; 70 | return this; 71 | } 72 | public String getName() { 73 | return name; 74 | } 75 | public User setName(String name) { 76 | this.name = name; 77 | return this; 78 | } 79 | public List getPictureList() { 80 | return pictureList; 81 | } 82 | public User setPictureList(List pictureList) { 83 | this.pictureList = pictureList; 84 | return this; 85 | } 86 | 87 | public String getTag() { 88 | return tag; 89 | } 90 | public User setTag(String tag) { 91 | this.tag = tag; 92 | return this; 93 | } 94 | @Override 95 | public List getContactIdList() { 96 | return contactIdList; 97 | } 98 | public User setContactIdList(List contactIdList) { 99 | this.contactIdList = contactIdList; 100 | return this; 101 | } 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/apijson/model/Verify.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package com.xlongwei.light4j.apijson.model; 16 | 17 | import static apijson.RequestRole.ADMIN; 18 | import static apijson.RequestRole.CIRCLE; 19 | import static apijson.RequestRole.CONTACT; 20 | import static apijson.RequestRole.LOGIN; 21 | import static apijson.RequestRole.OWNER; 22 | import static apijson.RequestRole.UNKNOWN; 23 | 24 | import apijson.MethodAccess; 25 | import apijson.framework.BaseModel; 26 | 27 | /**验证码 28 | * @author Lemon 29 | */ 30 | @MethodAccess( 31 | GET = {}, 32 | HEAD = {}, 33 | GETS = {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN}, 34 | HEADS = {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN}, 35 | POST = {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN}, 36 | PUT = {ADMIN}, 37 | DELETE = {ADMIN} 38 | ) 39 | public class Verify extends BaseModel { 40 | private static final long serialVersionUID = 1L; 41 | 42 | public static final int TYPE_LOGIN = 0; //登录 43 | public static final int TYPE_REGISTER = 1; //注册 44 | public static final int TYPE_PASSWORD = 2; //登录密码 45 | public static final int TYPE_PAY_PASSWORD = 3; //支付密码 46 | public static final int TYPE_RELOAD = 4; //重载配置 47 | 48 | private String phone; //手机 49 | private String verify; //验证码 50 | private Integer type; //验证类型 51 | 52 | public Verify() { 53 | super(); 54 | } 55 | /**type和phone为联合主键,必传 56 | * @param type 57 | * @param phone 58 | */ 59 | public Verify(int type, String phone) { 60 | this(); 61 | setType(type); 62 | setPhone(phone); 63 | } 64 | 65 | 66 | public String getVerify() { 67 | return verify; 68 | } 69 | public Verify setVerify(String verify) { 70 | this.verify = verify; 71 | return this; 72 | } 73 | 74 | public String getPhone() { 75 | return phone; 76 | } 77 | public Verify setPhone(String phone) { 78 | this.phone = phone; 79 | return this; 80 | } 81 | 82 | public Integer getType() { 83 | return type; 84 | } 85 | public Verify setType(Integer type) { 86 | this.type = type; 87 | return this; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/beetl/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.beetl.dao; 2 | 3 | import java.util.List; 4 | 5 | import org.beetl.sql.mapper.BaseMapper; 6 | 7 | import com.xlongwei.light4j.beetl.model.User; 8 | 9 | public interface UserDao extends BaseMapper { 10 | /** sample */ 11 | List sample(User user); 12 | } -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/beetl/model/District.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.beetl.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class District { 7 | private String province; 8 | private String provinceName; 9 | private String city; 10 | private String cityName; 11 | private String county; 12 | private String countyName; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/beetl/model/Ecdict.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.beetl.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Ecdict { 7 | private String word; 8 | private String phonetic; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/beetl/model/User.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.beetl.model; 2 | 3 | import java.util.Date; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class User { 9 | private Integer id; 10 | private Integer age; 11 | private String name; 12 | private Date createDate; 13 | 14 | } -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/DemoHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler; 2 | 3 | import java.util.Deque; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | import com.networknt.handler.LightHttpHandler; 9 | import com.networknt.utility.StringUtils; 10 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 11 | import com.xlongwei.light4j.util.HandlerUtil; 12 | import com.xlongwei.light4j.util.PathEndpointSource; 13 | import com.xlongwei.light4j.util.StringUtil; 14 | 15 | import cn.hutool.core.util.ClassUtil; 16 | import cn.hutool.core.util.ReflectUtil; 17 | import cn.hutool.extra.template.Template; 18 | import cn.hutool.extra.template.TemplateConfig; 19 | import cn.hutool.extra.template.TemplateConfig.ResourceMode; 20 | import cn.hutool.extra.template.TemplateEngine; 21 | import cn.hutool.extra.template.TemplateUtil; 22 | import io.undertow.server.HttpServerExchange; 23 | import io.undertow.util.Headers; 24 | import lombok.extern.slf4j.Slf4j; 25 | 26 | /** 27 | * demo handler 28 | * @author xlongwei 29 | * 30 | */ 31 | @Slf4j 32 | public class DemoHandler implements LightHttpHandler { 33 | public static final TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("beetl/demo", ResourceMode.CLASSPATH)); 34 | private Map handlers = new HashMap<>(); 35 | 36 | public DemoHandler() { 37 | String pkg = getClass().getPackage().getName()+".demo"; 38 | Set> list = ClassUtil.scanPackageBySuper(pkg, AbstractHandler.class); 39 | for(Class clazz : list) { 40 | AbstractHandler handler = (AbstractHandler)ReflectUtil.newInstanceIfPossible(clazz); 41 | String name = handler.name(); 42 | handlers.put(name, handler); 43 | log.info("demo {} => {}", name, handler.getClass().getName()); 44 | } 45 | } 46 | 47 | @Override 48 | public void handleRequest(HttpServerExchange exchange) throws Exception { 49 | Map> queryParameters = exchange.getQueryParameters(); 50 | String service = queryParameters.remove("*").getFirst(); 51 | log.info("{} {}", exchange.getRequestMethod(), exchange.getRequestURI()); 52 | int dot = service.indexOf('.'); 53 | String[] split = StringUtils.split(dot>0 ? service.substring(0, dot) : service, "/"); 54 | String name = split.length>0 ? split[0] : "index", path = split.length>1 ? split[1] : ""; 55 | AbstractHandler handler = handlers.get(name); 56 | if(handler != null) { 57 | exchange.putAttachment(AbstractHandler.PATH, path); 58 | HandlerUtil.parseBody(exchange); 59 | handler.handleRequest(exchange); 60 | String accept = exchange.getRequestHeaders().getFirst(Headers.ACCEPT); 61 | if (accept == null || !accept.contains("html")) { 62 | HandlerUtil.sendResp(exchange); 63 | return; 64 | } 65 | } 66 | Template template = engine.getTemplate((StringUtil.isBlank(path) ? name : name+"/"+path)+".html"); 67 | String html = template.render((Map)exchange.getAttachment(HandlerUtil.RESP)); 68 | if(StringUtils.isBlank(html)) { 69 | HandlerUtil.sendResp(exchange); 70 | }else { 71 | exchange.removeAttachment(HandlerUtil.RESP); 72 | exchange.setStatusCode(200); 73 | exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, "text/html"); 74 | exchange.getResponseSender().send(html); 75 | } 76 | } 77 | 78 | public static class DemoEndpointSource extends PathEndpointSource { 79 | public DemoEndpointSource() { 80 | super("/demo/*"); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/UploadHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler; 2 | 3 | import java.io.File; 4 | import java.util.Deque; 5 | import java.util.Map; 6 | 7 | import com.networknt.handler.LightHttpHandler; 8 | import com.xlongwei.light4j.util.HandlerUtil; 9 | import com.xlongwei.light4j.util.NumberUtil; 10 | import com.xlongwei.light4j.util.StringUtil; 11 | import com.xlongwei.light4j.util.UploadUtil; 12 | 13 | import io.undertow.server.HttpServerExchange; 14 | import io.undertow.server.handlers.form.FormData.FormValue; 15 | import lombok.extern.slf4j.Slf4j; 16 | 17 | /** 18 | * 上传服务 19 | * @author xlongwei 20 | * 21 | */ 22 | @Slf4j 23 | public class UploadHandler implements LightHttpHandler { 24 | 25 | @Override 26 | public void handleRequest(HttpServerExchange exchange) throws Exception { 27 | Map> queryParameters = exchange.getQueryParameters(); 28 | String service = queryParameters.remove("*").getFirst(); 29 | log.info("{} {}", exchange.getRequestMethod(), exchange.getRequestURI()); 30 | int dot = service.indexOf('.'); 31 | String name = dot==-1 ? service : service.substring(0, dot); 32 | HandlerUtil.parseBody(exchange); 33 | if(name.length()==0 || UploadUtil.TEMP.equals(name) || UploadUtil.DIRECT.equals(name)) { 34 | //上传文件 35 | upload(exchange, name); 36 | }else if(UploadUtil.CONFIRM.equals(name) || UploadUtil.TRASH.equals(name)) { 37 | //移动文件 38 | move(exchange, name); 39 | } 40 | HandlerUtil.sendResp(exchange); 41 | } 42 | 43 | private void upload(HttpServerExchange exchange, String name) { 44 | FormValue file = HandlerUtil.getFile(exchange, "file"); 45 | if(file!=null && file.isFileItem()) { 46 | String type = StringUtil.firstNotBlank(HandlerUtil.getParam(exchange, "type"), "image"); 47 | //temp方式重命名 direct方式默认不重命名,保存目录也不同 48 | boolean temp = UploadUtil.DIRECT.equals(name) ? false : true; 49 | boolean rename = temp ? true : NumberUtil.parseBoolean(HandlerUtil.getParam(exchange, "rename"), Boolean.FALSE); 50 | String fileName = file.getFileName(); 51 | String path = rename ? UploadUtil.path(type, fileName) : type+"/"+fileName; 52 | File target = new File(temp ? UploadUtil.SAVE_TEMP : UploadUtil.SAVE, path); 53 | try { 54 | boolean save = UploadUtil.save(file.getFileItem().getInputStream(), target); 55 | log.info("direct upload save={}, file={}, size={}K, path={}", save, fileName, target.length()/1024, path); 56 | if(save) { 57 | String string = UploadUtil.string((temp ? UploadUtil.URL_TEMP : UploadUtil.URL) + "," + path); 58 | exchange.putAttachment(HandlerUtil.RESP, string); 59 | } 60 | }catch(Exception e) { 61 | log.warn("fail to {} upload file, ex:{}", name, e.getMessage()); 62 | } 63 | } 64 | } 65 | 66 | private void move(HttpServerExchange exchange, String name) { 67 | String path = HandlerUtil.getParam(exchange, "path"); 68 | boolean move = UploadUtil.move(path, name); 69 | exchange.putAttachment(HandlerUtil.RESP, move ? "1" : "0"); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/WeixinHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import com.networknt.handler.LightHttpHandler; 8 | import com.xlongwei.light4j.util.HandlerUtil; 9 | import com.xlongwei.light4j.util.StringUtil; 10 | import com.xlongwei.light4j.util.WeixinUtil; 11 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage; 12 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler; 13 | 14 | import cn.hutool.core.util.ClassUtil; 15 | import cn.hutool.core.util.ReflectUtil; 16 | import io.undertow.server.HttpServerExchange; 17 | import lombok.extern.slf4j.Slf4j; 18 | 19 | /** 20 | * weixin handler 21 | * @author xlongwei 22 | * 23 | */ 24 | @Slf4j 25 | @SuppressWarnings({"rawtypes"}) 26 | public class WeixinHandler implements LightHttpHandler { 27 | 28 | public WeixinHandler() { 29 | String pkg = getClass().getPackage().getName()+".weixin"; 30 | List> list = new ArrayList<>(ClassUtil.scanPackageBySuper(pkg, AbstractMessageHandler.class)); 31 | Collections.sort(list, (a,b)->{ return a.getName().compareTo(b.getName()); }); 32 | for(Class clazz : list) { 33 | AbstractMessageHandler handler = (AbstractMessageHandler)ReflectUtil.newInstanceIfPossible(clazz); 34 | WeixinUtil.register(handler); 35 | } 36 | } 37 | 38 | @Override 39 | public void handleRequest(HttpServerExchange exchange) throws Exception { 40 | HandlerUtil.parseBody(exchange); 41 | String echostr = HandlerUtil.getParam(exchange, "echostr"); 42 | String timestamp = HandlerUtil.getParam(exchange, "timestamp"); 43 | String nonce = HandlerUtil.getParam(exchange, "nonce"); 44 | if(!StringUtil.isBlank(echostr)) { 45 | String signature = HandlerUtil.getParam(exchange, "signature"); 46 | String token = HandlerUtil.getParam(exchange, "token"); 47 | String response = WeixinUtil.checkSignature(signature, timestamp, nonce, token) ? echostr : ""; 48 | exchange.getResponseSender().send(response); 49 | log.info("echostr: {}, timestamp: {}, nonce: {}, signature: {}, token: {}", echostr, timestamp, nonce, signature, token); 50 | }else { 51 | String xml = HandlerUtil.getBodyString(exchange); 52 | boolean aes = "aes".equals(HandlerUtil.getParam(exchange, "encrypt_type")); 53 | log.info("timestamp: {}, nonce: {}, aes: {}", timestamp, nonce, aes); 54 | if(aes) { 55 | String msgSignature = HandlerUtil.getParam(exchange, "msg_signature"); 56 | String decrypt = WeixinUtil.decrypt(WeixinUtil.appid, msgSignature, timestamp, nonce, xml); 57 | log.info("msg_signature: {}, decrypt: {}", msgSignature, decrypt); 58 | xml = decrypt; 59 | } 60 | AbstractMessage msg = StringUtil.isBlank(xml) ? null : AbstractMessage.fromXML(xml); 61 | msg = msg == null ? null : WeixinUtil.dispatch(msg); 62 | xml = msg !=null ? msg.toXML() : ""; 63 | log.info("response: {}", xml); 64 | if(aes && !StringUtil.isBlank(xml)) { 65 | String encrypt = WeixinUtil.encrypt(WeixinUtil.appid, xml, timestamp, nonce); 66 | log.info("encrypt: {}", encrypt); 67 | xml = encrypt; 68 | } 69 | exchange.getResponseSender().send(xml); 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/demo/IndexHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.demo; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | 6 | import javax.script.ScriptContext; 7 | import javax.script.SimpleScriptContext; 8 | 9 | import org.beetl.sql.core.SQLReady; 10 | import org.beetl.sql.core.SqlId; 11 | 12 | import com.networknt.config.Config; 13 | import com.networknt.server.Servers; 14 | import com.xlongwei.light4j.beetl.dao.UserDao; 15 | import com.xlongwei.light4j.beetl.model.User; 16 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 17 | import com.xlongwei.light4j.handler.service.IpHandler; 18 | import com.xlongwei.light4j.util.HandlerUtil; 19 | import com.xlongwei.light4j.util.JsonUtil; 20 | import com.xlongwei.light4j.util.MySqlUtil; 21 | import com.xlongwei.light4j.util.RedisConfig; 22 | import com.xlongwei.light4j.util.StringUtil; 23 | import com.xlongwei.light4j.util.TaskUtil; 24 | 25 | import cn.hutool.script.ScriptUtil; 26 | import io.undertow.server.HttpServerExchange; 27 | import lombok.extern.slf4j.Slf4j; 28 | 29 | /** 30 | * beetl index demo 31 | * @author xlongwei 32 | * 33 | */ 34 | @Slf4j 35 | public class IndexHandler extends AbstractHandler { 36 | 37 | public void index(HttpServerExchange exchange) throws Exception { 38 | String ip = HandlerUtil.getIp(exchange); 39 | String region = IpHandler.searchToMap(ip).get("region"); 40 | HandlerUtil.setResp(exchange, StringUtil.params("ip", ip, "region", region)); 41 | } 42 | 43 | public void mysql(HttpServerExchange exchange) throws Exception { 44 | String type = StringUtil.firstNotBlank(HandlerUtil.getParam(exchange, "type"), "tables"); 45 | Object obj = null; 46 | switch(type) { 47 | case "all": obj = MySqlUtil.SQLMANAGER.all(User.class); break; 48 | case "sql": obj = MySqlUtil.SQLMANAGER.select(SqlId.of("user.sample"), User.class); break; 49 | case "dao": obj = MySqlUtil.SQLMANAGER.getMapper(UserDao.class).all(); break; 50 | default: obj = MySqlUtil.SQLMANAGER.getMetaDataManager().allTable(); break; 51 | } 52 | HandlerUtil.setResp(exchange, Collections.singletonMap("allTable", obj)); 53 | } 54 | 55 | public void refresh(HttpServerExchange exchange) throws Exception { 56 | Map startup = Config.getInstance().getJsonMapConfig(Servers.STARTUP_CONFIG_NAME); 57 | Servers.loadConfigs(); 58 | HandlerUtil.setResp(exchange, startup); 59 | } 60 | 61 | public void script(HttpServerExchange exchange) throws Exception { 62 | String script = HandlerUtil.getParam(exchange, "script"); 63 | if(!StringUtil.isBlank(script)) { 64 | ScriptContext context = new SimpleScriptContext(); 65 | context.setAttribute("log", log, ScriptContext.ENGINE_SCOPE); 66 | context.setAttribute("util", new Util(), ScriptContext.ENGINE_SCOPE); 67 | TaskUtil.submit(()->{ 68 | ScriptUtil.eval(script, context); 69 | }); 70 | } 71 | HandlerUtil.setResp(exchange, exchange.getAttachment(HandlerUtil.BODY)); 72 | } 73 | 74 | public static class Util { 75 | public Map hgetall(String key) { 76 | return StringUtil.isBlank(key) ? Collections.emptyMap() : RedisConfig.hgetAll(RedisConfig.CACHE, key); 77 | } 78 | public String get(String json, String path) { 79 | return StringUtil.isBlank(json) || StringUtil.isBlank(path) ? "" : JsonUtil.get(json, path); 80 | } 81 | /** 仅支持insert ignore | into,replace ,不能有分号 */ 82 | public void insert(String sql, Object ... args) { 83 | if(!StringUtil.isBlank(sql) && !sql.contains(";") && (sql.startsWith("insert ") || sql.startsWith("replace ")) ) { 84 | MySqlUtil.SQLMANAGER.executeUpdate(new SQLReady(sql, args)); 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/demo/LogHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.demo; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Objects; 8 | import java.util.stream.Collectors; 9 | 10 | import org.slf4j.LoggerFactory; 11 | 12 | import com.networknt.utility.StringUtils; 13 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 14 | import com.xlongwei.light4j.util.HandlerUtil; 15 | 16 | import ch.qos.logback.classic.Level; 17 | import ch.qos.logback.classic.LoggerContext; 18 | import cn.hutool.core.map.MapUtil; 19 | import io.undertow.server.HttpServerExchange; 20 | import lombok.extern.slf4j.Slf4j; 21 | 22 | /** 23 | * log handler 24 | * @author xlongwei 25 | */ 26 | @Slf4j 27 | public class LogHandler extends AbstractHandler { 28 | public static final String token = System.getProperty("token"); 29 | 30 | public void log(HttpServerExchange exchange) throws Exception { 31 | LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 32 | String loggerName = HandlerUtil.getParam(exchange, "logger"); 33 | List loggers = null; 34 | if (StringUtils.isNotBlank(loggerName)) { 35 | ch.qos.logback.classic.Logger logger = lc.getLogger(loggerName); 36 | if (logger != null) { 37 | loggers = Arrays.asList(logger); 38 | String levelName = HandlerUtil.getParam(exchange, "level"); 39 | if (StringUtils.isNotBlank(levelName) 40 | && (StringUtils.isBlank(token) || token.equals(HandlerUtil.getParam(exchange, "token")))) { 41 | Level level = Level.toLevel(levelName, null); 42 | log.warn("change logger:{} level from:{} to:{}", logger.getName(), logger.getLevel(), level); 43 | logger.setLevel(level); 44 | } 45 | } 46 | } 47 | if (loggers == null) { 48 | loggers = lc.getLoggerList(); 49 | } 50 | log.info("check logger level, loggers:{}", loggers.size()); 51 | List> list = loggers.stream().sorted((a, b) -> a.getName().compareTo(b.getName())) 52 | .map(logger -> { 53 | Map map = new HashMap<>(4); 54 | map.put("logger", logger.getName()); 55 | map.put("level", Objects.toString(logger.getLevel(), "")); 56 | return map; 57 | }).collect(Collectors.toList()); 58 | HandlerUtil.setResp(exchange, MapUtil.of("loggers", list)); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/service/AnsjHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.service; 2 | // 3 | //import java.util.List; 4 | //import java.util.ListIterator; 5 | // 6 | //import com.networknt.utility.StringUtils; 7 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 8 | //import com.xlongwei.light4j.util.FenciUtil; 9 | //import com.xlongwei.light4j.util.FenciUtil.Method; 10 | //import com.xlongwei.light4j.util.HandlerUtil; 11 | //import com.xlongwei.light4j.util.NumberUtil; 12 | //import com.xlongwei.light4j.util.StringUtil; 13 | // 14 | //import io.undertow.server.HttpServerExchange; 15 | // 16 | /** 17 | * ansj handler 18 | * @author xlongwei 19 | * 20 | */ 21 | public class AnsjHandler extends AbstractHandler { 22 | // 23 | // @Override 24 | // public void handleRequest(HttpServerExchange exchange) throws Exception { 25 | // String path = exchange.getAttachment(AbstractHandler.PATH); 26 | // if(StringUtils.isBlank(path)) { 27 | // return; 28 | // } 29 | // String text = HandlerUtil.getParam(exchange, "text"); 30 | // if(StringUtils.isBlank(text)) { 31 | // return; 32 | // } 33 | // List list = null; String string = null; 34 | // switch(path) { 35 | // case "fenci": 36 | // list = FenciUtil.fenci(text, NumberUtil.parseEnum(HandlerUtil.getParam(exchange, "method"), Method.TO)); 37 | // break; 38 | // case "keywords": 39 | // int num = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "num"), 10); 40 | // list = FenciUtil.keywords(HandlerUtil.getParam(exchange, "title"), text, num, NumberUtil.parseEnum(HandlerUtil.getParam(exchange, "method"), Method.TO)); 41 | // break; 42 | // case "summary": 43 | // boolean red = NumberUtil.parseBoolean(HandlerUtil.getParam(exchange, "red"), true); 44 | // string = FenciUtil.summary(HandlerUtil.getParam(exchange, "title"), text, red, NumberUtil.parseEnum(HandlerUtil.getParam(exchange, "method"), Method.TO)); 45 | // break; 46 | // case "jianfan": 47 | // boolean fan = NumberUtil.parseBoolean(HandlerUtil.getParam(exchange, "fan"), true); 48 | // string = FenciUtil.jianfan(text, fan); 49 | // break; 50 | // case "pinyin": 51 | // int caseType = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "caseType"), 0); 52 | // int toneType = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "toneType"), 0); 53 | // int vcharType = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "vcharType"), 0); 54 | // list = FenciUtil.pinyin(text, caseType, toneType, vcharType); 55 | // ListIterator listIterator = list.listIterator(); 56 | // while(listIterator.hasNext()) { 57 | // if(listIterator.next()==null) { 58 | // listIterator.set(" "); 59 | // } 60 | // } 61 | // break; 62 | // default: 63 | // break; 64 | // } 65 | // if(list!=null) { 66 | // HandlerUtil.setResp(exchange, StringUtil.params("result", StringUtil.join(list, null, null, " "))); 67 | // }else if(string!=null) { 68 | // HandlerUtil.setResp(exchange, StringUtil.params("result", string)); 69 | // } 70 | // } 71 | // 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/service/BankCardHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.service; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.InputStream; 5 | import java.nio.charset.StandardCharsets; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import com.github.benmanes.caffeine.cache.Cache; 11 | import com.github.benmanes.caffeine.cache.Caffeine; 12 | import com.networknt.utility.StringUtils; 13 | import com.xlongwei.light4j.apijson.DemoApplication; 14 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 15 | import com.xlongwei.light4j.util.BankUtil; 16 | import com.xlongwei.light4j.util.BankUtil.CardInfo; 17 | import com.xlongwei.light4j.util.ConfigUtil; 18 | import com.xlongwei.light4j.util.HandlerUtil; 19 | import com.xlongwei.light4j.util.MySqlUtil; 20 | import com.xlongwei.light4j.util.StringUtil; 21 | 22 | import org.apache.commons.io.IOUtils; 23 | import org.apache.commons.lang3.BooleanUtils; 24 | import org.beetl.sql.core.SQLReady; 25 | 26 | import io.undertow.server.HttpServerExchange; 27 | import lombok.extern.slf4j.Slf4j; 28 | 29 | /** 30 | * bank card handler 31 | * @author xlongwei 32 | * 33 | */ 34 | @Slf4j 35 | public class BankCardHandler extends AbstractHandler { 36 | static boolean loadFromFile = !DemoApplication.apijsonEnabled;//停用apijson时不从数据库加载数据 37 | static Cache cache = null; 38 | static boolean cardBin = BooleanUtils.toBoolean(System.getenv("bank.cardBin")); 39 | @Override 40 | public void handleRequest(HttpServerExchange exchange) throws Exception { 41 | String bankCardNumber = HandlerUtil.getParam(exchange, "bankCardNumber"); 42 | if(StringUtil.isNumbers(bankCardNumber)) { 43 | CardInfo cardInfo = cardInfo(bankCardNumber); 44 | Map map = new HashMap<>(16); 45 | map.put("valid", Boolean.toString(StringUtil.isBankCardNumber(bankCardNumber))); 46 | if(cardInfo != null) { 47 | map.put("cardBin", cardInfo.getCardBin()); 48 | map.put("bankId", cardInfo.getBankId()); 49 | map.put("bankName", cardInfo.getBankName()); 50 | map.put("cardName", cardInfo.getCardName()); 51 | map.put("cardDigits", cardInfo.getCardDigits()); 52 | map.put("cardType", cardInfo.getCardType()); 53 | map.put("bankCode", cardInfo.getBankCode()); 54 | map.put("bankName2", cardInfo.getBankName2()); 55 | } 56 | HandlerUtil.setResp(exchange, map); 57 | } 58 | } 59 | 60 | public static CardInfo cardInfo(String bankCardNumber) { 61 | if(!StringUtil.isNumbers(bankCardNumber)) { 62 | return null; 63 | }else if(loadFromFile) { 64 | return BankUtil.cardInfo(bankCardNumber); 65 | }else if(cardBin) { 66 | String cardBin = BankUtil.cardBin(bankCardNumber); 67 | return StringUtils.isBlank(cardBin) ? null : cache.get(cardBin, (bin) -> MySqlUtil.SQLMANAGER.executeQueryOne(new SQLReady("select cardBin,issuerCode as bankId,issuerName as bankName,cardName,cardDigits,cardType,bankCode,bankName as bankName2 from bank_card where cardBin=?", bin), CardInfo.class)); 68 | }else { 69 | return MySqlUtil.SQLMANAGER.executeQueryOne(new SQLReady("select cardBin,issuerCode as bankId,issuerName as bankName,cardName,cardDigits,cardType,bankCode,bankName as bankName2 from bank_card where cardBin=?", bankCardNumber), CardInfo.class); 70 | } 71 | } 72 | 73 | static { 74 | if(loadFromFile == false) { 75 | if(cardBin){ 76 | MySqlUtil.SQLMANAGER.execute(new SQLReady("select cardBin from bank_card"), CardInfo.class).forEach(cardInfo -> { 77 | BankUtil.addBin(cardInfo.getCardBin()); 78 | }); 79 | cache = Caffeine.newBuilder() 80 | .expireAfterAccess(5, TimeUnit.MINUTES) 81 | .maximumSize(256) 82 | .build(); 83 | } 84 | log.info("bank_card loaded cardBin={}", cardBin); 85 | }else { 86 | try(InputStream inputStream = new BufferedInputStream(ConfigUtil.stream("cardBin.txt"))) { 87 | IOUtils.lineIterator(inputStream, StandardCharsets.UTF_8).forEachRemaining(line -> BankUtil.addData(new CardInfo().rowIn(line))); 88 | log.info("cardBin.txt loaded"); 89 | }catch (Exception e) { 90 | log.warn("fail to init cardBin.txt, ex: {} {}", e.getClass().getSimpleName(), e.getMessage()); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/service/Base64ImageHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.service; 2 | 3 | import java.net.URL; 4 | 5 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 6 | import com.xlongwei.light4j.util.FileUtil; 7 | import com.xlongwei.light4j.util.HandlerUtil; 8 | import com.xlongwei.light4j.util.ImageUtil; 9 | import com.xlongwei.light4j.util.StringUtil; 10 | 11 | import io.undertow.server.HttpServerExchange; 12 | import io.undertow.server.handlers.form.FormData.FormValue; 13 | 14 | /** 15 | * 转码图片为base64字符串 16 | * @author xlongwei 17 | * 18 | */ 19 | public class Base64ImageHandler extends AbstractHandler { 20 | 21 | @Override 22 | public void handleRequest(HttpServerExchange exchange) throws Exception { 23 | byte[] data = null; String ext = null; 24 | String url = HandlerUtil.getParam(exchange, "url"); 25 | if(StringUtil.isUrl(url)) { 26 | try { 27 | data = FileUtil.readStream(new URL(url).openStream()).toByteArray(); 28 | ext = FileUtil.getFileExt(url); 29 | }catch (Exception e) {} 30 | }else { 31 | FormValue file = HandlerUtil.getFile(exchange, "img"); 32 | if(file!=null && file.isFileItem()) { 33 | try { 34 | data = FileUtil.readStream(file.getFileItem().getInputStream()).toByteArray(); 35 | ext = FileUtil.getFileExt(file.getFileName()); 36 | }catch (Exception e) {} 37 | } 38 | } 39 | if(data != null) { 40 | String base64Image = ImageUtil.encode(data, ext); 41 | HandlerUtil.setResp(exchange, StringUtil.params("image", base64Image)); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/service/DelayHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.service; 2 | 3 | import java.util.Set; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 9 | import com.xlongwei.light4j.util.DateUtil; 10 | import com.xlongwei.light4j.util.HandlerUtil; 11 | import com.xlongwei.light4j.util.HttpUtil; 12 | import com.xlongwei.light4j.util.NumberUtil; 13 | import com.xlongwei.light4j.util.RedisConfig; 14 | import com.xlongwei.light4j.util.RedisUtil; 15 | import com.xlongwei.light4j.util.StringUtil; 16 | import com.xlongwei.light4j.util.TaskUtil; 17 | 18 | import io.undertow.server.HttpServerExchange; 19 | import lombok.extern.slf4j.Slf4j; 20 | 21 | @Slf4j 22 | public class DelayHandler extends AbstractHandler { 23 | private byte[] byteKey = RedisUtil.byteKey(RedisConfig.CACHE, "delay"); 24 | 25 | public DelayHandler() { 26 | TaskUtil.submitKeepRunning(() -> { 27 | while (true) { 28 | RedisConfig.execute((jedis) -> { 29 | Set members = jedis.zrangeByScore(byteKey, 0, System.currentTimeMillis()); 30 | for (byte[] member : members) { 31 | long zrem = jedis.zrem(byteKey, member); 32 | if (zrem >= 1) { 33 | String url = RedisUtil.stringValue(member); 34 | log.info("pop {}", url); 35 | TaskUtil.submit(() -> { 36 | HttpUtil.get(url, null); 37 | }); 38 | } 39 | } 40 | return null; 41 | }); 42 | TaskUtil.sleep(TimeUnit.SECONDS.toMillis(1)); 43 | } 44 | }); 45 | } 46 | 47 | @Override 48 | public void handleRequest(HttpServerExchange exchange) throws Exception { 49 | String url = HandlerUtil.getParamOrBody(exchange, "url"); 50 | long delay = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "delay"), 0); 51 | TimeUnit unit = TimeUnit.valueOf( 52 | StringUtils.defaultString(HandlerUtil.getParam(exchange, "unit"), TimeUnit.MINUTES.name())); 53 | if (StringUtil.isUrl(url) && delay > 0) { 54 | final long score = unit.toMillis(delay) + System.currentTimeMillis(); 55 | byte[] byteValue = RedisUtil.byteValue(url); 56 | String until = DateUtil.datetimeFormat.format(score); 57 | log.info("push {} until {}", url, until); 58 | RedisConfig.execute((jedis) -> { 59 | jedis.zadd(byteKey, score, byteValue); 60 | return null; 61 | }); 62 | HandlerUtil.setResp(exchange, StringUtil.params("until", until)); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/service/DesHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.service; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 10 | import com.xlongwei.light4j.util.DesUtil; 11 | import com.xlongwei.light4j.util.HandlerUtil; 12 | import com.xlongwei.light4j.util.StringUtil; 13 | 14 | import de.rrze.jpwgen.utils.PwHelper; 15 | import io.undertow.server.HttpServerExchange; 16 | 17 | /** 18 | * des handler 19 | * @author xlongwei 20 | * 21 | */ 22 | public class DesHandler extends AbstractHandler { 23 | 24 | public void encrypt(HttpServerExchange exchange) throws Exception { 25 | String password = HandlerUtil.getParam(exchange, "password", "passwordCacheKey"); 26 | String data = HandlerUtil.getParam(exchange, "data"); 27 | String encrypt = DesUtil.getInstance(StringUtils.trimToEmpty(password)).doEncrypt(data==null ? "" : data); 28 | HandlerUtil.setResp(exchange, StringUtil.params("data", encrypt)); 29 | } 30 | 31 | public void decrypt(HttpServerExchange exchange) throws Exception { 32 | String password = HandlerUtil.getParam(exchange, "password", "passwordCacheKey"); 33 | String data = HandlerUtil.getParam(exchange, "data"); 34 | String encrypt = DesUtil.getInstance(StringUtils.trimToEmpty(password)).doDecrypt(data==null ? "" : data); 35 | HandlerUtil.setResp(exchange, StringUtil.params("data", encrypt)); 36 | } 37 | 38 | public void pwgen(HttpServerExchange exchange) throws Exception { 39 | String data = StringUtil.firstNotBlank(HandlerUtil.getParam(exchange, "options"), "-N 6 -s 24"); 40 | List passwords = PwHelper.process(StringUtils.split(data), null); 41 | if(passwords.size()>0) { 42 | Map map = new HashMap<>(1); 43 | map.put("data", passwords); 44 | HandlerUtil.setResp(exchange, map); 45 | } 46 | } 47 | 48 | public void pwcheck(HttpServerExchange exchange) throws Exception { 49 | String password = HandlerUtil.getParam(exchange, "password"); 50 | HandlerUtil.setResp(exchange, DesUtil.pwcheck(password)); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/service/DictHandler.java: -------------------------------------------------------------------------------- 1 | //package com.xlongwei.light4j.handler.service; 2 | // 3 | //import java.util.ArrayList; 4 | //import java.util.HashMap; 5 | //import java.util.List; 6 | //import java.util.Map; 7 | // 8 | //import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 9 | //import com.xlongwei.light4j.util.DictUtil; 10 | //import com.xlongwei.light4j.util.DictUtil.WordScore; 11 | //import com.xlongwei.light4j.util.HandlerUtil; 12 | //import com.xlongwei.light4j.util.PinyinUtil; 13 | //import com.xlongwei.light4j.util.StringUtil; 14 | // 15 | //import io.undertow.server.HttpServerExchange; 16 | // 17 | ///** 18 | // * dict handler 19 | // * @author xlongwei 20 | // * 21 | // */ 22 | //public class DictHandler extends AbstractHandler { 23 | // 24 | // @Override 25 | // public void handleRequest(HttpServerExchange exchange) throws Exception { 26 | // String parts = HandlerUtil.getParam(exchange, "parts"); 27 | // if(!StringUtil.isBlank(parts)) { 28 | // List list = DictUtil.parse(parts); 29 | // if(list!=null && list.size()>0) { 30 | // Map map = new HashMap<>(1); 31 | // List array = new ArrayList<>(); 32 | // for(WordScore word : list) { 33 | // Map item = new HashMap<>(list.size()); 34 | // item.put("word", word.getWord()); 35 | // item.put("pinyin", PinyinUtil.getPinyin(word.getWord(), 0, 0, 0)[0]); 36 | // array.add(item); 37 | // if(array.size() >= 10) { 38 | // break; 39 | // } 40 | // } 41 | // map.put("words", array); 42 | // HandlerUtil.setResp(exchange, map); 43 | // } 44 | // } 45 | // } 46 | // 47 | //} 48 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/handler/service/DruidHandler.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.handler.service; 2 | 3 | import java.util.Map; 4 | 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 8 | import com.xlongwei.light4j.util.DruidUtil; 9 | import com.xlongwei.light4j.util.HandlerUtil; 10 | import com.xlongwei.light4j.util.NumberUtil; 11 | import com.xlongwei.light4j.util.StringUtil; 12 | 13 | import io.undertow.server.HttpServerExchange; 14 | 15 | /** 16 | * 封装druid密码处理工具 17 | * @author xlongwei 18 | * 19 | */ 20 | public class DruidHandler extends AbstractHandler { 21 | 22 | /** 23 | *
24 | 	 * publicKey有默认值,可以不提供
25 | 	 * spring.datasource.publicKey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKHGwq7q2RmwuRgKxBypQHw0mYu4BQZ3eMsTrdK8E6igRcxsobUC7uT0SoxIjl1WveWniCASejoQtn/BY6hVKWsCAwEAAQ==
26 | 	 */
27 | 	public void genKeyPair(HttpServerExchange exchange) throws Exception {
28 | 		String password = HandlerUtil.getParam(exchange, "password");
29 | 		int keySize = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "keySize"), 512);
30 | 		String[] genKeyPair = DruidUtil.genKeyPair(keySize);
31 | 		String privateKey = genKeyPair[0];
32 | 		String publicKey = genKeyPair[1];
33 | 		Map resp = StringUtil.params("privateKey", privateKey, "publicKey", publicKey);
34 | 		if(password != null) {
35 | 			resp.put("password", DruidUtil.encrypt(privateKey, password));
36 | 		}
37 | 		HandlerUtil.setResp(exchange, resp);
38 | 	}
39 | 	
40 | 	/**
41 | 	 * privateKey有默认值,可以不提供
42 | 	 * privateKey=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAocbCrurZGbC5GArEHKlAfDSZi7gFBnd4yxOt0rwTqKBFzGyhtQLu5PRKjEiOXVa95aeIIBJ6OhC2f8FjqFUpawIDAQABAkAPejKaBYHrwUqUEEOe8lpnB6lBAsQIUFnQI/vXU4MV+MhIzW0BLVZCiarIQqUXeOhThVWXKFt8GxCykrrUsQ6BAiEA4vMVxEHBovz1di3aozzFvSMdsjTcYRRo82hS5Ru2/OECIQC2fAPoXixVTVY7bNMeuxCP4954ZkXp7fEPDINCjcQDywIgcc8XLkkPcs3Jxk7uYofaXaPbg39wuJpEmzPIxi3k0OECIGubmdpOnin3HuCP/bbjbJLNNoUdGiEmFL5hDI4UdwAdAiEAtcAwbm08bKN7pwwvyqaCBC//VnEWaq39DCzxr+Z2EIk=
43 | 	 */
44 | 	public void encrypt(HttpServerExchange exchange) throws Exception {
45 | 		String password = StringUtils.trimToEmpty(HandlerUtil.getParam(exchange, "password"));
46 | 		String privateKey = StringUtils.trimToNull(HandlerUtil.getParam(exchange, "privateKey"));
47 | 		String encrypt = DruidUtil.encrypt(privateKey, password);
48 | 		HandlerUtil.setResp(exchange, StringUtil.params("encrypt", encrypt));
49 | 	}
50 | 	
51 | 	/**
52 | 	 * 
53 | 	 * spring.datasource.filters=config,stat,wall,log4j
54 | 	 * spring.datasource.connectionProperties=config.decrypt=true;druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
55 | 	 * spring.datasource.password=brW4Fq8Z9eiWpM1+0zcvgrkqX+b/FQq0P71dDxF3FxoqX7KINU2JTTqgru0UOr3Pp9rsPFqTbZvBUwnIbjR9jA==
56 | 	 */
57 | 	public void decrypt(HttpServerExchange exchange) throws Exception {
58 | 		String password = StringUtils.trimToEmpty(HandlerUtil.getParam(exchange, "password"));
59 | 		String publicKey = StringUtils.trimToNull(HandlerUtil.getParam(exchange, "publicKey"));
60 | 		String decrypt = DruidUtil.decrypt(publicKey, password);
61 | 		HandlerUtil.setResp(exchange, StringUtil.params("decrypt", decrypt));
62 | 	}
63 | 
64 | }
65 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/service/PdfHandler.java:
--------------------------------------------------------------------------------
  1 | package com.xlongwei.light4j.handler.service;
  2 | 
  3 | import java.io.ByteArrayInputStream;
  4 | import java.io.File;
  5 | import java.util.HashMap;
  6 | import java.util.Map;
  7 | 
  8 | import org.apache.commons.codec.binary.Base64;
  9 | 
 10 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 11 | import com.xlongwei.light4j.util.FileUtil;
 12 | import com.xlongwei.light4j.util.HandlerUtil;
 13 | import com.xlongwei.light4j.util.IdWorker;
 14 | import com.xlongwei.light4j.util.ImageUtil;
 15 | import com.xlongwei.light4j.util.NumberUtil;
 16 | import com.xlongwei.light4j.util.PdfUtil;
 17 | import com.xlongwei.light4j.util.SealUtil;
 18 | import com.xlongwei.light4j.util.StringUtil;
 19 | import com.xlongwei.light4j.util.UploadUtil;
 20 | 
 21 | import io.undertow.server.HttpServerExchange;
 22 | import io.undertow.server.handlers.form.FormData.FormValue;
 23 | 
 24 | /**
 25 |  * pdf handler
 26 |  * @author xlongwei
 27 |  *
 28 |  */
 29 | public class PdfHandler extends AbstractHandler {
 30 | 
 31 | 	public void sealImage(HttpServerExchange exchange) throws Exception {
 32 | 		byte[] seal = null;
 33 | 		String person = HandlerUtil.getParam(exchange, "person");
 34 | 		if(!StringUtil.isBlank(person)) {
 35 | 			seal = SealUtil.seal(person);
 36 | 		}else {
 37 | 			String name = HandlerUtil.getParam(exchange, "name");
 38 | 			String company = HandlerUtil.getParam(exchange, "company");
 39 | 			String license = HandlerUtil.getParam(exchange, "license");
 40 | 			if(StringUtil.isBlank(name) && StringUtil.isBlank(company) && StringUtil.isBlank(license)) {
 41 | 				return;
 42 | 			}else {
 43 | 				seal = SealUtil.seal(name, company, license);
 44 | 			}
 45 | 		}
 46 | 		
 47 | 		if(seal != null) {
 48 | 			HandlerUtil.setResp(exchange, StringUtil.params("image", ImageUtil.encode(seal, null)));
 49 | 		}
 50 | 	}
 51 | 	
 52 | 	public void seal(HttpServerExchange exchange) throws Exception {
 53 | 		File pdf = getPdf(exchange);
 54 | 		if(pdf==null || !pdf.exists()) {
 55 | 			return;
 56 | 		}
 57 | 		
 58 | 		String path = "pdf/"+IdWorker.getId()+".pdf";
 59 | 		File target = new File(UploadUtil.SAVE_TEMP, path);
 60 | 		int page = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "page"), 1);
 61 | 		int x = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "page"), 360);
 62 | 		int y = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "page"), 40);
 63 | 		String person = HandlerUtil.getParam(exchange, "person");
 64 | 		int height = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "page"), StringUtil.isBlank(person) ? 120 : 32);
 65 | 		if(!StringUtil.isBlank(person)) {
 66 | 			PdfUtil.seal(pdf, target, person, page, x, y, height);
 67 | 		}else {
 68 | 			String name = HandlerUtil.getParam(exchange, "name");
 69 | 			String company = HandlerUtil.getParam(exchange, "company");
 70 | 			String license = HandlerUtil.getParam(exchange, "license");
 71 | 			if(StringUtil.isBlank(name) && StringUtil.isBlank(company) && StringUtil.isBlank(license)) {
 72 | 				return;
 73 | 			}else {
 74 | 				PdfUtil.seal(pdf, target, name, company, license, page, x, y, height);
 75 | 			}
 76 | 		}
 77 | 		
 78 | 		if(target.exists()) {
 79 | 			Map map = new HashMap<>(4);
 80 | 			map.put(UploadUtil.DOMAIN, UploadUtil.URL_TEMP);
 81 | 			map.put(UploadUtil.PATH, path);
 82 | 			boolean base64File = NumberUtil.parseBoolean(HandlerUtil.getParam(exchange, "base64File"), false);
 83 | 			if(base64File) {
 84 | 				map.put("base64", Base64.encodeBase64String(FileUtil.readStream(target).toByteArray()));
 85 | 			}
 86 | 		}
 87 | 	}
 88 | 
 89 | 	private File getPdf(HttpServerExchange exchange) throws Exception {
 90 | 		File target = new File(UploadUtil.SAVE_TEMP, "pdf/"+IdWorker.getId()+".pdf");
 91 | 		String url = HandlerUtil.getParam(exchange, "url");
 92 | 		if(StringUtil.isUrl(url)) {
 93 | 			FileUtil.down(url, target);
 94 | 		}else {
 95 | 			String base64 = HandlerUtil.getParam(exchange, "base64");
 96 | 			base64 = StringUtil.isBlank(base64) ? null : ImageUtil.prefixRemove(base64);
 97 | 			if(!StringUtil.isBlank(base64)) {
 98 | 				byte[] bs = Base64.decodeBase64(base64);
 99 | 				UploadUtil.save(new ByteArrayInputStream(bs), target);
100 | 			}else {
101 | 				FormValue pdf = HandlerUtil.getFile(exchange, "pdf");
102 | 				if(pdf!=null && pdf.isFileItem()) {
103 | 					UploadUtil.save(pdf.getFileItem().getInputStream(), target);
104 | 				}
105 | 			}
106 | 		}
107 | 		return target.exists() ? target : null;
108 | 	}
109 | }
110 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/service/PlateHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.service;
 2 | 
 3 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 4 | import com.xlongwei.light4j.util.HandlerUtil;
 5 | import com.xlongwei.light4j.util.PlateUtil;
 6 | 
 7 | import cn.hutool.core.map.MapUtil;
 8 | import io.undertow.server.HttpServerExchange;
 9 | 
10 | /**
11 |  * plate handler
12 |  * @author xlongwei
13 |  *
14 |  */
15 | public class PlateHandler extends AbstractHandler {
16 | 
17 | 	@Override
18 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
19 | 		String text = HandlerUtil.getParam(exchange, "text");
20 | 		text = PlateUtil.search(text);
21 | 		if(text != null) {
22 | 			HandlerUtil.setResp(exchange, MapUtil.of("text", text));
23 | 		}
24 | 	}
25 | 
26 | }
27 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/service/PropertyHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.service;
 2 | 
 3 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 4 | import com.xlongwei.light4j.util.HandlerUtil;
 5 | import com.xlongwei.light4j.util.NumberUtil;
 6 | import com.xlongwei.light4j.util.RedisConfig;
 7 | import com.xlongwei.light4j.util.StringUtil;
 8 | 
 9 | import io.undertow.server.HttpServerExchange;
10 | 
11 | /**
12 |  * property handler
13 |  * @author xlongwei
14 |  *
15 |  */
16 | public class PropertyHandler extends AbstractHandler {
17 | 
18 | 	@Override
19 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
20 | 		String key = HandlerUtil.getParam(exchange, "key");
21 | 		if(StringUtil.isBlank(key)) {
22 | 			return;
23 | 		}
24 | 		String value = HandlerUtil.getParam(exchange, "value");
25 | 		String type = HandlerUtil.getParam(exchange, "type");
26 | 		int expires = NumberUtil.parseInt(HandlerUtil.getParam(exchange, "expire"), 0);
27 | 		if(StringUtil.isBlank(type)) {
28 | 			type = StringUtil.isBlank(value)==false||expires>0 ? "set" : "get";
29 | 		}
30 | 		String set = "set";
31 | 		if(set.equals(type)) {
32 | 			if(expires == 0) {
33 | 				RedisConfig.set(key, value);
34 | 			}else if(expires > 0){
35 | 				RedisConfig.set(RedisConfig.CACHE, key, value, expires);
36 | 			}else {
37 | 				RedisConfig.persist(key, value);
38 | 			}
39 | 			HandlerUtil.setResp(exchange, StringUtil.params("value", value));
40 | 		}else {
41 | 			String get = RedisConfig.get(key);
42 | 			HandlerUtil.setResp(exchange, StringUtil.params("value", get));
43 | 		}
44 | 	}
45 | 
46 | }
47 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/service/RsaHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.service;
 2 | 
 3 | import java.security.KeyPair;
 4 | import java.util.Map;
 5 | import java.util.concurrent.TimeUnit;
 6 | 
 7 | import com.networknt.utility.StringUtils;
 8 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 9 | import com.xlongwei.light4j.util.HandlerUtil;
10 | import com.xlongwei.light4j.util.IdWorker;
11 | import com.xlongwei.light4j.util.RedisConfig;
12 | import com.xlongwei.light4j.util.RsaUtil;
13 | 
14 | import cn.hutool.core.map.MapUtil;
15 | import io.undertow.server.HttpServerExchange;
16 | 
17 | /**
18 |  * rsa handler
19 |  * @author xlongwei
20 |  *
21 |  */
22 | public class RsaHandler extends AbstractHandler {
23 | 
24 | 	private static final String PUBLIC_KEY = "publicKey";
25 | 	private static final String PRIVATE_KEY = "privateKey";
26 | 	private static final String PUBLIC_CACHE_KEY = "publicCacheKey";
27 | 	private static final String PRIVATE_CACHE_KEY = "privateCacheKey";
28 | 	private static final String RSA_PUBKEY = "rsa.pubkey.";
29 | 	private static final String RSA_PRIKEY = "rsa.prikey.";
30 | 
31 | 	public void keypair(HttpServerExchange exchange) throws Exception {
32 | 		KeyPair keyPair = RsaUtil.getKeyPair();
33 | 		String publicKey = RsaUtil.getKeyString(keyPair.getPublic());
34 | 		String privateKey = RsaUtil.getKeyString(keyPair.getPrivate());
35 | 		setKeys(exchange, publicKey, privateKey);
36 | 	}
37 | 
38 | 	public void config(HttpServerExchange exchange) throws Exception {
39 | 		String publicKey = HandlerUtil.getParam(exchange, PUBLIC_KEY);
40 | 		String privateKey = HandlerUtil.getParam(exchange, PRIVATE_KEY);
41 | 		if(StringUtils.isNotBlank(publicKey) && StringUtils.isNotBlank(privateKey) && RsaUtil.verify(publicKey, privateKey)) {
42 | 			setKeys(exchange, publicKey, privateKey);
43 | 		}
44 | 	}
45 | 
46 | 	private void setKeys(HttpServerExchange exchange, String publicKey, String privateKey) {
47 | 		Map map = MapUtil.newHashMap(4);
48 | 		map.put(PUBLIC_KEY, publicKey);
49 | 		map.put(PRIVATE_KEY, privateKey);
50 | 		map.put(PUBLIC_CACHE_KEY, RSA_PUBKEY+IdWorker.getId());
51 | 		map.put(PRIVATE_CACHE_KEY, RSA_PRIKEY+IdWorker.getId());
52 | 		RedisConfig.set(map.get(PUBLIC_CACHE_KEY), publicKey);
53 | 		RedisConfig.set(map.get(PRIVATE_CACHE_KEY), privateKey);
54 | 		int expire = (int)TimeUnit.DAYS.toSeconds(30);
55 | 		RedisConfig.expire(RedisConfig.CACHE, map.get(PUBLIC_CACHE_KEY), expire);
56 | 		RedisConfig.expire(RedisConfig.CACHE, map.get(PRIVATE_CACHE_KEY), expire);
57 | 		HandlerUtil.setResp(exchange, map);
58 | 	}
59 | 	
60 | 	public void encrypt(HttpServerExchange exchange) throws Exception {
61 | 		String publicKey = HandlerUtil.getParam(exchange, PUBLIC_KEY, PUBLIC_CACHE_KEY);
62 | 		String data = HandlerUtil.getParam(exchange, "data");
63 | 		if(StringUtils.isNotBlank(publicKey) && StringUtils.isNotBlank(data)) {
64 | 			data = RsaUtil.encrypt(RsaUtil.getPublicKey(publicKey), data);
65 | 			HandlerUtil.setResp(exchange, MapUtil.of("data", data));
66 | 		}
67 | 	}
68 | 	
69 | 	public void decrypt(HttpServerExchange exchange) throws Exception {
70 | 		String privateKey = HandlerUtil.getParam(exchange, PRIVATE_KEY, PRIVATE_CACHE_KEY);
71 | 		String data = HandlerUtil.getParam(exchange, "data");
72 | 		if(StringUtils.isNotBlank(privateKey) && StringUtils.isNotBlank(data)) {
73 | 			data = RsaUtil.decrypt(RsaUtil.getPrivateKey(privateKey), data);
74 | 			HandlerUtil.setResp(exchange, MapUtil.of("data", data));
75 | 		}
76 | 	}
77 | 	
78 | 	public void sign(HttpServerExchange exchange) throws Exception {
79 | 		String privateKey = HandlerUtil.getParam(exchange, PRIVATE_KEY, PRIVATE_CACHE_KEY);
80 | 		String data = HandlerUtil.getParam(exchange, "data");
81 | 		if(StringUtils.isNotBlank(privateKey) && StringUtils.isNotBlank(data)) {
82 | 			data = RsaUtil.sign(RsaUtil.getPrivateKey(privateKey), data);
83 | 			HandlerUtil.setResp(exchange, MapUtil.of("sign", data));
84 | 		}
85 | 	}
86 | 	
87 | 	public void verify(HttpServerExchange exchange) throws Exception {
88 | 		String publicKey = HandlerUtil.getParam(exchange, PUBLIC_KEY, PUBLIC_CACHE_KEY);
89 | 		String data = HandlerUtil.getParam(exchange, "data");
90 | 		String sign = HandlerUtil.getParam(exchange, "sign");
91 | 		if(StringUtils.isNotBlank(publicKey) && StringUtils.isNotBlank(data)) {
92 | 			boolean verify = RsaUtil.verify(RsaUtil.getPublicKey(publicKey), data, sign);
93 | 			HandlerUtil.setResp(exchange, MapUtil.of("verify", String.valueOf(verify)));
94 | 		}
95 | 	}
96 | 
97 | }
98 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/service/SequenceHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.service;
 2 | 
 3 | import java.util.Collections;
 4 | import java.util.Date;
 5 | 
 6 | import com.networknt.utility.StringUtils;
 7 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 8 | import com.xlongwei.light4j.util.HandlerUtil;
 9 | import com.xlongwei.light4j.util.MySqlUtil;
10 | import com.xlongwei.light4j.util.NumberUtil;
11 | import com.xlongwei.light4j.util.RedisConfig;
12 | 
13 | import io.undertow.server.HttpServerExchange;
14 | 
15 | public class SequenceHandler extends AbstractHandler {
16 | 
17 | 	public void next(HttpServerExchange exchange) throws Exception {
18 | 		String sequence = sequence(exchange);
19 | 		boolean mysql = "mysql".equals(HandlerUtil.getParam(exchange, "type"));
20 | 		long step = NumberUtil.parseLong(HandlerUtil.getParam(exchange, "step"), 0L);
21 | 		if(step > 1) {
22 | 			step -= 1; //这个很奇怪
23 | 			long next = mysql ? MySqlUtil.Sequence.next(sequence, step) : RedisConfig.Sequence.next(sequence, step);
24 | 			HandlerUtil.setResp(exchange, Collections.singletonMap("next", next));
25 | 		}
26 | 		long next = mysql ? MySqlUtil.Sequence.next(sequence) : RedisConfig.Sequence.next(sequence);
27 | 		String format = HandlerUtil.getParam(exchange, "format");
28 | 		if (StringUtils.isNotBlank(format)) {
29 | 			try {
30 | 				HandlerUtil.setResp(exchange,
31 | 						Collections.singletonMap("next", String.format(format, next, new Date())));
32 | 				return;
33 | 			} catch (Exception e) {
34 | 				// ignore
35 | 			}
36 | 		}
37 | 		HandlerUtil.setResp(exchange, Collections.singletonMap("next", next));
38 | 	}
39 | 	
40 | 	public void update(HttpServerExchange exchange) throws Exception {
41 | 		String sequence = sequence(exchange);
42 | 		boolean mysql = "mysql".equals(HandlerUtil.getParam(exchange, "type"));
43 | 		long value = NumberUtil.parseLong(HandlerUtil.getParam(exchange, "value"), 0L);
44 | 		boolean update = mysql ? MySqlUtil.Sequence.update(sequence, value) : RedisConfig.Sequence.update(sequence, value);
45 | 		HandlerUtil.setResp(exchange, Collections.singletonMap("update", update));
46 | 	}
47 | 
48 | 	private String sequence(HttpServerExchange exchange) {
49 | 		String name = StringUtils.trimToEmpty(HandlerUtil.getParam(exchange, "name"));
50 | 		String userName = "common";
51 | 		if(StringUtils.isNotBlank(HandlerUtil.getShowapiUserName(exchange))) {
52 | 			String showapiUserName = HandlerUtil.getShowapiUserName(exchange);
53 | 			userName = StringUtils.isNotBlank(showapiUserName) ? showapiUserName : userName;
54 | 		}
55 | 		return userName + "." + name;
56 | 	}
57 | }
58 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/service/TrainHandler.java:
--------------------------------------------------------------------------------
  1 | //package com.xlongwei.light4j.handler.service;
  2 | //
  3 | //import java.util.LinkedList;
  4 | //import java.util.List;
  5 | //import java.util.Map.Entry;
  6 | //
  7 | //import org.apache.commons.collections4.CollectionUtils;
  8 | //
  9 | //import com.alibaba.fastjson.JSONArray;
 10 | //import com.alibaba.fastjson.JSONObject;
 11 | //import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 12 | //import com.xlongwei.light4j.util.HandlerUtil;
 13 | //import com.xlongwei.light4j.util.StringUtil;
 14 | //import com.xlongwei.light4j.util.TrainUtil;
 15 | //
 16 | //import io.undertow.server.HttpServerExchange;
 17 | //
 18 | ///**
 19 | // * train handler
 20 | // * @author xlongwei
 21 | // *
 22 | // */
 23 | //public class TrainHandler extends AbstractHandler {
 24 | //
 25 | //	public void info(HttpServerExchange exchange) throws Exception {
 26 | //		String line = HandlerUtil.getParam(exchange, "line");
 27 | //		if(StringUtil.isBlank(line)) {
 28 | //			return;
 29 | //		}
 30 | //		JSONObject json = TrainUtil.info(line.toUpperCase());
 31 | //		if(json != null) {
 32 | //			HandlerUtil.setResp(exchange, json);
 33 | //		}
 34 | //	}
 35 | //	
 36 | //	public void query(HttpServerExchange exchange) throws Exception {
 37 | //		String name = HandlerUtil.getParam(exchange, "station");
 38 | //		if(!StringUtil.isChinese(name)) {
 39 | //			return;
 40 | //		}
 41 | //		List lines = TrainUtil.stations.get(name);
 42 | //		JSONObject json = lines(lines);
 43 | //		if(json != null) {
 44 | //			HandlerUtil.setResp(exchange, json);
 45 | //		}
 46 | //	}
 47 | //	
 48 | //	public void search(HttpServerExchange exchange) throws Exception {
 49 | //		String from = HandlerUtil.getParam(exchange, "from"), to = HandlerUtil.getParam(exchange, "to");
 50 | //		if(!StringUtil.isChinese(from) || !StringUtil.isChinese(to) || from.startsWith(to) || to.startsWith(from)) {
 51 | //			return;
 52 | //		}
 53 | //		List list1 = TrainUtil.stations.get(from), list2 = TrainUtil.stations.get(to);
 54 | //		if(CollectionUtils.isNotEmpty(list1) && CollectionUtils.isNotEmpty(list2)) {
 55 | //			list1.retainAll(list2);
 56 | //			if(!list1.isEmpty()) {
 57 | //				list1 = TrainUtil.filter(from, to, list1);
 58 | //			}
 59 | //			if(!list1.isEmpty()) {
 60 | //				//车次 成都东-重庆北
 61 | //				JSONObject lines = lines(list1);
 62 | //				if(lines != null) {
 63 | //					HandlerUtil.setResp(exchange, lines);
 64 | //					return;
 65 | //				}
 66 | //			}
 67 | //		}
 68 | //		
 69 | //		list1 = new LinkedList<>(); list2 = new LinkedList<>();
 70 | //		for(Entry> entry : TrainUtil.stations.entrySet()) {
 71 | //			String key = entry.getKey();
 72 | //			if(key.startsWith(from)) {
 73 | //				list1.addAll(entry.getValue());
 74 | //			} else if(key.startsWith(to)) {
 75 | //				list2.addAll(entry.getValue());
 76 | //			}
 77 | //		}
 78 | //		if(CollectionUtils.isNotEmpty(list1) && CollectionUtils.isNotEmpty(list2)) {
 79 | //			list1.retainAll(list2);
 80 | //			if(!list1.isEmpty()) {
 81 | //				list1 = TrainUtil.filter(from, to, list1);
 82 | //			}
 83 | //			if(!list1.isEmpty()) {
 84 | //				//车次 成都-重庆
 85 | //				JSONObject lines = lines(list1);
 86 | //				if(lines != null) {
 87 | //					HandlerUtil.setResp(exchange, lines);
 88 | //					return;
 89 | //				}
 90 | //			}
 91 | //		}
 92 | //	}
 93 | //	
 94 | //	private JSONObject lines(List lines) {
 95 | //		if(CollectionUtils.isEmpty(lines)) {
 96 | //			return null;
 97 | //		}
 98 | //		JSONObject json = new JSONObject();
 99 | //		JSONArray array = new JSONArray();
100 | //		for(String line : lines) {
101 | //			JSONObject item = TrainUtil.info(line);
102 | //			if(item!=null) {
103 | //				array.add(item);
104 | //			}
105 | //		}
106 | //		json.put("total", lines.size());
107 | //		json.put("infos", array);
108 | //		return json;
109 | //	}
110 | //}
111 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/service/UploadHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.service;
 2 | 
 3 | import java.io.ByteArrayInputStream;
 4 | import java.io.File;
 5 | 
 6 | import org.apache.commons.codec.binary.Base64;
 7 | 
 8 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 9 | import com.xlongwei.light4j.util.HandlerUtil;
10 | import com.xlongwei.light4j.util.IdWorker;
11 | import com.xlongwei.light4j.util.ImageUtil;
12 | import com.xlongwei.light4j.util.StringUtil;
13 | import com.xlongwei.light4j.util.UploadUtil;
14 | 
15 | import io.undertow.server.HttpServerExchange;
16 | import io.undertow.server.handlers.form.FormData.FormValue;
17 | 
18 | /**
19 |  * 上传文件和确认路径
20 |  * @author xlongwei
21 |  *
22 |  */
23 | public class UploadHandler extends AbstractHandler {
24 | 
25 | 	@Override
26 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
27 | 		String type = StringUtil.firstNotBlank(HandlerUtil.getParam(exchange, "type"), "image");
28 | 		if(UploadUtil.CONFIRM.equals(type) || UploadUtil.TRASH.equals(type)) {
29 | 			String name = HandlerUtil.getParam(exchange, "name");
30 | 			boolean move = UploadUtil.move(name, UploadUtil.CONFIRM);
31 | 			HandlerUtil.setResp(exchange, StringUtil.params(type, move ? "1" : "0"));
32 | 		}else {
33 | 			String base64 = HandlerUtil.getParam(exchange, "base64");
34 | 			String path = type;
35 | 			File target = null;
36 | 			if(ImageUtil.isBase64(base64)) {
37 | 				String ext = ImageUtil.prefixFormat(base64);
38 | 				path = type + "/" + IdWorker.getId() + "." + ext;
39 | 				byte[] bs = Base64.decodeBase64(ImageUtil.prefixRemove(base64));
40 | 				target = new File(UploadUtil.SAVE_TEMP, path);
41 | 				UploadUtil.save(new ByteArrayInputStream(bs), target);
42 | 			}else {
43 | 				FormValue file = HandlerUtil.getFile(exchange, "file");
44 | 				if(file!=null && file.isFileItem()) {
45 | 					String fileName = file.getFileName();
46 | 					path = UploadUtil.path(type, fileName);
47 | 					target = new File(UploadUtil.SAVE_TEMP, path);
48 | 					UploadUtil.save(file.getFileItem().getInputStream(), target);
49 | 				}
50 | 			}
51 | 			if(target!=null && target.exists()) {
52 | 				HandlerUtil.setResp(exchange, StringUtil.params(UploadUtil.DOMAIN, UploadUtil.URL_TEMP, UploadUtil.PATH, path));
53 | 			}
54 | 		}
55 | 	}
56 | 
57 | }
58 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/CalcHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import java.util.Map;
 4 | import java.util.regex.Matcher;
 5 | import java.util.regex.Pattern;
 6 | 
 7 | import com.alibaba.fastjson.JSON;
 8 | import com.alibaba.fastjson.JSONObject;
 9 | import com.xlongwei.light4j.util.JsonUtil;
10 | import com.xlongwei.light4j.util.NumberUtil;
11 | import com.xlongwei.light4j.util.RedisConfig;
12 | import com.xlongwei.light4j.util.StringUtil;
13 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
14 | 
15 | import cn.hutool.core.map.MapUtil;
16 | import lombok.extern.slf4j.Slf4j;
17 | 
18 | 
19 | /**
20 |  * calc handler
21 |  * @author xlongwei
22 |  * 
23 |  */
24 | @Slf4j
25 | public class CalcHandler extends AbstractTextHandler {
26 | 	private static final String TAG = "计算";
27 | 	private	Pattern pattern = Pattern.compile("[0-9a-z\\.\\,\\(\\+\\-\\*/%^\\)]{3,}");
28 | 	private Pattern params = Pattern.compile("([^ ]+)=(\\d+(\\.\\d+)?)");
29 | 	
30 | 	@Override
31 | 	public String handle(String content) {
32 | 		if(StringUtil.isBlank(content)) {
33 | 			return null;
34 | 		}
35 | 		if(pattern.matcher(content=StringUtil.toDBC(content)).matches() && !StringUtil.isNumbers(content)) {
36 | 			String parseExp = NumberUtil.parseExp(content);
37 | 			if(StringUtil.hasLength(parseExp)) {
38 | 				return parseExp;
39 | 			}
40 | 		}
41 | 		if(!content.startsWith(TAG)) {
42 | 			return null;
43 | 		}
44 | 		String exp = content.substring(2).trim();
45 | 		if(StringUtil.isBlank(exp)) {
46 | 			return null;
47 | 		}
48 | 		String key = "weixin.calc."+message.get().getFromUserName();
49 | 		if(exp.indexOf('=')>0) {
50 | 			Map map = MapUtil.newHashMap();
51 | 			Matcher matcher = params.matcher(exp);
52 | 			while(matcher.find()) {
53 | 				map.put(matcher.group(1), matcher.group(2));
54 | 			}
55 | 			if(map.size() > 0) {
56 | 				RedisConfig.set(key, JSON.toJSONString(map));
57 | 				return map.toString();
58 | 			}else {
59 | 				return null;
60 | 			}
61 | 		}
62 | 		
63 | 		String formula = RedisConfig.get("weixin.key."+exp);
64 | 		if(StringUtil.hasLength(formula)) {
65 | 			log.info("{} = {}", exp, formula);
66 | 			exp = formula;
67 | 		}
68 | 		
69 | 		JSONObject json = JsonUtil.parse(RedisConfig.get(key));
70 | 		Map context = MapUtil.newHashMap();
71 | 		json.forEach((k, v) -> {
72 | 			String paramName = k, paramValue = v.toString();
73 | 			Number number = StringUtil.isNumbers(paramValue) ? NumberUtil.parseInt(paramValue, null) : null;
74 | 			if(number == null && StringUtil.isDecimal(paramValue)) {
75 | 				number = NumberUtil.parseDouble(paramValue, null);
76 | 			}
77 | 			if(number != null) {
78 | 				context.put(paramName, number);
79 | 			}
80 | 		});
81 | 		String parseExp = NumberUtil.parseExp(exp, context);
82 | 		if(StringUtil.hasLength(parseExp)) {
83 | 			if(StringUtil.hasLength(formula)) {
84 | 				return new StringBuilder(content.substring(2).trim()).append(":").append(context.toString()).append("\n").append(formula).append("=").append(parseExp).toString();
85 | 			}else {
86 | 				return parseExp;
87 | 			}
88 | 		}
89 | 		return "示例:sqrt(3^2)*sin(pi/2)";
90 | 	}
91 | 
92 | }
93 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/ClickHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import com.xlongwei.light4j.util.StringUtil;
 4 | import com.xlongwei.light4j.util.WeixinUtil;
 5 | import com.xlongwei.light4j.util.WeixinUtil.AbstractEventHandler.AbstractClickHandler;
 6 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage;
 7 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.TextMessage;
 8 | 
 9 | /**
10 |  * 将click事件的key作为消息转发处理
11 |  * @author xlongwei
12 |  *
13 |  */
14 | public class ClickHandler extends AbstractClickHandler {
15 | 
16 | 	@Override
17 | 	public AbstractMessage handle(String key) {
18 | 		if(StringUtil.isBlank(key)) {
19 | 			return null;
20 | 		}else {
21 | 			TextMessage textMsg = new TextMessage();
22 | 			textMsg.setContent(key);
23 | 			return WeixinUtil.dispatch(textMsg);
24 | 		}
25 | 	}
26 | 
27 | }
28 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/DictHandler.java:
--------------------------------------------------------------------------------
 1 | //package com.xlongwei.light4j.handler.weixin;
 2 | //
 3 | //import java.util.Arrays;
 4 | //import java.util.List;
 5 | //
 6 | //import com.xlongwei.light4j.util.DictUtil;
 7 | //import com.xlongwei.light4j.util.DictUtil.WordScore;
 8 | //import com.xlongwei.light4j.util.PinyinUtil;
 9 | //import com.xlongwei.light4j.util.StringUtil;
10 | //import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
11 | //
12 | ///**
13 | // * dict handler
14 | // * @author xlongwei
15 | // *
16 | // */
17 | //public class DictHandler extends AbstractTextHandler {
18 | //	private String regex = "^(查字|字典|生字|查询|生僻字)[  ]+[\\u4E00-\\u9FA5]+(([+,;+,;、]|[  ]+)[\\u4E00-\\u9FA5]+)*$";
19 | //
20 | //	@Override
21 | //	public String handle(String content) {
22 | //		if(content.matches(regex)) {
23 | //			StringBuilder answer = new StringBuilder();
24 | //			content = content.substring(3).trim();
25 | //			List list = DictUtil.parse(content);
26 | //			for(WordScore word : list) {
27 | //				answer.append(word.getWord()+"  ");
28 | //				String[] py = PinyinUtil.getPinyin(word.getWord().charAt(0), 0, 0, 0);
29 | //				answer.append(StringUtil.join(Arrays.asList(py), null, null, ", "));
30 | //				answer.append("\n");
31 | //			}
32 | //			if(answer.length() > 0) {
33 | //				return answer.substring(0, answer.length()-1);
34 | //			}
35 | //		}
36 | //		return null;
37 | //	}
38 | //
39 | //}
40 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/ImageHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import com.xlongwei.light4j.util.FileUtil;
 4 | import com.xlongwei.light4j.util.StringUtil;
 5 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage;
 6 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.ImageMessage;
 7 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.TextMessage;
 8 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler;
 9 | import com.xlongwei.light4j.util.ZxingUtil;
10 | 
11 | /**
12 |  * image handler
13 |  * @author xlongwei
14 |  *
15 |  */
16 | public class ImageHandler extends AbstractMessageHandler {
17 | 
18 | 	@Override
19 | 	public AbstractMessage handle(ImageMessage message) {
20 | 		String url = message.getPicUrl();
21 | 		if(StringUtil.isUrl(url)) {
22 | 			byte[] bytes = FileUtil.bytes(url);
23 | 			if(bytes != null) {
24 | 				String decode = ZxingUtil.decode(bytes);
25 | 				if(!StringUtil.isBlank(decode)) {
26 | 					TextMessage txtMsg = new TextMessage();
27 | 					txtMsg.setContent(decode);
28 | 					return txtMsg;
29 | 				}
30 | 			}
31 | 		}
32 | 		return null;
33 | 	}
34 | 
35 | }
36 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/KeyHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import java.util.ArrayList;
 4 | import java.util.Collections;
 5 | import java.util.Map;
 6 | 
 7 | import com.alibaba.fastjson.JSONObject;
 8 | import com.xlongwei.light4j.handler.service.IpHandler;
 9 | // import com.xlongwei.light4j.handler.service.MobileHandler;
10 | import com.xlongwei.light4j.util.JsonUtil;
11 | import com.xlongwei.light4j.util.RedisConfig;
12 | import com.xlongwei.light4j.util.StringUtil;
13 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
14 | 
15 | import cn.hutool.core.map.MapUtil;
16 | import cn.hutool.http.HttpRequest;
17 | import cn.hutool.http.HttpUtil;
18 | 
19 | /**
20 |  * key handler
21 |  * @author xlongwei
22 |  *
23 |  */
24 | public class KeyHandler extends AbstractTextHandler {
25 | 	
26 | 	@Override
27 | 	public String handle(String content) {
28 | 		if(!StringUtil.isBlank(content)) {
29 | 			if("openid".equals(content)) {
30 | 				return message.get().getFromUserName();
31 | 			}else if("metric".equals(content)){
32 | 				String string = HttpUtil.get("https://log.xlongwei.com/log?type=metric");
33 | 				@SuppressWarnings("unchecked")
34 | 				Map map = JsonUtil.parse(string, Map.class);
35 | 				if(MapUtil.isNotEmpty(map)) {
36 | 					StringBuilder response = new StringBuilder();
37 | 					ArrayList list = new ArrayList<>(map.keySet());
38 | 					Collections.sort(list);
39 | 					for(String key : list) {
40 | 						Object value = map.get(key);
41 | 						response.append(key).append('=').append(value).append('\n');
42 | 					}
43 | 					return response.toString();
44 | 				}
45 | 			}else if(content.startsWith("ip=")){
46 | 				content = content.substring("ip=".length());
47 | 				String openid = message.get().getFromUserName();
48 | 				if(!StringUtil.isBlank(openid)) {
49 | 					JSONObject alidnsConfig = JsonUtil.parseNew(RedisConfig.get("alidns.config"));
50 | 					String token = alidnsConfig.getString("token"), recordId = alidnsConfig.getString(openid);
51 | 					if(!StringUtil.isBlank(recordId)) {
52 | 						String ip = StringUtil.isIp(content) ? content : "";
53 | 						return HttpRequest.get("https://log.xlongwei.com/log?type=alidns&recordId="+recordId+"&ip="+ip).header("X-Request-Token", token).execute().body();
54 | 					}
55 | 				}
56 | 			}else  if(StringUtil.isIp(content)) {
57 | 				Map searchToMap = IpHandler.searchToMap(content);
58 | 				if(searchToMap!=null) {
59 | 					return searchToMap.get("region");
60 | 				}
61 | 			// }else if(StringUtil.getMobileType(content)>0) {
62 | 			// 	Map searchToMap = MobileHandler.searchToMap(content);
63 | 			// 	if(searchToMap!=null) {
64 | 			// 		return StringUtil.firstNotBlank(searchToMap.get("region"), MobileHandler.NUMBER_TYPE[StringUtil.getMobileType(content)]);
65 | 			// 	}
66 | 			}else {
67 | 				String string = RedisConfig.get("weixin.key."+content);
68 | 				if(!StringUtil.isBlank(string)) {
69 | 					return string;
70 | 				}
71 | 			}
72 | 		}
73 | 		return null;
74 | 	}
75 | 
76 | }
77 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/LocationHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage;
 4 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.LocationMessage;
 5 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.TextMessage;
 6 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler;
 7 | 
 8 | /**
 9 |  * location handler
10 |  * @author xlongwei
11 |  *
12 |  */
13 | public class LocationHandler extends AbstractMessageHandler {
14 | 
15 | 	@Override
16 | 	public AbstractMessage handle(LocationMessage message) {
17 | 		double locationX = message.getLocationX();
18 | 		double locationY = message.getLocationY();
19 | 		int scale = message.getScale();
20 | 		String label = message.getLabel();
21 | 		TextMessage textMsg = new TextMessage();
22 | 		textMsg.setContent("位置:"+label+"\n纬度:"+locationX+"\n经度:"+locationY+"\n放大比例:"+scale);
23 | 		return textMsg;
24 | 	}
25 | 
26 | }
27 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/NongliHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import java.util.Date;
 4 | import java.util.regex.Matcher;
 5 | import java.util.regex.Pattern;
 6 | 
 7 | import com.xlongwei.light4j.util.DateUtil;
 8 | import com.xlongwei.light4j.util.IdWorker.SystemClock;
 9 | import com.xlongwei.light4j.util.NumberUtil;
10 | import com.xlongwei.light4j.util.StringUtil;
11 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
12 | import com.xlongwei.light4j.util.ZhDate;
13 | 
14 | /**
15 |  * 农历转换
16 |  * @author xlongwei
17 |  *
18 |  */
19 | public class NongliHandler extends AbstractTextHandler {
20 | 	
21 | 	private Pattern pattern = Pattern.compile("(\\d{4})[\\.\\-](\\d{1,2})[\\.\\-](\\d{1,2})([,,](true|false))?");
22 | 
23 | 	@Override
24 | 	public String handle(String content) {
25 | 		if(StringUtil.isBlank(content)) {
26 | 			return null;
27 | 		}
28 | 		if(content.startsWith("农历")) {
29 | 			Date day = DateUtil.parseNow(content.substring(2));
30 | 			ZhDate zhDate = ZhDate.fromDate(day);
31 | 			int age = cn.hutool.core.date.DateUtil.ageOfNow(day);
32 | 			return zhDate.chinese()+" "+zhDate.ganzhi()+zhDate.shengxiao()+(age>0?" "+age:"");
33 | 		}else if(content.startsWith("阳历")) {
34 | 			Matcher matcher = pattern.matcher(content.substring(2));
35 | 			if(matcher.matches()) {
36 | 				int lunarYear = NumberUtil.parseInt(matcher.group(1), 2020), lunarMonth = NumberUtil.parseInt(matcher.group(2), 1), lunarDay = NumberUtil.parseInt(matcher.group(3), 1);
37 | 				boolean leapMonth = NumberUtil.parseBoolean(matcher.group(5), false);
38 | 				if(ZhDate.validate(lunarYear, lunarMonth, lunarDay, leapMonth)) {
39 | 					ZhDate zhDate = new ZhDate(lunarYear, lunarMonth, lunarDay, leapMonth);
40 | 					return DateUtil.dayFormat.format(zhDate.toDate());
41 | 				}else {
42 | 					return "农历日期不支持";
43 | 				}
44 | 			}else {
45 | 				return "示例:阳历2020.1.1";
46 | 			}
47 | 		}else if(content.startsWith("生肖") || content.startsWith("干支")) {
48 | 			int thisYear = Integer.valueOf(DateUtil.yearFormat.format(SystemClock.date()));
49 | 			int year = NumberUtil.parseInt(content.substring(2), thisYear);
50 | 			return year+ZhDate.ganzhi(year)+ZhDate.shengxiao(year)+(year>=thisYear?"":(thisYear-year));
51 | 		}
52 | 		return null;
53 | 	}
54 | 
55 | }
56 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/PinyinHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import java.util.Arrays;
 4 | 
 5 | import com.xlongwei.light4j.util.PinyinUtil;
 6 | import com.xlongwei.light4j.util.StringUtil;
 7 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
 8 | 
 9 | import net.sourceforge.pinyin4j.PinyinHelper2;
10 | 
11 | /**
12 |  * 获取拼音
13 |  * @author xlongwei
14 |  *
15 |  */
16 | public class PinyinHandler extends AbstractTextHandler {
17 | 	private String regex = "^拼音"+split+"(.+)$";
18 | 
19 | 	@Override
20 | 	public String handle(String content) {
21 | 		if(PinyinHelper2.hasPinyin(content)) {
22 | 			StringBuilder answer = new StringBuilder();
23 | 			String[] py = PinyinUtil.getPinyin(content, 0, 0, 0);
24 | 			answer.append(content+"  ");
25 | 			answer.append(StringUtil.join(Arrays.asList(py), null, null, ", "));
26 | 			return answer.toString();
27 | 		}else if(content.matches(regex)) {
28 | 			String text = content.substring(3).trim();
29 | 			String[] pinyin = PinyinUtil.getPinyin(text, 0, 0, 0);
30 | 			return StringUtil.join(Arrays.asList(pinyin), null, null, " ");
31 | 		}
32 | 		return null;
33 | 	}
34 | 
35 | }
36 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/PlateHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import com.xlongwei.light4j.util.PlateUtil;
 4 | import com.xlongwei.light4j.util.StringUtil;
 5 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
 6 | 
 7 | /**
 8 |  * plate handler
 9 |  * @author xlongwei
10 |  *
11 |  */
12 | public class PlateHandler extends AbstractTextHandler {
13 | 	
14 | 	@Override
15 | 	public String handle(String content) {
16 | 		if(StringUtil.isBlank(content)) {
17 | 			return null;
18 | 		}
19 | 		boolean search = false;
20 | 		if(content.length()>3 && content.startsWith("车牌")) {
21 | 			content = content.charAt(2)=='号' ? content.substring(3) : content.substring(2);
22 | 			search = true;
23 | 		}else {
24 | 			search = Character.isAlphabetic(content.charAt(1));
25 | 		}
26 | 		return search ? PlateUtil.search(content) : null;
27 | 	}
28 | 
29 | }
30 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/PoetryHandler.java:
--------------------------------------------------------------------------------
 1 | //package com.xlongwei.light4j.handler.weixin;
 2 | //
 3 | //import java.io.BufferedInputStream;
 4 | //import java.util.ArrayList;
 5 | //import java.util.Collections;
 6 | //import java.util.List;
 7 | //
 8 | //import com.xlongwei.light4j.util.ConfigUtil;
 9 | //import com.xlongwei.light4j.util.StringUtil;
10 | //import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
11 | //
12 | //import cn.hutool.core.util.NumberUtil;
13 | //import cn.hutool.poi.excel.ExcelUtil;
14 | //import lombok.extern.slf4j.Slf4j;
15 | //
16 | ///**
17 | // * poetry handler
18 | // * @author xlongwei
19 | // *
20 | // */
21 | //@Slf4j
22 | //public class PoetryHandler extends AbstractTextHandler {
23 | //	
24 | //	private static final String TAG = "唐诗";
25 | //
26 | //	@Override
27 | //	public String handle(String content) {
28 | //		if(StringUtil.isBlank(content) || !content.startsWith(TAG) || StringUtil.isBlank(content=content.substring(TAG.length()))) {
29 | //				return null;
30 | //		}
31 | //		return search(content);
32 | //	}
33 | //	
34 | //	public static String search(String str) {
35 | //		if(str == null || (str=str.trim()).length()==0) {
36 | //			return null;
37 | //		}
38 | //		if(StringUtil.isNumbers(str)) {
39 | //			return poetry(poetrys.get((NumberUtil.parseInt(str)-1) % poetrys.size()));
40 | //		}
41 | //		List authors = new ArrayList<>(), rows = new ArrayList<>();
42 | //		for(int i=0;i poetrys = new ArrayList<>();
76 | //	static {
77 | //		try{
78 | //			ExcelUtil.readBySax(new BufferedInputStream(ConfigUtil.stream("ts300.xlsx")), 0, (int i, long j, List list) -> {
79 | //					if(j > 0) {
80 | //						poetrys.add(list.toArray(new String[list.size()]));
81 | //					}
82 | //			});
83 | //			log.info("poetrys loaded, record={}", poetrys.size());
84 | //		}catch(Exception e) {
85 | //			log.warn("fail to init poetrys: {}", e.getMessage());
86 | //		}
87 | //	}
88 | //}
89 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/PostHandler.java:
--------------------------------------------------------------------------------
 1 | //package com.xlongwei.light4j.handler.weixin;
 2 | //
 3 | //import java.util.HashSet;
 4 | //import java.util.regex.Pattern;
 5 | //
 6 | //import org.apache.commons.collections4.CollectionUtils;
 7 | //
 8 | //import com.xlongwei.light4j.util.IdCardUtil;
 9 | //import com.xlongwei.light4j.util.PostUtil;
10 | //import com.xlongwei.light4j.util.StringUtil;
11 | //import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
12 | //
13 | ///**
14 | // * post handler
15 | // * @author xlongwei
16 | // *
17 | // */
18 | //public class PostHandler extends AbstractTextHandler {
19 | //
20 | //	private static final String TAG = "邮编";
21 | //	private Pattern pattern = Pattern.compile("\\d{6}");
22 | //	
23 | //	@Override
24 | //	public String handle(String content) {
25 | //		if(StringUtil.isBlank(content)) {
26 | //			return null;
27 | //		}
28 | //		
29 | //		if(pattern.matcher(content).matches()) {
30 | //			return post(content);
31 | //		}
32 | //		if(!content.startsWith(TAG)) {
33 | //			return null;
34 | //		}
35 | //		
36 | //		String post = content.substring(2).trim();
37 | //		if(StringUtil.isBlank(post)) {
38 | //			return null;
39 | //		}
40 | //		if(pattern.matcher(post).matches()) {
41 | //			return post(post);
42 | //		}
43 | //		
44 | //		for(String code : PostUtil.posts.allL()) {
45 | //			HashSet cities = PostUtil.posts.getR(code);
46 | //			for(String city : cities) {
47 | //				if(city.startsWith(post)) {
48 | //					return code;
49 | //				}
50 | //			}
51 | //		}
52 | //		return null;
53 | //	}
54 | //
55 | //	private String post(String code) {
56 | //		HashSet cities = PostUtil.posts.getR(code);
57 | //		if(CollectionUtils.isNotEmpty(cities)) {
58 | //			return new StringBuilder("邮编:").append(StringUtil.join(cities, null, null, null)).toString();
59 | //		}
60 | //		String area = StringUtil.join(IdCardUtil.areas(code), null, null, null);;
61 | //		if(StringUtil.hasLength(area)) {
62 | //			return new StringBuilder("行政区:").append(area).toString();
63 | //		}
64 | //		return null;
65 | //	}
66 | //}
67 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/SubscribeHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import com.xlongwei.light4j.util.RedisConfig;
 4 | import com.xlongwei.light4j.util.StringUtil;
 5 | import com.xlongwei.light4j.util.WeixinUtil;
 6 | import com.xlongwei.light4j.util.WeixinUtil.AbstractEvent.SubscribeEvent;
 7 | import com.xlongwei.light4j.util.WeixinUtil.AbstractEventHandler;
 8 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage;
 9 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.TextMessage;
10 | 
11 | import cn.hutool.core.date.DateUtil;
12 | import lombok.extern.slf4j.Slf4j;
13 | 
14 | /**
15 |  * subscribe handler
16 |  * @author xlongwei
17 |  *
18 |  */
19 | @Slf4j
20 | public class SubscribeHandler extends AbstractEventHandler {
21 | 
22 | 	public static final String WEIXIN_SUBSCRIBE = "weixin.subscribe.";
23 | 
24 | 	@Override
25 | 	public AbstractMessage handle(SubscribeEvent msg) {
26 | 		TextMessage textMessage = new TextMessage();
27 | 		String string = null;
28 | 		String fromUserName = msg.getFromUserName();
29 | 		String toUserName = msg.getToUserName();
30 | 		boolean isTest = WeixinUtil.touserTest.equals(toUserName);
31 | 		log.info("weixin.subscribe from={} to={} test={}", fromUserName, toUserName, isTest);
32 | 		if(isTest) {
33 | 			RedisConfig.persist(RedisConfig.CACHE, WEIXIN_SUBSCRIBE+fromUserName, DateUtil.now());
34 | 			string = "欢迎关注,您的openid是:\n" + fromUserName;
35 | 		}else {
36 | 			string = RedisConfig.get("weixin.key.help");
37 | 		}
38 | 		textMessage.setContent(StringUtil.firstNotBlank(string, "欢迎关注!"));
39 | 		return textMessage;
40 | 	}
41 | 
42 | }
43 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/VoiceHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import com.xlongwei.light4j.util.StringUtil;
 4 | import com.xlongwei.light4j.util.WeixinUtil;
 5 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage;
 6 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.TextMessage;
 7 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessage.VoiceMessage;
 8 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler;
 9 | 
10 | /**
11 |  * voice handler
12 |  * @author xlongwei
13 |  *
14 |  */
15 | public class VoiceHandler extends AbstractMessageHandler {
16 | 
17 | 	@Override
18 | 	public AbstractMessage handle(VoiceMessage msg) {
19 | 		String recognition = msg.getRecognition();
20 | 		if(!StringUtil.isBlank(recognition)) {
21 | 			TextMessage respMsg = new TextMessage();
22 | 			respMsg.setContent(recognition);
23 | 			AbstractMessage dispatch = null;
24 | 			if(recognition.length()>1) {
25 | 				TextMessage txtMsg = new TextMessage();
26 | 				//微信识别出的文字以句号结尾
27 | 				txtMsg.setContent(recognition.substring(0, recognition.length()-1));
28 | 				dispatch = WeixinUtil.dispatch(txtMsg);
29 | 			}
30 | 			return dispatch!=null ? dispatch : respMsg;
31 | 		}
32 | 		return null;
33 | 	}
34 | 
35 | }
36 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/handler/weixin/YoudaoHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.handler.weixin;
 2 | 
 3 | import java.util.List;
 4 | import java.util.regex.Matcher;
 5 | import java.util.regex.Pattern;
 6 | 
 7 | import com.xlongwei.light4j.util.HttpUtil;
 8 | import com.xlongwei.light4j.util.JsonUtil;
 9 | import com.xlongwei.light4j.util.RedisCache;
10 | import com.xlongwei.light4j.util.RedisConfig;
11 | import com.xlongwei.light4j.util.StringUtil;
12 | import com.xlongwei.light4j.util.WeixinUtil.AbstractMessageHandler.AbstractTextHandler;
13 | 
14 | /**
15 |  * youdao dict
16 |  * @author xlongwei
17 |  *
18 |  */
19 | public class YoudaoHandler extends AbstractTextHandler {
20 | 	private Pattern pattern = Pattern.compile("^翻译"+split+"([a-zA-Z]+|[\\u4E00-\\u9FA5]+)$");
21 | 	private static final String WORD = "[a-zA-Z]{3,}";
22 | 	private static final String ERROR_CODE = "errorCode";
23 | 	private static String KEY_FROM = "xlongwei", YOUDAO_API = "http://fanyi.youdao.com/openapi.do";
24 | 	private static String CACHE_WEIXIN = "weixin.translate", CACHE_YOUDAO = "youdao.translate";
25 | 	
26 | 	@Override
27 | 	public String handle(String content) {
28 | 		if(StringUtil.isBlank(content)) {
29 | 			return null;
30 | 		}
31 | 		String translate = null;
32 | 		Matcher matcher = pattern.matcher(content);
33 | 		if(matcher.matches()) {
34 | 			translate = matcher.group(1);
35 | 		} else if(content.matches(WORD)) {
36 | 			translate = content;
37 | 		}
38 | 		if(StringUtil.isBlank(translate)) {
39 | 			return null;
40 | 		}
41 | 		String cached = RedisCache.get(CACHE_WEIXIN, translate);
42 | 		if(!StringUtil.isBlank(cached)) {
43 | 			return cached;
44 | 		}
45 | 		cached = translate(translate);
46 | 		if(JsonUtil.getInt(cached, ERROR_CODE) == 0) {
47 | 			StringBuilder response = new StringBuilder();
48 | 			response.append(StringUtil.join(JsonUtil.getList(cached, "translation", String.class),null,null,","));
49 | 			response.append(", "+JsonUtil.get(cached, "basic.phonetic"));
50 | 			if(StringUtil.isIdentifier(translate)) {
51 | 				response.append(", (美) "+JsonUtil.get(cached, "basic.us-phonetic")+", (英) "+JsonUtil.get(cached, "basic.uk-phonetic"));
52 | 			}
53 | 			response.append("\n\n"+StringUtil.join(JsonUtil.getList(cached, "basic.explains", String.class), null, null, "\n"));
54 | 			List webs = JsonUtil.getList(cached, "web", String.class);
55 | 			if(webs!=null && webs.size()>0) {
56 | 				response.append("\n");
57 | 				for(String web : webs) {
58 | 					response.append("\n"+JsonUtil.get(web, "key")+" "+StringUtil.join(JsonUtil.getList(web, "value", String.class), null, null, ","));
59 | 				}
60 | 			}
61 | 			cached = response.toString();
62 | 			RedisCache.set(CACHE_WEIXIN, translate, cached);
63 | 			return cached;
64 | 		}
65 | 		return null;
66 | 	}
67 | 
68 | 	public static String translate(String text) {
69 | 		String key = RedisConfig.get("youdao.key");
70 | 		if(StringUtil.isBlank(key) || StringUtil.isBlank(KEY_FROM) || StringUtil.isBlank(text)) {
71 | 			return null;
72 | 		}
73 | 		String cached = RedisCache.get(CACHE_YOUDAO, text);
74 | 		if(!StringUtil.isBlank(cached)) {
75 | 			return cached;
76 | 		}
77 | 		cached = HttpUtil.post(YOUDAO_API, StringUtil.params("keyfrom",KEY_FROM,"key",key,"type","data","doctype","json","version","1.1","q",text));
78 | 		RedisCache.set(CACHE_YOUDAO, text, cached);
79 | 		return cached;
80 | 	}
81 | }
82 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/openapi/OpenapiHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.openapi;
 2 | 
 3 | import java.util.Deque;
 4 | import java.util.HashMap;
 5 | import java.util.Map;
 6 | import java.util.Set;
 7 | 
 8 | import com.networknt.handler.LightHttpHandler;
 9 | import com.networknt.utility.StringUtils;
10 | import com.xlongwei.light4j.handler.ServiceHandler;
11 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
12 | import com.xlongwei.light4j.util.HandlerUtil;
13 | import com.xlongwei.light4j.util.PathEndpointSource;
14 | 
15 | import cn.hutool.core.util.ClassUtil;
16 | import cn.hutool.core.util.ReflectUtil;
17 | import io.undertow.server.HttpServerExchange;
18 | import lombok.extern.slf4j.Slf4j;
19 | 
20 | /**
21 |  * openapi handler
22 |  * @author xlongwei
23 |  *
24 |  */
25 | @Slf4j
26 | public class OpenapiHandler implements LightHttpHandler {
27 | 	private Map handlers = new HashMap<>();
28 | 	
29 | 	public OpenapiHandler() {
30 | 		String service = getClass().getPackage().getName()+".handler";
31 | 		Set> list = ClassUtil.scanPackageBySuper(service, AbstractHandler.class);
32 | 		for(Class clazz : list) {
33 | 			AbstractHandler handler = (AbstractHandler)ReflectUtil.newInstanceIfPossible(clazz);
34 | 			String name = handler.name();
35 | 			handlers.put(name, handler);
36 | 			log.info("openapi {} => {}", name, handler.getClass().getName());
37 | 		}
38 | 	}
39 | 
40 | 	@Override
41 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
42 | 		Map> queryParameters = exchange.getQueryParameters();
43 | 		String service = queryParameters.remove("*").getFirst();
44 | 		log.info("{} {}", exchange.getRequestMethod(), exchange.getRequestURI());
45 | 		int dot = service.indexOf('.');
46 | 		String[] split = StringUtils.split(dot>0 ? service.substring(0, dot) : service, "/");
47 | 		if(split.length > 0) {
48 | 			String name = split[0];
49 | 			AbstractHandler handler = handlers.get(name);
50 | 			if(handler == null) {
51 | 				handler = ServiceHandler.handlers.get(name);
52 | 				ServiceHandler.serviceCount(name);
53 | 			}
54 | 			if(handler != null) {
55 | 				String path = split.length>1 ? split[1] : "";
56 | 				exchange.putAttachment(AbstractHandler.PATH, path);
57 | 				HandlerUtil.parseBody(exchange);
58 | 				handler.handleRequest(exchange);
59 | 			}
60 | 		}
61 | 		HandlerUtil.sendResp(exchange);
62 | 	}
63 | 	public static class OpenapiEndpointSource extends PathEndpointSource {
64 | 		public OpenapiEndpointSource() {
65 | 			super("/openapi/*");
66 | 		}
67 | 	}
68 | }
69 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/openapi/extend/DummyMiddlewareHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.openapi.extend;
 2 | 
 3 | import com.networknt.handler.Handler;
 4 | import com.networknt.handler.MiddlewareHandler;
 5 | import com.networknt.utility.ModuleRegistry;
 6 | 
 7 | import io.undertow.Handlers;
 8 | import io.undertow.server.HttpHandler;
 9 | import io.undertow.server.HttpServerExchange;
10 | 
11 | /**
12 |  * MiddlewareHandler adapter
13 |  * @author xlongwei
14 |  *
15 |  */
16 | public class DummyMiddlewareHandler implements MiddlewareHandler {
17 | 	protected volatile HttpHandler next;
18 | 	
19 | 	@Override
20 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
21 | 		Handler.next(exchange, next);
22 | 	}
23 | 
24 | 	@Override
25 | 	public HttpHandler getNext() {
26 | 		return next;
27 | 	}
28 | 
29 | 	@Override
30 | 	public MiddlewareHandler setNext(HttpHandler next) {
31 | 		Handlers.handlerNotNull(next);
32 |         this.next = next;
33 |         return this;
34 | 	}
35 | 
36 | 	@Override
37 | 	public boolean isEnabled() {
38 | 		return true;
39 | 	}
40 | 
41 | 	@Override
42 | 	public void register() {
43 | 		ModuleRegistry.registerModule(getClass().getName(), null, null);
44 | 	}
45 | 
46 | }
47 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/openapi/extend/MyCorrelationHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.openapi.extend;
 2 | 
 3 | import com.networknt.config.Config;
 4 | import com.networknt.correlation.CorrelationHandler;
 5 | import com.networknt.handler.Handler;
 6 | import com.networknt.httpstring.HttpStringConstants;
 7 | import com.networknt.utility.ModuleRegistry;
 8 | import com.networknt.utility.StringUtils;
 9 | import com.networknt.utility.Util;
10 | 
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.slf4j.MDC;
14 | 
15 | import io.undertow.server.HttpServerExchange;
16 | 
17 | public class MyCorrelationHandler extends DummyMiddlewareHandler {
18 |     private static final Logger logger = LoggerFactory.getLogger(MyCorrelationHandler.class);
19 |     private static final String CID = "cId";
20 |     private static final String CONFIG_NAME = "correlation";
21 | 
22 |     @Override
23 |     public void handleRequest(final HttpServerExchange exchange) throws Exception {
24 |         // check if the cid is in the request header
25 |         String cId = exchange.getRequestHeaders().getFirst(HttpStringConstants.CORRELATION_ID);
26 |         if (cId == null) {
27 |             // if not set, check the autgen flag and generate if set to true
28 |             String tId = exchange.getRequestHeaders().getFirst(HttpStringConstants.TRACEABILITY_ID);
29 |             if (StringUtils.isBlank(tId)) {// showapi转发请求头有bug
30 |                 tId = exchange.getRequestHeaders().getFirst("showapi_res_id");
31 |                 exchange.getResponseHeaders().put(HttpStringConstants.TRACEABILITY_ID, tId);
32 |             }
33 |             if (CorrelationHandler.config.isAutogenCorrelationID()) {
34 |                 // generate a UUID and put it into the request header
35 |                 cId = Util.getUUID();
36 |             } else {
37 |                 cId = tId;
38 |             }
39 |             if (tId != null) {
40 |                 exchange.getRequestHeaders().put(HttpStringConstants.CORRELATION_ID, cId);
41 |                 if (!tId.equals(cId) && logger.isInfoEnabled()) {
42 |                     logger.info("Associate traceability Id " + tId + " with correlation Id " + cId);
43 |                 }
44 |             }
45 |         }
46 |         // Add the cId into MDC so that all log statement will have cId as part of it.
47 |         MDC.put(CID, cId);
48 |         // logger.debug("Init cId:" + cId);
49 |         Handler.next(exchange, next);
50 |     }
51 | 
52 |     @Override
53 |     public boolean isEnabled() {
54 |         return CorrelationHandler.config.isEnabled();
55 |     }
56 | 
57 |     @Override
58 |     public void register() {
59 |         ModuleRegistry.registerModule(CorrelationHandler.class.getName(),
60 |                 Config.getInstance().getJsonMapConfigNoCache(CONFIG_NAME), null);
61 |     }
62 | }
63 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/openapi/extend/MyRedisSessionRepository.java:
--------------------------------------------------------------------------------
 1 | // package com.xlongwei.light4j.openapi.extend;
 2 | 
 3 | // import org.redisson.config.Config;
 4 | 
 5 | // import com.alibaba.fastjson.JSONObject;
 6 | // import com.networknt.session.redis.RedisSessionRepository;
 7 | // import com.xlongwei.light4j.util.FileUtil;
 8 | // import com.xlongwei.light4j.util.FileUtil.CharsetNames;
 9 | // import com.xlongwei.light4j.util.JsonUtil;
10 | // import com.xlongwei.light4j.util.RedisConfig;
11 | 
12 | // import lombok.extern.slf4j.Slf4j;
13 | 
14 | // /**
15 | //  * service.yml可选配置RedisSessionRepository,默认使用此类会使用-Dredis.configDb的配置
16 | //  * @author xlongwei
17 | //  */
18 | // @Slf4j
19 | // public class MyRedisSessionRepository extends RedisSessionRepository {
20 | // 	static Config configRef = null;
21 | // 	static {
22 | // 		String address = "redis://" + RedisConfig.host + ":" + RedisConfig.port;
23 | // 		String configJsonFile = "/singleNodeConfig.json";
24 | // 		try {
25 | // 			String configJsonString = FileUtil.readString(MyRedisSessionRepository.class.getResourceAsStream(configJsonFile), CharsetNames.UTF_8);
26 | // 			JSONObject configJson = JsonUtil.parse(configJsonString);
27 | // 			JSONObject singleServerConfig = configJson.getJSONObject("singleServerConfig");
28 | // //			if(!singleServerConfig.containsKey("address")) {
29 | // 				singleServerConfig.put("address", address);
30 | // 				configJsonString = configJson.toJSONString();
31 | // //			}
32 | // 			log.info("singleServerConfig.address={}", singleServerConfig.getString("address"));
33 | // 			config = Config.fromJSON(configJsonString);
34 | // 		}catch(Exception e) {
35 | // 			config = new Config();
36 | // 			config.useSingleServer().setAddress(address);
37 | // 		}
38 | // 		configRef = config;
39 | // 	}
40 | // 	public MyRedisSessionRepository() {
41 | // 		super();
42 | // 		assert(configRef == config);
43 | // 	}
44 | // }
45 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/openapi/handler/DatetimeHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.openapi.handler;
 2 | 
 3 | import java.net.URI;
 4 | import java.util.List;
 5 | import java.util.Map;
 6 | 
 7 | import com.networknt.cluster.Cluster;
 8 | import com.networknt.server.Server;
 9 | import com.networknt.server.ServerConfig;
10 | import com.networknt.server.Servers;
11 | import com.networknt.service.SingletonServiceFactory;
12 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
13 | import com.xlongwei.light4j.util.HandlerUtil;
14 | import com.xlongwei.light4j.util.Http2Util;
15 | import com.xlongwei.light4j.util.JsonUtil;
16 | import com.xlongwei.light4j.util.StringUtil;
17 | 
18 | import io.undertow.client.ClientRequest;
19 | import io.undertow.server.HttpServerExchange;
20 | import io.undertow.util.Methods;
21 | 
22 | /**
23 |  * 用于体验consul registry功能,需要在server.yml开启enableRegistry,并配置client.trustore、consul.yml
24 |  * @author xlongwei
25 |  */
26 | public class DatetimeHandler extends AbstractHandler {
27 | 	static Cluster cluster = SingletonServiceFactory.getBean(Cluster.class);
28 | 	static ServerConfig serverConfig = Servers.currentPort!=-1 ? Servers.getServerConfig() : Server.getServerConfig();
29 | 	static String protocal = serverConfig.isEnableHttps() ? "https" : "http";
30 | 	static URI localhost = null;
31 |     static String path = "/service/datetime";
32 |     static String serviceId = Server.getServerConfig().getServiceId();
33 |     static String tag = Server.getServerConfig().getEnvironment();
34 | 
35 | 	@Override
36 | 	@SuppressWarnings({ "unchecked" })
37 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
38 | 		if (Server.getServerConfig().isEnableRegistry() == false) {
39 | 			// enableRegistry=false时可以没有consul,此时可避免自动重试连接consul
40 | 			if (localhost == null) {
41 | 				// localhost与启动类有关,light4j的start.sh使用了自定义的Servers会同时监听两个端口,也可以使用启动类为Server
42 | 				localhost = new URI(protocal + "://localhost:" + (Servers.currentPort!=-1 ? Servers.currentPort : Server.currentPort));
43 | 			}
44 | 			String datetime = Http2Util.execute(localhost, new ClientRequest().setMethod(Methods.GET).setPath(path), null);
45 | 			HandlerUtil.setResp(exchange, JsonUtil.parse(datetime, Map.class));
46 | 			return;
47 | 		}
48 | 		List services = cluster.services(protocal, serviceId, tag);
49 | 		for (URI service : services) {
50 | 			// 通过循环可以自动重试下一个节点
51 | 			String datetime = Http2Util.execute(service, new ClientRequest().setMethod(Methods.GET).setPath(path), null);
52 | 			if (StringUtil.hasLength(datetime)) {
53 | 				HandlerUtil.setResp(exchange, JsonUtil.parse(datetime, Map.class));
54 | 				return;
55 | 			}
56 | 		}
57 | 	}
58 | 
59 | }
60 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/openapi/handler/ServiceHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.openapi.handler;
 2 | 
 3 | import com.networknt.cors.CorsUtil;
 4 | import com.networknt.utility.StringUtils;
 5 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 6 | import com.xlongwei.light4j.util.HandlerUtil;
 7 | import com.xlongwei.light4j.util.StringUtil;
 8 | 
 9 | import cn.hutool.core.map.MapUtil;
10 | import io.undertow.server.HttpServerExchange;
11 | 
12 | /**
13 |  * service handler
14 |  * @author xlongwei
15 |  *
16 |  */
17 | public class ServiceHandler extends AbstractHandler {
18 | 
19 | 	@Override
20 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
21 | 		String service = exchange.getRequestHeaders().getFirst(com.xlongwei.light4j.handler.ServiceHandler.HANDLER_PATH);
22 | 		String name = HandlerUtil.getParam(exchange, "handler"), path = HandlerUtil.getParam(exchange, "path");
23 | 		if (StringUtil.hasLength(service)) {
24 | 			String[] split = StringUtils.split(service, "/");
25 | 			name = split[0];
26 | 			path = split.length > 1 ? split[1] : null;
27 | 		}
28 | 		if(StringUtils.isBlank(name)) {
29 | 			return;
30 | 		}
31 | 		AbstractHandler handler = com.xlongwei.light4j.handler.ServiceHandler.handlers.get(name);
32 | 		if(handler==null) {
33 | 			return;
34 | 		}
35 | 		if(CorsUtil.isPreflightedRequest(exchange)) {
36 | 			HandlerUtil.setResp(exchange, MapUtil.newHashMap());
37 | 		}else {
38 | 			exchange.putAttachment(AbstractHandler.PATH, StringUtils.isBlank(path)?"":path);
39 | 			handler.handleRequest(exchange);
40 | 			com.xlongwei.light4j.handler.ServiceHandler.serviceCount(name);
41 | 		}
42 | 	}
43 | 
44 | }
45 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/openapi/handler/UploadHandler.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.openapi.handler;
 2 | 
 3 | import java.io.File;
 4 | 
 5 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler;
 6 | import com.xlongwei.light4j.util.FileUtil;
 7 | import com.xlongwei.light4j.util.HandlerUtil;
 8 | import com.xlongwei.light4j.util.IdWorker;
 9 | import com.xlongwei.light4j.util.StringUtil;
10 | import com.xlongwei.light4j.util.UploadUtil;
11 | 
12 | import io.undertow.server.HttpServerExchange;
13 | import io.undertow.server.handlers.form.FormData.FormValue;
14 | import lombok.extern.slf4j.Slf4j;
15 | 
16 | /**
17 |  * openapi upload handler
18 |  * @author xlongwei
19 |  *
20 |  */
21 | @Slf4j
22 | public class UploadHandler extends AbstractHandler {
23 | 
24 | 	@Override
25 | 	public void handleRequest(HttpServerExchange exchange) throws Exception {
26 | 		FormValue file = HandlerUtil.getFile(exchange, "file");
27 | 		if(file!=null && file.isFileItem()) {
28 | 			String fileName = file.getFileName();
29 | 			String path = "openapi/"+IdWorker.getId()+"."+FileUtil.getFileExt(fileName);
30 | 			File target = new File(UploadUtil.SAVE, path);
31 | 			boolean save = UploadUtil.save(file.getFileItem().getInputStream(), target);
32 | 			log.info("direct upload save={}, file={}, size={}K, path={}", save, fileName, target.length()/1024, path);
33 | 			if(save) {
34 | 				String url = UploadUtil.string(UploadUtil.URL + path);
35 | 				HandlerUtil.setResp(exchange, StringUtil.params("url", url));
36 | 			}
37 | 		}else {
38 | 			String type = HandlerUtil.getParam(exchange, "type");
39 | 			String name = HandlerUtil.getParam(exchange, "name");
40 | 			if(!StringUtil.isBlank(name) && (UploadUtil.CONFIRM.equals(type) || UploadUtil.TRASH.equals(type))) {
41 | 				boolean move = UploadUtil.move(name, type);
42 | 				HandlerUtil.setResp(exchange, StringUtil.params(type, move ? "1" : "0"));
43 | 			}
44 | 		}
45 | 	}
46 | 
47 | }
48 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/provider/WebSocketAbstractCallback.java:
--------------------------------------------------------------------------------
  1 | package com.xlongwei.light4j.provider;
  2 | 
  3 | import java.util.Map;
  4 | import java.util.concurrent.ConcurrentHashMap;
  5 | 
  6 | import com.xlongwei.light4j.util.StringUtil;
  7 | 
  8 | import io.undertow.websockets.WebSocketConnectionCallback;
  9 | import io.undertow.websockets.core.AbstractReceiveListener;
 10 | import io.undertow.websockets.core.BufferedTextMessage;
 11 | import io.undertow.websockets.core.WebSocketChannel;
 12 | import io.undertow.websockets.core.WebSockets;
 13 | import io.undertow.websockets.spi.WebSocketHttpExchange;
 14 | import lombok.extern.slf4j.Slf4j;
 15 | 
 16 | /**
 17 |  * WebSocket抽象类
 18 |  * @author xlongwei
 19 |  *
 20 |  */
 21 | @Slf4j
 22 | public abstract class WebSocketAbstractCallback implements WebSocketConnectionCallback {
 23 | 	private String name = getClass().getSimpleName().replace("WebSocket", "").replace("Callback", "").toLowerCase();
 24 | 	private Map serverMapClients = new ConcurrentHashMap<>();
 25 | 	private static String[] ipHeaders = {"X-Forwarded-For", "X-Real-IP"};
 26 | 
 27 | 	@Override
 28 | 	public void onConnect(WebSocketHttpExchange exchange, WebSocketChannel channel) {
 29 | 		channel.getReceiveSetter().set(new AbstractReceiveListener() {
 30 | 			@Override
 31 | 			protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {
 32 | 				String text = message.getData();
 33 | 				log.info("receive {} <= {} {}", getServerPort(channel), getClientPort(channel), text);
 34 | 				onTextMessage(channel, text);
 35 | 			}
 36 | 		});
 37 | 		String serverPort = getServerPort(channel);
 38 | 		String clientPort = getClientPort(exchange, channel);
 39 | 		log.info("connect {} {} <=> {}", name, serverPort, clientPort);
 40 | 		serverMapClients.put(serverPort, clientPort);
 41 | 		channel.resumeReceives();
 42 | 		onConnectEvent(exchange, channel);
 43 | 	}
 44 | 	
 45 | 	/** /127.0.0.1:61642 */
 46 | 	public static String getClientPort(WebSocketHttpExchange exchange, WebSocketChannel channel) {
 47 | 		String clientPort = channel.getSourceAddress().toString();
 48 | 		String clientIp = null;
 49 | 		for(String ipHeader : ipHeaders) {
 50 | 			String ipValue = exchange.getRequestHeader(ipHeader);
 51 | 			if(!StringUtil.isBlank(ipValue) && ipValue.indexOf('.')>0) {
 52 | 				int p = ipValue.indexOf(',');
 53 | 				if(p>0) {
 54 | 					ipValue = ipValue.substring(0, p);
 55 | 				}
 56 | 				if(StringUtil.isIp(ipValue) && !"127.0.0.1".equals(ipValue)) {
 57 | 					clientIp = ipValue;
 58 | 				}
 59 | 			}
 60 | 			if(clientIp != null) {
 61 | 				break;
 62 | 			}
 63 | 		}
 64 | 		return clientIp==null ? clientPort : "/"+clientIp+clientPort.substring(clientPort.indexOf(':'));
 65 | 	}
 66 | 	
 67 | 	/** 发送消息给客户端 */
 68 | 	protected void sendText(WebSocketChannel channel, String text, boolean broadcast) {
 69 | 		if(broadcast) {
 70 | 			log.info("broadcast {} => {} {}", getServerPort(channel), getClientPort(channel), text);
 71 | 			channel.getPeerConnections().parallelStream().forEach(c -> WebSockets.sendText(text, c, null));
 72 | 		}else {
 73 | 			log.info("send {} => {} {}", getServerPort(channel), getClientPort(channel), text);
 74 | 			WebSockets.sendText(text, channel, null);
 75 | 		}
 76 | 	}
 77 | 	
 78 | 	protected void sendText(WebSocketChannel channel, String text) {
 79 | 		sendText(channel, text, false);
 80 | 	}
 81 | 
 82 | 	/** 处理接受到的消息 */
 83 | 	protected abstract void onTextMessage(WebSocketChannel channel, String text);
 84 | 	
 85 | 	/** 处理客户端连接事件 */
 86 | 	protected void onConnectEvent(WebSocketHttpExchange exchange, WebSocketChannel channel) { }
 87 | 	
 88 | 	/** /127.0.0.1:61642 */
 89 | 	protected String getServerPort(WebSocketChannel channel) {
 90 | 		return channel.getDestinationAddress().toString();
 91 | 	}
 92 | 	
 93 | 	/** /127.0.0.1:61642 */
 94 | 	protected String getClientPort(WebSocketChannel channel) {
 95 | 		return serverMapClients.get(getServerPort(channel));
 96 | 	}
 97 | 	
 98 | 	protected String getClientIp(WebSocketChannel channel) {
 99 | 		String clientPort = getClientPort(channel);
100 | 		return StringUtil.isBlank(clientPort) ? "" : clientPort.substring(1, clientPort.lastIndexOf(':'));
101 | 	}
102 | }
103 | 


--------------------------------------------------------------------------------
/src/main/java/com/xlongwei/light4j/provider/WebSocketChatCallback.java:
--------------------------------------------------------------------------------
 1 | package com.xlongwei.light4j.provider;
 2 | 
 3 | import java.util.List;
 4 | 
 5 | import com.xlongwei.light4j.util.DateUtil;
 6 | import com.xlongwei.light4j.util.IdWorker.SystemClock;
 7 | import com.xlongwei.light4j.util.NumberUtil;
 8 | import com.xlongwei.light4j.util.RedisConfig;
 9 | 
10 | import io.undertow.websockets.core.WebSocketChannel;
11 | import io.undertow.websockets.core.WebSockets;
12 | import io.undertow.websockets.spi.WebSocketHttpExchange;
13 | import lombok.extern.slf4j.Slf4j;
14 | 
15 | /**
16 |  * 简单群聊
17 |  * @author xlongwei
18 |  *
19 |  */
20 | @Slf4j
21 | public class WebSocketChatCallback extends WebSocketAbstractCallback {
22 | 	private final String key = "ws.chat";
23 | 	private final int length = 18;
24 | 	boolean mute = false;
25 | 
26 | 	@Override
27 | 	protected void onTextMessage(WebSocketChannel channel, String text) {
28 | 		String msg = String.format("
 [%s]%s/%d:
 %s", DateUtil.format(SystemClock.date()), getClientIp(channel), channel.getPeerConnections().size(), text); 29 | if("mute".equals(text)) { 30 | mute = !mute; 31 | log.info("chat mute: {}", mute); 32 | }else if(!mute){ 33 | sendText(channel, msg, true); 34 | Long size = RedisConfig.lpush(RedisConfig.CACHE, key, msg); 35 | if(size > length) { 36 | RedisConfig.ltrim(RedisConfig.CACHE, key, 0, length-1); 37 | } 38 | } 39 | } 40 | 41 | @Override 42 | protected void onConnectEvent(WebSocketHttpExchange exchange, WebSocketChannel channel) { 43 | boolean history = NumberUtil.parseBoolean(RedisConfig.get("ws.chat.history"), true); 44 | List list = RedisConfig.lrange(RedisConfig.CACHE, key, 0, length); 45 | int size = list==null ? 0 : list.size(); 46 | log.info("history size: {}, history enabled: {}", size, history); 47 | if(size > 0 && history) { 48 | for(int i=size-1; i>=0; i--) { 49 | String msg = list.get(i); 50 | WebSockets.sendText(msg, channel, null); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/provider/WebSocketHandlerProvider.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.provider; 2 | 3 | import static io.undertow.Handlers.path; 4 | import static io.undertow.Handlers.resource; 5 | import static io.undertow.Handlers.websocket; 6 | 7 | import com.networknt.handler.HandlerProvider; 8 | 9 | import io.undertow.server.HttpHandler; 10 | import io.undertow.server.handlers.ResponseCodeHandler; 11 | import io.undertow.server.handlers.resource.ClassPathResourceManager; 12 | 13 | /** 14 | * web socket handler 15 | * @author xlongwei 16 | * 17 | */ 18 | public class WebSocketHandlerProvider implements HandlerProvider { 19 | @Override 20 | public HttpHandler getHandler() { 21 | return path() 22 | .addPrefixPath("/ws/chat", websocket(new WebSocketChatCallback())) 23 | .addPrefixPath("/ws/service", websocket(new WebSocketServiceCallback())) 24 | .addPrefixPath("/ws/ok", ResponseCodeHandler.HANDLE_200) 25 | .addPrefixPath("/ws/", resource(new ClassPathResourceManager(WebSocketHandlerProvider.class.getClassLoader(), "public"))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/provider/WebSocketServiceCallback.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.provider; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.alibaba.fastjson.JSONObject; 7 | import com.networknt.utility.StringUtils; 8 | import com.xlongwei.light4j.handler.ServiceHandler; 9 | import com.xlongwei.light4j.handler.ServiceHandler.AbstractHandler; 10 | import com.xlongwei.light4j.util.HandlerUtil; 11 | import com.xlongwei.light4j.util.JsonUtil; 12 | import com.xlongwei.light4j.util.StringUtil; 13 | 14 | import org.xnio.IoUtils; 15 | 16 | import io.undertow.server.HttpServerExchange; 17 | import io.undertow.util.Headers; 18 | import io.undertow.websockets.core.WebSocketChannel; 19 | 20 | /** 21 | * 服务调用 22 | * @author xlongwei 23 | * 24 | */ 25 | public class WebSocketServiceCallback extends WebSocketAbstractCallback { 26 | 27 | @Override 28 | protected void onTextMessage(WebSocketChannel channel, String text) { 29 | JSONObject request = JsonUtil.parseNew(text);//{handler,path,data:{},sequence} 30 | String handler = request.getString("handler"), path = request.getString("path"); 31 | if(!StringUtil.isBlank(handler)) { 32 | AbstractHandler service = ServiceHandler.handlers.get(handler); 33 | if(service != null) { 34 | HttpServerExchange exchange = new HttpServerExchange(null); 35 | exchange.getRequestHeaders().add(Headers.X_FORWARDED_FOR, getClientIp(channel)); 36 | exchange.setSourceAddress(channel.getSourceAddress()); 37 | boolean ipsConfig = HandlerUtil.ipsConfig(exchange, handler); 38 | ServiceHandler.serviceCount(handler); 39 | if(!ipsConfig) { 40 | sendText(channel, "{\"error\":\"access is limited\"}"); 41 | IoUtils.safeClose(channel); 42 | return; 43 | } 44 | exchange.putAttachment(AbstractHandler.PATH, StringUtils.isBlank(path)?"":path); 45 | if(request.containsKey("data")) { 46 | //{"handler":"datetime","path":"info","data":{"day":"2020-12-17"}} 47 | JSONObject data = request.getJSONObject("data"); 48 | exchange.putAttachment(HandlerUtil.BODY, data); 49 | } 50 | try{ 51 | service.handleRequest(exchange); 52 | Object resp = exchange.removeAttachment(HandlerUtil.RESP); 53 | if(resp != null) { 54 | Map map = new HashMap<>(4); 55 | if(request.containsKey("sequence")) { 56 | map.put("sequence", request.getString("sequence")); 57 | } 58 | map.put("data", resp); 59 | sendText(channel, JSONObject.toJSONString(map)); 60 | }else { 61 | sendText(channel, ServiceHandler.BAD_REQUEST); 62 | } 63 | }catch(Exception e) { 64 | sendText(channel, "{\"error\":\""+e.getMessage()+"\"}"); 65 | } 66 | } 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/BankUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import lombok.Data; 8 | 9 | /** 10 | * 银行卡号信息查询 11 | * @author xlongwei 12 | * 13 | */ 14 | public class BankUtil { 15 | static CardBin cardBin = new CardBin(); 16 | static Map cardMap = new HashMap<>(); 17 | 18 | /** 19 | * 通过银行卡号查找卡片信息 20 | * @param accountNo 21 | * @return CardInfo 22 | */ 23 | public static CardInfo cardInfo(String accountNo) { 24 | String bin = cardBin.bin(accountNo); 25 | return bin==null ? null : cardMap.get(bin); 26 | } 27 | 28 | /** 通过银行卡号查找卡bin码 */ 29 | public static String cardBin(String accountNo) { 30 | return cardBin.bin(accountNo); 31 | } 32 | 33 | /** 34 | * 添加基础卡片信息 35 | * @param cardInfo 36 | */ 37 | public static void addData(CardInfo cardInfo) { 38 | cardBin.add(cardInfo.getCardBin()); 39 | cardMap.put(cardInfo.getCardBin(), cardInfo); 40 | } 41 | 42 | /** 添加卡bin码 */ 43 | public static void addBin(String bin) { 44 | cardBin.add(bin); 45 | } 46 | 47 | @Data 48 | public static class CardInfo { 49 | private String cardBin;//620058 50 | private String bankId;//01020000 51 | private String bankName;//中国工商银行 52 | private String cardName;//银联标准卡 53 | private String cardDigits;//19 卡号长度 54 | private String cardType;//借记卡 55 | private String bankCode;//ICBC 56 | private String bankName2;//中国工商银行 57 | public String rowOut() { 58 | return StringUtil.join(Arrays.asList(cardBin,bankId,bankName,cardName,cardDigits,cardType,bankCode,bankName2), null, null, ","); 59 | } 60 | public CardInfo rowIn(String row) { 61 | //需要指定limit>=8,增加字段时需要注意limit值>=字段数 62 | String[] split = row.split("[,]", 18); 63 | int idx = 0; 64 | cardBin = split[idx++]; 65 | bankId = split[idx++]; 66 | bankName = split[idx++]; 67 | cardName = split[idx++]; 68 | cardDigits = NumberUtil.correctNumber(split[idx++]); 69 | cardType = split[idx++]; 70 | bankCode = split[idx++]; 71 | bankName2 = split[idx++]; 72 | return this; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/CardBin.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | /** 4 | * 卡bin搜索 5 | * @author xlongwei 6 | */ 7 | public class CardBin { 8 | 9 | /** 匹配bin码 */ 10 | public String bin(String bin) { 11 | if(bin != null && bin.length() > 0) { 12 | Node cn = root; 13 | for(char c : bin.toCharArray()) { 14 | if(cn.child == null) { 15 | break; 16 | }else { 17 | boolean found = false; 18 | Node n = cn.child; 19 | while(n != null) { 20 | if(n.c == c) { 21 | cn = n; 22 | found = true; 23 | break; 24 | } 25 | n = n.sibling; 26 | } 27 | if(found == false) { 28 | break; 29 | } 30 | } 31 | } 32 | return cn == null || (cn.child != null && !cn.leaf) ? null : cn.toString(); 33 | } 34 | return null; 35 | } 36 | 37 | /** 添加bin码对应数据 */ 38 | public void add(String bin) { 39 | char[] cs = bin.toCharArray(); 40 | Node cn = root; 41 | for(char c : cs) { 42 | if(cn.child != null) { 43 | boolean found = false; 44 | Node n = cn.child; 45 | while(n != null) { 46 | if(n.c == c) { 47 | cn = n; 48 | found = true; 49 | break; 50 | } 51 | n = n.sibling; 52 | } 53 | if(found == false) { 54 | n = cn.child; 55 | while(n.sibling != null) { 56 | n = n.sibling; 57 | } 58 | n.sibling = new Node(); 59 | n.sibling.c = c; 60 | n.sibling.parent = cn; 61 | cn = n.sibling; 62 | } 63 | }else { 64 | cn.child = new Node(); 65 | cn.child.c = c; 66 | cn.child.parent = cn; 67 | cn = cn.child; 68 | } 69 | } 70 | cn.leaf = true; 71 | } 72 | 73 | Node root = new Node(); 74 | static class Node { 75 | char c = 0; 76 | Node parent; 77 | Node child; 78 | Node sibling; 79 | boolean leaf = false; 80 | @Override 81 | public String toString() { 82 | StringBuilder sb = new StringBuilder(); 83 | Node cn = this; 84 | while(cn.parent != null) { 85 | sb.append(cn.c); 86 | cn = cn.parent; 87 | }; 88 | return sb.reverse().toString(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/ConfigUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.InputStream; 6 | import java.net.URL; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import com.fasterxml.jackson.core.type.TypeReference; 11 | import com.networknt.config.Config; 12 | import com.networknt.utility.StringUtils; 13 | 14 | import lombok.extern.slf4j.Slf4j; 15 | 16 | /** 17 | * light4j.yml 18 | * @author xlongwei 19 | * 20 | */ 21 | @Slf4j 22 | @SuppressWarnings("unchecked") 23 | public class ConfigUtil { 24 | 25 | public static final Map CONFIG = Config.getInstance().getJsonMapConfig("light4j"); 26 | 27 | static { 28 | //使用env或properties覆盖自定义配置 29 | Map replace = new HashMap<>(4); 30 | for(String key : CONFIG.keySet()) { 31 | Object value = CONFIG.get(key); 32 | if(value instanceof Map) { 33 | Map map = (Map)value; 34 | replace.clear(); 35 | for(String name : map.keySet()) { 36 | String keyName = key+"."+name; 37 | String keyValue = System.getenv(keyName); 38 | if(StringUtil.isBlank(keyValue)) { 39 | keyValue = System.getProperty(keyName); 40 | } 41 | if(StringUtil.isBlank(keyValue)==false) { 42 | replace.put(name, keyValue); 43 | log.info("config {} => {}", keyName, keyValue); 44 | } 45 | } 46 | map.putAll(replace); 47 | } 48 | } 49 | log.info("light4j config loaded"); 50 | Map light4j = config("light4j"); 51 | DIRECTORY = light4j.get("directory"); 52 | FRONT_URL = light4j.get("frontUrl"); 53 | } 54 | 55 | public static final String DIRECTORY, FRONT_URL; 56 | 57 | public static final TypeReference> STRING_MAP_INTEGER = new TypeReference>() {}; 58 | public static final TypeReference> STRING_MAP_OBJECT = new TypeReference>() {}; 59 | 60 | public static InputStream stream(String resource) { 61 | if(StringUtils.isBlank(resource)) { 62 | return null; 63 | }else { 64 | try { 65 | if(StringUtil.isUrl(DIRECTORY)) { 66 | return new URL(DIRECTORY+resource).openStream(); 67 | }else { 68 | File file = new File(DIRECTORY, resource); 69 | if(file.exists() && file.isFile()) { 70 | return new FileInputStream(file); 71 | }else { 72 | log.info("file not exist or is not file, resource: {}, exists: {}, isFile: {}", resource, file.exists(), file.isFile()); 73 | } 74 | } 75 | }catch(Exception e) { 76 | log.info("fail to get resource: {}, ex: {}", resource, e.getMessage()); 77 | } 78 | } 79 | return null; 80 | } 81 | 82 | public static Map config(String name) { 83 | return (Map)CONFIG.get(name); 84 | } 85 | 86 | public static Map stringMapInteger(String json) { 87 | try { 88 | return Config.getInstance().getMapper().readValue(json, STRING_MAP_INTEGER); 89 | }catch(Exception e) { 90 | return null; 91 | } 92 | } 93 | 94 | public static Map stringMapObject(String json) { 95 | try { 96 | return Config.getInstance().getMapper().readValue(json, STRING_MAP_OBJECT); 97 | }catch(Exception e) { 98 | return null; 99 | } 100 | } 101 | 102 | /** 判断用户是否客户 */ 103 | public static boolean isClient(String userName) { 104 | String clientNames = RedisConfig.get("liveqrcode.client.names"); 105 | boolean isClient = !StringUtil.isBlank(userName) && StringUtil.splitContains(clientNames, userName); 106 | log.info("userName: {}, isClient: {}, clientNames: {}", userName, isClient, clientNames); 107 | return isClient; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.Locale; 7 | import java.util.TimeZone; 8 | 9 | import org.apache.commons.lang3.time.FastDateFormat; 10 | 11 | import com.networknt.utility.StringUtils; 12 | import com.xlongwei.light4j.util.IdWorker.SystemClock; 13 | 14 | import lombok.extern.slf4j.Slf4j; 15 | 16 | /** 17 | * 常见日期类型处理:字符串、日期Date、长整数new Date(long),parse(time).getTime() 18 | * 19 | * @author xlongwei 20 | */ 21 | @Slf4j 22 | public class DateUtil { 23 | /** yyyy */ 24 | public static final FastDateFormat yearFormat = FastDateFormat.getInstance("yyyy"); 25 | /** yyyy年M月d日 */ 26 | public static final FastDateFormat dayFormat = FastDateFormat.getInstance("yyyy年M月d日"); 27 | /** yyyy-MM-dd */ 28 | public static final FastDateFormat dateFormat = FastDateFormat.getInstance("yyyy-MM-dd"); 29 | /** yyyy-MM-dd HH:mm:ss */ 30 | public static final FastDateFormat datetimeFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); 31 | public static final FastDateFormat httpHeader = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss zzz", 32 | TimeZone.getTimeZone("GMT"), Locale.US); 33 | private static final List fastDateFormats = new ArrayList<>(); 34 | 35 | static { 36 | String[] strings = { "yyyyMMdd", "yyyy-MM-dd", "yyyy.MM.dd", "yyyy/MM/dd", "yyyyMMddHHmmss", 37 | "yyyy-MM-dd HH:mm:ss", "yyyy年MM月dd日", "yy年MM月dd日" }; 38 | for (String string : strings) { 39 | addFormat(string); 40 | } 41 | } 42 | 43 | /** 44 | * 添加日期格式 45 | * @param format 46 | */ 47 | public static void addFormat(String format) { 48 | try { 49 | FastDateFormat fastDateFormat = FastDateFormat.getInstance(format); 50 | fastDateFormats.add(fastDateFormat); 51 | } catch (Exception e) { 52 | log.warn("fail to add format: {}, ex: {}", format, e.getMessage()); 53 | } 54 | } 55 | 56 | /** 57 | * @param datetime 58 | * 支持格式: 59 | *
  • yyyy-MM-dd, mysql: curdate()
  • 60 | *
  • yyyy-MM-dd HH:mm:ss, mysql: now()
  • 61 | *
  • 1406167122870,java: System.currentTimeInMillis()
  • 62 | *
  • 1406166160,mysql: unix_timestamp(now())
  • 63 | */ 64 | public static Date parse(String datetime) { 65 | if (StringUtils.isBlank(datetime)) { 66 | return null; 67 | } 68 | for (FastDateFormat df : fastDateFormats) { 69 | try { 70 | return df.parse(datetime); 71 | } catch (Exception e) { 72 | // ignore 73 | } 74 | } 75 | int length = datetime.length(); 76 | boolean isLongTime = (length == 10 || length == 13) && datetime.matches("\\d+"); 77 | if (isLongTime) { 78 | return new Date(length == 13 ? Long.parseLong(datetime) : Long.parseLong(datetime) * 1000); 79 | } 80 | int httpHeaderLength = 29; 81 | if (length == httpHeaderLength) { 82 | try { 83 | return httpHeader.parse(datetime); 84 | } catch (Exception e) { 85 | // ignore 86 | } 87 | } 88 | log.info("fail to parse time: {}", datetime); 89 | return null; 90 | } 91 | 92 | /** 93 | * 解析日期,或返回当前日期 94 | * @param datetime 95 | * @return 96 | */ 97 | public static Date parseNow(String datetime) { 98 | Date date = parse(datetime); 99 | if(date != null) { 100 | return date; 101 | }else { 102 | return SystemClock.date(); 103 | } 104 | } 105 | 106 | /** 107 | * 108 | * @param date 109 | * @param format yyyy-MM-dd HH:mm:ss 110 | */ 111 | public static String format(Date date, String format) { 112 | if (date == null || StringUtils.isBlank(format)) { 113 | return null; 114 | } 115 | return FastDateFormat.getInstance(format).format(date); 116 | } 117 | 118 | /** 119 | * @param date 120 | * @return yyyy-MM-dd HH:mm:ss 121 | */ 122 | public static String format(Date date) { 123 | return datetimeFormat.format(date); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/ExecUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import org.apache.commons.exec.CommandLine; 12 | import org.apache.commons.exec.DaemonExecutor; 13 | import org.apache.commons.exec.ExecuteStreamHandler; 14 | import org.apache.commons.exec.ExecuteWatchdog; 15 | import org.apache.commons.exec.Executor; 16 | import org.apache.commons.exec.OS; 17 | import org.apache.commons.exec.PumpStreamHandler; 18 | import org.apache.commons.io.FilenameUtils; 19 | 20 | import lombok.extern.slf4j.Slf4j; 21 | 22 | /** 23 | * 使用find+grep检索日志 24 | * @author xlongwei 25 | * 26 | */ 27 | @Slf4j 28 | public class ExecUtil { 29 | public static final boolean isWindows = OS.isFamilyWindows(); 30 | 31 | /** 32 | * 搜索dir目录下的日志文件,列出包含search文本的文件名 33 | * @param dir 34 | * @param search 35 | * @return 36 | */ 37 | public static List list(String dir, String search) { 38 | try{ 39 | String find = find(dir, search); 40 | String[] lines = find.split("[\r\n]+"); 41 | List files = new ArrayList<>(); 42 | for(String line : lines) { 43 | if(StringUtil.isBlank(line)) { 44 | continue; 45 | }else if(isWindows) { 46 | int e = line.indexOf(':'), s = e==-1 ? -1 : line.lastIndexOf(' ', e); 47 | if(s == -1) { 48 | continue; 49 | }else if(NumberUtil.parseInt(line.substring(e+1).trim(), 0) > 0) { 50 | files.add(line.substring(s, e).trim()); 51 | } 52 | }else { 53 | files.add(FilenameUtils.getName(line)); 54 | } 55 | } 56 | return files; 57 | }catch(Exception e) { 58 | log.info("fail to find dir:{}+search:{}, ex:{}", dir, search, e.getMessage()); 59 | } 60 | return Collections.emptyList(); 61 | } 62 | 63 | public static String find(String dir, String search) throws Exception { 64 | CommandLine command = null; 65 | if(isWindows) { 66 | //find /C "a" * 67 | command = CommandLine.parse("find"); 68 | command.addArgument("/C"); 69 | command.addArgument("\"${search}\"", false); 70 | command.addArgument("*"); 71 | }else { 72 | //find . -type f -exec zgrep -li '${search}' {} \; 73 | //find ! -name *.gz -exec grep -li '${search}' {} \; 74 | //1,命令行的分号需要转义\;或引号';'而CommandLine不需要;2,为提高效率可以自定义查找最近几天内的日志,这里查找未gz压缩的日志(通过gz规则控制数量) 75 | //command = CommandLine.parse("find . -type f -exec zgrep -li ''${search}'' {} ;"); 76 | command = CommandLine.parse("find ! -name *.gz -exec grep -li ''${search}'' {} ;"); 77 | } 78 | Map substitutionMap = new HashMap<>(4); 79 | substitutionMap.put("search", search); 80 | command.setSubstitutionMap(substitutionMap); 81 | 82 | Executor exe = new DaemonExecutor(); 83 | exe.setWorkingDirectory(new File(dir)); 84 | exe.setExitValues(new int[]{0,1,2}); 85 | 86 | ExecuteWatchdog watchDog = new ExecuteWatchdog(60000); 87 | exe.setWatchdog(watchDog); 88 | 89 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 90 | ExecuteStreamHandler streamHandler = new PumpStreamHandler(baos); 91 | exe.setStreamHandler(streamHandler); 92 | 93 | exe.execute(command); 94 | String out = baos.toString(isWindows ? "GBK" : "UTF-8"); 95 | log.debug(out); 96 | return out; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/HttpSessionNetworknt.java: -------------------------------------------------------------------------------- 1 | // package com.xlongwei.light4j.util; 2 | 3 | // import java.util.Collections; 4 | // import java.util.Enumeration; 5 | // import java.util.HashSet; 6 | 7 | // import com.networknt.session.Session; 8 | 9 | // /** 10 | // * 包装networknt的Session为apijson所需的HttpSession 11 | // * @author xlongwei 12 | // * 13 | // */ 14 | // public final class HttpSessionNetworknt extends HttpSessionWrapper { 15 | // private final Session session; 16 | // public HttpSessionNetworknt(Session session) { 17 | // this.session = session; 18 | // } 19 | // @Override 20 | // public long getCreationTime() { 21 | // return session.getCreationTime(); 22 | // } 23 | // @Override 24 | // public String getId() { 25 | // return session.getId(); 26 | // } 27 | // @Override 28 | // public long getLastAccessedTime() { 29 | // return session.getLastAccessedTime(); 30 | // } 31 | // @Override 32 | // public void setMaxInactiveInterval(int interval) { 33 | // session.setMaxInactiveInterval(interval); 34 | // } 35 | // @Override 36 | // public int getMaxInactiveInterval() { 37 | // return session.getMaxInactiveInterval(); 38 | // } 39 | // @Override 40 | // public Object getAttribute(String name) { 41 | // return session.getAttribute(name); 42 | // } 43 | // @Override 44 | // public Enumeration getAttributeNames() { 45 | // return Collections.enumeration(session.getAttributeNames()); 46 | // } 47 | // @Override 48 | // public void setAttribute(String name, Object value) { 49 | // session.setAttribute(name, value); 50 | // } 51 | // @Override 52 | // public void removeAttribute(String name) { 53 | // session.removeAttribute(name); 54 | // } 55 | // @Override 56 | // public void invalidate() { 57 | // new HashSet<>(session.getAttributeNames()).forEach(session::removeAttribute); 58 | // } 59 | // } -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/HttpSessionUndertow.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.util.Collections; 4 | import java.util.Enumeration; 5 | 6 | import io.undertow.server.HttpServerExchange; 7 | import io.undertow.server.session.Session; 8 | 9 | /** 10 | * 包装undertow的Session为apijson所需的HttpSession 11 | * @author xlongwei 12 | * 13 | */ 14 | public final class HttpSessionUndertow extends HttpSessionWrapper { 15 | private final Session session; 16 | private final HttpServerExchange exchange; 17 | public HttpSessionUndertow(Session session, HttpServerExchange exchange) { 18 | this.session = session; 19 | this.exchange = exchange; 20 | } 21 | @Override 22 | public long getCreationTime() { 23 | return session.getCreationTime(); 24 | } 25 | @Override 26 | public String getId() { 27 | return session.getId(); 28 | } 29 | @Override 30 | public long getLastAccessedTime() { 31 | return session.getLastAccessedTime(); 32 | } 33 | @Override 34 | public void setMaxInactiveInterval(int interval) { 35 | session.setMaxInactiveInterval(interval); 36 | } 37 | @Override 38 | public int getMaxInactiveInterval() { 39 | return session.getMaxInactiveInterval(); 40 | } 41 | @Override 42 | public Object getAttribute(String name) { 43 | return session.getAttribute(name); 44 | } 45 | @Override 46 | public Enumeration getAttributeNames() { 47 | return Collections.enumeration(session.getAttributeNames()); 48 | } 49 | @Override 50 | public void setAttribute(String name, Object value) { 51 | session.setAttribute(name, value); 52 | } 53 | @Override 54 | public void removeAttribute(String name) { 55 | session.removeAttribute(name); 56 | } 57 | @Override 58 | public void invalidate() { 59 | session.getAttributeNames().forEach(session::removeAttribute); 60 | session.invalidate(exchange); 61 | } 62 | } -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/HttpSessionWrapper.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import javax.servlet.http.HttpSession; 4 | 5 | /** 6 | * 包装具体的Session为apijson所需的HttpSession 7 | * @author xlongwei 8 | * 9 | */ 10 | public abstract class HttpSessionWrapper implements HttpSession { 11 | @Override public boolean isNew() { return true; } 12 | @Deprecated @Override public javax.servlet.http.HttpSessionContext getSessionContext() { return null; } 13 | @Deprecated @Override public javax.servlet.ServletContext getServletContext() { return null; } 14 | @Deprecated @Override public Object getValue(String name) { return null; } 15 | @Deprecated @Override public String[] getValueNames() { return null; } 16 | @Deprecated @Override public void putValue(String name, Object value) { } 17 | @Deprecated @Override public void removeValue(String name) { } 18 | } -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.Map; 5 | 6 | import org.apache.http.HttpEntity; 7 | import org.apache.http.HttpResponse; 8 | import org.apache.http.client.HttpClient; 9 | import org.apache.http.client.config.RequestConfig; 10 | import org.apache.http.client.methods.HttpUriRequest; 11 | import org.apache.http.client.methods.RequestBuilder; 12 | import org.apache.http.entity.ContentType; 13 | import org.apache.http.entity.mime.HttpMultipartMode; 14 | import org.apache.http.entity.mime.MultipartEntityBuilder; 15 | import org.apache.http.entity.mime.content.FileBody; 16 | import org.apache.http.impl.client.HttpClients; 17 | import org.apache.http.util.EntityUtils; 18 | 19 | import com.xlongwei.light4j.util.FileUtil.FileItem; 20 | 21 | import lombok.extern.slf4j.Slf4j; 22 | 23 | /** 24 | * http util over okhttp 25 | * @author xlongwei 26 | * 27 | */ 28 | @Slf4j 29 | public class HttpUtil { 30 | public static final HttpClient httpClient; 31 | public static final ContentType txtUtf8 = ContentType.create("text/plain", StandardCharsets.UTF_8); 32 | 33 | private static int connectionRequestTimeout = 10000; 34 | private static int connectionTimeout = 20000; 35 | private static int socketTimeout = 30000; 36 | private static int maxConnTotal = 384; 37 | private static int maxConnPerRoute = maxConnTotal; 38 | 39 | public static String get(String api, Map params) { 40 | log.info("get: {}", api); 41 | RequestBuilder requestBuilder = RequestBuilder.get(api); 42 | if(params!=null && params.isEmpty()==false) { 43 | params.forEach((k, v) -> { 44 | if(v!=null && v.length()>0) { 45 | requestBuilder.addParameter(k, v); 46 | } 47 | }); 48 | log.info("with params: {}", params.toString()); 49 | } 50 | return execute(requestBuilder.build()); 51 | } 52 | 53 | public static String post(String api, Map params, FileItem ... fileItems) { 54 | MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532); 55 | log.info("post: {}", api); 56 | if(params!=null && params.size()>0) { 57 | for(String param : params.keySet()) { 58 | String value = params.get(param); 59 | if(value!=null && (value=value.trim()).length()>0) { 60 | entityBuilder.addTextBody(param, value, txtUtf8); 61 | } else { 62 | log.info("empty param omitted: {}", param); 63 | } 64 | } 65 | log.info("with params: {}", params.toString()); 66 | } 67 | 68 | if(fileItems!=null && fileItems.length>0) { 69 | for(FileItem fileItem : fileItems) { 70 | if(fileItem.file.exists()==false || fileItem.file.isFile()==false) { 71 | log.info("upload file ommited, file not exists or not file"); 72 | }else { 73 | entityBuilder.addPart(fileItem.name, new FileBody(fileItem.file)); 74 | log.info("upload name: {}, file: {}", fileItem.name, fileItem.file.getAbsolutePath()); 75 | } 76 | } 77 | } 78 | 79 | HttpEntity entity = entityBuilder.build(); 80 | HttpUriRequest request = RequestBuilder.post() 81 | .setUri(api) 82 | .setEntity(entity) 83 | .build(); 84 | 85 | return execute(request); 86 | } 87 | 88 | private static String execute(HttpUriRequest request) { 89 | try { 90 | long s = System.currentTimeMillis(); 91 | HttpResponse response = httpClient.execute(request); 92 | int status = response.getStatusLine().getStatusCode(); 93 | String string = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); 94 | long e = System.currentTimeMillis(); 95 | log.info("status: {}, elapsed: {}ms", status, e-s); 96 | log.info("result: {}", string); 97 | return string; 98 | }catch(Exception e) { 99 | log.warn("failed with ex: {}", e.getMessage()); 100 | return null; 101 | } 102 | } 103 | 104 | static { 105 | RequestConfig requestConfig = RequestConfig.custom() 106 | .setConnectionRequestTimeout(connectionRequestTimeout) 107 | .setConnectTimeout(connectionTimeout) 108 | .setSocketTimeout(socketTimeout) 109 | .build(); 110 | httpClient = HttpClients.custom() 111 | .setDefaultRequestConfig(requestConfig) 112 | .setMaxConnTotal(maxConnTotal) 113 | .setMaxConnPerRoute(maxConnPerRoute) 114 | .setSSLContext(FileUtil.sslContext) 115 | .build(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/IdCardUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.io.InputStream; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | 11 | import com.alibaba.fastjson.JSONArray; 12 | import com.xlongwei.light4j.apijson.DemoApplication; 13 | import com.xlongwei.light4j.util.FileUtil.CharsetNames; 14 | import com.xlongwei.light4j.util.FileUtil.TextReader; 15 | import com.xlongwei.light4j.util.JsonUtil.JsonBuilder; 16 | 17 | import lombok.extern.slf4j.Slf4j; 18 | 19 | /** 20 | * idcard util 21 | * @author xlongwei 22 | * 23 | */ 24 | @Slf4j 25 | public class IdCardUtil { 26 | public static final Integer year = 2020; 27 | public static final Map areas = new HashMap<>(); 28 | 29 | static { 30 | if(!DemoApplication.apijsonEnabled){ 31 | try(InputStream inputStream = ConfigUtil.stream("idcard.txt")) { 32 | TextReader reader = new TextReader(); 33 | reader.open(inputStream, CharsetNames.UTF_8); 34 | String line = null; 35 | while ((line = reader.read()) != null) { 36 | if (StringUtil.isBlank(line) || line.startsWith("#")) { 37 | continue; 38 | } 39 | String[] split = StringUtils.split(line); 40 | if (split == null || split.length != 2) { 41 | continue; 42 | } 43 | areas.put(split[0], split[1]); 44 | } 45 | reader.close(); 46 | log.info("idcard areas initialized, total areas: {}", areas.size()); 47 | }catch(Exception e) { 48 | log.info("fail to init idcard.txt, ex: {}", e.getMessage()); 49 | } 50 | } 51 | } 52 | 53 | /** 解析六位行政区划码 */ 54 | public static List areas(String area) { 55 | List list = new ArrayList<>(3); 56 | if (StringUtil.isNumbers(area) && area.length()>1) { 57 | String area1 = area.substring(0, 2) + "0000"; 58 | String area2 = area.length()<4 ? null : area.substring(0, 4) + "00"; 59 | String area3 = area.length()<6 ? null : area.substring(0, 6); 60 | if(DemoApplication.apijsonEnabled){ 61 | JsonBuilder json = JsonUtil.builder(false); 62 | json = json.putJSON("Idcard[]").putJSON("Idcard").put("@column", "name").put("@order", "code").putArray("code{}").add(area1); 63 | if(area2 != null) json.add(area2); 64 | if(area3 != null) json.add(area3); 65 | String string = json.top().build().toJSONString(); 66 | string = DemoApplication.apijson.get(string, null); 67 | JSONArray array = JsonUtil.parseNew(string).getJSONArray("Idcard[]"); 68 | for(int i=0,s=array==null ? 0 : array.size();i")); 45 | if(isHtml) { 46 | message.setContent(content, "text/html;charset=utf-8"); 47 | }else { 48 | message.setText(content, CharsetNames.UTF_8); 49 | } 50 | log.info("mail content is html:{}", isHtml); 51 | message.setSentDate(new Date()); 52 | message.saveChanges(); 53 | Transport transport = session.getTransport("smtp"); 54 | transport.connect(from, password); 55 | transport.sendMessage(message, message.getAllRecipients()); 56 | transport.close(); 57 | log.info("mail send success"); 58 | return true; 59 | }catch(Exception e) { 60 | log.warn("fail to send mail, ex: {}", e.getMessage()); 61 | } 62 | return false; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/PathEndpointSource.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.networknt.handler.config.EndpointSource; 7 | import com.networknt.utility.Util; 8 | 9 | /** 10 | * 让路径支持所有http方法 11 | * @author xlongwei 12 | * 13 | */ 14 | public class PathEndpointSource implements EndpointSource { 15 | private String path; 16 | public PathEndpointSource(String path) { 17 | this.path = path; 18 | } 19 | 20 | @Override 21 | public Iterable listEndpoints() { 22 | List endpoints = new ArrayList<>(); 23 | for(String method : Util.METHODS) { 24 | Endpoint endpoint = new Endpoint(path, method); 25 | endpoints.add(endpoint); 26 | } 27 | return endpoints; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/PinyinUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.io.File; 4 | import java.util.Comparator; 5 | 6 | import org.apache.commons.lang3.reflect.FieldUtils; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | import net.sourceforge.pinyin4j.PinyinHelper2; 10 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; 11 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; 12 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; 13 | import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; 14 | 15 | /** 16 | * @author Hongwei 17 | */ 18 | @Slf4j 19 | public class PinyinUtil { 20 | /** 21 | * return pinyin of zhStr, eg: zhongguo for 中国 22 | */ 23 | public static String getPinyin(String zhStr) { 24 | if(StringUtil.isBlank(zhStr)) { 25 | return ""; 26 | } 27 | String[] pinyin = getPinyin(zhStr, 0, 1, 0); 28 | StringBuilder sb = new StringBuilder(); 29 | for(String str : pinyin) { 30 | sb.append(str); 31 | } 32 | return sb.toString(); 33 | } 34 | 35 | /** 36 | * return pinyin of zhCh, eg: zhong for 中 37 | */ 38 | public static String getPinyin(char zhCh) { 39 | String zhChStr = Character.toString(zhCh); 40 | if (StringUtil.isChinese(zhCh)) { 41 | try { 42 | return PinyinHelper2.toHanYuPinyinString(zhChStr, format)[0]; 43 | } catch (Exception e) { 44 | } 45 | } 46 | return zhChStr; 47 | } 48 | 49 | /** 50 | * 处理句子 51 | * @param caseType 0-lower 1-camel 2-upper 52 | * @param toneType 0-mark 1-no 2-number 53 | * @param vcharType 0-ü 1-v 2-u: (toneType=0时必须vcharType=0) 54 | */ 55 | public static String[] getPinyin(String sentence, int caseType, int toneType, int vcharType) { 56 | if(toneType!=1 && toneType!=2) vcharType=0; //avoid BadHanyuPinyinOutputFormatCombination 57 | try{ 58 | HanyuPinyinOutputFormat outputFormat = new HanyuPinyinOutputFormat(); 59 | outputFormat.setToneType(toneType==1?HanyuPinyinToneType.WITHOUT_TONE:(toneType==2?HanyuPinyinToneType.WITH_TONE_NUMBER:HanyuPinyinToneType.WITH_TONE_MARK)); 60 | outputFormat.setVCharType(vcharType==1?HanyuPinyinVCharType.WITH_V:(vcharType==2?HanyuPinyinVCharType.WITH_U_AND_COLON:HanyuPinyinVCharType.WITH_U_UNICODE)); 61 | String[] split = PinyinHelper2.toHanYuPinyinString(sentence, outputFormat); 62 | if(caseType==1 || caseType==2) { 63 | for(int i=0,len=split.length;i ZH_COMPARATOR = (o1, o2) -> { 81 | if (o1 == null) { 82 | if (o2 == null) { 83 | // 空 = 空 84 | return 0; 85 | } 86 | else { 87 | // 空 < 非空 88 | return -1; 89 | } 90 | } else { 91 | if (o2 == null) { 92 | // 非空 > 空 93 | return 1; 94 | } else { 95 | return getPinyin(o1).compareTo(getPinyin(o2)); 96 | } 97 | } 98 | }; 99 | 100 | /** 101 | * 获取实体某个中文字段的比较器 102 | */ 103 | public static Comparator zhStringFieldComparator(Class clazz, final String zhStringField){ 104 | return (o1, o2) -> { 105 | try{ 106 | String left = (String)FieldUtils.readField(o1, zhStringField, true); 107 | String right = (String)FieldUtils.readField(o2, zhStringField, true); 108 | return ZH_COMPARATOR.compare(left, right); 109 | }catch(Exception e) { 110 | log.warn("fail to zhCompare, ex={}, msg={}", e.getClass().getSimpleName(), e.getMessage()); 111 | } 112 | return 0; 113 | }; 114 | } 115 | 116 | /** 文件名是拼音时,按拼音顺序排序 */ 117 | public static class PinyinFileNameComparator implements Comparator { 118 | @Override 119 | public int compare(File o1, File o2) { 120 | String left = FileUtil.getFileName(o1); 121 | String right = FileUtil.getFileName(o1); 122 | return ZH_COMPARATOR.compare(left, right); 123 | } 124 | } 125 | 126 | public static HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); 127 | static { 128 | format.setCaseType(HanyuPinyinCaseType.LOWERCASE); 129 | format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 130 | format.setVCharType(HanyuPinyinVCharType.WITH_V); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/PlateUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.InputStream; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import cn.hutool.core.util.CharUtil; 9 | import cn.hutool.poi.excel.ExcelUtil; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /** 13 | * plate util 14 | * @author xlongwei 15 | * @date 2019-10-30 16 | */ 17 | @Slf4j 18 | public class PlateUtil { 19 | 20 | /** 搜索城市或车牌 */ 21 | public static String search(String str) { 22 | if(str==null || (str=str.trim().toUpperCase()).length()1 && row[1].startsWith(str2)) { 48 | return row[3]; 49 | } 50 | }else if(str.length()==2 && str.charAt(0)==row[3].charAt(0)) { 51 | //渝D ==》 重庆市 52 | guess = row[0]; 53 | } 54 | } 55 | return guess; 56 | } 57 | 58 | /** List[province,city,nick,plate] */ 59 | static List plates = new ArrayList<>(); 60 | static final int PLATE_PREFIX_LENGTH = 2; 61 | static final String YUN_A_V = "云A-?V[0-9A-Z]{0,4}"; 62 | static { 63 | try(InputStream in = new BufferedInputStream(ConfigUtil.stream("chepaihao.xlsx"))) { 64 | ExcelUtil.readBySax(in, 0, (int i, long j, List list) -> { 65 | if(j > 0) { 66 | plates.add(list.toArray(new String[list.size()])); 67 | } 68 | }); 69 | log.info("chepaihao loaded, record={}", plates.size()); 70 | }catch(Exception e) { 71 | log.warn("fail to init chepaihao: {}", e.getMessage()); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/PostUtil.java: -------------------------------------------------------------------------------- 1 | //package com.xlongwei.light4j.util; 2 | // 3 | //import com.alibaba.fastjson.JSON; 4 | //import com.alibaba.fastjson.JSONObject; 5 | //import com.xlongwei.light4j.util.FileUtil.CharsetNames; 6 | //import com.xlongwei.light4j.util.FileUtil.TextReader; 7 | //import com.xlongwei.light4j.util.RelationUtil.Relation1N; 8 | // 9 | //import lombok.extern.slf4j.Slf4j; 10 | // 11 | ///** 12 | // * 邮编区号 13 | // * @author xlongwei 14 | // */ 15 | //@Slf4j 16 | //public class PostUtil { 17 | // public static final Relation1N posts = new Relation1N<>(); 18 | // public static final Relation1N areas = new Relation1N<>(); 19 | // 20 | // public static class Info { 21 | // public static final String 区号 = "区号"; 22 | // public static final String 邮编 = "邮编"; 23 | // public static final String 城市 = "城市"; 24 | // } 25 | // 26 | // static { 27 | // String line = null; 28 | // TextReader reader = new TextReader(ConfigUtil.stream("posts.json"), CharsetNames.UTF_8); 29 | // while((line=reader.read())!=null) { 30 | // JSONObject info = JSON.parseObject(line); 31 | // String post = info.getString(Info.邮编); 32 | // String area = info.getString(Info.区号); 33 | // String city = info.getString(Info.城市); 34 | // posts.add(post, city); 35 | // areas.add(area, city); 36 | // } 37 | // reader.close(); 38 | // log.info("post init success"); 39 | // } 40 | //} 41 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/RedisPubsub.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | import java.util.concurrent.CopyOnWriteArrayList; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | import redis.clients.jedis.Jedis; 10 | import redis.clients.jedis.JedisPubSub; 11 | 12 | /** 13 | * redis pubsub 14 | * @author xlongwei 15 | */ 16 | @Slf4j 17 | public class RedisPubsub { 18 | public static final String CHANNEL = "pubsub"; 19 | private static final List listeners = new CopyOnWriteArrayList<>(); 20 | private static final Map pubsubs = new ConcurrentHashMap<>(); 21 | 22 | /** 发布消息到默认渠道 */ 23 | public static void pub(final String message) { 24 | pub(CHANNEL, message); 25 | } 26 | 27 | /** 发布消息到指定渠道 */ 28 | public static void pub(final String channel, final String message) { 29 | RedisConfig.execute((jedis) -> { 30 | jedis.publish(channel, message); 31 | return null; 32 | }); 33 | } 34 | 35 | /** 订阅默认渠道消息 */ 36 | public static void sub(MessageListener listener) { 37 | listeners.add(listener); 38 | } 39 | 40 | /** 订阅指定渠道消息 */ 41 | public static void sub(final String channel, final JedisPubSub pubsub) { 42 | if(StringUtil.isBlank(channel) || pubsub==null) { 43 | return; 44 | } 45 | TaskUtil.submitKeepRunning(() -> { 46 | Jedis jedis = null; 47 | try { 48 | jedis = RedisConfig.JEDIS_POOL.getResource(); 49 | jedis.subscribe(pubsub, channel); 50 | }finally { 51 | RedisConfig.JEDIS_POOL.returnBrokenResource(jedis); 52 | } 53 | }); 54 | pubsubs.put(channel, pubsub); 55 | } 56 | 57 | /** 58 | * 默认渠道消息监听器 59 | * @author xlongwei 60 | */ 61 | @FunctionalInterface 62 | public static interface MessageListener { 63 | /** 64 | * 接收消息通知 65 | * @param message 66 | */ 67 | void onMessage(String message); 68 | } 69 | 70 | /** 消息监听器适配 */ 71 | public static class JedisPubSubAdapter extends JedisPubSub { 72 | @Override 73 | public void onMessage(String channel, String message) {} 74 | @Override 75 | public void onPMessage(String pattern, String channel, String message) {} 76 | @Override 77 | public void onSubscribe(String channel, int subscribedChannels) {} 78 | @Override 79 | public void onUnsubscribe(String channel, int subscribedChannels) {} 80 | @Override 81 | public void onPUnsubscribe(String pattern, int subscribedChannels) {} 82 | @Override 83 | public void onPSubscribe(String pattern, int subscribedChannels) {} 84 | } 85 | 86 | static { 87 | //注册默认渠道监听器 88 | JedisPubSub pubsub = new JedisPubSubAdapter() { 89 | @Override 90 | public void onMessage(String channel, String message) { 91 | log.info("onMessage chanel: {}, message: {}", channel, message); 92 | for(MessageListener listener : listeners) { 93 | listener.onMessage(message); 94 | } 95 | } 96 | }; 97 | sub(CHANNEL, pubsub); 98 | TaskUtil.addShutdownHook((Runnable)() -> { 99 | log.info("redis pubsub shutdown"); 100 | for(Map.Entry entry : pubsubs.entrySet()) { 101 | entry.getValue().unsubscribe(entry.getKey()); 102 | } 103 | }); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/RedisUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.ObjectInputStream; 6 | import java.io.ObjectOutputStream; 7 | 8 | import org.apache.commons.codec.binary.StringUtils; 9 | 10 | import redis.clients.jedis.JedisPoolConfig; 11 | 12 | /** 13 | * redis公共部分 14 | * @author xlongwei 15 | * 16 | */ 17 | public class RedisUtil { 18 | 19 | static JedisPoolConfig poolConfig = new JedisPoolConfig(); 20 | 21 | static { 22 | poolConfig.setMinIdle(Integer.getInteger("redis.minIdle", 1)); 23 | //<=0时,不启动Timer-0线程,容易出现SocketException,因此RedisCache、RedisConfig默认重试一次 24 | poolConfig.setTimeBetweenEvictionRunsMillis(Integer.getInteger("redis.timeBetweenEvictionRunsMillis", 0)); 25 | } 26 | 27 | /** 获取字节key */ 28 | public static byte[] byteKey(String key) { 29 | return StringUtils.getBytesUtf8(key); 30 | } 31 | 32 | /** 默认使用冒号分隔 */ 33 | public static byte[] byteKey(String cache, String key) { 34 | return StringUtils.getBytesUtf8(cache+":"+key); 35 | } 36 | 37 | /** 获取String key */ 38 | public static String stringKey(byte[] byteKey) { 39 | return StringUtils.newStringUtf8(byteKey); 40 | } 41 | 42 | /** 默认使用jdk序列化对象 */ 43 | public static byte[] byteValue(String value) { 44 | if(value == null) { 45 | return new byte[0]; 46 | } 47 | try { 48 | ByteArrayOutputStream baos = new ByteArrayOutputStream(256); 49 | ObjectOutputStream oos = new ObjectOutputStream(baos); 50 | oos.writeObject(value); 51 | oos.flush(); 52 | return baos.toByteArray(); 53 | }catch(Exception e) { 54 | return null; 55 | } 56 | } 57 | 58 | /** 默认使用jdk序列化对象 */ 59 | public static String stringValue(byte[] byteValue) { 60 | try { 61 | ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(byteValue)); 62 | return ois.readObject().toString(); 63 | }catch(Exception e) { 64 | return null; 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/ThrowingFunction.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.util.Objects; 4 | import java.util.function.Function; 5 | 6 | /** 7 | * @see http://codingjunkie.net/functional-iterface-exceptions/ 8 | */ 9 | @FunctionalInterface 10 | public interface ThrowingFunction extends Function { 11 | 12 | @Override 13 | default R apply(T t) { 14 | try { 15 | return applyThrows(t); 16 | } catch (Exception e) { 17 | throw new RuntimeException(e); 18 | } 19 | } 20 | 21 | R applyThrows(T t) throws Exception; 22 | 23 | default ThrowingFunction andThen(ThrowingFunction after) { 24 | Objects.requireNonNull(after); 25 | try { 26 | return (T t) -> after.apply(apply(t)); 27 | } catch (Exception e) { 28 | throw new RuntimeException(e); 29 | } 30 | } 31 | 32 | default ThrowingFunction compose(ThrowingFunction before) { 33 | Objects.requireNonNull(before); 34 | try { 35 | return (V v) -> apply(before.apply(v)); 36 | } catch (Exception e) { 37 | throw new RuntimeException(e); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/xlongwei/light4j/util/UploadUtil.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j.util; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.Map; 8 | 9 | import org.apache.commons.codec.binary.StringUtils; 10 | 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | /** 14 | * 文件上传工具类 15 | * @author xlongwei 16 | * 17 | */ 18 | @Slf4j 19 | public class UploadUtil { 20 | public static final Map CONFIG = ConfigUtil.config("upload"); 21 | /** SAVE-文件系统保存目录 URL-互联网访问网址 */ 22 | public static final String SAVE = CONFIG.get("save"), URL = CONFIG.get("url"); 23 | /** SAVE-临时文件保存目录 URL-临时文件访问网址 */ 24 | public static final String SAVE_TEMP = SAVE + "temp/", URL_TEMP = URL + "temp/"; 25 | /** 文件上传操作码 */ 26 | public static final String DIRECT = "direct", TEMP = "temp", CONFIRM = "confirm", TRASH = "trash"; 27 | /** 文件上传响应码 */ 28 | public static final String DOMAIN ="domain", PATH = "path"; 29 | 30 | /** 31 | * 根据文件名获取可用保存路径 32 | * @param type image word pdf等 33 | * @param fileName 34 | * @return 35 | */ 36 | public static String path(String type, String fileName) { 37 | type = StringUtil.isBlank(type) ? "" : type.trim()+"/"; 38 | String name = FileUtil.getFileName(fileName), ext = FileUtil.getFileExt(fileName); 39 | if(StringUtil.isHasChinese(fileName)) { 40 | fileName = name + "." + IdWorker.getId() + (StringUtil.isBlank(ext) ? "" : "." + ext); 41 | } 42 | String dir = SAVE_TEMP, file = type+fileName; 43 | File target = new File(dir, file); 44 | while(target.exists()) { 45 | file = type + name + "." + IdWorker.getId() + (StringUtil.isBlank(ext) ? "" : "." + ext); 46 | target = new File(dir, file); 47 | } 48 | return file; 49 | } 50 | 51 | /** 尝试处理中文乱码 */ 52 | public static String string(String string) { 53 | return StringUtils.newStringIso8859_1(StringUtils.getBytesUtf8(string)); 54 | } 55 | 56 | /** 57 | * 保存文件 58 | * @param is 59 | * @param target 60 | * @return 61 | */ 62 | public static boolean save(InputStream is, File target) { 63 | if(target.getParentFile().exists()==false) { 64 | target.getParentFile().mkdirs(); 65 | } 66 | try { 67 | FileOutputStream out = new FileOutputStream(target, false); 68 | FileUtil.copyStream(is, out); 69 | out.close(); 70 | log.info("save file to target:{}", target); 71 | return true; 72 | } catch (IOException e) { 73 | log.warn("fail to save file to target:{}", target); 74 | } 75 | return false; 76 | } 77 | 78 | /** 79 | * 移动文件 80 | * @param path path/name.ext 81 | * @param type confirm:temp->uploads,trash:uploads->trash 82 | * @return 83 | */ 84 | public static boolean move(String path, String type) { 85 | if(StringUtil.isBlank(path)) { 86 | return false; 87 | } 88 | String from = null, to = null; 89 | if(CONFIRM.equals(type)) { 90 | from = SAVE_TEMP; 91 | to = SAVE; 92 | }else if(TRASH.equals(type)) { 93 | from = SAVE; 94 | to = SAVE + "/trash"; 95 | }else { 96 | return false; 97 | } 98 | File source = new File(from, path); 99 | if(!source.exists() || source.isFile()==false) { 100 | log.info("move "+path+" from: "+from+" to: " + to + ", source not exist or not file."); 101 | return false; 102 | } 103 | File target = new File(to, path), targetParent = target.getParentFile(); 104 | if(targetParent.exists()==false) { 105 | targetParent.mkdirs(); 106 | } 107 | boolean b = FileUtil.tryRenameTo(source, target, 3); 108 | log.info("move:{} file:{} from:{} to:{}", b, path,from, to); 109 | return b; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/java.sql.Driver: -------------------------------------------------------------------------------- 1 | net.sf.log4jdbc.DriverSpy -------------------------------------------------------------------------------- /src/main/resources/beetl/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | index 6 | 7 | 8 | IP:${ip} 9 |
    10 | Region:${region} 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/beetl/demo/index/mysql.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mysql 6 | 7 | 8 | allTable:
    9 |
      10 | <% 11 | for(table in allTable){ 12 | print("
    1. "); 13 | //print(tableLP.index); 14 | print(table); 15 | print("
    2. "); 16 | } 17 | %> 18 |
    19 | 20 | -------------------------------------------------------------------------------- /src/main/resources/beetl/demo/index/script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | script 7 | 11 | 14 | 15 | 17 | 18 | 19 | 20 |
    21 | 22 | 24 |
    25 | 26 | -------------------------------------------------------------------------------- /src/main/resources/beetl/sql/user.md: -------------------------------------------------------------------------------- 1 | sample 2 | === 3 | * 注释 4 | 5 | select #{use("cols")} from user where #{use("condition")} 6 | 7 | cols 8 | === 9 | id,name,age,createDate 10 | 11 | updateSample 12 | === 13 | 14 | id=#{id},name=#{name},age=#{age},createDate=#{createDate} 15 | 16 | condition 17 | === 18 | 19 | 1 = 1 20 | -- @if(!isEmpty(id)){ 21 | and id=#{id} 22 | -- @} 23 | -- @if(!isEmpty(name)){ 24 | and name=#{name} 25 | -- @} 26 | -- @if(!isEmpty(age)){ 27 | and age=#{age} 28 | -- @} 29 | -- @if(!isEmpty(createDate)){ 30 | and createDate=#{createDate} 31 | -- @} 32 | -------------------------------------------------------------------------------- /src/main/resources/btsql-ext.properties: -------------------------------------------------------------------------------- 1 | PRODUCT_MODE=true 2 | CHARSET=UTF-8 3 | OFFSET_START_ZERO=false 4 | -------------------------------------------------------------------------------- /src/main/resources/config/client.truststore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xlongwei/light4j/16d0030e8aae1ed9f7b7687c3a05f43cbb88a5a6/src/main/resources/config/client.truststore -------------------------------------------------------------------------------- /src/main/resources/config/config.yml: -------------------------------------------------------------------------------- 1 | exclusionConfigFileList: 2 | - openapi 3 | - swagger 4 | - values 5 | - status 6 | 7 | decryptorClass: 8 | com.networknt.config.AesCrypto 9 | # com.networknt.decrypt.AESDecryptor 10 | # com.networknt.decrypt.ManualAESDecryptor 11 | # com.networknt.decrypt.AutoAESDecryptor -------------------------------------------------------------------------------- /src/main/resources/config/consul.yml: -------------------------------------------------------------------------------- 1 | # Consul URL for accessing APIs 2 | consulUrl: ${consul.consulUrl:http://localhost:8500} 3 | # number of requests before reset the shared connection. 4 | maxReqPerConn: 1000000 5 | # deregister the service after the amount of time after health check failed. 6 | deregisterAfter: 2m 7 | # health check interval for TCP or HTTP check. Or it will be the TTL for TTL check. Every 10 seconds, 8 | # TCP or HTTP check request will be sent. Or if there is no heart beat request from service after 10 seconds, 9 | # then mark the service is critical. 10 | checkInterval: 10s 11 | # One of the following health check approach will be selected. Two passive (TCP and HTTP) and one active (TTL) 12 | # enable health check TCP. Ping the IP/port to ensure that the service is up. This should be used for most of 13 | # the services with simple dependencies. If the port is open on the address, it indicates that the service is up. 14 | tcpCheck: false 15 | # enable health check HTTP. A http get request will be sent to the service to ensure that 200 response status is 16 | # coming back. This is suitable for service that depending on database or other infrastructure services. You should 17 | # implement a customized health check handler that checks dependencies. i.e. if db is down, return status 400. 18 | httpCheck: false 19 | # enable health check TTL. When this is enabled, Consul won't actively check your service to ensure it is healthy, 20 | # but your service will call check endpoint with heart beat to indicate it is alive. This requires that the service 21 | # is built on top of light-4j and the above options are not available. For example, your service is behind NAT. 22 | ttlCheck: true 23 | # endpoints that support blocking will also honor a wait parameter specifying a maximum duration for the blocking request. 24 | # This is limited to 10 minutes.This value can be specified in the form of "10s" or "5m" (i.e., 10 seconds or 5 minutes, 25 | # respectively). 26 | wait: 600s 27 | # enable HTTP/2 28 | # must disable when using HTTP with Consul (mostly using local Consul agent), Consul only supports HTTP/1.1 when not using TLS 29 | # optional to enable when using HTTPS with Consul, it will have better performance 30 | enableHttp2: false 31 | -------------------------------------------------------------------------------- /src/main/resources/config/correlation.yml: -------------------------------------------------------------------------------- 1 | enabled: true 2 | # false使用请求头X-Traceability-Id,true重新生成X-Correlation-Id 3 | autogenCorrelationID: false 4 | -------------------------------------------------------------------------------- /src/main/resources/config/handler.yml: -------------------------------------------------------------------------------- 1 | enabled: true 2 | 3 | handlers: 4 | - com.xlongwei.light4j.handler.ServiceHandler@service 5 | - com.xlongwei.light4j.handler.UploadHandler@upload 6 | - com.xlongwei.light4j.handler.WeixinHandler@weixin 7 | - com.xlongwei.light4j.handler.DemoHandler@demo 8 | - com.xlongwei.light4j.provider.WebSocketHandlerProvider@websocket 9 | # openapi 10 | - com.networknt.exception.ExceptionHandler@exception 11 | - com.networknt.cors.CorsHttpHandler@cors 12 | - com.networknt.traceability.TraceabilityHandler@traceability 13 | # - com.networknt.correlation.CorrelationHandler@correlation 14 | - com.xlongwei.light4j.openapi.extend.MyCorrelationHandler@correlation 15 | - com.networknt.openapi.JwtVerifyHandler@security 16 | # - com.xlongwei.light4j.openapi.extend.MyJwtShiroHandler@shiro 17 | - com.networknt.specification.SpecDisplayHandler@spec 18 | - com.networknt.specification.SpecSwaggerUIHandler@swaggerui 19 | - com.xlongwei.light4j.openapi.OpenapiHandler@openapi 20 | - com.networknt.security.JwtMockHandler@jwtmock 21 | 22 | chains: 23 | service: 24 | - exception 25 | - cors 26 | - traceability 27 | - correlation 28 | - service 29 | weixin: 30 | - exception 31 | - cors 32 | - weixin 33 | openapi: 34 | - exception 35 | - cors 36 | - traceability 37 | - correlation 38 | - security 39 | # - shiro 40 | - openapi 41 | demo: 42 | - exception 43 | - cors 44 | - demo 45 | upload: 46 | - exception 47 | - cors 48 | - upload 49 | 50 | paths: 51 | - source: com.xlongwei.light4j.handler.ServiceHandler$ServiceEndpointSource 52 | exec: 53 | - service 54 | - path: '/upload/*' 55 | method: 'POST' 56 | exec: 57 | - upload 58 | - path: '/callback/weixin.xml' 59 | method: 'GET' 60 | exec: 61 | - weixin 62 | - path: '/callback/weixin.xml' 63 | method: 'POST' 64 | exec: 65 | - weixin 66 | - path: '/ws/*' 67 | method: 'GET' 68 | exec: 69 | - websocket 70 | # openapi 71 | - path: '/openapi/spec.yaml' 72 | method: 'get' 73 | exec: 74 | - spec 75 | - path: '/openapi/swagger' 76 | method: 'get' 77 | exec: 78 | - swaggerui 79 | - path: '/openapi/token' 80 | method: 'POST' 81 | exec: 82 | - jwtmock 83 | - source: com.xlongwei.light4j.openapi.OpenapiHandler$OpenapiEndpointSource 84 | exec: 85 | - openapi 86 | # demo 87 | - source: com.xlongwei.light4j.handler.DemoHandler$DemoEndpointSource 88 | exec: 89 | - demo 90 | -------------------------------------------------------------------------------- /src/main/resources/config/jwt.yml: -------------------------------------------------------------------------------- 1 | # This is the default JWT configuration and need to be updated when used to issue JWT tokens. It is a component that used to 2 | # issue JWT token. Normally, it should be used by light-oauth2 only but can be used to issue tokens distributely. 3 | --- 4 | # Signature private key that used to sign JWT tokens. 5 | key: 6 | kid: '100' # kid that used to sign the JWT tokens. It will be shown up in the token header. 7 | filename: "server.keystore" # private key that is used to sign JWT tokens. 8 | keyName: server # key name that is used to identify the right key in keystore. 9 | issuer: urn:com:networknt:oauth2:v1 # default issuer of the JWT token 10 | audience: urn:com.networknt # default audience of the JWT token 11 | expiredInMinutes: 30 # expired in 10 minutes by default for issued JWT tokens 12 | version: '1.0' # JWT token version 13 | -------------------------------------------------------------------------------- /src/main/resources/config/light4j.yml: -------------------------------------------------------------------------------- 1 | light4j: 2 | # http://t.xlongwei.com/softwares/library/ 3 | directory: /soft/softwares/library/ 4 | frontUrl: http://cms.xlongwei.com 5 | 6 | redis: 7 | # host:port:db:password:timeout 8 | configDb: 127.0.0.1:6379:1 9 | # host:port:dbs:password:timeout:weight 10 | cacheDbs: 127.0.0.1:6379:3-7 11 | 12 | soffice: 13 | hosts: 127.0.0.1:8100-8102:false 14 | 15 | upload: 16 | save: /soft/uploads/ 17 | url: http://s.xlongwei.com/uploads/ -------------------------------------------------------------------------------- /src/main/resources/config/secret.yml: -------------------------------------------------------------------------------- 1 | # This file contains all the secrets for the server and client in order to manage and 2 | # secure all of them in the same place. In Kubernetes, this file will be mapped to 3 | # Secrets and all other config files will be mapped to mapConfig 4 | 5 | --- 6 | 7 | # Sever section 8 | 9 | # Key store password, the path of keystore is defined in server.yml 10 | serverKeystorePass: CRYPT:08eXg9TmK604+w06RaBlsPQbplU1F1Ez5pkBO/hNr8w= 11 | 12 | # Key password, the key is in keystore 13 | serverKeyPass: password 14 | 15 | # Trust store password, the path of truststore is defined in server.yml 16 | serverTruststorePass: password 17 | 18 | 19 | # Client section 20 | 21 | # Key store password, the path of keystore is defined in server.yml 22 | clientKeystorePass: password 23 | 24 | # Key password, the key is in keystore 25 | clientKeyPass: password 26 | 27 | # Trust store password, the path of truststore is defined in server.yml 28 | clientTruststorePass: password 29 | 30 | # Authorization code client secret for OAuth2 server 31 | authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA 32 | 33 | # Client credentials client secret for OAuth2 server 34 | clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA 35 | 36 | # Key distribution client secret for OAuth2 server 37 | keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA 38 | 39 | 40 | # Consul service registry and discovery 41 | 42 | # Consul Token for service registry and discovery 43 | # consulToken: the_one_ring 44 | 45 | # EmailSender password 46 | emailPassword: change-to-real-password 47 | 48 | # jwt private key password, used by light-oauth2 token and code services. 49 | jwtPrivateKeyPassword: password 50 | -------------------------------------------------------------------------------- /src/main/resources/config/security.yml: -------------------------------------------------------------------------------- 1 | # Security configuration for security module in light-4j. For each individual framework, 2 | # it has a framework specific security config file to control if security and scopes 3 | # verification are enabled or not. 4 | 5 | # This configuration file is only for JwtHelper class most of the cases. However, if there 6 | # is no framework specific security configuration available. The fallback security config 7 | # is read from this file. Hence we leave the enableVerifyJwt and enableVerifyScope to true. 8 | --- 9 | # Enable JWT verification flag. 10 | enableVerifyJwt: true 11 | 12 | # Enable JWT scope verification. Only valid when enableVerifyJwt is true. 13 | enableVerifyScope: false 14 | enableExtractScopeToken: false 15 | 16 | # User for test only. should be always be false on official environment. 17 | enableMockJwt: false 18 | 19 | # JWT signature public certificates. kid and certificate path mappings. 20 | jwt: 21 | certificate: 22 | '100': server.crt 23 | clockSkewInSeconds: 60 24 | 25 | # Enable or disable JWT token logging for audit. This is to log the entire token 26 | # or choose the next option that only logs client_id, user_id and scope. 27 | logJwtToken: true 28 | 29 | # Enable or disable client_id, user_id and scope logging if you don't want to log 30 | # the entire token. Choose this option or the option above. 31 | logClientUserScope: false 32 | 33 | # Enable JWT token cache to speed up verification. This will only verify expired time 34 | # and skip the signature verification as it takes more CPU power and long time. 35 | enableJwtCache: true 36 | 37 | # If you are using light-oauth2, then you don't need to have oauth subfolder for public 38 | # key certificate to verify JWT token, the key will be retrieved from key endpoint once 39 | # the first token is arrived. Default to false for dev environment without oauth2 server 40 | # or official environment that use other OAuth 2.0 providers. 41 | bootstrapFromKeyService: false 42 | -------------------------------------------------------------------------------- /src/main/resources/config/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDMjCCAhqgAwIBAgIEUPqtaDANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJH 3 | QjEOMAwGA1UECBMFU3RhdGUxDTALBgNVBAcTBENpdHkxDDAKBgNVBAoTA09yZzEL 4 | MAkGA1UECxMCT1UxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMzAxMTkxNDI3NTJa 5 | Fw0yMzAxMTcxNDI3NTJaMFsxCzAJBgNVBAYTAkdCMQ4wDAYDVQQIEwVTdGF0ZTEN 6 | MAsGA1UEBxMEQ2l0eTEMMAoGA1UEChMDT3JnMQswCQYDVQQLEwJPVTESMBAGA1UE 7 | AxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumYc 8 | FtCUib7X6HEuLwa9iNhbARofhSis73aoBe2IngR62/NKQ1oFsWRGR2liRH0XeXAO 9 | QwqqRnG7VBy8C+AMsT3Smk7Tfwk7/ReUfjrhc1kjcUf4SBJ2/JRFUA5DB5nW8htx 10 | lo/qAdq3Iv6RUBnYlR4lSGR8sH1zLUZ+GQVj3k6nU3+Ezsdr3+PHPBiEqtnvjpee 11 | /Idt76ZIoZkC2eg/ecxci9X086fl0ySdFrvoJD5XoZc2aS+fDxebBSQElWcpIn5S 12 | 7oGOtBd/ce8Yxj42gCIkkOp+IPua5Vy9pRW4Bwd9hGvb5aBW1UprxqyZ1VRgKXr8 13 | vOaLozQebE2Deq61NQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBjO2dTMzvq++zk 14 | Ee8AS5LXbahPbrUvGlSKGs+cU0o78ieJTBlt+8zTO8Gfh2gdcj1sLLEXAOSrVuqZ 15 | nB5hurlxVz9Nq9On3eEhzZMKiTOBJHm1XG05mb4WOwDK0u1rjcf/ctMmSXkaDSlH 16 | D1OX1NMXo1t9KifW8xdNSCPSbwgP4Ff3GMnOoiAjarcynd3X1CgeybwQQR39nIvK 17 | boEFB+kLwMbfbJ9Y76wtaJLHk5XYDRySFI8TE0ptt8NVHQNX3lDNdMwa3/OXTlMF 18 | 7lRZvzjib/yRc4EkjtChz0Ai0Ydv6gAWLrRg40ScLDFo2FXGRANXiPBBkvZeohdA 19 | oFalnAXq 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /src/main/resources/config/server.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xlongwei/light4j/16d0030e8aae1ed9f7b7687c3a05f43cbb88a5a6/src/main/resources/config/server.keystore -------------------------------------------------------------------------------- /src/main/resources/config/server.yml: -------------------------------------------------------------------------------- 1 | ip: 0.0.0.0 2 | httpPort: ${httpPort:8080} 3 | enableHttp: ${enableHttp:true} 4 | enableHttp2: true 5 | httpsPort: ${httpsPort:8443} 6 | enableHttps: ${enableHttps:false} 7 | keystoreName: server.keystore 8 | serviceId: light4j 9 | enableRegistry: ${enableRegistry:false} 10 | dynamicPort: ${dynamicPort:false} 11 | minPort: ${minPort:12400} 12 | maxPort: ${maxPort:12500} 13 | ioThreads: ${ioThreads:2} 14 | workerThreads: ${workerThreads:3} 15 | alwaysSetDate: false 16 | -------------------------------------------------------------------------------- /src/main/resources/config/service.yml: -------------------------------------------------------------------------------- 1 | # Singleton service factory configuration/IoC injection 2 | singletons: 3 | # - com.networknt.server.StartupHookProvider: 4 | # If you are using mask module to remove sensitive info before logging, uncomment the following line. 5 | # - com.networknt.server.JsonPathStartupHookProvider 6 | # - com.networknt.server.ShutdownHookProvider: 7 | # - com.networknt.server.Test1ShutdownHook 8 | - javax.sql.DataSource: 9 | - com.zaxxer.hikari.HikariDataSource: 10 | # java.sql.DriverManager auto detect META-INF/services/java.sql.Driver, call Driver.acceptsURL, we add net.sf.log4jdbc.DriverSpy to it, so driverClassName is optional 11 | # driverClassName: com.mysql.jdbc.Driver 12 | # jdbcUrl: jdbc:mysql://localhost:3306/apijson?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 13 | driverClassName: net.sf.log4jdbc.DriverSpy 14 | jdbcUrl: jdbc:log4jdbc:mysql://${db.hostPort:localhost:3306}/${db.database:apijson}?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 15 | username: ${db.username:apijson} 16 | password: ${db.password:apijson} 17 | minimumIdle: 1 18 | maximumPoolSize: ${db.maximumPoolSize:1} 19 | autoCommit: true 20 | useServerPrepStmts: true 21 | cachePrepStmts: true 22 | cacheCallableStmts: true 23 | cacheResultSetMetadata: true 24 | prepStmtCacheSize: 10 25 | prepStmtCacheSqlLimit: 2048 26 | # comment out the following line to use ping 27 | # connectionTestQuery: SELECT 1 28 | connectionTimeout: 3000 29 | 30 | # redis-manager or memory session 31 | # - io.undertow.server.session.SessionConfig: 32 | # - io.undertow.server.session.SessionCookieConfig 33 | #- io.undertow.server.session.SessionManager: 34 | # - io.undertow.server.session.InMemorySessionManager: 35 | # - java.lang.String: INMEMORY-SESSION 36 | # - com.networknt.session.SessionRepository: 37 | # - com.networknt.session.redis.RedisSessionRepository 38 | # - com.xlongwei.light4j.openapi.extend.MyRedisSessionRepository 39 | # - com.networknt.session.SessionManager: 40 | # - com.networknt.session.redis.RedisSessionManager 41 | 42 | - com.networknt.registry.URL: 43 | - com.networknt.registry.URLImpl: 44 | # protocol: light 45 | # host: localhost 46 | # port: 8080 47 | # path: consul 48 | parameters: 49 | # registryRetryPeriod: '30000' 50 | light4j: http://localhost:8080 51 | - com.networknt.consul.client.ConsulClient: 52 | - com.networknt.consul.client.ConsulClientImpl 53 | - com.networknt.registry.Registry: 54 | # - com.networknt.consul.ConsulRegistry 55 | - com.networknt.registry.support.DirectRegistry 56 | - com.networknt.balance.LoadBalance: 57 | - com.networknt.balance.RoundRobinLoadBalance 58 | - com.networknt.cluster.Cluster: 59 | - com.networknt.cluster.LightCluster 60 | -------------------------------------------------------------------------------- /src/main/resources/config/startup.yml: -------------------------------------------------------------------------------- 1 | configLoaderClass: com.networknt.server.UrlConfigLoader 2 | projectName: light4j 3 | projectVersion: v1 4 | serviceName: light4j 5 | serviceVersion: v1 6 | -------------------------------------------------------------------------------- /src/main/resources/config/values.yml: -------------------------------------------------------------------------------- 1 | dummy: dummyEntry -------------------------------------------------------------------------------- /src/main/resources/log4jdbc.properties: -------------------------------------------------------------------------------- 1 | log4jdbc.sqltiming.warn.threshold = 500 2 | log4jdbc.sqltiming.error.threshold = 1000 3 | log4jdbc.dump.sql.maxlinelength = 256 4 | log4jdbc.dump.sql.addsemicolon = true 5 | log4jdbc.trim.sql.extrablanklines = false -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ${contextName:-light4j} 4 | 5 | 6 | 7 | 8 | 9 | ${logPattern} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ${redis.key:-logserver} 20 | ${redis.pubsub:-true} 21 | ${redis.pushpop:-false} 22 | ${redis.queueSize:-10240} 23 | ${redis.host:-localhost} 24 | ${redis.port:-6379} 25 | 26 | 27 | 28 | ${includeCallerData:-true} 29 | 30 | 31 | 32 | 33 | logserver 34 | 6000 35 | 10240 36 | 10000 37 | false 38 | 39 | 40 | 41 | ${includeCallerData:-true} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ${logfile} 56 | 57 | ${logfile}.%d{yyyy-MM-dd} 58 | 59 | 60 | ${logPattern} 61 | 62 | 63 | 64 | 65 | ${includeCallerData:-true} 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/main/resources/logserver.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ${contextName:-light4j} 4 | 5 | 6 | 7 | logserver 8 | 6000 9 | 1024 10 | 10000 11 | false 12 | 13 | 14 | 15 | ${includeCallerData:-true} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | # copy this file to library/shiro.ini 2 | 3 | [users] 4 | # user=pwd,role1,role2 5 | admin=123456,admin 6 | steve=1000:5b2d372c2032382c202d3131372c202d31392c202d38352c203131392c2036352c202d3131342c2034382c202d362c202d3132332c202d35312c202d32392c2033362c202d38322c202d39355d:4882a2b9f8b95c628e110e992e3ccfe53b4730855788f7de65aa41589dd25515b78530f02532acf1d94d8b11830e4fedc3bafe76effed30b8185e4010bffceb5,service 7 | 8 | [roles] 9 | # role=perm1,perm2 10 | admin=*:*:* 11 | 12 | [urls] 13 | # url=roles[role1,role2],perms[perm1,perm2] 14 | # /openapi/upload*/**=roles["admin,user",admin],perms[openapi:upload:*,"service:upload:upload,delete"] 15 | /openapi/service*/**=roles[service] 16 | -------------------------------------------------------------------------------- /src/main/resources/singleNodeConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleServerConfig": { 3 | "idleConnectionTimeout": 10000, 4 | "pingTimeout": 1000, 5 | "connectTimeout": 10000, 6 | "timeout": 3000, 7 | "retryAttempts": 3, 8 | "retryInterval": 1500, 9 | "reconnectionTimeout": 3000, 10 | "failedAttempts": 3, 11 | "password": null, 12 | "subscriptionsPerConnection": 5, 13 | "clientName": null, 14 | "address": "redis://127.0.0.1:6379", 15 | "subscriptionConnectionMinimumIdleSize": 1, 16 | "subscriptionConnectionPoolSize": 3, 17 | "connectionMinimumIdleSize": 1, 18 | "connectionPoolSize": 3, 19 | "database": 0, 20 | "dnsMonitoring": false, 21 | "dnsMonitoringInterval": 5000 22 | }, 23 | "threads": 1, 24 | "nettyThreads": 1, 25 | "codec": null, 26 | "useLinuxNativeEpoll": false 27 | } -------------------------------------------------------------------------------- /src/test/java/com/xlongwei/light4j/AesCryptoTest.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.Map; 6 | 7 | import com.networknt.config.AesCrypto; 8 | import com.networknt.config.Config; 9 | import com.xlongwei.light4j.util.DesUtil; 10 | 11 | import org.junit.Test; 12 | 13 | public class AesCryptoTest { 14 | @Test 15 | public void test() throws Exception { 16 | AesCrypto aes = new AesCrypto(); 17 | String e = aes.encrypt("password"); 18 | System.out.println(e); 19 | String d = aes.decrypt(e); 20 | System.out.println(d); 21 | } 22 | 23 | @Test 24 | public void testConfig() throws Exception { 25 | Map map = Config.getInstance().getJsonMapConfig("secret"); 26 | assertEquals("password", map.get("serverKeystorePass")); 27 | } 28 | 29 | @Test 30 | public void pwcheck() throws Exception { 31 | assertEquals(0, DesUtil.pwcheck(null).get("score")); 32 | assertEquals(98, DesUtil.pwcheck("OOTNia!x5#gn").get("score")); 33 | assertEquals(4, DesUtil.pwcheck("123456").get("score")); 34 | assertEquals(7, DesUtil.pwcheck("admin").get("score")); 35 | assertEquals(8, DesUtil.pwcheck("qwerty").get("score")); 36 | assertEquals(80, DesUtil.pwcheck("Aa123456").get("score")); 37 | 38 | DesUtil.pwcheck("qweasd").entrySet().forEach(System.out::println); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/com/xlongwei/light4j/QnObjectTest.java: -------------------------------------------------------------------------------- 1 | package com.xlongwei.light4j; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import com.xlongwei.light4j.util.QnObject; 7 | import com.xlongwei.light4j.util.QnObject.QnException; 8 | 9 | /** 10 | * QnObject测试类 11 | * @author xlongwei 12 | * 13 | */ 14 | public class QnObjectTest { 15 | 16 | @Test public void test1() { 17 | QnObject qnObj = QnObject.fromQn("您好:{姓名}(性别=男)[先生](性别=女)[女士]"); 18 | System.out.println(qnObj.toString()); 19 | System.out.println(qnObj.toJs()); 20 | } 21 | 22 | @Test public void test2() { 23 | QnObject qnObj = QnObject.fromQn("您好:{姓名}(性别=男)[(年龄>=60)[老]先生]"); 24 | System.out.println(qnObj.toString()); 25 | System.out.println(qnObj.toJs()); 26 | } 27 | 28 | @Test public void test3() { 29 | QnObject qnObj = QnObject.fromQn("您好:{姓名}(性别=男 and 年龄>=60)[老先生]"); 30 | System.out.println(qnObj.toString()); 31 | System.out.println(qnObj.toJs()); 32 | } 33 | 34 | @Test public void test4() { 35 | QnObject qnObj = QnObject.fromQn("您好:{姓名}(({性别}=男 and {年龄}>=60) or {机构}!=北京)[老先生]"); 36 | System.out.println(qnObj.toString()); 37 | System.out.println(qnObj.toJs()); 38 | } 39 | 40 | @Test public void testLoop() { 41 | QnObject qnObj = null; 42 | qnObj = QnObject.fromQn("{姓名}的老婆有:<老婆>[{昵称}、-]"); 43 | System.out.println(qnObj.toString()); 44 | System.out.println(qnObj.toJs()); 45 | qnObj = QnObject.fromQn("您好:({列表}<>EMPTY)[<列表>[{姓名}、-]]"); 46 | System.out.println(qnObj.toString()); 47 | System.out.println(qnObj.toJs()); 48 | qnObj = QnObject.fromQn("您好:<>[<列表>[{姓名},]]"); 49 | System.out.println(qnObj.toString()); 50 | System.out.println(qnObj.toJs()); 51 | } 52 | 53 | @Test public void testCond() { 54 | String qc = "{姓名}=张三"; 55 | System.out.println(QnObject.fromQc(qc).toJs()); 56 | } 57 | 58 | @Test public void testFails() { 59 | String qn = null; 60 | try { 61 | qn = "您好:{姓名(性别=男 and 年龄>=60)[老先生]"; 62 | QnObject.fromQn(qn); 63 | Assert.fail(); 64 | }catch(QnException e) { 65 | System.out.println(qn); 66 | System.out.println(qn.substring(0, e.getPos())+" => "+e.getMessage()); 67 | Assert.assertEquals(QnException.MISS_VAR_END, e.getMessage()); 68 | } 69 | try { 70 | qn = "您好:{姓名}(性别=男 and 年龄>=60)老先生]"; 71 | QnObject.fromQn(qn); 72 | Assert.fail(); 73 | }catch(QnException e) { 74 | System.out.println(qn); 75 | System.out.println(qn.substring(0, e.getPos())+" => "+e.getMessage()); 76 | Assert.assertEquals(QnException.MISS_CONDITION_INNER, e.getMessage()); 77 | } 78 | try { 79 | qn = "您好:{}(性别=男 and 年龄>=60)[老先生]"; 80 | QnObject.fromQn(qn); 81 | Assert.fail(); 82 | }catch(QnException e) { 83 | System.out.println(qn); 84 | System.out.println(qn.substring(0, e.getPos())+" => "+e.getMessage()); 85 | Assert.assertEquals(QnException.EMPTY_VAR, e.getMessage()); 86 | } 87 | try { 88 | qn = "您好:{姓名}(性别=男 and 年龄>=60)[老先生"; 89 | QnObject.fromQn(qn); 90 | Assert.fail(); 91 | }catch(QnException e) { 92 | System.out.println(qn); 93 | System.out.println(qn.substring(0, e.getPos())+" => "+e.getMessage()); 94 | Assert.assertEquals(QnException.MISS_CONDITION_END, e.getMessage()); 95 | } 96 | try { 97 | qn = "您好:{姓名}({性别}=男 and {年龄}>=60 or 机构!=北京)[老先生]"; 98 | QnObject.fromQn(qn); 99 | Assert.fail(); 100 | }catch(QnException e) { 101 | System.out.println(qn); 102 | System.out.println(qn.substring(0, e.getPos())+" => "+e.getMessage()); 103 | Assert.assertEquals(QnException.BAD_AND_OR, e.getMessage()); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /start.bat: -------------------------------------------------------------------------------- 1 | java -server -Xmx384m -jar target/light4j.jar --------------------------------------------------------------------------------