原来的老项目基于spring mvc,使用jsp网页文件。当前为了方便开发和维护,需要转换为spring boot。中间遇到一些坑。在此整理出来,供大家参考。

1、修改pom.xml文件

        删除spring相关依赖jar,添加spring boot相关依赖jar。

			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter</artifactId>
				<version>${spring-boot-version}</version>
				<exclusions>
					<!-- 与log4j冲突,排除自带的logback依赖 -->
					<exclusion>
						<groupId>org.springframework.boot</groupId>
						<artifactId>spring-boot-starter-logging</artifactId>
					</exclusion>
				</exclusions>
			</dependency>
            <!--引入spring security相关jar组件-->
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-security</artifactId>
				<version>${spring-boot-version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-web</artifactId>
				<version>${spring-boot-version}</version>
				<exclusions>
                    <!-- 与log4j冲突,排除自带的logback依赖 -->
					<exclusion>
						<groupId>org.springframework.boot</groupId>
						<artifactId>spring-boot-starter-logging</artifactId>
					</exclusion>
				</exclusions>
			</dependency>
			<dependency> <!-- 引入log4j2依赖 -->
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-log4j2</artifactId>
				<version>${spring-boot-version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-jdbc</artifactId>
				<version>${spring-boot-version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-data-jpa</artifactId>
				<version>${spring-boot-version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-devtools</artifactId>
				<version>${spring-boot-version}</version>
				<scope>runtime</scope>
				<optional>true</optional>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-configuration-processor</artifactId>
				<version>${spring-boot-version}</version>
				<optional>true</optional>
			</dependency>
			<!--junit test -->
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-test</artifactId>
				<version>${spring-boot-version}</version>
				<scope>test</scope>
			</dependency>

这里特别要注意,引入spring-boot-starter及spring-boot-starter-web时,要排除spring-boot-starter-logging,否则会一直提醒:slf4j的两个实现log4j与logback冲突。spring boot 中默认内嵌的tomcat对jsp的支持不够理想。需要添加内嵌tomcat的增强jar包,

			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-tomcat</artifactId>
				<version>${spring-boot-version}</version>
				<scope>provided</scope>
			</dependency>
			<dependency>
				<groupId>org.apache.tomcat.embed</groupId>
				<artifactId>tomcat-embed-jasper</artifactId>
				<version>9.0.33</version>
				<scope>provided</scope>
			</dependency>

其实包spring-boot-starter-web中包含spring-boot-starter-tomcat,而spring-boot-starter-tomcat中又包含tomcat-embed-jasper,所以下面两个包可以不显示引用,而只在web项目中添加tomcat-embed-jasper即可,如下:

            <dependency>
				<groupId>org.apache.tomcat.embed</groupId>
				<artifactId>tomcat-embed-jasper</artifactId>
				<scope>provided</scope>
			</dependency>

spring boot默认动态网页是/resources目录下的template,而spring mvc动态网页默认路径是webapp/WEB-INF/views。在pom.xml中需要配置资源文件路径src/main/webapp,并通过spring-boot-maven-plugin插件打包:

    <build>
		<resources>
            <!--resource用来编译包括的资源文件和排除的资源文件,但是仅限于class目录下的文件。在编译期和调试期都会执行,把directory中的文件移动到targetPath目录下 -->
			<resource>
				<directory>src/main/webapp</directory>
				<targetPath>META-INF/resources</targetPath>
				<includes>
					<include>**/**</include>
				</includes>
				<filtering>false</filtering>
			</resource>
		</resources>
        <plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<fork>true</fork>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<artifactId>maven-surefire-plugin</artifactId>
				<configuration>
					<skipTests>true</skipTests>
				</configuration>
			</plugin>
            <plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<configuration>
					<!--排除掉war包指定文件(*:文件夹下所有文件;**:文件夹下所有文件,包含子文件夹的文件)-->
					<packagingExcludes>
						WEB-INF/classes/log4j2.xml,
						WEB-INF/classes/*.yml,
						WEB-INF/classes/META-INF/resources/**
					</packagingExcludes>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-resources-plugin</artifactId>
				<version>3.1.0</version>
				<executions>
					<execution>
						<id>copy-resources</id>
						<phase>validate</phase>
						<goals>
							<goal>copy-resources</goal>
						</goals>
						<configuration>
                        <!--输出资源文件到war包外的文件夹,仅在编译期执行,调试期不执行-->
					<outputDirectory>${project.build.directory}/config</outputDirectory>
							<resources>
								<resource>
									<directory>src/main/resources</directory>
									<filtering>true</filtering>
									<includes>
										<include>**/*.yml</include>
										<include>log4j2.xml</include>
									</includes>
								</resource>
							</resources>
						</configuration>
					</execution>
				</executions>
			</plugin>
        </plugins>
    </build>

另外,对于此spring boot 项目,打包时只能打包成war包,不能打包成jar包,否则执行失败。

  <packaging>war</packaging>

此包的运行方式通jar包的运行方式,若配置文件在war包外,则指定文件,若在包内,则不用指定:

java -jar webapplication.war -Dspring.config.location=./config/application.yml

2、新增启动类WebApplication

新增启动类WebApplication,并添加main方法。


@SpringBootApplication(exclude= HibernateJpaAutoConfiguration.class)
public class WebApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

3、添加配置文件application.yml

spring boot的配置文件默认名称为application.yml,放到resources目录下,内容如下:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://10.74.0.218/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false
    password: 123456
    username: root
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      connection-test-query: SELECT 1 FROM DUAL
      minimum-idle: 1
      maximum-pool-size: 5
  jpa:
    hibernate:
      ddl-auto: none
    properties:
      hibernate:
        show_sql: true
        format_sql: false
        dialect: org.hibernate.dialect.MySQL5Dialect
        current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
        cache:
          use_second_level_cache: true
          use_query_cache: true
          region.factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
        javax.cache:
          provider: org.ehcache.jsr107.EhcacheCachingProvider
          uri: classpath:ehcache.xml
      javax:
        persistence:
          sharedCache:
            mode: ENABLE_SELECTIVE
  mvc:
    view:
      suffix: .jsp
      prefix: /WEB-INF/views/
  main:
    allow-bean-definition-overriding: true
  web:
    resources:
      static-locations: classpath:/resources/,classpath:/static/,./config/
  application:
    name: test-web

  servlet:
    multipart:
      enabled: true
      max-file-size: 10MB
      max-request-size: 10MB

logging:
  config: classpath:log4j2.xml

# --- server
server:
  port: 8090

4、新增配置类

WebSecurityConfig用户登录控制.
package com.test.web.config;

import com.test.web.security.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private UserDetailsService userDetailsService;
    private PasswordEncoder passwordEncoder;

    private UserAuthenticationSuccessHandler userAuthenticationSuccessHandler;
    private UserAuthenticationFailureHandler userAuthenticationFailureHandler;


    public WebSecurityConfig(UserDetailsService userDetailsService,
                             PasswordEncoder passwordEncoder,
                             UserAuthenticationSuccessHandler userAuthenticationSuccessHandler,
                             UserAuthenticationFailureHandler userAuthenticationFailureHandler){
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
        this.userAuthenticationSuccessHandler = userAuthenticationSuccessHandler;
        this.userAuthenticationFailureHandler = userAuthenticationFailureHandler;

    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        //被忽略的路径是不经过权限认证的,也不能获取权限信息。
   web.ignoring().antMatchers("/webjars/**","/resources/**","/getValidateCode","/login");
        web.httpFirewall(httpFirewall());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        final String rememberMeKey = "cJAvjSVcKbsBOCfOmTLayw==";
        //配置授权认证,允许匿名访问的路径配置要放在最前面,否则无效。
        http.authorizeRequests()
                .antMatchers("/loginCheck","/login")
                .permitAll()
                .and()
                .authorizeRequests()
                .antMatchers("/**")
                .authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/loginCheck")
                .defaultSuccessUrl("/")
                .successHandler(userAuthenticationSuccessHandler)
                .failureHandler(userAuthenticationFailureHandler)
                .permitAll()
                .and()
                .rememberMe().key(rememberMeKey)
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login")
                .invalidateHttpSession(true);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    public HttpFirewall httpFirewall() {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        firewall.setUnsafeAllowAnyHttpMethod(true);
        firewall.setAllowBackSlash(true);
        firewall.setAllowUrlEncodedDoubleSlash(true);
        return firewall;
    }

}

HibernateConfig:Hibernate相关控制.

package com.test.web.config;

import org.hibernate.SessionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.*;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

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


@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.test.dao","com.test.service"})
public class HibernateConfig {

    @Bean
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory){
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);
        return txManager;
    }


    @Bean
    @ConfigurationProperties(prefix = "spring.jpa.properties")
    public Properties properties(){
        Properties properties = new Properties();
        return properties;
    }



    @Bean

    public LocalSessionFactoryBean sessionFactory(DataSource dataSource){
        Properties properties = properties();

        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setHibernateProperties(properties);
        sessionFactoryBean.setPackagesToScan("com.test.model");
        return sessionFactoryBean;
    }

}

到此基本完成转换spring boot工作。

5、问题总结

生成的war包,可以直接通过java -jar test.war直接运行,在windows中运行,一切正常,但是若是在Linux中运行,就会发现,打开网页的速度特别慢,具体原因见:Springboot 第一次访问慢的问题研究&解决方案。我根据网上查询的解决办法都试过了(包括修改随机数生成器和替换servlet容器为jetty),但是成效并不明显。最后只能使用外部servlet容器,即使用外部的tomcat或jetty服务器。

Logo

更多推荐