当前位置: 首页 > news >正文

自己做网站类型网站开发代理招商

自己做网站类型,网站开发代理招商,余姚做网站首荐荣盛网络,网站首页按钮图片衡量一个人是否幸福#xff0c;不应看他有多少高兴的事#xff0c;而应看他是否为小事烦扰。只有幸福的人#xff0c;才会把无关痛痒的小事挂心上。那些真正经历巨大灾难和深重痛苦的人#xff0c;根本无暇顾及这些小事的。因此人们往往在失去幸福之后#xff0c;才会发现… 衡量一个人是否幸福不应看他有多少高兴的事而应看他是否为小事烦扰。只有幸福的人才会把无关痛痒的小事挂心上。那些真正经历巨大灾难和深重痛苦的人根本无暇顾及这些小事的。因此人们往往在失去幸福之后才会发现它们曾经存在。 在上篇我们实现了最基础的导出功能本篇我们拓展样式 API封装为通用 Jar 包提升开发者的使用友好度并且优化性能以及基本的测试。 基于 JNI Rust 实现一种高性能 Excel 导出方案上篇 一、写入表头 1、实现逻辑 1、定义一个注解作用与类字段上用于标识字段对应的表头名称 2、定义一个 Excel 导出 VO 类为每个字段添加注解如果没有注解则默认采用字段名 3、创建 WorkSheet 时通过反射获取所有字段与注解整合到一个 TreeMap然后写入表头 2、Java 部分 新增注解类 ExcelColumn /*** version: V1.0* author: 余衫马* description: Excel导出属性* data: 2024-11-28 10:26**/ Retention(RetentionPolicy.RUNTIME) // 注解在运行时可用 Target(ElementType.FIELD) // 注解作用于字段 public interface ExcelColumn {/*** 列名*/String value();}调整构造方法 调整构造方法的参数通过参数指定是否导出表头。 /*** version: V1.0* author: 余衫马* description: Excel 导出处理器* data: 2024-11-21 19:56**/ public class MyExportResultHandler implements ResultHandlerTestVo, AutoCloseable {// 省略.../*** 构造方法* 初始化一个 Excel 对象*/public MyExportResultHandler() {this(DEFAULT_SHEET_NAME, true, ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse());}/*** 构造方法* 初始化一个 Excel 对象** param writeHeader 是否需要写入表头默认 true*/public MyExportResultHandler(String sheetName, boolean writeHeader, HttpServletResponse response) {// 基本配置this.sheetName StringUtils.isEmpty(sheetName) ? DEFAULT_SHEET_NAME : sheetName;this.writeHeader writeHeader;this.startRowIndex writeHeader ? 1 : 0;this.httpServletResponse response;// 解析字段this.fieldMap getExportFieldMap();// 创建 Excel 指针Object[] objects this.fieldMap.keySet().toArray();this.handle writeHeader ? createWorksheet(this.sheetName, objects, objects.length) : createWorksheet(this.sheetName);}// 省略... }控制数据顺序 封装方法 getExportFieldMap 将导出类字段转为 TreeMap这用于控制表头顺序与写入数据的顺序。 /*** version: V1.0* author: 余衫马* description: Excel 导出处理器* data: 2024-11-21 19:56**/ public class MyExportResultHandler implements ResultHandlerTestVo, AutoCloseable {// 省略.../*** 将导出类字段转为 TreeMap** return TreeMap*/private TreeMapString, String getExportFieldMap() {// 创建 TreeMap 来存储字段名和注解值TreeMapString, String fieldMap new TreeMap();// 获取 TestVo 类的所有字段Field[] fields TestVo.class.getDeclaredFields();// 遍历所有字段for (Field field : fields) {// 检查字段是否有 ExcelColumn 注解if (field.isAnnotationPresent(ExcelColumn.class)) {// 获取注解ExcelColumn excelColumn field.getAnnotation(ExcelColumn.class);// 将注解值和字段名存储到 TreeMap 中fieldMap.put(excelColumn.value(), field.getName());} else {// 如果没有注解使用字段名作为键fieldMap.put(field.getName(), field.getName());}}// 打印 TreeMap 内容for (String key : fieldMap.keySet()) {System.out.println(key - fieldMap.get(key));}return fieldMap;}// 省略... } 写入数据逻辑 写入数据时按照 TreeMap 顺序。 /*** version: V1.0* author: 余衫马* description: Excel 导出处理器* data: 2024-11-21 19:56**/ public class MyExportResultHandler implements ResultHandlerTestVo, AutoCloseable {// 省略.../*** 获取类字段值* param obj 类实例* param fieldName 字段名* return Object* throws Exception*/public static Object getFieldValueUsingGetter(Object obj, String fieldName) throws Exception {// 获取类对象Class? clazz obj.getClass();// 构造getter方法名String getterName get Character.toUpperCase(fieldName.charAt(0)) fieldName.substring(1);// 获取getter方法Method getterMethod clazz.getMethod(getterName);// 调用getter方法并返回值return getterMethod.invoke(obj);}Overridepublic void handleResult(ResultContext? extends TestVo resultContext) {TestVo testVo resultContext.getResultObject();int row startRowIndex 0 ? resultContext.getResultCount() - 1 : resultContext.getResultCount();int col 0;try {// 处理逻辑按照 TreeMap 顺序写入数据for (String key : fieldMap.keySet()) {String fieldName fieldMap.get(key);writeToWorksheet(handle, row, col, getFieldValueUsingGetter(testVo, fieldName).toString());col col 1;}} catch (Exception e) {e.printStackTrace();}}// 省略...} 3、Rust部分 改动 createWorksheet 函数新建参数解析。 #[no_mangle] pub extern system fn Java_com_yushanma_crazyexcel_handler_MyExportResultHandler_createWorksheet(mut env: JNIEnv,_class: JClass,sheet_name: JObject,header_array: JObjectArray,header_length: jint, ) - jlong {// worksheet 为空if sheet_name.is_null() {eprintln!(sheet name argument is null);return 0;}// 需要写表头但是为空if header_length 0 header_array.is_null() {eprintln!(excel header argument is null);return 0;}let name: String match unsafe { env.get_string_unchecked(sheet_name.into()) } {Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return 0;}};let workbook Box::new(Workbook::new());let workbook_ptr Box::into_raw(workbook);// SAFETY: We just created the raw pointer from a Box, so its valid.let worksheet unsafe { (*workbook_ptr).add_worksheet().set_name(name.as_str()).unwrap() };// 写入表头if header_length 0 {let mut data: VecString Vec::with_capacity(header_length as usize);for i in 0..header_length {let e env.get_object_array_element(header_array, i).unwrap();data.push(unsafe { env.get_string_unchecked(e.into()).unwrap().into() });}if let Err(e) worksheet.write_row(0, 0, data) {eprintln!(Failed to write to worksheet: {:?}, e);// 释放指针unsafe {let _ Box::from_raw(workbook_ptr);}return 0;}}let handle Box::new(WorksheetHandle {workbook: workbook_ptr,worksheet,});Box::into_raw(handle) as jlong }4、运行效果 给 TestVo 的后 5 个字段添加表头注解 可以看到表头与数据的顺序保持一致。 二、配置样式 1、常见样式 宽度高度 // Set the column width for clarity. worksheet.set_column_width(0, 22)?;// Set the row height in Excel character units. worksheet.set_row_height(0, 30)?;字体加粗 let bold_format Format::new().set_bold(); // Write a string with the bold format defined above. worksheet.write_with_format(1, 0, World, bold_format)?;日期格式 let date_format Format::new().set_num_format(yyyy-mm-dd); // Write a date. let date ExcelDateTime::from_ymd(2024, 11, 30)?; worksheet.write_with_format(6, 0, date, date_format)?;小数格式 let decimal_format Format::new().set_num_format(0.000); // Write a number with formatting. worksheet.write_with_format(4, 0, 3.00, decimal_format)?;颜色相关 // 字体颜色 let format Format::new().set_font_color(Color::Red); // let format Format::new().set_font_color(Color::RGB(0x000000)); worksheet.write_string_with_format(0, 0, Wheelbarrow, format)?;// 背景颜色 let format1 Format::new().set_background_color(Color::Green); // let format1 Format::new().set_font_color(Color::RGB(0x000000)); worksheet.write_string_with_format(0, 0, Rust, format1)?;Url 超链接 // Write some links. worksheet.write(7, 0, Url::new(https://www.rust-lang.org))?; worksheet.write(8, 0, Url::new(https://www.rust-lang.org).set_text(Rust))?;2、实现逻辑 Java添加注解属性拓展对应字段的属性同样通过反射机制将属性解析到 TreeMapString,ObjectRust解析是否有格式没有则采用默认格式 3、实现表头样式 Java 部分 新增注解属性 /*** version: V1.0* author: 余衫马* description: Excel导出属性* data: 2024-11-28 10:26**/ Retention(RetentionPolicy.RUNTIME) // 注解在运行时可用 Target(ElementType.FIELD) // 注解作用于字段 public interface ExcelColumn {/*** 列名*/String value();/*** 宽度* return int*/int columnWidth() default 0;/*** 高度* return int*/int rowHeight() default 0;/*** 字体加粗* return boolean*/boolean bold() default false;/*** 时间格式* return String*/String dateFormat() default yyyy-mm-dd;/*** 小数格式* return String*/String decimalFormat() default 0.000;/*** 字体颜色* return int*/int fontColor() default 0x000000;/*** 背景颜色* return int*/int backgroundColor() default 0xFFFFFF;/*** 是否超链接* return boolean*/boolean isLink() default false; }构造函数解析导出属性 /*** version: V1.0* author: 余衫马* description: Excel 导出处理器* data: 2024-11-21 19:56**/ public class MyExportResultHandler implements ResultHandlerTestVo, AutoCloseable {// 省略.../*** 解析字段类型** param fieldType 字段* return int*/private int parseFieldType(Class? fieldType) {// 确定字段类型if (fieldType String.class) {// Stringreturn 0;} else if (fieldType Date.class) {// Datereturn 1;} else if (fieldType java.sql.Timestamp.class || fieldType java.time.LocalDateTime.class) {// DateTimereturn 2;} else if (Number.class.isAssignableFrom(fieldType) || fieldType.isPrimitive()) {// Numberreturn 3;} else {// Unknownreturn 99;}}/*** 将导出类字段转为 TreeMap** return TreeMap*/public TreeMapString, Object getExportFieldMap() {// 创建 TreeMap 来存储字段名和注解值TreeMapString, Object fieldMap new TreeMap();// 获取 TestVo 类的所有字段Field[] fields TestVo.class.getDeclaredFields();// 遍历所有字段for (Field field : fields) {int fieldType parseFieldType(field.getType());// 创建 ExcelColumnProperties 对象ExcelColumnProperties properties new ExcelColumnProperties();properties.setFieldType(fieldType);properties.setFieldName(field.getName());// 检查字段是否有 ExcelColumn 注解if (field.isAnnotationPresent(ExcelColumn.class)) {// 获取注解ExcelColumn excelColumn field.getAnnotation(ExcelColumn.class);// 设置属性properties.setColumnName(excelColumn.value());properties.setColumnWidth(excelColumn.columnWidth());properties.setRowHeight(excelColumn.rowHeight());properties.setBold(excelColumn.bold());properties.setDateFormat(excelColumn.dateFormat());properties.setDecimalFormat(excelColumn.decimalFormat());properties.setFontColor(excelColumn.fontColor());properties.setBackgroundColor(excelColumn.backgroundColor());properties.setIsLink(excelColumn.isLink());// 将注解值和字段名存储到 TreeMap 中fieldMap.put(excelColumn.value(), properties);} else {// 设置默认属性properties.setColumnName(field.getName());properties.setColumnWidth(0);properties.setRowHeight(0);properties.setBold(false);properties.setDateFormat(DEFAULT_DATE_FORMAT);properties.setDecimalFormat(DEFAULT_DECIMAL_FORMAT);properties.setFontColor(DEFAULT_FONT_COLOR_RGB);properties.setBackgroundColor(0xFFFFFF);properties.setIsLink(DEFAULT_IS_LINK);// 将字段名存储到 TreeMap 中fieldMap.put(field.getName(), properties);}}// 打印 TreeMap 内容for (String key : fieldMap.keySet()) {System.out.println(key - fieldMap.get(key));}return fieldMap;}// 省略... }创建 worksheet 时使用默认表头样式 /*** version: V1.0* author: 余衫马* description: Excel 导出处理器* data: 2024-11-21 19:56**/ public class MyExportResultHandler implements ResultHandlerTestVo, AutoCloseable {// 省略...private final static Integer DEFAULT_COLUMN_WIDTH 50;private final static Integer DEFAULT_ROW_HEIGHT 26;private final static Boolean DEFAULT_BOLD true;private final static Integer DEFAULT_FONT_COLOR_RGB 0x000000;private final static Integer DEFAULT_BG_COLOR_RGB 0x808080;private final static Boolean DEFAULT_IS_LINK false;private final static String DEFAULT_DATE_FORMAT yyyy-mm-dd;private final static String DEFAULT_DECIMAL_FORMAT 0.000;/*** 创建一个 Worksheet** param sheetName worksheet name* param headers 表头数组* param length 表头列数* param columnWidth 列宽度* param rowHeight 行高度* param bold 字体加粗* param fontColorRgb 字体颜色* param backgroundColorRgb 背景颜色* return 指针 handle*/private native long createWorksheet(String sheetName, Object[] headers, int length,int columnWidth, int rowHeight, boolean bold,int fontColorRgb, int backgroundColorRgb);/*** 构造方法* 初始化一个 Excel 对象** param writeHeader 是否需要写入表头默认 true*/public MyExportResultHandler(String sheetName, boolean writeHeader, HttpServletResponse response) {// 基本配置this.sheetName StringUtils.isEmpty(sheetName) ? DEFAULT_SHEET_NAME : sheetName;this.writeHeader writeHeader;this.startRowIndex writeHeader ? 1 : 0;this.httpServletResponse response;// 解析字段this.fieldMap getExportFieldMap();// 创建 Excel 指针Object[] objects this.fieldMap.keySet().toArray();this.handle writeHeader ?createWorksheet(this.sheetName, objects, objects.length,HEADER_COLUMN_WIDTH, HEADER_ROW_HEIGHT, HEADER_BOLD, HEADER_FONT_COLOR_RGB, HEADER_BG_COLOR_RGB): createWorksheet(this.sheetName);}// 省略... } Rust 部分 #[no_mangle] pub extern system fn Java_com_yushanma_crazyexcel_handler_MyExportResultHandler_createWorksheet(mut env: JNIEnv,_class: JClass,sheet_name: JObject,header_array: JObjectArray,header_length: jint,column_width: jint,row_height: jint,bold: jboolean,font_color: jint,bg_color: jint, ) - jlong {// worksheet 为空if sheet_name.is_null() {eprintln!(sheet name argument is null);return 0;}// 需要写表头但是为空if header_length 0 header_array.is_null() {eprintln!(excel header argument is null);return 0;}let name: String match unsafe { env.get_string_unchecked(sheet_name.into()) } {Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return 0;}};let workbook Box::new(Workbook::new());let workbook_ptr Box::into_raw(workbook);// SAFETY: We just created the raw pointer from a Box, so its valid.let worksheet unsafe {(*workbook_ptr).add_worksheet().set_name(name.as_str()).unwrap()};// 写入表头if header_length 0 {// Set the row height in Excel character units.if row_height 0 {worksheet.set_row_height(0, row_height).unwrap();}let mut data: VecString Vec::with_capacity(header_length as usize);for i in 0..header_length {// Set the column width for clarity.if column_width 0 {worksheet.set_column_width(i as u16, column_width).unwrap();}let e env.get_object_array_element(header_array, i).unwrap();data.push(unsafe { env.get_string_unchecked(e.into()).unwrap().into() });}// 样式let mut format Format::new();// 字体颜色format format.set_font_color(Color::RGB(font_color as u32));// 背景颜色format format.set_background_color(Color::RGB(bg_color as u32));// 字体大小format format.set_font_size(20);// 边框format format.set_border(FormatBorder::Thin);// 字体加粗if bold 1 {format format.set_bold();}// 写入数据if let Err(e) worksheet.write_row_with_format(0, 0, data, format) {eprintln!(Failed to write to worksheet: {:?}, e);// 释放指针unsafe {let _ Box::from_raw(workbook_ptr);}return 0;}}let handle Box::new(WorksheetHandle {workbook: workbook_ptr,worksheet,});Box::into_raw(handle) as jlong } 4、实现内容样式 Java 部分 /*** version: V1.0* author: 余衫马* description: Excel 导出处理器* data: 2024-11-21 19:56**/ public class MyExportResultHandler implements ResultHandlerTestVo, AutoCloseable {// 省略.../*** 把数据写入 Worksheet** param handle 指针* param row 行* param col 列* param text 内容* param columnWidth 列宽度* param rowHeight 行高度* param bold 字体加粗* param dateFormat 日期格式* param decimalFormat 小数格式* param fontColorRgb 字体颜色* param backgroundColorRgb 背景颜色* param isLink 是否超链接* param fieldType 字段类型*/private native void writeToWorksheet(long handle, int row, int col, String text,int columnWidth, int rowHeight, boolean bold,String dateFormat, String decimalFormat,int fontColorRgb, int backgroundColorRgb, boolean isLink,int fieldType);Overridepublic void handleResult(ResultContext? extends TestVo resultContext) {//invoke(resultContext.getResultObject());TestVo testVo resultContext.getResultObject();int row startRowIndex 0 ? resultContext.getResultCount() - 1 : resultContext.getResultCount();int col 0;try {// 处理逻辑按照 TreeMap 顺序写入数据for (String key : fieldMap.keySet()) {ExcelColumnProperties properties (ExcelColumnProperties) fieldMap.get(key);String fieldName properties.getFieldName();writeToWorksheet(handle, row, col, getFieldValueUsingGetter(testVo, fieldName).toString(),properties.getColumnWidth(),properties.getRowHeight(),properties.getBold(),properties.getDateFormat(),properties.getDecimalFormat(),properties.getFontColor(),properties.getBackgroundColor(),properties.getIsLink(),);col col 1;}} catch (Exception e) {e.printStackTrace();}}// 省略...}Rust 部分 #[no_mangle] pub extern system fn Java_com_yushanma_crazyexcel_handler_MyExportResultHandler_writeToWorksheet(env: JNIEnv,_class: JClass,handle_ptr: jlong,row: u32,col: u16,text: JObject,column_width: jint,row_height: jint,bold: jboolean,date_format: JString,decimal_format: JString,font_color: jint,bg_color: jint,is_link: jboolean,field_type: jint, ) {if handle_ptr 0 {eprintln!(Invalid handle pointer);return;}if text.is_null() {eprintln!(Text argument is null);return;}let handle unsafe { *(handle_ptr as *mut WorksheetHandle) };let worksheet: mut Worksheet unsafe { mut *handle.worksheet };// 列宽度if column_width 0 {worksheet.set_column_width(col, column_width).unwrap();}// 行高度if row_height 0 {worksheet.set_row_height(row, row_height).unwrap();}// 样式let mut format Format::new();// 字体颜色format format.set_font_color(Color::RGB(font_color as u32));// 背景颜色format format.set_background_color(Color::RGB(bg_color as u32));// 边框format format.set_border(FormatBorder::Thin);// 字体加粗if bold 1 {format format.set_bold();}// 写入 URLif is_link 1 {// let content: String match env.get_string(text.into()) {// Ok(java_str) java_str.into(),// Err(e) {// eprintln!(Couldnt get java string: {:?}, e);// return;// }// };let content: String match unsafe { env.get_string_unchecked(text.into()) } {Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return;}};if let Err(e) worksheet.write_with_format(row, col, Url::new(content), format) {eprintln!(Failed to write to worksheet: {:?}, e);}return;}// 写入字符串if field_type 0 {let content: String match unsafe { env.get_string_unchecked(text.into()) } {Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return;}};if let Err(e) worksheet.write_string_with_format(row, col, content, format) {eprintln!(Failed to write to worksheet: {:?}, e);}return;}// 写入日期时间if field_type 1 || field_type 2 {// 日期格式if !date_format.is_null() {let date_format: String match unsafe { env.get_string_unchecked(date_format.into()) }{Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return;}};format format.set_num_format(date_format);}let content: String match unsafe { env.get_string_unchecked(text.into()) } {Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return;}};let datetime ExcelDateTime::parse_from_str(content.as_str()).unwrap();if let Err(e) worksheet.write_datetime_with_format(row, col, datetime, format) {eprintln!(Failed to write to worksheet: {:?}, e);}return;}// 写入数字if field_type 3 {//小数格式if !decimal_format.is_null() {let decimal_format: String match unsafe { env.get_string_unchecked(decimal_format.into()) } {Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return;}};format format.set_num_format(decimal_format);}let content: String match unsafe { env.get_string_unchecked(text.into()) } {Ok(java_str) java_str.into(),Err(e) {eprintln!(Couldnt get java string: {:?}, e);return;}};let number match content.parse::f64() {Ok(number) number,Err(e) {eprintln!(Failed to parse the string: {}, e);return;}};if let Err(e) worksheet.write_number_with_format(row, col, number, format) {eprintln!(Failed to write to worksheet: {:?}, e);}return;} } 效果 三、泛型抽象 /*** version: V1.0* author: 余衫马* description: BaseExcel 导出处理器* data: 2024-12-03 18:00**/ public abstract class BaseExportResultHandlerT implements ResultHandlerT {// 省略.../*** 构造方法* 初始化一个 Excel 对象** param writeHeader 是否需要写入表头默认 true*/public BaseExportResultHandler(String sheetName, boolean writeHeader, HttpServletResponse response) {// 基本配置this.sheetName StringUtils.isEmpty(sheetName) ? DEFAULT_SHEET_NAME : sheetName;this.writeHeader writeHeader;this.startRowIndex writeHeader ? 1 : 0;this.httpServletResponse response;// 解析字段this.fieldMap getExportFieldMap();// 创建 Excel 指针Object[] objects this.fieldMap.keySet().toArray();this.handle writeHeader ?createWorksheet(this.sheetName, objects, objects.length,DEFAULT_COLUMN_WIDTH, DEFAULT_ROW_HEIGHT, DEFAULT_BOLD, DEFAULT_FONT_COLOR_RGB, DEFAULT_BG_COLOR_RGB): createWorksheet(this.sheetName);}/*** 通过 ResultHandler 流式查询数据由子类自定义实现*/public abstract void fetchDataByStream();/*** 开始导出* throws IOException*/public void startExportExcel() throws IOException {httpServletResponse.setContentType(application/vnd.ms-excel);httpServletResponse.setCharacterEncoding(utf-8);httpServletResponse.setHeader(Content-disposition, attachment;filenameout.xlsx);OutputStream outputStream httpServletResponse.getOutputStream();try {// 子类流式获取数据this.fetchDataByStream();// 写入响应流给客户端writeToStream(handle, outputStream);} finally {if (handle ! 0) {freeWorksheetHandle(handle);handle 0;}// 关闭流if (outputStream ! null) {outputStream.flush();outputStream.close();}}}// 省略...}ServiceImpl 调用 /*** version: V1.0* author: 余衫马* description: 测试 impl* data: 2024-11-21 19:59**/ Service public class TestServiceImpl implements TestService {// 省略...Overridepublic void testResultHandler(HttpServletResponse response) throws IOException {LocalDateTime startDatetime LocalDateTime.now();// try (MyExportResultHandler handler new MyExportResultHandler(mysheet1, true, response)) { // testDao.selectMillionData(handler); // }BaseExportResultHandlerTestVo handler new BaseExportResultHandlerTestVo(sheetName1, true, response) {/*** 子类重写 fetchDataByStream 自定义获取数据的方式*/Overridepublic void fetchDataByStream() {// 这里的this 指的就是 BaseExportResultHandlerTestVo handler 这个对象在这里写 mapper 调用获取数据的调用testDao.selectMillionData(this);}};// startExportExcel 方法中调用 fetchDataByStream 方法// 而 fetchDataByStream 方法中 selectMillionData 方法会调用 handler 中的 handleResult 方法handler.startExportExcel();// 计算两个时间点之间的 DurationDuration duration Duration.between(startDatetime, LocalDateTime.now());// 获取分钟、秒和毫秒long minutes duration.toMinutes();long seconds duration.getSeconds() - minutes * 60;long millis duration.toMillis() - minutes * 60 * 1000 - seconds * 1000;System.out.printf(数量100W20行耗时%d 分 %d 秒 %d 毫秒\n, minutes, seconds, millis);} }导出一波10W行20列的数据效果如下 耗时0 分 17 秒 37 毫秒 四、反射优化 这里使用了反射机制会消耗性能 /*** 获取类字段值** param obj 类实例* param fieldName 字段名* return Object* throws Exception*/public static Object getFieldValueUsingGetter(Object obj, String fieldName) throws Exception {// 获取类对象Class? clazz obj.getClass();// 构造getter方法名String getterName get Character.toUpperCase(fieldName.charAt(0)) fieldName.substring(1);// 获取getter方法Method getterMethod clazz.getMethod(getterName);// 调用getter方法并返回值return getterMethod.invoke(obj);}使用缓存优化一下 /*** 获取类字段值** param obj 类实例* param fieldName 字段名* return Object* throws Exception*/public Object getFieldValueUsingGetter(Object obj, String fieldName) throws Exception {Class? clazz obj.getClass();String getterName get Character.toUpperCase(fieldName.charAt(0)) fieldName.substring(1);// 从缓存中获取方法Method getterMethod methodCache.computeIfAbsent(getterName, k - {try {return clazz.getMethod(k);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}});// 调用getter方法并返回值return getterMethod.invoke(obj);}数量100W20行耗时3 分 35 秒 792 毫秒生成文件大小约 485M。而同样的数据量级下EasyExcel 需要 4分20秒左右。 可以看到 CPU 跟堆内存使用情况表现良好 五、导出 Jar 包 新建一个 Maven 项目 1、修改外部库加载方式 在Java中System.loadLibrary 方法只能加载系统库路径或 java.library.path 中的库而不能直接从JAR包内部加载DLL文件。为了从JAR包内加载DLL我们需要先将DLL提取到一个临时目录然后再加载它。 /*** version: V1.0* author: 余衫马* description: 从 Jar 包内加载外部库* data: 2024-12-06 13:46**/ public class NativeUtils {public static void loadLibraryFromJar(String path) throws IOException {// 获取操作系统的临时目录String tempDir System.getProperty(java.io.tmpdir);File tempFile new File(tempDir, new File(path).getName());try (InputStream is NativeUtils.class.getResourceAsStream(path);FileOutputStream fos new FileOutputStream(tempFile)) {if (is null) {throw new IllegalArgumentException(File path was not found inside JAR.);}byte[] buffer new byte[1024];int bytesRead;while ((bytesRead is.read(buffer)) ! -1) {fos.write(buffer, 0, bytesRead);}}System.load(tempFile.getAbsolutePath());}public static void loadLibrary(String libName) throws IOException {String osName System.getProperty(os.name).toLowerCase();String libPath /libs/;if (osName.contains(win)) {libPath windows/;} else if (osName.contains(mac)) {libPath macos/;} else if (osName.contains(nix) || osName.contains(nux) || osName.contains(aix)) {libPath linux/;} else {throw new UnsupportedOperationException(Unsupported operating system: osName);}libPath x86_64/;libPath System.mapLibraryName(libName);loadLibraryFromJar(libPath);}}/*** version: V1.0* author: 余衫马* description: BaseExcel 导出处理器* data: 2024-12-03 18:00**/ public abstract class BaseExportResultHandlerT implements ResultHandlerT {// 省略...static {try {NativeUtils.loadLibrary(my_excel_writer_lib);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(Failed to load native library, e);}}// 省略... }2、重新编译 Rust 库文件 查看支持的 target rustc --print target-list分别编译三个平台的库文件 cargo build --release --target x86_64-pc-windows-msvc cargo build --release --target x86_64-unknown-linux-gnu cargo build --release --target x86_64-apple-darwinwin10 cargo build --release --target x86_64-pc-windows-msvc可以看到 build 成功。 linux cargo build --release --target x86_64-unknown-linux-gnu如果编译 x86_64-unknown-linux-gnu 报错则需要先安装目标架构 error[E0463]: cant find crate for core| note: the x86_64-unknown-linux-gnu target may not be installed help: consider downloading the target with rustup target add x86_64-unknown-linux-gnuFor more information about this error, try rustc --explain E0463. error: could not compile cfg-if (lib) due to 1 previous error warning: build failed, waiting for other jobs to finish... error[E0463]: cant find crate for std | note: the x86_64-unknown-linux-gnu target may not be installed help: consider downloading the target with rustup target add x86_64-unknown-linux-gnu执行指令安装 # 安装 x86_64-unknown-linux-gnu 目标架构 rustup target add x86_64-unknown-linux-gnu没有编译环境的话直接到 Linux 上编译也可以 这里在 Deepin 系统下 build 成功。 macos cargo build --release --target x86_64-apple-darwin如果编译 x86_64-apple-darwin 报错则需要先安装目标架构 error[E0463]: cant find crate for core| note: the x86_64-apple-darwin target may not be installed help: consider downloading the target with rustup target add x86_64-apple-darwinFor more information about this error, try rustc --explain E0463. error: could not compile cfg-if (lib) due to 1 previous error warning: build failed, waiting for other jobs to finish... error[E0463]: cant find crate for std| note: the x86_64-apple-darwin target may not be installed help: consider downloading the target with rustup target add x86_64-apple-darwin 如果是 MacOS 直接安装工具链编译即可 # rustup toolchain install stable-x86_64-apple-darwin这里我是 Deepin 系统即便安装 toolchain 也用不了不过可以先安装 target然后交叉编译 rustup target add x86_64-apple-darwin直接跑编译会报错 cargo build --release --target x86_64-apple-darwin接下来我们安装 MacOS 跨平台编译工具链 # Step1 git clone https://github.com/tpoechtrager/osxcross # Step2 cd osxcross # Step3 wget -nc https://s3.dockerproject.org/darwin/v2/MacOSX10.10.sdk.tar.xz # Step4 mv MacOSX10.10.sdk.tar.xz tarballs/ # Step5 UNATTENDEDyes OSX_VERSION_MIN10.10 ./build.sh需要 clang # Required dependency clang is not installed # 安装基础构建工具 # sudo apt install build-essential sudo apt install clang需要 cmake (base) samsam-PC:~/AwesomeWorkSpace/RustStudy/osxcross$ UNATTENDEDyes OSX_VERSION_MIN10.10 ./build.sh Required dependency cmake is not installedsudo apt install cmake所需环境可以在 readme 文档中看到 重新执行 UNATTENDEDyes OSX_VERSION_MIN10.10 ./build.sh遇到报错 error while loading shared libraries: libicui18n.so.73 testing i386-apple-darwin14-clang -stdliblibc -stdc11 ... failed (ignored) testing x86_64-apple-darwin14-clang -stdliblibc -stdc11 ... failed (ignored)testing i386-apple-darwin14-clang ... /home/sam/AwesomeWorkSpace/RustStudy/osxcross/target/bin/i386-apple-darwin14-ld: error while loading shared libraries: libicui18n.so.73: cannot open shared object file: No such file or directory clang: error: unable to execute command: No such file or directory clang: error: linker command failed due to signal (use -v to see invocation)关键在于没有 libicui18n.so 这个库 sudo apt-get install libicu-dev系统自带的版本太低了我们从源码编译安装 # https://icu.unicode.org/download/73 wget https://github.com/unicode-org/icu/releases/download/release-73-1/icu4c-73_1-src.tgz#编译与安装 tar -xzf icu4c-73_1-src.tgz cd icu/source ./configure make sudo make install sudo ldconfig重新执行 UNATTENDEDyes OSX_VERSION_MIN10.10 ./build.sh可以看到已经 build 成功需要配置系统变量 sudo vim ~/.bashrc # 添加路径 export PATH/home/sam/AwesomeWorkSpace/RustStudy/osxcross/target/bin:$PATH # 刷新 source ~/.bashrc配置交叉编译工具后回归主线继续编译 x86_64-apple-darwin修改 Cargo.toml 指定链接器 [target.x86_64-apple-darwin] linker o64-clang ar x86_64-apple-darwin-ar# 指定交叉编译的编译器 export CCo64-clang export CXXo64-clang# 告诉 Cargo 使用正确的链接器和存档工具 export CARGO_TARGET_X86_64_APPLE_DARWIN_LINKERo64-clang export CARGO_TARGET_X86_64_APPLE_DARWIN_ARx86_64-apple-darwin-ar# 设置当前会话环境变量 export CC_x86_64_apple_darwino64-clang export CXX_x86_64_apple_darwino64-clang# 设置 SDKROOT 环境变量 # export SDKROOT/path/to/osxcross/target/SDK/MacOSX10.10.sdk# 清理项目 # cargo clean# 编译 cargo build -Zbuild-std --release --target x86_64-apple-darwin# 查看输出确保调用了 o64-clang 而不是系统的 cc # cargo build --target x86_64-apple-darwin -vv报错版本过高 warning: deployment target in MACOSX_DEPLOYMENT_TARGET was set to 10.10, but the minimum supported by rustc is 10.12-mmacosx-version-min10.12.0note: osxcross: error: targeted macOS version must be 10.10.0 (SDK)osxcross: error: while detecting target解决升级 SDK 版本这里升级到 10.14 版本。 注意如果是使用自己的 Clang 环境LLVM 编译的时候需要启用 lld否则期间不能编译安装 TAPI 举个例子 TAPIText-based Stubs for System Libraries是 Apple 用于处理动态库符号的一套工具。在构建 cctools-portosxcross 使用的工具集时如果系统中缺少 libtapi就会报错 ERROR: Failed TAPI checks in XXX。 # Step1、编译安装 llvm# 下载 llvm-project wget -nc https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/llvm-project-18.1.8.src.tar.xz # 解压 llvm-project-18.1.8.src.tar.xz # cd llvm-project-18.1.8.src# 创建文件夹 mkdir build cd build # sudo apt install ninja-build # 注意将默认的Debug模式换成Release模式. cmake -G Ninja -DLLVM_ENABLE_PROJECTSlld -DCMAKE_BUILD_TYPERelease ../llvm # 编译安装 sudo cmake --build . -j4 --target installcd ../# Step2、编译安装 clang # 创建文件夹 mkdir clang-build cd clang-build # 注意将默认的Debug模式换成Release模式. cmake -G Ninja -DLLVM_ENABLE_PROJECTSlld -DCMAKE_BUILD_TYPERelease ../clang # 编译安装 sudo cmake --build . -j4 --target install3、打包 jar mvn install六、使用 Jar 包 在 Resource 文件夹下新建一个 lib 文件夹把 jar 包放到文件夹下 添加项目依赖 现在我们就可以直接使用 jar 包中的方法了 或者直接在 pom.xml 添加本地 jar 依赖这适用于 Maven 项目 dependencygroupIdcom.yushanma/groupIdartifactIdBaseCrazyExcel/artifactIdversion1.0.0/version/dependency七、测试效果 Windows 下 1、10W行20列 耗时0 分 20 秒 625 毫秒 2、50W行20列 耗时1 分 36 秒 533 毫秒 3、100W行20列 耗时3 分 23 秒 413 毫秒 补充远程查看 Linux JVM Linux 配置策略 找到 Java 主目录 (base) samsam-PC:~$ which java /usr/bin/java (base) samsam-PC:~$ ls -lrt /usr/bin/java lrwxrwxrwx 1 root root 22 11月 12 17:38 /usr/bin/java - /etc/alternatives/java (base) samsam-PC:~$ ls -lrt /etc/alternatives/java lrwxrwxrwx 1 root root 46 11月 12 17:38 /etc/alternatives/java - /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java在 usr/bin/ 下创建文件 sudo vim jstatd.all.policy# 写入以下内容 grant codebase file:/usr/lib/jvm/java-8-openjdk-amd64/lib/tools.jar {permission java.security.AllPermission; };运行 jstatd nohup jstatd -J-Djava.security.policyjstatd.all.policy -p 8066 /dev/null 21 # 查看是否启动成功 # ps -ef |grep jstatd # lsof -i:8066 添加 JVM 启动参数 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.portXXXX -Dcom.sun.management.jmxremote.rmi.portXXXX -Dcom.sun.management.jmxremote.sslfalse -Dcom.sun.management.jmxremote.authenticatefalseJVM 调参 -Xms1024m -Xmx10240m -Xmn3840m -Xss512kjava -Xms1024m -Xmx8192m -Xmn3840m -Xss512k -Djava.io.tmpdir./tmp -Djava.rmi.server.hostname0.0.0.0 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port8067 -Dcom.sun.management.jmxremote.rmi.port8067 -Dcom.sun.management.jmxremote.authenticatefalse -Dcom.sun.management.jmxremote.sslfalse -jar CrazyExcel-0.0.1-SNAPSHOT.jar在本地电脑打 jdk下的bin目录启动 jvisualvm.exe 添加远程主机输入 ip 添加 JMX 连接输入端口 这样就可以连接远程主机监控 JVM 状态了。如果是本地虚拟机则使用内网 ip 连接
http://www.w-s-a.com/news/329767/

相关文章:

  • 怎么自己做网站地图网站建设弹窗代码
  • wordpress 作品集网站企业做网站建设的好处
  • 公司开发的网站健身网站开发项目总结
  • 怎样做游戏网站网站建设万首先金手指14
  • 英德建设局网站龙岩网上房地产网
  • wordpress vr网站电影网页设计尺寸
  • 做淘宝客新增网站推广怎样开一家公司
  • 企业网站有必要做吗?网站平均停留时间
  • 蘑菇街的网站建设凡科网站建设网页怎么建
  • 中国光大国际建设工程公司网站论坛是做网站还是app好
  • 地产集团网站建设高德是外国公司吗?
  • 天津市网站建站制作网站建设新报价图片欣赏
  • 怎么样在百度搜到自己的网站高端房产网站建设
  • 邯郸做移动网站多少钱ui设计好就业吗
  • 共享虚拟主机普惠版做网站产品推广包括哪些内容
  • 广州市网站建站免费咨询医生有问必答
  • app网站建设制作哪个网站可以做魔方图片
  • 教育培训网站建设方案模板下载网站文风
  • 电龙网站建设wordpress文章两端对齐
  • 做外单网站亚马逊免费的网站加速器
  • 英文网站推广工作一个虚拟主机可以做几个网站吗
  • 微网站 合同重庆电力建设设计公司网站
  • 网站怎么设置支付网站源码下载后怎么布置
  • 广州市公需课在哪个网站可以做手机商城软件下载
  • app网站建设需要什么长治网站建设公司
  • 网站模板平台广告宣传网站
  • cc域名的网站做网站放太多视频
  • 让公司做网站要注意什么建设工程公司企业文化
  • 佛山搭建建网站哪家好微信如何建立自己的公众号
  • 联想公司网站建设现状广州建网站兴田德润团队