# milkbox2-api **Repository Path**: guo-yongchen/milkbox2-api ## Basic Information - **Project Name**: milkbox2-api - **Description**: 全新架构milkbox - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-12-30 - **Last Updated**: 2025-05-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringBoot3, java21, SaToken, BCrypt, 三员权限管理 ## README # 技术栈 ## 主要技术 基础语言(Java 21) 整合框架(SpringBoot 3) 持久层框架(MybatisPlus) 缓存(Redis) ## 辅助技术 简化类(Lombok) 接口文档(SpringDoc) 糊涂工具包(Hutool) 权限认证(SaToken) 密码保护(BCrypt) # 升级java21的问题 升级到java21以后的启动参数,不加会报错 启动举例 ```shell java21的bin目录/java -jar jar包目录/jar包名称.jar --add-opens java.base/sun.util.calendar=ALL-UNNAMED ``` 必选参数 ```shell --add-opens java.base/sun.util.calendar=ALL-UNNAMED ``` 这些以后可能会用到 ```shell --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/jdk.internal.access=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED ``` # 打包与启动 ## 如何打jar包 在项目根路径下执行maven的package命令,之后会在milkbox-app模块下的target目录下生成一个jar包,可以使用指令启动这个jar包 ## 在idea中启动 启动时需要添加环境变量,如下图所示 ![image-20240112111124776](img/image-20240112111124776.png) 主要包含的环境变量 ```bash DB_HOST=localhost DB_PASSWORD=xxxx DB_PORT=3306 DB_USERNAME=root ``` ## 在命令行中启动 启动命令参考 win,注意要使用cmd,不要用powershell ```bash chcp chcp 65001 C:\Users\Administrator\.jdks\openjdk-21.0.1\bin\java -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 --add-opens java.base/sun.util.calendar=ALL-UNNAMED -jar .\milkbox-app-1.0-DEV.jar ``` # 新建模块 ## 在milkbox-service模块下新建模块后需要配置maven的导包依赖 在项目根目录下的pom.xml的dependencyManagement中定义新模块的版本,然后在milkbox-app模块中引入新模块 # MapStruct 项目建议使用MapStruct来做对象转换。定义一个转换接口与转换方法,MapStruct会根据方法的参数与返回,在启动项目之前的编译阶段值自动生成实现类。 > 注意:如果对接口进行了修改,一定先执行maven的clean命令然后再编译项目。否则新修改的内容可能不会更新编译。 当前其对应接口的实现类生成的源码文件位于`模块.../target/generated-sources/annotations/包路径.../XxxxxxImpl.java` 其实现类的字节码文件将会按照接口的包路径位置生成 写法举例如下: ```java package top.milkbox.sys.modular.user.mapStruct; import org.mapstruct.Mapper; import top.milkbox.sys.modular.user.entity.SysUserEntity; import top.milkbox.sys.modular.user.param.SysUserAddParam; import top.milkbox.sys.modular.user.param.SysUserEditParam; import top.milkbox.sys.modular.user.vo.SysUserVo; /** * SysUser相关的实体类之间的转换
* 此接口由MapStruct在编译时生成实现代码,详细解释请看readme
* * @author milkbox * @Data 2024-11-19 */ @Mapper // 注意这个Mapper不是String的Mapper public interface SysUserMapStruct { /** * entity转vo */ SysUserVo entityToVo(SysUserEntity entity); /** * addParam转entity */ SysUserEntity addParamToEntity(SysUserAddParam addParam); /** * editParam转entity */ SysUserEntity editParamToEntity(SysUserEditParam editParam); } ``` 生成的实现类源码: ```java package top.milkbox.sys.modular.user.mapStruct; import javax.annotation.processing.Generated; import org.springframework.stereotype.Component; import top.milkbox.sys.modular.user.entity.SysUserEntity; import top.milkbox.sys.modular.user.param.SysUserAddParam; import top.milkbox.sys.modular.user.param.SysUserEditParam; import top.milkbox.sys.modular.user.vo.SysUserVo; @Generated( value = "org.mapstruct.ap.MappingProcessor", date = "2024-11-19T09:38:00+0800", comments = "version: 1.5.5.Final, compiler: javac, environment: Java 21.0.1 (Oracle Corporation)" ) @Component public class SysUserMapStructImpl implements SysUserMapStruct { @Override public SysUserVo entityToVo(SysUserEntity entity) { if ( entity == null ) { return null; } SysUserVo sysUserVo = new SysUserVo(); sysUserVo.setSortCode( entity.getSortCode() ); sysUserVo.setCreateUser( entity.getCreateUser() ); sysUserVo.setCreateTime( entity.getCreateTime() ); sysUserVo.setUpdateUser( entity.getUpdateUser() ); sysUserVo.setUpdateTime( entity.getUpdateTime() ); sysUserVo.setId( entity.getId() ); sysUserVo.setAccount( entity.getAccount() ); sysUserVo.setNickname( entity.getNickname() ); sysUserVo.setEmail( entity.getEmail() ); sysUserVo.setPhone( entity.getPhone() ); sysUserVo.setAvatar( entity.getAvatar() ); sysUserVo.setGender( entity.getGender() ); sysUserVo.setSecretLevel( entity.getSecretLevel() ); sysUserVo.setStatus( entity.getStatus() ); sysUserVo.setBeforeLoginIp( entity.getBeforeLoginIp() ); sysUserVo.setBeforeLoginAddress( entity.getBeforeLoginAddress() ); sysUserVo.setBeforeLoginTime( entity.getBeforeLoginTime() ); sysUserVo.setBeforeLoginDevice( entity.getBeforeLoginDevice() ); sysUserVo.setNewLoginIp( entity.getNewLoginIp() ); sysUserVo.setNewLoginAddress( entity.getNewLoginAddress() ); sysUserVo.setNewLoginTime( entity.getNewLoginTime() ); sysUserVo.setNewLoginDevice( entity.getNewLoginDevice() ); return sysUserVo; } @Override public SysUserEntity addParamToEntity(SysUserAddParam addParam) { if ( addParam == null ) { return null; } SysUserEntity sysUserEntity = new SysUserEntity(); sysUserEntity.setAccount( addParam.getAccount() ); sysUserEntity.setNickname( addParam.getNickname() ); sysUserEntity.setEmail( addParam.getEmail() ); sysUserEntity.setPhone( addParam.getPhone() ); sysUserEntity.setAvatar( addParam.getAvatar() ); sysUserEntity.setGender( addParam.getGender() ); sysUserEntity.setSecretLevel( addParam.getSecretLevel() ); sysUserEntity.setStatus( addParam.getStatus() ); return sysUserEntity; } @Override public SysUserEntity editParamToEntity(SysUserEditParam editParam) { if ( editParam == null ) { return null; } SysUserEntity sysUserEntity = new SysUserEntity(); sysUserEntity.setId( editParam.getId() ); sysUserEntity.setAccount( editParam.getAccount() ); sysUserEntity.setPassword( editParam.getPassword() ); sysUserEntity.setNickname( editParam.getNickname() ); sysUserEntity.setEmail( editParam.getEmail() ); sysUserEntity.setPhone( editParam.getPhone() ); sysUserEntity.setAvatar( editParam.getAvatar() ); sysUserEntity.setGender( editParam.getGender() ); sysUserEntity.setSecretLevel( editParam.getSecretLevel() ); sysUserEntity.setStatus( editParam.getStatus() ); sysUserEntity.setBeforeLoginIp( editParam.getBeforeLoginIp() ); sysUserEntity.setBeforeLoginAddress( editParam.getBeforeLoginAddress() ); sysUserEntity.setBeforeLoginTime( editParam.getBeforeLoginTime() ); sysUserEntity.setBeforeLoginDevice( editParam.getBeforeLoginDevice() ); sysUserEntity.setNewLoginIp( editParam.getNewLoginIp() ); sysUserEntity.setNewLoginAddress( editParam.getNewLoginAddress() ); sysUserEntity.setNewLoginTime( editParam.getNewLoginTime() ); sysUserEntity.setNewLoginDevice( editParam.getNewLoginDevice() ); return sysUserEntity; } } ``` # 有关时区的问题 ## 时间的存取过程 在java中使用new Date()方式创建亚洲上海时区时间->mysql数据库中使用datetime数据类型存储无时区时间->java读取时间并转为上海时区时间->springmvc中使用jackson将java时间转为字符串(其会按照application配置文件中的配置进行转换)->返回给前端年月日格式的字符串。