Spring Boot 開發系列一 開發踩坑
這是學習spring boot 的第二周,公司號稱這玩意是啥都不會的新手就可以填空開發,於是決定上手一把,怎麽說我也是搞了快七八年的.NET和.NETcore,沒想到無情打臉,快被這個能填空開的IDE搞瘋了,下面是記下一些自己踩坑開發中遇到的一系列無窮無盡的問題。
一 .集成MyBatis
a)首先如何理解這個 MyBatis 的東西,我的理解是 :MyBatis 有點類似ORM的感覺,跟 JPA很類似,就是一個orm,需要一個類似 dbcontext的東西,這個東西,在MyBatis 裏面叫做 sqlSessionFactoryBean,好了知道這個,我們就不需要像百度上面一樣,搞各種各樣的配置,不知道所雲的東西全都搞在工程裏面。我的是這樣配置的
package com.example.demo.config; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; 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; import org.mybatis.spring.boot.autoconfigure.*; 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.sql.DataSource; @Configuration @EnableTransactionManagement public class MyBatisConfig { @Autowired private DataSource dataSource; //當容器裏沒有指定的Bean的情況下創建該對象 @Bean(name = "SqlSessionFactoryBean") @ConditionalOnMissingBean public SqlSessionFactoryBean sqlSessionFactoryBean() { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); // 設置數據源 sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; }
,去執行他內置的一些鬼CURD操作,對,他只需要這一個方法就可以了,設置數據源,然後你的 MyBatis 就可以認為有了 我們常說的 dbcontext了。
有了這個數據庫上下文的 sqlSessionFactoryBean,我們需要一些 CRUD的方法,方法在哪裏呢,在那什麽 mapper.xml文件裏面的。
b). 配置 這些方法的路徑,什麽,路徑,對是路徑,我沒有寫過 之前的spring mvc的,但是了解到這些 Mapper.xml 其它就是對應的一個個之前配置的Bean節點下的 方法,只是換了個馬甲而已吧。
package com.example.demo.config; 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(MapperScannerConfig.class) //保證在MyBatisConfig實例化之後再實例化該類 public class MapperScannerConfig { // mapper接口的掃描器 @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.example.demo"); return mapperScannerConfigurer; } }
mapperScannerConfigurer.setBasePackage("com.example.demo"); 註意這句,是說我配置了我的數據庫上下文之後,我要掃我這個上下文裏面 有哪些方法,我要從哪個基包開始掃描找到這些方法,傳說是遞歸去找的。這裏你查看你的mapper接口的包名是什麽,可以直接設置成上一層去,就可以掃描到的。
@AutoConfigureAfter(MapperScannerConfig.class) //保證在MyBatisConfig實例化之後再實例化該類
c)設置mapper.xml的路徑 也就是你的 mapper接口寫好了,得有一個對應的 mapper.xml對應,這樣才知道 你這個接口具體是執行了什麽操作,對,就是這樣,殺人放火的動作,都是寫在XML文件裏面的,當然,寫這個XML文件,個人覺得,沒有什麽比用這各方法寫CRUD操作更坑爹的了,沒有。配置 application.yaml 裏面:
# mybatis_config
mybatis:
mapper-locations: classpath:mapperXml/**/*.xml
具體路徑以自己項目做適當調整。
註意:坑來了,這個XML的坑很嚴重,有時候會折騰到你想死的心都有了,但是還是死不甘心。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.example.demo.permission.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.example.demo.permission.model.User"> <id column="id" property="id" jdbcType="INTEGER"/> <result column="nickname" property="nickname" jdbcType="VARCHAR"/> <result column="email" property="email" jdbcType="VARCHAR"/> <result column="pswd" property="pswd" jdbcType="VARCHAR"/> <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/> <result column="last_login_time" property="lastLoginTime" jdbcType="TIMESTAMP"/> <result column="status" property="status" jdbcType="TINYINT"/> </resultMap> <sql id="Base_Column_List"> id, nickname, email, pswd, create_time, last_login_time, status </sql> <select id="selectByPrimaryKey" resultMap="BaseResultMap" resultType="com.example.demo.permission.model.User" parameterType="java.lang.Integer"> select <include refid="Base_Column_List"/> from sys_user where id = #{id,jdbcType=INTEGER} </select> </mapper>
(1).mapper.xml 文件的namespace要與 mapper接口的包名相同
(2).UserMapper 的方法在UserMapper.xml中沒有,然後執行 userService 的方法會報錯
(3).UserMapper 的方法返回值是List<User>,而select元素沒有正確配置ResultMap,或者只配置ResultType! 這個第三個非常隱敝,我在這裏折騰了三天,就是少了一個ResultType
二 整合Druid
這玩意 取了一個 德魯伊 的名字,估計是阿裏哪位大神喜歡玩遊戲吧,哈哈。好了,這個東西主要是就是一個db連接池的作用。
所以我們只需要把一系列連接數據庫的參數配置上去就Ok了
1) DruidConfig
package com.example.demo.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.*;
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 com.alibaba.druid.*;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration()
public class DruidConfig {
private Logger logger = LoggerFactory.getLogger(getClass());
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.filters}")
private String filters;
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable", "true");
filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
return filterRegistrationBean;
}
@Bean
@Primary
public DataSource druidDataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter", e);
}
return datasource;
}
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
reg.addInitParameter("loginUsername", "druid");
reg.addInitParameter("loginPassword", "druid");
return reg;
}
}
其實只需要配置一個 : druidDataSource 這個就可以了。
FilterRegistrationBean 與 ServletRegistrationBean 主要是為了試一試 Druid的監控介面而已,不要的話,完全沒有問題的。
2)配置文件
#datasource
spring:
datasource:
name: testdb
url: jdbc:mysql://localhost:3306/spring_boot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
#initalSize: 5
filters: stat
applictaion.yaml文件裏面把這些提供一下,OK,鳥德配置成功。
三 配置文件的讀到,各種坑,慢慢踩
暫且說有兩種配置文件吧,
第一種,application.yaml 這個,註意,springboot中 @Configraperporties 標記的 配置節點,讀到的都是application.yaml或得application.properties 裏面的值的。
第二種,自定義的配置文件,註意,雖然 springboot 號稱能讀取.YAML文件,但是,只限 application.yaml 這一個,自定義的文件,只能用 .properties的文件做後綴才能讀的到。
@PropertySource(value = {"classpath:config/globalconfig.properties"}) 是不能讀取 .yaml文件。
Spring Boot 開發系列一 開發踩坑