一人撸前后端后台管理系统(vue+springboot)——后端篇

分析

针对项目的一些背景和环境的分析:

  • 该项目采用的是oracle数据,生产上的数据采用专线物理隔离的形式隔离开。
  • 系统的使用方为内部工作人员,是小范围的操作,使用用户量不高于3000人。
  • 目前不考虑权限的问题,但是后面功能扩展可能需要用到。
  • 每次登录token的有效时间在1小时左右,并不需要控制单点登录功能

因此:

  1. 决定采用前后端分离,后端采用springboot+maven;
  2. 利用mybatis plus连接oralce,数据库连接池采用druid;
  3. 鉴权采用springSecurity+jwtToken的形式,json解析用fastjson;
  4. 本来也就我一个人开发,但是还是撸上了swagger对接口进行说明,便于后期管理与维护;
  5. 并不会与外部系统做交互,所以不用考虑暴露接口问题。

预备:

  1. 如果后面访问量上去,可以撸上redis;
  2. 利用redis可以做单点登录控制。

正式工作

一、初始化springboot项目

1.在idea里面初始化spingboot项目非常方便,网上的参考资料很多,不懂的读者随便百度一下都可以初始化一个maven管理的springboot项目。

  1. 根据前面提到的引入相应的maven配置
        
            org.springframework.boot
            spring-boot-starter-security
        

        
            com.alibaba
            druid-spring-boot-starter
            1.1.14

        
        
            io.springfox
            springfox-swagger2
            2.6.1
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.1.0
        
        
            com.baomidou
            mybatis-plus
            3.1.0
        
        
            com.baomidou
            mybatis-plus-generator
            3.1.0
        

        
            io.jsonwebtoken
            jjwt
            0.7.0
        

关于maven的介绍,不清楚的读者可以参考我之前的博客:https://www.jianshu.com/p/477ad2e14150

二、搭建数据库连接

DataSourceConfig

@Configuration
@Slf4j
@Order(1)
public class DataSourceConfig {
    @Autowired
    private DruidConfig druidConfig;

    // 如果不是 druid 的 datasource, 直接用下面这个方式就可以, 但是 SpringBoot 默认还不支持 druid
    //    @Bean(name = "hkb2bDataSource")
    //    @ConfigurationProperties(prefix = "datasource.hkb2b")
    //    public DataSource hkb2bDataSource() {
    //                return DataSourceBuilder.create().build();
    //    }

    @Bean(name = "demoDataSource")
    public DataSource demoDataSource() {
        DruidDataSource datasource = new DruidDataSource();

        datasource.setUrl(druidConfig.getUrl());
        datasource.setUsername(druidConfig.getUsername());
        datasource.setPassword(druidConfig.getPassword());
        datasource.setDriverClassName(druidConfig.getDriverClassName());

        datasource.setInitialSize(druidConfig.getInitialSize());
        datasource.setMinIdle(druidConfig.getMinIdle());
        datasource.setMaxActive(druidConfig.getMaxActive());
        datasource.setMaxWait(druidConfig.getMaxWait());
        datasource.setTimeBetweenEvictionRunsMillis(druidConfig.getTimeBetweenEvictionRunsMillis());
        datasource.setMinEvictableIdleTimeMillis(druidConfig.getMinEvictableIdleTimeMillis());
        datasource.setValidationQuery(druidConfig.getValidationQuery());
        datasource.setTestWhileIdle(druidConfig.isTestWhileIdle());
        datasource.setTestOnBorrow(druidConfig.isTestOnBorrow());
        datasource.setTestOnReturn(druidConfig.isTestOnReturn());
        datasource.setPoolPreparedStatements(druidConfig.isPoolPreparedStatements());
        datasource.setMaxPoolPreparedStatementPerConnectionSize(
                druidConfig.getMaxPoolPreparedStatementPerConnectionSize());

        try {
            datasource.setFilters(druidConfig.getFilters());
        } catch (SQLException e) {
            log.error("druid configuration initialization filter", e);
        }
        datasource.setConnectionProperties(druidConfig.getConnectionProperties());

        return datasource;

    }

//    @Primary
//    @Bean(name = "demoJdbcTemplate")
//    public NamedParameterJdbcTemplate demoJdbcTemplate() {
//        return new NamedParameterJdbcTemplate(demoDataSource());
//    }

    @Configuration
    @ConfigurationProperties(prefix = "datasource.demo")
    @Data
    public class DruidConfig {
        // http://www.voidcn.com/blog/blueheart20/article/p-6181465.html
        // http://my.oschina.net/letao/blog/518012
        // https://github.com/alibaba/druid/wiki/配置_DruidDataSource参考配置
        private String url;
        private String username;
        private String password;
        private String driverClassName;
        private int initialSize;
        private int minIdle;
        private int maxActive;
        private int maxWait;
        private int timeBetweenEvictionRunsMillis;
        private int minEvictableIdleTimeMillis;
        private String validationQuery;
        private boolean testWhileIdle;
        private boolean testOnBorrow;
        private boolean testOnReturn;
        private boolean poolPreparedStatements;
        private int maxPoolPreparedStatementPerConnectionSize;
        private String filters;
        private String connectionProperties;
    }
}

MybatisPlusConfig

/**
 * @author wyk on 2019/02/28
 */
@Configuration
@Slf4j
public class MybatisPlusConfig {

    //@Qualifier(value = "demoDataSource")
    @Autowired
    DataSource dataSource;

    @Value("${mybatis-plus.global-config.db-config.capital-mode}")
    private boolean capitalMode;
    @Value("${mybatis-plus.mapper-locations}")
    private String mapperLocations;
    @Value("${mybatis-plus.type-aliases-package}")
    private String typeAliasesPackage;
    @Value("${mybatis-plus.global-config.db-config.logic-delete-value}")
    private String delete;
    @Value("${mybatis-plus.global-config.db-config.logic-not-delete-value}")
    private String notDelete;


    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory createSqlSessionFactoryBean() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations));
        sqlSessionFactoryBean.setPlugins(new PaginationInterceptor[]{this.paginationInterceptor()});

        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
        configuration.setJdbcTypeForNull(JdbcType.NULL);

        sqlSessionFactoryBean.setConfiguration(configuration);
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setDbConfig(this.globalConfiguration());
        globalConfig.setSqlInjector(new LogicSqlInjector());
        sqlSessionFactoryBean.setGlobalConfig(globalConfig);

        return sqlSessionFactoryBean.getObject();
    }

    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }


    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        /**/
        performanceInterceptor.setMaxTime(1000);
        /**/
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }

    /**
     * mybatis-plus分页插件
     */
    private PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor page = new PaginationInterceptor();
        page.setDialectType("oracle");
        return page;
    }



    private GlobalConfig.DbConfig globalConfiguration() {

        GlobalConfig.DbConfig configuration = new GlobalConfig.DbConfig();
        //主键策略
        configuration.setIdType(IdType.INPUT);
        //字段策略
        configuration.setFieldStrategy(FieldStrategy.NOT_EMPTY);
        //数据库大写 下划线转换
        configuration.setCapitalMode(capitalMode);
        configuration.setLogicDeleteValue(delete);
        configuration.setLogicNotDeleteValue(notDelete);
        configuration.setKeyGenerator(new OracleKeyGenerator());
        return configuration;
    }
}

三、搭建springSecurity权限拦截

SecurityConfig

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //@Autowired
    //UserDetailService userDetailService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//      http.httpBasic()// httpBasic 登录

        http.formLogin()// 表单登录  来身份认证
                .loginPage("/login") //
                .failureUrl("/login?error")
                .permitAll()// 自定义登录页面
                .and()
                .authorizeRequests()// 对请求授权
                .antMatchers(
                        "/login/*","/test/*").permitAll()// 这些页面不需要身份认证,其他请求需要认证
                .antMatchers("/admin/*").hasAuthority(TYPE_ADMIN)
                .antMatchers("/normal/*").hasAnyAuthority(TYPE_ADMIN,TYPE_NORMAL)
                .anyRequest() // 任何请求
                .authenticated()//; // 都需要身份认证
                .and()
                .csrf().disable()// 禁用跨站攻击
        .logout().logoutUrl("/logout").permitAll();

        http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
            String jwtToken = request.getHeader("jwtToken");
            Assert.notNull(jwtToken,CodeDefault.LOGIN);
        });

        // 关闭跨域拦截
        http.csrf().disable();
        // 关闭不允许在frame中访问的拦截
        http.headers().frameOptions().disable();
        // 单用户最大登陆数
        http.sessionManagement().maximumSessions(1);

        TokenLoginFilter tokenLoginFilter = new TokenLoginFilter();
        Map tokenLoginStrategys = this.getApplicationContext()
                .getBeansOfType(TokenLoginStrategy.class);
        ArrayList tokenLoginStrategysList = new ArrayList<>(tokenLoginStrategys.values());
        tokenLoginFilter.setTokenLoginStrategys(tokenLoginStrategysList);
        http.addFilterBefore(tokenLoginFilter, UsernamePasswordAuthenticationFilter.class);
    }

}

四、增加swagger

/**
 * @author wyk on 2019/02/28
 */
@Configuration
@EnableSwagger2
@Profile({"dev","sit"})//生产和预发布环境不开启
public class SwaggerConfig {

//    @Value("${spring.profiles.active}")
//    private String active;

    @Bean
    public Docket createRestApi() {
        //生产和预发布环境不开启
//        if (Constant.ACTIVE_PROD.equals(active) || Constant.ACTIVE_PROP.equals(active)) {
//            return null;
//        }
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // 指定 package,避免展现 spring-boot-starter-actuator 引入的 log-file-mvc-endpoint、health-mvc-endpoint 等
                .apis(RequestHandlerSelectors.basePackage("com.psbc.wyk.eirs"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("SpringBoot 示例框架")
                .description("SpringBoot 示例框架")
                .contact(new Contact("文宇坤", "yk.wen", "[email protected]"))
                .version("1.0").build();
    }
}

五、完成

一个基本的框架就完成了,读者可以从github上下载我搭建的一个demo:
https://github.com/YukunWen/dangjian
后续工作只需要往里面添加业务代码即可。

参考网址:
  1. jwtToken官网:https://jwt.io/
    请翻墙后访问,国内和国外看到的界面不完全一致
  2. springSecurity:http://blog.didispace.com/springbootsecurity/
  3. mybatis-plus:https://mp.baomidou.com/
  4. swagger:https://swagger.io/tools/swagger-ui/

你可能感兴趣的:(一人撸前后端后台管理系统(vue+springboot)——后端篇)