• mapstruct的基本使用


    你好呀,我是小邹。

    今天给大家分享一下mapstruct的基本使用

    前言

    MapStruct是一个Java注释处理器,用于生成类型安全的bean映射类。

    您要做的就是定义一个映射器接口,该接口声明任何必需的映射方法。在编译期间,MapStruct将生成此接口的实现。此实现使用简单的Java方法调用在源对象和目标对象之间进行映射,即没有反射或类似内容。

    与手动编写映射代码相比,MapStruct通过生成繁琐且易于出错的代码来节省时间。遵循配置方法上的约定,MapStruct使用合理的默认值,但在配置或实现特殊行为时不加理会。
    与动态映射框架相比,MapStruct具有以下优点:

    • 通过使用普通方法调用(settter/getter)而不是反射来快速执行

    • 编译时类型安全性:只能映射相互映射的对象和属性,不能将order实体意外映射到customer DTO等。

    • 如果有如下问题,编译时会抛出异常

      • 映射不完整(并非所有目标属性都被映射)
      • 映射不正确(找不到正确的映射方法或类型转换)
    • 可以通过freemarker定制化开发

    需求

    我的个人博客评论功能初期是通过如下代码实现的:

    /**
         * 发表评论
         */
        @ResponseBody
        @PostMapping(value = {"comments"})
        public void comments(HttpServletRequest request, @RequestBody @RequestParam("blogid") Integer blogId,
                             @RequestBody @RequestParam("blogUrl") String blogUrl,
                             @RequestBody @RequestParam("content") String content,
                             @RequestBody @RequestParam("nickname") String nickname,
                             @RequestBody @RequestParam("email") String email,
                             @RequestBody @RequestParam("avatar") String avatar,
                             @RequestBody @RequestParam("parentId") Integer parentId,
                             @RequestBody @RequestParam("parentName") String parentName,
                             @RequestBody @RequestParam("parentCommentId") Integer parentCommentId) throws Exception {
            String ip = IpUtils.getIpAddr(request);
            String province = IpUtils.getIpPossession(ip);
            Comments comments = new Comments();
            comments.setContent(content);
            comments.setEmail(email);
            comments.setCreateTime(new Date());
            comments.setBlogId(blogId);
            comments.setBlogUrl(blogUrl);
            comments.setProvince(province);
            comments.setIp(ip);
            comments.setUpdateTime(new Date());
            //数值越大则优先展示
            if (parentId == -1) {
                comments.setSort(1);
            } else {
                comments.setSort(Integer.parseInt(String.valueOf(System.currentTimeMillis() / 990)));
            }
            //未审核的评论默认不可见
            //暂时可见
            comments.setIsVisible(CommentStatus.VISIBLE.getStatus());
            //设置父节点id,-1为首节点
            comments.setParentId(parentId);
            comments.setParentName(parentName);
            comments.setNickname(nickname);
            comments.setAvatar(avatar);
            commentService.save(comments, parentCommentId);
    }
    
    • 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

    上面的代码有什么毛病吗?没有!

    但是看起来很臃肿,实现的一点也不优雅。今天就用mapstruct改造一下代码

    代码

    引入相关依赖

    
    <dependency>
        <groupId>org.mapstructgroupId>
        <artifactId>mapstruct-jdk8artifactId>
        <version>1.2.0.CR1version>
    dependency>
    
    <dependency>
        <groupId>org.mapstructgroupId>
        <artifactId>mapstruct-processorartifactId>
        <version>1.2.0.CR1version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    创建CommentInfoConverter接口

    package com.zou.blog.convert;
    
    import com.zou.blog.model.domain.Comments;
    import com.zou.blog.model.enums.CommentStatus;
    import com.zou.blog.util.IpUtils;
    import org.mapstruct.Mapper;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Date;
    
    /**
     * @author: 邹祥发
     * @date: 2022/9/8 13:46
     */
    @Mapper(componentModel = "spring")
    public interface CommentInfoConverter {
        default Comments map(HttpServletRequest request) throws Exception {
            String ip = IpUtils.getIpAddr(request);
            String province = IpUtils.getIpPossession(ip);
            Comments comments = new Comments();
            comments.setContent(request.getParameter("content"));
            comments.setEmail(request.getParameter("email"));
            comments.setCreateTime(new Date());
            comments.setBlogId(Integer.valueOf(request.getParameter("blogid")));
            comments.setBlogUrl(request.getParameter("blogUrl"));
            comments.setProvince(province);
            comments.setIp(ip);
            comments.setUpdateTime(new Date());
            int parentId = Integer.parseInt(request.getParameter("parentId"));
            //数值越大则优先展示
            if (parentId == -1) {
                comments.setSort(1);
            } else {
                comments.setSort(Integer.parseInt(String.valueOf(System.currentTimeMillis() / 990)));
            }
            //未审核的评论默认不可见
            //暂时可见
            comments.setIsVisible(CommentStatus.VISIBLE.getStatus());
            //设置父节点id,-1为首节点
            comments.setParentId(parentId);
            comments.setParentName(request.getParameter("parentName"));
            comments.setNickname(request.getParameter("nickname"));
            comments.setAvatar(request.getParameter("avatar"));
    
            return comments;
        }
    }
    
    • 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

    controller层(这样看起来是不是优雅多了😄)

      @Resource
      private CommentInfoConverter commentInfoConverter;		
    
    /**
     * 发表评论
     */
     @ResponseBody
     @PostMapping(value = {"comments"})
     public void comments(HttpServletRequest request, @RequestBody @RequestParam("parentCommentId") Integer parentCommentId) throws Exception {
         Comments comments = commentInfoConverter.map(request);
         commentService.save(comments, parentCommentId);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    测试

    启动报错:

    java: Internal error in the mapping processor: java.lang.NullPointerException  	
    at org.mapstruct.ap.internal.processor.DefaultVersionInformation.createManifestUrl(DefaultVersionInformation.java:182)  	
    at org.mapstruct.ap.internal.processor.DefaultVersionInformation.openManifest(DefaultVersionInformation.java:153)  	
    at org.mapstruct.ap.internal.processor.DefaultVersionInformation.getLibraryName(DefaultVersionInformation.java:129)  	
    at org.mapstruct.ap.internal.processor.DefaultVersionInformation.getCompiler(DefaultVersionInformation.java:122)  	
    at org.mapstruct.ap.internal.processor.DefaultVersionInformation.fromProcessingEnvironment(DefaultVersionInformation.java:95)  	
    at org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext.<init>(DefaultModelElementProcessorContext.java:50)  
    at org.mapstruct.ap.MappingProcessor.processMapperElements(MappingProcessor.java:218)  	
    at org.mapstruct.ap.MappingProcessor.process(MappingProcessor.java:156)  	
    at org.jetbrains.jps.javac.APIWrappers$ProcessorWrapper.process(APIWrappers.java:109)  	
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  	
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)  	
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  	
    at java.lang.reflect.Method.invoke(Method.java:498)  	
    at org.jetbrains.jps.javac.APIWrappers$1.invoke(APIWrappers.java:213)  	
    at org.mapstruct.ap.MappingProcessor.process(Unknown Source)  	
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)  	
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)  
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)  	
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)  	
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)  	
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)  	
    at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)  	
    at com.sun.tools.javac.main.Main.compile(Main.java:523)  	
    at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)  	
    at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)  	
    at org.jetbrains.jps.javac.JavacMain.compile(JavacMain.java:231)  	
    at org.jetbrains.jps.incremental.java.JavaBuilder.compileJava(JavaBuilder.java:501)  	
    at org.jetbrains.jps.incremental.java.JavaBuilder.compile(JavaBuilder.java:353)  	
    at org.jetbrains.jps.incremental.java.JavaBuilder.doBuild(JavaBuilder.java:277)  	
    at org.jetbrains.jps.incremental.java.JavaBuilder.build(JavaBuilder.java:231)  	
    at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1441)  	
    at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:1100)  	at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:1224)  	at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:1066)  	at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:832)  	at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:419)  	at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:183)  	at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:132)  	at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:302)  	at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:132)  	at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler.lambda$channelRead0$0(BuildMain.java:219)  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)  	at java.lang.Thread.run(Thread.java:748) 
    
    • 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

    问题描述:

    在使用MapStruct,idea2022.2版本在build项目的时候出现错误:java: Internal error in the mapping processor: java.lang.NullPointerException

    解决方案:
    Setting -->Build,Execution,Deployment -->Compiler -->User-local build加上参数:
    -Djps.track.ap.dependencies=false

    然后就可以正常启动了,评论功能的代码也正常执行。

    总结

    本篇文章记录了使用mapstruct改造代码的具体步骤,大家可作参考。

    作为一名合格的Java工程师,不应该只局限于"功能的实现",我们更应该追求高性能,优雅整洁的代码!

  • 相关阅读:
    Sangria:类似Nova folding scheme的relaxed PLONK for PLONK
    2023-09-26力扣每日一题-水题
    Promise 面试常考手写方法汇总
    数据结构 · 线性表 | 单链表
    测试老鸟总结,性能测试三大核心指标详解,并发/TPS/响应时间...
    c语言---18 函数(自定义函数)
    VUE+Spring前后台传值的坑,后台接收的String参数在末尾会出现 “=”
    构建企业级DNS系统(十)搭建Docker容器bind
    OpenCV入门(C++/Python)- 使用OpenCV标注图像(六)
    Spring拦截器的简单应用
  • 原文地址:https://blog.csdn.net/Zou_05/article/details/126764467