Excel文件读取和生成_模板方法模式&建造者模式&反射

2023-11-06

一、需求说明

        系统中经常有读取各种不同表头excel的需求,如根据用户上传的数据来实现某种功能的批量操作,我们通常会根据读取的内容把数据放入不同的实体中,形成List<rowEntity>。这跟jdbctemplate中查询rowMapper方法相似,将读取的数据库字段映射至实体中,将接口作为调用该方法的参数,使用时必须实现接口中的映射方法,其实这就是模板方法模式的钩子函数。

        完成一个excel文件的读取具有固定的流程,1判断文件是否存在->2判断是否为excel->3根据excel版本新建读取对象->4按行读取文件内容->5行数据放入实体中->6返回List<rowEntity>对象,其中行数据放入实体中这一步是读取不同excel而有所差异的,可以把该步定义成抽象方法或接口,交给具体的调用方来实现。

二、Excel文件读取代码实现

2.1 引入工具包

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.5</version>
</dependency>

2.2 代码实现

 1)先创建ExcelRowMapper接口

public interface ExcelRowMapper<T> {
    T mapRow(RowSet rs);

}

2)定义Excel中Row实体,方便单元格的设置和读取

import com.mszlu.blog.utils.date.DateTimeUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;

import java.util.Date;
import java.util.Map;
public class RowSet {

    private Row row;
    private Map<String, Integer> headMap;

    public RowSet() {
        super();
    }

    /**
     * 传入字段名和字段名索引的对应关系,对应放置每一行的数据
     *
     * @param headMap
     */
    public RowSet(Map<String, Integer> headMap) {
        this.headMap = headMap;
    }

    public RowSet(Row row, Map<String, Integer> headMap) {
        this.row = row;
        this.headMap = headMap;
    }

    protected Row getRow() {
        return row;
    }

    protected void setRow(Row row) {
        this.row = row;
    }

    protected Map<String, Integer> getHeadMap() {
        return headMap;
    }

    protected void setHeadMap(Map<String, Integer> headMap) {
        this.headMap = headMap;
    }


    public Date getDate(String rowName) {
        Cell cell = this.getCell(rowName);
        if (cell == null) {
            return null;
        }
        Date date = null;
        if (cell.getCellStyle().getDataFormatString().indexOf("m/d/yy") > -1) {
            date = cell.getDateCellValue();
        } else {
            cell.setCellType(CellType.STRING);
            String dateStr = cell.getRichStringCellValue().getString();
            date = DateTimeUtil.getDateTimeStr(dateStr, null);
        }
        return date;
    }

    public Integer getInt(String rowName) {
        String val = getString(rowName);
        return StringUtils.isEmpty(val) ? null : Integer.valueOf(val);
    }

    public Long getLong(String rowName) {
        String val = getString(rowName);
        return StringUtils.isEmpty(val) ? null : Long.valueOf(val);
    }

    public Double getDouble(String rowName) {
        Cell cell = this.getCell(rowName);
        if (cell == null) {
            return null;
        }
        if (cell.getCellType() == CellType.NUMERIC) {
            return cell.getNumericCellValue();
        } else {
            return Double.valueOf(this.getString(cell));
        }
    }

    /**
     * 按文本获取cell的内容
     *
     * @param rowName
     * @return
     */
    public String getString(String rowName) {
        Cell cell = this.getCell(rowName);
        if (cell == null) {
            return null;
        }
        return this.getString(cell);
    }

    private String getString(Cell cell) {
        if (cell.getCellType() == CellType.STRING) {
            return cell.getRichStringCellValue().getString();
        } else {
            cell.setCellType(CellType.STRING);
            return cell.getRichStringCellValue().getString();
        }
    }

    private Cell getCell(String rowName) {
        Integer idx = headMap.get(rowName);
        if (idx == null) {
            return null;
        } else {
            return this.row.getCell(idx);
        }
    }

    public void setString(int i, String val) {
        row.createCell(i).setCellValue(val);
    }


}

3)定义ExcelTemplateUtil模板工具类,实现具体的读取流程

import com.mszlu.blog.utils.Exception.AppBaseException;
import com.mszlu.blog.utils.response.ResponseStatus;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.ss.usermodel.Cell;
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.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.util.*;
public class ExcelTemplateUtil {


    private static final String SUFFIX_2003 = ".xls";
    private static final String SUFFIX_2007 = ".xlsx";
    private static final String SUFFIX_CSV = ".csv";

    public static <T> List<T> parseExcel_v2(String fileName, ExcelRowMapper<T> rowMapper) {
        List<T> rows = new ArrayList<>();
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            //1、判断文件是否存在
            File file = new File(fileName);
            if (!file.exists()){
                throw new AppBaseException(fileName + "文件不存在!", ResponseStatus.FAIL.getStatus());
            }
            fis = new FileInputStream(file);
            bis = new BufferedInputStream(fis);
            //2、判断是否为Excel文件
            if (isExcelFile(bis)) {
                excelRead_v2(bis, rowMapper, rows, fileName, 0);
            } else {
                throw new AppBaseException(fileName + "不是excel文件!", ResponseStatus.FAIL.getStatus());
            }
        } catch (FileNotFoundException e) {
            throw new AppBaseException(fileName + "解析Excel报错!" + e.getMessage(), ResponseStatus.FAIL.getStatus());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    throw new AppBaseException("解析Excel关闭BufferedInputStream报错!" + e.getMessage(), ResponseStatus.FAIL.getStatus());
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new AppBaseException("解析Excel关闭FileInputStream报错!" + e.getMessage(), ResponseStatus.FAIL.getStatus());
                }
            }
        }
        return rows;
    }


    public static <T> void excelRead_v2(BufferedInputStream bis, ExcelRowMapper<T> rowMapper, List<T> dataList, String fileName, int sheetIndex) {
        Workbook workbook = null;
        try {
            //3、根据excel版本新建读取对象
            if (fileName.endsWith(SUFFIX_2003)) {
                try {
                    workbook = new HSSFWorkbook(bis);
                } catch (IOException e) {
                    if (e.getMessage().contains("XSSF")) {
                        workbook = new XSSFWorkbook(bis);
                    }
                }
            } else if (fileName.endsWith(SUFFIX_2007)) {
                try {
                    workbook = new XSSFWorkbook(bis);
                } catch (IOException e) {
                    if (e.getMessage().contains("HSSF")) {
                        workbook = new HSSFWorkbook(bis);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        //4按行读取文件内容
        Sheet sheet = workbook.getSheetAt(sheetIndex);
        int totalRows = sheet.getPhysicalNumberOfRows();

        // 获取第一行:作为表头(字段),并把表头(字段)和索引存起来
        Map<String, Integer> headerMap = new HashMap<String, Integer>();
        Row row = sheet.getRow(0);
        if (row == null) {
            throw new AppBaseException("excel的第一行不能为空!", ResponseStatus.FAIL.getStatus());
        }
        int minColIdx = row.getFirstCellNum();
        int maxColIdx = row.getLastCellNum();
        for (int colIx = minColIdx; colIx < maxColIdx; colIx++) {
            Cell cell = row.getCell(colIx);
            headerMap.put(cell.getStringCellValue(), cell.getColumnIndex());
        }
        // 封装数据
        RowSet rowSet = new RowSet(headerMap);
        for (int i = 1; i < totalRows; i++) {
            Row dataRow = sheet.getRow(i);
            if (dataRow != null) {
                //5、行数据放入实体中
                rowSet.setRow(dataRow);
                T t = rowMapper.mapRow(rowSet);
                dataList.add(t);
            }
        }
    }


    /**
     * 判断是否是EXCEL文件
     *
     * @param bis
     * @return
     */
    private static boolean isExcelFile(BufferedInputStream bis) {
        Boolean judgeResult = false;
        try {
            FileMagic fileMagic = FileMagic.valueOf(bis);
            if (Objects.equals(fileMagic, FileMagic.OLE2) || Objects.equals(fileMagic, FileMagic.OOXML)) {
                judgeResult = true;
            }
        } catch (IOException e) {
            throw new AppBaseException("判断是否excel报错!" + e.getMessage(), ResponseStatus.FAIL.getStatus());
        }
        return judgeResult;
    }

}

4)定义映射实体类

import lombok.Data;
import java.util.Date;
@Data
public class UserEntity {

    private String name;
    private int age;
    private Date date;


}

5)excel文件读取测试

public class FileReadWriteTest {

        public static void main(String[] args) {

        List<UserEntity> userEntitys = ExcelTemplateUtil.parseExcel_v2("F:\\tmp\\test.xls", rs -> {
                UserEntity userEntity = new UserEntity();
                userEntity.setName(rs.getString("name"));
                userEntity.setAge(rs.getInt("age"));
                userEntity.setDate(rs.getDate("date"));
                return userEntity;
        });

        for(UserEntity userEntity : userEntitys) {
            System.out.println(userEntity);
        }

    }
}

6)补充异常类,在项目中可以通用

/**
 * 定义项目异常基础类
 */
public class AppBaseException extends RuntimeException {

    private String msg;
    private String status;

    public AppBaseException(){

    }

    public AppBaseException(Throwable e){
        super(e);
    }

    public AppBaseException(String msg, String status){
        super(msg);
        this.msg = msg;
        this.status = status;
    }

}

7)补充统一响应码类,在项目中可以通用

/**
 * 定义项目统一响应码
 */
public enum ResponseStatus {

    /**
     * 成功
     */
    SUCCESS("0", "成功"),
    /**
     * 失败
     */
    FAIL("1", "失败"),
    /**
     * 请登录
     */
    LOGIN("2", "请登录"),
    /**
     * 参数为空
     */
    SERVICE_METHOD_PARAM_NULL("3", "参数%s为空"),
    /**
     * ID为空
     */
    SERVICE_METHOD_PARAM_ID_NULL("4", "ID为空"),
    /**
     * 数据不存在
     */
    SERVICE_DATA_NULL("5", "数据不存在"),
    /**
     * token验证出错
     */
    TOKEN_FAIL("6", "token验证出错");

    private String status;
    private String msg;


    ResponseStatus(String status, String msg){
        this.status = status;
        this.msg = msg;
    }

    public String getStatus(){
        return status;
    }

    public String getMsg(){
        return msg;
    }

}

三、Excel文件生成代码实现

        与读取excel类似,传入List<Entity>,将数据写入到不同表头的excel文件中,同样将表头和表数据写入表格中的步骤定义成抽象方法,交给具体的调用方来继承实现。

1)定义抽象类,用于写表头和表数据

import java.util.List;

public abstract class ExcelSet{

    public abstract void setValues(int i, RowSet rs);
    public abstract List<String> statementHeader();

}

2)定义创建表格的建造者类,这里使用到建造者模式,该模式将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式适用于创建对象需要很多步骤,如excel数据写入单元格,1创建工作簿->2创建sheet页->3创建行->4创建单元格->5放入单元格数据->6生成excel文件,在应用中可采用链式编程的方式来构造对象

import com.mszlu.blog.utils.Exception.AppBaseException;
import com.mszlu.blog.utils.response.ResponseStatus;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

public class ExcelBuilder {


    private XSSFWorkbook book;
    private XSSFSheet sheet;

    /**
     * 创建工作簿
     *
     * @return
     */
    public ExcelBuilder buildWorkBook() {
        this.book = new XSSFWorkbook();
        return this;
    }

    /**
     * 创建sheet
     *
     * @param sheetName
     */
    public ExcelBuilder buildSheet(String sheetName) {
        this.sheet = this.book.createSheet(sheetName);
        return this;
    }

    /**
     * 创建表头
     *
     * @param headerList
     */
    public ExcelBuilder buildHeader(List<String> headerList) {

        XSSFRow row = sheet.createRow(0);
        row.setHeightInPoints(100);

        XSSFCellStyle style = book.createCellStyle();
        //居中
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //自动换行
        style.setWrapText(true);

        for (int i = 0; i < headerList.size(); i++) {
            craeteCell(row, i, headerList.get(i), style);
        }
        return this;
    }

    public <T> ExcelBuilder buildRows(List<T> list, ExcelSet es) throws Exception {
        return this.buildRows(list.size(), es);
    }

    public ExcelBuilder buildRows(int size, ExcelSet es) throws Exception {

        RowSet rowSet = new RowSet();
        for (int i = 0; i < size; i++) {
            // 数据从第二行开始
            XSSFRow row = sheet.createRow(i + 1);
            rowSet.setRow(row);
            //设置行,并创建单元格
            es.setRow(i, rowSet);
        }
        return this;
    }

    public void build(String fileName) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(new File(fileName));
            book.write(out);
        } catch (Exception e) {
            throw new AppBaseException(fileName + "写文件失败,报错信息为:" + e.getMessage(), ResponseStatus.FAIL.getStatus());
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                throw new AppBaseException(fileName + "写文件时关闭文件流失败,报错信息为:" + e.getMessage(), ResponseStatus.FAIL.getStatus());
            }
        }
    }

    private void craeteCell(Row row, int idx, String value, CellStyle style) {
        Cell cell = row.createCell(idx);
        cell.setCellValue(value);
        cell.setCellStyle(style);
    }

}

3)定义ExcelTemplateUtil模板工具类,实现具体的写流程

public class ExcelTemplateUtil {
     /**
     * excel文件写入
     * @param fileName
     * @param size
     * @param es
     * @param <T>
     */
    public static <T> void write(String fileName, int size, ExcelSet es) {
        ExcelBuilder excelBuilder = new ExcelBuilder();
        if (size == 0) {
            //数据为0,只创建空表头
            excelBuilder.buildWorkBook().buildSheet("sheet1").buildHeader(es.setHeader()).build(fileName);
        } else {
            excelBuilder.buildWorkBook().buildSheet("sheet1").buildHeader(es.setHeader()).buildRows(size, es).build(fileName);
        }

    }

}

4)excel文件写测试

public class FileReadWriteTest {

    public static void main(String[] args) {

        List<UserEntity> userEntitys = ExcelTemplateUtil.parseExcel_v2("F:\\tmp\\test.xls", rs -> {
            UserEntity userEntity = new UserEntity();
            userEntity.setName(rs.getString("name"));
            userEntity.setAge(rs.getInt("age"));
            userEntity.setDate(rs.getDate("date"));
            return userEntity;
        });

        for (UserEntity userEntity : userEntitys) {
            System.out.println(userEntity);
        }

//        ExcelTemplateUtil.saveExcel("F:\\tmp\\test1.xls", "shee1", userEntitys);

        ExcelTemplateUtil.write("F:\\tmp\\test2.xls", userEntitys.size(), new ExcelSet(){

            @Override
            public void setRow(int i, RowSet rs){

                UserEntity userEntity = userEntitys.get(i);
                rs.setString(0, userEntity.getName());
                rs.setString(1, String.valueOf(userEntity.getAge()));
                rs.setString(2, DateTimeUtil.getDateTimeStr(userEntity.getDate(),null));
            }

            @Override
            public List<String> setHeader() {
                return Arrays.asList("姓名", "年龄", "日期");
            }
        });
    }
}

四、Excel文件读取代码实现_自动反射生成实体

        在前面第二节文件读取时,需要按列去读取每行单元格的内容再放入实体中,这里可以进一步做简化,可以根据字段名反射获取实体的set方法,自动将单元格数据放入实体属性中,这里需要根据实体的字段属性类型,将单元格的数据内容进行相应的转换,而单元格的数据内容统一当字符串读取(不好一一做判断),对于单元格是日期类型读取会有一点问题。既要判断单元格类型,又要判断实体属性类型,还要反射设置实体数据,个人不太建议这样做,下面演示一个简单版本。

1)在ExcelTemplateUtil中添加数据行转为实体的方法

public class ExcelTemplateUtil {

    public static <T> void rowToModel(RowSet rowSet, T t) {
        List<String> actualFields = rowSet.getHeadMap().keySet().stream().collect(Collectors.toList());
        Field[] fields = t.getClass().getDeclaredFields();
        if (actualFields.size() > fields.length) {
            throw new AppBaseException("读取文件的list大于entity的字段数量", ResponseStatus.FAIL.getStatus());
        }
        for (int i = 0, len = fields.length; i < len; i++) {
            //根据属性名称获取set方法
            String name = fields[i].getName();
            String setMethodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
            Class<?> clazz = t.getClass();
            try {
                Method method = clazz.getMethod(setMethodName, fields[i].getType());
                String fieldType = fields[i].getType().toString();
                if (!actualFields.contains(name)) {
                    //允许实体字段比excel字段多
                    continue;
                }
                fieldTypeTran(rowSet, t, name, method, fieldType);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw new AppBaseException("将数据转换成实体报错!" + e.getMessage(), ResponseStatus.FAIL.getStatus());
            }
        }

    }

/**
     * 根据实体类中属性的字段类型获取excel不同类型的数据并进行转换
     * @param rowSet
     * @param t
     * @param name
     * @param method
     * @param fieldType
     * @param <T>
     */
    private static <T> void fieldTypeTran(RowSet rowSet, T t, String name, Method method, String fieldType) throws InvocationTargetException, IllegalAccessException {
        switch (fieldType) {
            case "class java.util.Date":
                method.invoke(t, DateTimeUtil.getDateTimeStr(rowSet.getString(name), null));
                break;
            case "class java.lang.Boolean":
                method.invoke(t, Boolean.valueOf(rowSet.getString(name)));
                break;
            case "class java.lang.Integer":
            case "int":
                method.invoke(t, Integer.valueOf(rowSet.getString(name)));
                break;
            case "class java.lang.Long":
            case "long":
                method.invoke(t, Long.valueOf(rowSet.getString(name)));
                break;
            case "double":
                method.invoke(t, Double.valueOf(rowSet.getString(name)));
                break;
            case "float":
                method.invoke(t, Float.valueOf(rowSet.getString(name)));
                break;
            case "class java.lang.String":
            default:
                method.invoke(t, rowSet.getString(name));
                break;
        }
    }

}

2)再测试excel文件读取

public class FileReadWriteTest {

    public static void main(String[] args) {

        List<UserEntity> userEntitys = ExcelTemplateUtil.parseExcel_v2("F:\\tmp\\test.xls", rs -> {
            UserEntity userEntity = new UserEntity();
            ExcelTemplateUtil.rowToModel(rs, userEntity);
            return userEntity;
        });

        for (UserEntity userEntity : userEntitys) {
            System.out.println(userEntity);
        }
    }
}

五、结束语

以上结合设计模式对excel文件读取和生成进行工具类封装,有部分代码还是比较简陋的,博友们可以继续深化,主要有以下几点:

1、对于大文件读取,不能直接这样读入内存中,需要进行分段按流进行读写。

2、对于CSV文件读取,可以一并封装至ExcelTemplateUtil类中,实现几种常见的表格读取,对于CSV的RowSet方法相对简单,有表头字段和索引关系,字段数据内容统一按照字符串来处理就行。

3、当然其余还有很多代码内容可以优化,这里只是提供一种思路。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Excel文件读取和生成_模板方法模式&建造者模式&反射 的相关文章

  • 如何从 AccountManager.getAccounts() 获取与特定帐户关联的图标

    每个帐户的帐户设置中都会显示一个图标 对于 Google 帐户有一个图标 对于 Facebook 帐户有另一个图标 有没有办法从应用程序的代码中获取该图标 最后我解决了 private Drawable getIconForAccount
  • 我可以为 Spring Boot 应用程序创建多个入口点吗?

    In 春季启动 需要指定一个主类 它是应用程序的入口点 通常 这是一个具有标准 main 方法的简单类 如下所示 SpringBootApplication public class MySpringApplication public s
  • Maven 配置文件相当于 Gradle

    我试图在我的 spring boot 项目构建中实现一个简单的场景 包括 排除依赖项以及根据环境打包 war 或 jar 例如 对于环境dev包括开发工具和包 jar 用于prod包战等 我知道它不再是基于 XML 的配置 我基本上可以在
  • Spring Batch 多线程

    我正在编写一个 Spring Batch 并希望在需要时对其进行扩展 我的 ApplicationContext 看起来像这样 Configuration EnableBatchProcessing EnableTransactionMan
  • Eclipse 说“更新 Android Developer Toolkit”

    我不知何故弄乱了我的 Eclipse 和 Android 设置 我不知道如何修复它 问题症状如下 在 首选项 gt Android 中 我尝试选择 android sdk linux 的位置 选择时出现错误 此 Android SDK 需要
  • 将对象列表传递给 Freemarker 然后循环

    我已经熟悉了 FreeMarker 一个 Java 模板引擎 我已经能够通过哈希映射将对象传递给模板引擎了 这样就可以了 但是 一旦我尝试将任何类型的多个对象集传递给 FreeMarker 它就会给我一个 freemarker templa
  • 如何使用 Apache Camel 路由从授权服务器获取访问令牌?

    我有一个授权服务器 带有注释的简单类 SpringBootApplication RestController Configuration EnableAuthorizationServer oauth2 security 在端口上运行80
  • Spring 可以理解 @Inject 替换 Weld 作为 JSR-299 实现吗?

    我从几个网页中注意到 Spring 3 0 显然支持来自 JSR 330 的 Inject 由于我们确实希望在 Web 应用程序和独立应用程序的库中使用 JSR 299 语法进行依赖项注入 并且有 Weld 的替代方案 因此如果 Sprin
  • SwingWorker 在 Unsafe.park() 处挂起

    我有一个SwingWorker与后台服务器通信 然后更新JFrame 我正在调试我的应用程序并注意到即使在SwingWorker完成了它的工作 它的线程仍然存在 它挂在Unsafe park java lang Object 这是一个本机方
  • 全屏独占模式下的 AWT 框架在窗口弹出对话框中最小化

    我正在开发一个在全屏独占模式下使用 awt 框架的应用程序 一切正常 直到弹出窗口可见 这会抢走焦点 我的应用程序将被最小化 这是我的框架的初始化代码 if ApplicationConfig getInstance useFullscre
  • Selenium Webdriver 中显式等待 findElements

    登录后 页面重定向到一个页面 我想等待页面加载 我在其中按 tagName 查找元素 By inputArea By tagName input List
  • 指定自定义应用程序上下文

    我们正在将一些数据服务从使用 jersey spring 的 Jersey 1 x 迁移到使用 jersey spring3 的 Jersey 2 x 我们有一些继承自 JerseyTest 的测试类 其中一些类使用 web xml 文件中
  • 内容安全策略:页面设置阻止自行加载资源?

    我有基于 Java 的 Web 应用程序运行在Tomcat http en wikipedia org wiki Apache Tomcat6 我的应用程序在本地主机和端口 9001 上运行 为了使我的应用程序更加安全并降低风险XSS ht
  • 使用 Spring 注入 Google Guava Hashmultimap

    是否可以提供一个创建示例Multimap
  • 摆动刷新周期

    我试图了解何时使用重新验证 重绘 打包 令人惊讶的是 我没有找到详细的底层文档 请随意链接 到目前为止我已经明白这都是 RepaintManager 的责任 油漆 重新油漆指的是脏 干净的东西 pack validate revalidat
  • Spring @Configuration如何缓存对bean的引用

    使用基于 Java 的配置时 Spring 如何防止再次调用 bar 我想知道编译时注释处理或通过代理方法 Configuration public class AppConfig Bean public Foo foo return ne
  • Java 通用问题

    下面的代码可以编译 但如果我取消注释行 它不会编译 我很困惑为什么 HashMap 确实扩展了 AbstractMap 并且声明映射的第一行可以正常编译 import java util AbstractMap import java ut
  • 如何在其他窗口之上生成独立的 JFileChooser 对话框?

    Like 其他一些人 https stackoverflow com questions 4161207 javavm windows 7 64bit jfilechooser not showing dialog box谁问过类似的问题
  • 如何使用SAXReader解析GPX文件?

    我正在尝试解析GPX file http en wikipedia org wiki GPS eXchange Format 我用 JDOM 尝试过 但效果不太好 SAXBuilder builder new SAXBuilder Docu
  • 使用反射 API 填充 Proto 中的地图字段

    我正在尝试编写一个模块 该模块将获取 Message Builder 和从字段名称到值的映射 并将用值填充构建器 一切正常 直到我遇到地图字段 使用 Proto3 我收到一条特定消息 我知道我可以执行该消息的字段 builder b put

随机推荐