数据库表导出到excel

news2024/11/21 19:25:42

数据库表导出到excel:前置知识1 ALL_TAB_COLS
数据库表导出到excel:前置知识2 Quartz基本使用
数据库表导出到excel:前置知识3 项目封装的Quartz实现动态定时任务
数据库表导出到excel:前置知识4 业务和效果

	发起清单下载

control层InventoryDownloadLogController

/*
* 
*/
package com.njry.sjzl.busi.rest;

import com.njry.annotation.Log;
import com.njry.sjzl.busi.domain.InventoryDownloadLog;
import com.njry.sjzl.busi.service.InventoryDownloadLogService;
import com.njry.sjzl.busi.domain.vo.InventoryDownloadLogQueryCriteria;
import lombok.RequiredArgsConstructor;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njry.utils.PageResult;

/**
* @author wj
* @date 2024-06-20
**/
@RestController
@RequiredArgsConstructor
@Api(tags = "清单任务下载表管理")
@RequestMapping("/api/inventoryDownloadLog")
public class InventoryDownloadLogController {

    private final InventoryDownloadLogService inventoryDownloadLogService;

    @Log("导出数据")
    @ApiOperation("导出数据")
    @GetMapping(value = "/download")
    @PreAuthorize("@el.check('inventoryDownloadLog:list')")
    public void exportInventoryDownloadLog(HttpServletResponse response, InventoryDownloadLogQueryCriteria criteria) throws IOException {
        inventoryDownloadLogService.download(inventoryDownloadLogService.queryAll(criteria), response);
    }


    @Log("下载文件")
    @ApiOperation("下载文件")
    @GetMapping(value = "/downloadFile")
    @PreAuthorize("@el.check('inventoryDownloadLog:list')")
    public void exportInventoryDownloadLogFile(HttpServletResponse response, InventoryDownloadLogQueryCriteria criteria) throws IOException {
        String attachmentId = criteria.getAttachmentId();
        inventoryDownloadLogService.downloadFile(attachmentId, response);
    }

    @GetMapping
    @Log("查询清单任务下载日志表")
    @ApiOperation("查询清单任务下载日志表")
    @PreAuthorize("@el.check('inventoryDownloadLog:list')")
    public ResponseEntity<PageResult<InventoryDownloadLog>> queryInventoryDownloadLog(InventoryDownloadLogQueryCriteria criteria, Page<Object> page){
        return new ResponseEntity<>(inventoryDownloadLogService.queryAll(criteria,page),HttpStatus.OK);
    }

    @PostMapping
    @Log("新增清单任务下载日志表--发起-----------调度任务异步把table数据变成文件")
    @ApiOperation("新增清单任务下载日志表--发起-----------调度任务异步把table数据变成文件")
    @PreAuthorize("@el.check('inventoryDownloadLog:add')")
    public ResponseEntity<Object> createInventoryDownloadLog(@Validated @RequestBody InventoryDownloadLog resources){
        inventoryDownloadLogService.create(resources);
        return new ResponseEntity<>(HttpStatus.CREATED);
    }

//    @PutMapping
//    @Log("修改清单任务下载日志表")
//    @ApiOperation("修改清单任务下载日志表")
//    @PreAuthorize("@el.check('inventoryDownloadLog:edit')")
//    public ResponseEntity<Object> updateInventoryDownloadLog(@Validated @RequestBody InventoryDownloadLog resources){
//        inventoryDownloadLogService.update(resources);
//        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
//    }

    @DeleteMapping
    @Log("删除清单任务下载日志表")
    @ApiOperation("删除清单任务下载日志表")
    @PreAuthorize("@el.check('inventoryDownloadLog:del')")
    public ResponseEntity<Object> deleteInventoryDownloadLog(@RequestBody List<Long> ids) {
        inventoryDownloadLogService.deleteAll(ids);
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

service层

/*
*
*/
package com.njry.sjzl.busi.service;

import com.njry.sjzl.busi.domain.InventoryDownloadLog;
import com.njry.sjzl.busi.domain.vo.InventoryDownloadLogQueryCriteria;
import java.util.Map;
import java.util.List;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.njry.utils.PageResult;

/**
* @description 服务接口
* @author wj
* @date 2024-06-20
**/
public interface InventoryDownloadLogService extends IService<InventoryDownloadLog> {

    /**
    * 查询数据分页
    * @param criteria 条件
    * @param page 分页参数
    * @return PageResult
    */
    PageResult<InventoryDownloadLog> queryAll(InventoryDownloadLogQueryCriteria criteria, Page<Object> page);

    /**
    * 查询所有数据不分页
    * @param criteria 条件参数
    * @return List<InventoryDownloadLogDto>
    */
    List<InventoryDownloadLog> queryAll(InventoryDownloadLogQueryCriteria criteria);

    /**
    * 创建
    * @param resources /
    */
    void create(InventoryDownloadLog resources);

//    /**
//    * 编辑
//    * @param resources /
//    */
//    void update(InventoryDownloadLog resources);

    /**
    * 多选删除
    * @param ids /
    */
    void deleteAll(List<Long> ids);

    /**
    * 导出数据
    * @param all 待导出的数据
    * @param response /
    * @throws IOException /
    */
    void download(List<InventoryDownloadLog> all, HttpServletResponse response) throws IOException;

    /**
     * 导出文件
     * @param attachmentId 文件名
     * @param response /
     * @throws IOException /
     */
    void downloadFile(String attachmentId, HttpServletResponse response) throws IOException;

}

实现层impl(主要看create方法)

/*
*
*/
package com.njry.sjzl.busi.service.impl;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.njry.config.FileProperties;
import com.njry.sjzl.busi.attachment.domain.Attachment;
import com.njry.sjzl.busi.attachment.domain.vo.AttachmentQueryCriteria;
import com.njry.sjzl.busi.attachment.mapper.AttachmentMapper;
import com.njry.sjzl.busi.domain.Inventory;
import com.njry.sjzl.busi.domain.InventoryAuth;
import com.njry.sjzl.busi.domain.InventoryDownloadLog;
import com.njry.sjzl.busi.domain.vo.InventoryQueryCriteria;
import com.njry.sjzl.busi.mapper.AtomBusiCategoryMapper;
import com.njry.sjzl.busi.mapper.InventoryAuthMapper;
import com.njry.sjzl.busi.mapper.InventoryMapper;
import com.njry.sjzl.busi.task.GenerateExcelTask;
import com.njry.sjzl.busi.task.vo.TransferVo;
import com.njry.utils.*;
import lombok.RequiredArgsConstructor;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njry.sjzl.busi.service.InventoryDownloadLogService;
import com.njry.sjzl.busi.domain.vo.InventoryDownloadLogQueryCriteria;
import com.njry.sjzl.busi.mapper.InventoryDownloadLogMapper;
import org.apache.poi.util.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

/**
* @description 服务实现
* @author wj
* @date 2024-06-20
**/
@Service
@RequiredArgsConstructor
public class InventoryDownloadLogServiceImpl extends ServiceImpl<InventoryDownloadLogMapper, InventoryDownloadLog> implements InventoryDownloadLogService {

    private final InventoryDownloadLogMapper inventoryDownloadLogMapper;

    private final InventoryMapper inventoryMapper;

    private final AttachmentMapper attachmentMapper;

    private final FileProperties properties;

    //    递归查询所属资产
    private final AtomBusiCategoryMapper atomBusiCategoryMapper;


    @Override
    public PageResult<InventoryDownloadLog> queryAll(InventoryDownloadLogQueryCriteria criteria, Page<Object> page){
        IPage<InventoryDownloadLog> all = inventoryDownloadLogMapper.findAll(criteria, page);
        List<InventoryDownloadLog> records = all.getRecords();
        //        根据每条数据类的busiSort递归向下查找归属业务分类(回显)
        if(records.size() > 0 ){
            for (int i = 0; i < records.size(); i++) {
                Set<String> taskSetResult  = new LinkedHashSet<>();
                Long categoryId = records.get(i).getCategoryId();
                if(categoryId != null){
                    List<String> subCategory = atomBusiCategoryMapper.findSubCategory(categoryId);
                    String currentCategoryName = atomBusiCategoryMapper.findCategoryNameByCateforyId(categoryId);
                    taskSetResult.addAll(subCategory);
                    taskSetResult.add(currentCategoryName);
                    String temp = "";
                    for(String item : taskSetResult){
                        temp += ","+item;
                    }
                    String result = temp.substring(1);
                    records.get(i).setCategoryName(result);
                }
            }
        }
        return PageUtil.toPage(all);
    }

    @Override
    public List<InventoryDownloadLog> queryAll(InventoryDownloadLogQueryCriteria criteria){
        return inventoryDownloadLogMapper.findAll(criteria);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(InventoryDownloadLog resources) {
//        前端发起只传inventoryId,别的基本数据这里查完赋值
        Long inventoryId = resources.getInventoryId();
        Inventory inventory = inventoryMapper.queryDetailByInventoryId(inventoryId);
        resources.setInventoryName(inventory.getInventoryName());
        resources.setCategoryId(inventory.getCategoryId());

//        新增的时候把操作人和操作时间
        Timestamp timestamp = DateTime.now().toTimestamp();
//        String username = "System";
//        try {username = SecurityUtils.getCurrentUsername();}catch (Exception ignored){}
//        操作人
        resources.setOperId(SecurityUtils.getCurrentUserId());
        resources.setOperDate(timestamp);
//        状态:0 待生成  2 正在生成  1 数据生成完成
        resources.setStatus(2);
//        正在生成没有附件id
        resources.setAttachmentId("");
        Long seq = inventoryDownloadLogMapper.getSeq();
        resources.setId(seq);
        save(resources);
//        异步生成文件(查询数据转成excel文件)


        Long currentUserId = SecurityUtils.getCurrentUserId();

//        获取系统定义的文件路径
        String dirPath = properties.getPath().getInventory();//系统文件路径下inventory
        String separator = properties.getPath().getSeparator();//获取系统分隔符
//        /inventory/日期/
        Date currentDate = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM");
        String currentYearMonth = formatter.format(currentDate);
        System.out.println(currentYearMonth);
        dirPath += currentYearMonth + separator;


//        生成需要的参数加入队列
        TransferVo transferVo = new TransferVo();
        transferVo.setDirPath(dirPath);
        transferVo.setFileSuffix("xlsx");
        transferVo.setSeq(seq);
        transferVo.setInventoryId(inventoryId);
        transferVo.setSeparator(separator);
//        transferVo.setTableHead(tableHead);//费时间,放在异步里面
//        transferVo.setMaps(maps);//费时间,放在异步里面
        transferVo.setCurrentUserId(currentUserId);
        GenerateExcelTask.addDataList(transferVo);
    }

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void update(InventoryDownloadLog resources) {
//        InventoryDownloadLog inventoryDownloadLog = getById(resources.getId());
//        inventoryDownloadLog.copy(resources);
//        saveOrUpdate(inventoryDownloadLog);
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Long> ids) {
        removeBatchByIds(ids);
    }

    @Override
    public void download(List<InventoryDownloadLog> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (InventoryDownloadLog inventoryDownloadLog : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("唯一标识  序列", inventoryDownloadLog.getLogId());
            map.put("清单ID", inventoryDownloadLog.getInventoryId());
            map.put("清单名称", inventoryDownloadLog.getInventoryName());
            map.put("归属业务类别   T_atom_busi_category.CATEGORY_ID", inventoryDownloadLog.getCategoryId());
            map.put("操作人", inventoryDownloadLog.getOperId());
            map.put("操作时间", inventoryDownloadLog.getOperDate());
            map.put("状态:0 发起任务  2 正在生成  1 数据生成完成", inventoryDownloadLog.getStatus());
            map.put("附件编号", inventoryDownloadLog.getAttachmentId());
            map.put("提醒手机号码", inventoryDownloadLog.getMobile());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    //        将文件转成响应流给前端
    @Override
    public void downloadFile(String attachmentId, HttpServletResponse response) throws IOException {
//        根据文件id查找文件所在位置   文件名
        String fileName = "";
        String dirPath = "";
        String separator = properties.getPath().getSeparator();//获取系统分隔符

        AttachmentQueryCriteria attachmentQueryCriteria = new AttachmentQueryCriteria();
        attachmentQueryCriteria.setAttachmentId(attachmentId);
        Attachment attachment = attachmentMapper.queryAllWithCondition(attachmentQueryCriteria);
        if(attachment != null){
            dirPath = attachment.getAttachmentPath();
            fileName = attachment.getFileName();
        }
//        因为保存的时候是在默认路径下加一个watermarkPath文件夹下生成同名的文件,这里取得时候也得取水印的文件
        String watermarkPath = dirPath + "watermarkPath" + separator;
        FileInputStream watermarkFileInput = null;
        //response为HttpServletResponse对象
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
        ServletOutputStream out = response.getOutputStream();
        File watermarkFile = new File(watermarkPath, fileName);
        watermarkFileInput = new FileInputStream(watermarkFile);
        IOUtils.copy(watermarkFileInput,out);
        watermarkFile.deleteOnExit();
        watermarkFileInput.close();
    }
}

生成的文件位置

/*
 * 
 */
package com.njry.config;

import lombok.Data;
import com.njry.utils.ElConstant;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @author njry
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "file")
public class FileProperties {

    /** 文件大小限制 */
    private Long maxSize;

    /** 头像大小限制 */
    private Long avatarMaxSize;

    private ElPath mac;

    private ElPath linux;

    private ElPath windows;

    public ElPath getPath(){
//        System.getProperty() 方法用于获取系统属性的值
        String os = System.getProperty("os.name");
        if(os.toLowerCase().startsWith(ElConstant.WIN)) {
            return windows;
        } else if(os.toLowerCase().startsWith(ElConstant.MAC)){
            return mac;
        }
        return linux;
    }

    @Data
    public static class ElPath{

        private String path;

        private String avatar;

        private String inventory;

        private String separator;
    }
}

配置文件里写

# 文件存储路径
file:
  mac:
    path: ~/file/
    avatar: ~/avatar/
    inventory: /file/inventory/
    separator: /
  linux:
    path: /home/eladmin/file/
    avatar: /home/eladmin/avatar/
    inventory: /eladmin/file/inventory/
    separator: /
  windows:
    path: D:\sjzl\file\
    avatar: D:\sjzl\avatar\
#    inventory: D:\sjzl\file\inventory\ ## 不设置固定路径,相对路径自动找到项目所在盘位置
    inventory: \sjzl\file\inventory\
    separator: \
  # 文件大小 /M
  maxSize: 100
  avatarMaxSize: 5

mapper层

/*
* 
*/
package com.njry.sjzl.busi.mapper;

import com.njry.sjzl.busi.domain.InventoryDownloadLog;
import com.njry.sjzl.busi.domain.vo.InventoryDownloadLogQueryCriteria;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

/**
* @author wj
* @date 2024-06-20
**/
@Mapper
public interface InventoryDownloadLogMapper extends BaseMapper<InventoryDownloadLog> {

    IPage<InventoryDownloadLog> findAll(@Param("criteria") InventoryDownloadLogQueryCriteria criteria, Page<Object> page);

    List<InventoryDownloadLog> findAll(@Param("criteria") InventoryDownloadLogQueryCriteria criteria);

    List<String> findTableHead(@Param("tableName") String tableName,@Param("owner")  String owner);

    List<Map<String, Object>> commonSql(@Param("selectColumnSql") String selectColumnSql,@Param("tableName") String tableName,@Param("whereSql") String whereSql);

    Long getSeq();
}

xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.njry.sjzl.busi.mapper.InventoryDownloadLogMapper">
    <resultMap id="BaseResultMap" type="com.njry.sjzl.busi.domain.InventoryDownloadLog">
        <result column="LOG_ID" property="logId"/>
        <result column="LOG_ID" property="id"/>
        <result column="INVENTORY_ID" property="inventoryId"/>
        <result column="INVENTORY_NAME" property="inventoryName"/>
        <result column="CATEGORY_ID" property="categoryId"/>
        <result column="OPER_ID" property="operId"/>
        <result column="OPER_NAME" property="operName"/>
        <result column="OPER_DATE" property="operDate"/>
        <result column="STATUS" property="status"/>
        <result column="ATTACHMENT_ID" property="attachmentId"/>
        <result column="MOBILE" property="mobile"/>
    </resultMap>

    <sql id="Base_Column_List">
        LOG_ID, INVENTORY_ID, INVENTORY_NAME, CATEGORY_ID, OPER_ID, OPER_DATE, STATUS, ATTACHMENT_ID, MOBILE
    </sql>

    <sql id="Prefix_Base_Column_List">
        tidl.LOG_ID, tidl.INVENTORY_ID, tidl.INVENTORY_NAME, tidl.CATEGORY_ID, tidl.OPER_ID, tidl.OPER_DATE, tidl.STATUS, tidl.ATTACHMENT_ID, tidl.MOBILE
    </sql>

    <select id="findAll" resultMap="BaseResultMap">
        select tuser.name OPER_NAME,
        <include refid="Prefix_Base_Column_List"/>
        from T_INVENTORY_DOWNLOAD_LOG tidl
        left join T_USER tuser on tuser.user_id = tidl.OPER_ID
        <where>
            <if test="criteria.inventoryId != null">
                and tidl.INVENTORY_ID = #{criteria.inventoryId}
            </if>
            <if test="criteria.inventoryName != null">
                and tidl.INVENTORY_NAME like concat('%'||#{criteria.inventoryName},'%')
            </if>
            <if test="criteria.status != null">
                and tidl.STATUS = #{criteria.status}
            </if>
            <if test="criteria.mobile != null">
                and tidl.MOBILE = #{criteria.mobile}
            </if>
        </where>
    </select>

    <select id="findTableHead" resultType="java.lang.String">
        select a.column_name from all_tab_cols a
        where a.table_name=upper(#{tableName}) and owner=#{owner} order by a.column_id
    </select>

    <select id="commonSql" resultType="java.util.Map">
        select ${selectColumnSql} from ${tableName}
        <if test="whereSql != ''">
            where ${whereSql}
        </if>
    </select>


    <select id="getSeq" resultType="java.lang.Long">
        select  seq_T_INVENTORY_DOWNLOAD_LOG.nextval user_user_id from dual
    </select>
</mapper>

自己定义了一个任务调度然后可以启动调度
在这里插入图片描述

package com.njry.sjzl.busi.task;

import cn.hutool.core.date.DateTime;
import com.njry.sjzl.busi.attachment.domain.Attachment;
import com.njry.sjzl.busi.attachment.mapper.AttachmentMapper;
import com.njry.sjzl.busi.domain.Inventory;
import com.njry.sjzl.busi.domain.InventoryAuth;
import com.njry.sjzl.busi.domain.InventoryDownloadLog;
import com.njry.sjzl.busi.mapper.InventoryAuthMapper;
import com.njry.sjzl.busi.mapper.InventoryDownloadLogMapper;
import com.njry.sjzl.busi.mapper.InventoryMapper;
import com.njry.sjzl.busi.task.vo.TransferVo;
import com.njry.utils.GenerateExcelToFile;
import com.njry.utils.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Map;
import java.util.Queue;

@Service
@RequiredArgsConstructor
public class GenerateExcelTask {

    /**
     * 定义一个队列
     */
    // 定义一个队列
    static Queue<TransferVo> queue = new ArrayDeque<>();

    private final AttachmentMapper attachmentMapper;

    private final InventoryDownloadLogMapper inventoryDownloadLogMapper;

    private final InventoryAuthMapper inventoryAuthMapper;

    private final InventoryMapper inventoryMapper;


    public static void addDataList(TransferVo transferVo){
        queue.offer(transferVo);
    }

    public static TransferVo pollDataList(){
        TransferVo poll = queue.poll();// poll 方法用于获取队列头部的元素并移除它
        return poll;
    }



    public void run(){
        System.out.println("在sjzl-busi下面的bean被任务调度");
//        异步生成excel
        try {
            TransferVo transferVo = GenerateExcelTask.pollDataList();
            System.out.println("取出一个数据后队列长度:"+queue.size());
            if(transferVo != null){
                String dirPath = transferVo.getDirPath();
//                List<Map<String, Object>> maps = transferVo.getMaps();
//                List<String> tableHead = transferVo.getTableHead();
                String fileSuffix = transferVo.getFileSuffix();
                Long seq = transferVo.getSeq();
                Long currentUserId = transferVo.getCurrentUserId();
                Long inventoryId = transferVo.getInventoryId();
                String separator = transferVo.getSeparator();
//        根据清单inventoryId和当前用户判断拥有的权限(要不要放where条件)  清单用户权限T_INVENTORY_AUTH
//        AUTH_TYPE  权限类别:1 全量 不放where  2 单元 (清单选择的列名和权限里的单元编号作为where条件)
//        AREA_ID    单元编号
                InventoryAuth inventoryAuth = inventoryAuthMapper.findByUserIdAndInventoryId(currentUserId, inventoryId);
                Inventory inventory = inventoryMapper.queryDetailByInventoryId(inventoryId);
                Integer authType = inventoryAuth.getAuthType();
                Long areaId = inventoryAuth.getAreaId();
                String whereSql = "";
                if(authType == 2){
                    String queryColName = inventory.getQueryColName();
                    whereSql = queryColName + "=" + areaId;
                }

                String tableName = inventory.getTableName();
//        tableName = "t_organization";//写死测试
//                tableName = "atom_base_info";//写死测试分sheet
//                whereSql = "";//写死测试(配置的列名称不对)
                String owner = "NJDATA";//从配置里读取

//        获取表的列名-------作为select  xxx,xxx,xxx,xxx from 表名
//        select a.column_name from all_tab_cols a
//        where a.table_name=upper('t_organization') and owner='NJDATA' order by a.column_id;
                List<String> tableHead = inventoryDownloadLogMapper.findTableHead(tableName, owner);
                String selectColumnSql = String.join(",",tableHead);

//      通用查询sql,传入查询字段,表名和where条件(区分#{}和${}的时候了)
                List<Map<String, Object>> maps = inventoryDownloadLogMapper.commonSql(selectColumnSql, tableName, whereSql);


//             将数据生成excel文件里面
                Map<String, Object> resultMap = GenerateExcelToFile.dataToExcel(maps, tableHead, dirPath, fileSuffix,separator);
                Attachment attachment = new Attachment();
//            将文件数据保存文件附件表 T_ATTACHMENT
                attachment.setAttachmentId(resultMap.get("attachmentId").toString());
                attachment.setFileName(resultMap.get("fileName").toString());
                attachment.setFileType(resultMap.get("fileType").toString());
                attachment.setFileExtension(resultMap.get("fileExtension").toString());
                attachment.setFileSize(resultMap.get("fileSize").toString());
                attachment.setAttachmentPath(resultMap.get("attachmentPath").toString());
                //        新增的时候把操作人和操作时间
                Timestamp timestampAgain = DateTime.now().toTimestamp();
                attachment.setOperDate(timestampAgain);
                //        操作人
//                SecurityContext context = SecurityContextHolder.getContext();
//                System.out.println("SecurityContext:这里可以获取到吗"+context);
//                attachment.setOperId(SecurityUtils.getCurrentUserId());
                attachment.setOperId(currentUserId);
                attachmentMapper.insert(attachment);
//            在文件生成记录T_INVENTORY_DOWNLOAD_LOG 修改文件生成状态 和添加附件编号
                InventoryDownloadLog inventoryDownloadLog = new InventoryDownloadLog();
                inventoryDownloadLog.setId(seq);
                inventoryDownloadLog.setAttachmentId(resultMap.get("attachmentId").toString());
                inventoryDownloadLog.setStatus(1);
                inventoryDownloadLogMapper.updateById(inventoryDownloadLog);

//            发送短信通知用户生成结束

            }else{
//            这里应该降低任务执行调度的频率
                System.out.println("暂时没有可以执行的生成文件");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

工具类(将数据库数据转成file保存)

package com.njry.utils;

import cn.hutool.core.util.IdUtil;
import com.njry.config.FileProperties;
import com.njry.exception.BadRequestException;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GenerateExcelToFile {


    /**
     *
     * @param list  数据库查询出来的信息
     * @param tableHead  数据库的表头(简单表头)
     * @param dirPath  保存的文件路径
     * @param fileSuffix 生成的excel格式后缀
     * @param separator 生成的excel带水印格要多加一层文件路径
     * @throws IOException
     */
    public static Map<String, Object> dataToExcel(List<Map<String, Object>> list,List<String> tableHead,String dirPath, String fileSuffix, String separator) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        Workbook wb = null;
        FileInputStream tempInput = null;
        String watermarkPath = dirPath + "watermarkPath" + separator;
        int type = 3;//默认用type区分一个sheet有多少行
        if("xlsx".equals(fileSuffix)){
            wb = new XSSFWorkbook();
            type = 1;
        }
        if("xls".equals(fileSuffix)){
            wb = new HSSFWorkbook();
            type = 2;
        }
        Workbook exportWorkbook = export(wb, list, tableHead, type);
        String attachmentId = IdUtil.simpleUUID();
        String fileSize = "";
        String to_file_name = attachmentId + "." + fileSuffix;	// 结果文件名称
//        判断保存的文件路径是否存在,不存在就创建
        File outFileExist = new File(dirPath);
        if(!outFileExist.exists()){
            outFileExist.mkdirs();
        }
        File outFile = new File(dirPath, to_file_name);
        try {
            FileOutputStream outStream = new FileOutputStream(outFile);
            // 写入Workbook到文件
            exportWorkbook.write(outStream);
//            也可以通过流获取大小
//            long size = outStream.getChannel().size();
            // 强制刷新文件流,确保所有数据都被写入到文件中
            outStream.flush();

            // 获取文件对象
            File outputFile = new File(dirPath, to_file_name);
            long length = outputFile.length();
            fileSize =  length  + " bytes";
            
            outStream.close();
        } catch (Exception e) {
            throw new BadRequestException("导出结果文件异常:" + e);
        }

//        将有数据的excel的文件再加水印
        File tempFile = new File(dirPath, to_file_name);
        tempInput = new FileInputStream(tempFile);
        XSSFWorkbook xSSFWorkbook = new XSSFWorkbook(tempInput);
//            将导出的数据加水印放到另一个文件watermarkPath里面
        File watermarkFileExist = new File(watermarkPath, to_file_name);
        PoiSecurity.addWatermarkToXlsx(new String[]{"test"},xSSFWorkbook,watermarkFileExist);
        xSSFWorkbook.close();
        tempInput.close();
        // 终止后删除临时文件
        tempFile.deleteOnExit();
//        处理文件信息返回
        resultMap.put("attachmentId",attachmentId);
        resultMap.put("fileName",to_file_name);
        resultMap.put("fileType","excel");
        resultMap.put("fileExtension",fileSuffix);
        resultMap.put("fileSize",fileSize);
        resultMap.put("attachmentPath",dirPath);
        return resultMap;
    }

    /**
     *
     * @param wb 操作的Workbook
     * @param list 数据库查询出来的信息
     * @param tableHead 数据库的表头(简单表头)
     * @param type excel类型  xlsx  1   xls 2   -------区分sheet最大告诉
     * @return
     */
    public static Workbook export(Workbook wb,List<Map<String, Object>> list, List<String> tableHead,int type) {
        HSSFWorkbook HSSwb = null;
        XSSFWorkbook XSSwb = null;
//        不定义sheet名字,自生成
//        Excel 2003及更早的版本中,行数上限是65,536行
//        2007开始,行数上限增加到了1,048,576行
        int maxRow = 49999;//去除一个表头行
        if(type == 1){
            maxRow = 1048575;//去除一个表头行
            XSSwb  = (XSSFWorkbook)wb;
        }

        if(type == 2){
            maxRow = 65535;//去除一个表头行
            HSSwb  = (HSSFWorkbook)wb;
        }
        maxRow = 49999;//去除一个表头行(无论啥格式默认都是50000一个sheet)
//        处理数据需要多少个sheet
        int size = list.size();
        int result = size / maxRow + 1;
        if(result == 0){
            result = 1;
        }
//        循环sheet
        for (int i = 0; i < result; i++) {
            
            if(type == 1){
                XSSFSheet sheet = XSSwb.createSheet();
                //            处理每个sheet的表头
                XSSFRow row = sheet.createRow((short) 0);
                Cell cell = null;
                for (int j = 0; j < tableHead.size(); j++) {
                    cell = row.createCell(j);
//                cell.setCellStyle(headStyle);
                    cell.setCellValue(tableHead.get(j));
                }
//          写入数据
                for (int n = 0 + maxRow * i; n < maxRow * (i + 1); n++) {
//                判断数据list的大小是否大于要创建的行
                    if(size - 1 >= n ){//下面list.get(n)就取不到数据,不应该继续创建行  size 14 get(n)时候 n只能到13
                        row = sheet.createRow(n % maxRow + 1);
                        Cell dataCell = null;
                        for (int m = 0; m < tableHead.size(); m++) {
                            dataCell = row.createCell(m);
                            dataCell.setCellValue(StringUtils.notEmpty(list.get(n).get(tableHead.get(m))));
                        }
                    }
                }
            }
            if(type == 2){
                HSSFSheet sheet = HSSwb.createSheet();
                //            处理每个sheet的表头
                HSSFRow row = sheet.createRow((short) 0);
                Cell cell = null;
                for (int j = 0; j < tableHead.size(); j++) {
                    cell = row.createCell(j);
//                cell.setCellStyle(headStyle);
                    cell.setCellValue(tableHead.get(j));
                }
//          写入数据
                for (int n = 0 + maxRow * i; n < maxRow * (i + 1); n++) {
//                判断数据list的大小是否大于要创建的行
                    if(size - 1 >= n ){//下面list.get(n)就取不到数据,不应该继续创建行  size 14 get(n)时候 n只能到13
                        row = sheet.createRow(n % maxRow + 1);
                        Cell dataCell = null;
                        for (int m = 0; m < tableHead.size(); m++) {
                            dataCell = row.createCell(m);
                            dataCell.setCellValue(StringUtils.notEmpty(list.get(n).get(tableHead.get(m))));
                        }
                    }
                }
            }

        }
        return wb;
    }
}

工具类PoiSecurity(之前贴过)

package com.njry.utils;

import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.security.GeneralSecurityException;

import javax.imageio.ImageIO;

import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.crypt.binaryrc4.BinaryRC4EncryptionInfoBuilder;
import org.apache.poi.poifs.crypt.binaryrc4.BinaryRC4Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
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.*;
import org.springframework.core.io.ClassPathResource;

public class PoiSecurity {

	public static void addWatermarkToXlsx(String[] content,XSSFWorkbook xssfworkbook,File outfile) throws IOException{
		ByteArrayOutputStream bytestream = createWaterMark(content,300,250);
//		XSSFWorkbook下面有几个sheet
		int sheetsize = xssfworkbook.getNumberOfSheets();
		for(int index=0;index<sheetsize;index++){
			XSSFSheet sheet = xssfworkbook.getSheetAt(index);
			XSSFWorkbook workbook = sheet.getWorkbook();
//			bytestream.toByteArray()(前置知识)
//			下面这一串看不懂(没看官网文档的下场)
	        int pictureIdx = workbook.addPicture(bytestream.toByteArray(), Workbook.PICTURE_TYPE_PNG);
	        POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx);
	        PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
			String relType = XSSFRelation.IMAGES.getRelation();
			PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
	        sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
		}

		if(!outfile.exists()){
			File par = outfile.getParentFile();
			if(!par.exists()){
				par.mkdirs();
			}
			outfile.createNewFile();
		}
		FileOutputStream out = new FileOutputStream(outfile);
		xssfworkbook.write(out);
		out.close();
	}

	public static void addImageToXlsx(String[] content,XSSFWorkbook xssfworkbook,File outfile) throws IOException{
		int imgW = 300,imgH = 250;
		ByteArrayOutputStream bytestream = createWaterMark(content,imgW,imgH);
		byte[] bytes = bytestream.toByteArray();
		int sheetsize = xssfworkbook.getNumberOfSheets();
		for(int index=0;index<sheetsize;index++){
			XSSFSheet sheet = xssfworkbook.getSheetAt(index);
			int[] wh = getSheetWidthAndHeight(sheet);
			int width = wh[0];
			int height = wh[1];

			XSSFDrawing drawingPatriarch = sheet.createDrawingPatriarch();

			//根据宽高进行插入
			for(int i = 0;i< (width / imgW) + 1;i++) {	//x轴
				for(int j = 0; j <( height / imgH) + 1;j++){	//y轴
					int x = i * imgW;
					int y = j * imgH;

					//根据图片插入
					/*XSSFClientAnchor anchor = new XSSFClientAnchor(x,y,x+width,y+height,0,0,1,1);
					int pIndex = xssfworkbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
					drawingPatriarch.createPicture(anchor,pIndex);*/
				}
			}

		}
		if(!outfile.exists()){
			File par = outfile.getParentFile();
			if(!par.exists()){
				par.mkdirs();
			}
			outfile.createNewFile();
		}
		FileOutputStream out = new FileOutputStream(outfile);
		xssfworkbook.write(out);
		out.close();
	}


	/**
	 * 获取sheet的宽高
	 * @param sheet
	 * @return
	 */
	private static int[] getSheetWidthAndHeight(Sheet sheet){
		float height = 0f;
		float width = 0f;
		int firstRowNum = sheet.getFirstRowNum();
		int lastRowNum = sheet.getLastRowNum();
		for (int i = firstRowNum; i < lastRowNum; i++) {
			Row row = sheet.getRow(i);
			if(i == firstRowNum){	//获取宽度
				short firstCellNum = row.getFirstCellNum();
				short lastCellNum = row.getLastCellNum();
				for(int j = firstCellNum;j<lastCellNum;j++){
					width = width + sheet.getColumnWidthInPixels(j);
				}
			}
			height = height+ row.getHeightInPoints();
		}
		return new int[]{Math.round(width),Math.round(height)};
	}


	private static ByteArrayOutputStream createWaterMark(String[] content,int width,int height) throws IOException {
		ClassPathResource resource = new ClassPathResource("font/simsun.ttc");//宋体
		InputStream resourceAsStream = null;
		Font font = null;
		try{
			resourceAsStream = resource.getInputStream();
			font = Font.createFont(Font.TRUETYPE_FONT, resourceAsStream);
			font = font.deriveFont(20f);
		}catch (Exception e){
			throw new IOException("PoiSecurity createWaterMark error",e);
		} finally {
			if(resourceAsStream!=null){
				resourceAsStream.close();
			}
		}
//		(前置知识)
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取bufferedImage对象
//        设置字体(前置知识)
        Graphics2D g2d = image.createGraphics(); // 获取Graphics2d对象(前置知识)
//		这里实在看不懂,为啥销毁后用BufferedImage重新获取Graphics2d对象
        image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g2d.dispose();
        g2d = image.createGraphics();
        g2d.setColor(new java.awt.Color(0, 0, 0, 40));//设置字体颜色和透明度,最后一个参数为透明度(前置知识)
        g2d.setStroke(new BasicStroke(1)); // 设置字体
        g2d.setFont(font); // 设置字体类型  加粗 大小
        g2d.rotate(-0.5, (double) image.getWidth() / 2, (double) image.getHeight() / 2);//设置倾斜度
//		要想得到表示屏幕设备字体属性的对象(前置知识)
        FontRenderContext context = g2d.getFontRenderContext();
//        循环设置水印文字位置(看不懂)
        for (int i = 0; i < content.length; i++) {
//        	返回包围字符串的矩形(前置知识)
			if(content[i] == null){
				continue;
			}
			Rectangle2D bounds = font.getStringBounds(content[i], context);
//            宽度
            double x = (width - bounds.getWidth()) / 2;
//            高度
            double y = (height - bounds.getHeight()) / 2;
//            上坡度
            double ascent = -bounds.getY();
            double baseY = y + ascent;
            // 写入水印文字原定高度过小,所以累计写水印,增加高度
            g2d.drawString(content[i], (int) x, (int) baseY+(30*i));
		}
        // 设置透明度(前置知识)
//        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER));
        // 释放对象
        g2d.dispose();
//		ByteArrayOutputStream(前置知识)
        ByteArrayOutputStream os = new ByteArrayOutputStream();
//		BufferedImage –> byte[](前置知识)
		ImageIO.write(image, "png", os);
        return os;
    }


	public static void encXlsx(String paasword,File file) throws InvalidFormatException, IOException, GeneralSecurityException{
		try (POIFSFileSystem fs = new POIFSFileSystem()) {
		    EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
		    // EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes192, HashAlgorithm.sha384, -1, -1, null);
		    Encryptor enc = info.getEncryptor();
		    enc.confirmPassword(paasword);
		    // Read in an existing OOXML file and write to encrypted output stream
		    // don't forget to close the output stream otherwise the padding bytes aren't added
		    try (OPCPackage opc = OPCPackage.open(file, PackageAccess.READ_WRITE);
		        OutputStream os = enc.getDataStream(fs)) {
		        opc.save(os);
		    }
		    // Write out the encrypted version
		    try (FileOutputStream fos = new FileOutputStream(file)) {
		        fs.writeFilesystem(fos);
		    }
		}
	}


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1893950.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用户资料门户的构建

1. 需求背景 老的页面停止维护了,且老旧, 功能单一,且页面分散. 急需做功能集成的平台化建设原先的用户资料查询没有做权限管控, 每一次查询都会消耗我们组的人力资源. 2. 项目介绍 2.1. 项目地址 服务地址: [公司内网服务(略)] 工蜂地址: [公司内网仓库(略)] 2.2 项目的价…

女性经济崛起,天润融通用客户感知挖掘市场潜力

每逢一年一度的国际妇女节&#xff0c;“女性”话题都会被郑重地讨论。 从消费市场上来说&#xff0c;最近几年女性群体正在拥有越来越大的影响力&#xff0c;甚至出现了“她经济”这样的专属词汇在最近几年被市场反复讨论。 毫无疑问&#xff0c;女性消费群体的崛起已经成为…

揭秘品牌成功秘诀:品牌营销策略的核心要素大公开

品牌营销作为企业战略中至关重要的一环&#xff0c;其核心是建立和传播品牌的独特魅力&#xff0c;使其在消费者心目中占据重要位置。 一个成功的品牌营销策略能够提升品牌的知名度和影响力&#xff0c;带来持续的销售和忠诚客户群体。 在当今竞争激烈的市场环境中&#xff0…

Prompt的万能公式和优化技巧

文章目录 前言一、万能公式二、优化技巧1.设定角色2.设定目标和动机3.引导主观回答4.预设条件5.做强调6.思维链&#xff08;COT&#xff09;7.巧用定界符 前言 随着LLM的发展&#xff0c;能给我们带来很多方便&#xff0c;但是又引出了一个新的问题就是我们该如何使用他们&…

明星代言方式8种助力品牌占领市场-华媒舍

1. 明星代言的重要性和市场价值 明星代言是一种常见的品牌推广方式&#xff0c;通过联系知名度高的明星来推广产品或服务&#xff0c;从而提升品牌的知名度和美誉度。明星代言能够借助明星的影响力和粉丝基础&#xff0c;将品牌信息传达给更广泛的受众&#xff0c;从而提高销量…

【数据结构】建堆的时间复杂度

一.向下调整建堆 1.二叉树层数与总节点个数关系 层数一定时&#xff0c;在二叉树节点个数最大的情况下&#xff0c;二叉树为满二叉树&#xff0c;如下图所示&#xff0c;可以清晰地看到在满二叉树中第h层有2^(h-1)个节点&#xff0c;总节点N就等于一个等比数列的求和&#xf…

【Python机器学习】模型评估与改进——在模型选择中使用评估指标

我们通常希望&#xff0c;在使用GridSearchCV或cross_val_score进行模型选择时能够使用AUC等指标。scikit-learn提供了一种非常简单的实现方法&#xff0c;那就是scoring参数&#xff0c;它可以同时用于GridSearchCV和cross_val_score。你只需要提供一个字符串&#xff0c;用于…

RabbitMQ入门教程(精细版二带图)

目录 六 RabbitMQ工作模式 6.1Hello World简单模式 6.1.1 什么是简单模式 6.1.2 RabbitMQ管理界面操作 6.1.3 生产者代码 6.1.4 消费者代码 6.2 Work queues工作队列模式 6.2.1 什么是工作队列模式 6.2.2 RabbitMQ管理界面操作 6.2.3 生产者代码 6.2.4 消费者代码 …

谷粒商城学习-06-使用vagrant快速创建linux虚拟机

这一节的内容是在Windows上安装虚拟机。 为什么要按照虚拟机呢&#xff1f; 原因是很多软件只能在Linux下运行&#xff0c;有的虽然也可以在Windows上运行&#xff0c;但从安装到运行会遇到很多问题&#xff0c;为这些解决这些问题花时间对于大多数人特别是初学者是没有什么价…

WPS操作技巧:制作可以打对勾的方框,只需简单几步!沈阳wps办公软件培训

日常工作中&#xff0c;我们经常需要在表格中添加复选框&#xff0c;比如【性别选择】、【任务完成状态】等等&#xff0c;通过打对勾来确定状态。今天就分别从WPS的Excel表格和Word文档2种场景&#xff0c;介绍制作可以打对勾的复选框的方法技巧&#xff0c;掌握技巧&#xff…

k8s-第十节-Ingress

Ingress 介绍 Ingress 为外部访问集群提供了一个 统一 入口,避免了对外暴露集群端口;功能类似 Nginx,可以根据域名、路径把请求转发到不同的 Service。可以配置 https跟 LoadBalancer 有什么区别? `LoadBalancer`` 需要对外暴露端口,不安全;无法根据域名、路径转发流量到…

Linux之文本三剑客

Linux之三剑客 Linux的三个命令,主要是用来处理文本,grep,sed,awk,处理日志的时候使用的非常多 1 grep 对文本的内容进行查找 1) 基础用法 语法 grep 选项 内容|正则表达式 文件选项: -i 不区分大小写 -v 排除,反选 -n 显示行号 -c 统计个数查看文件里包含有的内容 [roo…

rtsp地址 + 测试网站 + java(免环境、免插件、零编码转换http播放)

目录 1、创建rtsp网站 2、测试rtsp网站 3、Java实现rtsp播放 ①maven添加依赖 ②访问http地址即可展示视频内容 1、创建rtsp网站 填写邮箱即可获得两个可用的rtsp网站&#xff08;每月可免费用2G&#xff09;&#xff1a; https://rtsp.stream/ 2、测试rtsp网站 测试网络…

k8s kubectl top pod报错error Metrics API not available

文章目录 1、场景2、解决方法1、确认Metrics Server是否已经在集群中安装2、安装metric-server组件2.1、组件地址2.2、组件与K8S集群版本对应关系2.3、apply资源清单文件2.4、验证Metrics Server正常工作 1、场景 在使用kubectl top pod 命令时遇到了error: Metrics API not a…

人力资源中的人工智能:你应该知道的一切

人工智能已经成为行业讨论更广泛的突出话题。人力资源(HR)对于人力资源专业人士来说&#xff0c;了解这门课程也是如此。除了简要介绍什么是人工智能&#xff0c;以及你可能遇到的主要人工智能类型(或者你可能很快就会遇到它&#xff01;)此外&#xff0c;本文还将探讨人工智能…

工业智能网关在现代工业生产中的重要性-天拓四方

工业智能网关是一款具备挖掘工业设备数据并接入到自主开发的云平台的智能嵌入式网络设备。它具备数据采集、协议解析、边缘计算&#xff0c;以及4G/5G/WiFi数据传输等功能&#xff0c;并能接入工业云平台。这种网关不仅支持采集PLC、传感器、仪器仪表和各种控制器&#xff0c;还…

公用对象池

什么是对象池&#xff1f; 对象池顾名思义就是存放对象的池子&#xff0c;主要是为了重复利用对象。将不用的对象扔进池子里&#xff0c;需要用的时候再从池子中取出来。这样的一套机制我们称为对象池。 为什么用对象池&#xff1f; 其实从定义我们就可以看出来&#xff0c;…

基于矩阵分解算法的评分预测实现---信息检索课设以及所涉及的深度学习原理

一、实验环境 Windows,Python 3 Python作为主要编程语言,使用Python的Pandas、NumPy、Matplotlib等库 二、实验内容 主要任务 查阅相关资料,了解矩阵分解算法的基本概念、应用场景及其难点。重点了解SVD(Singular Value Decomposition,奇异值分解)系列方法。掌握Pyth…

2023年的Facebook营销:超级完整指南

Facebook营销不是可选的&#xff0c;是必须的。Facebook是世界上使用最多的社交平台&#xff0c;每天吸引22.9亿活跃用户。 它也不全是度假照片和虚张声势。对于53.2% 的 16-24 岁互联网用户&#xff0c;社交媒体是他们进行品牌研究的主要来源。而且&#xff0c;66% 的 Facebo…