1 qiniu云存储sdk
1 导入依赖
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.0</version>
</dependency>
2 代码untils
package com.itheima.health.utils;
import com.google.gson.Gson;
import com.itheima.health.constant.MessageConstant;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;
import java.util.ArrayList;
import java.util.List;
public class QiNiuUtils {
//七牛密匙
private static final String ACCESSKEY = "xxx";
private static final String SECRETKEY = "xxxx";
//空间名
private static final String BUCKET = "xxxx";
//外链域名
public static final String DOMAIN= "http://xxxx.com";
/**
* 遍历7牛上的所有图片
* @return
*/
public static List<String> listFile(){
BucketManager bucketManager = getBucketManager();
//列举空间文件列表, 第一个参数:图片的仓库(空间名),第二个参数,文件名前缀过滤。“”代理所有
BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(BUCKET,"");
List<String> imageFiles = new ArrayList<String>();
while (fileListIterator.hasNext()) {
//处理获取的file list结果
FileInfo[] items = fileListIterator.next();
for (FileInfo item : items) {
// item.key 文件名
imageFiles.add(item.key);
System.out.println(item.key);
}
}
return imageFiles;
}
/**
* 批量删除
* @param filenames 需要删除的文件名列表
* @return 删除成功的文件名列表
*/
public static List<String> removeFiles(String... filenames){
// 删除成功的文件名列表
List<String> removeSuccessList = new ArrayList<String>();
if(filenames.length > 0){
// 创建仓库管理器
BucketManager bucketManager = getBucketManager();
// 创建批处理器
BucketManager.Batch batch = new BucketManager.Batch();
// 批量删除多个文件
batch.delete(BUCKET,filenames);
try {
// 获取服务器的响应
Response res = bucketManager.batch(batch);
// 获得批处理的状态
BatchStatus[] batchStatuses = res.jsonToObject(BatchStatus[].class);
for (int i = 0; i < filenames.length; i++) {
BatchStatus status = batchStatuses[i];
String key = filenames[i];
System.out.print(key + "\t");
if (status.code == 200) {
removeSuccessList.add(key);
System.out.println("delete success");
} else {
System.out.println("delete failure");
}
}
} catch (QiniuException e) {
e.printStackTrace();
throw new RuntimeException(MessageConstant.PIC_UPLOAD_FAIL);
}
}
return removeSuccessList;
}
public static void uploadFile(String localFilePath, String savedFilename){
UploadManager uploadManager = getUploadManager();
String upToken = getToken();
try {
Response response = uploadManager.put(localFilePath, savedFilename, upToken);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(String.format("key=%s, hash=%s",putRet.key, putRet.hash));
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
throw new RuntimeException(MessageConstant.PIC_UPLOAD_FAIL);
}
}
//文件字节数组和文件名
public static void uploadViaByte(byte[] bytes, String savedFilename){
UploadManager uploadManager = getUploadManager();
String upToken = getToken();
try {
Response response = uploadManager.put(bytes, savedFilename, upToken);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
throw new RuntimeException(MessageConstant.PIC_UPLOAD_FAIL);
}
}
private static String getToken(){
// 创建授权
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
// 获得认证后的令牌
String upToken = auth.uploadToken(BUCKET);
return upToken;
}
private static UploadManager getUploadManager(){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone2());
//构建上传管理器
return new UploadManager(cfg);
}
private static BucketManager getBucketManager(){
// 创建授权信息
Auth auth = Auth.create(ACCESSKEY, SECRETKEY);
// 创建操作某个仓库的管理器
return new BucketManager(auth, new Configuration(Zone.zone2()));
}
}
2;POI 读取excel 工具类
A:导入依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.14</version>
</dependency>
B POI组件
Java 读取Excel表格日期类型数据的时候,读出来的是这样的 12-十月-2019,而Excel中输入的是 2019/10/12 或 2019-10-12
poi处理excel时,当excel没有明确指明是哪个类型的数据时,poi很可能处理单元格的日期数据时就有可能是一串数字,而使用java程序基本无法转换。
为了解决以上的问题,本人收集了各种资料,目前来总结一下,供碰到此类问题的你作参考。
Excel数据处理:
Excel存储日期、时间均以数值类型进行存储,读取时POI先判断是是否是数值类型,再进行判断转化
1、数值格式(CELL_TYPE_NUMERIC):
1.纯数值格式:getNumericCellValue() 直接获取数据
2.日期格式:处理yyyy-MM-dd, d/m/yyyy h:mm, HH:mm 等不含文字的日期格式
1).判断是否是日期格式:HSSFDateUtil.isCellDateFormatted(cell) 拿到的是数字
cell.getCellStyle().getDataFormatString();拿到的是格式化模板
cell.getCellStyle().getDataFormat();拿到的是short类型数字
所有日期格式都可以通过getDataFormat()值或者getDataFormatString来判断
yyyy-MM-dd----- 14
yyyy年m月d日— 31
yyyy年m月------- 57
m月d日 ---------- 58
HH:mm----------- 20
h时mm分 ------- 32
public class POIUtils {
private final static String xls = "xls";
private final static String xlsx = "xlsx";
private final static String DATE_FORMAT = "yyyy/MM/dd";
/**
* 注意,获取总行数和总列数的时候,如果直接使用获取总行数的方法,获取到的是不为空的行或者列的个数,
* 遍历会出现问题,还是用第一行和最后一行的方式去遍历
eg
一共三列或三行,第二列或第二行为空,直接用总行数获取的是2行,用第一和最后的方式获取的是3行
*/
/**
* 读入excel文件,解析后返回
*
* @param file
* @throws IOException
*/
public static List<String[]> readExcel(MultipartFile file) throws IOException {
//检查文件
checkFile(file);
//获得Workbook工作薄对象
Workbook workbook = getWorkBook(file);
//创建返回对象,把每行中的值作为一个数组,所有行作为一个集合返回
List<String[]> list = new ArrayList<>();
if (workbook != null) {
for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
//获得当前sheet工作表
Sheet sheet = workbook.getSheetAt(sheetNum);
if (sheet == null) {
continue;
}
//获得当前sheet的开始行
int firstRowNum = sheet.getFirstRowNum();
//获得当前sheet的结束行
int lastRowNum = sheet.getLastRowNum();
//获取非空总行数(用它作为总数去遍历会出现问题)
//int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();
//循环除了第一行的所有行
for (int rowNum = firstRowNum + 1; rowNum <= lastRowNum; rowNum++) {
//获得当前行
Row row = sheet.getRow(rowNum);
if (row == null) {
continue;
}
//获得当前行的开始列
int firstCellNum = row.getFirstCellNum();
//获取最后不为空的一列的下标(获取的是最有一个不为空的列的下标,即所有不为空的列数=下标+1)
int lastCellNum = row.getPhysicalNumberOfCells();
//获取最后一列的下标
//int lastCellNum = row.getLastCellNum();
String[] cells = new String[row.getPhysicalNumberOfCells()];
//循环当前行
for (int cellNum = firstCellNum; cellNum < lastCellNum; cellNum++) {
Cell cell = row.getCell(cellNum);
/**
* xssfcell重写了tostring方法,可以直接拿到单元格的值
*/
if (cell == null||StringUtils.isBlank(cell.toString().trim())) {
throw new HealthException("单元格不能为空");
}
cells[cellNum] = getCellValue(cell);
}
list.add(cells);
}
}
workbook.close();
}
return list;
}
//校验文件是否合法
public static void checkFile(MultipartFile file) throws IOException {
//判断文件是否存在
if (null == file) {
throw new FileNotFoundException("文件不存在!");
}
//获得文件名
String fileName = file.getOriginalFilename();
//判断文件是否是excel文件
if (!fileName.endsWith(xls) && !fileName.endsWith(xlsx)) {
throw new IOException(fileName + "不是excel文件");
}
}
public static Workbook getWorkBook(MultipartFile file) {
//获得文件名
String fileName = file.getOriginalFilename();
//创建Workbook工作薄对象,表示整个excel
Workbook workbook = null;
try {
//获取excel文件的io流
InputStream is = file.getInputStream();
//根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象
if (fileName.endsWith(xls)) {
//2003
workbook = new HSSFWorkbook(is);
} else if (fileName.endsWith(xlsx)) {
//2007
workbook = new XSSFWorkbook(is);
}
} catch (IOException e) {
e.printStackTrace();
}
return workbook;
}
public static String getCellValue(Cell cell) {
String cellValue = "";
if (cell == null) {
return cellValue;
}
//如果当前单元格内容为日期类型,需要特殊处理
String dataFormatString = cell.getCellStyle().getDataFormatString();
/**
* 处理时间格式时候,需要注意模板里设置的时间格式,根据格式判断格式化类型,这里只处理了一种时间格式类型,多余的参考末尾代码段
*/
if (dataFormatString.equals("m/d/yy")) {
cellValue = new SimpleDateFormat(DATE_FORMAT).format(cell.getDateCellValue());
return cellValue;
}
//把数字当成String来读,避免出现1读成1.0的情况
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
cell.setCellType(Cell.CELL_TYPE_STRING);
}
//判断数据的类型(不同类型做不同的处理,如果将日期转换为字符串类型,会得到数字)
switch (cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC: //数字
cellValue = String.valueOf(cell.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING: //字符串
cellValue = String.valueOf(cell.getStringCellValue());
break;
case Cell.CELL_TYPE_BOOLEAN: //Boolean
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_FORMULA: //公式
cellValue = String.valueOf(cell.getCellFormula());
break;
case Cell.CELL_TYPE_BLANK: //空值
cellValue = "";
break;
case Cell.CELL_TYPE_ERROR: //故障
cellValue = "非法字符";
break;
default:
cellValue = "未知类型";
break;
}
return cellValue;
}
}
------------其余时间格式类型可以参考下面------------
//获取单元格各类型值,返回字符串类型
public static String getCellValueByCell(Cell cell) {
//判断是否为null或空串
if (cell==null || cell.toString().trim().equals("")) {
return "";
}
String cellValue = "";
int cellType=cell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_NUMERIC: // 数字
short format = cell.getCellStyle().getDataFormat();
if (DateUtil.isCellDateFormatted(cell)) {
SimpleDateFormat sdf = null;
//System.out.println("cell.getCellStyle().getDataFormat()="+cell.getCellStyle().getDataFormat());
if (format == 20 || format == 32) {
sdf = new SimpleDateFormat("HH:mm");
} else if (format == 14 || format == 31 || format == 57 || format == 58) {
// 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是58)
sdf = new SimpleDateFormat("yyyy-MM-dd");
double value = cell.getNumericCellValue();
Date date = org.apache.poi.ss.usermodel.DateUtil
.getJavaDate(value);
cellValue = sdf.format(date);
}else {// 日期
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
try {
cellValue = sdf.format(cell.getDateCellValue());// 日期
} catch (Exception e) {
try {
throw new Exception("exception on get date data !".concat(e.toString()));
} catch (Exception e1) {
e1.printStackTrace();
}
}finally{
sdf = null;
}
} else {
BigDecimal bd = new BigDecimal(cell.getNumericCellValue());
cellValue = bd.toPlainString();// 数值 这种用BigDecimal包装再获取plainString,可以防止获取到科学计数值
}
break;
case Cell.CELL_TYPE_STRING: // 字符串
cellValue = cell.getStringCellValue();
break;
case Cell.CELL_TYPE_BOOLEAN: // Boolean
cellValue = cell.getBooleanCellValue()+"";;
break;
case Cell.CELL_TYPE_FORMULA: // 公式
cellValue = cell.getCellFormula();
break;
case Cell.CELL_TYPE_BLANK: // 空值
cellValue = "";
break;
case Cell.CELL_TYPE_ERROR: // 故障
cellValue = "ERROR VALUE";
break;
default:
cellValue = "UNKNOW VALUE";
break;
}
return cellValue;
}
3 写EXCEL DEMO
1.创建工作簿对象
2.创建工作表对象
3.创建行对象
4.创建列(单元格)对象, 设置内容
5.通过输出流将workbook对象下载到磁盘
public class WriteExcel {
@Test
public void createExcel() throws Exception {
// 创建工作簿,内存中
Workbook workbook = new XSSFWorkbook();
// 创建工作表
Sheet sht = workbook.createSheet("测试写excel");
// 在工作表下创建行
Row row = sht.createRow(0);// 行的下标是从0开始
// 使用行创建单元格
Cell cell = row.createCell(0);// 单元格的下标也是从0开始, 多个单元格合并后成为1个单元格
// 给单元格赋值
// 表头
cell.setCellValue("姓名");
row.createCell(1).setCellValue("年龄");
row.createCell(2).setCellValue("所在地");
row = sht.createRow(1);
row.createCell(0).setCellValue("小明");
row.createCell(1).setCellValue(20);
row.createCell(2).setCellValue("北京");
row = sht.createRow(2);
row.createCell(0).setCellValue("小李");
row.createCell(1).setCellValue(30);
row.createCell(2).setCellValue("南京");
// 保存工作簿,持久化本地硬盘里
workbook.write(new FileOutputStream(new File("d:\\createExcel.xlsx")));
// 关闭工作簿
workbook.close();
}
}
阿里云发送短信
引入依赖
<!--阿里云服务器短信平台-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0</version>
</dependency>
随机生成验证码工具类
public class ValidateCodeUtils {
/**
* 随机生成验证码
* @param length 长度为4位或者6位
* @return
*/
public static Integer generateValidateCode(int length){
Integer maxCode = new Double(Math.pow((double) 10, (double) length)).intValue();
//这里(double) length-1是先都转为double再计算
Integer minCode = new Double(Math.pow((double) 10, (double) (length-1))).intValue();
//获取验证码
Integer code = new Random().nextInt(maxCode-1);//生成随机数,最大为9999
if(code < minCode){
code = code + minCode;//保证随机数为4位数字
}
return code;
}
/**
* 随机生成指定长度字符串验证码
* @param length 长度
* @return
*/
public static String generateValidateCode4String(int length){
Random rdm = new Random();
String hash1 = Integer.toHexString(rdm.nextInt());
String capstr = hash1.substring(0, length);
return capstr;
}
}
SMSUtils工具类:(短信服务,用于发送短消息服务(SMS))
/**
* 短信发送工具类
*/
public class SMSUtils {
public static final String VALIDATE_CODE = "SMS_189616640";//发送短信验证码
public static final String ORDER_NOTICE = "SMS_159771588";//体检预约成功通知
private static final String SIGN_NAEM = "黑马程序员";// 短信的签名
private static final String PARAMETER_NAME="code";
private static final String ACCESS_KEY="LTAI4GERJj7v71F3FKjw3z2A"; //你的AccessKey ID
private static final String SECRET_KEY="dIVZnHGdUTYbqOKMlxZ7R7jXVcnPoz"; //你的AccessKey Secret
public static void main(String[] args) throws ClientException {
SMSUtils.sendShortMessage(VALIDATE_CODE,"13652431027","666666");
}
/**
* 发送短信
* @param phoneNumbers
* @param param
* @throws ClientException
*/
public static void sendShortMessage(String templateCode,String phoneNumbers,String param) throws ClientException{
// 设置超时时间-可自行调整
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
// 初始化ascClient需要的几个参数
final String product = "Dysmsapi";// 短信API产品名称(短信产品名固定,无需修改)
final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名(接口地址固定,无需修改)
// 替换成你的AK
final String accessKeyId = "LTAIak3CfAehK7cE";// 你的accessKeyId,参考本文档步骤2
final String accessKeySecret = "zsykwhTIFa48f8fFdU06GOKjHWHel4";// 你的accessKeySecret,参考本文档步骤2
// 初始化ascClient,暂时不支持多region(请勿修改)
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", ACCESS_KEY, SECRET_KEY);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
// 组装请求对象
SendSmsRequest request = new SendSmsRequest();
// 使用post提交
request.setMethod(MethodType.POST);
// 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
request.setPhoneNumbers(phoneNumbers);
// 必填:短信签名-可在短信控制台中找到
request.setSignName(SIGN_NAEM);
// 必填:短信模板-可在短信控制台中找到
request.setTemplateCode(templateCode);
// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
// 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
//request.setTemplateParam("{\"code\":\""+param+"\"}");
request.setTemplateParam(String.format("{\"%s\":\"%s\"}",PARAMETER_NAME,param));
// 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
// request.setSmsUpExtendCode("90997");
// 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
// request.setOutId("yourOutId");
// 请求失败这里会抛ClientException异常
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
// 请求成功
System.out.println("请求成功");
}else{
System.out.println(sendSmsResponse.getMessage());
}
}
}
RedisMessageConstant常量类:
package com.itheima.health.constant;
public interface RedisMessageConstant {
static final String SENDTYPE_ORDER = "001";//用于缓存体检预约时发送的验证码
static final String SENDTYPE_LOGIN = "002";//用于缓存手机号快速登录时发送的验证码
static final String SENDTYPE_GETPWD = "003";//用于缓存找回密码时发送的验证码
}
下载文件
// 工作簿写给reponse输出流
res.setContentType("application/vnd.ms-excel");
String filename = "运营统计数据报表.xlsx";
// 解决下载的文件名 中文乱码
filename = new String(filename.getBytes(), "ISO-8859-1");
// 设置头信息,告诉浏览器,是带附件的,文件下载
res.setHeader("Content-Disposition","attachement;filename=" + filename);
wk.write(os);
os.flush();
itext导出PDF
<dependencies>....
<!--导入Itext报表-->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<!-- 导入iText报表,支持中文 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
...
</dependencies>
测试代码
import com.lowagie.text.Document;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
/**
* Description: No Description
* User: Eric
*/
public class TestItext {
@Test
public void testItext() throws Exception {
// 创建文件对象
Document doc = new Document();
// 设置文件存储
PdfWriter.getInstance(doc,new FileOutputStream(new File("d:\\iText.pdf")));
// 打开文档
doc.open();
doc.add(new Paragraph("Hello World"));
// 关闭文档
doc.close();
}
}
这里注意:中文是无法生成到pdf的。
3:iText报表解决中文问题
需要设置字体(设置可以支持中文的字库 【操作系统】 , 【导入itext-asian的jar包】)
## 把 资料\iText\中文乱码\中的iTextAsian.jar 安装到仓库中
mvn install:install-file -Dfile=E:\iTextAsian.jar -DgroupId=com.alpha -DartifactId=itextasian -Dversion=1.0.0 -Dpackaging=jar
## -Dfile=E:\iTextAsian.jar iTextAsian 不要有中文空格
## idea 中的maven仓库索引更新一下
添加支持中文的jar包
<!-- 导入iText报表,支持中文 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
改成以下的
<!-- 导入iText报表,支持中文 -->
<dependency>
<groupId>com.alpha</groupId>
<artifactId>itextasian</artifactId>
<version>1.0.0</version>
</dependency>