SpringBoot 使用easypoi.excel实现导入解析数据,并结合数据字典实现对数据的校验

news2024/11/17 10:05:23

在日常开发工作中避免不了的功能需求:导入Excel文件,然而导入文件流操作、对数据的校验有是件麻烦事,自从接触了easypoi后,觉得封装的很好,很简洁。

使用的主要依赖如下:

<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>4.5.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>4.5.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>4.5.0</version>
</dependency>

controller不贴了,这里贴一下serviceImpl

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;

@Autowired
private DictHandler dictHandler;
@Autowired
private Bd3OrderHandlerNew bd3OrderHandlerNew;

// Bd3OrderDetailExcelNew 是导入的承载实体类
private List<Bd3OrderDetailExcelNew> checkNewExcel(MultipartFile excel, IExcelVerifyHandler verifyHandler) {
        ImportParams importParams = new ImportParams();
        importParams.setNeedVerify(true);
		// 这里是对表格字段一些不为空、正则的判断
        importParams.setVerifyHandler(verifyHandler);
        // 这里是数据字典的校验
        importParams.setDictHandler(dictHandler);
		// 这里是表格的表头  根据自己需求进行更改
        String[] importFields = {"序号", "用户终端序列号", "终端用户类型", "使用区域", "使用人姓名", "使用人证件号", "使用人联系电话", "服务频度", "通讯等级",
                "自建编组数量", "区域与全球是否互通", "系统回执", "频度接收系统调控", "北二与北三是否互通", "是否应急搜救用户", "搜救中心ID", "检测报告编号", "北斗卡号"};
        importParams.setImportFields(importFields);
        ExcelImportResult<Bd3OrderDetailExcelNew> excelResult;
        InputStream in = null;
        try {
            in = excel.getInputStream();
            excelResult = ExcelImportUtil.importExcelMore(in, Bd3OrderDetailExcelNew.class, importParams);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RdssException(MessageExceptionEnum.CUSTOM_CODE.getCode(), "表格内容错误,请重新上传正确格式的入网注册详表!");
        } finally {
            ThreadLocal<List<Bd3OrderDetailExcelNew>> threadLocal = bd3OrderHandlerNew.getThreadLocal();
            if (threadLocal != null) {
                threadLocal.remove();
            }
            IOUtils.closeQuietly(in);
        }

        List<Bd3OrderDetailExcelNew> failList = excelResult.getFailList();
        if (ObjectUtil.isNotEmpty(failList)) {
            throw new RdssException(MessageExceptionEnum.EXCEL_CODE.getCode(),
                    MessageExceptionEnum.EXCEL_CODE.getMessage(), failList);
        }
        List<Bd3OrderDetailExcelNew> resultList = excelResult.getList().stream()
                .filter(bd3OrderDetailExcelNew -> bd3OrderDetailExcelNew.getApplyIndex() != null).collect(Collectors.toList());
        if (resultList.isEmpty()) {
            throw new RdssException(ResponseCodeEnum.FAIL.getCode(), "导入Excel内容为空");
        }
        return resultList;
    }
       

对表格数据的校验

其中的IExcelVerifyHandler是对表格字段的校验,需要自己去实现,例如我的实现类为Bd3OrderHandler

import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import com.rdss.bus.model.entity.ApplyOrderBd3DetailInfo;
import com.rdss.bus.model.entity.Terminal;
import com.rdss.bus.model.excel.Bd3OrderDetailExcelNew;
import com.rdss.bus.service.*;
import com.rdss.common.util.StringUtils1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.StringJoiner;

@Slf4j
@Service
public class Bd3OrderHandlerNew implements IExcelVerifyHandler<Bd3OrderDetailExcelNew> {

    private ThreadLocal<List<Bd3OrderDetailExcel>> threadLocal = ThreadLocal.withInitial(LinkedList::new);
    @Autowired
    private TermianlBdcardService termianlBdcardService;
    @Autowired
    private BdcardService bdcardService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private BdcardService tBusBdcardService;


    @Autowired
    private TermianlService termianlService;

    @Autowired
    private ApplyOrderBd3DetailInfoService aoBd3DetailInfoService;
 
    @Override
    public ExcelVerifyHandlerResult verifyHandler(Bd3OrderDetailExcelNewdetailExcel) {
        StringJoiner joiner = new StringJoiner(",");
        if(isAllFieldNull(detailExcel)){
            return new ExcelVerifyHandlerResult(true);
        }

        List<Bd3OrderDetailExcelNew> detailExcelList = threadLocal.get();
        if (detailExcelList == null) {
            detailExcelList = new LinkedList<>();
        }
        if(detailExcel.getApplyIndex() == null){
            joiner.add("[序号]不能为空");
        }
        if (StringUtils1.isEmpty(detailExcel.getTerminalSerialNumber())) {
            joiner.add("[用户终端序列号]不能为空");
        }
        if(!detailExcel.getTerminalSerialNumber().matches("^[0-9]{14}([0-9]{2})?$")){
            joiner.add("[终端序列号]格式错误");
        }
        if(detailExcel.getCardType() == null){
            joiner.add("[北斗卡类型]不能为空");
        }
        if(StringUtils1.isEmpty(detailExcel.getUsageArea())){
            joiner.add("[使用区域]不能为空");
        }
        if(StringUtils1.isEmpty(detailExcel.getUserName())){
            joiner.add("[使用人姓名]不能为空");
        }
        // 添加本行数据对象到ThreadLocal中
        detailExcelList.add(detailExcel);
        threadLocal.set(detailExcelList);
        if (joiner.length() != 0) {
            return new ExcelVerifyHandlerResult(false, joiner.toString());
        }

        //查询数据库是否存在机构编号
        if( detailExcel.getApplyIndex() != detailExcelList.size()){
            joiner.add("[序号]错误");
        }
        String terminalSerialNumber = detailExcel.getTerminalSerialNumber();
        if(termianlService.getByNum(terminalSerialNumber)!=null) {
            Terminal terminal = termianlService.getByNum(terminalSerialNumber);
            if (termianlBdcardService.terminalnumber(terminal.getId()) > 0) {
                joiner.add("[终端号]已和北斗卡绑定");
            }
        }
        List<ApplyOrderBd3DetailInfo> terminal00= aoBd3DetailInfoService.getListByTerminal(terminalSerialNumber);
            if(terminal00.size()!=0){
                joiner.add("[终端序列号]重复提交申请,请确认");
            }

        if (joiner.length() != 0) {
            return new ExcelVerifyHandlerResult(false, joiner.toString());
        }
        return new ExcelVerifyHandlerResult(true);
    }
	
	/**
     * 是否是空表?
     *
     */
    public boolean isAllFieldNull(Bd3OrderDetailExcel detailExcel) {
        try {
            for (Field f : detailExcel.getClass().getDeclaredFields()) {
                f.setAccessible(true);
                if(f.getName().equals("rowNum") || f.getName().equals("errorMsg")){
                    continue;
                }
                if (f.get(detailExcel) != null && org.apache.commons.lang3.StringUtils.isNotBlank(f.get(detailExcel).toString())) {
                    return false;
                }
            }
        } catch (Exception e) {
            log.error("程序异常,错误信息为{}", e);
        }

        return true;
    }

	public ThreadLocal<List<Bd3OrderDetailExcelNew>> getThreadLocal() {
        return threadLocal;
    }
    
    public void removeThreadLocal () { threadLocal.remove(); }

数据字典的处理

针对导入表格单元格存在下拉框选项,获取对应的数值时,需要数据字典解决:

import cn.afterturn.easypoi.handler.inter.IExcelDictHandler;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rdss.bus.model.entity.DictionaryData;
import com.rdss.bus.service.DictionaryDataService;
import com.rdss.common.entity.Dictionary;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
@Service
public class DictHandler implements IExcelDictHandler, InitializingBean {

    @Autowired
    private DictionaryDataService dictionaryDataService;
    private HashOperations<String, Object, Object> dictHash;

    @Autowired
    public void setDictHash(RedisTemplate<String, Object> redisTemplate) {
        this.dictHash = redisTemplate.opsForHash();
    }

    @Override
    public String toName(String dict, Object obj, String name, Object value) {
        if (value==null) {
            return null;
        }
        Map<Object, Object> map = dictHash.entries(dict);
        Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
        String key = "";
        for(Map.Entry<Object, Object> entry : entrySet){
            if(entry.getValue().equals(value)){
                key = String.valueOf(entry.getKey());
            }
        }

        return key;
    }

    @Override
    public String toValue(String dict, Object obj, String name, Object value) {
        if (value==null) {
            return null;
        }
        Object dictType = dictHash.get(dict, value);
        return String.valueOf(dictType);
    }

    @Override
    public void afterPropertiesSet() {
        List<DictionaryData> dictionaryDataList = dictionaryDataService.list(new QueryWrapper<DictionaryData>().lambda().eq(DictionaryData::getStatus, 1));
        List<Dictionary> dictList = dictionaryDataService.getDictionaryList();
        dictList.stream().forEach(str->{
            Map<String,Object> tagMap=new HashMap<>(8);
            dictionaryDataList.stream().filter(dict -> {
                Integer id = str.getId();
                Integer dictId = str.getId();
                return (dictId!=null && id.equals(dictId));
            }).forEach(dict->
                    tagMap.put(dict.getTag(),dict.getKey()+"")
            );
            dictHash.putAll(str.getType(),tagMap);
        });
    }
}

其中数据字典 是分类操作,比如字典标题是汽车颜色,对应子字典子集有红色、白色、黑色等
这是字典标题
这是字典子集信息
父字典:

import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.rdss.common.vo.DictionaryData2;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Transient;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.List;

@Data
@Accessors(chain = true)
@TableName("t_sys_dictionary")
public class Dictionary implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 字典名称
     */
    @TableField(insertStrategy = FieldStrategy.IGNORED,updateStrategy = FieldStrategy.IGNORED,whereStrategy = FieldStrategy.IGNORED)
    private String name;

    /**
     * 字典值
     */
    @TableField(insertStrategy = FieldStrategy.IGNORED,updateStrategy = FieldStrategy.IGNORED,whereStrategy = FieldStrategy.IGNORED)
    private String type;

    /**
     * 更新时间
     */

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Timestamp updateTime;

    /**
     *状态:0 正常 ,1 停用
     */
    private Integer status;

    /**
     * 备注
     */
    @TableField(insertStrategy = FieldStrategy.IGNORED,updateStrategy = FieldStrategy.IGNORED,whereStrategy = FieldStrategy.IGNORED)
    private String remark;

     @Transient
    @TableField(exist = false)
    private List<DictionaryData2> datas;
}

子字典:

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@TableName("t_sys_dictionary_data")
public class DictionaryData{

    /**
     * ID
     */
    @TableId
    private Integer id;
    /**
     * 字典主表id
     */
    private Integer dictId;
    /**
     * 字典标签
     */
    private String tag;
    /**
     * 字典标签-英文
     */
    private String tagEn;
    /**
     * 字典键值
     */
    private Integer key;
    /**
     * 状态:1-正常,2-停用
     */
    private Integer status;
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
    /**
     * 备注
     */
    private String remark;

}

涉及导入表格的实体类

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.handler.inter.IExcelDataModel;
import cn.afterturn.easypoi.handler.inter.IExcelModel;
import lombok.Data;

/**
 * @author ztz
 * @date 2023/9/4 13:16
 */
@Data
public class Bd3OrderDetailExcelNew implements IExcelDataModel, IExcelModel {

    /**
     * 行号
     */
    private Integer rowNum;

    /**
     * 错误消息
     */
    private String errorMsg;

    /**
     * 申请序号
     */
    //@NotNull(message = "不能为空")
    @Excel(name = "序号")
    private Integer applyIndex;

    /**
     * 终端序列号
     */
    //@NotBlank(message = "不能为空")
    @Excel(name = "用户终端序列号")
    private String terminalSerialNumber;

    /**
     * 北斗卡类型/终端用户类型(
     1:民用智能卡、
     2:民用指挥卡)

     1.日常通信卡,2.数据监测卡,3.应急指挥卡,4.其他类型卡
     */
    //@NotNull(message = "不能为空")
    @Excel(name = "终端用户类型",dict = "terminal_user_type")
    private Integer cardType;

    /**
     * 使用区域
     */
    //@NotBlank(message = "不能为空")
    @Excel(name = "使用区域")
    private String usageArea;

    /**
     * 使用人姓名
     */
    //@NotBlank(message = "不能为空")
    @Excel(name = "使用人姓名")
    private String userName;

    /**
     * 使用人证件号
     */
    //@NotBlank(message = "不能为空")
    @Excel(name = "使用人证件号")
    private String userIdNumber;

    /**
     * 使用人联系电话
     */
    //@NotBlank(message = "不能为空")
    @Excel(name = "使用人联系电话")
    private String userMobile;

    /**
     * 使用频度/服务频度
     */
    //@NotNull(message = "不能为空")
    @Excel(name = "服务频度",dict = "bdcard_frequency")
    private Integer frequency;

	@Excel(name = "通讯等级",dict = "bdcard_level")
    private Integer cardLevel;

    /**.
     * 自建编组数量
     */
    //@NotNull(message = "不能为空")
    @Excel(name = "自建编组数量",dict = "group_number")
    private Integer groupNumber;

    /**
     * 区域与全球是否互通  开通1  不开通0
     */
    @Excel(name = "区域与全球是否互通",dict = "local_global_Inter_flow")
    private Integer localGlobalInterflow;

    /**
     * 系统回执
     */
    @Excel(name = "系统回执",dict = "sys_receipt")
    private Integer sysReceipt;

    /**
     *  频度接收系统调控 0否1是
     */
    @Excel(name = "频度接收系统调控",dict = "frequency_rec_sys")
    private Integer frequencyRecSys;

    /**
     * 北二与北三是否互通
     */
    @Excel(name = "北二与北三是否互通",dict = "bd2_bd3_lInter_flow")
    private Integer bd2Bd3Interflow;

    /**
     * 是否应急搜救用户 0否1是
     */
    @Excel(name = "是否应急搜救用户",dict = "emergency_search_rescue_user")
    private Integer emergencySearchUser;

    /**
     * 搜救中心ID
     */
    //@NotBlank(message = "不能为空")
    @Excel(name = "搜救中心ID")
    private String searchCenterId;

//    /**
//     * 通播号
//     */
//    @Excel(name = "通播号")
//    private String broadcastNum;
//
    /**
     * 新申请到的北斗卡号
     */
    @Excel(name = "北斗卡号")
    private String cardNum;

    @Excel(name = "检测报告编号")
    private String testNumber;

//    @Override
//    public Integer getRowNum() {
//        return null;
//    }
//
    @Override
    public void setRowNum(Integer rowNum) {
        this.rowNum = rowNum+1;
    }
}

一些其他工具类 可以参考 可有可无代码

异常:

import lombok.Data;

@Data
public class RdssException extends RuntimeException{

    private Integer code;
    private String errorMessage;
    private transient  Object data;

    public RdssException() {
    }

    public RdssException(String message) {
        super(message);
        this.errorMessage=message;
    }

    public RdssException(Integer code,String message) {
        super(message);
        this.code=code;
        this.errorMessage=message;
    }

    public RdssException(Integer code,String message,Object data) {
        super(message);
        this.code=code;
        this.errorMessage=message;
        this.data=data;
    }

    public RdssException(MessageExceptionEnum exception) {
        super(exception.getMessage());
        this.code = exception.getCode();
        this.errorMessage = exception.getMessage();
    }
}

枚举:

package com.rdss.common.exception;

/**
 * 消息服务异常集合
 *
 */
public enum MessageExceptionEnum  {

    QUEUE_CANT_EMPTY(600, "消息队列不能为空"),
    MESSAGE_ID_CANT_EMPTY(601, "消息id不能为空"),
    MESSAGE_BODY_CANT_EMPTY(602, "消息body不能为空"),
    CANT_FIND_MESSAGE(603, "查找不到消息"),
    MESSAGE_NUMBER_WRONG(604, "消息数量错误"),
    MESSAGE_QUEUE_ERROR(605, "消息队列服务器处理异常"),
    MESSAGE_TYPE_ERROR(606, "消息接收到的格式错误,非TEXT类型"),
    CUSTOM_CODE(4, "发生异常"),
    EXCEL_CODE(5, "excel数据不正确"),
    INVALIDTOKEN(500,"令牌失效"),
    SERVER_NOTCOMPLETE(501,"服务未启动"),
    USERNAME_PWD_ERROR(400, "用户名或密码错误");

    MessageExceptionEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    private Integer code;

    private String message;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

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

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

相关文章

Unity3D结合AI教育大模型 开发AI教师 AI外教 AI英语教师案例

自2022年底ChatGPT引爆全球之后&#xff0c;大模型技术便迎来了一段崭新的快速发展期&#xff0c;由其在GPT4.0发布后&#xff0c;AI与教育领域结合产品研发、已成为教育AI科技竞争的新高地、未来产业的新赛道、经济发展的新引擎和新产品的诞生地。 据不完全统计&#xff0c;目…

代码随想录 day 22 回溯

第七章 回溯算法part01 理论基础 其实在讲解二叉树的时候&#xff0c;就给大家介绍过回溯&#xff0c;这次正式开启回溯算法&#xff0c;大家可以先看视频&#xff0c;对回溯算法有一个整体的了解。 题目链接/文章讲解&#xff1a;https://programmercarl.com/%E5%9B%9E%E6%B…

pdf格式过大怎么样变小 pdf文件过大如何缩小上传 超实用的简单方法

面对体积庞大的 PDF 文件&#xff0c;我们常常需要寻找有效的方法来缩减其大小。这不仅能够优化存储空间&#xff0c;还能提升文件的传输和打开速度。PDF文件以其稳定性和跨平台兼容性成为工作和学习中的重要文件格式。然而&#xff0c;当我们需要通过邮件发送或上传大文件时&a…

力扣94题(java语言)

题目 思路 使用一个栈来模拟递归的过程&#xff0c;以非递归的方式完成中序遍历(使用栈可以避免递归调用的空间消耗)。 遍历顺序步骤&#xff1a; 遍历左子树访问根节点遍历右子树 package algorithm_leetcode;import java.util.ArrayList; import java.util.List; import…

无人机之环保监控篇

随着科技的不断进步&#xff0c;无人机作为一种创新的技术手段&#xff0c;在环保监控领域发挥着越来越重要的作用。 一、覆盖范围广 无人机能够轻松覆盖广阔的地理区域&#xff0c;无论是偏远的山区、广袤的森林还是大型的工业园区。相比传统的地面检测方式&#xff0c;其不…

vue3 常用的知识点

setup:容许在script当中书写组合式API 并且vue3的template不再要求唯一的根元素 <script setup>const name app; </script>组合式API的用法&#xff1a; 可以直接在script标签中定义变量或者函数&#xff0c;然后直接在template当中使用 <template>{{mes…

机器学习 | 回归算法原理——多重回归

Hi&#xff0c;大家好&#xff0c;我是半亩花海。接着上次的多项式回归继续更新《白话机器学习的数学》这本书的学习笔记&#xff0c;在此分享多重回归这一回归算法原理。本章的回归算法原理基于《基于广告费预测点击量》项目&#xff0c;欢迎大家交流学习&#xff01; 目录 一…

从零入门 AI for Science(AI+药物) #Datawhale AI 夏令营

使用平台 我的Notebook 魔搭社区 https://modelscope.cn/my/mynotebook/preset 主要操作 运行实例&#xff0c;如果有时长尽量选择方式二&#xff08;以下操作基于方式二的实例实现&#xff09; 创建文件夹&#xff0c;并重命名为 2.3siRNA 上传两个文件 到文件夹&#…

android手势监听

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 未经允许不得转载 目录 一、导读二、概览三、使用四、 如何实…

数据库窗口函数实战

目录 前言 窗口函数语法 创建测试表和数据 使用示例 PARTITION BY 窗口函数 ROW_NUMBER RANK DENSE_RANK RANGE ROWS 前言 SQL 具有很高的灵活性&#xff0c;可以根据需求进行复杂的数据查询和分析&#xff0c;支持多表联合查询&#xff08;join&#xff09;、排序…

[Unity] ShaderGraph实现镜头加速线/残血效果 URP

效果如下所示&#xff1a;残血状态时&#xff0c;画面会压暗角&#xff0c;并出现速度线营造紧迫感。 使用到的素材如下&#xff0c;换别的当然也可以。[这是张白色的png放射图&#xff0c;并非皇帝的新图hhh] 这个效果的实现逻辑&#xff0c;其实就是利用time向圆心做透明度的…

学习笔记-系统框图简化求传递函数公式例题

简化系统结构图求系统传递函数例题 基础知识回顾 第四讲 控制系统的方框图 (zhihu.com) 「自控原理」2.3 方框图的绘制及化简_方框图化简-CSDN博客 自动控制原理笔记-结构图及其等效变换_结构图等效变换-CSDN博客 例子一 「自控原理」2.3 方框图的绘制及化简_方框图化简-CS…

【ARM】MDK-ARM软件开发工具的最终用户许可协议获取

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 了解MDK-ARM系列产品内软件开发工具的最终用户许可协议的获取。 2、 问题场景 对于部分外企客户需要软件开发工具的最终用户许可协议作为产品资料&#xff0c;以便附录并说明。 3、软硬件环境 1&#xff09;、软件…

Axure怎么样?全面功能评测与用户体验分析!

软件 Axure 曾经成为产品经理必备的原型设计工具&#xff0c;被认为是专门为产品经理设计的工具。但事实上&#xff0c;软件 Axure 的使用场景并不局限于产品经理构建产品原型。UI/UX 设计师还可以使用 Axure 软件构件应用程序 APP 原型&#xff0c;网站设计师也可以使用 Axure…

快速上手,spring boot3整合task实现定时任务

在已经上线的项目中&#xff0c;定时任务是必不可少的。基于spring boot自动装配的原理&#xff0c;我们要集成task定时任务还是非常简单的。只需要简单的两步就可以实现。 1、创建一个spring boot项目&#xff0c;并在项目的启动类&#xff08;也不一定非要是启动类&#xff…

二手车小程序

本文来自&#xff1a;FastAdmin二手车小程序 - 源码1688 一款基于ThinkPHPFastAdmin开发的原生微信小程序二手车管理系统。 前端小程序码&#xff1a; 后台演示地址&#xff1a; https://facars.site100.cn/OHNYSKzuba.php/carswxsys/sysinit?refaddtabs

wpf中轮询显示图片

本文的需求是&#xff0c;在一个文件夹中&#xff0c;放一堆图片的集合&#xff0c;然后在wpf程序中&#xff0c;按照定时的方式&#xff0c;循序显示照片。 全部代码 1.声明一个PictureInfo类 namespace WpfApp1 {public class PictureInfo{public string? FileName { get; …

GPT-4o mini小型模型具备卓越的文本智能和多模态推理能力

GPT-4o mini 是首个应用OpenAI 指令层次结构方法的模型&#xff0c;这有助于增强模型抵抗越狱、提示注入和系统提示提取的能力。这使得模型的响应更加可靠&#xff0c;并有助于在大规模应用中更安全地使用。 GPT-4o mini 在学术基准测试中&#xff0c;无论是在文本智能还是多模…

mac怎样清理photoshop垃圾的方法 ps清理缓存和垃圾 苹果电脑暂存盘已满怎么清理

很多使用过ps&#xff0c;尤其是Adobe全家桶的小伙伴会发现&#xff0c;这些软件占用缓存很多&#xff0c;而且随着使用时间的增长&#xff0c;缓存也会越多&#xff0c;并不会自动清理。那么mac系统怎么清理ps暂存盘呢&#xff1f;mac又该怎么最高效清理磁盘空间呢&#xff1f…

【专题】2024年云计算白皮书报告合集PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37112 2023年全球云计算市场显著增长&#xff0c;预计将持续繁荣至2027年突破万亿美元&#xff0c;中国市场同样保持强劲势头&#xff0c;预计也将大幅跃升。国内云计算经过十余年发展&#xff0c;虽取得显著进展&#xff0c;但在资…