shikeying
2024-02-23 1d6e7763f4a30272cc0818ea12f83697b7375c45
测试了aws oss,另外 mybatis模块还未完成
20个文件已添加
19个文件已修改
1866 ■■■■■ 已修改文件
deploy-jar-template/pom.xml 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/src/main/resources/application-dev.yml 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/src/main/resources/application-prod.yml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/src/main/resources/application-test.yml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/src/main/resources/application.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-admin/src/main/java/com/iplatform/base/controller/GenController.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-admin/src/main/java/com/iplatform/base/controller/UserController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-security/src/main/java/com/iplatform/security/DefaultAuthenticationFailureHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-security/src/main/java/com/iplatform/security/FailedAuthenticationEntryPoint.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-security/src/main/java/com/iplatform/security/JwtAuthenticationTokenFilter.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-tcp-client/src/test/java/com/iplatform/AppTest.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/DemoLoginResponse.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/DemoWebsocketClient.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/WebsocketClientTest.java 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/WebsocketDemo.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base/src/main/java/com/iplatform/base/AbstractFileOperateSpiController.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base/src/main/java/com/iplatform/base/ArgumentsConstants.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-base/src/main/java/com/iplatform/base/config/FileProperties.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-file-server/pom.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-file-server/src/main/java/com/iplatform/file/FileEngineFactory.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-file-server/src/main/java/com/iplatform/file/config/FileConfig.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-file-server/src/main/java/com/iplatform/file/support/AbstractOssFileEngine.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-file-server/src/main/java/com/iplatform/file/support/AwsOssFileEngine.java 359 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-support-mybatis/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-support-mybatis/src/main/java/com/iplatform/mybatis/service/MetaDataServiceImpl.java 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-support-mybatis/src/main/java/com/iplatform/mybatis/util/DataTypeUtils.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-support-mybatis/src/main/java/com/iplatform/mybatis/util/SqlUtils.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/pom.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/Test1.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/controller/EbUserController.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/EbUser.java 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/bo/EbUserBo.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/bo/EbUserQueryBo.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/vo/EbUserVo.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/mapper/EbUserMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/service/IEbUserService.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/main/java/com/iplatform/test/service/impl/EbUserServiceImpl.java 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iplatform-test-mybatis/src/test/java/com/iplatform/AppTest.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
deploy-jar-template/pom.xml
@@ -83,10 +83,10 @@
        </dependency>
        <!-- tcp通信模块引入,可配置是否开启:包括聊天功能基础等。2023-04-17 -->
        <dependency>
            <groupId>com.iplatform</groupId>
            <artifactId>iplatform-base-tcp</artifactId>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>com.iplatform</groupId>-->
<!--            <artifactId>iplatform-base-tcp</artifactId>-->
<!--        </dependency>-->
        <!-- 启用Rocket队列消息模块,聊天集群使用,2023-09-26 -->
        <dependency>
            <groupId>com.walkersoft</groupId>
@@ -161,16 +161,15 @@
        </dependency>
        <!-- 测试商户功能模块,2023-06-01 -->
        <dependency>
            <groupId>com.iplatform</groupId>
            <artifactId>ishop-merchant</artifactId>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>com.iplatform</groupId>-->
<!--            <artifactId>ishop-merchant</artifactId>-->
<!--        </dependency>-->
        <!-- 测试移动端,2023-06-23 -->
        <dependency>
            <groupId>com.iplatform</groupId>
            <artifactId>ishop-mobile</artifactId>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>com.iplatform</groupId>-->
<!--            <artifactId>ishop-mobile</artifactId>-->
<!--        </dependency>-->
        <!-- 测试mongo聊天写入,2023-07-07 -->
<!--        <dependency>-->
deploy-jar-template/src/main/resources/application-dev.yml
@@ -87,7 +87,7 @@
    host: 116.198.40.76
    port: 6379
    password: Jmy2019.
    database: 2
    database: 15
  mvc:
    pathmatch:
@@ -161,7 +161,7 @@
  # 平台缓存,是否启用redis缓存,默认使用基于内存缓存.
  # 注意:如果开启redis缓存,业务工程必须依赖(walker-support-redis)
  cache:
    redis-enabled: false
    redis-enabled: true
    # redis 缓存是否要重建,如果设置 true,则系统启动后会删除缓存,并执行默认重新加载方法。2023-08-26
    # 注意:该参数一般在测试阶段使用,正式环境不要使用!
    redis-rebuild: true
@@ -303,7 +303,21 @@
    file-root: d:/tmp/
    # 调用远程上传文件,是否按照本地文件处理,2023-07-03
    # 在测试过程中如果没有FTP等服务,可以设置为true临时存储本地
    remote-as-local: true
    remote-as-local: false
    # oss实现类型:aws_s3(亚马逊) | tx(腾讯) | ali(阿里) | qn(七牛),2023-12-13
    # | ftp,2024-02-23增加
    oss-type: aws_s3
    # oss访问前缀,如:http://localhost:8082/admin/oss/,2023-12-13
    oss-prefix: http://localhost:8082/admin/oss/
    oss-access-key: HDKSYC2Y4FELF5CL5FIB
    oss-secret-key: ktf8Px9uTvLFFpQNGsO41ehRsgJ0hWnLtxZnDBCX
    # oss服务地址
    oss-endpoint: http://eos-beijing-1.cmecloud.cn
    # oss默认的桶名称
    oss-bucket-name: ctoms-file
    protocol: http
    ftp:
      ip: 116.198.40.76
      port: 22
@@ -343,7 +357,8 @@
    # websocket连接端口
    port-ws: 60000
    # websocket连接uri
    websocket-uri: ws://localhost:60000/websocket
#    websocket-uri: ws://localhost:60000/websocket
    websocket-uri: ws://localhost:60000
    # 通信线程数量
    boss-thread-num: 2
    # 业务处理线程数量
deploy-jar-template/src/main/resources/application-prod.yml
@@ -285,6 +285,19 @@
    # 调用远程上传文件,是否按照本地文件处理,2023-07-03
    # 在测试过程中如果没有FTP等服务,可以设置为true临时存储本地
    remote-as-local: true
    # oss实现类型:aws_s3(亚马逊) | tx(腾讯) | ali(阿里) | qn(七牛),2023-12-13
    oss-type: aws_s3
    # oss访问前缀,如:http://localhost:8082/admin/oss/,2023-12-13
    oss-prefix: http://localhost:8082/admin/oss/
    oss-access-key: HDKSYC2Y4FELF5CL5FIB
    oss-secret-key: 111
    # oss服务地址
    oss-endpoint: http://eos-beijing-1.cmecloud.cn
    # oss默认的桶名称
    oss-bucket-name: ctoms-file
    protocol: http
    ftp:
      ip: 116.198.40.76
      port: 22
deploy-jar-template/src/main/resources/application-test.yml
@@ -281,6 +281,20 @@
    # 调用远程上传文件,是否按照本地文件处理,2023-07-03
    # 在测试过程中如果没有FTP等服务,可以设置为true临时存储本地
    remote-as-local: true
    # oss实现类型:aws_s3(亚马逊) | tx(腾讯) | ali(阿里) | qn(七牛),2023-12-13
    # | ftp,2024-02-23增加
    oss-type: aws_s3
    # oss访问前缀,如:http://localhost:8082/admin/oss/,2023-12-13
    oss-prefix: http://localhost:8082/admin/oss/
    oss-access-key: HDKSYC2Y4FELF5CL5FIB
    oss-secret-key: ktf8Px9uTvLFFpQNGsO41ehRsgJ0hWnLtxZnDBCX
    # oss服务地址
    oss-endpoint: http://eos-beijing-1.cmecloud.cn
    # oss默认的桶名称
    oss-bucket-name: ctoms-file
    protocol: http
#    ftp:
#      ip: 116.198.40.76
#      port: 22
deploy-jar-template/src/main/resources/application.yml
@@ -1,7 +1,7 @@
spring:
  profiles:
#    active: oracle
#    active: dev
    active: master
    active: dev
#    active: master
#    active: test
iplatform-base-admin/src/main/java/com/iplatform/base/controller/GenController.java
@@ -1,14 +1,22 @@
package com.iplatform.base.controller;
import com.iplatform.base.SystemController;
import com.iplatform.core.util.CharsetKit;
import com.iplatform.core.util.Convert;
import com.iplatform.mybatis.domain.GenTable;
import com.iplatform.mybatis.domain.GenTableColumn;
import com.iplatform.mybatis.domain.TableDataInfo;
import com.iplatform.mybatis.service.IGenTableColumnService;
import com.iplatform.mybatis.service.IGenTableService;
import com.iplatform.mybatis.service.MetaDataServiceImpl;
import com.iplatform.mybatis.util.VelocityInitializer;
import com.iplatform.mybatis.util.VelocityUtils;
import com.walker.infrastructure.utils.StringUtils;
import com.walker.web.ResponseValue;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
@@ -22,10 +30,14 @@
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * 代码生成 操作处理。
@@ -48,6 +60,9 @@
    @Autowired
    private IGenTableColumnService genTableColumnService;
    @Autowired
    private MetaDataServiceImpl metaDataService;
    /**
     * 查询代码生成列表
@@ -233,4 +248,51 @@
        rspData.setTotal(0);
        return rspData;
    }
    /**
     * 生成指定表结构代码,支持多数据库。
     * @param response
     * @param tableName 表名,可以是精确的表名,如:s_ment,也可以是前缀,如:s_
     * @param isPrecision 是否精确查询(单表)
     * @param packageName
     * @throws IOException
     * @date 2024-02-20
     */
    @GetMapping("/batchDownloadGenCode")
    public void batchDownloadGenCode(HttpServletResponse response, String tableName, boolean isPrecision, String packageName) throws IOException{
        List<GenTable> list = this.metaDataService.queryDatabaseTableInfo(tableName, isPrecision, packageName, null, null, null);
        if(StringUtils.isEmptyList(list)){
            logger.error("未查找到任何表信息,无法生存代码,tableName={}", tableName);
            return;
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        for(GenTable table : list){
            VelocityInitializer.initVelocity();
            VelocityContext context = VelocityUtils.prepareContext(table);
            // 获取模板列表
            List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
            for (String template : templates) {
                // 渲染模板
                StringWriter sw = new StringWriter();
                Template tpl = Velocity.getTemplate(template, CharsetKit.UTF_8);
                tpl.merge(context, sw);
                try {
                    // 添加到zip
                    zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
                    IOUtils.write(sw.toString(), zip, CharsetKit.UTF_8);
                    IOUtils.closeQuietly(sw);
                    zip.flush();
                    zip.closeEntry();
                }
                catch (IOException e) {
                    logger.error("渲染模板失败,表名:" + table.getTableName(), e);
                }
            }
        }
        IOUtils.closeQuietly(zip);
        byte[] data = outputStream.toByteArray();
        genCode(response, data);
    }
}
iplatform-base-admin/src/main/java/com/iplatform/base/controller/UserController.java
@@ -19,6 +19,7 @@
import com.walker.di.DataImportException;
import com.walker.file.FileInfo;
import com.walker.infrastructure.utils.DateUtils;
import com.walker.infrastructure.utils.FileCopyUtils;
import com.walker.infrastructure.utils.NumberGenerator;
import com.walker.infrastructure.utils.StringUtils;
import com.walker.web.ResponseValue;
@@ -35,6 +36,8 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -68,6 +71,18 @@
    @PostMapping("/import")
    public ResponseValue importExcel(MultipartFile file, boolean updateSupport){
        try {
            // ~~~~~~~~~~~~~~~~~~~~~ 测试
//            String filePath = "d:/tmp/test_user_001.csv";
//            FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath));
//            FileCopyUtils.copy(file.getInputStream(), fileOutputStream);
//            logger.info("文件写入成功:{}", filePath);
//            FileInfo testFileInfo = this.uploadFileToRemote(filePath, null, String.valueOf(this.getOwner()));
            // 2024-02-23 以下代码成功执行,暂时注释
//            FileInfo testFileInfo = this.uploadFileToRemote(file.getInputStream(), "avatar.jpg", null, file.getSize(), null, String.valueOf(Constants.OWNER_PLATFORM));
//            logger.info("testFileInfo = {}", testFileInfo);
            // ~~~~~~~~~~~~~~~~~~~~~ 测试 end
            UserDataImportor dataImportor = new UserDataImportor(file.getInputStream());
            dataImportor.setId("user_import");
            this.getDataImportEngine().executeImport(dataImportor, this.getCurrentUserPrincipal().getUserName());
@@ -75,6 +90,9 @@
            logger.info("错误结果文件:{}", dataImportor.getErrorFile());
//            FileInfo errorFileInfo = this.uploadFileToRemote(dataImportor.getErrorFile());
//            this.uploadFileToRemote(file.getInputStream(), null, null, String.valueOf(this.getOwner()),)
            // 这里会报错,因为上传 s3 oss时动态生成的文件,总是说读取长度和期望长度不一致:
            // 保存文件到【oss】错误:Data read has a different length than the expected: dataLength=2764; expectedLength=107374178304;
            FileInfo errorFileInfo = this.uploadFileToRemote(dataImportor.getErrorFile(), null, String.valueOf(this.getOwner()));
            if(errorFileInfo != null){
                logger.debug("用户导入存在'不符合数据': ,", errorFileInfo.toString());
iplatform-base-security/src/main/java/com/iplatform/security/DefaultAuthenticationFailureHandler.java
@@ -51,7 +51,7 @@
        }
        try {
            ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(code, message)));
            ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(message)));
        } catch (Exception e) {
            logger.error("认证失败:" + request.getRequestURI(), e);
        }
iplatform-base-security/src/main/java/com/iplatform/security/FailedAuthenticationEntryPoint.java
@@ -28,7 +28,7 @@
        String msg = "认证失败,无权限访问系统资源" + request.getRequestURI();
        try {
            ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(ResponseCode.NO_PERMISSION.getCode(), msg)));
            ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(ResponseCode.EXCEPTION.getCode(), msg)));
        } catch (Exception e) {
            logger.error("无权限访问系统资源" + request.getRequestURI());
        }
iplatform-base-security/src/main/java/com/iplatform/security/JwtAuthenticationTokenFilter.java
@@ -143,7 +143,7 @@
                , userPrincipal.getUserName(), uuid, this.tokenGenerator, securityProperties.getTokenExpireWeb());
        // 重新设置用户创建token时间
        userPrincipal.setLastLoginTime(System.currentTimeMillis());
        this.userOnlineProvider.cacheUserPrincipal(uuid, userPrincipal);
        this.userOnlineProvider.cacheUserPrincipal(uuid, userPrincipal, securityProperties.getTokenExpireWeb());
        response.addHeader(Constants.TOKEN_HEADER_REFRESH, token);
        if(this.logger.isDebugEnabled()){
            logger.debug("刷新token, uuid = " + uuid + ", " + token);
iplatform-base-tcp-client/src/test/java/com/iplatform/AppTest.java
New file
@@ -0,0 +1,16 @@
package com.iplatform;
import com.iplatform.tcp.WebsocketClientTest;
/**
 * Unit test for simple App.
 */
public class AppTest
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        WebsocketClientTest test = new WebsocketClientTest();
        test.createBatch();
    }
}
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/DemoLoginResponse.java
New file
@@ -0,0 +1,51 @@
package com.iplatform.tcp;
public class DemoLoginResponse {
    /**
     *
     */
    private static final long serialVersionUID = 1167352207355638142L;
//    @Override
//    protected void translateProperties(JSONObject result) {
//        result.put("status", status);
//    }
    @Override
    public String toString(){
        return new StringBuilder("[protocol=").append(this.getProtocol())
                .append(", name=").append(this.getUid())
                .append(", status=").append(this.status)
                .append("]").toString();
    }
    public String getUid() {
        return uid;
    }
    public void setUid(String uid) {
        this.uid = uid;
    }
    private String protocol;
    public String getProtocol() {
        return protocol;
    }
    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }
    public int getStatus() {
        return status;
    }
    public void setStatus(int status) {
        this.status = status;
    }
    private int status = 0;
    private String uid;
}
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/DemoWebsocketClient.java
New file
@@ -0,0 +1,81 @@
package com.iplatform.tcp;
import com.walker.infrastructure.utils.JsonUtils;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
public class DemoWebsocketClient extends WebSocketClient {
    protected final transient Logger logger = LoggerFactory.getLogger(this.getClass());
    public DemoWebsocketClient(URI serverUri) {
        super(serverUri);
    }
    @Override
    public void onOpen(ServerHandshake serverHandshake) {
//        logger.info("ws 连接成功");
        String data = null;
        Map<String, String> map = new HashMap<>(4);
        map.put("protocol", "login");
        map.put("uid", this.uid);
        try {
            data = JsonUtils.objectToJsonString(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        this.send(data);
        logger.info("客户端发送登录请求,name = {}", this.uid);
    }
    @Override
    public void onMessage(String s) {
        if(s.indexOf("heartbeat") >= 0){
            return;
        }
        logger.info("ws 收到消息:{}", s);
        try {
            DemoLoginResponse response = JsonUtils.jsonStringToObject(s, DemoLoginResponse.class);
            if(response.getProtocol().equals("login")){
                logger.info("websocket 登录成功:{}", response.getUid());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public void onClose(int i, String s, boolean b) {
        logger.warn("连接被关闭:code={}, reason={}, remote={}", i, s, b);
    }
    @Override
    public void onError(Exception e) {
        logger.error("连接错误:" + e.getMessage(), e);
    }
    public String getUid() {
        return uid;
    }
    public void setUid(String uid) {
        this.uid = uid;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    private String uid;
    private String userName;
}
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/WebsocketClientTest.java
New file
@@ -0,0 +1,100 @@
package com.iplatform.tcp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WebsocketClientTest {
    protected final transient Logger logger = LoggerFactory.getLogger(this.getClass());
//    private static final URI wsUri = URI.create("ws://127.0.0.1:60000/websocket");
//    private static final URI wsUri = URI.create("ws://116.198.40.76:60000/websocket");
//    private static final URI wsUri = URI.create("ws://10.8.4.35:60035/websocket");
//    private static final URI wsUri = URI.create("ws://www.shikeying.com:60001/websocket");
//    private static final URI wsUri = URI.create("ws://ctoms.chinapost.com.cn/ws/websocket");
    private static final URI wsUri = URI.create("ws://localhost:60000");
//    private static final URI wsUri = URI.create("ws://10.8.4.98:60011/websocket");
    private static Map<String, DemoWebsocketClient> cacheClient = new ConcurrentHashMap<>(32770);
    private ExecutorService executorService = Executors.newFixedThreadPool(4);
//    private static int currentSize = 20000;
    private static int currentSize = 1;
    private static final int TOTAL_LINES = 2;
//    private static final int TOTAL_LINES = 16;
//    private static final int BATCH_SIZE = 8;
    private static final int BATCH_SIZE = 2;
    public void createBatch(){
        logger.info(".........开始测试通信连接.......... TOTAL_LINES = {}, url = {}", TOTAL_LINES, wsUri);
        while(currentSize < TOTAL_LINES){
            try {
                this.executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        int count = BATCH_SIZE;
                        for(int i=0; i<count; i++){
                            String uri = "mike" + (currentSize);
                            DemoWebsocketClient client = createOneClient(wsUri, uri);
                            logger.info("创建了一个客户端: " + uri);
                            cacheClient.put(uri, client);
                            currentSize ++;
                        }
                    }
                });
            } catch (Exception ex){
                ex.printStackTrace();
            } finally {
                try {
                    logger.info("currentSize = {}", currentSize);
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        logger.info("已累计创建连接:{} 个", currentSize);
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
//        logger.info("准备关闭所有链接对象...");
//        for(DemoWebsocketClient client : cacheClient.values()){
//            client.close();
//        }
//        logger.info("执行了关闭操作,所有连接稍后会完全关闭");
    }
    private DemoWebsocketClient createOneClient(URI uri, String uid){
        DemoWebsocketClient client = new DemoWebsocketClient(uri);
        client.setUid(uid);
        client.setConnectionLostTimeout(0);
        try {
            client.connectBlocking();
        } catch (InterruptedException e) {
            throw new RuntimeException("创建client错误, uid=" + uid + ", " + e.getMessage(), e);
        }
        return client;
    }
//    public void createOneClient(){
//        DemoWebsocketClient client = new DemoWebsocketClient(wsUri);
//        client.setUid("mike");
//        try {
//            client.connectBlocking();
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
//        WaitConsoleInput.waitInput();
//    }
}
iplatform-base-tcp-client/src/test/java/com/iplatform/tcp/WebsocketDemo.java
New file
@@ -0,0 +1,22 @@
package com.iplatform.tcp;
import com.iplatform.tcp.util.ws.WebDataResponse;
import com.walker.infrastructure.utils.JsonUtils;
import com.walker.infrastructure.utils.NumberGenerator;
import org.junit.Test;
public class WebsocketDemo {
    @Test
    public void sendDataFormat(){
        WebDataResponse msg = new WebDataResponse();
        msg.setMessageId(NumberGenerator.getLongSequenceId());
        msg.setName("shikeying");    // 指定用户发送,该id与浏览器端注册的id保持一致。
        msg.setData("你好,这是推送给浏览器的内容,一般是JSON格式。");
        try {
            System.out.println(JsonUtils.objectToJsonString(msg));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
iplatform-base/src/main/java/com/iplatform/base/AbstractFileOperateSpiController.java
@@ -1,5 +1,6 @@
package com.iplatform.base;
import com.iplatform.base.config.FileProperties;
import com.iplatform.core.BeanContextAware;
import com.walker.file.FileInfo;
import com.walker.file.FileStoreType;
@@ -144,34 +145,47 @@
    protected FileInfo uploadFileToRemote(InputStream inputStream
            , String fileName, String groupId, long fileSize, Integer businessType, String owner) throws Exception{
        String remoteFileStoreType = this.getArgumentVariable(ArgumentsConstants.CONFIG_UPLOAD_TYPE).getStringValue();
        if(StringUtils.isEmpty(remoteFileStoreType)){
            throw new PlatformRuntimeException("平台未配置任何远程存储类别:" + ArgumentsConstants.CONFIG_UPLOAD_TYPE);
        }
        // 2023-07-03,如果配置远程上传为本地
        if(this.acquireFileOperateSpi().isRemoteAsLocal()){
            return this.acquireFileOperateSpi().uploadFileToLocal(inputStream, fileName, groupId, fileSize, businessType, owner);
        }
        FileStoreType fileStoreType = FileStoreType.getType(remoteFileStoreType);
//        String remoteFileStoreType = this.getArgumentVariable(ArgumentsConstants.CONFIG_UPLOAD_TYPE).getStringValue();
//        if(StringUtils.isEmpty(remoteFileStoreType)){
//            throw new PlatformRuntimeException("平台未配置任何远程存储类别:" + ArgumentsConstants.CONFIG_UPLOAD_TYPE);
//        }
//        FileStoreType fileStoreType = FileStoreType.getType(remoteFileStoreType);
        String ossType = BeanContextAware.getBeanByType(FileProperties.class).getOssType();
        if(StringUtils.isEmpty(ossType)){
            throw new PlatformRuntimeException("平台未配置任何ossType");
        }
        FileStoreType fileStoreType = FileStoreType.getType(ossType);
        if(fileStoreType == FileStoreType.Ftp){
            return this.acquireFileOperateSpi().uploadFileToFtp(inputStream, fileName, groupId, fileSize, businessType, owner);
        } else {
            return this.acquireFileOperateSpi().uploadFileToOss(inputStream, fileName, groupId, fileSize, businessType, owner, fileStoreType);
        }
    }
    protected FileInfo[] uploadFileToRemote(InputStream[] inputStream
            , String[] fileName, String groupId, long[] fileSize, Integer businessType, String owner) throws Exception{
        String remoteFileStoreType = this.getArgumentVariable(ArgumentsConstants.CONFIG_UPLOAD_TYPE).getStringValue();
        if(StringUtils.isEmpty(remoteFileStoreType)){
            throw new PlatformRuntimeException("平台未配置任何远程存储类别:" + ArgumentsConstants.CONFIG_UPLOAD_TYPE);
        }
//        String remoteFileStoreType = this.getArgumentVariable(ArgumentsConstants.CONFIG_UPLOAD_TYPE).getStringValue();
//        if(StringUtils.isEmpty(remoteFileStoreType)){
//            throw new PlatformRuntimeException("平台未配置任何远程存储类别:" + ArgumentsConstants.CONFIG_UPLOAD_TYPE);
//        }
//        FileStoreType fileStoreType = FileStoreType.getType(remoteFileStoreType);
        // 2023-07-03,如果配置远程上传为本地
        if(this.acquireFileOperateSpi().isRemoteAsLocal()){
            return this.acquireFileOperateSpi().uploadFileToLocal(inputStream, fileName, groupId, fileSize, businessType, owner);
        }
        FileStoreType fileStoreType = FileStoreType.getType(remoteFileStoreType);
        String ossType = BeanContextAware.getBeanByType(FileProperties.class).getOssType();
        if(StringUtils.isEmpty(ossType)){
            throw new PlatformRuntimeException("平台未配置任何ossType");
        }
        FileStoreType fileStoreType = FileStoreType.getType(ossType);
        if(fileStoreType == FileStoreType.Ftp){
            return this.acquireFileOperateSpi().uploadFileToFtp(inputStream, fileName, groupId, fileSize, businessType, owner);
        } else {
iplatform-base/src/main/java/com/iplatform/base/ArgumentsConstants.java
@@ -28,9 +28,15 @@
    /** 移动端域名 */
    public static final String CONFIG_KEY_SITE_URL = "site_url";
    /** 图片上传类型 1本地 2七牛云 3OSS 4COS, 默认本地
    /** 图片上传类型 1-本地 2-七牛云 3-阿里云OSS 4-腾讯OSS 5-亚马逊s3, 默认本地
     * <p>支持系统自己的定义常量,参考:{@linkplain com.walker.file.FileStoreType}</p>
     * <pre>
     *     1) 上传到本地,还是远程,业务选择,系统会配置远程ossType标识哪个平台。
     *     2) 对于文件是存储本地还是远程,通过:isRemoteAsLocal()方法判断,可以用在测试阶段。
     * </pre>
     *
     * */
    @Deprecated
    public static final String CONFIG_UPLOAD_TYPE = "uploadType";
    /** 全局本地图片域名 */
@@ -41,6 +47,8 @@
    public static final String CONFIG_AL_UPLOAD_URL = "alUploadUrl";
    /** 腾讯云上传URL */
    public static final String CONFIG_TX_UPLOAD_URL = "txUploadUrl";
    /** 亚马逊S3上传URL */
    public static final String CONFIG_S3_UPLOAD_URL = "s3UploadUrl";
    /** FTP上传URL */
    public static final String CONFIG_FTP_UPLOAD_URL = "ftpUploadUrl";
iplatform-base/src/main/java/com/iplatform/base/config/FileProperties.java
@@ -30,6 +30,79 @@
        this.remoteAsLocal = remoteAsLocal;
    }
    /**
     * oss实现类型:aws_s3(亚马逊) | tx(腾讯) | ali(阿里) | qn(七牛)
     * @return
     * @date 2023-12-13
     */
    public String getOssType() {
        return ossType;
    }
    public void setOssType(String ossType) {
        this.ossType = ossType;
    }
    /**
     * oss访问前缀,如:http://localhost:8082/admin/oss/
     * @return
     * @date 2023-12-13
     */
    public String getOssPrefix() {
        return ossPrefix;
    }
    public void setOssPrefix(String ossPrefix) {
        this.ossPrefix = ossPrefix;
    }
    public String getOssAccessKey() {
        return ossAccessKey;
    }
    public void setOssAccessKey(String ossAccessKey) {
        this.ossAccessKey = ossAccessKey;
    }
    public String getOssSecretKey() {
        return ossSecretKey;
    }
    public void setOssSecretKey(String ossSecretKey) {
        this.ossSecretKey = ossSecretKey;
    }
    public String getOssEndpoint() {
        return ossEndpoint;
    }
    public void setOssEndpoint(String ossEndpoint) {
        this.ossEndpoint = ossEndpoint;
    }
    public String getOssBucketName() {
        return ossBucketName;
    }
    public void setOssBucketName(String ossBucketName) {
        this.ossBucketName = ossBucketName;
    }
    public String getProtocolStr() {
        return protocolStr;
    }
    public void setProtocolStr(String protocolStr) {
        this.protocolStr = protocolStr;
    }
    private String ossAccessKey;
    private String ossSecretKey;
    private String ossEndpoint;
    private String ossBucketName;
    private String ossType;
    private String ossPrefix;
    private String protocolStr = "http";
    private boolean remoteAsLocal = true;
    private String fileRoot = null;
iplatform-file-server/pom.xml
@@ -39,6 +39,13 @@
            <scope>provided</scope>
        </dependency>
        <!-- 亚马逊S3 OSS 服务配置,2023-12-12 -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-s3</artifactId>
            <version>1.11.126</version>
        </dependency>
        <!--
        |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        |~ 以下配置为"独立部署方式",2023-02-12
iplatform-file-server/src/main/java/com/iplatform/file/FileEngineFactory.java
@@ -1,5 +1,6 @@
package com.iplatform.file;
import com.iplatform.base.PlatformRuntimeException;
import com.iplatform.file.util.FileStoreUtils;
import com.walker.file.FileInfo;
import com.walker.file.FileOperateEngine;
@@ -25,6 +26,21 @@
public class FileEngineFactory implements ApplicationBeanInitialized {
    protected final transient Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 下载oss文件
     * @param fileStoreType
     * @param id 文件唯一编号
     * @return
     * @date 2023-12-13
     */
    public byte[] downloadOssFile(FileStoreType fileStoreType, String id){
        try {
            return this.fileOperateEngineMap.get(fileStoreType).downloadFile(id);
        } catch (FileOperateException e) {
            throw new PlatformRuntimeException("下载oss文件错误:" + e.getMessage() + ", id=" + id, e);
        }
    }
    /**
     * 根据文件ID,返回文件对象。
@@ -142,7 +158,8 @@
    public FileInfo uploadFileToOss(InputStream inputStream, String fileName, String groupId
            , long fileSize, Integer businessType, String owner, FileStoreType fileStoreType) throws FileOperateException{
        if(fileStoreType != FileStoreType.OssQiNiu
                && fileStoreType != FileStoreType.OssTx && fileStoreType != FileStoreType.OssAli){
                && fileStoreType != FileStoreType.OssTx && fileStoreType != FileStoreType.OssAli
                && fileStoreType != FileStoreType.OssAws){
            throw new UnsupportedOperationException("不支持的OSS类型:" + fileStoreType);
        }
        if(this.remoteAsLocal){
@@ -155,7 +172,8 @@
    public FileInfo[] uploadFileToOss(InputStream[] inputStream, String[] fileName, String groupId
            , long[] fileSize, Integer businessType, String owner, FileStoreType fileStoreType) throws FileOperateException{
        if(fileStoreType != FileStoreType.OssQiNiu
                && fileStoreType != FileStoreType.OssTx && fileStoreType != FileStoreType.OssAli){
                && fileStoreType != FileStoreType.OssTx && fileStoreType != FileStoreType.OssAli
                && fileStoreType != FileStoreType.OssAws){
            throw new UnsupportedOperationException("不支持的OSS类型:" + fileStoreType);
        }
        if(this.remoteAsLocal){
iplatform-file-server/src/main/java/com/iplatform/file/config/FileConfig.java
@@ -1,11 +1,13 @@
package com.iplatform.file.config;
import com.iplatform.base.config.FileProperties;
import com.iplatform.core.PlatformConfiguration;
import com.iplatform.file.FileEngineFactory;
import com.iplatform.file.FileStoreCallback;
import com.iplatform.file.service.FileServiceImpl;
import com.iplatform.file.support.AliOssFileEngine;
import com.iplatform.file.support.AttachmentJdbcCallback;
import com.iplatform.file.support.AwsOssFileEngine;
import com.iplatform.file.support.DefaultFileSystemEngine;
import com.iplatform.file.support.DefaultFtpFileEngine;
import com.iplatform.file.support.QnOssFileEngine;
@@ -17,7 +19,7 @@
import org.springframework.context.annotation.Configuration;
@Configuration
public class FileConfig {
public class FileConfig extends PlatformConfiguration {
    /**
     * 配置一个文件引擎工厂对象。
@@ -30,6 +32,7 @@
    @Bean
    public FileEngineFactory fileEngineFactory(DefaultFtpFileEngine ftpFileEngine, DefaultFileSystemEngine fileSystemEngine
            , QnOssFileEngine qnOssFileEngine, TxOssFileEngine txOssFileEngine, AliOssFileEngine aliOssFileEngine
            , AwsOssFileEngine awsOssFileEngine
            , ArgumentsManager argumentsManager, FileProperties fileProperties){
        FileEngineFactory fileEngineFactory = new FileEngineFactory();
        fileEngineFactory.register(FileStoreType.Ftp, ftpFileEngine);
@@ -37,6 +40,9 @@
        fileEngineFactory.register(FileStoreType.OssQiNiu, qnOssFileEngine);
        fileEngineFactory.register(FileStoreType.OssTx, txOssFileEngine);
        fileEngineFactory.register(FileStoreType.OssAli, aliOssFileEngine);
        // 2023-12-13
        fileEngineFactory.register(FileStoreType.OssAws, awsOssFileEngine);
        fileEngineFactory.setArgumentsManager(argumentsManager);
        fileEngineFactory.setRemoteAsLocal(fileProperties.isRemoteAsLocal());
        fileEngineFactory.startup();
@@ -44,6 +50,28 @@
    }
    /**
     * 创建:OSS服务引擎。
     *
     * @param fileProperties
     * @param fileStoreCallback
     * @return
     * @date 2023-12-13
     */
    @Bean
    public AwsOssFileEngine awsOssFileEngine(FileProperties fileProperties, FileStoreCallback fileStoreCallback) throws Exception {
        AwsOssFileEngine engine = new AwsOssFileEngine();
        engine.setPrefix(fileProperties.getOssPrefix());
        engine.setFileStoreCallback(fileStoreCallback);
        engine.setAccessKey(fileProperties.getOssAccessKey());
        engine.setSecretKey(fileProperties.getOssSecretKey());
        engine.setEndpoint(fileProperties.getOssEndpoint());
        engine.setBucketName(fileProperties.getOssBucketName());
        engine.initS3Client();
        logger.info(".............. OSS 初始化: 亚马逊S3!");
        return engine;
    }
    /**
     * 阿里云 OSS 文件引擎定义。
     * @param fileProperties
     * @param fileStoreCallback
iplatform-file-server/src/main/java/com/iplatform/file/support/AbstractOssFileEngine.java
@@ -38,5 +38,19 @@
        this.fileStoreCallback = fileStoreCallback;
    }
    /**
     * 返回OSS访问前缀,通常在配置yaml文件中配置。
     * @return
     * @date 2023-12-13
     */
    public String getPrefix() {
        return prefix;
    }
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
    private String prefix;  // oss前缀,2023-12-13
    private FileStoreCallback fileStoreCallback = null;
}
iplatform-file-server/src/main/java/com/iplatform/file/support/AwsOssFileEngine.java
New file
@@ -0,0 +1,359 @@
package com.iplatform.file.support;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.policy.Policy;
import com.amazonaws.auth.policy.Principal;
import com.amazonaws.auth.policy.Resource;
import com.amazonaws.auth.policy.Statement;
import com.amazonaws.auth.policy.actions.S3Actions;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration;
import com.amazonaws.services.s3.model.CORSRule;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
import com.amazonaws.services.s3.model.SetBucketPolicyRequest;
import com.walker.file.DefaultFileInfo;
import com.walker.file.FileInfo;
import com.walker.file.FileOperateException;
import com.walker.file.FileStoreType;
import com.walker.infrastructure.utils.Base64;
import com.walker.infrastructure.utils.JsonUtils;
import com.walker.infrastructure.utils.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Calendar;
/**
 * 亚马逊S3 OSS 实现。
 *
 * @author 时克英
 * @date 2023-12-12
 */
public class AwsOssFileEngine extends AbstractOssFileEngine {
    public AwsOssFileEngine() {
    }
    @Override
    protected void executeUpload(InputStream inputStream, FileInfo fileInfo) throws FileOperateException {
        //初始化对象元数据
        ObjectMetadata metadata = new ObjectMetadata();
        // metadata.setContentType("plain/text");
        AmazonS3 client = this.acquireOneClient();
        try {
            String fileNameBase64 = new String(Base64.encode(fileInfo.getFileName().getBytes(StringUtils.DEFAULT_CHARSET_UTF8)));
            metadata.addUserMetadata("x-amz-meta-title", fileNameBase64);
            metadata.setContentLength(fileInfo.getFileSize());
            //设置对象元数据
            String objectKey = fileInfo.getId();
            logger.debug("准备上传文件 objectKey = {}", objectKey);
//            String objectKey = createFileOssPath(fileInfo.getId(), fileInfo.getFileExt());
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectKey, inputStream, metadata);
//            PutObjectResult result = amazonS3Client.putObject(putObjectRequest);
            PutObjectResult result = client.putObject(putObjectRequest);
            System.out.println(JsonUtils.objectToJsonString(result));
            StringBuilder url = new StringBuilder();
            url.append(objectKey);
//            ((DefaultFileInfo) fileInfo).setFileSize(result.getMetadata().getContentLength());
            ((DefaultFileInfo) fileInfo).setUrl(url.toString());
        } catch (Exception var11) {
            throw new FileOperateException("保存文件到【oss】错误:" + var11.getMessage() + ", id=" + fileInfo.getId(), var11);
        } finally {
            if(client != null){
                client.shutdown();
            }
        }
    }
    @Override
    protected byte[] executeDownload(FileInfo fileInfo) throws FileOperateException {
//        throw new IllegalAccessError("不能调用OSS下载方法,请访问第三方链接");
        AmazonS3 client = this.acquireOneClient();
        S3ObjectInputStream objectContent = null;
        ByteArrayOutputStream fileOutputStream = null;
        try {
            //下载对象
            S3Object object = client.getObject(bucketName, fileInfo.getId());
            //获取对象流
            objectContent = object.getObjectContent();
            //初始化文件输出流
//        FileOutputStream fileOutputStream = new FileOutputStream(new File(file_path));
            fileOutputStream = new ByteArrayOutputStream();
            byte[] readbuf = new byte[1024 * 20];
            int read_len = 0;
            while ((read_len = objectContent.read(readbuf)) > 0) {
                //对象下载字节写入文件输出流
                fileOutputStream.write(readbuf, 0, read_len);
            }
            return fileOutputStream.toByteArray();
        } catch (Exception ex) {
            throw new FileOperateException("下载文件错误:" + ex.getMessage() + ", fileId=" + fileInfo.getId(), ex);
        } finally {
            //关闭流
            try {
                if(objectContent != null){
                    objectContent.close();
                }
//                if(fileOutputStream != null){
//                    fileOutputStream.close();
//                }
                if(client != null){
                    client.shutdown();
                }
            } catch (IOException e) {
//                throw new RuntimeException(e);
                logger.error("这里不需要抛出异常,仅用于调试知道流没有被关闭即可。", e);
            }
        }
    }
    @Override
    public FileStoreType getFileStoreType() {
        return FileStoreType.OssAws;
    }
    @Override
    public void close() {
        super.close();
        this.closeAmazonS3Client();
    }
    private AmazonS3 acquireOneClient(){
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        ClientConfiguration clientConfiguration = new ClientConfiguration();
        if (endpoint.contains("https")) {
            clientConfiguration.setProtocol(Protocol.HTTPS);
            logger.error("===================>  HTTPS  ");
        } else {
            clientConfiguration.setProtocol(Protocol.HTTP);
            logger.error("===================>  HTTP  ");
        }
        return AmazonS3ClientBuilder.standard()
                .withClientConfiguration(clientConfiguration)
                .withEndpointConfiguration(
                        new AwsClientBuilder.EndpointConfiguration(this.endpoint, Regions.DEFAULT_REGION.getName()))
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .build();
//        AmazonS3 amazonS3Client = new AmazonS3Client(credentials, clientConfiguration);
//        amazonS3Client.setEndpoint(endpoint);
//        amazonS3Client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).disableChunkedEncoding().build());
//        return amazonS3Client;
    }
    /**
     * 初始化amazonS3Client
     * @author 时克英
     * @date 2024-02-02 使用多例,无需初始化,废弃方法。
     */
    @Deprecated
    public void initS3Client() {
        logger.warn("不再使用单例,无需初始化,每次上传下载会创建新客户端连接!");
//        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);   //创建AWS凭证
//        ClientConfiguration connconfig = new ClientConfiguration();            //初始化客户端config
//        connconfig.setProtocol(Protocol.HTTP);                                //设置mos 请求协议为http
//
//        //使用AWS凭证和clientConfiguration初始化AmazonS3Client客户端
//        amazonS3Client = new AmazonS3Client(credentials, connconfig);
//        amazonS3Client.setEndpoint(endpoint);                               ////设置mos对象服务接口地址
//        amazonS3Client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).disableChunkedEncoding().build());
//        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
//        ClientConfiguration clientConfiguration = new ClientConfiguration();
//
//        if (endpoint.contains("https")) {
//            clientConfiguration.setProtocol(Protocol.HTTPS);
//            logger.error("===================>  HTTPS  ");
//        } else {
//            clientConfiguration.setProtocol(Protocol.HTTP);
//            logger.error("===================>  HTTP  ");
//        }
//
//        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpoint, "beijing1");
//        AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
//
//
//        amazonS3Client = AmazonS3ClientBuilder.standard()
//                .withEndpointConfiguration(endpointConfiguration)
//                .withCredentials(credentialsProvider).build();
////        amazonS3Client = new AmazonS3Client(credentials, clientConfiguration);
////        amazonS3Client.setEndpoint(endpoint);
////        amazonS3Client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).disableChunkedEncoding().build());
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        ClientConfiguration clientConfiguration = new ClientConfiguration();
        if (endpoint.contains("https")) {
            clientConfiguration.setProtocol(Protocol.HTTPS);
            logger.error("===================>  HTTPS  ");
        } else {
            clientConfiguration.setProtocol(Protocol.HTTP);
            logger.error("===================>  HTTP  ");
        }
        // 设置允许打开的最大 HTTP 连接数,默认为 50 个,此示例代码设置为 100 个。
//        clientConfiguration.setMaxConnections(100 * 2);
//        // 设置 Socket 层传输数据的超时时间(单位:毫秒),默认为 50000 毫秒,此示例代码设置为 60000 毫秒。
//        clientConfiguration.setSocketTimeout(60000 * 2);
//        // 设置建立连接的超时时间(单位:毫秒),默认为 10000 毫秒,此示例代码设置为 5000 毫秒。
//        clientConfiguration.setConnectionTimeout(5000 * 2);
//        // 设置等待请求完成的超时时间(单位:毫秒)。默认不超时(0),此示例代码设置为 60000 毫秒。
//        clientConfiguration.setRequestTimeout(60000 * 2);
//        // 设置客户端请求执行超时时间(单位:毫秒)。默认不超时(0),此示例代码设置为 60000 毫秒。
//        clientConfiguration.setClientExecutionTimeout(60000 * 2);
//        // 设置连接空闲超时时间。超时则关闭连接,默认为 60000 毫秒,此示例代码设置为 90000 毫秒。
////        clientConfiguration.setConnectionMaxIdleMillis(90000 * 2);
//        // 设置请求失败后最大的重试次数,默认 3 次,此示例代码设置为 5 次。
//        clientConfiguration.setMaxErrorRetry(5);
        // 设置连接 EOS 所使用的协议(HTTP 或 HTTPS),默认为 HTTPS,此示例代码设置为 HTTP。
//        clientConfiguration.setProtocol(Protocol.HTTP);
        // 设置用户代理前缀,即 HTTP 的 User-Agent 头的前缀,此示例代码设置为 "EOS S3 Java SDK"。
//        clientConfiguration.setUserAgentPrefix("EOS S3 Java SDK");
        // 设置用户代理后缀,即 HTTP 的 User-Agent 头的后缀,此示例代码设置为 "1.12.378"。
//        clientConfiguration.setUserAgentSuffix("1.12.378");
        // 设置签名算法,默认为 v4 签名。此示例代码设置为 S3SignerType,即采用 v2 签名。
//        clientConfiguration.setSignerOverride("S3SignerType");
        // 2024-02-02,不用单例,使用多例即:每次调用创建客户端方式!
//        amazonS3Client = new AmazonS3Client(credentials, clientConfiguration);
//        amazonS3Client.setEndpoint(endpoint);
//        amazonS3Client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).disableChunkedEncoding().build());
    }
    /**
     * 对应MOS JAVA SDK文档4.3.6章节 设置存储桶策略
     */
    @Deprecated
    public void setBucketPolicy() throws IOException {
//        List<String> readLines = Files.readLines(new File("policy.txt"), Charset.forName("utf8"));
//        StringBuilder sb = new StringBuilder();
//        for(String str : readLines)
//        {
//            sb.append(str);
//        }
//        System.out.println(sb.toString());
//
//        //policy 信息查看项目根目录 policy.txt文件
//        String policy = sb.toString();
//        amazonS3Client.setBucketPolicy(bucket_name, policy);
        //通过Policy类构建桶策略
        Policy bucket_policy = new Policy().withStatements(new Statement(
                Statement.Effect.Allow)
                .withPrincipals(Principal.AllUsers)
                .withActions(S3Actions.GetObject)
                .withResources(
                        new Resource("arn:aws:s3:::" + bucketName + "/*")));
        SetBucketPolicyRequest setBucketPolicyRequest = new SetBucketPolicyRequest(bucketName, bucket_policy.toJson());
        //设置桶策略
//        amazonS3Client.setBucketPolicy(setBucketPolicyRequest);
    }
    @Deprecated
    public void configBucketCors() {
        // 配置跨域访问策略
        BucketCrossOriginConfiguration conf = new BucketCrossOriginConfiguration()
                .withRules(
                        new CORSRule()
                                .withId("1")// 配置规则 ID
                                .withAllowedHeaders(Arrays.asList("*")) // 跨域请求可以使用的 HTTP 请求头部,支持通配符 *
                                .withAllowedMethods(Arrays.asList(CORSRule.AllowedMethods.GET, CORSRule.AllowedMethods.PUT))// 跨域请求允许的 HTTP 操作,例如:GET,PUT,HEAD,POST,DELETE
//                                .withAllowedOrigins(Arrays.asList("http://www.example1.com"))// 允许的访问来源,支持通配符 *,格式为:协议://域名[:端口]
//                                .withMaxAgeSeconds(30)// 跨域请求得到结果的有效期
                );
//        SetBucketCrossOriginConfigurationRequest req = new SetBucketCrossOriginConfigurationRequest("bkt", conf);
//        amazonS3Client.setBucketCrossOriginConfiguration(req);
        // 删除跨域访问策略
//        amazonS3Client.deleteBucketCrossOriginConfiguration("1");
    }
    /**
     * 关闭amazonS3Client
     */
    private void closeAmazonS3Client() {
//        if (this.amazonS3Client != null) {
//            amazonS3Client.shutdown();  //关闭客户端
//        }
    }
    public byte[] testDownload(String fileId){
        DefaultFileInfo fileInfo = new DefaultFileInfo();
        fileInfo.setId(fileId);
        try {
            return this.executeDownload(fileInfo);
        } catch (FileOperateException e) {
            throw new RuntimeException("下载oss文件报错:" + e.getMessage() + ", fileId=" + fileId, e);
        }
    }
    public void setAccessKey(String accessKey) {
        this.accessKey = accessKey;
    }
    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }
    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }
    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }
    public void setProtocol(Protocol protocol) {
        this.protocol = protocol;
    }
    private String bucketName = "ctoms-file";
    public String endpoint = "http://10.2.36.9:8080";
    private String accessKey = "4XJOR8RXEWWRVV8N4HOC";
    private String secretKey = "1Dp2ua3lcCocEQJMf1VtHBABPfpkUxF4gGE3xacW";
    private Protocol protocol = Protocol.HTTP;
//    private AmazonS3 amazonS3Client;
    public String createFileOssPath(String fileId, String ext) {
        Calendar ca = Calendar.getInstance();
        String year = ca.get(Calendar.YEAR) + "";
        String mon = ca.get(Calendar.MONTH) + 1 + "";
        String day = ca.get(Calendar.DAY_OF_MONTH) + "";
        String directory = year + "/" + mon + "/" + day + "/";
//        mkdirFolder(directory);
        return fileId + StringUtils.SYMBOL_DOT + ext;
    }
    // 上传前上设置文件夹
    public boolean mkdirFolder(String directory) {
        AmazonS3 client = this.acquireOneClient();
        PutObjectResult putObjectResult = client.putObject(bucketName, directory, new ByteArrayInputStream(new byte[0]), null);
        return putObjectResult != null;
    }
}
iplatform-support-mybatis/pom.xml
@@ -48,6 +48,12 @@
            <artifactId>iplatform-core</artifactId>
        </dependency>
        <!-- 提供数据库jdbc支持,查询表元数据, 2024/02/20 -->
        <dependency>
            <groupId>com.walkersoft</groupId>
            <artifactId>walker-jdbc</artifactId>
        </dependency>
        <!--velocity代码生成使用模板 -->
<!--        <dependency>-->
<!--            <groupId>org.apache.velocity</groupId>-->
iplatform-support-mybatis/src/main/java/com/iplatform/mybatis/service/MetaDataServiceImpl.java
New file
@@ -0,0 +1,179 @@
package com.iplatform.mybatis.service;
import com.iplatform.mybatis.domain.GenTable;
import com.iplatform.mybatis.domain.GenTableColumn;
import com.iplatform.mybatis.util.DataTypeUtils;
import com.iplatform.mybatis.util.SqlUtils;
import com.walker.db.DatabaseType;
import com.walker.infrastructure.utils.DateUtils;
import com.walker.infrastructure.utils.StringUtils;
import com.walker.jdbc.JdbcInspector;
import com.walker.jdbc.service.BaseServiceImpl;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class MetaDataServiceImpl extends BaseServiceImpl {
    /**
     * 返回从元数据中查询的表结构信息
     * @param tableName 表名称,可以是表前缀
     * @param isPrecision 是否精确查找,如果是则仅返回和表名一样的表结构。
     * @param packageName 包名称,必填
     * @param moduleName 模块名称,选填
     * @param businessName 业务名称,选填
     * @param functionName 功能名称,选填
     * @return
     * @date 2024-02-20
     */
    public List<GenTable> queryDatabaseTableInfo(String tableName, boolean isPrecision
            , String packageName, String moduleName, String businessName, String functionName){
        List<GenTable> genTableList = new ArrayList<>(8);
        DatabaseType databaseType = JdbcInspector.getInstance().getPrimaryDatabaseType();
        log.debug("databaseType = " + databaseType.toString());
        if(DataTypeUtils.isOracle(databaseType)){
            // oracle元数据中表名都是大写
            tableName = tableName.toUpperCase();
        } else {
            tableName = tableName.toLowerCase();
        }
        Map<String, Object> sqlMap = new HashMap<>();
        if(isPrecision){
            sqlMap.put("tablename", "%" + tableName);
        } else {
            sqlMap.put("tablename", tableName + "%");
        }
        String sql_table = "";
//        String sql_pk = "";
        String sql_column = "";
        if (DataTypeUtils.isOracle(databaseType)) {
            sql_table = "select table_name from user_tables where table_name like :tablename order by table_name desc";
//            sql_pk = "select  col.table_name,col.column_name from user_constraints con,user_cons_columns col where con.constraint_name=col.constraint_name and con.constraint_type='P' and col.table_name like :tablename ";
            sql_column = SqlUtils.ORACLE_QUERY_COLUMNS;
        } else if(DataTypeUtils.isMysql(databaseType)) {
            sql_table = "select table_name from information_schema.tables where table_schema=(SELECT DATABASE()) and table_name like :tablename order by table_name desc";
//            sql_pk = "select table_name,column_name from INFORMATION_SCHEMA.Columns where column_key='PRI' AND table_schema=(SELECT DATABASE()) and table_name like :tablename";
            sql_column = "select table_name,column_name,data_type,NUMERIC_PRECISION data_precision,NUMERIC_SCALE data_scale, column_key from INFORMATION_SCHEMA.Columns where table_schema=(SELECT DATABASE()) and table_name like :tablename order by table_name,ordinal_position\n";
        } else if(databaseType == DatabaseType.POSTGRES){
            sql_table = "SELECT c.relname table_name from pg_class c, pg_namespace n  where c.relkind = 'r' and n.nspname = 'public' and c.relnamespace = n.oid and c.relname like :tablename";
            sql_column = SqlUtils.SQL_PG_FIELDS;
            log.debug("POSTGRES......");
        } else {
            throw new UnsupportedOperationException("(po生成)不支持的数据库类型:" + databaseType);
        }
        List<Map<String, Object>> table_list = this.dao.select(sql_table, sqlMap);
        List<Map<String, Object>> column_list = this.dao.select(sql_column, sqlMap);
        log.debug("生成表结构(PO) = {}", table_list);
        for (Map<String, Object> table : table_list) {
            String table_name = table.get("table_name").toString();
            String pk_name = "id";
            String pk_type = "NUMBER";
            List<Map<String, Object>> column_temp = new ArrayList<>();
            String columnKey = null;
            for (Map<String, Object> column : column_list) {
                if(!column.get("table_name").toString().equalsIgnoreCase(table.get("table_name").toString())){
                    // 只有当前表字段才处理,老代码遍历所有表字段有问题。2022-09-20
                    continue;
                }
                // 2022-09-07 修改(后续有oracle需求还需要改)
                if(column.get("column_key") != null){
                    columnKey = column.get("column_key").toString();
                    if(DataTypeUtils.isPrimaryColumn(columnKey)){
                        // mysql主键字段是:PRI,oracle是:P,2023-03-03 修改
                        pk_name = column.get("column_name").toString().toLowerCase();
                        pk_type = column.get("data_type").toString().toLowerCase();
                        log.info(table_name + " 找到主键:" + pk_name + ", " + pk_type);
                        continue;
                    }
                }
                if ((table_name.equalsIgnoreCase(column.get("table_name").toString())) && (!column.get("column_name").toString().equalsIgnoreCase(pk_name))) {
                    String type = column.get("data_type").toString().toLowerCase();
                    column.put("name", column.get("column_name").toString().toLowerCase());
                    if ((type.equalsIgnoreCase("number")) || (type.equalsIgnoreCase("decimal"))) {
                        int precision = Integer.valueOf(column.get("data_precision") == null ? "0" : column.get("data_precision").toString()).intValue();
                        int scale = Integer.valueOf(column.get("data_scale") == null ? "0" : column.get("data_scale").toString()).intValue();
                        type = DataTypeUtils.getType(type, precision, scale);
                    }
                    column.put("type", type);
                    column_temp.add(column);
                }
            }
            table.put("table_name", table_name.toLowerCase());
            table.put("pk_name", pk_name);
//            table.put("pk_type", pk_type);
            table.put("pk_type", DataTypeUtils.getType(pk_type, 0, 0));
            table.put("columns", column_temp);
            GenTable genTable = this.acquireGenTable(table, packageName, moduleName, businessName, functionName, pk_name);
            genTableList.add(genTable);
        }
        return genTableList;
    }
    private GenTable acquireGenTable(Map<String, Object> table
            , String packageName, String moduleName, String businessName, String functionName, String pkName){
        GenTable genTable = new GenTable();
        genTable.setCreateTime(DateUtils.getDateTimeNumber());
        genTable.setTableName(table.get("table_name").toString());
        genTable.setTableComment(StringUtils.EMPTY_STRING);
        genTable.setClassName(StringUtils.transferUnderlineName2Camel(genTable.getTableName(), true));
        genTable.setTplCategory("crud");
        genTable.setGenType("0");
        genTable.setFunctionAuthor("shikeying");
        genTable.setPackageName(packageName);
//        genTable.setGenPath("/");
        if(StringUtils.isNotEmpty(moduleName)){
            genTable.setModuleName(moduleName);
        }
        if(StringUtils.isNotEmpty(businessName)){
            genTable.setBusinessName(businessName);
        }
        if(StringUtils.isNotEmpty(functionName)){
            genTable.setFunctionName(functionName);
        }
        List<GenTableColumn> genTableColumnList = new ArrayList<>();
        List<Map<String, Object>> columns = (List<Map<String, Object>>)table.get("columns");
        GenTableColumn genTableColumn = null;
        boolean isPrimaryKey = false;
        for(Map<String, Object> map : columns){
            if(StringUtils.isNotEmpty(pkName) && map.get("column_name").toString().equals(pkName)){
                isPrimaryKey = true;
            }
            genTableColumn = this.acquireGenColumn(map, isPrimaryKey);
            if(isPrimaryKey){
                genTable.setPkColumn(genTableColumn);
            }
            genTableColumnList.add(genTableColumn);
        }
        genTable.setColumns(genTableColumnList);
        return genTable;
    }
    private GenTableColumn acquireGenColumn(Map<String, Object> map, boolean isPrimaryKey){
        GenTableColumn genTableColumn = new GenTableColumn();
        genTableColumn.setCreateTime(DateUtils.getDateTimeNumber());
        genTableColumn.setColumnName(map.get("column_name").toString());
        genTableColumn.setColumnType(map.get("type").toString());
        genTableColumn.setColumnComment(StringUtils.EMPTY_STRING);
        if(isPrimaryKey){
            genTableColumn.setIsPk("1");
        }
        genTableColumn.setJavaField(StringUtils.transferUnderlineName2Camel(genTableColumn.getColumnName(), true));
        return genTableColumn;
    }
}
iplatform-support-mybatis/src/main/java/com/iplatform/mybatis/util/DataTypeUtils.java
New file
@@ -0,0 +1,90 @@
package com.iplatform.mybatis.util;
import com.walker.db.DatabaseType;
public class DataTypeUtils {
    public static final String PRIMARY_KEY_MYSQL = "PRI";
    public static final String PRIMARY_KEY_ORACLE = "P";
    public static boolean isMysql(DatabaseType databaseType){
//        if (databaseType == DatabaseType.ORACLE || databaseType == DatabaseType.DAMENG) {
//            return false;
//        } else {
//            return true;
//        }
        return databaseType == DatabaseType.MYSQL || databaseType == DatabaseType.SQLITE;
    }
    public static boolean isOracle(DatabaseType databaseType){
        if (databaseType == DatabaseType.ORACLE || databaseType == DatabaseType.DAMENG) {
            return true;
        }
        return false;
    }
    public static boolean isPrimaryColumn(String columnKey){
        if(columnKey.equalsIgnoreCase(PRIMARY_KEY_MYSQL) || columnKey.equalsIgnoreCase(PRIMARY_KEY_ORACLE)){
            return true;
        }
        return false;
    }
    public static String getType(String type_name, int column_size, int decimal_digits) {
        if (type_name.contains("CHAR")
                || type_name.toLowerCase().indexOf("varchar") >= 0
                || type_name.equalsIgnoreCase("nvarchar2")
                // PG数据库字符串字段类型,2023-10-10
                || type_name.indexOf("character") >= 0)
            return "string";
        if (("NUMBER".equalsIgnoreCase(type_name)) || ("DECIMAL".equalsIgnoreCase(type_name))) {
            if (decimal_digits == 0) {
                if (column_size > 0 && column_size <= 8) {
                    return "int";
                }
                return "long";
            }
            if (column_size < 14) {
                return "double";
            }
            return "big_decimal";
        }
        // 2023-10-10 postgresql
        if(type_name.equalsIgnoreCase("integer")){
            if(column_size > 4){
                // 8 位表示长整形
                return "long";
            } else {
                return "int";
            }
        }
        if(type_name.indexOf("numeric") >= 0){
            return "double";
        }
        if (("DATE".equalsIgnoreCase(type_name)) || ("DATETIME".equalsIgnoreCase(type_name)) || (type_name.startsWith("TIMESTAMP")))
            return "date";
        if ("INT".equalsIgnoreCase(type_name))
            return "int";
        if (("Long".equalsIgnoreCase(type_name)) || ("BIGINT".equalsIgnoreCase(type_name)))
            return "long";
        if ("FLOAT".equalsIgnoreCase(type_name))
            return "float";
        if ("SMALLINT".equalsIgnoreCase(type_name))
            return "int";
        if ("TINYINT".equalsIgnoreCase(type_name))
            return "byte";
        if ("DOUBLE".equalsIgnoreCase(type_name) || type_name.indexOf("double") >= 0)
            return "double";
        if (("CLOB".equalsIgnoreCase(type_name)) || ("TEXT".equalsIgnoreCase(type_name)) || ("MEDIUMTEXT".equalsIgnoreCase(type_name)) || ("LONGTEXT".equalsIgnoreCase(type_name)))
//            return "materialized_clob";
            return "string";
        if (type_name.contains("BLOB")) {
            return "materialized_blob";
        }
        throw new RuntimeException("类型 " + type_name + " 不支持! ");
    }
}
iplatform-support-mybatis/src/main/java/com/iplatform/mybatis/util/SqlUtils.java
New file
@@ -0,0 +1,29 @@
package com.iplatform.mybatis.util;
public class SqlUtils {
    public static final String SQL_PG_FIELDS = "SELECT\n" +
            "\tC.relname table_name,\n" +
            "\tA.attname AS column_name, A.attlen data_precision,\n" +
            "\tformat_type ( A.atttypid, A.atttypmod ) AS data_type,\n" +
            "\tcol_description ( A.attrelid, A.attnum ) AS COMMENT, 0 AS data_scale,\n" +
            "(CASE WHEN ( SELECT COUNT(*) FROM pg_constraint WHERE conrelid = a.attrelid AND conkey[1]= attnum AND contype = 'p' ) > 0 THEN\n" +
            "        'PRI' ELSE '' \n" +
            "        END ) AS column_key\n" +
            "FROM\n" +
            "\tpg_class AS C,\n" +
            "\tpg_attribute AS A,\n" +
            "\tpg_tables AS B\n" +
            "WHERE A.attrelid = C.oid\n" +
            "  and C.relname=B.tablename\n" +
            "  AND A.attnum > 0\n" +
            "  AND B.schemaname = 'public' and c.relname like :tablename";
    public static final String ORACLE_QUERY_COLUMNS = new StringBuilder("select t1.*, ucc.constraint_name, uc.constraint_type column_key from (")
            .append("select c.table_name, c.column_name, c.data_type, c.data_length, c.data_precision, c.data_scale, c.nullable, c.column_id, s.comments ")
            .append("from user_tab_columns c, user_col_comments s ")
            .append("where c.table_name like :tablename and c.table_name = s.table_name and c.column_name = s.column_name order by c.column_id")
            .append(") t1 ")
            .append("left join user_cons_columns ucc on ucc.table_name=t1.table_name and ucc.column_name=t1.column_name ")
            .append("left join user_constraints uc on uc.constraint_name=ucc.constraint_name").toString();
}
iplatform-test-mybatis/pom.xml
New file
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>iplatform</artifactId>
        <groupId>com.iplatform</groupId>
        <version>2.7.18</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>iplatform-test-mybatis</artifactId>
    <name>iplatform-test-mybatis</name>
    <packaging>jar</packaging>
    <properties>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.iplatform</groupId>
            <artifactId>iplatform-support-mybatis</artifactId>
        </dependency>
    </dependencies>
</project>
iplatform-test-mybatis/src/main/java/com/iplatform/test/Test1.java
New file
@@ -0,0 +1,4 @@
package com.iplatform.test;
public class Test1 {
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/controller/EbUserController.java
New file
@@ -0,0 +1,107 @@
package com.iplatform.test.controller;
import java.util.List;
import java.util.Arrays;
import com.insurance.common.annotation.RepeatSubmit;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.insurance.common.annotation.Log;
import com.insurance.common.core.controller.BaseController;
import com.insurance.common.core.domain.AjaxResult;
import com.insurance.common.enums.BusinessType;
import com.iplatform.test.domain.vo.EbUserVo;
import com.iplatform.test.domain.bo.EbUserBo;
import com.iplatform.test.domain.bo.EbUserQueryBo;
import com.iplatform.test.service.IEbUserService;
import com.insurance.common.utils.poi.ExcelUtil;
import com.insurance.common.core.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
 * 【请填写功能名称】Controller
 *
 * @author shikeying
 * @date 2024-02-20
 */
@Api(value = "【请填写功能名称】控制器", tags = {"【请填写功能名称】管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/${moduleName}/${businessName}")
public class EbUserController extends BaseController {
    private final IEbUserService iEbUserService;
    @ApiOperation("查询【请填写功能名称】列表")
    @GetMapping("/list")
    public TableDataInfo list(EbUserQueryBo bo)
    {
        startPage();
        List<EbUserVo> list = iEbUserService.queryList(bo);
        return getDataTable(list);
    }
    @ApiOperation("导出【请填写功能名称】列表")
    //@PreAuthorize("@ss.hasPermi('null:null:export')")
    @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT)
    @GetMapping("/export")
    @RepeatSubmit
    public AjaxResult export(EbUserQueryBo bo)
    {
        List<EbUserVo> list = iEbUserService.queryList(bo);
        ExcelUtil<EbUserVo> util = new ExcelUtil<EbUserVo>(EbUserVo.class);
        return util.exportExcel(list, "【请填写功能名称】");
    }
    @ApiOperation("获取【请填写功能名称】详细信息")
    @GetMapping("/{${pkColumn.javaField}}")
    public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}" ) ${pkColumn.javaType} ${pkColumn.javaField})
    {
        return AjaxResult.success(iEbUserService.queryById(${pkColumn.javaField}));
    }
    @ApiOperation("新增【请填写功能名称】")
    //@PreAuthorize("@ss.hasPermi('null:null:add')")
    @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @RepeatSubmit
    public AjaxResult add(@RequestBody EbUserBo bo)
    {
        return toAjax(iEbUserService.insertByBo(bo) ? 1 : 0);
    }
    @ApiOperation("修改【请填写功能名称】")
    //@PreAuthorize("@ss.hasPermi('null:null:edit')")
    @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE)
    @PostMapping("/upd")
    @RepeatSubmit
    public AjaxResult upd(@RequestBody EbUserBo bo)
    {
        return toAjax(iEbUserService.updateByBo(bo) ? 1 : 0);
    }
    @ApiOperation("删除【请填写功能名称】")
    //@PreAuthorize("@ss.hasPermi('null:null:remove')")
    @Log(title = "【请填写功能名称】" , businessType = BusinessType.DELETE)
    @DeleteMapping("/{${pkColumn.javaField}s}")
    @RepeatSubmit
    public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
    {
        return toAjax(iEbUserService.deleteByIds(Arrays.asList(${pkColumn.javaField}s)) ? 1 : 0);
    }
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/EbUser.java
New file
@@ -0,0 +1,158 @@
package com.iplatform.test.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
//import io.swagger.annotations.ApiModel;
//import io.swagger.annotations.ApiModelProperty;
/**
 * 【请填写功能名称】对象 eb_user
 *
 * @author shikeying
 * @date 2024-02-20
 */
@Data
@NoArgsConstructor
@Accessors(chain = true)
@TableName("eb_user")
//@ApiModel("【请填写功能名称】实体对象")
public class EbUser implements Serializable {
    private static final long serialVersionUID=1L;
    @ApiModelProperty("")
    private $column.javaType Account;
    @ApiModelProperty("")
    private $column.javaType Pwd;
    @ApiModelProperty("")
    private $column.javaType RealName;
    @ApiModelProperty("")
    private $column.javaType Birthday;
    @ApiModelProperty("")
    private $column.javaType IdentityCardNo;
    @ApiModelProperty("")
    private $column.javaType TagId;
    @ApiModelProperty("")
    private $column.javaType Nickname;
    @ApiModelProperty("")
    private $column.javaType Avatar;
    @ApiModelProperty("")
    private $column.javaType Phone;
    @ApiModelProperty("")
    private $column.javaType Country;
    @ApiModelProperty("")
    private $column.javaType Province;
    @ApiModelProperty("")
    private $column.javaType City;
    @ApiModelProperty("")
    private $column.javaType District;
    @ApiModelProperty("")
    private $column.javaType Address;
    @ApiModelProperty("")
    private $column.javaType Sex;
    @ApiModelProperty("")
    private $column.javaType Integral;
    @ApiModelProperty("")
    private $column.javaType Experience;
    @ApiModelProperty("")
    private $column.javaType NowMoney;
    @ApiModelProperty("")
    private $column.javaType BrokeragePrice;
    @ApiModelProperty("")
    private $column.javaType Level;
    @ApiModelProperty("")
    private $column.javaType SignNum;
    @ApiModelProperty("")
    private $column.javaType IsWechatPublic;
    @ApiModelProperty("")
    private $column.javaType IsWechatRoutine;
    @ApiModelProperty("")
    private $column.javaType PayCount;
    @ApiModelProperty("")
    private $column.javaType IsPromoter;
    @ApiModelProperty("")
    private $column.javaType PromoterTime;
    @ApiModelProperty("")
    private $column.javaType SpreadUid;
    @ApiModelProperty("")
    private $column.javaType SpreadTime;
    @ApiModelProperty("")
    private $column.javaType SpreadCount;
    @ApiModelProperty("")
    private $column.javaType RegisterType;
    @ApiModelProperty("")
    private $column.javaType AddIp;
    @ApiModelProperty("")
    private $column.javaType LastIp;
    @ApiModelProperty("")
    private $column.javaType LastLoginTime;
    @ApiModelProperty("")
    private $column.javaType Status;
    @ApiModelProperty("")
    private $column.javaType Mark;
    @ApiModelProperty("")
    private $column.javaType CreateTime;
    @ApiModelProperty("")
    private $column.javaType UpdateTime;
    @ApiModelProperty("")
    private $column.javaType IsLogoff;
    @ApiModelProperty("")
    private $column.javaType LogoffTime;
    @ApiModelProperty("")
    private $column.javaType IsWechatIos;
    @ApiModelProperty("")
    private $column.javaType IsWechatAndroid;
    @ApiModelProperty("")
    private $column.javaType IsBindingIos;
    @ApiModelProperty("")
    private $column.javaType MoneySign;
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/bo/EbUserBo.java
New file
@@ -0,0 +1,20 @@
package com.iplatform.test.domain.bo;
//import io.swagger.annotations.ApiModel;
//import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
/**
 * 【请填写功能名称】编辑对象 eb_user
 *
 * @author shikeying
 * @date 2024-02-20
 */
@Data
//@ApiModel("【请填写功能名称】操作对象")
public class EbUserBo {
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/bo/EbUserQueryBo.java
New file
@@ -0,0 +1,36 @@
package com.iplatform.test.domain.bo;
import com.insurance.common.core.domain.BaseQuery;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 【请填写功能名称】分页查询对象 eb_user
 *
 * @author shikeying
 * @date 2024-02-20
 */
@EqualsAndHashCode(callSuper = true)
@Data
//@ApiModel("【请填写功能名称】分页查询对象")
public class EbUserQueryBo extends BaseQuery{
    /** 分页大小 */
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    /** 当前页数 */
    @ApiModelProperty("当前页数")
    private Integer pageNum;
    /** 排序列 */
    @ApiModelProperty("排序列")
    private String orderByColumn;
    /** 排序的方向desc或者asc */
    @ApiModelProperty(value = "排序的方向", example = "asc,desc")
    private String isAsc;
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/domain/vo/EbUserVo.java
New file
@@ -0,0 +1,25 @@
package com.iplatform.test.domain.vo;
import com.iplatform.mybatis.Excel;
import com.fasterxml.jackson.annotation.JsonFormat;
//import io.swagger.annotations.ApiModel;
//import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * 【请填写功能名称】视图对象 mall_package
 *
 * @author shikeying
 * @date 2024-02-20
 */
@Data
//@ApiModel("【请填写功能名称】视图对象")
public class EbUserVo {
    private static final long serialVersionUID = 1L;
    /** $pkColumn.columnComment */
    //@ApiModelProperty("$pkColumn.columnComment")
    private ${pkColumn.javaType} ${pkColumn.javaField};
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/mapper/EbUserMapper.java
New file
@@ -0,0 +1,14 @@
package com.iplatform.test.mapper;
import com.iplatform.test.domain.EbUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
 * 【请填写功能名称】Mapper接口
 *
 * @author shikeying
 * @date 2024-02-20
 */
public interface EbUserMapper extends BaseMapper<EbUser> {
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/service/IEbUserService.java
New file
@@ -0,0 +1,53 @@
package com.iplatform.test.service;
import com.iplatform.test.domain.EbUser;
import com.iplatform.test.domain.vo.EbUserVo;
import com.iplatform.test.domain.bo.EbUserBo;
import com.iplatform.test.domain.bo.EbUserQueryBo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.iplatform.mybatis.IBaseService;
import java.util.Collection;
import java.util.List;
/**
 * 【请填写功能名称】Service接口
 *
 * @author shikeying
 * @date 2024-02-20
 */
public interface IEbUserService extends IBaseService<EbUser> {
    /**
     * 查询列表
     */
    List<EbUserVo> queryList(EbUserQueryBo bo);
    /**
     * 查询单个
     * @return  EbUserVo
     */
    EbUserVo queryById(${pkColumn.javaType} ${pkColumn.javaField});
    /**
     * 根据新增业务对象插入【请填写功能名称】
     * @param bo 【请填写功能名称】新增业务对象
     * @return  true成功 false失败
     */
    Boolean insertByBo(EbUserBo bo);
    /**
     * 根据编辑业务对象修改【请填写功能名称】
     * @param bo 【请填写功能名称】编辑业务对象
     * @return  true成功 false失败
     */
    Boolean updateByBo(EbUserBo bo);
    /**
     * 校验并删除数据
     * @param ids 主键集合
     * @return  true成功 false失败
     */
    Boolean deleteByIds(Collection<Long> ids);
}
iplatform-test-mybatis/src/main/java/com/iplatform/test/service/impl/EbUserServiceImpl.java
New file
@@ -0,0 +1,100 @@
package com.iplatform.test.service.impl;
import lombok.RequiredArgsConstructor;
import cn.hutool.core.convert.Convert;
import com.iplatform.core.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.iplatform.test.domain.vo.EbUserVo;
import com.iplatform.test.domain.bo.EbUserBo;
import com.iplatform.test.domain.bo.EbUserQueryBo;
import com.iplatform.test.domain.EbUser;
import com.iplatform.test.mapper.EbUserMapper;
import com.iplatform.test.service.IEbUserService;
import java.util.Collection;
import java.util.List;
/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author shikeying
 * @date 2024-02-20
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class EbUserServiceImpl extends ServiceImpl<EbUserMapper, EbUser> implements IEbUserService {
    @Override//列表查询
    public List<EbUserVo> queryList(EbUserQueryBo bo)
    {
        QueryWrapper<EbUser> qw = getQw(bo);
        List<EbUser> list = this.list(qw);
        return Convert.toList(EbUserVo.class , list);
    }
    @Override//id查询
    public EbUserVo queryById(${pkColumn.javaType} ${pkColumn.javaField})
    {
        EbUser db = this.baseMapper.selectById(${pkColumn.javaField});
        return Convert.convert(EbUserVo.class , db);
    }
    @Override//添加
    @Transactional
    public Boolean insertByBo(EbUserBo bo)
    {
        EbUser add = Convert.convert(EbUser.class, bo);
        validEntityBeforeSave(add);
        return this.save(add);
    }
    @Override//修改
    @Transactional
    public Boolean updateByBo(EbUserBo bo)
    {
        EbUser update = Convert.convert(EbUser.class, bo);
        validEntityBeforeSave(update);
        return this.updateById(update);
    }
    @Override//删除
    @Transactional
    public Boolean deleteByIds(Collection<Long> ids)
    {
        //做一些业务上的校验,判断是否需要校验
        return this.removeByIds(ids);
    }
//-------------------------------------------------------------------------------------
    //保存前校验
    private void validEntityBeforeSave(EbUser entity)
    {
        //做一些数据校验,如唯一约束
    }
    //获取查询参数
    private QueryWrapper<EbUser> getQw(EbUserQueryBo bo)
    {
        QueryWrapper<EbUser> qw = Wrappers.query();
        if (StringUtils.isNotEmpty(bo.getIsAsc()) && StringUtils.isNotEmpty(bo.getOrderByColumn())){
            if ("acs".equals(bo.getIsAsc())) {
                qw.orderByAsc(bo.getOrderByColumn());
            } else if ("desc".equals(bo.getIsAsc())) {
                qw.orderByDesc(bo.getOrderByColumn());
            }
        }
        return qw;
    }
}
iplatform-test-mybatis/src/test/java/com/iplatform/AppTest.java
New file
@@ -0,0 +1,20 @@
package com.iplatform;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
 * Unit test for simple App.
 */
public class AppTest
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        assertTrue( true );
    }
}
pom.xml
@@ -27,6 +27,7 @@
    <module>ishop-mobile</module>
      <module>iplatform-base-tcp-client</module>
    <module>iplatform-support-mybatis</module>
      <module>iplatform-test-mybatis</module>
  </modules>
  <parent>
@@ -221,6 +222,13 @@
        <version>${iplatform.version}</version>
      </dependency>
      <!-- mybatis示例模块,2024-02-19 -->
      <dependency>
        <groupId>com.iplatform</groupId>
        <artifactId>iplatform-test-mybatis</artifactId>
        <version>${iplatform.version}</version>
      </dependency>
      <!-- 推送实现模块,2023-04-24 -->
      <dependency>
        <groupId>com.walkersoft</groupId>