mapstruct的基本使用

  Java   24分钟   774浏览   0评论

你好呀,我是小邹。

今天给大家分享一下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);
}

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

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

代码

引入相关依赖

<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-jdk8 -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-jdk8</artifactId>
    <version>1.2.0.CR1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.2.0.CR1</version>
</dependency>

创建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;
    }
}

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);
}

测试

启动报错:

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)

问题描述:

在使用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工程师,不应该只局限于"功能的实现",我们更应该追求高性能,优雅整洁的代码!

如果你觉得文章对你有帮助,那就请作者喝杯咖啡吧☕
微信
支付宝
😀
😃
😄
😁
😆
😅
🤣
😂
🙂
🙃
😉
😊
😇
🥰
😍
🤩
😘
😗
☺️
😚
😙
🥲
😋
😛
😜
🤪
😝
🤑
🤗
🤭
🫢
🫣
🤫
🤔
🤨
😐
😑
😶
😏
😒
🙄
😬
😮‍💨
🤤
😪
😴
😷
🤒
🤕
🤢
🤮
🤧
🥵
🥶
🥴
😵
😵‍💫
🤯
🥳
🥺
😠
😡
🤬
🤯
😈
👿
💀
☠️
💩
👻
👽
👾
🤖
😺
😸
😹
😻
😼
😽
🙀
😿
😾
👋
🤚
🖐️
✋️
🖖
🫱
🫲
🫳
🫴
🫷
🫸
👌
🤌
🤏
✌️
🤞
🫰
🤟
🤘
🤙
👈️
👉️
👆️
🖕
👇️
☝️
🫵
👍️
👎️
✊️
👊
🤛
🤜
👏
🙌
👐
🤲
🤝
🙏
✍️
💅
🤳
💪
🦾
🦿
🦵
🦶
👂
🦻
👃
👶
👧
🧒
👦
👩
🧑
👨
👩‍🦱
👨‍🦱
👩‍🦰
👨‍🦰
👱‍♀️
👱‍♂️
👩‍🦳
👨‍🦳
👩‍🦲
👨‍🦲
🧔‍♀️
🧔‍♂️
👵
🧓
👴
👲
👳‍♀️
👳‍♂️
🧕
👮‍♀️
👮‍♂️
👷‍♀️
👷‍♂️
💂‍♀️
💂‍♂️
🕵️‍♀️
🕵️‍♂️
👩‍⚕️
👨‍⚕️
👩‍🌾
👨‍🌾
👩‍🍳
👨‍🍳
🐶
🐱
🐭
🐹
🐰
🦊
🐻
🐼
🐨
🐯
🦁
🐮
🐷
🐸
🐵
🐔
🐧
🐦
🦅
🦉
🐴
🦄
🐝
🪲
🐞
🦋
🐢
🐍
🦖
🦕
🐬
🦭
🐳
🐋
🦈
🐙
🦑
🦀
🦞
🦐
🐚
🐌
🦋
🐛
🦟
🪰
🪱
🦗
🕷️
🕸️
🦂
🐢
🐍
🦎
🦖
🦕
🐊
🐢
🐉
🦕
🦖
🐘
🦏
🦛
🐪
🐫
🦒
🦘
🦬
🐃
🐂
🐄
🐎
🐖
🐏
🐑
🐐
🦌
🐕
🐩
🦮
🐕‍🦺
🐈
🐈‍⬛
🐓
🦃
🦚
🦜
🦢
🦩
🕊️
🐇
🦝
🦨
🦡
🦫
🦦
🦥
🐁
🐀
🐿️
🦔
🌵
🎄
🌲
🌳
🌴
🌱
🌿
☘️
🍀
🎍
🎋
🍃
🍂
🍁
🍄
🌾
💐
🌷
🌹
🥀
🌺
🌸
🌼
🌻
🌞
🌝
🌛
🌜
🌚
🌕
🌖
🌗
🌘
🌑
🌒
🌓
🌔
🌙
🌎
🌍
🌏
🪐
💫
🌟
🔥
💥
☄️
☀️
🌤️
🌥️
🌦️
🌧️
⛈️
🌩️
🌨️
❄️
☃️
🌬️
💨
💧
💦
🌊
🍇
🍈
🍉
🍊
🍋
🍌
🍍
🥭
🍎
🍏
🍐
🍑
🍒
🍓
🥝
🍅
🥥
🥑
🍆
🥔
🥕
🌽
🌶️
🥒
🥬
🥦
🧄
🧅
🍄
🥜
🍞
🥐
🥖
🥨
🥯
🥞
🧇
🧀
🍖
🍗
🥩
🥓
🍔
🍟
🍕
🌭
🥪
🌮
🌯
🥙
🧆
🥚
🍳
🥘
🍲
🥣
🥗
🍿
🧈
🧂
🥫
🍱
🍘
🍙
🍚
🍛
🍜
🍝
🍠
🍢
🍣
🍤
🍥
🥮
🍡
🥟
🥠
🥡
🦪
🍦
🍧
🍨
🍩
🍪
🎂
🍰
🧁
🥧
🍫
🍬
🍭
🍮
🍯
🍼
🥛
🍵
🍶
🍾
🍷
🍸
🍹
🍺
🍻
🥂
🥃
🥤
🧃
🧉
🧊
🗺️
🏔️
⛰️
🌋
🏕️
🏖️
🏜️
🏝️
🏞️
🏟️
🏛️
🏗️
🏘️
🏙️
🏚️
🏠
🏡
🏢
🏣
🏤
🏥
🏦
🏨
🏩
🏪
🏫
🏬
🏭
🏯
🏰
💒
🗼
🗽
🕌
🛕
🕍
⛩️
🕋
🌁
🌃
🏙️
🌄
🌅
🌆
🌇
🌉
🎠
🎡
🎢
💈
🎪
🚂
🚃
🚄
🚅
🚆
🚇
🚈
🚉
🚊
🚝
🚞
🚋
🚌
🚍
🚎
🚐
🚑
🚒
🚓
🚔
🚕
🚖
🚗
🚘
🚙
🚚
🚛
🚜
🏎️
🏍️
🛵
🦽
🦼
🛺
🚲
🛴
🛹
🚏
🛣️
🛤️
🛢️
🚨
🚥
🚦
🚧
🛶
🚤
🛳️
⛴️
🛥️
🚢
✈️
🛩️
🛫
🛬
🪂
💺
🚁
🚟
🚠
🚡
🛰️
🚀
🛸
🧳
📱
💻
⌨️
🖥️
🖨️
🖱️
🖲️
💽
💾
📀
📼
🔍
🔎
💡
🔦
🏮
📔
📕
📖
📗
📘
📙
📚
📓
📒
📃
📜
📄
📰
🗞️
📑
🔖
🏷️
💰
💴
💵
💶
💷
💸
💳
🧾
✉️
📧
📨
📩
📤
📥
📦
📫
📪
📬
📭
📮
🗳️
✏️
✒️
🖋️
🖊️
🖌️
🖍️
📝
📁
📂
🗂️
📅
📆
🗒️
🗓️
📇
📈
📉
📊
📋
📌
📍
📎
🖇️
📏
📐
✂️
🗃️
🗄️
🗑️
🔒
🔓
🔏
🔐
🔑
🗝️
🔨
🪓
⛏️
⚒️
🛠️
🗡️
⚔️
🔫
🏹
🛡️
🔧
🔩
⚙️
🗜️
⚗️
🧪
🧫
🧬
🔬
🔭
📡
💉
🩸
💊
🩹
🩺
🚪
🛏️
🛋️
🪑
🚽
🚿
🛁
🧴
🧷
🧹
🧺
🧻
🧼
🧽
🧯
🛒
🚬
⚰️
⚱️
🗿
🏧
🚮
🚰
🚹
🚺
🚻
🚼
🚾
🛂
🛃
🛄
🛅
⚠️
🚸
🚫
🚳
🚭
🚯
🚱
🚷
📵
🔞
☢️
☣️
❤️
🧡
💛
💚
💙
💜
🖤
💔
❣️
💕
💞
💓
💗
💖
💘
💝
💟
☮️
✝️
☪️
🕉️
☸️
✡️
🔯
🕎
☯️
☦️
🛐
🆔
⚛️
🉑
☢️
☣️
📴
📳
🈶
🈚
🈸
🈺
🈷️
✴️
🆚
💮
🉐
㊙️
㊗️
🈴
🈵
🈹
🈲
🅰️
🅱️
🆎
🆑
🅾️
🆘
🛑
💢
💯
💠
♨️
🚷
🚯
🚳
🚱
🔞
📵
🚭
‼️
⁉️
🔅
🔆
🔱
⚜️
〽️
⚠️
🚸
🔰
♻️
🈯
💹
❇️
✳️
🌐
💠
Ⓜ️
🌀
💤
🏧
🚾
🅿️
🈳
🈂️
🛂
🛃
🛄
🛅
  0 条评论