springboot5
阅读原文时间:2023年07月16日阅读:1

1.改造购物车系统
1.1.创建购物车的Spring Boot工程

1.1.导入依赖
http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE
com.taotao.cart
taotao-cart-springboot
1.0.0-SNAPSHOT
war

<dependencies>  
    <dependency>  
        <groupId>com.taotao.common</groupId>  
        <artifactId>taotao-common</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
    </dependency>  
    <dependency>  
        <groupId>com.taotao.sso</groupId>  
        <artifactId>taotao-sso-interface</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
    </dependency>  
    <!-- 单元测试 -->  
    <dependency>  
        <groupId>junit</groupId>  
        <artifactId>junit</artifactId>  
        <scope>test</scope>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-jdbc</artifactId>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-aspects</artifactId>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-web</artifactId>  
    </dependency>

    <!-- Mybatis -->  
    <dependency>  
        <groupId>org.mybatis</groupId>  
        <artifactId>mybatis</artifactId>  
        <version>3.2.8</version>  
    </dependency>  
    <dependency>  
        <groupId>org.mybatis</groupId>  
        <artifactId>mybatis-spring</artifactId>  
        <version>1.2.2</version>  
    </dependency>  
    <!-- 分页助手 -->  
    <dependency>  
        <groupId>com.github.pagehelper</groupId>  
        <artifactId>pagehelper</artifactId>  
        <version>3.7.5</version>  
    </dependency>  
    <dependency>  
        <groupId>com.github.jsqlparser</groupId>  
        <artifactId>jsqlparser</artifactId>  
        <version>0.9.1</version>  
    </dependency>

    <!-- 通用Mapper -->  
    <dependency>  
        <groupId>com.github.abel533</groupId>  
        <artifactId>mapper</artifactId>  
        <version>2.3.4</version>  
    </dependency>  
    <!-- MySql -->  
    <dependency>  
        <groupId>mysql</groupId>  
        <artifactId>mysql-connector-java</artifactId>  
    </dependency>  
    <dependency>  
        <groupId>org.slf4j</groupId>  
        <artifactId>slf4j-log4j12</artifactId>  
    </dependency>  
    <!-- 连接池 -->  
    <dependency>  
        <groupId>com.jolbox</groupId>  
        <artifactId>bonecp-spring</artifactId>  
        <version>0.8.0.RELEASE</version>  
    </dependency>

    <!-- httpclient -->  
    <dependency>  
        <groupId>org.apache.httpcomponents</groupId>  
        <artifactId>httpclient</artifactId>  
    </dependency>

    <!-- JSP相关 -->  
    <dependency>  
        <groupId>jstl</groupId>  
        <artifactId>jstl</artifactId>  
        <version>1.2</version>  
    </dependency>

    <!-- Apache工具组件 -->  
    <dependency>  
        <groupId>org.apache.commons</groupId>  
        <artifactId>commons-lang3</artifactId>  
        <version>3.3.2</version>  
    </dependency>  
    <dependency>  
        <groupId>org.apache.commons</groupId>  
        <artifactId>commons-io</artifactId>  
        <version>1.3.2</version>  
    </dependency>  
    <dependency>  
        <groupId>commons-codec</groupId>  
        <artifactId>commons-codec</artifactId>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework.amqp</groupId>  
        <artifactId>spring-rabbit</artifactId>  
        <version>1.4.0.RELEASE</version>  
    </dependency>

    <dependency>  
        <groupId>com.alibaba</groupId>  
        <artifactId>dubbo</artifactId>  
        <version>2.5.3</version>  
        <exclusions>  
            <exclusion>  
                <!-- 排除传递spring依赖 -->  
                <artifactId>spring</artifactId>  
                <groupId>org.springframework</groupId>  
            </exclusion>  
        </exclusions>  
    </dependency>

    <dependency>  
        <groupId>org.apache.zookeeper</groupId>  
        <artifactId>zookeeper</artifactId>  
        <version>3.3.3</version>  
    </dependency>

    <dependency>  
        <groupId>com.github.sgroschupf</groupId>  
        <artifactId>zkclient</artifactId>  
        <version>0.1</version>  
    </dependency>  
</dependencies>

<build>  
    <plugins>  
        <!-- 资源文件拷贝插件 -->  
        <plugin>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-resources-plugin</artifactId>  
            <configuration>  
                <encoding>UTF-8</encoding>  
            </configuration>  
        </plugin>  
        <!-- java编译插件 -->  
        <plugin>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-compiler-plugin</artifactId>  
            <configuration>  
                <source>1.7</source>  
                <target>1.7</target>  
                <encoding>UTF-8</encoding>  
            </configuration>  
        </plugin>  
        <plugin>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-maven-plugin</artifactId>  
        </plugin>  
    </plugins>  
</build>  


1.2.将taotao-cart中的java代码拷贝到taotao-car-springboot

拷贝完成后:

并且将properties文件也拷贝过来:

将页面也拷贝过来:web.xml在spring-boot中是不需要的。

1.1.1. 编写Spring配置类TaotaoApplication

1.1.1.设置tomcat端口
application.properties:

读取外部的配置文件
@Configuration
@PropertySource(value = { "classpath:jdbc.properties", "classpath:env.properties",
"classpath:httpclient.properties", "classpath:redis.properties", "classpath:rabbitmq.properties" }, ignoreResourceNotFound = true)
public class TaotaoApplication {

}
1.1.1.设置扫描包

1.1.1.定义数据源
@Value("${jdbc.url}")
private String jdbcUrl;

@Value("${jdbc.driverClassName}")  
private String jdbcDriverClassName;

@Value("${jdbc.username}")  
private String jdbcUsername;

@Value("${jdbc.password}")  
private String jdbcPassword;

@Bean(destroyMethod = "close")  
public DataSource dataSource() {  
    BoneCPDataSource boneCPDataSource = new BoneCPDataSource();  
    // 数据库驱动  
    boneCPDataSource.setDriverClass(jdbcDriverClassName);  
    // 相应驱动的jdbcUrl  
    boneCPDataSource.setJdbcUrl(jdbcUrl);  
    // 数据库的用户名  
    boneCPDataSource.setUsername(jdbcUsername);  
    // 数据库的密码  
    boneCPDataSource.setPassword(jdbcUsername);  
    // 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0  
    boneCPDataSource.setIdleConnectionTestPeriodInMinutes(60);  
    // 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0  
    boneCPDataSource.setIdleMaxAgeInMinutes(30);  
    // 每个分区最大的连接数  
    boneCPDataSource.setMaxConnectionsPerPartition(100);  
    // 每个分区最小的连接数  
    boneCPDataSource.setMinConnectionsPerPartition(5);  
    return boneCPDataSource;  

}
1.1.2.设置Mybatis和Spring Boot整合
Spring Boot官方没有提供Mybatis自动配置的starter,不能直接去用,Mybatis和Spring Boot的整合有两种方式:
第一种:使用mybatis官方提供的Spring Boot整合包实现,地址:https://github.com/mybatis/spring-boot-starter
第二种:使用mybatis-spring整合的方式,也就是我们传统的方式,xml的方式改成java方式。

这里我们推荐使用第二种,因为这样我们可以很方便的控制Mybatis的各种配置,便于扩展mybatis。

首先,创建一个Mybatis的配置类:

代码:
import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

@Configuration
public class MyBatisConfig {

@Bean  
@ConditionalOnMissingBean //当容器里没有指定的Bean的情况下创建该对象  
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {  
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();  
    // 设置数据源  
    sqlSessionFactoryBean.setDataSource(dataSource);  
    // 设置mybatis的主配置文件  
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();  
    Resource mybatisConfigXml = resolver.getResource("classpath:mybatis/mybatis-config.xml");  
    sqlSessionFactoryBean.setConfigLocation(mybatisConfigXml);  
    // 设置别名包  
    sqlSessionFactoryBean.setTypeAliasesPackage("com.taotao.cart.pojo");  
    return sqlSessionFactoryBean;  
}  

}

然后,创建Mapper接口的扫描类MapperScannerConfig:如图上面的xml文件中的bean

代码:
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(MyBatisConfig.class) //保证在MyBatisConfig实例化之后再实例化该类
public class MapperScannerConfig {

// mapper接口的扫描器  
@Bean  
public MapperScannerConfigurer mapperScannerConfigurer() {  
    MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();  
    mapperScannerConfigurer.setBasePackage("com.taotao.cart.mapper");  
    return mapperScannerConfigurer;  
}  

}
1.1.1.设置事务管理
在Spring Boot中推荐使用@Transactional注解来申明事务。

首先需要导入依赖:
org.springframework.boot spring-boot-starter-jdbc

当引入jdbc依赖之后,Spring Boot会做一系列的初始化操作,并且把一些初始化的事务管理都搞定了,并把事务Spring Boot会自动默认分别注入DataSourceTransactionManager或JpaTransactionManager,不需要我们配置DataSourceTransactionManager类了。所以我们不需要任何额外配置就可以用@Transactional注解进行事务的使用。

在Service中添加@Transactional注解:CartService类是和数据库有关系的,所以要加事务。加到类上是所有的public方法都有事务。

1.1.1.设置Redis和Spring的整合
在Spring Boot中提供了RedisTempplate的操作,我们暂时不做学习,先按照我们之前的实现来完成。

代码:

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedisPool;

@Configuration
@PropertySource(value = "classpath:redis.properties")
public class RedisSpringConfig {

@Value("${redis.maxTotal}")  
private Integer redisMaxTotal;

@Value("${redis.node1.host}")  
private String redisNode1Host;

@Value("${redis.node1.port}")  
private Integer redisNode1Port;

private JedisPoolConfig jedisPoolConfig() {  
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();  
    jedisPoolConfig.setMaxTotal(redisMaxTotal);  
    return jedisPoolConfig;  
}

@Bean  
public ShardedJedisPool shardedJedisPool() {  
    List<JedisShardInfo> jedisShardInfos = new ArrayList<JedisShardInfo>();  
    jedisShardInfos.add(new JedisShardInfo(redisNode1Host, redisNode1Port));  
    return new ShardedJedisPool(jedisPoolConfig(), jedisShardInfos);  
}  

}
1.1.2.设置Httpclient和Spring的整合

import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;

import com.taotao.common.httpclient.IdleConnectionEvictor;

@Configuration
@PropertySource(value = "classpath:httpclient.properties")
public class HttpclientSpringConfig {

@Value("${http.maxTotal}")  
private Integer httpMaxTotal;

@Value("${http.defaultMaxPerRoute}")  
private Integer httpDefaultMaxPerRoute;

@Value("${http.connectTimeout}")  
private Integer httpConnectTimeout;

@Value("${http.connectionRequestTimeout}")  
private Integer httpConnectionRequestTimeout;

@Value("${http.socketTimeout}")  
private Integer httpSocketTimeout;

@Value("${http.staleConnectionCheckEnabled}")  
private Boolean httpStaleConnectionCheckEnabled;

@Autowired  
private PoolingHttpClientConnectionManager manager;

@Bean  
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {  
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();  
    // 最大连接数  
    poolingHttpClientConnectionManager.setMaxTotal(httpMaxTotal);  
    // 每个主机的最大并发数  
    poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpDefaultMaxPerRoute);  
    return poolingHttpClientConnectionManager;  
}

// 定期关闭无效连接  
@Bean  
public IdleConnectionEvictor idleConnectionEvictor() {  
    return new IdleConnectionEvictor(manager);  
}

// 定义Httpclient对  
@Bean  
@Scope("prototype")  
public CloseableHttpClient closeableHttpClient() {  
    return HttpClients.custom().setConnectionManager(this.manager).build();  
}

// 请求配置  
@Bean  
public RequestConfig requestConfig() {  
    return RequestConfig.custom().setConnectTimeout(httpConnectTimeout) // 创建连接的最长时间  
            .setConnectionRequestTimeout(httpConnectionRequestTimeout) // 从连接池中获取到连接的最长时间  
            .setSocketTimeout(httpSocketTimeout) // 数据传输的最长时间  
            .setStaleConnectionCheckEnabled(httpStaleConnectionCheckEnabled) // 提交请求前测试连接是否可用  
            .build();  
}

}
1.1.1.设置RabbitMQ和Spring的整合
我们之前使用的Spring-Rabbit的xml方式,现在我们要改造成java方式,并且Spring Boot对RabbitMQ的使用做了自动配置,更加的简化了我们的使用。

在导入spring-boot-starter-amqp的依赖;

在application.properties文件中配置RabbitMQ的连接信息

3、编写Rabbit的Spring配置类
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //之前都是写在xml配置文件
public class RabbitMQSpringConfig {

@Autowired  //连接工厂是springboot帮我们构建的,不需要配置,这里直接使用。  
private ConnectionFactory connectionFactory;

// 管理  
@Bean  
public RabbitAdmin rabbitAdmin() {  
    return new RabbitAdmin(connectionFactory);  
}

// 声明队列  
@Bean  
public Queue taotaoCartLoginQueue() {  
    // 默认就是自动声明的  
    return new Queue("TAOTAO-CART-LOGIN-QUEUE", true);  
}

// 声明队列  
@Bean  
public Queue taotaoCartOrderSuccessQueue() {  
    // 默认就是自动声明的  
    return new Queue("TAOTAO-CART-ORDER-SUCCESS-QUEUE", true);  
}

}
设置监听:之前都是写在xml配置文件里面的。

1.1.1.设置SpringMVC的配置
原有配置:springboot也会自动扫描,所以这个不需要了。注解驱动就是springmvc的自动配置升级版,springboot对springmvc也做了自动配置。视图解析器是前缀后缀。配置拦截器继承WebMvcConfigurerAdapter 重写addInterceptors方法。

具体实现:
视图解析器配置:

自定义拦截器:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.taotao.cart.interceptors.UserLoginHandlerInterceptor;

@Configuration
public class SpringMVCConfig extends WebMvcConfigurerAdapter {

@Override  
public void addInterceptors(InterceptorRegistry registry) {  
    // 判断用户是否登录的拦截器  
    registry.addInterceptor(new UserLoginHandlerInterceptor()).addPathPatterns("/cart/\*\*");  
}

}

1.1.1.设置dubbo的配置
Dubbo目前只能使用xml配置的方式,所以我们需要保留xml,并且需要将该xml加入到现有的Spring容器中才能生效。

将dubbo目录以及下面的xml配置文件拷贝到taotao-cat-springboot中

将dubbo的xml文件加入到spring容器

1.1.1.启动错误1

关键错误(丢失了web容器的工厂,也就是说我们并没有把它作为一个web应用来启动):
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.

解决:

让Spring Boot来自动选择并且完成web的相关加载工作。

1.1.1. Slf4j日志警告

提示我们当前的项目中slf4j引入了2个,导致了jar冲突。

解决:
删除自己引入到slf4j的依赖,保留springboot的依赖。

将taotao-common中传递的依赖排除掉

1.1.1.解决jsp访问404的问题
由于Spring boot使用的内嵌的tomcat,而内嵌的tamcat是不支持jsp页面的,所有需要导入额外的包才能解决。Springboot不支持jsp而推荐模版引擎。

org.apache.tomcat.embed tomcat-embed-jasper provided

1.1.1.拦截器中的UserService空指针异常
分析:由于添加拦截器时,直接对UserLoginHandlerInterceptor进行new操作,导致UserService无法注入,所以有空指针异常。

解决:

1.发布到独立的tomcat中运行
在开发阶段我们推荐使用内嵌的tomcat进行开发,因为这样会方便很多,但是到生成环境,我希望在独立的tomcat容器中运行,因为我们需要对tomcat做额外的优化,这时我们需要将工程打包成war包发进行发布。
1.1.工程的打包方式为war

1.1.将spring-boot-starter-tomcat的范围设置为provided
设置为provided是在打包时会将该包排除,因为要放到独立的tomcat中运行,是不需要spring-boot-starter-tomcat的。spring-boot-starter-web也是会传递加载tomcat的。

org.springframework.boot spring-boot-starter-tomcat provided
1.2.修改代码,设置启动配置
需要集成SpringBootServletInitializer,然后重写configure,将Spring Boot的入口类设置进去。

打包成功:

解压apache-tomcat-7.0.57.tar.gz,将war包解压到webapps下的ROOT目录中,启动:没有web.xml文件,springboot帮助我们搞了。