当前位置:   article > 正文

hutools简单使用和与一些工具的比较

hutools

hutools使用

官网:https://hutool.cn/docs/

简单生成验证码

使用hutools的http服务器发送验证码

 private static void writeToServlet(){
        ICaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100);
       // captcha.write(response.getOutputStream());
       //Servlet的OutputStream记得自行关闭哦!
        HttpUtil.createServer(8088)
                .addAction("/", (request,response)->{
                    captcha.write(response.getOut());
                }).start();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iFK8R8YO-1609126961496)(hutools使用简介.assets/image-20201227220510370.png)]

如果是通过HttpServletResponse发送,修改为:

 private static void writeToServlet(HttpServletResponse response){
        ICaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100);
        captcha.write(response.getOutputStream());
       //Servlet的OutputStream记得自行关闭哦!
    }
  • 1
  • 2
  • 3
  • 4
  • 5

实现简单http服务

写一个简单的登录验证

public class SimpleHttpServer
{
    public static void main( String[] args )
    {
        HttpUtil.createServer(8085)
                //根据url跳转页面
                .addAction("/", (request,response)->{
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter writer = response.getWriter();
                    String url=request.getPath();
                    if(url.equals("/login")){
                        ListValueMap<String, String> params = request.getParams();
                        if(!replace(params.get("name").toString()).equals("lwf")) {
                            response.getHttpExchange().setAttribute("auth", null);
                            writer.write(message(300, "用户名不存在"));
                        }else {
                            if(!replace(params.get("password").toString()).equals("123")){
                                response.getHttpExchange().setAttribute("auth", null);
                                writer.write(message(300, "密码错误"));
                            }else {
                                response.getHttpExchange().setAttribute("auth", "lwf");
                                writer.write(message(200, "登录成功"));
                            }
                        }
                    }else {
                        if (request.getHttpExchange().getAttribute("auth")!=null&&request.getHttpExchange().getAttribute("auth").equals("lwf")) {
                            Map<String,Object> msg=new HashMap<>();
                            msg.put("code", 200);
                            msg.put("msg", "已登录用户"+request.getHttpExchange().getAttribute("auth"));
                            writer.write(JSONUtil.toJsonPrettyStr(msg));
                        }else {
                            writer.write(message(300, "用户未登录"));
                        }
                    }
                    writer.flush();
                    writer.close();
                })
                .start();
    }



    private static String message(Integer code,String msg){
        Map<String,Object> response=new HashMap<>();
        response.put("code", code);
        response.put("msg", msg);
        return JSONUtil.parse(response).toStringPretty();
    }
    public static String replace(String value){
        return value.substring(1, value.lastIndexOf(']'));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

上面的代码是:在8085端口监听,如果url是login就检查用户名密码,否则去首页(需要检查登录凭证)。这个小demo就是用来玩的,因为这个东西是单线程的而且多次访问共享一个凭证(相当于session),只要有一个地方登录成功,其他地方都拥有凭证;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-chNchCPx-1609126961498)(hutools使用简介.assets/image-20201228084259912.png)]

正确密码登录:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P6mg6ltw-1609126961500)(hutools使用简介.assets/image-20201228084328786.png)]

首页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bxtej1D7-1609126961502)(hutools使用简介.assets/image-20201228084354969.png)]

换个浏览器,访问首页(不用登录,但是首页会通过,和上面的共享了自定义的凭证;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IgKfhSbr-1609126961505)(hutools使用简介.assets/image-20201228084604805.png)]

而且这个action封装的request,response并不是servlet的HttpServletRequest和HttpServletResponse,而是hutools自己弄得,我没有发现可以发cookie的地方,所有要模仿session;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bHzWPS9r-1609126961506)(hutools使用简介.assets/image-20201228090603313.png)]

还有实现简单的文件服务器

作为文件服务器根路径[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nQRiVft0-1609126961508)(hutools使用简介.assets/image-20201228091101300.png)]

public class FileServer {
    public static void main(String[] args) {
        //根据url获取文件
        HttpUtil.createServer(8889)
                // 设置默认根目录,该文件夹下文件访问路径为   localhost:8888/文件名
                .setRoot("G:\\Dockerfile\\nginx\\html\\baidu")
                .start();
        //上传文件到根路径
        HttpUtil.createServer(8888)
                // 设置默认根目录,该文件夹下文件访问路径为   localhost:8888/文件名
               // .setRoot("G:\\Dockerfile\\nginx\\html\\baidu")
                .addAction("/file", (request, response) -> {
                            final UploadFile file = request.getMultipart().getFile("file");
                            // 传入目录,默认读取HTTP头中的文件名然后创建文件
                            file.write("G:\\Dockerfile\\nginx\\html\\baidu");
                            response.write("OK!", ContentType.TEXT_PLAIN.toString());
                        }
                )
                .start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

8889端口映射本地路径:G:\\Dockerfile\\nginx\\html\\baidu ,该目录下的文件,全路径将G:\\Dockerfile\\nginx\\html\\baidu替换为http://localhost:8889

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kiyikEQD-1609126961509)(hutools使用简介.assets/image-20201228091301271.png)]

上传文件端口为8888,上传url为file,且表单提交文件name属性为file

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u809z0C6-1609126961511)(hutools使用简介.assets/image-20201228091611083.png)]

上传成功,访问该图片http://localhost:8889/img1.jfif,可以看到请求图片成功

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c16vQwku-1609126961512)(hutools使用简介.assets/image-20201228092146613.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3aYse4UN-1609126961513)(hutools使用简介.assets/image-20201228092236714.png)]

http请求

spring boot使用的是RestTemplate

这里演示hutools的Http请求;

public class HttpRequest {
    public static void main(String[] args) {
//        //链式构建请求,表单数据提交
//        String result2 = HttpRequest.post(url)
//                .header(Header.USER_AGENT, "Hutool http")//头信息,多个头信息多次调用此方法即可
//                .form(paramMap)//表单内容
//                .timeout(20000)//超时,毫秒
//                .execute().body();
//        Console.log(result2);
        Panda panda=new Panda();
        panda.setName("大熊猫");
        panda.setPlace("四川");
        String result2 = cn.hutool.http.HttpRequest.post("http://localhost:8091/test/post")
                .body(JSONUtil.parse(panda).toStringPretty())
                .execute().body();
        System.out.println("响应数据");
        System.out.println(result2);
        Reciver bean = JSONUtil.toBean(result2, Reciver.class);
        System.out.println(bean.getData());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

控制器:http://localhost:8091/test/post,并接收json数据

@RestController
@RequestMapping("/test")
public class TestController {
    @PostMapping("/post")
    public Map<String,Object> test(@RequestBody Panda panda){
        Map<String,Object> map=new HashMap<>();
        map.put("type", "json");
        map.put("data", panda);
        map.put("msg", "接受到数据");
        return map;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里接收到响应,并且将响应的json转为对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-obLpXjSA-1609126961515)(hutools使用简介.assets/image-20201228111018419.png)]

DFA关键搜索和布隆过滤

DFA

import cn.hutool.dfa.WordTree;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

/**
 * DFA检索关键字
 */
public class AppTest 
{
    WordTree tree=new WordTree();
    @Before
    public void before(){
        tree.addWord("大");
        tree.addWord("大土豆");
        tree.addWord("土豆");
        tree.addWord("刚出锅");
        tree.addWord("出锅");
    }

    /**
     * 情况一:标准匹配,匹配到最短关键词,并跳过已经匹配的关键词
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        //正文
        String text = "我有一颗大土豆,刚出锅的";

        // 匹配到【大】,就不再继续匹配了,因此【大土豆】不匹配
        // 匹配到【刚出锅】,就跳过这三个字了,因此【出锅】不匹配(由于刚首先被匹配,因此长的被匹配,最短匹配只针对第一个字相同选最短)
        List<String> matchAll = tree.matchAll(text, -1, false, false);
        Assert.assertEquals(matchAll.toString(), "[大, 土豆, 刚出锅]");
    }

    /**
     * 情况二:匹配到最短关键词,不跳过已经匹配的关键词
     */
    @Test
    public void two()
    {
        //正文
        String text = "我有一颗大土豆,刚出锅的";

        // 【大】被匹配,最短匹配原则【大土豆】被跳过,【土豆继续被匹配】
// 【刚出锅】被匹配,由于不跳过已经匹配的词,【出锅】被匹配
        List<String> matchAll = tree.matchAll(text, -1, true, false);
        Assert.assertEquals(matchAll.toString(), "[大, 土豆, 刚出锅, 出锅]");
    }
    /**
     * 情况三:匹配到最长关键词,跳过已经匹配的关键词
     */
    @Test
    public void three()
    {
        //正文
        String text = "我有一颗大土豆,刚出锅的";

        // 匹配到【大】,由于到最长匹配,因此【大土豆】接着被匹配
// 由于【大土豆】被匹配,【土豆】被跳过,由于【刚出锅】被匹配,【出锅】被跳过
        List<String> matchAll = tree.matchAll(text, -1, false, true);
        Assert.assertEquals(matchAll.toString(), "[大, 大土豆, 刚出锅]");
    }

    /**
     * 情况四:匹配到最长关键词,不跳过已经匹配的关键词(最全关键词)
     */
    @Test
    public void four()
    {
        //正文
        String text = "我有一颗大土豆,刚出锅的";

        // 匹配到【大】,由于到最长匹配,因此【大土豆】接着被匹配,由于不跳过已经匹配的关键词,土豆继续被匹配
// 【刚出锅】被匹配,由于不跳过已经匹配的词,【出锅】被匹配
         List<String>   matchAll = tree.matchAll(text, -1, true, true);
        Assert.assertEquals(matchAll.toString(), "[大, 大土豆, 土豆, 刚出锅, 出锅]");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

我们在before里初始化WrodTree;

tree.addWord(“大”);
tree.addWord(“大土豆”);
tree.addWord(“土豆”);
tree.addWord(“刚出锅”);
tree.addWord(“出锅”);

对应的DFA:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yshjfmSh-1609126961516)(hutools使用简介.assets/image-20201228092850041.png)]

布隆过滤

public class BloomFilter {
    public static void main(String[] args) {
        // 初始化
        BitMapBloomFilter filter = new BitMapBloomFilter(10);
        filter.add("123");
        filter.add("abc");
        filter.add("ddd");

        // 查找
        System.out.println(filter.contains("abc"));

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。

Bloom Filter跟单哈希函数Bit-Map不同之处在于:Bloom Filter使用了k个哈希函数,每个字符串跟k个bit对应。从而降低了冲突的概率。

下面这张图是我在网上找的,这张图的模式可能存在

这里出现的构造方法:

 public BitMapBloomFilter(int m) {
      long mNum = NumberUtil.div(String.valueOf(m), String.valueOf(5)).longValue();
        long size = mNum * 1024L * 1024L * 8L;
        this.filters = new BloomFilter[]{new DefaultFilter(size), new ELFFilter(size), new JSFilter(size), new PJWFilter(size), new SDBMFilter(size)};
    }
  • 1
  • 2
  • 3
  • 4
  • 5

这里传入了5个hash处理类,并且使用10*223位bit数组记录hash。布隆过滤器会使用这5个类的hash()方法对加入的每个元素分别求值(作为下标),然后把bit数组相应下标的bit位置为1。(有几个过滤器就有几个这样的数据)

传入元素:filter.add("123");

new DefaultFilter(size):

该类的核心

public long hash(String str) {
        return (long)HashUtil.javaDefaultHash(str) % this.size;
    }
  • 1
  • 2
  • 3

调用了:

public static int javaDefaultHash(String str) {
        int h = 0;
        int off = 0;
        int len = str.length();

        for(int i = 0; i < len; ++i) {
            h = 31 * h + str.charAt(off++);
        }

        return h;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
HashUtil.javaDefaultHash("abc") % 10 * 1024 * 1024 * 8
  • 1

结果为:33554432

每个过滤器都维护了一个BitMap

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nKJ3quK1-1609126961517)(hutools使用简介.assets/image-20201228100920730.png)]

这里的BitMap是用int数组存的,而且默认数组长度很大,并且多个过滤器还不是共享同一个BitMap的(避免多个过滤器间在不同元素的hash碰撞,使用空间弥补准确率,和布隆过滤器原始的模型有优有劣吧。),所以可以见得空间耗费极为巨大,但是与运算很快,效率很高:

public class IntMap implements BitMap, Serializable {
    private static final long serialVersionUID = 1L;
    private final int[] ints;

    public IntMap() {
        this.ints = new int[93750000];
    }

    public IntMap(int size) {
        this.ints = new int[size];
    }

    public void add(long i) {
        int r = (int)(i / 32L);
        int c = (int)(i % 32L);
        this.ints[r] |= 1 << c;
    }

    public boolean contains(long i) {
        int r = (int)(i / 32L);
        int c = (int)(i % 32L);
        return (this.ints[r] >>> c & 1) == 1;
    }

    public void remove(long i) {
        int r = (int)(i / 32L);
        int c = (int)(i % 32L);
        int[] var10000 = this.ints;
        var10000[r] &= ~(1 << c);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

excel表格从对象数组的导入导出

这个东西对应数据库数据表的导入导出简单了许多;

比如上星期写的数据库表通过控制器导入导出的,开始使用了opi,从网上找的代码,改啊改,表的字段有28个,写了100多行,步骤冗余,每个字段操作差不多却要重复28次。写的代码有臭又长。

EasyPoi(个人觉得并不Easy,很容易出问题)

改进时使用了EasyPoi对表导出,但是导入却一直空指针异常,而且数据库表对应pojo类要在类上和属性上加注解ExcelTarget,Excel。代码如下:

依赖:

<dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>4.0.0</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

pojo类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_employee")
@ApiModel(value="Employee对象", description="")
@ExcelTarget("employee")
public class Employee implements Serializable {

    @ApiModelProperty(value = "员工编号")
    @TableId(value = "id", type = IdType.AUTO)

    private Integer id;
    @Excel(name = "员工姓名")
    @ApiModelProperty(value = "员工姓名")
    private String name;
    @Excel(name="性别")
    @ApiModelProperty(value = "性别")
    private String gender;
    @Excel(name="出生日期")
    @ApiModelProperty(value = "出生日期")
    private LocalDate birthday;
    @Excel(name="身份证号")
    @ApiModelProperty(value = "身份证号")
    private String idCard;
    @Excel(name="婚姻状况")
    @ApiModelProperty(value = "婚姻状况")
    private String wedlock;
    @Excel(name="民族")
    @ApiModelProperty(value = "民族")
    private Integer nationId;
    @Excel(name="籍贯")
    @ApiModelProperty(value = "籍贯")
    private String nativePlace;
    @Excel(name="政治面貌")
    @ApiModelProperty(value = "政治面貌")
    private Integer politicId;
    @Excel(name="邮箱")
    @ApiModelProperty(value = "邮箱")
    private String email;
    @Excel(name="电话号码")
    @ApiModelProperty(value = "电话号码")
    private String phone;
    @Excel(name="联系地址")

    @ApiModelProperty(value = "联系地址")
    private String address;
    @Excel(name="所属部门")

    @ApiModelProperty(value = "所属部门")
    private Integer departmentId;
    @Excel(name="职称ID")
    @ApiModelProperty(value = "职称ID")
    private Integer jobLevelId;
    @Excel(name="职位ID")

    @ApiModelProperty(value = "职位ID")
    private Integer posId;
    @Excel(name="聘用形式")

    @ApiModelProperty(value = "聘用形式")
    private String engageForm;
    @Excel(name="最高学历")

    @ApiModelProperty(value = "最高学历")
    private String tiptopDegree;
    @Excel(name="所属专业")

    @ApiModelProperty(value = "所属专业")
    private String specialty;
    @Excel(name="毕业院校")

    @ApiModelProperty(value = "毕业院校")
    private String school;
    @Excel(name="入职日期")
    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    @ApiModelProperty(value = "入职日期")
    private LocalDate beginDate;
    @Excel(name="在职状态")

    @ApiModelProperty(value = "在职状态")
    private String workState;
    @Excel(name="工号")

    @ApiModelProperty(value = "工号")
    private String workID;
    @Excel(name="合同期限")
    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    @ApiModelProperty(value = "合同期限")
    private Double contractTerm;
    @Excel(name="转正日期")
    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    @ApiModelProperty(value = "转正日期")
    private LocalDate conversionTime;
    @Excel(name="离职日期")
    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    @ApiModelProperty(value = "离职日期")
    private LocalDate notWorkDate;
    @Excel(name="合同起始日期")
    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    @ApiModelProperty(value = "合同起始日期")
    private LocalDate beginContract;
    @Excel(name="合同终止日期")
    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    @ApiModelProperty(value = "合同终止日期")
    private LocalDate endContract;
    @Excel(name = "工龄")
    @ApiModelProperty(value = "工龄")
    private Integer workAge;
    @Excel(name = "工资账套ID")

    @ApiModelProperty(value = "工资账套ID")
    private Integer salaryId;

    @ApiModelProperty(value = "工资套账")
    @TableField(exist = false)
    private Salary salary;

    @ApiModelProperty(value = "部门")
    @TableField(exist = false)
    private  Department department;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

控制层:

@ApiOperation("导出表格")
    @RequestMapping(value = "/basic/export")
    @ResponseBody
    public void export(HttpServletResponse response) throws IOException {
        List<Employee> employees=employeeService.list();
        //参数:(一级标题,二级标题,表名),实体类类对象,导出的集合
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("员工列表", "632宿舍", "计算机学院宿舍信息表"),
                Employee.class, employees);
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        OutputStream os = response.getOutputStream();
        response.setHeader("Content-disposition", "attachment;filename=employee.xls");//默认Excel名称
        workbook.write(os);
        os.flush();
        os.close();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

很麻烦是不是;

ExcelUtil

这是utools给我们封装的表格工具:

导出

这个方法可以放到工具类里,在控制器中调用,传入数据库传入的对象列表,注入HttpServletResponse就可以了。

 /**
     * 通过网络导出
     * @param list
     * @param response
     */
    private static void writerToNet(List<?> list, HttpServletResponse response){
        // 通过工具类创建writer,默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter();
         // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(list, true);
        //out为OutputStream,需要写出到的目标流

        //response为HttpServletResponse对象
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
       //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
        response.setHeader("Content-Disposition","attachment;filename=test.xls");
        ServletOutputStream out= null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

        writer.flush(out, true);
       // 关闭writer,释放内存
        writer.close();
//此处记得关闭输出Servlet流
        IoUtil.close(out);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

我这里测试使用的hutools的httpServer的写法,懒得导入servlet或者使用springboot 的控制器(这个模块是maven的quackStart,懒得导入那么多依赖);

 public static void main(String[] args) throws Exception {
        //要写入excel的对象列表
        List<Panda> list= CollUtil.list(true);
        for(int i=0;i<100;i++){
            Panda panda=new Panda();
            panda.setName("熊猫"+i);
            panda.setPlace("成都");
            list.add(panda);
        }
        
        //模拟servlet发送表格
        HttpUtil.createServer(8088)
                .addAction("/", (request,response)->{
                    // 通过工具类创建writer,默认创建xls格式
                    ExcelWriter writer = ExcelUtil.getWriter();
                    // 一次性写出内容,使用默认样式,强制输出标题
                    writer.write(list, true);
                    //out为OutputStream,需要写出到的目标流

                    //response为HttpServletResponse对象
                    response.setContentType("application/vnd.ms-excel;charset=utf-8");
                    //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
                    response.setHeader("Content-Disposition","attachment;filename=test.xls");
                    OutputStream out= null;
                    try {
                        out = response.getOut();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    writer.flush(out, true);
                    // 关闭writer,释放内存
                    writer.close();
                    //此处记得关闭输出Servlet流
                    IoUtil.close(out);
                })
                .start();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

访问http://localhost:8088/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3NbWryZG-1609126961519)(hutools使用简介.assets/image-20201228104419404.png)]

下面就是对象列表导出的excel

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dmqorupg-1609126961520)(hutools使用简介.assets/image-20201228104451068.png)]

我们可以看出,在导出非常多字段的表时,EasyPoi需要写非常多注解,而hutools则以不变应万变,只要传入对象数据和HttpServletResponse就可以导出;

导入

public class ImportTable
{
    public static void main( String[] args )
    {
        HttpUtil.createServer(8088)
                .addAction("/file", (request, response) -> {
                final UploadFile file = request.getMultipart().getFile("file");
                //关键代码,就两行
                    ExcelReader reader = ExcelUtil.getReader(file.getFileInputStream());
                    reader.readAll(Panda.class).forEach(System.out::println);
                    
            }
    )
            .start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

是不是很简单,传入一个excel文件的MultiFile就可以了;

 //前端文件input传过来的Multipart文件
 ExcelReader reader = ExcelUtil.getReader(file.getFileInputStream());
 //读出Panda.class的List列表,这里我直接forEach打印了
 reader.readAll(Panda.class).forEach(System.out::println);
  • 1
  • 2
  • 3
  • 4

前端:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<form action="http://localhost:8088/file" enctype="multipart/form-data" method="post">
			选择文件:<input name="file" type="file" /><br>
			<input type="submit"  value="提交文件"/>
		</form>
	</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yWgzLugX-1609126961521)(hutools使用简介.assets/image-20201228104451068.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjGkJMkz-1609126961523)(hutools使用简介.assets/image-20201228110241239.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10Fa7wMh-1609126961524)(hutools使用简介.assets/image-20201228110315007.png)]

时钟调度(spring quartz 和CronUtil)

hutools也写了一套时钟调度;

spring quartZ

配置类:这是固定的,可以定义多个Job和多个触发器

任务执行时间(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))格式:秒 分 时 星期 日 月 年

*:所有

1,12 :1和12

1-5: 1到5

星期:*表示所有 ,可以用“MON-FRI”,“MON,WED,FRI”或甚至“MON-WED,SAT”代替前一个

import com.lwf.quartz.job.MyFirstJob;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuartzConfig {
 @Bean
 public JobDetail jobDetail1(){
 return JobBuilder.newJob(MyFirstJob.class).storeDurably().build();
 }
 // 每5秒触发⼀次任务
 @Bean
 public Trigger trigger2(){
     return TriggerBuilder.newTrigger()
                  .withIdentity("trigger2", "group1")
                   .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
                   .forJob(jobDetail1())
                   .build();
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

具体调度要执行的任务(类),在excute里写要定时执行的代码;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MyFirstJob implements Job {

 private Logger log = LoggerFactory.getLogger(MyFirstJob.class);
 @Override
 public void execute(JobExecutionContext context) throws
         JobExecutionException {
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 log.info(sdf.format(new Date()) + "-->" + "Hello Spring BootQuartz...");
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

启动spring boot启动程序,任务就开始执行。

CronUtil

写要执行的任务:继承extends 或者实现Runable,在run里写任务:

我试过上面两种,官方文档没有说清楚,我后来试过,是个方法能用,方法名不是run也可以,只要配置文件中方法全限定路径对了就可以。当然任务方法要非静态的。如果任务方法为静态方法,程序不会报错,但是任务不能执行。

/**
 * @author lwf
 * @title: ShowTime
 * @projectName hutoolstest
 * @description: 打印农历
 * @date 2020/12/2719:07
 */
public class ShowTime implements Runnable{
    public static  void  showTime(){
        ChineseDate date=new ChineseDate(new Date());
        System.out.println(date);
    }

    @Override
    public void run() {
       showTime();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

配置文件 resources\config\cron.setting里指定要执行的任务:

下面的写法等同:com.lwf.quartz.job.ShowTime.run= */10 * * * * * *

# 类(任务方法所在类)全限定路径
[com.lwf.quartz.job]
#每10秒执行,支持Quarzy  要加CronUtil.setMatchSecond(true);   秒 分 时 星期  日 月 年
ShowTime.run= */10 * * * * * *
  • 1
  • 2
  • 3
  • 4

任务执行时间:QuartZ的时间写法;

@SpringBootApplication
public class QuartzApplication {

    public static void main(String[] args) {
        SpringApplication.run(QuartzApplication.class, args);
        //hutools时钟任务
        CronUtil.start();
        //默认使用 分 秒 时 日 月 年
        //要使用Quartz格式使用下面代码开启
        CronUtil.setMatchSecond(true);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/544483
推荐阅读
相关标签
  

闽ICP备14008679号