spring boot sa-token練手專案
阿新 • • 發佈:2022-05-16
rbac
基於SpringBoot、sa-token 、MyBatis-plus 的許可權後臺管理系統
專案說明
一個練手的專案,具有RBAC的功能許可權系統
技術選型
1、系統環境
- Java EE 8
- Servlet 3.0
- Apache Maven 3
2、主框架
- Spring Boot 2.3.x
- Spring Framework 5.2.x
- sa-token 1.28.0
3、持久層
- MyBatis-plus 3.5.x
- Hibernate Validation 6.0.x
- Alibaba Druid 1.2.x
4、檢視層
- Bootstrap 3.3.7
- Thymeleaf 3.0.x
1、專案依賴與系統配置
1.1、專案依賴
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.pj</groupId> <artifactId>rbac-service</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- SpringBoot --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.1</version> </parent> <!-- 指定一些屬性 --> <properties> <java.version>1.8</java.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> <druid.version>1.2.6</druid.version> <fastjson.version>1.2.76</fastjson.version> </properties> <dependencies> <!-- SpringBoot Web模組 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Mysql驅動包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--阿里資料庫連線池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.version}</version> </dependency> <!-- 阿里JSON解析器 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <!-- mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <!-- 程式碼生成器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version> </dependency> <!--freemarker--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency> <!-- Sa-Token 許可權認證, 線上文件:http://sa-token.dev33.cn/ --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.28.0</version> </dependency> <!-- Sa-Token 整合 Redis (使用jackson序列化方式) --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-dao-redis-jackson</artifactId> <version>1.28.0</version> </dependency> <!-- 提供Redis連線池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.2</version> </dependency> <!-- 神lombok外掛 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- hutool - 線上文件:https://hutool.cn/docs/#/ --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.5.15</version> </dependency> <!-- validation --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>2.5.1</version> </dependency> <!--Swagger3--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> <!-- swagger ui--> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.8.5</version> </dependency> <!--驗證碼 --> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency> <!-- easyexcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> <!--aspectj--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> </dependencies> </project>
1.2、系統配置
application.yml
# 自定義配置 custom: # 檔案路徑 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 驗證碼型別 math 陣列計算 char 字元驗證 captchaType: math server: port: 8080 # Spring配置 spring: # 檔案上傳 servlet: multipart: # 單個檔案大小 max-file-size: 10MB # 設定總上傳的檔案大小 max-request-size: 20MB # 資料來源配置 datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo-rbac?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: root druid: # 初始連線數 initialSize: 5 # 最小連線池數量 minIdle: 10 # 最大連線池數量 maxActive: 20 # 配置獲取連線等待超時的時間 maxWait: 60000 # 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一個連線在池中最小生存的時間,單位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一個連線在池中最大生存的時間,單位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置檢測連線是否有效 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 設定白名單,不填則允許所有訪問 allow: url-pattern: /druid/* # 控制檯管理使用者名稱和密碼 login-username: galen login-password: galen filter: stat: enabled: true # 慢SQL記錄 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true # redis配置 redis: # Redis資料庫索引(預設為0) database: 1 # Redis伺服器地址 host: 127.0.0.1 # Redis伺服器連線埠 port: 6379 # Redis伺服器連線密碼(預設為空) # password: # 連線超時時間 timeout: 10s lettuce: pool: # 連線池最大連線數 max-active: 200 # 連線池最大阻塞等待時間(使用負值表示沒有限制) max-wait: -1ms # 連線池中的最大空閒連線 max-idle: 10 # 連線池中的最小空閒連線 min-idle: 0 # Logger Config logging: level: com.heyuht.hospital.mapper: debug # Sa-Token 配置 sa-token: # token名稱 (同時也是cookie名稱) token-name: satoken # token有效期,單位s 預設30天, -1代表永不過期 timeout: 2592000 # token臨時有效期 (指定時間內無操作就視為token過期) 單位: 秒 activity-timeout: -1 # 是否允許同一賬號併發登入 (為true時允許一起登入, 為false時新登入擠掉舊登入) is-concurrent: true # 在多人登入同一賬號時,是否共用一個token (為true時所有登入共用一個token, 為false時每次登入新建一個token) is-share: true # token風格 token-style: uuid # 是否輸出操作日誌 is-log: false # cookie裡讀取token is-read-cookie: false # cookie裡讀取token is-print: false
2、配置連線池
2.1配置檔案
DruidConfig.java
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.sql.DataSource;
import java.io.IOException;
/**
* druid 配置多資料來源
*
* @author heyuht
*/
@Configuration
public class DruidConfig
{
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druid(){
return new DruidDataSource();
}
/**
* 去除監控頁面底部的廣告
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
@ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
{
// 獲取web監控頁面的引數
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
// 提取common.js的配置路徑
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
final String filePath = "support/http/resources/js/common.js";
// 建立filter進行過濾
Filter filter = new Filter()
{
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
chain.doFilter(request, response);
// 重置緩衝區,響應頭不會被重置
response.resetBuffer();
// 獲取common.js
String text = Utils.readFromResource(filePath);
// 正則替換banner, 除去底部的廣告資訊
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
text = text.replaceAll("powered.*?shrek.wang</a>", "");
response.getWriter().write(text);
}
@Override
public void destroy()
{
}
};
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
}
3、配置 mybatis plus 程式碼生成
1、自定義模板controller
controller.java.ftl
package ${package.Controller};
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};
import com.heyuht.hospital.utils.AjaxResult;
import com.heyuht.hospital.utils.TableDataInfo;
<#if swagger2>
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
</#if>
/**
* <p>
* ${table.comment!} 前端控制器
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if swagger2>
@Api(tags = "${table.comment!}")
</#if>
@RestController
@RequestMapping("${table.entityPath}")
public class ${table.controllerName} {
@Autowired
private ${table.serviceName} ${table.entityPath}Service;
// 查詢
<#if swagger2>
@ApiOperation(value = "查詢",notes = "查詢列表")
</#if>
@GetMapping("/list")
public TableDataInfo list(Integer pageNum,Integer pageSize){
Page<${entity}> page = new Page<>();
if (pageNum != null && pageSize != null){
page = new Page<>(pageNum, pageSize);
}
Page<${entity}> ${table.entityPath}Page = ${table.entityPath}Service.page(page);
return new TableDataInfo(${table.entityPath}Page);
}
// 新增
<#if swagger2>
@ApiOperation(value = "新增",notes = "新增資料")
</#if>
@PostMapping("/add")
public AjaxResult add(${entity} ${table.entityPath}){
boolean flag = ${table.entityPath}Service.save(${table.entityPath});
return AjaxResult.toAjax(flag);
}
// 修改
<#if swagger2>
@ApiOperation(value = "修改",notes = "修改資料")
</#if>
@PostMapping("/update")
public AjaxResult update(${entity} ${table.entityPath}){
return AjaxResult.toAjax(${table.entityPath}Service.updateById(${table.entityPath}));
}
// 刪除
<#if swagger2>
@ApiOperation(value = "刪除",notes = "刪除資料")
</#if>
@PostMapping("/delete/{id}")
public AjaxResult delete(@PathVariable Long id){
return AjaxResult.toAjax(${table.entityPath}Service.removeById(id));
}
}
2.程式碼生成
CodeGenerator.java
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
// 演示例子,執行 main 方法控制檯輸入模組表名回車自動生成對應專案目錄中
public class CodeGenerator {
public static void main(String[] args) {
// 表名,通過,分割
String tableName = "sys_attachment";
// 程式碼生成器
AutoGenerator mpg = new AutoGenerator();
// 全域性配置
GlobalConfig gc = new GlobalConfig();
String projectPath = "D:/hy-project/new-base-cloud/demo/rbac-service/src/main";
gc.setOutputDir(projectPath + "/java/");
gc.setAuthor("galen");
gc.setOpen(false);
gc.setSwagger2(true); //實體屬性 Swagger2 註解
mpg.setGlobalConfig(gc);
// 資料來源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/demo-rbac?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.heyuht.hospital");
mpg.setPackageInfo(pc);
// 自定義配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定義輸出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定義配置會被優先輸出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定義輸出檔名 , 如果你 Entity 設定了前後綴、此處注意 xml 的名稱會跟著發生變化!!
return projectPath + "/resources/mapper/"
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定義輸出模板
//指定自定義模板路徑,注意不要帶上.ftl/.vm, 會根據使用的模板引擎自動識別
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
templateConfig.setController("/templates/ftl/controller.java");
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 自定義需要填充的欄位 資料庫中的欄位
List<TableFill> tableFillList = new ArrayList<>();
tableFillList.add(new TableFill("create_time", FieldFill.INSERT));
tableFillList.add(new TableFill("create_by", FieldFill.INSERT));
tableFillList.add(new TableFill("update_time", FieldFill.UPDATE));
tableFillList.add(new TableFill("update_by", FieldFill.UPDATE));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude(tableName.split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
//自動填充設定
strategy.setTableFillList(tableFillList);
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
mybatis plus 其它配置
1、配置分頁
MybatisPlusConfig.java
package com.heyuht.hospital.config.mybatisPlus;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//Spring boot方式
@Configuration
@MapperScan("com.heyuht.hospital.*.mapper*")
public class MybatisPlusConfig {
// 舊版
// @Bean
// public PaginationInterceptor paginationInterceptor() {
// PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// // 設定請求的頁面大於最大頁後操作, true調回到首頁,false 繼續請求 預設false
// // paginationInterceptor.setOverflow(false);
// // 設定最大單頁限制數量,預設 500 條,-1 不受限制
// // paginationInterceptor.setLimit(500);
// // 開啟 count 的 join 優化,只針對部分 left join
// paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
// return paginationInterceptor;
// }
// 分頁最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
2、配置欄位填充
MyMetaObjectHandler.java
package com.heyuht.hospital.config.mybatisPlus;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
/**
* 自動填充功能
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "createTime", () -> new Date(), Date.class); // 起始版本 3.3.3(推薦)
this.strictInsertFill(metaObject, "createBy", () -> StpUtil.getLoginIdAsString(), String.class);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", () -> new Date(), Date.class); // 起始版本 3.3.3(推薦)
this.strictUpdateFill(metaObject, "updateBy", () -> StpUtil.getLoginIdAsString(), String.class);
}
}
5、系統管理
1、生成使用者,許可權,選單表
1、編寫對應表的CRUD介面
2、新增登入介面
LoginController.java
package com.heyuht.hospital.controller;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.alibaba.fastjson.JSONObject;
import com.heyuht.hospital.config.satoken.StpInterfaceImpl;
import com.heyuht.hospital.entity.SysUser;
import com.heyuht.hospital.entity.vo.LoginVo;
import com.heyuht.hospital.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
/**
*
* 登入相關
*
* @author galen
* @since 2022-01-22
*/
@Api(tags = "登入相關")
@RestController
@RequestMapping("/")
public class LoginController {
@Autowired
ISysUserService sysUserService;
@Autowired
StpInterfaceImpl stpInterface;
@ApiOperation(value = "登入",notes = "用來登入")
@PostMapping("login")
public SaResult login(@RequestBody LoginVo loginVo){
String username = loginVo.getUserName();
String password = loginVo.getPassword();
if (username == null || username.trim().length() == 0 || password == null || password.trim().length() == 0){
return SaResult.error("使用者或密碼不能為空");
}
SysUser one = sysUserService.lambdaQuery()
.eq(SysUser::getUserName, username)
.eq(SysUser::getPassword, SaSecureUtil.sha1(password)).one();
if (one != null){
StpUtil.login(one.getUserId());
return SaResult.ok("登入成功");
}
return SaResult.error("使用者名稱或密碼錯誤");
}
@ApiOperation(value = "退出登入")
@GetMapping("logout")
public SaResult logout(){
// 當前會話登出登入
StpUtil.logout();
return SaResult.ok("退出成功");
}
}
StpInterfaceImpl.java
package com.heyuht.hospital.config.satoken;
import cn.dev33.satoken.stp.StpInterface;
import com.heyuht.hospital.service.ISysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 自定義許可權驗證介面擴充套件
* 許可權認證。
*/
// 保證此類被SpringBoot掃描,完成Sa-Token的自定義許可權驗證擴充套件
@Component
public class StpInterfaceImpl implements StpInterface {
@Autowired
ISysRoleService sysRoleService;
/**
* 返回一個賬號所擁有的許可權碼集合
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 在判斷許可權時,會呼叫該方法
List<String> list = new ArrayList<String>();
Integer userId = Integer.valueOf(loginId.toString());
if (userId == 1){
list.add("*");
return list;
}
list = sysRoleService.queryRoleMenu(userId);
// list.add("101");
// list.add("user:add");
// list.add("user:delete");
// list.add("user:update");
return list;
}
/**
* 返回一個賬號所擁有的角色標識集合 (許可權與角色可分開校驗)
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 本list僅做模擬,實際專案中要根據具體業務邏輯來查詢角色
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super:admin");
return list;
}
}
新增攔截器 SaTokenConfigure.java
package com.heyuht.hospital.config.satoken;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 註冊攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 註冊Sa-Token的路由攔截器
registry.addInterceptor(new SaRouteInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/login","/captchaImage");
// 註冊註解攔截器,並排除不需要註解鑑權的介面地址 (與登入攔截器無關)
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
}
}
3、新增驗證碼
CaptchaConfig.java
package com.heyuht.hospital.config.captcha;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static com.google.code.kaptcha.Constants.*;
import java.util.Properties;
/**
* 驗證碼配置
* https://www.cnblogs.com/louis80/p/5230507.html
* @author galen
*/
@Configuration
public class CaptchaConfig
{
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有邊框 預設為true 我們可以自己設定yes,no
properties.setProperty(KAPTCHA_BORDER, "yes");
// 驗證碼文字字元顏色 預設為Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
// 驗證碼圖片寬度 預設為200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 驗證碼圖片高度 預設為50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 驗證碼文字字元大小 預設為40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
// 驗證碼文字字元長度 預設為5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// 驗證碼文字字型樣式 預設為new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 圖片樣式 水紋com.google.code.kaptcha.impl.WaterRipple 魚眼com.google.code.kaptcha.impl.FishEyeGimpy 陰影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
@Bean(name = "captchaProducerMath")
public DefaultKaptcha getKaptchaBeanMath()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有邊框 預設為true 我們可以自己設定yes,no
properties.setProperty(KAPTCHA_BORDER, "yes");
// 邊框顏色 預設為Color.BLACK
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
// 驗證碼文字字元顏色 預設為Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
// 驗證碼圖片寬度 預設為200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 驗證碼圖片高度 預設為50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 驗證碼文字字元大小 預設為40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
// 驗證碼文字生成器
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.heyuht.hospital.config.captcha.KaptchaTextCreator");
// 驗證碼文字字元間距 預設為2
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
// 驗證碼文字字元長度 預設為5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
// 驗證碼文字字型樣式 預設為new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 驗證碼噪點顏色 預設為Color.BLACK
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
// 干擾實現類
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
// 圖片樣式 水紋com.google.code.kaptcha.impl.WaterRipple 魚眼com.google.code.kaptcha.impl.FishEyeGimpy 陰影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
KaptchaTextCreator.java
package com.heyuht.hospital.config.captcha;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
import java.util.Random;
/**
* 驗證碼文字生成器
*
* @author ruoyi
*/
public class KaptchaTextCreator extends DefaultTextCreator
{
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
@Override
public String getText()
{
Integer result = 0;
Random random = new Random();
int x = random.nextInt(10);
int y = random.nextInt(10);
StringBuilder suChinese = new StringBuilder();
int randomoperands = (int) Math.round(Math.random() * 2);
if (randomoperands == 0)
{
result = x * y;
suChinese.append(CNUMBERS[x]);
suChinese.append("*");
suChinese.append(CNUMBERS[y]);
}
else if (randomoperands == 1)
{
if (!(x == 0) && y % x == 0)
{
result = y / x;
suChinese.append(CNUMBERS[y]);
suChinese.append("/");
suChinese.append(CNUMBERS[x]);
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
}
else if (randomoperands == 2)
{
if (x >= y)
{
result = x - y;
suChinese.append(CNUMBERS[x]);
suChinese.append("-");
suChinese.append(CNUMBERS[y]);
}
else
{
result = y - x;
suChinese.append(CNUMBERS[y]);
suChinese.append("-");
suChinese.append(CNUMBERS[x]);
}
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
suChinese.append("=?@" + result);
return suChinese.toString();
}
}
4、新增許可權相關介面
1、角色授權選單功能
3、使用者授權角色功能
5、測試認證
1、新增角色選單
2、新增使用者角色
3、新增許可權驗證
6、新增swagger3
1、整合swagger3+UI美化包
package com.heyuht.hospital.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
/**
* Swagger3(可選配置)
*/
@Configuration
public class Swagger3 {
@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30).apiInfo(
new ApiInfoBuilder()
.contact(new Contact("Galen", "", ""))
.title("Swagger3介面測試專案")
.build()
);
}
}
7、新增系統日誌
1、新增日誌表
2、日誌儲存方法
3、新增日誌切面
8、新增檔案上傳
1、檔案上傳服務
9、新增匯出匯入功能
1、引用EasyExcel依賴。
參考文件https://blog.csdn.net/qidasheng2012/article/details/102707394
10、字典管理
1、新增字典主表和字典明細表。