SpringBoot 项目(若依脚手架)2

mac2024-08-18  68

 

前言:

在上一章的基础上继续完成系统登录功能

一、连接数据库

1)引入依赖 有:

mysql 连接数据库的依赖、阿里数据库连接池依赖、pagehelper 分页插件依赖(包含了 mybatis 依赖在内)、lombok依赖

<!-- Mysql驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--阿里数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.14</version> </dependency> <!-- pagehelper 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>

2)编写 Druid 配置属性类

package com.ruoyi.framework.config.properties; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; /** * druid 配置属性 * * @author ruoyi */ @Configuration public class DruidProperties { @Value("${spring.datasource.druid.initialSize}") private int initialSize; @Value("${spring.datasource.druid.minIdle}") private int minIdle; @Value("${spring.datasource.druid.maxActive}") private int maxActive; @Value("${spring.datasource.druid.maxWait}") private int maxWait; @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") private int timeBetweenEvictionRunsMillis; @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") private int minEvictableIdleTimeMillis; @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") private int maxEvictableIdleTimeMillis; @Value("${spring.datasource.druid.validationQuery}") private String validationQuery; @Value("${spring.datasource.druid.testWhileIdle}") private boolean testWhileIdle; @Value("${spring.datasource.druid.testOnBorrow}") private boolean testOnBorrow; @Value("${spring.datasource.druid.testOnReturn}") private boolean testOnReturn; public DruidDataSource dataSource(DruidDataSource datasource) { /** 配置初始化大小、最小、最大 */ datasource.setInitialSize(initialSize); datasource.setMaxActive(maxActive); datasource.setMinIdle(minIdle); /** 配置获取连接等待超时的时间 */ datasource.setMaxWait(maxWait); /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); /** * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 */ datasource.setValidationQuery(validationQuery); /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ datasource.setTestWhileIdle(testWhileIdle); /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ datasource.setTestOnBorrow(testOnBorrow); /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ datasource.setTestOnReturn(testOnReturn); return datasource; } }

3)编写 Druid 连接池的配置类

package com.ruoyi.framework.config; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; import com.alibaba.druid.util.Utils; import com.ruoyi.framework.config.properties.DruidProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.*; import javax.sql.DataSource; import java.io.IOException; /** * druid 配置多数据源 * * @author ruoyi */ @Configuration public class DruidConfig { @Bean @ConfigurationProperties("spring.datasource.druid.master") public DataSource masterDataSource(DruidProperties druidProperties) { DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); return druidProperties.dataSource(dataSource); } /** * 去除监控页面底部的广告 */ @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { // 获取web监控页面的参数 DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); // 提取common.js的配置路径 String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); final String filePath = "support/http/resources/js/common.js"; // 创建filter进行过滤 Filter filter = new Filter() { @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); // 重置缓冲区,响应头不会被重置 response.resetBuffer(); // 获取common.js String text = Utils.readFromResource(filePath); // 正则替换banner, 除去底部的广告信息 text = text.replaceAll("<a.*?banner\"></a><br/>", ""); text = text.replaceAll("powered.*?shrek.wang</a>", ""); response.getWriter().write(text); } @Override public void destroy() { } }; FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(filter); registrationBean.addUrlPatterns(commonJsPattern); return registrationBean; } }

补充:多数据源的的配置可以在这个类中编写,等以后有机会在弄多数据源的配置

4)编写 application.yml 配置文件,添加数据库连接的信息

# 数据源配置 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: # 主库数据源 master: url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: 123456 # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: false url: username: password: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: login-password: filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true

5)放行 /druid/** 的请求

上一章的放行静态资源的时候,顺便就已经放行了。如图:

6)启动项目,测试Druid是否能访问,地址:http://localhost:8080/druid/index.html

 7)在 application.yml 中添加 mybatis 的配置

# MyBatis mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml

8)创建 resources/mybatis/mybatis-config.xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="cacheEnabled" value="true" /> <!-- 全局映射器启用缓存 --> <setting name="useGeneratedKeys" value="true" /> <!-- 允许 JDBC 支持自动生成主键 --> <setting name="defaultExecutorType" value="REUSE" /> <!-- 配置默认的执行器 --> <setting name="logImpl" value="SLF4J" /> <!-- 指定 MyBatis 所用日志的具体实现 --> <!-- <setting name="mapUnderscoreToCamelCase" value="true"/> 驼峰式命名 --> </settings> </configuration>

二、创建 实体类与表

1)创建 BaseEntity 类,以便后续实体类的继承

package com.ruoyi.common.core.domain; import lombok.Data; import java.io.Serializable; import java.util.Date; import java.util.Map; /** * @author liangcy * @create 2019/10/14 - 9:35 */ @Data public class BaseEntity implements Serializable { private static final long serialVersionUID = 1L; //搜索值 private String searchValue; //创建者 private String createBy; //创建时间 private Date createTime; //更新者 private String updateBy; //更新时间 private Date updateTime; //备注 private String remark; //请求参数 private Map<String, Object> params; }

2)创建 SysUser 类

package com.ruoyi.system.domain; import com.ruoyi.common.core.domain.BaseEntity; import lombok.Data; import java.util.Date; import java.util.List; /** * 用户对象 sys_user * @author liangcy * @create 2019/10/11 - 22:06 */ @Data public class SysUser extends BaseEntity { private Long userId; private Long deptId; private Long parentId; private Long roleId; private String loginName; private String userName; private String email; private String phonenumber; private String sex; private String avatar; private String password; private String salt; private String status; private String delFlag; private String loginIp; private Date loginDate; private SysDept dept; private List<SysRole> roles; private Long[] roleIds; private Long[] postIds; }

由于 SysUser 类中 用到了 SysDept、SysRole 类,因此顺手也将这两个类创建出来

3) 创建 SysDept 类

package com.ruoyi.system.domain; import com.ruoyi.common.core.domain.BaseEntity; import lombok.Data; /** * 部门表 sys_dept * @author liangcy * @create 2019/10/11 - 22:28 */ @Data public class SysDept extends BaseEntity { private Long deptId; private Long parentId; private String ancestors; private String deptName; private String orderNum; private String leader; private String phone; private String email; private String status; private String delFlag; private String parentName; }

4)创建 SysRole 类

package com.ruoyi.system.domain; import com.ruoyi.common.core.domain.BaseEntity; import lombok.Data; import java.util.Arrays; /** * 角色表 sys_role * @author liangcy * @create 2019/10/11 - 22:32 */ @Data public class SysRole extends BaseEntity { private Long roleId; private String roleName; private String roleKey; private String roleSort; private String dataScope; private String status; private String delFlag; /** 用户是否存在次角色标识 默认不存在*/ private boolean flag = false; private Long[] menuIds; }

5)创建数据库名为(ry),字符编码为 UTF-8,过程略

6)创建 用户表,角色表,部门表,并且往这3表中插入数据

-- ---------------------------- -- 1、部门表 -- ---------------------------- drop table if exists sys_dept; create table sys_dept ( dept_id bigint(20) not null auto_increment comment '部门id', parent_id bigint(20) default 0 comment '父部门id', ancestors varchar(50) default '' comment '祖级列表', dept_name varchar(30) default '' comment '部门名称', order_num int(4) default 0 comment '显示顺序', leader varchar(20) default null comment '负责人', phone varchar(11) default null comment '联系电话', email varchar(50) default null comment '邮箱', status char(1) default '0' comment '部门状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', primary key (dept_id) ) engine=innodb auto_increment=200 comment = '部门表'; -- ---------------------------- -- 初始化-部门表数据 -- ---------------------------- insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); -- ---------------------------- -- 2、用户信息表 -- ---------------------------- drop table if exists sys_user; create table sys_user ( user_id bigint(20) not null auto_increment comment '用户ID', dept_id bigint(20) default null comment '部门ID', login_name varchar(30) not null comment '登录账号', user_name varchar(30) not null comment '用户昵称', user_type varchar(2) default '00' comment '用户类型(00系统用户)', email varchar(50) default '' comment '用户邮箱', phonenumber varchar(11) default '' comment '手机号码', sex char(1) default '0' comment '用户性别(0男 1女 2未知)', avatar varchar(100) default '' comment '头像路径', password varchar(50) default '' comment '密码', salt varchar(20) default '' comment '盐加密', status char(1) default '0' comment '帐号状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', login_ip varchar(50) default '' comment '最后登陆IP', login_date datetime comment '最后登陆时间', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (user_id) ) engine=innodb auto_increment=100 comment = '用户信息表'; -- ---------------------------- -- 初始化-用户信息表数据 -- ---------------------------- insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员'); insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '8e6d98b90472783cc73c17047ddccf36', '222222', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '测试员'); -- ---------------------------- -- 3、角色信息表 -- ---------------------------- drop table if exists sys_role; create table sys_role ( role_id bigint(20) not null auto_increment comment '角色ID', role_name varchar(30) not null comment '角色名称', role_key varchar(100) not null comment '角色权限字符串', role_sort int(4) not null comment '显示顺序', data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', status char(1) not null comment '角色状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (role_id) ) engine=innodb auto_increment=100 comment = '角色信息表'; -- ---------------------------- -- 初始化-角色信息表数据 -- ---------------------------- insert into sys_role values('1', '管理员', 'admin', 1, 1, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员'); insert into sys_role values('2', '普通角色', 'common', 2, 2, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '普通角色');

三、创建 Dao层

1)创建 SysUserMapper 接口

接口中含有三个方法 :selectUserByLoginName、selectUserByPhoneNumber、selectUserByEmail 分别是通过用户名、电话号码、邮箱来查询用户

package com.ruoyi.system.mapper; import com.ruoyi.system.domain.SysUser; import java.util.List; /** * @author liangcy * @create 2019/10/13 - 10:09 */ public interface SysUserMapper { /** * 通过用户名查询用户 * * @param userName 用户名 * @return 用户对象信息 */ public SysUser selectUserByLoginName(String userName); /** * 通过手机号码查询用户 * * @param phoneNumber 手机号码 * @return 用户对象信息 */ public SysUser selectUserByPhoneNumber(String phoneNumber); /** * 通过邮箱查询用户 * * @param email 邮箱 * @return 用户对象信息 */ public SysUser selectUserByEmail(String email); }

2)编写 SysUserMapper 接口对应的  SysUserMapper.xml 文件

所有的 mapper接口对应的 xml文件应该放在:resources/mapper/system 目录下,在 application.yml 中有定义过这个路径

 

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.system.mapper.SysUserMapper"> <resultMap id="SysUserResult" type="SysUser"> <id property="userId" column="user_id" /> <result property="deptId" column="dept_id"/> <result property="loginName" column="login_name"/> <result property="userName" column="user_name"/> <result property="email" column="email"/> <result property="phonenumber" column="phonenumber"/> <result property="sex" column="sex"/> <result property="avatar" column="avatar"/> <result property="password" column="password"/> <result property="salt" column="salt"/> <result property="status" column="status"/> <result property="delFlag" column="del_flag"/> <result property="loginIp" column="login_ip"/> <result property="loginDate" column="login_date"/> <result property="createBy" column="create_by"/> <result property="createTime" column="create_time"/> <result property="updateBy" column="update_by"/> <result property="updateTime" column="update_time"/> <result property="updateBy" column="update_by"/> <result property="updateTime" column="update_time"/> <result property="remark" column="remark"/> <association property="dept" column="dept_id" javaType="SysDept" resultMap="deptResult"/> <collection property="roles" javaType="java.util.List" resultMap="roleResult"/> </resultMap> <resultMap id="deptResult" type="SysDept"> <id property="deptId" column="dept_id"/> <result property="parentId" column="parent_id"/> <result property="deptName" column="dept_name"/> <result property="orderNum" column="order_num"/> <result property="leader" column="leader"/> <result property="status" column="dept_status"/> </resultMap> <resultMap id="roleResult" type="SysRole"> <id property="roleId" column="role_id"/> <result property="roleName" column="role_name"/> <result property="roleKey" column="role_key"/> <result property="roleSort" column="role_sort"/> <result property="dataScope" column="data_scope"/> <result property="status" column="role_status"/> </resultMap> <sql id="selectUserVo"> select u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.password, u.salt, u.status, u.del_flag, u.login_ip, u.login_date, u.create_time, u.remark, d.dept_id, d.parent_id, d.dept_name, d.order_num, d.leader, d.status as dept_status, r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status from sys_user u left join sys_dept d on u.dept_id = d.dept_id left join sys_user_role ur on u.user_id = ur.user_id left join sys_role r on r.role_id = ur.role_id </sql> <select id="selectUserByLoginName" parameterType="String" resultMap="SysUserResult"> <include refid="selectUserVo" /> where u.login_name = #{userName} </select> <select id="selectUserByPhoneNumber" parameterType="String" resultMap="SysUserResult"> <include refid="selectUserVo" /> where u.phonenumber = #{phonenumber} </select> <select id="selectUserByEmail" parameterType="String" resultMap="SysUserResult"> <include refid="selectUserVo" /> where u.email = #{email} </select> </mapper>

补充:

①、type="SysUser"  不需要写全类名,因为在application.yml 中已经指定搜索的包别名

②、需要注意的一点,在结果集映射中的 一对一,一对多关系 是怎么写的?

3)配置Mabatis包扫描,加到启动类中

@MapperScan("com.ruoyi.**.mapper")

四、编写Dao测试类

选中需要测试的 接口类名,然后 按住 alt + 回车, 选生产测试类

package com.ruoyi.system.mapper; import com.ruoyi.system.domain.SysUser; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; import static org.junit.Assert.*; /** * @author liangcy * @create 2019/10/31 - 22:05 */ @RunWith(SpringRunner.class) @SpringBootTest public class SysUserMapperTest { @Resource SysUserMapper userMapper; @Test public void selectUserByLoginName() { SysUser user = userMapper.selectUserByLoginName("admin"); System.out.println(user); } @Test public void selectUserByPhoneNumber() { SysUser user = userMapper.selectUserByPhoneNumber("15888888888"); System.out.println(user); } @Test public void selectUserByEmail() { SysUser user = userMapper.selectUserByEmail("ry@163.com"); System.out.println(user); } }

运行测试方法,报错 :Could not resolve type alias 'SysUser'

解决的办法:

方法一、将 resultMap 中的结果集 全部写全类名

方法二、修改别名,之前写 ** 会报错,但是在项目中运行是正常的。

修改完后运行结果:

测试 电话号码登录以及邮箱登录 也是OK的。

五、定义用户相关的异常类

5.1 自定义异常的 基类 BaseException

package com.ruoyi.common.exception.base; import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.StringUtils; import lombok.Data; /** * 基础异常 * @author liangcy * @create 2019/10/12 - 10:14 */ @Data public class BaseException extends RuntimeException{ private static final long serialVersionUID = 1L; // 所属模块 private String module; //错误码 private String code; //错误码对应的参数 private Object[] args; //错误消息 private String defaultMessage; @Override public String getMessage() { String message = null; if(!StringUtils.isEmpty(code)){ message = MessageUtils.message(code, args); } if(message == null){ message = defaultMessage; } return message; } public BaseException(String module, String code, Object[] args, String defaultMessage) { this.module = module; this.code = code; this.args = args; this.defaultMessage = defaultMessage; } public BaseException(){ } }

5.1.1 上一步自定义 BaseException 中用到的 StringUtils 类

package com.ruoyi.common.utils; import java.util.Collection; import java.util.Map; //import com.ruoyi.common.core.text.StrFormatter; /** * 字符串工具类 * * @author ruoyi */ public class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 空字符串 */ private static final String NULLSTR = ""; /** * 下划线 */ private static final char SEPARATOR = '_'; /** * 获取参数不为空值 * * @param value defaultValue 要判断的value * @return value 返回值 */ public static <T> T nvl(T value, T defaultValue) { return value != null ? value : defaultValue; } /** * * 判断一个Collection是否为空, 包含List,Set,Queue * * @param coll 要判断的Collection * @return true:为空 false:非空 */ public static boolean isEmpty(Collection<?> coll) { return isNull(coll) || coll.isEmpty(); } /** * * 判断一个Collection是否非空,包含List,Set,Queue * * @param coll 要判断的Collection * @return true:非空 false:空 */ public static boolean isNotEmpty(Collection<?> coll) { return !isEmpty(coll); } /** * * 判断一个对象数组是否为空 * * @param objects 要判断的对象数组 * * @return true:为空 false:非空 */ public static boolean isEmpty(Object[] objects) { return isNull(objects) || (objects.length == 0); } /** * * 判断一个对象数组是否非空 * * @param objects 要判断的对象数组 * @return true:非空 false:空 */ public static boolean isNotEmpty(Object[] objects) { return !isEmpty(objects); } /** * * 判断一个Map是否为空 * * @param map 要判断的Map * @return true:为空 false:非空 */ public static boolean isEmpty(Map<?, ?> map) { return isNull(map) || map.isEmpty(); } /** * * 判断一个Map是否为空 * * @param map 要判断的Map * @return true:非空 false:空 */ public static boolean isNotEmpty(Map<?, ?> map) { return !isEmpty(map); } /** * * 判断一个字符串是否为空串 * * @param str String * @return true:为空 false:非空 */ public static boolean isEmpty(String str) { return isNull(str) || NULLSTR.equals(str.trim()); } /** * * 判断一个字符串是否为非空串 * * @param str String * @return true:非空串 false:空串 */ public static boolean isNotEmpty(String str) { return !isEmpty(str); } /** * * 判断一个对象是否为空 * * @param object Object * @return true:为空 false:非空 */ public static boolean isNull(Object object) { return object == null; } /** * * 判断一个对象是否非空 * * @param object Object * @return true:非空 false:空 */ public static boolean isNotNull(Object object) { return !isNull(object); } /** * * 判断一个对象是否是数组类型(Java基本型别的数组) * * @param object 对象 * @return true:是数组 false:不是数组 */ public static boolean isArray(Object object) { return isNotNull(object) && object.getClass().isArray(); } /** * 去空格 */ public static String trim(String str) { return (str == null ? "" : str.trim()); } /** * 截取字符串 * * @param str 字符串 * @param start 开始 * @return 结果 */ public static String substring(final String str, int start) { if (str == null) { return NULLSTR; } if (start < 0) { start = str.length() + start; } if (start < 0) { start = 0; } if (start > str.length()) { return NULLSTR; } return str.substring(start); } /** * 截取字符串 * * @param str 字符串 * @param start 开始 * @param end 结束 * @return 结果 */ public static String substring(final String str, int start, int end) { if (str == null) { return NULLSTR; } if (end < 0) { end = str.length() + end; } if (start < 0) { start = str.length() + start; } if (end > str.length()) { end = str.length(); } if (start > end) { return NULLSTR; } if (start < 0) { start = 0; } if (end < 0) { end = 0; } return str.substring(start, end); } /** * 格式化文本, {} 表示占位符<br> * 此方法只是简单将占位符 {} 按照顺序替换为参数<br> * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br> * 例:<br> * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br> * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br> * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> * * @param template 文本模板,被替换的部分用 {} 表示 * @param params 参数值 * @return 格式化后的文本 */ // public static String format(String template, Object... params) // { // if (isEmpty(params) || isEmpty(template)) // { // return template; // } // return StrFormatter.format(template, params); // } /** * 下划线转驼峰命名 */ public static String toUnderScoreCase(String str) { if (str == null) { return null; } StringBuilder sb = new StringBuilder(); // 前置字符是否大写 boolean preCharIsUpperCase = true; // 当前字符是否大写 boolean curreCharIsUpperCase = true; // 下一字符是否大写 boolean nexteCharIsUpperCase = true; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (i > 0) { preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); } else { preCharIsUpperCase = false; } curreCharIsUpperCase = Character.isUpperCase(c); if (i < (str.length() - 1)) { nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); } if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { sb.append(SEPARATOR); } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { sb.append(SEPARATOR); } sb.append(Character.toLowerCase(c)); } return sb.toString(); } /** * 是否包含字符串 * * @param str 验证字符串 * @param strs 字符串组 * @return 包含返回true */ public static boolean inStringIgnoreCase(String str, String... strs) { if (str != null && strs != null) { for (String s : strs) { if (str.equalsIgnoreCase(trim(s))) { return true; } } } return false; } /** * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld * * @param name 转换前的下划线大写方式命名的字符串 * @return 转换后的驼峰式命名的字符串 */ public static String convertToCamelCase(String name) { StringBuilder result = new StringBuilder(); // 快速检查 if (name == null || name.isEmpty()) { // 没必要转换 return ""; } else if (!name.contains("_")) { // 不含下划线,仅将首字母大写 return name.substring(0, 1).toUpperCase() + name.substring(1); } // 用下划线将原始字符串分割 String[] camels = name.split("_"); for (String camel : camels) { // 跳过原始字符串中开头、结尾的下换线或双重下划线 if (camel.isEmpty()) { continue; } // 首字母大写 result.append(camel.substring(0, 1).toUpperCase()); result.append(camel.substring(1).toLowerCase()); } return result.toString(); } /** * 驼峰式命名法 例如:user_name->userName */ public static String toCamelCase(String s) { if (s == null) { return null; } s = s.toLowerCase(); StringBuilder sb = new StringBuilder(s.length()); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == SEPARATOR) { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(c)); upperCase = false; } else { sb.append(c); } } return sb.toString(); } }

补充:这一步需要导入依赖

<!--常用工具类 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency>

5.1.2 BaseExcetpion 类中用到的 MessageUtils

package com.ruoyi.common.utils; import com.ruoyi.common.utils.spring.SpringUtils; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; /** * 获取 i18n资源文件 * @author liangcy * @create 2019/10/12 - 10:23 */ public class MessageUtils { /** * 根据消息键和参数 获取消息 委托给spring messageSource * * @param code 消息键 * @param args 参数 * @return 获取国际化翻译值 */ public static String message(String code, Object... args) { MessageSource messageSource = SpringUtils.getBean(MessageSource.class); return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); } }

补充:

由于 LocaleContextHolder.getLocale() 这个地方用到了国际化,因此顺便把国际化也加上

①、I18nConfig :国际化配置类

package com.ruoyi.framework.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.i18n.SessionLocaleResolver; import java.util.Locale; /** * 资源文件配置加载 * * @author ruoyi */ @Configuration public class I18nConfig implements WebMvcConfigurer { @Bean public LocaleResolver localeResolver() { SessionLocaleResolver slr = new SessionLocaleResolver(); // 默认语言 slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE); return slr; } @Bean public LocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); // 参数名 lci.setParamName("lang"); return lci; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); } }

②、在application.yml 中国际化的配置

# 数据源配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: static/i18n/messages

③、创建国际化资源文件,由于之前在stati 文件夹的以及提供过了,在此截图出来

最新回复(0)