项目源码地址:github
最近在开发一个小项目,偶然在逛spring网站的时候对Spring boot产生了兴趣,这种基于微服务的形式就是我一直想要的程序开发方式。有些感兴趣的同学可以试一试。现记录一下我在运行第一个Spring Boot程序的时候遇到的问题,方便各位参考。
首先是我使用的开发工具。
ide:IntelliJ IDEA 2018.2.4
jdk:1.8
第一步:建立一个SpringBoot项目
a、在New Project 中选择Spring Initializr,选择你的jdk版本以及初始化的服务器地址,我这里都选择默认(注:国内可能慢一点)
b、填写项目相关信息,我这里偷懒就直接选择默认了。
c、这一步很关键,因为Spring Boot内置了很多模板,因此你需要选择你需要开发项目的模板,我们这里选择web>web模板。
d、这一步设置项目存放的地方,然后直接点击我们的Finish就完成整个测试项目的创建。
第二步、测试基础项目
到这里我们的Spring Boot项目就已经创建好了,现在我们来测试一下整个项目。找到DemoApplication.java,直接运行就OK
请看控制台,控制台上方出现了Spring的标识,说明我们的示例项目已经运行起来了。
第三步、处理请求
因为上面仅仅是测试我们SpringBoot是否启动起来了,但是我们还没有实质的操作,现在我们加入一个Controller,来实现Spring Mvc中的功能。
具体做法,在DemoApplication.java同级目录下建立Controller 包。为什么是这种方式呢?因为在DemoApplication.java启动类中加入了@SpringBootApplication注解。有兴趣的同学可以去看一看这个注解的源代码,这个注解可以自动扫描项目启动类下的所有包,也就是说我们的@RestController在传统的Springmvc项目中是需要注册到spring容器中的。但是Spring Boot现在自动将启动类下所有包里面包含注解的部分都已经注册到容器中了。
现在我们启动项目,访问http://localhost:8080/sayHello,就可以看到我们返回的值了。我这里使用的是postman,有兴趣的同学也可以试试。
到这里我们的项目就能处理一些请求了,如何与数据库进行交互呢?现在我们来进行mybatis的整合。
第四步、与mybatis整合实现数据读取。
a、引入tomcat-jdbc、mybatis与mysql依赖。
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
经过测试,该版本的mybatis能很好的支持Spring boot (2.1.0.RELEASE)
b、配置数据库连接信息
在Spring Boot中提供了全局的配置文件application.properties。在该文件中我们可以配置我们的数据库信息。
c、在数据库中建用户表
DROP TABLE IF EXISTS `pm_user`;
CREATE TABLE `pm_user` (
`user_id` decimal(8,0) NOT NULL,
`user_name` varchar(64) DEFAULT NULL,
`user_loginname` varchar(64) DEFAULT NULL,
`user_password` varchar(64) DEFAULT NULL,
`mobile` varchar(20) DEFAULT NULL,
`email` varchar(20) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`first_login_time` datetime DEFAULT NULL,
`last_login_time` datetime DEFAULT NULL,
`login_count` decimal(8,0) DEFAULT NULL,
`image` longblob,
`user_memo` varchar(1024) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='用户表\r\n';
SET FOREIGN_KEY_CHECKS = 1;
d、生成一系列的mybatis相关文件(这个地方就不一一赘述怎么去弄的了,我只将代码贴出来,请原谅我的懒...)
UserMapper.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.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.example.demo.model.User">
<id column="user_id" property="userId" jdbcType="DECIMAL"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="user_loginname" property="userLoginname" jdbcType="VARCHAR"/>
<result column="user_password" property="userPassword" jdbcType="VARCHAR"/>
<result column="mobile" property="mobile" jdbcType="VARCHAR"/>
<result column="email" property="email" jdbcType="VARCHAR"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="first_login_time" property="firstLoginTime" jdbcType="TIMESTAMP"/>
<result column="last_login_time" property="lastLoginTime" jdbcType="TIMESTAMP"/>
<result column="login_count" property="loginCount" jdbcType="DECIMAL"/>
<result column="user_memo" property="userMemo" jdbcType="VARCHAR"/>
</resultMap>
<resultMap id="ResultMapWithBLOBs" type="com.example.demo.model.User" extends="BaseResultMap">
<result column="image" property="image" jdbcType="LONGVARBINARY"/>
</resultMap>
<sql id="Base_Column_List">
user_id, user_name, user_loginname, user_password, mobile, email, create_time, first_login_time,
last_login_time, login_count, user_memo
</sql>
<sql id="Blob_Column_List">
image
</sql>
<select id="getUserByUserId" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select * from pm_user
where user_id = ${userId}
</select>
</mapper>
UserMapper.java
package com.example.demo.mapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
/**
* 根据用户ID查找用户信息
*
* @param userId 用户ID
* @return 用户信息
*/
User getUserByUserId(@Param("userId")Integer userId);
}
User.java
package com.example.demo.entity;
import java.util.Date;
public class User {
private Integer userId;
private String userName;
private String userLoginname;
private String userPassword;
private String mobile;
private String email;
private Date createTime;
private Date firstLoginTime;
private Date lastLoginTime;
private Integer loginCount;
private String userMemo;
private byte[] image;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName == null ? null : userName.trim();
}
public String getUserLoginname() {
return userLoginname;
}
public void setUserLoginname(String userLoginname) {
this.userLoginname = userLoginname == null ? null : userLoginname.trim();
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword == null ? null : userPassword.trim();
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile == null ? null : mobile.trim();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getFirstLoginTime() {
return firstLoginTime;
}
public void setFirstLoginTime(Date firstLoginTime) {
this.firstLoginTime = firstLoginTime;
}
public Date getLastLoginTime() {
return lastLoginTime;
}
public void setLastLoginTime(Date lastLoginTime) {
this.lastLoginTime = lastLoginTime;
}
public Integer getLoginCount() {
return loginCount;
}
public void setLoginCount(Integer loginCount) {
this.loginCount = loginCount;
}
public String getUserMemo() {
return userMemo;
}
public void setUserMemo(String userMemo) {
this.userMemo = userMemo == null ? null : userMemo.trim();
}
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
}
重要:在resource文件夹下建立mybatis文件夹存放UserMapper.xml。
e、Service层
1、创建service接口
package com.example.demo.service;
import com.example.demo.entity.User;
public interface UserService {
/**
* 根据用户ID查询用户信息
* @param userId 用户ID
* @return 用户信息
*/
User getUserByUserId(int userId);
}
2、实现service
package com.example.demo.service.impl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
public UserMapper userMapper;
@Override
public User getUserByUserId(int userId) {
return userMapper.getUserByUserId(Integer.valueOf(userId));
}
}
f、controller层
创建UserController
package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "getUserByUserId",method = RequestMethod.GET)
public User getUserByUserId(int userId){
return userService.getUserByUserId(userId);
}
}
好了,现在已经完成了整体框架的搭建,启动项目。
启动项目中报错了,遇到报错我们不要惊慌,先看看什么错误
看日志 Consider defining a bean of type 'com.example.demo.mapper.UserMapper' in your configuration.
我们在DemoAction中没有扫描UserMapper,那么我们在启动类中声明一下
这里一定要注意!!!!!!!!
@MapperScan
这个注解是扫描的mapper包,不是具体到一个类,比如说@MapperScan("com.example.demo.mapper")是可以扫描到的,但是你如果写成@MapperScan("com.example.demo.mapper.UserMapper"),是不能被扫描的!!!
g、我们再启动一下整个项目
控制台中报错了
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [/Users/ron/idea_workspace/demo01/target/classes/com/example/demo/service/UserService.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1378) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:575) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) ~[spring-context-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at com.example.demo.DemoApplication.main(DemoApplication.java:24) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [/Users/ron/idea_workspace/demo01/target/classes/com/example/demo/service/UserService.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1745) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:273) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1239) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1166) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
... 19 common frames omitted
Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
at org.springframework.util.Assert.notNull(Assert.java:198) ~[spring-core-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.mybatis.spring.support.SqlSessionDaoSupport.checkDaoConfig(SqlSessionDaoSupport.java:74) ~[mybatis-spring-1.3.1.jar:1.3.1]
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:73) ~[mybatis-spring-1.3.1.jar:1.3.1]
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44) ~[spring-tx-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1741) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
... 29 common frames omitted
这个错误里面说:Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
那么在启动类中加入:
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new org.apache.tomcat.jdbc.pool.DataSource();
}
/**
* 提供sqlsessionfactory
* @return
* @throws Exception
*/
@Bean
public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mybatis/*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean
public PlatformTransactionManager transactionManager(){
return new DataSourceTransactionManager(dataSource());
}
你会发现PlatformTransactionManager这个找不到引入包,因为这个事Spring的一部分,我们需要在pom文件中声明引入相应的jar包。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
好的,现在我们再启动,发现已经完全启动了。