# utils **Repository Path**: project_24/utils ## Basic Information - **Project Name**: utils - **Description**: 11111111111111111111111111 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-09 - **Last Updated**: 2024-10-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # linux ## 命令 ```shell # 查看日志 tail -f -n 1000 log/a.log #查询java进程 ps -ef|grep java # 杀死进程 kill -9 java ``` ## 服务器部署流程 ```shell docker安装 安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 设置阿里云镜像源 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 安装docker yum -y install docker-ce -y表示不询问安装,直到安装成功,安装完后再次查看安装列表 自启 systemctl enable docker 启动docker systemctl start docker mysql安装 docker run --name mysql -p 3306:3306 --restart=always -v /usr/local/docker/mysql/conf:/etc/mysql/conf.d -v /usr/local/docker/mysql/logs:/var/log/mysql -v /usr/local/docker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=Sh2024# -d mysql:8.0 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci docker run --name mysql5.7 -p 3306:3306 -v C:/docker/mysql/conf:/etc/mysql/conf.d -v C:/docker/mysql/data:/var/lib/mysql -v C:/docker/mysql/log:/var/log/mysql -e MYSQL_ROOT_PASSWORD=root --restart=always -d mysql:5.7 docker run --name mysql5.7 -p 3306:3306 -v /home/docker1/mysql/conf:/etc/mysql/conf.d -v /home/docker1/mysql/data:/var/lib/mysql -v /home/docker1/mysql/log:/var/log/mysql -e MYSQL_ROOT_PASSWORD=Sh2024# --restart=always -d mysql:5.7 redis安装 docker run -d --name redis -p 6379:6379 --restart=always redis --requirepass root nginx安装 docker pull nginx docker run -d --name nginx -p 80:80 -p 443:443 --net=mes5_bridge --restart=always -v /opt/bim/mes5/docker/nginx/conf.d:/etc/nginx/conf.d -v /opt/bim/mes5/docker/nginx/cert:/etc/nginx/cert -v /opt/bim/mes5/docker/nginx/log:/var/log/nginx -v /opt/bim/mes5/docker/nginx/www:/usr/share/nginx/html nginx nginx 安装 yum install -y nginx systemctl start nginx # 开机自启 chkconfig nginx on jdk安装 yum install -y java-1.8.0-openjdk-devel.x86_64 # redis 安装 yum install -y redis # redis启动 systemctl start redis # 开机自启 chkconfig redis on nacos 安装 docker run --privileged --restart=always -d -p 8848:8848 -p 9848:9848 -p 9849:9849 -e MODE=standalone -e MYSQL_SERVICE_HOST=192.168.35.36 -e MYSQL_SERVICE_DB_NAME=ry-config -e MYSQL_SERVICE_USER=root -e MYSQL_SERVICE_PASSWORD=Sh2024# -v /home/docker1/nacos/logs:/home/nacos/logs --name nacos nacos/nacos-server:v2.1.0 sqlserver 安装 docker run -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=root' --name qtsqlserver -p 1433:1433 -v /docker1/docker1/mssql:/var/opt/mssql -d mcr.microsoft.com/mssql/server:2017-latest --restart=always ``` ## 防火墙操作 ```shell # 查看防火墙状态 firewall-cmd --state # 查看已经开放的端口 firewall-cmd --list-ports # 查看指定端口是否开放 firewall-cmd --query-port=8848/tcp # 放行一个端口 firewall-cmd --zone=public --add-port=443/tcp --permanent # 重载刷新防火墙配置 firewall-cmd --reload # 重启防火墙 systemctl restart firewalld.service ``` # nginx ## 命令 ```shell # linux ## 启动 systemctl restart nginx systemctl reload nginx # window ## 启动 start nginx nginx.exe ## 停止 nginx.exe -s stop nginx.exe -s quit ## 重启 nginx.exe -s reload ## 重新打开日志 nginx.exe -s reopen ``` ## 配置文件 ```nginx server { listen 9094; server_name localhost; # https配置参考 start #listen 443 ssl; # 证书直接存放 /docker/nginx/cert/ 目录下即可 更改证书名称即可 无需更改证书路径 #ssl on; #ssl_certificate /etc/nginx/cert/xxx.local.crt; # /etc/nginx/cert/ 为docker映射路径 不允许更改 #ssl_certificate_key /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 为docker映射路径 不允许更改 #ssl_session_timeout 5m; #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #ssl_prefer_server_ciphers on; # https配置参考 end # 演示环境配置 拦截除 GET POST 之外的所有请求 # if ($request_method !~* GET|POST) { # rewrite ^/(.*)$ /403; # } # location = /403 { # default_type application/json; # return 200 '{"msg":"演示模式,不允许操作","code":500}'; # } # 限制外网访问内网 actuator 相关路径 location ~ ^(/[^/]*)?/actuator(/.*)?$ { return 403; } location / { root /usr/www/zj-mes/dist; try_files $uri $uri/ /index.html; index index.html index.htm; } location /uploadFile/ { alias /usr/www/zj-mes/uploadFile/; try_files $uri $uri/ /index.html; index index.html index.htm; } location /prod-api/ { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:8094/; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } ``` ## 解决413Request Entity Too Large(请求实体太大) ``` 在http{}中加入 client_max_body_size 10m; ``` # Redis ## Windows设置开机自启 ```shell 从 Redis 的安装目录进入 cmd redis-server --service-install redis.windows.conf --loglevel verbose // 安装redis服务 redis-server --service-start // 启动服务 redis-server --service-stop // 停止服务 ``` # docker ## 启动报错 ```shell netsh winsock reset ``` ## 安装 ```sh # 安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 # 设置阿里云镜像源 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # docker-ce安装 yum install -y docker-ce # 启动docker并设置开机自启 #启动docker命令 systemctl start docker #设置开机自启命令 systemctl enable docker #查看docker版本命令 docker version # 下载docker-compose sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 授予权限 sudo chmod +x /usr/local/bin/docker-compose # 测试安装结果 docker-compose --version ``` ## 禅道部署 ```sh docker run -d --restart=always -p 8183:80 -p 8184:3306 -e USER="admin" -e PASSWD="123456" -e BIND_ADDRESS="false" -v /home/docker/zentao/:/opt/zbox/ --name zentao idoop/zentao:latest ``` # Docker compose ## 安装 1. 下载地址:https://github.com/docker/compose/releases 2. 安装地址:/usr/local/bin/docker-compose 3. 设置为可执行:sudo chmod +x /usr/local/bin/docker-compose 4. 测试是否安装成功:docker-compose --version ## 安装命令补全工具 sudo curl -L https://raw.githubusercontent.com/docker/compose/1.22.0/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose ## 常用命令 - 构建、创建、启动相关容器:docker-compose up - 列出所有容器:docker-compose ps - 删除指定服务的容器:docker-compose rm eureka - 对容器进行动态扩容:docker-compose scale eureka=3 - 停止相关容器:docker-compose stop eureka - 启动相关容器:docker-compose start eureka ## 编排SpringCloud微服务 ### 所使用到的工程 - eureka-server - hello-service - feign-consumer - api-gateway ### 编排模式 1. 编排SpringCloud微服务:见eureka-server/docker-res/docker-compose.yml 2. 简化SpringCloud微服务编排:见eureka-server/docker-res/docker-compose-simple.yml 3. 编排高可用的注册中心:见eureka-server/docker-res/docker-compose-eureka.yml # Java ## 编码重复校验 ```java /** * 保存前的数据校验 */ private void validEntityBeforeSave(ProductRouteBo entity) { ProductRoute productRoute = this.getByCode(entity.getCode()); if (entity.getId() == null) { Assert.isNull(productRoute, "工艺流程编码【{}】重复", entity.getCode()); } else { if (productRoute != null && !Objects.equals(productRoute.getId(), entity.getId())) { Assert.isTrue(false, "工艺流程编码【{}】重复", entity.getCode()); } } Map processMap = entity.getProcessList().stream().collect(Collectors.groupingBy(RouteProcessLinkBo::getProcessCode, Collectors.counting())); processMap.forEach((processCode, count) -> { Assert.isTrue(count == 1, "工序编码【{}】重复", processCode); }); } ``` ## BigDecimal求和 ```java BigDecimal totalOutput = outputList.stream().map(MesOutputDayReport::getOutput) .reduce(BigDecimal.ZERO, BigDecimal::add); ``` ## 根据创建SQL解析字段 ```java private static void getInfo(String a) { String[] split = a.split("\n"); for (String s : split) { int i1 = s.indexOf("`"); int i2 = s.indexOf("`", i1 + 1); String b = s.substring(i1 + 1, i2); int i3 = s.indexOf("COMMENT"); int i4 = s.indexOf("'", i3 + 1); int i5 = s.indexOf("'", i4 + 1); if (i4 > 0) { String c = s.substring(i4 + 1, i5); System.out.println(b + "\t\t" + c); } else { System.out.println(b); } } } ``` ## 分页超1000处理 ```java package com.liyu.sewing.common.utils; import java.util.List; import java.util.stream.Collectors; /** * 对数据集合进分页获取 * * @author liyu * @date 2023/8/8 */ public class PagingList { /** * 每页默认大小 */ private static final int DEFAULT_PAGE_SIZE = 500; /** * 总页数 */ private int totalPage = 0; /** * 当前是第几页 */ private int curPageNo = 0; /** * 每页的大小 */ private int pageSize = 0; private List pageData = null; public PagingList(List pageResult, int pageSize) { this.pageSize = pageSize; this.pageData = pageResult; init(pageResult, pageSize); } public PagingList(List pageResult) { this(pageResult, DEFAULT_PAGE_SIZE); } private void init(List pageResult, int pageSize) { if (pageSize <= 0) { throw new IllegalArgumentException("Paging size must be greater than zero."); } if (null == pageResult) { throw new NullPointerException("Paging resource list must be not null."); } if (pageResult.size() % pageSize > 0) { this.totalPage = (pageResult.size() / pageSize) + 1; } else { this.totalPage = pageResult.size() / pageSize; } } /** * 返回当前剩余页数 * * @return */ private int getSurplusPage() { if (pageData.size() % pageSize > 0) { return (pageData.size() / pageSize) + 1; } else { return pageData.size() / pageSize; } } /** * 返回是否还有下一页数据 * * @return */ public boolean hasNext() { return pageData.size() > 0; } /** * 获取分页后,总的页数 * * @return */ public int getTotalPage() { return totalPage; } public List next() { List pagingData = pageData.stream().limit(pageSize).collect(Collectors.toList()); pageData = pageData.stream().skip(pageSize).collect(Collectors.toList()); return pagingData; } /** * 返回当前页数 * * @return */ public int getCurPageNo() { return totalPage - getSurplusPage(); } } ``` ```java List details = new ArrayList<>(); PagingList pagingList = new PagingList<>(ids, 500); while (pagingList.hasNext()) { List next = pagingList.next(); details.addAll(baseMapper.selectBatchIds(next)); } import com.google.common.collect.Lists; List> lists=Lists.partition(numList,3); ``` ## stream流分组生成有序列表 ```java Map> dayReportMap = dayReports.stream().collect(Collectors.groupingBy(MesOutputDayReport::getDeviceCode,LinkedHashMap::new,Collectors.toCollection(ArrayList::new))); ``` ## 【Spring Boot|MyBatis Plus】解决Oracle报错:无效的列类型1111 在Spring Boot 的 **application.yml** 配置文件中加上一句这样的配置 ```java mybatis-plus: configuration: jdbc-type-for-null: 'null' ``` ## springboot 按月分表的优雅实现方式 [springboot 按月分表的优雅实现方式_springboot 根据月份分表-CSDN博客](https://blog.csdn.net/Martin_chen2/article/details/122491174) ## SpringBoot配置文件中数据库密码加密两种方案 ### 1)引入maven依赖 ```xml com.github.ulisesbocchio jasypt-spring-boot-starter 2.1.1 ``` ### 2)在配置文件application ```yml #jasypt加密的盐值 jasypt.encryptor.password=erp ``` ### 3)测试用例中生成加密后的密匙 ```java @Autowired StringEncryptor encryptor; @Test public void getPass() { String url = encryptor.encrypt("jdbc:mysql://127.0.0.1:3306/erp-framework?useUnicode=true&characterEncoding=utf8"); String name = encryptor.encrypt("root"); String password = encryptor.encrypt("mysql"); System.out.println(url+"----------------"); System.out.println(name+"----------------"); System.out.println(password+"----------------"); Assert.assertTrue(name.length() > 0); Assert.assertTrue(password.length() > 0); } ``` 执行后,会生成: ``` BA9uZ35umFic6NbuaLdGzZBodw/wSqvztMt9UGdlOtxxs/fr/W5kf8Bs6GzzHklNfkcU30g8aQ/XdihsZtqRz1J34zNIQxuH3BCG1kknFayp13G8RhkeF4ptBfx6i6nqnP4Uc0UKpjcsxxfTZImHBVvcTY0RDANk26IGBPZvQry7qKuna/RTMQ== kyMvAncHqzcvGAildsK67w== 7QCSL5/HKjxFQRPLGgGH7kAElrmf/mgQ ``` 4)将上面的生成的密匙如下替换,此处主要是数据库密码 密文使用ENC进行标识 ```yml first.spring.datasource.password=ENC(7QCSL5/HKjxFQRPLGgGH7kAElrmf/mgQ) ``` # git ## 代码迁移 ```shell 1. 打开命令行工具 2. 以 bare 的方式克隆老的仓库 git clone --bare https://github.com/exampleuser/old-repository.git 3. 镜像 push 到新的仓库地址 cd old-repository.git git push --mirror https://github.com/exampleuser/new-repository.git 4. 在电脑中删掉老得仓库,把新的仓库重新拉下来 cd .. rm -rf old-repository.git ``` ## Git 常用命令 ### 仓库 ``` # 在当前目录新建一个Git代码库 $ git init # 新建一个目录,将其初始化为Git代码库 $ git init [project-name] # 下载一个项目和它的整个代码历史 $ git clone [url] ``` ### 配置 ``` # 显示当前的Git配置 $ git config --list # 编辑Git配置文件 $ git config -e [--global] # 设置提交代码时的用户信息 $ git config [--global] user.name "[name]" $ git config [--global] user.email "[email address]" ``` ### 增加/删除文件 ``` # 添加指定文件到暂存区 $ git add [file1] [file2] ... # 添加指定目录到暂存区,包括子目录 $ git add [dir] # 添加当前目录的所有文件到暂存区 $ git add . # 添加每个变化前,都会要求确认 # 对于同一个文件的多处变化,可以实现分次提交 $ git add -p # 删除工作区文件,并且将这次删除放入暂存区 $ git rm [file1] [file2] ... # 停止追踪指定文件,但该文件会保留在工作区 $ git rm --cached [file] # 改名文件,并且将这个改名放入暂存区 $ git mv [file-original] [file-renamed] ``` ### 代码提交 ``` # 提交暂存区到仓库区 $ git commit -m [message] # 提交暂存区的指定文件到仓库区 $ git commit [file1] [file2] ... -m [message] # 提交工作区自上次commit之后的变化,直接到仓库区 $ git commit -a # 提交时显示所有diff信息 $ git commit -v # 使用一次新的commit,替代上一次提交 # 如果代码没有任何新变化,则用来改写上一次commit的提交信息 $ git commit --amend -m [message] # 重做上一次commit,并包括指定文件的新变化 $ git commit --amend [file1] [file2] ... ``` ### 分支 ``` # 列出所有本地分支 $ git branch # 列出所有远程分支 $ git branch -r # 列出所有本地分支和远程分支 $ git branch -a # 新建一个分支,但依然停留在当前分支 $ git branch [branch-name] # 新建一个分支,并切换到该分支 $ git checkout -b [branch] # 新建一个分支,指向指定commit $ git branch [branch] [commit] # 新建一个分支,与指定的远程分支建立追踪关系 $ git branch --track [branch] [remote-branch] # 切换到指定分支,并更新工作区 $ git checkout [branch-name] # 切换到上一个分支 $ git checkout - # 建立追踪关系,在现有分支与指定的远程分支之间 $ git branch --set-upstream [branch] [remote-branch] # 合并指定分支到当前分支 $ git merge [branch] # 选择一个commit,合并进当前分支 $ git cherry-pick [commit] # 删除分支 $ git branch -d [branch-name] # 删除远程分支 $ git push origin --delete [branch-name] $ git branch -dr [remote/branch] ``` ### 标签 ``` # 列出所有tag $ git tag # 新建一个tag在当前commit $ git tag [tag] # 新建一个tag在指定commit $ git tag [tag] [commit] # 删除本地tag $ git tag -d [tag] # 删除远程tag $ git push origin :refs/tags/[tagName] # 查看tag信息 $ git show [tag] # 提交指定tag $ git push [remote] [tag] # 提交所有tag $ git push [remote] --tags # 新建一个分支,指向某个tag $ git checkout -b [branch] [tag] ``` ### 查看信息 ``` # 显示有变更的文件 $ git status # 显示当前分支的版本历史 $ git log # 显示commit历史,以及每次commit发生变更的文件 $ git log --stat # 搜索提交历史,根据关键词 $ git log -S [keyword] # 显示某个commit之后的所有变动,每个commit占据一行 $ git log [tag] HEAD --pretty=format:%s # 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件 $ git log [tag] HEAD --grep feature # 显示某个文件的版本历史,包括文件改名 $ git log --follow [file] $ git whatchanged [file] # 显示指定文件相关的每一次diff $ git log -p [file] # 显示过去5次提交 $ git log -5 --pretty --oneline # 显示所有提交过的用户,按提交次数排序 $ git shortlog -sn # 显示指定文件是什么人在什么时间修改过 $ git blame [file] # 显示暂存区和工作区的差异 $ git diff # 显示暂存区和上一个commit的差异 $ git diff --cached [file] # 显示工作区与当前分支最新commit之间的差异 $ git diff HEAD # 显示两次提交之间的差异 $ git diff [first-branch]...[second-branch] # 显示今天你写了多少行代码 $ git diff --shortstat "@{0 day ago}" # 显示某次提交的元数据和内容变化 $ git show [commit] # 显示某次提交发生变化的文件 $ git show --name-only [commit] # 显示某次提交时,某个文件的内容 $ git show [commit]:[filename] # 显示当前分支的最近几次提交 $ git reflog ``` ### 远程同步 ``` # 下载远程仓库的所有变动 $ git fetch [remote] # 显示所有远程仓库 $ git remote -v # 显示某个远程仓库的信息 $ git remote show [remote] # 增加一个新的远程仓库,并命名 $ git remote add [shortname] [url] # 取回远程仓库的变化,并与本地分支合并 $ git pull [remote] [branch] # 上传本地指定分支到远程仓库 $ git push [remote] [branch] # 强行推送当前分支到远程仓库,即使有冲突 $ git push [remote] --force # 推送所有分支到远程仓库 $ git push [remote] --all ``` ### 撤销 ``` # 恢复暂存区的指定文件到工作区 $ git checkout [file] # 恢复某个commit的指定文件到暂存区和工作区 $ git checkout [commit] [file] # 恢复暂存区的所有文件到工作区 $ git checkout . # 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变 $ git reset [file] # 重置暂存区与工作区,与上一次commit保持一致 $ git reset --hard # 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变 $ git reset [commit] # 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致 $ git reset --hard [commit] # 重置当前HEAD为指定commit,但保持暂存区和工作区不变 $ git reset --keep [commit] # 新建一个commit,用来撤销指定commit # 后者的所有变化都将被前者抵消,并且应用到当前分支 $ git revert [commit] 暂时将未提交的变化移除,稍后再移入 $ git stash $ git stash pop ``` ### 其他 ``` # 生成一个可供发布的压缩包 $ git archive ``` # MySQL ## 数据库备份语句 ```shell @echo off set "Ymd=%date:~,4%%date:~5,2%%date:~8,2%" mysqldump -h 192.168.0.147 -P13306 -ulylzk -ply123456 liyu-mes > C:\project\liyu\数据库备份\liyu-mes\data_backup_%Ymd%.sql @echo on ``` ## navicat连接MySQL8.0提示caching_sha2_password问题解决方法 ```mysql mysql -h localhost -u root -p; ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456'; FLUSH PRIVILEGES; ``` ## 表结构查询 ```sql select table_name, table_comment, create_time, update_time from information_schema.tables where table_schema = (select database()) AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%' AND table_name NOT IN (select table_name from gen_table) order by table_name SELECT * FROM information_schema.TABLES WHERE table_schema = 'liyu-mes-zj' ORDER BY TABLE_NAME; select * from information_schema.columns where table_schema = 'liyu-mes-zj'; ``` ## 事务锁查询释放 ```mysql # 查询慢SQL show processlist where time>500; # 查询使用的表 show OPEN TABLES where In_use > 0; # 查询事务 select * from information_schema.innodb_trx; # 释放锁 kill 999; ``` ## too many connection ```mysql # 查看最大连接数 show variables like '%max_connections%'; # 查看当前所有线程数 show full processlist; 进入 docker 内部的 bash 命令可执行界面: docker ps 查看 mysql 镜像 docker exec -it 镜像的containerID /bin/bash 进入镜像内部可执行 bash 命令界面 永久修改方案,重启后仍有效: vim /etc/mysql/mysql.conf.d/mysqld.cnf 如果没有 vim 命令,则安装 vim: 第一步:apt-get update 第二步:apt-get install vim max_connections=16384 -- 设置该 DB 最大连接数 max_user_connections=2000 -- 设置单用户最大连接数 临时修改方案,重启后失效: 在任意连接到 mysql 的 session 会话里,或者 navicat 界面中执行以下命令都可以。进入 docker 以后,执行:mysql -u root -p 然后回车,之后按提示输入 mysql 密码。 set GLOBAL max_connections=1020; -- 设置该 DB 最大连接数为 1020 set GLOBAL max_user_connections = 1000; -- 设置单用户最大连接数为 1000 ``` ## MYSQL安装 ```mysql 一、mysql的安装 之前搭建linux下项目的发布,最后遗留的问题时数据库的迁移,如何从windows上迁移到linux上?这里首先进行mysql数据库的安装 1、下载mysql安装包 在这里下载的是如下版本的mysql https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz 下载完毕后上传到linux服务器 2、解压 [root@localhost sdb1]# tar -xzvf mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz -C /usr/local/ 将其解压到指定路径,并且通过mv命令修改名字为mysql 3、创建用户和组 [root@localhost ~]# groupadd mysql [root@localhost ~]# useradd -r -g mysql mysql 4、将安装目录所有者及所属组改为mysql [root@localhost ~]# chown -R mysql.mysql /usr/local/mysql 5、创建data文件夹,用于存放数据库表之类的数据 [root@localhost mysql]# mkdir data #进入mysql文件夹 6、初始化 安装依赖包 [root@localhost mysql]# yum install libaio 进行初始化 [root@localhost mysql]# /usr/local/mysql/bin/mysqld --user=mysql --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data --initialize 7、编辑配置文件 /etc/my.cnf 在配置文件中写入以下内容 复制代码 [mysqld] datadir=/usr/local/mysql/data basedir=/usr/local/mysql socket=/tmp/mysql.sock user=mysql port=3306 character-set-server=utf8 取消密码验证 skip-grant-tables Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 skip-grant-tables [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid 复制代码 8、将mysql加入到服务中 [root@localhost mysql]# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql 9、开机启动 [root@localhost mysql]# chkconfig mysql on 10、启动mysql服务 [root@localhost mysql]# service mysql start 11、登陆mysql 在配置文件/etc/my.cnf中跳过密码登陆,所以可以免密登陆 [root@localhost mysql]# /usr/local/mysql/bin/mysql -uroot -p 可以加入到环境变量 编辑配置文件 [root@localhost mysql]# vim /etc/profile 输出 [root@localhost mysql]# source /etc/profile 这时可以使用 [root@localhost mysql]# mysql -u root -p 进入到mysql 二、迁移数据库 之前项目中需要将windows中的数据库迁移到llinux中,这是就可以进行了。 在windows本地的navicat将sql文件导出,生成yw_crm.sql文件 此时先查看项目配置的数据库信息 1、新建数据库 因为数据库为yw_crm,所以需要新建数据库 mysql> create database yw_crm -> ; Query OK, 1 row affected (0.00 sec) 2、设置编码 为防止数据库文件出现乱码,进入数据库,进行编码设置 mysql> use yw_crm Database changed mysql> set names utf8; Query OK, 0 rows affected (0.00 sec) 3、导入sql文件 将已经上传到linux的sql文件进行导入数据库 复制代码 mysql> source /root/Envs/yw_crm_project/yw_crm.sql Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected, 1 warning (0.12 sec) Query OK, 0 rows affected (0.39 sec) 复制代码 4.查看是否成功 可以看到已经导入成功。 接着再去登陆以下之前的项目,看是否还有验证码问题? 此时已经没有任何问题了。 ``` ## 分区 ```sql create table foo_range ( id int not null auto_increment, created DATETIME, primary key (id, created) ) engine = innodb partition by range (TO_DAYS(created))( PARTITION foo_1 VALUES LESS THAN (TO_DAYS('2016-10-18')), PARTITION foo_2 VALUES LESS THAN (TO_DAYS('2016-01-01')) ); //新增一个分区 ALTER TABLE foo_range ADD PARTITION( PARTITION foo_3 VALUES LESS THAN (TO_DAYS('2017-10-18')) ); //插入数据 insert into `foo_range` (`id`, `created`) values (1, '2016-10-17'),(2, '2016-10-20'),(3, '2016-1-25'); //查询 explain partitions select * from foo_range where created = '2016-10-20'; //查询结果: mysql> explain partitions select * from foo_range where created = '2016-10-20'; //修改分区 ALTER TABLE foo_range ADD PARTITION( PARTITION foo_5 VALUES LESS THAN (TO_DAYS('2016-10-19')) ); ``` ![image.png](https://ucc.alicdn.com/pic/developer-ecology/ab31244c481a43f18cd81e98c26b1682.png) ### 分区报错 ```sql 未设置对应分区 1526 - Table has no partition for value 736719 如果没有进行适当的处理,将会报错。所以在进行 RANGE 分区时,要思考这种情况。一般情况下,就时在最后添加一个 MAXVALUE 分区,如下: PARTITION p_max VALUES LESS THAN MAXVALUE ``` [Mysql数据库表分区深入详解-阿里云开发者社区 (aliyun.com)](https://developer.aliyun.com/article/708095) # ORACLE ## 表数据迁移 ```mysql insert into T_MATERIAL_INFO2 (select * from T_MATERIAL_INFO where MATERIAL_id =1701825013171806211); -- 大数据量迁移 merge into T_MATERIAL_INFO2 a using (SELECT * from T_MATERIAL_INFO where company = '219') b on(1=0) when not matched then insert values(b.MATERIAL_ID,b.NAME,b.CODE,b.SOURCE,b.MATERIAL_NO,b.MATERIAL_DIFF,b.DISTRIBUTION_ATTR,b.PRICE,b.LENGTH,b.WIDTH,b.HEIGHT,b.VOLUME, b.NET_WEIGHT,b.GROSS_WEIGHT,b.GRADE,b.MIN_PACK_NUM,b.PURCHASE_MIN_PACK_NUM,b.INGREDIENT_MIN_PACK_NUM,b.SHELF_LIFE,b.ABC,b.QUALITY_ATTR, b.INSPECTION_LEVEL,b.SAFETY_STOCK,b.COLOUR,b.QUALITY_PLAN_ID,b.PACK_SPEC,b.IS_GENERAL,b.UNIT,b.CHECK_UNIT,b.MONETARY_UNIT, b.VERSION,b.PROPERTY,b.SPECS,b.DEPOSIT_UPPER_LIMIT,b.DEPOSIT_LOWER_LIMIT,b.PURCHASE_UNIT,b.INVENTORY_UNIT,b.STATUS, b.IS_CONFIG_SHELF,b.REMARK,b.CREATE_TIME,b.CREATE_BY,b.UPDATE_TIME, b.UPDATE_BY,b.DEL_FLAG,b.COMPANY,b.QUALITY_GRADE,b.MATERIAL_TYPE_NAME,b.QUALITY_PLAN_NAME, b.MATERIAL_TYPE_CODE,b.PROCESS_TYPES,b.AREA_CODE,b.AREA_NAME, b.WAREHOUSE_CODE,b.WAREHOUSE_NAME,b.LOCATION_CODE,b.LOCATION_NAME) ``` ## 时间查询 ```sql select * from T_LOG where CREATE_TIME >= to_date('2023-07-20', 'yyyy-mm-dd') order by CREATE_TIME desc; select * from WP_SYS_LOG where CREATE_TIME between to_date('2023-07-20', 'yyyy-mm-dd') and to_date('2023-07-20', 'yyyy-mm-dd') + 1; ``` ## 锁表查询和解锁方法 ```sql -- 杀掉锁表进程 select sess.sid,sess.serial#, lo.oracle_username,lo.os_user_name, ao.object_name,lo.locked_mode from v$locked_object lo,dba_objects ao,v$session sess where ao.object_id=lo.object_id and lo.session_id=sess.sid; -- 杀掉锁表进程 alter system kill session '68,51';--分别为SID和SERIAL#号 -- 查看数据库引起锁表的SQL语句 SELECT A.USERNAME, A.MACHINE, A.PROGRAM, A.SID, A.SERIAL#, A.STATUS, C.PIECE, C.SQL_TEXT FROM V$SESSION A, V$SQLTEXT C WHERE A.SID IN (SELECT DISTINCT T2.SID FROM V$LOCKED_OBJECT T1, V$SESSION T2 WHERE T1.SESSION_ID = T2.SID) AND A.SQL_ADDRESS = C.ADDRESS(+) ORDER BY C.PIECE; ``` ## Oracle报错ORA-12516 TNS:listener could not find available handler with matching protocol stack ```sql -- 以sysdba身份登陆PL/SQL sqlplus / as sysdba; -- 授予查询视图权限 grant select_catalog_role to wms; -- 查看当前连接进程数 SQL>select count(*) from v$process; -- 查看连接数上限 SQL>select value from v$parameter where name = 'processes'; -- 查询processes数量 SQL> show parameter processes NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ aq_tm_processes integer 0 db_writer_processes integer 3 gcs_server_processes integer 0 job_queue_processes integer 10 log_archive_max_processes integer 2 processes integer 150 -- 查询sessions数量 SQL> show parameter sessions NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ java_max_sessionspace_size integer 0 java_soft_sessionspace_limit integer 0 license_max_sessions integer 0 license_sessions_warning integer 0 logmnr_max_persistent_sessions integer 1 sessions integer 170 shared_server_sessions integer SQL> -- 以sysdba身份登陆PL/SQL -- 查询目前连接数 show parameter processes; -- 修改processes alter system set processes=500 scope=spfile; -- 修改processes alter system set sessions=555 scope=spfile; -- 重启Oracle服务或重启Oracle服务器 -- 然后reboot数据库,使其生效 ``` ## ORACLE启动命令 ```shell -- 切换用户 su - oracle sqlplus / as sysdba startup -- 查看共享内存大小 df -h /dev/shm/ -- 调整/dev/shm大小 mount -t tmpfs shmfs -o size=8G /dev/shm ``` ## 创建表结构 ```mysql oracle新建用户详细操作步骤: 1.cmd输入 sqlplus; 回车,然后输入 system as sysdba; 登录依次执行 2.创建表空间 CREATE TABLESPACE 表空间 DATAFILE 'D:\oracle2\app\Administrator\oradata\orcl\表空间.dbf' SIZE 30720M AUTOEXTEND ON; CREATE TABLESPACE TSP_TMGLASS DATAFILE 'D:\oracle2\app\Administrator\oradata\orcl\TSP_TMGLASS.dbf' SIZE 30720M AUTOEXTEND ON; 3.创建用户执行: CREATE USER 用户名 IDENTIFIED BY 密码 DEFAULT TABLESPACE 表空间 TEMPORARY TABLESPACE temp; CREATE USER TMGLASS IDENTIFIED BY TieMao2023 DEFAULT TABLESPACE TSP_TMGLASS TEMPORARY TABLESPACE temp; 4.为用户赋权限执行: GRANT CREATE SESSION,CREATE TABLE,CREATE VIEW,CREATE SEQUENCE,UNLIMITED TABLESPACE TO 用户名; GRANT CONNECT TO 用户名; GRANT RESOURCE TO 用户名; GRANT DBA TO 用户名; GRANT CREATE SESSION,CREATE TABLE,CREATE VIEW,CREATE SEQUENCE,UNLIMITED TABLESPACE TO TMGLASS; GRANT CONNECT TO TMGLASS; GRANT RESOURCE TO TMGLASS; GRANT DBA TO TMGLASS; ``` ## 导入导出数据 ```sql exp WMS/qwer1234@orcl file=E:\SRMDB\dbbackup\tmglass%date:~0,4%%date:~5,2%%date:~8,2%.dmp log=E:\SRMDB\dbbackup\tmglass%date:~0,4%%date:~5,2%%date:~8,2%.log imp tmglass/TieMao2023@127.0.0.1:1521/orcl tables=('SYS_ROLE_OFFICE','SYS_USER','SYS_ROLE','SYS_ROLE_MENU','SYS_NUM','SYS_OFFICE','SYS_MDICT','SYS_MENU','SYS_MATERIAL') file=tmglass20230815.dmp full = y; imp tmglass/TieMao2023@127.0.0.1:1521/orcl file=tmglass20230815.dmp full = y; imp tmglass/TieMao2023@127.0.0.1:1521/orcl file=tmglass20230815.dmp tables=(SYS_ROLE_OFFICE,SYS_USER,SYS_ROLE,SYS_ROLE_MENU,SYS_NUM,SYS_OFFICE,SYS_MDICT,SYS_MENU,SYS_MATERIAL) ; expdb WMS/qwer1234@orcl file=test.dmp full = y; exp WMS/qwer1234@orcl file=test.dmp full = y; exp WMS/qwer1234@orcl file=test.dmp full = y tables=(t_material_info); imp WMS/qwer1234@127.0.0.1:1521/orcl file=test.dmp full = y; -- 完全导入导出 exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp" full = y; -- 部分导入导出 exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp" tabels= (table1,table2,table3,...); -- 表空间tablespaces导入导出 exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp" owner(username1,username2,username3); -- 用户名username对象导入导出 exp(imp) username/password@SERVICENAME:1521 file="e:\temp.dmp" owner(username1,username2,username3); expdp WMS/qwer1234@127.0.0.1:1521/orcl TABLES=sys_area dumpfile=expdp.dmp directory=dmp logfile=expdlog.log; ``` ## expdp使用方法 ### 1、创建expdp导出目录,默认导出目录为D:\app\Administrator/admin/orcl/dpdump/(其中前面为Oracle安装目录)。 ```mysql su - oracle sqlplus / as sysdba chown -R oracle:oinstall dmp create or replace directory dmp as '/home/oracle/dmp'; ``` ### 2、查看当前创建的所有dmp导出目录 (验证看是否创建成功) ```mysql select * from dba_directories; ``` ### 3、为创建的目录赋权限,需要以其他用户运行,建议在sys用户下执行。 ```mysql grant read,write on directory 目录名 to 需要赋值的用户名 -- 例:grant read,write on directory dmp to WMS; ``` ### 4、导出(这里使用最简单的导出方式,推荐使用该方式)!!! ```mysql expdp 用户名/密码@数据库实例名 directory=导出目录 dumpfile=导出的文件名.dmp logfile=导出的日志名.log -- 例:expdp GISDATA/GISDATA@LOCALHOST/orcl directory=dmp dumpfile=GISDATA20200921.dmp logfile=GISDATA20200921.log -- expdp WMS/qwer1234@orcl schemas=wms dumpfile=expdp.dmp directory=dmp exclude=table:\"in\(\'B_INTERFACE_LOG\',\'SYS_OPER_LOG\',\'T_MATERIAL_INFO\'\)\"; -- impdp WMS/qwer1234@orcl schemas=wms dumpfile=expdp.dmp directory=dmp; ``` ### 5、常用导出命令 ```mysql 1、按用户导 expdp GISDATA/GISDATA@localhost/orcl schemas=GISDATA dumpfile=expdp.dmp directory=dmp logfile=expdlog.log; 2、并行进程parallel expdp GISDATA/GISDATA@localhost/orcl directory=dmp dumpfile=expdp.dmp parallel=40 job_name=expdpjob logfile=expdlog.log 3、按表名导 expdp GISDATA/GISDATA@localhost/orcl TABLES=test1,test2 dumpfile=expdp.dmp directory=dmp logfile=expdlog.log; 4、按查询条件导 expdp GISDATA/GISDATA@localhost/orcl directory=dmp dumpfile=expdp.dmp Tables=test query='WHERE id<20' logfile=expdlog.log; 5、按表空间导 expdp GISDATA/GISDATA directory=dmp dumpfile=expdp.dmp TABLESPACES=GIDDATA,YWDATA logfile=expdlog.log; 6、导整个数据库 expdp GISDATA/GISDATA directory=dmp dumpfile=expdp.dmp FULL=y logfile=expdlog.log; ``` [expdp&impdp(orcle数据库的导出导入,只导出元数据,不导出表数据,最全,最完善的步骤)_oracle expdp不导出表数据-CSDN博客](https://blog.csdn.net/kou869929526/article/details/125791113) ## 删除用户和表空间 ``` --删除user drop user cduser cascade; --删除tablespace DROP TABLESPACE tablespace_name INCLUDING CONTENTS AND DATAFILES; DROP TABLESPACE tmglass INCLUDING CONTENTS AND DATAFILES; ``` ## 查询字符编码 ``` 1、查询远程数据库字符集。 SQL> select userenv('language') from dual; 查询结果: USERENV('LANGUAGE') ---------------------------------------------------- AMERICAN_AMERICA.UTF8 2、查询dmp文件所使用的字符集。 用exp导出的文件是以dmp结尾的。以十六进制的格式打开dmp文件。然后看它的第2和第3个字节,如:0354。这两个字节是记录dmp文件的字符集的。 SQL查出它对应的字符集: SQL> select nls_charset_name(to_number('0354','xxxx')) from dual; 3、查询本地数据库的字符集 与查询远程数据库字符集的方法一样,不再介绍。 如果三者的字符集都不相同,那么就需要统一字符集,首先修改dmp字符集,网上查到的一种方法是用ultraEdit打开dmp文件,然后把字符集修改相同的,我使用的是另一种方法,在cmd窗口临时设置字符集为相同的。然后使用exp 导出dmp文件。会发现导出的文件的字符集跟数据库是一样的。然后再修改本地数据库的字符集,网上有修改的方法,我不再介绍。然后直接使用imp导入到本地数据库。其实解决乱码的方法就是统一字符集!! ``` ## 删除重复数据保留第一条 ```mysql Delete From T_MATERIAL_INFO Where MATERIAL_id In (Select MATERIAL_id From ( Select t.*, Row_Number() Over(Partition By code,area_code order By code) Su From T_MATERIAL_INFO t where t.del_flag = 0) Where Su > 1); ``` ## 查询表结构 ```mysql select ut.COLUMN_NAME,--字段名称 uc.comments,--字段注释 ut.DATA_TYPE,--字典类型 ut.DATA_LENGTH,--字典长度 ut.NULLABLE--是否为空 from user_tab_columns ut inner JOIN user_col_comments uc on ut.TABLE_NAME = uc.table_name and ut.COLUMN_NAME = uc.column_name where ut.Table_Name='W_WAREHOUSE_ORDER_DETAIL' order by ut.column_name ``` ## 查询表空间 ```mysql SELECT a.tablespace_name "表空间名", total "表空间大小", free "表空间剩余大小", (total - free) "表占用空间大小", ROUND((total - free) / total * 100, 2) || '%' "已使用空间百分比" FROM (SELECT tablespace_name, SUM(bytes) / 1024 / 1024 total FROM dba_data_files GROUP BY tablespace_name) a, (SELECT tablespace_name, SUM(bytes) / 1024 / 1024 free FROM dba_free_space GROUP BY tablespace_name) b WHERE a.tablespace_name = b.tablespace_name ORDER BY (total - free) DESC; ``` ![image-20231031211324503](../../Users/86180/AppData/Roaming/Typora/typora-user-images/image-20231031211324503.png) ## 查询表空间位置 ```mysql select tablespace_name, file_id, file_name, round(bytes / (1024 * 1024), 0) total_space from sys.dba_data_files order by tablespace_name ``` ![image-20231031211341344](../../Users/86180/AppData/Roaming/Typora/typora-user-images/image-20231031211341344.png) ## 查询表空间占用情况 ```mysql select t.owner,t.segment_name,t.tablespace_name,bytes/1024/1024/1024 as sizes,q.num_rows,t.segment_type from dba_segments t left join dba_tables q on t.segment_name=q.table_name and t.owner=q.owner where t.segment_type='TABLE' and t.tablespace_name='USERS' --需要查看的表空间 order by 4 desc; ``` ![image-20231103110730520](../../Users/86180/AppData/Roaming/Typora/typora-user-images/image-20231103110730520.png) # 项目部署 ## WINDOW ``` ``` # ELK ## ELK 处理 Spring Boot 日志,不错! https://mp.weixin.qq.com/s/WxZaloqAQWNg7xlmnJ4OrA # Mybatis ## 批量插入修改Mapper ```xml INSERT INTO tableName(id,user_name,dept,plate_code) VALUES (#{item.id},#{item.userName},#{item.dept},#{item.plateCode) update tableName when id=#{i.id} then #{i.id} when id=#{i.id} then #{i.userName} when id=#{i.id} then #{i.dept} when id=#{i.id} then #{i.plateCode} where id = #{i.id} ``` ## 批量插入修改xml生成器 ```java package com.sh; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class Test { private static final String SQL = "`id` bigint(11) NOT NULL AUTO_INCREMENT,\n" + " `user_name` varchar(64) DEFAULT NULL COMMENT '姓名',\n" + " `dept` varchar(64) DEFAULT NULL COMMENT '部门',\n" + " `plate_code` varchar(64) DEFAULT NULL COMMENT '车牌号',\n"; public static void main(String[] args) { List fields = new ArrayList<>(); String[] split = SQL.split("\n"); String trimSql = ""; for (String s : split) { int i1 = s.indexOf("`"); int i2 = s.indexOf("`", i1 + 1); String b = s.substring(i1 + 1, i2); trimSql = trimSql + " \n" + " \n" + " \n" + " when id=#{i.id} then #{i." + toCamelCase(b) + "}\n" + " \n" + " \n" + " \n"; fields.add(b); } String insertSql = fields.stream().collect(Collectors.joining(",")); String valueSql = fields.stream().map(e -> "item." + toCamelCase(e)).collect(Collectors.joining("},#{")); String inertSql = "\n" + " INSERT INTO tableName(" + insertSql + ")\n" + " VALUES\n" + " \n" + " (#{" + valueSql + ")\n" + " \n" + ""; String updateSql = "\n" + "\n" + " update tableName\n" + " \n" + trimSql + " \n" + " where\n" + " \n" + " id = #{i.id}\n" + " \n" + ""; System.out.println(inertSql); System.out.println(updateSql); } /** * 下划线转驼峰 plate_code -> plateCode * @param str * @return */ public static String toCamelCase(String str) { if (str == null) { return null; } StringBuilder sb = new StringBuilder(); boolean upperCase = false; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c == '_') { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(c)); upperCase = false; } else { sb.append(c); } } return sb.toString(); } } ``` ## MyBatis Plus 批量插入优化 ### 1.新建批量插入 SQL 注入器 在工程 `config` 目录下创建一个 SQL 注入器 `InsertBatchSqlInjector` : ```java /** * @author: 犬小哈 * @date: 2023-01-05 14:42 * @version: v1.0.0 * @description: 批量插入 SQL 注入器 **/ public class InsertBatchSqlInjector extends DefaultSqlInjector { @Override public List getMethodList(Class mapperClass, TableInfo tableInfo) { // super.getMethodList() 保留 Mybatis Plus 自带的方法 List methodList = super.getMethodList(mapperClass, tableInfo); // 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn methodList.add(new InsertBatchSomeColumn()); return methodList; } } ``` 说说 InsertBatchSomeColumn `InsertBatchSomeColumn` 是 Mybatis Plus 内部提供的默认批量插入,只不过这个方法作者只在 MySQL 数据测试过,所以没有将它作为通用方法供外部调用,注意看注释:源码复制出来,如下: ```java /** * 批量新增数据,自选字段 insert *

不同的数据库支持度不一样!!! 只在 mysql 下测试过!!! 只在 mysql 下测试过!!! 只在 mysql 下测试过!!!

*

除了主键是 数据库自增的未测试 外理论上都可以使用!!!

*

如果你使用自增有报错或主键值无法回写到entity,就不要跑来问为什么了,因为我也不知道!!!

*

* 自己的通用 mapper 如下使用: *

 * int insertBatchSomeColumn(List entityList);
 * 
*

* *
  • 注意: 这是自选字段 insert !!,如果个别字段在 entity 里为 null 但是数据库中有配置默认值, insert 后数据库字段是为 null 而不是默认值
  • * *

    * 常用的 {@link Predicate}: *

    * *
  • 例1: t -> !t.isLogicDelete() , 表示不要逻辑删除字段
  • *
  • 例2: t -> !t.getProperty().equals("version") , 表示不要字段名为 version 的字段
  • *
  • 例3: t -> t.getFieldFill() != FieldFill.UPDATE) , 表示不要填充策略为 UPDATE 的字段
  • * * @author miemie * @since 2018-11-29 */ @SuppressWarnings("serial") public class InsertBatchSomeColumn extends AbstractMethod { /** * 字段筛选条件 */ @Setter @Accessors(chain = true) private Predicate predicate; /** * 默认方法名 */ public InsertBatchSomeColumn() { // 方法名 super("insertBatchSomeColumn"); } /** * 默认方法名 * * @param predicate 字段筛选条件 */ public InsertBatchSomeColumn(Predicate predicate) { super("insertBatchSomeColumn"); this.predicate = predicate; } /** * @param name 方法名 * @param predicate 字段筛选条件 * @since 3.5.0 */ public InsertBatchSomeColumn(String name, Predicate predicate) { super(name); this.predicate = predicate; } @SuppressWarnings("Duplicates") @Override public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; SqlMethod sqlMethod = SqlMethod.INSERT_ONE; List fieldList = tableInfo.getFieldList(); String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, false) + this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY); String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET; String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) + this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY); insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET; String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA); String keyProperty = null; String keyColumn = null; // 表包含主键处理逻辑,如果不包含主键当普通字段处理 if (tableInfo.havePK()) { if (tableInfo.getIdType() == IdType.AUTO) { /* 自增主键 */ keyGenerator = Jdbc3KeyGenerator.INSTANCE; keyProperty = tableInfo.getKeyProperty(); keyColumn = tableInfo.getKeyColumn(); } else { if (null != tableInfo.getKeySequence()) { keyGenerator = TableInfoHelper.genKeyGenerator(this.methodName, tableInfo, builderAssistant); keyProperty = tableInfo.getKeyProperty(); keyColumn = tableInfo.getKeyColumn(); } } } String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript); SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); return this.addInsertMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource, keyGenerator, keyProperty, keyColumn); } } ``` ### 2.配置 SQL 注入器 在 `config` 包下创建 `MybatisPlusConfig` 配置类: ```java /** * @Author: 犬小哈 * @Date: 2022-12-15 18:29 * @Version: v1.0.0 * @Description: TODO **/ @Configuration @MapperScan("com.quanxiaoha.mybatisplusdemo.mapper") public class MybatisPlusConfig { /** * 自定义批量插入 SQL 注入器 */ @Bean public InsertBatchSqlInjector insertBatchSqlInjector() { return new InsertBatchSqlInjector(); } } ``` ### 3.新建 MyBaseMapper ​ 在 `config` 包下创建 `MyBaseMapper` 接口,让其继承自 Mybatis Plus 提供的 `BaseMapper`, 并定义批量插入方法: ```java /** * @author: 犬小哈 * @date: 2022-12-13 14:13 * @version: v1.0.0 * @description: TODO **/ public interface MyBaseMapper extends BaseMapper { // 批量插入 int insertBatchSomeColumn(@Param("list") List batchList); } ``` 注意:方法名必须为 `insertBatchSomeColumn`, 和 `InsertBatchSomeColumn` 内部定义好的方法名保持一致。 ### 4.新建 UserMapper 在 `mapper` 包下创建 `UserMapper` 接口,注意继承刚刚自定义的 `MyBaseMapper`, 而不是 `BaseMapper` : ```java /** * @author: 犬小哈 * @date: 2022-12-13 14:13 * @version: v1.0.0 * @description: TODO **/ public interface UserMapper extends MyBaseMapper { } ``` ## 前端 #### 如何处理 Node 报错 Error: error:0308010c:digital envelope routines::unsupported ```json "scripts": { "dev": "SET NODE_OPTIONS=--openssl-legacy-provider &&vue-cli-service serve" } ``` #### 弹出对话框确认方法 ```js submitDialogForm(isCallback) { if (isCallback) { this.isCallBack = isCallback } this.$refs["dialogForm"].validate(async valid => { if (valid) { this.loading = true; try { const dialogForm = this.beforeDialogFormSubmit({ ...this.dialogForm }); this.editDialogSubmitResArg = await this.dialogFormSubmitMethod( dialogForm ); this.submitLoading = false; this.afterSubmitDialog(); this.closeDialog(); } catch (e) { this.loading = false; } } else { this.loading = false; } }); }, ``` #### 处理修改删除 ```js async handleDialogFormUpdate ( { dialogTitle, crudModel, crudMethods, params }, editDialogFlag, titlePrefix = "" ) { console.log('handleDialogFormUpdate') this.editDialogFlag = editDialogFlag; const { getDetail, update, beforeDialogFormEdit } = crudMethods; const dataObject = await getDetail.call(this, params); this.editDialogDetailArg = dataObject; const crudModelWithData = this.genModelObject({ modelObject: { ...crudModel }, dataObject }); this.editDialogType = 1; this.dialogFormSubmitMethod = update; this.dialogForm = beforeDialogFormEdit ? beforeDialogFormEdit.call(this, { ...crudModelWithData }) : { ...crudModelWithData }; this.openDialog({ title: titlePrefix + dialogTitle }); // 打开对话框 }, ``` #### 弹出对话框关闭 ```js closeDialog () { this.$refs["dialogForm"].resetFields(); this.editDialogFlag = ""; this.dialogVisible = false; bus.$emit("callback"); }, // 显示对话框 openDialog ({ title,width }) { this.dialogProps.title = title; if (width) { this.dialogProps.width = width; } this.dialogVisible = true; }, ``` #### 新增和修改后的回调 ```js async afterSubmitDialog () { if (this.pageRouteArg.needRefreshTodo && !this.isEditPage) { bus.$emit("refreshTodo"); } await this.init(); }, ``` ## 表单 ```vue ``` ```js const familyMemberTableColumns = [ { label: "联系人", prop: "name" }, { label: "两者关系", prop: "relationshipName" }, { label: "联系电话", prop: "mobile" }, { label: "性别", prop: "sex", render: (h, { row }) => { return h("div", row.sex === 1 ? "女" : "男"); } }, { label: "身份证号", prop: "familyCardNo" }, { label: "决策人", prop: "decisionFlag", render: (h, { row }) => { return h("div", row.decisionFlag === 1 ? "是" : "否"); } }, { label: "地址", prop: "addr" } ]; //处理修改删除方法 handleFamilyMemberTableAction(action, row, column, index) { switch (action) { case "update": this.updateIndex = index; this.handleDialogFormUpdate( { ...dialogCrud.familyMember, params: { index } }, "familyMember" ); break; case "del": this.handleDel({ ...dialogCrud.familyMember, params: { index } }); break; } }, //处理删除方法 handleActionBarAction() { this.handleDialogFormAdd(dialogCrud.familyMember, "familyMember"); }, const dialogCrud = { familyMember: { dialogTitle: "家庭成员", crudModel: familyMemberModel, crudMethods: { add() { const { name, relationshipId, mobile, familyCardNo, employer, profession, liveCondition, sex, addr, decisionFlag, relationshipName } = this.dialogForm; this.family.push({ name, relationshipId, mobile, familyCardNo, employer, profession, liveCondition, sex, addr, decisionFlag, relationshipName }); this.family = [...this.family]; return true; }, update(member) { this.family[this.updateIndex] = member; // console.log(member); this.family = [...this.family]; }, async getDetail({ index }) { return this.family[index]; }, async del({ index }) { // console.log(index); this.family = this.family.filter((item, itemIndex) => { return itemIndex !== index; }); return true; }, afterDel() { return false; } } } }; ``` # KAFKA ```shell -- 启动zookeeper .\bin\windows\zookeeper-server-start.bat .\config\zookeeper.properties -- 启动kafka .\bin\windows\zookeeper-server-start.bat .\config\zookeeper.properties 创建一个主题test-topic kafka-topics.bat --create --if-not-exists --topic test --bootstrap-server localhost:9092 查看创建的主题列表 kafka-topics.bat --list --bootstrap-server localhost:9092 启动生产者: kafka-console-producer.bat --broker-list localhost:9092 --topic test 启动消费者: kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic test --from-beginning ``` # MAVEN ## Try to run Maven import with -U flag (force update snapshots) ```shell mvn clean install -e -U -e详细异常,-U强制更新 ``` ## 手动导入maven ```shell jar下载地址 https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc/9.2.1.jre8 mvn install:install-file -Dfile=D:\jar\itextpdf-5.5.13.3.jar -DgroupId=com.itextpdf -DartifactId=itextpdf -Dversion=5.5.13.3 -Dpackaging=jar mvn install:install-file -Dfile=D:\jar\maven-surefire-plugin-3.2.2.jar -DgroupId=org.apache.maven.plugins -DartifactId=maven-surefire-plugin -Dversion=3.2.2 -Dpackaging=jar ``` # VUE相关实现 ## 前端启动报错 ```vue 出现这个错误是因为 node.js V17版本中最近发布的OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响. 添加 package.json 信息 "dev": "SET NODE_OPTIONS=--openssl-legacy-provider &&vue-cli-service serve", "build:prod": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build", ``` ## 动态列表实现 ```vue
    点击上传
    请上传图片文件
    ``` ```js data() { return { showColumn: [ {"prop":"createTime","type":0,"label":"创建时间"} ], } } ``` ## 甘特图实现 ```vue 官方文档 https://docs.dhtmlx.com/gantt/api__gantt_scales_config.html ``` ## 前端开发 ### table ```vue changeQuery(val) { this.form.warehouseId = val.id; this.form.warehouseCode = val.code; this.form.warehouseName = val.name; }, onClear() { this.form.warehouseId = undefined; this.form.warehouseCode = undefined; this.form.warehouseName = undefined; }, ``` # 若依集成积木报表 [快速集成 · JimuReport 积木报表 · 看云 (kancloud.cn)](https://static.kancloud.cn/zhangdaiscott/jimureport/2078875) ## 1、执行初始化脚本积木报表sql ## 2、pom中引入积木报表最新依赖 ```xml org.jeecgframework.jimureport jimureport-spring-boot-starter 1.5.0-beta ``` ## 3、RuoYiApplication添加积木扫描目录 ```java @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class , MongoAutoConfiguration.class}, scanBasePackages = {"com.sh"}) ``` ## 4、SecurityConfig拦截排除 目录在ruoyi-framework ``` .antMatchers("/jmreport/**").anonymous() ``` ## 5、yml中配置minidao(可忽略) ``` minidao : base-package: org.jeecg.modules.jmreport.desreport.dao* ``` ## 6、启动项目访问 http://localhost:8848/jmreport/list ## 7、问题 ``` 包缺失 应该需要商用版本 class path resource [org/jeecgframework/minidao/aspect/EmptyInterceptor.class] cannot be opened because it does not exist ``` ## 8、查看 ``` http://localhost:8092/jmreport/list http://localhost:8092/jmreport/view/1111 ``` ## 9、权限限制 [Ruoyi-Vue集成JimuReport:Token权限控制&菜单集成_jimureporttokenservice-CSDN博客](https://blog.csdn.net/wu_zeqin/article/details/126384991) # 若依集成ureport [RuoYi-Vue前后端分离版集成UReport2(IDEA版)_ureport2二次开发-CSDN博客](https://blog.csdn.net/qq_40183977/article/details/126462300) [ureport2报表详细使用 - niceyoo - 博客园 (cnblogs.com)](https://www.cnblogs.com/niceyoo/p/14311257.html) [UReport2 与业务结合_w3cschool](https://www.w3cschool.cn/ureport/ureport-y4op2han.html) [若依前后端分离框架集成UReport2,保存至数据库并结合业务使用导出-CSDN博客](https://blog.csdn.net/Elf12138/article/details/134049769) [RuoYi-Vue 集成 UReport2 | 月牙坠 (yueyazhui.top)](https://www.yueyazhui.top/posts/RuoYi-Vue-集成-UReport2/) 表设计:http://localhost:8080/ureport/designer 表查看:http://localhost:8080/ureport/preview?_u=file:aaa.ureport.xml ### 1.pom.xml文件中引入ureport2的依赖 ```xml com.bstek.ureport ureport2-console 2.2.9 ``` ### 2.启动类指定xml文件,注册Bean ```java package com.sh.ureport; import com.bstek.ureport.console.UReportServlet; import com.bstek.ureport.definition.datasource.BuildinDatasource; import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; import javax.sql.DataSource; import java.sql.Connection; @ImportResource("classpath:ureport-console-context.xml")//不加项目能够启动但是会导致加载数据源报错或加载不了 @Configuration public class UReportConfig implements BuildinDatasource { @Autowired private DataSource datasource; @Bean //定义ureport的启动servlet @SuppressWarnings("unchecked") public ServletRegistrationBean ureportServlet(){ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new UReportServlet()); servletRegistrationBean.addUrlMappings("/ureport/*"); return servletRegistrationBean; } @Override public String name() { return "内部数据源"; } @SneakyThrows @Override public Connection getConnection() { return datasource.getConnection(); } } ``` ### 3.配置ureport配置文件。名为ureport.properties ```properties ureport.disableHttpSessionReportCache=false ureport.disableFileProvider=true ureport.fileStoreDir=${sh.profile}/ureport2 ureport.debug=true ``` ### 4.在application.yml加入运行匿名访问,将拦截排除 ```yml security: # 排除路径 excludes: - /ureport/** ``` ### 5.自定义系统文件保存 ```java package com.sh.ureport; import com.bstek.ureport.exception.ReportException; import com.bstek.ureport.provider.report.ReportFile; import com.bstek.ureport.provider.report.ReportProvider; import com.sh.common.utils.ServletUtils; import lombok.Getter; import lombok.Setter; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.util.*; @Component @PropertySource(value = {"classpath:ureport.properties"}) public abstract class FileReportProvider implements ReportProvider { private String prefix = "file:"; private boolean disabled; @Getter @Setter @Value("${ureport.fileStoreDir}") private String fileStoreDir; @PostConstruct public void init() { File file = new File(fileStoreDir); if (!file.exists()) { file.mkdirs(); } } @Override public InputStream loadReport(String file) { HttpServletRequest request = ServletUtils.getRequest(); if (file.startsWith(prefix)) { file = file.substring(prefix.length(), file.length()); } String fullPath = fileStoreDir + "/" + file; try { return new FileInputStream(fullPath); } catch (FileNotFoundException e) { throw new ReportException(e); } } @Override public void deleteReport(String file) { if (file.startsWith(prefix)) { file = file.substring(prefix.length(), file.length()); } String fullPath = fileStoreDir + "/" + file; File f = new File(fullPath); if (f.exists()) { f.delete(); } } @Override public List getReportFiles() { File file = new File(fileStoreDir); List list = new ArrayList(); for (File f : file.listFiles()) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(f.lastModified()); list.add(new ReportFile(f.getName(), calendar.getTime())); } Collections.sort(list, new Comparator() { @Override public int compare(ReportFile f1, ReportFile f2) { return f2.getUpdateDate().compareTo(f1.getUpdateDate()); } }); return list; } @Override public void saveReport(String file, String content) { if (file.startsWith(prefix)) { file = file.substring(prefix.length(), file.length()); } String fullPath = fileStoreDir + "/" + file; FileOutputStream outStream = null; try { outStream = new FileOutputStream(new File(fullPath)); IOUtils.write(content, outStream, "utf-8"); } catch (Exception ex) { throw new ReportException(ex); } finally { if (outStream != null) { try { outStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public String getName() { return "自定义文件系统"; } @Override public boolean disabled() { return false; } @Override public String getPrefix() { return prefix; } } ``` # 多租户实现方式 ## **独立数据库** 每个租户使用独立的数据库,这种方案类似于传统的部署,其区别在于多租户的实现是将每个租户的数据库都统一管理起来。这种一租户一数据库的方案优缺点都很明显: **优点** 数据隔离性好,安全级别高; 数据库表不需要额外的字段来区分租户; 需求扩展独立性好,不影响其他租户的使用; 出现故障时,恢复数据简单。 **缺点** 增加了数据库的安装数量和安装成本; 支持租户的数量有限; 跨租户统计数据较困难; 新增租户需要重启服务。 **应用场景** 适用于定价高,安全级别要求高的租户。例如,银行、医院等对数据隔离性有严格要求的租户。这些租户的特点是租户较少,数据规模大,数据隔离性强。 ## **共享数据库、独立Schema** 每个租户共享同一个数据库,但使用的是不同的Schema。像Oracle和PgSql都支持一个数据库下多个Schema。 **优点** 数据隔离性较好。为每个租户提供了一定程度上的逻辑隔离; 相较于独立数据库方案,可以支持的租户数量更多; 安装成本相对较低。 **缺点** 跨租户统计数据较困难; 各个租户的数据库sql需要带上Schema名称。 **应用场景** 适用于数据规模中等,租户数量中等的项目。 ## **共享数据库、共享Schema、共享表** 每个租户共享同一个数据库,同一个Schema,甚至是同一张表。每个表里都有一个tenant_id字段用来区分表里的记录是来自于哪一个租户。这种多租户方案是三个方案里隔离级别最低但是共享程度最高的一个。 **优点** 安装成本最低; 支持的租户数量最多; 添加租户不需要重启服务; 跨租户统计较容易。 **缺点** 安全性最差,隔离级别最低; 维护成本最高。其成本体现在表设计需要额外字段,sql代码需要额外查询条件,故障后数据恢复需要额外操作; 每个租户的数据量规模不宜较大。 **应用场景** 适用于低成本,租户数量多,租户数据量小,对安全性和隔离级别要求低的产品。例如一些To C的产品。 [若依系统单租户扩展为多租户的大体方案 - 漫游云巅 - 博客园 (cnblogs.com)](https://www.cnblogs.com/vishun/p/17861285.html) # U9开发流程 ## 补丁制作 [U9二次开发之补丁制作-CSDN博客](https://blog.csdn.net/zhanyd/article/details/126607039) ## 轻量级服务开发 1、环境搭建 2、开发集成平台-轻量级服务,构造 UFIDA.U9.ZF.Cust.HZZFSHXM02. &__dm=true 3、用打开工具打开,开发,生成解决方案 ```c# namespace UFIDA.U9.CUST.SH.CreateMiscRcvTrans { using System; using System.Collections.Generic; using UFIDA.U9.Base; using UFIDA.U9.Base.Organization; using UFIDA.U9.CBO.Pub.Controller; using UFIDA.U9.CBO.SCM.Item; using UFIDA.U9.CBO.SCM.Warehouse; using UFIDA.U9.InvDoc.MiscRcv; using UFIDA.U9.ISV.MiscRcvISV; using UFIDA.U9.ISV.MiscRcvISV.Proxy; using UFSoft.UBF.AopFrame; using UFSoft.UBF.Transactions; /// /// CreateMiscRcvTransService partial /// public partial class CreateMiscRcvTransService { internal BaseStrategy Select() { return new CreateMiscRcvTransServiceImpementStrategy(); } } #region implement strategy /// /// Impement Implement /// /// internal partial class CreateMiscRcvTransServiceImpementStrategy : BaseStrategy { public CreateMiscRcvTransServiceImpementStrategy() { } public override object Do(object obj) { CreateMiscRcvTransService bpObj = (CreateMiscRcvTransService)obj; ReturnDTOData returnDTO = new ReturnDTOData(); using (UBFTransactionScope scope = new UBFTransactionScope(TransactionOption.RequiresNew)) { try { Organization org = Context.LoginOrg; CommonCreateMiscRcvProxy proxy = new CommonCreateMiscRcvProxy(); proxy.MiscRcvDTOList = new List(); IC_MiscRcvDTOData headData = new IC_MiscRcvDTOData(); string documentType = string.IsNullOrEmpty(bpObj.MiscRcvDocType) ? "MiscRcv001" : bpObj.MiscRcvDocType; MiscRcvDocType docType = MiscRcvDocType.Finder.Find("Code='" + documentType + "' and Org=" + org.ID + ""); if (docType == null) { returnDTO.IsSussece = false; returnDTO.DocNo = ""; returnDTO.ErrorMessage = "根据传入单据类型【" + bpObj.MiscRcvDocType + "】在组织【" + org.Name + "】下未找到"; } headData.Memo = bpObj.Memo; headData.BusinessDate = Convert.ToDateTime(bpObj.BusinessDate); headData.MiscRcvDocType = new CommonArchiveDataDTOData(docType.ID, docType.Code, docType.Name); headData.Org = new CommonArchiveDataDTOData(org.ID, org.Code, org.Name); headData.MiscRcvTransLs = new List(); int num = 10; foreach (var item in bpObj.LineDTOs) { IC_MiscRcvTransLsDTOData lineData = new IC_MiscRcvTransLsDTOData(); lineData.DocLineNo = num; lineData.IsMFG = docType.IsMFG; //料号 ItemMaster itemMaster = ItemMaster.Finder.Find("Code='" + item.ItemCode + "' and Org.ID=" + org.ID + ""); if (itemMaster == null) { returnDTO.IsSussece = false; returnDTO.DocNo = ""; returnDTO.ErrorMessage = "行【" + num + "】根据传入的料号【" + item.ItemCode + "】在组织【" + org.Name + "】下未找到"; return returnDTO; } lineData.ItemInfo = new ItemInfoData(); lineData.ItemInfo.ItemID = itemMaster.ID; lineData.ItemInfo.ItemCode = itemMaster.Code; lineData.ItemInfo.ItemName = itemMaster.Name; //仓库 Warehouse warehouse = Warehouse.FindByCode(org, item.WhCode); if (warehouse == null) { returnDTO.IsSussece = false; returnDTO.DocNo = ""; returnDTO.ErrorMessage = "行【" + num + "】根据传入的存储地点【" + item.WhCode + "】在组织【" + org.Name + "】下未找到"; return returnDTO; } lineData.Wh = new CommonArchiveDataDTOData(warehouse.ID, warehouse.Code, warehouse.Name); if (warehouse.Manager != null) { lineData.WhMan = new CommonArchiveDataDTOData(warehouse.Manager.ID, warehouse.Manager.Code, warehouse.Manager.Name); headData.WhMan = warehouse.Manager.ID; } lineData.StoreType = 4; lineData.CostPrice = 4; lineData.CostUOM = new CommonArchiveDataDTOData(itemMaster.CostUOM.ID, itemMaster.CostUOM.Code, itemMaster.CostUOM.Name); lineData.StoreUOM = new CommonArchiveDataDTOData(itemMaster.InventorySecondUOM.ID, itemMaster.InventorySecondUOM.Code, itemMaster.InventorySecondUOM.Name); lineData.Memo = item.Memo; lineData.StoreUOMQty = item.StoreUOMQty; headData.MiscRcvTransLs.Add(lineData); num += 10; } proxy.MiscRcvDTOList.Add(headData); List resultList = proxy.Do(org.ID); MiscRcvTrans miscRcv = MiscRcvTrans.Finder.FindByID(resultList[0].ID); if (miscRcv != null) { returnDTO.IsSussece = true; returnDTO.DocNo = miscRcv.DocNo; returnDTO.ErrorMessage = ""; // 提交 审核 CommonCommitMiscRcvProxy commitProxy = new CommonCommitMiscRcvProxy(); commitProxy.MiscRcvKeys = resultList; commitProxy.Do(); CommonApproveMiscRcvProxy approveProxy = new CommonApproveMiscRcvProxy(); approveProxy.MiscRcvKeys = resultList; approveProxy.Do(); } } catch (Exception ex) { returnDTO.IsSussece = false; returnDTO.DocNo = ""; returnDTO.ErrorMessage = ex.Message; scope.Rollback(); } scope.Commit(); } return returnDTO; } } #endregion } ``` ```c# namespace UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.GetShipListSV { using Newtonsoft.Json; using System.Collections.Generic; using UFIDA.U9.SM.Ship; using UFSoft.UBF.AopFrame; using UFIDA.U9.Base; using UFIDA.U9.Base.Organization; using UFIDA.U9.CBO.SCM.Item; /// /// GetShipListService partial /// public partial class GetShipListService { internal BaseStrategy Select() { return new GetShipListServiceImpementStrategy(); } } #region implement strategy /// /// Impement Implement /// /// internal partial class GetShipListServiceImpementStrategy : BaseStrategy { public GetShipListServiceImpementStrategy() { } public override object Do(object obj) { GetShipListService bpObj = (GetShipListService)obj; Organization org = Context.LoginOrg; ReturnDtoData dto = new ReturnDtoData(); Ship.EntityList entityList = Ship.Finder.FindAll("OrderBy.Code='" + bpObj.Customer + "' and status=" + bpObj.Status + " and BusinessDate>'" + bpObj.AfterDate + "'"); //Ship.EntityList entityList = Ship.Finder.FindAll("OrderBy.Code='" + bpObj.Customer + "' and status=" + bpObj.Status); dto.IsSussece = false; dto.ErrorMessage = "112"; List orders = new List(); foreach (var item in entityList) { ShipOrder order = new ShipOrder(); order.docNo = item.DocNo; order.createBy = item.CreatedBy; List details = new List(); ShipLine.EntityList lines = item.ShipLines; foreach (var line in lines) { ShipOrderDetail detail = new ShipOrderDetail(); ShipLine.ItemInfo itemInfo = line.ItemInfo; //detail.itemCode = line.ItemInfo; detail.dscription = ""; detail.quantity = ""; detail.price = ""; detail.whsCode = ""; } orders.Add(order); } dto.Data = JsonConvert.SerializeObject(orders); return dto; } } public class ShipOrder { public string docNo; public string createBy; public List details; } public class ShipOrderDetail { public string itemCode; public string dscription; public string quantity; public string price; public string whsCode; } #endregion } ``` 4、执行AutoBuild.bat脚本 5、接口请求 ```json { "context": { "CultureName": "zh-CN", "OrgCode": "540", "UserCode": "admin", "EntCode": "100" }, "miscRcvDocType": "ZS50010", "businessDate": "2023-02-08", "memo": "4444", "lineDTOs": [ { "ItemCode": "331012075", "StoreUOMQty": 180, "WhCode": "1001", "Memo": "3333" } ] } ``` 补丁制作 ``` copy .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Deploy.dll D:\yonyou\U9V60\Portal\ApplicationLib copy .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Deploy.pdb D:\yonyou\U9V60\Portal\ApplicationLib copy .\BpAgent\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Agent.dll D:\yonyou\U9V60\Portal\ApplicationLib copy .\BpAgent\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Agent.pdb D:\yonyou\U9V60\Portal\ApplicationLib copy .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Deploy.dll D:\yonyou\U9V60\Portal\ApplicationServer\Libs copy .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Deploy.pdb D:\yonyou\U9V60\Portal\ApplicationServer\Libs copy .\BpAgent\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Agent.dll D:\yonyou\U9V60\Portal\ApplicationServer\Libs copy .\BpAgent\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Agent.pdb D:\yonyou\U9V60\Portal\ApplicationServer\Libs copy .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.dll D:\yonyou\U9V60\Portal\ApplicationServer\Libs copy .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.pdb D:\yonyou\U9V60\Portal\ApplicationServer\Libs copy .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.ubfsvc D:\yonyou\U9V60\Portal\ApplicationServer\Libs copy .\BpImplement\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.IService.svc D:\yonyou\U9V60\Portal\RestServices 补丁 .\BpAgent\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Agent.dll .\BpAgent\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Agent.pdb .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Deploy.dll .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.Deploy.pdb .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.dll .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.pdb .\BpImplement\bin\Debug\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.ubfsvc .\BpImplement\UFIDA.U9.ZF.Cust.HZZFSHXM02.LZK.Test.IService.svc D:\yonyou\U9V60\Portal\ApplicationLib D:\yonyou\U9V60\Portal\ApplicationServer\Libs D:\yonyou\U9V60\Portal\RestServices ``` [U9轻量服务项目学习(创建、配置) 阶段一 - 既来之.则安之 - 博客园 (cnblogs.com)](https://www.cnblogs.com/youmin3205/p/14784994.html) [U9二次开发之轻量服务项目开发_u9c二次开发-CSDN博客](https://blog.csdn.net/zhanyd/article/details/134500849) ## BP定时开发 [U9二次开发之BP定时任务插件开发_ufidau9 iprojectserviceproxy-CSDN博客](https://blog.csdn.net/zhanyd/article/details/126635853) ## 插件开发流程 ### 1、添加解决方案 新建解决方案、添加项目、添加事件集、添加事件 ### 2、生成代码 ### 3、编写代码 ### 4、打包 ``` 将D:\yonyou\UFIDA\SHPXProject\Plug\UFIDA.U9.Cust.SHPX.Plug\BEPLug\SO xml文件拷贝到 D:\yonyou\U9V60\Portal\bin 将D:\yonyou\UFIDA\SHPXProject\Plug\UFIDA.U9.Cust.SHPX.Plug\BEPLug\bin\Debug dll和pdb文件拷贝到 D:\yonyou\U9V60\Portal\ApplicationServer\Libs ``` [U9二次开发之BE插件开发_用友u9二次开发-CSDN博客](https://blog.csdn.net/zhanyd/article/details/126596364) ## U9插件部署【BE、BP、UI】 ### 1、BE插件部署 XML部署位置:D:\yonyou\U9V60\Portal\bin; DLL部署位置:D:\yonyou\U9V60\Portal\ApplicationServer\Libs; ### 2、BP插件部署 配置文件位置:D:\yonyou\U9V60\Portal\UBFConfig 配置目标文件:UFIDA.UBF.BPSVExtend.config (说明:BP插件配置信息均配置在该配置文件中) DLL部署位置:D:\yonyou\U9V60\Portal\ApplicationServer\Libs ### 3、UI插件部署 配置文件位置:D:\yonyou\U9V60\Portal 配置目标文件:WebPartExtend.config (说明:UI插件配置信息均配置在该配置文件中) DLL部署位置:D:\yonyou\U9V60\Portal\UILib ## U9报表开发 # SpringBoot ## 相关注解作用 ```java @EnableConfigurationProperties 注解的作用是@ConfigurationProperties注解生效 @ConfigurationProperties把properties或者yml配置文件转化为bean来使用 ```