dubbo多层嵌套异常报错抛出会有点问题

会多很多字符
,所以可以才有报错向上抛出的原则来实现

 /**
        * 注册用户信息
        *
        * @param member 用户信息
        * @return 结果
        */
       Boolean registerUserInfo(Member member) throws ServiceException;
       
       
       @Override
       public Boolean registerUserInfo(Member member) throws ServiceException{
           //判断账号是否已注册
           boolean exist = TenantHelper.dynamic(member.getTenantId(), () -> {
               return memberMapper.exists(new LambdaQueryWrapper<Member>()
                   .eq(Member::getUsername, member.getUsername()));
           });
           if (exist) {
               throw new ServiceException("账号已存在,请勿重复注册!");
           }
   
   //        //判断账号是否已注册
   //        boolean register = TenantHelper.dynamic(member.getTenantId(), () -> {
   //            return remoteMemberService.registerByMobile(registerBody.getUsername());
   //        });
   //        if (register) {
   //            throw new ServiceException("账号已存在,请勿重复注册!");
   //        }
           RedisUtils.deleteObject(RedisKeyEnum.SMS.getKey() + member.getUsername() + member.getType());
   
           String username = member.getUsername();
   //        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
   //            throw new ServiceException("当前系统没有开启注册功能");
   //        }
           member.setName("U:" + RandomUtil.randomNumbers(6));
           member.setAccountStatus(0);
           member.setAuthStatus(3);
           member.setAuthType(0);//默认个人认证  认证类型0 未认证 1个人认证 2企业认证
           //member.setShopStatus(0);
           member.setAccountStatus(0);
           member.setStatus(0);
           member.setIsDeleted(0);
           member.setShippersStatus(0);
   
           member.setCreateBy(member.getUsername());
           member.setUpdateBy(member.getUsername());
           member.setCreateTime(TimeUtils.getNowDate());
           boolean save = userService.save(member);
           if (save) {
               Company company = new Company();
               company.setTenantId(member.getTenantId());
               company.setMemberId(member.getId());
               company.setCompanyName("个人");
               company.setRoleId(1);
               company.setCompanyMobile(username);
               company.setCheckStatus(3);//审核状态 0 待审核 1审核通过 2审核不通过  3待提交
               company.setIsDefault(1);
               companyService.save(company);
           }
           return save;
       }

Ubuntu安装中文字体

安装中文字体

在centos中,字体库的存放位置就是/usr/shared/fonts目录,所以我们要做的就是在Windows系统找到中文字体文件,然后拷贝到该目录下。Windows系统中的字体文件

就在C:\Windows\Fonts目录中。所以,安装步骤就是:

在CentOS中创建新的中文字体文件夹,输入命令

mkdir -p /usr/share/fonts/chinese && chmod -R 755 /usr/share/fonts/chinese

将C:\Windows\Fonts中的中文字体——比如msyh.ttc

(微软雅黑)、simhei.ttf(黑体)、simsun.ttc(宋体)——拷贝上传到CentOS中刚刚创建的目录/usr/share/fonts/chinese下。PS:在WIndows中打开字体文件夹显示的不是msyh.ttc这样名字的文件,而是中文的字体名字,可以将需要的字体拷贝到桌面上先,到桌面上就会显示出真正的文件名
,再从桌面上上传到centos中。
安装字体索引指令,输入命令

yum install mkfontscale -y

进入目录/usr/share/fonts/chinese,生成字体索引,输入命令:

cd /usr/share/fonts/chinese mkfontscale

最后,通过上面介绍的查看已安装中文字体的命令,确认字体是否已安装成功

fc-list :lang=zh

ubuntu使用方法:

再刷新字体缓存就可以了,命令如下

sudo mkfontscale
sudo mkfontdir
sudo fc-cache -fv

注意:
如果运行mkfontscale命令时终端提示mkfontscale: command not found,则需要首先安装mkfontscale mkfontdir和fc-cache这个命令,安装方法如下:

使mkfontscale和mkfontdir命令正常运行

sudo apt-get install ttf-mscorefonts-installer

使fc-cache命令正常运行

sudo apt-get install fontconfig 

redis+mysql生成商品的唯一货号 带自动递增

如果redis数据被丢失,则从数据库查询出最大数值保存到redis在自增

  // 生成递增的货号逻辑
    public String generateProductCode() {
        lock.lock();  // 加锁,确保多线程安全
        try {
            // 从 Redis 获取当前货号,如果 Redis 中不存在,初始化货号
            String currentCodeStr = redisTemplate.opsForValue().get(PRODUCT_CODE_KEY);
            if (currentCodeStr == null) {
                // 从数据库中获取当前最大的货号
                Integer maxCode = productMapper.findMaxProductCode();
                if (maxCode == null) {
                    maxCode = 0;  // 如果数据库中没有数据,从 0 开始
                }
                // 初始化 Redis 中的货号为数据库中的最大值
                redisTemplate.opsForValue().set(PRODUCT_CODE_KEY, maxCode.toString());
            }

            // 使用 Redis 的 INCR 命令自增货号
            Long newCode = redisTemplate.opsForValue().increment(PRODUCT_CODE_KEY);
            return String.format("%08d", newCode);  // 格式化为 8 位数字
        } finally {
            lock.unlock();  // 解锁
        }
    }
 // 生成递增的货号
        String productCode = generateProductCode();
        product.setItemNumberPrefix("ZML");
        product.setItemNumber(productCode);
 private static final String PRODUCT_CODE_KEY = "product:code";  // Redis 中货号的 key
private final Lock lock = new ReentrantLock();  // 创建一个 ReentrantLock 锁

    @Autowired
    private StringRedisTemplate redisTemplate;
 // 查询当前数据库中最大的货号
    @Select("SELECT MAX(p.item_number) FROM Product p")
    Integer findMaxProductCode();

为了方便查询我是把编号和编号前缀分成了两个字段保存

private String itemNumberPrefix;
@ApiModelProperty(value = "商品货号")
private String itemNumber;

百度UEditor调试

提示后端配置有误的解决方案

package com.honghan.site.controller;

import com.alibaba.fastjson2.JSON;
import com.baidu.ueditor.ActionEnter;
import com.honghan.resource.api.RemoteFileService;
import com.honghan.resource.api.domain.SysFile;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.poi.util.IOUtils;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@RequestMapping("/ueditor")
@RestController
public class UeditorController {


    @DubboReference
    private RemoteFileService remoteFileService;
    //配置ueditor后端上传接口的验证
    @RequestMapping("/config")
    public String config(HttpServletRequest request, HttpServletResponse response, String action, MultipartFile[] upfile) throws IOException {
         //获取配置文件json内容返回给前端
        if (action.equals("config")) {
            request.setCharacterEncoding("utf-8");
            response.setHeader("Content-Type", "text/html");
            //注意path不能含有中文路径,确认该path能指向config.json
            String path = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "config";
            System.out.println("path = " + path);
            PrintWriter printWriter = response.getWriter();
            printWriter.write(new ActionEnter(request, path).exec());
            printWriter.flush();
            printWriter.close();
        }
        //上传图片
        else if (action.equals("uploadimage")) {
            Map<String, Object> result = new HashMap<String, Object>();
            for (MultipartFile multipartFile : upfile) {
                //调用系统写好的文件上传方法,并返回给前端上传后的文件路径,组件需要拼接回显
                SysFile sysFile = remoteFileService.upload(multipartFile.getName(),
                    multipartFile.getOriginalFilename(), multipartFile.getContentType(), multipartFile.getBytes());
                result.put("title", sysFile);
                result.put("original", multipartFile.getOriginalFilename());
                result.put("state", "SUCCESS");
                result.put("url", sysFile.getUrl());
                String jStr = JSON.toJSONString(result);
                return jStr;
            }
            return null;
        }
        //上传视频
        else if(action.equals("uploadvideo")){
            Map<String, Object> result = new HashMap<String, Object>();
            for (MultipartFile multipartFile : upfile) {
                SysFile sysFile = remoteFileService.upload(multipartFile.getName(),
                    multipartFile.getOriginalFilename(), multipartFile.getContentType(), multipartFile.getBytes());
                result.put("title", sysFile);
                result.put("original", multipartFile.getOriginalFilename());
                result.put("state", "SUCCESS");
                result.put("url", sysFile.getUrl());
                String jStr = JSON.toJSONString(result);
                return jStr;
            }
        }else{
            Map<String, Object> result = new HashMap<String, Object>();
            for (MultipartFile multipartFile : upfile) {
                SysFile sysFile = remoteFileService.upload(multipartFile.getName(),
                    multipartFile.getOriginalFilename(), multipartFile.getContentType(), multipartFile.getBytes());
                result.put("title", sysFile);
                result.put("original", multipartFile.getOriginalFilename());
                result.put("state", "SUCCESS");
                result.put("url", sysFile.getUrl());
                String jStr = JSON.toJSONString(result);
                return jStr;
            }
        }
        return null;
    }
}

config.json文件

    {
      "imageActionName": "uploadimage", /* 执行上传图片的action名称 */
      "imageFieldName": "upfile", /* 提交的图片表单名称 */
      "imageMaxSize": 2048000, /* 上传大小限制,单位B */
      "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
      "imageCompressEnable": true, /* 是否压缩图片,默认是true */
      "imageCompressBorder": 1600, /* 图片压缩最长边限制 */
      "imageInsertAlign": "none", /* 插入的图片浮动方式 */
      "imageUrlPrefix": "", /* 图片访问路径前缀 */
      "imagePathFormat": "image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
      /* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
      /* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
      /* {time} 会替换成时间戳 */                                /* {yyyy} 会替换成四位年份 */
      /* {yy} 会替换成两位年份 */
      /* {mm} 会替换成两位月份 */
      /* {dd} 会替换成两位日期 */
      /* {hh} 会替换成两位小时 */
      /* {ii} 会替换成两位分钟 */
      /* {ss} 会替换成两位秒 */
      /* 非法字符 \ : * ? " < > | */
      /* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */
      /* 涂鸦图片上传配置项 */
      "scrawlActionName": "uploadscrawl", /* 执行上传涂鸦的action名称 */
      "scrawlFieldName": "upfile", /* 提交的图片表单名称 */
      "scrawlPathFormat": "image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
      "scrawlMaxSize": 2048000, /* 上传大小限制,单位B */
      "scrawlUrlPrefix": "", /* 图片访问路径前缀 */
      "scrawlInsertAlign": "none",    /* 截图工具上传 */
      "snapscreenActionName": "uploadimage", /* 执行上传截图的action名称 */
      "snapscreenPathFormat": "image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
      "snapscreenUrlPrefix": "", /* 图片访问路径前缀 */
      "snapscreenInsertAlign": "none", /* 插入的图片浮动方式 */
      /* 抓取远程图片配置 */
      "catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
      "catcherActionName": "catchimage", /* 执行抓取远程图片的action名称 */
      "catcherFieldName": "source", /* 提交的图片列表表单名称 */
      "catcherPathFormat": "image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
      "catcherUrlPrefix": "", /* 图片访问路径前缀 */
      "catcherMaxSize": 2048000, /* 上传大小限制,单位B */
      "catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 抓取图片格式显示 */
      /* 上传视频配置 */
      "videoActionName": "uploadvideo", /* 执行上传视频的action名称 */
      "videoFieldName": "upfile", /* 提交的视频表单名称 */
      "videoPathFormat": "video/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
      "videoUrlPrefix": "http://localhost:81/dev-api/", /* 视频访问路径前缀 */
      "videoMaxSize": 102400000, /* 上传大小限制,单位B,默认100MB */
      "videoAllowFiles": [        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], /* 上传视频格式显示 */
      /* 上传文件配置 */
      "fileActionName": "uploadfile", /* controller里,执行上传视频的action名称 */
      "fileFieldName": "upfile", /* 提交的文件表单名称 */
      "filePathFormat": "file/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
      "fileUrlPrefix": "", /* 文件访问路径前缀 */
      "fileMaxSize": 51200000, /* 上传大小限制,单位B,默认50MB */
      "fileAllowFiles": [        ".png", ".jpg", ".jpeg", ".gif", ".bmp",        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"    ], /* 上传文件格式显示 */
      /* 列出指定目录下的图片 */
      "imageManagerActionName": "listimage", /* 执行图片管理的action名称 */
      "imageManagerListPath": "image/", /* 指定要列出图片的目录 */
      "imageManagerListSize": 20, /* 每次列出文件数量 */
      "imageManagerUrlPrefix": "", /* 图片访问路径前缀 */
      "imageManagerInsertAlign": "none", /* 插入的图片浮动方式 */
      "imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 列出的文件类型 */
      /* 列出指定目录下的文件 */
      "fileManagerActionName": "listfile", /* 执行文件管理的action名称 */
      "fileManagerListPath": "file/", /* 指定要列出文件的目录 */
      "fileManagerUrlPrefix": "", /* 文件访问路径前缀 */
      "fileManagerListSize": 20, /* 每次列出文件数量 */
      "fileManagerAllowFiles": [        ".png", ".jpg", ".jpeg", ".gif", ".bmp",        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"    ] /* 列出的文件类型 */
    }
    

What's more: 服务端需要做的配置

配置完上述内容后,控制台可能会出现"后台配置项返回格式出错,上传功能将不能正常使用!"的报错,
我们在编辑器中上传图片或者视频,也会出现响应的报错,这是因为没有配置服务器的请求接口,在ueditor.config.js中,对serverUrl进行配置:

// 服务器统一请求接口路径
, serverUrl: 'http://xxx/ueditor/config'
//地址管你们后端要去

MapStructPlus 报错整理

1."Couldn't retrieve @Mapper annotation" 异常

该异常是因为 MapStruct 依赖冲突导致的,由于 MapStructPlus 中已经依赖了 MapStruct,所以在使用时无需再添加 MapStruct 的依赖。 同时,建议其它依赖中的 MapStruct,也建议排除掉,比如 springfox-swagger2 中就依赖了 MapStruct。

排除完依赖后,重新执行 clean compile

2.两个类型不一致
可用注解:

@AutoMapping(target = "menuIds", expression = "java(com.honghan.common.core.utils.StringUtils.join(source.getMenuIds(), \",\"))")

例如类型:
private Long[] menuIds

private String menuIds;
类型

3.pom 的build设置

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.verison}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>com.github.therapi</groupId>
                            <artifactId>therapi-runtime-javadoc-scribe</artifactId>
                            <version>0.15.0</version>
                        </path>
                        <path>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                            <version>${spring-boot.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                        <path>
                            <groupId>io.github.linpeilie</groupId>
                            <artifactId>mapstruct-plus-processor</artifactId>
                            <version>${mapstruct-plus.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>${mapstruct-plus.lombok.version}</version>
                        </path>
                    </annotationProcessorPaths>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <!-- 单元测试使用 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surefire-plugin.version}</version>
                <configuration>
                    <argLine>-Dfile.encoding=UTF-8</argLine>
                    <!-- 根据打包环境执行对应的@Tag测试方法 -->
                    <groups>${profiles.active}</groups>
                    <!-- 排除标签 -->
                    <excludedGroups>exclude</excludedGroups>
                </configuration>
            </plugin>
            <!-- 统一版本号管理 -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>flatten-maven-plugin</artifactId>
                <version>${flatten-maven-plugin.version}</version>
                <configuration>
                    <updatePomFile>true</updatePomFile>
                    <flattenMode>resolveCiFriendliesOnly</flattenMode>
                </configuration>
                <executions>
                    <execution>
                        <id>flatten</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>flatten</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>flatten.clean</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>clean</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>com.spotify</groupId>
                    <artifactId>docker-maven-plugin</artifactId>
                    <version>${docker.plugin.version}</version>
                    <configuration>
                        <imageName>${docker.namespace}/${project.artifactId}:${project.version}</imageName>
                        <dockerDirectory>${project.basedir}</dockerDirectory>
                        <dockerHost>${docker.registry.host}</dockerHost>
                        <registryUrl>${docker.registry.url}</registryUrl>
                        <serverId>${docker.registry.url}</serverId>
                        <resources>
                            <resource>
                                <targetPath>/</targetPath>
                                <directory>${project.build.directory}</directory>
                                <include>${project.build.finalName}.jar</include>
                            </resource>
                        </resources>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <!-- 关闭过滤 -->
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/webapp/</directory>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <!-- 引入所有 匹配文件进行过滤 -->
                <includes>
                    <include>application*</include>
                    <include>bootstrap*</include>
                    <include>logback*</include>
                </includes>
                <!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>