SpringBoot+Vue+ElementUI實現含國際化的前後端不分離的傳統簡易管理系統搭建(一)

本項目在GitHub上可以下載源代碼,歡迎大家指點。謝謝
GitHub地址:點擊進入

開發IED使用IntelliJ IDEA
目前僅僅在架構運用層解析框架如何使用,後續在此項目完結後會剖析所用到的所有架構的底層原理技術,額,比較傾向於,先學會簡單使用,再剖析其底層原理的學習模式。

1 項目構建

新建一個maven項目,這裏就不多說了,給大家看下我這邊項目的結構:
在這裏插入圖片描述
config:主要存放配置文件資源,我這裏目前比較簡單,就一個application.properties,當然也可以是推薦的springboot推薦的application.yml
i18n:主要存放國際化語言文件,這裏需要在application.properties中指定其文件路徑和位置
即:

# i18n
spring.messages.encoding=utf-8
spring.messages.basename=i18n/index

META-INF:目前可不需要,我這裏是想要以後可能會寫一些jsp文件,所以在這裏也支持下,配置的jsp文件就會在這裏文件夾中
在這裏插入圖片描述
views主要是前端代碼了,比如html、js等等

我們先來看後端
首先是pom.xml中jar包的引入:
springboot項目,必要的,必須繼承其父項目

<!--支持全棧式Web開發,包括Tomcat和spring-webmvc-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- spring boot 集成spring security-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!--支持常規的測試依賴,包括JUnit、Hamcrest、Mockito以及spring-test模塊-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

<!-- 支持JDBC數據庫 -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jdbc</artifactId>
	<version>2.0.4.RELEASE</version>
</dependency>


<!--mybatis-spring適配器-->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>1.3.0</version>
</dependency>

<!--mybatis-->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.4.0</version>
</dependency>

<!--mysql連接數據庫驅動-->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.11</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
<!-- dbcp常見主流數據庫連接池工具 -->
<dependency>
	<groupId>commons-dbcp</groupId>
	<artifactId>commons-dbcp</artifactId>
	<version>1.4</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
<dependency>
	<groupId>commons-pool</groupId>
	<artifactId>commons-pool</artifactId>
	<version>1.6</version>
</dependency>

<!-- aop切面支持 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!--支持Thymeleaf模板引擎,包括與Spring的集成-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
	<groupId>net.sourceforge.nekohtml</groupId>
	<artifactId>nekohtml</artifactId>
	<version>1.9.22</version>
</dependency>

<!-- 標準Java庫無法提供足夠的方法來處理其核心類。Apache Commons Lang提供了這些額外的方法。-->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-lang3</artifactId>
	<version>3.7</version>
</dependency>

<!-- XML操作jar包-->
<dependency>
	<groupId>dom4j</groupId>
	<artifactId>dom4j</artifactId>
	<version>1.6.1</version>
</dependency>

後端使用mybatis操作數據庫增、刪、改、查,Thymeleaf模板引擎進行頁面渲染,項目使用mysql做數據庫支撐

這裏還需要解決,IDE工具編譯java文件時,不編譯.xml文件及其他資源文件(字體等等)的問題,需要設置:

<resources>
    <!---解決字體問題-->
    <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
        <excludes>
            <exclude>**/fonts/**</exclude>
            <exclude>**/**.ico</exclude>
        </excludes>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>false</filtering>
        <includes>
            <include>**/fonts/**</include>
            <include>**/**.ico</include>
        </includes>
    </resource>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.xml</include>
        </includes>
    </resource>
</resources>

看下application.properties:

# service port
server.port=8080
# close favicon
spring.mvc.favicon.enabled=false
# database
default.datasource.driverClassName=com.mysql.cj.jdbc.Driver
default.datasource.url=jdbc:mysql://localhost:3306/xttl?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT&useSSL=false
default.datasource.username=root
default.datasource.password=soft01
# thymeleaf
spring.thymeleaf.prefix=classpath:/views/
spring.thymeleaf.check-template-location=true
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.cache=false
# jsp
spring.mvc.view.prefix=/jsp/
spring.mvc.view.suffix=.jsp
# i18n
spring.messages.encoding=utf-8
spring.messages.basename=i18n/index

8.0版本的mysql默認連接數據庫會使用useSSL,這裏我們需要禁掉,否則會出現Establishing SSL connection without server’s identity verification is not recommended的警告,同時我們需要設置時區,即:serverTimezone,否則會出現Could not get JDBC Connection; nested exception is java.sql.SQLException: The server time zone value ‘XXX’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support的錯誤信息。這裏目前先隨便設置個時區(serverTimezone=GMT,這表示格林威治中央區時區),後面來看,其實還是有問題的,請看後續分解。這兒不再詳述。
thymeleaf模板引擎配置:由於前段使用VUE+ElementUI,使得會在html標籤上存在一些非常規html規範的寫法,會導致模板解析報錯,所以這裏引入了JAR包nekohtml解決這個問題,同時spring.thymeleaf.mode配置需要更改爲LEGACYHTML5。SpringBoot默認模板放在resource下templates中的,可以看出我們的項目結構並不是這樣子,所以這裏需要指定模板路徑spring.thymeleaf.prefix=classpath:/views/

2 SpringBoot整合SpringSecurity

繼承org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter,重寫configure方法,這裏直接貼入樓主的整個類文件

package com.tllg.sysset.mvcconfig.security;

import com.tllg.sysset.mvcconfig.auth.MyAuthProvider;
import com.tllg.sysset.mvcconfig.user.MyUserDetailsService;
import com.tllg.sysset.mvcconfig.handler.MyFailHandler;
import com.tllg.sysset.mvcconfig.handler.MySuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author lgli
 * 安全信息配置
 * 項目基本配置信息,主要包括登錄攔截,靜態資源訪問
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private MyAuthProvider myAuthProvider;

    @Override
    public void configure(WebSecurity web){
        //定義登錄頁面的靜態資源(包括js)
        web.ignoring().antMatchers("/login/**",//登錄界面及其資源
                "/login.html",//登錄界面及其資源
                "/base/js/**",//主要js,jquery及其vue
                "/*.ico"//圖標
        );
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .formLogin()//定義需要用戶登錄時,跳轉到登錄頁面
            .loginPage("/login.html")//定義登錄頁面
            .usernameParameter("username").passwordParameter("password")//定義登錄界面傳參
            .loginProcessingUrl("/login_to_sys")//登錄接口,該接口被SpringSecurity執行;
            .permitAll()//表示不需要攔截,全部通過
            .failureHandler(new MyFailHandler())//登錄失敗處理handler
            .successHandler(new MySuccessHandler())//登錄成功處理handler
            .and().headers().frameOptions().sameOrigin()//保證同源iframe中可訪問,不攔截
            .and().authorizeRequests().anyRequest().authenticated()
            .and().csrf().disable()
        ;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService);
        auth.authenticationProvider(myAuthProvider);
//        auth.eraseCredentials(true);
    }
}

web.ignoring().antMatchers過濾不需要攔截的一些資源文件,如登錄所用到的所有html及js文件。
configure(HttpSecurity http)方法主要是攔截設置,其代碼主要含義,也有明確的註釋,設置frameOptions().sameOrigin()主要是因爲項目前端通過iframe嵌套訪問後端請求,否則請求將訪問異常。
此外,我們需要實現org.springframework.security.core.userdetails.UserDetailsService的loadUserByUsername方法,進行自定義驗證信息,也可以不實現,那樣就直接默認不處理了。我這裏實現了改方法,並組裝了登錄成功驗證後的一些資源信息,核心代碼如下《所涉及到的其他相關代碼,見GitHub》

if(UtilBase.STRING.isBlank(name)){
	throw new UsernameNotFoundException("請傳入用戶名");
}
logger.info("傳入用戶名爲{}的試圖登錄",name);
UserBaseInfo user = userMapper.selectUserByUserUniqueSign(name, "0");
if(user == null){
	throw new UsernameNotFoundException("無效用戶");
}
UserBaseSys userBaseSys = new UserBaseSys(user);
//獲取用戶角色
userBaseSys.setUserResource((List<ResourceInfo>)dealWithCascade(
		userMapper.selectUserResourcesByUserUniqueSign(name, StaticEnum.ZERO.getValue()),ResourceInfo.class
));
//獲取用戶資源
userBaseSys.setUserRoles((List<RoleBaseInfo >)dealWithCascade(
		userMapper.selectUserRolesByUserUniqueSign(name),RoleBaseInfo.class
));
logger.info("獲取到用戶數據,返回userDetail");
return userBaseSys;

configure方法設定了登錄驗證失敗或者成功的處理handler,這裏需要實現各自的接口
失敗,需要實現org.springframework.security.web.authentication.AuthenticationFailureHandler的onAuthenticationFailure方法,這裏就簡單的返回登錄頁面:

package com.tllg.sysset.mvcconfig.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * @author lgli
 * 登錄失敗處理handler
 *
 */
public class MyFailHandler implements AuthenticationFailureHandler {

    private Logger logger = LoggerFactory.getLogger(MyFailHandler.class);

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException e) throws IOException {
        logger.error("本次操作出現認證異常:"+new Date());
        response.sendRedirect("/login.html?error="+e.getMessage());//返回登錄頁面,重新登錄
    }
}

成功需要實現org.springframework.security.web.authentication.AuthenticationSuccessHandler的onAuthenticationSuccess方法,這裏登錄成功直接進入系統首頁

package com.tllg.sysset.mvcconfig.handler;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author lgli
 * 實現自定義的用戶成功登陸處理
 * 登錄成功處理handler
 *
 */
public class MySuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        response.sendRedirect("home/entryHomeIndex");
    }
}

3.SpringBoot整合Mybatis

由於長時間沒有仔細回顧Mybatis原理了,所以這裏採用@Configuration方式,一步步回顧mybatis,這裏也只做步驟層解析,不做底層原理解讀。

package com.tllg.sysset.datasource;

import com.tllg.util.PropertyUtil;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

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 org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import java.io.IOException;


/**
 * @author lgli
 * 初始化主數據源
 * 數據源連接池 --> 會話工廠sqlSessionFactoryBean --> 自動掃描對象關係映射 --> 事務管理
 */
@Configuration
@EnableTransactionManagement//支持事物
public class MainSource implements TransactionManagementConfigurer {

    private static final Logger log = LoggerFactory.getLogger(MainSource.class);

    @Autowired
    private PropertyUtil propertyUtil;

    private PooledDataSource datasource;

    private SqlSessionFactory sessionFactory;

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        initDataSource();
        return new DataSourceTransactionManager(datasource);
    }

    /**
     * 初始化數據源及其連接
     */
    @Bean(name="mainDatasource")
    public PooledDataSource initDataSource(){
        try {
            PooledDataSource datasource = new PooledDataSource();
            //設置連接驅動-數據庫類型
            datasource.setDriver(propertyUtil.getValueByKey("default.datasource.driverClassName"));
            //設置URL
            datasource.setUrl(propertyUtil.getValueByKey("default.datasource.url"));
            //設置用戶名
            datasource.setUsername(propertyUtil.getValueByKey("default.datasource.username"));
            //設置密碼
            datasource.setPassword(propertyUtil.getValueByKey("default.datasource.password"));
            //連接池其他信息默認PooledDataSource中的屬性
            this.datasource = datasource;
            return datasource;
        }catch (Exception e){
            log.error("初始化主數據源連接池失敗,"+e,e);
            throw new RuntimeException("初始化主數據源連接池失敗異常"+e);
        }
    }


    /**
     * 註冊sqlSessionFactoryBean
     *
     */
    @Bean(name="mainSqlSessionFactory")
    public SqlSessionFactory registerSqlSessionFactory(){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(this.datasource);//設置數據源
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            //指定xml配置文件路徑
            sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:com/tllg/**/mapper/xml/*.xml"));
            this.sessionFactory = sqlSessionFactoryBean.getObject();
            return this.sessionFactory;
        }catch (IOException ioe){
            log.error("主數據源配置Mapper映射文件不存在"+ioe,ioe);
            throw new RuntimeException("配置Mapper映射文件不存在"+ioe);
        }catch (Exception ex){
            log.error("主數據源註冊sqlSessionFactoryBean異常"+ex,ex);
            throw new RuntimeException("主數據源註冊sqlSessionFactoryBean異常"+ex);
        }
    }

    /**
     * 註冊sqlSessionTemplate
     * @param factory SqlSessionFactory
     * @return
     */
    @Bean(name="mainSqlSessionTemplate")
    public SqlSessionTemplate setSqlSessionTemplate(SqlSessionFactory factory){
        return new SqlSessionTemplate(factory);
    }
}

-------------------------------------------------


package com.tllg.sysset.datasource;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@AutoConfigureAfter(MainSource.class)
public class MainMapper {
    /**
     * 註冊Mapper映射文件信息
     */
    @Bean(name="mainMapperScannerConfigurer")
    public MapperScannerConfigurer registerMapperConfig(){
        MapperScannerConfigurer mapper = new MapperScannerConfigurer();
        //指定sqlSessionFactory
        mapper.setSqlSessionFactoryBeanName("mainSqlSessionFactory");
        //指定dao接口配置文件路徑
        mapper.setBasePackage("com.tllg.**.mapper");
        return mapper;
    }
}

代碼簡單描述下:
mybatis主要行動軌跡是,連接數據庫–>SqlSessionFactoryBuilder–>SqlSessionFactory–>SqlSession–>do Something -->return result
mybatis通過讀取配置文件信息,得到數據庫連接,由連接配置對象,得到當前數據庫連接的會話工廠SqlSessionFactoryBuilder對象,由SqlSessionFactoryBuilder對象得到SqlSessionFactory實例,由SqlSessionFactory得到SqlSession實例,SqlSession可以執行我們的sql了。所有對象實例,使用單例模式。當然一般來說,必須使用的單例模式,否則創建多了,數據庫連接會被佔滿了。
registerSqlSessionFactory()方法主要是SqlSessionFactory的一些配置信息,比如數據源,及其sql文件。
setSqlSessionTemplate()方法則是通過代理執行獲取SqlSession實例,內部封裝了其事物信息,不需要我們手動去調用SqlSessionFactory獲取SqlSession來執行sql了,即前面描述的後續過程交給SqlSessionTemplate處理了。

這裏有2個@Configuration配置文件,其中前面一個主要是mybatis行動軌跡過程代碼化,後面一個主要是設置映射關係文件,注意@AutoConfigureAfter註解,表示改配置文件需要先執行其他的配置文件,設置映射關係,我們需要得到SqlSessionFactory,所以第二個配置文件執行在第一個配置文件之後。

4 Resolver整合

我們需要重寫org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter的addResourceHandlers方法,使其可以訪問靜態資源文件

package com.tllg.sysset.mvcconfig.resolver;


import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * @author lgli
 * 資源路徑的配置信息
 * 指定訪問資源路徑
 */
@Component
public class SourceResolverConfig extends WebMvcConfigurerAdapter {

    /**
     * 添加目錄配置
     * 默認配置/**
     * 可以多次使用 addResourceLocations 添加目錄
     * 優先級先添加的高於後添加的
     * @param registry registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/views/");
        super.addResourceHandlers(registry);
    }
}

此時,基本後臺配置就差不多了,項目也是可以跑起來了。
目前先到這兒了,下一節,將繼續前端代碼的引入。
每天溫習一點點,學習才能進步
有喜歡的朋友可以關注下我的公衆號,不定期更新一些學習分享經驗。純屬個人所學總結,希望大家可以指出不正確的地方,共同學習成長。
在這裏插入圖片描述
代碼之路之長,因爲喜歡,所以堅持。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章