首页
关于
壁纸
直播
留言
友链
统计
Search
1
《三国志英杰传》攻略
6,130 阅读
2
Emby客户端IOS破解
5,999 阅读
3
白嫖Emby
5,981 阅读
4
《吞食天地1》金手指代码
5,283 阅读
5
破解emby-server
4,243 阅读
moonjerx
game
age-of-empires
zx3
san-guo-zhi
尼尔:机械纪元
net
emby
learn-video
docker
torrent
photoshop
route
minio
git
ffmpeg
im
vue
gitlab
typecho
svn
alipay
nasm
srs
mail-server
tailscale
kkfileview
aria2
webdav
synology
redis
oray
chemical
mxsite
math
π
x-ui
digital-currency
server
nginx
baota
k8s
http
cloud
linux
shell
database
vpn
esxi
rancher
domain
k3s
ewomail
os
android
windows
ios
app-store
macos
develop
java
javascript
uniapp
nodejs
hbuildx
maven
android-studio
jetbrain
jenkins
css
mybatis
php
python
hardware
hard-disk
pc
RAM
software
pt
calibre
notion
office
language
literature
philosophy
travel
登录
Search
标签搜索
ubuntu
mysql
openwrt
zerotier
springboot
centos
openvpn
jdk
吞食天地2
synology
spring
idea
windows11
吞食天地1
transmission
google-play
Japanese
xcode
群晖
kiftd
MoonjerX
累计撰写
375
篇文章
累计收到
464
条评论
首页
栏目
moonjerx
game
age-of-empires
zx3
san-guo-zhi
尼尔:机械纪元
net
emby
learn-video
docker
torrent
photoshop
route
minio
git
ffmpeg
im
vue
gitlab
typecho
svn
alipay
nasm
srs
mail-server
tailscale
kkfileview
aria2
webdav
synology
redis
oray
chemical
mxsite
math
π
x-ui
digital-currency
server
nginx
baota
k8s
http
cloud
linux
shell
database
vpn
esxi
rancher
domain
k3s
ewomail
os
android
windows
ios
app-store
macos
develop
java
javascript
uniapp
nodejs
hbuildx
maven
android-studio
jetbrain
jenkins
css
mybatis
php
python
hardware
hard-disk
pc
RAM
software
pt
calibre
notion
office
language
literature
philosophy
travel
页面
关于
壁纸
直播
留言
友链
统计
搜索到
69
篇与
develop
的结果
2022-04-19
jenkins详细教程
最近花了一段时间研究jenkins这个工具。所以写下这篇文章,算是当做记录吧!一、jenkins是什么? Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson(Hudson是商用的),主要用于持续、自动的构建/测试软件项目、监控外部任务的运行(这个比较抽象,暂且写上,不做解释)。Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。常用的版本控制工具有SVN、GIT,构建工具有Maven、Ant、Gradle。二、CI/CD是什么? CI(Continuous integration,中文意思是持续集成)是一种软件开发时间。持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。借用网络图片对CI加以理解。CD(Continuous Delivery, 中文意思持续交付)是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。下图反应的是CI/CD 的大概工作模式。三、使用Jenkins进行PHP代码(单元)测试、打包。 Jenkins是一个强大的CI工具,虽然本身使用Java开发,但也能用来做其他语言开发的项目CI。下面讲解如何使用Jenkins创建一个构建任务。 登录Jenkins, 点击左侧的新建,创建新的构建任务。跳转到如下界面。任务名称可以自行设定,但需要全局唯一。输入名称后选择构建一个自由风格的软件项目(其他选项不作介绍)。并点击下方的确定按钮即创建了一个构建任务。之后会自动跳转到该job的配置页面。下图是构建任务设置界面,可以看到上方的几个选项"General", "源码管理", "构建触发器","构建环境", "构建", "构建后操作"。下面逐一介绍。1.GeneralGeneral是构建任务的一些基本配置。名称,描述之类的。 项目名称: 是刚才创建构建任务步骤设置的,当然在这里也可以更改。描述: 对构建任务的描述。 丢弃旧的构建: 服务器资源是有限的,有时候保存了太多的历史构建,会导致Jenkins速度变慢,并且服务器硬盘资源也会被占满。当然下方的"保持构建天数" 和 保持构建的最大个数是可以自定义的,需要根据实际情况确定一个合理的值。其他几个选项在这里不做介绍,有兴趣的可以查看Jenkins"帮助信息", 会有一个大概的介绍。不过这些"帮助信息"都是英文的。2.源码管理源码管理就是配置你代码的存放位置。Git: 支持主流的github 和gitlab代码仓库。因我们的研发团队使用的是gitlab,所以下面我只会对该项进行介绍。Repository URL:仓库地址Credentials:凭证。可以使用HTTP方式的用户名密码,也可以是RSA文件。 但要通过后面的"ADD"按钮添加凭证。Branches to build:构建的分支。*/master表示master分支,也可以设置为其他分支。源码浏览器:你所使用的代码仓库管理工具,如github, gitlab. URL:填入上方的仓库地址即可。Version: 8.7 这个是我们gitlab服务器的版本。Subversion:就是SVN,这里不作介绍。3.构建触发器构建触发器,顾名思义,就是构建任务的触发器。触发远程构建(例如,使用脚本): 该选项会提供一个接口,可以用来在代码层面触发构建。这里不做介绍,后期可能会用到。Build after other projects are built: 该选项意思是"在其他projects构建后构建"。这里不作介绍,后期可能会用到该选项。Build periodically: 周期性的构建。很好理解,就是每隔一段时间进行构建。日程表类似 linux crontab书写格式。如下图的设置,表示每隔30分钟进行一次构建。Build when a change is pushed to GitLab:当有更改push到gitlab代码仓库,即触发构建。后面会有一个触发构建的地址,一般被称为webhooks。需要将这个地址配置到gitlab中,webhooks如何配置后面介绍。这个是常用的构建触发器。Poll SCM:该选项是配合上面这个选项使用的。当代码仓库发生改动,jenkins并不知道。需要配置这个选项,周期性的去检查代码仓库是否发生改动。4.构建环境构建环境就是构建之前的一些准备工作,如指定构建工具(在这里我使用ant)。With Ant:选择这个工具,并指定ant版本和jdk版本。这两个工具的版本我都事先在服务器上安装,并且在jenkins全局工具中配置好了。其他选项不作介绍,同样可以查看"帮助信息" 获得使用帮助。5.构建选择下方的增加构建步骤。可以选择的项很多。这里就介绍"Invoke Ant" 和"Execute shell".Eexcute shell: 执行shell命令,该工具是针对linux环境的,windows环境也有对应的工 具"Execute Windows batch command"。 在构建之前,可能我们需要执行一些命令,比如压缩包的解压之类的。为了演示,我就简单的执行 "echo $RANDOM" 这样的linux shell下生产随机数命令。Invoke Ant:Ant是一款java项目构建工具,当然也能用来构建php。Ant Version: 选择Ant版本。这个ant版本是安装在jenkins服务器上的版本,并且需要在jenkins"系统工具"中设置好。Targets:要执行的操作,一行一个操作任务。以上图为例,build是构建,tar是打包。Build File: 是Ant构建的配置文件,如果不指定,则是在项目路径下的workspace目录中的build.xml。build.xml文件具体怎么配置,后面再细讲。properties: 设定一些变量,这些变量可以在build.xml 中被引用。Send files or execute commands over SSH:发送文件到远程主机或执行命令(脚本)Name: SSH Server的名称。SSH Server可以在jenkins-系统设置中配置。source files: 需要发送给远程主机的源文件。Remove prefix: 移除前面的路径。如果不设置这个参数,则远程主机会自动创建构建源 source files 包含的那个路径。Remote directory: 远程主机目录。Exec command:在远程主机上执行的命令,或者执行的脚本。6.构建后操作构建后操作,就是对project构建完成后的一些后续操作,比如生成相应的代码测试报告。Publish Clover PHP Coverage Report:发布代码覆盖率xml格式的文件报告。路径会在"build.xml"文件中定义Publish HTML reports:发布代码覆盖率的HTML报告。 Report Crap: 发布crap报告。E-mail Notification: 邮件通知,构建完成后发邮件到指定的邮箱。以上配置完成后,点击保存。7.其他相关配置 SSH Server配置登录jenkins -- 系统管理 -- 系统设置配置请看下图SSH Servers: 由于jenkins服务器公钥文件我已经配置好,所以之后新增SSH Servers 只需要配置这一项即可。 Name: 自定义,需要全局唯一。HostName: 主机名,直接用ip地址即可。Username: 新增Server的用户名,这里配置的是root。Remote Directory: 远程目录。jenkins服务器发送文件给新增的server默认是在这个目录。Ant 配置文件 "build.xml"接下来讲解Ant 构建配置文件"build.xml"。 之所以是build.xml 这是因为官方惯例。就好比任何编程语言的入门都会是打印"Hello world". 你也可以用其他名称代替"build.xml" .下面针对配置文件"build.xml" 关键配置进行说明。project name就是项目名称,和jenkins所创建的对应。target name="build" 就是构建的名称,和jenkins构建步骤 那里的targets对应。depends指明构建需要进行的一些操作。property 用来设置变量。fileset 这一行指明了一个文件夹,用include来指明需要包含的文件,exclude指明不包含的文件,"tar"即是打包这个文件夹中匹配到的文件。下面的这些target都是一些实际的操作步骤,比如make_runtime这个"target" 就是创建了一些目录。phpcs就是利用PHP_CodeSniffer这个工具 对PHP代码规范与质量检查工具。最后这个target "tar" 就是打包文件。因为上面的build 并没有包含这个target,所以默认情况下,执行build是不会打包文件的,所以在jenkins project配置界面,Ant构建那一步的targets,我们才会有"build" 和 "tar" 这两个targets。如果build.xml 中 "build"这个target depends中已经包含"tar" , 就不需要在jenkins中增加"tar"了。其他一些target 都是利用一些工具对php代码的操作,比如phpunit是进行php单元测试。这一些方面我没有深入的研究,只是进行了一些简单的配置,毕竟不是这方面的专业人士。配置 Gitlab webhooks在gitlab的project页面 打开settings,再打开 web hooks 。点击"ADD WEB HOOK" 添加webhook。把之前jenkins配置中的那个url 添加到这里,添加完成后,点击"TEST HOOK"进行测试,如果显示SUCCESS 则表示添加成功。配置phpunit.xmlphpunit.xml是phpunit这个工具用来单元测试所需要的配置文件。这个文件的名称同样也是可以自定义的,但是要在"build.xml"中配置好名字就行。默认情况下,用"phpunit.xml", 则不需要在"build.xml"中配置文件名。fileset dir 指定单元测试文件所在路径,include指定包含哪些文件,支持通配符匹配。当然也可以用exclude关键字指定不包含的文件。四、进行jenkins project 构建第一次配置好jenkins project之后,会自动触发一次构建。此后,每当有commit 提交到master分支(前面设置的是master分支,也可以设置为其他分支),就会触发一次构建。当然也可以在project页面手动触发构建。点击左边的"立即构建" 手动触发构建。五、构建结果说明构建状态Successful蓝色:构建完成,并且被认为是稳定的。Unstable黄色:构建完成,但被认为是不稳定的。Failed红色:构建失败。Disable灰色:构建已禁用构建稳定性构建稳定性用天气表示:晴、晴转多云、多云、小雨、雷阵雨。天气越好表示构建越稳定,反之亦然。构建历史界面 console output: 输出构建的日志信息六、jenkins权限管理由于jenkins默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,本文将使用Role Strategy Plugin。基于这个插件的权限管理设置请参考这篇文章:http://blog.csdn.net/russ44/article/details/52276222,这里不作详细介绍。至此,就可以用jenkins周而复始的进行CI了,当然jenkins是一个强大的工具,功能绝不仅仅是以上这些,其他方面要是以后用到,我会更新到这篇文章中。有疑问欢迎在下方留言。最后,放上一张Jenkins的思维导图
2022年04月19日
88 阅读
0 评论
0 点赞
2022-04-08
Android Studio生成Key Store打包含有app安装包证书的apk应用
https://blog.csdn.net/xubingtao/article/details/108887466
2022年04月08日
184 阅读
0 评论
0 点赞
2022-04-04
跨域请求如何携带cookie
前言最近在参加面试找工作,陆陆续续的面了两三家。其中面试官问到了一个问题:如何解决跨域问题?我巴巴拉拉的一顿说,大概了说了四种方法,然后面试官紧接着又问:那跨域请求怎么携带 cookie 呢?(常规的面试套路,一般都会顺着你的回答往深了问)由于之前的项目都是同源的,不牵涉跨域访问,所以一时没有回答出来,后来研究了下,所以有了这篇文章。阅读本文,你将学到:1.学会`withCredentials`属性; 2.学会`axios`配置`withCredentials`; 3.学会设置`Access-Control-Allow-Origin`属性; 4.学会设置`Access-Control-Allow-Credentials`属性; 5.学会解决跨域请求携带源站cookie的问题;一. 搭建一个跨域请求的环境思路:使用 express 搭建第一个服务A( http://localhost:8000 ),运行在8000端口上;A服务托管index.html(用于在前端页面发送网络请求)文件;在A服务中写一个处理请求的路由,加载index.html页面时,种下 cookie (这里种cookie为了在请求B服务时携带上);使用 express 搭建第二个服务B( http://localhost:8003 ),运行在8003端口上;在A服务托管的index.html页面去请求B服务,然后把 cookie 传过去;先看下代码结构,相对比较的简单:A服务的代码: // src/app1.js const express = require("express"); const app = express(); // `index.html` 加载时会请求login接口 // 设置`cookie` app.get("/login", (req, res) => { res.cookie("user", "jay", { maxAge: 2000000, httpOnly: true }); res.json({ code: 0, message: "登录成功" }); }); // 此接口是检测`cookie`是否设置成功,如果设置成功的话,浏览器会自动携带上`cookie` app.get("/user", (req, res) => { // req.headers.cookie: user=jay const user = req.headers.cookie.split("=")[1]; res.json({ code: 0, user }); }); // 托管`index.html`页面 // 这样的话在`index.html`中发起的请求,默认的源就是`http://localhost:8000` // 然后再去请求`http://localhost:8003`就会出现跨域了 app.use("/static", express.static("public")); app.listen("8000", () => { console.log("app1 running at port 8000"); });index.html的代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <h2>this is index.html at port 8000</h2> <button id="button">发送同源请求</button> <button id="cross-button">发送跨域请求</button> <script src="https://static.4ce.cn/npm/axios/dist/axios.min.js"></script> <script> const button = document.querySelector("#button"); const crossButton = document.querySelector("#cross-button"); axios.get("http://localhost:8000/login", {}).then((res) => { console.log(res); }); // 发送同域请求 button.onclick = function () { axios.get("http://localhost:8000/user", {}).then((res) => { console.log(res); }); }; // 发送跨域请求 crossButton.onclick = function () { axios({ method: "get", url: "http://localhost:8003/anotherService", }).then((res) => { console.log(res); }); }; </script> </body> </html>B服务的代码:// src/app2.js const express = require("express"); const app = express(); // 定义一个接口,index.html页面请求这个接口就是跨域(因为端口不同) app.get("/anotherService", (req, res) => { res.json({ code: 0, msg: "这是8003端口返回的" }); }); app.listen("8003", () => { console.log("app2 running at port 8003"); });这个时候环境基本就搭建好了。二、解决跨域携带cookie问题首先我们先在A服务的index.html页面中得到一个cookie,运行A服务:npm install express -D node src/app1.js然后打开 http://localhost:8000/static/index.html : 没有问题的话,页面长这样:这个时候F12打开控制台:可以看到发送了一个 login 请求,并且设置了 cookie ,也可以选择浏览器控制台的Application页签,选中cookie,可以看到cookie的信息:然后我们点击页面上的发送同源请求按钮,可以看到发送了一个user请求,并且已经携带上了cookie:接下来刺激的画面来了,我们点击 发送跨域请求 按钮,出现了跨域请求的报错:重点:接下来开始解决跨域携带cookie问题:1.在前端请求的时候设置request对象的属性withCredentials为true;什么是withCredentials?XMLHttpRequest.withCredentials 属性是一个Boolean类型,它指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。在同一个站点下使用withCredentials属性是无效的。如果在发送来自其他域的XMLHttpRequest请求之前,未设置withCredentials 为true,那么就不能为它自己的域设置cookie值。而通过设置withCredentials 为true获得的第三方cookies,将会依旧享受同源策略,因此不能被通过document.cookie或者从头部相应请求的脚本等访问。// 修改跨域请求的代码 crossButton.onclick = function () { axios({ withCredentials: true, // ++ 新增 method: "get", url: "http://localhost:8003/anotherService", }).then((res) => { console.log(res); }); };这个时候再去发送一个跨域请求,你会发现依旧报错,但是我们仔细看下报错,意思是需要设置header的 Access-Control-Allow-Origin 属性:2.在服务端设置Access-Control-Allow-Origin我们修改B(app2.js)服务的代码:// 在所有路由前增加,可以拦截所有请求 app.all("*", (req, res, next) => { res.header("Access-Control-Allow-Origin", "http://localhost:8000"); next(); });修改完之后再次发送一个跨域请求,你会发现,又报错了(接近崩溃),但是跟之前报的错不一样了,意思大概就是Access-Control-Allow-Credentials这个属性应该设置为true,但是显示得到的是个'':3.在服务端设置Access-Control-Allow-Credentials再次修改B服务的代码(每次修改后需要重新运行):// 在所有路由前增加,可以拦截所有请求 app.all("*", (req, res, next) => { res.header("Access-Control-Allow-Origin", "http://localhost:8000"); res.header("Access-Control-Allow-Credentials", "true"); // ++ 新增 next(); });再发送一个跨域请求:可以看到,这个跨域请求已经请求成功并且返回数据了!而且也携带了A服务的cookie,这个时候已经大功告成了。三、总结前端请求时在 request 对象中配置 "withCredentials": true服务端在 response 的 header 中配置 "Access-Control-Allow-Origin", "http://xxx:${port}"服务端在 response 的 header 中配置 "Access-Control-Allow-Credentials", "true"
2022年04月04日
148 阅读
0 评论
0 点赞
2022-03-27
ExcelUtils.java
package com.landicorp.cash.util; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.DecimalFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.beanutils.BeanMap; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.DataFormat; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import com.landicorp.core.util.common.DateUtil; import com.landicorp.core.util.export.annotations.CollectionExcelTarget; import com.landicorp.core.util.export.annotations.ExcelField; public class ExcelUtil { private Workbook workbook; private OutputStream os; private String pattern;// 日期格式 public void setPattern(String pattern) { this.pattern = pattern; } public ExcelUtil(Workbook workboook) { this.workbook = workboook; } public ExcelUtil(InputStream is, String version) throws FileNotFoundException, IOException { if ("2003".equals(version)) { workbook = new HSSFWorkbook(is); } else { workbook = new XSSFWorkbook(is); } } public String toString() { return "共有 " + getSheetCount() + "个sheet 页!"; } public String toString(int sheetIx) throws IOException { return "第 " + (sheetIx + 1) + "个sheet 页,名称: " + getSheetName(sheetIx) + ",共 " + getRowCount(sheetIx) + "行!"; } /** * * 根据后缀判断是否为 Excel 文件,后缀匹配xls和xlsx * * @param pathname * @return * */ public static boolean isExcel(String pathname) { if (pathname == null) { return false; } return pathname.endsWith(".xls") || pathname.endsWith(".xlsx"); } /** * 对象转map * @param obj * @return */ public static Map<String, Object> obj2Map(Object obj) { Map<String, Object> map = new HashMap<String, Object>(); try { Class<?> cls = obj.getClass(); while (!"java.lang.Object".equals(cls.getName())) { Field[] fields = cls.getDeclaredFields(); Field.setAccessible(fields, true); for (int i = 0; i < fields.length; i++) { try { String fieldName = fields[i].getName(); // 获取原来的访问控制权限 boolean accessFlag = fields[i].isAccessible(); // 修改访问控制权限 fields[i].setAccessible(true); // 获取在对象f中属性fields[i]对应的对象中的变量 if (!"serialVersionUID".equals(fieldName) && !"calss".equals(fieldName)) { String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); Object o = obj.getClass().getMethod(methodName).invoke(obj); if(null == map.get(fieldName)){ map.put(fieldName, o); } } // 恢复访问控制权限 fields[i].setAccessible(accessFlag); } catch (Exception e) { e.printStackTrace(); } } cls = cls.getSuperclass(); } } catch (Exception e) { e.printStackTrace(); } return map; } /** * 对象转map * @param obj * @return */ public static Map<String, Object> obj2Map2(Object obj) { Map<String, Object> map = new HashMap<String, Object>(); try { Map<String, Object> objMap = new BeanMap(obj); for (Entry<String, Object> entry : objMap.entrySet()) map.put(entry.getKey(), entry.getValue()); } catch (SecurityException e) { e.printStackTrace(); } return map; } /** * 对象转map,适用于没有继承属性的对象 * @param obj * @return */ public static Map<String, Object> object2Map(Object obj) { Map<String, Object> map = new HashMap<String, Object>(); Class<? extends Object> clazz = obj.getClass(); Field[] fds = clazz.getFields(); Field[] fields = clazz.getDeclaredFields(); for (int i = 0, len = fields.length; i < len; i++) { String varName = fields[i].getName(); try { // 获取原来的访问控制权限 boolean accessFlag = fields[i].isAccessible(); // 修改访问控制权限 fields[i].setAccessible(true); // 获取在对象f中属性fields[i]对应的对象中的变量 Object o = fields[i].get(obj); if (o != null) map.put(varName, o); // 恢复访问控制权限 fields[i].setAccessible(accessFlag); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } catch (IllegalAccessException ex) { ex.printStackTrace(); } } return map; } /** * * 读取 Excel 第一页所有数据 * * @return * @throws Exception * */ public List<List<String>> read() throws Exception { return read(0, 0, getRowCount(0) - 1); } /** * * 读取指定sheet 页所有数据 * * @param sheetIx * 指定 sheet 页,从 0 开始 * @return * @throws Exception */ public List<List<String>> read(int sheetIx) throws Exception { return read(sheetIx, 0, getRowCount(sheetIx) - 1); } /** * * 读取指定sheet 页指定行数据 * * @param sheetIx * 指定 sheet 页,从 0 开始 * @param start * 指定开始行,从 0 开始 * @param end * 指定结束行,从 0 开始 * @return * @throws Exception */ public List<List<String>> read(int sheetIx, int start, int end) throws Exception { Sheet sheet = workbook.getSheetAt(sheetIx); List<List<String>> list = new ArrayList<List<String>>(); if (end > getRowCount(sheetIx)) { end = getRowCount(sheetIx); } int cols = sheet.getRow(0).getLastCellNum(); // 第一行总列数 for (int i = start; i <= end; i++) { List<String> rowList = new ArrayList<String>(); Row row = sheet.getRow(i); for (int j = 0; j < cols; j++) { if (row == null) { rowList.add(null); continue; } rowList.add(getCellValueToString(row.getCell(j))); } list.add(rowList); } return list; } public static <T> List<T> importExcel(Class<T> clazz, InputStream stream, int startRow) throws Exception { Workbook workbook = WorkbookFactory.create(stream); Sheet sheet = workbook.getSheetAt(0); List<T> dataList = new ArrayList<T>(); // 获取工作表 for (int i = 0; i <= sheet.getLastRowNum(); i++) { if (i < startRow) { continue; } Row row = sheet.getRow(i); Field[] fields = clazz.getFields(); T data = clazz.newInstance(); boolean hasValue = false; for (Field fd : fields) { ExcelField ef = fd.getAnnotation(ExcelField.class); if (ef != null) { Cell cell = row.getCell(ef.cindex()); if (cell == null) { continue; } Object value = getCellValue(cell, fd.getType(), ef.defaultValue()); fd.set(data, value); if (cell.getCellTypeEnum() != CellType.BLANK) { hasValue = true; } } } if (hasValue) { Method method = clazz.getMethod("setRowNum", new Class[] { int.class }); method.invoke(data, i); dataList.add(data); } } workbook.close(); return dataList; } private static Object getCellValue(Cell cell, Class<?> fieldType, String defaultValue) throws ParseException { if (cell == null) { return null; } Object cellValue = null; boolean isDouble = false; boolean isString = false; switch (cell.getCellTypeEnum()) { case NUMERIC: cellValue = cell.getNumericCellValue(); isDouble = true; // if ((double) cellValue == 0) { // return null; // } break; case STRING: cellValue = cell.getStringCellValue(); isString = true; break; case BLANK: if (defaultValue != null && !"".equals(defaultValue)) { cellValue = defaultValue; isString = true; } break; default: { cellValue = cell.getStringCellValue(); break; } } if (cellValue == null || cellValue == "") { return null; } String typeName = fieldType.getName(); if (typeName.equals("int")) { if (!isString) { DecimalFormat df = new DecimalFormat("0"); return new Double(df.format(cellValue)).intValue(); } else { return new Double(cellValue.toString()).intValue(); } } if (typeName.equals("double")) { return new Double(cellValue + ""); } if (typeName.equals("long")) { if (!isString) { DecimalFormat df = new DecimalFormat("0"); return new Double(df.format(cellValue)).longValue(); } else { return new Double(cellValue.toString()).longValue(); } } if (typeName.equals("java.util.Date")) { return DateUtil.toDate(cellValue + "", "yyyy-MM-dd HH:mm:ss"); } if (isDouble) { DecimalFormat df = new DecimalFormat("0"); return df.format(cellValue); } return (cellValue + "").trim(); } /** * 过滤全空的行 * * @param list * @return * @throws Exception */ public List<List<String>> filterEmptyRow(List<List<String>> list) throws Exception { for (int i = 0; i < list.size(); i++) { boolean isAllEmpty = true; for (String str : list.get(i)) { if (null != str && !str.equals("")) { isAllEmpty = false; break; } } if (isAllEmpty) { list.remove(i); i--; } } return list; } /** * * 将数据写入到 Excel 默认第一页中,从第1行开始写入 * * @param rowData * 数据 * @return * @throws IOException * */ public boolean write(List<List<String>> rowData) throws IOException { return write(0, rowData, 0); } /** * * 将数据写入到 Excel 新创建的 Sheet 页 * * @param rowData * 数据 * @param sheetName * 长度为1-31,不能包含后面任一字符: :\ / ? * [ ] * @return * @throws IOException */ public boolean write(List<List<String>> rowData, String sheetName, boolean isNewSheet) throws IOException { Sheet sheet = null; if (isNewSheet) { sheet = workbook.createSheet(sheetName); } else { sheet = workbook.createSheet(); } int sheetIx = workbook.getSheetIndex(sheet); return write(sheetIx, rowData, 0); } /** * * 将数据追加到sheet页最后 * * @param rowData * 数据 * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param isAppend * 是否追加,true 追加,false 重置sheet再添加 * @return * @throws IOException */ public boolean write(int sheetIx, List<List<String>> rowData, boolean isAppend) throws IOException { if (isAppend) { return write(sheetIx, rowData, getRowCount(sheetIx)); } else {// 清空再添加 clearSheet(sheetIx); return write(sheetIx, rowData, 0); } } /** * * 将数据写入到 Excel 指定 Sheet 页指定开始行中,指定行后面数据向后移动 * * @param rowData * 数据 * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param startRow * 指定开始行,从 0 开始 * @return * @throws IOException */ public boolean write(int sheetIx, List<List<String>> rowData, int startRow) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); int dataSize = rowData.size(); if (getRowCount(sheetIx) > 0) {// 如果小于等于0,则一行都不存在 sheet.shiftRows(startRow, getRowCount(sheetIx), dataSize); } for (int i = 0; i < dataSize; i++) { Row row = sheet.createRow(i + startRow); for (int j = 0; j < rowData.get(i).size(); j++) { Cell cell = row.createCell(j); cell.setCellValue(rowData.get(i).get(j) + ""); } } return true; } /** * * 设置cell 样式 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param colIndex * 指定列,从 0 开始 * @return * @throws IOException */ public boolean setStyle(int sheetIx, int rowIndex, int colIndex, CellStyle style) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); // sheet.autoSizeColumn(colIndex, true);// 设置列宽度自适应 sheet.setColumnWidth(colIndex, 4000); Cell cell = sheet.getRow(rowIndex).getCell(colIndex); cell.setCellStyle(style); return true; } /** * * 设置样式 * * @param type * 1:标题 2:第一行 * @return */ public CellStyle makeStyle(int type) { CellStyle style = workbook.createCellStyle(); DataFormat format = workbook.createDataFormat(); style.setDataFormat(format.getFormat("@"));// // 内容样式 设置单元格内容格式是文本 style.setAlignment(CellStyle.ALIGN_CENTER);// 内容居中 // style.setBorderTop(CellStyle.BORDER_THIN);// 边框样式 // style.setBorderRight(CellStyle.BORDER_THIN); // style.setBorderBottom(CellStyle.BORDER_THIN); // style.setBorderLeft(CellStyle.BORDER_THIN); Font font = workbook.createFont();// 文字样式 if (type == 1) { // style.setFillForegroundColor(HSSFColor.LIGHT_BLUE.index);//颜色样式 // 前景颜色 // style.setFillBackgroundColor(HSSFColor.LIGHT_BLUE.index);//背景色 // style.setFillPattern(CellStyle.ALIGN_FILL);// 填充方式 font.setBold(true); font.setFontHeight((short) 500); } if (type == 2) { font.setBold(true); font.setFontHeight((short) 300); } style.setFont(font); return style; } /** * * 合并单元格 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param firstRow * 开始行 * @param lastRow * 结束行 * @param firstCol * 开始列 * @param lastCol * 结束列 */ public void region(int sheetIx, int firstRow, int lastRow, int firstCol, int lastCol) { Sheet sheet = workbook.getSheetAt(sheetIx); sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); } /** * * 指定行是否为空 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定开始行,从 0 开始 * @return true 不为空,false 不行为空 * @throws IOException */ public boolean isRowNull(int sheetIx, int rowIndex) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); return sheet.getRow(rowIndex) == null; } /** * * 创建行,若行存在,则清空 * * @param sheetIx * 指定 sheet 页,从 0 开始 * @param rownum * 指定创建行,从 0 开始 * @return * @throws IOException */ public boolean createRow(int sheetIx, int rowIndex) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); sheet.createRow(rowIndex); return true; } /** * * 指定单元格是否为空 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定开始行,从 0 开始 * @param colIndex * 指定开始列,从 0 开始 * @return true 行不为空,false 行为空 * @throws IOException */ public boolean isCellNull(int sheetIx, int rowIndex, int colIndex) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); if (!isRowNull(sheetIx, rowIndex)) { return false; } Row row = sheet.getRow(rowIndex); return row.getCell(colIndex) == null; } /** * * 创建单元格 * * @param sheetIx * 指定 sheet 页,从 0 开始 * @param rowIndex * 指定行,从 0 开始 * @param colIndex * 指定创建列,从 0 开始 * @return true 列为空,false 行不为空 * @throws IOException */ public boolean createCell(int sheetIx, int rowIndex, int colIndex) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); Row row = sheet.getRow(rowIndex); row.createCell(colIndex); return true; } /** * 返回sheet 中的行数 * * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @return */ public int getRowCount(int sheetIx) { Sheet sheet = workbook.getSheetAt(sheetIx); if (sheet.getPhysicalNumberOfRows() == 0) { return 0; } return sheet.getLastRowNum() + 1; } /** * * 返回所在行的列数 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定行,从0开始 * @return 返回-1 表示所在行为空 */ public int getColumnCount(int sheetIx, int rowIndex) { Sheet sheet = workbook.getSheetAt(sheetIx); Row row = sheet.getRow(rowIndex); return row == null ? -1 : row.getLastCellNum(); } /** * * 设置row 和 column 位置的单元格值 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定行,从0开始 * @param colIndex * 指定列,从0开始 * @param value * 值 * @return * @throws IOException */ public boolean setValueAt(int sheetIx, int rowIndex, int colIndex, String value) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); sheet.getRow(rowIndex).getCell(colIndex).setCellValue(value); return true; } /** * 返回第一页row和column位置单元格值 * * @param rowIndex * @param colIndex * @return */ public String getValueAt(int rowIndex, int colIndex) { Sheet sheet = workbook.getSheetAt(0); return getCellValueToString(sheet.getRow(rowIndex).getCell(colIndex)); } /** * * 返回 row 和 column 位置的单元格值 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定行,从0开始 * @param colIndex * 指定列,从0开始 * @return * */ public String getValueAt(int sheetIx, int rowIndex, int colIndex) { Sheet sheet = workbook.getSheetAt(sheetIx); return getCellValueToString(sheet.getRow(rowIndex).getCell(colIndex)); } /** * * 重置指定行的值 * * @param rowData * 数据 * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定行,从0开始 * @return * @throws IOException */ public boolean setRowValue(int sheetIx, List<String> rowData, int rowIndex) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); Row row = sheet.getRow(rowIndex); for (int i = 0; i < rowData.size(); i++) { row.getCell(i).setCellValue(rowData.get(i)); } return true; } /** * * 返回指定行的值的集合 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定行,从0开始 * @return */ public List<String> getRowValue(int sheetIx, int rowIndex) { Sheet sheet = workbook.getSheetAt(sheetIx); Row row = sheet.getRow(rowIndex); List<String> list = new ArrayList<String>(); if (row == null) { list.add(null); } else { for (int i = 0; i < row.getLastCellNum(); i++) { list.add(getCellValueToString(row.getCell(i))); } } return list; } /** * * 返回列的值的集合 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定行,从0开始 * @param colIndex * 指定列,从0开始 * @return */ public List<String> getColumnValue(int sheetIx, int rowIndex, int colIndex) { Sheet sheet = workbook.getSheetAt(sheetIx); List<String> list = new ArrayList<String>(); for (int i = rowIndex; i < getRowCount(sheetIx); i++) { Row row = sheet.getRow(i); if (row == null) { list.add(null); continue; } list.add(getCellValueToString(sheet.getRow(i).getCell(colIndex))); } return list; } /** * * 获取excel 中sheet 总页数 * * @return */ public int getSheetCount() { return workbook.getNumberOfSheets(); } public void createSheet() { workbook.createSheet(); } /** * * 设置sheet名称,长度为1-31,不能包含后面任一字符: :\ / ? * [ ] * * @param sheetIx * 指定 Sheet 页,从 0 开始,// * @param name * @return * @throws IOException */ public boolean setSheetName(int sheetIx, String name) throws IOException { workbook.setSheetName(sheetIx, name); return true; } /** * * 获取 sheet名称 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @return * @throws IOException */ public String getSheetName(int sheetIx) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); return sheet.getSheetName(); } /** * 获取sheet的索引,从0开始 * * @param name * sheet 名称 * @return -1表示该未找到名称对应的sheet */ public int getSheetIndex(String name) { return workbook.getSheetIndex(name); } /** * * 删除指定sheet * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @return * @throws IOException */ public boolean removeSheetAt(int sheetIx) throws IOException { workbook.removeSheetAt(sheetIx); return true; } /** * * 删除指定sheet中行,改变该行之后行的索引 * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @param rowIndex * 指定行,从0开始 * @return * @throws IOException */ public boolean removeRow(int sheetIx, int rowIndex) throws IOException { Sheet sheet = workbook.getSheetAt(sheetIx); sheet.shiftRows(rowIndex + 1, getRowCount(sheetIx), -1); Row row = sheet.getRow(getRowCount(sheetIx) - 1); sheet.removeRow(row); return true; } /** * * 设置sheet 页的索引 * * @param sheetname * Sheet 名称 * @param pos * Sheet 索引,从0开始 */ public void setSheetOrder(String sheetname, int sheetIx) { workbook.setSheetOrder(sheetname, sheetIx); } /** * * 清空指定sheet页(先删除后添加并指定sheetIx) * * @param sheetIx * 指定 Sheet 页,从 0 开始 * @return * @throws IOException */ public boolean clearSheet(int sheetIx) throws IOException { String sheetname = getSheetName(sheetIx); removeSheetAt(sheetIx); workbook.createSheet(sheetname); setSheetOrder(sheetname, sheetIx); return true; } public Workbook getWorkbook() { return workbook; } /** * * 关闭流 * * @throws IOException */ public void close() throws IOException { if (os != null) { os.close(); } workbook.close(); } /** * * 转换单元格的类型为String 默认的 <br> * 默认的数据类型:CELL_TYPE_BLANK(3), CELL_TYPE_BOOLEAN(4), * CELL_TYPE_ERROR(5),CELL_TYPE_FORMULA(2), CELL_TYPE_NUMERIC(0), * CELL_TYPE_STRING(1) * * @param cell * @return * */ private String getCellValueToString(Cell cell) { String strCell = ""; if (cell == null) { return null; } switch (cell.getCellType()) { case Cell.CELL_TYPE_BOOLEAN: strCell = String.valueOf(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_NUMERIC: if (HSSFDateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); if (pattern != null) { SimpleDateFormat sdf = new SimpleDateFormat(pattern); strCell = sdf.format(date); } else { strCell = date.toString(); } break; } // 不是日期格式,则防止当数字过长时以科学计数法显示 cell.setCellType(HSSFCell.CELL_TYPE_STRING); strCell = cell.toString(); break; case Cell.CELL_TYPE_STRING: strCell = cell.getStringCellValue(); break; default: break; } return strCell; } }
2022年03月27日
60 阅读
0 评论
0 点赞
2022-02-09
激活JetBrains 2020全系列软件
需要准备激活文件 BetterIntelliJ.zip 注意:本教程适用于 JetBrains 2020.3 全系列产品,下面以 IDEA 软件为例一、下载最新的 IDEA 2020 版本安装包1、下载地址如下,这个地址中包含了各种历史版本!来来来,热乎的!下面以3.1为例,目前可以支持到3.2https://www.jetbrains.com/idea/download/other.html2、安装idea3、安装破解插件1.安装破解补丁2.选中zip破解包3.重启idea,最好右上角关闭idea,重新打开idea。点击Restart IDE有时候无效,会报错“key is invaild”。4.输入破解key5.破解成功6.BetterIntelliJ IDEA失效的解决办法:This license BISACXYELK has been cancelled解决方法一:再次激活,然后直接点击Exit退出,然后重新打开idea,就不会弹出提示要求激活了解决方法二:以管理员方式打开命令行,运行以下命令echo 127.0.0.1 jrebel.npegeek.com >>%windir%\System32\drivers\etc\hosts以windows为例,正确配置如下:-javaagent:C:\Users\Public\.BetterIntelliJ\BetterIntelliJ-版本号.jar## 以unix为例,正确配置如下:-javaagent:${HOME}//.BetterIntelliJ/BetterIntelliJ-版本号.jar注意:破解补丁的位置不要更换,不要删除,否则激活之后还会失效5、 打开注册界面 Help -> Register,选择添加激活码(见:激活补丁key.txt),如下图所示9、 这时,你便激活成功了,到2099年~打不开IDEA?由于你安装了其它的破解补丁,需要去看看idea64.exe.vmoptions的配置对不对?建议去掉之前的 -javaagent 的配置。然后,再根据上面的教程安装咱们的破解补丁~vmoptions找不到?打开IDEA,菜单栏:Help -> Edit Custom Properties,进行修改即可
2022年02月09日
156 阅读
0 评论
0 点赞
1
...
7
8
9
...
14
您的IP: