jws = Jwts.parser()
+ .setSigningKey(jwtProperties.getSecret().getBytes(UTF8))
+ .parseClaimsJws(token);
+ return jws;
+ } catch (Exception e) {
+ log.error("verify token exception",e);
+ }
+ return null;
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/ClientInfo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/ClientInfo.java
new file mode 100644
index 0000000..100f53d
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/ClientInfo.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.security.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 用户客户端信息对象
+ *
+ * @author geekidea
+ * @date 2019-05-23
+ **/
+@Data
+public class ClientInfo implements Serializable {
+
+ private static final long serialVersionUID = -5549531244606897514L;
+
+ /**
+ * ip
+ */
+ private String ip;
+
+ /**
+ * ip对应的地址
+ */
+ private String addree;
+
+ /**
+ * 浏览器名称
+ */
+ private String browserName;
+
+ /**
+ * 浏览器版本
+ */
+ private String browserversion;
+
+ /**
+ * 浏览器引擎名称
+ */
+ private String engineName;
+
+ /**
+ * 浏览器引擎版本
+ */
+ private String engineVersion;
+
+ /**
+ * 系统名称
+ */
+ private String osName;
+
+ /**
+ * 平台名称
+ */
+ private String platformName;
+
+ /**
+ * 是否是手机
+ */
+ private boolean mobile;
+
+ /**
+ * 移动端设备型号
+ */
+ private String deviceName;
+
+ /**
+ * 移动端设备型号
+ */
+ private String deviceModel;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/DeviceInfo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/DeviceInfo.java
new file mode 100644
index 0000000..8cba35c
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/DeviceInfo.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.security.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 设备信息
+ *
+ * @author geekidea
+ * @date 2019-05-24
+ **/
+@Data
+public class DeviceInfo implements Serializable {
+ private static final long serialVersionUID = -5912785220335057555L;
+
+ /**
+ * 设备名称
+ */
+ private String name;
+
+ /**
+ * 设备型号
+ */
+ private String model;
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/JwtTokenRedisVo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/JwtTokenRedisVo.java
new file mode 100644
index 0000000..96adbf6
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/JwtTokenRedisVo.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.security.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ *
+ *
+ * @author geekidea
+ * @date 2019-05-23
+ **/
+@Data
+public class JwtTokenRedisVo implements Serializable {
+ private static final long serialVersionUID = 5631646796482815114L;
+
+ /**
+ * 登录token
+ */
+ private String token;
+
+ /**
+ * 登录token md5
+ */
+ private String tokenMd5;
+
+ /**
+ * 创建时间
+ */
+ private Date createDate;
+
+ /**
+ * 过期时间
+ */
+ private Date expiredDate;
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/LoginSysUserRedisVo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/LoginSysUserRedisVo.java
new file mode 100644
index 0000000..b94dc2c
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/LoginSysUserRedisVo.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.security.vo;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 登录用户redis对象,后台使用
+ *
+ * @author geekidea
+ * @date 2019-05-15
+ **/
+@Data
+@ApiModel("系统用户登录值对象")
+public class LoginSysUserRedisVo implements Serializable {
+
+ private static final long serialVersionUID = -4497185071769175695L;
+
+ /**
+ * 登录对象vo
+ */
+ private LoginSysUserVo loginSysUserVo;
+
+ /**
+ * jwt token对象
+ */
+ private JwtTokenRedisVo jwtTokenRedisVo;
+
+ /**
+ * 唯一标识
+ */
+ private String uuid;
+
+ /**
+ * 登录ip
+ */
+ private ClientInfo clientInfo;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/LoginSysUserVo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/LoginSysUserVo.java
new file mode 100644
index 0000000..5a53e3a
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/security/vo/LoginSysUserVo.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.security.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 登录用户对象,响应给前端
+ *
+ * @author geekidea
+ * @date 2019-05-15
+ **/
+@Data
+public class LoginSysUserVo implements Serializable {
+
+ private static final long serialVersionUID = -1758338570596088158L;
+
+ private Long id;
+
+ private String userName;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/Ip.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/Ip.java
new file mode 100644
index 0000000..993ec5f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/Ip.java
@@ -0,0 +1,48 @@
+package com.ruoyi.plus.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.ruoyi.plus.common.entity.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ *
+ * IP地址
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value="Ip对象", description="IP地址")
+public class Ip extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "ip开始地址")
+ private String ipStart;
+
+ @ApiModelProperty(value = "ip结束地址")
+ private String ipEnd;
+
+ @ApiModelProperty(value = "区域")
+ private String area;
+
+ @ApiModelProperty(value = "运营商")
+ private String operator;
+
+ @ApiModelProperty(value = "主键")
+ @TableId(value = "id", type = IdType.ID_WORKER)
+ private Long id;
+
+ @ApiModelProperty(value = "ip开始地址数字")
+ private Long ipStartNum;
+
+ @ApiModelProperty(value = "ip结束地址数字")
+ private Long ipEndNum;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/SysLog.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/SysLog.java
new file mode 100644
index 0000000..a057a6b
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/SysLog.java
@@ -0,0 +1,44 @@
+package com.ruoyi.plus.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.ruoyi.plus.common.entity.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ *
+ * 系统日志
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value="SysLog对象", description="系统日志")
+public class SysLog extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "主键")
+ @TableId(value = "log_id", type = IdType.ID_WORKER)
+ private Long logId;
+
+ @ApiModelProperty(value = "类型")
+ private Boolean type;
+
+ @ApiModelProperty(value = "内容")
+ private String content;
+
+ @ApiModelProperty(value = "创建人ID")
+ private Long createId;
+
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/SysUser.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/SysUser.java
new file mode 100644
index 0000000..04c826d
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/entity/SysUser.java
@@ -0,0 +1,51 @@
+package com.ruoyi.plus.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.util.Date;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.ruoyi.plus.common.entity.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ *
+ * SystemUser
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value="SysUser对象", description="SystemUser")
+public class SysUser extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.ID_WORKER)
+ private Long id;
+
+ @ApiModelProperty(value = "name")
+ private String name;
+
+ @ApiModelProperty(value = "account")
+ private String account;
+
+ @ApiModelProperty(value = "password")
+ private String pwd;
+
+ @ApiModelProperty(value = "remark")
+ private String remark;
+
+ @ApiModelProperty(value = "create time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "update time")
+ private Date updateTime;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/IpMapper.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/IpMapper.java
new file mode 100644
index 0000000..0432691
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/IpMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.plus.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.plus.system.entity.Ip;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * IP地址 Mapper 接口
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+@Repository
+public interface IpMapper extends BaseMapper {
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/SysLogMapper.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/SysLogMapper.java
new file mode 100644
index 0000000..e7875eb
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/SysLogMapper.java
@@ -0,0 +1,40 @@
+package com.ruoyi.plus.system.mapper;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.plus.system.entity.SysLog;
+import com.ruoyi.plus.system.web.param.SysLogQueryParam;
+import com.ruoyi.plus.system.web.vo.SysLogQueryVo;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 系统日志 Mapper 接口
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+@Repository
+public interface SysLogMapper extends BaseMapper {
+
+ /**
+ * 根据ID获取查询对象
+ * @param id
+ * @return
+ */
+ SysLogQueryVo getSysLogById(Serializable id);
+
+ /**
+ * 获取分页对象
+ * @param page
+ * @param sysLogQueryParam
+ * @return
+ */
+ IPage getSysLogPageList(@Param("page") Page page, @Param("param") SysLogQueryParam sysLogQueryParam);
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/SysUserMapper.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/SysUserMapper.java
new file mode 100644
index 0000000..976d79f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/mapper/SysUserMapper.java
@@ -0,0 +1,40 @@
+package com.ruoyi.plus.system.mapper;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.plus.system.entity.SysUser;
+import com.ruoyi.plus.system.web.param.SysUserQueryParam;
+import com.ruoyi.plus.system.web.vo.SysUserQueryVo;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.io.Serializable;
+
+/**
+ *
+ * SystemUser Mapper 接口
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-26
+ */
+@Repository
+public interface SysUserMapper extends BaseMapper {
+
+ /**
+ * 根据ID获取查询对象
+ * @param id
+ * @return
+ */
+ SysUserQueryVo getSysUserById(Serializable id);
+
+ /**
+ * 获取分页对象
+ * @param page
+ * @param sysUserQueryParam
+ * @return
+ */
+ IPage getSysUserPageList(@Param("page") Page page, @Param("param") SysUserQueryParam sysUserQueryParam);
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/IpService.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/IpService.java
new file mode 100644
index 0000000..061f822
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/IpService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.plus.system.service;
+
+import com.ruoyi.plus.common.service.BaseService;
+import com.ruoyi.plus.system.entity.Ip;
+
+/**
+ *
+ * IP地址 服务类
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+public interface IpService extends BaseService {
+
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/SysLogService.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/SysLogService.java
new file mode 100644
index 0000000..b542521
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/SysLogService.java
@@ -0,0 +1,35 @@
+package com.ruoyi.plus.system.service;
+
+import com.ruoyi.plus.system.entity.SysLog;
+import com.ruoyi.plus.common.service.BaseService;
+import com.ruoyi.plus.system.web.param.SysLogQueryParam;
+import com.ruoyi.plus.system.web.vo.SysLogQueryVo;
+import com.ruoyi.plus.common.web.vo.Paging;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 系统日志 服务类
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+public interface SysLogService extends BaseService {
+
+ /**
+ * 根据ID获取查询对象
+ * @param id
+ * @return
+ */
+ SysLogQueryVo getSysLogById(Serializable id) throws Exception;
+
+ /**
+ * 获取分页对象
+ * @param sysLogQueryParam
+ * @return
+ */
+ Paging getSysLogPageList(SysLogQueryParam sysLogQueryParam) throws Exception;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/SysUserService.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/SysUserService.java
new file mode 100644
index 0000000..bef9d5e
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/SysUserService.java
@@ -0,0 +1,35 @@
+package com.ruoyi.plus.system.service;
+
+import com.ruoyi.plus.system.entity.SysUser;
+import com.ruoyi.plus.common.service.BaseService;
+import com.ruoyi.plus.system.web.param.SysUserQueryParam;
+import com.ruoyi.plus.system.web.vo.SysUserQueryVo;
+import com.ruoyi.plus.common.web.vo.Paging;
+
+import java.io.Serializable;
+
+/**
+ *
+ * SystemUser 服务类
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-26
+ */
+public interface SysUserService extends BaseService {
+
+ /**
+ * 根据ID获取查询对象
+ * @param id
+ * @return
+ */
+ SysUserQueryVo getSysUserById(Serializable id) throws Exception;
+
+ /**
+ * 获取分页对象
+ * @param sysUserQueryParam
+ * @return
+ */
+ Paging getSysUserPageList(SysUserQueryParam sysUserQueryParam) throws Exception;
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/IpServiceImpl.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/IpServiceImpl.java
new file mode 100644
index 0000000..ab9c143
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/IpServiceImpl.java
@@ -0,0 +1,30 @@
+package com.ruoyi.plus.system.service.impl;
+
+import com.ruoyi.plus.common.service.impl.BaseServiceImpl;
+import com.ruoyi.plus.system.entity.Ip;
+import com.ruoyi.plus.system.mapper.IpMapper;
+import com.ruoyi.plus.system.service.IpService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+
+/**
+ *
+ * IP地址 服务实现类
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+@Slf4j
+public class IpServiceImpl extends BaseServiceImpl implements IpService {
+
+ @Autowired
+ private IpMapper ipMapper;
+
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/SysLogServiceImpl.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/SysLogServiceImpl.java
new file mode 100644
index 0000000..4d8c438
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/SysLogServiceImpl.java
@@ -0,0 +1,49 @@
+package com.ruoyi.plus.system.service.impl;
+
+import com.ruoyi.plus.system.entity.SysLog;
+import com.ruoyi.plus.system.mapper.SysLogMapper;
+import com.ruoyi.plus.system.service.SysLogService;
+import com.ruoyi.plus.system.web.param.SysLogQueryParam;
+import com.ruoyi.plus.system.web.vo.SysLogQueryVo;
+import com.ruoyi.plus.common.service.impl.BaseServiceImpl;
+import com.ruoyi.plus.common.web.vo.Paging;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import java.io.Serializable;
+
+
+/**
+ *
+ * 系统日志 服务实现类
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+@Slf4j
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class SysLogServiceImpl extends BaseServiceImpl implements SysLogService {
+
+ @Autowired
+ private SysLogMapper sysLogMapper;
+
+ @Override
+ public SysLogQueryVo getSysLogById(Serializable id) throws Exception{
+ return sysLogMapper.getSysLogById(id);
+ }
+
+ @Override
+ public Paging getSysLogPageList(SysLogQueryParam sysLogQueryParam) throws Exception{
+ Page page = setPageParam(sysLogQueryParam,OrderItem.desc("create_time"));
+ IPage iPage = sysLogMapper.getSysLogPageList(page,sysLogQueryParam);
+ return new Paging(iPage);
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/SysUserServiceImpl.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/SysUserServiceImpl.java
new file mode 100644
index 0000000..63bd7e5
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/service/impl/SysUserServiceImpl.java
@@ -0,0 +1,49 @@
+package com.ruoyi.plus.system.service.impl;
+
+import com.ruoyi.plus.system.entity.SysUser;
+import com.ruoyi.plus.system.mapper.SysUserMapper;
+import com.ruoyi.plus.system.service.SysUserService;
+import com.ruoyi.plus.system.web.param.SysUserQueryParam;
+import com.ruoyi.plus.system.web.vo.SysUserQueryVo;
+import com.ruoyi.plus.common.service.impl.BaseServiceImpl;
+import com.ruoyi.plus.common.web.vo.Paging;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import java.io.Serializable;
+
+
+/**
+ *
+ * SystemUser 服务实现类
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-26
+ */
+@Slf4j
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class SysUserServiceImpl extends BaseServiceImpl implements SysUserService {
+
+ @Autowired
+ private SysUserMapper sysUserMapper;
+
+ @Override
+ public SysUserQueryVo getSysUserById(Serializable id) throws Exception{
+ return sysUserMapper.getSysUserById(id);
+ }
+
+ @Override
+ public Paging getSysUserPageList(SysUserQueryParam sysUserQueryParam) throws Exception{
+ Page page = setPageParam(sysUserQueryParam,OrderItem.desc("create_time"));
+ IPage iPage = sysUserMapper.getSysUserPageList(page,sysUserQueryParam);
+ return new Paging(iPage);
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/controller/SysLogController.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/controller/SysLogController.java
new file mode 100644
index 0000000..5cf0152
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/controller/SysLogController.java
@@ -0,0 +1,90 @@
+package com.ruoyi.plus.system.web.controller;
+
+import com.ruoyi.plus.common.api.ApiResult;
+import com.ruoyi.plus.common.web.controller.BaseController;
+import com.ruoyi.plus.common.web.param.IdParam;
+import com.ruoyi.plus.common.web.vo.Paging;
+import com.ruoyi.plus.system.entity.SysLog;
+import com.ruoyi.plus.system.service.SysLogService;
+import com.ruoyi.plus.system.web.param.SysLogQueryParam;
+import com.ruoyi.plus.system.web.vo.SysLogQueryVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+/**
+ *
+ * 系统日志 前端控制器
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-04
+ */
+@Slf4j
+@RestController
+@RequestMapping("/sysLog")
+@Api("系统日志 API")
+public class SysLogController extends BaseController {
+
+ @Autowired
+ private SysLogService sysLogService;
+
+ /**
+ * 添加系统日志
+ */
+ @PostMapping("/add")
+ @ApiOperation(value = "添加SysLog对象",notes = "添加系统日志",response = ApiResult.class)
+ public ApiResult addSysUser(@Valid @RequestBody SysLog sysLog) throws Exception{
+ boolean flag = sysLogService.save(sysLog);
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * 修改系统日志
+ */
+ @PostMapping("/update")
+ @ApiOperation(value = "修改SysLog对象",notes = "修改系统日志",response = ApiResult.class)
+ public ApiResult updateSysUser(@Valid @RequestBody SysLog sysLog) throws Exception{
+ boolean flag = sysLogService.updateById(sysLog);
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * 删除系统日志
+ */
+ @PostMapping("/delete")
+ @ApiOperation(value = "删除SysLog对象",notes = "删除系统日志",response = ApiResult.class)
+ public ApiResult deleteSysUser(@Valid @RequestBody IdParam idParam) throws Exception{
+ boolean flag = sysLogService.removeById(idParam.getId());
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * 获取系统日志
+ */
+ @PostMapping("/info")
+ @ApiOperation(value = "获取SysLog对象详情",notes = "查看系统日志",response = SysLogQueryVo.class)
+ public ApiResult getSysUser(@Valid @RequestBody IdParam idParam) throws Exception{
+ SysLogQueryVo sysLogQueryVo = sysLogService.getSysLogById(idParam.getId());
+ return ApiResult.ok(sysLogQueryVo);
+ }
+
+ /**
+ * 系统日志分页列表
+ */
+ @PostMapping("/getPageList")
+ @ApiOperation(value = "获取SysLog分页列表",notes = "系统日志分页列表",response = SysLogQueryVo.class)
+ public ApiResult> getSysLogPageList(@Valid @RequestBody(required = false) SysLogQueryParam sysLogQueryParam) throws Exception{
+ Paging paging = sysLogService.getSysLogPageList(sysLogQueryParam);
+ return ApiResult.ok(paging);
+ }
+
+}
+
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/controller/SysUserController.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/controller/SysUserController.java
new file mode 100644
index 0000000..280ec5d
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/controller/SysUserController.java
@@ -0,0 +1,91 @@
+package com.ruoyi.plus.system.web.controller;
+
+import com.ruoyi.plus.system.entity.SysUser;
+import com.ruoyi.plus.system.service.SysUserService;
+import com.ruoyi.plus.system.web.param.SysUserQueryParam;
+import com.ruoyi.plus.system.web.vo.SysUserQueryVo;
+import com.ruoyi.plus.common.web.controller.BaseController;
+import com.ruoyi.plus.common.api.ApiResult;
+ import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+import com.ruoyi.plus.common.web.vo.Paging;
+import com.ruoyi.plus.common.web.param.IdParam;
+
+/**
+ *
+ * SystemUser 前端控制器
+ *
+ *
+ * @author geekidea
+ * @since 2019-08-26
+ */
+@Slf4j
+@RestController
+@RequestMapping("/sysUser")
+@Api("SystemUser API")
+public class SysUserController extends BaseController {
+
+ @Autowired
+ private SysUserService sysUserService;
+
+ /**
+ * Save SystemUser
+ */
+ @PostMapping("/add")
+ @ApiOperation(value = "Save SysUser",notes = "Save SystemUser",response = ApiResult.class)
+ public ApiResult addSysUser(@Valid @RequestBody SysUser sysUser) throws Exception{
+ boolean flag = sysUserService.save(sysUser);
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * Update SystemUser
+ */
+ @PostMapping("/update")
+ @ApiOperation(value = "Update SysUser",notes = "Update SystemUser",response = ApiResult.class)
+ public ApiResult updateSysUser(@Valid @RequestBody SysUser sysUser) throws Exception{
+ boolean flag = sysUserService.updateById(sysUser);
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * Delete SystemUser
+ */
+ @PostMapping("/delete")
+ @ApiOperation(value = "Delete SysUser",notes = "Delete SystemUser",response = ApiResult.class)
+ public ApiResult deleteSysUser(@Valid @RequestBody IdParam idParam) throws Exception{
+ boolean flag = sysUserService.removeById(idParam.getId());
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * Get SystemUser
+ */
+ @PostMapping("/info")
+ @ApiOperation(value = "Get SysUser Detail",notes = "SystemUser Info",response = SysUserQueryVo.class)
+ public ApiResult getSysUser(@Valid @RequestBody IdParam idParam) throws Exception{
+ SysUserQueryVo sysUserQueryVo = sysUserService.getSysUserById(idParam.getId());
+ return ApiResult.ok(sysUserQueryVo);
+ }
+
+ /**
+ * SystemUser Pagination
+ */
+ @PostMapping("/getPageList")
+ @ApiOperation(value = "Get SysUserPagination",notes = "SystemUser Pagination",response = SysUserQueryVo.class)
+ public ApiResult> getSysUserPageList(@Valid @RequestBody(required = false) SysUserQueryParam sysUserQueryParam) throws Exception{
+ Paging paging = sysUserService.getSysUserPageList(sysUserQueryParam);
+ return ApiResult.ok(paging);
+ }
+
+}
+
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/param/SysLogQueryParam.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/param/SysLogQueryParam.java
new file mode 100644
index 0000000..acc10fa
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/param/SysLogQueryParam.java
@@ -0,0 +1,22 @@
+package com.ruoyi.plus.system.web.param;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import com.ruoyi.plus.common.web.param.QueryParam;
+
+/**
+ *
+ * 系统日志 查询参数对象
+ *
+ *
+ * @author geekidea
+ * @date 2019-08-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value="SysLogQueryParam对象", description="系统日志查询参数")
+public class SysLogQueryParam extends QueryParam {
+ private static final long serialVersionUID = 1L;
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/param/SysUserQueryParam.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/param/SysUserQueryParam.java
new file mode 100644
index 0000000..05db1c0
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/param/SysUserQueryParam.java
@@ -0,0 +1,22 @@
+package com.ruoyi.plus.system.web.param;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import com.ruoyi.plus.common.web.param.QueryParam;
+
+/**
+ *
+ * SystemUser 查询参数对象
+ *
+ *
+ * @author geekidea
+ * @date 2019-08-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value="SysUserQueryParam对象", description="SystemUser查询参数")
+public class SysUserQueryParam extends QueryParam {
+ private static final long serialVersionUID = 1L;
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/IpQueryVo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/IpQueryVo.java
new file mode 100644
index 0000000..cf6c805
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/IpQueryVo.java
@@ -0,0 +1,44 @@
+package com.ruoyi.plus.system.web.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *
+ * IP地址 查询结果对象
+ *
+ *
+ * @author geekidea
+ * @date 2019-08-04
+ */
+@Data
+@ApiModel(value="IpQueryVo对象", description="IP地址查询参数")
+public class IpQueryVo implements Serializable{
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "ip开始地址")
+ private String ipStart;
+
+ @ApiModelProperty(value = "ip结束地址")
+ private String ipEnd;
+
+ @ApiModelProperty(value = "区域")
+ private String area;
+
+ @ApiModelProperty(value = "运营商")
+ private String operator;
+
+ @ApiModelProperty(value = "主键")
+ private Long id;
+
+ @ApiModelProperty(value = "ip开始地址数字")
+ private Long ipStartNum;
+
+ @ApiModelProperty(value = "ip结束地址数字")
+ private Long ipEndNum;
+
+}
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/SysLogQueryVo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/SysLogQueryVo.java
new file mode 100644
index 0000000..16126ac
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/SysLogQueryVo.java
@@ -0,0 +1,38 @@
+package com.ruoyi.plus.system.web.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+
+import java.util.Date;
+
+/**
+ *
+ * 系统日志 查询结果对象
+ *
+ *
+ * @author geekidea
+ * @date 2019-08-04
+ */
+@Data
+@ApiModel(value="SysLogQueryVo对象", description="系统日志查询参数")
+public class SysLogQueryVo implements Serializable{
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "主键")
+ private Long logId;
+
+ @ApiModelProperty(value = "类型")
+ private Boolean type;
+
+ @ApiModelProperty(value = "内容")
+ private String content;
+
+ @ApiModelProperty(value = "创建人ID")
+ private Long createId;
+
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+}
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/SysUserQueryVo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/SysUserQueryVo.java
new file mode 100644
index 0000000..fb0041f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/system/web/vo/SysUserQueryVo.java
@@ -0,0 +1,44 @@
+package com.ruoyi.plus.system.web.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+
+import java.util.Date;
+
+/**
+ *
+ * SystemUser 查询结果对象
+ *
+ *
+ * @author geekidea
+ * @date 2019-08-26
+ */
+@Data
+@ApiModel(value="SysUserQueryVo对象", description="SystemUser查询参数")
+public class SysUserQueryVo implements Serializable{
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ @ApiModelProperty(value = "name")
+ private String name;
+
+ @ApiModelProperty(value = "account")
+ private String account;
+
+ @ApiModelProperty(value = "password")
+ private String pwd;
+
+ @ApiModelProperty(value = "remark")
+ private String remark;
+
+ @ApiModelProperty(value = "create time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "update time")
+ private Date updateTime;
+
+}
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/AnsiUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/AnsiUtil.java
new file mode 100644
index 0000000..217041b
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/AnsiUtil.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.fusesource.jansi.Ansi;
+import org.springframework.core.env.Environment;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+@Slf4j
+public class AnsiUtil {
+
+ private static boolean enableAnsi;
+
+ static {
+ Boolean value = false;
+ try {
+ Environment environment = SpringContextUtil.getBean(Environment.class);
+ value = environment.getProperty("spring-boot-plus.enable-ansi",boolean.class);
+ value = value == null ? false : value;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ enableAnsi = value;
+ }
+
+ public static String getAnsi(Ansi.Color color,String text){
+
+ if (enableAnsi){
+ return Ansi.ansi().eraseScreen().fg(color).a(text).reset().toString();
+ }
+ return text;
+ }
+
+ public static String getAnsi(Ansi.Color color,String text,boolean flag){
+ if (flag){
+ return Ansi.ansi().eraseScreen().fg(color).a(text).reset().toString();
+ }
+ return text;
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/BrowserUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/BrowserUtil.java
new file mode 100644
index 0000000..c3ae182
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/BrowserUtil.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * 浏览器工具类
+ * 1.获取当前浏览器名称
+ * 2.判断当前用户的浏览器
+ *
+ *
+ * @author geekidea
+ * @since 2018-11-08
+ */
+public final class BrowserUtil {
+ public static final String IE = "msie";
+ public static final String FIREFOX = "firefox";
+ public static final String CHROME = "chrome";
+ private BrowserUtil(){
+ throw new AssertionError();
+ }
+
+ /**
+ * 获取当前浏览器名称
+ *
+ * @param request
+ * @return 返回浏览器名称
+ */
+ public static String getCurrent(HttpServletRequest request) {
+ String userAgent = request.getHeader("USER-AGENT").toLowerCase();
+ if (userAgent != null && !userAgent.trim().equals("")) {
+ if (userAgent.indexOf(CHROME) >= 0) {
+ return CHROME;
+ } else if (userAgent.indexOf(FIREFOX) >= 0) {
+ return FIREFOX;
+ } else if (userAgent.indexOf(IE) >= 0) {
+ return IE;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 是否是IE浏览器
+ *
+ * @param request
+ * @return
+ */
+ public static boolean isIE(HttpServletRequest request) {
+ return IE.equals(getCurrent(request));
+ }
+
+ /**
+ * 是否是Firefox浏览器
+ *
+ * @param request
+ * @return
+ */
+ public static boolean isFirefox(HttpServletRequest request) {
+ return FIREFOX.equals(getCurrent(request));
+ }
+
+ /**
+ * 是否是Chrome浏览器
+ *
+ * @param request
+ * @return
+ */
+ public static boolean isChrome(HttpServletRequest request) {
+ return CHROME.equals(getCurrent(request));
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/ClientInfoUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/ClientInfoUtil.java
new file mode 100644
index 0000000..f56d673
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/ClientInfoUtil.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import com.ruoyi.plus.security.vo.ClientInfo;
+import com.ruoyi.plus.security.vo.DeviceInfo;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * 用户客户端信息工具类
+ *
+ * @author geekidea
+ * @date 2019-05-24
+ **/
+public class ClientInfoUtil {
+
+ /**
+ * 获取用户客户端信息
+ * @param userAgentString
+ * @return
+ */
+ public static ClientInfo get(String userAgentString){
+ ClientInfo clientInfo = new ClientInfo();
+
+ UserAgent userAgent = UserAgentUtil.parse(userAgentString);
+
+ // 浏览器名称
+ clientInfo.setBrowserName(userAgent.getBrowser().getName());
+ // 浏览器版本
+ clientInfo.setBrowserversion(userAgent.getVersion());
+ // 浏览器引擎名称
+ clientInfo.setEngineName(userAgent.getEngine().getName());
+ // 浏览器引擎版本
+ clientInfo.setEngineVersion(userAgent.getEngineVersion());
+ // 用户操作系统名称
+ clientInfo.setOsName(userAgent.getOs().getName());
+ // 用户操作平台名称
+ clientInfo.setPlatformName(userAgent.getPlatform().getName());
+ // 是否是手机
+ clientInfo.setMobile(userAgent.isMobile());
+
+ // 获取移动设备名称和机型
+ DeviceInfo deviceInfo = getDeviceInfo(userAgentString);
+ // 设置移动设备名称和机型
+ clientInfo.setDeviceName(deviceInfo.getName());
+ clientInfo.setDeviceModel(deviceInfo.getModel());
+
+ // ip
+ clientInfo.setIp(IpUtil.getRequestIp());
+
+ return clientInfo;
+ }
+
+ /**
+ * 获取移动端用户设备的名称和机型
+ * @param userAgentString
+ * @return
+ */
+ public static DeviceInfo getDeviceInfo(String userAgentString){
+ DeviceInfo deviceInfo = new DeviceInfo();
+ try {
+ Pattern pattern = Pattern.compile(";\\s?(\\S*?\\s?\\S*?)\\s?Build/(\\S*?)[;)]");
+ Matcher matcher = pattern.matcher(userAgentString);
+ String model = null;
+ String name = null;
+
+ if (matcher.find()) {
+ model = matcher.group(1);
+ name = matcher.group(2);
+ }
+
+ if (model == null && name == null){
+ pattern = Pattern.compile(";\\s?(\\S*?\\s?\\S*?)\\s?\\)");
+ matcher = pattern.matcher(userAgentString);
+ if (matcher.find()) {
+ model = matcher.group(1);
+ }
+ }
+
+ deviceInfo.setName(name);
+ deviceInfo.setModel(model);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return deviceInfo;
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/ContentTypeUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/ContentTypeUtil.java
new file mode 100644
index 0000000..5b8de2f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/ContentTypeUtil.java
@@ -0,0 +1,88 @@
+package com.ruoyi.plus.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+/**
+ * 获取文件的内容类型
+ * mime-type参考:https://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?revision=1752884&view=co
+ * @author geekidea
+ * @date 2019/08/20
+ * @since
+ */
+@Slf4j
+public final class ContentTypeUtil {
+
+ private static String MIME_TYPE_CONFIG_FILE = "config/mime-type.properties";
+
+ private static String DEFAULT_MIME_TYPE = "application/octet-stream";
+
+ private static Properties properties;
+
+ static {
+ try {
+ properties = PropertiesLoaderUtils.loadProperties(new ClassPathResource(MIME_TYPE_CONFIG_FILE));
+ } catch (IOException e) {
+ log.error("读取配置文件" + MIME_TYPE_CONFIG_FILE + "异常",e);
+ }
+ log.info(MIME_TYPE_CONFIG_FILE + " = " + properties);
+ }
+
+ /**
+ * 获取文件内容类型
+ * @param file
+ * @return
+ */
+ public static String getContentType(File file){
+ if (file == null){
+ return null;
+ }
+ Path path = Paths.get(file.toURI());
+ if (path == null){
+ return null;
+ }
+ String contentType = null;
+ try {
+ contentType = Files.probeContentType(path);
+ } catch (IOException e) {
+ log.error("获取文件ContentType异常",e);
+ }
+ if (contentType == null){
+ // 读取拓展的自定义配置
+ contentType = getContentTypeByExtension(file);
+ }
+ // 设置默认的内容类型
+ if (contentType == null){
+ contentType = DEFAULT_MIME_TYPE;
+ }
+ return contentType;
+ }
+
+ /**
+ * 根据文件后缀获取自定义配置的文件mime-type
+ * @param file
+ * @return
+ */
+ private static String getContentTypeByExtension(File file){
+ if (properties == null){
+ return null;
+ }
+ String extension = FilenameUtils.getExtension(file.getName());
+ if (StringUtils.isBlank(extension)){
+ return null;
+ }
+ String contentType = properties.getProperty(extension);
+ return contentType;
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/DateUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/DateUtil.java
new file mode 100644
index 0000000..8c57805
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/DateUtil.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class DateUtil {
+
+ public static final String formatStr_yyyyMMddHHmmssS_ = "yyyyMMddHHmmss";
+ public static final String formatStr_yyyyMMddHHmmssS = "yyyy-MM-dd HH:mm:ss.S";
+ public static final String formatStr_yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss";
+ public static final String formatStr_yyyyMMddHHmm = "yyyy-MM-dd HH:mm";
+ public static final String formatStr_yyyyMMddHH = "yyyy-MM-dd HH";
+ public static final String formatStr_yyyyMMdd = "yyyy-MM-dd";
+ public static final String formatStr_yyyy = "yyyy";
+ public static final String formatStr_yyyy_MM_dd = "yyyyMMdd";
+ public static final String formatStr_yyyyMMddDelimiter = "-";
+
+ public static String getYYYYMMDDHHMMSS(Date date){
+ if (date == null){
+ return null;
+ }
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String dateString = simpleDateFormat.format(date);
+ return dateString;
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/DownloadUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/DownloadUtil.java
new file mode 100644
index 0000000..2f395ec
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/DownloadUtil.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.util.Base64Utils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.FileCopyUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.util.List;
+
+/**
+ * 文件下载工具类
+ * @author geekidea
+ * @date 2019/8/21
+ * @since 1.2.1-RELEASE
+ */
+@Slf4j
+public final class DownloadUtil {
+
+ /**
+ * 下载文件,使用默认下载处理器
+ * @param downloadDir
+ * @param downloadFileName
+ * @param allowFileExtensions
+ * @param response
+ * @throws Exception
+ */
+ public static void download( String downloadDir, String downloadFileName, List allowFileExtensions, HttpServletResponse response) throws Exception{
+ download(downloadDir,downloadFileName,allowFileExtensions,response,new DefaultDownloadHandler());
+ }
+
+ /**
+ * 下载文件,使用自定义下载处理器
+ * @param downloadDir 文件目录
+ * @param downloadFileName 文件名称
+ * @throws Exception
+ */
+ public static void download( String downloadDir, String downloadFileName, List allowFileExtensions, HttpServletResponse response,DownloadHandler downloadHandler) throws Exception {
+ log.info("downloadDir:{}",downloadDir);
+ log.info("downloadFileName:{}",downloadFileName);
+
+ if (StringUtils.isBlank(downloadDir)){
+ throw new IOException("文件目录不能为空");
+ }
+ if (StringUtils.isBlank(downloadFileName)){
+ throw new IOException("文件名称不能为空");
+ }
+ // 安全判断,防止../情况,防止出现类似非法文件名称:../../hello/123.txt
+ if (downloadFileName.contains("..")||downloadFileName.contains("../")){
+ throw new IOException("非法的文件名称");
+ }
+ // 允许下载的文件后缀判断
+ if (CollectionUtils.isEmpty(allowFileExtensions)){
+ throw new IllegalArgumentException("请设置允许下载的文件后缀");
+ }
+ // 获取文件名称
+ String fileExtension = FilenameUtils.getExtension(downloadFileName);
+
+ // 从服务器读取文件,然后输出
+ File downloadFile = new File(downloadDir,downloadFileName);
+ if (!downloadFile.exists()){
+ throw new IOException("文件不存在");
+ }
+
+ // 判断文件类型,输出对应ContentType,如果没有对应的内容类型,可在config/mime-type.properties配置
+ String contentType = ContentTypeUtil.getContentType(downloadFile);
+ log.info("contentType:{}",contentType);
+ // 文件大小
+ long length = downloadFile.length();
+ log.info("length:{}",length);
+
+ // 下载回调处理
+ if (downloadHandler == null){
+ // 使用默认下载处理器
+ downloadHandler = new DefaultDownloadHandler();
+ }
+ boolean flag = downloadHandler.handle(downloadDir,downloadFileName,downloadFile,fileExtension,contentType,length);
+ if (!flag){
+ log.info("下载自定义校验失败,取消下载");
+ return;
+ }
+
+ // 下载文件名称编码,Firefox中文乱码处理
+ String encodeDownFileName;
+
+ HttpServletRequest request = HttpServletRequestUtil.getRequest();
+
+ String browser = BrowserUtil.getCurrent(request);
+ if(BrowserUtil.FIREFOX.equals(browser)) {
+ encodeDownFileName = "=?UTF-8?B?" + (new String(Base64Utils.encodeToString(downloadFileName.getBytes("UTF-8")))) + "?=";
+ } else {
+ encodeDownFileName = URLEncoder.encode(downloadFileName,"utf-8").replaceAll("\\+", "%20");
+ }
+ log.info("encodeDownFileName:{}",encodeDownFileName);
+
+ log.info("下载文件:" + downloadFile.getAbsolutePath());
+
+ response.reset();
+ // 设置Content-Disposition响应头
+ response.setHeader("Content-Disposition", "attachment;fileName=\"" + encodeDownFileName + "\"");
+ // 设置响应Content-Type
+ response.setContentType(contentType);
+ // 设置响应文件大小
+ response.setContentLengthLong(length);
+
+ // 文件下载
+ InputStream in = new BufferedInputStream(new FileInputStream(downloadFile));
+ FileCopyUtils.copy(in, response.getOutputStream());
+ }
+
+ public static interface DownloadHandler{
+ boolean handle(String dir, String fileName, File file, String fileExtension, String contentType, long length) throws Exception;
+ }
+ public static class DefaultDownloadHandler implements DownloadHandler{
+ @Override
+ public boolean handle(String dir, String fileName, File file, String fileExtension, String contentType, long length) throws Exception {
+ return false;
+ }
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/EnumUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/EnumUtil.java
new file mode 100644
index 0000000..f625f7e
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/EnumUtil.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Method;
+
+/**
+ * 枚举工具类
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class EnumUtil {
+
+ /**
+ * 通过key获取name
+ * @param clazz
+ * @param key
+ * @return
+ */
+ public static String getEnum(Class> clazz,Integer key){
+ try{
+ Object[] objects = clazz.getEnumConstants();
+ Method keyMethod = clazz.getDeclaredMethod("getKey");
+ Method valueMethod = clazz.getDeclaredMethod("getValue");
+ for (Object object : objects) {
+ Integer k = (Integer) keyMethod.invoke(object);
+ if (k.equals(key)){
+ String value = (String) valueMethod.invoke(object);
+ return value;
+ }
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 判断key在枚举中是否存在
+ * @param clazz
+ * @param key
+ * @return
+ */
+ public static boolean exists(Class> clazz,Integer key){
+ String name = getEnum(clazz,key);
+ if (StringUtils.isBlank(name)){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 判断key在枚举中是否不存在
+ * @param clazz
+ * @param key
+ * @return
+ */
+ public static boolean notExists(Class> clazz,Integer key){
+ return !exists(clazz,key);
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/HttpServletRequestUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/HttpServletRequestUtil.java
new file mode 100644
index 0000000..c7659ef
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/HttpServletRequestUtil.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 获取当前请求的HttpServletRequest对象
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class HttpServletRequestUtil {
+
+ public static HttpServletRequest getRequest() {
+ return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/HttpServletResponseUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/HttpServletResponseUtil.java
new file mode 100644
index 0000000..2b5bf50
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/HttpServletResponseUtil.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import com.alibaba.fastjson.JSON;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.PrintWriter;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public final class HttpServletResponseUtil {
+
+ private static String UTF8 = "UTF-8";
+ private static String CONTENT_TYPE = "application/json";
+
+ private HttpServletResponseUtil(){
+ throw new AssertionError();
+ }
+
+ public static void printJSON(HttpServletResponse response, Object object) throws Exception{
+ response.setCharacterEncoding(UTF8);
+ response.setContentType(CONTENT_TYPE);
+ PrintWriter printWriter = response.getWriter();
+ printWriter.write(JSON.toJSONString(object));
+ printWriter.flush();
+ printWriter.close();
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/IpUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/IpUtil.java
new file mode 100644
index 0000000..6787426
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/IpUtil.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 获取IP地址工具类
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public final class IpUtil {
+ private IpUtil(){
+ throw new AssertionError();
+ }
+
+ /**
+ * 获取请求用户的IP地址
+ * @return
+ */
+ public static String getRequestIp() {
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ HttpServletRequest request = attributes.getRequest();
+ return getRequestIp(request);
+ }
+
+ /**
+ * 获取请求用户的IP地址
+ * @param request
+ * @return
+ */
+ public static String getRequestIp(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+
+ if ("0:0:0:0:0:0:0:1".equals(ip)){
+ ip = getLocalhostIp();
+ }
+ return ip;
+ }
+
+ public static String getLocalhostIp(){
+ try {
+ return InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ }
+ return null;
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/LoginUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/LoginUtil.java
new file mode 100644
index 0000000..6d03d01
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/LoginUtil.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import com.ruoyi.plus.common.constant.CommonConstant;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.env.Environment;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+@Slf4j
+public class LoginUtil {
+
+ /**
+ * TOKEN有效时间,单位分钟
+ */
+ public static Integer TOKEN_VALID_TIME_MINUTE;
+
+ static {
+ Environment environment = SpringContextUtil.getBean(Environment.class);
+ String time = environment.getProperty("spring-boot-plus.login.token-valid-time");
+ TOKEN_VALID_TIME_MINUTE = Integer.valueOf(time);
+ log.info("TOKEN_VALID_TIME_MINUTE:{}",TOKEN_VALID_TIME_MINUTE);
+ }
+
+ /**
+ * 从请求头或者请求参数中
+ * @param request
+ * @return
+ */
+ public static String getToken(HttpServletRequest request){
+ // 从请求头中获取token
+ String token = request.getHeader(CommonConstant.TOKEN);
+ if (StringUtils.isBlank(token)){
+ // 从请求参数中获取token
+ token = request.getParameter(CommonConstant.TOKEN);
+ }
+ return token;
+ }
+
+// /**
+// * 获取当前登陆用户对象
+// * @return
+// */
+// public static LoginSysUserVo getLoginSysUser(){
+// LoginSysUserVo loginSysUserVo = (LoginSysUserVo) HttpServletRequestUtil.getRequest().getAttribute(CommonConstant.LOGIN_SYS_USER);
+// return loginSysUserVo;
+// }
+//
+// /**
+// * 获取当前登陆用户的ID
+// * @return
+// */
+// public static String getUserId(){
+// LoginSysUserVo loginSysUserVo = getLoginSysUser();
+// if (loginSysUserVo !=null){
+// return loginSysUserVo.getUserId();
+// }
+// return null;
+// }
+//
+// /**
+// * 获取当前登陆用户的账号
+// * @return
+// */
+// public static String getAccount(){
+// LoginSysUserVo loginSysUserVo = getLoginSysUser();
+// if (loginSysUserVo !=null){
+// return loginSysUserVo.getAccount();
+// }
+// return null;
+// }
+//
+// /**
+// * 获取当前登陆用户的名称
+// * @return
+// */
+// public static String getUserName(){
+// LoginSysUserVo loginSysUserVo = getLoginSysUser();
+// if (loginSysUserVo !=null){
+// return loginSysUserVo.getUserName();
+// }
+// return null;
+// }
+//
+// /**
+// * 判断是否是管理员,true:是,false:否
+// * @return
+// */
+// public static Boolean isAdmin() {
+// LoginSysUserVo loginSysUserVo = getLoginSysUser();
+// if (loginSysUserVo !=null){
+// return loginSysUserVo.getAdmin();
+// }
+// return null;
+// }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/MapUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/MapUtil.java
new file mode 100644
index 0000000..db0f841
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/MapUtil.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * Map构建工具类
+ *
+ * @author geekidea
+ * @date 2019-05-23
+ **/
+public class MapUtil {
+
+ private Map map;
+
+ private MapUtil(){
+ map = new HashMap<>();
+ }
+
+ public static MapUtil builder(){
+ return new MapUtil();
+ }
+
+ public MapUtil put(String key,Object value){
+ this.map.put(key,value);
+ return this;
+ }
+
+ public Map build(){
+ return this.map;
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/PasswordUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/PasswordUtil.java
new file mode 100644
index 0000000..9f9173a
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/PasswordUtil.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 密码加密工具类
+ * @author geekidea
+ * @date 2018-11-08
+ */
+@Slf4j
+public class PasswordUtil {
+ private static final String KEY = "com.ruoyi.plus.springbootplus.pwd.key";
+ public static String encrypt(String pwd){
+ if (StringUtils.isBlank(pwd)){
+ return null;
+ }
+ pwd = pwd + KEY;
+ String newPwd = DigestUtils.sha256Hex(pwd) + DigestUtils.md5Hex(pwd);
+ return newPwd;
+ }
+
+ public static void main(String[] args) {
+ log.debug(encrypt("7c4a8d09ca3762af61e59520943dc26494f8941b"));
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/PrintApplicationInfo.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/PrintApplicationInfo.java
new file mode 100644
index 0000000..83e5619
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/PrintApplicationInfo.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.fusesource.jansi.Ansi;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.env.ConfigurableEnvironment;
+
+/**
+ *
+ * 打印项目信息
+ *
+ * @author geekidea
+ * @date 2019-05-08
+ **/
+@Slf4j
+public class PrintApplicationInfo {
+
+
+ /**
+ * 执行之前,打印前置条件提示
+ */
+ public static void printTip(){
+ StringBuffer tip = new StringBuffer();
+ tip.append("======================================================================================\n");
+ tip.append(" \n");
+ tip.append(" !!!准备工作!!! \n");
+ tip.append(" 1.请先在MySQL中创建数据库,默认数据库名称为:spring_boot_plus \n");
+ tip.append(" 2.数据库脚本在项目docs/mysql_spring_boot_plus.sql \n");
+ tip.append(" 3.请先启动redis服务 \n");
+ tip.append(" 4.更多注意事项:请查看: https://springboot.plus \n");
+ tip.append(" \n");
+ tip.append("======================================================================================\n");
+ log.info("\n{}",Ansi.ansi().eraseScreen().fg(Ansi.Color.YELLOW).a(tip.toString()).reset().toString());
+ }
+
+ /**
+ * 启动成功之后,打印项目信息
+ */
+ public static void print(ConfigurableApplicationContext context){
+ ConfigurableEnvironment environment = context.getEnvironment();
+
+ // 项目名称
+ String projectFinalName = environment.getProperty("info.project-finalName");
+ // 项目版本
+ String projectVersion = environment.getProperty("info.project-version");
+ // 项目profile
+ String profileActive = environment.getProperty("spring.profiles.active");
+ // 项目路径
+ String contextPath = environment.getProperty("server.servlet.context-path");
+ // 项目端口
+ String port = environment.getProperty("server.port");
+
+ log.info("projectFinalName : {}",projectFinalName);
+ log.info("projectVersion : {}",projectVersion);
+ log.info("profileActive : {}",profileActive);
+ log.info("contextPath : {}",contextPath);
+ log.info("port : {}",port);
+
+ String startSuccess = " ____ __ __ ____ \n" +
+ "/\\ _`\\ /\\ \\__ /\\ \\__ /\\ _`\\ \n" +
+ "\\ \\,\\L\\_\\ \\ ,_\\ __ _ __\\ \\ ,_\\ \\ \\,\\L\\_\\ __ __ ___ ___ __ ____ ____ \n" +
+ " \\/_\\__ \\\\ \\ \\/ /'__`\\ /\\`'__\\ \\ \\/ \\/_\\__ \\ /\\ \\/\\ \\ /'___\\ /'___\\ /'__`\\ /',__\\ /',__\\ \n" +
+ " /\\ \\L\\ \\ \\ \\_/\\ \\L\\.\\_\\ \\ \\/ \\ \\ \\_ /\\ \\L\\ \\ \\ \\_\\ \\/\\ \\__//\\ \\__//\\ __//\\__, `\\/\\__, `\\\n" +
+ " \\ `\\____\\ \\__\\ \\__/.\\_\\\\ \\_\\ \\ \\__\\ \\ `\\____\\ \\____/\\ \\____\\ \\____\\ \\____\\/\\____/\\/\\____/\n" +
+ " \\/_____/\\/__/\\/__/\\/_/ \\/_/ \\/__/ \\/_____/\\/___/ \\/____/\\/____/\\/____/\\/___/ \\/___/ \n" +
+ " \n" +
+ " ";
+
+ String homeUrl = "http://" + IpUtil.getLocalhostIp() + ":" + port + contextPath;
+ String swaggerUrl = "http://" + IpUtil.getLocalhostIp() + ":" + port + contextPath + "docs";
+ log.info("home:{}",homeUrl);
+ log.info("docs:{}",swaggerUrl);
+ log.info("spring-boot-plus project start success...........");
+ log.info("\n{}",AnsiUtil.getAnsi(Ansi.Color.BLUE,startSuccess));
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/RedisCacheUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/RedisCacheUtil.java
new file mode 100644
index 0000000..04ae942
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/RedisCacheUtil.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+@Component
+@Slf4j
+public class RedisCacheUtil {
+
+ private static RedisCacheUtil redisCacheUtil;
+
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ /**
+ * 将当前对象赋值给静态对象,调用spring组件: redisCacheUtil.redisTemplate.xxx()
+ */
+ @PostConstruct
+ public void init(){
+ redisCacheUtil = this;
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/RedisKey.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/RedisKey.java
new file mode 100644
index 0000000..37a8930
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/RedisKey.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public interface RedisKey {
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/SpringContextUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/SpringContextUtil.java
new file mode 100644
index 0000000..b0b1805
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/SpringContextUtil.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * Spring工具类,获取Spring上下文对象等
+ * @author geekidea
+ * @date 2018-11-08
+ */
+@Component
+public class SpringContextUtil implements ApplicationContextAware {
+
+ private static ApplicationContext applicationContext = null;
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if(SpringContextUtil.applicationContext == null){
+ SpringContextUtil.applicationContext = applicationContext;
+ }
+ }
+
+ public static ApplicationContext getApplicationContext() {
+ return applicationContext;
+ }
+
+ public static Object getBean(String name){
+ return getApplicationContext().getBean(name);
+ }
+
+ public static T getBean(Class clazz){
+ return getApplicationContext().getBean(clazz);
+ }
+
+ public static T getBean(String name,Class clazz){
+ return getApplicationContext().getBean(name, clazz);
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/StorageDB.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/StorageDB.java
new file mode 100644
index 0000000..3f075cc
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/StorageDB.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class StorageDB {
+
+ }
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/TokenUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/TokenUtil.java
new file mode 100644
index 0000000..95f0201
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/TokenUtil.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class TokenUtil {
+
+ /**
+ * 生成token
+ * @return
+ */
+ public static String generatetoken(){
+ String token = "x-auth-token:" + UUIDUtil.getUUID();
+ return token;
+ }
+
+ /**
+ * 生成token
+ * @return
+ */
+ public static String generateFirstLoginRestPwdToken(){
+ String token = "first-login-rest-pwd-token:" + UUIDUtil.getUUID();
+ return token;
+ }
+
+ /**
+ * 生成验证码token
+ * @return
+ */
+ public static String generateVerificationCodeToken(){
+ String token = "verification-code-token:" + UUIDUtil.getUUID();
+ return token;
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/UUIDUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/UUIDUtil.java
new file mode 100644
index 0000000..558b0ae
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/UUIDUtil.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import java.util.UUID;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class UUIDUtil {
+
+ public static String getUUID(){
+ String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+ return uuid;
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/UploadUtil.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/UploadUtil.java
new file mode 100644
index 0000000..ba6d48d
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/UploadUtil.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.InputStream;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 文件上传工具类
+ * @author geekidea
+ * @date 2019/8/21
+ * @since 1.2.1-RELEASE
+ */
+@Slf4j
+public final class UploadUtil {
+
+ /**
+ * 上传文件,默认文件名格式,yyyyMMddHHmmssS
+ * @param uploadPath
+ * @param multipartFile
+ * @return
+ * @throws Exception
+ */
+ public static String upload(String uploadPath, MultipartFile multipartFile) throws Exception {
+ return upload(uploadPath,multipartFile,new DefaultUploadFileNameHandleImpl());
+ }
+
+ /**
+ * 上传文件
+ * @param uploadPath 上传目录
+ * @param multipartFile 上传文件
+ * @param uploadFileNameHandle 回调
+ * @return
+ * @throws Exception
+ */
+ public static String upload(String uploadPath, MultipartFile multipartFile,UploadFileNameHandle uploadFileNameHandle) throws Exception {
+ // 获取输入流
+ InputStream inputStream = multipartFile.getInputStream();
+ // 文件保存目录
+ File saveDir = new File(uploadPath);
+ // 判断目录是否存在,不存在,则创建,如创建失败,则抛出异常
+ if (!saveDir.exists()){
+ boolean flag = saveDir.mkdirs();
+ if (!flag){
+ throw new RuntimeException("创建" +saveDir + "目录失败!");
+ }
+ }
+
+ String originalFilename = multipartFile.getOriginalFilename();
+ String saveFileName;
+ if (uploadFileNameHandle == null){
+ saveFileName = new DefaultUploadFileNameHandleImpl().handle(originalFilename);
+ }else{
+ saveFileName = uploadFileNameHandle.handle(originalFilename);
+ }
+ log.info("saveFileName = " + saveFileName);
+
+ File saveFile = new File(saveDir,saveFileName);
+ // 保存文件到服务器指定路径
+ FileUtils.copyToFile(inputStream,saveFile);
+ return saveFileName;
+ }
+
+
+ public static interface UploadFileNameHandle{
+ String handle(String originalFilename);
+ }
+
+ public static class DefaultUploadFileNameHandleImpl implements UploadFileNameHandle{
+
+ @Override
+ public String handle(String originalFilename) {
+ // 文件后缀
+ String fileExtension= FilenameUtils.getExtension(originalFilename);
+ // 这里可自定义文件名称,比如按照业务类型/文件格式/日期
+ // 此处按照文件日期存储
+ String dateString = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssS"));
+ String fileName = dateString + "." +fileExtension;
+ return fileName;
+ }
+ }
+
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/VerificationCode.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/VerificationCode.java
new file mode 100644
index 0000000..cff9e1d
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/VerificationCode.java
@@ -0,0 +1,154 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.util.Random;
+
+/**
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class VerificationCode {
+ private int weight = 110; //验证码图片的长和宽
+ private int height = 38;
+ private String text; //用来保存验证码的文本内容
+ private Random r = new Random(); //获取随机数对象
+ private String[] fontNames = {"宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312"}; //字体数组
+ private String codes = "23456789acdefghjkmnopqrstuvwxyzACDEFGHJKMNPQRSTUVWXYZ"; //验证码数组
+
+ /**
+ * 获取随机的颜色
+ */
+ private Color randomColor() {
+ //这里为什么是150,因为当r,g,b都为255时,即为白色,为了好辨认,需要颜色深一点。
+ int r = this.r.nextInt(150);
+ int g = this.r.nextInt(150);
+ int b = this.r.nextInt(150);
+ //返回一个随机颜色
+ return new Color(r, g, b);
+ }
+
+ /**
+ * 获取随机字体
+ */
+ private Font randomFont() {
+ //获取随机的字体
+ int index = r.nextInt(fontNames.length);
+ String fontName = fontNames[index];
+ //随机获取字体的样式,0是无样式,1是加粗,2是斜体,3是加粗加斜体
+ int style = r.nextInt(4);
+ //随机获取字体的大小
+ int size = r.nextInt(5) + 24;
+ //返回一个随机的字体
+ return new Font(fontName, style, size);
+ }
+
+ /**
+ * 获取随机字符
+ */
+ private char randomChar() {
+ int index = r.nextInt(codes.length());
+ return codes.charAt(index);
+ }
+
+ /**
+ * 画干扰线,验证码干扰线用来防止计算机解析图片
+ */
+ private void drawLine(BufferedImage image) {
+ int num = 155;
+ //定义干扰线的数量
+ Graphics2D g = (Graphics2D) image.getGraphics();
+ for (int i = 0; i < num; i++) {
+ int x = r.nextInt(weight);
+ int y = r.nextInt(height);
+ int xl = r.nextInt(weight);
+ int yl = r.nextInt(height);
+ g.setColor(getRandColor(160, 200));
+ g.drawLine(x, y, x + xl, y + yl);
+ }
+ }
+
+ /**
+ * 创建图片的方法
+ */
+ private BufferedImage createImage() {
+ //创建图片缓冲区
+ BufferedImage image = new BufferedImage(weight, height, BufferedImage.TYPE_INT_RGB);
+ //获取画笔
+ Graphics2D g = (Graphics2D) image.getGraphics();
+ // 设定图像背景色(因为是做背景,所以偏淡)
+ g.setColor(getRandColor(200, 250));
+ g.fillRect(0, 0, weight, height);
+ //返回一个图片
+ return image;
+ }
+
+ /**
+ * 获取验证码图片的方法
+ */
+ public BufferedImage getImage() {
+ BufferedImage image = createImage();
+ //获取画笔
+ Graphics2D g = (Graphics2D) image.getGraphics();
+ StringBuilder sb = new StringBuilder();
+ drawLine(image);
+ //画四个字符即可
+ for (int i = 0; i < 4; i++) {
+ //随机生成字符,因为只有画字符串的方法,没有画字符的方法,所以需要将字符变成字符串再画
+ String s = randomChar() + "";
+ //添加到StringBuilder里面
+ sb.append(s);
+ //定义字符的x坐标
+ float x = i * 1.0F * weight / 4;
+ //设置字体,随机
+ g.setFont(randomFont());
+ //设置颜色,随机
+ g.setColor(randomColor());
+ g.drawString(s, x, height - 5);
+ }
+ this.text = sb.toString();
+ return image;
+ }
+
+ /**
+ * 给定范围获得随机颜色
+ */
+ Color getRandColor(int fc, int bc) {
+ Random random = new Random();
+ if (fc > 255) {
+ fc = 255;
+ }
+
+ if (bc > 255) {
+ bc = 255;
+ }
+
+ int r = fc + random.nextInt(bc - fc);
+ int g = fc + random.nextInt(bc - fc);
+ int b = fc + random.nextInt(bc - fc);
+ return new Color(r, g, b);
+ }
+
+ /**
+ * 获取验证码文本的方法
+ */
+ public String getText() {
+ return text;
+ }
+}
diff --git a/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/package-info.java b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/package-info.java
new file mode 100644
index 0000000..1f7fa8f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/java/com/ruoyi/plus/util/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * 公共工具包
+ * @author geekidea
+ * @date 2018-11-08
+ */
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.util;
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/resources/config/application-dev.yml b/ruoyi-plus-api/src/main/resources/config/application-dev.yml
new file mode 100644
index 0000000..e3271ea
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/application-dev.yml
@@ -0,0 +1,32 @@
+spring-boot-plus:
+ # 是否启用ansi控制台输出有颜色的字体,local环境建议开启,服务器环境设置为false
+ enable-ansi: true
+ # 请求日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ request-log-format: true
+ # 响应日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ response-log-format: true
+ # 登录设置
+ login:
+ token-valid-time: 60 # 登录token失效时间,单位分钟
+
+server:
+ port: 8888
+ servlet:
+ context-path: /
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/plus?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
+ username: root
+ password: root
+
+ # Redis配置
+ redis:
+ database: 0
+ host: localhost
+ password:
+ port: 6379
+
+# 方便Spring Boot Admin页面上实时查看日志
+# logback.xml中有详细的日志配置
+logging:
+ file: logs/spring-boot-plus-log.log
diff --git a/ruoyi-plus-api/src/main/resources/config/application-local.yml b/ruoyi-plus-api/src/main/resources/config/application-local.yml
new file mode 100644
index 0000000..657310f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/application-local.yml
@@ -0,0 +1,48 @@
+spring-boot-plus:
+ # 是否启用ansi控制台输出有颜色的字体,local环境建议开启,服务器环境设置为false
+ enable-ansi: true
+ # 请求日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ request-log-format: true
+ # 响应日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ response-log-format: true
+ # 登录设置
+ login:
+ token-valid-time: 60 # 登录token失效时间,单位分钟
+
+ # 拦截器配置
+ interceptor-config:
+ resource-config:
+ include-path: ${spring-boot-plus.resource-access-patterns}
+ # 文件上传下载配置
+ upload-path: /opt/upload/
+ # 资源访问路径
+ resource-access-path: /resource/
+ # 资源访问路径匹配:/resource/**
+ resource-access-patterns: ${spring-boot-plus.resource-access-path}**
+ # 资源访问全路径前缀:http://localhost:8888/resource/
+ resource-access-url: http://localhost:${server.port}${server.servlet.context-path}${spring-boot-plus.resource-access-path}
+
+
+server:
+ port: 8888
+ servlet:
+ context-path: /
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/ruoyi?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
+ username: root
+ password: root
+
+# Redis配置
+ redis:
+ database: 0
+ host: localhost
+ password:
+ port: 6379
+
+
+# logback.xml中有详细的日志配置
+logging:
+ config: classpath:config/logback.xml
+ # 方便Spring Boot Admin页面上实时查看日志
+ file: logs/spring-boot-plus.log
diff --git a/ruoyi-plus-api/src/main/resources/config/application-prod.yml b/ruoyi-plus-api/src/main/resources/config/application-prod.yml
new file mode 100644
index 0000000..53c101f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/application-prod.yml
@@ -0,0 +1,32 @@
+spring-boot-plus:
+ # 是否启用ansi控制台输出有颜色的字体,local环境建议开启,服务器环境设置为false
+ enable-ansi: false
+ # 请求日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ request-log-format: false
+ # 响应日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ response-log-format: false
+ # 登录设置
+ login:
+ token-valid-time: 60 # 登录token失效时间,单位分钟
+
+server:
+ port: 8888
+ servlet:
+ context-path: /
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/ruoyi?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
+ username: root
+ password: root
+
+ # Redis配置
+ redis:
+ database: 0
+ host: localhost
+ password:
+ port: 6379
+
+# 方便Spring Boot Admin页面上实时查看日志
+# logback.xml中有详细的日志配置
+logging:
+ file: logs/spring-boot-plus-log.log
diff --git a/ruoyi-plus-api/src/main/resources/config/application-test.yml b/ruoyi-plus-api/src/main/resources/config/application-test.yml
new file mode 100644
index 0000000..f2fd591
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/application-test.yml
@@ -0,0 +1,32 @@
+spring-boot-plus:
+ # 是否启用ansi控制台输出有颜色的字体,local环境建议开启,服务器环境设置为false
+ enable-ansi: false
+ # 请求日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ request-log-format: true
+ # 响应日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ response-log-format: true
+ # 登录设置
+ login:
+ token-valid-time: 60 # 登录token失效时间,单位分钟
+
+server:
+ port: 8888
+ servlet:
+ context-path: /
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/ruoyi?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
+ username: root
+ password: Springbootplus666!
+
+ # Redis配置
+ redis:
+ database: 0
+ host: localhost
+ password:
+ port: 6379
+
+# 方便Spring Boot Admin页面上实时查看日志
+# logback.xml中有详细的日志配置
+logging:
+ file: logs/spring-boot-plus-log.log
diff --git a/ruoyi-plus-api/src/main/resources/config/application-uat.yml b/ruoyi-plus-api/src/main/resources/config/application-uat.yml
new file mode 100644
index 0000000..53c101f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/application-uat.yml
@@ -0,0 +1,32 @@
+spring-boot-plus:
+ # 是否启用ansi控制台输出有颜色的字体,local环境建议开启,服务器环境设置为false
+ enable-ansi: false
+ # 请求日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ request-log-format: false
+ # 响应日志在控制台是否格式化输出,local环境建议开启,服务器环境设置为false
+ response-log-format: false
+ # 登录设置
+ login:
+ token-valid-time: 60 # 登录token失效时间,单位分钟
+
+server:
+ port: 8888
+ servlet:
+ context-path: /
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/ruoyi?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
+ username: root
+ password: root
+
+ # Redis配置
+ redis:
+ database: 0
+ host: localhost
+ password:
+ port: 6379
+
+# 方便Spring Boot Admin页面上实时查看日志
+# logback.xml中有详细的日志配置
+logging:
+ file: logs/spring-boot-plus-log.log
diff --git a/ruoyi-plus-api/src/main/resources/config/application.yml b/ruoyi-plus-api/src/main/resources/config/application.yml
new file mode 100644
index 0000000..9c3666a
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/application.yml
@@ -0,0 +1,210 @@
+# spring-boot-plus Common Config
+
+############################# 访问路径、端口tomcat start ############################
+server:
+ port: 8888
+ servlet:
+ context-path: /api
+ tomcat:
+ max-threads: 1000
+ min-spare-threads: 30
+ uri-encoding: UTF-8
+############################# 访问路径、端口tomcat end ##############################
+
+
+################################ spring config start ###############################
+spring:
+ application:
+ name: spring-boot-plus
+ http:
+ encoding:
+ charset: UTF-8
+ enabled: true
+ force: true
+ jackson:
+ date-format: yyy-MM-dd HH:mm:ss
+ time-zone: GMT+8
+ banner:
+ charset: UTF-8
+ location: classpath:config/banner.txt
+
+# 当前项目maven激活环境,例如:local/dev/test,对应pom.xml中profile设置值
+---
+spring:
+ profiles:
+ active: '@profileActive@'
+################################ spring config end ################################
+
+
+############################## spring-boot-plus start #############################
+spring-boot-plus:
+ # jwt配置
+ jwt:
+ header: token
+ secret: 666666
+ issuer: spring-boot-plus
+ subject: spring-boot-plus-jwt
+ audience: web
+ expire-minutes: 2
+ # 拦截器配置
+ interceptor-config:
+ jwt-config:
+ enabled: true
+ include-path: /**
+ exclude-path: /swagger-resources/**,/api-docs/**,/v2/api-docs/**,/login,/verificationCode,/doc/**,/error/**,/docs,/test/**,/resource/**
+ permission-config:
+ enabled: false
+ include-path: /**
+ exclude-path: /swagger-resources/**,/api-docs/**,/v2/api-docs/**,/adminLogin,/sysLogin,/login.html,/verificationCode,/doc/**,/error/**,/docs,/resource/**
+ token-timeout-config:
+ enabled: false
+ include-path: /**
+ exclude-path: /swagger-resources/**,/api-docs/**,/v2/api-docs/**,/docs,/resource/**
+ resource-config:
+ enabled: true
+ include-path: ${spring-boot-plus.resource-access-patterns}
+ upload-config:
+ enabled: true
+ include-path: /upload/**
+ download-config:
+ enabled: true
+ include-path: /download/**
+ # 文件上传下载配置
+ # 上传路径配置
+ upload-path: /opt/upload/
+ # 资源访问路径
+ resource-access-path: /resource/
+ # 资源访问路径匹配:/resource/**
+ resource-access-patterns: ${spring-boot-plus.resource-access-path}**
+ # 资源访问全路径前缀:http://localhost:8888/resource/
+ resource-access-url: http://localhost:${server.port}${server.servlet.context-path}${spring-boot-plus.resource-access-path}
+ # 全局允许上传的类型
+ allow-upload-file-extensions: jpg,png,docx,xlsx,pptx,pdf
+ allow-download-file-extensions: jpg,png,docx,xlsx,pptx,pdf
+############################### spring-boot-plus end ###############################
+
+
+############################### mybatis-plus start #################################
+mybatis-plus:
+ check-config-location: true
+ configuration:
+ map-underscore-to-camel-case: true
+ global-config:
+ db-config:
+ id-type: id_worker
+ logic-delete-value: 0
+ logic-not-delete-value: 1
+ mapper-locations: classpath*:mapper/**/*Mapper.xml
+################################ mybatis-plus end #################################
+
+
+############################### DRUID数据源配置 start ##############################
+---
+spring:
+ datasource:
+ driver-class-name: com.mysql.jdbc.Driver
+ druid:
+ filter:
+ slf4j:
+ enabled: true
+ stat:
+ log-slow-sql: true
+ merge-sql: true
+ slow-sql-millis: 3000
+ wall:
+ config:
+ delete-allow: true
+ drop-table-allow: false
+ enabled: true
+ filters: stat,wall,slf4j
+ initial-size: 10
+ max-active: 100
+ max-pool-prepared-statement-per-connection-size: 20
+ max-wait: 60000
+ min-evictable-idle-time-millis: 300000
+ min-idle: 10
+ pool-prepared-statements: true
+ stat-view-servlet:
+ enabled: true
+ login-password: druid123
+ login-username: druid
+ url-pattern: /druid/*
+ test-on-borrow: false
+ test-on-return: false
+ test-while-idle: true
+ time-between-eviction-runs-millis: 60000
+ validation-query: SELECT 1 FROM DUAL
+ type: com.alibaba.druid.pool.DruidDataSource
+############################### DRUID数据源配置 end ################################
+
+
+############################### Redis 公共配置 start ###############################
+---
+spring:
+ redis:
+ jedis:
+ pool:
+ max-active: 2000
+ max-wait: -1ms
+ min-idle: 8
+ max-idle: 200
+ timeout: 10s
+ lettuce:
+ pool:
+ max-active: 200
+ max-idle: 8
+ max-wait: 10s
+ min-idle: 2
+ shutdown-timeout: 3s
+############################### Redis 公共配置 end ##################################
+
+
+#################################### Swagger start ####################################
+# swagger配置
+swagger:
+ base:
+ package: io.geekidea.springbootplus
+ contact:
+ email: geekidea@qq.com
+ name: geekidea
+ url: ''
+ description: ''
+ title: spring-boot-plus
+ url: ''
+ version: 1.0
+#################################### Swagger end #####################################
+
+
+################################ Spring boot admin start ################################
+---
+spring:
+ boot:
+ admin:
+ client:
+ url: http://localhost:${server.port}/${server.servlet.context-path}
+
+# 开启和暴露所有端点
+management:
+ endpoints:
+ web:
+ exposure:
+ include: "*"
+ endpoint:
+ health:
+ show-details: ALWAYS
+ logfile:
+ enabled: true #可在线查看日志
+
+# 自定义项目信息,Spring Boot Admin展示使用
+info:
+ project-groupId: '@project.groupId@'
+ project-artifactId: '@project.artifactId@'
+ project-name: '@project.name@'
+ project-finalName: '@project.build.finalName@'
+ project-author: ${swagger.contact.name}
+ project-description: '@project.description@'
+ project-sourceEncoding: '@project.build.sourceEncoding@'
+ project-spring-boot-version: '@spring-boot.version@'
+ project-mybatis-plus-version: '@mybatis-plus-boot-starter.version@'
+ project-version: '@project.version@'
+################################ Spring boot admin end #################################
diff --git a/ruoyi-plus-api/src/main/resources/config/banner.txt b/ruoyi-plus-api/src/main/resources/config/banner.txt
new file mode 100644
index 0000000..dcc3fd7
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/banner.txt
@@ -0,0 +1,14 @@
+${AnsiColor.BLUE}
+ _ _ _ _
+ (_) | | | | | |
+ ___ _ __ _ __ _ _ __ __ _ ______| |__ ___ ___ | |_ ______ _ __ | |_ _ ___
+ / __| '_ \| '__| | '_ \ / _` |______| '_ \ / _ \ / _ \| __|______| '_ \| | | | / __|
+ \__ \ |_) | | | | | | | (_| | | |_) | (_) | (_) | |_ | |_) | | |_| \__ \
+ |___/ .__/|_| |_|_| |_|\__, | |_.__/ \___/ \___/ \__| | .__/|_|\__,_|___/
+ | | __/ | | |
+ |_| |___/ |_|
+
+${AnsiColor.YELLOW} :: Spring Boot :: ${AnsiColor.WHITE}(v${spring-boot.version})
+${AnsiColor.YELLOW} :: Spring Boot Plus :: ${AnsiColor.WHITE}(v${project.version})
+${AnsiColor.YELLOW} :: spring-boot-plus :: ${AnsiColor.WHITE}https://springboot.plus
+
diff --git a/ruoyi-plus-api/src/main/resources/config/logback.xml b/ruoyi-plus-api/src/main/resources/config/logback.xml
new file mode 100644
index 0000000..29d0d94
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/logback.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+ ${CONTEXT_NAME}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${CONSOLE_LOG_PATTERN}
+
+
+
+
+
+
+ ${FILE_LOG_PATTERN}
+
+ ${LOG_PATH}/spring-boot-plus.log
+
+ ${LOG_PATH}/spring-boot-plus-%d{yyyy-MM-dd}.%i.log
+ ${MAX_FILE_SIZE}
+ ${MAX_HISTORY}
+
+
+
+
+
+
+ ${FILE_LOG_PATTERN}
+
+ ${LOG_PATH}/spring-boot-plus-error.log
+
+ ${LOG_PATH}/spring-boot-plus-error-%d{yyyy-MM-dd}.%i.log
+ ${MAX_FILE_SIZE}
+ ${MAX_HISTORY}
+
+
+ ERROR
+ ACCEPT
+ DENY
+
+
+
+
+
+ 0
+ 1024
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/resources/config/mime-type.properties b/ruoyi-plus-api/src/main/resources/config/mime-type.properties
new file mode 100644
index 0000000..70bf2e3
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/config/mime-type.properties
@@ -0,0 +1,3 @@
+# 扩展mime-type
+# 参考:https://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?revision=1752884&view=co
+md=text/markdown
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/resources/mapper/system/IpMapper.xml b/ruoyi-plus-api/src/main/resources/mapper/system/IpMapper.xml
new file mode 100644
index 0000000..d47212f
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/mapper/system/IpMapper.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ ip_start, ip_end, area, operator, id, ip_start_num, ip_end_num
+
+
+
+
diff --git a/ruoyi-plus-api/src/main/resources/mapper/system/SysLogMapper.xml b/ruoyi-plus-api/src/main/resources/mapper/system/SysLogMapper.xml
new file mode 100644
index 0000000..479b9a3
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/mapper/system/SysLogMapper.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ log_id, type, content, create_id, create_time
+
+
+
+ select from sys_log where log_id = #{id}
+
+
+
+ select from sys_log
+
+
+
diff --git a/ruoyi-plus-api/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-plus-api/src/main/resources/mapper/system/SysUserMapper.xml
new file mode 100644
index 0000000..6843024
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/mapper/system/SysUserMapper.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ id, name, account, pwd, remark, create_time, update_time
+
+
+
+ select from sys_user where id = #{id}
+
+
+
+ select from sys_user
+
+
+
diff --git a/ruoyi-plus-api/src/main/resources/static/welcome.html b/ruoyi-plus-api/src/main/resources/static/welcome.html
new file mode 100644
index 0000000..3a547f2
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/static/welcome.html
@@ -0,0 +1,19 @@
+
+
+
+
+ Welcome to spring-boot-plus
+
+
+Welcome to spring-boot-plus
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/main/resources/templates/springbootplus.html b/ruoyi-plus-api/src/main/resources/templates/springbootplus.html
new file mode 100644
index 0000000..d0f97a1
--- /dev/null
+++ b/ruoyi-plus-api/src/main/resources/templates/springbootplus.html
@@ -0,0 +1,12 @@
+
+
+
+
+ spring-boot-plus
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/BaseTest.java b/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/BaseTest.java
new file mode 100644
index 0000000..53e0b56
--- /dev/null
+++ b/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/BaseTest.java
@@ -0,0 +1,12 @@
+
+package com.ruoyi.plus.test;
+
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class BaseTest {
+
+}
diff --git a/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/CodeGenerator.java b/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/CodeGenerator.java
new file mode 100644
index 0000000..ecff97b
--- /dev/null
+++ b/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/CodeGenerator.java
@@ -0,0 +1,212 @@
+/**
+ * Copyright 2019-2029 geekidea(https://github.com/geekidea)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ruoyi.plus.test;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.DateType;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * spring-boot-plus代码生成器入口类
+ * @author geekidea
+ * @date 2018-11-08
+ */
+public class CodeGenerator {
+
+ private static final String USER_NAME = "root";
+ private static final String PASSWORD = "root";
+ private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
+ private static final String DRIVER_URL = "jdbc:mysql://localhost:3306/spring_boot_plus?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
+
+ private static final String PARENT_PACKAGE = "io.geekidea.springbootplus";
+ private static final String SUPER_ENTITY = PARENT_PACKAGE + ".common.entity.BaseEntity";
+ private static final String[] SUPER_ENTITY_COMMON_COLUMNS = new String[]{};
+ private static final String SUPER_CONTROLLER = PARENT_PACKAGE + ".common.web.controller.BaseController";
+ private static final String SUPER_SERVICE = PARENT_PACKAGE + ".common.service.BaseService";
+ private static final String SUPER_SERVICE_IMPL = PARENT_PACKAGE + ".common.service.impl.BaseServiceImpl";
+
+ private static final String PROJECT_PACKAGE_PATH = "io/geekidea/springbootplus";
+
+
+ // ############################ 配置部分 start ############################
+ // 模块名称
+ private static final String MODULE_NAME = "system";
+ // 作者
+ private static final String AUTHOR = "geekidea";
+ // 生成的表名称
+ private static final String TABLE_NAME = "sys_user";
+ // 主键数据库列名称
+ private static final String PK_ID_COLUMN_NAME = "id";
+ // 代码生成策略 true:All/false:SIMPLE
+ private static final boolean GENERATOR_STRATEGY = true;
+ // 分页列表查询是否排序 true:有排序参数/false:无
+ private static final boolean PAGE_LIST_ORDER = false;
+ // ############################ 配置部分 end ############################
+
+
+ public static void main(String[] args) {
+ // 代码生成器
+ AutoGenerator mpg = new AutoGenerator();
+
+ // 全局配置
+ GlobalConfig gc = new GlobalConfig();
+ String projectPath = System.getProperty("user.dir");
+ gc.setOutputDir(projectPath + "/src/main/java");
+ gc.setAuthor(AUTHOR);
+ gc.setOpen(false); // 是否打开输出目录
+ gc.setSwagger2(true); // 启用swagger注解
+ gc.setIdType(IdType.ID_WORKER); // 主键类型:ID_WORKER
+ gc.setServiceName("%sService"); // 自定义文件命名,注意 %s 会自动填充表实体属性!
+ gc.setFileOverride(true); // 是否覆盖已有文件
+ gc.setDateType(DateType.ONLY_DATE); // 设置日期类型为Date
+
+ mpg.setGlobalConfig(gc);
+
+ // 数据源配置
+ DataSourceConfig dsc = new DataSourceConfig();
+ dsc.setUrl(DRIVER_URL);
+ // dsc.setSchemaName("public");
+ dsc.setDriverName(DRIVER_NAME);
+ dsc.setUsername(USER_NAME);
+ dsc.setPassword(PASSWORD);
+ mpg.setDataSource(dsc);
+
+ // 包配置
+ PackageConfig pc = new PackageConfig();
+ pc.setModuleName(MODULE_NAME);
+ pc.setParent(PARENT_PACKAGE);
+ pc.setController("web.controller");
+
+ mpg.setPackageInfo(pc);
+
+ // 自定义配置
+ InjectionConfig cfg = new InjectionConfig() {
+ @Override
+ public void initMap() {
+ Map map = new HashMap();
+ map.put("customField", "Hello " + this.getConfig().getGlobalConfig().getAuthor());
+ // 查询参数包路径
+ map.put("queryParamPath",PARENT_PACKAGE + StringPool.DOT + pc.getModuleName() + ".web.param." + underlineToPascal(TABLE_NAME) + "QueryParam");
+ // 查询参数共公包路径
+ map.put("queryParamCommonPath",PARENT_PACKAGE + StringPool.DOT + "common.web.param." + "QueryParam");
+ // 查询参数共公包路径
+ map.put("idParamPath",PARENT_PACKAGE + StringPool.DOT + "common.web.param." + "IdParam");
+ // 响应结果包路径
+ map.put("queryVoPath",PARENT_PACKAGE + StringPool.DOT + pc.getModuleName() + ".web.vo." + underlineToPascal(TABLE_NAME) + "QueryVo");
+ // 实体对象名称
+ map.put("entityObjectName",underlineToCamel(TABLE_NAME));
+ // service对象名称
+ map.put("serviceObjectName",underlineToCamel(TABLE_NAME) + "Service");
+ // mapper对象名称
+ map.put("mapperObjectName",underlineToCamel(TABLE_NAME) + "Mapper");
+ // 主键ID列名
+ map.put("pkIdColumnName",PK_ID_COLUMN_NAME);
+ // 主键ID驼峰名称
+ map.put("pkIdCamelName",underlineToCamel(PK_ID_COLUMN_NAME));
+ // 导入分页类
+ map.put("paging",PARENT_PACKAGE + ".common.web.vo.Paging");
+ // 导入排序枚举
+ map.put("orderEnum",PARENT_PACKAGE + ".common.enums.OrderEnum");
+ // 分页列表查询是否排序
+ map.put("pageListOrder",PAGE_LIST_ORDER);
+ // 导入排序查询参数类
+ map.put("orderQueryParamPath",PARENT_PACKAGE + StringPool.DOT + "common.web.param." + "OrderQueryParam");
+ // 代码生成策略
+ map.put("generatorStrategy",GENERATOR_STRATEGY);
+ this.setMap(map);
+ }
+ };
+ List focList = new ArrayList<>();
+ focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
+ @Override
+ public String outputFile(TableInfo tableInfo) {
+ // 自定义输入文件名称
+ return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
+ }
+ });
+
+ // 自定义queryParam模板
+ focList.add(new FileOutConfig("/templates/queryParam.java.vm") {
+ @Override
+ public String outputFile(TableInfo tableInfo) {
+ return projectPath + "/src/main/java/"+ PROJECT_PACKAGE_PATH +"/" + pc.getModuleName() + "/web/param/" + tableInfo.getEntityName() + "QueryParam" + StringPool.DOT_JAVA;
+ }
+ });
+
+ // 自定义queryVo模板
+ focList.add(new FileOutConfig("/templates/queryVo.java.vm") {
+ @Override
+ public String outputFile(TableInfo tableInfo) {
+ return projectPath + "/src/main/java/"+ PROJECT_PACKAGE_PATH +"/" + pc.getModuleName() + "/web/vo/" + tableInfo.getEntityName() + "QueryVo" + StringPool.DOT_JAVA;
+ }
+ });
+
+
+ cfg.setFileOutConfigList(focList);
+ mpg.setCfg(cfg);
+ mpg.setTemplate(new TemplateConfig().setXml(null));
+
+ // 策略配置
+ StrategyConfig strategy = new StrategyConfig();
+ strategy.setNaming(NamingStrategy.underline_to_camel);
+ strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+ strategy.setSuperEntityClass(SUPER_ENTITY);
+ strategy.setEntityLombokModel(true);
+ strategy.setRestControllerStyle(true);
+ strategy.setSuperControllerClass(SUPER_CONTROLLER);
+ strategy.setSuperServiceClass(SUPER_SERVICE);
+ strategy.setSuperServiceImplClass(SUPER_SERVICE_IMPL);
+ strategy.setInclude(TABLE_NAME);
+ strategy.setSuperEntityColumns(SUPER_ENTITY_COMMON_COLUMNS);
+ strategy.setControllerMappingHyphenStyle(true);
+ /**
+ * 注意,根据实际情况,进行设置
+ * 当表名称的前缀和模块名称一样时,会去掉表的前缀
+ * 比如模块名称为user,表明为user_info,则生成的实体名称是Info.java,一定要注意
+ */
+ //strategy.setTablePrefix(pc.getModuleName() + "_");
+ mpg.setStrategy(strategy);
+ mpg.execute();
+ }
+
+ public static String underlineToCamel(String underline){
+ if (StringUtils.isNotBlank(underline)){
+ return NamingStrategy.underlineToCamel(underline);
+ }
+ return null;
+ }
+
+ public static String underlineToPascal(String underline){
+ if (StringUtils.isNotBlank(underline)){
+ return NamingStrategy.capitalFirst(NamingStrategy.underlineToCamel(underline));
+ }
+ return null;
+ }
+
+}
diff --git a/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/IpTest.java b/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/IpTest.java
new file mode 100644
index 0000000..d4a9269
--- /dev/null
+++ b/ruoyi-plus-api/src/test/java/com/ruoyi/plus/test/IpTest.java
@@ -0,0 +1,8 @@
+package com.ruoyi.plus.test;
+
+/**
+ * @author geekidea
+ * @date 2019/8/4
+ */
+public class IpTest {
+}
diff --git a/ruoyi-plus-api/src/test/resources/templates/controller.java.vm b/ruoyi-plus-api/src/test/resources/templates/controller.java.vm
new file mode 100644
index 0000000..4f81d86
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/controller.java.vm
@@ -0,0 +1,114 @@
+package ${package.Controller};
+
+import ${package.Entity}.${entity};
+import ${package.Service}.${table.serviceName};
+import ${cfg.queryParamPath};
+import ${cfg.queryVoPath};
+#if(${superControllerClassPackage})
+import ${superControllerClassPackage};
+#end
+import io.geekidea.springbootplus.common.api.ApiResult;
+ #if(${swagger2})
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+#end
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+#if(${restControllerStyle})
+import org.springframework.web.bind.annotation.RestController;
+#else
+import org.springframework.stereotype.Controller;
+#end
+
+import javax.validation.Valid;
+
+import ${cfg.paging};
+import ${cfg.idParamPath};
+
+/**
+ *
+ * $!{table.comment} 前端控制器
+ *
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+@Slf4j
+#if(${restControllerStyle})
+@RestController
+#else
+@Controller
+#end
+@RequestMapping("/${cfg.entityObjectName}")
+@Api("$!{table.comment} API")
+#if(${kotlin})
+class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end
+
+#else
+#if(${superControllerClass})
+public class ${table.controllerName} extends ${superControllerClass} {
+#else
+public class ${table.controllerName} {
+#end
+
+ @Autowired
+ private ${table.serviceName} ${cfg.serviceObjectName};
+
+#if(${cfg.generatorStrategy})
+ /**
+ * 添加$!{table.comment}
+ */
+ @PostMapping("/add")
+ @ApiOperation(value = "添加${entity}对象",notes = "添加$!{table.comment}",response = ApiResult.class)
+ public ApiResult add${entity}(@Valid @RequestBody ${entity} ${cfg.entityObjectName}) throws Exception{
+ boolean flag = ${cfg.serviceObjectName}.save(${cfg.entityObjectName});
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * 修改$!{table.comment}
+ */
+ @PostMapping("/update")
+ @ApiOperation(value = "修改${entity}对象",notes = "修改$!{table.comment}",response = ApiResult.class)
+ public ApiResult update${entity}(@Valid @RequestBody ${entity} ${cfg.entityObjectName}) throws Exception{
+ boolean flag = ${cfg.serviceObjectName}.updateById(${cfg.entityObjectName});
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * 删除$!{table.comment}
+ */
+ @PostMapping("/delete")
+ @ApiOperation(value = "删除${entity}对象",notes = "删除$!{table.comment}",response = ApiResult.class)
+ public ApiResult delete${entity}(@Valid @RequestBody IdParam idParam) throws Exception{
+ boolean flag = ${cfg.serviceObjectName}.removeById(idParam.getId());
+ return ApiResult.result(flag);
+ }
+
+ /**
+ * 获取$!{table.comment}
+ */
+ @PostMapping("/info")
+ @ApiOperation(value = "获取${entity}对象详情",notes = "查看$!{table.comment}",response = ${entity}QueryVo.class)
+ public ApiResult<${entity}QueryVo> get${entity}(@Valid @RequestBody IdParam idParam) throws Exception{
+ ${entity}QueryVo ${cfg.entityObjectName}QueryVo = ${cfg.serviceObjectName}.get${entity}ById(idParam.getId());
+ return ApiResult.ok(${cfg.entityObjectName}QueryVo);
+ }
+
+ /**
+ * $!{table.comment}分页列表
+ */
+ @PostMapping("/getPageList")
+ @ApiOperation(value = "获取${entity}分页列表",notes = "$!{table.comment}分页列表",response = ${entity}QueryVo.class)
+ public ApiResult> get${entity}PageList(@Valid @RequestBody(required = false) ${entity}QueryParam ${cfg.entityObjectName}QueryParam) throws Exception{
+ Paging<${entity}QueryVo> paging = ${cfg.entityObjectName}Service.get${entity}PageList(${cfg.entityObjectName}QueryParam);
+ return ApiResult.ok(paging);
+ }
+#end
+
+}
+
+#end
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/test/resources/templates/entity.java.vm b/ruoyi-plus-api/src/test/resources/templates/entity.java.vm
new file mode 100644
index 0000000..61c3326
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/entity.java.vm
@@ -0,0 +1,161 @@
+package ${package.Entity};
+
+#foreach($pkg in ${table.importPackages})
+import ${pkg};
+#end
+#if(${swagger2})
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+#end
+#if(${entityLombokModel})
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+## import lombok.experimental.Accessors;
+#end
+
+import java.util.Date;
+
+/**
+ *
+ * $!{table.comment}
+ *
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${entityLombokModel})
+@Data
+#if(${superEntityClass})
+@EqualsAndHashCode(callSuper = true)
+#else
+@EqualsAndHashCode(callSuper = false)
+#end
+## @Accessors(chain = true)
+#end
+#if(${table.convert})
+@TableName("${table.name}")
+#end
+#if(${swagger2})
+@ApiModel(value="${entity}对象", description="$!{table.comment}")
+#end
+#if(${superEntityClass})
+public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
+#elseif(${activeRecord})
+public class ${entity} extends Model<${entity}> {
+#else
+public class ${entity} implements Serializable {
+#end
+
+ private static final long serialVersionUID = 1L;
+## ---------- BEGIN 字段循环遍历 ----------
+#foreach($field in ${table.fields})
+## 自定义属性,是否是主键
+#set($custom_is_pk=false)
+
+#if(${field.keyFlag})
+#set($keyPropertyName=${field.propertyName})
+#end
+#if("$!field.comment" != "")
+ #if(${swagger2})
+@ApiModelProperty(value = "${field.comment}")
+ #else
+/**
+ * ${field.comment}
+ */
+ #end
+#end
+#if(${field.keyFlag})
+## 主键
+#if(${field.keyIdentityFlag})
+@TableId(value = "${field.name}", type = IdType.AUTO)
+#elseif(!$null.isNull(${idType}) && "$!idType" != "")
+## 设置主键注解
+@TableId(value = "${field.name}", type = IdType.${idType})
+## 是主键类型
+#set($custom_is_pk=true)
+#elseif(${field.convert})
+@TableId("${field.name}")
+#end
+## 普通字段
+#elseif(${field.fill})
+## ----- 存在字段填充设置 -----
+#if(${field.convert})
+ @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
+#else
+ @TableField(fill = FieldFill.${field.fill})
+#end
+#elseif(${field.convert})
+ @TableField("${field.name}")
+#end
+## 乐观锁注解
+#if(${versionFieldName}==${field.name})
+ @Version
+#end
+## 逻辑删除注解
+#if(${logicDeleteFieldName}==${field.name})
+ @TableLogic
+#end
+#if(${custom_is_pk})
+ private ${field.propertyType} ${field.propertyName};
+#else
+private ${field.propertyType} ${field.propertyName};
+#end
+#end
+## ---------- END 字段循环遍历 ----------
+#if(!${entityLombokModel})
+#foreach($field in ${table.fields})
+#if(${field.propertyType.equals("boolean")})
+#set($getprefix="is")
+#else
+#set($getprefix="get")
+#end
+
+ public ${field.propertyType} ${getprefix}${field.capitalName}() {
+ return ${field.propertyName};
+ }
+
+#if(${entityBuilderModel})
+ public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+#else
+ public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+#end
+ this.${field.propertyName} = ${field.propertyName};
+#if(${entityBuilderModel})
+ return this;
+#end
+ }
+#end
+#end
+
+#if(${entityColumnConstant})
+#foreach($field in ${table.fields})
+ public static final String ${field.name.toUpperCase()} = "${field.name}";
+
+#end
+#end
+#if(${activeRecord})
+ @Override
+ protected Serializable pkVal() {
+#if(${keyPropertyName})
+ return this.${keyPropertyName};
+#else
+ return null;
+#end
+ }
+
+#end
+#if(!${entityLombokModel})
+ @Override
+ public String toString() {
+ return "${entity}{" +
+#foreach($field in ${table.fields})
+#if($!{foreach.index}==0)
+ "${field.propertyName}=" + ${field.propertyName} +
+#else
+ ", ${field.propertyName}=" + ${field.propertyName} +
+#end
+#end
+ "}";
+ }
+#end
+}
diff --git a/ruoyi-plus-api/src/test/resources/templates/mapper.java.vm b/ruoyi-plus-api/src/test/resources/templates/mapper.java.vm
new file mode 100644
index 0000000..207c1cb
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/mapper.java.vm
@@ -0,0 +1,46 @@
+package ${package.Mapper};
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import ${superMapperClassPackage};
+import ${package.Entity}.${entity};
+import ${cfg.queryParamPath};
+import ${cfg.queryVoPath};
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.io.Serializable;
+
+/**
+ *
+ * $!{table.comment} Mapper 接口
+ *
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${kotlin})
+interface ${table.mapperName} : ${superMapperClass}<${entity}>
+#else
+@Repository
+public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
+#if(${cfg.generatorStrategy})
+
+ /**
+ * 根据ID获取查询对象
+ * @param id
+ * @return
+ */
+ ${entity}QueryVo get${entity}ById(Serializable id);
+
+ /**
+ * 获取分页对象
+ * @param page
+ * @param ${cfg.entityObjectName}QueryParam
+ * @return
+ */
+ IPage<${entity}QueryVo> get${entity}PageList(@Param("page") Page page, @Param("param") ${entity}QueryParam ${cfg.entityObjectName}QueryParam);
+#end
+
+}
+#end
diff --git a/ruoyi-plus-api/src/test/resources/templates/mapper.xml.vm b/ruoyi-plus-api/src/test/resources/templates/mapper.xml.vm
new file mode 100644
index 0000000..b3829d3
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/mapper.xml.vm
@@ -0,0 +1,47 @@
+
+
+
+
+#if(${enableCache})
+
+
+
+#end
+#if(${baseResultMap})
+
+
+#foreach($field in ${table.fields})
+#if(${field.keyFlag})##生成主键排在第一位
+
+#end
+#end
+#foreach($field in ${table.commonFields})##生成公共字段
+
+#end
+#foreach($field in ${table.fields})
+#if(!${field.keyFlag})##生成普通字段
+
+#end
+#end
+
+
+#end
+
+
+#foreach($field in ${table.commonFields})
+ ${field.name},
+#end
+ ${table.fieldNames}
+
+#if(${cfg.generatorStrategy})
+
+
+ select from ${table.name} where ${cfg.pkIdColumnName} = #{id}
+
+
+
+ select from ${table.name}
+
+
+#end
+
diff --git a/ruoyi-plus-api/src/test/resources/templates/queryParam.java.vm b/ruoyi-plus-api/src/test/resources/templates/queryParam.java.vm
new file mode 100644
index 0000000..15357e7
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/queryParam.java.vm
@@ -0,0 +1,30 @@
+package io.geekidea.springbootplus.${package.ModuleName}.web.param;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+#if(${cfg.pageListOrder})
+import ${cfg.orderQueryParamPath};
+#else
+import ${cfg.queryParamCommonPath};
+#end
+
+/**
+ *
+ * $!{table.comment} 查询参数对象
+ *
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value="${entity}QueryParam对象", description="$!{table.comment}查询参数")
+#if(${cfg.pageListOrder})
+public class ${entity}QueryParam extends OrderQueryParam {
+#else
+public class ${entity}QueryParam extends QueryParam {
+#end
+ private static final long serialVersionUID = 1L;
+}
diff --git a/ruoyi-plus-api/src/test/resources/templates/queryVo.java.vm b/ruoyi-plus-api/src/test/resources/templates/queryVo.java.vm
new file mode 100644
index 0000000..4ccd4ce
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/queryVo.java.vm
@@ -0,0 +1,124 @@
+package io.geekidea.springbootplus.${package.ModuleName}.web.vo;
+
+#if(${swagger2})
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+#end
+#if(${entityLombokModel})
+import lombok.Data;
+#end
+import java.io.Serializable;
+
+import java.util.Date;
+
+/**
+ *
+ * $!{table.comment} 查询结果对象
+ *
+ *
+ * @author ${author}
+ * @date ${date}
+ */
+#if(${entityLombokModel})
+@Data
+#end
+#if(${table.convert})
+@TableName("${table.name}")
+#end
+@ApiModel(value="${entity}QueryVo对象", description="$!{table.comment}查询参数")
+public class ${entity}QueryVo implements Serializable{
+ private static final long serialVersionUID = 1L;
+## ---------- BEGIN 字段循环遍历 ----------
+#foreach($field in ${table.fields})
+
+#if(${field.keyFlag})
+#set($keyPropertyName=${field.propertyName})
+#end
+#if("$!field.comment" != "")
+ #if(${swagger2})
+@ApiModelProperty(value = "${field.comment}")
+ #else
+/**
+ * ${field.comment}
+ */
+ #end
+#end
+#if(${field.keyFlag})
+## 普通字段
+#elseif(${field.fill})
+## ----- 存在字段填充设置 -----
+#if(${field.convert})
+ @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
+#else
+ @TableField(fill = FieldFill.${field.fill})
+#end
+#elseif(${field.convert})
+ @TableField("${field.name}")
+#end
+## 乐观锁注解
+#if(${versionFieldName}==${field.name})
+ @Version
+#end
+## 逻辑删除注解
+#if(${logicDeleteFieldName}==${field.name})
+ @TableLogic
+#end
+private ${field.propertyType} ${field.propertyName};
+#end
+## ---------- END 字段循环遍历 ----------
+#if(!${entityLombokModel})
+#foreach($field in ${table.fields})
+#if(${field.propertyType.equals("boolean")})
+#set($getprefix="is")
+#else
+#set($getprefix="get")
+#end
+
+ public ${field.propertyType} ${getprefix}${field.capitalName}() {
+ return ${field.propertyName};
+ }
+
+#if(${entityBuilderModel})
+ public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+#else
+ public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+#end
+ this.${field.propertyName} = ${field.propertyName};
+#if(${entityBuilderModel})
+ return this;
+#end
+ }
+#end
+#end
+
+#if(${entityColumnConstant})
+#foreach($field in ${table.fields})
+ public static final String ${field.name.toUpperCase()} = "${field.name}";
+
+#end
+#end
+#if(${activeRecord})
+ @Override
+ protected Serializable pkVal() {
+#if(${keyPropertyName})
+ return this.${keyPropertyName};
+#else
+ return null;
+#end
+ }
+#end
+#if(!${entityLombokModel})
+ @Override
+ public String toString() {
+ return "${entity}{" +
+#foreach($field in ${table.fields})
+#if($!{foreach.index}==0)
+ "${field.propertyName}=" + ${field.propertyName} +
+#else
+ ", ${field.propertyName}=" + ${field.propertyName} +
+#end
+#end
+ "}";
+ }
+#end
+}
\ No newline at end of file
diff --git a/ruoyi-plus-api/src/test/resources/templates/service.java.vm b/ruoyi-plus-api/src/test/resources/templates/service.java.vm
new file mode 100644
index 0000000..9009d5c
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/service.java.vm
@@ -0,0 +1,41 @@
+package ${package.Service};
+
+import ${package.Entity}.${entity};
+import ${superServiceClassPackage};
+import ${cfg.queryParamPath};
+import ${cfg.queryVoPath};
+import ${cfg.paging};
+
+import java.io.Serializable;
+
+/**
+ *
+ * $!{table.comment} 服务类
+ *
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${kotlin})
+interface ${table.serviceName} : ${superServiceClass}<${entity}>
+#else
+public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
+#if(${cfg.generatorStrategy})
+
+ /**
+ * 根据ID获取查询对象
+ * @param id
+ * @return
+ */
+ ${entity}QueryVo get${entity}ById(Serializable id) throws Exception;
+
+ /**
+ * 获取分页对象
+ * @param ${cfg.entityObjectName}QueryParam
+ * @return
+ */
+ Paging<${entity}QueryVo> get${entity}PageList(${entity}QueryParam ${cfg.entityObjectName}QueryParam) throws Exception;
+#end
+
+}
+#end
diff --git a/ruoyi-plus-api/src/test/resources/templates/serviceImpl.java.vm b/ruoyi-plus-api/src/test/resources/templates/serviceImpl.java.vm
new file mode 100644
index 0000000..648f327
--- /dev/null
+++ b/ruoyi-plus-api/src/test/resources/templates/serviceImpl.java.vm
@@ -0,0 +1,57 @@
+package ${package.ServiceImpl};
+
+import ${package.Entity}.${entity};
+import ${package.Mapper}.${table.mapperName};
+import ${package.Service}.${table.serviceName};
+import ${cfg.queryParamPath};
+import ${cfg.queryVoPath};
+import ${superServiceImplClassPackage};
+import ${cfg.paging};
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import java.io.Serializable;
+
+
+/**
+ *
+ * $!{table.comment} 服务实现类
+ *
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+@Slf4j
+@Service
+@Transactional(rollbackFor = Exception.class)
+#if(${kotlin})
+open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
+
+}
+#else
+public class ${table.serviceImplName} extends BaseServiceImpl<${table.mapperName}, ${entity}> implements ${table.serviceName} {
+
+ @Autowired
+ private ${table.mapperName} ${cfg.mapperObjectName};
+#if(${cfg.generatorStrategy})
+
+ @Override
+ public ${entity}QueryVo get${entity}ById(Serializable id) throws Exception{
+ return ${cfg.mapperObjectName}.get${entity}ById(id);
+ }
+
+ @Override
+ public Paging<${entity}QueryVo> get${entity}PageList(${entity}QueryParam ${cfg.entityObjectName}QueryParam) throws Exception{
+ Page page = setPageParam(${cfg.entityObjectName}QueryParam,OrderItem.desc("create_time"));
+ IPage<${entity}QueryVo> iPage = ${cfg.mapperObjectName}.get${entity}PageList(page,${cfg.entityObjectName}QueryParam);
+ return new Paging(iPage);
+ }
+#end
+
+}
+#end