1. 程式人生 > 程式設計 >SpringBoot 後臺許可權框架搭建(一)—後臺框架搭建

SpringBoot 後臺許可權框架搭建(一)—後臺框架搭建

SpringBoot 後臺許可權框架搭建(一)—後臺框架搭建
SpringBoot後臺許可權管理系統(二)—前端工程搭建
SpringBoot後臺許可權管理系統(三)—許可權模組
SpringBoot後臺許可權管理系統(四)—部署

專案簡介

專案名稱定義為mountain(山),主要實現後端許可權管理系統,包括使用者管理、
角色管理、部門管理、選單管理等。專案採用前後端分離模式開發,
後端使用springboot+shiro+mybatis+MySQL等;前端選用Element UI框架,
直接基於vue-element-admin的基礎上擴充套件開發。
複製程式碼

檢視專案地址

工程目錄說明

整合jar包

整合 Springboot、Shiro、Mybatis、Druid等jar包
複製程式碼
  • 在pom.xml 檔案中引用相對應的jar包
<?xml version="1.0" encoding="UTF-8"?>
<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.site</groupId> <artifactId>mountain</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>mountain</name> <description>Demo project for Spring Boot</description
>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <!--// swagger2 --> <!-- 新增oracle jdbc driver --> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc14</artifactId> <version>10.2.0.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.43</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> <!-- 該依賴必加,裡面有sping對schedule的支援 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.0.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- Docker maven plugin --> <plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>1.2.0</version> <configuration> <!-- docker私服的地址 --> <dockerHost>http://192.168.75.129:2375</dockerHost> <!--映象名稱以及版本號--> <imageName>mountain:1.0.0</imageName> <!--依賴的基礎映象--> <baseImage>java</baseImage> <!--Dockerfile的位置 --> <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory> <!-- 這裡是複製 jar 包到 docker 容器指定目錄配置 --> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}.jar</include> </resource> </resources> </configuration> </plugin> <!-- Docker maven plugin --> </plugins> </build> <repositories> <repository> <!-- Maven 自帶的中央倉庫使用的Id為central 如果其他的倉庫宣告也是用該Id 就會覆蓋中央倉庫的配置 --> <id>mvnrepository</id> <name>mvnrepository</name> <url>http://www.mvnrepository.com/</url> <layout>default</layout> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>aliyun</id> <name>aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project> 複製程式碼

springboot相關配置

application 配置檔案

server.port=8080 # 訪問埠號
server.servlet.context-path=/mt # 訪問專案名稱
server.servlet.session.timeout=10 # session失效實現
#MVC
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html # 設定字尾名稱
spring.resources.static-locations=classpath:/static/dist/ #靜態檔案可訪問路徑


#當遇到同樣名字的時候,是否允許覆蓋註冊
#spring.main.allow-bean-definition-overriding=true

#配置監控統計攔截的filters,去掉後監控介面SQL無法進行統計,'wall'用於防火牆
spring.datasource.mysql.filters=stat,wall
spring.datasource.mysql.driverClassName=com.mysql.jdbc.Driver
spring.datasource.mysql.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.mysql.url=jdbc:mysql://127.0.0.1:3306/mountain
spring.datasource.mysql.username=root
spring.datasource.mysql.password=root


#spring.datasource.mysql.driverClassName=com.mysql.jdbc.Driver
## 這裡配置springboot2 預設Hikari連線池,不識別url,需要用jdbc-url,不然報錯jdbcUrl is required with driverClassName.
#spring.datasource.mysql.jdbc-url=jdbc:mysql://127.0.0.1:3306/mountain
#spring.datasource.mysql.username=root
#spring.datasource.mysql.password=root

mybatis.type-aliases-package=com.site.mountain.entity
複製程式碼

注意點

  • springboot2 預設Hikari連線池,可以直接使用不需要引用其他額外jar包
  • 本專案中使用的連線池是Druid,請關注與Hikari連線池配置時的不同點

Shiro相關配置

路徑

ShiroConfig類

package com.site.mountain.config;

import com.site.mountain.filter.ShiroUserFilter;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    //將自己的驗證方式加入容器
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }

    @Bean
    public SessionManager sessionManager() {
        MySessionManager mySessionManager = new MySessionManager();
        return mySessionManager;
    }

    //許可權管理,配置主要是Realm的管理認證
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        // 自定義session管理
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    //Filter工廠,設定對應的過濾條件和跳轉條件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        /**
         * 覆蓋預設的user攔截器(預設攔截器解決不了ajax請求 session超時的問題,若有更好的辦法請及時反饋作者)
         */
        Map<String,Filter> filters = new LinkedHashMap<>();
        ShiroUserFilter shiroUserFilter = new ShiroUserFilter();
        // 名字不能自己隨意寫,要用shiro提供的anon、authc、user
        filters.put("authc",shiroUserFilter);
        shiroFilterFactoryBean.setFilters(filters);


        /**
         * 配置shiro攔截器鏈
         *
         * anon  不需要認證
         * authc 需要認證
         * user  驗證通過或RememberMe登入的都可以
         *
         * 當應用開啟了rememberMe時,使用者下次訪問時可以是一個user,但不會是authc,因為authc是需要重新認證的
         *
         * 順序從上到下,優先順序依次降低
         *
         */
        Map<String,String> map = new HashMap<String,String>();
        //登出
        map.put("/logout","logout");
        //對所有使用者認證
        map.put("/**","authc");
        //start 訪問設定
        map.put("/swagger-ui.html","anon");
        map.put("/swagger-resources","anon");
        map.put("/v2/api-docs","anon");
        map.put("/webjars/springfox-swagger-ui/**","anon");
        map.put("/sysuser/login","anon");
        map.put("/sysuser/info","anon");
        map.put("/sysuser/logout","anon");
        map.put("/index.html","anon");
        map.put("/*.ico","anon");
        map.put("/static/**","anon");
//        map.put("/**","user");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        //登入(預設的登陸訪問url)
        shiroFilterFactoryBean.setLoginUrl("/sysuser/login");
        //首頁(登陸成功後跳轉的url)
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //沒有許可權跳轉的url(錯誤頁面,認證不通過跳轉)
        shiroFilterFactoryBean.setUnauthorizedUrl("/invalid");

        return shiroFilterFactoryBean;
    }

    /**
     * 開啟Shiro的註解(如@RequiresRoles,@RequiresPermissions),* 需藉助SpringAOP掃描使用Shiro註解的類,並在必要時進行安全邏輯驗證
     * 配置以下兩個bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可實現此功能
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    //加入註解的使用,不加入這個註解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

複製程式碼

SchedulerConfig類

package com.site.mountain.config;

import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import java.io.IOException;
import java.util.Properties;

@Configuration
public class SchedulerConfig {

    @Bean(name = "SchedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setQuartzProperties(quartzProperties());
        return factory;
    }

    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        //propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        //在quartz.properties中的屬性被讀取並注入後再初始化物件
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    /*
     * quartz初始化監聽器
     */
    @Bean
    public QuartzInitializerListener executorListener() {
        return new QuartzInitializerListener();
    }

    /*
     * 通過SchedulerFactoryBean獲取Scheduler的例項
     */
    @Bean
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }

}
複製程式碼

MyShiroRealm類

package com.site.mountain.config;

import com.site.mountain.entity.SysMenu;
import com.site.mountain.entity.SysRole;
import com.site.mountain.entity.SysUser;
import com.site.mountain.service.SysUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.List;

public class MyShiroRealm extends AuthorizingRealm {
    @Autowired
    @Lazy
    private SysUserService sysUserService;

    //角色許可權和對應許可權新增
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //獲取登入使用者名稱
        String name = (String) principalCollection.getPrimaryPrincipal();
        SysUser sysUser = new SysUser();
        sysUser.setUsername(name);
        //查詢使用者名稱稱
        List<SysUser> list = sysUserService.selectAllUserAndRoles(sysUser);
        SysUser userInfo = null;
        if (list.size() != 0) {
            userInfo = list.get(0);
        }
        //新增角色和許可權
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        for (SysRole role : userInfo.getRoleList()) {
            //新增角色
            simpleAuthorizationInfo.addRole(role.getRoleName());
            for (SysMenu sysMenu : userInfo.getMenuList()) {
                //新增許可權
                simpleAuthorizationInfo.addStringPermission(sysMenu.getPerms());
            }
        }
        return simpleAuthorizationInfo;
    }

    //使用者認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //加這一步的目的是在Post請求的時候會先進認證,然後在到請求
        if (authenticationToken.getPrincipal() == null) {
            return null;
        }
        //獲取使用者資訊
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        String name = usernamePasswordToken.getUsername();
        SysUser sysUser = new SysUser();
        sysUser.setUsername(name);
        List<SysUser> list = sysUserService.selectAllUserAndRoles(sysUser);
        SysUser userInfo = null;
        if (list.size() != 0) {
            userInfo = list.get(0);
        }
        if (userInfo == null) {
            //這裡返回後會報出對應異常
            return null;
        } else {
            //這裡驗證authenticationToken和simpleAuthenticationInfo的資訊
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name,userInfo.getPassword().toString(),getName());
            return simpleAuthenticationInfo;
        }

    }
}

複製程式碼

注意點

  • ShiroConfig中配置shiro攔截器鏈,配置攔截和攔截的路徑

  • 在MyShiroRealm中新增角色許可權和對應許可權,並且新增使用者認證。

  • 如果添加了許可權,例如下面MyShiroRealm中程式碼

    //新增角色和許可權
    SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    for (SysRole role : userInfo.getRoleList()) {
        //新增角色
        simpleAuthorizationInfo.addRole(role.getRoleName());
        for (SysMenu sysMenu : userInfo.getMenuList()) {
            //新增許可權
            simpleAuthorizationInfo.addStringPermission(sysMenu.getPerms());
        }
    }
    複製程式碼

    例如使用者列表介面sysuser/list 你添加了userInfo:view 許可權,那麼你在controller這個介面上必須新增

    @RequiresPermissions,如下面程式碼:

    @RequiresPermissions("userInfo:view")
    @RequestMapping(value = "list",method = RequestMethod.POST)
    @ResponseBody
    public JSONObject findList(@RequestBody SysUser sysUser,HttpServletRequest request,HttpServletResponse response){
            ......
        }
    複製程式碼

Mybatis相關配置

配置檔案

  • 在application.properties 配置檔案中新增mybatis包掃描

    mybatis.type-aliases-package=com.site.mountain.entity
    複製程式碼
  • 在springboot啟動類上開啟事務註解

    @SpringBootApplication
    @EnableTransactionManagement   //開啟事物管理功能
    public class MountainApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MountainApplication.class,args);
        }
    }
    複製程式碼

注意點

  • 事務失效:springboot和shiro框架整合時,先載入shiro,這時sysUserService還沒有例項化,導致事務失效, 在sysUserService 上載入 @Lazy

配置多資料來源

配置檔案

server.port=8080
server.servlet.context-path=/mt
server.servlet.session.timeout=10
#MVC
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
spring.resources.static-locations=classpath:/static/dist/

spring.profiles.active=dev

#當遇到同樣名字的時候,是否允許覆蓋註冊
#spring.main.allow-bean-definition-overriding=true

#配置監控統計攔截的filters,去掉後監控介面SQL無法進行統計,'wall'用於防火牆
spring.datasource.mysql.filters=stat,不然報錯jdbcUrl is required with driverClassName.
#spring.datasource.mysql.jdbc-url=jdbc:mysql://127.0.0.1:3306/mountain
#spring.datasource.mysql.username=root
#spring.datasource.mysql.password=root


spring.datasource.test1.driverClassName=com.mysql.jdbc.Driver
# 這裡配置springboot2 預設Hikari連線池,不識別url,需要用jdbc-url,不然報錯jdbcUrl is required with driverClassName.
spring.datasource.test1.jdbc-url=jdbc:mysql://127.0.0.1:3306/mountain
spring.datasource.test1.username=root
spring.datasource.test1.password=root
#spring.datasource.test1.type=com.alibaba.druid.pool.DruidDataSource
#spring.datasource.test1.initialSize=5
#spring.datasource.test1.minIdle=5
#spring.datasource.test1.maxActive=20
spring.datasource.test2.driverClassName=com.mysql.jdbc.Driver
# 這裡配置springboot2 預設Hikari連線池,不識別url,需要用jdbc-url,不然報錯jdbcUrl is required with driverClassName.
spring.datasource.test2.jdbc-url=jdbc:mysql://127.0.0.1:3306/xjone
spring.datasource.test2.username=root
spring.datasource.test2.password=root
#spring.datasource.test2.type=com.alibaba.druid.pool.DruidDataSource
#spring.datasource.test2.initialSize=5
#spring.datasource.test2.minIdle=5
#spring.datasource.test2.maxActive=20
#mybatis.mapper-locations=mapping/*.xml
oracle.datasource.url=jdbc:oracle:thin:@192.168.25.142:1521:helowin
oracle.datasource.username=SJZX_ODS
oracle.datasource.password=SJZX_ODS
oracle.datasource.driverClassName=oracle.jdbc.driver.OracleDriver

mybatis.type-aliases-package=com.site.mountain.entity



複製程式碼

MySQL資料來源配置類

package com.site.mountain.datasource;


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration
@MapperScan(basePackages = "com.site.mountain.dao.mysql",sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
public class MysqlDataSourceConfig {
    // @Primary 確定此資料來源為master
    @Bean(name = "mysqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.mysql")
    @Primary
    public DruidDataSource mysqlDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "mysqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqlDataSource") DruidDataSource druidDataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(druidDataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/mysql/*.xml"));
        return bean.getObject();
    }

    //配置事務管理器
    @Bean(name = "mysqlTransactionManager")
    @Primary
    public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("mysqlDataSource") DruidDataSource druidDataSource) {
        return new DataSourceTransactionManager(druidDataSource);
    }

    @Bean(name = "mysqlSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

複製程式碼

Oracle 資料來源配置類

package com.site.mountain.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = OracleDataSourceConfig.PACKAGE,sqlSessionTemplateRef = "oracleSqlSessionTemplate")
public class OracleDataSourceConfig {

    // 精確到 oracle 目錄,以便跟其他資料來源隔離
    static final String PACKAGE = "com.site.mountain.dao.oracle";
    static final String MAPPER_LOCATION = "classpath:mybatis/mapper/oracle/*.xml";

    @Value("${oracle.datasource.url}")
    private String url;

    @Value("${oracle.datasource.username}")
    private String user;

    @Value("${oracle.datasource.password}")
    private String password;

    @Value("${oracle.datasource.driverClassName}")
    private String driverClass;

    @Bean(name = "oracleDataSource")
    public DataSource oracleDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean(name = "oracleTransactionManager")
    public DataSourceTransactionManager oracleTransactionManager() {
        return new DataSourceTransactionManager(oracleDataSource());
    }

    @Bean(name = "oracleSqlSessionFactory")
    public SqlSessionFactory oracleSqlSessionFactory(@Qualifier("oracleDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(OracleDataSourceConfig.MAPPER_LOCATION));
        return bean.getObject();
    }

    @Bean(name = "oracleSqlSessionTemplate")
    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("oracleSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
複製程式碼

注意點

  • 資料來源類中配置了Mybatis對應的Mapper.xml檔案路徑

  • MySQL 和Oracle對應配置檔案中的配置的方式是不一樣的,MySQL直接註解@ConfigurationProperties(prefix = "spring.datasource.mysql"),而Oracle是使用的

    @Value("${oracle.datasource.url}")

配置日誌

由於springboot2 預設引入logback相關的jar包,即下面的jar包中關聯引用了

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
</parent>
複製程式碼

logback 配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 專案名稱 -->
    <property name="PROJECT_NAME" value="mountain" />

    <!--定義日誌檔案的儲存地址 勿在 LogBack 的配置中使用相對路徑-->
    <property name="LOG_HOME" value="${catalina.base}/logs" />

    <!-- 控制檯輸出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--<withJansi>true</withJansi>-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化輸出:%d表示日期,%thread表示執行緒名,%-5level:級別從左顯示5個字元寬度%msg:日誌訊息,%n是換行符-->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %highlight([%-5level] %logger{50} - %msg%n)</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 系統錯誤日誌檔案 -->
    <appender name="SYSTEM_FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 過濾器,只打印ERROR級別的日誌 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日誌檔案輸出的檔名-->
            <FileNamePattern>${LOG_HOME}/${PROJECT_NAME}.system_error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日誌檔案保留天數-->
            <MaxHistory>15</MaxHistory>
            <!--日誌檔案最大的大小-->
            <MaxFileSize>10MB</MaxFileSize>
        </rollingPolicy>

        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化輸出:%d表示日期,%thread表示執行緒名,%-5level:級別從左顯示5個字元寬度%msg:日誌訊息,%n是換行符-->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%-5level] %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <logger name="system_error" additivity="true">
        <appender-ref ref="SYSTEM_FILE"/>
    </logger>

    <!-- 自己列印的日誌檔案,用於記錄重要日誌資訊 -->
    <appender name="MY_INFO_FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 過濾器,只打印ERROR級別的日誌 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日誌檔案輸出的檔名-->
            <FileNamePattern>${LOG_HOME}/${PROJECT_NAME}.my_info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日誌檔案保留天數-->
            <MaxHistory>15</MaxHistory>
            <!--日誌檔案最大的大小-->
            <MaxFileSize>10MB</MaxFileSize>
        </rollingPolicy>

        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化輸出:%d表示日期,%thread表示執行緒名,%-5level:級別從左顯示5個字元寬度%msg:日誌訊息,%n是換行符-->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%-5level] %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <logger name="my_info" additivity="true">
        <appender-ref ref="MY_INFO_FILE"/>
    </logger>

    <!-- 開發環境下的日誌配置 -->
    <springProfile name="dev">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="SYSTEM_FILE" />
        </root>
    </springProfile>

    <!-- 生產環境下的日誌配置 -->
    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="SYSTEM_FILE" />
        </root>
    </springProfile>
</configuration>
複製程式碼

注意點

  • 各個環境(開發、測試、生產)的日誌輸出級別
  • 輸出日誌大小、保留的時間、路徑。

其他

更改springboot啟動圖案

  • 首先獲圖案:去http://patorjk.com/software/taag/#p=testall&f=Zodi&t=mountain 網站,輸入需要生成的文字,例如輸入mountain
  • 把生成的文字複製儲存為banner.txt 檔案,把這個檔案放到mountain\src\main\resources 路徑下,這樣在啟動程式,圖案就變成自定義了

後端專案地址

mountain專案地址:github.com/jinshw/moun…

待續...

  • 整合Swagger2
  • 整合quartz框架
  • 整合docker
  • 前端工程搭建:基於vue-element-admin擴充套件
  • 許可權管理系統實現:使用者管理、角色管理、部門管理、選單管理等模組