├── web ├── src │ └── main │ │ ├── resources │ │ ├── static │ │ │ ├── css │ │ │ │ └── login.css │ │ │ └── login.html │ │ ├── application.yml │ │ ├── xlsx_template │ │ │ ├── 导出模板.xls │ │ │ ├── 日志导出模板.xls │ │ │ └── 设备导入模板.xls │ │ ├── resources │ │ │ └── error │ │ │ │ └── 500.html │ │ ├── banner.txt │ │ ├── application-sysconfig.yml │ │ ├── application-dev.yml │ │ └── logback-spring.xml │ │ └── java │ │ └── com │ │ └── example │ │ └── janche │ │ ├── web │ │ ├── aop │ │ │ ├── Log.java │ │ │ └── LogAspect.java │ │ ├── controller │ │ │ ├── config │ │ │ │ └── ApplicationConfigController.java │ │ │ ├── log │ │ │ │ └── SysLogController.java │ │ │ └── user │ │ │ │ ├── MenuRightController.java │ │ │ │ └── RoleController.java │ │ ├── config │ │ │ └── WebConfigration.java │ │ ├── datasource │ │ │ └── DruidConfig.java │ │ └── cache │ │ │ └── RedisConfig.java │ │ └── WebApplication.java └── pom.xml ├── common ├── src │ └── main │ │ └── java │ │ └── com │ │ └── example │ │ └── janche │ │ └── common │ │ ├── config │ │ ├── IApplicationConfig.java │ │ └── ApplicationConfig.java │ │ ├── core │ │ ├── Mapper.java │ │ ├── TkMapper.java │ │ └── Service.java │ │ ├── model │ │ ├── Constant.java │ │ ├── ProjectPath.java │ │ └── ProjectConstant.java │ │ ├── util │ │ ├── DateUtils.java │ │ ├── EntityUtil.java │ │ ├── CopyUtils.java │ │ └── IPUtils.java │ │ ├── restResult │ │ ├── ResultGenerator.java │ │ ├── PageParam.java │ │ ├── RestResult.java │ │ └── ResultCode.java │ │ ├── exception │ │ ├── CustomException.java │ │ └── ControllerExceptionHandler.java │ │ ├── mybatis │ │ └── handler │ │ │ ├── EmptyStringIfNullHandler.java │ │ │ └── JsonTypeHandler.java │ │ └── utils │ │ ├── date │ │ ├── DateStyleEnum.java │ │ └── WeekEnum.java │ │ ├── MD5Util.java │ │ └── encrypt │ │ ├── TestDecryptCode.java │ │ └── Encodes.java └── pom.xml ├── .gitignore ├── backend ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── janche │ │ │ │ ├── user │ │ │ │ ├── dao │ │ │ │ │ ├── RoleAndMenuMapper.java │ │ │ │ │ ├── UserAndRoleMapper.java │ │ │ │ │ ├── RoleMapper.java │ │ │ │ │ ├── MenuRightMapper.java │ │ │ │ │ └── UserMapper.java │ │ │ │ ├── domain │ │ │ │ │ ├── UserAndRole.java │ │ │ │ │ ├── RoleAndMenu.java │ │ │ │ │ ├── Role.java │ │ │ │ │ ├── MenuRight.java │ │ │ │ │ └── User.java │ │ │ │ ├── dto │ │ │ │ │ ├── role │ │ │ │ │ │ ├── RoleConditionDTO.java │ │ │ │ │ │ ├── RoleDTO.java │ │ │ │ │ │ ├── RoleOutpDTO.java │ │ │ │ │ │ └── RoleInputDTO.java │ │ │ │ │ ├── user │ │ │ │ │ │ ├── UserPwdDTO.java │ │ │ │ │ │ ├── UserConditionDTO.java │ │ │ │ │ │ ├── UserInputDTO.java │ │ │ │ │ │ ├── UserDTO.java │ │ │ │ │ │ └── UserOutpDTO.java │ │ │ │ │ ├── MenuDTO.java │ │ │ │ │ ├── LoginOutpDTO.java │ │ │ │ │ ├── TreeNodeDTO.java │ │ │ │ │ └── LoginUserDTO.java │ │ │ │ └── service │ │ │ │ │ ├── MenuRightService.java │ │ │ │ │ ├── RoleService.java │ │ │ │ │ ├── UserService.java │ │ │ │ │ └── impl │ │ │ │ │ └── MenuRightServiceImpl.java │ │ │ │ ├── NoWarnMapper.java │ │ │ │ └── log │ │ │ │ ├── dao │ │ │ │ └── SysLogMapper.java │ │ │ │ ├── dto │ │ │ │ ├── SysLogInputDTO.java │ │ │ │ ├── SysLogExportDTO.java │ │ │ │ └── SysLogOutpDTO.java │ │ │ │ ├── service │ │ │ │ ├── SysLogService.java │ │ │ │ └── impl │ │ │ │ │ └── SysLogServiceImpl.java │ │ │ │ └── domain │ │ │ │ └── SysLog.java │ │ └── resources │ │ │ └── mapper │ │ │ ├── user │ │ │ ├── UserAndRoleMapper.xml │ │ │ ├── RoleAndMenuMapper.xml │ │ │ ├── MenuRightMapper.xml │ │ │ ├── RoleMapper.xml │ │ │ └── UserMapper.xml │ │ │ └── log │ │ │ └── SysLogMapper.xml │ └── test │ │ └── resources │ │ ├── generator │ │ └── template │ │ │ ├── simpleDict │ │ │ ├── service.ftl │ │ │ ├── service-impl.ftl │ │ │ └── controller.ftl │ │ │ ├── default │ │ │ ├── service.ftl │ │ │ ├── service-impl.ftl │ │ │ └── controller.ftl │ │ │ └── controller-restful.ftl │ │ ├── template.sql │ │ └── demo-user.sql └── pom.xml ├── security ├── src │ └── main │ │ └── java │ │ └── com │ │ └── example │ │ └── janche │ │ └── security │ │ ├── ignore │ │ ├── CustomConfig.java │ │ └── IgnoreConfig.java │ │ ├── hadler │ │ ├── SecurityAccessDeniedHandler.java │ │ ├── SecurityAuthenticationEntryPoint.java │ │ ├── SecurityLogoutSuccessHandler.java │ │ ├── SecurityAuthenticationFailureHandler.java │ │ └── UserLoginSuccessHandler.java │ │ ├── service │ │ └── SecurityUserService.java │ │ ├── authentication │ │ └── SecurityUser.java │ │ ├── utils │ │ ├── SecurityUtils.java │ │ └── ResponseUtils.java │ │ ├── manager │ │ └── UrlAccessDecisionManager.java │ │ ├── provider │ │ └── SecurityAuthenticationProvider.java │ │ └── metadatasource │ │ └── UrlFilterInvocationSecurityMetadataSource.java └── pom.xml ├── swagger ├── src │ └── main │ │ └── java │ │ └── com │ │ └── example │ │ └── janche │ │ └── swagger │ │ ├── SwaggerProperties.java │ │ └── SwaggerConfig.java └── pom.xml ├── log4cxx.properties └── README.md /web/src/main/resources/static/css/login.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: dev 4 | -------------------------------------------------------------------------------- /web/src/main/resources/xlsx_template/导出模板.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janche/springboot-security-project/HEAD/web/src/main/resources/xlsx_template/导出模板.xls -------------------------------------------------------------------------------- /web/src/main/resources/xlsx_template/日志导出模板.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janche/springboot-security-project/HEAD/web/src/main/resources/xlsx_template/日志导出模板.xls -------------------------------------------------------------------------------- /web/src/main/resources/xlsx_template/设备导入模板.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janche/springboot-security-project/HEAD/web/src/main/resources/xlsx_template/设备导入模板.xls -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/config/IApplicationConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.config; 2 | 3 | public interface IApplicationConfig { 4 | String[] getOrigins(); 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---> Java 2 | # Compiled class file 3 | *.class 4 | 5 | # Log file 6 | *.log 7 | 8 | # Package Files # 9 | *.war 10 | *.ear 11 | *.zip 12 | *.tar.gz 13 | *.rar 14 | 15 | /target 16 | /log 17 | 18 | ### IntelliJ IDEA ### 19 | .idea 20 | *.iws 21 | *.iml 22 | *.ipr 23 | 24 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dao/RoleAndMenuMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dao; 2 | 3 | import com.example.janche.common.core.TkMapper; 4 | import com.example.janche.user.domain.RoleAndMenu; 5 | 6 | public interface RoleAndMenuMapper extends TkMapper { 7 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dao/UserAndRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dao; 2 | 3 | import com.example.janche.common.core.TkMapper; 4 | import com.example.janche.user.domain.UserAndRole; 5 | 6 | public interface UserAndRoleMapper extends TkMapper { 7 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/NoWarnMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche; 2 | 3 | 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | /** 7 | * @author lirong 8 | * @ClassName: NoWarnMapper 9 | * @Description: 为了消除启动时mybatis的警告 10 | * @date 2019-07-24 15:06 11 | */ 12 | @Mapper 13 | public interface NoWarnMapper { 14 | } 15 | -------------------------------------------------------------------------------- /web/src/main/resources/resources/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 500 6 | 7 | 8 | 异常处理第一种方式:改变浏览器访问接口时产生的异常信息 根据http状态码返回响应的html
9 | 状态码参考:HttpStatus
10 | 500错误的响应页面,必须在reources/reources/error/xxx.html 创建对应状态码页面
11 | 默认异常处理参考:BasicErrorController
12 | 13 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/core/Mapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.core; 2 | 3 | import tk.mybatis.mapper.common.*; 4 | 5 | /** 6 | *

7 | * 8 | * @author lirong 9 | * @version v1.0 10 | * @since 2018/1/25 11:45 11 | */ 12 | public interface Mapper extends 13 | BaseMapper, 14 | MySqlMapper, 15 | IdsMapper, 16 | ConditionMapper, 17 | ExampleMapper{ 18 | } 19 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dao/RoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dao; 2 | 3 | import com.example.janche.common.core.Mapper; 4 | import com.example.janche.user.domain.Role; 5 | import com.example.janche.user.dto.role.RoleDTO; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | public interface RoleMapper extends Mapper { 9 | 10 | /** 11 | * 获取所有角色信息与权限 12 | * @return ArrayList 角色信息集合 13 | */ 14 | RoleDTO getMenusByRoleId(@Param("id") Long id); 15 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dao/MenuRightMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dao; 2 | 3 | import com.example.janche.common.core.Mapper; 4 | import com.example.janche.user.domain.MenuRight; 5 | import com.example.janche.user.dto.MenuDTO; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | import java.util.List; 9 | 10 | public interface MenuRightMapper extends Mapper { 11 | List getAllMenus(); 12 | 13 | List getUserMenus(@Param("userId") Long userId); 14 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dao/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dao; 2 | 3 | import com.example.janche.common.core.Mapper; 4 | import com.example.janche.user.domain.User; 5 | import com.example.janche.user.dto.user.UserDTO; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | public interface UserMapper extends Mapper { 9 | /** 10 | * 根据用户名获取权限 11 | * @param username 12 | * @return 13 | */ 14 | UserDTO getRolesByUsername(@Param("username") String username); 15 | } -------------------------------------------------------------------------------- /backend/src/main/resources/mapper/user/UserAndRoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/model/Constant.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.model; 2 | 3 | /** 4 | * 常量 5 | */ 6 | public interface Constant { 7 | 8 | /** 9 | * 时间格式化 10 | */ 11 | String DATE_FORMATTER_TIME = "YYYY-MM-dd HH:mm:ss"; 12 | String DATE_FORMATTER_DATE = "YYYY-MM-dd"; 13 | 14 | /** 15 | * 公共状态: 启用、未启用 16 | */ 17 | int STATUS_ENABLE = 1; 18 | int STATUS_DISABLE = 0; 19 | 20 | String RESET_PASSWORD = "123456"; 21 | 22 | String ADMIN_NAME = "超级管理员"; 23 | 24 | String ROLE_ADMIN = "ROLE_超级管理员"; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /backend/src/main/resources/mapper/user/RoleAndMenuMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /web/src/main/resources/static/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 登录 6 | 7 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/core/TkMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.core; 2 | 3 | import tk.mybatis.mapper.additional.insert.InsertListMapper; 4 | import tk.mybatis.mapper.common.BaseMapper; 5 | import tk.mybatis.mapper.common.ConditionMapper; 6 | import tk.mybatis.mapper.common.ExampleMapper; 7 | 8 | /** 9 | *

10 | * 11 | * @author lirong 12 | * @version v1.0 13 | * @since 2018/1/25 11:45 14 | */ 15 | public interface TkMapper extends 16 | BaseMapper, 17 | InsertListMapper, 18 | ConditionMapper, 19 | ExampleMapper{ 20 | } 21 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/ignore/CustomConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.ignore; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | * @author lirong 9 | * @ClassName: CustomConfig 10 | * @Description: 自定义的配置 11 | * @date 2019-07-29 17:06 12 | */ 13 | @Configuration 14 | @ConfigurationProperties(prefix = "custom.config") 15 | @Data 16 | public class CustomConfig { 17 | /** 18 | * 不需要拦截的地址 19 | */ 20 | private IgnoreConfig ignores; 21 | } 22 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/domain/UserAndRole.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.Table; 10 | import java.io.Serializable; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Builder 16 | @Table(name = "user_role") 17 | public class UserAndRole implements Serializable { 18 | 19 | @Column(name = "role_id") 20 | private Long roleId; 21 | 22 | @Column(name = "user_id") 23 | private Long userId; 24 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/role/RoleConditionDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.role; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | /** 8 | * @author lirong 9 | * @ClassName: RoleConditionDTO 10 | * @Description: 角色筛选条件 11 | * @date 2019-07-25 10:43 12 | */ 13 | @Data 14 | @ApiModel(value="RoleConditionDTO",description="角色筛选条件") 15 | public class RoleConditionDTO { 16 | 17 | @ApiModelProperty(value="角色名称") 18 | private String name; 19 | 20 | @ApiModelProperty(value="启用状态(0-禁用,1-启用)") 21 | private Integer status; 22 | } 23 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/log/dao/SysLogMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.log.dao; 2 | 3 | import com.example.janche.common.core.Mapper; 4 | import com.example.janche.log.domain.SysLog; 5 | import com.example.janche.log.dto.SysLogExportDTO; 6 | import com.example.janche.log.dto.SysLogInputDTO; 7 | import com.example.janche.log.dto.SysLogOutpDTO; 8 | import org.apache.ibatis.annotations.Param; 9 | 10 | import java.util.List; 11 | 12 | public interface SysLogMapper extends Mapper { 13 | List selectLogByQuery(@Param("dto") SysLogInputDTO inputDTO); 14 | 15 | List exportLogList(@Param("dto") SysLogInputDTO inputDTO); 16 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/user/UserPwdDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.user; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | /** 8 | * @author lirong 9 | * @ClassName: UserPwdDTO 10 | * @Description: 用户密码DTO 11 | * @date 2019-07-25 15:36 12 | */ 13 | @Data 14 | @ApiModel(value="UserPwdDTO",description="用户密码类") 15 | public class UserPwdDTO { 16 | 17 | @ApiModelProperty(value="主键ID") 18 | private Long id; 19 | 20 | @ApiModelProperty(value="旧密码") 21 | private String password; 22 | 23 | @ApiModelProperty(value="新密码") 24 | private String newPassword; 25 | } 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/user/UserConditionDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.user; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | /** 8 | * @author lirong 9 | * @ClassName: UserConditionDTO 10 | * @Description: 用户列表筛选条件 11 | * @date 2019-07-25 10:06 12 | */ 13 | @Data 14 | @ApiModel(value="UserConditionDTO",description="用户筛选条件") 15 | public class UserConditionDTO { 16 | 17 | @ApiModelProperty(value="用户名") 18 | private String username; 19 | 20 | @ApiModelProperty(value="真实姓名") 21 | private String actualName; 22 | 23 | @ApiModelProperty(value="账号状态") 24 | private Integer status; 25 | } 26 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/domain/RoleAndMenu.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.Table; 10 | import java.io.Serializable; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Builder 16 | @Table(name = "role_right") 17 | public class RoleAndMenu implements Serializable { 18 | /** 19 | * 角色id 20 | */ 21 | @Column(name = "role_id") 22 | private Long roleId; 23 | 24 | /** 25 | * 菜单id 26 | */ 27 | @Column(name = "menu_id") 28 | private Long menuId; 29 | 30 | 31 | } -------------------------------------------------------------------------------- /backend/src/test/resources/generator/template/simpleDict/service.ftl: -------------------------------------------------------------------------------- 1 | package ${modulePackage}.${moduleName}.service; 2 | 3 | import ${modulePackage}.${moduleName}.domain.${modelNameUpperCamel}; 4 | import ${basePackage}.common.core.Service; 5 | import ${basePackage}.common.restResult.PageParam; 6 | import java.util.List; 7 | 8 | /** 9 | * @author ${author} 10 | * @Description: // TODO 为类添加注释 11 | * @date ${date} 12 | */ 13 | public interface ${modelNameUpperCamel}Service extends Service<${modelNameUpperCamel}> { 14 | 15 | /** 16 | * 根据分页、排序信息和检索条件查询 @size 条 字典表数据 17 | * @param pageParam 分页参数 18 | * @param query 查询关键字 19 | * @return 20 | */ 21 | List<${modelNameUpperCamel}> list(PageParam pageParam, String query); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/util/DateUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.util; 2 | 3 | import org.apache.commons.lang3.time.DateFormatUtils; 4 | 5 | /** 6 | * Class description 7 | * 日期格式化 8 | * @version 1.0, 18/09/22 9 | * @author pitt 10 | */ 11 | public class DateUtils extends DateFormatUtils { 12 | 13 | /** 14 | * 自定义日期格式 15 | * 使用方法: DateFormatUtils.format(new Date(), DateUtils.DATE_AND_HOURS_PATTERN)) 16 | * 年月日-时分秒 17 | */ 18 | public static final String DATE_AND_HOURS_PATTERN = "yyyy-MM-dd HH:mm:ss"; 19 | 20 | /** 21 | * 年月日 22 | * */ 23 | public static final String DATE_PATTERN = "yyyy-MM-dd"; 24 | 25 | /** 26 | * 还缺少时间的加减运算,后面添加 27 | * */ 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /swagger/src/main/java/com/example/janche/swagger/SwaggerProperties.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.swagger; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | 8 | /** 9 | * SwaggerProperties 10 | * 11 | * @author lirong 12 | * @date 2018/09/ 13 | */ 14 | @ConfigurationProperties("swagger") 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class SwaggerProperties { 19 | 20 | private String title; 21 | private String basepackage; 22 | private String version; 23 | private String contractName; 24 | private String description; 25 | private String contractUrl; 26 | private String contractEmail; 27 | 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/log/dto/SysLogInputDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.log.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author lirong 9 | * @ClassName: SysLogInputDTO 10 | * @Description: TODO 11 | * @date 2018-12-07 9:38 12 | */ 13 | @Data 14 | public class SysLogInputDTO implements Serializable { 15 | 16 | /** 17 | * 日志详情 18 | */ 19 | private String logDesc; 20 | 21 | /** 22 | * 操作人员 23 | */ 24 | private String logType; 25 | 26 | /** 27 | * 操作类型 28 | */ 29 | private String operation; 30 | 31 | /** 32 | * 开始时间 33 | */ 34 | private String startTime; 35 | 36 | /** 37 | * 结束时间 38 | */ 39 | private String endTime; 40 | } 41 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/log/dto/SysLogExportDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.log.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.Date; 7 | 8 | /** 9 | * @author lirong 10 | * @ClassName: ExportOutpDTO 11 | * @Description: 导出实体类 12 | * @date 2018-12-07 15:20 13 | */ 14 | @Data 15 | public class SysLogExportDTO implements Serializable { 16 | private Long id; 17 | 18 | /** 19 | * 操作类型: 添加-1 删除-2 更新-3 查看-4 20 | */ 21 | private String operation; 22 | 23 | /** 24 | * 操作人员名称 25 | */ 26 | private String username; 27 | 28 | /** 29 | * 日志描述 30 | */ 31 | private String logDesc; 32 | 33 | /** 34 | * 创建时间 35 | */ 36 | private Date createTime; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/role/RoleDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.role; 2 | 3 | import com.example.janche.user.domain.MenuRight; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.io.Serializable; 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Data 17 | @Builder 18 | public class RoleDTO implements Serializable { 19 | private Long id; 20 | private String name; 21 | private Integer seq; 22 | private String description; 23 | private Integer status; 24 | private Date createTime; 25 | private Date modifyTime; 26 | 27 | private List menus; 28 | } 29 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/MenuDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto; 2 | 3 | import com.example.janche.user.domain.Role; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | * @author lirong 11 | * @ClassName: MenuDTO 12 | * @Description: 前端展示的菜单 13 | * @date 2018-12-14 11:16 14 | */ 15 | @Data 16 | public class MenuDTO implements Serializable { 17 | 18 | private Long id; 19 | 20 | private Long parentId; 21 | 22 | private String name; 23 | 24 | private Integer seq; 25 | 26 | private String url; 27 | 28 | private Integer status; 29 | 30 | private String icon; 31 | 32 | private String method; 33 | 34 | private Integer grades; 35 | 36 | private List roles; 37 | } 38 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/restResult/ResultGenerator.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.restResult; 2 | 3 | /** 4 | * lirong 5 | */ 6 | public class ResultGenerator { 7 | 8 | public static RestResult genSuccessResult() { 9 | return new RestResult(ResultCode.SUCCESS); 10 | } 11 | 12 | public static RestResult genSuccessResult(T data) { 13 | 14 | return new RestResult(200, "SUCCESS", data); 15 | } 16 | 17 | public static RestResult genFailResult(String message) { 18 | return new RestResult(ResultCode.FAIL.getCode(), message); 19 | } 20 | 21 | /** 22 | * 未验证error 构造器 23 | * @return 24 | */ 25 | public static RestResult genUnauthResult() { 26 | return new RestResult(ResultCode.UNAUTHORIZED); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | springboot-security-project 7 | com.example.janche 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | common 13 | 14 | 15 | 16 | com.example.janche 17 | swagger 18 | 0.0.1-SNAPSHOT 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/aop/Log.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.aop; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * log annotation 10 | *

11 | * use:在方法上打上 @Log("log的描述") 12 | * 在控制台看到对应数据,后面改为入库操作 13 | */ 14 | @Target(ElementType.METHOD) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Log { 17 | /** 18 | * 增1 删2 改3 查4 登陆5 登出6 导入7 导出8, 默认0 19 | */ 20 | int value() default 0; 21 | 22 | /** 23 | * 操作模块类型 24 | * 1: "首页" 25 | * 2: "系统管理" 26 | * 7: "系统管理" 27 | * 8: "运维管理" 28 | */ 29 | int type() default 1; 30 | 31 | /** 32 | * 接口的描述 33 | */ 34 | String description() default "XXX方法"; 35 | } 36 | -------------------------------------------------------------------------------- /swagger/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | springboot-security-project 7 | com.example.janche 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | swagger 13 | 14 | 15 | 16 | com.github.xiaoymin 17 | knife4j-spring-boot-starter 18 | 2.0.5 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /web/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BRIGHT_CYAN} 2 | _ooOoo_ 3 | o8888888o 4 | 88" . "88 5 | (| -_- |) 6 | O\ = /O 7 | ____/`---'\____ 8 | .' \\| |// `. 9 | / \\||| : |||// \ 10 | / _||||| -:- |||||- \ 11 | | | \\\ - /// | | 12 | | \_| ''\---/'' | | 13 | \ .-\__ `-` ___/-. / 14 | ___`. .' /--.--\ `. . __ 15 | ."" '< `.___\_<|>_/___.' >'"". 16 | | | : `- \`.;`\ _ /`;.`/ - ` : | | 17 | \ \ `-. \_ __\ /__ _/ .-` / / 18 | ======`-.____`-.___\_____/___.-`____.-'====== 19 | `=---=' 20 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 21 | 佛祖保佑 永不宕机 永无BUG 22 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 23 | SpringBoot : ${spring-boot.version} -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/exception/CustomException.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.exception; 2 | 3 | import com.example.janche.common.restResult.ResultCode; 4 | import lombok.Data; 5 | 6 | /** 7 | * 自定义异常 8 | */ 9 | @Data 10 | public class CustomException extends RuntimeException { 11 | 12 | private Integer code; 13 | 14 | private ResultCode resultCode; 15 | 16 | public CustomException(){ 17 | } 18 | 19 | public CustomException(ResultCode resultCode){ 20 | super(resultCode.getMessage()); 21 | this.code = resultCode.getCode(); 22 | this.resultCode = resultCode; 23 | } 24 | 25 | 26 | public CustomException(Integer code, String message) { 27 | super(message); 28 | this.code = code; 29 | } 30 | 31 | public CustomException(String message, Throwable cause) { 32 | super(message, cause); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /web/src/main/resources/application-sysconfig.yml: -------------------------------------------------------------------------------- 1 | janche: 2 | # 跨域ip处理 3 | origins: 4 | - http://localhost:8080 5 | - http://192.168.1.202:8080 6 | - http://127.0.0.1:8080 7 | 8 | #=============日志操作类型============== 9 | logOperation: 10 | 1: "新增" 11 | 2: "删除" 12 | 3: "修改" 13 | 4: "查看" 14 | 5: "登录" 15 | 6: "退出" 16 | 7: "导出" 17 | 8: "导入" 18 | 19 | custom: 20 | config: 21 | ignores: 22 | # 需要过滤的 post 请求 23 | post: 24 | - "/refresh/token" 25 | # options的请求不拦截 26 | options: 27 | - "/**" 28 | # 需要过滤的请求,不限方法 29 | pattern: 30 | # 配置 不拦截 的请求,测试可以配置 /** 31 | - "/swagger-ui.html" 32 | - "/v2/**" 33 | - "/webjars/**" 34 | - "/swagger-resources/**" 35 | - "/doc.html" 36 | 37 | # 热部署插件指定端口,具体视自己情况而定,只要不重复就可以,默认是35729 38 | spring: 39 | devtools: 40 | livereload: 41 | port: 35730 42 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/model/ProjectPath.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.model; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.util.ResourceUtils; 6 | 7 | import java.io.File; 8 | import java.io.FileNotFoundException; 9 | 10 | /** 11 | * 项目路径 12 | *

文件上传下载获取项目路径

13 | */ 14 | public class ProjectPath { 15 | private static final Logger logger = LoggerFactory.getLogger(ProjectPath.class); 16 | 17 | /** 18 | * 获取根目录 19 | */ 20 | public static String getProjectAbsolutPath() { 21 | File path = null; 22 | try { 23 | path = new File(ResourceUtils.getURL("classpath:").getPath()); 24 | } catch (FileNotFoundException e) { 25 | e.printStackTrace(); 26 | logger.error("获取项目路径失败"); 27 | } 28 | if (!path.exists()) path = new File(""); 29 | return path.getAbsolutePath(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /backend/src/test/resources/generator/template/default/service.ftl: -------------------------------------------------------------------------------- 1 | package ${modulePackage}.${moduleName}.service; 2 | 3 | import ${modulePackage}.${moduleName}.domain.${modelNameUpperCamel}; 4 | import ${basePackage}.common.core.Service; 5 | import java.util.List; 6 | 7 | /** 8 | * 9 | * @author ${author} 10 | * @date ${date} 11 | */ 12 | public interface ${modelNameUpperCamel}Service extends Service<${modelNameUpperCamel}> { 13 | 14 | /** 15 | * 根据分页、排序信息和检索条件查询 @size 条 字典表数据 16 | * 17 | * @param page 第几页 18 | * @param size 每页有多少记录 19 | * @param sortField 排序字段 20 | * @param sortOrder 升序or降序 21 | * @param query 查询关键字 22 | * @return 23 | */ 24 | List<${modelNameUpperCamel}> search(Integer page, 25 | Integer size, 26 | String sortField, 27 | String sortOrder, 28 | String query); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/restResult/PageParam.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.restResult; 2 | 3 | import com.example.janche.common.utils.CoreUtils; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * @author lirong 10 | * @ClassName: PageParam 11 | * @Description: 分页信息的封装 12 | * @date 2018-11-02 10:28 13 | */ 14 | @Data 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class PageParam { 18 | 19 | /** 20 | * 当前页码 21 | */ 22 | private Integer page = 1; 23 | 24 | /** 25 | * 每页尺寸 26 | */ 27 | private Integer size = 10; 28 | 29 | /** 30 | * 排序字段,默认使用ID来排序 31 | */ 32 | private String sortField = "id"; 33 | 34 | /** 35 | * 排序方式,默认升序 36 | */ 37 | private String sortOrder = "DESC"; 38 | 39 | public String getOrderBy(){ 40 | return CoreUtils.getOrderBy(sortField, sortOrder); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/util/EntityUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.util; 2 | 3 | import org.springframework.beans.BeanWrapper; 4 | import org.springframework.beans.BeanWrapperImpl; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * @ClassName EntityUtil 11 | * @Description 实体工具类 12 | * @Author Wwei 13 | */ 14 | public class EntityUtil { 15 | 16 | // 获取类中为null的属性名 17 | public static String[] getNullPropertyNames (Object source) { 18 | final BeanWrapper src = new BeanWrapperImpl(source); 19 | java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); 20 | 21 | Set emptyNames = new HashSet(); 22 | for(java.beans.PropertyDescriptor pd : pds) { 23 | Object srcValue = src.getPropertyValue(pd.getName()); 24 | if (srcValue == null) emptyNames.add(pd.getName()); 25 | } 26 | String[] result = new String[emptyNames.size()]; 27 | return emptyNames.toArray(result); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/role/RoleOutpDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.role; 2 | 3 | import com.example.janche.user.dto.TreeNodeDTO; 4 | import lombok.Data; 5 | 6 | import java.util.Date; 7 | import java.util.List; 8 | 9 | /** 10 | * @author lirong 11 | * @ClassName: RoleOutpDTO 12 | * @Description: TODO 13 | * @date 2019-07-24 15:30 14 | */ 15 | @Data 16 | public class RoleOutpDTO { 17 | /** 18 | * Id 19 | */ 20 | private Long id; 21 | 22 | /** 23 | * 角色描述 24 | */ 25 | private String description; 26 | 27 | /** 28 | * 角色名称 29 | */ 30 | private String name; 31 | 32 | /** 33 | * 排序号 34 | */ 35 | private Integer seq; 36 | 37 | /** 38 | * 启用状态(0-禁用,1-启用) 39 | */ 40 | private Integer status; 41 | 42 | /** 43 | * 创建时间 44 | */ 45 | private Date createTime; 46 | 47 | /** 48 | * 修改时间 49 | */ 50 | private Date modifyTime; 51 | 52 | /** 53 | * 权限树 54 | */ 55 | private List menus; 56 | } 57 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/model/ProjectConstant.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.model; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * 项目常量 7 | */ 8 | @Slf4j 9 | public final class ProjectConstant { 10 | 11 | /** 12 | * 项目基础包名称 13 | */ 14 | public static final String BASE_PACKAGE = "com.example.janche"; 15 | /** 16 | * Model所在包 17 | */ 18 | public static final String MODEL_PACKAGE = BASE_PACKAGE + ".*.*.domain"; 19 | /** 20 | * DAO所在包 21 | */ 22 | public static final String DAO_PACKAGE = BASE_PACKAGE + ".*.dao"; 23 | public static final String MAPPER_XML_PACKAGE = "classpath:mapper/*/*.xml"; 24 | public static final String SERVICE_PACKAGE = BASE_PACKAGE + ".*.*.service"; 25 | public static final String SERVICE_IMPL_PACKAGE = SERVICE_PACKAGE + ".impl"; 26 | public static final String CONTROLLER_PACKAGE = BASE_PACKAGE + ".*.*.controller"; 27 | /** 28 | * Mapper插件基础接口的完全限定名 29 | */ 30 | public static final String MAPPER_INTERFACE_REFERENCE = BASE_PACKAGE + ".common.core.Mapper"; 31 | } 32 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/controller/config/ApplicationConfigController.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.controller.config; 2 | 3 | import com.example.janche.common.restResult.RestResult; 4 | import com.example.janche.common.restResult.ResultGenerator; 5 | import com.example.janche.common.config.ApplicationConfig; 6 | import com.example.janche.web.aop.Log; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | /** 13 | * @Auther: LiaoPeng 14 | * @Date: 2018/11/20 15 | */ 16 | @RestController 17 | @RequestMapping("/config") 18 | public class ApplicationConfigController { 19 | 20 | @Autowired 21 | ApplicationConfig applicationConfig; 22 | /** 23 | * 返回配置信息 24 | */ 25 | @Log(description = "获取配置信息", value = 4, type = 1) 26 | @GetMapping(value = "/info") 27 | public RestResult info() { 28 | return ResultGenerator.genSuccessResult(applicationConfig); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/role/RoleInputDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.role; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * @author lirong 11 | * @ClassName: RoleInputDTO 12 | * @Description: 角色输入实体类 13 | * @date 2019-07-24 15:29 14 | */ 15 | @Data 16 | @ApiModel(value="RoleInputDTO",description="角色输入类") 17 | public class RoleInputDTO { 18 | 19 | @ApiModelProperty(value="主键ID, 新增不传值, 修改传值") 20 | private Long id; 21 | 22 | @ApiModelProperty(value="角色描述") 23 | private String description; 24 | 25 | @ApiModelProperty(value="角色名称") 26 | private String name; 27 | 28 | @ApiModelProperty(value="排序号") 29 | private Integer seq; 30 | 31 | @ApiModelProperty(value="启用状态(0-禁用,1-启用)") 32 | private Integer status; 33 | 34 | @ApiModelProperty(value="创建时间") 35 | private Date createTime; 36 | 37 | @ApiModelProperty(value="修改时间") 38 | private Date modifyTime; 39 | 40 | @ApiModelProperty(value="权限ID集合") 41 | private String menuIds; 42 | } 43 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/LoginOutpDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto; 2 | 3 | import com.example.janche.user.domain.MenuRight; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author lirong 10 | * @ClassName: LoginOutpDTO 11 | * @Description: TODO 12 | * @date 2019-08-15 15:39 13 | */ 14 | @Data 15 | public class LoginOutpDTO { 16 | 17 | /** 18 | * 主键ID 19 | */ 20 | private Long id; 21 | 22 | /** 23 | * 用户名 24 | */ 25 | private String username; 26 | 27 | /** 28 | * 真实姓名 29 | */ 30 | private String actualName; 31 | 32 | /** 33 | * 性别 34 | */ 35 | private int sex; 36 | 37 | /** 38 | * 电话 39 | */ 40 | private String phone; 41 | 42 | /** 43 | * 邮箱 44 | */ 45 | private String email; 46 | 47 | /** 48 | * 地址 49 | */ 50 | private String address; 51 | 52 | /** 53 | * 职务Id 54 | */ 55 | private Integer postId; 56 | 57 | /** 58 | * 职务名称 59 | */ 60 | private String postName; 61 | 62 | /** 63 | * 前端需要显示的菜单 64 | */ 65 | private List menus; 66 | } 67 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/log/service/SysLogService.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.log.service; 2 | 3 | import com.example.janche.log.domain.SysLog; 4 | import com.example.janche.common.core.Service; 5 | import com.example.janche.common.restResult.PageParam; 6 | import com.example.janche.log.dto.SysLogInputDTO; 7 | import com.example.janche.log.dto.SysLogOutpDTO; 8 | import org.springframework.http.ResponseEntity; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @author lirong 14 | * @Description: // TODO 为类添加注释 15 | * @date 2018-12-05 03:21:19 16 | */ 17 | public interface SysLogService extends Service { 18 | 19 | /** 20 | * 根据分页、排序信息和检索条件查询 @size 条 字典表数据 21 | * @param pageParam 分页参数 22 | * @param inputDTO 查询关键字 23 | * @return 24 | */ 25 | List list(PageParam pageParam, SysLogInputDTO inputDTO); 26 | 27 | /** 28 | * 保存日志 29 | */ 30 | void saveLog(SysLog sysLog); 31 | 32 | /** 33 | * 删除日志 34 | */ 35 | void deleteById(String ids); 36 | 37 | /** 38 | * 分页导出日志 39 | * @param inputDTO 40 | * @return 41 | */ 42 | ResponseEntity exportLogList(SysLogInputDTO inputDTO); 43 | } 44 | -------------------------------------------------------------------------------- /security/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | springboot-security-project 7 | com.example.janche 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | security 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-security 17 | 18 | 19 | io.jsonwebtoken 20 | jjwt 21 | 0.9.0 22 | 23 | 24 | com.example.janche 25 | backend 26 | 0.0.1-SNAPSHOT 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /backend/src/test/resources/template.sql: -------------------------------------------------------------------------------- 1 | # 根据账号查询用户的信息 2 | 3 | SELECT 4 | u.id u_id, 5 | u.org_id u_org_Id, 6 | u.account, 7 | u.username, 8 | u.staff_id u_staff_id, 9 | u.staff_type u_staff_type, 10 | u.staff_position u_staff_position, 11 | u.staff_title u_staff_title, 12 | u.tel, 13 | u.email, 14 | u.status u_status, 15 | u.description u_description, 16 | u.gmt_create u_gmt_create, 17 | r.id r_id, 18 | r.name r_name, 19 | r.org_id r_org_id, 20 | r.description r_description, 21 | r.gmt_create r_gmt_create, 22 | 23 | p.id p_id, 24 | p.org_id p_org_id, 25 | p.name p_name, 26 | p.url url, 27 | p.per_type p_type, 28 | p.menu_sort p_menu_sort, 29 | p.parent_id p_parent_id, 30 | p.available p_available, 31 | p.gmt_create p_gmt_create 32 | FROM sys_user AS u 33 | LEFT JOIN sys_user_role AS ur ON u.id = ur.uid 34 | LEFT JOIN sys_role AS r ON r.id = ur.rid 35 | LEFT JOIN sys_role_permission AS rp ON r.id = rp.rid 36 | LEFT JOIN sys_permission AS p ON rp.pid = p.id 37 | WHERE u.account = 'admin' and p.per_type='menu' 38 | ORDER BY p.parent_id , p.menu_sort -------------------------------------------------------------------------------- /backend/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | springboot-security-project 7 | com.example.janche 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | backend 13 | jar 14 | 15 | 16 | mysql 17 | mysql-connector-java 18 | runtime 19 | 20 | 21 | com.example.janche 22 | common 23 | 0.0.1-SNAPSHOT 24 | 25 | 26 | 27 | org.springframework.security 28 | spring-security-crypto 29 | 5.1.2.RELEASE 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/domain/Role.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.domain; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import javax.persistence.*; 11 | import java.io.Serializable; 12 | import java.util.Date; 13 | 14 | @Data 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | @Builder 18 | @Table(name = "role") 19 | @ApiModel(value="Role",description="角色实体类") 20 | public class Role implements Serializable { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | @ApiModelProperty(value="角色主键ID") 25 | private Long id; 26 | 27 | @ApiModelProperty(value="角色名称") 28 | private String name; 29 | 30 | @ApiModelProperty(value="角色描述") 31 | private String description; 32 | 33 | @ApiModelProperty(value="排序") 34 | private Integer seq; 35 | 36 | @ApiModelProperty(value="状态:0-禁用,1-启用") 37 | private Integer status; 38 | 39 | @Column(name = "create_time") 40 | @ApiModelProperty(value="创建时间") 41 | private Date createTime; 42 | 43 | @Column(name = "modify_time") 44 | @ApiModelProperty(value="修改时间") 45 | private Date modifyTime; 46 | } -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/hadler/SecurityAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.hadler; 2 | 3 | import com.example.janche.common.config.IApplicationConfig; 4 | import com.example.janche.common.restResult.ResultCode; 5 | import com.example.janche.security.utils.ResponseUtils; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.security.access.AccessDeniedException; 9 | import org.springframework.security.web.access.AccessDeniedHandler; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | 15 | /** 16 | * 用户访问没有权限资源的处理 17 | * @author lirong 18 | * @date 19 | */ 20 | 21 | @Component("securityAccessDeniedHandler") 22 | @Slf4j 23 | public class SecurityAccessDeniedHandler implements AccessDeniedHandler { 24 | @Autowired 25 | private IApplicationConfig applicationConfig; 26 | @Override 27 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) { 28 | log.info(request.getRequestURL()+"没有权限"); 29 | ResponseUtils.renderJson(request, response, ResultCode.LIMITED_AUTHORITY, applicationConfig.getOrigins()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/mybatis/handler/EmptyStringIfNullHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.mybatis.handler; 2 | 3 | import org.apache.ibatis.type.JdbcType; 4 | import org.apache.ibatis.type.TypeHandler; 5 | 6 | import java.sql.CallableStatement; 7 | import java.sql.PreparedStatement; 8 | import java.sql.ResultSet; 9 | import java.sql.SQLException; 10 | 11 | /** 12 | * @author lirong 13 | * @version v1.0 14 | * @since 2018/08/20 12:45 15 | */ 16 | public class EmptyStringIfNullHandler implements TypeHandler { 17 | @Override 18 | public String getResult(ResultSet rs, String columnName) throws SQLException { 19 | return (rs.getString(columnName) == null) ? "" : rs.getString(columnName); 20 | } 21 | 22 | @Override 23 | public String getResult(ResultSet rs, int columnIndex) throws SQLException { 24 | return (rs.getString(columnIndex) == null) ? "" : rs.getString(columnIndex); 25 | } 26 | @Override 27 | public String getResult(CallableStatement cs, int columnIndex) throws SQLException { 28 | return (cs.getString(columnIndex) == null) ? "" : cs.getString(columnIndex); 29 | } 30 | @Override 31 | public void setParameter(PreparedStatement ps, int arg1, String str, JdbcType jdbcType) throws SQLException { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/TreeNodeDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * @author lirong 13 | * @ClassName: TreeNodeDTO 14 | * @Description: 树节点 15 | * @date 2019-7-24 17:03:22 16 | */ 17 | @Data 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | public class TreeNodeDTO implements Serializable, Comparable { 21 | 22 | private Long id; 23 | private Long parentId; 24 | private String name; 25 | private Boolean checked; 26 | private List children = new ArrayList<>(); 27 | 28 | public void add(TreeNodeDTO node) { 29 | //递归添加节点 30 | if (0 == node.parentId) { 31 | this.children.add(node); 32 | } else if (node.parentId.equals(this.id)) { 33 | this.children.add(node); 34 | } else { 35 | // 递归 36 | for (TreeNodeDTO tmp_node : children) { 37 | tmp_node.add(node); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * 按照 ID 排序 44 | */ 45 | @Override 46 | public int compareTo(TreeNodeDTO o) { 47 | return this.getId().compareTo(o.getId()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /log4cxx.properties: -------------------------------------------------------------------------------- 1 | #\u7F3A\u7701\u4E0D\u8F93\u51FA\u65E5\u5FD7\u5230\u63A7\u5236\u53F0 2 | #FATAL\u3001ERROR\u3001WARN\u3001INFO\u3001DEBUG \u4F18\u5148\u7EA7\u987A\u5E8F \u5982\u679C\u5B50\u6A21\u5757\u548C\u6839\u6A21\u5757\u90FD\u5339\u914D\uFF0C\u90A3\u4E48\u90FD\u4F1A\u8F93\u51FA 3 | log4j.rootLogger=DEBUG, stdout 4 | #log4j.rootLogger=DEBUG 5 | ##hlog.async=false 6 | ##hlog.secret.show=true 7 | ##hlog.secret.encrypt=false 8 | #log4j.logger\u7528\u4E8E\u63A7\u5236\u65E5\u5FD7\u91C7\u96C6\u7EA7\u522B\u53CA\u91C7\u96C6\u5185\u5BB9\uFF0CThreshold\u7528\u4E8E\u63A7\u5236\u65E5\u5FD7\u8F93\u51FA\u7EA7\u522B 9 | 10 | #\u5E94\u7528\u4E8E\u63A7\u5236\u53F0 11 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 12 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 13 | log4j.appender.stdout.layout.ConversionPattern=[%d][%t][%-5p]- %m%n 14 | 15 | log4j.logger.NPQ=ERROR, NPQ 16 | log4j.appender.NPQ=org.apache.log4j.RollingFileAppender 17 | log4j.appender.NPQ.File=./NPQLog/NPQ.log 18 | log4j.appender.NPQ.MaxFileSize=80MB 19 | log4j.appender.NPQ.MaxBackupIndex=12 20 | log4j.appender.NPQ.Append=true 21 | log4j.appender.NPQ.Threshold=TRACE 22 | log4j.appender.NPQ.layout=org.apache.log4j.PatternLayout 23 | log4j.appender.NPQ.layout.ConversionPattern=[%d][%t][%-5p]- %m%n 24 | log4j.additivity.NPQ = false 25 | #\u6700\u540E\u4E00\u4F4D\u4FEE\u6539\u4E3Atrue \u65E2\u53EF\u4EE5\u63A7\u5236\u53F0\u8F93\u51FA\u53C8\u53EF\u4EE5\u6587\u4EF6\u8F93\u51FA 26 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/ignore/IgnoreConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.ignore; 2 | 3 | import com.google.common.collect.Lists; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author lirong 10 | * @ClassName: IgnoreConfig 11 | * @Description: 忽略的配置 12 | * @date 2019-7-29 17:21:26 13 | */ 14 | @Data 15 | public class IgnoreConfig { 16 | /** 17 | * 需要忽略的 URL 格式,不考虑请求方法 18 | */ 19 | private List pattern = Lists.newArrayList(); 20 | 21 | /** 22 | * 需要忽略的 GET 请求 23 | */ 24 | private List get = Lists.newArrayList(); 25 | 26 | /** 27 | * 需要忽略的 POST 请求 28 | */ 29 | private List post = Lists.newArrayList(); 30 | 31 | /** 32 | * 需要忽略的 DELETE 请求 33 | */ 34 | private List delete = Lists.newArrayList(); 35 | 36 | /** 37 | * 需要忽略的 PUT 请求 38 | */ 39 | private List put = Lists.newArrayList(); 40 | 41 | /** 42 | * 需要忽略的 HEAD 请求 43 | */ 44 | private List head = Lists.newArrayList(); 45 | 46 | /** 47 | * 需要忽略的 PATCH 请求 48 | */ 49 | private List patch = Lists.newArrayList(); 50 | 51 | /** 52 | * 需要忽略的 OPTIONS 请求 53 | */ 54 | private List options = Lists.newArrayList(); 55 | 56 | /** 57 | * 需要忽略的 TRACE 请求 58 | */ 59 | private List trace = Lists.newArrayList(); 60 | } 61 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/log/dto/SysLogOutpDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.log.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.Date; 7 | 8 | /** 9 | * @author lirong 10 | * @ClassName: SysLogOutpDTO 11 | * @Description: 日志输出实体类 12 | * @date 2018-12-07 14:59 13 | */ 14 | @Data 15 | public class SysLogOutpDTO implements Serializable { 16 | 17 | private Long id; 18 | 19 | /** 20 | * 日志类型 根据系统模块来定义日志类型 21 | */ 22 | private Integer logType; 23 | 24 | /** 25 | * 操作类型: 添加-1 删除-2 更新-3 查看-4 26 | */ 27 | private Integer operation; 28 | 29 | /** 30 | * 操作人员ID 31 | */ 32 | private String logUser; 33 | 34 | /** 35 | * 操作人员名称 36 | */ 37 | private String username; 38 | 39 | /** 40 | * 访问IP 41 | */ 42 | private String logIp; 43 | 44 | /** 45 | * 请求方法 46 | */ 47 | private String logMethod; 48 | 49 | /** 50 | * 请求参数 51 | */ 52 | private String logParams; 53 | 54 | /** 55 | * 日志描述 56 | */ 57 | private String logDesc; 58 | 59 | /** 60 | * 响应时间 61 | */ 62 | private Long logTime; 63 | 64 | /** 65 | * 异常码 66 | */ 67 | private String exceptionCode; 68 | 69 | /** 70 | * 异常描述 71 | */ 72 | private String exceptionDetail; 73 | 74 | /** 75 | * 创建时间 76 | */ 77 | private Date createTime; 78 | 79 | } 80 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/WebApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.janche; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 7 | import org.springframework.cache.annotation.EnableCaching; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.data.web.config.EnableSpringDataWebSupport; 10 | import org.springframework.scheduling.annotation.EnableScheduling; 11 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 12 | import tk.mybatis.spring.annotation.MapperScan; 13 | 14 | @SpringBootApplication 15 | @MapperScan("com.example.janche.**.dao") 16 | @EnableScheduling 17 | @Configuration 18 | @EnableCaching // 缓存 19 | @EnableSwagger2 20 | @EnableSpringDataWebSupport 21 | // 为了测试修改了扫描包路径,后面修改为自己的路径 22 | public class WebApplication extends SpringBootServletInitializer { 23 | 24 | @Override 25 | public SpringApplicationBuilder configure(SpringApplicationBuilder application) { 26 | return application.sources(WebApplication.class); 27 | } 28 | 29 | 30 | /** 31 | * 启动 32 | */ 33 | public static void main(String[] args) throws InterruptedException { 34 | SpringApplication.run(WebApplication.class, args); 35 | } 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/config/WebConfigration.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.config; 2 | 3 | import com.example.janche.common.config.ApplicationConfig; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 7 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9 | 10 | @Configuration 11 | public class WebConfigration implements WebMvcConfigurer { 12 | 13 | @Autowired 14 | private ApplicationConfig applicationConfig; 15 | 16 | @Override 17 | public void addCorsMappings(CorsRegistry registry) { 18 | String[] IPs = this.applicationConfig.getOrigins(); 19 | registry.addMapping("/**") 20 | .allowedOrigins(IPs) 21 | //允许的请求方式 22 | .allowedMethods("*") 23 | // 允许的请求头 24 | .allowedHeaders("*") 25 | .maxAge(3600) 26 | .allowCredentials(true); 27 | } 28 | 29 | @Override 30 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 31 | //处理的路径规则 32 | registry.addResourceHandler("/static/**") 33 | //到哪些目录下去查找静态资源 34 | .addResourceLocations("classpath:/static/"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/hadler/SecurityAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.hadler; 2 | 3 | import com.example.janche.common.config.IApplicationConfig; 4 | import com.example.janche.common.restResult.ResultCode; 5 | import com.example.janche.security.utils.ResponseUtils; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpMethod; 9 | import org.springframework.security.core.AuthenticationException; 10 | import org.springframework.security.web.AuthenticationEntryPoint; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.io.IOException; 16 | 17 | /** 18 | * 用户未登录时的处理 19 | * @author lirong 20 | * @date 2019-8-8 17:37:27 21 | */ 22 | @Component("securityAuthenticationEntryPoint") 23 | @Slf4j 24 | public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint { 25 | @Autowired 26 | private IApplicationConfig applicationConfig; 27 | @Override 28 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { 29 | if(request.getMethod() != HttpMethod.OPTIONS.toString()) { 30 | log.info("尚未登录:" + authException.getMessage()); 31 | } 32 | ResponseUtils.renderJson(request, response, ResultCode.UNLOGIN, applicationConfig.getOrigins()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/service/MenuRightService.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.service; 2 | 3 | import com.example.janche.common.core.Service; 4 | import com.example.janche.common.restResult.PageParam; 5 | import com.example.janche.user.domain.MenuRight; 6 | import com.example.janche.user.dto.MenuDTO; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 12 | * @author CodeGenerator 13 | * @date 2018-11-01 09:34:51 14 | */ 15 | public interface MenuRightService extends Service { 16 | 17 | /** 18 | * 根据分页、排序信息和检索条件查询 数据 19 | * @param pageParam 分页参数 20 | * @param query 查询关键字 21 | * @return 22 | */ 23 | List list(PageParam pageParam, String query); 24 | 25 | /** 26 | * 根据id查询权限菜单节点 27 | * @param id 权限菜单节点id 28 | * @return MenuRight 权限菜单信息 29 | */ 30 | MenuRight findOne(Long id); 31 | 32 | /** 33 | * 添加一个权限节点 34 | * @param menuRight 权限菜单实体对象 35 | */ 36 | void addMenuRight(MenuRight menuRight); 37 | 38 | /** 39 | * 删除单个权限菜单节点 40 | * @param id 权限菜单id 41 | */ 42 | void deleteMenuRight(Long id); 43 | 44 | /** 45 | * 修改单个权限菜单节点 46 | * @param menuRight 权限菜单节点对象 47 | */ 48 | void updateMenuRight(MenuRight menuRight); 49 | 50 | /** 51 | * 获取用户所有权限 52 | * @param userId 用户ID 53 | * @return 54 | */ 55 | List getUserMenus(Long userId); 56 | 57 | /** 58 | * 获取系统列表 59 | * @return 60 | */ 61 | List getSystemList(); 62 | } 63 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/domain/MenuRight.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.domain; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import javax.persistence.*; 11 | import java.io.Serializable; 12 | import java.util.Date; 13 | 14 | @Data 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | @Builder 18 | @Table(name = "menu_right") 19 | @ApiModel(value="MenuRight",description="权限实体类") 20 | public class MenuRight implements Serializable { 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | @ApiModelProperty(value="权限主键ID") 24 | private Long id; 25 | 26 | @Column(name = "parent_id") 27 | @ApiModelProperty(value="父ID") 28 | private Long parentId; 29 | 30 | @ApiModelProperty(value="权限名称") 31 | private String name; 32 | 33 | @ApiModelProperty(value="排序") 34 | private Integer seq; 35 | 36 | @ApiModelProperty(value="访问地址") 37 | private String url; 38 | 39 | @ApiModelProperty(value="是否启用 ") 40 | private Integer status; 41 | 42 | @ApiModelProperty(value="图标样式") 43 | private String icon; 44 | 45 | @ApiModelProperty(value="方法(get、post)") 46 | private String method; 47 | 48 | @ApiModelProperty(value="层级") 49 | private Integer grades; 50 | 51 | @Column(name = "modify_time") 52 | @ApiModelProperty(value="修改时间") 53 | private Date modifyTime; 54 | 55 | @Column(name = "create_time") 56 | @ApiModelProperty(value="创建时间") 57 | private Date createTime; 58 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import lombok.Data; 5 | 6 | import javax.persistence.Column; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | import java.util.Date; 11 | 12 | @Data 13 | public class User { 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private Long id; 17 | 18 | /** 19 | * 用户名 20 | */ 21 | private String username; 22 | 23 | /** 24 | * 密码 25 | */ 26 | @JsonIgnore 27 | private String password; 28 | 29 | /** 30 | * 真实姓名 31 | */ 32 | @Column(name = "actual_name") 33 | private String actualName; 34 | 35 | /** 36 | * 性别 0:男 1:女 37 | */ 38 | private Integer sex; 39 | 40 | /** 41 | * 手机号码 42 | */ 43 | private String phone; 44 | 45 | /** 46 | * 邮箱 47 | */ 48 | private String email; 49 | 50 | /** 51 | * 地址 52 | */ 53 | private String address; 54 | 55 | /** 56 | * 职务ID 57 | */ 58 | @Column(name = "post_id") 59 | private Integer postId; 60 | 61 | /** 62 | * 职务名称 63 | */ 64 | @Column(name = "post_name") 65 | private String postName; 66 | 67 | /** 68 | * 账号状态:0-禁用,1-启用 69 | */ 70 | private Integer status; 71 | 72 | /** 73 | * 创建时间 74 | */ 75 | @Column(name = "create_time") 76 | private Date createTime; 77 | 78 | /** 79 | * 修改时间 80 | */ 81 | @Column(name = "modify_time") 82 | private Date modifyTime; 83 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/user/UserInputDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.user; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * @author lirong 11 | * @ClassName: UserInputDTO 12 | * @Description: 用户输入类 13 | * @date 2019-07-24 11:21 14 | */ 15 | @Data 16 | @ApiModel(value="UserInputDTO",description="用户输入类") 17 | public class UserInputDTO { 18 | 19 | @ApiModelProperty(value="主键ID, 新增不传值, 修改传值") 20 | private Long id; 21 | 22 | @ApiModelProperty(value="用户名") 23 | private String username; 24 | 25 | @ApiModelProperty(value="密码") 26 | private String password; 27 | 28 | @ApiModelProperty(value="真实姓名") 29 | private String actualName; 30 | 31 | @ApiModelProperty(value="性别") 32 | private int sex; 33 | 34 | @ApiModelProperty(value="电话") 35 | private String phone; 36 | 37 | @ApiModelProperty(value="邮箱") 38 | private String email; 39 | 40 | @ApiModelProperty(value="地址") 41 | private String address; 42 | 43 | @ApiModelProperty(value="职务Id") 44 | private Integer postId; 45 | 46 | @ApiModelProperty(value="职务名称") 47 | private String postName; 48 | 49 | @ApiModelProperty(value="启用状态(0-禁用,1-启用)") 50 | private Integer status; 51 | 52 | @ApiModelProperty(value="创建时间") 53 | private Date createTime; 54 | 55 | @ApiModelProperty(value="修改时间") 56 | private Date modifyTime; 57 | 58 | @ApiModelProperty(value="角色ID 集合(eg: 1,2,5,6)") 59 | private String roleIds; 60 | 61 | @ApiModelProperty(value="权限ID 集合(eg: 1,2,5,6)") 62 | private String menuIds; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/util/CopyUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.util; 2 | 3 | import java.beans.BeanInfo; 4 | import java.beans.Introspector; 5 | import java.beans.PropertyDescriptor; 6 | 7 | /** 8 | * @ClassName CopyUtils 9 | * @Description 复制所需属性到dto模板中(前提是目标类与来源类的属性是同名且包含关系) 10 | * @Author Wwei 11 | */ 12 | public class CopyUtils { 13 | public static void copyProperties(Object source,Object dest) throws Exception { 14 | try { 15 | // 获取目标类的属性 16 | BeanInfo destBean = Introspector.getBeanInfo(dest.getClass(), Object.class); 17 | PropertyDescriptor[] destProperty = destBean.getPropertyDescriptors(); 18 | 19 | // 获取来源类的属性 20 | BeanInfo sourceBean = Introspector.getBeanInfo(source.getClass(), Object.class); 21 | PropertyDescriptor[] sourceProperty = sourceBean.getPropertyDescriptors(); 22 | 23 | for (int i = 0;i logOperation; 25 | private Map logType; 26 | 27 | 28 | 29 | public enum sortType { 30 | ASC(Sort.Direction.ASC), 31 | DESC(Sort.Direction.DESC); 32 | @Getter 33 | private Sort.Direction sortType; 34 | 35 | sortType(Sort.Direction sortType) { 36 | this.sortType = sortType; 37 | } 38 | } 39 | 40 | public Integer getKeyByValue(Map map, String value){ 41 | Set> entrySet = map.entrySet(); 42 | Iterator> it = entrySet.iterator(); 43 | while (it.hasNext()){ 44 | Map.Entry entry = it.next(); 45 | if (entry.getValue().equals(value)){ 46 | return entry.getKey(); 47 | } 48 | } 49 | return null; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/utils/date/DateStyleEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.utils.date; 2 | 3 | /** 4 | *

日期展示风格枚举类

5 | * @author qxb 6 | * @version 1.0 7 | * @since 2018.01.24 8 | * 9 | */ 10 | public enum DateStyleEnum { 11 | YYYY_MM("yyyy-MM", false), 12 | YYYY_MM_DD("yyyy-MM-dd", false), 13 | YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm", false), 14 | YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss", false), 15 | 16 | YYYY_MM_EN("yyyy/MM", false), 17 | YYYY_MM_DD_EN("yyyy/MM/dd", false), 18 | YYYY_MM_DD_HH_MM_EN("yyyy/MM/dd HH:mm", false), 19 | YYYY_MM_DD_HH_MM_SS_EN("yyyy/MM/dd HH:mm:ss", false), 20 | 21 | YYYY_MM_CN("yyyy年MM月", false), 22 | YYYY_MM_DD_CN("yyyy年MM月dd日", false), 23 | YYYY_MM_DD_HH_MM_CN("yyyy年MM月dd日 HH:mm", false), 24 | YYYY_MM_DD_HH_MM_SS_CN("yyyy年MM月dd日 HH:mm:ss", false), 25 | 26 | HH_MM("HH:mm", true), 27 | HH_MM_SS("HH:mm:ss", true), 28 | 29 | MM_DD("MM-dd", true), 30 | MM_DD_HH_MM("MM-dd HH:mm", true), 31 | MM_DD_HH_MM_SS("MM-dd HH:mm:ss", true), 32 | 33 | MM_DD_EN("MM/dd", true), 34 | MM_DD_HH_MM_EN("MM/dd HH:mm", true), 35 | MM_DD_HH_MM_SS_EN("MM/dd HH:mm:ss", true), 36 | 37 | MM_DD_CN("MM月dd日", true), 38 | MM_DD_HH_MM_CN("MM月dd日 HH:mm", true), 39 | MM_DD_HH_MM_SS_CN("MM月dd日 HH:mm:ss", true); 40 | 41 | private String value; 42 | 43 | private boolean isShowOnly; 44 | 45 | DateStyleEnum(String value, boolean isShowOnly) { 46 | this.value = value; 47 | this.isShowOnly = isShowOnly; 48 | } 49 | 50 | public String getValue() { 51 | return value; 52 | } 53 | 54 | public boolean isShowOnly() { 55 | return isShowOnly; 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/user/UserDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.user; 2 | 3 | import com.example.janche.user.domain.MenuRight; 4 | import com.example.janche.user.domain.Role; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import java.io.Serializable; 11 | import java.util.Date; 12 | import java.util.List; 13 | 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Data 17 | @Builder 18 | public class UserDTO implements Serializable { 19 | 20 | /** 21 | * 主键ID 22 | */ 23 | private Long id; 24 | 25 | /** 26 | * 用户名 27 | */ 28 | private String username; 29 | 30 | /** 31 | * 密码 32 | */ 33 | private String password; 34 | 35 | /** 36 | * 真实姓名 37 | */ 38 | private String actualName; 39 | 40 | /** 41 | * 性别 42 | */ 43 | private int sex; 44 | 45 | /** 46 | * 电话 47 | */ 48 | private String phone; 49 | 50 | /** 51 | * 邮箱 52 | */ 53 | private String email; 54 | 55 | /** 56 | * 地址 57 | */ 58 | private String address; 59 | 60 | /** 61 | * 职务Id 62 | */ 63 | private Integer postId; 64 | 65 | /** 66 | * 职务名称 67 | */ 68 | private String postName; 69 | 70 | /** 71 | * 启用状态(0-禁用,1-启用) 72 | */ 73 | private Integer status; 74 | 75 | /** 76 | * 创建时间 77 | */ 78 | private Date createTime; 79 | 80 | /** 81 | * 修改时间 82 | */ 83 | private Date modifyTime; 84 | 85 | /** 86 | * 角色 87 | */ 88 | private List roles; 89 | 90 | /** 91 | * 权限菜单 92 | */ 93 | private List menus; 94 | 95 | } 96 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/user/UserOutpDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto.user; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | import lombok.Data; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * @author lirong 12 | * @ClassName: UserOutpDTO 13 | * @Description: 14 | * @date 2019-07-24 11:21 15 | */ 16 | @Data 17 | @ApiModel(value="UserOutpDTO",description="用户输出展示类") 18 | public class UserOutpDTO { 19 | 20 | @ApiModelProperty(value="主键ID, 新增不传值, 修改传值") 21 | private Long id; 22 | 23 | @ApiModelProperty(value="用户名") 24 | private String username; 25 | 26 | @JsonIgnore 27 | @ApiModelProperty(value="密码") 28 | private String password; 29 | 30 | @ApiModelProperty(value="真实姓名") 31 | private String actualName; 32 | 33 | @ApiModelProperty(value="性别") 34 | private int sex; 35 | 36 | @ApiModelProperty(value="电话") 37 | private String phone; 38 | 39 | @ApiModelProperty(value="邮箱") 40 | private String email; 41 | 42 | @ApiModelProperty(value="地址") 43 | private String address; 44 | 45 | @ApiModelProperty(value="职务Id") 46 | private Integer postId; 47 | 48 | @ApiModelProperty(value="职务名称") 49 | private String postName; 50 | 51 | @ApiModelProperty(value="启用状态(0-禁用,1-启用)") 52 | private Integer status; 53 | 54 | @ApiModelProperty(value="创建时间") 55 | private Date createTime; 56 | 57 | @ApiModelProperty(value="修改时间") 58 | private Date modifyTime; 59 | 60 | @ApiModelProperty(value="角色ID 集合(eg: 1,2,5,6)") 61 | private String roleIds; 62 | 63 | @ApiModelProperty(value="权限ID 集合(eg: 1,2,5,6)") 64 | private String menuIds; 65 | } 66 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/utils/date/WeekEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.utils.date; 2 | 3 | /** 4 | *

星期枚举类

5 | * @author qxb 6 | * @version 1.0 7 | * @since 2018.01.24 8 | * 9 | */ 10 | public enum WeekEnum { 11 | MONDAY("星期一", "Monday", "Mon.", 1), 12 | TUESDAY("星期二", "Tuesday", "Tues.", 2), 13 | WEDNESDAY("星期三", "Wednesday", "Wed.", 3), 14 | THURSDAY("星期四", "Thursday", "Thur.", 4), 15 | FRIDAY("星期五", "Friday", "Fri.", 5), 16 | SATURDAY("星期六", "Saturday", "Sat.", 6), 17 | SUNDAY("星期日", "Sunday", "Sun.", 7); 18 | 19 | String name_cn; 20 | String name_en; 21 | String name_enShort; 22 | int number; 23 | 24 | WeekEnum(String name_cn, String name_en, String name_enShort, int number) { 25 | this.name_cn = name_cn; 26 | this.name_en = name_en; 27 | this.name_enShort = name_enShort; 28 | this.number = number; 29 | } 30 | 31 | /** 32 | * 33 | *
  • getChineseName 得到中文日期
  • 34 | * @return 星期一 星期二... 35 | * @throws 36 | */ 37 | public String getChineseName() { 38 | return name_cn; 39 | } 40 | 41 | /** 42 | * 43 | *
  • 方法名:getName 得到英文日期(Monday..)
  • 44 | * @return Monday Tuesday... 45 | * @throws 46 | */ 47 | public String getName() { 48 | return name_en; 49 | } 50 | 51 | /** 52 | * 53 | *
  • 方法名:getShortName 得到日期缩写
  • 54 | * @return Mon. Tue. Fri... 55 | * @throws 56 | */ 57 | public String getShortName() { 58 | return name_enShort; 59 | } 60 | 61 | /** 62 | * 63 | *
  • 方法名:getNumber 得到星期几
  • 64 | * @return 数字1、2、3.. 65 | * @throws 66 | */ 67 | public int getNumber() { 68 | return number; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /backend/src/test/resources/generator/template/simpleDict/service-impl.ftl: -------------------------------------------------------------------------------- 1 | package ${modulePackage}.${moduleName}.service.impl; 2 | 3 | import ${basePackage}.common.core.AbstractService; 4 | import ${modulePackage}.${moduleName}.dao.${modelNameUpperCamel}Mapper; 5 | import ${modulePackage}.${moduleName}.domain.${modelNameUpperCamel}; 6 | import ${modulePackage}.${moduleName}.service.${modelNameUpperCamel}Service; 7 | import ${basePackage}.common.restResult.PageParam; 8 | import com.github.pagehelper.PageHelper; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.transaction.annotation.Transactional; 12 | import tk.mybatis.mapper.entity.Example; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.List; 16 | 17 | /** 18 | * @author ${author} 19 | * @Description: // TODO 为类添加注释 20 | * @date ${date} 21 | */ 22 | @Slf4j 23 | @Service 24 | @Transactional 25 | public class ${modelNameUpperCamel}ServiceImpl extends AbstractService<${modelNameUpperCamel}> implements ${modelNameUpperCamel}Service { 26 | @Resource 27 | private ${modelNameUpperCamel}Mapper ${modelNameLowerCamel}Mapper; 28 | 29 | /** 30 | * 根据分页、排序信息和检索条件查询 @size 条 字典表数据 31 | * @param pageParam 分页参数 32 | * @param query 查询关键字 33 | * @return 34 | */ 35 | @Override 36 | public List<${modelNameUpperCamel}> list(PageParam pageParam, String query) { 37 | Example example = new Example(${modelNameUpperCamel}.class); 38 | //TODO 设置查询字段 39 | //example.or().andLike("name", "%"+query+"%"); 40 | //example.or().andLike("code", "%"+query+"%"); 41 | 42 | PageHelper.startPage(pageParam.getPage(), pageParam.getSize(), pageParam.getOrderBy()); 43 | return ${modelNameLowerCamel}Mapper.selectByExample(example); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/utils/MD5Util.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.utils; 2 | 3 | import java.security.MessageDigest; 4 | 5 | /** 6 | * @author lirong 7 | * @ClassName: MD5Util 8 | * @Description: MD5加密解密工具类 9 | * @date 2018-12-14 10:18 10 | */ 11 | 12 | public class MD5Util { 13 | private static final String SALT = "CDJCY"; 14 | 15 | /** 16 | * 使用系统指定的盐加密 17 | * @param password 18 | * @return 19 | */ 20 | public static String encode(String password) { 21 | return MD5Util.encode(SALT, password); 22 | } 23 | 24 | /** 25 | * 使用传入的盐加密 26 | * @param salt 27 | * @param password 28 | * @return 29 | */ 30 | public static String encode(String salt, String password) { 31 | password = password + salt; 32 | MessageDigest md5 = null; 33 | try { 34 | md5 = MessageDigest.getInstance("MD5"); 35 | } catch (Exception e) { 36 | throw new RuntimeException(e); 37 | } 38 | char[] charArray = password.toCharArray(); 39 | byte[] byteArray = new byte[charArray.length]; 40 | 41 | for (int i = 0; i < charArray.length; i++) { 42 | byteArray[i] = (byte) charArray[i]; 43 | } 44 | byte[] md5Bytes = md5.digest(byteArray); 45 | StringBuffer hexValue = new StringBuffer(); 46 | for (int i = 0; i < md5Bytes.length; i++) { 47 | int val = ((int) md5Bytes[i]) & 0xff; 48 | if (val < 16) { 49 | hexValue.append("0"); 50 | } 51 | 52 | hexValue.append(Integer.toHexString(val)); 53 | } 54 | return hexValue.toString(); 55 | } 56 | 57 | public static void main(String[] args) { 58 | System.out.println(MD5Util.encode("123456")); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/utils/encrypt/TestDecryptCode.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.utils.encrypt; 2 | 3 | import org.springframework.util.Base64Utils; 4 | 5 | import javax.crypto.Cipher; 6 | import java.security.KeyFactory; 7 | import java.security.PublicKey; 8 | import java.security.spec.X509EncodedKeySpec; 9 | 10 | /** 11 | *

    12 | * 13 | * @author qxb 14 | * @version v1.0 15 | * @since 2018/9/20 17:33 16 | */ 17 | public class TestDecryptCode { 18 | public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception{ 19 | 20 | //实例化密钥工厂 21 | KeyFactory keyFactory=KeyFactory.getInstance("RSA"); 22 | //初始化公钥 23 | //密钥材料转换 24 | X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key); 25 | //产生公钥 26 | PublicKey pubKey=keyFactory.generatePublic(x509KeySpec); 27 | //数据解密 28 | Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm()); 29 | cipher.init(Cipher.DECRYPT_MODE, pubKey); 30 | return cipher.doFinal(data); 31 | } 32 | public static void main(String[] args) throws Exception { 33 | String publickey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDj+78kFLF8w1vjX1VXafTFJlGZ5tQ05jvNIFODi1sKWDQtGI+J5mRBNfIlvZgY4Evq1kZpUe20aeU1pzFZCnvLha3KFsB5dlCSPs4JJ9UUsN2FoEGv6Iajuv+lOVMhFUh2pX64qsJgvLHD/S9i+nD+FVvrEgJpkww1CECJKu26NwIDAQAB"; 34 | byte[] key = Base64Utils.decodeFromString(publickey); 35 | String data ="NL5b6ytxzKRlJwu5gfIvYSTxEU0Icm55Ymk5Hy3DHaO/3ALlsrumsQohmB5L88fP/HL3+nbTs3VRysEw7+7qDgvoDzlOSizgR8Mp3M1o846QrkEVQszPD4aSN4lZ7jDrH/lenaPiz7SDET7PbaTZCFlg0Y64NE5cmH+BmoYLca8="; 36 | byte[] value = Base64Utils.decodeFromString(data); 37 | byte[] decode1=TestDecryptCode.decryptByPublicKey(value, key); 38 | System.out.println(new String(decode1)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/datasource/DruidConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.datasource; 2 | 3 | import com.alibaba.druid.support.http.StatViewServlet; 4 | import com.alibaba.druid.support.http.WebStatFilter; 5 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 6 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class DruidConfig { 12 | 13 | @Bean 14 | public ServletRegistrationBean statViewServlet() { 15 | // 创建servlet注册实体 16 | ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), 17 | "/druid/*"); 18 | // 设置ip白名单 19 | servletRegistrationBean.addInitParameter("allow", "127.0.0.1"); 20 | // 设置ip黑名单,如果allow与deny共同存在时,deny优先于allow 21 | // servletRegistrationBean.addInitParameter("deny", "192.168.0.1"); 22 | // 设置控制台管理用户 23 | servletRegistrationBean.addInitParameter("loginUsername", "admin"); 24 | servletRegistrationBean.addInitParameter("loginPassword", "admin"); 25 | // 是否可以重置数据 26 | servletRegistrationBean.addInitParameter("resetEnable", "false"); 27 | return servletRegistrationBean; 28 | } 29 | 30 | // @Bean 31 | // public FilterRegistrationBean statFilter() { 32 | // // 创建过滤器 33 | // FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); 34 | // // 设置过滤器过滤路径 35 | // filterRegistrationBean.addUrlPatterns("/*"); 36 | // // 忽略过滤的形式 37 | // filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); 38 | // return filterRegistrationBean; 39 | // } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## springboot-security-project 2 | **基于`springboot2` + `springsecurity` + `mybatis` + `redis` + `swagger` + `oauth2` 的脚手架工程(前后端分离)** 3 | 4 | 1. 配置了mybatis的通用mapper,单表操作无需写SQL,实现了批量插入、批量删除等功能。 5 | 2. 内含freemarker的代码生成器,可以一键根据表名直接生成controller、service、dao、mapper等基础代码, 6 | 大大提高了开发效率,让你更专注于对业务的开发。 7 | 3. spring-security目前使用的是基于权限的动态校验,采用黑名单的方式对接口权限的判断。 8 | 4. 框架内已包含许多工具类,MD5加密、json、POI的excel文档操作,以及时间和日期等常见工具类。 9 | 5. 采用了@Log对项目日志的记录。 10 | 6. 接口文档地址:http://localhost:9999/doc.html (采用knife4j的文档风格) 11 | 7. 加入对OAuth2的支持,这部分代码目前已迁移到oauth2分支 ([博客地址](https://blog.csdn.net/qq_34997906/article/details/89600076)) 12 | 13 | |依赖 |版本 | 14 | |:------------- |:------------| 15 | |[Spring Boot](http://mvnrepository.com/artifact/org.springframework.boot/spring-boot) |2.1.8.RELEASE| 16 | |[Spring Web MVC](http://mvnrepository.com/artifact/org.springframework/spring-webmvc) |5.1.9.RELEASE| 17 | |[Spring Security Web](http://mvnrepository.com/artifact/org.springframework.security/spring-security-web)|5.1.5.RELEASE| 18 | |[MyBatis](http://mvnrepository.com/artifact/org.mybatis/mybatis) |4.1.5| 19 | |[通用mapper](https://mvnrepository.com/artifact/tk.mybatis/mapper-spring-boot-starter) |2.1.5| 20 | |[Druid](http://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter) |1.1.21| 21 | 22 | ### 启动步骤 23 | > 1. 创建数据库boot2-oauth, 执行web模块下resources/sql/init.sql文件 24 | > 2. 使用postman测试登录接口 /login POST 方式 ,本项目返回均是JSON字符串,重定向到登录页面,需要前端做处理,若想要后端直接重定向到登录页面的话,需要配置WebSecurityConfig中引入的那几个Handler,将里面返回的json值改为重定向到登录页面即可。 25 | 26 | ### 温馨提示 27 | 1. 可根据项目需要自定义 `backend/src/test/resources/generator/template/**` 目录下的模板文件 28 | 2. 定义好表结构后,配置 `backend/src/test/java/CodeGenerator.java` 这个文件,运行即可生成项目的基础代码 29 | 30 | ### 完成模块 31 | 1. 用户管理 32 | - [x] 用户的CRUD 33 | - [x] 在线用户数量统计 34 | 2. 角色管理 35 | - [x] 角色的CRUD 36 | - [x] 角色权限树 37 | 3. 权限管理 38 | - [x] 权限的CRUD 39 | 4. 日志管理 40 | - [x] 日志的CRUD 41 | 42 | ### OAuth2 授权码和password测试如下: 43 | ![OAuth2测试](https://img-blog.csdnimg.cn/20200320172751161.gif) 44 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/log/domain/SysLog.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.log.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | import java.util.Date; 8 | import javax.persistence.*; 9 | @Data 10 | @Table(name = "sys_log") 11 | @JsonInclude(JsonInclude.Include.NON_NULL) 12 | public class SysLog implements Serializable { 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | private Long id; 16 | 17 | /** 18 | * 日志类型 根据系统模块来定义日志类型 19 | */ 20 | @Column(name = "log_type") 21 | private Integer logType; 22 | 23 | /** 24 | * 操作类型: 添加-1 删除-2 更新-3 查看-4 25 | */ 26 | private Integer operation; 27 | 28 | /** 29 | * 操作人员ID 30 | */ 31 | @Column(name = "log_user") 32 | private Long logUser; 33 | 34 | /** 35 | * 访问IP 36 | */ 37 | @Column(name = "log_ip") 38 | private String logIp; 39 | 40 | /** 41 | * 请求方法 42 | */ 43 | @Column(name = "log_method") 44 | private String logMethod; 45 | 46 | /** 47 | * 请求参数 48 | */ 49 | @Column(name = "log_params") 50 | private String logParams; 51 | 52 | /** 53 | * 日志描述 54 | */ 55 | @Column(name = "log_desc") 56 | private String logDesc; 57 | 58 | /** 59 | * 响应时间 60 | */ 61 | @Column(name = "log_time") 62 | private Long logTime; 63 | 64 | /** 65 | * 异常码 66 | */ 67 | @Column(name = "exception_code") 68 | private String exceptionCode; 69 | 70 | /** 71 | * 异常描述 72 | */ 73 | @Column(name = "exception_detail") 74 | private String exceptionDetail; 75 | 76 | /** 77 | * 创建时间 78 | */ 79 | @Column(name = "create_time") 80 | private Date createTime; 81 | 82 | /** 83 | * 用户名 84 | */ 85 | @Transient 86 | private String username; 87 | 88 | /** 89 | * 操作类型 90 | */ 91 | @Transient 92 | private String logOperation; 93 | 94 | } -------------------------------------------------------------------------------- /web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | com.example.janche 7 | springboot-security-project 8 | 0.0.1-SNAPSHOT 9 | 10 | 11 | web 12 | web项目 13 | 14 | 4.0.0 15 | 16 | web 17 | 0.0.1-SNAPSHOT 18 | war 19 | 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-tomcat 29 | provided 30 | 31 | 32 | org.springframework.data 33 | spring-data-commons 34 | 35 | 36 | com.example.janche 37 | security 38 | 0.0.1-SNAPSHOT 39 | 40 | 41 | 42 | org.springframework.security.oauth 43 | spring-security-oauth2 44 | 2.3.5.RELEASE 45 | 46 | 47 | 48 | ROOT 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | true 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/hadler/SecurityLogoutSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.hadler; 2 | 3 | import com.example.janche.common.config.IApplicationConfig; 4 | import com.example.janche.common.restResult.RestResult; 5 | import com.example.janche.log.domain.SysLog; 6 | import com.example.janche.log.service.SysLogService; 7 | import com.example.janche.security.utils.ResponseUtils; 8 | import com.example.janche.security.utils.SecurityUtils; 9 | import com.example.janche.user.dto.LoginUserDTO; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.security.core.Authentication; 13 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 14 | import org.springframework.stereotype.Component; 15 | 16 | import javax.annotation.Resource; 17 | import javax.servlet.http.HttpServletRequest; 18 | import javax.servlet.http.HttpServletResponse; 19 | 20 | 21 | @Component("securityLogoutSuccessHandler") 22 | @Slf4j 23 | public class SecurityLogoutSuccessHandler implements LogoutSuccessHandler { 24 | @Autowired 25 | private IApplicationConfig applicationConfig; 26 | @Resource 27 | private SysLogService sysLogService; 28 | @Override 29 | public void onLogoutSuccess(HttpServletRequest request , HttpServletResponse response , Authentication authentication) { 30 | 31 | // 清除登录的session 32 | request.getSession().invalidate(); 33 | 34 | // 记录登出日志 35 | if (null != authentication) { 36 | this.saveLog(request, authentication); 37 | } 38 | log.info("退出成功"); 39 | // JSON 格式的返回 40 | ResponseUtils.renderSuccessJson(request, response, new RestResult(200, "退出成功"), applicationConfig.getOrigins()); 41 | 42 | } 43 | 44 | /** 45 | * 记录登出日志 46 | * @param request 47 | */ 48 | private void saveLog(HttpServletRequest request, Authentication authentication) { 49 | LoginUserDTO user = (LoginUserDTO) authentication.getPrincipal(); 50 | SysLog sysLog = SecurityUtils.buildLog(request, authentication); 51 | sysLog.setOperation(6); 52 | sysLog.setLogDesc(user.getUsername() + " 退出了系统 "); 53 | sysLog.setLogType(2); 54 | sysLogService.saveLog(sysLog); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /backend/src/test/resources/demo-user.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : Localhost 5 | Source Server Version : 50713 6 | Source Host : localhost:3306 7 | Source Database : test 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50713 11 | File Encoding : 65001 12 | 13 | Date: 2017-06-23 14:25:27 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for user 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `user`; 22 | CREATE TABLE `user` ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT, 24 | `username` varchar(255) NOT NULL, 25 | `password` varchar(255) NOT NULL, 26 | `nick_name` varchar(255) DEFAULT NULL, 27 | `sex` int(1) DEFAULT NULL, 28 | `register_date` datetime NOT NULL, 29 | PRIMARY KEY (`id`) 30 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 31 | 32 | -- ---------------------------- 33 | -- Records of user 34 | -- ---------------------------- 35 | INSERT INTO `user` VALUES ('1', '89921218@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆', '1', '2017-06-23 14:24:23'); 36 | INSERT INTO `user` VALUES ('2', '2@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-2', '1', '2017-06-23 14:24:23'); 37 | INSERT INTO `user` VALUES ('3', '3@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-3', '1', '2017-06-23 14:24:23'); 38 | INSERT INTO `user` VALUES ('4', '4@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-4', '1', '2017-06-23 14:24:23'); 39 | INSERT INTO `user` VALUES ('5', '5@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-5', '1', '2017-06-23 14:24:23'); 40 | INSERT INTO `user` VALUES ('6', '6@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-6', '1', '2017-06-23 14:24:23'); 41 | INSERT INTO `user` VALUES ('7', '7@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-7', '1', '2017-06-23 14:24:23'); 42 | INSERT INTO `user` VALUES ('8', '8@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-8', '1', '2017-06-23 14:24:23'); 43 | INSERT INTO `user` VALUES ('9', '9@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-9', '1', '2017-06-23 14:24:23'); 44 | INSERT INTO `user` VALUES ('10', '10@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-10', '1', '2017-06-23 14:24:23'); 45 | SET FOREIGN_KEY_CHECKS=1; 46 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/service/RoleService.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.service; 2 | 3 | import com.example.janche.common.core.Service; 4 | import com.example.janche.common.restResult.PageParam; 5 | import com.example.janche.user.domain.Role; 6 | import com.example.janche.user.dto.LoginUserDTO; 7 | import com.example.janche.user.dto.TreeNodeDTO; 8 | import com.example.janche.user.dto.role.RoleConditionDTO; 9 | import com.example.janche.user.dto.role.RoleDTO; 10 | import com.example.janche.user.dto.role.RoleInputDTO; 11 | import com.example.janche.user.dto.role.RoleOutpDTO; 12 | 13 | import java.util.List; 14 | import java.util.Set; 15 | 16 | /** 17 | * @author lirong 18 | * @Description: 19 | * @date 2019-7-18 18:21:55 20 | */ 21 | public interface RoleService extends Service { 22 | 23 | /** 24 | * 根据分页、排序信息和检索条件查询 @size 条 字典表数据 25 | * @param pageParam 分页参数 26 | * @return 27 | */ 28 | List list(PageParam pageParam, RoleConditionDTO dto, LoginUserDTO userDTO); 29 | 30 | /** 31 | * 下拉框角色列表 32 | * @return 33 | */ 34 | List listAll(); 35 | 36 | /** 37 | * 添加单个角色信息 38 | * @param inputDTO 角色信息 39 | */ 40 | void addRole(RoleInputDTO inputDTO); 41 | 42 | /** 43 | * 删除单个角色 44 | * @param id 角色id 45 | */ 46 | void deleteRole(Long id); 47 | 48 | /** 49 | * 修改单个角色 50 | * @param inputDTO 角色信息 51 | */ 52 | void updateRole(RoleInputDTO inputDTO); 53 | 54 | /** 55 | * 获取角色详情 56 | * @param id 57 | * @return 58 | */ 59 | RoleOutpDTO findOne(Long id); 60 | 61 | /** 62 | * 获取角色的权限信息 63 | * @return 64 | */ 65 | RoleDTO getMenusByRoleId(Long id); 66 | 67 | /** 68 | * 获取权限树 69 | * @return 70 | */ 71 | TreeNodeDTO getMenuTree(); 72 | 73 | /** 74 | * 批量删除角色 75 | * @param ids 76 | */ 77 | void deleteRole(String ids); 78 | 79 | /** 80 | * 批量冻结成功 81 | * @param ids 82 | * @param status 83 | */ 84 | void frozeRole(String ids, Integer status); 85 | 86 | /** 87 | * 根据角色Ids获取权限Ids 88 | * @param ids 89 | * @return 90 | */ 91 | Set getMenuIdsByRoleIds(String ids); 92 | } 93 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/exception/ControllerExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.exception; 2 | 3 | import com.example.janche.common.restResult.RestResult; 4 | import com.example.janche.common.restResult.ResultGenerator; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | import java.io.PrintWriter; 12 | 13 | /** 14 | * Controller异常处理->返回前端 15 | * 自定义异常处理来改变默认的客户端访问接口产生的异常信息 16 | */ 17 | @Slf4j 18 | @ControllerAdvice 19 | public class ControllerExceptionHandler { 20 | 21 | /** 22 | * 错误码 23 | */ 24 | public static final String CODE = "code"; 25 | 26 | /** 27 | * 消息 28 | */ 29 | public static final String MESSAGE = "message"; 30 | 31 | /** 32 | * 处理异常的类型 33 | * 34 | * @param e 异常 35 | * @return 36 | */ 37 | @ExceptionHandler(Exception.class) 38 | public void handleCustomException(Exception e, HttpServletResponse response) { 39 | response.setCharacterEncoding("UTF-8"); 40 | response.setContentType("application/json;charset=UTF-8"); 41 | PrintWriter writer = null; 42 | RestResult result = null; 43 | if (e instanceof CustomException){ 44 | // 可设置不同的HTTP状态 45 | response.setStatus(200); 46 | CustomException ex = (CustomException) e; 47 | result = new RestResult(ex.getResultCode()); 48 | }else if(e instanceof RuntimeException){ 49 | response.setStatus(500); 50 | result = ResultGenerator.genFailResult(e.getMessage()); 51 | }else { 52 | response.setStatus(500); 53 | result = new RestResult(500,"未知错误,请联系管理员"); 54 | } 55 | try { 56 | // 重置response的输出流 57 | // response.reset(); 58 | writer = response.getWriter(); 59 | writer.print(result.toJson()); 60 | writer.flush(); 61 | } catch (IOException e1) { 62 | e1.printStackTrace(); 63 | } 64 | e.printStackTrace(); 65 | } 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /backend/src/test/resources/generator/template/default/service-impl.ftl: -------------------------------------------------------------------------------- 1 | package ${modulePackage}.${moduleName}.service.impl; 2 | 3 | import ${basePackage}.common.core.AbstractService; 4 | import ${modulePackage}.${moduleName}.dao.${modelNameUpperCamel}Mapper; 5 | import ${modulePackage}.${moduleName}.domain.${modelNameUpperCamel}; 6 | import ${modulePackage}.${moduleName}.service.${modelNameUpperCamel}Service; 7 | import ${basePackage}.common.utils.CoreUtils; 8 | import com.github.pagehelper.PageHelper; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.transaction.annotation.Transactional; 12 | import tk.mybatis.mapper.entity.Example; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.List; 16 | 17 | /** 18 | * 19 | * @author ${author} 20 | * @date ${date} 21 | */ 22 | @Slf4j 23 | @Service 24 | @Transactional 25 | public class ${modelNameUpperCamel}ServiceImpl extends AbstractService<${modelNameUpperCamel}> implements ${modelNameUpperCamel}Service { 26 | @Resource 27 | private ${modelNameUpperCamel}Mapper ${modelNameLowerCamel}Mapper; 28 | 29 | /** 30 | * 根据分页、排序信息和检索条件查询 @size 条 字典表数据 31 | * 32 | * @param page 第几页 33 | * @param size 每页有多少记录 34 | * @param sortField 排序字段 35 | * @param sortOrder 升序or降序 36 | * @param query 查询关键字 37 | * @return 38 | */ 39 | @Override 40 | public List<${modelNameUpperCamel}> search(Integer page, 41 | Integer size, 42 | String sortField, 43 | String sortOrder, 44 | String query) { 45 | Example example = new Example(${modelNameUpperCamel}.class); 46 | //TODO 6. 设置查询字段 47 | //example.or().andLike("itemName", "%"+query+"%"); 48 | //example.or().andLike("itemCode", "%"+query+"%"); 49 | //example.or().andLike("itemInputCode", "%"+query+"%"); 50 | 51 | String orderBy = CoreUtils.getOrderBy(sortField, sortOrder); 52 | PageHelper.startPage(page, size, orderBy); 53 | return ${modelNameLowerCamel}Mapper.selectByExample(example); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/hadler/SecurityAuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.hadler; 2 | 3 | import com.example.janche.common.config.IApplicationConfig; 4 | import com.example.janche.common.restResult.ResultCode; 5 | import com.example.janche.common.util.IPUtils; 6 | import com.example.janche.log.domain.SysLog; 7 | import com.example.janche.log.service.SysLogService; 8 | import com.example.janche.security.utils.ResponseUtils; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.security.core.AuthenticationException; 12 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 13 | import org.springframework.stereotype.Component; 14 | 15 | import javax.annotation.Resource; 16 | import javax.servlet.http.HttpServletRequest; 17 | import javax.servlet.http.HttpServletResponse; 18 | import java.util.Date; 19 | 20 | @Component("securityAuthenticationFailureHandler") 21 | @Slf4j 22 | public class SecurityAuthenticationFailureHandler implements AuthenticationFailureHandler { 23 | @Autowired 24 | private IApplicationConfig applicationConfig; 25 | @Resource 26 | private SysLogService sysLogService; 27 | @Override 28 | public void onAuthenticationFailure(HttpServletRequest request , HttpServletResponse response , AuthenticationException exception) { 29 | // 记录登录失败的日志 30 | this.saveLog(request, exception); 31 | log.info("登录失败: "+ exception.getMessage()); 32 | // JSON 格式的返回 33 | ResultCode.LOGIN_ERROR.message = exception.getMessage(); 34 | // JSON 格式的返回 35 | ResponseUtils.renderJson(request, response, ResultCode.LOGIN_ERROR, applicationConfig.getOrigins()); 36 | } 37 | 38 | /** 39 | * 记录登录失败的日志 40 | * @param request 41 | */ 42 | private void saveLog(HttpServletRequest request, AuthenticationException exception) { 43 | SysLog sysLog = new SysLog(); 44 | sysLog.setOperation(5); 45 | sysLog.setLogUser(null); 46 | sysLog.setCreateTime(new Date()); 47 | sysLog.setLogIp(IPUtils.getIpAddr(request)); 48 | sysLog.setLogDesc(exception.getMessage() +" 登录系统失败 "); 49 | sysLog.setLogMethod(request.getMethod()); 50 | sysLog.setLogType(1); 51 | sysLogService.saveLog(sysLog); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /backend/src/test/resources/generator/template/controller-restful.ftl: -------------------------------------------------------------------------------- 1 | package ${basePackage}.controller; 2 | 3 | import ${basePackage}.util.restResult.RestResult; 4 | import ${basePackage}.util.restResult.ResultGenerator; 5 | import ${basePackage}.domain.${modelNameUpperCamel}; 6 | import ${basePackage}.service.${modelNameUpperCamel}Service; 7 | import com.github.pagehelper.PageHelper; 8 | import com.github.pagehelper.PageInfo; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | /** 16 | * 17 | * @author ${author} 18 | * @date ${date} 19 | * 20 | */ 21 | @Slf4j 22 | @RestController 23 | @RequestMapping("${baseRequestMapping}") 24 | public class ${modelNameUpperCamel}Controller { 25 | @Resource 26 | private ${modelNameUpperCamel}Service ${modelNameLowerCamel}Service; 27 | 28 | @PostMapping 29 | public RestResult add(${modelNameUpperCamel} ${modelNameLowerCamel}) { 30 | ${modelNameLowerCamel}Service.save(${modelNameLowerCamel}); 31 | return ResultGenerator.genSuccessResult(); 32 | } 33 | 34 | @DeleteMapping("/{id}") 35 | public RestResult delete(@PathVariable String id) { 36 | ${modelNameLowerCamel}Service.deleteById(id); 37 | return ResultGenerator.genSuccessResult(); 38 | } 39 | 40 | @PutMapping 41 | public RestResult update(${modelNameUpperCamel} ${modelNameLowerCamel}) { 42 | ${modelNameLowerCamel}Service.update(${modelNameLowerCamel}); 43 | return ResultGenerator.genSuccessResult(); 44 | } 45 | 46 | @GetMapping("/{id}") 47 | public RestResult detail(@PathVariable String id) { 48 | ${modelNameUpperCamel} ${modelNameLowerCamel} = ${modelNameLowerCamel}Service.findById(id); 49 | return ResultGenerator.genSuccessResult(${modelNameLowerCamel}); 50 | } 51 | 52 | @GetMapping 53 | public RestResult list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) { 54 | PageHelper.startPage(page, size); 55 | List<${modelNameUpperCamel}> list = ${modelNameLowerCamel}Service.findAll(page,size); 56 | PageInfo pageInfo = new PageInfo(list); 57 | return ResultGenerator.genSuccessResult(pageInfo); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/restResult/RestResult.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.restResult; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.annotation.JSONField; 5 | import com.alibaba.fastjson.serializer.SerializerFeature; 6 | import com.example.janche.common.model.Constant; 7 | import com.fasterxml.jackson.annotation.JsonInclude; 8 | import lombok.Data; 9 | 10 | /** 11 | * 12 | *

    封装统一的返回结果

    13 | * 14 | */ 15 | @Data 16 | @JsonInclude(JsonInclude.Include.NON_NULL) 17 | public class RestResult { 18 | @JSONField(ordinal=1) 19 | private int code; 20 | 21 | @JSONField(ordinal=2) 22 | private String message; 23 | 24 | @JSONField(ordinal=3) 25 | private T data; 26 | 27 | public int getCode() { 28 | return code; 29 | } 30 | 31 | public RestResult() { 32 | } 33 | 34 | public RestResult(ResultCode resultCode){ 35 | this.code = resultCode.getCode(); 36 | this.message = resultCode.getMessage(); 37 | } 38 | public RestResult(ResultCode resultCode, T data){ 39 | this(resultCode); 40 | this.data = data; 41 | } 42 | 43 | public RestResult(Integer code, String message){ 44 | this.code = code; 45 | this.message = message; 46 | } 47 | 48 | public RestResult(Integer code, String message, T data){ 49 | this.code = code; 50 | this.message = message; 51 | this.data = data; 52 | } 53 | 54 | public RestResult setCode(int code) { 55 | this.code = code; 56 | return this; 57 | } 58 | 59 | public String getMessage() { 60 | return message; 61 | } 62 | 63 | public RestResult setMessage(String message) { 64 | this.message = message; 65 | return this; 66 | } 67 | 68 | public T getData() { 69 | return data; 70 | } 71 | 72 | public RestResult setData(T data) { 73 | this.data = data; 74 | return this; 75 | } 76 | 77 | /** 78 | * WARN: fastjson关闭了引用监测,在循环引用时可能会内存溢出 79 | * - 如果前端能够解析$ref 指针引用,则考虑开启引用监测 80 | * - 先默认前端不能解析 81 | */ 82 | public String toJson() { 83 | return JSON.toJSONStringWithDateFormat(this, Constant.DATE_FORMATTER_TIME, SerializerFeature.DisableCircularReferenceDetect); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/service/SecurityUserService.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.service; 2 | 3 | 4 | import com.example.janche.security.authentication.SecurityUser; 5 | import com.example.janche.user.dao.MenuRightMapper; 6 | import com.example.janche.user.dao.RoleMapper; 7 | import com.example.janche.user.domain.MenuRight; 8 | import com.example.janche.user.domain.Role; 9 | import com.example.janche.user.dto.LoginUserDTO; 10 | import com.example.janche.user.dto.user.UserDTO; 11 | import com.example.janche.user.service.UserService; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.security.core.userdetails.UserDetails; 14 | import org.springframework.security.core.userdetails.UserDetailsService; 15 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 16 | import org.springframework.stereotype.Component; 17 | 18 | import javax.annotation.Resource; 19 | import java.util.List; 20 | 21 | @Component("securityUserService") 22 | public class SecurityUserService implements UserDetailsService { 23 | @Autowired 24 | private UserService userService; 25 | @Resource 26 | private RoleMapper roleMapper; 27 | @Resource 28 | private MenuRightMapper menuRightMapper; 29 | 30 | @Override 31 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 32 | 33 | UserDTO userDTO = userService.getRolesByUsername(username); 34 | // 默认用户ID为1的为管理员 35 | if (null != userDTO){ 36 | if(1L == userDTO.getId()) { 37 | this.getAdminPermission(userDTO); 38 | } 39 | SecurityUser securityUser = new SecurityUser(LoginUserDTO.user2LoginUserDTO(userDTO)); 40 | return securityUser; 41 | } else { 42 | throw new UsernameNotFoundException(username + " 用户不存在!"); 43 | } 44 | } 45 | 46 | /** 47 | * 为管理员赋所有权限 48 | * @param userDTO 49 | * @return 50 | */ 51 | private UserDTO getAdminPermission(UserDTO userDTO) { 52 | List roles = roleMapper.selectAll(); 53 | List menuRights = menuRightMapper.selectAll(); 54 | userDTO.setRoles(roles); 55 | userDTO.setMenus(menuRights); 56 | return userDTO; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/mybatis/handler/JsonTypeHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.mybatis.handler; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import org.apache.ibatis.type.BaseTypeHandler; 5 | import org.apache.ibatis.type.JdbcType; 6 | 7 | import java.sql.CallableStatement; 8 | import java.sql.PreparedStatement; 9 | import java.sql.ResultSet; 10 | import java.sql.SQLException; 11 | 12 | /** 13 | * @author lirong 14 | * @version v1.0 15 | * @since 2018/07/17 16:25 16 | */ 17 | 18 | public class JsonTypeHandler extends BaseTypeHandler { 19 | 20 | private Class clazz; 21 | 22 | public JsonTypeHandler(Class clazz) { 23 | if (clazz == null) { 24 | throw new IllegalArgumentException("Type argument cannot be null"); 25 | } 26 | this.clazz = clazz; 27 | } 28 | 29 | /** 30 | * 保存数据的时候的处理,将对象转为JSON字符串 31 | * @param ps 32 | * @param i 33 | * @param parameter 34 | * @param jdbcType 35 | * @throws SQLException 36 | */ 37 | @Override 38 | public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { 39 | ps.setString(i, this.toJson(parameter)); 40 | } 41 | 42 | /** 43 | * 获取对象时候的处理,将字段里的JSON串转为java对象 44 | * @param rs 45 | * @param columnName 46 | * @return 47 | * @throws SQLException 48 | */ 49 | @Override 50 | public T getNullableResult(ResultSet rs, String columnName) throws SQLException { 51 | return this.toObject(rs.getString(columnName), clazz); 52 | } 53 | 54 | @Override 55 | public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 56 | return this.toObject(rs.getString(columnIndex), clazz); 57 | } 58 | 59 | @Override 60 | public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 61 | return this.toObject(cs.getString(columnIndex), clazz); 62 | } 63 | 64 | private String toJson(T object) { 65 | return JSON.toJSONString(object); 66 | } 67 | 68 | private T toObject(String content, Class clazz) { 69 | if (content != null && !content.isEmpty()) { 70 | return (T)JSON.parseObject(content, clazz); 71 | } else { 72 | return null; 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.service; 2 | 3 | import com.example.janche.common.core.Service; 4 | import com.example.janche.common.restResult.PageParam; 5 | import com.example.janche.user.domain.User; 6 | import com.example.janche.user.dto.MenuDTO; 7 | import com.example.janche.user.dto.user.*; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * 13 | * @author lirong 14 | * @date 2018-11-01 09:59:47 15 | */ 16 | public interface UserService extends Service { 17 | 18 | /** 19 | * 添加用户 20 | * @param inputDTO 21 | */ 22 | void addUser(UserInputDTO inputDTO); 23 | 24 | /** 25 | * 修改用户信息 26 | * @param inputDTO 27 | */ 28 | void updateUser(UserInputDTO inputDTO); 29 | 30 | /** 31 | * 删除用户 32 | * @param id 用户id 33 | */ 34 | void deleteUser(Long id); 35 | 36 | /** 37 | * 根据分页、排序信息和检索条件查询 数据 38 | * @param pageParam 分页参数 39 | * @param query 查询关键字 40 | * @return 41 | */ 42 | List list(PageParam pageParam, String query); 43 | 44 | /** 45 | * 下拉框用户列表 46 | * @return 47 | */ 48 | List listAll(); 49 | 50 | /** 51 | * 根据用户名获取用户的相关权限信息 52 | * @param username 53 | * @return 54 | */ 55 | UserDTO getRolesByUsername(String username); 56 | 57 | /** 58 | * 分页条件查询所有用户 59 | * @param pageParam 60 | * @param dto 61 | * @return 62 | */ 63 | List findAll(PageParam pageParam, UserConditionDTO dto); 64 | 65 | /** 66 | * 修改用户密码 67 | * @param dto 68 | */ 69 | void updateUserPwd(UserPwdDTO dto); 70 | 71 | /** 72 | * 重置用户密码 73 | * @param userId 74 | */ 75 | void resetUserPwd(Long userId); 76 | 77 | /** 78 | * 批量删除用户 79 | * @param ids 80 | */ 81 | void deleteUser(String ids); 82 | 83 | /** 84 | * 批量冻结用户 85 | * @param ids 86 | * @param status 87 | */ 88 | void frozeUser(String ids, Integer status); 89 | 90 | /** 91 | * 获取用户明细 92 | * @param id 93 | * @return 94 | */ 95 | UserOutpDTO findOne(Long id); 96 | 97 | /** 98 | * 获取用户所有的权限 99 | * @return 100 | */ 101 | List getUserMenus(Long userId); 102 | } 103 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/core/Service.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.core; 2 | 3 | import org.apache.ibatis.exceptions.TooManyResultsException; 4 | import tk.mybatis.mapper.entity.Condition; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * Service 层 基础接口,其他Service 接口 请继承该接口 11 | */ 12 | public interface Service { 13 | 14 | void save(T model);//持久化 15 | 16 | void save(List models);//批量持久化 17 | 18 | void deleteById(Long id);//通过主鍵刪除 19 | 20 | /** 21 | * 通过字段和值删除数据 22 | * 23 | * @param field 24 | * @param value 25 | * @author lirong 26 | * @since 2018/6/01 18:28 27 | */ 28 | void delete(String field, String value); 29 | 30 | // void deleteByIds(String ids);//批量刪除 eg:ids -> “1,2,3,4” 31 | 32 | void update(T model);//更新 33 | 34 | T findById(Long id);//通过ID查找 35 | 36 | T findBy(String fieldName, Object value) throws TooManyResultsException; 37 | 38 | /** 39 | * 查找符合条件的集合 40 | * 41 | * @param fieldName Model中某个成员变量名称(非数据表中column的名称) 42 | * @param value 43 | * @return 44 | * @author lirong 45 | * @since 2018-6-27 11:44:14 46 | */ 47 | List findAllBy(String fieldName, Object value); 48 | 49 | // List findByIds(String ids);//通过多个ID查找//eg:ids -> “1,2,3,4” 50 | 51 | List findByCondition(Condition condition);//根据条件查找 52 | 53 | List findAll();//获取所有 54 | 55 | List findAll(int page, int size);//获取所有 56 | 57 | List findAll(int page, int size, String orderBy);//获取所有,加排序 58 | 59 | /** 60 | * 根据分页和排序信息查询size条数据 61 | * 62 | * @param page 63 | * @param size 64 | * @param sortField 排序字段 65 | * @param sortOrder 排序类型 66 | * @return 67 | */ 68 | List findAll(int page, int size, String sortField, String sortOrder); 69 | 70 | /** 71 | * 根据分页、排序信息和检索条件查询 size 条数据 72 | * 73 | * @param page 74 | * @param size 75 | * @param sortField 76 | * @param sortOrder 77 | * @param query 78 | * @return 79 | */ 80 | List findAll(int page, int size, String sortField, String sortOrder, Map query); 81 | 82 | /** 83 | * 检查对应的记录是否存在,在过滤条件中添加机构号 84 | * 85 | * @param domainField 86 | * @param value 87 | * @return 88 | */ 89 | Integer keyIsExist(String domainField, String value); 90 | 91 | } 92 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/authentication/SecurityUser.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.authentication; 2 | 3 | 4 | import com.example.janche.user.domain.Role; 5 | import com.example.janche.user.dto.LoginUserDTO; 6 | import lombok.Setter; 7 | import org.springframework.beans.BeanUtils; 8 | import org.springframework.security.core.GrantedAuthority; 9 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | 12 | import java.io.Serializable; 13 | import java.util.ArrayList; 14 | import java.util.Collection; 15 | import java.util.List; 16 | 17 | public class SecurityUser extends LoginUserDTO implements UserDetails, Serializable { 18 | 19 | @Setter 20 | private Boolean accountNonExpired=true; 21 | @Setter 22 | private Boolean accountNonLocked=true; 23 | @Setter 24 | private Boolean credentialsNonExpired=true; 25 | @Setter 26 | private Boolean enabled=true; 27 | public SecurityUser (LoginUserDTO user) { 28 | if(user != null) { 29 | BeanUtils.copyProperties(user, this); 30 | } 31 | } 32 | 33 | @Override 34 | public Collection getAuthorities() { 35 | Collection authorities = new ArrayList<>(); 36 | List userRoles = this.getRoles(); 37 | if(userRoles != null){ 38 | for (Role role : userRoles) { 39 | SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + role.getName()); 40 | authorities.add(authority); 41 | } 42 | } 43 | return authorities; 44 | } 45 | 46 | @Override 47 | public String getPassword() { 48 | return super.getPassword(); 49 | } 50 | 51 | @Override 52 | public String getUsername() { 53 | return super.getUsername(); 54 | } 55 | 56 | 57 | @Override 58 | public boolean isAccountNonExpired() { 59 | return this.accountNonExpired; 60 | } 61 | 62 | @Override 63 | public boolean isAccountNonLocked() { 64 | return this.accountNonLocked; 65 | } 66 | 67 | @Override 68 | public boolean isCredentialsNonExpired() { 69 | return this.credentialsNonExpired; 70 | } 71 | 72 | @Override 73 | public boolean isEnabled() { 74 | return this.enabled; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/utils/SecurityUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.utils; 2 | 3 | import com.example.janche.common.util.IPUtils; 4 | import com.example.janche.log.domain.SysLog; 5 | import com.example.janche.security.authentication.SecurityUser; 6 | import com.example.janche.user.dto.LoginUserDTO; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.context.SecurityContextHolder; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import java.util.Date; 13 | 14 | 15 | @Component 16 | public class SecurityUtils { 17 | 18 | /** 19 | * 判断当前用户是否已经登陆 20 | * @return 登陆状态返回 true, 否则返回 false 21 | */ 22 | public static boolean isLogin() { 23 | String username = SecurityContextHolder.getContext().getAuthentication().getName(); 24 | return !"anonymousUser".equals(username); 25 | } 26 | /** 27 | * 取得登陆用户的 ID, 如果没有登陆则返回 -1 28 | * @return 登陆用户的 ID 29 | */ 30 | public static Long getLoginUserId() { 31 | Object principle = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 32 | if (SecurityUtils.isLogin()) { 33 | SecurityUser userDetails = (SecurityUser) principle; 34 | return userDetails.getId(); 35 | } 36 | return -1L; 37 | } 38 | /** 39 | * 40 | * 功能:返回当前用户
    41 | * @return 42 | * @exception 43 | * 44 | */ 45 | public static LoginUserDTO getCurrentUser() { 46 | if (SecurityContextHolder.getContext().getAuthentication() != null) { 47 | if ((SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof LoginUserDTO)) { 48 | return (LoginUserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 49 | } 50 | } 51 | return null; 52 | } 53 | 54 | /** 55 | * 构建Security操作的日志 56 | * @param request 57 | */ 58 | public static SysLog buildLog(HttpServletRequest request, Authentication authentication) { 59 | LoginUserDTO user = (LoginUserDTO) authentication.getPrincipal(); 60 | SysLog sysLog = new SysLog(); 61 | sysLog.setLogUser(user.getId()); 62 | sysLog.setCreateTime(new Date()); 63 | sysLog.setLogIp(IPUtils.getIpAddr(request)); 64 | sysLog.setLogMethod(request.getMethod()); 65 | return sysLog; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/manager/UrlAccessDecisionManager.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.manager; 2 | 3 | import com.example.janche.common.model.Constant; 4 | import org.springframework.security.access.AccessDecisionManager; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.security.access.ConfigAttribute; 7 | import org.springframework.security.authentication.AnonymousAuthenticationToken; 8 | import org.springframework.security.authentication.BadCredentialsException; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.AuthenticationException; 11 | import org.springframework.security.core.GrantedAuthority; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.Collection; 15 | import java.util.Iterator; 16 | 17 | 18 | @Component("urlAccessDecisionManager") 19 | public class UrlAccessDecisionManager implements AccessDecisionManager { 20 | 21 | @Override 22 | public void decide(Authentication auth, Object o, Collection collection) throws AccessDeniedException, AuthenticationException { 23 | 24 | //当前用户所具有的权限 25 | Collection authorities = auth.getAuthorities(); 26 | Iterator iterator = collection.iterator(); 27 | while (iterator.hasNext()) { 28 | ConfigAttribute ca = iterator.next(); 29 | //当前请求需要的权限 30 | String needRole = ca.getAttribute(); 31 | if ("ROLE_LOGIN".equals(needRole)) { 32 | if (auth instanceof AnonymousAuthenticationToken) { 33 | throw new BadCredentialsException("用户未登录"); 34 | } else { 35 | return; 36 | } 37 | } 38 | //当前用户所具有的权限 39 | for (GrantedAuthority authority : authorities) { 40 | if (authority.getAuthority().equals(needRole) || 41 | Constant.ROLE_ADMIN.equals(authority.getAuthority())) { 42 | return; 43 | } 44 | } 45 | } 46 | throw new AccessDeniedException("权限不足!"); 47 | } 48 | 49 | @Override 50 | public boolean supports(ConfigAttribute configAttribute) { 51 | return true; 52 | } 53 | 54 | @Override 55 | public boolean supports(Class aClass) { 56 | return true; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /swagger/src/main/java/com/example/janche/swagger/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.swagger; 2 | 3 | import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.Import; 9 | import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; 10 | import springfox.documentation.builders.ApiInfoBuilder; 11 | import springfox.documentation.builders.PathSelectors; 12 | import springfox.documentation.builders.RequestHandlerSelectors; 13 | import springfox.documentation.service.ApiInfo; 14 | import springfox.documentation.service.Contact; 15 | import springfox.documentation.spi.DocumentationType; 16 | import springfox.documentation.spring.web.plugins.Docket; 17 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 18 | 19 | @Configuration 20 | @EnableKnife4j 21 | @Import(BeanValidatorPluginsConfiguration.class) 22 | @EnableConfigurationProperties(SwaggerProperties.class) 23 | public class SwaggerConfig { 24 | @Autowired 25 | private SwaggerProperties swaggerProperties; 26 | 27 | @Bean 28 | public Docket api() { 29 | return new Docket(DocumentationType.SWAGGER_2) 30 | .apiInfo(apiInfo()) 31 | .select() 32 | // 自行修改为自己的包路径 33 | .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasepackage())) 34 | .paths(PathSelectors.any()) 35 | .build(); 36 | } 37 | 38 | private ApiInfo apiInfo() { 39 | ApiInfoBuilder apiInfoBuilder = new ApiInfoBuilder(); 40 | if (swaggerProperties.getTitle() != null) { 41 | apiInfoBuilder.title(swaggerProperties.getTitle()); 42 | } 43 | if (swaggerProperties.getContractName() != null && swaggerProperties.getContractUrl() != null 44 | && swaggerProperties.getContractEmail() != null) { 45 | apiInfoBuilder.contact(new Contact(swaggerProperties.getContractName(), swaggerProperties.getContractUrl(), 46 | swaggerProperties.getContractEmail())); 47 | } 48 | if (swaggerProperties.getVersion() != null) { 49 | apiInfoBuilder.version(swaggerProperties.getVersion()); 50 | } 51 | return apiInfoBuilder.build(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /backend/src/test/resources/generator/template/default/controller.ftl: -------------------------------------------------------------------------------- 1 | package ${basePackage}.web.controller.${moduleName}; 2 | 3 | import ${basePackage}.common.utils.restResult.RestResult; 4 | import ${basePackage}.common.utils.restResult.ResultGenerator; 5 | import ${basePackage}.modules.${moduleName}.domain.${modelNameUpperCamel}; 6 | import ${basePackage}.modules.${moduleName}.service.${modelNameUpperCamel}Service; 7 | import com.github.pagehelper.PageHelper; 8 | import com.github.pagehelper.PageInfo; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.annotation.Resource; 16 | import java.util.List; 17 | 18 | 19 | /** 20 | * @author ${author} 21 | * @date ${date} 22 | */ 23 | @Slf4j 24 | @RestController 25 | @RequestMapping("${baseRequestMapping}") 26 | public class ${modelNameUpperCamel}Controller { 27 | @Resource 28 | private ${modelNameUpperCamel}Service ${modelNameLowerCamel}Service; 29 | 30 | @PostMapping("/add") 31 | public RestResult add(${modelNameUpperCamel} ${modelNameLowerCamel}) { 32 | ${modelNameLowerCamel}Service.save(${modelNameLowerCamel}); 33 | return ResultGenerator.genSuccessResult(); 34 | } 35 | 36 | @PostMapping("/delete") 37 | public RestResult delete(@RequestParam String id) { 38 | ${modelNameLowerCamel}Service.deleteById(id); 39 | return ResultGenerator.genSuccessResult(); 40 | } 41 | 42 | @PostMapping("/update") 43 | public RestResult update(${modelNameUpperCamel} ${modelNameLowerCamel}) { 44 | ${modelNameLowerCamel}Service.update(${modelNameLowerCamel}); 45 | return ResultGenerator.genSuccessResult(); 46 | } 47 | 48 | @PostMapping("/detail") 49 | public RestResult detail(@RequestParam String id) { 50 | ${modelNameUpperCamel} ${modelNameLowerCamel} = ${modelNameLowerCamel}Service.findById(id); 51 | return ResultGenerator.genSuccessResult(${modelNameLowerCamel}); 52 | } 53 | 54 | @PostMapping("/list") 55 | public RestResult list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) { 56 | PageHelper.startPage(page, size); 57 | List<${modelNameUpperCamel}> list = ${modelNameLowerCamel}Service.findAll(page,size); 58 | PageInfo pageInfo = new PageInfo(list); 59 | return ResultGenerator.genSuccessResult(pageInfo); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/dto/LoginUserDTO.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.dto; 2 | 3 | 4 | import com.example.janche.user.domain.MenuRight; 5 | import com.example.janche.user.domain.Role; 6 | import com.example.janche.user.dto.user.UserDTO; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | 12 | import java.io.Serializable; 13 | import java.util.Date; 14 | import java.util.List; 15 | 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @Data 19 | @Builder 20 | public class LoginUserDTO implements Serializable { 21 | 22 | /** 23 | * 主键ID 24 | */ 25 | private Long id; 26 | 27 | /** 28 | * 用户名 29 | */ 30 | private String username; 31 | 32 | /** 33 | * 密码 34 | */ 35 | private String password; 36 | 37 | /** 38 | * 真实姓名 39 | */ 40 | private String actualName; 41 | 42 | /** 43 | * 性别 44 | */ 45 | private int sex; 46 | 47 | /** 48 | * 电话 49 | */ 50 | private String phone; 51 | 52 | /** 53 | * 邮箱 54 | */ 55 | private String email; 56 | 57 | /** 58 | * 地址 59 | */ 60 | private String address; 61 | 62 | /** 63 | * 职务Id 64 | */ 65 | private Integer postId; 66 | 67 | /** 68 | * 职务名称 69 | */ 70 | private String postName; 71 | 72 | /** 73 | * 启用状态(0-禁用,1-启用) 74 | */ 75 | private Integer status; 76 | 77 | /** 78 | * 创建时间 79 | */ 80 | private Date createTime; 81 | 82 | /** 83 | * 修改时间 84 | */ 85 | private Date modifyTime; 86 | 87 | /** 88 | * 角色 89 | */ 90 | private List roles; 91 | 92 | /** 93 | * 权限菜单 94 | */ 95 | private List menus; 96 | 97 | public static LoginUserDTO user2LoginUserDTO(UserDTO user) { 98 | return LoginUserDTO.builder() 99 | .id(user.getId()) 100 | .username(user.getUsername()) 101 | .password(user.getPassword()) 102 | .address(user.getAddress()) 103 | .actualName(user.getActualName()) 104 | .email(user.getEmail()) 105 | .postId(user.getPostId()) 106 | .postName(user.getPostName()) 107 | .phone(user.getPhone()) 108 | .status(user.getStatus()) 109 | .createTime(user.getCreateTime()) 110 | .modifyTime(user.getModifyTime()) 111 | .roles(user.getRoles()) 112 | .menus(user.getMenus()) 113 | .build(); 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/user/service/impl/MenuRightServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.user.service.impl; 2 | 3 | import com.example.janche.common.core.AbstractService; 4 | import com.example.janche.common.restResult.PageParam; 5 | import com.example.janche.user.dao.MenuRightMapper; 6 | import com.example.janche.user.domain.MenuRight; 7 | import com.example.janche.user.dto.MenuDTO; 8 | import com.example.janche.user.service.MenuRightService; 9 | import com.github.pagehelper.PageHelper; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | import tk.mybatis.mapper.entity.Example; 14 | 15 | import javax.annotation.Resource; 16 | import java.util.List; 17 | 18 | /** 19 | * @author lirong 20 | * @date 2019-7-19 09:41:37 21 | * @desc 权限service 22 | */ 23 | @Slf4j 24 | @Service 25 | @Transactional 26 | public class MenuRightServiceImpl extends AbstractService implements MenuRightService { 27 | 28 | @Resource 29 | private MenuRightMapper menuRightMapper; 30 | 31 | @Override 32 | public List list(PageParam pageParam, String query) { 33 | Example example = new Example(MenuRight.class); 34 | // example.or().andLike("code", "%"+query+"%"); 35 | // example.or().andLike("deviceId", "%"+query+"%"); 36 | 37 | PageHelper.startPage(pageParam.getPage(), pageParam.getSize(), pageParam.getOrderBy()); 38 | return menuRightMapper.selectByExample(example); 39 | } 40 | 41 | /** 42 | * 新增权限 43 | * @param menuRight 权限菜单实体对象 44 | */ 45 | @Override 46 | public void addMenuRight(MenuRight menuRight) { 47 | menuRightMapper.insert(menuRight); 48 | } 49 | 50 | /** 51 | * 删除权限 52 | * @param id 权限菜单id 53 | */ 54 | @Override 55 | public void deleteMenuRight(Long id) { 56 | menuRightMapper.deleteByPrimaryKey(id); 57 | } 58 | 59 | /** 60 | * 修改权限 61 | * @param menuRight 权限菜单节点对象 62 | */ 63 | @Override 64 | public void updateMenuRight(MenuRight menuRight) { 65 | menuRightMapper.updateByPrimaryKeySelective(menuRight); 66 | } 67 | 68 | /** 69 | * 权限详情 70 | * @param id 权限菜单节点id 71 | * @return 72 | */ 73 | @Override 74 | public MenuRight findOne(Long id) { 75 | return menuRightMapper.selectByPrimaryKey(id); 76 | } 77 | 78 | /** 79 | * 获取用户所有权限 80 | * @return 81 | */ 82 | @Override 83 | public List getUserMenus(Long userId) { 84 | // return menuRightMapper.getUserMenus(userId); 85 | return null; 86 | } 87 | 88 | /** 89 | * 获取系统列表 90 | * @return 91 | */ 92 | @Override 93 | public List getSystemList() { 94 | Example example = new Example(MenuRight.class); 95 | example.and().andEqualTo("grades", 1); 96 | return menuRightMapper.selectByExample(example); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /web/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | #开发环境 2 | server: 3 | port: 9999 4 | # session失效时间 5 | servlet: 6 | session: 7 | timeout: 7200s 8 | 9 | spring: 10 | profiles: 11 | include: sysconfig 12 | #json数据 日期 格式化 13 | jackson: 14 | date-format: "yyyy-MM-dd HH:mm:ss" 15 | time-zone: GMT+8 16 | # 数据源 17 | datasource: 18 | driver-class-name: com.mysql.cj.jdbc.Driver 19 | url: jdbc:mysql://192.168.0.25:3306/boot2-oauth?useUnicode=true&characterEncoding=UTF-8&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC 20 | username: root 21 | password: xuejinyu 22 | 23 | # Druid连接池配置 24 | type: com.alibaba.druid.pool.DruidDataSource 25 | druid: 26 | # 初始化 27 | initialSize: 3 28 | # 最大 29 | maxActive: 20 30 | # 最小 31 | minIdle: 3 32 | # 最大连接等待超时时间 33 | maxWait: 60000 34 | # 打开PSCache,并且指定每个连接PSCache的大小 35 | poolPreparedStatements: true 36 | maxPoolPreparedStatementPerConnectionSize: 20 37 | validationQuery: select 'x' 38 | testWhileIdle: true 39 | testOnBorrow: false 40 | testOnReturn: false 41 | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 42 | timeBetweenEvictionRunsMillis: 60000 43 | # 配置一个连接在池中最小生存的时间,单位是毫秒 44 | minEvictableIdleTimeMillis: 300000 45 | # 配置监控统计拦截的filters,去掉后监控界面sql将无法统计,'wall'用于防火墙 46 | filters: stat, wall, slf4j 47 | 48 | # http 49 | http: 50 | # 过滤字符编码 51 | encoding: 52 | charset: UTF-8 53 | enabled: true 54 | force: true 55 | 56 | # 文件上传大小 57 | servlet: 58 | multipart: 59 | # 单个文件大小 60 | max-file-size: 50MB 61 | # 一次传多个文件的总大小 62 | max-request-size: 100MB 63 | 64 | #redis 65 | redis: 66 | database: 0 67 | # Redis服务器地址 68 | host: 127.0.0.1 69 | port: 6379 70 | password: 71 | timeout: 5000ms 72 | 73 | jedis: 74 | pool: 75 | # 连接池中的最大连接数 76 | max-active: 8 77 | # 连接池中的最大空闲连接 78 | max-idle: 8 79 | min-idle: 0 80 | max-wait: -1ms 81 | # 取消spring对freemarker默认templates目录的检测 82 | freemarker: 83 | check-template-location: false 84 | jpa: 85 | open-in-view: false 86 | 87 | ### Mybatis Config ### 88 | mybatis: 89 | check-config-location: true 90 | typeAliasesPackage: com.example.janche.**.domain 91 | mapperLocations: classpath:mapper/**/*.xml 92 | type-handlers-package: com.example.janche.common.mybatis.handler.* 93 | 94 | ## Pagehelper 95 | pagehelper: 96 | helperDialect: mysql 97 | reasonable: true 98 | supportMethodsArguments: true 99 | params: count=countSql 100 | 101 | ### 通用 Mapper ### 102 | mapper: 103 | IDENTITY: mysql 104 | notEmpty: false 105 | mappers: 106 | - com.example.janche.common.core.Mapper 107 | - com.example.janche.common.core.TkMapper 108 | 109 | # 日志 110 | logging.config: classpath:logging-spring.xml 111 | swagger: 112 | title: 脚手架接口文档 113 | basepackage: com.example.janche 114 | version: 1.0.0 115 | contract-name: Janche 116 | contract-url: https://blog.csdn.net/qq_34997906 117 | contract-email: lirong_xx@qq.com 118 | 119 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/utils/ResponseUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.utils; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.example.janche.common.exception.CustomException; 5 | import com.example.janche.common.restResult.RestResult; 6 | import com.example.janche.common.restResult.ResultCode; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.util.Arrays; 13 | 14 | @Slf4j 15 | public class ResponseUtils { 16 | 17 | public static void addResponseHeader(HttpServletResponse response , String[] origins, String originHeader) { 18 | String[] IPs = origins; 19 | response.setContentType("application/json;charset=UTF-8"); 20 | response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); 21 | response.setHeader("Access-Control-Allow-Credentials", "true"); 22 | response.setHeader( "Access-Control-Allow-Headers", "Content-Type"); 23 | // response.setHeader("Access-Control-Allow-Origin", "*"); 24 | if (Arrays.asList(IPs).contains(originHeader)) { 25 | response.setHeader("Access-Control-Allow-Origin", originHeader); 26 | } 27 | } 28 | 29 | 30 | public static void renderJson(HttpServletRequest request, HttpServletResponse response, CustomException e, String[] origins) { 31 | renderJson(request, response, e.getResultCode(), null, origins); 32 | } 33 | 34 | public static void renderJson(HttpServletRequest request, HttpServletResponse response, ResultCode code, String[] origins) { 35 | renderJson(request, response, code, null, origins); 36 | } 37 | 38 | /** 39 | * 往 response 写出 json 40 | * 41 | * @param response 响应 42 | * @param code 状态 43 | * @param data 返回数据 44 | */ 45 | public static void renderJson(HttpServletRequest request, HttpServletResponse response, ResultCode code, Object data, String[] origins) { 46 | try { 47 | String origin = request.getHeader("Origin"); 48 | addResponseHeader(response, origins, origin); 49 | response.setStatus(200); 50 | // 将JSON转为String的时候,忽略null值的时候转成的String存在错误 51 | RestResult result = null != data ? new RestResult(code, data) : new RestResult(code); 52 | response.getWriter().write(JSON.toJSONString(result)); 53 | } catch (IOException ex) { 54 | log.error("Response写出JSON异常,", ex); 55 | } 56 | } 57 | 58 | /** 59 | * 往 response 写出 json 60 | * 61 | * @param response 响应 62 | * @param result 返回数据 63 | */ 64 | public static void renderSuccessJson(HttpServletRequest request, HttpServletResponse response, RestResult result, String[] origins) { 65 | try { 66 | String origin = request.getHeader("Origin"); 67 | addResponseHeader(response, origins, origin); 68 | response.setStatus(200); 69 | response.getWriter().write(JSON.toJSONString(result)); 70 | } catch (IOException ex) { 71 | log.error("Response写出JSON异常,", ex); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /backend/src/main/resources/mapper/user/MenuRightMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 53 | 54 | 55 | 69 | 70 | -------------------------------------------------------------------------------- /backend/src/main/resources/mapper/user/RoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/hadler/UserLoginSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.hadler; 2 | 3 | 4 | import com.alibaba.fastjson.JSON; 5 | import com.example.janche.common.config.IApplicationConfig; 6 | import com.example.janche.common.restResult.RestResult; 7 | import com.example.janche.common.util.IPUtils; 8 | import com.example.janche.log.domain.SysLog; 9 | import com.example.janche.log.service.SysLogService; 10 | import com.example.janche.security.utils.ResponseUtils; 11 | import com.example.janche.security.utils.SecurityUtils; 12 | import com.example.janche.user.dao.MenuRightMapper; 13 | import com.example.janche.user.domain.MenuRight; 14 | import com.example.janche.user.dto.LoginOutpDTO; 15 | import com.example.janche.user.dto.LoginUserDTO; 16 | import lombok.extern.slf4j.Slf4j; 17 | import org.springframework.beans.BeanUtils; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.security.core.Authentication; 20 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 21 | import org.springframework.stereotype.Component; 22 | 23 | import javax.annotation.Resource; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | import java.io.IOException; 27 | import java.util.List; 28 | 29 | @Component("userLoginSuccessHandler") 30 | @Slf4j 31 | public class UserLoginSuccessHandler implements AuthenticationSuccessHandler { 32 | @Resource 33 | private MenuRightMapper menuRightMapper; 34 | @Autowired 35 | private IApplicationConfig applicationConfig; 36 | @Resource 37 | private SysLogService sysLogService; 38 | 39 | 40 | @Override 41 | public void onAuthenticationSuccess(HttpServletRequest request, 42 | HttpServletResponse response, 43 | Authentication authentication) throws IOException { 44 | 45 | //获得授权后可得到用户信息 可使用SecurityUserService进行数据库操作 46 | LoginUserDTO userDetails = (LoginUserDTO) authentication.getPrincipal(); 47 | Long userId = userDetails.getId(); 48 | List menus = menuRightMapper.getUserMenus(userId); 49 | LoginOutpDTO dto = new LoginOutpDTO(); 50 | BeanUtils.copyProperties(userDetails, dto); 51 | dto.setMenus(menus); 52 | 53 | //输出登录提示信息 54 | log.info("用户 " + userDetails.getUsername() + " 登录"); 55 | log.info("用户 " + JSON.toJSONString(authentication.getAuthorities()) + "角色权限"); 56 | log.info("IP :"+ IPUtils.getIpAddr(request)); 57 | 58 | // 记录登录成功的日志 59 | this.saveLog(request, authentication); 60 | // JSON 格式的返回 61 | ResponseUtils.renderSuccessJson(request, response, new RestResult(200, "登录成功", dto), applicationConfig.getOrigins()); 62 | } 63 | 64 | 65 | /** 66 | * 记录登录成功的日志 67 | * @param request 68 | */ 69 | private void saveLog(HttpServletRequest request, Authentication authentication) { 70 | LoginUserDTO user = (LoginUserDTO) authentication.getPrincipal(); 71 | SysLog sysLog = SecurityUtils.buildLog(request, authentication); 72 | sysLog.setOperation(5); 73 | sysLog.setLogDesc(user.getUsername() + " 登录了系统 "); 74 | sysLog.setLogType(2); 75 | sysLogService.saveLog(sysLog); 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/provider/SecurityAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.provider; 2 | 3 | import com.example.janche.security.authentication.SecurityUser; 4 | import com.example.janche.security.utils.SecurityUtils; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.beans.factory.annotation.Qualifier; 8 | import org.springframework.security.authentication.*; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.AuthenticationException; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | import org.springframework.stereotype.Component; 15 | 16 | import javax.annotation.Resource; 17 | 18 | 19 | @Component("securityAuthenticationProvider") 20 | @Slf4j 21 | public class SecurityAuthenticationProvider implements AuthenticationProvider { 22 | 23 | 24 | @Autowired 25 | @Qualifier("securityUserService") 26 | UserDetailsService securityUserService; 27 | 28 | @Resource(name = "securityUtils") 29 | private SecurityUtils securityUtils; 30 | 31 | @Autowired 32 | @Qualifier("passwordEncoder") 33 | private PasswordEncoder passwordEncoder; 34 | 35 | @Override 36 | public Authentication authenticate(Authentication authentication ) throws AuthenticationException { 37 | 38 | System.out.println("*********************"); 39 | // [1] 获取 username 和 password 40 | String userName = (String) authentication.getPrincipal(); 41 | String inputPassword = (String) authentication.getCredentials(); 42 | 43 | // [2] 使用用户名从数据库读取用户信息 44 | SecurityUser userDetails = (SecurityUser) securityUserService.loadUserByUsername(userName); 45 | 46 | // 判断账号是否被禁用 47 | if (null != userDetails && userDetails.getStatus() == 0){ 48 | userDetails.setEnabled(false); 49 | } 50 | 51 | // [3] 检查用户信息 52 | if(userDetails == null) { 53 | throw new UsernameNotFoundException(userName + " 用户不存在"); 54 | } else if (!userDetails.isEnabled()){ 55 | throw new DisabledException(userName + " 用户已被禁用,请联系管理员"); 56 | } else if (!userDetails.isAccountNonExpired()) { 57 | throw new AccountExpiredException(userName + " 账号已过期"); 58 | } else if (!userDetails.isAccountNonLocked()) { 59 | throw new LockedException(userName + " 账号已被锁定"); 60 | } else if (!userDetails.isCredentialsNonExpired()) { 61 | throw new LockedException(userName + " 凭证已过期"); 62 | } 63 | 64 | // [4] 数据库用户的密码,一般都是加密过的 65 | String encryptedPassword = userDetails.getPassword(); 66 | // 根据加密算法加密用户输入的密码,然后和数据库中保存的密码进行比较 67 | if(!passwordEncoder.matches(inputPassword, encryptedPassword)) { 68 | throw new BadCredentialsException(userName + " 输入账号或密码不正确"); 69 | } 70 | 71 | // [5] 成功登陆,把用户信息提交给 Spring Security 72 | // 把 userDetails 作为 principal 的好处是可以放自定义的 UserDetails,这样可以存储更多有用的信息,而不只是 username, 73 | // 默认只有 username,这里的密码使用数据库中保存的密码,而不是用户输入的明文密码,否则就暴露了密码的明文 74 | return new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities()); 75 | } 76 | 77 | @Override 78 | public boolean supports( Class authentication ) { 79 | return authentication.equals(UsernamePasswordAuthenticationToken.class); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/utils/encrypt/Encodes.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.utils.encrypt; 2 | 3 | import org.apache.commons.codec.DecoderException; 4 | import org.apache.commons.codec.binary.Base64; 5 | import org.apache.commons.codec.binary.Hex; 6 | import org.apache.commons.lang3.StringEscapeUtils; 7 | 8 | import java.io.UnsupportedEncodingException; 9 | import java.net.URLDecoder; 10 | import java.net.URLEncoder; 11 | 12 | /** 13 | *

    封装各种格式的编码解码工具类.

    14 | *
  • 1.Commons-Codec的 hex/base64 编码
  • 15 | *
  • 2.自定义的base62 编码
  • 16 | *
  • 3.Commons-Lang的xml/html escape
  • 17 | *
  • 4.JDK提供的URLEncoder
  • 18 | * @author qxb 19 | * @version 1.0 20 | * @since 2018.01.24 21 | * 22 | */ 23 | public class Encodes { 24 | private static final String DEFAULT_URL_ENCODING = "UTF-8"; 25 | private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); 26 | 27 | /** 28 | * Hex编码. 29 | */ 30 | public static String encodeHex(byte[] input) { 31 | return Hex.encodeHexString(input); 32 | } 33 | 34 | /** 35 | * Hex解码. 36 | */ 37 | public static byte[] decodeHex(String input) { 38 | try { 39 | return Hex.decodeHex(input.toCharArray()); 40 | } catch (DecoderException e) { 41 | throw new RuntimeException("Hex解码出错:",e); 42 | } 43 | } 44 | 45 | /** 46 | * Base64编码. 47 | */ 48 | public static String encodeBase64(byte[] input) { 49 | return Base64.encodeBase64String(input); 50 | } 51 | 52 | /** 53 | * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548). 54 | */ 55 | public static String encodeUrlSafeBase64(byte[] input) { 56 | return Base64.encodeBase64URLSafeString(input); 57 | } 58 | 59 | /** 60 | * Base64解码. 61 | */ 62 | public static byte[] decodeBase64(String input) { 63 | return Base64.decodeBase64(input); 64 | } 65 | 66 | /** 67 | * Base62编码。 68 | */ 69 | public static String encodeBase62(byte[] input) { 70 | char[] chars = new char[input.length]; 71 | for (int i = 0; i < input.length; i++) { 72 | chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)]; 73 | } 74 | return new String(chars); 75 | } 76 | 77 | /** 78 | * Html 转码. 79 | */ 80 | public static String escapeHtml(String html) { 81 | return StringEscapeUtils.escapeHtml4(html); 82 | } 83 | 84 | /** 85 | * Html 解码. 86 | */ 87 | public static String unescapeHtml(String htmlEscaped) { 88 | return StringEscapeUtils.unescapeHtml4(htmlEscaped); 89 | } 90 | 91 | /** 92 | * Xml 转码. 93 | */ 94 | public static String escapeXml(String xml) { 95 | return StringEscapeUtils.escapeXml(xml); 96 | } 97 | 98 | /** 99 | * Xml 解码. 100 | */ 101 | public static String unescapeXml(String xmlEscaped) { 102 | return StringEscapeUtils.unescapeXml(xmlEscaped); 103 | } 104 | 105 | /** 106 | * URL 编码, Encode默认为UTF-8. 107 | */ 108 | public static String urlEncode(String part) { 109 | try { 110 | return URLEncoder.encode(part, DEFAULT_URL_ENCODING); 111 | } catch (UnsupportedEncodingException e) { 112 | throw new RuntimeException("URL 编码出错:",e); 113 | } 114 | } 115 | 116 | /** 117 | * URL 解码, Encode默认为UTF-8. 118 | */ 119 | public static String urlDecode(String part) { 120 | 121 | try { 122 | return URLDecoder.decode(part, DEFAULT_URL_ENCODING); 123 | } catch (UnsupportedEncodingException e) { 124 | throw new RuntimeException("URL 解码出错:",e); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/util/IPUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.util; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | /** 6 | * 从httprequest中获取IP地址等信息 7 | */ 8 | public class IPUtils { 9 | 10 | /** 11 | * 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址, 12 | * @param request 13 | * @return 14 | */ 15 | public static String getIpAddr(HttpServletRequest request) { 16 | String ip = request.getHeader("x-forwarded-for"); 17 | 18 | if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) { 19 | ip = request.getHeader("Proxy-Client-IP"); 20 | } 21 | 22 | if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) { 23 | ip = request.getHeader("WL-Proxy-Client-IP"); 24 | } 25 | 26 | if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) { 27 | ip = request.getHeader("HTTP_CLIENT_IP"); 28 | } 29 | 30 | if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) { 31 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 32 | } 33 | 34 | if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) { 35 | ip = request.getRemoteAddr(); 36 | } 37 | 38 | return ip; 39 | } 40 | 41 | /** 42 | * 判断IP是否在此IP段中 43 | * @param ipSection 44 | * @param ip 45 | * @return 46 | */ 47 | public static boolean ipIsValid(String ipSection, String ip) { 48 | if (ipSection == null) { 49 | throw new NullPointerException("IP段不能为空!"); 50 | } 51 | if (ip == null) { 52 | throw new NullPointerException("IP不能为空!"); 53 | } 54 | ipSection = ipSection.trim(); 55 | ip = ip.trim(); 56 | final String REGX_IP = "((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)"; 57 | final String REGX_IPB = REGX_IP + "\\-" + REGX_IP; 58 | if (!ipSection.matches(REGX_IPB) || !ip.matches(REGX_IP)) { 59 | return false; 60 | } 61 | int idx = ipSection.indexOf('-'); 62 | String[] sips = ipSection.substring(0, idx).split("\\."); 63 | String[] sipe = ipSection.substring(idx + 1).split("\\."); 64 | String[] sipt = ip.split("\\."); 65 | long ips = 0L, ipe = 0L, ipt = 0L; 66 | for (int i = 0; i < 4; ++i) { 67 | ips = ips << 8 | Integer.parseInt(sips[i]); 68 | ipe = ipe << 8 | Integer.parseInt(sipe[i]); 69 | ipt = ipt << 8 | Integer.parseInt(sipt[i]); 70 | } 71 | if (ips > ipe) { 72 | long t = ips; 73 | ips = ipe; 74 | ipe = t; 75 | } 76 | return ips <= ipt && ipt <= ipe; 77 | } 78 | 79 | /** 80 | * 判断IP地址的合法性,这里采用了正则表达式的方法来判断 81 | * return true,合法,false 不合法 82 | * */ 83 | public static boolean iPCheck(String text) { 84 | if (text != null && !text.isEmpty()) { 85 | // 定义正则表达式 86 | String regex = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$"; 87 | // 判断ip地址是否与正则表达式匹配 88 | if (text.matches(regex)) { 89 | // 返回判断信息 90 | return true; 91 | } else { 92 | // 返回判断信息 93 | return false; 94 | } 95 | } 96 | return false; 97 | } 98 | 99 | public static void main(String[] args) { 100 | // if (ipIsValid("192.168.99.1-192.168.99.255", "192.168.99.54")) { 101 | // System.out.println("ip属于该网段"); 102 | // } else { 103 | // System.out.println("ip不属于该网段"); 104 | // } 105 | boolean b = iPCheck("192.168.99.1"); 106 | System.out.println(b); 107 | } 108 | 109 | } 110 | 111 | 112 | -------------------------------------------------------------------------------- /web/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${project.name} 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | ${project.pattern} 17 | 18 | 19 | 20 | 21 | 22 | ${project.pattern} 23 | 24 | 25 | ${log.path}/%d{YYYY-MM-dd}/${project.name}_info_%d{YYYY-MM-dd}_%i.log 26 | 3GB 27 | 14 28 | 29 | 30 | INFO 31 | ACCEPT 32 | DENY 33 | 34 | 35 | 36 | 37 | 38 | ${project.pattern} 39 | 40 | 41 | ${log.path}/%d{YYYY-MM-dd}/${project.name}_warn_%d{YYYY-MM-dd}_%i.log 42 | 3GB 43 | 14 44 | 45 | 46 | WARN 47 | ACCEPT 48 | DENY 49 | 50 | 51 | 52 | 53 | 54 | ${project.pattern} 55 | 56 | 57 | ${log.path}/%d{YYYY-MM-dd}/${project.name}_error_%d{YYYY-MM-dd}_%i.log 58 | 3GB 59 | 14 60 | 61 | 62 | ERROR 63 | ACCEPT 64 | DENY 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 79 | 80 | 81 | 82 | 83 | 84 | 87 | 88 | -------------------------------------------------------------------------------- /backend/src/test/resources/generator/template/simpleDict/controller.ftl: -------------------------------------------------------------------------------- 1 | package ${modulePackage}.web.controller.${moduleName}; 2 | 3 | import ${modulePackage}.${moduleName}.domain.${modelNameUpperCamel}; 4 | import ${modulePackage}.${moduleName}.service.${modelNameUpperCamel}Service; 5 | import ${basePackage}.common.restResult.RestResult; 6 | import ${basePackage}.common.restResult.ResultGenerator; 7 | import ${basePackage}.web.aop.Log; 8 | import ${basePackage}.common.restResult.PageParam; 9 | 10 | import com.github.pagehelper.PageInfo; 11 | import io.swagger.annotations.Api; 12 | import io.swagger.annotations.ApiOperation; 13 | import io.swagger.annotations.ApiParam; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | import javax.annotation.Resource; 18 | import java.util.Date; 19 | import java.util.List; 20 | /** 21 | * 22 | * @author ${author} 23 | * @Description: // TODO 1. 为类添加注释 24 | * @date ${date} 25 | */ 26 | @Slf4j 27 | @RestController 28 | @RequestMapping("${baseRequestMapping}")//TODO 2. 适当修改url 29 | @Api(basePath = "${baseRequestMapping}", tags = "XX模块管理") //TODO 3. 修改tags内容 30 | public class ${modelNameUpperCamel}Controller { 31 | @Resource 32 | private ${modelNameUpperCamel}Service ${modelNameLowerCamel}Service; 33 | 34 | @Log 35 | @PostMapping 36 | @ApiOperation(value = "新增XX", notes = "单个新增", produces = "application/json") // TODO 4. API方法的说明 37 | public RestResult add(@ApiParam(name = "XX信息", required = true) ${modelNameUpperCamel} ${modelNameLowerCamel}) { // TODO 5. API方法参数的说明 38 | ${modelNameLowerCamel}.setCreateTime(new Date()); 39 | ${modelNameLowerCamel}Service.save(${modelNameLowerCamel}); 40 | return ResultGenerator.genSuccessResult().setMessage("保存成功"); 41 | } 42 | 43 | @Log 44 | @DeleteMapping 45 | @ApiOperation(value = "删除XX", notes = "单个删除", produces = "application/json") 46 | public RestResult delete(@ApiParam(name = "XX信息", required = true) Long id) { 47 | ${modelNameLowerCamel}Service.deleteById(id); 48 | return ResultGenerator.genSuccessResult().setMessage("删除成功"); 49 | } 50 | 51 | @Log 52 | @PutMapping 53 | @ApiOperation(value = "修改XX", notes = "单个修改" , code = 200, produces = "application/json") 54 | public RestResult update(@ApiParam(name = "XX信息", required = true) ${modelNameUpperCamel} ${modelNameLowerCamel}) { 55 | ${modelNameLowerCamel}.setModifyTime(new Date()); 56 | ${modelNameLowerCamel}Service.update(${modelNameLowerCamel}); 57 | return ResultGenerator.genSuccessResult().setMessage("修改成功"); 58 | } 59 | 60 | @Log 61 | @GetMapping 62 | @ApiOperation(value = "获取XX信息", notes = "单个获取", code = 200, produces = "application/json") 63 | public RestResult detail(@ApiParam(value = "主键ID") @RequestParam Long id) { 64 | ${modelNameUpperCamel} ${modelNameLowerCamel} = ${modelNameLowerCamel}Service.findById(id); 65 | return ResultGenerator.genSuccessResult(${modelNameLowerCamel}); 66 | } 67 | 68 | /** 69 | * 用于分页查询,默认可以不用传分页信息 70 | * 默认值:page=1,size=10,sortField="id",sortOrder="ASC" 71 | */ 72 | @Log 73 | @GetMapping(value = "/list") 74 | @ApiOperation(value = "XX列表分页查询", notes = "分页列表", code = 200, produces = "application/json") 75 | public RestResult list(@ApiParam(value = "分页信息") PageParam pageParam, 76 | @ApiParam(value = "查询条件") @RequestParam(required = false, defaultValue = "") String query) { 77 | List<${modelNameUpperCamel}> list = ${modelNameLowerCamel}Service.list(pageParam, query); 78 | PageInfo pageInfo = new PageInfo(list); 79 | return ResultGenerator.genSuccessResult(pageInfo); 80 | } 81 | 82 | /** 83 | * 下拉框查询所有 84 | */ 85 | @Log 86 | @ApiOperation(value = "XX列表查询所有", notes = "下拉框列表", code = 200, produces = "application/json") 87 | @GetMapping(value = "/all") 88 | public RestResult listAll() { 89 | List<${modelNameUpperCamel}> list = ${modelNameLowerCamel}Service.findAll(); 90 | return ResultGenerator.genSuccessResult(list); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/cache/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.cache; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.cache.CacheManager; 7 | import org.springframework.cache.annotation.CachingConfigurerSupport; 8 | import org.springframework.cache.interceptor.KeyGenerator; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.data.redis.cache.RedisCacheConfiguration; 12 | import org.springframework.data.redis.cache.RedisCacheManager; 13 | import org.springframework.data.redis.connection.RedisConnectionFactory; 14 | import org.springframework.data.redis.core.RedisTemplate; 15 | import org.springframework.data.redis.core.StringRedisTemplate; 16 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 17 | import org.springframework.data.redis.serializer.RedisSerializationContext; 18 | import org.springframework.data.redis.serializer.RedisSerializer; 19 | import org.springframework.data.redis.serializer.StringRedisSerializer; 20 | 21 | import java.time.Duration; 22 | 23 | /** redis配置 */ 24 | @Configuration 25 | public class RedisConfig extends CachingConfigurerSupport { 26 | // 自定义缓存key生成策略 27 | @Override 28 | @Bean 29 | public KeyGenerator keyGenerator() { 30 | return new KeyGenerator() { 31 | @Override 32 | public Object generate(Object target, java.lang.reflect.Method method, Object... params) { 33 | StringBuffer sb = new StringBuffer(); 34 | sb.append(target.getClass().getName()); 35 | sb.append(method.getName()); 36 | for (Object obj : params) { 37 | sb.append(obj.toString()); 38 | } 39 | return sb.toString(); 40 | } 41 | }; 42 | } 43 | 44 | // 缓存管理器 45 | @Bean 46 | public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { 47 | RedisSerializer redisSerializer = new StringRedisSerializer(); 48 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); 49 | 50 | //反序列化问题 51 | ObjectMapper om = new ObjectMapper(); 52 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 53 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 54 | jackson2JsonRedisSerializer.setObjectMapper(om); 55 | 56 | // 解决存储乱码问题 57 | RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() 58 | .entryTtl(Duration.ofHours(1))// 缓存过期时间1hours 59 | .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) 60 | .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) 61 | .disableCachingNullValues(); 62 | 63 | RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory) 64 | .cacheDefaults(config) 65 | .build(); 66 | return cacheManager; 67 | } 68 | 69 | @Bean 70 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) { 71 | StringRedisTemplate template = new StringRedisTemplate(factory); 72 | setSerializer(template);// 设置序列化工具 73 | template.afterPropertiesSet(); 74 | return template; 75 | } 76 | 77 | private void setSerializer(StringRedisTemplate template) { 78 | @SuppressWarnings({"rawtypes", "unchecked"}) 79 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); 80 | ObjectMapper om = new ObjectMapper(); 81 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 82 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 83 | jackson2JsonRedisSerializer.setObjectMapper(om); 84 | template.setValueSerializer(jackson2JsonRedisSerializer); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/controller/log/SysLogController.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.controller.log; 2 | 3 | import com.example.janche.log.domain.SysLog; 4 | import com.example.janche.log.dto.SysLogInputDTO; 5 | import com.example.janche.log.dto.SysLogOutpDTO; 6 | import com.example.janche.log.service.SysLogService; 7 | import com.example.janche.common.restResult.RestResult; 8 | import com.example.janche.common.restResult.ResultGenerator; 9 | import com.example.janche.web.aop.Log; 10 | import com.example.janche.common.restResult.PageParam; 11 | 12 | import com.github.pagehelper.PageInfo; 13 | import io.swagger.annotations.Api; 14 | import io.swagger.annotations.ApiOperation; 15 | import io.swagger.annotations.ApiParam; 16 | import lombok.extern.slf4j.Slf4j; 17 | import org.springframework.http.ResponseEntity; 18 | import org.springframework.web.bind.annotation.*; 19 | 20 | import javax.annotation.Resource; 21 | import java.util.Date; 22 | import java.util.List; 23 | /** 24 | * 25 | * @author lirong 26 | * @Description: 日志管理模块 27 | * @date 2018-12-05 03:21:19 28 | */ 29 | @Slf4j 30 | @RestController 31 | @RequestMapping("/log") 32 | @Api(basePath = "/log", tags = "日志模块管理") 33 | public class SysLogController { 34 | @Resource 35 | private SysLogService sysLogService; 36 | 37 | @Log(description = "删除日志", value = 1, type = 9) 38 | @PostMapping 39 | @ApiOperation(value = "新增日志", notes = "单个新增", produces = "application/json") 40 | public RestResult add(@ApiParam(name = "日志信息", required = true) SysLog sysLog) { 41 | sysLog.setCreateTime(new Date()); 42 | sysLogService.save(sysLog); 43 | return ResultGenerator.genSuccessResult().setMessage("保存成功"); 44 | } 45 | 46 | @Log(description = "删除日志", value = 2, type = 9) 47 | @DeleteMapping("/{ids}") 48 | @ApiOperation(value = "删除日志", notes = "单个删除", produces = "application/json") 49 | public RestResult delete(@ApiParam(name = "日志信息", required = true)@PathVariable("ids") String ids) { 50 | sysLogService.deleteById(ids); 51 | return ResultGenerator.genSuccessResult().setMessage("删除成功"); 52 | } 53 | 54 | @Log(description = "修改日志", value = 3, type = 9) 55 | @PutMapping 56 | @ApiOperation(value = "修改日志", notes = "单个修改" , code = 200, produces = "application/json") 57 | public RestResult update(@ApiParam(name = "日志信息", required = true) SysLog sysLog) { 58 | sysLogService.update(sysLog); 59 | return ResultGenerator.genSuccessResult().setMessage("修改成功"); 60 | } 61 | 62 | @Log(description = "单个获取", value = 4, type = 9) 63 | @GetMapping 64 | @ApiOperation(value = "获取日志信息", notes = "单个获取", code = 200, produces = "application/json") 65 | public RestResult detail(@ApiParam(value = "主键ID") @RequestParam Long id) { 66 | SysLog sysLog = sysLogService.findById(id); 67 | return ResultGenerator.genSuccessResult(sysLog); 68 | } 69 | 70 | /** 71 | * 用于分页查询,默认可以不用传分页信息 72 | * 默认值:page=1,size=10,sortField="id",sortOrder="ASC" 73 | */ 74 | @Log(description = "日志分页列表", value = 4, type = 9) 75 | @GetMapping(value = "/list") 76 | @ApiOperation(value = "日志列表分页查询", notes = "分页列表", code = 200, produces = "application/json") 77 | public RestResult list(@ApiParam(value = "分页信息") PageParam pageParam, 78 | @ApiParam(value = "查询条件") SysLogInputDTO inputDTO) { 79 | List list = sysLogService.list(pageParam, inputDTO); 80 | PageInfo pageInfo = new PageInfo(list); 81 | return ResultGenerator.genSuccessResult(pageInfo); 82 | } 83 | 84 | /** 85 | * 下拉框查询所有 86 | */ 87 | @Log(description = "日志列表查询所有", value = 4, type = 9) 88 | @ApiOperation(value = "日志列表查询所有", notes = "下拉框列表", code = 200, produces = "application/json") // TODO 89 | @GetMapping(value = "/all") 90 | public RestResult listAll() { 91 | List list = sysLogService.findAll(); 92 | return ResultGenerator.genSuccessResult(list); 93 | } 94 | 95 | /** 96 | * 导出日志 97 | * @return 98 | */ 99 | @Log(description = "日志分页列表", value = 8, type = 8) 100 | @ApiOperation(value = "导出日志列表", notes = "导出报表", code = 200, produces = "application/json") 101 | @GetMapping(value = "/export") 102 | public ResponseEntity exportSysLogList(@ApiParam(value = "查询条件") SysLogInputDTO inputDTO){ 103 | return sysLogService.exportLogList(inputDTO); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /backend/src/main/resources/mapper/user/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 102 | 103 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/controller/user/MenuRightController.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.controller.user; 2 | 3 | import com.example.janche.common.restResult.PageParam; 4 | import com.example.janche.common.restResult.RestResult; 5 | import com.example.janche.common.restResult.ResultGenerator; 6 | import com.example.janche.security.utils.SecurityUtils; 7 | import com.example.janche.user.domain.MenuRight; 8 | import com.example.janche.user.dto.LoginUserDTO; 9 | import com.example.janche.user.service.MenuRightService; 10 | import com.example.janche.web.aop.Log; 11 | import com.github.pagehelper.PageInfo; 12 | import io.swagger.annotations.Api; 13 | import io.swagger.annotations.ApiOperation; 14 | import io.swagger.annotations.ApiParam; 15 | import lombok.extern.slf4j.Slf4j; 16 | import org.springframework.web.bind.annotation.*; 17 | 18 | import javax.annotation.Resource; 19 | import java.util.Date; 20 | import java.util.List; 21 | 22 | 23 | /** 24 | * @author lirong 25 | * @date 2019-7-19 09:37:47 26 | * @desc 权限管理 27 | */ 28 | @Slf4j 29 | @RestController 30 | @RequestMapping("/menu") 31 | @Api(value = "/menu", tags = "权限菜单表") 32 | public class MenuRightController { 33 | 34 | @Resource 35 | private MenuRightService menuRightService; 36 | 37 | @Log 38 | @ApiOperation(value = "权限字典分页信息查看", notes = "权限字典,分页查看,需要传入分页信息", produces = "application/json") 39 | @GetMapping (value = "/list") 40 | public RestResult queryList( @ApiParam(value = "分页信息") PageParam pageParam, 41 | @ApiParam(value = "查询条件") @RequestParam(required = false, defaultValue = "") String query) { 42 | List list = menuRightService.list(pageParam, query); 43 | PageInfo pageInfo = new PageInfo(list); 44 | return ResultGenerator.genSuccessResult().setData(pageInfo); 45 | } 46 | 47 | @Log(description = "添加权限", type = 2, value = 1) 48 | @ApiOperation(value = "添加权限", notes = "添加权限", produces = "application/json") 49 | @PostMapping ("/add") 50 | public RestResult add(@ApiParam(name = "权限信息", required = true) MenuRight menuRight) { 51 | Date date=new Date(); 52 | menuRight.setCreateTime(date); 53 | menuRightService.addMenuRight(menuRight); 54 | return ResultGenerator.genSuccessResult(); 55 | } 56 | 57 | 58 | @Log(description = "删除权限", type = 2, value = 2) 59 | @ApiOperation(value = "删除权限", notes = "权限", produces = "application/json") 60 | @DeleteMapping ("/delete") 61 | public RestResult delete(@ApiParam(name = "权限id", required = true) Long id) { 62 | menuRightService.deleteMenuRight(id); 63 | return ResultGenerator.genSuccessResult(); 64 | } 65 | 66 | @Log(description = "修改权限", type = 2, value = 3) 67 | @ApiOperation(value = "修改权限", notes = "权限字典", produces = "application/json") 68 | @PutMapping ("/update") 69 | public RestResult update(@ApiParam(name = "权限信息", required = true) MenuRight menuRight) { 70 | menuRightService.updateMenuRight(menuRight); 71 | return ResultGenerator.genSuccessResult(); 72 | } 73 | 74 | @Log 75 | @ApiOperation(value = "权限明细", notes = "权限明细", produces = "application/json") 76 | @GetMapping ("/detail") 77 | public RestResult detail(@ApiParam(name = "权限id", required = true) Long id) { 78 | MenuRight menuRight = menuRightService.findOne(id); 79 | return ResultGenerator.genSuccessResult(menuRight); 80 | } 81 | 82 | @Log 83 | @ApiOperation(value = "获取所有权限信息", notes = "获取所有权限信息", produces = "application/json") 84 | @GetMapping ("/all") 85 | public RestResult findAll() { 86 | List list = menuRightService.findAll(); 87 | PageInfo pageInfo = new PageInfo(list); 88 | return ResultGenerator.genSuccessResult(pageInfo); 89 | } 90 | 91 | 92 | @Log 93 | @ApiOperation(value = "下拉框系统列表", notes = "下拉框系统列表", produces = "application/json") 94 | @GetMapping ("/system") 95 | public RestResult getSystemList() { 96 | List list = menuRightService.getSystemList(); 97 | return ResultGenerator.genSuccessResult(list); 98 | } 99 | 100 | @Log 101 | @ApiOperation(value = "检查用户是否有此按钮权限", notes = "检查用户是否有此按钮权限", produces = "application/json") 102 | @GetMapping ("/check/url") 103 | public RestResult checkUrl(String url) { 104 | Boolean hasButton = false; 105 | LoginUserDTO userDTO = SecurityUtils.getCurrentUser(); 106 | // 判断登录用户是否为管理员 107 | if (userDTO.getId() == 1L) { 108 | hasButton = true; 109 | }else{ 110 | List menus = userDTO.getMenus(); 111 | for (MenuRight menuRight: menus) { 112 | if(menuRight.getUrl().equals(url)){ 113 | hasButton = true; 114 | } 115 | } 116 | } 117 | return ResultGenerator.genSuccessResult(hasButton); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /backend/src/main/resources/mapper/log/SysLogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 76 | 101 | -------------------------------------------------------------------------------- /backend/src/main/java/com/example/janche/log/service/impl/SysLogServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.log.service.impl; 2 | 3 | import com.example.janche.common.core.AbstractService; 4 | import com.example.janche.common.util.PoiUtils; 5 | import com.example.janche.common.restResult.PageParam; 6 | import com.example.janche.common.config.ApplicationConfig; 7 | import com.example.janche.log.dao.SysLogMapper; 8 | import com.example.janche.log.domain.SysLog; 9 | import com.example.janche.log.dto.SysLogExportDTO; 10 | import com.example.janche.log.dto.SysLogInputDTO; 11 | import com.example.janche.log.dto.SysLogOutpDTO; 12 | import com.example.janche.log.service.SysLogService; 13 | import com.github.pagehelper.PageHelper; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.springframework.http.HttpHeaders; 16 | import org.springframework.http.HttpStatus; 17 | import org.springframework.http.ResponseEntity; 18 | import org.springframework.stereotype.Service; 19 | import org.springframework.transaction.annotation.Transactional; 20 | import tk.mybatis.mapper.entity.Example; 21 | 22 | import javax.annotation.Resource; 23 | import java.io.ByteArrayOutputStream; 24 | import java.io.IOException; 25 | import java.io.UnsupportedEncodingException; 26 | import java.util.ArrayList; 27 | import java.util.Arrays; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.stream.Collectors; 31 | 32 | /** 33 | * @author lirong 34 | * @Description: 日志业务层 35 | * @date 2018-12-05 03:21:19 36 | */ 37 | @Slf4j 38 | @Service 39 | @Transactional 40 | public class SysLogServiceImpl extends AbstractService implements SysLogService { 41 | @Resource 42 | private SysLogMapper sysLogMapper; 43 | 44 | @Resource 45 | private ApplicationConfig applicationConfig; 46 | 47 | private static final int FIND = 4; 48 | /** 49 | * 根据分页、排序信息和检索条件查询 @size 条 字典表数据 50 | * @param pageParam 分页参数 51 | * @param inputDTO 查询关键字 52 | * @return 53 | */ 54 | @Override 55 | public List list(PageParam pageParam, SysLogInputDTO inputDTO) { 56 | PageHelper.startPage(pageParam.getPage(), pageParam.getSize(), pageParam.getOrderBy()); 57 | return sysLogMapper.selectLogByQuery(inputDTO); 58 | } 59 | 60 | /** 61 | * 保存日志 62 | * @param sysLog 63 | */ 64 | @Override 65 | public void saveLog(SysLog sysLog) { 66 | //todo 查看不做操作 Log注解上没写注释的也不保存 67 | Integer operation = sysLog.getOperation(); 68 | if (operation != FIND && operation != 0){ 69 | sysLogMapper.insert(sysLog); 70 | } 71 | } 72 | 73 | /** 74 | * 删除日志k 75 | * @param ids 76 | */ 77 | @Override 78 | public void deleteById(String ids) { 79 | List list = Arrays.stream(ids.split(",")).collect(Collectors.toList()); 80 | Example example = new Example(SysLog.class); 81 | example.and().andIn("id",list); 82 | sysLogMapper.deleteByExample(example); 83 | } 84 | 85 | /** 86 | * 分页导出日志 87 | * @param inputDTO 88 | * @return 89 | */ 90 | @Override 91 | public ResponseEntity exportLogList(SysLogInputDTO inputDTO) { 92 | List data = sysLogMapper.selectLogByQuery(inputDTO); 93 | Map sysLogMap = applicationConfig.getLogOperation(); 94 | List list = new ArrayList<>(); 95 | Long logId=1L; 96 | for (SysLogOutpDTO sysLog: data) { 97 | SysLogExportDTO exportDTO = new SysLogExportDTO(); 98 | exportDTO.setId(logId); 99 | logId+=1L; 100 | exportDTO.setOperation(sysLogMap.get(sysLog.getOperation())); 101 | exportDTO.setUsername(sysLog.getUsername()); 102 | exportDTO.setLogDesc(sysLog.getLogDesc()); 103 | exportDTO.setCreateTime(sysLog.getCreateTime()); 104 | list.add(exportDTO); 105 | } 106 | String[] headers = {"序号","操作类型","操作者","操作详情","操作时间"}; 107 | PoiUtils poiUtils = new PoiUtils("日志列表", "日志导出模板.xls"); 108 | poiUtils.setHeaders(headers, "日志列表"); 109 | 110 | // 为excel表生成数据 111 | poiUtils.fillDataAndStyle(list,2); 112 | // 将内容返回响应 113 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 114 | try { 115 | poiUtils.getWorkbook().write(bos); 116 | } catch (IOException e) { 117 | e.printStackTrace(); 118 | } finally { 119 | if (bos != null) { 120 | try { 121 | bos.close(); 122 | } catch (IOException e) { 123 | e.printStackTrace(); 124 | } 125 | } 126 | } 127 | 128 | 129 | // 文件名 130 | String filename = "日志列表"; 131 | try { 132 | filename = new String(filename.getBytes("gbk"), "iso8859-1"); 133 | } catch (UnsupportedEncodingException e) { 134 | log.warn("不支持编码格式"); 135 | e.printStackTrace(); 136 | 137 | } 138 | // 设置http响应头 139 | HttpHeaders header = new HttpHeaders(); 140 | header.add("Content-Disposition", "attachment;filename=" + filename + ".xls"); 141 | 142 | return new ResponseEntity(bos.toByteArray(), header, HttpStatus.CREATED); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/controller/user/RoleController.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.controller.user; 2 | 3 | import com.example.janche.common.restResult.PageParam; 4 | import com.example.janche.common.restResult.RestResult; 5 | import com.example.janche.common.restResult.ResultGenerator; 6 | import com.example.janche.security.utils.SecurityUtils; 7 | import com.example.janche.user.domain.Role; 8 | import com.example.janche.user.dto.TreeNodeDTO; 9 | import com.example.janche.user.dto.role.RoleConditionDTO; 10 | import com.example.janche.user.dto.role.RoleInputDTO; 11 | import com.example.janche.user.dto.role.RoleOutpDTO; 12 | import com.example.janche.user.service.RoleService; 13 | import com.example.janche.web.aop.Log; 14 | import com.github.pagehelper.PageInfo; 15 | import io.swagger.annotations.Api; 16 | import io.swagger.annotations.ApiOperation; 17 | import io.swagger.annotations.ApiParam; 18 | import lombok.extern.slf4j.Slf4j; 19 | import org.springframework.web.bind.annotation.*; 20 | 21 | import javax.annotation.Resource; 22 | import java.util.List; 23 | import java.util.Set; 24 | 25 | /** 26 | * @author lirong 27 | * @Description: 角色管理 28 | * @date 2019-7-18 17:47:06 29 | */ 30 | @Slf4j 31 | @RestController 32 | @RequestMapping("/role") 33 | @Api(value = "/role", tags = "角色管理") 34 | public class RoleController { 35 | @Resource 36 | private RoleService roleService; 37 | 38 | @Log(value = 1, description = "新增角色", type = 2) 39 | @PostMapping("/add") 40 | @ApiOperation(value = "新增角色", notes = "新增角色", produces = "application/json") 41 | public RestResult add(@ApiParam(name = "角色", required = true) RoleInputDTO inputDTO) { 42 | roleService.addRole(inputDTO); 43 | return ResultGenerator.genSuccessResult().setMessage("保存成功"); 44 | } 45 | 46 | @Log(value = 2, description = "删除角色", type = 2) 47 | @DeleteMapping("/delete/{id}") 48 | @ApiOperation(value = "删除角色", notes = "删除角色", produces = "application/json") 49 | public RestResult delete(@PathVariable("id") Long id) { 50 | roleService.deleteRole(id); 51 | return ResultGenerator.genSuccessResult().setMessage("删除成功"); 52 | } 53 | 54 | @Log(value = 2, description = "批量删除角色", type = 2) 55 | @DeleteMapping("/delete/batch/{ids}") 56 | @ApiOperation(value = "批量删除角色", notes = "批量删除角色", produces = "application/json") 57 | public RestResult delete(@ApiParam(name = "角色ID集合", required = true) @PathVariable("ids") String ids) { 58 | roleService.deleteRole(ids); 59 | return ResultGenerator.genSuccessResult().setMessage("删除成功"); 60 | } 61 | 62 | @Log(value = 3, description = "批量冻结角色", type = 2) 63 | @PostMapping("/froze/batch") 64 | @ApiOperation(value = "批量冻结角色", notes = "批量冻结角色", produces = "application/json") 65 | public RestResult frozeRole(@ApiParam(name = "角色ID集合", required = true) String ids, 66 | @ApiParam(name = "冻结状态(0-冻结,1-解冻)", required = true) Integer status) { 67 | roleService.frozeRole(ids, status); 68 | return ResultGenerator.genSuccessResult().setMessage("冻结成功"); 69 | } 70 | 71 | @Log(value = 3, description = "修改角色", type = 2) 72 | @PutMapping("/update") 73 | @ApiOperation(value = "修改角色", notes = "修改角色" , produces = "application/json") 74 | public RestResult update(@ApiParam(name = "角色信息", required = true) RoleInputDTO inputDTO) { 75 | roleService.updateRole(inputDTO); 76 | return ResultGenerator.genSuccessResult().setMessage("修改成功"); 77 | } 78 | 79 | @Log 80 | @GetMapping("/detail") 81 | @ApiOperation(value = "获取角色信息", notes = "获取角色信息", produces = "application/json") 82 | public RestResult detail(@ApiParam(value = "主键ID") @RequestParam Long id) { 83 | RoleOutpDTO dto = roleService.findOne(id); 84 | return ResultGenerator.genSuccessResult(dto); 85 | } 86 | 87 | @Log 88 | @GetMapping("/menu/{ids}") 89 | @ApiOperation(value = "获取权限Ids", notes = "获取权限Ids", produces = "application/json") 90 | public RestResult getMenus(@ApiParam(name = "角色ID集合", required = true) @PathVariable("ids") String ids) { 91 | Set list = roleService.getMenuIdsByRoleIds(ids); 92 | return ResultGenerator.genSuccessResult(list); 93 | } 94 | 95 | @Log 96 | @GetMapping(value = "/list") 97 | @ApiOperation(value = "分页查询角色", notes = "分页查询", produces = "application/json") 98 | public RestResult list(@ApiParam(value = "分页信息") PageParam pageParam, 99 | @ApiParam(value = "筛选条件") RoleConditionDTO dto) { 100 | List list = roleService.list(pageParam, dto, SecurityUtils.getCurrentUser()); 101 | PageInfo pageInfo = new PageInfo(list); 102 | return ResultGenerator.genSuccessResult(pageInfo); 103 | } 104 | 105 | @Log 106 | @GetMapping(value = "/all") 107 | @ApiOperation(value = "角色列表", notes = "下拉框角色列表", produces = "application/json") 108 | public RestResult listAll() { 109 | List list = roleService.listAll(); 110 | return ResultGenerator.genSuccessResult(list); 111 | } 112 | 113 | @Log 114 | @GetMapping("/menu/tree") 115 | @ApiOperation(value = "获取权限树", notes = "获取权限树", produces = "application/json") 116 | public RestResult menuTree() { 117 | TreeNodeDTO nodeDTO = roleService.getMenuTree(); 118 | return ResultGenerator.genSuccessResult(nodeDTO.getChildren()); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/janche/web/aop/LogAspect.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.web.aop; 2 | 3 | import com.example.janche.common.util.IPUtils; 4 | import com.example.janche.common.utils.CoreUtils; 5 | import com.example.janche.log.domain.SysLog; 6 | import com.example.janche.log.service.SysLogService; 7 | import com.example.janche.security.utils.SecurityUtils; 8 | import com.example.janche.user.dto.LoginUserDTO; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.aspectj.lang.JoinPoint; 11 | import org.aspectj.lang.ProceedingJoinPoint; 12 | import org.aspectj.lang.annotation.AfterThrowing; 13 | import org.aspectj.lang.annotation.Around; 14 | import org.aspectj.lang.annotation.Aspect; 15 | import org.aspectj.lang.annotation.Pointcut; 16 | import org.aspectj.lang.reflect.MethodSignature; 17 | import org.springframework.core.LocalVariableTableParameterNameDiscoverer; 18 | import org.springframework.stereotype.Component; 19 | import org.springframework.web.context.request.RequestContextHolder; 20 | import org.springframework.web.context.request.ServletRequestAttributes; 21 | 22 | import javax.annotation.Resource; 23 | import javax.servlet.http.HttpServletRequest; 24 | import java.io.Serializable; 25 | import java.lang.reflect.Method; 26 | import java.util.Date; 27 | 28 | 29 | /** 30 | * 操作日志handler 31 | */ 32 | @Slf4j 33 | @Aspect 34 | @Component 35 | public class LogAspect implements Serializable { 36 | 37 | @Resource 38 | private SysLogService sysLogService; 39 | 40 | /** 如果Log注解的包名改变,记得这里要更新 */ 41 | @Pointcut("@annotation(com.example.janche.web.aop.Log)") 42 | public void pointcut() { 43 | } 44 | 45 | @Around("pointcut()") 46 | public Object around(ProceedingJoinPoint point) throws Throwable { 47 | Object result = null; 48 | long beginTime = System.currentTimeMillis(); 49 | try { 50 | // 执行方法 51 | result = point.proceed(); 52 | } catch (Throwable e) { 53 | // e.printStackTrace(); 54 | throw e; 55 | } 56 | // 执行时长(毫秒) 57 | long time = System.currentTimeMillis() - beginTime; 58 | // 保存日志 59 | saveLog(point, time); 60 | return result; 61 | } 62 | 63 | @AfterThrowing(pointcut = "pointcut()", throwing = "e") 64 | public void doAfterThrowing(JoinPoint point, Throwable e){ 65 | // 保存异常日志 66 | if(null != e){ 67 | saveLog(point, 0, e); 68 | } 69 | } 70 | 71 | /** 72 | * 存储log 73 | */ 74 | private void saveLog(JoinPoint joinPoint, long time) { 75 | saveLog(joinPoint, time, null); 76 | } 77 | 78 | /** 79 | * 存储log 80 | */ 81 | private void saveLog(JoinPoint joinPoint, long time, Throwable e) { 82 | LoginUserDTO currentUser = SecurityUtils.getCurrentUser(); 83 | // TODO 是否记录未登录用户的信息 84 | if(null == currentUser){ 85 | currentUser = LoginUserDTO.builder() 86 | .id(0L) 87 | .username("未登录用户") 88 | .build(); 89 | } 90 | MethodSignature signature = (MethodSignature) joinPoint.getSignature(); 91 | Method method = signature.getMethod(); 92 | SysLog sysLog = new SysLog(); 93 | Log logAnnotation = method.getAnnotation(Log.class); 94 | if (logAnnotation != null) { 95 | // 注解上的描述 96 | int operate = logAnnotation.value(); 97 | String operation = CoreUtils.getOperation(operate); 98 | sysLog.setOperation(operate); 99 | // 注解上的模块类型 100 | int type = logAnnotation.type(); 101 | String module = CoreUtils.getModule(type); 102 | sysLog.setLogType(type); 103 | // 注解上的日志描述 104 | String desc = currentUser.getUsername() + "在 " + module + " 调用了 " + logAnnotation.description() + " 的方法"; 105 | sysLog.setLogDesc(desc); 106 | } 107 | // 请求的方法名 108 | String className = joinPoint.getTarget().getClass().getName(); 109 | String methodName = signature.getName(); 110 | sysLog.setLogMethod(className + "." + methodName + "()"); 111 | // 请求的方法参数值 112 | Object[] args = joinPoint.getArgs(); 113 | // 请求的方法参数名称 114 | LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); 115 | String[] paramNames = u.getParameterNames(method); 116 | if (args != null && paramNames != null) { 117 | String params = ""; 118 | for (int i = 0; i < args.length; i++) { 119 | params += " " + paramNames[i] + ": " + args[i]; 120 | } 121 | sysLog.setLogParams(params); 122 | } 123 | // 获取request 124 | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 125 | // 设置IP地址 126 | sysLog.setLogIp(IPUtils.getIpAddr(request)); 127 | request.getRemoteAddr(); 128 | sysLog.setLogUser(currentUser.getId()); 129 | sysLog.setLogTime(time); 130 | sysLog.setCreateTime(new Date()); 131 | 132 | // 加入异常的信息 133 | if(null != e){ 134 | sysLog.setExceptionCode(e.getClass().getName()); 135 | sysLog.setExceptionDetail(e.getMessage()); 136 | } 137 | // TODO 保存系统日志,入库,这里模拟打出信息即可 138 | System.out.println(sysLog); 139 | sysLogService.saveLog(sysLog); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /common/src/main/java/com/example/janche/common/restResult/ResultCode.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.common.restResult; 2 | 3 | /** 4 | * @author lirong 5 | * @ClassName: ResultCode 6 | * @Description: 返回的状态码 7 | * @date 2018-12-03 9:26 8 | */ 9 | 10 | public enum ResultCode { 11 | 12 | /** 13 | * HTTP通信使用 14 | */ 15 | SUCCESS(200, "SUCCESS"), 16 | 17 | ERROR(500, "服务器内部错误"), 18 | 19 | NOT_FOUND(404, "接口不存在"), 20 | 21 | FAIL(400, "接口异常,请联系管理员"), 22 | 23 | UNAUTHORIZED(401, "未认证(签名错误)"), 24 | 25 | 26 | /** 27 | * security 28 | */ 29 | LOGIN_ERROR(-990, "登录失败"), 30 | 31 | OVER_MAX_LOGIN_NUM(-991, "当前在线人数过多,请稍后登录"), 32 | 33 | REFRESH_TOKEN_EXPIRED(-997, "用户 刷新令牌过期"), 34 | 35 | LIMITED_AUTHORITY(-1000, "权限不够"), 36 | 37 | UNLOGIN(-999, "用户未登录"), 38 | 39 | TOKEN_ILLEGAL(-996, "用户令牌不合法"), 40 | 41 | TOKEN_EXPIRED(-998, "用户 普通令牌过期"), 42 | 43 | IP_NOT_ALLOW(-980, "登录的IP不被允许"), 44 | 45 | /** 46 | * oauth2 47 | */ 48 | MISSING_CLIENT_INFO(-1009, "客户端注册信息缺失"), 49 | 50 | CLIENT_ID_ALREADY_EXIST(-1010, "client_id已存在"), 51 | 52 | /** 53 | * 导入导出 54 | */ 55 | DATA_IS_NULL(4901, "请选择数据导出"), 56 | 57 | IMPORT_FAIL(4902, "未知错误,导入失败"), 58 | 59 | 60 | 61 | /** 62 | * 用户管理 63 | */ 64 | 65 | USER_FINDNOWUSER_FAIL(2004, "获取登录用户失败"), 66 | 67 | USER_NOT_EXIST(2005, "用户不存在"), 68 | 69 | OLD_PASSWORD_ERROR(2002, "原密码错误"), 70 | 71 | PASSWORD_ERROR(2003, "密码错误"), 72 | 73 | RESET_PASSWORD_ERROR(2004, "重置密码失败"), 74 | 75 | 76 | /** 77 | * 角色管理 78 | */ 79 | ROLE_ADD_FAIL(7101, "新增角色失败"), 80 | 81 | ROLE_UPDATE_FAIL(7102, "修改角色失败"), 82 | 83 | ROLE_DELETE_FAIL(7103, "删除角色失败"), 84 | 85 | 86 | ; 87 | 88 | /** 89 | * 统计数据 90 | */ 91 | 92 | public int code; 93 | 94 | public String message; 95 | 96 | ResultCode (int code, String message){ 97 | this.code = code; 98 | this.message = message; 99 | } 100 | 101 | public int getCode(){ 102 | return code; 103 | } 104 | 105 | public String getMessage(){ 106 | return message; 107 | } 108 | // /** 109 | // * 登录失败 110 | // */ 111 | // int LOGIN_ERROR = -990; 112 | // /** 113 | // * 用户令牌不合法 114 | // */ 115 | // int TOKEN_ILLEGAL = -996; 116 | // /** 117 | // * 用户 刷新令牌过期 118 | // */ 119 | // int REFRESH_TOKEN_EXPIRED = -997; 120 | // /** 121 | // * 用户 普通令牌过期 122 | // */ 123 | // int TOKEN_EXPIRED = -998; 124 | 125 | 126 | // /** 127 | // * 非自定义异常 128 | // */ 129 | // int NOT_CUSTOM_EXCEPTION = -2000; 130 | // /** 131 | // * 非自定义运行时异常 132 | // */ 133 | // int NOT_CUSTOM_RUNTIME_EXCEPTION = -2001; 134 | // 135 | // /** 136 | // * 区域管理----查找单元列表失败 137 | // */ 138 | // int FAIL_AREA_LIST_FIND = -1301; 139 | // /** 140 | // * 区域管理----新增区域失败 141 | // */ 142 | // int FAIL_AREA_ADD = -1302; 143 | // /** 144 | // * 区域管理----删除区域失败 145 | // */ 146 | // int FAIL_AREA_DELETE = -1303; 147 | // /** 148 | // * 区域管理----更新区域失败 149 | // */ 150 | // int FAIL_AREA_UPATE = -1304; 151 | // /** 152 | // * 区域管理----根据Id查询区域 153 | // */ 154 | // int FAIL_AREA_FIND_BY_ID = -1305; 155 | // 156 | // /** 157 | // * 房间管理----查找房间列表失败 158 | // */ 159 | // int FAIL_ROOM_LIST_FIND = -1306; 160 | // /** 161 | // * 房间管理----新增房间失败 162 | // */ 163 | // int FAIL_ROOM_ADD = -1307; 164 | // /** 165 | // * 房间管理----删除房间失败 166 | // */ 167 | // int FAIL_ROOM_DELETE = -1308; 168 | // /** 169 | // * 房间管理----更新房间失败 170 | // */ 171 | // int FAIL_ROOM_UPATE = -1309; 172 | // /** 173 | // * 房间管理----根据Id查询房间 174 | // */ 175 | // int FAIL_ROOM_FIND_BY_ID = -1310; 176 | // 177 | // 178 | // /** 179 | // * 设备管理----查找设备列表失败 180 | // */ 181 | // int FAIL_DEVICE_LIST_FIND = -1311; 182 | // /** 183 | // * 设备管理----新增设备失败 184 | // */ 185 | // int FAIL_DEVICE_ADD = -1312; 186 | // /** 187 | // * 设备管理----删除设备失败 188 | // */ 189 | // int FAIL_DEVICE_DELETE = -1313; 190 | // /** 191 | // * 设备管理----更新设备失败 192 | // */ 193 | // int FAIL_DEVICE_UPATE = -1314; 194 | // /** 195 | // * 设备管理----根据Id查询设备 196 | // */ 197 | // int FAIL_DEVICE_FIND_BY_ID = -1315; 198 | // 199 | // /** 200 | // * 获取ID_TEXT类型数据 201 | // */ 202 | // int FAIL_ROOM_FIND_ID_NAME = -1316; 203 | // /** 204 | // * 根据区域id_name形式的Json 205 | // */ 206 | // int FAIL_AREA_FIND_ID_NAME = -1317; 207 | // /** 208 | // * 设备详情----根据设备ID获取设备详细参数 209 | // */ 210 | // int FAIL_DEVICEPARA_FIND_BY_DEVID = -1318; 211 | // /** 212 | // * 设备详情----更新设备详情 213 | // */ 214 | // int FAIL__UPDATE_DEVICEPARA = -1319; 215 | // /** 216 | // * 设备详情----应用到更多的设备 217 | // */ 218 | // int FAIL_APPLY_MORE_DEVICE = -1320; 219 | // /** 220 | // * 设备详情----应用到更多房间 221 | // */ 222 | // int FAIL_APPLY_MORE_ROOM = -1321; 223 | // /** 224 | // * 设备详情----应用到此房间 225 | // */ 226 | // int FAIL_APPLY_CURRENT_ROOM = -1322; 227 | // /** 228 | // * 将设备应用到房间 229 | // */ 230 | // int FAIL_APPLY_DEV_TO_ROOM = -1323; 231 | // /** 232 | // * 查询所有勾选房间的设备 233 | // */ 234 | // int FAIL_SELECT_ROOM_DEVICE = -1324; 235 | // /** 236 | // * 根据查询条件获取设备个数 237 | // */ 238 | // int FAIL_DEVICE_COUNT_CONDITION = -1325; 239 | // /** 240 | // * 获取选中的区域的所有的房间 241 | // */ 242 | // int FAIL_SELECT_AREA_ROOM = -1326; 243 | // /** 244 | // * 根据查询条件获取房间个数 245 | // */ 246 | // int FAIL_ROOM_COUNT_CONDITION = -1327; 247 | 248 | 249 | } 250 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/janche/security/metadatasource/UrlFilterInvocationSecurityMetadataSource.java: -------------------------------------------------------------------------------- 1 | package com.example.janche.security.metadatasource; 2 | 3 | import com.example.janche.security.ignore.CustomConfig; 4 | import com.example.janche.security.utils.SecurityUtils; 5 | import com.example.janche.user.dao.MenuRightMapper; 6 | import com.example.janche.user.domain.Role; 7 | import com.example.janche.user.dto.MenuDTO; 8 | import com.google.common.collect.Sets; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.http.HttpMethod; 13 | import org.springframework.security.access.ConfigAttribute; 14 | import org.springframework.security.access.SecurityConfig; 15 | import org.springframework.security.web.FilterInvocation; 16 | import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 17 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 18 | import org.springframework.stereotype.Component; 19 | 20 | import javax.annotation.Resource; 21 | import javax.servlet.http.HttpServletRequest; 22 | import java.util.Collection; 23 | import java.util.List; 24 | import java.util.Set; 25 | 26 | @Component("urlFilterInvocationSecurityMetadataSource") 27 | @Slf4j 28 | public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { 29 | @Resource 30 | private MenuRightMapper menuRightMapper; 31 | @Autowired 32 | private CustomConfig customConfig; 33 | /** 34 | * 当前激活的配置文件 35 | */ 36 | @Value("${spring.profiles.active}") 37 | private String env; 38 | 39 | AntPathRequestMatcher antPathMatcher = null; 40 | 41 | @Override 42 | public Collection getAttributes(Object o) throws IllegalArgumentException { 43 | 44 | // 开发环境不启用权限验证 45 | // if (env.contains("dev")) { 46 | // return null; 47 | // } 48 | 49 | HttpServletRequest request = ((FilterInvocation) o).getHttpRequest(); 50 | // 检查是否为放行的请求 51 | if (checkIgnores(request)){ 52 | return null; 53 | } 54 | 55 | // 获取用户ID 56 | Long userId = SecurityUtils.getLoginUserId(); 57 | if (null != userId && userId != -1){ 58 | // 获取系统所有权限 59 | List menuDTOS = menuRightMapper.getAllMenus(); 60 | for (MenuDTO menu : menuDTOS) { 61 | antPathMatcher = new AntPathRequestMatcher(menu.getUrl(), menu.getMethod()); 62 | if (antPathMatcher.matches(request) && menu.getRoles().size() > 0) { 63 | List roles = menu.getRoles(); 64 | int size = roles.size(); 65 | String[] values = new String[size]; 66 | for (int i = 0; i < size; i++) { 67 | values[i] = "ROLE_" + roles.get(i).getName(); 68 | } 69 | return SecurityConfig.createList(values); 70 | } 71 | } 72 | } 73 | //没有匹配上的资源,都是登录访问 74 | return SecurityConfig.createList("ROLE_LOGIN"); 75 | } 76 | 77 | @Override 78 | public Collection getAllConfigAttributes() { 79 | return null; 80 | } 81 | 82 | @Override 83 | public boolean supports(Class aClass) { 84 | return FilterInvocation.class.isAssignableFrom(aClass); 85 | } 86 | 87 | /** 88 | * 请求是否不需要进行权限拦截 89 | * 90 | * @param request 当前请求 91 | * @return true - 忽略,false - 不忽略 92 | */ 93 | private boolean checkIgnores(HttpServletRequest request) { 94 | String method = request.getMethod(); 95 | 96 | HttpMethod httpMethod = HttpMethod.resolve(method); 97 | if (null == httpMethod) { 98 | httpMethod = HttpMethod.GET; 99 | } 100 | 101 | Set ignores = Sets.newHashSet(); 102 | 103 | switch (httpMethod) { 104 | case GET: 105 | ignores.addAll(customConfig.getIgnores() 106 | .getGet()); 107 | break; 108 | case PUT: 109 | ignores.addAll(customConfig.getIgnores() 110 | .getPut()); 111 | break; 112 | case HEAD: 113 | ignores.addAll(customConfig.getIgnores() 114 | .getHead()); 115 | break; 116 | case POST: 117 | ignores.addAll(customConfig.getIgnores() 118 | .getPost()); 119 | break; 120 | case PATCH: 121 | ignores.addAll(customConfig.getIgnores() 122 | .getPatch()); 123 | break; 124 | case TRACE: 125 | ignores.addAll(customConfig.getIgnores() 126 | .getTrace()); 127 | break; 128 | case DELETE: 129 | ignores.addAll(customConfig.getIgnores() 130 | .getDelete()); 131 | break; 132 | case OPTIONS: 133 | ignores.addAll(customConfig.getIgnores() 134 | .getOptions()); 135 | break; 136 | default: 137 | break; 138 | } 139 | 140 | ignores.addAll(customConfig.getIgnores().getPattern()); 141 | 142 | if (!ignores.isEmpty()) { 143 | for (String ignore : ignores) { 144 | AntPathRequestMatcher matcher = new AntPathRequestMatcher(ignore, method); 145 | if (matcher.matches(request)) { 146 | return true; 147 | } 148 | } 149 | } 150 | return false; 151 | } 152 | } 153 | --------------------------------------------------------------------------------