公司老项目springmvc jsp 自定义多数据源 转到springboot 整理

真实完整步骤,踩坑整理 有同样的坑,欢迎补充整理

网上的案例老是少了很多配置,本案例涉及到 spring-mvc,自定义多数据源,统一前缀,事务,mybatis,jsp访问异常,静态文件。

项目还是老的目录结构

springboot的目的就是为了简化开发,使用配置的方式,因此 我们最终的目标 就是删除springmvc项目中 web.xml  springmvc相关配置  mybatis配置等;

1.添加springboot相关的pom依赖 
redis、日志等等按需添加,老的spring的相关都删除

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
</parent>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

<build>
    <finalName>JoeProject</finalName>
    <outputDirectory>${basedir}/target/site</outputDirectory>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.*</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.*</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/webapp</directory>
            <includes>
                <include>**/*.*</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>


2.添加启动类

@SpringBootApplication
public class JoeApplication extends SpringBootServletInitializer {
    // 入口
    public static void main(String[] args) {
        SpringApplication.run(JoeApplication.class, args);
    }

    // Java EE应用服务器配置,
    // 如果要使用tomcat来加载jsp的话就必须继承SpringBootServletInitializer类并且重写其中configure方法
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(JoeApplication.class);
    }

}


3.添加 application.yml
3.1包括端口,全局参数以及全局路径,环境分支,上传
3.2本案例 数据源暂时不用配置(因为老的使用了多数据源 并且需要自定义解析数据库的密文,因此下面将使用编程式(较传统)配置多数据源),也可以使用苞米豆的 多数据源配置,然后注解Ds()

server:
  port: 8082
  servlet:
    encoding:
      charset: utf-8
    context-path: /Joe
    # 全局变量参数,可以用在jsp中 <script src="<%=application.getInitParameter("Joe") %>/static/ss.js></script>
    context-parameters:
      Joe: /Joe
      
spring:
  profiles:
    active: branch

  servlet:
    multipart:
      max-file-size: 500MB
      max-request-size: 500MB


      
4.重点!! web.xml的处理
4.1 老的web.xml都可以删除,但是里面一些主要的,包括全局参数 、欢迎页、异常处理、以及springmvc的配置文件(拦截器、事务、数据源与mybatis配置)都需要代码来处理
4.2 老项目全是*.do idea可以全局替换(注意要全词匹配 .do,然后大概看下防止错误) Eidt-find-replace in files
4.2.1 静态文件get请求处理
4.3 对spring-mvc.xml进行配置
4.3.1 路径拦截处理
<!-- 老版本
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/marketing/*"/>
        <bean class="com.Joe.until.LoginInterceptor" ></bean>
    </mvc:interceptor>
</mvc:interceptors> -->

修改后:
WebmvcConfig.java
@Configuration
// 踩坑 extends WebMvcConfigurationSupport导致我的页面访问请求都被当作一个Controller层请求而被处理了。导致页面的 js css都加载不出来

@Configuration
// public class WebmvcConfig extends WebMvcConfigurationSupport {
public class WebmvcConfig implements WebMvcConfigurer {
    // 首页添加
    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("views/loadLogin");
    }

    // 踩坑,不能使用application.yml的配置方式
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
            .addPathPatterns("/test/*")
            .excludePathPatterns("/", "/login", "/css/**", "/js/**", "/views/**");
        super.addInterceptors(registry);
    }
}


LoginInterceptor.java

public class LoginInterceptor extends BaseInterceptor implements HandlerInterceptor {

    // 验证
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            Cookie userSysno = CookiesUntil.getCookieByName(request, "userSysno");
            Cookie sid = CookiesUntil.getCookieByName(request, "sid");
            boolean re;
            if (userSysno != null && sid != null) {
                re = this.checkLogin(request, response, sid, userSysno);
            } else {
                RedisUtil.ClearKey(userSysno.getValue() + "permissions");
                re = false;
            }
            if (!re) {
                RedisUtil.ClearKey(userSysno.getValue() + "permissions");
                request.getRequestDispatcher("/login/loginOut").forward(request, response);
                return false;
            } else {
                return true;
            }
        } catch (Exception ex) {
            System.out.println("preHandle:" + ex.getMessage());
            request.getRequestDispatcher("/login/loginOut").forward(request, response);
            return false;
        }

    }
}

5.重点!!spring-mybatis配置修改 多数据源处理 
老项目采用的AbstractRoutingDataSource、自定义SqlSessionFactoryBean、ThreadLocal<String> contextHolder切换数据源。
四个类搞定自定义多数据源

DynamicDataSource.java

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return CustomerContextHolder.getCustomerType();
    }

}

DatasourceConfig.java 多数元配置

@Configuration
public class DatasourceConfig {
    @Value("${jdbc.url: sqlserver://allin.w.allin}")
    public String jdbcUrl;
    @Value("${jdbc17.url: sqlserver://allin.r.Joe}")
    public String jdbc17Url;
    @Value("${jdbcallinDatatool.url: sqlserver://allin.w.allindatatool}")
    public String jdbcallinDatatoolUrl;
    @Value("${jdbc17Joeallin.url: sqlserver://allin.w.Joeallin}")

    @Primary
    @Bean(name = "dataSource1")
    public DataSource dataSource1() {
        DruidDataSource ds = new DruidDataSource();
        try {
            ds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            // 自定义解析 配置文件中的url,可以使用setpassword setname
            ds.setUrl(AllineDecoderClient.getInstance().getConnectionString(jdbcUrl));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ds;
    }

    @Bean(name = "dataSource2")
    public DataSource dataSource2() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        ds.setUrl(AllineDecoderClient.getInstance().getConnectionString(jdbc17Url));
        return ds;
    }

    @Bean(name = "dataSource3")
    public DataSource dataSource3() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        ds.setUrl(AllineDecoderClient.getInstance().getConnectionString(jdbcallinDatatoolUrl));
        return ds;
    }

    @Bean(name = "dataSource4")
    public DataSource dataSource4() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        ds.setUrl(AllineDecoderClient.getInstance().getConnectionString(jdbc17JoeallinUrl));
        return ds;
    }

    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("dataSource1", dataSource1());
        dataSourceMap.put("dataSource2", dataSource2());
        dataSourceMap.put("dataSource3", dataSource3());
        dataSourceMap.put("dataSource4", dataSource4());
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        // 设置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
        return dynamicDataSource;
    }

}

CustomerContextHolder.java


public class CustomerContextHolder {
    public static final String DATA_SOURCE_A = "dataSource1";

    public static final String DATA_SOURCE_B = "dataSource2";

    public static final String DATA_SOURCE_C = "dataSource3";

    public static final String DATA_SOURCE_D = "dataSource4";

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setCustomerType(String customerType) {
        contextHolder.set(customerType);
    }

    public static String getCustomerType() {
        return contextHolder.get();
    }

    public static void clearCustomerType() {
        contextHolder.remove();
    }
}

DataSourceConfigDynamic.java  

@Configuration
@MapperScan(basePackages = "com.Joe.allin.dao", sqlSessionFactoryRef = "sqlSessionFactory") // 踩坑 未配置sqlSessionFactoryRef
public class DataSourceConfigDynamic {

    @Primary
    @Bean("sqlSessionFactory")
    SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        // 踩坑 未配置setMapperLocations
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/Joe/allin/mapping/*.xml"));
        return bean.getObject();
    }

}

-- 使用多数据源 在service调用dao层数据源前使用,然后清楚,默认数据源A不用写

CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
xxService.test();
CustomerContextHolder.clearCustomerType();

6.全局事务采用注解方式
7.全局异常处理 度娘一大堆
8.可能还会出现循环依赖、乱码、版本依赖冲突等。根据自己的问题自行处理
9.关于war jar的问题,我还是使用的war包,启动 直接application的方式就可以,依赖里内嵌了tomcat

---------页面加载静态资源很慢

@Configuration
public class EmbeddedTomcatConfiguration {

    @Bean
    TomcatServletWebServerFactory tomcatFactory() {
        return new TomcatServletWebServerFactory() {

            @Override
            protected void postProcessContext(Context context) {
                context.setResources(new ExtractingRoot());
            }
        };
    }

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainerCustomizer() {
        return new WebServerFactoryCustomizer<TomcatServletWebServerFactory>() {

            @Override
            public void customize(TomcatServletWebServerFactory container) {
                container.addContextCustomizers(
                        new TomcatContextCustomizer() {
                            @Override
                            public void customize(Context cntxt) {
                                cntxt.setReloadable(false);
                            }
                        });
            }
        };
    }
}

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

自定义链接池


public class DruidDataSourceFactory implements DataSourceFactory {
    private Properties properties;

    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public DataSource getDataSource() {
        DruidDataSource dds = new DruidDataSource();
        dds.setUrl(this.properties.getProperty("url"));
        switch (this.properties.getProperty("driver").toLowerCase()) {
            case "sqlserver":
                dds.setDriver(new SQLServerDriver());
                break;
        }
        try {
            dds.setFilters("stat");
            dds.setInitialSize(5); // 连接池初始化大小
            dds.setMinIdle(5); // 连接池中维护的空闲连接的数量,可以根据实际情况调整,建议和maxActive的值相同
            dds.setMaxActive(15); // 连接池最大连接数
            dds.setMaxWait(60000L); // 获取连接最大等待时间,单位毫秒(ms)
            dds.setTimeBetweenEvictionRunsMillis(10000L); // 超过则检测连接,检测需要关闭的空闲连接数
            dds.setValidationQuery("select 1"); // 创建连接校验连接是否有效执行的sql语句
            dds.setKeepAlive(true); // 连接保活配置项,建议保持不变,否则可能出现连接断开
            dds.setKeepAliveBetweenTimeMillis(120000); //  连接空闲多久以后,会检查连接的有效性
            dds.setTimeBetweenEvictionRunsMillis(60000); // 多久执行一次淘汰连接和保活操作
            dds.setMinEvictableIdleTimeMillis(300000L); // 连接再线程池中最小空闲时间 5分钟
            dds.setMaxEvictableIdleTimeMillis(600000L); // 连接再线程池中最大空闲时间 10分钟

            // 开启统计功能
            Properties connProperties = new Properties();
            connProperties.put("druid.stat.mergeSql", true);
            connProperties.put("druid.stat.slowSqlMillis", 5000);

            dds.setConnectProperties(connProperties);
            dds.init();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return dds;
    }
}

1.后续问题 多数据源老容易串,修改为配置的方式

2. 分页以及事务的配置

public MybatisPlusInterceptor sqlserverInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.SQL_SERVER2005));
        return interceptor;
    }

    @Bean(name = "SqlSessionFactory")
    SqlSessionFactory SqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(DataSource());
        bean.setPlugins(sqlserverInterceptor);
        return bean.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(DataSource());
    }

    private DataSource DataSource() {
        String connectionStr = ;
        properties.put("url", connectionStr);
        properties.put("driver", "sqlserver");
        DruidDataSourceFactory druidDataSourceFactory = new DruidDataSourceFactory();
        druidDataSourceFactory.setProperties(properties);
        return druidDataSourceFactory.getDataSource();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值