SpringBoot+mybatis+Maven+Eclipse完整搭建流程以及一些坑的注意

搭建SpringBoot环境

首先在Eclipse创建Maven工程。创建完后,在pom.xml里设置

<groupId>com.xx</groupId>
<artifactId>xxx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

这个设定了工程文件打包后,输出为war。
添加springboot的基础包,

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

用于引用springboot,其中version可以根据自己的需要自选。
还要在pom.xml里设定JDK的版本,

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<maven.compiler.source>1.8</maven.compiler.source>
	<maven.compiler.target>1.8</maven.compiler.target>
</properties>

此外,还要在Eclipse检查下工程的库对应的是JDK还是JRE,要确保是JDK。
同时,要设定

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

这个是用于在mvn package时,将spring相关的包打入到war里。如果没有这一项,那么在mvn package时,只会把工程文件相关的包打入。在tomcat上部署时,不要这个plugin打包也能运行。
此外,也可以添加配置

	<build>
		<finalName>${project.artifactId}</finalName>
	</build>

这个指明了打war包时,文件名仅为artifactId,不带版本号。
下面要添加dependency了:

<!--开发时内嵌tomcat,会在打包时去掉这些包-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
		</exclusion>
	</exclusions>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-tomcat</artifactId>
	<scope>provided</scope>
</dependency>
<!-- 用于springboot的单元测试,后续会看到 -->
<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
</dependency>
<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<scope>test</scope>
</dependency>

同时为了支持@Slf4j注解(用于log打印)和@Data注解(用于自动产生getter, setter),引用

<!-- support log -->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>

用于支持properties属性加密。

<!-- encrypt properties -->
<dependency>
	<groupId>com.github.ulisesbocchio</groupId>
	<artifactId>jasypt-spring-boot-starter</artifactId>
	<version>{jasypt.version.id}</version>
</dependency>

为了让eclipse能支持lombok,需要在lombok.jar下载完毕后,找到对应的jar文件,运行以下命令,将lombok.jar作为插件安装在Eclipse上。

java -jar lombok.jar

创建启动类

在package的根目录下,创建启动类。

@Controller //spring mvc的handler
@EnableEncryptableProperties // 可读取加密的properties。ENC(xxx)
@SpringBootApplication //spring项目的入口类,用于开启自动配置
@Configuration //自身就是一个applicationContext.xml
@RequestMapping("ctrl") //指定该controller的访问路径
@Slf4j //用于调用log
public class App extends SpringBootServletInitializer {
	public static void main( String[] args ) {
        // 这个是在开发的时候用,run as application时指定该类即可启动
        SpringApplication.run(App.class, args);
    }
    
	@Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    	// 这个用于以war包运行时,由外部容器进行配置
        return builder.sources(App.class);
    }
	
	@RequestMapping("hello") //访问路径/ctrl/hello
    @ResponseBody //以json格式返回对象
    public String hello() {
        return "hello world!";
    }
}

创建单元测试类

在工程的src/test/java里面的创建的包下,创建测试类

@RunWith(SpringRunner.class)
@SpringBootTest //可以在这里设定启动的主类
public class AppTest {
	@Test
	public void testxx() {
	};
}

这样,就可以在测试类中直接@Autowired Spring的Bean,然后就可以对各个Bean进行单元测试了。

静态文件

默认静态文件的路径是src/main/resources/static下,在这个文件里,可以创建html,css,js文件。

全局异常处理

SpringBoot默认出现异常时,不会printstacktrace,只会在页面显示简单的错误信息。为了能够自定义全局异常处理,可以注解类@ControllerAdvice,如下:

@ControllerAdvice
public class GlobalExceptionHandler {
	@ExceptionHandler(Exception.class) //用于处理throw new Exception()类型
	public ModelAndView defaultExceptionHandler(Exception ex) {
		ex.printStackTrace();
		ModelAndView mav = new ModelAndView();
		mav.setViewName("showerr"); //异常模板文件:showerr.html
		mav.addObject("code", 500);
		mav.addObject("msg", ex.toString());
		return mav;
	}
}

这里使用了ModelAndView作为异常显示页面的模板,为了让Spring支持模板,还需要在pom.xml中定义

<!-- support html template -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

默认模板文件在src/main/resources/templates下。上面的ModelAndView模板文件可以写为

<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8"></meta>
<title>异常页面</title>
</head>
<body>
	<h1>http错误:<span th:text="${code}"></span></h1>
	<div th:text="${msg}"></div>
</body>

这样ModelAndView就可以把addObject里的值传到src/main/resources/templates/showerr.html文件中。

配置文件

源代码默认配置文件路径是src/main/resources/application.properties下。

多profile支持

我们在开发时需要针对开发、测试、生产环境指定不同的application.properties配置文件。如在application.properties定义

spring.profiles.active=dev

那么SpringBoot默认配置文件就会取application.properties + application-dev.properties。这样就可以同时指定不同的配置信息,只需修改spring.profiles.active就可以自由进行配置信息的切换了。

关于前端和后端的Date类型的坑

Spring一直存在的坑是,Date始终要单独进行配置处理。首先,后端向前端返回Date类型时,需要指定返回的格式,默认下返回的是一个整数。可以在application.properties里面定义全局的后端向前端传送的格式:

spring.jackson.date-format=yyyy-MM-dd
spring.jackson.time-zone=GMT+8

这样返回给前端的才是一个以北京时间字符串。
另外在javascript里注意,用字符串初始化Date会发现有以下的不同

var x1 = new Date("2019-01-01"); //返回的是2019-01-01 00:00:00格林尼治时间
var x2 = new Date("2019-01-01 00:00:00"); //这个才是2019-01-01 00:00:00北京时间

此外,前台向后台传Date时,如果想要以字符串的形式传,还需要在后端的controller的函数中,进行参数转换,Date才能接收:

@RequestMapping("getVal")
@ResponseBody
public String getVal(@DateTimeFormat(pattern="yyyy-mm-dd") Date day) throws Exception{
    
}

运行

在开发环境下,用Eclipse选定App.java类,run as application即可运行。
在测试环境下,先用maven对源代码进行编译:

mvn compile

编译通过后,就可以运行

mvn spring-boot:run

在正式环境下运行,需要将工程文件打包成war,可以在Eclipse或者命令行运行

mvn clean package

Oracle数据库支持

由于Oracle停止了和Maven的合作,所以在Maven的仓库中是无法找到Oracle的连接支持的。一种方法是按照Oracle官网的做法,通过一系列复杂的操作链接Oracle的repository;还有一种做法就是用本地的jar包。首先在本地安装的Oracle客户端找到ojdbcxx.jar的包,把它复制到工程目录的lib/下,这样,就可以在pom.xml配置本地jar的路径:

<!-- local jar for oracle -->
<dependency>
	<groupId>com.oracle</groupId>
	<artifactId>ojdbc</artifactId>
	<version>8</version>
	<scope>system</scope>
	<systemPath>${project.basedir}/lib/ojdbc8.jar</systemPath>
</dependency>

然而,采用这种方法,在打war包时,不会自动将这个jar文件添加到war包中,需要人工将对应的文件拷入。

日志支持

前面提到的lombok包里,自动带了对日志的支持。相关日志可以配置在application.properties里,如下:

logging.level.org.springframework=INFO # 可定义对不同package的类的日志打印级别
logging.path=/home/xx/log # 可将log除打印在console外,也可以记录到文件里。

这样,对于任何要调用log的类,只需要注解@Slf4j,如下:

@Slf4j
public class ClassWithLog {
	public void someAction() {
		try {
			// TODO:
			log.info("finish");
		}
		catch(Exception e) {
			log.error("error happens", e); //自动打印e.printstackTrace到log中
		}
	}
}

Mybatis支持

在pom.xml中定义

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>1.3.5</version>
</dependency>

同时在application.properties里定义数据库连接

spring.datasource.username=xx
spring.datasource.password=xx
spring.datasource.url=jdbc:oracle:thin:@mydbip:1521:dbservicename
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
# mybatis.mapper-locations.classpath=mapping/*Mapper.xml
# mybatis.type-aliases-package=com.example.entit

SpringBoot建议之前在xml的定义,都改在代码里。因此,这里注释掉了后两项。
在Java的interface上,只要注解了@Mapper,就可以当成mapper处理,如

@Mapper
public interface NormalNVMapper {
	@Select({"<script>",
    "SELECT * FROM tbl_order",
    "WHERE 1=1",
    "<when test='title!=null'>",
    "AND mydate = #{mydate}",
    "</when>",
    "</script>"})
    public List<MyQueryResult> getDataBySelect(@Param("mydate") Date mydate);

	static class SQLProvider {
		public String sql(Map<String, Object> param) {
			Date mydate = (Date)param.get("mydate");
			SQL sql = new SQL().SELECT("*").FROM(TBL_ORDER);
        	if (myDate != null) {
            	sql.WHERE("mydate LIKE #{mydate}");
        	}
        	return sql.toString();
		}
	};
	
	@SelectProvider(type = SQLProvider.class, method = "sql")
	public List<MyQueryResult> getDataBySelect2(@Param("mydate") Date mydate);
}

上面代码要注意的点是:

  • Mybatis的Mapper支持两种构造动态sql的方法,一种是@Select注解,使用方法和xml文件方法一样,只是首尾要带上<script>;另一种是@SelectProvider,通过java进行拼接。两种方法不能混用,只能任选一种
  • 函数的参数必须要带@Param,否则Mapper会按照arg0,arg1解析参数,导致参数找不到

多数据源的支持

Springboot默认情况下只会产生一个sqlsessionfactory。如果想要让Springboot支持多个Mybatis数据源,需要自定义bean来处理了。
以配置2个数据源为例,在application.properties里定义

spring.datasource.db1.username=xx
spring.datasource.db1.password=xx
spring.datasource.db1.url=jdbc:oracle:thin:@xx
spring.datasource.db1.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.db2.username=xx
spring.datasource.db2.password=xx
spring.datasource.db2.url=jdbc:oracle:thin:@xx
spring.datasource.db2.driver-class-name=oracle.jdbc.driver.OracleDriver

这里定义了2个数据库的连接db1,db2。对应的db1 Bean的配置为:

@Configuration
@MapperScan(basePackages="${db1扫描的mapper路径}", sqlSessionTemplateRef = "db1Template")
public class DB1Configuration {
	@Bean
	@Primary // 注意spring在初始化时,会尝试调用DataSource Bean初始化一个数据库的连接,如果有多个dataSource会报错,因此要指定primary。如果想禁止Spring的这种行为,可以设置spring.datasource.initialize=false
	@ConfigurationProperties(prefix = "spring.datasource.db1") //.properties里对应的db1的配置
	public DataSource db1DataSource() {
		return DataSourceBuilder.create().build();
	}
	
	@Bean
	public SqlSessionFactory db1SqlSessionFactory(DataSource db1DataSource) throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(db1DataSource);
		return bean.getObject();
	}
	
	@Bean
	public DataSourceTransactionManager db1TransactionManager(DataSource db1DataSource) {
		return new DataSourceTransactionManager(db1DataSource);
	}
	
	@Bean
	public SqlSessionTemplate db1Template(SqlSessionFactory db1SqlSessionFactory) throws Exception {
		return new SqlSessionTemplate(db1SqlSessionFactory);
	}
}

db2的Bean配置和db1类似,除了不需要指定primary dataSource了。

@Configuration
@MapperScan(basePackages="${db2扫描的mapper路径}", sqlSessionTemplateRef = "db2Template")
public class DB2Configuration {
	
	@Bean
	@ConfigurationProperties(prefix = "spring.datasource.db2")
	public DataSource db2DataSource() {
		return DataSourceBuilder.create().build();
	}
	
	// 指定了@Primary之后,将无法通过autowired按照名称绑定DataSource,必须要用@Qualifier
	@Bean
	public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource") DataSource db2DataSource) throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(db2DataSource);
		return bean.getObject();
	}
	
	@Bean
	public DataSourceTransactionManager db2TransactionManager(@Qualifier("db2DataSource") DataSource db2DataSource) {
		return new DataSourceTransactionManager(db2DataSource);
	}
	
	@Bean
	public SqlSessionTemplate db2Template(SqlSessionFactory db2SqlSessionFactory) throws Exception {
		return new SqlSessionTemplate(db2SqlSessionFactory);
	}
	
	
}

这样将db1、db2对应的mapper分别放置在对应的base package下就可以自动读取了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值