QiYuAdmin-架构搭建一(SpringBoot实战)

本文是作者作为研发经理,以 QiYuAdmin 后台管理系统为背景,分享的SpringBoot集成实战。文章介绍了项目基础架构的搭建,包括基于Maven的SpringBoot项目创建、Druid与Mybatis的集成、封装的基础接口BaseService等。作者还计划在后续文章中分享更多功能的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

工作5年了,现在自我定义是一个产品的研发经理,去年公司老板要每个人拿着自己的PPT在他面前做年终总结,我其中有一条是今年要写一套技术博客文集 then just do it。接下来的一系列的文章是以我现在带的一个项目为基础,从新开始一个后台管理类型的项目(QiYuAdmin–后台管理系统)为推动力来完成,里面有很多东西需要我去注意和学习的地方,太多。

成果

登录
这里写图片描述
首页
这里写图片描述


技术架构

这篇文章主要的内容就是搭建项目的基础架构

  • SpringBoot 1.5.1
  • Mybatis 3.3.8
  • Thymeleaf 3.0
  • BootStrap 3
  • SpringBoot和Druid集成
  • SpringBoot、通用Mapper集成和分页插件集成
  • 自己封装的基础接口BaseService
  • Maven3.3.9、intellij idea2016、MySQL、Tomcat

基于Maven创建SpringBoot项目

项目结构

解释一下以上几个模块的作用
* qiyu-framework-web:Metronic框架和一些插件
* qiyu-framework-core:整个项目的核心模块
* qiyu-amin-web:qyAdmin所有的页面和自定义静态资源
* qiyu-admin-auth:权限模块

SpringBoot集成Druid

这里写图片描述

这里写图片描述

源码网上搜索一大堆,还是贴出来吧
Application.properties配置:


# DataSource settings
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driverClassName = com.mysql.jdbc.Driver
#连接池的配置信息
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

Bean配置:

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 * alibaba druid数据库连接池
 *
 * @author zhangqing
 * @date 2017年02月25日
 */
@Configuration
public class DruidDBConfig {
    private Logger logger = LoggerFactory.getLogger(DruidDBConfig.class);
    @Value("${spring.datasource.url}")
    private String dbUrl;

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

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

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

    @Value("${spring.datasource.initialSize}")
    private int initialSize;

    @Value("${spring.datasource.minIdle}")
    private int minIdle;

    @Value("${spring.datasource.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;

    @Value("${spring.datasource.filters}")
    private String filters;

    @Value("{spring.datasource.connectionProperties}")
    private String connectionProperties;

    @Bean(initMethod = "init", destroyMethod = "close")   //声明其为Bean实例
    @Primary  //在同样的DataSource中,首先使用被标注的DataSource
    public DataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();

        datasource.setUrl(this.dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);

        //configuration
        datasource.setInitialSize(initialSize);
        datasource.setMinIdle(minIdle);
        datasource.setMaxActive(maxActive);
        datasource.setMaxWait(maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setValidationQuery(validationQuery);
        datasource.setTestWhileIdle(testWhileIdle);
        datasource.setTestOnBorrow(testOnBorrow);
        datasource.setTestOnReturn(testOnReturn);
        try {
            datasource.setFilters(filters);
        } catch (SQLException e) {
            logger.error("druid configuration initialization filter", e);
        }
        datasource.setConnectionProperties(connectionProperties);

        return datasource;
    }

    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");
        reg.addInitParameter("allow", "127.0.0.1"); //白名单
        reg.addInitParameter("deny",""); //黑名单
        reg.addInitParameter("loginUsername", "admin");
        reg.addInitParameter("loginPassword", "admin");
        return reg;
    }

    @Bean public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

SpringBoot集成Mybatis


import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Properties;

/**
 * MyBatis基础配置
 */
@Configuration
@EnableTransactionManagement
public class MyBatisConfig implements TransactionManagementConfigurer {

    @Resource
    DataSource dataSource;

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.qiyu.admin.*.model");

        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);

        //添加插件
        bean.setPlugins(new Interceptor[]{pageHelper});

        //添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath*:mapper/*Mapper.xml"));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }
}

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

import java.util.Properties;

/**
 * MyBatis扫描接口,使用的tk.mybatis.spring.mapper.MapperScannerConfigurer,
 */
@Configuration
//注意,由于MapperScannerConfigurer执行的比较早,所以必须有下面的注解
@AutoConfigureAfter(MyBatisConfig.class)
public class MyBatisMapperScannerConfig {

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.qiyu.admin.*.mapper");
        Properties properties = new Properties();
        properties.setProperty("mappers", "com.qiyu.framework.base.BaseMapper");
        properties.setProperty("notEmpty", "false");
        properties.setProperty("IDENTITY", "MYSQL");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }

}

封装的基础接口BaseService

这个是自己封装的接口,没啥技术含量就是为了方便



import com.qiyu.framework.util.PagedResult;

import java.util.List;

/**
 *
 * 基础接口
 * @author zhangqing
 * @date 2016年09月02日
 */

public interface BaseService<T extends BaseModel>{
    /**
     *
     * 增加一个实体,增加所有字段
     * @param pojo
     * @return 返回实体类
     */
    public T insert(T pojo) throws Exception;

    /**
     *
     * 增加一个实体,只会增加不是null的字段
     * @param pojo
     * @return 返回实体类
     */
    public T insertSelective(T pojo)throws Exception;

    /**
     * 根据主键进行更新一个实体类,更新所有字段
     * @param pojo
     * @return 修改成功状态
     */
    public T updateByPrimaryKey(T pojo)throws Exception;

    /**
     * 根据主键进行更新一个实体类,只会更新不是null的字段
     * @param pojo
     * @return
     */
    public T updateByPrimaryKeySelective(T pojo)throws Exception;

    /**
     * 根据实体类中字段不为null的条件进行删除,条件全部使用=号and条件
     * @param key
     * @return
     */
    public int delete(T key)throws Exception;

    /**
     * 通过主键进行删除,这里最多只会删除一条数据
     * 单个字段做主键时,可以直接写主键的值
     * 联合主键时,key可以是实体类,也可以是Map
     * @param key
     * @return
     */
    public int deleteByPrimaryKey(Object key)throws Exception;

    /**
     * 根据主键的集合批量删除数据
     * @param keys
     * @return 是否删除成功
     */
    public boolean deleteByPrimaryKeyList(List<String> keys)throws Exception;

    /**
     * 根据实体类不为null的字段进行查询集合,条件全部使用=号and条件
     * @param pojo
     * @return
     */
    public List<T> select(T pojo)throws Exception;

    /**
     * 根据实体类不为null的字段查询总数,条件全部使用=号and条件
     * @param pojo
     * @return
     */
    public int selectCount(T pojo)throws Exception;

    /**
     * 根据主键进行查询,必须保证结果唯一
     * 单个字段做主键时,可以直接写主键的值
     * 联合主键时,key可以是实体类,也可以是Map
     * @param key
     * @return
     */
    public T selectByPrimaryKey(Object key)throws Exception;

    /**
     * 查询所有实体集合
     * @return
     */
    public List<T> selectAll()throws Exception;

    /**
     * 查询分页
     * @param pageNo
     * @param pageSize
     * @param pojo
     * @return
     */
    public PagedResult<T> findPageList(Integer pageNo, Integer pageSize, T pojo)throws Exception;

尝试的小白

第一篇先写到这里,写的比较粗糙,源码先不分享了,现在还是一个半成品,后续我将把用户、部门的增删改查功能做出来之后分享到github上,希望大家一起学习。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山竹之七语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值