Compare commits

...

27 Commits
0.4.0 ... 0.7.1

Author SHA1 Message Date
曾文豪
149f4ab061 publish 0.7.1 2023-02-23 12:13:55 +08:00
曾文豪
a22c08738a publish 0.7.0 2023-02-23 11:57:01 +08:00
曾文豪
d28f3250e3 perf:优化脱敏类 2023-02-22 12:52:14 +08:00
曾文豪
bf3b88b43b publish 0.6.2 2023-02-22 12:16:51 +08:00
曾文豪
0a98e81109 perf:标记为false,可以不实现 2023-02-22 12:04:45 +08:00
曾文豪
e3c051d443 publish 0.6.1 2023-02-22 00:26:15 +08:00
曾文豪
282a46458a publish 40.6.1 2023-02-22 00:25:33 +08:00
曾文豪
637a9d1ace perf:增加数据库同步后的执行 2023-02-22 00:24:26 +08:00
曾文豪
959eff62df publish 0.6.0 2023-02-21 10:47:52 +08:00
曾文豪
fdbdf79383 perf:移除数据库备份方案 2023-02-21 10:47:12 +08:00
曾文豪
800c53c6fd perf:移除数据库备份方案 2023-02-21 10:47:05 +08:00
曾文豪
c3f4f91a37 feat:增加微信小程序登录 2023-02-21 10:45:44 +08:00
曾文豪
31f6babb97 perf:测试数据库备份 2023-02-21 09:25:32 +08:00
曾文豪
668e7069f7 perf:测试数据库备份 2023-02-21 09:22:40 +08:00
曾文豪
5cd4994624 perf:测试数据库备份 2023-02-21 09:14:27 +08:00
曾文豪
941bd0f65e perf:测试数据库备份 2023-02-21 09:11:45 +08:00
曾文豪
5cf6e1f8d4 perf:测试数据库备份 2023-02-21 09:09:25 +08:00
曾文豪
def1b4e06a perf:测试数据库备份 2023-02-21 09:08:19 +08:00
曾文豪
f5b8e989b7 perf:测试数据库备份 2023-02-21 09:06:53 +08:00
曾文豪
1918dfbaa0 perf:增加数据库备份 2023-02-20 18:25:36 +08:00
曾文豪
7fcc407514 perf:升级Ip2Region 2023-02-20 14:28:13 +08:00
曾文豪
b79895aa56 perf:.gitignore调整 2023-02-20 13:13:49 +08:00
曾文豪
4700d4e061 perf:调整ip2region存放目录 2023-02-20 13:10:37 +08:00
曾文豪
a8be751e65 publish 0.5.0 2023-02-17 17:15:45 +08:00
曾文豪
1b1073eab1 publish 0.4.1 2023-02-17 15:22:51 +08:00
曾文豪
56e2a66bdf fixed:修改sql文件执行过滤的判断方式 2023-02-17 15:22:11 +08:00
曾文豪
c5654474b0 perf:增加runtime目录,日志也移动到runtime目录中 2023-02-17 14:55:32 +08:00
44 changed files with 753 additions and 974 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ rebel.xml
*.iml
/static/
/config/
/runtime/

View File

@@ -16,4 +16,3 @@ deploy-jar:
- git add .
- git commit -m "deploy $CI_PROJECT_NAME $CI_COMMIT_TAG"
- git push origin master

27
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
<packaging>pom</packaging>
<name>springboot-parent</name>
<description>杭州铁晟科技有限公司基础依赖</description>
@@ -19,7 +19,7 @@
<modules>
<module>springboot-ademo</module>
<module>springboot-db-migration</module>
<module>springboot-database</module>
<module>springboot-login</module>
<module>springboot-web</module>
<module>springboot-util</module>
@@ -56,56 +56,56 @@
<dependencies>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-db-migration</artifactId>
<version>0.4.0</version>
<artifactId>springboot-database</artifactId>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-login</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-web</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-util</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-platform</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-message</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-encrypt</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-annotation</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-poi</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</dependency>
<dependency>
@@ -136,12 +136,13 @@
<plugin>
<groupId>com.tiesheng.springboot-plugin</groupId>
<artifactId>tiesheng-maven-plugin</artifactId>
<version>0.0.3</version>
<version>0.0.5</version>
<executions>
<execution>
<goals>
<goal>initStartScript</goal>
<goal>mysqlComparison</goal>
<goal>mysqlDoc</goal>
</goals>
</execution>
</executions>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-ademo</artifactId>

View File

@@ -1,7 +1,7 @@
package com.tiesheng.demo.config;
import cn.hutool.core.util.StrUtil;
import com.tiesheng.core.pojos.CurrentWebUser;
import com.tiesheng.core.pojos.RequestUserInfo;
import com.tiesheng.core.pojos.dao.CorePlatformUnique;
import com.tiesheng.core.service.TieshengWebConfigurer;
import com.tiesheng.login.config.token.bean.TokenBean;
@@ -19,7 +19,7 @@ public class DemoWebConfigurer implements TieshengWebConfigurer {
GlobalConfig globalConfig;
@Override
public CurrentWebUser getCurrentUserName(TokenBean tokenBean) {
public RequestUserInfo getCurrentUserName(TokenBean tokenBean) {
return null;
}

View File

@@ -1,13 +1,16 @@
package com.tiesheng.demo.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.LogFactory;
import com.tiesheng.annotation.token.TokenIgnore;
import com.tiesheng.demo.pojos.TestFile;
import com.tiesheng.login.config.token.TsTokenConfig;
import com.tiesheng.login.config.token.bean.TokenBean;
import com.tiesheng.message.config.aliyun.AliyunSmsConfig;
import com.tiesheng.message.pojos.MessageReqResp;
import com.tiesheng.util.config.GlobalConfig;
import com.tiesheng.util.config.Ip2regionConfig;
import com.tiesheng.util.pojos.ApiResp;
import com.tiesheng.util.pojos.FileUploadPath;
import org.springframework.beans.factory.annotation.Autowired;
@@ -15,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author hao
@@ -29,6 +33,9 @@ public class TestController {
AliyunSmsConfig aliyunSmsConfig;
@Autowired
TsTokenConfig tsTokenConfig;
@Autowired
Ip2regionConfig ip2regionConfig;
@RequestMapping("/index")
@TokenIgnore
@@ -80,4 +87,21 @@ public class TestController {
return ApiResp.respOK(uploadPath.getAbsolutePath());
}
@RequestMapping("searchIP")
@TokenIgnore
public ApiResp<String> searchIp() {
String search = ip2regionConfig.search("127.0.0.1");
return ApiResp.respOK(search);
}
@RequestMapping("desensitize")
@TokenIgnore
public ApiResp<List<TestFile>> desensitize() {
TestFile file = new TestFile("11111");
TestFile file1 = new TestFile("22222");
return ApiResp.respOK(CollUtil.newArrayList(file, file1));
}
}

View File

@@ -1,27 +1,27 @@
//package com.tiesheng.demo.pojos;
//
//import com.alibaba.excel.annotation.ExcelProperty;
//import com.tiesheng.poi.pojos.PoiWriteBase;
//
//public class TestFile implements PoiWriteBase {
//
//
// @ExcelProperty("测试")
// private String test;
//
// public TestFile(String test) {
// this.test = test;
// }
//
// ///////////////////////////////////////////////////////////////////////////
// // setter、getter
// ///////////////////////////////////////////////////////////////////////////
//
// public String getTest() {
// return test;
// }
//
// public void setTest(String test) {
// this.test = test;
// }
//}
package com.tiesheng.demo.pojos;
import com.tiesheng.annotation.desensitize.Desensitize;
import com.tiesheng.poi.pojos.PoiWriteBase;
public class TestFile implements PoiWriteBase {
@Desensitize()
private String test;
public TestFile(String test) {
this.test = test;
}
///////////////////////////////////////////////////////////////////////////
// setter、getter
///////////////////////////////////////////////////////////////////////////
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}

View File

@@ -1,6 +1,7 @@
server:
compression:
enabled: true
port: 8100
## Spring配置
spring:
@@ -18,4 +19,4 @@ spring:
## 日志
logging:
file:
name: logs/tiesheng.log
name: runtime/logs/tiesheng.log

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-annotation</artifactId>

View File

@@ -0,0 +1,16 @@
package com.tiesheng.annotation.desensitize;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author hao
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Desensitize {
int prefix() default 1;
int suffix() default 1;
}

View File

@@ -6,10 +6,10 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-db-migration</artifactId>
<artifactId>springboot-database</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>

View File

@@ -0,0 +1,12 @@
package com.tiesheng.database;
import org.springframework.context.annotation.ComponentScan;
/**
* @author hao
*/
@ComponentScan({
"com.tiesheng.database.**.*"
})
public class DatabaseAutoConfigurer {
}

View File

@@ -0,0 +1,72 @@
package com.tiesheng.database.config;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.log.LogFactory;
import com.tiesheng.database.utls.TieshengDbUtil;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
/**
* @author hao
*/
@Configuration
@ConfigurationProperties(prefix = "tiesheng.db-backup")
public class DbBackupConfig {
/**
* 数据库备份的路径
*/
private String path = "/root/backup/";
/**
* 备份文件的时间格式
*/
private String format = "yyyyMMdd";
public void dbBackup() {
String url = SpringUtil.getProperty("spring.datasource.url");
String username = SpringUtil.getProperty("spring.datasource.username");
String password = SpringUtil.getProperty("spring.datasource.password");
String dbName = TieshengDbUtil.getTableSchema(url);
try {
String saveFile = StrUtil.format("{}{}/{}.sql", getPath(), dbName, DateUtil.format(new Date(), format));
FileUtil.mkParentDirs(saveFile);
String cmd = StrUtil.format("mysqldump -u{} -p {} > {}", username, dbName, saveFile);
LogFactory.get().info("cmd: " + cmd);
String forStr = RuntimeUtil.execForStr(cmd);
LogFactory.get().info("dbBackup: " + forStr);
forStr = RuntimeUtil.execForStr(password);
LogFactory.get().info("dbBackup: " + forStr);
} catch (Exception ignored) {
}
}
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}

View File

@@ -1,4 +1,4 @@
package com.tiesheng.migration.config;
package com.tiesheng.database.config;
import cn.hutool.core.collection.CollUtil;
@@ -21,7 +21,7 @@ public class DbMigrationConfig {
private String table = "core_config_db";
private List<String> locations = CollUtil.newArrayList("classpath*:db/migration/*.sql");
private String ignoreSqls = "drop,delete";
private String ignoreSqls = "drop table,delete from";
/**
* 检查数据库是否存在

View File

@@ -0,0 +1,16 @@
package com.tiesheng.database.service;
import org.springframework.stereotype.Component;
/**
* @author hao
*/
@Component
public interface DbDataInitializer {
/**
* 初始化数据
*/
void init();
}

View File

@@ -1,4 +1,4 @@
package com.tiesheng.migration.service;
package com.tiesheng.database.service;
import cn.hutool.core.date.DateUtil;
@@ -9,7 +9,7 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.tiesheng.migration.config.DbMigrationConfig;
import com.tiesheng.database.config.DbMigrationConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.core.io.Resource;
@@ -35,12 +35,17 @@ public class DbMigrationInitializer implements ServletContextInitializer {
DataSource dataSource;
@Autowired
DbMigrationConfig dbMigrationConfig;
@Autowired(required = false)
List<DbDataInitializer> dbDataInitializerList;
@Override
public void onStartup(ServletContext servletContext) {
try {
startDeal();
if (dbDataInitializerList != null) {
dbDataInitializerList.forEach(DbDataInitializer::init);
}
} catch (Exception ignore) {
}
}
@@ -91,7 +96,7 @@ public class DbMigrationInitializer implements ServletContextInitializer {
if (StrUtil.isEmpty(sql)) {
continue;
}
if (StrUtil.startWithAnyIgnoreCase(sql, StrUtil.splitToArray(dbMigrationConfig.getIgnoreSqls(), ","))) {
if (StrUtil.containsAnyIgnoreCase(sql, StrUtil.splitToArray(dbMigrationConfig.getIgnoreSqls(), ","))) {
continue;
}
try {

View File

@@ -0,0 +1,17 @@
package com.tiesheng.database.utls;
import cn.hutool.core.util.StrUtil;
public class TieshengDbUtil {
/**
* 通过url获取table_schema
*
* @param url
* @return
*/
public static String getTableSchema(String url) {
return StrUtil.sub(url, url.lastIndexOf('/') + 1, StrUtil.indexOf(url, '?'));
}
}

View File

@@ -1,12 +0,0 @@
package com.tiesheng.migration;
import org.springframework.context.annotation.ComponentScan;
/**
* @author hao
*/
@ComponentScan({
"com.tiesheng.migration.**.*"
})
public class MigrationAutoConfigurer {
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-encrypt</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-login</artifactId>

View File

@@ -1,94 +0,0 @@
package com.tiesheng.login.config.zust;
public class CasLoginDTO {
private String data;
/**
* 工号
*/
private String casUser;
/**
* 用户容器
*/
private String casUserContainerId;
/**
* 用户姓名
*/
private String casUserCn;
/**
* 用户别名
*/
private String casUserAlias;
/**
* 用户所在组
*/
private String casUserMemberOf;
/**
* 用户性别
*/
private String casUserGender;
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getCasUser() {
return casUser;
}
public void setCasUser(String casUser) {
this.casUser = casUser;
}
public String getCasUserContainerId() {
return casUserContainerId;
}
public void setCasUserContainerId(String casUserContainerId) {
this.casUserContainerId = casUserContainerId;
}
public String getCasUserCn() {
return casUserCn;
}
public void setCasUserCn(String casUserCn) {
this.casUserCn = casUserCn;
}
public String getCasUserAlias() {
return casUserAlias;
}
public void setCasUserAlias(String casUserAlias) {
this.casUserAlias = casUserAlias;
}
public String getCasUserMemberOf() {
return casUserMemberOf;
}
public void setCasUserMemberOf(String casUserMemberOf) {
this.casUserMemberOf = casUserMemberOf;
}
public String getCasUserGender() {
return casUserGender;
}
public void setCasUserGender(String casUserGender) {
this.casUserGender = casUserGender;
}
}

View File

@@ -9,11 +9,14 @@ import com.tiesheng.login.config.token.bean.TokenBean;
import com.tiesheng.login.pojos.CodeExtraDTO;
import com.tiesheng.login.pojos.DoLoginInfo;
import com.tiesheng.login.pojos.UniqueIndexDTO;
import com.tiesheng.login.pojos.WxminiLoginVo;
import com.tiesheng.login.service.TieshengLoginConfigurer;
import com.tiesheng.platform.config.ding.PlatformDingConfig;
import com.tiesheng.platform.config.ding.bean.DingJsapiSignature;
import com.tiesheng.platform.config.ding.bean.DingUserInfo;
import com.tiesheng.platform.config.wxmini.PlatformWxminiConfig;
import com.tiesheng.platform.config.wxmp.PlatformWxmpConfig;
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
import com.tiesheng.platform.config.wxmp.bean.WxJsapiSignature;
import com.tiesheng.platform.config.wxmp.bean.WxUserInfo;
import com.tiesheng.util.config.GlobalConfig;
@@ -40,6 +43,8 @@ public class LoginController {
@Autowired
PlatformDingConfig platformDingConfig;
@Autowired
PlatformWxminiConfig platformWxminiConfig;
@Autowired
TieshengLoginConfigurer tieshengLoginConfigurer;
@Autowired
GlobalConfig globalConfig;
@@ -186,5 +191,30 @@ public class LoginController {
return ApiResp.respOK(jsapiSignature);
}
///////////////////////////////////////////////////////////////////////////
// 小程序相关
///////////////////////////////////////////////////////////////////////////
/**
* 微信小程序登录
*
* @return
*/
@RequestMapping("/wxmini/index/{service}")
@TokenIgnore
public ApiResp<WxminiLoginVo> wxminiIndex(@PathVariable String service, String code) {
String openid = platformWxminiConfig.jscode2session(service, code);
WxConfigBean configBean = platformWxminiConfig.getConfigBean(service);
TokenBean tokenBean = tieshengLoginConfigurer.doLogin(new DoLoginInfo(configBean.getAppId(),
openid, "wxmini", "mini", "{}"));
WxminiLoginVo loginVo = new WxminiLoginVo();
loginVo.setOpenid(openid);
if (tokenBean != null) {
loginVo.setToken(tokenBean.toToken());
}
return ApiResp.respOK(loginVo);
}
}

View File

@@ -0,0 +1,27 @@
package com.tiesheng.login.pojos;
public class WxminiLoginVo {
private String openid;
private String token;
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-message</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-platform</artifactId>

View File

@@ -0,0 +1,95 @@
package com.tiesheng.platform.config.wxmini;
import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
import com.tiesheng.util.exception.ApiException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
/**
* @author hao
*/
@Configuration
@ConfigurationProperties(prefix = "platform.wxmini")
public class PlatformWxminiConfig {
private WxConfigBean global;
private Map<String, WxConfigBean> configs = MapUtil.newHashMap();
/**
* 获取一个DingConfigBean
*
* @param service
* @return
*/
public WxConfigBean getConfigBean(String service) {
WxConfigBean bean = configs.get(service);
if (bean == null) {
bean = global;
}
if (bean == null) {
throw new ApiException("该服务未配置微信小程序授权");
}
return bean;
}
///////////////////////////////////////////////////////////////////////////
// 业务逻辑
///////////////////////////////////////////////////////////////////////////
/**
* 通过code获取openid
*
* @return
*/
public String jscode2session(String service, String code) {
WxConfigBean configBean = getConfigBean(service);
String body = HttpRequest.get("https://api.weixin.qq.com/sns/jscode2session"
+ "?appid=" + configBean.getAppId()
+ "&secret=" + configBean.getAppSecret()
+ "&js_code=" + code + "&grant_type=authorization_code").execute().body();
JSONObject object = JSONUtil.parseObj(body);
return object.getStr("openid");
}
/**
* 获取access_token
*
* @return
*/
public String getAccessToken(String service) {
WxConfigBean configBean = getConfigBean(service);
String body = HttpRequest.get("https://api.weixin.qq.com/cgi-bin/token"
+ "?grant_type=client_credential&appid=" + configBean.getAppId()
+ "&secret=" + configBean.getAppSecret()).execute().body();
JSONObject object = JSONUtil.parseObj(body);
return object.getStr("access_token");
}
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public Map<String, WxConfigBean> getConfigs() {
return configs;
}
public void setConfigs(Map<String, WxConfigBean> configs) {
this.configs = configs;
}
public WxConfigBean getGlobal() {
return global;
}
public void setGlobal(WxConfigBean global) {
this.global = global;
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-poi</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-util</artifactId>

View File

@@ -3,12 +3,11 @@ package com.tiesheng.util.config;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.log.LogFactory;
import com.tiesheng.util.ip2region.Searcher;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
/**
* @author hao
@@ -17,8 +16,8 @@ import java.io.RandomAccessFile;
@ConfigurationProperties(prefix = "tiesheng.ip2region")
public class Ip2regionConfig {
private String dbUrl = "http://git.kepai365.com/zeng_wenhao/kepai-repo/raw/master/ipdb/ip2region.db";
private String dbPath = System.getProperty("user.dir") + "/config/ip2region.db";
private String dbUrl = "http://git.kepai365.com/zeng_wenhao/kepai-repo/raw/master/ipdb/ip2region.xdb";
private String dbPath = System.getProperty("user.dir") + "/runtime/ip2region/ip2region.xdb";
///////////////////////////////////////////////////////////////////////////
// 逻辑方法
@@ -35,15 +34,20 @@ public class Ip2regionConfig {
/**
* 获取db文件
* 搜索ip
*
* @param ip
* @return
*/
public RandomAccessFile getDbAccessFile() throws FileNotFoundException {
if (!FileUtil.exist(dbPath)) {
downloadDbFile();
public String search(String ip) {
String region = "";
try {
Searcher searcher = Searcher.newWithFileOnly(dbPath);
region = searcher.search(ip);
searcher.close();
} catch (Exception ignored) {
}
return new RandomAccessFile(dbPath, "r");
return region;
}
///////////////////////////////////////////////////////////////////////////

View File

@@ -1,76 +0,0 @@
package com.tiesheng.util.ip2region;
/**
* data block class
*
* @author chenxin<chenxin619315 @ gmail.com>
*/
public class DataBlock {
/**
* city id
*/
private int cityId;
/**
* region address
*/
private String region;
/**
* region ptr in the db file
*/
private int dataPtr;
/**
* construct method
*
* @param cityId
* @param region region string
* @param dataPtr data ptr
*/
public DataBlock(int cityId, String region, int dataPtr) {
this.cityId = cityId;
this.region = region;
this.dataPtr = dataPtr;
}
public DataBlock(int cityId, String region) {
this(cityId, region, 0);
}
public int getCityId() {
return cityId;
}
public DataBlock setCityId(int cityId) {
this.cityId = cityId;
return this;
}
public String getRegion() {
return region;
}
public DataBlock setRegion(String region) {
this.region = region;
return this;
}
public int getDataPtr() {
return dataPtr;
}
public DataBlock setDataPtr(int dataPtr) {
this.dataPtr = dataPtr;
return this;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(cityId).append('|').append(region).append('|').append(dataPtr);
return sb.toString();
}
}

View File

@@ -1,51 +0,0 @@
package com.tiesheng.util.ip2region;
/**
* database configuration class
*
* @author chenxin<chenxin619315 @ gmail.com>
*/
public class DbConfig {
/**
* total header data block size
*/
private int totalHeaderSize;
/**
* max index data block size
* u should always choice the fastest read block size
*/
private int indexBlockSize;
/**
* construct method
*
* @param totalHeaderSize
*/
public DbConfig(int totalHeaderSize) {
this.totalHeaderSize = totalHeaderSize;
this.indexBlockSize = 8192;
}
public DbConfig() {
this(8 * 2048);
}
public int getTotalHeaderSize() {
return totalHeaderSize;
}
public DbConfig setTotalHeaderSize(int totalHeaderSize) {
this.totalHeaderSize = totalHeaderSize;
return this;
}
public int getIndexBlockSize() {
return indexBlockSize;
}
public DbConfig setIndexBlockSize(int dataBlockSize) {
this.indexBlockSize = dataBlockSize;
return this;
}
}

View File

@@ -0,0 +1,34 @@
package com.tiesheng.util.ip2region;
/**
* @author hao
*/
public class Header {
public final int version;
public final int indexPolicy;
public final int createdAt;
public final int startIndexPtr;
public final int endIndexPtr;
public final byte[] buffer;
public Header(byte[] buff) {
assert buff.length >= 16;
version = Searcher.getInt2(buff, 0);
indexPolicy = Searcher.getInt2(buff, 2);
createdAt = Searcher.getInt(buff, 4);
startIndexPtr = Searcher.getInt(buff, 8);
endIndexPtr = Searcher.getInt(buff, 12);
buffer = buff;
}
@Override
public String toString() {
return "{" +
"Version: " + version + ',' +
"IndexPolicy: " + indexPolicy + ',' +
"CreatedAt: " + createdAt + ',' +
"StartIndexPtr: " + startIndexPtr + ',' +
"EndIndexPtr: " + endIndexPtr +
'}';
}
}

View File

@@ -1,102 +0,0 @@
package com.tiesheng.util.ip2region;
/**
* item index class
*
* @author chenxin<chenxin619315 @ gmail.com>
*/
public class IndexBlock {
private static int LENGTH = 12;
/**
* start ip address
*/
private long startIp;
/**
* end ip address
*/
private long endIp;
/**
* data ptr and data length
*/
private int dataPtr;
/**
* data length
*/
private int dataLen;
public IndexBlock(long startIp, long endIp, int dataPtr, int dataLen) {
this.startIp = startIp;
this.endIp = endIp;
this.dataPtr = dataPtr;
this.dataLen = dataLen;
}
public static int getIndexBlockLength() {
return LENGTH;
}
public long getStartIp() {
return startIp;
}
public IndexBlock setStartIp(long startIp) {
this.startIp = startIp;
return this;
}
public long getEndIp() {
return endIp;
}
public IndexBlock setEndIp(long endIp) {
this.endIp = endIp;
return this;
}
public int getDataPtr() {
return dataPtr;
}
public IndexBlock setDataPtr(int dataPtr) {
this.dataPtr = dataPtr;
return this;
}
public int getDataLen() {
return dataLen;
}
public IndexBlock setDataLen(int dataLen) {
this.dataLen = dataLen;
return this;
}
/**
* get the bytes for storage
*
* @return byte[]
*/
public byte[] getBytes() {
/*
* +------------+-----------+-----------+
* | 4bytes | 4bytes | 4bytes |
* +------------+-----------+-----------+
* start ip end ip data ptr + len
*/
byte[] b = new byte[12];
IpUtil.writeIntLong(b, 0, startIp); //start ip
IpUtil.writeIntLong(b, 4, endIp); //end ip
//write the data ptr and the length
long mix = dataPtr | ((dataLen << 24) & 0xFF000000L);
IpUtil.writeIntLong(b, 8, mix);
return b;
}
}

View File

@@ -1,416 +0,0 @@
package com.tiesheng.util.ip2region;
import cn.hutool.extra.spring.SpringUtil;
import com.tiesheng.util.config.Ip2regionConfig;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
/**
* ip db searcher class (Not thread safe)
*
* @author chenxin<chenxin619315 @ gmail.com>
*/
public class Ip2Region {
private static Ip2Region ip2Region;
/**
* db config
*/
private final DbConfig dbConfig;
/**
* db file access handler
*/
private RandomAccessFile raf = null;
/**
* header blocks buffer
*/
private long[] headerSip = null;
private int[] headerPtr = null;
private int headerLength;
/**
* super blocks info
*/
private long firstIndexPtr = 0;
private long lastIndexPtr = 0;
private int totalIndexBlocks = 0;
/**
* for memory mode
* the original db binary string
*/
private byte[] dbBinStr = null;
/**
* construct class
*/
public Ip2Region() {
this.dbConfig = new DbConfig();
try {
Ip2regionConfig ip2regionConfig = SpringUtil.getBean(Ip2regionConfig.class);
raf = ip2regionConfig.getDbAccessFile();
} catch (Exception ignored) {
}
}
/**
* 获取单例
*
* @return
*/
public static Ip2Region getInstance() {
if (ip2Region == null) {
synchronized (Ip2Region.class) {
if (ip2Region == null) {
ip2Region = new Ip2Region();
}
}
}
return ip2Region;
}
/**
* get the region with an int ip address with memory binary search algorithm
*
* @param ip
* @throws IOException
*/
public DataBlock memorySearch(long ip) throws IOException {
int blen = IndexBlock.getIndexBlockLength();
if (dbBinStr == null) {
dbBinStr = new byte[(int) raf.length()];
raf.seek(0L);
raf.readFully(dbBinStr, 0, dbBinStr.length);
//initialize the global vars
firstIndexPtr = IpUtil.getIntLong(dbBinStr, 0);
lastIndexPtr = IpUtil.getIntLong(dbBinStr, 4);
totalIndexBlocks = (int) ((lastIndexPtr - firstIndexPtr) / blen) + 1;
}
//search the index blocks to define the data
int l = 0, h = totalIndexBlocks;
long sip, eip, dataptr = 0;
while (l <= h) {
int m = (l + h) >> 1;
int p = (int) (firstIndexPtr + m * blen);
sip = IpUtil.getIntLong(dbBinStr, p);
if (ip < sip) {
h = m - 1;
} else {
eip = IpUtil.getIntLong(dbBinStr, p + 4);
if (ip > eip) {
l = m + 1;
} else {
dataptr = IpUtil.getIntLong(dbBinStr, p + 8);
break;
}
}
}
//not matched
if (dataptr == 0) {
return null;
}
//get the data
int dataLen = (int) ((dataptr >> 24) & 0xFF);
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
int cityId = (int) IpUtil.getIntLong(dbBinStr, dataPtr);
String region = new String(dbBinStr, dataPtr + 4, dataLen - 4, StandardCharsets.UTF_8);
return new DataBlock(cityId, region, dataPtr);
}
/**
* get the region throught the ip address with memory binary search algorithm
*
* @return DataBlock
* @throws IOException
*/
public DataBlock memorySearch() throws IOException {
return memorySearch(null);
}
/**
* get the region throught the ip address with memory binary search algorithm
*
* @param ip
* @return DataBlock
* @throws IOException
*/
public DataBlock memorySearch(String ip) throws IOException {
return memorySearch(IpUtil.ip2long(ip));
}
/**
* get by index ptr
*
* @param ptr
* @throws IOException
*/
public DataBlock getByIndexPtr(long ptr) throws IOException {
raf.seek(ptr);
byte[] buffer = new byte[12];
raf.readFully(buffer, 0, buffer.length);
long extra = IpUtil.getIntLong(buffer, 8);
int dataLen = (int) ((extra >> 24) & 0xFF);
int dataPtr = (int) ((extra & 0x00FFFFFF));
raf.seek(dataPtr);
byte[] data = new byte[dataLen];
raf.readFully(data, 0, data.length);
int cityId = (int) IpUtil.getIntLong(data, 0);
String region = new String(data, 4, data.length - 4, StandardCharsets.UTF_8);
return new DataBlock(cityId, region, dataPtr);
}
/**
* get the region with an int ip address with b-tree algorithm
*
* @param ip
* @throws IOException
*/
public DataBlock btreeSearch(long ip) throws IOException {
//check and load the header
if (headerSip == null) {
raf.seek(8L);
byte[] b = new byte[dbConfig.getTotalHeaderSize()];
raf.readFully(b, 0, b.length);
//fill the header
int len = b.length >> 3, idx = 0;
headerSip = new long[len];
headerPtr = new int[len];
long startIp, dataPtr;
for (int i = 0; i < b.length; i += 8) {
startIp = IpUtil.getIntLong(b, i);
dataPtr = IpUtil.getIntLong(b, i + 4);
if (dataPtr == 0) {
break;
}
headerSip[idx] = startIp;
headerPtr[idx] = (int) dataPtr;
idx++;
}
headerLength = idx;
}
//1. define the index block with the binary search
if (ip == headerSip[0]) {
return getByIndexPtr(headerPtr[0]);
} else if (ip == headerSip[headerLength - 1]) {
return getByIndexPtr(headerPtr[headerLength - 1]);
}
int l = 0, h = headerLength, sptr = 0, eptr = 0;
while (l <= h) {
int m = (l + h) >> 1;
//perfetc matched, just return it
if (ip == headerSip[m]) {
if (m > 0) {
sptr = headerPtr[m - 1];
eptr = headerPtr[m];
} else {
sptr = headerPtr[m];
eptr = headerPtr[m + 1];
}
break;
}
//less then the middle value
if (ip < headerSip[m]) {
if (m == 0) {
sptr = headerPtr[m];
eptr = headerPtr[m + 1];
break;
} else if (ip > headerSip[m - 1]) {
sptr = headerPtr[m - 1];
eptr = headerPtr[m];
break;
}
h = m - 1;
} else {
if (m == headerLength - 1) {
sptr = headerPtr[m - 1];
eptr = headerPtr[m];
break;
} else if (ip <= headerSip[m + 1]) {
sptr = headerPtr[m];
eptr = headerPtr[m + 1];
break;
}
l = m + 1;
}
}
//match nothing just stop it
if (sptr == 0) {
return null;
}
//2. search the index blocks to define the data
int blockLen = eptr - sptr, blen = IndexBlock.getIndexBlockLength();
//include the right border block
byte[] iBuffer = new byte[blockLen + blen];
raf.seek(sptr);
raf.readFully(iBuffer, 0, iBuffer.length);
l = 0;
h = blockLen / blen;
long sip, eip, dataptr = 0;
while (l <= h) {
int m = (l + h) >> 1;
int p = m * blen;
sip = IpUtil.getIntLong(iBuffer, p);
if (ip < sip) {
h = m - 1;
} else {
eip = IpUtil.getIntLong(iBuffer, p + 4);
if (ip > eip) {
l = m + 1;
} else {
dataptr = IpUtil.getIntLong(iBuffer, p + 8);
break;
}
}
}
//not matched
if (dataptr == 0) {
return null;
}
//3. get the data
int dataLen = (int) ((dataptr >> 24) & 0xFF);
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
raf.seek(dataPtr);
byte[] data = new byte[dataLen];
raf.readFully(data, 0, data.length);
int cityId = (int) IpUtil.getIntLong(data, 0);
String region = new String(data, 4, data.length - 4, StandardCharsets.UTF_8);
return new DataBlock(cityId, region, dataPtr);
}
/**
* get the region throught the ip address with b-tree search algorithm
*
* @param ip
* @return DataBlock
* @throws IOException
*/
public DataBlock btreeSearch(String ip) {
try {
return btreeSearch(IpUtil.ip2long(ip));
} catch (IOException ignored) {
}
return new DataBlock(0, "未知IP");
}
/**
* get the region with a int ip address with binary search algorithm
*
* @param ip
* @throws IOException
*/
public DataBlock binarySearch(long ip) throws IOException {
int blen = IndexBlock.getIndexBlockLength();
if (totalIndexBlocks == 0) {
raf.seek(0L);
byte[] superBytes = new byte[8];
raf.readFully(superBytes, 0, superBytes.length);
//initialize the global vars
firstIndexPtr = IpUtil.getIntLong(superBytes, 0);
lastIndexPtr = IpUtil.getIntLong(superBytes, 4);
totalIndexBlocks = (int) ((lastIndexPtr - firstIndexPtr) / blen) + 1;
}
//search the index blocks to define the data
int l = 0, h = totalIndexBlocks;
byte[] buffer = new byte[blen];
long sip, eip, dataptr = 0;
while (l <= h) {
int m = (l + h) >> 1;
raf.seek(firstIndexPtr + m * blen);
raf.readFully(buffer, 0, buffer.length);
sip = IpUtil.getIntLong(buffer, 0);
if (ip < sip) {
h = m - 1;
} else {
eip = IpUtil.getIntLong(buffer, 4);
if (ip > eip) {
l = m + 1;
} else {
dataptr = IpUtil.getIntLong(buffer, 8);
break;
}
}
}
//not matched
if (dataptr == 0) {
return null;
}
//get the data
int dataLen = (int) ((dataptr >> 24) & 0xFF);
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
raf.seek(dataPtr);
byte[] data = new byte[dataLen];
raf.readFully(data, 0, data.length);
int cityId = (int) IpUtil.getIntLong(data, 0);
String region = new String(data, 4, data.length - 4, StandardCharsets.UTF_8);
return new DataBlock(cityId, region, dataPtr);
}
/**
* get the region throught the ip address with binary search algorithm
*
* @param ip
* @return DataBlock
* @throws IOException
*/
public DataBlock binarySearch(String ip) throws IOException {
return binarySearch(IpUtil.ip2long(ip));
}
/**
* get the db config
*
* @return DbConfig
*/
public DbConfig getDbConfig() {
return dbConfig;
}
/**
* close the db
*
* @throws IOException
*/
public void close() throws IOException {
headerSip = null;
headerPtr = null;
dbBinStr = null;
if (raf != null) {
raf.close();
}
}
}

View File

@@ -1,117 +0,0 @@
package com.tiesheng.util.ip2region;
/**
* util class
*
* @author chenxin<chenxin619315 @ gmail.com>
*/
public class IpUtil {
/**
* write specfield bytes to a byte array start from offset
*
* @param b
* @param offset
* @param v
* @param bytes
*/
public static void write(byte[] b, int offset, long v, int bytes) {
for (int i = 0; i < bytes; i++) {
b[offset++] = (byte) ((v >>> (8 * i)) & 0xFF);
}
}
/**
* write a int to a byte array
*
* @param b
* @param offset
* @param v
*/
public static void writeIntLong(byte[] b, int offset, long v) {
b[offset++] = (byte) ((v >> 0) & 0xFF);
b[offset++] = (byte) ((v >> 8) & 0xFF);
b[offset++] = (byte) ((v >> 16) & 0xFF);
b[offset] = (byte) ((v >> 24) & 0xFF);
}
/**
* get a int from a byte array start from the specifiled offset
*
* @param b
* @param offset
*/
public static long getIntLong(byte[] b, int offset) {
return (
((b[offset++] & 0x000000FFL)) |
((b[offset++] << 8) & 0x0000FF00L) |
((b[offset++] << 16) & 0x00FF0000L) |
((b[offset] << 24) & 0xFF000000L)
);
}
/**
* get a int from a byte array start from the specifield offset
*
* @param b
* @param offset
*/
public static int getInt3(byte[] b, int offset) {
return (
(b[offset++] & 0x000000FF) |
(b[offset++] & 0x0000FF00) |
(b[offset] & 0x00FF0000)
);
}
public static int getInt2(byte[] b, int offset) {
return (
(b[offset++] & 0x000000FF) |
(b[offset] & 0x0000FF00)
);
}
public static int getInt1(byte[] b, int offset) {
return (
(b[offset] & 0x000000FF)
);
}
/**
* string ip to long ip
*
* @param ip
* @return long
*/
public static long ip2long(String ip) {
String[] p = ip.split("\\.");
if (p.length != 4) {
return 0;
}
int p1 = ((Integer.valueOf(p[0]) << 24) & 0xFF000000);
int p2 = ((Integer.valueOf(p[1]) << 16) & 0x00FF0000);
int p3 = ((Integer.valueOf(p[2]) << 8) & 0x0000FF00);
int p4 = ((Integer.valueOf(p[3]) << 0) & 0x000000FF);
return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL);
}
/**
* int to ip string
*
* @param ip
* @return string
*/
public static String long2ip(long ip) {
StringBuilder sb = new StringBuilder();
sb
.append((ip >> 24) & 0xFF).append('.')
.append((ip >> 16) & 0xFF).append('.')
.append((ip >> 8) & 0xFF).append('.')
.append((ip >> 0) & 0xFF);
return sb.toString();
}
}

View File

@@ -0,0 +1,258 @@
package com.tiesheng.util.ip2region;
import java.io.IOException;
import java.io.RandomAccessFile;
public class Searcher {
// constant defined copied from the xdb maker
public static final int HeaderInfoLength = 256;
public static final int VectorIndexRows = 256;
public static final int VectorIndexCols = 256;
public static final int VectorIndexSize = 8;
public static final int SegmentIndexSize = 14;
public static final byte[] shiftIndex = {24, 16, 8, 0};
// random access file handle for file based search
private final RandomAccessFile handle;
// vector index.
// use the byte[] instead of VectorIndex entry array to keep
// the minimal memory allocation.
private final byte[] vectorIndex;
// xdb content buffer, used for in-memory search
private final byte[] contentBuff;
// --- static method to create searchers
private int ioCount = 0;
public Searcher(String dbFile, byte[] vectorIndex, byte[] cBuff) throws IOException {
if (cBuff != null) {
this.handle = null;
this.vectorIndex = null;
this.contentBuff = cBuff;
} else {
this.handle = new RandomAccessFile(dbFile, "r");
this.vectorIndex = vectorIndex;
this.contentBuff = null;
}
}
public static Searcher newWithFileOnly(String dbPath) throws IOException {
return new Searcher(dbPath, null, null);
}
// --- End of creator
public static Searcher newWithVectorIndex(String dbPath, byte[] vectorIndex) throws IOException {
return new Searcher(dbPath, vectorIndex, null);
}
public static Searcher newWithBuffer(byte[] cBuff) throws IOException {
return new Searcher(null, null, cBuff);
}
public static Header loadHeader(RandomAccessFile handle) throws IOException {
handle.seek(0);
final byte[] buff = new byte[HeaderInfoLength];
handle.read(buff);
return new Header(buff);
}
public static Header loadHeaderFromFile(String dbPath) throws IOException {
final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
final Header header = loadHeader(handle);
handle.close();
return header;
}
public static byte[] loadVectorIndex(RandomAccessFile handle) throws IOException {
handle.seek(HeaderInfoLength);
int len = VectorIndexRows * VectorIndexCols * VectorIndexSize;
final byte[] buff = new byte[len];
int rLen = handle.read(buff);
if (rLen != len) {
throw new IOException("incomplete read: read bytes should be " + len);
}
return buff;
}
public static byte[] loadVectorIndexFromFile(String dbPath) throws IOException {
final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
final byte[] vIndex = loadVectorIndex(handle);
handle.close();
return vIndex;
}
// --- static cache util function
public static byte[] loadContent(RandomAccessFile handle) throws IOException {
handle.seek(0);
final byte[] buff = new byte[(int) handle.length()];
int rLen = handle.read(buff);
if (rLen != buff.length) {
throw new IOException("incomplete read: read bytes should be " + buff.length);
}
return buff;
}
public static byte[] loadContentFromFile(String dbPath) throws IOException {
final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
final byte[] content = loadContent(handle);
handle.close();
return content;
}
/* get an int from a byte array start from the specified offset */
public static long getIntLong(byte[] b, int offset) {
return (
((b[offset++] & 0x000000FFL)) |
((b[offset++] << 8) & 0x0000FF00L) |
((b[offset++] << 16) & 0x00FF0000L) |
((b[offset] << 24) & 0xFF000000L)
);
}
public static int getInt(byte[] b, int offset) {
return (
((b[offset++] & 0x000000FF)) |
((b[offset++] << 8) & 0x0000FF00) |
((b[offset++] << 16) & 0x00FF0000) |
((b[offset] << 24) & 0xFF000000)
);
}
public static int getInt2(byte[] b, int offset) {
return (
((b[offset++] & 0x000000FF)) |
((b[offset] << 8) & 0x0000FF00)
);
}
/* long int to ip string */
public static String long2ip(long ip) {
return String.valueOf((ip >> 24) & 0xFF) + '.' +
((ip >> 16) & 0xFF) + '.' + ((ip >> 8) & 0xFF) + '.' + ((ip) & 0xFF);
}
// --- End cache load util function
// --- static util method
/* check the specified ip address */
public static long checkIP(String ip) throws Exception {
String[] ps = ip.split("\\.");
if (ps.length != 4) {
throw new Exception("invalid ip address `" + ip + "`");
}
long ipDst = 0;
for (int i = 0; i < ps.length; i++) {
int val = Integer.parseInt(ps[i]);
if (val > 255) {
throw new Exception("ip part `" + ps[i] + "` should be less then 256");
}
ipDst |= ((long) val << shiftIndex[i]);
}
return ipDst & 0xFFFFFFFFL;
}
public void close() throws IOException {
if (this.handle != null) {
this.handle.close();
}
}
public int getIOCount() {
return ioCount;
}
public String search(String ipStr) throws Exception {
long ip = checkIP(ipStr);
return search(ip);
}
public String search(long ip) throws IOException {
// reset the global counter
this.ioCount = 0;
// locate the segment index block based on the vector index
int sPtr = 0, ePtr = 0;
int il0 = (int) ((ip >> 24) & 0xFF);
int il1 = (int) ((ip >> 16) & 0xFF);
int idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize;
// System.out.printf("il0: %d, il1: %d, idx: %d\n", il0, il1, idx);
if (vectorIndex != null) {
sPtr = getInt(vectorIndex, idx);
ePtr = getInt(vectorIndex, idx + 4);
} else if (contentBuff != null) {
sPtr = getInt(contentBuff, HeaderInfoLength + idx);
ePtr = getInt(contentBuff, HeaderInfoLength + idx + 4);
} else {
final byte[] buff = new byte[VectorIndexSize];
read(HeaderInfoLength + idx, buff);
sPtr = getInt(buff, 0);
ePtr = getInt(buff, 4);
}
// System.out.printf("sPtr: %d, ePtr: %d\n", sPtr, ePtr);
// binary search the segment index block to get the region info
final byte[] buff = new byte[SegmentIndexSize];
int dataLen = -1, dataPtr = -1;
int l = 0, h = (ePtr - sPtr) / SegmentIndexSize;
while (l <= h) {
int m = (l + h) >> 1;
int p = sPtr + m * SegmentIndexSize;
// read the segment index
read(p, buff);
long sip = getIntLong(buff, 0);
if (ip < sip) {
h = m - 1;
} else {
long eip = getIntLong(buff, 4);
if (ip > eip) {
l = m + 1;
} else {
dataLen = getInt2(buff, 8);
dataPtr = getInt(buff, 10);
break;
}
}
}
// empty match interception
// System.out.printf("dataLen: %d, dataPtr: %d\n", dataLen, dataPtr);
if (dataPtr < 0) {
return null;
}
// load and return the region data
final byte[] regionBuff = new byte[dataLen];
read(dataPtr, regionBuff);
return new String(regionBuff, "utf-8");
}
protected void read(int offset, byte[] buffer) throws IOException {
// check the in-memory buffer first
if (contentBuff != null) {
// @TODO: reduce data copying, directly decode the data ?
System.arraycopy(contentBuff, offset, buffer, 0, buffer.length);
return;
}
// read from the file handle
assert handle != null;
handle.seek(offset);
this.ioCount++;
int rLen = handle.read(buffer);
if (rLen != buffer.length) {
throw new IOException("incomplete read: read bytes should be " + buffer.length);
}
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>0.4.0</version>
<version>0.7.1</version>
</parent>
<artifactId>springboot-web</artifactId>
@@ -64,7 +64,7 @@
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-db-migration</artifactId>
<artifactId>springboot-database</artifactId>
</dependency>
<dependency>

View File

@@ -1,9 +1,9 @@
package com.tiesheng.core;
import com.tiesheng.core.service.TieshengWebConfigurer;
import com.tiesheng.database.DatabaseAutoConfigurer;
import com.tiesheng.login.LoginAutoConfigurer;
import com.tiesheng.message.MessageAutoConfigurer;
import com.tiesheng.migration.MigrationAutoConfigurer;
import com.tiesheng.util.UtilAutoConfigurer;
import org.springframework.context.annotation.Import;
@@ -20,7 +20,7 @@ import java.lang.annotation.*;
MessageAutoConfigurer.class,
CoreAutoConfigurer.class,
LoginAutoConfigurer.class,
MigrationAutoConfigurer.class
DatabaseAutoConfigurer.class
})
public @interface EnableTieshengWeb {

View File

@@ -0,0 +1,37 @@
package com.tiesheng.core.config.desensitize;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.tiesheng.annotation.desensitize.Desensitize;
import java.lang.reflect.Field;
/**
* 脱敏过滤类
*
* @author hao
*/
public class DesensitizeValueFilter implements ValueFilter {
@Override
public Object process(Object object, String name, Object value) {
if (ObjectUtil.isEmpty(value) || !(value instanceof String)) {
return value;
}
Field field = ClassUtil.getDeclaredField(object.getClass(), name);
if (ObjectUtil.isEmpty(field)) {
return value;
}
Desensitize desensitize = field.getAnnotation(Desensitize.class);
if (String.class != field.getType() || ObjectUtil.isEmpty(desensitize)) {
return value;
}
String originVal = String.valueOf(value);
return StrUtil.hide(originVal, desensitize.prefix(),
StrUtil.length(originVal) - desensitize.suffix());
}
}

View File

@@ -3,6 +3,7 @@ package com.tiesheng.core.config.json;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.tiesheng.core.config.desensitize.DesensitizeValueFilter;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -30,6 +31,7 @@ public class FastJsonMessageConverter {
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteEnumUsingName);
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
config.setSerializeFilters(new DesensitizeValueFilter());
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
fastConverter.setFastJsonConfig(config);

View File

@@ -1,6 +1,11 @@
package com.tiesheng.core.pojos;
public class CurrentWebUser {
/**
* 当前token的数据
*
* @author hao
*/
public class RequestUserInfo {
private String id;
private String name;

View File

@@ -6,7 +6,7 @@ import cn.hutool.json.JSONUtil;
import com.tiesheng.core.mapper.CoreLogLoginMapper;
import com.tiesheng.core.mapper.CoreLogMessageMapper;
import com.tiesheng.core.mapper.CoreLogOperationMapper;
import com.tiesheng.core.pojos.CurrentWebUser;
import com.tiesheng.core.pojos.RequestUserInfo;
import com.tiesheng.core.pojos.dao.CoreLogLogin;
import com.tiesheng.core.pojos.dao.CoreLogMessage;
import com.tiesheng.core.pojos.dao.CoreLogOperation;
@@ -16,8 +16,7 @@ import com.tiesheng.login.config.token.bean.TokenBean;
import com.tiesheng.message.pojos.MessageReqResp;
import com.tiesheng.message.service.TieshengMessageConfigurer;
import com.tiesheng.util.ServletKit;
import com.tiesheng.util.ip2region.DataBlock;
import com.tiesheng.util.ip2region.Ip2Region;
import com.tiesheng.util.config.Ip2regionConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -35,6 +34,8 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
CoreLogLoginMapper coreLogLoginMapper;
@Autowired
CoreLogMessageMapper coreLogMessageMapper;
@Autowired
Ip2regionConfig ip2regionConfig;
public CoreLogLoginMapper getLogLoginMapper() {
return coreLogLoginMapper;
@@ -54,9 +55,9 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
*/
public void addOperationLog(String title, String subject, Object params) {
CoreLogOperation operation = new CoreLogOperation();
CurrentWebUser currentWebUser = tieshengWebConfigurer.getCurrentUserName(TsTokenConfig.get());
operation.setUserId(currentWebUser.getId());
operation.setUserName(currentWebUser.getName());
RequestUserInfo requestUserInfo = tieshengWebConfigurer.getCurrentUserName(TsTokenConfig.get());
operation.setUserId(requestUserInfo.getId());
operation.setUserName(requestUserInfo.getName());
operation.setTitle(title);
operation.setSubject(subject);
if (params != null) {
@@ -84,12 +85,11 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
login.setUserId(platformUnique.getUserId());
login.setPlatform(platformUnique.getPlatform());
CurrentWebUser currentWebUser = tieshengWebConfigurer.getCurrentUserName(tokenBean);
login.setUserName(currentWebUser.getName());
RequestUserInfo requestUserInfo = tieshengWebConfigurer.getCurrentUserName(tokenBean);
login.setUserName(requestUserInfo.getName());
login.setIp(ip);
DataBlock dataBlock = Ip2Region.getInstance().btreeSearch(ip);
login.setAddress(dataBlock.getRegion());
login.setAddress(ip2regionConfig.search(login.getIp()));
coreLogLoginMapper.insert(login);
}

View File

@@ -1,7 +1,6 @@
package com.tiesheng.core.service;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.tiesheng.core.mapper.CorePlatformUniqueMapper;
import com.tiesheng.core.pojos.dao.CorePlatformUnique;
import com.tiesheng.login.config.token.bean.TokenBean;
@@ -11,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author hao
@@ -35,15 +33,12 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
platformUnique.setUniqueId(loginInfo.getUnique());
}
platformUnique.setInfo(loginInfo.getInfo());
saveOrUpdate(platformUnique);
TokenBean tokenBean = tieshengWebConfigurer.loginConfigurer().doLogin(platformUnique, loginInfo.getTo());
if (tokenBean != null) {
platformUnique.setUserId(tokenBean.getId());
platformUnique.setIsDeleted(0);
saveOrUpdate(platformUnique);
// 添加登录日志
coreLogService.addLoginLog(platformUnique,tokenBean);
coreLogService.addLoginLog(platformUnique, tokenBean);
}
return tokenBean;
}
@@ -55,22 +50,18 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
/**
* 通过平台和用户id查询
* 更新用户id
*
* @param platform
* @param userIds
* @param uniqueId
* @param userId
* @return
*/
private List<CorePlatformUnique> getByPlatformAndUser(String platform, List<String> userIds) {
if (CollUtil.isEmpty(userIds)) {
return CollUtil.newArrayList();
}
QueryWrapper<CorePlatformUnique> queryWrapper = new QueryWrapper<>();
queryWrapper.in("user_id", userIds);
queryWrapper.eq("platform", platform);
queryWrapper.last("limit 1");
return list(queryWrapper);
public boolean updateUserId(String uniqueId, String userId) {
return update(new UpdateWrapper<CorePlatformUnique>().eq("unique_id", uniqueId)
.set("user_id", userId)
.set("is_deleted", 0)
);
}
}

View File

@@ -1,7 +1,7 @@
package com.tiesheng.core.service;
import cn.hutool.log.LogFactory;
import com.tiesheng.core.pojos.CurrentWebUser;
import com.tiesheng.core.pojos.RequestUserInfo;
import com.tiesheng.core.pojos.dao.CorePlatformUnique;
import com.tiesheng.login.config.token.bean.TokenBean;
import com.tiesheng.util.exception.ApiRespEnum;
@@ -22,7 +22,7 @@ public interface TieshengWebConfigurer {
*
* @return
*/
CurrentWebUser getCurrentUserName(TokenBean userId);
RequestUserInfo getCurrentUserName(TokenBean userId);
/**