【案例实战】SpringBoot整合EasyExcel实现列表导出功能

news2024/11/27 20:35:13

这篇文章会给大家实操一个关于列表导出成excel表格的功能,相信大家在日常工作中也会遇到列表导出的需求,看完本篇文章那么你就可以轻松的去整合列表导出的功能。

在这里插入图片描述

本次使用的导出工具是阿里巴巴开源的EasyExcel,关于EasyExcel我这里简单的介绍一下:

我们知道Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。

easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。

在这里插入图片描述

ok,下面我们就开始实操整合一下EasyExcel,实现导出功能。

第一步:我们先创建Maven项目,整合成SpringBoot的项目。

  • 加入依赖,创建测试接口,确保项目能够运行。
  • pom.xml加入依赖
		<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
    </dependencies>
  • 定义主类
/**
 * @author lixiang
 * @date 2023/5/26 16:02
 */
@SpringBootApplication
public class ExcelApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExcelApplication.class, args);
    }
}
  • 创建控制器
/**
 * @author lixiang
 * @date 2023/5/26 16:00
 */
@RestController
@RequestMapping("/excel")
public class ExcelController {

    @GetMapping("/create")
    public String create(){
        String msg = "SUCCESS";
        return msg;
    }

}
  • 测试运行

在这里插入图片描述

第二步:引入EasyExcel依赖,封装工具类

        <dependency>
            <groupId>com.pig4cloud.excel</groupId>
            <artifactId>excel-spring-boot-starter</artifactId>
            <version>0.5.0</version>
        </dependency>
package com.lixiang.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 导出excel 表格 工具类
 * @author lixiang
 * @date 2023/5/26 10:18 
 */
public class EasyExcelUtil implements RowWriteHandler {

    private int mergeRowIndex;//从哪一行开始合并
    private int[] mergeColumnIndex;//excel合并的列
    private int[] signNum;//合并的唯一标识
    private int total;//总行数
    private int lastRow;
    private int firstCol;
    private int lastCol;
    private int firstRow;
    private int mergeCount = 1;

    private EasyExcelUtil(){}

    private EasyExcelUtil(int mergeRowIndex, int[] mergeColumnIndex, int[] signNum, int total) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
        this.signNum = signNum;
        this.total = total;
    }

    /**
     * 导出excel
     * @param response
     * @param fileName 文件名称
     * @param exportList 导出数据
     * @param clazz 导出实体bean class对象
     * @param <T>
     * @throws IOException
     */
    public static <T> void createExcel(HttpServletResponse response, String fileName, List<T> exportList,
      Class<T> clazz)
      throws IOException {
        createExcel(response,fileName,exportList,clazz,null);
    }

    /**
     * 导出excel
     * @param response
     * @param fileName 文件名称
     * @param exportList 导出数据
     * @param clazz 导出实体bean class对象
     * @param cellMerge 单元格合并规则
     * @param <T>
     * @throws IOException
     */
    public static <T> void createExcel(HttpServletResponse response, String fileName, List<T> exportList,
      Class<T> clazz, CellMerge cellMerge)
      throws IOException {
        // 设置下载信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        //定义ExcelWriterSheetBuilder
        ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcel
          .write(response.getOutputStream(), clazz)
          .sheet(fileName);

        //合并单元格
        if (cellMerge != null) {
            // 从那一行开始合并
            int mergeRowIndex = 1;
            EasyExcelUtil
              excelMergeRowByRowStrategy = new EasyExcelUtil(mergeRowIndex, cellMerge.getMergeColumIndex(),
              cellMerge.getMergeRuleColumIndex(), exportList.size());
            excelWriterSheetBuilder.registerWriteHandler(excelMergeRowByRowStrategy);
        }

        //设置头样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置内容格式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
          new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        //设计内容居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置内容自动换行
        contentWriteCellStyle.setWrapped(true);
        excelWriterSheetBuilder.registerWriteHandler(horizontalCellStyleStrategy);

        //调用doWrite方法
        excelWriterSheetBuilder.doWrite(exportList);
    }

    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
      Integer relativeRowIndex, Boolean isHead) {
        //当前行
        int curRowIndex = row.getRowNum();
        //每一行的最大列数
        short lastCellNum = row.getLastCellNum();

        if (curRowIndex == 1) {
            //赋初值 第一行
            firstRow = curRowIndex;
        }
        //开始合并位置
        if (curRowIndex > mergeRowIndex && !row.getCell(0).getStringCellValue().equals("")) {
            for (int i = 0; i < lastCellNum; i++) {
                if (i == mergeColumnIndex[i]) {
                    //当前行号 当前行对象 合并的标识位
                    mergeWithPrevAnyRow(writeSheetHolder.getSheet(), curRowIndex, row, signNum);
                    break;//已经进入到合并单元格操作里面了,执行一次就行
                }
            }
        }
    }

    public void mergeWithPrevAnyRow(Sheet sheet, int curRowIndex, Row row, int[] signNum) {
        Row preRow = row.getSheet().getRow(curRowIndex - 1);
        List<String> rowDataList = new ArrayList<>();
        List<String> preDataList = new ArrayList<>();

        for (int i : signNum) {
            Object currentData =
              row.getCell(i).getCellTypeEnum() == CellType.STRING ? row.getCell(i).getStringCellValue() :
                row.getCell(i).getNumericCellValue();
            Object preData =
              preRow.getCell(i).getCellTypeEnum() == CellType.STRING ? preRow.getCell(i).getStringCellValue() :
                preRow.getCell(i).getNumericCellValue();
            rowDataList.add(String.valueOf(currentData));
            preDataList.add(String.valueOf(preData));
        }

        String rowDataStr = String.join(",", rowDataList);
        String preDataStr = String.join(",", preDataList);

        //判断是否合并单元格
        boolean curEqualsPre = rowDataStr.equals(preDataStr);
        //判断前一个和后一个相同 并且 标识位相同
        if (curEqualsPre) {
            lastRow = curRowIndex;
            mergeCount++;
        }
        //excel过程中合并
        if (!curEqualsPre && mergeCount > 1) {
            mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
            mergeCount = 1;
        }

        //excel结尾处合并
        if (mergeCount > 1 && total == curRowIndex) {
            mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
            mergeCount = 1;
        }

        if (!curEqualsPre) {
            firstRow = curRowIndex;
        }

    }

    private void mergeSheet(int firstRow, int lastRow, int[] mergeColumnIndex, Sheet sheet) {
        for (int colNum : mergeColumnIndex) {
            firstCol = colNum;
            lastCol = colNum;
            CellRangeAddress cellRangeAddress = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
            sheet.addMergedRegion(cellRangeAddress);
        }
    }

    /**
     * 单元格合并类
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CellMerge {
        private int[] mergeColumIndex;
        private int[] mergeRuleColumIndex;
    }

    /**
     * 设置单元格合并规则
     * @param mergeColumIndex
     * @param mergeRuleColumIndex
     * @return
     */
    public static CellMerge setCellMerge(int[] mergeColumIndex,int[] mergeRuleColumIndex){
        EasyExcelUtil excelUtil = new EasyExcelUtil();
        CellMerge cellMerge = excelUtil.new CellMerge();
        cellMerge.setMergeColumIndex(mergeColumIndex);
        cellMerge.setMergeRuleColumIndex(mergeRuleColumIndex);
        return cellMerge;
    }
}

第三步:模拟测试数据

  • 创建学生实体类

/**
 * @ColumnWidth(20) 这个是设置单元格长度的
 * @ExcelProperty("")  这个是设置表格头部的
 * @author lixiang
 * @date 2023/5/26 16:30
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ColumnWidth(20)
public class Student {

    @ExcelProperty("年级")
    private String gradeName;

    @ExcelProperty("班级")
    private String className;

    @ExcelProperty("姓名")
    private String name;

    @ExcelProperty("年龄")
    private Integer age;

    @ExcelProperty("性别")
    private String sex;

}

  • 模拟学生数据
/**
 * @author lixiang
 * @date 2023/5/26 16:13
 */
@Service
public class StudentService {

    List<String> classNames;

    List<String> gradeNames;

    {
        classNames = new ArrayList<>();
        classNames.add("一班");
        classNames.add("二班");
        classNames.add("三班");
        gradeNames = new ArrayList<>();
        gradeNames.add("2017级");
        gradeNames.add("2018级");
        gradeNames.add("2019级");
    }

    public List<Student> getStudentData(){
        List<Student> list = new ArrayList<>();
        for (int i = 1; i < 20; i++) {
            Student student = new Student();
            student.setName("李祥"+i);
            student.setClassName(getClassName());
            student.setGradeName(getGradeName());
            student.setSex("男");
            student.setAge(18);
            list.add(student);
        }

        return list;
    }

    /**
     * 获取班级
     * @return
     */
    private String getClassName(){
        Random rand = new Random();
        return classNames.get(rand.nextInt(classNames.size()));
    }

    /**
     * 获取年级
     * @return
     */
    private String getGradeName(){
        Random rand = new Random();
        return gradeNames.get(rand.nextInt(gradeNames.size()));
    }
}
/**
 * @author lixiang
 * @date 2023/5/26 16:00
 */
@RestController
@RequestMapping("/excel")
public class ExcelController {

    @Autowired
    private StudentService  studentService;

    @GetMapping("/create")
    public List<Student> create(){

        List<Student> studentData = studentService.getStudentData();

        return  studentData;
    }

}

在这里插入图片描述

第四步:基于这个数据我们进行导出成excel

/**
 * @author lixiang
 * @date 2023/5/26 16:00
 */
@RestController
@RequestMapping("/excel")
public class ExcelController {

    @Autowired
    private StudentService  studentService;

    @GetMapping("/create")
    public void create(HttpServletResponse response) throws Exception{

        List<Student> studentData = studentService.getStudentData();
        String fileName  =  "学生列表";
        /**
         * 第一个参数:HttpServletResponse
         * 第二个参数:文件名称
         * 第三个参数:数据集
         * 第四个参数:数据集实体class对象
         */
        EasyExcelUtil.createExcel(response,fileName,studentData, Student.class);
    }

}

在这里插入图片描述
在这里插入图片描述

Ok,那么现在 我们想要合并单元格,将同年级的同班级的单元格进行合并。

    @GetMapping("/create")
    public void create(HttpServletResponse response) throws Exception{

        List<Student> studentData = studentService.getStudentData();
        String fileName  =  "学生列表";
        /**
         * 第一个参数:HttpServletResponse
         * 第二个参数:文件名称
         * 第三个参数:数据集
         * 第四个参数:数据集实体class对象
         * 第五个参数:合并单元格的规则
         *  EasyExcelUtil.setCellMerge(meargeColl, meargeColl);
         *  第一个参数 是 我们要合并的那些列,第二个是合并的规则。
         */
        int[] meargeColl = new int[]{0,1};
        EasyExcelUtil.CellMerge cellMerge = EasyExcelUtil.setCellMerge(meargeColl, meargeColl);
        EasyExcelUtil.createExcel(response,fileName,studentData, Student.class,cellMerge);
    }

在这里插入图片描述

注意合并的时候,需要将数据进行排序,确保年级,班级相同的数据都在一起。现在我们先进行数据排序。

  • 定义中文排序工具
/**
 * @author lixiang
 * @date 2023/5/26 17:14
 */
public class ChineseNumberUtil {
    public static int chineseNumber2Int(String chineseNumber){
        int result = 0;
        int temp = 1;//存放一个单位的数字如:十万
        int count = 0;//判断是否有chArr
        char[] cnArr = new char[]{'一','二','三','四','五','六','七','八','九'};
        char[] chArr = new char[]{'十','百','千','万','亿'};
        for (int i = 0; i < chineseNumber.length(); i++) {
            boolean b = true;//判断是否是chArr
            char c = chineseNumber.charAt(i);
            for (int j = 0; j < cnArr.length; j++) {//非单位,即数字
                if (c == cnArr[j]) {
                    if(0 != count){//添加下一个单位之前,先把上一个单位值添加到结果中
                        result += temp;
                        temp = 1;
                        count = 0;
                    }
                    // 下标+1,就是对应的值
                    temp = j + 1;
                    b = false;
                    break;
                }
            }
            if(b){//单位{'十','百','千','万','亿'}
                for (int j = 0; j < chArr.length; j++) {
                    if (c == chArr[j]) {
                        switch (j) {
                            case 0:
                                temp *= 10;
                                break;
                            case 1:
                                temp *= 100;
                                break;
                            case 2:
                                temp *= 1000;
                                break;
                            case 3:
                                temp *= 10000;
                                break;
                            case 4:
                                temp *= 100000000;
                                break;
                            default:
                                break;
                        }
                        count++;
                    }
                }
            }
            if (i == chineseNumber.length() - 1) {//遍历到最后一个字符
                result += temp;
            }
        }
        return result;
    }
}
  • service进行排序
public List<Student> getStudentData(){
        List<Student> list = new ArrayList<>();
        for (int i = 1; i < 20; i++) {
            Student student = new Student();
            student.setName("李祥"+i);
            student.setClassName(getClassName());
            student.setGradeName(getGradeName());
            student.setSex("男");
            student.setAge(18);
            list.add(student);
        }
  			//排序逻辑
        list.sort((s1,s2)->{
            Integer flag = Integer.parseInt(s1.getGradeName().substring(0,4)) - Integer.parseInt(s2.getGradeName().substring(0,4));
            if(flag == 0){
                return Integer.compare(ChineseNumberUtil.chineseNumber2Int(s1.getClassName().substring(0,2)),
                        ChineseNumberUtil.chineseNumber2Int(s2.getClassName().substring(0,2)));
            }
            return flag;
        });
        return list;
    }

在这里插入图片描述

OK,我们排序完成就可以进行合并啦。

				int[] meargeColl = new int[]{0,1};
        EasyExcelUtil.CellMerge cellMerge = EasyExcelUtil.setCellMerge(meargeColl, meargeColl);
        EasyExcelUtil.createExcel(response,fileName,studentData, Student.class,cellMerge);

在这里插入图片描述

我们看到相同的行已经被合并啦,ok,excel整合我们就完成啦。

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

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

相关文章

Nacos使用详解

一、部署nacos 1、方式一&#xff08;一般的windows和linux部署&#xff09; 需要的nacos-server-1.4.1文件&#xff1a;https://download.csdn.net/download/yueyue763184/87822434?spm1001.2014.3001.5503 一般的nacos部署方式教程&#xff1a;https://blog.csdn.net/yue…

敲代码都两年半了,还不会用SDL、C语言rap一个推箱子?

前言 欢迎来到小K的SDL专栏第三小节&#xff0c;本节将为大家带来小项目~C语言SDL版坤坤推箱子详细讲解&#xff0c;这里也为大家上传了源码和图片资源&#xff0c;需要的自取看完以后&#xff0c;希望对你有所帮助 ✨效果如下 文章目录 前言一、推箱子思路讲解二、加SDL绘图代…

离散系统函数零积点分析

离散系统函数零积点分析 在 Matlab中&#xff0c;系统函数的零极点就可以通过函数 roots 得到。 函数的零极点也可以通过函数 tf2zp 获得&#xff0c;其调用格式为&#xff1a;[Z, P, K] tf2zp(B, A)&#xff0c;函数 tf2zp 可以将H(z)的有理分式转换为零极点增益形式&#…

WEB端唤起 百度|腾讯|高德 地图一键导航功能

WEB端唤起 百度|腾讯|高德 地图一键导航功能 目录 腾讯地图&#xff1a; 百度地图&#xff1a; 高德地图&#xff1a; 坐标拾取器&#xff1a; 腾讯地图&#xff1a; 极简写法&#xff1a; https://3gimg.qq.com/lightmap/v1/marker/index.html?markercoord:纬度,经度;t…

工业设备状态监测:振动常见原因分析

在工业生产中&#xff0c;设备的正常运行和可靠性对于保障生产效率和安全至关重要。然而&#xff0c;工业设备在运行过程中常常会出现振动现象&#xff0c;这可能是由于多种原因导致的。 根据设备劣化趋势P-F曲线我们可以知道&#xff0c;振动信号监测是状态监测过程中可以被快…

Markdown编辑器 测试

测试一下TOC 你好Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支…

MongoDB的应用

目录 一、MongoDb是什么 1.特点 2.功能 3.基本的指令 二、MongoDB的使用场景 1.适用场合 2.常见应用场景 三、可能遇到的问题 1.MongoDB是否支持事务&#xff1f; 2.MongoDB大数据迁移怎么做&#xff1f; 3.MongoDB的水平扩展是什么原理&#xff1f; 4.MongoDB出现负…

Jenkins UI与接口自动化测试持续集成实战

篇幅较长&#xff0c;要耐心阅读哦~ 基础知识简要回顾 持续集成、持续交付的好处与产生的必然性Jenkins服务的搭建方法Jenkins节点管理与用户权限Jenkins插件Jenkins父子多任务关联运行Jenkins报警机制 目录 SeleniumUI自动化测试持续集成演练接口自动化测试持续集成演练 …

采埃孚-4D毫米波雷达拆解分析

采埃孚4D毫米波雷达拆解分析 4D毫米波雷达具有4个维度的信息&#xff0c;分别是距离、速度、方向角和高度。下面分析采埃孚再飞凡汽车上的4D毫米波雷达。 4D毫米波雷达共由四部分组成&#xff0c;分别为&#xff1a;数字接口板及结构件、屏蔽罩、发射单元及PCB以及雷达天线罩…

如何在 Linux、Windows 和 Mac 上查找 WiFi 密码?

无线网络已成为我们日常生活中不可或缺的一部分&#xff0c;我们经常需要连接各种WiFi网络。但是&#xff0c;有时我们可能会忘记自己的WiFi密码&#xff0c;或者需要连接到一个以前连接过的网络。在这种情况下&#xff0c;我们可以使用一些方法来查找已连接网络的密码。 本文将…

研报精选230526

目录 【行业230526山西证券】有色金属行业周报&#xff1a;锂价强势反弹回30万元or吨 【行业230526开源证券】食品饮料行业投资策略&#xff1a;消费复苏贯穿全年&#xff0c;结构分化择机布局 【行业230526德邦证券】核电行业深度系列报告&#xff1a;积极安全有序发展核电&am…

8-JDBC 编程

目录 1.数据库编程的必备条件 PS&#xff1a;程序是怎么操作数据库的&#xff1f; 2.什么是JDBC&#xff1f; 2.1.JDBC定义 2.2.JDBC工作原理 3.JDBC使用 3.1.创建项目并添加MySQL驱动包 3.2.使用代码操作数据库 3.2.1.获得数据源 3.2.2.获得连接 3.2.3.获得执行器 …

软考A计划-2022年11月软件设计师下午真题及答案解析

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

【云原生|Kubernetes】06-Pod的生命周期和重启策略

【云原生|Kubernetes】06-Pod的生命周期和重启策略 文章目录 【云原生|Kubernetes】06-Pod的生命周期和重启策略Pod生命周期生命周期Pod的状态Pod子状态 Pod重启策略调试PodPod 停滞在 Pending 状态Pod 停滞在 Waiting 状态Pod 处于 Crashing 或别的不健康状态Pod 处于 Running…

【LeetCode热题100】打卡第4天:寻找两个正序数组的中位数

文章目录 寻找两个正序数组的中位数⛅前言&#x1f512;题目&#x1f511;题解 寻找两个正序数组的中位数 ⛅前言 大家好&#xff0c;我是知识汲取者&#xff0c;欢迎来到我的LeetCode热题100刷题专栏&#xff01; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的…

89.qt qml-WorkerScript多线程使用(无需C++代码)

由于我们自定义Table中需要实现排序,如下图所示: 考虑到如果数据量太大的情况,为了避免主线程阻塞,所以我们添加多线程排序功能,为了方便大家更好学习qml组件,所以学习WorkerScript实现多线程,无需C++ 1.描述 使用 WorkerScript 在新线程中运行操作。这对于在后台运行操…

微信小程序为什么不用HTML5、CSS,自己搞了个WXML、WXSS,很多框架用不了,好处一点不知道?

你在小程序中需要使用HTML5、 CSS来创建页面&#xff0c;那么你一定会碰到一些问题&#xff0c;比如&#xff1a; 1.小程序中的布局没有 JS支持&#xff0c;没有 JS渲染逻辑。 2.没有内置 css&#xff0c;都是靠 JS自己实现的。 3.很多框架不能使用&#xff0c;比如&#xf…

5年华为外包,外包究竟怎么样....

最近身边很多人进了外包或者被问到进到外包公司怎么样&#xff0c;感觉大家对外包公司不是很了解&#xff0c;也有一些误解&#xff0c;我们看看过来人怎么说。 5年外包时光 我曾是华为外包软件测试员工&#xff0c;就职于东莞松山湖&#xff0c;2017年9月12号入职&#xff0c…

ARM--计算机基础知识

目录 一.Linux层次结构 谈谈对嵌入式的理解 三层&#xff1a; 应用层 内核层 硬件层 二、计算机的进制 三、计算机的组成 1.输入设备 2.输出设备 3.存储器 4.运算器 5.控制器 总线 四、ARM存储模型 1. Cache:高速缓冲存储器 2. 主存储器&#xff1a;相当于内存 …

Day1:手写第一个Win32程序

学习重点&#xff1a; 1. 理解这个Win32窗口程序的实现逻辑 2. 学习Windows消息循环机制 3. 了解Windows的数据类型 4. 明白Winmain函数的作用 首先这个Winodws窗口程序在之后的学习并不需要进行手写&#xff0c;这里的重点是学习代码的逻辑&#xff0c;虽然有一些参数的含义尚…